Pull PCI updates from Bjorn Helgaas: "Enumeration: - Don't try to enable Extended Tags on VFs since that bit is Reserved and causes misleading log messages (Håkon Bugge) - Initialize Endpoint Read Completion Boundary to match Root Port, regardless of ACPI _HPX (Håkon Bugge) - Apply _HPX PCIe Setting Record only to AER configuration, and only when OS owns PCIe hotplug but not AER, to avoid clobbering Extended Tag and Relaxed Ordering settings (Håkon Bugge) Resource management: - Move CardBus code to setup-cardbus.c and only build it when CONFIG_CARDBUS is set (Ilpo Järvinen) - Fix bridge window alignment with optional resources, where additional alignment requirement was previously lost (Ilpo Järvinen) - Stop over-estimating bridge window size since they are now assigned without any gaps between them (Ilpo Järvinen) - Increase resource MAX_IORES_LEVEL to avoid /proc/iomem flattening for nested bridges and endpoints (Ilpo Järvinen) - Add pbus_mem_size_optional() to handle sizes of optional resources (SR-IOV VF BARs, expansion ROMs, bridge windows) (Ilpo Järvinen) - Don't claim disabled bridge windows to avoid spurious claim failures (Ilpo Järvinen) Driver binding: - Fix device reference leak in pcie_port_remove_service() (Uwe Kleine-König) - Move pcie_port_bus_match() and pcie_port_bus_type to PCIe-specific portdrv.c (Uwe Kleine-König) - Convert portdrv to use pcie_port_bus_type.probe() and .remove() callbacks so .probe() and .remove() can eventually be removed from struct device_driver (Uwe Kleine-König) Error handling: - Clear stale errors on reporting agents upon probe so they don't look like recent errors (Lukas Wunner) - Add generic RAS tracepoint for hotplug events (Shuai Xue) - Add RAS tracepoint for link speed changes (Shuai Xue) Power management: - Avoid redundant delay on transition from D3hot to D3cold if the device was already in D3hot (Brian Norris) - Prevent runtime suspend until devices are fully initialized to avoid saving incompletely configured device state (Brian Norris) Power control: - Add power_on/off callbacks with generic signature to pwrseq, tc9563, and slot drivers so they can be used by pwrctrl core (Manivannan Sadhasivam) - Add PCIe M.2 connector support to the slot pwrctrl driver (Manivannan Sadhasivam) - Switch to pwrctrl interfaces to create, destroy, and power on/off devices, calling them from host controller drivers instead of the PCI core (Manivannan Sadhasivam) - Drop qcom .assert_perst() callbacks since this is now done by the controller driver instead of the pwrctrl driver (Manivannan Sadhasivam) Virtualization: - Remove an incorrect unlock in pci_slot_trylock() error handling (Jinhui Guo) - Lock the bridge device for slot reset (Keith Busch) - Enable ACS after IOMMU configuration on OF platforms so ACS is enabled an all devices; previously the first device enumerated (typically a Root Port) didn't have ACS enabled (Manivannan Sadhasivam) - Disable ACS Source Validation for IDT 0x80b5 and 0x8090 switches to work around hardware erratum; previously ACS SV was only temporarily disabled, which worked for enumeration but not after reset (Manivannan Sadhasivam) Peer-to-peer DMA: - Release per-CPU pgmap ref when vm_insert_page() fails to avoid hang when removing the PCI device (Hou Tao) - Remove incorrect p2pmem_alloc_mmap() warning about page refcount (Hou Tao) Endpoint framework: - Add configfs sub-groups synchronously to avoid NULL pointer dereference when racing with removal (Liu Song) - Fix swapped parameters in pci_{primary/secondary}_epc_epf_unlink() functions (Manikanta Maddireddy) ASPEED PCIe controller driver: - Add ASPEED Root Complex DT binding and driver (Jacky Chou) Freescale i.MX6 PCIe controller driver: - Add DT binding and driver support for an optional external refclock in addition to the refclock from the internal PLL (Richard Zhu) - Fix CLKREQ# control so host asserts it during enumeration and Endpoints can use it afterwards to exit the L1.2 link state (Richard Zhu) NVIDIA Tegra PCIe controller driver: - Export irq_domain_free_irqs() to allow PCI/MSI drivers that tear down MSI domains to be built as modules (Aaron Kling) - Allow pci-tegra to be built as a module (Aaron Kling) NVIDIA Tegra194 PCIe controller driver: - Relax Kconfig so tegra194 can be built for platforms beyond Tegra194 (Vidya Sagar) Qualcomm PCIe controller driver: - Merge SC8180x DT binding into SM8150 (Krzysztof Kozlowski) - Move SDX55, SDM845, QCS404, IPQ5018, IPQ6018, IPQ8074 Gen3, IPQ8074, IPQ4019, IPQ9574, APQ8064, MSM8996, APQ8084 to dedicated schema (Krzysztof Kozlowski) - Add DT binding and driver support for SA8255p Endpoint being configured by firmware (Mrinmay Sarkar) - Parse PERST# from all PCIe bridge nodes for future platforms that will have PERST# in Switch Downstream Ports as well as in Root Ports (Manivannan Sadhasivam) Renesas RZ/G3S PCIe controller driver: - Use pci_generic_config_write() since the writability provided by the custom wrapper is unnecessary (Claudiu Beznea) SOPHGO PCIe controller driver: - Disable ASPM L0s and L1 on Sophgo 2044 PCIe Root Ports (Inochi Amaoto) Synopsys DesignWare PCIe controller driver: - Extend PCI_FIND_NEXT_CAP() and PCI_FIND_NEXT_EXT_CAP() to return a pointer to the preceding Capability, to allow removal of Capabilities that are advertised but not fully implemented (Qiang Yu) - Remove MSI and MSI-X Capabilities in platforms that can't support them, so the PCI core automatically falls back to INTx (Qiang Yu) - Add ASPM L1.1 and L1.2 Substates context to debugfs ltssm_status for drivers that support this (Shawn Lin) - Skip PME_Turn_Off broadcast and L2/L3 transition during suspend if link is not up to avoid an unnecessary timeout (Manivannan Sadhasivam) - Revert dw-rockchip, qcom, and DWC core changes that used link-up IRQs to trigger enumeration instead of waiting for link to be up because the PCI core doesn't allocate bus number space for hierarchies that might be attached (Niklas Cassel) - Make endpoint iATU entry for MSI permanent instead of programming it dynamically, which is slow and racy with respect to other concurrent traffic, e.g., eDMA (Koichiro Den) - Use iMSI-RX MSI target address when possible to fix endpoints using 32-bit MSI (Shawn Lin) - Allow DWC host controller driver probe to continue if device is not found or found but inactive; only fail when there's an error with the link (Manivannan Sadhasivam) - For controllers like NXP i.MX6QP and i.MX7D, where LTSSM registers are not accessible after PME_Turn_Off, simply wait 10ms instead of polling for L2/L3 Ready (Richard Zhu) - Use multiple iATU entries to map large bridge windows and DMA ranges when necessary instead of failing (Samuel Holland) - Add EPC dynamic_inbound_mapping feature bit for Endpoint Controllers that can update BAR inbound address translation without requiring EPF driver to clear/reset the BAR first, and advertise it for DWC-based Endpoints (Koichiro Den) - Add EPC subrange_mapping feature bit for Endpoint Controllers that can map multiple independent inbound regions in a single BAR, implement subrange mapping, advertise it for DWC-based Endpoints, and add Endpoint selftests for it (Koichiro Den) - Make resizable BARs work for Endpoint multi-PF configurations; previously it only worked for PF 0 (Aksh Garg) - Fix Endpoint non-PF 0 support for BAR configuration, ATU mappings, and Address Match Mode (Aksh Garg) - Set up iATU when ECAM is enabled; previously IO and MEM outbound windows weren't programmed, and ECAM-related iATU entries weren't restored after suspend/resume, so config accesses failed (Krishna Chaitanya Chundru) Miscellaneous: - Use system_percpu_wq and WQ_PERCPU to explicitly request per-CPU work so WQ_UNBOUND can eventually be removed (Marco Crivellari)" * tag 'pci-v7.0-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (176 commits) PCI/bwctrl: Disable BW controller on Intel P45 using a quirk PCI: Disable ACS SV for IDT 0x8090 switch PCI: Disable ACS SV for IDT 0x80b5 switch PCI: Cache ACS Capabilities register PCI: Enable ACS after configuring IOMMU for OF platforms PCI: Add ACS quirk for Pericom PI7C9X2G404 switches [12d8:b404] PCI: Add ACS quirk for Qualcomm Hamoa & Glymur PCI: Use device_lock_assert() to verify device lock is held PCI: Use lockdep_assert_held(pci_bus_sem) to verify lock is held PCI: Fix pci_slot_lock () device locking PCI: Fix pci_slot_trylock() error handling PCI: Mark Nvidia GB10 to avoid bus reset PCI: Mark ASM1164 SATA controller to avoid bus reset PCI: host-generic: Avoid reporting incorrect 'missing reg property' error PCI/PME: Replace RMW of Root Status register with direct write PCI/AER: Clear stale errors on reporting agents upon probe PCI: Don't claim disabled bridge windows PCI: rzg3s-host: Fix device node reference leak in rzg3s_pcie_host_parse_port() PCI: dwc: Fix missing iATU setup when ECAM is enabled PCI: dwc: Clean up iATU index usage in dw_pcie_iatu_setup() ...
Unified · Split
| @@ -95,6 +95,30 @@ by the PCI endpoint function driver. · 94 unmodified lines | |||
| 95 | Register space of the function driver is usually configured | 95 | Register space of the function driver is usually configured |
| 96 | using this API. | 96 | using this API. |
| 97 | 97 | ||
| 98 | Some endpoint controllers also support calling pci_epc_set_bar() again | ||
| 99 | for the same BAR (without calling pci_epc_clear_bar()) to update inbound | ||
| 100 | address translations after the host has programmed the BAR base address. | ||
| 101 | Endpoint function drivers can check this capability via the | ||
| 102 | dynamic_inbound_mapping EPC feature bit. | ||
| 103 | |||
| 104 | When pci_epf_bar.num_submap is non-zero, the endpoint function driver is | ||
| 105 | requesting BAR subrange mapping using pci_epf_bar.submap. This requires | ||
| 106 | the EPC to advertise support via the subrange_mapping EPC feature bit. | ||
| 107 | |||
| 108 | When an EPF driver wants to make use of the inbound subrange mapping | ||
| 109 | feature, it requires that the BAR base address has been programmed by | ||
| 110 | the host during enumeration. Thus, it needs to call pci_epc_set_bar() | ||
| 111 | twice for the same BAR (requires dynamic_inbound_mapping): first with | ||
| 112 | num_submap set to zero and configuring the BAR size, then after the PCIe | ||
| 113 | link is up and the host enumerates the endpoint and programs the BAR | ||
| 114 | base address, again with num_submap set to non-zero value. | ||
| 115 | |||
| 116 | Note that when making use of the inbound subrange mapping feature, the | ||
| 117 | EPF driver must not call pci_epc_clear_bar() between the two | ||
| 118 | pci_epc_set_bar() calls, because clearing the BAR can clear/disable the | ||
| 119 | BAR register or BAR decode on the endpoint while the host still expects | ||
| 120 | the assigned BAR address to remain valid. | ||
| 121 | |||
| 98 | * pci_epc_clear_bar() | 122 | * pci_epc_clear_bar() |
| 99 | 123 | ||
| 100 | The PCI endpoint function driver should use pci_epc_clear_bar() to reset | 124 | The PCI endpoint function driver should use pci_epc_clear_bar() to reset |
| @@ -84,6 +84,25 @@ device, the following commands can be used:: · 83 unmodified lines | |||
| 84 | # echo 32 > functions/pci_epf_test/func1/msi_interrupts | 84 | # echo 32 > functions/pci_epf_test/func1/msi_interrupts |
| 85 | # echo 2048 > functions/pci_epf_test/func1/msix_interrupts | 85 | # echo 2048 > functions/pci_epf_test/func1/msix_interrupts |
| 86 | 86 | ||
| 87 | By default, pci-epf-test uses the following BAR sizes:: | ||
| 88 | |||
| 89 | # grep . functions/pci_epf_test/func1/pci_epf_test.0/bar?_size | ||
| 90 | functions/pci_epf_test/func1/pci_epf_test.0/bar0_size:131072 | ||
| 91 | functions/pci_epf_test/func1/pci_epf_test.0/bar1_size:131072 | ||
| 92 | functions/pci_epf_test/func1/pci_epf_test.0/bar2_size:131072 | ||
| 93 | functions/pci_epf_test/func1/pci_epf_test.0/bar3_size:131072 | ||
| 94 | functions/pci_epf_test/func1/pci_epf_test.0/bar4_size:131072 | ||
| 95 | functions/pci_epf_test/func1/pci_epf_test.0/bar5_size:1048576 | ||
| 96 | |||
| 97 | The user can override a default value using e.g.:: | ||
| 98 | # echo 1048576 > functions/pci_epf_test/func1/pci_epf_test.0/bar1_size | ||
| 99 | |||
| 100 | Overriding the default BAR sizes can only be done before binding the | ||
| 101 | pci-epf-test device to a PCI endpoint controller driver. | ||
| 102 | |||
| 103 | Note: Some endpoint controllers might have fixed-size BARs or reserved BARs; | ||
| 104 | for such controllers, the corresponding BAR size in configfs will be ignored. | ||
| 105 | |||
| 87 | 106 | ||
| 88 | Binding pci-epf-test Device to EP Controller | 107 | Binding pci-epf-test Device to EP Controller |
| 89 | -------------------------------------------- | 108 | -------------------------------------------- |
| @@ -52,14 +52,14 @@ pci-epf-vntb device, the following commands can be used:: · 51 unmodified lines | |||
| 52 | # cd /sys/kernel/config/pci_ep/ | 52 | # cd /sys/kernel/config/pci_ep/ |
| 53 | # mkdir functions/pci_epf_vntb/func1 | 53 | # mkdir functions/pci_epf_vntb/func1 |
| 54 | 54 | ||
| 55 | The "mkdir func1" above creates the pci-epf-ntb function device that will | 55 | The "mkdir func1" above creates the pci-epf-vntb function device that will |
| 56 | be probed by pci_epf_vntb driver. | 56 | be probed by pci_epf_vntb driver. |
| 57 | 57 | ||
| 58 | The PCI endpoint framework populates the directory with the following | 58 | The PCI endpoint framework populates the directory with the following |
| 59 | configurable fields:: | 59 | configurable fields:: |
| 60 | 60 | ||
| 61 | # ls functions/pci_epf_ntb/func1 | 61 | # ls functions/pci_epf_vntb/func1 |
| 62 | baseclass_code deviceid msi_interrupts pci-epf-ntb.0 | 62 | baseclass_code deviceid msi_interrupts pci-epf-vntb.0 |
| 63 | progif_code secondary subsys_id vendorid | 63 | progif_code secondary subsys_id vendorid |
| 64 | cache_line_size interrupt_pin msix_interrupts primary | 64 | cache_line_size interrupt_pin msix_interrupts primary |
| 65 | revid subclass_code subsys_vendor_id | 65 | revid subclass_code subsys_vendor_id |
| @@ -111,13 +111,13 @@ A sample configuration for virtual NTB driver for virtual PCI bus:: · 45 unmodified lines | |||
| 111 | # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid | 111 | # echo 0x080A > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vntb_pid |
| 112 | # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number | 112 | # echo 0x10 > functions/pci_epf_vntb/func1/pci_epf_vntb.0/vbus_number |
| 113 | 113 | ||
| 114 | Binding pci-epf-ntb Device to EP Controller | 114 | Binding pci-epf-vntb Device to EP Controller |
| 115 | -------------------------------------------- | 115 | -------------------------------------------- |
| 116 | 116 | ||
| 117 | NTB function device should be attached to PCI endpoint controllers | 117 | NTB function device should be attached to PCI endpoint controllers |
| 118 | connected to the host. | 118 | connected to the host. |
| 119 | 119 | ||
| 120 | # ln -s controllers/5f010000.pcie_ep functions/pci-epf-ntb/func1/primary | 120 | # ln -s controllers/5f010000.pcie_ep functions/pci_epf_vntb/func1/primary |
| 121 | 121 | ||
| 122 | Once the above step is completed, the PCI endpoint controllers are ready to | 122 | Once the above step is completed, the PCI endpoint controllers are ready to |
| 123 | establish a link with the host. | 123 | establish a link with the host. |
| @@ -139,7 +139,7 @@ lspci Output at Host side · 15 unmodified lines | |||
| 139 | ------------------------- | 139 | ------------------------- |
| 140 | 140 | ||
| 141 | Note that the devices listed here correspond to the values populated in | 141 | Note that the devices listed here correspond to the values populated in |
| 142 | "Creating pci-epf-ntb Device" section above:: | 142 | "Creating pci-epf-vntb Device" section above:: |
| 143 | 143 | ||
| 144 | # lspci | 144 | # lspci |
| 145 | 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) | 145 | 00:00.0 PCI bridge: Freescale Semiconductor Inc Device 0000 (rev 01) |
| @@ -152,7 +152,7 @@ lspci Output at EP Side / Virtual PCI bus · 6 unmodified lines | |||
| 152 | ----------------------------------------- | 152 | ----------------------------------------- |
| 153 | 153 | ||
| 154 | Note that the devices listed here correspond to the values populated in | 154 | Note that the devices listed here correspond to the values populated in |
| 155 | "Creating pci-epf-ntb Device" section above:: | 155 | "Creating pci-epf-vntb Device" section above:: |
| 156 | 156 | ||
| 157 | # lspci | 157 | # lspci |
| 158 | 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) | 158 | 10:00.0 Unassigned class [ffff]: Dawicontrol Computersysteme GmbH Device 1234 (rev ff) |
| @@ -98,7 +98,7 @@ function:: · 97 unmodified lines | |||
| 98 | 98 | ||
| 99 | which allocates up to max_vecs interrupt vectors for a PCI device. It | 99 | which allocates up to max_vecs interrupt vectors for a PCI device. It |
| 100 | returns the number of vectors allocated or a negative error. If the device | 100 | returns the number of vectors allocated or a negative error. If the device |
| 101 | has a requirements for a minimum number of vectors the driver can pass a | 101 | has a requirement for a minimum number of vectors the driver can pass a |
| 102 | min_vecs argument set to this limit, and the PCI core will return -ENOSPC | 102 | min_vecs argument set to this limit, and the PCI core will return -ENOSPC |
| 103 | if it can't meet the minimum number of vectors. | 103 | if it can't meet the minimum number of vectors. |
| 104 | 104 | ||
| @@ -127,7 +127,7 @@ not be able to allocate as many vectors for MSI as it could for MSI-X. On · 22 unmodified lines | |||
| 127 | some platforms, MSI interrupts must all be targeted at the same set of CPUs | 127 | some platforms, MSI interrupts must all be targeted at the same set of CPUs |
| 128 | whereas MSI-X interrupts can all be targeted at different CPUs. | 128 | whereas MSI-X interrupts can all be targeted at different CPUs. |
| 129 | 129 | ||
| 130 | If a device supports neither MSI-X or MSI it will fall back to a single | 130 | If a device supports neither MSI-X nor MSI it will fall back to a single |
| 131 | legacy IRQ vector. | 131 | legacy IRQ vector. |
| 132 | 132 | ||
| 133 | The typical usage of MSI or MSI-X interrupts is to allocate as many vectors | 133 | The typical usage of MSI or MSI-X interrupts is to allocate as many vectors |
| @@ -203,7 +203,7 @@ How to tell whether MSI/MSI-X is enabled on a device · 69 unmodified lines | |||
| 203 | ---------------------------------------------------- | 203 | ---------------------------------------------------- |
| 204 | 204 | ||
| 205 | Using 'lspci -v' (as root) may show some devices with "MSI", "Message | 205 | Using 'lspci -v' (as root) may show some devices with "MSI", "Message |
| 206 | Signalled Interrupts" or "MSI-X" capabilities. Each of these capabilities | 206 | Signaled Interrupts" or "MSI-X" capabilities. Each of these capabilities |
| 207 | has an 'Enable' flag which is followed with either "+" (enabled) | 207 | has an 'Enable' flag which is followed with either "+" (enabled) |
| 208 | or "-" (disabled). | 208 | or "-" (disabled). |
| 209 | 209 | ||
| @@ -0,0 +1,182 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/aspeed,ast2600-pcie.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: ASPEED PCIe Root Complex Controller | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Jacky Chou <jacky_chou@aspeedtech.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | The ASPEED PCIe Root Complex controller provides PCI Express Root Complex | ||
| 14 | functionality for ASPEED SoCs, such as the AST2600 and AST2700. | ||
| 15 | This controller enables connectivity to PCIe endpoint devices, supporting | ||
| 16 | memory and I/O windows, MSI and INTx interrupts, and integration with | ||
| 17 | the SoC's clock, reset, and pinctrl subsystems. On AST2600, the PCIe Root | ||
| 18 | Port device number is always 8. | ||
| 19 | |||
| 20 | properties: | ||
| 21 | compatible: | ||
| 22 | enum: | ||
| 23 | - aspeed,ast2600-pcie | ||
| 24 | - aspeed,ast2700-pcie | ||
| 25 | |||
| 26 | reg: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | ranges: | ||
| 30 | minItems: 2 | ||
| 31 | maxItems: 2 | ||
| 32 | |||
| 33 | interrupts: | ||
| 34 | maxItems: 1 | ||
| 35 | description: INTx and MSI interrupt | ||
| 36 | |||
| 37 | resets: | ||
| 38 | items: | ||
| 39 | - description: PCIe controller reset | ||
| 40 | |||
| 41 | reset-names: | ||
| 42 | items: | ||
| 43 | - const: h2x | ||
| 44 | |||
| 45 | aspeed,ahbc: | ||
| 46 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 47 | description: | ||
| 48 | Phandle to the ASPEED AHB Controller (AHBC) syscon node. | ||
| 49 | This reference is used by the PCIe controller to access | ||
| 50 | system-level configuration registers related to the AHB bus. | ||
| 51 | To enable AHB access for the PCIe controller. | ||
| 52 | |||
| 53 | aspeed,pciecfg: | ||
| 54 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 55 | description: | ||
| 56 | Phandle to the ASPEED PCIe configuration syscon node. | ||
| 57 | This reference allows the PCIe controller to access | ||
| 58 | SoC-specific PCIe configuration registers. There are the others | ||
| 59 | functions such PCIe RC and PCIe EP will use this common register | ||
| 60 | to configure the SoC interfaces. | ||
| 61 | |||
| 62 | interrupt-controller: true | ||
| 63 | |||
| 64 | patternProperties: | ||
| 65 | "^pcie@[0-9a-f]+,0$": | ||
| 66 | type: object | ||
| 67 | $ref: /schemas/pci/pci-pci-bridge.yaml# | ||
| 68 | |||
| 69 | properties: | ||
| 70 | reg: | ||
| 71 | maxItems: 1 | ||
| 72 | |||
| 73 | resets: | ||
| 74 | items: | ||
| 75 | - description: PERST# signal | ||
| 76 | |||
| 77 | reset-names: | ||
| 78 | items: | ||
| 79 | - const: perst | ||
| 80 | |||
| 81 | clocks: | ||
| 82 | maxItems: 1 | ||
| 83 | |||
| 84 | phys: | ||
| 85 | maxItems: 1 | ||
| 86 | |||
| 87 | required: | ||
| 88 | - resets | ||
| 89 | - reset-names | ||
| 90 | - clocks | ||
| 91 | - phys | ||
| 92 | - ranges | ||
| 93 | |||
| 94 | unevaluatedProperties: false | ||
| 95 | |||
| 96 | allOf: | ||
| 97 | - $ref: /schemas/pci/pci-host-bridge.yaml# | ||
| 98 | - $ref: /schemas/interrupt-controller/msi-controller.yaml# | ||
| 99 | - if: | ||
| 100 | properties: | ||
| 101 | compatible: | ||
| 102 | contains: | ||
| 103 | const: aspeed,ast2600-pcie | ||
| 104 | then: | ||
| 105 | required: | ||
| 106 | - aspeed,ahbc | ||
| 107 | else: | ||
| 108 | properties: | ||
| 109 | aspeed,ahbc: false | ||
| 110 | - if: | ||
| 111 | properties: | ||
| 112 | compatible: | ||
| 113 | contains: | ||
| 114 | const: aspeed,ast2700-pcie | ||
| 115 | then: | ||
| 116 | required: | ||
| 117 | - aspeed,pciecfg | ||
| 118 | else: | ||
| 119 | properties: | ||
| 120 | aspeed,pciecfg: false | ||
| 121 | |||
| 122 | required: | ||
| 123 | - reg | ||
| 124 | - interrupts | ||
| 125 | - bus-range | ||
| 126 | - ranges | ||
| 127 | - resets | ||
| 128 | - reset-names | ||
| 129 | - msi-controller | ||
| 130 | - interrupt-controller | ||
| 131 | - interrupt-map-mask | ||
| 132 | - interrupt-map | ||
| 133 | |||
| 134 | unevaluatedProperties: false | ||
| 135 | |||
| 136 | examples: | ||
| 137 | - | | ||
| 138 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 139 | #include <dt-bindings/clock/ast2600-clock.h> | ||
| 140 | |||
| 141 | pcie0: pcie@1e770000 { | ||
| 142 | compatible = "aspeed,ast2600-pcie"; | ||
| 143 | device_type = "pci"; | ||
| 144 | reg = <0x1e770000 0x100>; | ||
| 145 | #address-cells = <3>; | ||
| 146 | #size-cells = <2>; | ||
| 147 | interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; | ||
| 148 | bus-range = <0x00 0xff>; | ||
| 149 | |||
| 150 | ranges = <0x01000000 0x0 0x00018000 0x00018000 0x0 0x00008000 | ||
| 151 | 0x02000000 0x0 0x60000000 0x60000000 0x0 0x20000000>; | ||
| 152 | |||
| 153 | resets = <&syscon ASPEED_RESET_H2X>; | ||
| 154 | reset-names = "h2x"; | ||
| 155 | |||
| 156 | #interrupt-cells = <1>; | ||
| 157 | msi-controller; | ||
| 158 | |||
| 159 | aspeed,ahbc = <&ahbc>; | ||
| 160 | |||
| 161 | interrupt-controller; | ||
| 162 | interrupt-map-mask = <0 0 0 7>; | ||
| 163 | interrupt-map = <0 0 0 1 &pcie0 0>, | ||
| 164 | <0 0 0 2 &pcie0 1>, | ||
| 165 | <0 0 0 3 &pcie0 2>, | ||
| 166 | <0 0 0 4 &pcie0 3>; | ||
| 167 | |||
| 168 | pcie@8,0 { | ||
| 169 | compatible = "pciclass,0604"; | ||
| 170 | reg = <0x00004000 0 0 0 0>; | ||
| 171 | #address-cells = <3>; | ||
| 172 | #size-cells = <2>; | ||
| 173 | device_type = "pci"; | ||
| 174 | resets = <&syscon ASPEED_RESET_PCIE_RC_O>; | ||
| 175 | reset-names = "perst"; | ||
| 176 | clocks = <&syscon ASPEED_CLK_GATE_BCLK>; | ||
| 177 | pinctrl-names = "default"; | ||
| 178 | pinctrl-0 = <&pinctrl_pcierc1_default>; | ||
| 179 | phys = <&pcie_phy1>; | ||
| 180 | ranges; | ||
| 181 | }; | ||
| 182 | }; | ||
| @@ -44,7 +44,7 @@ properties: · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | clock-names: | 45 | clock-names: |
| 46 | minItems: 3 | 46 | minItems: 3 |
| 47 | maxItems: 5 | 47 | maxItems: 6 |
| 48 | 48 | ||
| 49 | interrupts: | 49 | interrupts: |
| 50 | minItems: 1 | 50 | minItems: 1 |
| @@ -212,14 +212,17 @@ allOf: · 161 unmodified lines | |||
| 212 | then: | 212 | then: |
| 213 | properties: | 213 | properties: |
| 214 | clocks: | 214 | clocks: |
| 215 | maxItems: 5 | 215 | minItems: 5 |
| 216 | maxItems: 6 | ||
| 216 | clock-names: | 217 | clock-names: |
| 218 | minItems: 5 | ||
| 217 | items: | 219 | items: |
| 218 | - const: pcie | 220 | - const: pcie |
| 219 | - const: pcie_bus | 221 | - const: pcie_bus |
| 220 | - const: pcie_phy | 222 | - const: pcie_phy |
| 221 | - const: pcie_aux | 223 | - const: pcie_aux |
| 222 | - const: ref | 224 | - const: ref |
| 225 | - const: extref # Optional | ||
| 223 | 226 | ||
| 224 | unevaluatedProperties: false | 227 | unevaluatedProperties: false |
| 225 | 228 | ||
| @@ -32,6 +32,8 @@ properties: · 31 unmodified lines | |||
| 32 | minItems: 1 | 32 | minItems: 1 |
| 33 | maxItems: 3 | 33 | maxItems: 3 |
| 34 | 34 | ||
| 35 | msi-parent: true | ||
| 36 | |||
| 35 | required: | 37 | required: |
| 36 | - compatible | 38 | - compatible |
| 37 | - reg | 39 | - reg |
| @@ -48,6 +48,7 @@ properties: · 47 unmodified lines | |||
| 48 | oneOf: | 48 | oneOf: |
| 49 | - items: | 49 | - items: |
| 50 | - enum: | 50 | - enum: |
| 51 | - mediatek,mt7981-pcie | ||
| 51 | - mediatek,mt7986-pcie | 52 | - mediatek,mt7986-pcie |
| 52 | - mediatek,mt8188-pcie | 53 | - mediatek,mt8188-pcie |
| 53 | - mediatek,mt8195-pcie | 54 | - mediatek,mt8195-pcie |
| @@ -0,0 +1,170 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-apq8064.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm APQ8064/IPQ8064 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-apq8064 | ||
| 17 | - qcom,pcie-ipq8064 | ||
| 18 | - qcom,pcie-ipq8064-v2 | ||
| 19 | |||
| 20 | reg: | ||
| 21 | maxItems: 4 | ||
| 22 | |||
| 23 | reg-names: | ||
| 24 | items: | ||
| 25 | - const: dbi | ||
| 26 | - const: elbi | ||
| 27 | - const: parf | ||
| 28 | - const: config | ||
| 29 | |||
| 30 | clocks: | ||
| 31 | minItems: 3 | ||
| 32 | maxItems: 5 | ||
| 33 | |||
| 34 | clock-names: | ||
| 35 | minItems: 3 | ||
| 36 | items: | ||
| 37 | - const: core # Clocks the pcie hw block | ||
| 38 | - const: iface # Configuration AHB clock | ||
| 39 | - const: phy | ||
| 40 | - const: aux | ||
| 41 | - const: ref | ||
| 42 | |||
| 43 | interrupts: | ||
| 44 | maxItems: 1 | ||
| 45 | |||
| 46 | interrupt-names: | ||
| 47 | items: | ||
| 48 | - const: msi | ||
| 49 | |||
| 50 | resets: | ||
| 51 | minItems: 5 | ||
| 52 | maxItems: 6 | ||
| 53 | |||
| 54 | reset-names: | ||
| 55 | minItems: 5 | ||
| 56 | items: | ||
| 57 | - const: axi | ||
| 58 | - const: ahb | ||
| 59 | - const: por | ||
| 60 | - const: pci | ||
| 61 | - const: phy | ||
| 62 | - const: ext | ||
| 63 | |||
| 64 | vdda-supply: | ||
| 65 | description: A phandle to the core analog power supply | ||
| 66 | |||
| 67 | vdda_phy-supply: | ||
| 68 | description: A phandle to the core analog power supply for PHY | ||
| 69 | |||
| 70 | vdda_refclk-supply: | ||
| 71 | description: A phandle to the core analog power supply for IC which generates reference clock | ||
| 72 | |||
| 73 | required: | ||
| 74 | - resets | ||
| 75 | - reset-names | ||
| 76 | - vdda-supply | ||
| 77 | - vdda_phy-supply | ||
| 78 | - vdda_refclk-supply | ||
| 79 | |||
| 80 | allOf: | ||
| 81 | - $ref: qcom,pcie-common.yaml# | ||
| 82 | - if: | ||
| 83 | properties: | ||
| 84 | compatible: | ||
| 85 | contains: | ||
| 86 | enum: | ||
| 87 | - qcom,pcie-apq8064 | ||
| 88 | then: | ||
| 89 | properties: | ||
| 90 | clocks: | ||
| 91 | maxItems: 3 | ||
| 92 | clock-names: | ||
| 93 | maxItems: 3 | ||
| 94 | resets: | ||
| 95 | maxItems: 5 | ||
| 96 | reset-names: | ||
| 97 | maxItems: 5 | ||
| 98 | else: | ||
| 99 | properties: | ||
| 100 | clocks: | ||
| 101 | minItems: 5 | ||
| 102 | clock-names: | ||
| 103 | minItems: 5 | ||
| 104 | resets: | ||
| 105 | minItems: 6 | ||
| 106 | reset-names: | ||
| 107 | minItems: 6 | ||
| 108 | |||
| 109 | unevaluatedProperties: false | ||
| 110 | |||
| 111 | examples: | ||
| 112 | - | | ||
| 113 | #include <dt-bindings/clock/qcom,gcc-msm8960.h> | ||
| 114 | #include <dt-bindings/gpio/gpio.h> | ||
| 115 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 116 | #include <dt-bindings/reset/qcom,gcc-msm8960.h> | ||
| 117 | |||
| 118 | pcie@1b500000 { | ||
| 119 | compatible = "qcom,pcie-apq8064"; | ||
| 120 | reg = <0x1b500000 0x1000>, | ||
| 121 | <0x1b502000 0x80>, | ||
| 122 | <0x1b600000 0x100>, | ||
| 123 | <0x0ff00000 0x100000>; | ||
| 124 | reg-names = "dbi", "elbi", "parf", "config"; | ||
| 125 | ranges = <0x81000000 0x0 0x00000000 0x0fe00000 0x0 0x00100000>, /* I/O */ | ||
| 126 | <0x82000000 0x0 0x08000000 0x08000000 0x0 0x07e00000>; /* mem */ | ||
| 127 | |||
| 128 | device_type = "pci"; | ||
| 129 | linux,pci-domain = <0>; | ||
| 130 | bus-range = <0x00 0xff>; | ||
| 131 | num-lanes = <1>; | ||
| 132 | #address-cells = <3>; | ||
| 133 | #size-cells = <2>; | ||
| 134 | |||
| 135 | clocks = <&gcc PCIE_A_CLK>, | ||
| 136 | <&gcc PCIE_H_CLK>, | ||
| 137 | <&gcc PCIE_PHY_REF_CLK>; | ||
| 138 | clock-names = "core", "iface", "phy"; | ||
| 139 | |||
| 140 | interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>; | ||
| 141 | interrupt-names = "msi"; | ||
| 142 | #interrupt-cells = <1>; | ||
| 143 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 144 | interrupt-map = <0 0 0 1 &intc GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 145 | <0 0 0 2 &intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 146 | <0 0 0 3 &intc GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 147 | <0 0 0 4 &intc GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 148 | |||
| 149 | resets = <&gcc PCIE_ACLK_RESET>, | ||
| 150 | <&gcc PCIE_HCLK_RESET>, | ||
| 151 | <&gcc PCIE_POR_RESET>, | ||
| 152 | <&gcc PCIE_PCI_RESET>, | ||
| 153 | <&gcc PCIE_PHY_RESET>; | ||
| 154 | reset-names = "axi", "ahb", "por", "pci", "phy"; | ||
| 155 | |||
| 156 | perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>; | ||
| 157 | vdda-supply = <&pm8921_s3>; | ||
| 158 | vdda_phy-supply = <&pm8921_lvs6>; | ||
| 159 | vdda_refclk-supply = <&v3p3_fixed>; | ||
| 160 | |||
| 161 | pcie@0 { | ||
| 162 | device_type = "pci"; | ||
| 163 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 164 | bus-range = <0x01 0xff>; | ||
| 165 | |||
| 166 | #address-cells = <3>; | ||
| 167 | #size-cells = <2>; | ||
| 168 | ranges; | ||
| 169 | }; | ||
| 170 | }; | ||
| @@ -0,0 +1,109 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-apq8084.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm APQ8084 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-apq8084 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | minItems: 4 | ||
| 20 | maxItems: 5 | ||
| 21 | |||
| 22 | reg-names: | ||
| 23 | minItems: 4 | ||
| 24 | items: | ||
| 25 | - const: parf | ||
| 26 | - const: dbi | ||
| 27 | - const: elbi | ||
| 28 | - const: config | ||
| 29 | - const: mhi | ||
| 30 | |||
| 31 | clocks: | ||
| 32 | maxItems: 4 | ||
| 33 | |||
| 34 | clock-names: | ||
| 35 | items: | ||
| 36 | - const: iface # Configuration AHB clock | ||
| 37 | - const: master_bus # Master AXI clock | ||
| 38 | - const: slave_bus # Slave AXI clock | ||
| 39 | - const: aux | ||
| 40 | |||
| 41 | interrupts: | ||
| 42 | maxItems: 1 | ||
| 43 | |||
| 44 | interrupt-names: | ||
| 45 | items: | ||
| 46 | - const: msi | ||
| 47 | |||
| 48 | resets: | ||
| 49 | maxItems: 1 | ||
| 50 | |||
| 51 | reset-names: | ||
| 52 | items: | ||
| 53 | - const: core | ||
| 54 | |||
| 55 | vdda-supply: | ||
| 56 | description: A phandle to the core analog power supply | ||
| 57 | |||
| 58 | required: | ||
| 59 | - power-domains | ||
| 60 | - resets | ||
| 61 | - reset-names | ||
| 62 | |||
| 63 | allOf: | ||
| 64 | - $ref: qcom,pcie-common.yaml# | ||
| 65 | |||
| 66 | unevaluatedProperties: false | ||
| 67 | |||
| 68 | examples: | ||
| 69 | - | | ||
| 70 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 71 | #include <dt-bindings/gpio/gpio.h> | ||
| 72 | pcie@fc520000 { | ||
| 73 | compatible = "qcom,pcie-apq8084"; | ||
| 74 | reg = <0xfc520000 0x2000>, | ||
| 75 | <0xff000000 0x1000>, | ||
| 76 | <0xff001000 0x1000>, | ||
| 77 | <0xff002000 0x2000>; | ||
| 78 | reg-names = "parf", "dbi", "elbi", "config"; | ||
| 79 | device_type = "pci"; | ||
| 80 | linux,pci-domain = <0>; | ||
| 81 | bus-range = <0x00 0xff>; | ||
| 82 | num-lanes = <1>; | ||
| 83 | #address-cells = <3>; | ||
| 84 | #size-cells = <2>; | ||
| 85 | ranges = <0x81000000 0 0 0xff200000 0 0x00100000>, | ||
| 86 | <0x82000000 0 0x00300000 0xff300000 0 0x00d00000>; | ||
| 87 | interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>; | ||
| 88 | interrupt-names = "msi"; | ||
| 89 | #interrupt-cells = <1>; | ||
| 90 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 91 | interrupt-map = <0 0 0 1 &intc 0 244 IRQ_TYPE_LEVEL_HIGH>, | ||
| 92 | <0 0 0 2 &intc 0 245 IRQ_TYPE_LEVEL_HIGH>, | ||
| 93 | <0 0 0 3 &intc 0 247 IRQ_TYPE_LEVEL_HIGH>, | ||
| 94 | <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; | ||
| 95 | clocks = <&gcc 324>, | ||
| 96 | <&gcc 325>, | ||
| 97 | <&gcc 327>, | ||
| 98 | <&gcc 323>; | ||
| 99 | clock-names = "iface", "master_bus", "slave_bus", "aux"; | ||
| 100 | resets = <&gcc 81>; | ||
| 101 | reset-names = "core"; | ||
| 102 | power-domains = <&gcc 1>; | ||
| 103 | vdda-supply = <&pma8084_l3>; | ||
| 104 | phys = <&pciephy0>; | ||
| 105 | phy-names = "pciephy"; | ||
| 106 | perst-gpios = <&tlmm 70 GPIO_ACTIVE_LOW>; | ||
| 107 | pinctrl-0 = <&pcie0_pins_default>; | ||
| 108 | pinctrl-names = "default"; | ||
| 109 | }; | ||
| @@ -0,0 +1,146 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-ipq4019.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm IPQ4019 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-ipq4019 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | maxItems: 4 | ||
| 20 | |||
| 21 | reg-names: | ||
| 22 | items: | ||
| 23 | - const: dbi | ||
| 24 | - const: elbi | ||
| 25 | - const: parf | ||
| 26 | - const: config | ||
| 27 | |||
| 28 | clocks: | ||
| 29 | maxItems: 3 | ||
| 30 | |||
| 31 | clock-names: | ||
| 32 | items: | ||
| 33 | - const: aux | ||
| 34 | - const: master_bus # Master AXI clock | ||
| 35 | - const: slave_bus # Slave AXI clock | ||
| 36 | |||
| 37 | interrupts: | ||
| 38 | maxItems: 1 | ||
| 39 | |||
| 40 | interrupt-names: | ||
| 41 | items: | ||
| 42 | - const: msi | ||
| 43 | |||
| 44 | resets: | ||
| 45 | maxItems: 12 | ||
| 46 | |||
| 47 | reset-names: | ||
| 48 | items: | ||
| 49 | - const: axi_m # AXI master reset | ||
| 50 | - const: axi_s # AXI slave reset | ||
| 51 | - const: pipe | ||
| 52 | - const: axi_m_vmid | ||
| 53 | - const: axi_s_xpu | ||
| 54 | - const: parf | ||
| 55 | - const: phy | ||
| 56 | - const: axi_m_sticky # AXI master sticky reset | ||
| 57 | - const: pipe_sticky | ||
| 58 | - const: pwr | ||
| 59 | - const: ahb | ||
| 60 | - const: phy_ahb | ||
| 61 | |||
| 62 | required: | ||
| 63 | - resets | ||
| 64 | - reset-names | ||
| 65 | |||
| 66 | allOf: | ||
| 67 | - $ref: qcom,pcie-common.yaml# | ||
| 68 | |||
| 69 | unevaluatedProperties: false | ||
| 70 | |||
| 71 | examples: | ||
| 72 | - | | ||
| 73 | #include <dt-bindings/clock/qcom,gcc-ipq4019.h> | ||
| 74 | #include <dt-bindings/gpio/gpio.h> | ||
| 75 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 76 | |||
| 77 | pcie@40000000 { | ||
| 78 | compatible = "qcom,pcie-ipq4019"; | ||
| 79 | reg = <0x40000000 0xf1d>, | ||
| 80 | <0x40000f20 0xa8>, | ||
| 81 | <0x80000 0x2000>, | ||
| 82 | <0x40100000 0x1000>; | ||
| 83 | reg-names = "dbi", "elbi", "parf", "config"; | ||
| 84 | ranges = <0x81000000 0x0 0x00000000 0x40200000 0x0 0x00100000>, | ||
| 85 | <0x82000000 0x0 0x40300000 0x40300000 0x0 0x00d00000>; | ||
| 86 | |||
| 87 | device_type = "pci"; | ||
| 88 | linux,pci-domain = <0>; | ||
| 89 | bus-range = <0x00 0xff>; | ||
| 90 | num-lanes = <1>; | ||
| 91 | #address-cells = <3>; | ||
| 92 | #size-cells = <2>; | ||
| 93 | |||
| 94 | clocks = <&gcc GCC_PCIE_AHB_CLK>, | ||
| 95 | <&gcc GCC_PCIE_AXI_M_CLK>, | ||
| 96 | <&gcc GCC_PCIE_AXI_S_CLK>; | ||
| 97 | clock-names = "aux", | ||
| 98 | "master_bus", | ||
| 99 | "slave_bus"; | ||
| 100 | |||
| 101 | interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; | ||
| 102 | interrupt-names = "msi"; | ||
| 103 | #interrupt-cells = <1>; | ||
| 104 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 105 | interrupt-map = <0 0 0 1 &intc GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 106 | <0 0 0 2 &intc GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 107 | <0 0 0 3 &intc GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 108 | <0 0 0 4 &intc GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 109 | |||
| 110 | resets = <&gcc PCIE_AXI_M_ARES>, | ||
| 111 | <&gcc PCIE_AXI_S_ARES>, | ||
| 112 | <&gcc PCIE_PIPE_ARES>, | ||
| 113 | <&gcc PCIE_AXI_M_VMIDMT_ARES>, | ||
| 114 | <&gcc PCIE_AXI_S_XPU_ARES>, | ||
| 115 | <&gcc PCIE_PARF_XPU_ARES>, | ||
| 116 | <&gcc PCIE_PHY_ARES>, | ||
| 117 | <&gcc PCIE_AXI_M_STICKY_ARES>, | ||
| 118 | <&gcc PCIE_PIPE_STICKY_ARES>, | ||
| 119 | <&gcc PCIE_PWR_ARES>, | ||
| 120 | <&gcc PCIE_AHB_ARES>, | ||
| 121 | <&gcc PCIE_PHY_AHB_ARES>; | ||
| 122 | reset-names = "axi_m", | ||
| 123 | "axi_s", | ||
| 124 | "pipe", | ||
| 125 | "axi_m_vmid", | ||
| 126 | "axi_s_xpu", | ||
| 127 | "parf", | ||
| 128 | "phy", | ||
| 129 | "axi_m_sticky", | ||
| 130 | "pipe_sticky", | ||
| 131 | "pwr", | ||
| 132 | "ahb", | ||
| 133 | "phy_ahb"; | ||
| 134 | |||
| 135 | perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; | ||
| 136 | |||
| 137 | pcie@0 { | ||
| 138 | device_type = "pci"; | ||
| 139 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 140 | bus-range = <0x01 0xff>; | ||
| 141 | |||
| 142 | #address-cells = <3>; | ||
| 143 | #size-cells = <2>; | ||
| 144 | ranges; | ||
| 145 | }; | ||
| 146 | }; | ||
| @@ -0,0 +1,189 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-ipq5018.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm IPQ5018 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-ipq5018 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | minItems: 5 | ||
| 20 | maxItems: 6 | ||
| 21 | |||
| 22 | reg-names: | ||
| 23 | minItems: 5 | ||
| 24 | items: | ||
| 25 | - const: dbi | ||
| 26 | - const: elbi | ||
| 27 | - const: atu | ||
| 28 | - const: parf | ||
| 29 | - const: config | ||
| 30 | - const: mhi | ||
| 31 | |||
| 32 | clocks: | ||
| 33 | maxItems: 6 | ||
| 34 | |||
| 35 | clock-names: | ||
| 36 | items: | ||
| 37 | - const: iface # PCIe to SysNOC BIU clock | ||
| 38 | - const: axi_m # AXI Master clock | ||
| 39 | - const: axi_s # AXI Slave clock | ||
| 40 | - const: ahb | ||
| 41 | - const: aux | ||
| 42 | - const: axi_bridge | ||
| 43 | |||
| 44 | interrupts: | ||
| 45 | maxItems: 9 | ||
| 46 | |||
| 47 | interrupt-names: | ||
| 48 | items: | ||
| 49 | - const: msi0 | ||
| 50 | - const: msi1 | ||
| 51 | - const: msi2 | ||
| 52 | - const: msi3 | ||
| 53 | - const: msi4 | ||
| 54 | - const: msi5 | ||
| 55 | - const: msi6 | ||
| 56 | - const: msi7 | ||
| 57 | - const: global | ||
| 58 | |||
| 59 | resets: | ||
| 60 | maxItems: 8 | ||
| 61 | |||
| 62 | reset-names: | ||
| 63 | items: | ||
| 64 | - const: pipe | ||
| 65 | - const: sleep | ||
| 66 | - const: sticky # Core sticky reset | ||
| 67 | - const: axi_m # AXI master reset | ||
| 68 | - const: axi_s # AXI slave reset | ||
| 69 | - const: ahb | ||
| 70 | - const: axi_m_sticky # AXI master sticky reset | ||
| 71 | - const: axi_s_sticky # AXI slave sticky reset | ||
| 72 | |||
| 73 | required: | ||
| 74 | - resets | ||
| 75 | - reset-names | ||
| 76 | |||
| 77 | allOf: | ||
| 78 | - $ref: qcom,pcie-common.yaml# | ||
| 79 | |||
| 80 | unevaluatedProperties: false | ||
| 81 | |||
| 82 | examples: | ||
| 83 | - | | ||
| 84 | #include <dt-bindings/clock/qcom,gcc-ipq5018.h> | ||
| 85 | #include <dt-bindings/gpio/gpio.h> | ||
| 86 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 87 | #include <dt-bindings/reset/qcom,gcc-ipq5018.h> | ||
| 88 | |||
| 89 | pcie@a0000000 { | ||
| 90 | compatible = "qcom,pcie-ipq5018"; | ||
| 91 | reg = <0xa0000000 0xf1d>, | ||
| 92 | <0xa0000f20 0xa8>, | ||
| 93 | <0xa0001000 0x1000>, | ||
| 94 | <0x00080000 0x3000>, | ||
| 95 | <0xa0100000 0x1000>, | ||
| 96 | <0x00083000 0x1000>; | ||
| 97 | reg-names = "dbi", | ||
| 98 | "elbi", | ||
| 99 | "atu", | ||
| 100 | "parf", | ||
| 101 | "config", | ||
| 102 | "mhi"; | ||
| 103 | ranges = <0x01000000 0 0x00000000 0xa0200000 0 0x00100000>, | ||
| 104 | <0x02000000 0 0xa0300000 0xa0300000 0 0x10000000>; | ||
| 105 | |||
| 106 | device_type = "pci"; | ||
| 107 | linux,pci-domain = <0>; | ||
| 108 | bus-range = <0x00 0xff>; | ||
| 109 | num-lanes = <2>; | ||
| 110 | #address-cells = <3>; | ||
| 111 | #size-cells = <2>; | ||
| 112 | |||
| 113 | /* The controller supports Gen3, but the connected PHY is Gen2-capable */ | ||
| 114 | max-link-speed = <2>; | ||
| 115 | |||
| 116 | clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>, | ||
| 117 | <&gcc GCC_PCIE0_AXI_M_CLK>, | ||
| 118 | <&gcc GCC_PCIE0_AXI_S_CLK>, | ||
| 119 | <&gcc GCC_PCIE0_AHB_CLK>, | ||
| 120 | <&gcc GCC_PCIE0_AUX_CLK>, | ||
| 121 | <&gcc GCC_PCIE0_AXI_S_BRIDGE_CLK>; | ||
| 122 | clock-names = "iface", | ||
| 123 | "axi_m", | ||
| 124 | "axi_s", | ||
| 125 | "ahb", | ||
| 126 | "aux", | ||
| 127 | "axi_bridge"; | ||
| 128 | |||
| 129 | msi-map = <0x0 &v2m0 0x0 0xff8>; | ||
| 130 | |||
| 131 | interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, | ||
| 132 | <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>, | ||
| 133 | <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>, | ||
| 134 | <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, | ||
| 135 | <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, | ||
| 136 | <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>, | ||
| 137 | <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>, | ||
| 138 | <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, | ||
| 139 | <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; | ||
| 140 | interrupt-names = "msi0", | ||
| 141 | "msi1", | ||
| 142 | "msi2", | ||
| 143 | "msi3", | ||
| 144 | "msi4", | ||
| 145 | "msi5", | ||
| 146 | "msi6", | ||
| 147 | "msi7", | ||
| 148 | "global"; | ||
| 149 | |||
| 150 | #interrupt-cells = <1>; | ||
| 151 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 152 | interrupt-map = <0 0 0 1 &intc 0 GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, | ||
| 153 | <0 0 0 2 &intc 0 GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>, | ||
| 154 | <0 0 0 3 &intc 0 GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>, | ||
| 155 | <0 0 0 4 &intc 0 GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; | ||
| 156 | |||
| 157 | phys = <&pcie0_phy>; | ||
| 158 | phy-names = "pciephy"; | ||
| 159 | |||
| 160 | resets = <&gcc GCC_PCIE0_PIPE_ARES>, | ||
| 161 | <&gcc GCC_PCIE0_SLEEP_ARES>, | ||
| 162 | <&gcc GCC_PCIE0_CORE_STICKY_ARES>, | ||
| 163 | <&gcc GCC_PCIE0_AXI_MASTER_ARES>, | ||
| 164 | <&gcc GCC_PCIE0_AXI_SLAVE_ARES>, | ||
| 165 | <&gcc GCC_PCIE0_AHB_ARES>, | ||
| 166 | <&gcc GCC_PCIE0_AXI_MASTER_STICKY_ARES>, | ||
| 167 | <&gcc GCC_PCIE0_AXI_SLAVE_STICKY_ARES>; | ||
| 168 | reset-names = "pipe", | ||
| 169 | "sleep", | ||
| 170 | "sticky", | ||
| 171 | "axi_m", | ||
| 172 | "axi_s", | ||
| 173 | "ahb", | ||
| 174 | "axi_m_sticky", | ||
| 175 | "axi_s_sticky"; | ||
| 176 | |||
| 177 | perst-gpios = <&tlmm 15 GPIO_ACTIVE_LOW>; | ||
| 178 | wake-gpios = <&tlmm 16 GPIO_ACTIVE_LOW>; | ||
| 179 | |||
| 180 | pcie@0 { | ||
| 181 | device_type = "pci"; | ||
| 182 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 183 | bus-range = <0x01 0xff>; | ||
| 184 | |||
| 185 | #address-cells = <3>; | ||
| 186 | #size-cells = <2>; | ||
| 187 | ranges; | ||
| 188 | }; | ||
| 189 | }; | ||
| @@ -0,0 +1,179 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-ipq6018.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm IPQ6018 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-ipq6018 | ||
| 17 | - qcom,pcie-ipq8074-gen3 | ||
| 18 | |||
| 19 | reg: | ||
| 20 | minItems: 5 | ||
| 21 | maxItems: 6 | ||
| 22 | |||
| 23 | reg-names: | ||
| 24 | minItems: 5 | ||
| 25 | items: | ||
| 26 | - const: dbi | ||
| 27 | - const: elbi | ||
| 28 | - const: atu | ||
| 29 | - const: parf | ||
| 30 | - const: config | ||
| 31 | - const: mhi | ||
| 32 | |||
| 33 | clocks: | ||
| 34 | maxItems: 5 | ||
| 35 | |||
| 36 | clock-names: | ||
| 37 | items: | ||
| 38 | - const: iface # PCIe to SysNOC BIU clock | ||
| 39 | - const: axi_m # AXI Master clock | ||
| 40 | - const: axi_s # AXI Slave clock | ||
| 41 | - const: axi_bridge | ||
| 42 | - const: rchng | ||
| 43 | |||
| 44 | interrupts: | ||
| 45 | maxItems: 9 | ||
| 46 | |||
| 47 | interrupt-names: | ||
| 48 | items: | ||
| 49 | - const: msi0 | ||
| 50 | - const: msi1 | ||
| 51 | - const: msi2 | ||
| 52 | - const: msi3 | ||
| 53 | - const: msi4 | ||
| 54 | - const: msi5 | ||
| 55 | - const: msi6 | ||
| 56 | - const: msi7 | ||
| 57 | - const: global | ||
| 58 | |||
| 59 | resets: | ||
| 60 | maxItems: 8 | ||
| 61 | |||
| 62 | reset-names: | ||
| 63 | items: | ||
| 64 | - const: pipe | ||
| 65 | - const: sleep | ||
| 66 | - const: sticky # Core sticky reset | ||
| 67 | - const: axi_m # AXI master reset | ||
| 68 | - const: axi_s # AXI slave reset | ||
| 69 | - const: ahb | ||
| 70 | - const: axi_m_sticky # AXI master sticky reset | ||
| 71 | - const: axi_s_sticky # AXI slave sticky reset | ||
| 72 | |||
| 73 | required: | ||
| 74 | - resets | ||
| 75 | - reset-names | ||
| 76 | |||
| 77 | allOf: | ||
| 78 | - $ref: qcom,pcie-common.yaml# | ||
| 79 | |||
| 80 | unevaluatedProperties: false | ||
| 81 | |||
| 82 | examples: | ||
| 83 | - | | ||
| 84 | #include <dt-bindings/clock/qcom,gcc-ipq6018.h> | ||
| 85 | #include <dt-bindings/gpio/gpio.h> | ||
| 86 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 87 | #include <dt-bindings/reset/qcom,gcc-ipq6018.h> | ||
| 88 | |||
| 89 | soc { | ||
| 90 | #address-cells = <2>; | ||
| 91 | #size-cells = <2>; | ||
| 92 | |||
| 93 | pcie@20000000 { | ||
| 94 | compatible = "qcom,pcie-ipq6018"; | ||
| 95 | reg = <0x0 0x20000000 0x0 0xf1d>, | ||
| 96 | <0x0 0x20000f20 0x0 0xa8>, | ||
| 97 | <0x0 0x20001000 0x0 0x1000>, | ||
| 98 | <0x0 0x80000 0x0 0x4000>, | ||
| 99 | <0x0 0x20100000 0x0 0x1000>; | ||
| 100 | reg-names = "dbi", "elbi", "atu", "parf", "config"; | ||
| 101 | ranges = <0x81000000 0x0 0x00000000 0x0 0x20200000 0x0 0x10000>, | ||
| 102 | <0x82000000 0x0 0x20220000 0x0 0x20220000 0x0 0xfde0000>; | ||
| 103 | |||
| 104 | device_type = "pci"; | ||
| 105 | linux,pci-domain = <0>; | ||
| 106 | bus-range = <0x00 0xff>; | ||
| 107 | num-lanes = <1>; | ||
| 108 | max-link-speed = <3>; | ||
| 109 | #address-cells = <3>; | ||
| 110 | #size-cells = <2>; | ||
| 111 | |||
| 112 | clocks = <&gcc GCC_SYS_NOC_PCIE0_AXI_CLK>, | ||
| 113 | <&gcc GCC_PCIE0_AXI_M_CLK>, | ||
| 114 | <&gcc GCC_PCIE0_AXI_S_CLK>, | ||
| 115 | <&gcc GCC_PCIE0_AXI_S_BRIDGE_CLK>, | ||
| 116 | <&gcc PCIE0_RCHNG_CLK>; | ||
| 117 | clock-names = "iface", | ||
| 118 | "axi_m", | ||
| 119 | "axi_s", | ||
| 120 | "axi_bridge", | ||
| 121 | "rchng"; | ||
| 122 | |||
| 123 | interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, | ||
| 124 | <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>, | ||
| 125 | <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>, | ||
| 126 | <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, | ||
| 127 | <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>, | ||
| 128 | <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>, | ||
| 129 | <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>, | ||
| 130 | <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, | ||
| 131 | <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; | ||
| 132 | interrupt-names = "msi0", | ||
| 133 | "msi1", | ||
| 134 | "msi2", | ||
| 135 | "msi3", | ||
| 136 | "msi4", | ||
| 137 | "msi5", | ||
| 138 | "msi6", | ||
| 139 | "msi7", | ||
| 140 | "global"; | ||
| 141 | |||
| 142 | #interrupt-cells = <1>; | ||
| 143 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 144 | interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 145 | <0 0 0 2 &intc 0 0 GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 146 | <0 0 0 3 &intc 0 0 GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 147 | <0 0 0 4 &intc 0 0 GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 148 | |||
| 149 | phys = <&pcie_phy>; | ||
| 150 | phy-names = "pciephy"; | ||
| 151 | |||
| 152 | resets = <&gcc GCC_PCIE0_PIPE_ARES>, | ||
| 153 | <&gcc GCC_PCIE0_SLEEP_ARES>, | ||
| 154 | <&gcc GCC_PCIE0_CORE_STICKY_ARES>, | ||
| 155 | <&gcc GCC_PCIE0_AXI_MASTER_ARES>, | ||
| 156 | <&gcc GCC_PCIE0_AXI_SLAVE_ARES>, | ||
| 157 | <&gcc GCC_PCIE0_AHB_ARES>, | ||
| 158 | <&gcc GCC_PCIE0_AXI_MASTER_STICKY_ARES>, | ||
| 159 | <&gcc GCC_PCIE0_AXI_SLAVE_STICKY_ARES>; | ||
| 160 | reset-names = "pipe", | ||
| 161 | "sleep", | ||
| 162 | "sticky", | ||
| 163 | "axi_m", | ||
| 164 | "axi_s", | ||
| 165 | "ahb", | ||
| 166 | "axi_m_sticky", | ||
| 167 | "axi_s_sticky"; | ||
| 168 | |||
| 169 | pcie@0 { | ||
| 170 | device_type = "pci"; | ||
| 171 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 172 | bus-range = <0x01 0xff>; | ||
| 173 | |||
| 174 | #address-cells = <3>; | ||
| 175 | #size-cells = <2>; | ||
| 176 | ranges; | ||
| 177 | }; | ||
| 178 | }; | ||
| 179 | }; | ||
| @@ -0,0 +1,165 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-ipq8074.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm IPQ8074 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-ipq8074 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | maxItems: 4 | ||
| 20 | |||
| 21 | reg-names: | ||
| 22 | items: | ||
| 23 | - const: dbi | ||
| 24 | - const: elbi | ||
| 25 | - const: parf | ||
| 26 | - const: config | ||
| 27 | |||
| 28 | clocks: | ||
| 29 | maxItems: 5 | ||
| 30 | |||
| 31 | clock-names: | ||
| 32 | items: | ||
| 33 | - const: iface # PCIe to SysNOC BIU clock | ||
| 34 | - const: axi_m # AXI Master clock | ||
| 35 | - const: axi_s # AXI Slave clock | ||
| 36 | - const: ahb | ||
| 37 | - const: aux | ||
| 38 | |||
| 39 | interrupts: | ||
| 40 | maxItems: 9 | ||
| 41 | |||
| 42 | interrupt-names: | ||
| 43 | items: | ||
| 44 | - const: msi0 | ||
| 45 | - const: msi1 | ||
| 46 | - const: msi2 | ||
| 47 | - const: msi3 | ||
| 48 | - const: msi4 | ||
| 49 | - const: msi5 | ||
| 50 | - const: msi6 | ||
| 51 | - const: msi7 | ||
| 52 | - const: global | ||
| 53 | |||
| 54 | resets: | ||
| 55 | maxItems: 7 | ||
| 56 | |||
| 57 | reset-names: | ||
| 58 | items: | ||
| 59 | - const: pipe | ||
| 60 | - const: sleep | ||
| 61 | - const: sticky # Core sticky reset | ||
| 62 | - const: axi_m # AXI master reset | ||
| 63 | - const: axi_s # AXI slave reset | ||
| 64 | - const: ahb | ||
| 65 | - const: axi_m_sticky # AXI master sticky reset | ||
| 66 | |||
| 67 | required: | ||
| 68 | - resets | ||
| 69 | - reset-names | ||
| 70 | |||
| 71 | allOf: | ||
| 72 | - $ref: qcom,pcie-common.yaml# | ||
| 73 | |||
| 74 | unevaluatedProperties: false | ||
| 75 | |||
| 76 | examples: | ||
| 77 | - | | ||
| 78 | #include <dt-bindings/clock/qcom,gcc-ipq8074.h> | ||
| 79 | #include <dt-bindings/gpio/gpio.h> | ||
| 80 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 81 | |||
| 82 | pcie@10000000 { | ||
| 83 | compatible = "qcom,pcie-ipq8074"; | ||
| 84 | reg = <0x10000000 0xf1d>, | ||
| 85 | <0x10000f20 0xa8>, | ||
| 86 | <0x00088000 0x2000>, | ||
| 87 | <0x10100000 0x1000>; | ||
| 88 | reg-names = "dbi", "elbi", "parf", "config"; | ||
| 89 | ranges = <0x81000000 0x0 0x00000000 0x10200000 0x0 0x10000>, /* I/O */ | ||
| 90 | <0x82000000 0x0 0x10220000 0x10220000 0x0 0xfde0000>; /* MEM */ | ||
| 91 | |||
| 92 | device_type = "pci"; | ||
| 93 | linux,pci-domain = <1>; | ||
| 94 | bus-range = <0x00 0xff>; | ||
| 95 | num-lanes = <1>; | ||
| 96 | max-link-speed = <2>; | ||
| 97 | #address-cells = <3>; | ||
| 98 | #size-cells = <2>; | ||
| 99 | |||
| 100 | clocks = <&gcc GCC_SYS_NOC_PCIE1_AXI_CLK>, | ||
| 101 | <&gcc GCC_PCIE1_AXI_M_CLK>, | ||
| 102 | <&gcc GCC_PCIE1_AXI_S_CLK>, | ||
| 103 | <&gcc GCC_PCIE1_AHB_CLK>, | ||
| 104 | <&gcc GCC_PCIE1_AUX_CLK>; | ||
| 105 | clock-names = "iface", | ||
| 106 | "axi_m", | ||
| 107 | "axi_s", | ||
| 108 | "ahb", | ||
| 109 | "aux"; | ||
| 110 | |||
| 111 | interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>, | ||
| 112 | <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>, | ||
| 113 | <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>, | ||
| 114 | <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>, | ||
| 115 | <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>, | ||
| 116 | <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>, | ||
| 117 | <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>, | ||
| 118 | <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>, | ||
| 119 | <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; | ||
| 120 | interrupt-names = "msi0", | ||
| 121 | "msi1", | ||
| 122 | "msi2", | ||
| 123 | "msi3", | ||
| 124 | "msi4", | ||
| 125 | "msi5", | ||
| 126 | "msi6", | ||
| 127 | "msi7", | ||
| 128 | "global"; | ||
| 129 | #interrupt-cells = <1>; | ||
| 130 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 131 | interrupt-map = <0 0 0 1 &intc 0 GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 132 | <0 0 0 2 &intc 0 GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 133 | <0 0 0 3 &intc 0 GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 134 | <0 0 0 4 &intc 0 GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 135 | |||
| 136 | phys = <&pcie_qmp1>; | ||
| 137 | phy-names = "pciephy"; | ||
| 138 | |||
| 139 | resets = <&gcc GCC_PCIE1_PIPE_ARES>, | ||
| 140 | <&gcc GCC_PCIE1_SLEEP_ARES>, | ||
| 141 | <&gcc GCC_PCIE1_CORE_STICKY_ARES>, | ||
| 142 | <&gcc GCC_PCIE1_AXI_MASTER_ARES>, | ||
| 143 | <&gcc GCC_PCIE1_AXI_SLAVE_ARES>, | ||
| 144 | <&gcc GCC_PCIE1_AHB_ARES>, | ||
| 145 | <&gcc GCC_PCIE1_AXI_MASTER_STICKY_ARES>; | ||
| 146 | reset-names = "pipe", | ||
| 147 | "sleep", | ||
| 148 | "sticky", | ||
| 149 | "axi_m", | ||
| 150 | "axi_s", | ||
| 151 | "ahb", | ||
| 152 | "axi_m_sticky"; | ||
| 153 | |||
| 154 | perst-gpios = <&tlmm 58 GPIO_ACTIVE_LOW>; | ||
| 155 | |||
| 156 | pcie@0 { | ||
| 157 | device_type = "pci"; | ||
| 158 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 159 | bus-range = <0x01 0xff>; | ||
| 160 | |||
| 161 | #address-cells = <3>; | ||
| 162 | #size-cells = <2>; | ||
| 163 | ranges; | ||
| 164 | }; | ||
| 165 | }; | ||
| @@ -0,0 +1,183 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-ipq9574.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm IPQ9574 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | oneOf: | ||
| 16 | - enum: | ||
| 17 | - qcom,pcie-ipq9574 | ||
| 18 | - items: | ||
| 19 | - enum: | ||
| 20 | - qcom,pcie-ipq5332 | ||
| 21 | - qcom,pcie-ipq5424 | ||
| 22 | - const: qcom,pcie-ipq9574 | ||
| 23 | |||
| 24 | reg: | ||
| 25 | maxItems: 6 | ||
| 26 | |||
| 27 | reg-names: | ||
| 28 | items: | ||
| 29 | - const: dbi | ||
| 30 | - const: elbi | ||
| 31 | - const: atu | ||
| 32 | - const: parf | ||
| 33 | - const: config | ||
| 34 | - const: mhi | ||
| 35 | |||
| 36 | clocks: | ||
| 37 | maxItems: 6 | ||
| 38 | |||
| 39 | clock-names: | ||
| 40 | items: | ||
| 41 | - const: axi_m # AXI Master clock | ||
| 42 | - const: axi_s # AXI Slave clock | ||
| 43 | - const: axi_bridge | ||
| 44 | - const: rchng | ||
| 45 | - const: ahb | ||
| 46 | - const: aux | ||
| 47 | |||
| 48 | interrupts: | ||
| 49 | minItems: 8 | ||
| 50 | maxItems: 9 | ||
| 51 | |||
| 52 | interrupt-names: | ||
| 53 | minItems: 8 | ||
| 54 | items: | ||
| 55 | - const: msi0 | ||
| 56 | - const: msi1 | ||
| 57 | - const: msi2 | ||
| 58 | - const: msi3 | ||
| 59 | - const: msi4 | ||
| 60 | - const: msi5 | ||
| 61 | - const: msi6 | ||
| 62 | - const: msi7 | ||
| 63 | - const: global | ||
| 64 | |||
| 65 | resets: | ||
| 66 | maxItems: 8 | ||
| 67 | |||
| 68 | reset-names: | ||
| 69 | items: | ||
| 70 | - const: pipe | ||
| 71 | - const: sticky # Core sticky reset | ||
| 72 | - const: axi_s_sticky # AXI Slave Sticky reset | ||
| 73 | - const: axi_s # AXI slave reset | ||
| 74 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 75 | - const: axi_m # AXI master reset | ||
| 76 | - const: aux | ||
| 77 | - const: ahb | ||
| 78 | |||
| 79 | required: | ||
| 80 | - resets | ||
| 81 | - reset-names | ||
| 82 | |||
| 83 | allOf: | ||
| 84 | - $ref: qcom,pcie-common.yaml# | ||
| 85 | |||
| 86 | unevaluatedProperties: false | ||
| 87 | |||
| 88 | examples: | ||
| 89 | - | | ||
| 90 | #include <dt-bindings/clock/qcom,ipq9574-gcc.h> | ||
| 91 | #include <dt-bindings/gpio/gpio.h> | ||
| 92 | #include <dt-bindings/interconnect/qcom,ipq9574.h> | ||
| 93 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 94 | #include <dt-bindings/reset/qcom,ipq9574-gcc.h> | ||
| 95 | |||
| 96 | pcie@10000000 { | ||
| 97 | compatible = "qcom,pcie-ipq9574"; | ||
| 98 | reg = <0x10000000 0xf1d>, | ||
| 99 | <0x10000f20 0xa8>, | ||
| 100 | <0x10001000 0x1000>, | ||
| 101 | <0x000f8000 0x4000>, | ||
| 102 | <0x10100000 0x1000>, | ||
| 103 | <0x000fe000 0x1000>; | ||
| 104 | reg-names = "dbi", | ||
| 105 | "elbi", | ||
| 106 | "atu", | ||
| 107 | "parf", | ||
| 108 | "config", | ||
| 109 | "mhi"; | ||
| 110 | ranges = <0x01000000 0x0 0x00000000 0x10200000 0x0 0x100000>, | ||
| 111 | <0x02000000 0x0 0x10300000 0x10300000 0x0 0x7d00000>; | ||
| 112 | |||
| 113 | device_type = "pci"; | ||
| 114 | linux,pci-domain = <1>; | ||
| 115 | bus-range = <0x00 0xff>; | ||
| 116 | num-lanes = <1>; | ||
| 117 | #address-cells = <3>; | ||
| 118 | #size-cells = <2>; | ||
| 119 | |||
| 120 | clocks = <&gcc GCC_PCIE1_AXI_M_CLK>, | ||
| 121 | <&gcc GCC_PCIE1_AXI_S_CLK>, | ||
| 122 | <&gcc GCC_PCIE1_AXI_S_BRIDGE_CLK>, | ||
| 123 | <&gcc GCC_PCIE1_RCHNG_CLK>, | ||
| 124 | <&gcc GCC_PCIE1_AHB_CLK>, | ||
| 125 | <&gcc GCC_PCIE1_AUX_CLK>; | ||
| 126 | clock-names = "axi_m", | ||
| 127 | "axi_s", | ||
| 128 | "axi_bridge", | ||
| 129 | "rchng", | ||
| 130 | "ahb", | ||
| 131 | "aux"; | ||
| 132 | |||
| 133 | interconnects = <&gcc MASTER_ANOC_PCIE1 &gcc SLAVE_ANOC_PCIE1>, | ||
| 134 | <&gcc MASTER_SNOC_PCIE1 &gcc SLAVE_SNOC_PCIE1>; | ||
| 135 | interconnect-names = "pcie-mem", "cpu-pcie"; | ||
| 136 | |||
| 137 | interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>, | ||
| 138 | <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>, | ||
| 139 | <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>, | ||
| 140 | <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>, | ||
| 141 | <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>, | ||
| 142 | <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>, | ||
| 143 | <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>, | ||
| 144 | <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; | ||
| 145 | interrupt-names = "msi0", | ||
| 146 | "msi1", | ||
| 147 | "msi2", | ||
| 148 | "msi3", | ||
| 149 | "msi4", | ||
| 150 | "msi5", | ||
| 151 | "msi6", | ||
| 152 | "msi7"; | ||
| 153 | |||
| 154 | #interrupt-cells = <1>; | ||
| 155 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 156 | interrupt-map = <0 0 0 1 &intc 0 GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>, | ||
| 157 | <0 0 0 2 &intc 0 GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, | ||
| 158 | <0 0 0 3 &intc 0 GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>, | ||
| 159 | <0 0 0 4 &intc 0 GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; | ||
| 160 | |||
| 161 | resets = <&gcc GCC_PCIE1_PIPE_ARES>, | ||
| 162 | <&gcc GCC_PCIE1_CORE_STICKY_ARES>, | ||
| 163 | <&gcc GCC_PCIE1_AXI_S_STICKY_ARES>, | ||
| 164 | <&gcc GCC_PCIE1_AXI_S_ARES>, | ||
| 165 | <&gcc GCC_PCIE1_AXI_M_STICKY_ARES>, | ||
| 166 | <&gcc GCC_PCIE1_AXI_M_ARES>, | ||
| 167 | <&gcc GCC_PCIE1_AUX_ARES>, | ||
| 168 | <&gcc GCC_PCIE1_AHB_ARES>; | ||
| 169 | reset-names = "pipe", | ||
| 170 | "sticky", | ||
| 171 | "axi_s_sticky", | ||
| 172 | "axi_s", | ||
| 173 | "axi_m_sticky", | ||
| 174 | "axi_m", | ||
| 175 | "aux", | ||
| 176 | "ahb"; | ||
| 177 | |||
| 178 | phys = <&pcie1_phy>; | ||
| 179 | phy-names = "pciephy"; | ||
| 180 | |||
| 181 | perst-gpios = <&tlmm 26 GPIO_ACTIVE_LOW>; | ||
| 182 | wake-gpios = <&tlmm 27 GPIO_ACTIVE_LOW>; | ||
| 183 | }; | ||
| @@ -0,0 +1,156 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-msm8996.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm MSM8996 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | oneOf: | ||
| 16 | - enum: | ||
| 17 | - qcom,pcie-msm8996 | ||
| 18 | - items: | ||
| 19 | - const: qcom,pcie-msm8998 | ||
| 20 | - const: qcom,pcie-msm8996 | ||
| 21 | |||
| 22 | reg: | ||
| 23 | minItems: 4 | ||
| 24 | maxItems: 5 | ||
| 25 | |||
| 26 | reg-names: | ||
| 27 | minItems: 4 | ||
| 28 | items: | ||
| 29 | - const: parf | ||
| 30 | - const: dbi | ||
| 31 | - const: elbi | ||
| 32 | - const: config | ||
| 33 | - const: mhi | ||
| 34 | |||
| 35 | clocks: | ||
| 36 | maxItems: 5 | ||
| 37 | |||
| 38 | clock-names: | ||
| 39 | items: | ||
| 40 | - const: pipe # Pipe Clock driving internal logic | ||
| 41 | - const: aux | ||
| 42 | - const: cfg | ||
| 43 | - const: bus_master # Master AXI clock | ||
| 44 | - const: bus_slave # Slave AXI clock | ||
| 45 | |||
| 46 | interrupts: | ||
| 47 | minItems: 8 | ||
| 48 | maxItems: 9 | ||
| 49 | |||
| 50 | interrupt-names: | ||
| 51 | minItems: 8 | ||
| 52 | items: | ||
| 53 | - const: msi0 | ||
| 54 | - const: msi1 | ||
| 55 | - const: msi2 | ||
| 56 | - const: msi3 | ||
| 57 | - const: msi4 | ||
| 58 | - const: msi5 | ||
| 59 | - const: msi6 | ||
| 60 | - const: msi7 | ||
| 61 | - const: global | ||
| 62 | |||
| 63 | vdda-supply: | ||
| 64 | description: A phandle to the core analog power supply | ||
| 65 | |||
| 66 | vddpe-3v3-supply: | ||
| 67 | description: A phandle to the PCIe endpoint power supply | ||
| 68 | |||
| 69 | required: | ||
| 70 | - power-domains | ||
| 71 | |||
| 72 | allOf: | ||
| 73 | - $ref: qcom,pcie-common.yaml# | ||
| 74 | |||
| 75 | unevaluatedProperties: false | ||
| 76 | |||
| 77 | examples: | ||
| 78 | - | | ||
| 79 | #include <dt-bindings/clock/qcom,gcc-msm8996.h> | ||
| 80 | #include <dt-bindings/gpio/gpio.h> | ||
| 81 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 82 | |||
| 83 | pcie@600000 { | ||
| 84 | compatible = "qcom,pcie-msm8996"; | ||
| 85 | reg = <0x00600000 0x2000>, | ||
| 86 | <0x0c000000 0xf1d>, | ||
| 87 | <0x0c000f20 0xa8>, | ||
| 88 | <0x0c100000 0x100000>; | ||
| 89 | reg-names = "parf", "dbi", "elbi", "config"; | ||
| 90 | ranges = <0x01000000 0x0 0x00000000 0x0c200000 0x0 0x100000>, | ||
| 91 | <0x02000000 0x0 0x0c300000 0x0c300000 0x0 0xd00000>; | ||
| 92 | |||
| 93 | device_type = "pci"; | ||
| 94 | bus-range = <0x00 0xff>; | ||
| 95 | num-lanes = <1>; | ||
| 96 | #address-cells = <3>; | ||
| 97 | #size-cells = <2>; | ||
| 98 | linux,pci-domain = <0>; | ||
| 99 | |||
| 100 | clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, | ||
| 101 | <&gcc GCC_PCIE_0_AUX_CLK>, | ||
| 102 | <&gcc GCC_PCIE_0_CFG_AHB_CLK>, | ||
| 103 | <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, | ||
| 104 | <&gcc GCC_PCIE_0_SLV_AXI_CLK>; | ||
| 105 | clock-names = "pipe", | ||
| 106 | "aux", | ||
| 107 | "cfg", | ||
| 108 | "bus_master", | ||
| 109 | "bus_slave"; | ||
| 110 | |||
| 111 | interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>, | ||
| 112 | <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>, | ||
| 113 | <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>, | ||
| 114 | <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>, | ||
| 115 | <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>, | ||
| 116 | <GIC_SPI 410 IRQ_TYPE_LEVEL_HIGH>, | ||
| 117 | <GIC_SPI 411 IRQ_TYPE_LEVEL_HIGH>, | ||
| 118 | <GIC_SPI 412 IRQ_TYPE_LEVEL_HIGH>; | ||
| 119 | interrupt-names = "msi0", | ||
| 120 | "msi1", | ||
| 121 | "msi2", | ||
| 122 | "msi3", | ||
| 123 | "msi4", | ||
| 124 | "msi5", | ||
| 125 | "msi6", | ||
| 126 | "msi7"; | ||
| 127 | #interrupt-cells = <1>; | ||
| 128 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 129 | interrupt-map = <0 0 0 1 &intc GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 130 | <0 0 0 2 &intc GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 131 | <0 0 0 3 &intc GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 132 | <0 0 0 4 &intc GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 133 | |||
| 134 | pinctrl-names = "default", "sleep"; | ||
| 135 | pinctrl-0 = <&pcie0_state_on>; | ||
| 136 | pinctrl-1 = <&pcie0_state_off>; | ||
| 137 | |||
| 138 | phys = <&pciephy_0>; | ||
| 139 | phy-names = "pciephy"; | ||
| 140 | |||
| 141 | power-domains = <&gcc PCIE0_GDSC>; | ||
| 142 | |||
| 143 | perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; | ||
| 144 | vddpe-3v3-supply = <&wlan_en>; | ||
| 145 | vdda-supply = <&vreg_l28a_0p925>; | ||
| 146 | |||
| 147 | pcie@0 { | ||
| 148 | device_type = "pci"; | ||
| 149 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 150 | bus-range = <0x01 0xff>; | ||
| 151 | |||
| 152 | #address-cells = <3>; | ||
| 153 | #size-cells = <2>; | ||
| 154 | ranges; | ||
| 155 | }; | ||
| 156 | }; | ||
| @@ -0,0 +1,131 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-qcs404.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm QCS404 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-qcs404 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | maxItems: 4 | ||
| 20 | |||
| 21 | reg-names: | ||
| 22 | items: | ||
| 23 | - const: dbi | ||
| 24 | - const: elbi | ||
| 25 | - const: parf | ||
| 26 | - const: config | ||
| 27 | |||
| 28 | clocks: | ||
| 29 | maxItems: 4 | ||
| 30 | |||
| 31 | clock-names: | ||
| 32 | items: | ||
| 33 | - const: iface # AHB clock | ||
| 34 | - const: aux | ||
| 35 | - const: master_bus # AXI Master clock | ||
| 36 | - const: slave_bus # AXI Slave clock | ||
| 37 | |||
| 38 | interrupts: | ||
| 39 | maxItems: 1 | ||
| 40 | |||
| 41 | interrupt-names: | ||
| 42 | items: | ||
| 43 | - const: msi | ||
| 44 | |||
| 45 | resets: | ||
| 46 | maxItems: 6 | ||
| 47 | |||
| 48 | reset-names: | ||
| 49 | items: | ||
| 50 | - const: axi_m # AXI Master reset | ||
| 51 | - const: axi_s # AXI Slave reset | ||
| 52 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 53 | - const: pipe_sticky | ||
| 54 | - const: pwr | ||
| 55 | - const: ahb | ||
| 56 | |||
| 57 | required: | ||
| 58 | - resets | ||
| 59 | - reset-names | ||
| 60 | |||
| 61 | allOf: | ||
| 62 | - $ref: qcom,pcie-common.yaml# | ||
| 63 | |||
| 64 | unevaluatedProperties: false | ||
| 65 | |||
| 66 | examples: | ||
| 67 | - | | ||
| 68 | #include <dt-bindings/clock/qcom,gcc-qcs404.h> | ||
| 69 | #include <dt-bindings/gpio/gpio.h> | ||
| 70 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 71 | |||
| 72 | pcie@10000000 { | ||
| 73 | compatible = "qcom,pcie-qcs404"; | ||
| 74 | reg = <0x10000000 0xf1d>, | ||
| 75 | <0x10000f20 0xa8>, | ||
| 76 | <0x07780000 0x2000>, | ||
| 77 | <0x10001000 0x2000>; | ||
| 78 | reg-names = "dbi", "elbi", "parf", "config"; | ||
| 79 | ranges = <0x81000000 0x0 0x00000000 0x10003000 0x0 0x00010000>, /* I/O */ | ||
| 80 | <0x82000000 0x0 0x10013000 0x10013000 0x0 0x007ed000>; /* memory */ | ||
| 81 | |||
| 82 | device_type = "pci"; | ||
| 83 | linux,pci-domain = <0>; | ||
| 84 | bus-range = <0x00 0xff>; | ||
| 85 | num-lanes = <1>; | ||
| 86 | #address-cells = <3>; | ||
| 87 | #size-cells = <2>; | ||
| 88 | |||
| 89 | clocks = <&gcc GCC_PCIE_0_CFG_AHB_CLK>, | ||
| 90 | <&gcc GCC_PCIE_0_AUX_CLK>, | ||
| 91 | <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, | ||
| 92 | <&gcc GCC_PCIE_0_SLV_AXI_CLK>; | ||
| 93 | clock-names = "iface", "aux", "master_bus", "slave_bus"; | ||
| 94 | |||
| 95 | interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>; | ||
| 96 | interrupt-names = "msi"; | ||
| 97 | #interrupt-cells = <1>; | ||
| 98 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 99 | interrupt-map = <0 0 0 1 &intc GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 100 | <0 0 0 2 &intc GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 101 | <0 0 0 3 &intc GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 102 | <0 0 0 4 &intc GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 103 | |||
| 104 | phys = <&pcie_phy>; | ||
| 105 | phy-names = "pciephy"; | ||
| 106 | |||
| 107 | perst-gpios = <&tlmm 43 GPIO_ACTIVE_LOW>; | ||
| 108 | |||
| 109 | resets = <&gcc GCC_PCIE_0_AXI_MASTER_ARES>, | ||
| 110 | <&gcc GCC_PCIE_0_AXI_SLAVE_ARES>, | ||
| 111 | <&gcc GCC_PCIE_0_AXI_MASTER_STICKY_ARES>, | ||
| 112 | <&gcc GCC_PCIE_0_CORE_STICKY_ARES>, | ||
| 113 | <&gcc GCC_PCIE_0_BCR>, | ||
| 114 | <&gcc GCC_PCIE_0_AHB_ARES>; | ||
| 115 | reset-names = "axi_m", | ||
| 116 | "axi_s", | ||
| 117 | "axi_m_sticky", | ||
| 118 | "pipe_sticky", | ||
| 119 | "pwr", | ||
| 120 | "ahb"; | ||
| 121 | |||
| 122 | pcie@0 { | ||
| 123 | device_type = "pci"; | ||
| 124 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 125 | bus-range = <0x01 0xff>; | ||
| 126 | |||
| 127 | #address-cells = <3>; | ||
| 128 | #size-cells = <2>; | ||
| 129 | ranges; | ||
| 130 | }; | ||
| 131 | }; | ||
| @@ -1,168 +0,0 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-sc8180x.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm SC8180x PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | description: | ||
| 14 | Qualcomm SC8180x SoC PCIe root complex controller is based on the Synopsys | ||
| 15 | DesignWare PCIe IP. | ||
| 16 | |||
| 17 | properties: | ||
| 18 | compatible: | ||
| 19 | const: qcom,pcie-sc8180x | ||
| 20 | |||
| 21 | reg: | ||
| 22 | minItems: 5 | ||
| 23 | maxItems: 6 | ||
| 24 | |||
| 25 | reg-names: | ||
| 26 | minItems: 5 | ||
| 27 | items: | ||
| 28 | - const: parf # Qualcomm specific registers | ||
| 29 | - const: dbi # DesignWare PCIe registers | ||
| 30 | - const: elbi # External local bus interface registers | ||
| 31 | - const: atu # ATU address space | ||
| 32 | - const: config # PCIe configuration space | ||
| 33 | - const: mhi # MHI registers | ||
| 34 | |||
| 35 | clocks: | ||
| 36 | minItems: 6 | ||
| 37 | maxItems: 6 | ||
| 38 | |||
| 39 | clock-names: | ||
| 40 | items: | ||
| 41 | - const: pipe # PIPE clock | ||
| 42 | - const: aux # Auxiliary clock | ||
| 43 | - const: cfg # Configuration clock | ||
| 44 | - const: bus_master # Master AXI clock | ||
| 45 | - const: bus_slave # Slave AXI clock | ||
| 46 | - const: slave_q2a # Slave Q2A clock | ||
| 47 | |||
| 48 | interrupts: | ||
| 49 | minItems: 8 | ||
| 50 | maxItems: 9 | ||
| 51 | |||
| 52 | interrupt-names: | ||
| 53 | minItems: 8 | ||
| 54 | items: | ||
| 55 | - const: msi0 | ||
| 56 | - const: msi1 | ||
| 57 | - const: msi2 | ||
| 58 | - const: msi3 | ||
| 59 | - const: msi4 | ||
| 60 | - const: msi5 | ||
| 61 | - const: msi6 | ||
| 62 | - const: msi7 | ||
| 63 | - const: global | ||
| 64 | |||
| 65 | resets: | ||
| 66 | maxItems: 1 | ||
| 67 | |||
| 68 | reset-names: | ||
| 69 | items: | ||
| 70 | - const: pci | ||
| 71 | |||
| 72 | allOf: | ||
| 73 | - $ref: qcom,pcie-common.yaml# | ||
| 74 | |||
| 75 | unevaluatedProperties: false | ||
| 76 | |||
| 77 | examples: | ||
| 78 | - | | ||
| 79 | #include <dt-bindings/clock/qcom,gcc-sc8180x.h> | ||
| 80 | #include <dt-bindings/interconnect/qcom,sc8180x.h> | ||
| 81 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 82 | |||
| 83 | soc { | ||
| 84 | #address-cells = <2>; | ||
| 85 | #size-cells = <2>; | ||
| 86 | |||
| 87 | pcie@1c00000 { | ||
| 88 | compatible = "qcom,pcie-sc8180x"; | ||
| 89 | reg = <0 0x01c00000 0 0x3000>, | ||
| 90 | <0 0x60000000 0 0xf1d>, | ||
| 91 | <0 0x60000f20 0 0xa8>, | ||
| 92 | <0 0x60001000 0 0x1000>, | ||
| 93 | <0 0x60100000 0 0x100000>; | ||
| 94 | reg-names = "parf", | ||
| 95 | "dbi", | ||
| 96 | "elbi", | ||
| 97 | "atu", | ||
| 98 | "config"; | ||
| 99 | ranges = <0x01000000 0x0 0x60200000 0x0 0x60200000 0x0 0x100000>, | ||
| 100 | <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>; | ||
| 101 | |||
| 102 | bus-range = <0x00 0xff>; | ||
| 103 | device_type = "pci"; | ||
| 104 | linux,pci-domain = <0>; | ||
| 105 | num-lanes = <2>; | ||
| 106 | |||
| 107 | #address-cells = <3>; | ||
| 108 | #size-cells = <2>; | ||
| 109 | |||
| 110 | assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; | ||
| 111 | assigned-clock-rates = <19200000>; | ||
| 112 | |||
| 113 | clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, | ||
| 114 | <&gcc GCC_PCIE_0_AUX_CLK>, | ||
| 115 | <&gcc GCC_PCIE_0_CFG_AHB_CLK>, | ||
| 116 | <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, | ||
| 117 | <&gcc GCC_PCIE_0_SLV_AXI_CLK>, | ||
| 118 | <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>; | ||
| 119 | clock-names = "pipe", | ||
| 120 | "aux", | ||
| 121 | "cfg", | ||
| 122 | "bus_master", | ||
| 123 | "bus_slave", | ||
| 124 | "slave_q2a"; | ||
| 125 | |||
| 126 | dma-coherent; | ||
| 127 | |||
| 128 | interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, | ||
| 129 | <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, | ||
| 130 | <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, | ||
| 131 | <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, | ||
| 132 | <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, | ||
| 133 | <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, | ||
| 134 | <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, | ||
| 135 | <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, | ||
| 136 | <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; | ||
| 137 | interrupt-names = "msi0", | ||
| 138 | "msi1", | ||
| 139 | "msi2", | ||
| 140 | "msi3", | ||
| 141 | "msi4", | ||
| 142 | "msi5", | ||
| 143 | "msi6", | ||
| 144 | "msi7", | ||
| 145 | "global"; | ||
| 146 | #interrupt-cells = <1>; | ||
| 147 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 148 | interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 149 | <0 0 0 2 &intc 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 150 | <0 0 0 3 &intc 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 151 | <0 0 0 4 &intc 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 152 | |||
| 153 | interconnects = <&aggre2_noc MASTER_PCIE 0 &mc_virt SLAVE_EBI_CH0 0>, | ||
| 154 | <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>; | ||
| 155 | interconnect-names = "pcie-mem", "cpu-pcie"; | ||
| 156 | |||
| 157 | iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, | ||
| 158 | <0x100 &apps_smmu 0x1d81 0x1>; | ||
| 159 | |||
| 160 | phys = <&pcie0_phy>; | ||
| 161 | phy-names = "pciephy"; | ||
| 162 | |||
| 163 | power-domains = <&gcc PCIE_0_GDSC>; | ||
| 164 | |||
| 165 | resets = <&gcc GCC_PCIE_0_BCR>; | ||
| 166 | reset-names = "pci"; | ||
| 167 | }; | ||
| 168 | }; | ||
| @@ -0,0 +1,190 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-sdm845.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm SDM845 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-sdm845 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | minItems: 4 | ||
| 20 | maxItems: 5 | ||
| 21 | |||
| 22 | reg-names: | ||
| 23 | minItems: 4 | ||
| 24 | items: | ||
| 25 | - const: parf | ||
| 26 | - const: dbi | ||
| 27 | - const: elbi | ||
| 28 | - const: config | ||
| 29 | - const: mhi | ||
| 30 | |||
| 31 | clocks: | ||
| 32 | minItems: 7 | ||
| 33 | maxItems: 8 | ||
| 34 | |||
| 35 | clock-names: | ||
| 36 | minItems: 7 | ||
| 37 | items: | ||
| 38 | - const: pipe | ||
| 39 | - const: aux | ||
| 40 | - const: cfg | ||
| 41 | - const: bus_master # Master AXI clock | ||
| 42 | - const: bus_slave # Slave AXI clock | ||
| 43 | - const: slave_q2a | ||
| 44 | - enum: [ ref, tbu ] | ||
| 45 | - const: tbu | ||
| 46 | |||
| 47 | interrupts: | ||
| 48 | minItems: 8 | ||
| 49 | maxItems: 9 | ||
| 50 | |||
| 51 | interrupt-names: | ||
| 52 | minItems: 8 | ||
| 53 | items: | ||
| 54 | - const: msi0 | ||
| 55 | - const: msi1 | ||
| 56 | - const: msi2 | ||
| 57 | - const: msi3 | ||
| 58 | - const: msi4 | ||
| 59 | - const: msi5 | ||
| 60 | - const: msi6 | ||
| 61 | - const: msi7 | ||
| 62 | - const: global | ||
| 63 | |||
| 64 | resets: | ||
| 65 | maxItems: 1 | ||
| 66 | |||
| 67 | reset-names: | ||
| 68 | items: | ||
| 69 | - const: pci | ||
| 70 | |||
| 71 | required: | ||
| 72 | - power-domains | ||
| 73 | - resets | ||
| 74 | - reset-names | ||
| 75 | |||
| 76 | allOf: | ||
| 77 | - $ref: qcom,pcie-common.yaml# | ||
| 78 | |||
| 79 | unevaluatedProperties: false | ||
| 80 | |||
| 81 | examples: | ||
| 82 | - | | ||
| 83 | #include <dt-bindings/clock/qcom,gcc-sdm845.h> | ||
| 84 | #include <dt-bindings/gpio/gpio.h> | ||
| 85 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 86 | |||
| 87 | soc { | ||
| 88 | #address-cells = <2>; | ||
| 89 | #size-cells = <2>; | ||
| 90 | |||
| 91 | pcie@1c00000 { | ||
| 92 | compatible = "qcom,pcie-sdm845"; | ||
| 93 | reg = <0x0 0x01c00000 0x0 0x2000>, | ||
| 94 | <0x0 0x60000000 0x0 0xf1d>, | ||
| 95 | <0x0 0x60000f20 0x0 0xa8>, | ||
| 96 | <0x0 0x60100000 0x0 0x100000>, | ||
| 97 | <0x0 0x01c07000 0x0 0x1000>; | ||
| 98 | reg-names = "parf", "dbi", "elbi", "config", "mhi"; | ||
| 99 | ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>, | ||
| 100 | <0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0xd00000>; | ||
| 101 | |||
| 102 | device_type = "pci"; | ||
| 103 | linux,pci-domain = <0>; | ||
| 104 | bus-range = <0x00 0xff>; | ||
| 105 | num-lanes = <1>; | ||
| 106 | |||
| 107 | #address-cells = <3>; | ||
| 108 | #size-cells = <2>; | ||
| 109 | |||
| 110 | clocks = <&gcc GCC_PCIE_0_PIPE_CLK>, | ||
| 111 | <&gcc GCC_PCIE_0_AUX_CLK>, | ||
| 112 | <&gcc GCC_PCIE_0_CFG_AHB_CLK>, | ||
| 113 | <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, | ||
| 114 | <&gcc GCC_PCIE_0_SLV_AXI_CLK>, | ||
| 115 | <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, | ||
| 116 | <&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>; | ||
| 117 | clock-names = "pipe", | ||
| 118 | "aux", | ||
| 119 | "cfg", | ||
| 120 | "bus_master", | ||
| 121 | "bus_slave", | ||
| 122 | "slave_q2a", | ||
| 123 | "tbu"; | ||
| 124 | |||
| 125 | interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, | ||
| 126 | <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, | ||
| 127 | <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, | ||
| 128 | <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, | ||
| 129 | <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, | ||
| 130 | <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, | ||
| 131 | <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, | ||
| 132 | <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, | ||
| 133 | <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; | ||
| 134 | interrupt-names = "msi0", | ||
| 135 | "msi1", | ||
| 136 | "msi2", | ||
| 137 | "msi3", | ||
| 138 | "msi4", | ||
| 139 | "msi5", | ||
| 140 | "msi6", | ||
| 141 | "msi7", | ||
| 142 | "global"; | ||
| 143 | #interrupt-cells = <1>; | ||
| 144 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 145 | interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 146 | <0 0 0 2 &intc 0 0 GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 147 | <0 0 0 3 &intc 0 0 GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 148 | <0 0 0 4 &intc 0 0 GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 149 | |||
| 150 | iommu-map = <0x0 &apps_smmu 0x1c10 0x1>, | ||
| 151 | <0x100 &apps_smmu 0x1c11 0x1>, | ||
| 152 | <0x200 &apps_smmu 0x1c12 0x1>, | ||
| 153 | <0x300 &apps_smmu 0x1c13 0x1>, | ||
| 154 | <0x400 &apps_smmu 0x1c14 0x1>, | ||
| 155 | <0x500 &apps_smmu 0x1c15 0x1>, | ||
| 156 | <0x600 &apps_smmu 0x1c16 0x1>, | ||
| 157 | <0x700 &apps_smmu 0x1c17 0x1>, | ||
| 158 | <0x800 &apps_smmu 0x1c18 0x1>, | ||
| 159 | <0x900 &apps_smmu 0x1c19 0x1>, | ||
| 160 | <0xa00 &apps_smmu 0x1c1a 0x1>, | ||
| 161 | <0xb00 &apps_smmu 0x1c1b 0x1>, | ||
| 162 | <0xc00 &apps_smmu 0x1c1c 0x1>, | ||
| 163 | <0xd00 &apps_smmu 0x1c1d 0x1>, | ||
| 164 | <0xe00 &apps_smmu 0x1c1e 0x1>, | ||
| 165 | <0xf00 &apps_smmu 0x1c1f 0x1>; | ||
| 166 | |||
| 167 | power-domains = <&gcc PCIE_0_GDSC>; | ||
| 168 | |||
| 169 | phys = <&pcie0_phy>; | ||
| 170 | phy-names = "pciephy"; | ||
| 171 | |||
| 172 | resets = <&gcc GCC_PCIE_0_BCR>; | ||
| 173 | reset-names = "pci"; | ||
| 174 | |||
| 175 | perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; | ||
| 176 | wake-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>; | ||
| 177 | |||
| 178 | vddpe-3v3-supply = <&pcie0_3p3v_dual>; | ||
| 179 | |||
| 180 | pcie@0 { | ||
| 181 | device_type = "pci"; | ||
| 182 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 183 | bus-range = <0x01 0xff>; | ||
| 184 | |||
| 185 | #address-cells = <3>; | ||
| 186 | #size-cells = <2>; | ||
| 187 | ranges; | ||
| 188 | }; | ||
| 189 | }; | ||
| 190 | }; | ||
| @@ -0,0 +1,172 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie-sdx55.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm SDX55 PCI Express Root Complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <andersson@kernel.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | properties: | ||
| 14 | compatible: | ||
| 15 | enum: | ||
| 16 | - qcom,pcie-sdx55 | ||
| 17 | |||
| 18 | reg: | ||
| 19 | minItems: 5 | ||
| 20 | maxItems: 6 | ||
| 21 | |||
| 22 | reg-names: | ||
| 23 | minItems: 5 | ||
| 24 | items: | ||
| 25 | - const: parf | ||
| 26 | - const: dbi | ||
| 27 | - const: elbi | ||
| 28 | - const: atu | ||
| 29 | - const: config | ||
| 30 | - const: mhi | ||
| 31 | |||
| 32 | clocks: | ||
| 33 | maxItems: 7 | ||
| 34 | |||
| 35 | clock-names: | ||
| 36 | items: | ||
| 37 | - const: pipe | ||
| 38 | - const: aux | ||
| 39 | - const: cfg | ||
| 40 | - const: bus_master # Master AXI clock | ||
| 41 | - const: bus_slave # Slave AXI clock | ||
| 42 | - const: slave_q2a | ||
| 43 | - const: sleep | ||
| 44 | |||
| 45 | interrupts: | ||
| 46 | maxItems: 8 | ||
| 47 | |||
| 48 | interrupt-names: | ||
| 49 | items: | ||
| 50 | - const: msi | ||
| 51 | - const: msi2 | ||
| 52 | - const: msi3 | ||
| 53 | - const: msi4 | ||
| 54 | - const: msi5 | ||
| 55 | - const: msi6 | ||
| 56 | - const: msi7 | ||
| 57 | - const: msi8 | ||
| 58 | |||
| 59 | resets: | ||
| 60 | maxItems: 1 | ||
| 61 | |||
| 62 | reset-names: | ||
| 63 | items: | ||
| 64 | - const: pci | ||
| 65 | |||
| 66 | required: | ||
| 67 | - power-domains | ||
| 68 | - resets | ||
| 69 | - reset-names | ||
| 70 | |||
| 71 | allOf: | ||
| 72 | - $ref: qcom,pcie-common.yaml# | ||
| 73 | |||
| 74 | unevaluatedProperties: false | ||
| 75 | |||
| 76 | examples: | ||
| 77 | - | | ||
| 78 | #include <dt-bindings/clock/qcom,gcc-sdx55.h> | ||
| 79 | #include <dt-bindings/gpio/gpio.h> | ||
| 80 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 81 | |||
| 82 | pcie@1c00000 { | ||
| 83 | compatible = "qcom,pcie-sdx55"; | ||
| 84 | reg = <0x01c00000 0x3000>, | ||
| 85 | <0x40000000 0xf1d>, | ||
| 86 | <0x40000f20 0xc8>, | ||
| 87 | <0x40001000 0x1000>, | ||
| 88 | <0x40100000 0x100000>; | ||
| 89 | reg-names = "parf", | ||
| 90 | "dbi", | ||
| 91 | "elbi", | ||
| 92 | "atu", | ||
| 93 | "config"; | ||
| 94 | ranges = <0x01000000 0x0 0x00000000 0x40200000 0x0 0x100000>, | ||
| 95 | <0x02000000 0x0 0x40300000 0x40300000 0x0 0x3fd00000>; | ||
| 96 | |||
| 97 | device_type = "pci"; | ||
| 98 | linux,pci-domain = <0>; | ||
| 99 | bus-range = <0x00 0xff>; | ||
| 100 | num-lanes = <1>; | ||
| 101 | |||
| 102 | #address-cells = <3>; | ||
| 103 | #size-cells = <2>; | ||
| 104 | |||
| 105 | interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, | ||
| 106 | <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, | ||
| 107 | <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, | ||
| 108 | <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, | ||
| 109 | <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, | ||
| 110 | <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, | ||
| 111 | <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>, | ||
| 112 | <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; | ||
| 113 | interrupt-names = "msi", | ||
| 114 | "msi2", | ||
| 115 | "msi3", | ||
| 116 | "msi4", | ||
| 117 | "msi5", | ||
| 118 | "msi6", | ||
| 119 | "msi7", | ||
| 120 | "msi8"; | ||
| 121 | #interrupt-cells = <1>; | ||
| 122 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 123 | interrupt-map = <0 0 0 1 &intc GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ | ||
| 124 | <0 0 0 2 &intc GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ | ||
| 125 | <0 0 0 3 &intc GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ | ||
| 126 | <0 0 0 4 &intc GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ | ||
| 127 | |||
| 128 | clocks = <&gcc GCC_PCIE_PIPE_CLK>, | ||
| 129 | <&gcc GCC_PCIE_AUX_CLK>, | ||
| 130 | <&gcc GCC_PCIE_CFG_AHB_CLK>, | ||
| 131 | <&gcc GCC_PCIE_MSTR_AXI_CLK>, | ||
| 132 | <&gcc GCC_PCIE_SLV_AXI_CLK>, | ||
| 133 | <&gcc GCC_PCIE_SLV_Q2A_AXI_CLK>, | ||
| 134 | <&gcc GCC_PCIE_SLEEP_CLK>; | ||
| 135 | clock-names = "pipe", | ||
| 136 | "aux", | ||
| 137 | "cfg", | ||
| 138 | "bus_master", | ||
| 139 | "bus_slave", | ||
| 140 | "slave_q2a", | ||
| 141 | "sleep"; | ||
| 142 | |||
| 143 | assigned-clocks = <&gcc GCC_PCIE_AUX_CLK>; | ||
| 144 | assigned-clock-rates = <19200000>; | ||
| 145 | |||
| 146 | iommu-map = <0x0 &apps_smmu 0x0200 0x1>, | ||
| 147 | <0x100 &apps_smmu 0x0201 0x1>, | ||
| 148 | <0x200 &apps_smmu 0x0202 0x1>, | ||
| 149 | <0x300 &apps_smmu 0x0203 0x1>, | ||
| 150 | <0x400 &apps_smmu 0x0204 0x1>; | ||
| 151 | |||
| 152 | power-domains = <&gcc PCIE_GDSC>; | ||
| 153 | |||
| 154 | phys = <&pcie_phy>; | ||
| 155 | phy-names = "pciephy"; | ||
| 156 | |||
| 157 | resets = <&gcc GCC_PCIE_BCR>; | ||
| 158 | reset-names = "pci"; | ||
| 159 | |||
| 160 | perst-gpios = <&tlmm 57 GPIO_ACTIVE_LOW>; | ||
| 161 | wake-gpios = <&tlmm 53 GPIO_ACTIVE_HIGH>; | ||
| 162 | |||
| 163 | pcie@0 { | ||
| 164 | device_type = "pci"; | ||
| 165 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
| 166 | bus-range = <0x01 0xff>; | ||
| 167 | |||
| 168 | #address-cells = <3>; | ||
| 169 | #size-cells = <2>; | ||
| 170 | ranges; | ||
| 171 | }; | ||
| 172 | }; | ||
| @@ -17,6 +17,7 @@ description: · 16 unmodified lines | |||
| 17 | properties: | 17 | properties: |
| 18 | compatible: | 18 | compatible: |
| 19 | oneOf: | 19 | oneOf: |
| 20 | - const: qcom,pcie-sc8180x | ||
| 20 | - const: qcom,pcie-sm8150 | 21 | - const: qcom,pcie-sm8150 |
| 21 | - items: | 22 | - items: |
| 22 | - enum: | 23 | - enum: |
| @@ -16,7 +16,12 @@ description: · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | properties: | 17 | properties: |
| 18 | compatible: | 18 | compatible: |
| 19 | const: qcom,pcie-x1e80100 | 19 | oneOf: |
| 20 | - const: qcom,pcie-x1e80100 | ||
| 21 | - items: | ||
| 22 | - enum: | ||
| 23 | - qcom,glymur-pcie | ||
| 24 | - const: qcom,pcie-x1e80100 | ||
| 20 | 25 | ||
| 21 | reg: | 26 | reg: |
| 22 | minItems: 6 | 27 | minItems: 6 |
| @@ -1,782 +0,0 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,pcie.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm PCI express root complex | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Bjorn Andersson <bjorn.andersson@linaro.org> | ||
| 11 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 12 | |||
| 13 | description: | | ||
| 14 | Qualcomm PCIe root complex controller is based on the Synopsys DesignWare | ||
| 15 | PCIe IP. | ||
| 16 | |||
| 17 | properties: | ||
| 18 | compatible: | ||
| 19 | oneOf: | ||
| 20 | - enum: | ||
| 21 | - qcom,pcie-apq8064 | ||
| 22 | - qcom,pcie-apq8084 | ||
| 23 | - qcom,pcie-ipq4019 | ||
| 24 | - qcom,pcie-ipq5018 | ||
| 25 | - qcom,pcie-ipq6018 | ||
| 26 | - qcom,pcie-ipq8064 | ||
| 27 | - qcom,pcie-ipq8064-v2 | ||
| 28 | - qcom,pcie-ipq8074 | ||
| 29 | - qcom,pcie-ipq8074-gen3 | ||
| 30 | - qcom,pcie-ipq9574 | ||
| 31 | - qcom,pcie-msm8996 | ||
| 32 | - qcom,pcie-qcs404 | ||
| 33 | - qcom,pcie-sdm845 | ||
| 34 | - qcom,pcie-sdx55 | ||
| 35 | - items: | ||
| 36 | - enum: | ||
| 37 | - qcom,pcie-ipq5332 | ||
| 38 | - qcom,pcie-ipq5424 | ||
| 39 | - const: qcom,pcie-ipq9574 | ||
| 40 | - items: | ||
| 41 | - const: qcom,pcie-msm8998 | ||
| 42 | - const: qcom,pcie-msm8996 | ||
| 43 | |||
| 44 | reg: | ||
| 45 | minItems: 4 | ||
| 46 | maxItems: 6 | ||
| 47 | |||
| 48 | reg-names: | ||
| 49 | minItems: 4 | ||
| 50 | maxItems: 6 | ||
| 51 | |||
| 52 | interrupts: | ||
| 53 | minItems: 1 | ||
| 54 | maxItems: 9 | ||
| 55 | |||
| 56 | interrupt-names: | ||
| 57 | minItems: 1 | ||
| 58 | maxItems: 9 | ||
| 59 | |||
| 60 | iommu-map: | ||
| 61 | minItems: 1 | ||
| 62 | maxItems: 16 | ||
| 63 | |||
| 64 | # Common definitions for clocks, clock-names and reset. | ||
| 65 | # Platform constraints are described later. | ||
| 66 | clocks: | ||
| 67 | minItems: 3 | ||
| 68 | maxItems: 13 | ||
| 69 | |||
| 70 | clock-names: | ||
| 71 | minItems: 3 | ||
| 72 | maxItems: 13 | ||
| 73 | |||
| 74 | dma-coherent: true | ||
| 75 | |||
| 76 | interconnects: | ||
| 77 | maxItems: 2 | ||
| 78 | |||
| 79 | interconnect-names: | ||
| 80 | items: | ||
| 81 | - const: pcie-mem | ||
| 82 | - const: cpu-pcie | ||
| 83 | |||
| 84 | resets: | ||
| 85 | minItems: 1 | ||
| 86 | maxItems: 12 | ||
| 87 | |||
| 88 | reset-names: | ||
| 89 | minItems: 1 | ||
| 90 | maxItems: 12 | ||
| 91 | |||
| 92 | vdda-supply: | ||
| 93 | description: A phandle to the core analog power supply | ||
| 94 | |||
| 95 | vdda_phy-supply: | ||
| 96 | description: A phandle to the core analog power supply for PHY | ||
| 97 | |||
| 98 | vdda_refclk-supply: | ||
| 99 | description: A phandle to the core analog power supply for IC which generates reference clock | ||
| 100 | |||
| 101 | vddpe-3v3-supply: | ||
| 102 | description: A phandle to the PCIe endpoint power supply | ||
| 103 | |||
| 104 | phys: | ||
| 105 | maxItems: 1 | ||
| 106 | |||
| 107 | phy-names: | ||
| 108 | items: | ||
| 109 | - const: pciephy | ||
| 110 | |||
| 111 | power-domains: | ||
| 112 | maxItems: 1 | ||
| 113 | |||
| 114 | perst-gpios: | ||
| 115 | description: GPIO controlled connection to PERST# signal | ||
| 116 | maxItems: 1 | ||
| 117 | |||
| 118 | required-opps: | ||
| 119 | maxItems: 1 | ||
| 120 | |||
| 121 | wake-gpios: | ||
| 122 | description: GPIO controlled connection to WAKE# signal | ||
| 123 | maxItems: 1 | ||
| 124 | |||
| 125 | required: | ||
| 126 | - compatible | ||
| 127 | - reg | ||
| 128 | - reg-names | ||
| 129 | - interrupt-map-mask | ||
| 130 | - interrupt-map | ||
| 131 | - clocks | ||
| 132 | - clock-names | ||
| 133 | |||
| 134 | anyOf: | ||
| 135 | - required: | ||
| 136 | - interrupts | ||
| 137 | - interrupt-names | ||
| 138 | - "#interrupt-cells" | ||
| 139 | - required: | ||
| 140 | - msi-map | ||
| 141 | |||
| 142 | allOf: | ||
| 143 | - $ref: /schemas/pci/pci-host-bridge.yaml# | ||
| 144 | - if: | ||
| 145 | properties: | ||
| 146 | compatible: | ||
| 147 | contains: | ||
| 148 | enum: | ||
| 149 | - qcom,pcie-apq8064 | ||
| 150 | - qcom,pcie-ipq4019 | ||
| 151 | - qcom,pcie-ipq8064 | ||
| 152 | - qcom,pcie-ipq8064v2 | ||
| 153 | - qcom,pcie-ipq8074 | ||
| 154 | - qcom,pcie-qcs404 | ||
| 155 | then: | ||
| 156 | properties: | ||
| 157 | reg: | ||
| 158 | minItems: 4 | ||
| 159 | maxItems: 4 | ||
| 160 | reg-names: | ||
| 161 | items: | ||
| 162 | - const: dbi # DesignWare PCIe registers | ||
| 163 | - const: elbi # External local bus interface registers | ||
| 164 | - const: parf # Qualcomm specific registers | ||
| 165 | - const: config # PCIe configuration space | ||
| 166 | |||
| 167 | - if: | ||
| 168 | properties: | ||
| 169 | compatible: | ||
| 170 | contains: | ||
| 171 | enum: | ||
| 172 | - qcom,pcie-ipq5018 | ||
| 173 | - qcom,pcie-ipq6018 | ||
| 174 | - qcom,pcie-ipq8074-gen3 | ||
| 175 | - qcom,pcie-ipq9574 | ||
| 176 | then: | ||
| 177 | properties: | ||
| 178 | reg: | ||
| 179 | minItems: 5 | ||
| 180 | maxItems: 6 | ||
| 181 | reg-names: | ||
| 182 | minItems: 5 | ||
| 183 | items: | ||
| 184 | - const: dbi # DesignWare PCIe registers | ||
| 185 | - const: elbi # External local bus interface registers | ||
| 186 | - const: atu # ATU address space | ||
| 187 | - const: parf # Qualcomm specific registers | ||
| 188 | - const: config # PCIe configuration space | ||
| 189 | - const: mhi # MHI registers | ||
| 190 | |||
| 191 | - if: | ||
| 192 | properties: | ||
| 193 | compatible: | ||
| 194 | contains: | ||
| 195 | enum: | ||
| 196 | - qcom,pcie-apq8084 | ||
| 197 | - qcom,pcie-msm8996 | ||
| 198 | - qcom,pcie-sdm845 | ||
| 199 | then: | ||
| 200 | properties: | ||
| 201 | reg: | ||
| 202 | minItems: 4 | ||
| 203 | maxItems: 5 | ||
| 204 | reg-names: | ||
| 205 | minItems: 4 | ||
| 206 | items: | ||
| 207 | - const: parf # Qualcomm specific registers | ||
| 208 | - const: dbi # DesignWare PCIe registers | ||
| 209 | - const: elbi # External local bus interface registers | ||
| 210 | - const: config # PCIe configuration space | ||
| 211 | - const: mhi # MHI registers | ||
| 212 | |||
| 213 | - if: | ||
| 214 | properties: | ||
| 215 | compatible: | ||
| 216 | contains: | ||
| 217 | enum: | ||
| 218 | - qcom,pcie-sdx55 | ||
| 219 | then: | ||
| 220 | properties: | ||
| 221 | reg: | ||
| 222 | minItems: 5 | ||
| 223 | maxItems: 6 | ||
| 224 | reg-names: | ||
| 225 | minItems: 5 | ||
| 226 | items: | ||
| 227 | - const: parf # Qualcomm specific registers | ||
| 228 | - const: dbi # DesignWare PCIe registers | ||
| 229 | - const: elbi # External local bus interface registers | ||
| 230 | - const: atu # ATU address space | ||
| 231 | - const: config # PCIe configuration space | ||
| 232 | - const: mhi # MHI registers | ||
| 233 | |||
| 234 | - if: | ||
| 235 | properties: | ||
| 236 | compatible: | ||
| 237 | contains: | ||
| 238 | enum: | ||
| 239 | - qcom,pcie-apq8064 | ||
| 240 | - qcom,pcie-ipq8064 | ||
| 241 | - qcom,pcie-ipq8064v2 | ||
| 242 | then: | ||
| 243 | properties: | ||
| 244 | clocks: | ||
| 245 | minItems: 3 | ||
| 246 | maxItems: 5 | ||
| 247 | clock-names: | ||
| 248 | minItems: 3 | ||
| 249 | items: | ||
| 250 | - const: core # Clocks the pcie hw block | ||
| 251 | - const: iface # Configuration AHB clock | ||
| 252 | - const: phy # Clocks the pcie PHY block | ||
| 253 | - const: aux # Clocks the pcie AUX block, not on apq8064 | ||
| 254 | - const: ref # Clocks the pcie ref block, not on apq8064 | ||
| 255 | resets: | ||
| 256 | minItems: 5 | ||
| 257 | maxItems: 6 | ||
| 258 | reset-names: | ||
| 259 | minItems: 5 | ||
| 260 | items: | ||
| 261 | - const: axi # AXI reset | ||
| 262 | - const: ahb # AHB reset | ||
| 263 | - const: por # POR reset | ||
| 264 | - const: pci # PCI reset | ||
| 265 | - const: phy # PHY reset | ||
| 266 | - const: ext # EXT reset, not on apq8064 | ||
| 267 | required: | ||
| 268 | - vdda-supply | ||
| 269 | - vdda_phy-supply | ||
| 270 | - vdda_refclk-supply | ||
| 271 | |||
| 272 | - if: | ||
| 273 | properties: | ||
| 274 | compatible: | ||
| 275 | contains: | ||
| 276 | enum: | ||
| 277 | - qcom,pcie-apq8084 | ||
| 278 | then: | ||
| 279 | properties: | ||
| 280 | clocks: | ||
| 281 | minItems: 4 | ||
| 282 | maxItems: 4 | ||
| 283 | clock-names: | ||
| 284 | items: | ||
| 285 | - const: iface # Configuration AHB clock | ||
| 286 | - const: master_bus # Master AXI clock | ||
| 287 | - const: slave_bus # Slave AXI clock | ||
| 288 | - const: aux # Auxiliary (AUX) clock | ||
| 289 | resets: | ||
| 290 | maxItems: 1 | ||
| 291 | reset-names: | ||
| 292 | items: | ||
| 293 | - const: core # Core reset | ||
| 294 | |||
| 295 | - if: | ||
| 296 | properties: | ||
| 297 | compatible: | ||
| 298 | contains: | ||
| 299 | enum: | ||
| 300 | - qcom,pcie-ipq4019 | ||
| 301 | then: | ||
| 302 | properties: | ||
| 303 | clocks: | ||
| 304 | minItems: 3 | ||
| 305 | maxItems: 3 | ||
| 306 | clock-names: | ||
| 307 | items: | ||
| 308 | - const: aux # Auxiliary (AUX) clock | ||
| 309 | - const: master_bus # Master AXI clock | ||
| 310 | - const: slave_bus # Slave AXI clock | ||
| 311 | resets: | ||
| 312 | minItems: 12 | ||
| 313 | maxItems: 12 | ||
| 314 | reset-names: | ||
| 315 | items: | ||
| 316 | - const: axi_m # AXI master reset | ||
| 317 | - const: axi_s # AXI slave reset | ||
| 318 | - const: pipe # PIPE reset | ||
| 319 | - const: axi_m_vmid # VMID reset | ||
| 320 | - const: axi_s_xpu # XPU reset | ||
| 321 | - const: parf # PARF reset | ||
| 322 | - const: phy # PHY reset | ||
| 323 | - const: axi_m_sticky # AXI sticky reset | ||
| 324 | - const: pipe_sticky # PIPE sticky reset | ||
| 325 | - const: pwr # PWR reset | ||
| 326 | - const: ahb # AHB reset | ||
| 327 | - const: phy_ahb # PHY AHB reset | ||
| 328 | |||
| 329 | - if: | ||
| 330 | properties: | ||
| 331 | compatible: | ||
| 332 | contains: | ||
| 333 | enum: | ||
| 334 | - qcom,pcie-ipq5018 | ||
| 335 | then: | ||
| 336 | properties: | ||
| 337 | clocks: | ||
| 338 | minItems: 6 | ||
| 339 | maxItems: 6 | ||
| 340 | clock-names: | ||
| 341 | items: | ||
| 342 | - const: iface # PCIe to SysNOC BIU clock | ||
| 343 | - const: axi_m # AXI Master clock | ||
| 344 | - const: axi_s # AXI Slave clock | ||
| 345 | - const: ahb # AHB clock | ||
| 346 | - const: aux # Auxiliary clock | ||
| 347 | - const: axi_bridge # AXI bridge clock | ||
| 348 | resets: | ||
| 349 | minItems: 8 | ||
| 350 | maxItems: 8 | ||
| 351 | reset-names: | ||
| 352 | items: | ||
| 353 | - const: pipe # PIPE reset | ||
| 354 | - const: sleep # Sleep reset | ||
| 355 | - const: sticky # Core sticky reset | ||
| 356 | - const: axi_m # AXI master reset | ||
| 357 | - const: axi_s # AXI slave reset | ||
| 358 | - const: ahb # AHB reset | ||
| 359 | - const: axi_m_sticky # AXI master sticky reset | ||
| 360 | - const: axi_s_sticky # AXI slave sticky reset | ||
| 361 | interrupts: | ||
| 362 | minItems: 9 | ||
| 363 | maxItems: 9 | ||
| 364 | interrupt-names: | ||
| 365 | items: | ||
| 366 | - const: msi0 | ||
| 367 | - const: msi1 | ||
| 368 | - const: msi2 | ||
| 369 | - const: msi3 | ||
| 370 | - const: msi4 | ||
| 371 | - const: msi5 | ||
| 372 | - const: msi6 | ||
| 373 | - const: msi7 | ||
| 374 | - const: global | ||
| 375 | |||
| 376 | - if: | ||
| 377 | properties: | ||
| 378 | compatible: | ||
| 379 | contains: | ||
| 380 | enum: | ||
| 381 | - qcom,pcie-msm8996 | ||
| 382 | then: | ||
| 383 | properties: | ||
| 384 | clocks: | ||
| 385 | minItems: 5 | ||
| 386 | maxItems: 5 | ||
| 387 | clock-names: | ||
| 388 | items: | ||
| 389 | - const: pipe # Pipe Clock driving internal logic | ||
| 390 | - const: aux # Auxiliary (AUX) clock | ||
| 391 | - const: cfg # Configuration clock | ||
| 392 | - const: bus_master # Master AXI clock | ||
| 393 | - const: bus_slave # Slave AXI clock | ||
| 394 | resets: false | ||
| 395 | reset-names: false | ||
| 396 | |||
| 397 | - if: | ||
| 398 | properties: | ||
| 399 | compatible: | ||
| 400 | contains: | ||
| 401 | enum: | ||
| 402 | - qcom,pcie-ipq8074 | ||
| 403 | then: | ||
| 404 | properties: | ||
| 405 | clocks: | ||
| 406 | minItems: 5 | ||
| 407 | maxItems: 5 | ||
| 408 | clock-names: | ||
| 409 | items: | ||
| 410 | - const: iface # PCIe to SysNOC BIU clock | ||
| 411 | - const: axi_m # AXI Master clock | ||
| 412 | - const: axi_s # AXI Slave clock | ||
| 413 | - const: ahb # AHB clock | ||
| 414 | - const: aux # Auxiliary clock | ||
| 415 | resets: | ||
| 416 | minItems: 7 | ||
| 417 | maxItems: 7 | ||
| 418 | reset-names: | ||
| 419 | items: | ||
| 420 | - const: pipe # PIPE reset | ||
| 421 | - const: sleep # Sleep reset | ||
| 422 | - const: sticky # Core Sticky reset | ||
| 423 | - const: axi_m # AXI Master reset | ||
| 424 | - const: axi_s # AXI Slave reset | ||
| 425 | - const: ahb # AHB Reset | ||
| 426 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 427 | |||
| 428 | - if: | ||
| 429 | properties: | ||
| 430 | compatible: | ||
| 431 | contains: | ||
| 432 | enum: | ||
| 433 | - qcom,pcie-ipq6018 | ||
| 434 | - qcom,pcie-ipq8074-gen3 | ||
| 435 | then: | ||
| 436 | properties: | ||
| 437 | clocks: | ||
| 438 | minItems: 5 | ||
| 439 | maxItems: 5 | ||
| 440 | clock-names: | ||
| 441 | items: | ||
| 442 | - const: iface # PCIe to SysNOC BIU clock | ||
| 443 | - const: axi_m # AXI Master clock | ||
| 444 | - const: axi_s # AXI Slave clock | ||
| 445 | - const: axi_bridge # AXI bridge clock | ||
| 446 | - const: rchng | ||
| 447 | resets: | ||
| 448 | minItems: 8 | ||
| 449 | maxItems: 8 | ||
| 450 | reset-names: | ||
| 451 | items: | ||
| 452 | - const: pipe # PIPE reset | ||
| 453 | - const: sleep # Sleep reset | ||
| 454 | - const: sticky # Core Sticky reset | ||
| 455 | - const: axi_m # AXI Master reset | ||
| 456 | - const: axi_s # AXI Slave reset | ||
| 457 | - const: ahb # AHB Reset | ||
| 458 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 459 | - const: axi_s_sticky # AXI Slave Sticky reset | ||
| 460 | |||
| 461 | - if: | ||
| 462 | properties: | ||
| 463 | compatible: | ||
| 464 | contains: | ||
| 465 | enum: | ||
| 466 | - qcom,pcie-ipq9574 | ||
| 467 | then: | ||
| 468 | properties: | ||
| 469 | clocks: | ||
| 470 | minItems: 6 | ||
| 471 | maxItems: 6 | ||
| 472 | clock-names: | ||
| 473 | items: | ||
| 474 | - const: axi_m # AXI Master clock | ||
| 475 | - const: axi_s # AXI Slave clock | ||
| 476 | - const: axi_bridge | ||
| 477 | - const: rchng | ||
| 478 | - const: ahb | ||
| 479 | - const: aux | ||
| 480 | |||
| 481 | resets: | ||
| 482 | minItems: 8 | ||
| 483 | maxItems: 8 | ||
| 484 | reset-names: | ||
| 485 | items: | ||
| 486 | - const: pipe # PIPE reset | ||
| 487 | - const: sticky # Core Sticky reset | ||
| 488 | - const: axi_s_sticky # AXI Slave Sticky reset | ||
| 489 | - const: axi_s # AXI Slave reset | ||
| 490 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 491 | - const: axi_m # AXI Master reset | ||
| 492 | - const: aux # AUX Reset | ||
| 493 | - const: ahb # AHB Reset | ||
| 494 | |||
| 495 | interrupts: | ||
| 496 | minItems: 8 | ||
| 497 | interrupt-names: | ||
| 498 | minItems: 8 | ||
| 499 | items: | ||
| 500 | - const: msi0 | ||
| 501 | - const: msi1 | ||
| 502 | - const: msi2 | ||
| 503 | - const: msi3 | ||
| 504 | - const: msi4 | ||
| 505 | - const: msi5 | ||
| 506 | - const: msi6 | ||
| 507 | - const: msi7 | ||
| 508 | - const: global | ||
| 509 | |||
| 510 | - if: | ||
| 511 | properties: | ||
| 512 | compatible: | ||
| 513 | contains: | ||
| 514 | enum: | ||
| 515 | - qcom,pcie-qcs404 | ||
| 516 | then: | ||
| 517 | properties: | ||
| 518 | clocks: | ||
| 519 | minItems: 4 | ||
| 520 | maxItems: 4 | ||
| 521 | clock-names: | ||
| 522 | items: | ||
| 523 | - const: iface # AHB clock | ||
| 524 | - const: aux # Auxiliary clock | ||
| 525 | - const: master_bus # AXI Master clock | ||
| 526 | - const: slave_bus # AXI Slave clock | ||
| 527 | resets: | ||
| 528 | minItems: 6 | ||
| 529 | maxItems: 6 | ||
| 530 | reset-names: | ||
| 531 | items: | ||
| 532 | - const: axi_m # AXI Master reset | ||
| 533 | - const: axi_s # AXI Slave reset | ||
| 534 | - const: axi_m_sticky # AXI Master Sticky reset | ||
| 535 | - const: pipe_sticky # PIPE sticky reset | ||
| 536 | - const: pwr # PWR reset | ||
| 537 | - const: ahb # AHB reset | ||
| 538 | |||
| 539 | - if: | ||
| 540 | properties: | ||
| 541 | compatible: | ||
| 542 | contains: | ||
| 543 | enum: | ||
| 544 | - qcom,pcie-sdm845 | ||
| 545 | then: | ||
| 546 | oneOf: | ||
| 547 | # Unfortunately the "optional" ref clock is used in the middle of the list | ||
| 548 | - properties: | ||
| 549 | clocks: | ||
| 550 | minItems: 8 | ||
| 551 | maxItems: 8 | ||
| 552 | clock-names: | ||
| 553 | items: | ||
| 554 | - const: pipe # PIPE clock | ||
| 555 | - const: aux # Auxiliary clock | ||
| 556 | - const: cfg # Configuration clock | ||
| 557 | - const: bus_master # Master AXI clock | ||
| 558 | - const: bus_slave # Slave AXI clock | ||
| 559 | - const: slave_q2a # Slave Q2A clock | ||
| 560 | - const: ref # REFERENCE clock | ||
| 561 | - const: tbu # PCIe TBU clock | ||
| 562 | - properties: | ||
| 563 | clocks: | ||
| 564 | minItems: 7 | ||
| 565 | maxItems: 7 | ||
| 566 | clock-names: | ||
| 567 | items: | ||
| 568 | - const: pipe # PIPE clock | ||
| 569 | - const: aux # Auxiliary clock | ||
| 570 | - const: cfg # Configuration clock | ||
| 571 | - const: bus_master # Master AXI clock | ||
| 572 | - const: bus_slave # Slave AXI clock | ||
| 573 | - const: slave_q2a # Slave Q2A clock | ||
| 574 | - const: tbu # PCIe TBU clock | ||
| 575 | properties: | ||
| 576 | resets: | ||
| 577 | maxItems: 1 | ||
| 578 | reset-names: | ||
| 579 | items: | ||
| 580 | - const: pci # PCIe core reset | ||
| 581 | |||
| 582 | - if: | ||
| 583 | properties: | ||
| 584 | compatible: | ||
| 585 | contains: | ||
| 586 | enum: | ||
| 587 | - qcom,pcie-sdx55 | ||
| 588 | then: | ||
| 589 | properties: | ||
| 590 | clocks: | ||
| 591 | minItems: 7 | ||
| 592 | maxItems: 7 | ||
| 593 | clock-names: | ||
| 594 | items: | ||
| 595 | - const: pipe # PIPE clock | ||
| 596 | - const: aux # Auxiliary clock | ||
| 597 | - const: cfg # Configuration clock | ||
| 598 | - const: bus_master # Master AXI clock | ||
| 599 | - const: bus_slave # Slave AXI clock | ||
| 600 | - const: slave_q2a # Slave Q2A clock | ||
| 601 | - const: sleep # PCIe Sleep clock | ||
| 602 | resets: | ||
| 603 | maxItems: 1 | ||
| 604 | reset-names: | ||
| 605 | items: | ||
| 606 | - const: pci # PCIe core reset | ||
| 607 | |||
| 608 | - if: | ||
| 609 | not: | ||
| 610 | properties: | ||
| 611 | compatible: | ||
| 612 | contains: | ||
| 613 | enum: | ||
| 614 | - qcom,pcie-apq8064 | ||
| 615 | - qcom,pcie-ipq4019 | ||
| 616 | - qcom,pcie-ipq5018 | ||
| 617 | - qcom,pcie-ipq8064 | ||
| 618 | - qcom,pcie-ipq8064v2 | ||
| 619 | - qcom,pcie-ipq8074 | ||
| 620 | - qcom,pcie-ipq8074-gen3 | ||
| 621 | - qcom,pcie-ipq9574 | ||
| 622 | - qcom,pcie-qcs404 | ||
| 623 | then: | ||
| 624 | required: | ||
| 625 | - power-domains | ||
| 626 | |||
| 627 | - if: | ||
| 628 | not: | ||
| 629 | properties: | ||
| 630 | compatible: | ||
| 631 | contains: | ||
| 632 | enum: | ||
| 633 | - qcom,pcie-msm8996 | ||
| 634 | then: | ||
| 635 | required: | ||
| 636 | - resets | ||
| 637 | - reset-names | ||
| 638 | |||
| 639 | - if: | ||
| 640 | properties: | ||
| 641 | compatible: | ||
| 642 | contains: | ||
| 643 | enum: | ||
| 644 | - qcom,pcie-ipq6018 | ||
| 645 | - qcom,pcie-ipq8074 | ||
| 646 | - qcom,pcie-ipq8074-gen3 | ||
| 647 | - qcom,pcie-msm8996 | ||
| 648 | - qcom,pcie-msm8998 | ||
| 649 | - qcom,pcie-sdm845 | ||
| 650 | then: | ||
| 651 | oneOf: | ||
| 652 | - properties: | ||
| 653 | interrupts: | ||
| 654 | maxItems: 1 | ||
| 655 | interrupt-names: | ||
| 656 | items: | ||
| 657 | - const: msi | ||
| 658 | - properties: | ||
| 659 | interrupts: | ||
| 660 | minItems: 8 | ||
| 661 | maxItems: 9 | ||
| 662 | interrupt-names: | ||
| 663 | minItems: 8 | ||
| 664 | items: | ||
| 665 | - const: msi0 | ||
| 666 | - const: msi1 | ||
| 667 | - const: msi2 | ||
| 668 | - const: msi3 | ||
| 669 | - const: msi4 | ||
| 670 | - const: msi5 | ||
| 671 | - const: msi6 | ||
| 672 | - const: msi7 | ||
| 673 | - const: global | ||
| 674 | |||
| 675 | - if: | ||
| 676 | properties: | ||
| 677 | compatible: | ||
| 678 | contains: | ||
| 679 | enum: | ||
| 680 | - qcom,pcie-apq8064 | ||
| 681 | - qcom,pcie-apq8084 | ||
| 682 | - qcom,pcie-ipq4019 | ||
| 683 | - qcom,pcie-ipq8064 | ||
| 684 | - qcom,pcie-ipq8064-v2 | ||
| 685 | - qcom,pcie-qcs404 | ||
| 686 | then: | ||
| 687 | properties: | ||
| 688 | interrupts: | ||
| 689 | maxItems: 1 | ||
| 690 | interrupt-names: | ||
| 691 | items: | ||
| 692 | - const: msi | ||
| 693 | |||
| 694 | unevaluatedProperties: false | ||
| 695 | |||
| 696 | examples: | ||
| 697 | - | | ||
| 698 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 699 | pcie@1b500000 { | ||
| 700 | compatible = "qcom,pcie-ipq8064"; | ||
| 701 | reg = <0x1b500000 0x1000>, | ||
| 702 | <0x1b502000 0x80>, | ||
| 703 | <0x1b600000 0x100>, | ||
| 704 | <0x0ff00000 0x100000>; | ||
| 705 | reg-names = "dbi", "elbi", "parf", "config"; | ||
| 706 | device_type = "pci"; | ||
| 707 | linux,pci-domain = <0>; | ||
| 708 | bus-range = <0x00 0xff>; | ||
| 709 | num-lanes = <1>; | ||
| 710 | #address-cells = <3>; | ||
| 711 | #size-cells = <2>; | ||
| 712 | ranges = <0x81000000 0 0 0x0fe00000 0 0x00100000>, | ||
| 713 | <0x82000000 0 0 0x08000000 0 0x07e00000>; | ||
| 714 | interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>; | ||
| 715 | interrupt-names = "msi"; | ||
| 716 | #interrupt-cells = <1>; | ||
| 717 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 718 | interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, | ||
| 719 | <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, | ||
| 720 | <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, | ||
| 721 | <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; | ||
| 722 | clocks = <&gcc 41>, | ||
| 723 | <&gcc 43>, | ||
| 724 | <&gcc 44>, | ||
| 725 | <&gcc 42>, | ||
| 726 | <&gcc 248>; | ||
| 727 | clock-names = "core", "iface", "phy", "aux", "ref"; | ||
| 728 | resets = <&gcc 27>, | ||
| 729 | <&gcc 26>, | ||
| 730 | <&gcc 25>, | ||
| 731 | <&gcc 24>, | ||
| 732 | <&gcc 23>, | ||
| 733 | <&gcc 22>; | ||
| 734 | reset-names = "axi", "ahb", "por", "pci", "phy", "ext"; | ||
| 735 | pinctrl-0 = <&pcie_pins_default>; | ||
| 736 | pinctrl-names = "default"; | ||
| 737 | vdda-supply = <&pm8921_s3>; | ||
| 738 | vdda_phy-supply = <&pm8921_lvs6>; | ||
| 739 | vdda_refclk-supply = <&ext_3p3v>; | ||
| 740 | }; | ||
| 741 | - | | ||
| 742 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 743 | #include <dt-bindings/gpio/gpio.h> | ||
| 744 | pcie@fc520000 { | ||
| 745 | compatible = "qcom,pcie-apq8084"; | ||
| 746 | reg = <0xfc520000 0x2000>, | ||
| 747 | <0xff000000 0x1000>, | ||
| 748 | <0xff001000 0x1000>, | ||
| 749 | <0xff002000 0x2000>; | ||
| 750 | reg-names = "parf", "dbi", "elbi", "config"; | ||
| 751 | device_type = "pci"; | ||
| 752 | linux,pci-domain = <0>; | ||
| 753 | bus-range = <0x00 0xff>; | ||
| 754 | num-lanes = <1>; | ||
| 755 | #address-cells = <3>; | ||
| 756 | #size-cells = <2>; | ||
| 757 | ranges = <0x81000000 0 0 0xff200000 0 0x00100000>, | ||
| 758 | <0x82000000 0 0x00300000 0xff300000 0 0x00d00000>; | ||
| 759 | interrupts = <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>; | ||
| 760 | interrupt-names = "msi"; | ||
| 761 | #interrupt-cells = <1>; | ||
| 762 | interrupt-map-mask = <0 0 0 0x7>; | ||
| 763 | interrupt-map = <0 0 0 1 &intc 0 244 IRQ_TYPE_LEVEL_HIGH>, | ||
| 764 | <0 0 0 2 &intc 0 245 IRQ_TYPE_LEVEL_HIGH>, | ||
| 765 | <0 0 0 3 &intc 0 247 IRQ_TYPE_LEVEL_HIGH>, | ||
| 766 | <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; | ||
| 767 | clocks = <&gcc 324>, | ||
| 768 | <&gcc 325>, | ||
| 769 | <&gcc 327>, | ||
| 770 | <&gcc 323>; | ||
| 771 | clock-names = "iface", "master_bus", "slave_bus", "aux"; | ||
| 772 | resets = <&gcc 81>; | ||
| 773 | reset-names = "core"; | ||
| 774 | power-domains = <&gcc 1>; | ||
| 775 | vdda-supply = <&pma8084_l3>; | ||
| 776 | phys = <&pciephy0>; | ||
| 777 | phy-names = "pciephy"; | ||
| 778 | perst-gpios = <&tlmm 70 GPIO_ACTIVE_LOW>; | ||
| 779 | pinctrl-0 = <&pcie0_pins_default>; | ||
| 780 | pinctrl-names = "default"; | ||
| 781 | }; | ||
| 782 | ... | ||
| @@ -0,0 +1,110 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/pci/qcom,sa8255p-pcie-ep.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Qualcomm firmware managed PCIe Endpoint Controller | ||
| 8 | |||
| 9 | description: | ||
| 10 | Qualcomm SA8255p SoC PCIe endpoint controller is based on the Synopsys | ||
| 11 | DesignWare PCIe IP which is managed by firmware. | ||
| 12 | |||
| 13 | maintainers: | ||
| 14 | - Manivannan Sadhasivam <mani@kernel.org> | ||
| 15 | |||
| 16 | properties: | ||
| 17 | compatible: | ||
| 18 | const: qcom,sa8255p-pcie-ep | ||
| 19 | |||
| 20 | reg: | ||
| 21 | items: | ||
| 22 | - description: Qualcomm-specific PARF configuration registers | ||
| 23 | - description: DesignWare PCIe registers | ||
| 24 | - description: External local bus interface registers | ||
| 25 | - description: Address Translation Unit (ATU) registers | ||
| 26 | - description: Memory region used to map remote RC address space | ||
| 27 | - description: BAR memory region | ||
| 28 | - description: DMA register space | ||
| 29 | |||
| 30 | reg-names: | ||
| 31 | items: | ||
| 32 | - const: parf | ||
| 33 | - const: dbi | ||
| 34 | - const: elbi | ||
| 35 | - const: atu | ||
| 36 | - const: addr_space | ||
| 37 | - const: mmio | ||
| 38 | - const: dma | ||
| 39 | |||
| 40 | interrupts: | ||
| 41 | items: | ||
| 42 | - description: PCIe Global interrupt | ||
| 43 | - description: PCIe Doorbell interrupt | ||
| 44 | - description: DMA interrupt | ||
| 45 | |||
| 46 | interrupt-names: | ||
| 47 | items: | ||
| 48 | - const: global | ||
| 49 | - const: doorbell | ||
| 50 | - const: dma | ||
| 51 | |||
| 52 | iommus: | ||
| 53 | maxItems: 1 | ||
| 54 | |||
| 55 | reset-gpios: | ||
| 56 | description: GPIO used as PERST# input signal | ||
| 57 | maxItems: 1 | ||
| 58 | |||
| 59 | wake-gpios: | ||
| 60 | description: GPIO used as WAKE# output signal | ||
| 61 | maxItems: 1 | ||
| 62 | |||
| 63 | power-domains: | ||
| 64 | maxItems: 1 | ||
| 65 | |||
| 66 | dma-coherent: true | ||
| 67 | |||
| 68 | num-lanes: | ||
| 69 | default: 2 | ||
| 70 | |||
| 71 | required: | ||
| 72 | - compatible | ||
| 73 | - reg | ||
| 74 | - reg-names | ||
| 75 | - interrupts | ||
| 76 | - interrupt-names | ||
| 77 | - reset-gpios | ||
| 78 | - power-domains | ||
| 79 | |||
| 80 | additionalProperties: false | ||
| 81 | |||
| 82 | examples: | ||
| 83 | - | | ||
| 84 | #include <dt-bindings/gpio/gpio.h> | ||
| 85 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 86 | soc { | ||
| 87 | #address-cells = <2>; | ||
| 88 | #size-cells = <2>; | ||
| 89 | pcie1_ep: pcie-ep@1c10000 { | ||
| 90 | compatible = "qcom,sa8255p-pcie-ep"; | ||
| 91 | reg = <0x0 0x01c10000 0x0 0x3000>, | ||
| 92 | <0x0 0x60000000 0x0 0xf20>, | ||
| 93 | <0x0 0x60000f20 0x0 0xa8>, | ||
| 94 | <0x0 0x60001000 0x0 0x4000>, | ||
| 95 | <0x0 0x60200000 0x0 0x100000>, | ||
| 96 | <0x0 0x01c13000 0x0 0x1000>, | ||
| 97 | <0x0 0x60005000 0x0 0x2000>; | ||
| 98 | reg-names = "parf", "dbi", "elbi", "atu", "addr_space", "mmio", "dma"; | ||
| 99 | interrupts = <GIC_SPI 518 IRQ_TYPE_LEVEL_HIGH>, | ||
| 100 | <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, | ||
| 101 | <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>; | ||
| 102 | interrupt-names = "global", "doorbell", "dma"; | ||
| 103 | reset-gpios = <&tlmm 4 GPIO_ACTIVE_LOW>; | ||
| 104 | wake-gpios = <&tlmm 5 GPIO_ACTIVE_LOW>; | ||
| 105 | dma-coherent; | ||
| 106 | iommus = <&pcie_smmu 0x80 0x7f>; | ||
| 107 | power-domains = <&scmi6_pd 1>; | ||
| 108 | num-lanes = <4>; | ||
| 109 | }; | ||
| 110 | }; | ||
| @@ -105,6 +105,12 @@ properties: · 104 unmodified lines | |||
| 105 | define it with this name (for instance pipe, core and aux can | 105 | define it with this name (for instance pipe, core and aux can |
| 106 | be connected to a single source of the periodic signal). | 106 | be connected to a single source of the periodic signal). |
| 107 | const: ref | 107 | const: ref |
| 108 | - description: | ||
| 109 | Some dwc wrappers (like i.MX95 PCIes) have two reference clock | ||
| 110 | inputs, one from an internal PLL, the other from an off-chip crystal | ||
| 111 | oscillator. If present, 'extref' refers to a reference clock from | ||
| 112 | an external oscillator. | ||
| 113 | const: extref | ||
| 108 | - description: | 114 | - description: |
| 109 | Clock for the PHY registers interface. Originally this is | 115 | Clock for the PHY registers interface. Originally this is |
| 110 | a PHY-viewport-based interface, but some platform may have | 116 | a PHY-viewport-based interface, but some platform may have |
| @@ -51,7 +51,7 @@ properties: · 50 unmodified lines | |||
| 51 | phy-names: | 51 | phy-names: |
| 52 | const: pcie-phy | 52 | const: pcie-phy |
| 53 | 53 | ||
| 54 | interrupt-controller: | 54 | legacy-interrupt-controller: |
| 55 | type: object | 55 | type: object |
| 56 | additionalProperties: false | 56 | additionalProperties: false |
| 57 | 57 | ||
| @@ -111,7 +111,7 @@ examples: · 53 unmodified lines | |||
| 111 | <0 0 0 3 &pcie_intc 2>, | 111 | <0 0 0 3 &pcie_intc 2>, |
| 112 | <0 0 0 4 &pcie_intc 3>; | 112 | <0 0 0 4 &pcie_intc 3>; |
| 113 | 113 | ||
| 114 | pcie_intc: interrupt-controller { | 114 | pcie_intc: legacy-interrupt-controller { |
| 115 | #address-cells = <0>; | 115 | #address-cells = <0>; |
| 116 | interrupt-controller; | 116 | interrupt-controller; |
| 117 | #interrupt-cells = <1>; | 117 | #interrupt-cells = <1>; |
| @@ -0,0 +1,74 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | =========================== | ||
| 4 | Subsystem Trace Points: PCI | ||
| 5 | =========================== | ||
| 6 | |||
| 7 | Overview | ||
| 8 | ======== | ||
| 9 | The PCI tracing system provides tracepoints to monitor critical hardware events | ||
| 10 | that can impact system performance and reliability. These events normally show | ||
| 11 | up here: | ||
| 12 | |||
| 13 | /sys/kernel/tracing/events/pci | ||
| 14 | |||
| 15 | Cf. include/trace/events/pci.h for the events definitions. | ||
| 16 | |||
| 17 | Available Tracepoints | ||
| 18 | ===================== | ||
| 19 | |||
| 20 | pci_hp_event | ||
| 21 | ------------ | ||
| 22 | |||
| 23 | Monitors PCI hotplug events including card insertion/removal and link | ||
| 24 | state changes. | ||
| 25 | :: | ||
| 26 | |||
| 27 | pci_hp_event "%s slot:%s, event:%s\n" | ||
| 28 | |||
| 29 | **Event Types**: | ||
| 30 | |||
| 31 | * ``LINK_UP`` - PCIe link established | ||
| 32 | * ``LINK_DOWN`` - PCIe link lost | ||
| 33 | * ``CARD_PRESENT`` - Card detected in slot | ||
| 34 | * ``CARD_NOT_PRESENT`` - Card removed from slot | ||
| 35 | |||
| 36 | **Example Usage**:: | ||
| 37 | |||
| 38 | # Enable the tracepoint | ||
| 39 | echo 1 > /sys/kernel/debug/tracing/events/pci/pci_hp_event/enable | ||
| 40 | |||
| 41 | # Monitor events (the following output is generated when a device is hotplugged) | ||
| 42 | cat /sys/kernel/debug/tracing/trace_pipe | ||
| 43 | irq/51-pciehp-88 [001] ..... 1311.177459: pci_hp_event: 0000:00:02.0 slot:10, event:CARD_PRESENT | ||
| 44 | |||
| 45 | irq/51-pciehp-88 [001] ..... 1311.177566: pci_hp_event: 0000:00:02.0 slot:10, event:LINK_UP | ||
| 46 | |||
| 47 | pcie_link_event | ||
| 48 | --------------- | ||
| 49 | |||
| 50 | Monitors PCIe link speed changes and provides detailed link status information. | ||
| 51 | :: | ||
| 52 | |||
| 53 | pcie_link_event "%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n" | ||
| 54 | |||
| 55 | **Parameters**: | ||
| 56 | |||
| 57 | * ``type`` - PCIe device type (4=Root Port, etc.) | ||
| 58 | * ``reason`` - Reason for link change: | ||
| 59 | |||
| 60 | - ``0`` - Link retrain | ||
| 61 | - ``1`` - Bus enumeration | ||
| 62 | - ``2`` - Bandwidth notification enable | ||
| 63 | - ``3`` - Bandwidth notification IRQ | ||
| 64 | - ``4`` - Hotplug event | ||
| 65 | |||
| 66 | |||
| 67 | **Example Usage**:: | ||
| 68 | |||
| 69 | # Enable the tracepoint | ||
| 70 | echo 1 > /sys/kernel/debug/tracing/events/pci/pcie_link_event/enable | ||
| 71 | |||
| 72 | # Monitor events (the following output is generated when a device is hotplugged) | ||
| 73 | cat /sys/kernel/debug/tracing/trace_pipe | ||
| 74 | irq/51-pciehp-88 [001] ..... 381.545386: pcie_link_event: 0000:00:02.0 type:4, reason:4, cur_bus_speed:20, max_bus_speed:23, width:1, flit_mode:0, status:DLLLA | ||
| @@ -54,6 +54,7 @@ applications. · 53 unmodified lines | |||
| 54 | events-power | 54 | events-power |
| 55 | events-nmi | 55 | events-nmi |
| 56 | events-msr | 56 | events-msr |
| 57 | events-pci | ||
| 57 | boottime-trace | 58 | boottime-trace |
| 58 | histogram | 59 | histogram |
| 59 | histogram-design | 60 | histogram-design |
| @@ -3922,6 +3922,14 @@ S: Maintained · 3921 unmodified lines | |||
| 3922 | F: Documentation/devicetree/bindings/media/aspeed,video-engine.yaml | 3922 | F: Documentation/devicetree/bindings/media/aspeed,video-engine.yaml |
| 3923 | F: drivers/media/platform/aspeed/ | 3923 | F: drivers/media/platform/aspeed/ |
| 3924 | 3924 | ||
| 3925 | ASPEED PCIE CONTROLLER DRIVER | ||
| 3926 | M: Jacky Chou <jacky_chou@aspeedtech.com> | ||
| 3927 | L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) | ||
| 3928 | L: linux-pci@vger.kernel.org | ||
| 3929 | S: Maintained | ||
| 3930 | F: Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml | ||
| 3931 | F: drivers/pci/controller/pcie-aspeed.c | ||
| 3932 | |||
| 3925 | ASUS EC HARDWARE MONITOR DRIVER | 3933 | ASUS EC HARDWARE MONITOR DRIVER |
| 3926 | M: Eugene Shalygin <eugene.shalygin@gmail.com> | 3934 | M: Eugene Shalygin <eugene.shalygin@gmail.com> |
| 3927 | L: linux-hwmon@vger.kernel.org | 3935 | L: linux-hwmon@vger.kernel.org |
| @@ -20503,6 +20511,7 @@ L: linux-pci@vger.kernel.org · 16575 unmodified lines | |||
| 20503 | L: linux-arm-msm@vger.kernel.org | 20511 | L: linux-arm-msm@vger.kernel.org |
| 20504 | S: Maintained | 20512 | S: Maintained |
| 20505 | F: Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml | 20513 | F: Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml |
| 20514 | F: Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml | ||
| 20506 | F: drivers/pci/controller/dwc/pcie-qcom-common.c | 20515 | F: drivers/pci/controller/dwc/pcie-qcom-common.c |
| 20507 | F: drivers/pci/controller/dwc/pcie-qcom-ep.c | 20516 | F: drivers/pci/controller/dwc/pcie-qcom-ep.c |
| 20508 | 20517 | ||
| @@ -336,6 +336,7 @@ void tegra_cpuidle_pcie_irqs_in_use(void) · 335 unmodified lines | |||
| 336 | pr_info("disabling CC6 state, since PCIe IRQs are in use\n"); | 336 | pr_info("disabling CC6 state, since PCIe IRQs are in use\n"); |
| 337 | tegra_cpuidle_disable_state(TEGRA_CC6); | 337 | tegra_cpuidle_disable_state(TEGRA_CC6); |
| 338 | } | 338 | } |
| 339 | EXPORT_SYMBOL_GPL(tegra_cpuidle_pcie_irqs_in_use); | ||
| 339 | 340 | ||
| 340 | static void tegra_cpuidle_setup_tegra114_c7_state(void) | 341 | static void tegra_cpuidle_setup_tegra114_c7_state(void) |
| 341 | { | 342 | { |
| @@ -39,6 +39,8 @@ · 38 unmodified lines | |||
| 39 | #define COMMAND_COPY BIT(5) | 39 | #define COMMAND_COPY BIT(5) |
| 40 | #define COMMAND_ENABLE_DOORBELL BIT(6) | 40 | #define COMMAND_ENABLE_DOORBELL BIT(6) |
| 41 | #define COMMAND_DISABLE_DOORBELL BIT(7) | 41 | #define COMMAND_DISABLE_DOORBELL BIT(7) |
| 42 | #define COMMAND_BAR_SUBRANGE_SETUP BIT(8) | ||
| 43 | #define COMMAND_BAR_SUBRANGE_CLEAR BIT(9) | ||
| 42 | 44 | ||
| 43 | #define PCI_ENDPOINT_TEST_STATUS 0x8 | 45 | #define PCI_ENDPOINT_TEST_STATUS 0x8 |
| 44 | #define STATUS_READ_SUCCESS BIT(0) | 46 | #define STATUS_READ_SUCCESS BIT(0) |
| @@ -55,6 +57,10 @@ · 10 unmodified lines | |||
| 55 | #define STATUS_DOORBELL_ENABLE_FAIL BIT(11) | 57 | #define STATUS_DOORBELL_ENABLE_FAIL BIT(11) |
| 56 | #define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12) | 58 | #define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12) |
| 57 | #define STATUS_DOORBELL_DISABLE_FAIL BIT(13) | 59 | #define STATUS_DOORBELL_DISABLE_FAIL BIT(13) |
| 60 | #define STATUS_BAR_SUBRANGE_SETUP_SUCCESS BIT(14) | ||
| 61 | #define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15) | ||
| 62 | #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16) | ||
| 63 | #define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17) | ||
| 58 | 64 | ||
| 59 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c | 65 | #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR 0x0c |
| 60 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 | 66 | #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR 0x10 |
| @@ -77,6 +83,7 @@ · 16 unmodified lines | |||
| 77 | #define CAP_MSI BIT(1) | 83 | #define CAP_MSI BIT(1) |
| 78 | #define CAP_MSIX BIT(2) | 84 | #define CAP_MSIX BIT(2) |
| 79 | #define CAP_INTX BIT(3) | 85 | #define CAP_INTX BIT(3) |
| 86 | #define CAP_SUBRANGE_MAPPING BIT(4) | ||
| 80 | 87 | ||
| 81 | #define PCI_ENDPOINT_TEST_DB_BAR 0x34 | 88 | #define PCI_ENDPOINT_TEST_DB_BAR 0x34 |
| 82 | #define PCI_ENDPOINT_TEST_DB_OFFSET 0x38 | 89 | #define PCI_ENDPOINT_TEST_DB_OFFSET 0x38 |
| @@ -100,6 +107,8 @@ · 17 unmodified lines | |||
| 100 | 107 | ||
| 101 | #define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588 | 108 | #define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588 |
| 102 | 109 | ||
| 110 | #define PCI_ENDPOINT_TEST_BAR_SUBRANGE_NSUB 2 | ||
| 111 | |||
| 103 | static DEFINE_IDA(pci_endpoint_test_ida); | 112 | static DEFINE_IDA(pci_endpoint_test_ida); |
| 104 | 113 | ||
| 105 | #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ | 114 | #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ |
| @@ -414,6 +423,193 @@ static int pci_endpoint_test_bars(struct pci_endpoint_test *test) · 308 unmodified lines | |||
| 414 | return 0; | 423 | return 0; |
| 415 | } | 424 | } |
| 416 | 425 | ||
| 426 | static u8 pci_endpoint_test_subrange_sig_byte(enum pci_barno barno, | ||
| 427 | unsigned int subno) | ||
| 428 | { | ||
| 429 | return 0x50 + (barno * 8) + subno; | ||
| 430 | } | ||
| 431 | |||
| 432 | static u8 pci_endpoint_test_subrange_test_byte(enum pci_barno barno, | ||
| 433 | unsigned int subno) | ||
| 434 | { | ||
| 435 | return 0xa0 + (barno * 8) + subno; | ||
| 436 | } | ||
| 437 | |||
| 438 | static int pci_endpoint_test_bar_subrange_cmd(struct pci_endpoint_test *test, | ||
| 439 | enum pci_barno barno, u32 command, | ||
| 440 | u32 ok_bit, u32 fail_bit) | ||
| 441 | { | ||
| 442 | struct pci_dev *pdev = test->pdev; | ||
| 443 | struct device *dev = &pdev->dev; | ||
| 444 | int irq_type = test->irq_type; | ||
| 445 | u32 status; | ||
| 446 | |||
| 447 | if (irq_type < PCITEST_IRQ_TYPE_INTX || | ||
| 448 | irq_type > PCITEST_IRQ_TYPE_MSIX) { | ||
| 449 | dev_err(dev, "Invalid IRQ type\n"); | ||
| 450 | return -EINVAL; | ||
| 451 | } | ||
| 452 | |||
| 453 | reinit_completion(&test->irq_raised); | ||
| 454 | |||
| 455 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0); | ||
| 456 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type); | ||
| 457 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1); | ||
| 458 | /* Reuse SIZE as a command parameter: bar number. */ | ||
| 459 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_SIZE, barno); | ||
| 460 | pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND, command); | ||
| 461 | |||
| 462 | if (!wait_for_completion_timeout(&test->irq_raised, | ||
| 463 | msecs_to_jiffies(1000))) | ||
| 464 | return -ETIMEDOUT; | ||
| 465 | |||
| 466 | status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS); | ||
| 467 | if (status & fail_bit) | ||
| 468 | return -EIO; | ||
| 469 | |||
| 470 | if (!(status & ok_bit)) | ||
| 471 | return -EIO; | ||
| 472 | |||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 476 | static int pci_endpoint_test_bar_subrange_setup(struct pci_endpoint_test *test, | ||
| 477 | enum pci_barno barno) | ||
| 478 | { | ||
| 479 | return pci_endpoint_test_bar_subrange_cmd(test, barno, | ||
| 480 | COMMAND_BAR_SUBRANGE_SETUP, | ||
| 481 | STATUS_BAR_SUBRANGE_SETUP_SUCCESS, | ||
| 482 | STATUS_BAR_SUBRANGE_SETUP_FAIL); | ||
| 483 | } | ||
| 484 | |||
| 485 | static int pci_endpoint_test_bar_subrange_clear(struct pci_endpoint_test *test, | ||
| 486 | enum pci_barno barno) | ||
| 487 | { | ||
| 488 | return pci_endpoint_test_bar_subrange_cmd(test, barno, | ||
| 489 | COMMAND_BAR_SUBRANGE_CLEAR, | ||
| 490 | STATUS_BAR_SUBRANGE_CLEAR_SUCCESS, | ||
| 491 | STATUS_BAR_SUBRANGE_CLEAR_FAIL); | ||
| 492 | } | ||
| 493 | |||
| 494 | static int pci_endpoint_test_bar_subrange(struct pci_endpoint_test *test, | ||
| 495 | enum pci_barno barno) | ||
| 496 | { | ||
| 497 | u32 nsub = PCI_ENDPOINT_TEST_BAR_SUBRANGE_NSUB; | ||
| 498 | struct device *dev = &test->pdev->dev; | ||
| 499 | size_t sub_size, buf_size; | ||
| 500 | resource_size_t bar_size; | ||
| 501 | void __iomem *bar_addr; | ||
| 502 | void *read_buf = NULL; | ||
| 503 | int ret, clear_ret; | ||
| 504 | size_t off, chunk; | ||
| 505 | u32 i, exp, val; | ||
| 506 | u8 pattern; | ||
| 507 | |||
| 508 | if (!(test->ep_caps & CAP_SUBRANGE_MAPPING)) | ||
| 509 | return -EOPNOTSUPP; | ||
| 510 | |||
| 511 | /* | ||
| 512 | * The test register BAR is not safe to reprogram and write/read | ||
| 513 | * over its full size. BAR_TEST already special-cases it to a tiny | ||
| 514 | * range. For subrange mapping tests, let's simply skip it. | ||
| 515 | */ | ||
| 516 | if (barno == test->test_reg_bar) | ||
| 517 | return -EBUSY; | ||
| 518 | |||
| 519 | bar_size = pci_resource_len(test->pdev, barno); | ||
| 520 | if (!bar_size) | ||
| 521 | return -ENODATA; | ||
| 522 | |||
| 523 | bar_addr = test->bar[barno]; | ||
| 524 | if (!bar_addr) | ||
| 525 | return -ENOMEM; | ||
| 526 | |||
| 527 | ret = pci_endpoint_test_bar_subrange_setup(test, barno); | ||
| 528 | if (ret) | ||
| 529 | return ret; | ||
| 530 | |||
| 531 | if (bar_size % nsub || bar_size / nsub > SIZE_MAX) { | ||
| 532 | ret = -EINVAL; | ||
| 533 | goto out_clear; | ||
| 534 | } | ||
| 535 | |||
| 536 | sub_size = bar_size / nsub; | ||
| 537 | if (sub_size < sizeof(u32)) { | ||
| 538 | ret = -ENOSPC; | ||
| 539 | goto out_clear; | ||
| 540 | } | ||
| 541 | |||
| 542 | /* Limit the temporary buffer size */ | ||
| 543 | buf_size = min_t(size_t, sub_size, SZ_1M); | ||
| 544 | |||
| 545 | read_buf = kmalloc(buf_size, GFP_KERNEL); | ||
| 546 | if (!read_buf) { | ||
| 547 | ret = -ENOMEM; | ||
| 548 | goto out_clear; | ||
| 549 | } | ||
| 550 | |||
| 551 | /* | ||
| 552 | * Step 1: verify EP-provided signature per subrange. This detects | ||
| 553 | * whether the EP actually applied the submap order. | ||
| 554 | */ | ||
| 555 | for (i = 0; i < nsub; i++) { | ||
| 556 | exp = (u32)pci_endpoint_test_subrange_sig_byte(barno, i) * | ||
| 557 | 0x01010101U; | ||
| 558 | val = ioread32(bar_addr + (i * sub_size)); | ||
| 559 | if (val != exp) { | ||
| 560 | dev_err(dev, | ||
| 561 | "BAR%d subrange%u signature mismatch @%#zx: exp %#08x got %#08x\n", | ||
| 562 | barno, i, (size_t)i * sub_size, exp, val); | ||
| 563 | ret = -EIO; | ||
| 564 | goto out_clear; | ||
| 565 | } | ||
| 566 | val = ioread32(bar_addr + (i * sub_size) + sub_size - sizeof(u32)); | ||
| 567 | if (val != exp) { | ||
| 568 | dev_err(dev, | ||
| 569 | "BAR%d subrange%u signature mismatch @%#zx: exp %#08x got %#08x\n", | ||
| 570 | barno, i, | ||
| 571 | ((size_t)i * sub_size) + sub_size - sizeof(u32), | ||
| 572 | exp, val); | ||
| 573 | ret = -EIO; | ||
| 574 | goto out_clear; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | /* Step 2: write unique pattern per subrange (write all first). */ | ||
| 579 | for (i = 0; i < nsub; i++) { | ||
| 580 | pattern = pci_endpoint_test_subrange_test_byte(barno, i); | ||
| 581 | memset_io(bar_addr + (i * sub_size), pattern, sub_size); | ||
| 582 | } | ||
| 583 | |||
| 584 | /* Step 3: read back and verify (read all after all writes). */ | ||
| 585 | for (i = 0; i < nsub; i++) { | ||
| 586 | pattern = pci_endpoint_test_subrange_test_byte(barno, i); | ||
| 587 | for (off = 0; off < sub_size; off += chunk) { | ||
| 588 | void *bad; | ||
| 589 | |||
| 590 | chunk = min_t(size_t, buf_size, sub_size - off); | ||
| 591 | memcpy_fromio(read_buf, bar_addr + (i * sub_size) + off, | ||
| 592 | chunk); | ||
| 593 | bad = memchr_inv(read_buf, pattern, chunk); | ||
| 594 | if (bad) { | ||
| 595 | size_t bad_off = (u8 *)bad - (u8 *)read_buf; | ||
| 596 | |||
| 597 | dev_err(dev, | ||
| 598 | "BAR%d subrange%u data mismatch @%#zx (pattern %#02x)\n", | ||
| 599 | barno, i, (size_t)i * sub_size + off + bad_off, | ||
| 600 | pattern); | ||
| 601 | ret = -EIO; | ||
| 602 | goto out_clear; | ||
| 603 | } | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | out_clear: | ||
| 608 | kfree(read_buf); | ||
| 609 | clear_ret = pci_endpoint_test_bar_subrange_clear(test, barno); | ||
| 610 | return ret ?: clear_ret; | ||
| 611 | } | ||
| 612 | |||
| 417 | static int pci_endpoint_test_intx_irq(struct pci_endpoint_test *test) | 613 | static int pci_endpoint_test_intx_irq(struct pci_endpoint_test *test) |
| 418 | { | 614 | { |
| 419 | u32 val; | 615 | u32 val; |
| @@ -936,12 +1132,17 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, · 516 unmodified lines | |||
| 936 | 1132 | ||
| 937 | switch (cmd) { | 1133 | switch (cmd) { |
| 938 | case PCITEST_BAR: | 1134 | case PCITEST_BAR: |
| 1135 | case PCITEST_BAR_SUBRANGE: | ||
| 939 | bar = arg; | 1136 | bar = arg; |
| 940 | if (bar <= NO_BAR || bar > BAR_5) | 1137 | if (bar <= NO_BAR || bar > BAR_5) |
| 941 | goto ret; | 1138 | goto ret; |
| 942 | if (is_am654_pci_dev(pdev) && bar == BAR_0) | 1139 | if (is_am654_pci_dev(pdev) && bar == BAR_0) |
| 943 | goto ret; | 1140 | goto ret; |
| 944 | ret = pci_endpoint_test_bar(test, bar); | 1141 | |
| 1142 | if (cmd == PCITEST_BAR) | ||
| 1143 | ret = pci_endpoint_test_bar(test, bar); | ||
| 1144 | else | ||
| 1145 | ret = pci_endpoint_test_bar_subrange(test, bar); | ||
| 945 | break; | 1146 | break; |
| 946 | case PCITEST_BARS: | 1147 | case PCITEST_BARS: |
| 947 | ret = pci_endpoint_test_bars(test); | 1148 | ret = pci_endpoint_test_bars(test); |
| @@ -39,6 +39,7 @@ obj-$(CONFIG_PCI_TSM) += tsm.o · 38 unmodified lines | |||
| 39 | obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o | 39 | obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o |
| 40 | obj-$(CONFIG_PCI_NPEM) += npem.o | 40 | obj-$(CONFIG_PCI_NPEM) += npem.o |
| 41 | obj-$(CONFIG_PCIE_TPH) += tph.o | 41 | obj-$(CONFIG_PCIE_TPH) += tph.o |
| 42 | obj-$(CONFIG_CARDBUS) += setup-cardbus.o | ||
| 42 | 43 | ||
| 43 | # Endpoint library must be initialized before its users | 44 | # Endpoint library must be initialized before its users |
| 44 | obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ | 45 | obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ |
| @@ -47,3 +48,6 @@ obj-y += controller/ · 2 unmodified lines | |||
| 47 | obj-y += switch/ | 48 | obj-y += switch/ |
| 48 | 49 | ||
| 49 | subdir-ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG | 50 | subdir-ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG |
| 51 | |||
| 52 | CFLAGS_trace.o := -I$(src) | ||
| 53 | obj-$(CONFIG_TRACING) += trace.o | ||
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
| 16 | #include <linux/of_platform.h> | 16 | #include <linux/of_platform.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/pm_runtime.h> | ||
| 18 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
| 19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 20 | 21 | ||
| @@ -344,7 +345,6 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { } · 323 unmodified lines | |||
| 344 | void pci_bus_add_device(struct pci_dev *dev) | 345 | void pci_bus_add_device(struct pci_dev *dev) |
| 345 | { | 346 | { |
| 346 | struct device_node *dn = dev->dev.of_node; | 347 | struct device_node *dn = dev->dev.of_node; |
| 347 | struct platform_device *pdev; | ||
| 348 | 348 | ||
| 349 | /* | 349 | /* |
| 350 | * Can not put in pci_device_add yet because resources | 350 | * Can not put in pci_device_add yet because resources |
| @@ -362,22 +362,11 @@ void pci_bus_add_device(struct pci_dev *dev) · 11 unmodified lines | |||
| 362 | pci_save_state(dev); | 362 | pci_save_state(dev); |
| 363 | 363 | ||
| 364 | /* | 364 | /* |
| 365 | * If the PCI device is associated with a pwrctrl device with a | 365 | * Enable runtime PM, which potentially allows the device to |
| 366 | * power supply, create a device link between the PCI device and | 366 | * suspend immediately, only after the PCI state has been |
| 367 | * pwrctrl device. This ensures that pwrctrl drivers are probed | 367 | * configured completely. |
| 368 | * before PCI client drivers. | ||
| 369 | */ | 368 | */ |
| 370 | pdev = of_find_device_by_node(dn); | 369 | pm_runtime_enable(&dev->dev); |
| 371 | if (pdev) { | ||
| 372 | if (of_pci_supply_present(dn)) { | ||
| 373 | if (!device_link_add(&dev->dev, &pdev->dev, | ||
| 374 | DL_FLAG_AUTOREMOVE_CONSUMER)) { | ||
| 375 | pci_err(dev, "failed to add device link to power control device %s\n", | ||
| 376 | pdev->name); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | put_device(&pdev->dev); | ||
| 380 | } | ||
| 381 | 370 | ||
| 382 | if (!dn || of_device_is_available(dn)) | 371 | if (!dn || of_device_is_available(dn)) |
| 383 | pci_dev_allow_binding(dev); | 372 | pci_dev_allow_binding(dev); |
| @@ -58,6 +58,22 @@ config PCI_VERSATILE · 57 unmodified lines | |||
| 58 | bool "ARM Versatile PB PCI controller" | 58 | bool "ARM Versatile PB PCI controller" |
| 59 | depends on ARCH_VERSATILE || COMPILE_TEST | 59 | depends on ARCH_VERSATILE || COMPILE_TEST |
| 60 | 60 | ||
| 61 | config PCIE_ASPEED | ||
| 62 | bool "ASPEED PCIe controller" | ||
| 63 | depends on ARCH_ASPEED || COMPILE_TEST | ||
| 64 | depends on OF | ||
| 65 | depends on PCI_MSI | ||
| 66 | select IRQ_MSI_LIB | ||
| 67 | help | ||
| 68 | Enable this option to support the PCIe controller found on ASPEED | ||
| 69 | SoCs. | ||
| 70 | |||
| 71 | This driver provides initialization and management for PCIe | ||
| 72 | Root Complex functionality, including INTx and MSI support. | ||
| 73 | |||
| 74 | Select Y if your platform uses an ASPEED SoC and requires PCIe | ||
| 75 | connectivity. | ||
| 76 | |||
| 61 | config PCIE_BRCMSTB | 77 | config PCIE_BRCMSTB |
| 62 | tristate "Broadcom Brcmstb PCIe controller" | 78 | tristate "Broadcom Brcmstb PCIe controller" |
| 63 | depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCMBCA || \ | 79 | depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCMBCA || \ |
| @@ -232,7 +248,7 @@ config PCI_HYPERV_INTERFACE · 168 unmodified lines | |||
| 232 | driver. | 248 | driver. |
| 233 | 249 | ||
| 234 | config PCI_TEGRA | 250 | config PCI_TEGRA |
| 235 | bool "NVIDIA Tegra PCIe controller" | 251 | tristate "NVIDIA Tegra PCIe controller" |
| 236 | depends on ARCH_TEGRA || COMPILE_TEST | 252 | depends on ARCH_TEGRA || COMPILE_TEST |
| 237 | depends on PCI_MSI | 253 | depends on PCI_MSI |
| 238 | select IRQ_MSI_LIB | 254 | select IRQ_MSI_LIB |
| @@ -243,6 +259,7 @@ config PCI_TEGRA · 4 unmodified lines | |||
| 243 | config PCIE_RCAR_HOST | 259 | config PCIE_RCAR_HOST |
| 244 | bool "Renesas R-Car PCIe controller (host mode)" | 260 | bool "Renesas R-Car PCIe controller (host mode)" |
| 245 | depends on ARCH_RENESAS || COMPILE_TEST | 261 | depends on ARCH_RENESAS || COMPILE_TEST |
| 262 | depends on OF | ||
| 246 | depends on PCI_MSI | 263 | depends on PCI_MSI |
| 247 | select IRQ_MSI_LIB | 264 | select IRQ_MSI_LIB |
| 248 | help | 265 | help |
| @@ -40,6 +40,7 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o · 39 unmodified lines | |||
| 40 | obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o | 40 | obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o |
| 41 | obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o | 41 | obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o |
| 42 | obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o | 42 | obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o |
| 43 | obj-$(CONFIG_PCIE_ASPEED) += pcie-aspeed.o | ||
| 43 | 44 | ||
| 44 | # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW | 45 | # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW |
| 45 | obj-y += dwc/ | 46 | obj-y += dwc/ |
| @@ -620,9 +620,11 @@ static int j721e_pcie_probe(struct platform_device *pdev) · 619 unmodified lines | |||
| 620 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); | 620 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); |
| 621 | } | 621 | } |
| 622 | 622 | ||
| 623 | ret = cdns_pcie_host_setup(rc); | 623 | if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) { |
| 624 | if (ret < 0) | 624 | ret = cdns_pcie_host_setup(rc); |
| 625 | goto err_pcie_setup; | 625 | if (ret < 0) |
| 626 | goto err_pcie_setup; | ||
| 627 | } | ||
| 626 | 628 | ||
| 627 | break; | 629 | break; |
| 628 | case PCI_MODE_EP: | 630 | case PCI_MODE_EP: |
| @@ -632,9 +634,11 @@ static int j721e_pcie_probe(struct platform_device *pdev) · 3 unmodified lines | |||
| 632 | goto err_get_sync; | 634 | goto err_get_sync; |
| 633 | } | 635 | } |
| 634 | 636 | ||
| 635 | ret = cdns_pcie_ep_setup(ep); | 637 | if (IS_ENABLED(CONFIG_PCI_J721E_EP)) { |
| 636 | if (ret < 0) | 638 | ret = cdns_pcie_ep_setup(ep); |
| 637 | goto err_pcie_setup; | 639 | if (ret < 0) |
| 640 | goto err_pcie_setup; | ||
| 641 | } | ||
| 638 | 642 | ||
| 639 | break; | 643 | break; |
| 640 | } | 644 | } |
| @@ -659,10 +663,11 @@ static void j721e_pcie_remove(struct platform_device *pdev) · 18 unmodified lines | |||
| 659 | struct cdns_pcie_ep *ep; | 663 | struct cdns_pcie_ep *ep; |
| 660 | struct cdns_pcie_rc *rc; | 664 | struct cdns_pcie_rc *rc; |
| 661 | 665 | ||
| 662 | if (pcie->mode == PCI_MODE_RC) { | 666 | if (IS_ENABLED(CONFIG_PCI_J721E_HOST) && |
| 667 | pcie->mode == PCI_MODE_RC) { | ||
| 663 | rc = container_of(cdns_pcie, struct cdns_pcie_rc, pcie); | 668 | rc = container_of(cdns_pcie, struct cdns_pcie_rc, pcie); |
| 664 | cdns_pcie_host_disable(rc); | 669 | cdns_pcie_host_disable(rc); |
| 665 | } else { | 670 | } else if (IS_ENABLED(CONFIG_PCI_J721E_EP)) { |
| 666 | ep = container_of(cdns_pcie, struct cdns_pcie_ep, pcie); | 671 | ep = container_of(cdns_pcie, struct cdns_pcie_ep, pcie); |
| 667 | cdns_pcie_ep_disable(ep); | 672 | cdns_pcie_ep_disable(ep); |
| 668 | } | 673 | } |
| @@ -728,10 +733,12 @@ static int j721e_pcie_resume_noirq(struct device *dev) · 59 unmodified lines | |||
| 728 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); | 733 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); |
| 729 | } | 734 | } |
| 730 | 735 | ||
| 731 | ret = cdns_pcie_host_link_setup(rc); | 736 | if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) { |
| 732 | if (ret < 0) { | 737 | ret = cdns_pcie_host_link_setup(rc); |
| 733 | clk_disable_unprepare(pcie->refclk); | 738 | if (ret < 0) { |
| 734 | return ret; | 739 | clk_disable_unprepare(pcie->refclk); |
| 740 | return ret; | ||
| 741 | } | ||
| 735 | } | 742 | } |
| 736 | 743 | ||
| 737 | /* | 744 | /* |
| @@ -741,10 +748,12 @@ static int j721e_pcie_resume_noirq(struct device *dev) · 3 unmodified lines | |||
| 741 | for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++) | 748 | for (enum cdns_pcie_rp_bar bar = RP_BAR0; bar <= RP_NO_BAR; bar++) |
| 742 | rc->avail_ib_bar[bar] = true; | 749 | rc->avail_ib_bar[bar] = true; |
| 743 | 750 | ||
| 744 | ret = cdns_pcie_host_init(rc); | 751 | if (IS_ENABLED(CONFIG_PCI_J721E_HOST)) { |
| 745 | if (ret) { | 752 | ret = cdns_pcie_host_init(rc); |
| 746 | clk_disable_unprepare(pcie->refclk); | 753 | if (ret) { |
| 747 | return ret; | 754 | clk_disable_unprepare(pcie->refclk); |
| 755 | return ret; | ||
| 756 | } | ||
| 748 | } | 757 | } |
| 749 | } | 758 | } |
| 750 | 759 | ||
| @@ -173,11 +173,21 @@ int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a, · 172 unmodified lines | |||
| 173 | const struct list_head *b) | 173 | const struct list_head *b) |
| 174 | { | 174 | { |
| 175 | struct resource_entry *entry1, *entry2; | 175 | struct resource_entry *entry1, *entry2; |
| 176 | u64 size1, size2; | ||
| 176 | 177 | ||
| 177 | entry1 = container_of(a, struct resource_entry, node); | 178 | entry1 = container_of(a, struct resource_entry, node); |
| 178 | entry2 = container_of(b, struct resource_entry, node); | 179 | entry2 = container_of(b, struct resource_entry, node); |
| 179 | 180 | ||
| 180 | return resource_size(entry2->res) - resource_size(entry1->res); | 181 | size1 = resource_size(entry1->res); |
| 182 | size2 = resource_size(entry2->res); | ||
| 183 | |||
| 184 | if (size1 > size2) | ||
| 185 | return -1; | ||
| 186 | |||
| 187 | if (size1 < size2) | ||
| 188 | return 1; | ||
| 189 | |||
| 190 | return 0; | ||
| 181 | } | 191 | } |
| 182 | EXPORT_SYMBOL_GPL(cdns_pcie_host_dma_ranges_cmp); | 192 | EXPORT_SYMBOL_GPL(cdns_pcie_host_dma_ranges_cmp); |
| 183 | 193 | ||
| @@ -13,13 +13,13 @@ · 12 unmodified lines | |||
| 13 | u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap) | 13 | u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap) |
| 14 | { | 14 | { |
| 15 | return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST, | 15 | return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST, |
| 16 | cap, pcie); | 16 | cap, NULL, pcie); |
| 17 | } | 17 | } |
| 18 | EXPORT_SYMBOL_GPL(cdns_pcie_find_capability); | 18 | EXPORT_SYMBOL_GPL(cdns_pcie_find_capability); |
| 19 | 19 | ||
| 20 | u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap) | 20 | u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap) |
| 21 | { | 21 | { |
| 22 | return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie); | 22 | return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, NULL, pcie); |
| 23 | } | 23 | } |
| 24 | EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability); | 24 | EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability); |
| 25 | 25 | ||
| @@ -228,7 +228,7 @@ config PCIE_TEGRA194 · 227 unmodified lines | |||
| 228 | 228 | ||
| 229 | config PCIE_TEGRA194_HOST | 229 | config PCIE_TEGRA194_HOST |
| 230 | tristate "NVIDIA Tegra194 (and later) PCIe controller (host mode)" | 230 | tristate "NVIDIA Tegra194 (and later) PCIe controller (host mode)" |
| 231 | depends on ARCH_TEGRA_194_SOC || COMPILE_TEST | 231 | depends on (ARCH_TEGRA && ARM64) || COMPILE_TEST |
| 232 | depends on PCI_MSI | 232 | depends on PCI_MSI |
| 233 | select PCIE_DW_HOST | 233 | select PCIE_DW_HOST |
| 234 | select PHY_TEGRA194_P2U | 234 | select PHY_TEGRA194_P2U |
| @@ -243,7 +243,7 @@ config PCIE_TEGRA194_HOST · 8 unmodified lines | |||
| 243 | 243 | ||
| 244 | config PCIE_TEGRA194_EP | 244 | config PCIE_TEGRA194_EP |
| 245 | tristate "NVIDIA Tegra194 (and later) PCIe controller (endpoint mode)" | 245 | tristate "NVIDIA Tegra194 (and later) PCIe controller (endpoint mode)" |
| 246 | depends on ARCH_TEGRA_194_SOC || COMPILE_TEST | 246 | depends on (ARCH_TEGRA && ARM64) || COMPILE_TEST |
| 247 | depends on PCI_ENDPOINT | 247 | depends on PCI_ENDPOINT |
| 248 | select PCIE_DW_EP | 248 | select PCIE_DW_EP |
| 249 | select PHY_TEGRA194_P2U | 249 | select PHY_TEGRA194_P2U |
| @@ -424,6 +424,7 @@ static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 423 unmodified lines | |||
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | static const struct pci_epc_features dra7xx_pcie_epc_features = { | 426 | static const struct pci_epc_features dra7xx_pcie_epc_features = { |
| 427 | DWC_EPC_COMMON_FEATURES, | ||
| 427 | .linkup_notifier = true, | 428 | .linkup_notifier = true, |
| 428 | .msi_capable = true, | 429 | .msi_capable = true, |
| 429 | }; | 430 | }; |
| @@ -52,6 +52,8 @@ · 51 unmodified lines | |||
| 52 | #define IMX95_PCIE_REF_CLKEN BIT(23) | 52 | #define IMX95_PCIE_REF_CLKEN BIT(23) |
| 53 | #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) | 53 | #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) |
| 54 | #define IMX95_PCIE_SS_RW_REG_1 0xf4 | 54 | #define IMX95_PCIE_SS_RW_REG_1 0xf4 |
| 55 | #define IMX95_PCIE_CLKREQ_OVERRIDE_EN BIT(8) | ||
| 56 | #define IMX95_PCIE_CLKREQ_OVERRIDE_VAL BIT(9) | ||
| 55 | #define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) | 57 | #define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) |
| 56 | 58 | ||
| 57 | #define IMX95_PE0_GEN_CTRL_1 0x1050 | 59 | #define IMX95_PE0_GEN_CTRL_1 0x1050 |
| @@ -114,6 +116,7 @@ enum imx_pcie_variants { · 56 unmodified lines | |||
| 114 | #define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9) | 116 | #define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9) |
| 115 | #define IMX_PCIE_FLAG_HAS_LUT BIT(10) | 117 | #define IMX_PCIE_FLAG_HAS_LUT BIT(10) |
| 116 | #define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11) | 118 | #define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11) |
| 119 | #define IMX_PCIE_FLAG_SKIP_L23_READY BIT(12) | ||
| 117 | 120 | ||
| 118 | #define imx_check_flag(pci, val) (pci->drvdata->flags & val) | 121 | #define imx_check_flag(pci, val) (pci->drvdata->flags & val) |
| 119 | 122 | ||
| @@ -136,6 +139,7 @@ struct imx_pcie_drvdata { · 16 unmodified lines | |||
| 136 | int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable); | 139 | int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable); |
| 137 | int (*core_reset)(struct imx_pcie *pcie, bool assert); | 140 | int (*core_reset)(struct imx_pcie *pcie, bool assert); |
| 138 | int (*wait_pll_lock)(struct imx_pcie *pcie); | 141 | int (*wait_pll_lock)(struct imx_pcie *pcie); |
| 142 | void (*clr_clkreq_override)(struct imx_pcie *pcie); | ||
| 139 | const struct dw_pcie_host_ops *ops; | 143 | const struct dw_pcie_host_ops *ops; |
| 140 | }; | 144 | }; |
| 141 | 145 | ||
| @@ -149,6 +153,8 @@ struct imx_pcie { · 7 unmodified lines | |||
| 149 | struct gpio_desc *reset_gpiod; | 153 | struct gpio_desc *reset_gpiod; |
| 150 | struct clk_bulk_data *clks; | 154 | struct clk_bulk_data *clks; |
| 151 | int num_clks; | 155 | int num_clks; |
| 156 | bool supports_clkreq; | ||
| 157 | bool enable_ext_refclk; | ||
| 152 | struct regmap *iomuxc_gpr; | 158 | struct regmap *iomuxc_gpr; |
| 153 | u16 msi_ctrl; | 159 | u16 msi_ctrl; |
| 154 | u32 controller_id; | 160 | u32 controller_id; |
| @@ -241,6 +247,8 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie) · 86 unmodified lines | |||
| 241 | 247 | ||
| 242 | static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) | 248 | static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) |
| 243 | { | 249 | { |
| 250 | bool ext = imx_pcie->enable_ext_refclk; | ||
| 251 | |||
| 244 | /* | 252 | /* |
| 245 | * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready | 253 | * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready |
| 246 | * Through Beacon or PERST# De-assertion | 254 | * Through Beacon or PERST# De-assertion |
| @@ -259,13 +267,12 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) · 12 unmodified lines | |||
| 259 | IMX95_PCIE_PHY_CR_PARA_SEL, | 267 | IMX95_PCIE_PHY_CR_PARA_SEL, |
| 260 | IMX95_PCIE_PHY_CR_PARA_SEL); | 268 | IMX95_PCIE_PHY_CR_PARA_SEL); |
| 261 | 269 | ||
| 262 | regmap_update_bits(imx_pcie->iomuxc_gpr, | 270 | regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, |
| 263 | IMX95_PCIE_PHY_GEN_CTRL, | 271 | ext ? IMX95_PCIE_REF_USE_PAD : 0, |
| 264 | IMX95_PCIE_REF_USE_PAD, 0); | 272 | IMX95_PCIE_REF_USE_PAD); |
| 265 | regmap_update_bits(imx_pcie->iomuxc_gpr, | 273 | regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, |
| 266 | IMX95_PCIE_SS_RW_REG_0, | ||
| 267 | IMX95_PCIE_REF_CLKEN, | 274 | IMX95_PCIE_REF_CLKEN, |
| 268 | IMX95_PCIE_REF_CLKEN); | 275 | ext ? 0 : IMX95_PCIE_REF_CLKEN); |
| 269 | 276 | ||
| 270 | return 0; | 277 | return 0; |
| 271 | } | 278 | } |
| @@ -685,7 +692,7 @@ static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) · 413 unmodified lines | |||
| 685 | return 0; | 692 | return 0; |
| 686 | } | 693 | } |
| 687 | 694 | ||
| 688 | static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) | 695 | static void imx8mm_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable) |
| 689 | { | 696 | { |
| 690 | int offset = imx_pcie_grp_offset(imx_pcie); | 697 | int offset = imx_pcie_grp_offset(imx_pcie); |
| 691 | 698 | ||
| @@ -695,6 +702,11 @@ static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) · 3 unmodified lines | |||
| 695 | regmap_update_bits(imx_pcie->iomuxc_gpr, offset, | 702 | regmap_update_bits(imx_pcie->iomuxc_gpr, offset, |
| 696 | IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, | 703 | IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, |
| 697 | enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0); | 704 | enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0); |
| 705 | } | ||
| 706 | |||
| 707 | static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) | ||
| 708 | { | ||
| 709 | imx8mm_pcie_clkreq_override(imx_pcie, enable); | ||
| 698 | return 0; | 710 | return 0; |
| 699 | } | 711 | } |
| 700 | 712 | ||
| @@ -706,6 +718,32 @@ static int imx7d_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) · 5 unmodified lines | |||
| 706 | return 0; | 718 | return 0; |
| 707 | } | 719 | } |
| 708 | 720 | ||
| 721 | static void imx95_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable) | ||
| 722 | { | ||
| 723 | regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, | ||
| 724 | IMX95_PCIE_CLKREQ_OVERRIDE_EN, | ||
| 725 | enable ? IMX95_PCIE_CLKREQ_OVERRIDE_EN : 0); | ||
| 726 | regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, | ||
| 727 | IMX95_PCIE_CLKREQ_OVERRIDE_VAL, | ||
| 728 | enable ? IMX95_PCIE_CLKREQ_OVERRIDE_VAL : 0); | ||
| 729 | } | ||
| 730 | |||
| 731 | static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) | ||
| 732 | { | ||
| 733 | imx95_pcie_clkreq_override(imx_pcie, enable); | ||
| 734 | return 0; | ||
| 735 | } | ||
| 736 | |||
| 737 | static void imx8mm_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie) | ||
| 738 | { | ||
| 739 | imx8mm_pcie_clkreq_override(imx_pcie, false); | ||
| 740 | } | ||
| 741 | |||
| 742 | static void imx95_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie) | ||
| 743 | { | ||
| 744 | imx95_pcie_clkreq_override(imx_pcie, false); | ||
| 745 | } | ||
| 746 | |||
| 709 | static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie) | 747 | static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie) |
| 710 | { | 748 | { |
| 711 | struct dw_pcie *pci = imx_pcie->pci; | 749 | struct dw_pcie *pci = imx_pcie->pci; |
| @@ -1322,6 +1360,12 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp) · 610 unmodified lines | |||
| 1322 | dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); | 1360 | dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); |
| 1323 | dw_pcie_dbi_ro_wr_dis(pci); | 1361 | dw_pcie_dbi_ro_wr_dis(pci); |
| 1324 | } | 1362 | } |
| 1363 | |||
| 1364 | /* Clear CLKREQ# override if supports_clkreq is true and link is up */ | ||
| 1365 | if (dw_pcie_link_up(pci) && imx_pcie->supports_clkreq) { | ||
| 1366 | if (imx_pcie->drvdata->clr_clkreq_override) | ||
| 1367 | imx_pcie->drvdata->clr_clkreq_override(imx_pcie); | ||
| 1368 | } | ||
| 1325 | } | 1369 | } |
| 1326 | 1370 | ||
| 1327 | /* | 1371 | /* |
| @@ -1387,6 +1431,7 @@ static int imx_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 59 unmodified lines | |||
| 1387 | } | 1431 | } |
| 1388 | 1432 | ||
| 1389 | static const struct pci_epc_features imx8m_pcie_epc_features = { | 1433 | static const struct pci_epc_features imx8m_pcie_epc_features = { |
| 1434 | DWC_EPC_COMMON_FEATURES, | ||
| 1390 | .msi_capable = true, | 1435 | .msi_capable = true, |
| 1391 | .bar[BAR_1] = { .type = BAR_RESERVED, }, | 1436 | .bar[BAR_1] = { .type = BAR_RESERVED, }, |
| 1392 | .bar[BAR_3] = { .type = BAR_RESERVED, }, | 1437 | .bar[BAR_3] = { .type = BAR_RESERVED, }, |
| @@ -1396,6 +1441,7 @@ static const struct pci_epc_features imx8m_pcie_epc_features = { · 3 unmodified lines | |||
| 1396 | }; | 1441 | }; |
| 1397 | 1442 | ||
| 1398 | static const struct pci_epc_features imx8q_pcie_epc_features = { | 1443 | static const struct pci_epc_features imx8q_pcie_epc_features = { |
| 1444 | DWC_EPC_COMMON_FEATURES, | ||
| 1399 | .msi_capable = true, | 1445 | .msi_capable = true, |
| 1400 | .bar[BAR_1] = { .type = BAR_RESERVED, }, | 1446 | .bar[BAR_1] = { .type = BAR_RESERVED, }, |
| 1401 | .bar[BAR_3] = { .type = BAR_RESERVED, }, | 1447 | .bar[BAR_3] = { .type = BAR_RESERVED, }, |
| @@ -1416,6 +1462,7 @@ static const struct pci_epc_features imx8q_pcie_epc_features = { · 14 unmodified lines | |||
| 1416 | * BAR5 | Enable | 32-bit | 64 KB | Programmable Size | 1462 | * BAR5 | Enable | 32-bit | 64 KB | Programmable Size |
| 1417 | */ | 1463 | */ |
| 1418 | static const struct pci_epc_features imx95_pcie_epc_features = { | 1464 | static const struct pci_epc_features imx95_pcie_epc_features = { |
| 1465 | DWC_EPC_COMMON_FEATURES, | ||
| 1419 | .msi_capable = true, | 1466 | .msi_capable = true, |
| 1420 | .bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_64K, }, | 1467 | .bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_64K, }, |
| 1421 | .align = SZ_4K, | 1468 | .align = SZ_4K, |
| @@ -1602,7 +1649,7 @@ static int imx_pcie_probe(struct platform_device *pdev) · 180 unmodified lines | |||
| 1602 | struct imx_pcie *imx_pcie; | 1649 | struct imx_pcie *imx_pcie; |
| 1603 | struct device_node *np; | 1650 | struct device_node *np; |
| 1604 | struct device_node *node = dev->of_node; | 1651 | struct device_node *node = dev->of_node; |
| 1605 | int ret, domain; | 1652 | int i, ret, domain; |
| 1606 | u16 val; | 1653 | u16 val; |
| 1607 | 1654 | ||
| 1608 | imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL); | 1655 | imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL); |
| @@ -1653,6 +1700,9 @@ static int imx_pcie_probe(struct platform_device *pdev) · 44 unmodified lines | |||
| 1653 | if (imx_pcie->num_clks < 0) | 1700 | if (imx_pcie->num_clks < 0) |
| 1654 | return dev_err_probe(dev, imx_pcie->num_clks, | 1701 | return dev_err_probe(dev, imx_pcie->num_clks, |
| 1655 | "failed to get clocks\n"); | 1702 | "failed to get clocks\n"); |
| 1703 | for (i = 0; i < imx_pcie->num_clks; i++) | ||
| 1704 | if (strncmp(imx_pcie->clks[i].id, "extref", 6) == 0) | ||
| 1705 | imx_pcie->enable_ext_refclk = true; | ||
| 1656 | 1706 | ||
| 1657 | if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) { | 1707 | if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) { |
| 1658 | imx_pcie->phy = devm_phy_get(dev, "pcie-phy"); | 1708 | imx_pcie->phy = devm_phy_get(dev, "pcie-phy"); |
| @@ -1740,6 +1790,7 @@ static int imx_pcie_probe(struct platform_device *pdev) · 81 unmodified lines | |||
| 1740 | /* Limit link speed */ | 1790 | /* Limit link speed */ |
| 1741 | pci->max_link_speed = 1; | 1791 | pci->max_link_speed = 1; |
| 1742 | of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed); | 1792 | of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed); |
| 1793 | imx_pcie->supports_clkreq = of_property_read_bool(node, "supports-clkreq"); | ||
| 1743 | 1794 | ||
| 1744 | ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux"); | 1795 | ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux"); |
| 1745 | if (ret < 0 && ret != -ENODEV) | 1796 | if (ret < 0 && ret != -ENODEV) |
| @@ -1777,6 +1828,8 @@ static int imx_pcie_probe(struct platform_device *pdev) · 31 unmodified lines | |||
| 1777 | */ | 1828 | */ |
| 1778 | imx_pcie_add_lut_by_rid(imx_pcie, 0); | 1829 | imx_pcie_add_lut_by_rid(imx_pcie, 0); |
| 1779 | } else { | 1830 | } else { |
| 1831 | if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY)) | ||
| 1832 | pci->pp.skip_l23_ready = true; | ||
| 1780 | pci->pp.use_atu_msg = true; | 1833 | pci->pp.use_atu_msg = true; |
| 1781 | ret = dw_pcie_host_init(&pci->pp); | 1834 | ret = dw_pcie_host_init(&pci->pp); |
| 1782 | if (ret < 0) | 1835 | if (ret < 0) |
| @@ -1838,6 +1891,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 55 unmodified lines | |||
| 1838 | .variant = IMX6QP, | 1891 | .variant = IMX6QP, |
| 1839 | .flags = IMX_PCIE_FLAG_IMX_PHY | | 1892 | .flags = IMX_PCIE_FLAG_IMX_PHY | |
| 1840 | IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | | 1893 | IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | |
| 1894 | IMX_PCIE_FLAG_SKIP_L23_READY | | ||
| 1841 | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, | 1895 | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, |
| 1842 | .dbi_length = 0x200, | 1896 | .dbi_length = 0x200, |
| 1843 | .gpr = "fsl,imx6q-iomuxc-gpr", | 1897 | .gpr = "fsl,imx6q-iomuxc-gpr", |
| @@ -1854,6 +1908,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 10 unmodified lines | |||
| 1854 | .variant = IMX7D, | 1908 | .variant = IMX7D, |
| 1855 | .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND | | 1909 | .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND | |
| 1856 | IMX_PCIE_FLAG_HAS_APP_RESET | | 1910 | IMX_PCIE_FLAG_HAS_APP_RESET | |
| 1911 | IMX_PCIE_FLAG_SKIP_L23_READY | | ||
| 1857 | IMX_PCIE_FLAG_HAS_PHY_RESET, | 1912 | IMX_PCIE_FLAG_HAS_PHY_RESET, |
| 1858 | .gpr = "fsl,imx7d-iomuxc-gpr", | 1913 | .gpr = "fsl,imx7d-iomuxc-gpr", |
| 1859 | .mode_off[0] = IOMUXC_GPR12, | 1914 | .mode_off[0] = IOMUXC_GPR12, |
| @@ -1873,6 +1928,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 13 unmodified lines | |||
| 1873 | .mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, | 1928 | .mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, |
| 1874 | .init_phy = imx8mq_pcie_init_phy, | 1929 | .init_phy = imx8mq_pcie_init_phy, |
| 1875 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, | 1930 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, |
| 1931 | .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, | ||
| 1876 | }, | 1932 | }, |
| 1877 | [IMX8MM] = { | 1933 | [IMX8MM] = { |
| 1878 | .variant = IMX8MM, | 1934 | .variant = IMX8MM, |
| @@ -1883,6 +1939,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 4 unmodified lines | |||
| 1883 | .mode_off[0] = IOMUXC_GPR12, | 1939 | .mode_off[0] = IOMUXC_GPR12, |
| 1884 | .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, | 1940 | .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, |
| 1885 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, | 1941 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, |
| 1942 | .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, | ||
| 1886 | }, | 1943 | }, |
| 1887 | [IMX8MP] = { | 1944 | [IMX8MP] = { |
| 1888 | .variant = IMX8MP, | 1945 | .variant = IMX8MP, |
| @@ -1893,6 +1950,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 4 unmodified lines | |||
| 1893 | .mode_off[0] = IOMUXC_GPR12, | 1950 | .mode_off[0] = IOMUXC_GPR12, |
| 1894 | .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, | 1951 | .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, |
| 1895 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, | 1952 | .enable_ref_clk = imx8mm_pcie_enable_ref_clk, |
| 1953 | .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, | ||
| 1896 | }, | 1954 | }, |
| 1897 | [IMX8Q] = { | 1955 | [IMX8Q] = { |
| 1898 | .variant = IMX8Q, | 1956 | .variant = IMX8Q, |
| @@ -1913,6 +1971,8 @@ static const struct imx_pcie_drvdata drvdata[] = { · 14 unmodified lines | |||
| 1913 | .core_reset = imx95_pcie_core_reset, | 1971 | .core_reset = imx95_pcie_core_reset, |
| 1914 | .init_phy = imx95_pcie_init_phy, | 1972 | .init_phy = imx95_pcie_init_phy, |
| 1915 | .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, | 1973 | .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, |
| 1974 | .enable_ref_clk = imx95_pcie_enable_ref_clk, | ||
| 1975 | .clr_clkreq_override = imx95_pcie_clr_clkreq_override, | ||
| 1916 | }, | 1976 | }, |
| 1917 | [IMX8MQ_EP] = { | 1977 | [IMX8MQ_EP] = { |
| 1918 | .variant = IMX8MQ_EP, | 1978 | .variant = IMX8MQ_EP, |
| @@ -1969,6 +2029,7 @@ static const struct imx_pcie_drvdata drvdata[] = { · 50 unmodified lines | |||
| 1969 | .core_reset = imx95_pcie_core_reset, | 2029 | .core_reset = imx95_pcie_core_reset, |
| 1970 | .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, | 2030 | .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, |
| 1971 | .epc_features = &imx95_pcie_epc_features, | 2031 | .epc_features = &imx95_pcie_epc_features, |
| 2032 | .enable_ref_clk = imx95_pcie_enable_ref_clk, | ||
| 1972 | .mode = DW_PCIE_EP_TYPE, | 2033 | .mode = DW_PCIE_EP_TYPE, |
| 1973 | }, | 2034 | }, |
| 1974 | }; | 2035 | }; |
| @@ -930,6 +930,7 @@ static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 929 unmodified lines | |||
| 930 | } | 930 | } |
| 931 | 931 | ||
| 932 | static const struct pci_epc_features ks_pcie_am654_epc_features = { | 932 | static const struct pci_epc_features ks_pcie_am654_epc_features = { |
| 933 | DWC_EPC_COMMON_FEATURES, | ||
| 933 | .msi_capable = true, | 934 | .msi_capable = true, |
| 934 | .msix_capable = true, | 935 | .msix_capable = true, |
| 935 | .bar[BAR_0] = { .type = BAR_RESERVED, }, | 936 | .bar[BAR_0] = { .type = BAR_RESERVED, }, |
| @@ -370,6 +370,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 369 unmodified lines | |||
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static const struct pci_epc_features artpec6_pcie_epc_features = { | 372 | static const struct pci_epc_features artpec6_pcie_epc_features = { |
| 373 | DWC_EPC_COMMON_FEATURES, | ||
| 373 | .msi_capable = true, | 374 | .msi_capable = true, |
| 374 | }; | 375 | }; |
| 375 | 376 | ||
| @@ -443,63 +443,13 @@ static ssize_t counter_value_read(struct file *file, char __user *buf, · 442 unmodified lines | |||
| 443 | return simple_read_from_buffer(buf, count, ppos, debugfs_buf, pos); | 443 | return simple_read_from_buffer(buf, count, ppos, debugfs_buf, pos); |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static const char *ltssm_status_string(enum dw_pcie_ltssm ltssm) | ||
| 447 | { | ||
| 448 | const char *str; | ||
| 449 | |||
| 450 | switch (ltssm) { | ||
| 451 | #define DW_PCIE_LTSSM_NAME(n) case n: str = #n; break | ||
| 452 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_QUIET); | ||
| 453 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_ACT); | ||
| 454 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_ACTIVE); | ||
| 455 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_COMPLIANCE); | ||
| 456 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_CONFIG); | ||
| 457 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_PRE_DETECT_QUIET); | ||
| 458 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_WAIT); | ||
| 459 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_START); | ||
| 460 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_ACEPT); | ||
| 461 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_WAI); | ||
| 462 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_ACEPT); | ||
| 463 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_COMPLETE); | ||
| 464 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_IDLE); | ||
| 465 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_LOCK); | ||
| 466 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_SPEED); | ||
| 467 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_RCVRCFG); | ||
| 468 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_IDLE); | ||
| 469 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0); | ||
| 470 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0S); | ||
| 471 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L123_SEND_EIDLE); | ||
| 472 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_IDLE); | ||
| 473 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_IDLE); | ||
| 474 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_WAKE); | ||
| 475 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_ENTRY); | ||
| 476 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_IDLE); | ||
| 477 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED); | ||
| 478 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ENTRY); | ||
| 479 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ACTIVE); | ||
| 480 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT); | ||
| 481 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT_TIMEOUT); | ||
| 482 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET_ENTRY); | ||
| 483 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET); | ||
| 484 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ0); | ||
| 485 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ1); | ||
| 486 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ2); | ||
| 487 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ3); | ||
| 488 | default: | ||
| 489 | str = "DW_PCIE_LTSSM_UNKNOWN"; | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | |||
| 493 | return str + strlen("DW_PCIE_LTSSM_"); | ||
| 494 | } | ||
| 495 | |||
| 496 | static int ltssm_status_show(struct seq_file *s, void *v) | 446 | static int ltssm_status_show(struct seq_file *s, void *v) |
| 497 | { | 447 | { |
| 498 | struct dw_pcie *pci = s->private; | 448 | struct dw_pcie *pci = s->private; |
| 499 | enum dw_pcie_ltssm val; | 449 | enum dw_pcie_ltssm val; |
| 500 | 450 | ||
| 501 | val = dw_pcie_get_ltssm(pci); | 451 | val = dw_pcie_get_ltssm(pci); |
| 502 | seq_printf(s, "%s (0x%02x)\n", ltssm_status_string(val), val); | 452 | seq_printf(s, "%s (0x%02x)\n", dw_pcie_ltssm_status_string(val), val); |
| 503 | 453 | ||
| 504 | return 0; | 454 | return 0; |
| 505 | } | 455 | } |
| @@ -72,47 +72,15 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar); · 71 unmodified lines | |||
| 72 | static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) | 72 | static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) |
| 73 | { | 73 | { |
| 74 | return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST, | 74 | return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST, |
| 75 | cap, ep, func_no); | 75 | cap, NULL, ep, func_no); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | /** | 78 | static u16 dw_pcie_ep_find_ext_capability(struct dw_pcie_ep *ep, |
| 79 | * dw_pcie_ep_hide_ext_capability - Hide a capability from the linked list | 79 | u8 func_no, u8 cap) |
| 80 | * @pci: DWC PCI device | ||
| 81 | * @prev_cap: Capability preceding the capability that should be hidden | ||
| 82 | * @cap: Capability that should be hidden | ||
| 83 | * | ||
| 84 | * Return: 0 if success, errno otherwise. | ||
| 85 | */ | ||
| 86 | int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap) | ||
| 87 | { | 80 | { |
| 88 | u16 prev_cap_offset, cap_offset; | 81 | return PCI_FIND_NEXT_EXT_CAP(dw_pcie_ep_read_cfg, 0, |
| 89 | u32 prev_cap_header, cap_header; | 82 | cap, NULL, ep, func_no); |
| 90 | |||
| 91 | prev_cap_offset = dw_pcie_find_ext_capability(pci, prev_cap); | ||
| 92 | if (!prev_cap_offset) | ||
| 93 | return -EINVAL; | ||
| 94 | |||
| 95 | prev_cap_header = dw_pcie_readl_dbi(pci, prev_cap_offset); | ||
| 96 | cap_offset = PCI_EXT_CAP_NEXT(prev_cap_header); | ||
| 97 | cap_header = dw_pcie_readl_dbi(pci, cap_offset); | ||
| 98 | |||
| 99 | /* cap must immediately follow prev_cap. */ | ||
| 100 | if (PCI_EXT_CAP_ID(cap_header) != cap) | ||
| 101 | return -EINVAL; | ||
| 102 | |||
| 103 | /* Clear next ptr. */ | ||
| 104 | prev_cap_header &= ~GENMASK(31, 20); | ||
| 105 | |||
| 106 | /* Set next ptr to next ptr of cap. */ | ||
| 107 | prev_cap_header |= cap_header & GENMASK(31, 20); | ||
| 108 | |||
| 109 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 110 | dw_pcie_writel_dbi(pci, prev_cap_offset, prev_cap_header); | ||
| 111 | dw_pcie_dbi_ro_wr_dis(pci); | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | 83 | } |
| 115 | EXPORT_SYMBOL_GPL(dw_pcie_ep_hide_ext_capability); | ||
| 116 | 84 | ||
| 117 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, | 85 | static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, |
| 118 | struct pci_epf_header *hdr) | 86 | struct pci_epf_header *hdr) |
| @@ -139,18 +107,23 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, · 20 unmodified lines | |||
| 139 | return 0; | 107 | return 0; |
| 140 | } | 108 | } |
| 141 | 109 | ||
| 142 | static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, | 110 | /* BAR Match Mode inbound iATU mapping */ |
| 143 | dma_addr_t parent_bus_addr, enum pci_barno bar, | 111 | static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type, |
| 144 | size_t size) | 112 | dma_addr_t parent_bus_addr, enum pci_barno bar, |
| 113 | size_t size) | ||
| 145 | { | 114 | { |
| 146 | int ret; | 115 | int ret; |
| 147 | u32 free_win; | 116 | u32 free_win; |
| 148 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 117 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
| 118 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); | ||
| 149 | 119 | ||
| 150 | if (!ep->bar_to_atu[bar]) | 120 | if (!ep_func) |
| 121 | return -EINVAL; | ||
| 122 | |||
| 123 | if (!ep_func->bar_to_atu[bar]) | ||
| 151 | free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows); | 124 | free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows); |
| 152 | else | 125 | else |
| 153 | free_win = ep->bar_to_atu[bar] - 1; | 126 | free_win = ep_func->bar_to_atu[bar] - 1; |
| 154 | 127 | ||
| 155 | if (free_win >= pci->num_ib_windows) { | 128 | if (free_win >= pci->num_ib_windows) { |
| 156 | dev_err(pci->dev, "No free inbound window\n"); | 129 | dev_err(pci->dev, "No free inbound window\n"); |
| @@ -168,12 +141,190 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, · 11 unmodified lines | |||
| 168 | * Always increment free_win before assignment, since value 0 is used to identify | 141 | * Always increment free_win before assignment, since value 0 is used to identify |
| 169 | * unallocated mapping. | 142 | * unallocated mapping. |
| 170 | */ | 143 | */ |
| 171 | ep->bar_to_atu[bar] = free_win + 1; | 144 | ep_func->bar_to_atu[bar] = free_win + 1; |
| 172 | set_bit(free_win, ep->ib_window_map); | 145 | set_bit(free_win, ep->ib_window_map); |
| 173 | 146 | ||
| 174 | return 0; | 147 | return 0; |
| 175 | } | 148 | } |
| 176 | 149 | ||
| 150 | static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, u8 func_no, enum pci_barno bar) | ||
| 151 | { | ||
| 152 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); | ||
| 153 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
| 154 | struct device *dev = pci->dev; | ||
| 155 | unsigned int i, num; | ||
| 156 | u32 atu_index; | ||
| 157 | u32 *indexes; | ||
| 158 | |||
| 159 | if (!ep_func) | ||
| 160 | return; | ||
| 161 | |||
| 162 | /* Tear down the BAR Match Mode mapping, if any. */ | ||
| 163 | if (ep_func->bar_to_atu[bar]) { | ||
| 164 | atu_index = ep_func->bar_to_atu[bar] - 1; | ||
| 165 | dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); | ||
| 166 | clear_bit(atu_index, ep->ib_window_map); | ||
| 167 | ep_func->bar_to_atu[bar] = 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | /* Tear down all Address Match Mode mappings, if any. */ | ||
| 171 | indexes = ep_func->ib_atu_indexes[bar]; | ||
| 172 | num = ep_func->num_ib_atu_indexes[bar]; | ||
| 173 | ep_func->ib_atu_indexes[bar] = NULL; | ||
| 174 | ep_func->num_ib_atu_indexes[bar] = 0; | ||
| 175 | if (!indexes) | ||
| 176 | return; | ||
| 177 | for (i = 0; i < num; i++) { | ||
| 178 | dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, indexes[i]); | ||
| 179 | clear_bit(indexes[i], ep->ib_window_map); | ||
| 180 | } | ||
| 181 | devm_kfree(dev, indexes); | ||
| 182 | } | ||
| 183 | |||
| 184 | static u64 dw_pcie_ep_read_bar_assigned(struct dw_pcie_ep *ep, u8 func_no, | ||
| 185 | enum pci_barno bar, int flags) | ||
| 186 | { | ||
| 187 | u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); | ||
| 188 | u32 lo, hi; | ||
| 189 | u64 addr; | ||
| 190 | |||
| 191 | lo = dw_pcie_ep_readl_dbi(ep, func_no, reg); | ||
| 192 | |||
| 193 | if (flags & PCI_BASE_ADDRESS_SPACE) | ||
| 194 | return lo & PCI_BASE_ADDRESS_IO_MASK; | ||
| 195 | |||
| 196 | addr = lo & PCI_BASE_ADDRESS_MEM_MASK; | ||
| 197 | if (!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) | ||
| 198 | return addr; | ||
| 199 | |||
| 200 | hi = dw_pcie_ep_readl_dbi(ep, func_no, reg + 4); | ||
| 201 | return addr | ((u64)hi << 32); | ||
| 202 | } | ||
| 203 | |||
| 204 | static int dw_pcie_ep_validate_submap(struct dw_pcie_ep *ep, | ||
| 205 | const struct pci_epf_bar_submap *submap, | ||
| 206 | unsigned int num_submap, size_t bar_size) | ||
| 207 | { | ||
| 208 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
| 209 | u32 align = pci->region_align; | ||
| 210 | size_t off = 0; | ||
| 211 | unsigned int i; | ||
| 212 | size_t size; | ||
| 213 | |||
| 214 | if (!align || !IS_ALIGNED(bar_size, align)) | ||
| 215 | return -EINVAL; | ||
| 216 | |||
| 217 | /* | ||
| 218 | * The submap array order defines the BAR layout (submap[0] starts | ||
| 219 | * at offset 0 and each entry immediately follows the previous | ||
| 220 | * one). Here, validate that it forms a strict, gapless | ||
| 221 | * decomposition of the BAR: | ||
| 222 | * - each entry has a non-zero size | ||
| 223 | * - sizes, implicit offsets and phys_addr are aligned to | ||
| 224 | * pci->region_align | ||
| 225 | * - each entry lies within the BAR range | ||
| 226 | * - the entries exactly cover the whole BAR | ||
| 227 | * | ||
| 228 | * Note: dw_pcie_prog_inbound_atu() also checks alignment for the | ||
| 229 | * PCI address and the target phys_addr, but validating up-front | ||
| 230 | * avoids partially programming iATU windows in vain. | ||
| 231 | */ | ||
| 232 | for (i = 0; i < num_submap; i++) { | ||
| 233 | size = submap[i].size; | ||
| 234 | |||
| 235 | if (!size) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | if (!IS_ALIGNED(size, align) || !IS_ALIGNED(off, align)) | ||
| 239 | return -EINVAL; | ||
| 240 | |||
| 241 | if (!IS_ALIGNED(submap[i].phys_addr, align)) | ||
| 242 | return -EINVAL; | ||
| 243 | |||
| 244 | if (off > bar_size || size > bar_size - off) | ||
| 245 | return -EINVAL; | ||
| 246 | |||
| 247 | off += size; | ||
| 248 | } | ||
| 249 | if (off != bar_size) | ||
| 250 | return -EINVAL; | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | /* Address Match Mode inbound iATU mapping */ | ||
| 256 | static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type, | ||
| 257 | const struct pci_epf_bar *epf_bar) | ||
| 258 | { | ||
| 259 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); | ||
| 260 | const struct pci_epf_bar_submap *submap = epf_bar->submap; | ||
| 261 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | ||
| 262 | enum pci_barno bar = epf_bar->barno; | ||
| 263 | struct device *dev = pci->dev; | ||
| 264 | u64 pci_addr, parent_bus_addr; | ||
| 265 | u64 size, base, off = 0; | ||
| 266 | int free_win, ret; | ||
| 267 | unsigned int i; | ||
| 268 | u32 *indexes; | ||
| 269 | |||
| 270 | if (!ep_func || !epf_bar->num_submap || !submap || !epf_bar->size) | ||
| 271 | return -EINVAL; | ||
| 272 | |||
| 273 | ret = dw_pcie_ep_validate_submap(ep, submap, epf_bar->num_submap, | ||
| 274 | epf_bar->size); | ||
| 275 | if (ret) | ||
| 276 | return ret; | ||
| 277 | |||
| 278 | base = dw_pcie_ep_read_bar_assigned(ep, func_no, bar, epf_bar->flags); | ||
| 279 | if (!base) { | ||
| 280 | dev_err(dev, | ||
| 281 | "BAR%u not assigned, cannot set up sub-range mappings\n", | ||
| 282 | bar); | ||
| 283 | return -EINVAL; | ||
| 284 | } | ||
| 285 | |||
| 286 | indexes = devm_kcalloc(dev, epf_bar->num_submap, sizeof(*indexes), | ||
| 287 | GFP_KERNEL); | ||
| 288 | if (!indexes) | ||
| 289 | return -ENOMEM; | ||
| 290 | |||
| 291 | ep_func->ib_atu_indexes[bar] = indexes; | ||
| 292 | ep_func->num_ib_atu_indexes[bar] = 0; | ||
| 293 | |||
| 294 | for (i = 0; i < epf_bar->num_submap; i++) { | ||
| 295 | size = submap[i].size; | ||
| 296 | parent_bus_addr = submap[i].phys_addr; | ||
| 297 | |||
| 298 | if (off > (~0ULL) - base) { | ||
| 299 | ret = -EINVAL; | ||
| 300 | goto err; | ||
| 301 | } | ||
| 302 | |||
| 303 | pci_addr = base + off; | ||
| 304 | off += size; | ||
| 305 | |||
| 306 | free_win = find_first_zero_bit(ep->ib_window_map, | ||
| 307 | pci->num_ib_windows); | ||
| 308 | if (free_win >= pci->num_ib_windows) { | ||
| 309 | ret = -ENOSPC; | ||
| 310 | goto err; | ||
| 311 | } | ||
| 312 | |||
| 313 | ret = dw_pcie_prog_inbound_atu(pci, free_win, type, | ||
| 314 | parent_bus_addr, pci_addr, size); | ||
| 315 | if (ret) | ||
| 316 | goto err; | ||
| 317 | |||
| 318 | set_bit(free_win, ep->ib_window_map); | ||
| 319 | indexes[i] = free_win; | ||
| 320 | ep_func->num_ib_atu_indexes[bar] = i + 1; | ||
| 321 | } | ||
| 322 | return 0; | ||
| 323 | err: | ||
| 324 | dw_pcie_ep_clear_ib_maps(ep, func_no, bar); | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | |||
| 177 | static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, | 328 | static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, |
| 178 | struct dw_pcie_ob_atu_cfg *atu) | 329 | struct dw_pcie_ob_atu_cfg *atu) |
| 179 | { | 330 | { |
| @@ -204,35 +355,34 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, · 24 unmodified lines | |||
| 204 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 355 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
| 205 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 356 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
| 206 | enum pci_barno bar = epf_bar->barno; | 357 | enum pci_barno bar = epf_bar->barno; |
| 207 | u32 atu_index = ep->bar_to_atu[bar] - 1; | 358 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); |
| 208 | 359 | ||
| 209 | if (!ep->bar_to_atu[bar]) | 360 | if (!ep_func || !ep_func->epf_bar[bar]) |
| 210 | return; | 361 | return; |
| 211 | 362 | ||
| 212 | __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); | 363 | __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); |
| 213 | 364 | ||
| 214 | dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); | 365 | dw_pcie_ep_clear_ib_maps(ep, func_no, bar); |
| 215 | clear_bit(atu_index, ep->ib_window_map); | 366 | |
| 216 | ep->epf_bar[bar] = NULL; | 367 | ep_func->epf_bar[bar] = NULL; |
| 217 | ep->bar_to_atu[bar] = 0; | ||
| 218 | } | 368 | } |
| 219 | 369 | ||
| 220 | static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci, | 370 | static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie_ep *ep, u8 func_no, |
| 221 | enum pci_barno bar) | 371 | enum pci_barno bar) |
| 222 | { | 372 | { |
| 223 | u32 reg, bar_index; | 373 | u32 reg, bar_index; |
| 224 | unsigned int offset, nbars; | 374 | unsigned int offset, nbars; |
| 225 | int i; | 375 | int i; |
| 226 | 376 | ||
| 227 | offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); | 377 | offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR); |
| 228 | if (!offset) | 378 | if (!offset) |
| 229 | return offset; | 379 | return offset; |
| 230 | 380 | ||
| 231 | reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); | 381 | reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); |
| 232 | nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); | 382 | nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); |
| 233 | 383 | ||
| 234 | for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) { | 384 | for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) { |
| 235 | reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); | 385 | reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); |
| 236 | bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg); | 386 | bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg); |
| 237 | if (bar_index == bar) | 387 | if (bar_index == bar) |
| 238 | return offset; | 388 | return offset; |
| @@ -253,7 +403,7 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no, · 14 unmodified lines | |||
| 253 | u32 rebar_cap, rebar_ctrl; | 403 | u32 rebar_cap, rebar_ctrl; |
| 254 | int ret; | 404 | int ret; |
| 255 | 405 | ||
| 256 | rebar_offset = dw_pcie_ep_get_rebar_offset(pci, bar); | 406 | rebar_offset = dw_pcie_ep_get_rebar_offset(ep, func_no, bar); |
| 257 | if (!rebar_offset) | 407 | if (!rebar_offset) |
| 258 | return -EINVAL; | 408 | return -EINVAL; |
| 259 | 409 | ||
| @@ -283,16 +433,16 @@ static int dw_pcie_ep_set_bar_resizable(struct dw_pcie_ep *ep, u8 func_no, · 23 unmodified lines | |||
| 283 | * 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes" | 433 | * 1 MB to 128 TB. Bits 31:16 in PCI_REBAR_CTRL define "supported sizes" |
| 284 | * bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB. | 434 | * bits for sizes 256 TB to 8 EB. Disallow sizes 256 TB to 8 EB. |
| 285 | */ | 435 | */ |
| 286 | rebar_ctrl = dw_pcie_readl_dbi(pci, rebar_offset + PCI_REBAR_CTRL); | 436 | rebar_ctrl = dw_pcie_ep_readl_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL); |
| 287 | rebar_ctrl &= ~GENMASK(31, 16); | 437 | rebar_ctrl &= ~GENMASK(31, 16); |
| 288 | dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl); | 438 | dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CTRL, rebar_ctrl); |
| 289 | 439 | ||
| 290 | /* | 440 | /* |
| 291 | * The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically | 441 | * The "selected size" (bits 13:8) in PCI_REBAR_CTRL are automatically |
| 292 | * updated when writing PCI_REBAR_CAP, see "Figure 3-26 Resizable BAR | 442 | * updated when writing PCI_REBAR_CAP, see "Figure 3-26 Resizable BAR |
| 293 | * Example for 32-bit Memory BAR0" in DWC EP databook 5.96a. | 443 | * Example for 32-bit Memory BAR0" in DWC EP databook 5.96a. |
| 294 | */ | 444 | */ |
| 295 | dw_pcie_writel_dbi(pci, rebar_offset + PCI_REBAR_CAP, rebar_cap); | 445 | dw_pcie_ep_writel_dbi(ep, func_no, rebar_offset + PCI_REBAR_CAP, rebar_cap); |
| 296 | 446 | ||
| 297 | dw_pcie_dbi_ro_wr_dis(pci); | 447 | dw_pcie_dbi_ro_wr_dis(pci); |
| 298 | 448 | ||
| @@ -341,12 +491,16 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, · 42 unmodified lines | |||
| 341 | { | 491 | { |
| 342 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 492 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
| 343 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 493 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
| 494 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); | ||
| 344 | enum pci_barno bar = epf_bar->barno; | 495 | enum pci_barno bar = epf_bar->barno; |
| 345 | size_t size = epf_bar->size; | 496 | size_t size = epf_bar->size; |
| 346 | enum pci_epc_bar_type bar_type; | 497 | enum pci_epc_bar_type bar_type; |
| 347 | int flags = epf_bar->flags; | 498 | int flags = epf_bar->flags; |
| 348 | int ret, type; | 499 | int ret, type; |
| 349 | 500 | ||
| 501 | if (!ep_func) | ||
| 502 | return -EINVAL; | ||
| 503 | |||
| 350 | /* | 504 | /* |
| 351 | * DWC does not allow BAR pairs to overlap, e.g. you cannot combine BARs | 505 | * DWC does not allow BAR pairs to overlap, e.g. you cannot combine BARs |
| 352 | * 1 and 2 to form a 64-bit BAR. | 506 | * 1 and 2 to form a 64-bit BAR. |
| @@ -360,21 +514,38 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, · 7 unmodified lines | |||
| 360 | * calling clear_bar() would clear the BAR's PCI address assigned by the | 514 | * calling clear_bar() would clear the BAR's PCI address assigned by the |
| 361 | * host). | 515 | * host). |
| 362 | */ | 516 | */ |
| 363 | if (ep->epf_bar[bar]) { | 517 | if (ep_func->epf_bar[bar]) { |
| 364 | /* | 518 | /* |
| 365 | * We can only dynamically change a BAR if the new BAR size and | 519 | * We can only dynamically change a BAR if the new BAR size and |
| 366 | * BAR flags do not differ from the existing configuration. | 520 | * BAR flags do not differ from the existing configuration. |
| 367 | */ | 521 | */ |
| 368 | if (ep->epf_bar[bar]->barno != bar || | 522 | if (ep_func->epf_bar[bar]->barno != bar || |
| 369 | ep->epf_bar[bar]->size != size || | 523 | ep_func->epf_bar[bar]->size != size || |
| 370 | ep->epf_bar[bar]->flags != flags) | 524 | ep_func->epf_bar[bar]->flags != flags) |
| 371 | return -EINVAL; | 525 | return -EINVAL; |
| 372 | 526 | ||
| 527 | /* | ||
| 528 | * When dynamically changing a BAR, tear down any existing | ||
| 529 | * mappings before re-programming. | ||
| 530 | */ | ||
| 531 | if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap) | ||
| 532 | dw_pcie_ep_clear_ib_maps(ep, func_no, bar); | ||
| 533 | |||
| 373 | /* | 534 | /* |
| 374 | * When dynamically changing a BAR, skip writing the BAR reg, as | 535 | * When dynamically changing a BAR, skip writing the BAR reg, as |
| 375 | * that would clear the BAR's PCI address assigned by the host. | 536 | * that would clear the BAR's PCI address assigned by the host. |
| 376 | */ | 537 | */ |
| 377 | goto config_atu; | 538 | goto config_atu; |
| 539 | } else { | ||
| 540 | /* | ||
| 541 | * Subrange mapping is an update-only operation. The BAR | ||
| 542 | * must have been configured once without submaps so that | ||
| 543 | * subsequent set_bar() calls can update inbound mappings | ||
| 544 | * without touching the BAR register (and clobbering the | ||
| 545 | * host-assigned address). | ||
| 546 | */ | ||
| 547 | if (epf_bar->num_submap) | ||
| 548 | return -EINVAL; | ||
| 378 | } | 549 | } |
| 379 | 550 | ||
| 380 | bar_type = dw_pcie_ep_get_bar_type(ep, bar); | 551 | bar_type = dw_pcie_ep_get_bar_type(ep, bar); |
| @@ -408,12 +579,16 @@ config_atu: · 27 unmodified lines | |||
| 408 | else | 579 | else |
| 409 | type = PCIE_ATU_TYPE_IO; | 580 | type = PCIE_ATU_TYPE_IO; |
| 410 | 581 | ||
| 411 | ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar, | 582 | if (epf_bar->num_submap) |
| 412 | size); | 583 | ret = dw_pcie_ep_ib_atu_addr(ep, func_no, type, epf_bar); |
| 584 | else | ||
| 585 | ret = dw_pcie_ep_ib_atu_bar(ep, func_no, type, | ||
| 586 | epf_bar->phys_addr, bar, size); | ||
| 587 | |||
| 413 | if (ret) | 588 | if (ret) |
| 414 | return ret; | 589 | return ret; |
| 415 | 590 | ||
| 416 | ep->epf_bar[bar] = epf_bar; | 591 | ep_func->epf_bar[bar] = epf_bar; |
| 417 | 592 | ||
| 418 | return 0; | 593 | return 0; |
| 419 | } | 594 | } |
| @@ -601,6 +776,16 @@ static void dw_pcie_ep_stop(struct pci_epc *epc) · 181 unmodified lines | |||
| 601 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); | 776 | struct dw_pcie_ep *ep = epc_get_drvdata(epc); |
| 602 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); | 777 | struct dw_pcie *pci = to_dw_pcie_from_ep(ep); |
| 603 | 778 | ||
| 779 | /* | ||
| 780 | * Tear down the dedicated outbound window used for MSI | ||
| 781 | * generation. This avoids leaking an iATU window across | ||
| 782 | * endpoint stop/start cycles. | ||
| 783 | */ | ||
| 784 | if (ep->msi_iatu_mapped) { | ||
| 785 | dw_pcie_ep_unmap_addr(epc, 0, 0, ep->msi_mem_phys); | ||
| 786 | ep->msi_iatu_mapped = false; | ||
| 787 | } | ||
| 788 | |||
| 604 | dw_pcie_stop_link(pci); | 789 | dw_pcie_stop_link(pci); |
| 605 | } | 790 | } |
| 606 | 791 | ||
| @@ -702,14 +887,37 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, · 95 unmodified lines | |||
| 702 | msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr_lower; | 887 | msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr_lower; |
| 703 | 888 | ||
| 704 | msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); | 889 | msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); |
| 705 | ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, | ||
| 706 | map_size); | ||
| 707 | if (ret) | ||
| 708 | return ret; | ||
| 709 | 890 | ||
| 710 | writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset); | 891 | /* |
| 892 | * Program the outbound iATU once and keep it enabled. | ||
| 893 | * | ||
| 894 | * The spec warns that updating iATU registers while there are | ||
| 895 | * operations in flight on the AXI bridge interface is not | ||
| 896 | * supported, so we avoid reprogramming the region on every MSI, | ||
| 897 | * specifically unmapping immediately after writel(). | ||
| 898 | */ | ||
| 899 | if (!ep->msi_iatu_mapped) { | ||
| 900 | ret = dw_pcie_ep_map_addr(epc, func_no, 0, | ||
| 901 | ep->msi_mem_phys, msg_addr, | ||
| 902 | map_size); | ||
| 903 | if (ret) | ||
| 904 | return ret; | ||
| 905 | |||
| 906 | ep->msi_iatu_mapped = true; | ||
| 907 | ep->msi_msg_addr = msg_addr; | ||
| 908 | ep->msi_map_size = map_size; | ||
| 909 | } else if (WARN_ON_ONCE(ep->msi_msg_addr != msg_addr || | ||
| 910 | ep->msi_map_size != map_size)) { | ||
| 911 | /* | ||
| 912 | * The host changed the MSI target address or the required | ||
| 913 | * mapping size changed. Reprogramming the iATU at runtime is | ||
| 914 | * unsafe on this controller, so bail out instead of trying to | ||
| 915 | * update the existing region. | ||
| 916 | */ | ||
| 917 | return -EINVAL; | ||
| 918 | } | ||
| 711 | 919 | ||
| 712 | dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); | 920 | writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset); |
| 713 | 921 | ||
| 714 | return 0; | 922 | return 0; |
| 715 | } | 923 | } |
| @@ -775,7 +983,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, · 59 unmodified lines | |||
| 775 | bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset); | 983 | bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset); |
| 776 | tbl_offset &= PCI_MSIX_TABLE_OFFSET; | 984 | tbl_offset &= PCI_MSIX_TABLE_OFFSET; |
| 777 | 985 | ||
| 778 | msix_tbl = ep->epf_bar[bir]->addr + tbl_offset; | 986 | msix_tbl = ep_func->epf_bar[bir]->addr + tbl_offset; |
| 779 | msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; | 987 | msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; |
| 780 | msg_data = msix_tbl[(interrupt_num - 1)].msg_data; | 988 | msg_data = msix_tbl[(interrupt_num - 1)].msg_data; |
| 781 | vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl; | 989 | vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl; |
| @@ -836,20 +1044,20 @@ void dw_pcie_ep_deinit(struct dw_pcie_ep *ep) · 54 unmodified lines | |||
| 836 | } | 1044 | } |
| 837 | EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); | 1045 | EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit); |
| 838 | 1046 | ||
| 839 | static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) | 1047 | static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no) |
| 840 | { | 1048 | { |
| 841 | struct dw_pcie_ep *ep = &pci->ep; | 1049 | struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); |
| 842 | unsigned int offset; | 1050 | unsigned int offset, nbars; |
| 843 | unsigned int nbars; | ||
| 844 | enum pci_barno bar; | 1051 | enum pci_barno bar; |
| 845 | u32 reg, i, val; | 1052 | u32 reg, i, val; |
| 846 | 1053 | ||
| 847 | offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); | 1054 | if (!ep_func) |
| 1055 | return; | ||
| 848 | 1056 | ||
| 849 | dw_pcie_dbi_ro_wr_en(pci); | 1057 | offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR); |
| 850 | 1058 | ||
| 851 | if (offset) { | 1059 | if (offset) { |
| 852 | reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); | 1060 | reg = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); |
| 853 | nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); | 1061 | nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); |
| 854 | 1062 | ||
| 855 | /* | 1063 | /* |
| @@ -870,16 +1078,28 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) · 14 unmodified lines | |||
| 870 | * the controller when RESBAR_CAP_REG is written, which | 1078 | * the controller when RESBAR_CAP_REG is written, which |
| 871 | * is why RESBAR_CAP_REG is written here. | 1079 | * is why RESBAR_CAP_REG is written here. |
| 872 | */ | 1080 | */ |
| 873 | val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); | 1081 | val = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL); |
| 874 | bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); | 1082 | bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); |
| 875 | if (ep->epf_bar[bar]) | 1083 | if (ep_func->epf_bar[bar]) |
| 876 | pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val); | 1084 | pci_epc_bar_size_to_rebar_cap(ep_func->epf_bar[bar]->size, &val); |
| 877 | else | 1085 | else |
| 878 | val = BIT(4); | 1086 | val = BIT(4); |
| 879 | 1087 | ||
| 880 | dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, val); | 1088 | dw_pcie_ep_writel_dbi(ep, func_no, offset + PCI_REBAR_CAP, val); |
| 881 | } | 1089 | } |
| 882 | } | 1090 | } |
| 1091 | } | ||
| 1092 | |||
| 1093 | static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) | ||
| 1094 | { | ||
| 1095 | struct dw_pcie_ep *ep = &pci->ep; | ||
| 1096 | u8 funcs = ep->epc->max_functions; | ||
| 1097 | u8 func_no; | ||
| 1098 | |||
| 1099 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 1100 | |||
| 1101 | for (func_no = 0; func_no < funcs; func_no++) | ||
| 1102 | dw_pcie_ep_init_rebar_registers(ep, func_no); | ||
| 883 | 1103 | ||
| 884 | dw_pcie_setup(pci); | 1104 | dw_pcie_setup(pci); |
| 885 | dw_pcie_dbi_ro_wr_dis(pci); | 1105 | dw_pcie_dbi_ro_wr_dis(pci); |
| @@ -967,6 +1187,18 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) · 81 unmodified lines | |||
| 967 | if (ep->ops->init) | 1187 | if (ep->ops->init) |
| 968 | ep->ops->init(ep); | 1188 | ep->ops->init(ep); |
| 969 | 1189 | ||
| 1190 | /* | ||
| 1191 | * PCIe r6.0, section 7.9.15 states that for endpoints that support | ||
| 1192 | * PTM, this capability structure is required in exactly one | ||
| 1193 | * function, which controls the PTM behavior of all PTM capable | ||
| 1194 | * functions. This indicates the PTM capability structure | ||
| 1195 | * represents controller-level registers rather than per-function | ||
| 1196 | * registers. | ||
| 1197 | * | ||
| 1198 | * Therefore, PTM capability registers are configured using the | ||
| 1199 | * standard DBI accessors, instead of func_no indexed per-function | ||
| 1200 | * accessors. | ||
| 1201 | */ | ||
| 970 | ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM); | 1202 | ptm_cap_base = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM); |
| 971 | 1203 | ||
| 972 | /* | 1204 | /* |
| @@ -1087,6 +1319,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) · 114 unmodified lines | |||
| 1087 | struct device *dev = pci->dev; | 1319 | struct device *dev = pci->dev; |
| 1088 | 1320 | ||
| 1089 | INIT_LIST_HEAD(&ep->func_list); | 1321 | INIT_LIST_HEAD(&ep->func_list); |
| 1322 | ep->msi_iatu_mapped = false; | ||
| 1323 | ep->msi_msg_addr = 0; | ||
| 1324 | ep->msi_map_size = 0; | ||
| 1090 | 1325 | ||
| 1091 | epc = devm_pci_epc_create(dev, &epc_ops); | 1326 | epc = devm_pci_epc_create(dev, &epc_ops); |
| 1092 | if (IS_ERR(epc)) { | 1327 | if (IS_ERR(epc)) { |
| @@ -244,7 +244,7 @@ void dw_pcie_msi_init(struct dw_pcie_rp *pp) · 243 unmodified lines | |||
| 244 | u64 msi_target = (u64)pp->msi_data; | 244 | u64 msi_target = (u64)pp->msi_data; |
| 245 | u32 ctrl, num_ctrls; | 245 | u32 ctrl, num_ctrls; |
| 246 | 246 | ||
| 247 | if (!pci_msi_enabled() || !pp->has_msi_ctrl) | 247 | if (!pci_msi_enabled() || !pp->use_imsi_rx) |
| 248 | return; | 248 | return; |
| 249 | 249 | ||
| 250 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; | 250 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; |
| @@ -356,10 +356,20 @@ int dw_pcie_msi_host_init(struct dw_pcie_rp *pp) · 105 unmodified lines | |||
| 356 | * order not to miss MSI TLPs from those devices the MSI target | 356 | * order not to miss MSI TLPs from those devices the MSI target |
| 357 | * address has to be within the lowest 4GB. | 357 | * address has to be within the lowest 4GB. |
| 358 | * | 358 | * |
| 359 | * Note until there is a better alternative found the reservation is | 359 | * Per DWC databook r6.21a, section 3.10.2.3, the incoming MWr TLP |
| 360 | * done by allocating from the artificially limited DMA-coherent | 360 | * targeting the MSI_CTRL_ADDR is terminated by the iMSI-RX and never |
| 361 | * memory. | 361 | * appears on the AXI bus. So MSI_CTRL_ADDR address doesn't need to be |
| 362 | * mapped and can be any memory that doesn't get allocated for the BAR | ||
| 363 | * memory. Since most of the platforms provide 32-bit address for | ||
| 364 | * 'config' region, try cfg0_base as the first option for the MSI target | ||
| 365 | * address if it's a 32-bit address. Otherwise, try 32-bit and 64-bit | ||
| 366 | * coherent memory allocation one by one. | ||
| 362 | */ | 367 | */ |
| 368 | if (!(pp->cfg0_base & GENMASK_ULL(63, 32))) { | ||
| 369 | pp->msi_data = pp->cfg0_base; | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 363 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | 373 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); |
| 364 | if (!ret) | 374 | if (!ret) |
| 365 | msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data, | 375 | msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data, |
| @@ -582,15 +592,15 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) · 216 unmodified lines | |||
| 582 | } | 592 | } |
| 583 | 593 | ||
| 584 | if (pci_msi_enabled()) { | 594 | if (pci_msi_enabled()) { |
| 585 | pp->has_msi_ctrl = !(pp->ops->msi_init || | 595 | pp->use_imsi_rx = !(pp->ops->msi_init || |
| 586 | of_property_present(np, "msi-parent") || | 596 | of_property_present(np, "msi-parent") || |
| 587 | of_property_present(np, "msi-map")); | 597 | of_property_present(np, "msi-map")); |
| 588 | 598 | ||
| 589 | /* | 599 | /* |
| 590 | * For the has_msi_ctrl case the default assignment is handled | 600 | * For the use_imsi_rx case the default assignment is handled |
| 591 | * in the dw_pcie_msi_host_init(). | 601 | * in the dw_pcie_msi_host_init(). |
| 592 | */ | 602 | */ |
| 593 | if (!pp->has_msi_ctrl && !pp->num_vectors) { | 603 | if (!pp->use_imsi_rx && !pp->num_vectors) { |
| 594 | pp->num_vectors = MSI_DEF_NUM_VECTORS; | 604 | pp->num_vectors = MSI_DEF_NUM_VECTORS; |
| 595 | } else if (pp->num_vectors > MAX_MSI_IRQS) { | 605 | } else if (pp->num_vectors > MAX_MSI_IRQS) { |
| 596 | dev_err(dev, "Invalid number of vectors\n"); | 606 | dev_err(dev, "Invalid number of vectors\n"); |
| @@ -602,7 +612,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) · 5 unmodified lines | |||
| 602 | ret = pp->ops->msi_init(pp); | 612 | ret = pp->ops->msi_init(pp); |
| 603 | if (ret < 0) | 613 | if (ret < 0) |
| 604 | goto err_deinit_host; | 614 | goto err_deinit_host; |
| 605 | } else if (pp->has_msi_ctrl) { | 615 | } else if (pp->use_imsi_rx) { |
| 606 | ret = dw_pcie_msi_host_init(pp); | 616 | ret = dw_pcie_msi_host_init(pp); |
| 607 | if (ret < 0) | 617 | if (ret < 0) |
| 608 | goto err_deinit_host; | 618 | goto err_deinit_host; |
| @@ -620,14 +630,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) · 11 unmodified lines | |||
| 620 | if (ret) | 630 | if (ret) |
| 621 | goto err_free_msi; | 631 | goto err_free_msi; |
| 622 | 632 | ||
| 623 | if (pp->ecam_enabled) { | ||
| 624 | ret = dw_pcie_config_ecam_iatu(pp); | ||
| 625 | if (ret) { | ||
| 626 | dev_err(dev, "Failed to configure iATU in ECAM mode\n"); | ||
| 627 | goto err_free_msi; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | |||
| 631 | /* | 633 | /* |
| 632 | * Allocate the resource for MSG TLP before programming the iATU | 634 | * Allocate the resource for MSG TLP before programming the iATU |
| 633 | * outbound window in dw_pcie_setup_rc(). Since the allocation depends | 635 | * outbound window in dw_pcie_setup_rc(). Since the allocation depends |
| @@ -655,13 +657,12 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) · 21 unmodified lines | |||
| 655 | } | 657 | } |
| 656 | 658 | ||
| 657 | /* | 659 | /* |
| 658 | * Note: Skip the link up delay only when a Link Up IRQ is present. | 660 | * Only fail on timeout error. Other errors indicate the device may |
| 659 | * If there is no Link Up IRQ, we should not bypass the delay | 661 | * become available later, so continue without failing. |
| 660 | * because that would require users to manually rescan for devices. | ||
| 661 | */ | 662 | */ |
| 662 | if (!pp->use_linkup_irq) | 663 | ret = dw_pcie_wait_for_link(pci); |
| 663 | /* Ignore errors, the link may come up later */ | 664 | if (ret == -ETIMEDOUT) |
| 664 | dw_pcie_wait_for_link(pci); | 665 | goto err_stop_link; |
| 665 | 666 | ||
| 666 | ret = pci_host_probe(bridge); | 667 | ret = pci_host_probe(bridge); |
| 667 | if (ret) | 668 | if (ret) |
| @@ -681,7 +682,7 @@ err_remove_edma: · 13 unmodified lines | |||
| 681 | dw_pcie_edma_remove(pci); | 682 | dw_pcie_edma_remove(pci); |
| 682 | 683 | ||
| 683 | err_free_msi: | 684 | err_free_msi: |
| 684 | if (pp->has_msi_ctrl) | 685 | if (pp->use_imsi_rx) |
| 685 | dw_pcie_free_msi(pp); | 686 | dw_pcie_free_msi(pp); |
| 686 | 687 | ||
| 687 | err_deinit_host: | 688 | err_deinit_host: |
| @@ -709,7 +710,7 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp) · 21 unmodified lines | |||
| 709 | 710 | ||
| 710 | dw_pcie_edma_remove(pci); | 711 | dw_pcie_edma_remove(pci); |
| 711 | 712 | ||
| 712 | if (pp->has_msi_ctrl) | 713 | if (pp->use_imsi_rx) |
| 713 | dw_pcie_free_msi(pp); | 714 | dw_pcie_free_msi(pp); |
| 714 | 715 | ||
| 715 | if (pp->ops->deinit) | 716 | if (pp->ops->deinit) |
| @@ -846,19 +847,10 @@ static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int · 130 unmodified lines | |||
| 846 | return pci->dbi_base + where; | 847 | return pci->dbi_base + where; |
| 847 | } | 848 | } |
| 848 | 849 | ||
| 849 | static int dw_pcie_op_assert_perst(struct pci_bus *bus, bool assert) | ||
| 850 | { | ||
| 851 | struct dw_pcie_rp *pp = bus->sysdata; | ||
| 852 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
| 853 | |||
| 854 | return dw_pcie_assert_perst(pci, assert); | ||
| 855 | } | ||
| 856 | |||
| 857 | static struct pci_ops dw_pcie_ops = { | 850 | static struct pci_ops dw_pcie_ops = { |
| 858 | .map_bus = dw_pcie_own_conf_map_bus, | 851 | .map_bus = dw_pcie_own_conf_map_bus, |
| 859 | .read = pci_generic_config_read, | 852 | .read = pci_generic_config_read, |
| 860 | .write = pci_generic_config_write, | 853 | .write = pci_generic_config_write, |
| 861 | .assert_perst = dw_pcie_op_assert_perst, | ||
| 862 | }; | 854 | }; |
| 863 | 855 | ||
| 864 | static struct pci_ops dw_pcie_ecam_ops = { | 856 | static struct pci_ops dw_pcie_ecam_ops = { |
| @@ -872,9 +864,10 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) · 7 unmodified lines | |||
| 872 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | 864 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
| 873 | struct dw_pcie_ob_atu_cfg atu = { 0 }; | 865 | struct dw_pcie_ob_atu_cfg atu = { 0 }; |
| 874 | struct resource_entry *entry; | 866 | struct resource_entry *entry; |
| 867 | int ob_iatu_index; | ||
| 868 | int ib_iatu_index; | ||
| 875 | int i, ret; | 869 | int i, ret; |
| 876 | 870 | ||
| 877 | /* Note the very first outbound ATU is used for CFG IOs */ | ||
| 878 | if (!pci->num_ob_windows) { | 871 | if (!pci->num_ob_windows) { |
| 879 | dev_err(pci->dev, "No outbound iATU found\n"); | 872 | dev_err(pci->dev, "No outbound iATU found\n"); |
| 880 | return -EINVAL; | 873 | return -EINVAL; |
| @@ -890,37 +883,74 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) · 9 unmodified lines | |||
| 890 | for (i = 0; i < pci->num_ib_windows; i++) | 883 | for (i = 0; i < pci->num_ib_windows; i++) |
| 891 | dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, i); | 884 | dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, i); |
| 892 | 885 | ||
| 893 | i = 0; | 886 | /* |
| 887 | * NOTE: For outbound address translation, outbound iATU at index 0 is | ||
| 888 | * reserved for CFG IOs (dw_pcie_other_conf_map_bus()), thus start at | ||
| 889 | * index 1. | ||
| 890 | * | ||
| 891 | * If using ECAM, outbound iATU at index 0 and index 1 is reserved for | ||
| 892 | * CFG IOs. | ||
| 893 | */ | ||
| 894 | if (pp->ecam_enabled) { | ||
| 895 | ob_iatu_index = 2; | ||
| 896 | ret = dw_pcie_config_ecam_iatu(pp); | ||
| 897 | if (ret) { | ||
| 898 | dev_err(pci->dev, "Failed to configure iATU in ECAM mode\n"); | ||
| 899 | return ret; | ||
| 900 | } | ||
| 901 | } else { | ||
| 902 | ob_iatu_index = 1; | ||
| 903 | } | ||
| 904 | |||
| 894 | resource_list_for_each_entry(entry, &pp->bridge->windows) { | 905 | resource_list_for_each_entry(entry, &pp->bridge->windows) { |
| 906 | resource_size_t res_size; | ||
| 907 | |||
| 895 | if (resource_type(entry->res) != IORESOURCE_MEM) | 908 | if (resource_type(entry->res) != IORESOURCE_MEM) |
| 896 | continue; | 909 | continue; |
| 897 | 910 | ||
| 898 | if (pci->num_ob_windows <= ++i) | ||
| 899 | break; | ||
| 900 | |||
| 901 | atu.index = i; | ||
| 902 | atu.type = PCIE_ATU_TYPE_MEM; | 911 | atu.type = PCIE_ATU_TYPE_MEM; |
| 903 | atu.parent_bus_addr = entry->res->start - pci->parent_bus_offset; | 912 | atu.parent_bus_addr = entry->res->start - pci->parent_bus_offset; |
| 904 | atu.pci_addr = entry->res->start - entry->offset; | 913 | atu.pci_addr = entry->res->start - entry->offset; |
| 905 | 914 | ||
| 906 | /* Adjust iATU size if MSG TLP region was allocated before */ | 915 | /* Adjust iATU size if MSG TLP region was allocated before */ |
| 907 | if (pp->msg_res && pp->msg_res->parent == entry->res) | 916 | if (pp->msg_res && pp->msg_res->parent == entry->res) |
| 908 | atu.size = resource_size(entry->res) - | 917 | res_size = resource_size(entry->res) - |
| 909 | resource_size(pp->msg_res); | 918 | resource_size(pp->msg_res); |
| 910 | else | 919 | else |
| 911 | atu.size = resource_size(entry->res); | 920 | res_size = resource_size(entry->res); |
| 921 | |||
| 922 | while (res_size > 0) { | ||
| 923 | /* | ||
| 924 | * Return failure if we run out of windows in the | ||
| 925 | * middle. Otherwise, we would end up only partially | ||
| 926 | * mapping a single resource. | ||
| 927 | */ | ||
| 928 | if (ob_iatu_index >= pci->num_ob_windows) { | ||
| 929 | dev_err(pci->dev, "Cannot add outbound window for region: %pr\n", | ||
| 930 | entry->res); | ||
| 931 | return -ENOMEM; | ||
| 932 | } | ||
| 912 | 933 | ||
| 913 | ret = dw_pcie_prog_outbound_atu(pci, &atu); | 934 | atu.index = ob_iatu_index; |
| 914 | if (ret) { | 935 | atu.size = MIN(pci->region_limit + 1, res_size); |
| 915 | dev_err(pci->dev, "Failed to set MEM range %pr\n", | 936 | |
| 916 | entry->res); | 937 | ret = dw_pcie_prog_outbound_atu(pci, &atu); |
| 917 | return ret; | 938 | if (ret) { |
| 939 | dev_err(pci->dev, "Failed to set MEM range %pr\n", | ||
| 940 | entry->res); | ||
| 941 | return ret; | ||
| 942 | } | ||
| 943 | |||
| 944 | ob_iatu_index++; | ||
| 945 | atu.parent_bus_addr += atu.size; | ||
| 946 | atu.pci_addr += atu.size; | ||
| 947 | res_size -= atu.size; | ||
| 918 | } | 948 | } |
| 919 | } | 949 | } |
| 920 | 950 | ||
| 921 | if (pp->io_size) { | 951 | if (pp->io_size) { |
| 922 | if (pci->num_ob_windows > ++i) { | 952 | if (ob_iatu_index < pci->num_ob_windows) { |
| 923 | atu.index = i; | 953 | atu.index = ob_iatu_index; |
| 924 | atu.type = PCIE_ATU_TYPE_IO; | 954 | atu.type = PCIE_ATU_TYPE_IO; |
| 925 | atu.parent_bus_addr = pp->io_base - pci->parent_bus_offset; | 955 | atu.parent_bus_addr = pp->io_base - pci->parent_bus_offset; |
| 926 | atu.pci_addr = pp->io_bus_addr; | 956 | atu.pci_addr = pp->io_bus_addr; |
| @@ -932,40 +962,71 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) · 5 unmodified lines | |||
| 932 | entry->res); | 962 | entry->res); |
| 933 | return ret; | 963 | return ret; |
| 934 | } | 964 | } |
| 965 | ob_iatu_index++; | ||
| 935 | } else { | 966 | } else { |
| 967 | /* | ||
| 968 | * If there are not enough outbound windows to give I/O | ||
| 969 | * space its own iATU, the outbound iATU at index 0 will | ||
| 970 | * be shared between I/O space and CFG IOs, by | ||
| 971 | * temporarily reconfiguring the iATU to CFG space, in | ||
| 972 | * order to do a CFG IO, and then immediately restoring | ||
| 973 | * it to I/O space. This is only implemented when using | ||
| 974 | * dw_pcie_other_conf_map_bus(), which is not the case | ||
| 975 | * when using ECAM. | ||
| 976 | */ | ||
| 977 | if (pp->ecam_enabled) { | ||
| 978 | dev_err(pci->dev, "Cannot add outbound window for I/O\n"); | ||
| 979 | return -ENOMEM; | ||
| 980 | } | ||
| 936 | pp->cfg0_io_shared = true; | 981 | pp->cfg0_io_shared = true; |
| 937 | } | 982 | } |
| 938 | } | 983 | } |
| 939 | 984 | ||
| 940 | if (pci->num_ob_windows <= i) | 985 | if (pp->use_atu_msg) { |
| 941 | dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n", | 986 | if (ob_iatu_index >= pci->num_ob_windows) { |
| 942 | pci->num_ob_windows); | 987 | dev_err(pci->dev, "Cannot add outbound window for MSG TLP\n"); |
| 943 | 988 | return -ENOMEM; | |
| 944 | pp->msg_atu_index = i; | 989 | } |
| 990 | pp->msg_atu_index = ob_iatu_index++; | ||
| 991 | } | ||
| 945 | 992 | ||
| 946 | i = 0; | 993 | ib_iatu_index = 0; |
| 947 | resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) { | 994 | resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) { |
| 995 | resource_size_t res_start, res_size, window_size; | ||
| 996 | |||
| 948 | if (resource_type(entry->res) != IORESOURCE_MEM) | 997 | if (resource_type(entry->res) != IORESOURCE_MEM) |
| 949 | continue; | 998 | continue; |
| 950 | 999 | ||
| 951 | if (pci->num_ib_windows <= i) | 1000 | res_size = resource_size(entry->res); |
| 952 | break; | 1001 | res_start = entry->res->start; |
| 1002 | while (res_size > 0) { | ||
| 1003 | /* | ||
| 1004 | * Return failure if we run out of windows in the | ||
| 1005 | * middle. Otherwise, we would end up only partially | ||
| 1006 | * mapping a single resource. | ||
| 1007 | */ | ||
| 1008 | if (ib_iatu_index >= pci->num_ib_windows) { | ||
| 1009 | dev_err(pci->dev, "Cannot add inbound window for region: %pr\n", | ||
| 1010 | entry->res); | ||
| 1011 | return -ENOMEM; | ||
| 1012 | } | ||
| 953 | 1013 | ||
| 954 | ret = dw_pcie_prog_inbound_atu(pci, i++, PCIE_ATU_TYPE_MEM, | 1014 | window_size = MIN(pci->region_limit + 1, res_size); |
| 955 | entry->res->start, | 1015 | ret = dw_pcie_prog_inbound_atu(pci, ib_iatu_index, |
| 956 | entry->res->start - entry->offset, | 1016 | PCIE_ATU_TYPE_MEM, res_start, |
| 957 | resource_size(entry->res)); | 1017 | res_start - entry->offset, window_size); |
| 958 | if (ret) { | 1018 | if (ret) { |
| 959 | dev_err(pci->dev, "Failed to set DMA range %pr\n", | 1019 | dev_err(pci->dev, "Failed to set DMA range %pr\n", |
| 960 | entry->res); | 1020 | entry->res); |
| 961 | return ret; | 1021 | return ret; |
| 1022 | } | ||
| 1023 | |||
| 1024 | ib_iatu_index++; | ||
| 1025 | res_start += window_size; | ||
| 1026 | res_size -= window_size; | ||
| 962 | } | 1027 | } |
| 963 | } | 1028 | } |
| 964 | 1029 | ||
| 965 | if (pci->num_ib_windows <= i) | ||
| 966 | dev_warn(pci->dev, "Dma-ranges exceed inbound iATU size (%u)\n", | ||
| 967 | pci->num_ib_windows); | ||
| 968 | |||
| 969 | return 0; | 1030 | return 0; |
| 970 | } | 1031 | } |
| 971 | 1032 | ||
| @@ -1087,7 +1148,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) · 115 unmodified lines | |||
| 1087 | * the platform uses its own address translation component rather than | 1148 | * the platform uses its own address translation component rather than |
| 1088 | * ATU, so we should not program the ATU here. | 1149 | * ATU, so we should not program the ATU here. |
| 1089 | */ | 1150 | */ |
| 1090 | if (pp->bridge->child_ops == &dw_child_pcie_ops) { | 1151 | if (pp->bridge->child_ops == &dw_child_pcie_ops || pp->ecam_enabled) { |
| 1091 | ret = dw_pcie_iatu_setup(pp); | 1152 | ret = dw_pcie_iatu_setup(pp); |
| 1092 | if (ret) | 1153 | if (ret) |
| 1093 | return ret; | 1154 | return ret; |
| @@ -1104,6 +1165,17 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) · 10 unmodified lines | |||
| 1104 | 1165 | ||
| 1105 | dw_pcie_dbi_ro_wr_dis(pci); | 1166 | dw_pcie_dbi_ro_wr_dis(pci); |
| 1106 | 1167 | ||
| 1168 | /* | ||
| 1169 | * The iMSI-RX module does not support receiving MSI or MSI-X generated | ||
| 1170 | * by the Root Port. If iMSI-RX is used as the MSI controller, remove | ||
| 1171 | * the MSI and MSI-X capabilities of the Root Port to allow the drivers | ||
| 1172 | * to fall back to INTx instead. | ||
| 1173 | */ | ||
| 1174 | if (pp->use_imsi_rx) { | ||
| 1175 | dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI); | ||
| 1176 | dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX); | ||
| 1177 | } | ||
| 1178 | |||
| 1107 | return 0; | 1179 | return 0; |
| 1108 | } | 1180 | } |
| 1109 | EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); | 1181 | EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); |
| @@ -1147,8 +1219,11 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci) · 37 unmodified lines | |||
| 1147 | int dw_pcie_suspend_noirq(struct dw_pcie *pci) | 1219 | int dw_pcie_suspend_noirq(struct dw_pcie *pci) |
| 1148 | { | 1220 | { |
| 1149 | u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); | 1221 | u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); |
| 1222 | int ret = 0; | ||
| 1150 | u32 val; | 1223 | u32 val; |
| 1151 | int ret; | 1224 | |
| 1225 | if (!dw_pcie_link_up(pci)) | ||
| 1226 | goto stop_link; | ||
| 1152 | 1227 | ||
| 1153 | /* | 1228 | /* |
| 1154 | * If L1SS is supported, then do not put the link into L2 as some | 1229 | * If L1SS is supported, then do not put the link into L2 as some |
| @@ -1165,6 +1240,16 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) · 10 unmodified lines | |||
| 1165 | return ret; | 1240 | return ret; |
| 1166 | } | 1241 | } |
| 1167 | 1242 | ||
| 1243 | /* | ||
| 1244 | * Some SoCs do not support reading the LTSSM register after | ||
| 1245 | * PME_Turn_Off broadcast. For those SoCs, skip waiting for L2/L3 Ready | ||
| 1246 | * state and wait 10ms as recommended in PCIe spec r6.0, sec 5.3.3.2.1. | ||
| 1247 | */ | ||
| 1248 | if (pci->pp.skip_l23_ready) { | ||
| 1249 | mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000); | ||
| 1250 | goto stop_link; | ||
| 1251 | } | ||
| 1252 | |||
| 1168 | ret = read_poll_timeout(dw_pcie_get_ltssm, val, | 1253 | ret = read_poll_timeout(dw_pcie_get_ltssm, val, |
| 1169 | val == DW_PCIE_LTSSM_L2_IDLE || | 1254 | val == DW_PCIE_LTSSM_L2_IDLE || |
| 1170 | val <= DW_PCIE_LTSSM_DETECT_WAIT, | 1255 | val <= DW_PCIE_LTSSM_DETECT_WAIT, |
| @@ -1183,6 +1268,7 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) · 12 unmodified lines | |||
| 1183 | */ | 1268 | */ |
| 1184 | udelay(1); | 1269 | udelay(1); |
| 1185 | 1270 | ||
| 1271 | stop_link: | ||
| 1186 | dw_pcie_stop_link(pci); | 1272 | dw_pcie_stop_link(pci); |
| 1187 | if (pci->pp.ops->deinit) | 1273 | if (pci->pp.ops->deinit) |
| 1188 | pci->pp.ops->deinit(&pci->pp); | 1274 | pci->pp.ops->deinit(&pci->pp); |
| @@ -1220,6 +1306,9 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) · 31 unmodified lines | |||
| 1220 | if (ret) | 1306 | if (ret) |
| 1221 | return ret; | 1307 | return ret; |
| 1222 | 1308 | ||
| 1309 | if (pci->pp.ops->post_init) | ||
| 1310 | pci->pp.ops->post_init(&pci->pp); | ||
| 1311 | |||
| 1223 | return ret; | 1312 | return ret; |
| 1224 | } | 1313 | } |
| 1225 | EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); | 1314 | EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); |
| @@ -61,6 +61,7 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 60 unmodified lines | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static const struct pci_epc_features dw_plat_pcie_epc_features = { | 63 | static const struct pci_epc_features dw_plat_pcie_epc_features = { |
| 64 | DWC_EPC_COMMON_FEATURES, | ||
| 64 | .msi_capable = true, | 65 | .msi_capable = true, |
| 65 | .msix_capable = true, | 66 | .msix_capable = true, |
| 66 | }; | 67 | }; |
| @@ -226,16 +226,70 @@ void dw_pcie_version_detect(struct dw_pcie *pci) · 225 unmodified lines | |||
| 226 | u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap) | 226 | u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap) |
| 227 | { | 227 | { |
| 228 | return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, | 228 | return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, |
| 229 | pci); | 229 | NULL, pci); |
| 230 | } | 230 | } |
| 231 | EXPORT_SYMBOL_GPL(dw_pcie_find_capability); | 231 | EXPORT_SYMBOL_GPL(dw_pcie_find_capability); |
| 232 | 232 | ||
| 233 | u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap) | 233 | u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap) |
| 234 | { | 234 | { |
| 235 | return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci); | 235 | return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci); |
| 236 | } | 236 | } |
| 237 | EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability); | 237 | EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability); |
| 238 | 238 | ||
| 239 | void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap) | ||
| 240 | { | ||
| 241 | u8 cap_pos, pre_pos, next_pos; | ||
| 242 | u16 reg; | ||
| 243 | |||
| 244 | cap_pos = PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap, | ||
| 245 | &pre_pos, pci); | ||
| 246 | if (!cap_pos) | ||
| 247 | return; | ||
| 248 | |||
| 249 | reg = dw_pcie_readw_dbi(pci, cap_pos); | ||
| 250 | next_pos = (reg & 0xff00) >> 8; | ||
| 251 | |||
| 252 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 253 | if (pre_pos == PCI_CAPABILITY_LIST) | ||
| 254 | dw_pcie_writeb_dbi(pci, PCI_CAPABILITY_LIST, next_pos); | ||
| 255 | else | ||
| 256 | dw_pcie_writeb_dbi(pci, pre_pos + 1, next_pos); | ||
| 257 | dw_pcie_dbi_ro_wr_dis(pci); | ||
| 258 | } | ||
| 259 | EXPORT_SYMBOL_GPL(dw_pcie_remove_capability); | ||
| 260 | |||
| 261 | void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap) | ||
| 262 | { | ||
| 263 | int cap_pos, next_pos, pre_pos; | ||
| 264 | u32 pre_header, header; | ||
| 265 | |||
| 266 | cap_pos = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, &pre_pos, pci); | ||
| 267 | if (!cap_pos) | ||
| 268 | return; | ||
| 269 | |||
| 270 | header = dw_pcie_readl_dbi(pci, cap_pos); | ||
| 271 | |||
| 272 | /* | ||
| 273 | * If the first cap at offset PCI_CFG_SPACE_SIZE is removed, | ||
| 274 | * only set its capid to zero as it cannot be skipped. | ||
| 275 | */ | ||
| 276 | if (cap_pos == PCI_CFG_SPACE_SIZE) { | ||
| 277 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 278 | dw_pcie_writel_dbi(pci, cap_pos, header & 0xffff0000); | ||
| 279 | dw_pcie_dbi_ro_wr_dis(pci); | ||
| 280 | return; | ||
| 281 | } | ||
| 282 | |||
| 283 | pre_header = dw_pcie_readl_dbi(pci, pre_pos); | ||
| 284 | next_pos = PCI_EXT_CAP_NEXT(header); | ||
| 285 | |||
| 286 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 287 | dw_pcie_writel_dbi(pci, pre_pos, | ||
| 288 | (pre_header & 0xfffff) | (next_pos << 20)); | ||
| 289 | dw_pcie_dbi_ro_wr_dis(pci); | ||
| 290 | } | ||
| 291 | EXPORT_SYMBOL_GPL(dw_pcie_remove_ext_capability); | ||
| 292 | |||
| 239 | static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, | 293 | static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, |
| 240 | u16 vsec_id) | 294 | u16 vsec_id) |
| 241 | { | 295 | { |
| @@ -246,7 +300,7 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id, · 4 unmodified lines | |||
| 246 | return 0; | 300 | return 0; |
| 247 | 301 | ||
| 248 | while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec, | 302 | while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec, |
| 249 | PCI_EXT_CAP_ID_VNDR, pci))) { | 303 | PCI_EXT_CAP_ID_VNDR, NULL, pci))) { |
| 250 | header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER); | 304 | header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER); |
| 251 | if (PCI_VNDR_HEADER_ID(header) == vsec_id) | 305 | if (PCI_VNDR_HEADER_ID(header) == vsec_id) |
| 252 | return vsec; | 306 | return vsec; |
| @@ -478,6 +532,9 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, · 225 unmodified lines | |||
| 478 | u32 retries, val; | 532 | u32 retries, val; |
| 479 | u64 limit_addr; | 533 | u64 limit_addr; |
| 480 | 534 | ||
| 535 | if (atu->index >= pci->num_ob_windows) | ||
| 536 | return -ENOSPC; | ||
| 537 | |||
| 481 | limit_addr = parent_bus_addr + atu->size - 1; | 538 | limit_addr = parent_bus_addr + atu->size - 1; |
| 482 | 539 | ||
| 483 | if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) || | 540 | if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) || |
| @@ -551,6 +608,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type, · 67 unmodified lines | |||
| 551 | u64 limit_addr = pci_addr + size - 1; | 608 | u64 limit_addr = pci_addr + size - 1; |
| 552 | u32 retries, val; | 609 | u32 retries, val; |
| 553 | 610 | ||
| 611 | if (index >= pci->num_ib_windows) | ||
| 612 | return -ENOSPC; | ||
| 613 | |||
| 554 | if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) || | 614 | if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) || |
| 555 | !IS_ALIGNED(parent_bus_addr, pci->region_align) || | 615 | !IS_ALIGNED(parent_bus_addr, pci->region_align) || |
| 556 | !IS_ALIGNED(pci_addr, pci->region_align) || !size) { | 616 | !IS_ALIGNED(pci_addr, pci->region_align) || !size) { |
| @@ -639,9 +699,69 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index) · 82 unmodified lines | |||
| 639 | dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0); | 699 | dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0); |
| 640 | } | 700 | } |
| 641 | 701 | ||
| 702 | const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm) | ||
| 703 | { | ||
| 704 | const char *str; | ||
| 705 | |||
| 706 | switch (ltssm) { | ||
| 707 | #define DW_PCIE_LTSSM_NAME(n) case n: str = #n; break | ||
| 708 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_QUIET); | ||
| 709 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_ACT); | ||
| 710 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_ACTIVE); | ||
| 711 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_COMPLIANCE); | ||
| 712 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_POLL_CONFIG); | ||
| 713 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_PRE_DETECT_QUIET); | ||
| 714 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DETECT_WAIT); | ||
| 715 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_START); | ||
| 716 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LINKWD_ACEPT); | ||
| 717 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_WAI); | ||
| 718 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_LANENUM_ACEPT); | ||
| 719 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_COMPLETE); | ||
| 720 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_CFG_IDLE); | ||
| 721 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_LOCK); | ||
| 722 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_SPEED); | ||
| 723 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_RCVRCFG); | ||
| 724 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_IDLE); | ||
| 725 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0); | ||
| 726 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L0S); | ||
| 727 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L123_SEND_EIDLE); | ||
| 728 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_IDLE); | ||
| 729 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_IDLE); | ||
| 730 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L2_WAKE); | ||
| 731 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_ENTRY); | ||
| 732 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED_IDLE); | ||
| 733 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_DISABLED); | ||
| 734 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ENTRY); | ||
| 735 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_ACTIVE); | ||
| 736 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT); | ||
| 737 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_LPBK_EXIT_TIMEOUT); | ||
| 738 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET_ENTRY); | ||
| 739 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_HOT_RESET); | ||
| 740 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ0); | ||
| 741 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ1); | ||
| 742 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ2); | ||
| 743 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_RCVRY_EQ3); | ||
| 744 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_1); | ||
| 745 | DW_PCIE_LTSSM_NAME(DW_PCIE_LTSSM_L1_2); | ||
| 746 | default: | ||
| 747 | str = "DW_PCIE_LTSSM_UNKNOWN"; | ||
| 748 | break; | ||
| 749 | } | ||
| 750 | |||
| 751 | return str + strlen("DW_PCIE_LTSSM_"); | ||
| 752 | } | ||
| 753 | |||
| 754 | /** | ||
| 755 | * dw_pcie_wait_for_link - Wait for the PCIe link to be up | ||
| 756 | * @pci: DWC instance | ||
| 757 | * | ||
| 758 | * Returns: 0 if link is up, -ENODEV if device is not found, -EIO if the device | ||
| 759 | * is found but not active and -ETIMEDOUT if the link fails to come up for other | ||
| 760 | * reasons. | ||
| 761 | */ | ||
| 642 | int dw_pcie_wait_for_link(struct dw_pcie *pci) | 762 | int dw_pcie_wait_for_link(struct dw_pcie *pci) |
| 643 | { | 763 | { |
| 644 | u32 offset, val; | 764 | u32 offset, val, ltssm; |
| 645 | int retries; | 765 | int retries; |
| 646 | 766 | ||
| 647 | /* Check if the link is up or not */ | 767 | /* Check if the link is up or not */ |
| @@ -653,7 +773,29 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci) · 5 unmodified lines | |||
| 653 | } | 773 | } |
| 654 | 774 | ||
| 655 | if (retries >= PCIE_LINK_WAIT_MAX_RETRIES) { | 775 | if (retries >= PCIE_LINK_WAIT_MAX_RETRIES) { |
| 656 | dev_info(pci->dev, "Phy link never came up\n"); | 776 | /* |
| 777 | * If the link is in Detect.Quiet or Detect.Active state, it | ||
| 778 | * indicates that no device is detected. | ||
| 779 | */ | ||
| 780 | ltssm = dw_pcie_get_ltssm(pci); | ||
| 781 | if (ltssm == DW_PCIE_LTSSM_DETECT_QUIET || | ||
| 782 | ltssm == DW_PCIE_LTSSM_DETECT_ACT) { | ||
| 783 | dev_info(pci->dev, "Device not found\n"); | ||
| 784 | return -ENODEV; | ||
| 785 | |||
| 786 | /* | ||
| 787 | * If the link is in POLL.{Active/Compliance} state, then the | ||
| 788 | * device is found to be connected to the bus, but it is not | ||
| 789 | * active i.e., the device firmware might not yet initialized. | ||
| 790 | */ | ||
| 791 | } else if (ltssm == DW_PCIE_LTSSM_POLL_ACTIVE || | ||
| 792 | ltssm == DW_PCIE_LTSSM_POLL_COMPLIANCE) { | ||
| 793 | dev_info(pci->dev, "Device found, but not active\n"); | ||
| 794 | return -EIO; | ||
| 795 | } | ||
| 796 | |||
| 797 | dev_err(pci->dev, "Link failed to come up. LTSSM: %s\n", | ||
| 798 | dw_pcie_ltssm_status_string(ltssm)); | ||
| 657 | return -ETIMEDOUT; | 799 | return -ETIMEDOUT; |
| 658 | } | 800 | } |
| 659 | 801 | ||
| @@ -305,6 +305,10 @@ · 304 unmodified lines | |||
| 305 | /* Default eDMA LLP memory size */ | 305 | /* Default eDMA LLP memory size */ |
| 306 | #define DMA_LLP_MEM_SIZE PAGE_SIZE | 306 | #define DMA_LLP_MEM_SIZE PAGE_SIZE |
| 307 | 307 | ||
| 308 | /* Common struct pci_epc_feature bits among DWC EP glue drivers */ | ||
| 309 | #define DWC_EPC_COMMON_FEATURES .dynamic_inbound_mapping = true, \ | ||
| 310 | .subrange_mapping = true | ||
| 311 | |||
| 308 | struct dw_pcie; | 312 | struct dw_pcie; |
| 309 | struct dw_pcie_rp; | 313 | struct dw_pcie_rp; |
| 310 | struct dw_pcie_ep; | 314 | struct dw_pcie_ep; |
| @@ -388,6 +392,10 @@ enum dw_pcie_ltssm { · 77 unmodified lines | |||
| 388 | DW_PCIE_LTSSM_RCVRY_EQ2 = 0x22, | 392 | DW_PCIE_LTSSM_RCVRY_EQ2 = 0x22, |
| 389 | DW_PCIE_LTSSM_RCVRY_EQ3 = 0x23, | 393 | DW_PCIE_LTSSM_RCVRY_EQ3 = 0x23, |
| 390 | 394 | ||
| 395 | /* Vendor glue drivers provide pseudo L1 substates from get_ltssm() */ | ||
| 396 | DW_PCIE_LTSSM_L1_1 = 0x141, | ||
| 397 | DW_PCIE_LTSSM_L1_2 = 0x142, | ||
| 398 | |||
| 391 | DW_PCIE_LTSSM_UNKNOWN = 0xFFFFFFFF, | 399 | DW_PCIE_LTSSM_UNKNOWN = 0xFFFFFFFF, |
| 392 | }; | 400 | }; |
| 393 | 401 | ||
| @@ -412,7 +420,7 @@ struct dw_pcie_host_ops { · 18 unmodified lines | |||
| 412 | }; | 420 | }; |
| 413 | 421 | ||
| 414 | struct dw_pcie_rp { | 422 | struct dw_pcie_rp { |
| 415 | bool has_msi_ctrl:1; | 423 | bool use_imsi_rx:1; |
| 416 | bool cfg0_io_shared:1; | 424 | bool cfg0_io_shared:1; |
| 417 | u64 cfg0_base; | 425 | u64 cfg0_base; |
| 418 | void __iomem *va_cfg0_base; | 426 | void __iomem *va_cfg0_base; |
| @@ -434,11 +442,11 @@ struct dw_pcie_rp { · 15 unmodified lines | |||
| 434 | bool use_atu_msg; | 442 | bool use_atu_msg; |
| 435 | int msg_atu_index; | 443 | int msg_atu_index; |
| 436 | struct resource *msg_res; | 444 | struct resource *msg_res; |
| 437 | bool use_linkup_irq; | ||
| 438 | struct pci_eq_presets presets; | 445 | struct pci_eq_presets presets; |
| 439 | struct pci_config_window *cfg; | 446 | struct pci_config_window *cfg; |
| 440 | bool ecam_enabled; | 447 | bool ecam_enabled; |
| 441 | bool native_ecam; | 448 | bool native_ecam; |
| 449 | bool skip_l23_ready; | ||
| 442 | }; | 450 | }; |
| 443 | 451 | ||
| 444 | struct dw_pcie_ep_ops { | 452 | struct dw_pcie_ep_ops { |
| @@ -463,6 +471,12 @@ struct dw_pcie_ep_func { · 18 unmodified lines | |||
| 463 | u8 func_no; | 471 | u8 func_no; |
| 464 | u8 msi_cap; /* MSI capability offset */ | 472 | u8 msi_cap; /* MSI capability offset */ |
| 465 | u8 msix_cap; /* MSI-X capability offset */ | 473 | u8 msix_cap; /* MSI-X capability offset */ |
| 474 | u8 bar_to_atu[PCI_STD_NUM_BARS]; | ||
| 475 | struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; | ||
| 476 | |||
| 477 | /* Only for Address Match Mode inbound iATU */ | ||
| 478 | u32 *ib_atu_indexes[PCI_STD_NUM_BARS]; | ||
| 479 | unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS]; | ||
| 466 | }; | 480 | }; |
| 467 | 481 | ||
| 468 | struct dw_pcie_ep { | 482 | struct dw_pcie_ep { |
| @@ -472,13 +486,16 @@ struct dw_pcie_ep { · 3 unmodified lines | |||
| 472 | phys_addr_t phys_base; | 486 | phys_addr_t phys_base; |
| 473 | size_t addr_size; | 487 | size_t addr_size; |
| 474 | size_t page_size; | 488 | size_t page_size; |
| 475 | u8 bar_to_atu[PCI_STD_NUM_BARS]; | ||
| 476 | phys_addr_t *outbound_addr; | 489 | phys_addr_t *outbound_addr; |
| 477 | unsigned long *ib_window_map; | 490 | unsigned long *ib_window_map; |
| 478 | unsigned long *ob_window_map; | 491 | unsigned long *ob_window_map; |
| 479 | void __iomem *msi_mem; | 492 | void __iomem *msi_mem; |
| 480 | phys_addr_t msi_mem_phys; | 493 | phys_addr_t msi_mem_phys; |
| 481 | struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; | 494 | |
| 495 | /* MSI outbound iATU state */ | ||
| 496 | bool msi_iatu_mapped; | ||
| 497 | u64 msi_msg_addr; | ||
| 498 | size_t msi_map_size; | ||
| 482 | }; | 499 | }; |
| 483 | 500 | ||
| 484 | struct dw_pcie_ops { | 501 | struct dw_pcie_ops { |
| @@ -493,7 +510,6 @@ struct dw_pcie_ops { · 8 unmodified lines | |||
| 493 | enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); | 510 | enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); |
| 494 | int (*start_link)(struct dw_pcie *pcie); | 511 | int (*start_link)(struct dw_pcie *pcie); |
| 495 | void (*stop_link)(struct dw_pcie *pcie); | 512 | void (*stop_link)(struct dw_pcie *pcie); |
| 496 | int (*assert_perst)(struct dw_pcie *pcie, bool assert); | ||
| 497 | }; | 513 | }; |
| 498 | 514 | ||
| 499 | struct debugfs_info { | 515 | struct debugfs_info { |
| @@ -562,6 +578,8 @@ void dw_pcie_version_detect(struct dw_pcie *pci); · 62 unmodified lines | |||
| 562 | 578 | ||
| 563 | u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap); | 579 | u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap); |
| 564 | u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap); | 580 | u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap); |
| 581 | void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap); | ||
| 582 | void dw_pcie_remove_ext_capability(struct dw_pcie *pci, u8 cap); | ||
| 565 | u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci); | 583 | u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci); |
| 566 | u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci); | 584 | u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci); |
| 567 | 585 | ||
| @@ -798,14 +816,6 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) · 230 unmodified lines | |||
| 798 | pci->ops->stop_link(pci); | 816 | pci->ops->stop_link(pci); |
| 799 | } | 817 | } |
| 800 | 818 | ||
| 801 | static inline int dw_pcie_assert_perst(struct dw_pcie *pci, bool assert) | ||
| 802 | { | ||
| 803 | if (pci->ops && pci->ops->assert_perst) | ||
| 804 | return pci->ops->assert_perst(pci, assert); | ||
| 805 | |||
| 806 | return 0; | ||
| 807 | } | ||
| 808 | |||
| 809 | static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) | 819 | static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) |
| 810 | { | 820 | { |
| 811 | u32 val; | 821 | u32 val; |
| @@ -818,6 +828,8 @@ static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) · 6 unmodified lines | |||
| 818 | return (enum dw_pcie_ltssm)FIELD_GET(PORT_LOGIC_LTSSM_STATE_MASK, val); | 828 | return (enum dw_pcie_ltssm)FIELD_GET(PORT_LOGIC_LTSSM_STATE_MASK, val); |
| 819 | } | 829 | } |
| 820 | 830 | ||
| 831 | const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm); | ||
| 832 | |||
| 821 | #ifdef CONFIG_PCIE_DW_HOST | 833 | #ifdef CONFIG_PCIE_DW_HOST |
| 822 | int dw_pcie_suspend_noirq(struct dw_pcie *pci); | 834 | int dw_pcie_suspend_noirq(struct dw_pcie *pci); |
| 823 | int dw_pcie_resume_noirq(struct dw_pcie *pci); | 835 | int dw_pcie_resume_noirq(struct dw_pcie *pci); |
| @@ -896,7 +908,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, · 72 unmodified lines | |||
| 896 | int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, | 908 | int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, |
| 897 | u16 interrupt_num); | 909 | u16 interrupt_num); |
| 898 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); | 910 | void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); |
| 899 | int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap); | ||
| 900 | struct dw_pcie_ep_func * | 911 | struct dw_pcie_ep_func * |
| 901 | dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no); | 912 | dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no); |
| 902 | #else | 913 | #else |
| @@ -954,12 +965,6 @@ static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) · 51 unmodified lines | |||
| 954 | { | 965 | { |
| 955 | } | 966 | } |
| 956 | 967 | ||
| 957 | static inline int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, | ||
| 958 | u8 prev_cap, u8 cap) | ||
| 959 | { | ||
| 960 | return 0; | ||
| 961 | } | ||
| 962 | |||
| 963 | static inline struct dw_pcie_ep_func * | 968 | static inline struct dw_pcie_ep_func * |
| 964 | dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) | 969 | dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) |
| 965 | { | 970 | { |
| @@ -68,6 +68,11 @@ · 67 unmodified lines | |||
| 68 | #define PCIE_CLKREQ_NOT_READY FIELD_PREP_WM16(BIT(0), 0) | 68 | #define PCIE_CLKREQ_NOT_READY FIELD_PREP_WM16(BIT(0), 0) |
| 69 | #define PCIE_CLKREQ_PULL_DOWN FIELD_PREP_WM16(GENMASK(13, 12), 1) | 69 | #define PCIE_CLKREQ_PULL_DOWN FIELD_PREP_WM16(GENMASK(13, 12), 1) |
| 70 | 70 | ||
| 71 | /* RASDES TBA information */ | ||
| 72 | #define PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN 0x154 | ||
| 73 | #define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4) | ||
| 74 | #define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5) | ||
| 75 | |||
| 71 | /* Hot Reset Control Register */ | 76 | /* Hot Reset Control Register */ |
| 72 | #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 | 77 | #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 |
| 73 | #define PCIE_LTSSM_APP_DLY2_EN BIT(1) | 78 | #define PCIE_LTSSM_APP_DLY2_EN BIT(1) |
| @@ -80,6 +85,8 @@ · 6 unmodified lines | |||
| 80 | #define PCIE_LINKUP_MASK GENMASK(17, 16) | 85 | #define PCIE_LINKUP_MASK GENMASK(17, 16) |
| 81 | #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) | 86 | #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) |
| 82 | 87 | ||
| 88 | #define PCIE_TYPE0_HDR_DBI2_OFFSET 0x100000 | ||
| 89 | |||
| 83 | struct rockchip_pcie { | 90 | struct rockchip_pcie { |
| 84 | struct dw_pcie pci; | 91 | struct dw_pcie pci; |
| 85 | void __iomem *apb_base; | 92 | void __iomem *apb_base; |
| @@ -181,11 +188,26 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) · 95 unmodified lines | |||
| 181 | return 0; | 188 | return 0; |
| 182 | } | 189 | } |
| 183 | 190 | ||
| 184 | static u32 rockchip_pcie_get_ltssm(struct rockchip_pcie *rockchip) | 191 | static u32 rockchip_pcie_get_ltssm_reg(struct rockchip_pcie *rockchip) |
| 185 | { | 192 | { |
| 186 | return rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS); | 193 | return rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS); |
| 187 | } | 194 | } |
| 188 | 195 | ||
| 196 | static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci) | ||
| 197 | { | ||
| 198 | struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); | ||
| 199 | u32 val = rockchip_pcie_readl_apb(rockchip, | ||
| 200 | PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN); | ||
| 201 | |||
| 202 | if (val & PCIE_CLIENT_CDM_RASDES_TBA_L1_1) | ||
| 203 | return DW_PCIE_LTSSM_L1_1; | ||
| 204 | |||
| 205 | if (val & PCIE_CLIENT_CDM_RASDES_TBA_L1_2) | ||
| 206 | return DW_PCIE_LTSSM_L1_2; | ||
| 207 | |||
| 208 | return rockchip_pcie_get_ltssm_reg(rockchip) & PCIE_LTSSM_STATUS_MASK; | ||
| 209 | } | ||
| 210 | |||
| 189 | static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) | 211 | static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) |
| 190 | { | 212 | { |
| 191 | rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, | 213 | rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, |
| @@ -201,7 +223,7 @@ static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip) · 9 unmodified lines | |||
| 201 | static bool rockchip_pcie_link_up(struct dw_pcie *pci) | 223 | static bool rockchip_pcie_link_up(struct dw_pcie *pci) |
| 202 | { | 224 | { |
| 203 | struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); | 225 | struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); |
| 204 | u32 val = rockchip_pcie_get_ltssm(rockchip); | 226 | u32 val = rockchip_pcie_get_ltssm_reg(rockchip); |
| 205 | 227 | ||
| 206 | return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP; | 228 | return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP; |
| 207 | } | 229 | } |
| @@ -292,6 +314,8 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp) · 84 unmodified lines | |||
| 292 | if (irq < 0) | 314 | if (irq < 0) |
| 293 | return irq; | 315 | return irq; |
| 294 | 316 | ||
| 317 | pci->dbi_base2 = pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET; | ||
| 318 | |||
| 295 | ret = rockchip_pcie_init_irq_domain(rockchip); | 319 | ret = rockchip_pcie_init_irq_domain(rockchip); |
| 296 | if (ret < 0) | 320 | if (ret < 0) |
| 297 | dev_err(dev, "failed to init irq domain\n"); | 321 | dev_err(dev, "failed to init irq domain\n"); |
| @@ -302,6 +326,10 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp) · 4 unmodified lines | |||
| 302 | rockchip_pcie_configure_l1ss(pci); | 326 | rockchip_pcie_configure_l1ss(pci); |
| 303 | rockchip_pcie_enable_l0s(pci); | 327 | rockchip_pcie_enable_l0s(pci); |
| 304 | 328 | ||
| 329 | /* Disable Root Ports BAR0 and BAR1 as they report bogus size */ | ||
| 330 | dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0); | ||
| 331 | dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0x0); | ||
| 332 | |||
| 305 | return 0; | 333 | return 0; |
| 306 | } | 334 | } |
| 307 | 335 | ||
| @@ -327,9 +355,7 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep) · 19 unmodified lines | |||
| 327 | if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep")) | 355 | if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep")) |
| 328 | return; | 356 | return; |
| 329 | 357 | ||
| 330 | if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI, | 358 | dw_pcie_remove_ext_capability(pci, PCI_EXT_CAP_ID_ATS); |
| 331 | PCI_EXT_CAP_ID_ATS)) | ||
| 332 | dev_err(dev, "failed to hide ATS capability\n"); | ||
| 333 | } | 359 | } |
| 334 | 360 | ||
| 335 | static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) | 361 | static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) |
| @@ -364,6 +390,7 @@ static int rockchip_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 28 unmodified lines | |||
| 364 | } | 390 | } |
| 365 | 391 | ||
| 366 | static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { | 392 | static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { |
| 393 | DWC_EPC_COMMON_FEATURES, | ||
| 367 | .linkup_notifier = true, | 394 | .linkup_notifier = true, |
| 368 | .msi_capable = true, | 395 | .msi_capable = true, |
| 369 | .msix_capable = true, | 396 | .msix_capable = true, |
| @@ -384,6 +411,7 @@ static const struct pci_epc_features rockchip_pcie_epc_features_rk3568 = { · 14 unmodified lines | |||
| 384 | * BARs) would be overwritten, resulting in (all other BARs) no longer working. | 411 | * BARs) would be overwritten, resulting in (all other BARs) no longer working. |
| 385 | */ | 412 | */ |
| 386 | static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = { | 413 | static const struct pci_epc_features rockchip_pcie_epc_features_rk3588 = { |
| 414 | DWC_EPC_COMMON_FEATURES, | ||
| 387 | .linkup_notifier = true, | 415 | .linkup_notifier = true, |
| 388 | .msi_capable = true, | 416 | .msi_capable = true, |
| 389 | .msix_capable = true, | 417 | .msix_capable = true, |
| @@ -485,36 +513,9 @@ static const struct dw_pcie_ops dw_pcie_ops = { · 95 unmodified lines | |||
| 485 | .link_up = rockchip_pcie_link_up, | 513 | .link_up = rockchip_pcie_link_up, |
| 486 | .start_link = rockchip_pcie_start_link, | 514 | .start_link = rockchip_pcie_start_link, |
| 487 | .stop_link = rockchip_pcie_stop_link, | 515 | .stop_link = rockchip_pcie_stop_link, |
| 516 | .get_ltssm = rockchip_pcie_get_ltssm, | ||
| 488 | }; | 517 | }; |
| 489 | 518 | ||
| 490 | static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) | ||
| 491 | { | ||
| 492 | struct rockchip_pcie *rockchip = arg; | ||
| 493 | struct dw_pcie *pci = &rockchip->pci; | ||
| 494 | struct dw_pcie_rp *pp = &pci->pp; | ||
| 495 | struct device *dev = pci->dev; | ||
| 496 | u32 reg; | ||
| 497 | |||
| 498 | reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); | ||
| 499 | rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); | ||
| 500 | |||
| 501 | dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg); | ||
| 502 | dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip)); | ||
| 503 | |||
| 504 | if (reg & PCIE_RDLH_LINK_UP_CHGED) { | ||
| 505 | if (rockchip_pcie_link_up(pci)) { | ||
| 506 | msleep(PCIE_RESET_CONFIG_WAIT_MS); | ||
| 507 | dev_dbg(dev, "Received Link up event. Starting enumeration!\n"); | ||
| 508 | /* Rescan the bus to enumerate endpoint devices */ | ||
| 509 | pci_lock_rescan_remove(); | ||
| 510 | pci_rescan_bus(pp->bridge->bus); | ||
| 511 | pci_unlock_rescan_remove(); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | return IRQ_HANDLED; | ||
| 516 | } | ||
| 517 | |||
| 518 | static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) | 519 | static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) |
| 519 | { | 520 | { |
| 520 | struct rockchip_pcie *rockchip = arg; | 521 | struct rockchip_pcie *rockchip = arg; |
| @@ -526,7 +527,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) · 5 unmodified lines | |||
| 526 | rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); | 527 | rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); |
| 527 | 528 | ||
| 528 | dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg); | 529 | dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg); |
| 529 | dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip)); | 530 | dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip)); |
| 530 | 531 | ||
| 531 | if (reg & PCIE_LINK_REQ_RST_NOT_INT) { | 532 | if (reg & PCIE_LINK_REQ_RST_NOT_INT) { |
| 532 | dev_dbg(dev, "hot reset or link-down reset\n"); | 533 | dev_dbg(dev, "hot reset or link-down reset\n"); |
| @@ -547,29 +548,14 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) · 14 unmodified lines | |||
| 547 | return IRQ_HANDLED; | 548 | return IRQ_HANDLED; |
| 548 | } | 549 | } |
| 549 | 550 | ||
| 550 | static int rockchip_pcie_configure_rc(struct platform_device *pdev, | 551 | static int rockchip_pcie_configure_rc(struct rockchip_pcie *rockchip) |
| 551 | struct rockchip_pcie *rockchip) | ||
| 552 | { | 552 | { |
| 553 | struct device *dev = &pdev->dev; | ||
| 554 | struct dw_pcie_rp *pp; | 553 | struct dw_pcie_rp *pp; |
| 555 | int irq, ret; | ||
| 556 | u32 val; | 554 | u32 val; |
| 557 | 555 | ||
| 558 | if (!IS_ENABLED(CONFIG_PCIE_ROCKCHIP_DW_HOST)) | 556 | if (!IS_ENABLED(CONFIG_PCIE_ROCKCHIP_DW_HOST)) |
| 559 | return -ENODEV; | 557 | return -ENODEV; |
| 560 | 558 | ||
| 561 | irq = platform_get_irq_byname(pdev, "sys"); | ||
| 562 | if (irq < 0) | ||
| 563 | return irq; | ||
| 564 | |||
| 565 | ret = devm_request_threaded_irq(dev, irq, NULL, | ||
| 566 | rockchip_pcie_rc_sys_irq_thread, | ||
| 567 | IRQF_ONESHOT, "pcie-sys-rc", rockchip); | ||
| 568 | if (ret) { | ||
| 569 | dev_err(dev, "failed to request PCIe sys IRQ\n"); | ||
| 570 | return ret; | ||
| 571 | } | ||
| 572 | |||
| 573 | /* LTSSM enable control mode */ | 559 | /* LTSSM enable control mode */ |
| 574 | val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1); | 560 | val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1); |
| 575 | rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); | 561 | rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); |
| @@ -580,19 +566,8 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev, · 4 unmodified lines | |||
| 580 | 566 | ||
| 581 | pp = &rockchip->pci.pp; | 567 | pp = &rockchip->pci.pp; |
| 582 | pp->ops = &rockchip_pcie_host_ops; | 568 | pp->ops = &rockchip_pcie_host_ops; |
| 583 | pp->use_linkup_irq = true; | ||
| 584 | |||
| 585 | ret = dw_pcie_host_init(pp); | ||
| 586 | if (ret) { | ||
| 587 | dev_err(dev, "failed to initialize host\n"); | ||
| 588 | return ret; | ||
| 589 | } | ||
| 590 | 569 | ||
| 591 | /* unmask DLL up/down indicator */ | 570 | return dw_pcie_host_init(pp); |
| 592 | val = FIELD_PREP_WM16(PCIE_RDLH_LINK_UP_CHGED, 0); | ||
| 593 | rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC); | ||
| 594 | |||
| 595 | return ret; | ||
| 596 | } | 571 | } |
| 597 | 572 | ||
| 598 | static int rockchip_pcie_configure_ep(struct platform_device *pdev, | 573 | static int rockchip_pcie_configure_ep(struct platform_device *pdev, |
| @@ -711,7 +686,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) · 112 unmodified lines | |||
| 711 | 686 | ||
| 712 | switch (data->mode) { | 687 | switch (data->mode) { |
| 713 | case DW_PCIE_RC_TYPE: | 688 | case DW_PCIE_RC_TYPE: |
| 714 | ret = rockchip_pcie_configure_rc(pdev, rockchip); | 689 | ret = rockchip_pcie_configure_rc(rockchip); |
| 715 | if (ret) | 690 | if (ret) |
| 716 | goto deinit_clk; | 691 | goto deinit_clk; |
| 717 | break; | 692 | break; |
| @@ -309,6 +309,7 @@ static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 308 unmodified lines | |||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | static const struct pci_epc_features keembay_pcie_epc_features = { | 311 | static const struct pci_epc_features keembay_pcie_epc_features = { |
| 312 | DWC_EPC_COMMON_FEATURES, | ||
| 312 | .msi_capable = true, | 313 | .msi_capable = true, |
| 313 | .msix_capable = true, | 314 | .msix_capable = true, |
| 314 | .bar[BAR_0] = { .only_64bit = true, }, | 315 | .bar[BAR_0] = { .only_64bit = true, }, |
| @@ -282,12 +282,12 @@ static int s32g_pcie_parse_ports(struct device *dev, struct s32g_pcie *s32g_pp) · 281 unmodified lines | |||
| 282 | 282 | ||
| 283 | ret = s32g_pcie_parse_port(s32g_pp, of_port); | 283 | ret = s32g_pcie_parse_port(s32g_pp, of_port); |
| 284 | if (ret) | 284 | if (ret) |
| 285 | goto err_port; | 285 | break; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | err_port: | 288 | if (ret) |
| 289 | list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) | 289 | list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) |
| 290 | list_del(&port->list); | 290 | list_del(&port->list); |
| 291 | 291 | ||
| 292 | return ret; | 292 | return ret; |
| 293 | } | 293 | } |
| @@ -168,11 +168,13 @@ enum qcom_pcie_ep_link_status { · 167 unmodified lines | |||
| 168 | * @hdma_support: HDMA support on this SoC | 168 | * @hdma_support: HDMA support on this SoC |
| 169 | * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache snooping | 169 | * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache snooping |
| 170 | * @disable_mhi_ram_parity_check: Disable MHI RAM data parity error check | 170 | * @disable_mhi_ram_parity_check: Disable MHI RAM data parity error check |
| 171 | * @firmware_managed: Set if the controller is firmware managed | ||
| 171 | */ | 172 | */ |
| 172 | struct qcom_pcie_ep_cfg { | 173 | struct qcom_pcie_ep_cfg { |
| 173 | bool hdma_support; | 174 | bool hdma_support; |
| 174 | bool override_no_snoop; | 175 | bool override_no_snoop; |
| 175 | bool disable_mhi_ram_parity_check; | 176 | bool disable_mhi_ram_parity_check; |
| 177 | bool firmware_managed; | ||
| 176 | }; | 178 | }; |
| 177 | 179 | ||
| 178 | /** | 180 | /** |
| @@ -377,6 +379,14 @@ err_disable_clk: · 198 unmodified lines | |||
| 377 | 379 | ||
| 378 | static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) | 380 | static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) |
| 379 | { | 381 | { |
| 382 | struct device *dev = pcie_ep->pci.dev; | ||
| 383 | |||
| 384 | pm_runtime_put(dev); | ||
| 385 | |||
| 386 | /* Skip resource disablement if controller is firmware-managed */ | ||
| 387 | if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) | ||
| 388 | return; | ||
| 389 | |||
| 380 | icc_set_bw(pcie_ep->icc_mem, 0, 0); | 390 | icc_set_bw(pcie_ep->icc_mem, 0, 0); |
| 381 | phy_power_off(pcie_ep->phy); | 391 | phy_power_off(pcie_ep->phy); |
| 382 | phy_exit(pcie_ep->phy); | 392 | phy_exit(pcie_ep->phy); |
| @@ -390,12 +400,24 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) · 7 unmodified lines | |||
| 390 | u32 val, offset; | 400 | u32 val, offset; |
| 391 | int ret; | 401 | int ret; |
| 392 | 402 | ||
| 403 | ret = pm_runtime_resume_and_get(dev); | ||
| 404 | if (ret < 0) { | ||
| 405 | dev_err(dev, "Failed to enable device: %d\n", ret); | ||
| 406 | return ret; | ||
| 407 | } | ||
| 408 | |||
| 409 | /* Skip resource enablement if controller is firmware-managed */ | ||
| 410 | if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) | ||
| 411 | goto skip_resources_enable; | ||
| 412 | |||
| 393 | ret = qcom_pcie_enable_resources(pcie_ep); | 413 | ret = qcom_pcie_enable_resources(pcie_ep); |
| 394 | if (ret) { | 414 | if (ret) { |
| 395 | dev_err(dev, "Failed to enable resources: %d\n", ret); | 415 | dev_err(dev, "Failed to enable resources: %d\n", ret); |
| 416 | pm_runtime_put(dev); | ||
| 396 | return ret; | 417 | return ret; |
| 397 | } | 418 | } |
| 398 | 419 | ||
| 420 | skip_resources_enable: | ||
| 399 | /* Perform cleanup that requires refclk */ | 421 | /* Perform cleanup that requires refclk */ |
| 400 | pci_epc_deinit_notify(pci->ep.epc); | 422 | pci_epc_deinit_notify(pci->ep.epc); |
| 401 | dw_pcie_ep_cleanup(&pci->ep); | 423 | dw_pcie_ep_cleanup(&pci->ep); |
| @@ -630,6 +652,17 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev, · 228 unmodified lines | |||
| 630 | return ret; | 652 | return ret; |
| 631 | } | 653 | } |
| 632 | 654 | ||
| 655 | pcie_ep->reset = devm_gpiod_get(dev, "reset", GPIOD_IN); | ||
| 656 | if (IS_ERR(pcie_ep->reset)) | ||
| 657 | return PTR_ERR(pcie_ep->reset); | ||
| 658 | |||
| 659 | pcie_ep->wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); | ||
| 660 | if (IS_ERR(pcie_ep->wake)) | ||
| 661 | return PTR_ERR(pcie_ep->wake); | ||
| 662 | |||
| 663 | if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) | ||
| 664 | return 0; | ||
| 665 | |||
| 633 | pcie_ep->num_clks = devm_clk_bulk_get_all(dev, &pcie_ep->clks); | 666 | pcie_ep->num_clks = devm_clk_bulk_get_all(dev, &pcie_ep->clks); |
| 634 | if (pcie_ep->num_clks < 0) { | 667 | if (pcie_ep->num_clks < 0) { |
| 635 | dev_err(dev, "Failed to get clocks\n"); | 668 | dev_err(dev, "Failed to get clocks\n"); |
| @@ -640,14 +673,6 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev, · 4 unmodified lines | |||
| 640 | if (IS_ERR(pcie_ep->core_reset)) | 673 | if (IS_ERR(pcie_ep->core_reset)) |
| 641 | return PTR_ERR(pcie_ep->core_reset); | 674 | return PTR_ERR(pcie_ep->core_reset); |
| 642 | 675 | ||
| 643 | pcie_ep->reset = devm_gpiod_get(dev, "reset", GPIOD_IN); | ||
| 644 | if (IS_ERR(pcie_ep->reset)) | ||
| 645 | return PTR_ERR(pcie_ep->reset); | ||
| 646 | |||
| 647 | pcie_ep->wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); | ||
| 648 | if (IS_ERR(pcie_ep->wake)) | ||
| 649 | return PTR_ERR(pcie_ep->wake); | ||
| 650 | |||
| 651 | pcie_ep->phy = devm_phy_optional_get(dev, "pciephy"); | 676 | pcie_ep->phy = devm_phy_optional_get(dev, "pciephy"); |
| 652 | if (IS_ERR(pcie_ep->phy)) | 677 | if (IS_ERR(pcie_ep->phy)) |
| 653 | ret = PTR_ERR(pcie_ep->phy); | 678 | ret = PTR_ERR(pcie_ep->phy); |
| @@ -820,6 +845,7 @@ static void qcom_pcie_ep_init_debugfs(struct qcom_pcie_ep *pcie_ep) · 166 unmodified lines | |||
| 820 | } | 845 | } |
| 821 | 846 | ||
| 822 | static const struct pci_epc_features qcom_pcie_epc_features = { | 847 | static const struct pci_epc_features qcom_pcie_epc_features = { |
| 848 | DWC_EPC_COMMON_FEATURES, | ||
| 823 | .linkup_notifier = true, | 849 | .linkup_notifier = true, |
| 824 | .msi_capable = true, | 850 | .msi_capable = true, |
| 825 | .align = SZ_4K, | 851 | .align = SZ_4K, |
| @@ -874,6 +900,12 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) · 48 unmodified lines | |||
| 874 | 900 | ||
| 875 | platform_set_drvdata(pdev, pcie_ep); | 901 | platform_set_drvdata(pdev, pcie_ep); |
| 876 | 902 | ||
| 903 | pm_runtime_get_noresume(dev); | ||
| 904 | pm_runtime_set_active(dev); | ||
| 905 | ret = devm_pm_runtime_enable(dev); | ||
| 906 | if (ret) | ||
| 907 | return ret; | ||
| 908 | |||
| 877 | ret = qcom_pcie_ep_get_resources(pdev, pcie_ep); | 909 | ret = qcom_pcie_ep_get_resources(pdev, pcie_ep); |
| 878 | if (ret) | 910 | if (ret) |
| 879 | return ret; | 911 | return ret; |
| @@ -894,6 +926,12 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) · 14 unmodified lines | |||
| 894 | goto err_disable_irqs; | 926 | goto err_disable_irqs; |
| 895 | } | 927 | } |
| 896 | 928 | ||
| 929 | ret = pm_runtime_put_sync(dev); | ||
| 930 | if (ret < 0) { | ||
| 931 | dev_err(dev, "Failed to suspend device: %d\n", ret); | ||
| 932 | goto err_disable_irqs; | ||
| 933 | } | ||
| 934 | |||
| 897 | pcie_ep->debugfs = debugfs_create_dir(name, NULL); | 935 | pcie_ep->debugfs = debugfs_create_dir(name, NULL); |
| 898 | qcom_pcie_ep_init_debugfs(pcie_ep); | 936 | qcom_pcie_ep_init_debugfs(pcie_ep); |
| 899 | 937 | ||
| @@ -930,7 +968,15 @@ static const struct qcom_pcie_ep_cfg cfg_1_34_0 = { · 30 unmodified lines | |||
| 930 | .disable_mhi_ram_parity_check = true, | 968 | .disable_mhi_ram_parity_check = true, |
| 931 | }; | 969 | }; |
| 932 | 970 | ||
| 971 | static const struct qcom_pcie_ep_cfg cfg_1_34_0_fw_managed = { | ||
| 972 | .hdma_support = true, | ||
| 973 | .override_no_snoop = true, | ||
| 974 | .disable_mhi_ram_parity_check = true, | ||
| 975 | .firmware_managed = true, | ||
| 976 | }; | ||
| 977 | |||
| 933 | static const struct of_device_id qcom_pcie_ep_match[] = { | 978 | static const struct of_device_id qcom_pcie_ep_match[] = { |
| 979 | { .compatible = "qcom,sa8255p-pcie-ep", .data = &cfg_1_34_0_fw_managed}, | ||
| 934 | { .compatible = "qcom,sa8775p-pcie-ep", .data = &cfg_1_34_0}, | 980 | { .compatible = "qcom,sa8775p-pcie-ep", .data = &cfg_1_34_0}, |
| 935 | { .compatible = "qcom,sdx55-pcie-ep", }, | 981 | { .compatible = "qcom,sdx55-pcie-ep", }, |
| 936 | { .compatible = "qcom,sm8450-pcie-ep", }, | 982 | { .compatible = "qcom,sm8450-pcie-ep", }, |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <linux/of_pci.h> | 24 | #include <linux/of_pci.h> |
| 25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
| 26 | #include <linux/pci-ecam.h> | 26 | #include <linux/pci-ecam.h> |
| 27 | #include <linux/pci-pwrctrl.h> | ||
| 27 | #include <linux/pm_opp.h> | 28 | #include <linux/pm_opp.h> |
| 28 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
| 29 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
| @@ -55,9 +56,6 @@ · 25 unmodified lines | |||
| 55 | #define PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1a8 | 56 | #define PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1a8 |
| 56 | #define PARF_Q2A_FLUSH 0x1ac | 57 | #define PARF_Q2A_FLUSH 0x1ac |
| 57 | #define PARF_LTSSM 0x1b0 | 58 | #define PARF_LTSSM 0x1b0 |
| 58 | #define PARF_INT_ALL_STATUS 0x224 | ||
| 59 | #define PARF_INT_ALL_CLEAR 0x228 | ||
| 60 | #define PARF_INT_ALL_MASK 0x22c | ||
| 61 | #define PARF_SID_OFFSET 0x234 | 59 | #define PARF_SID_OFFSET 0x234 |
| 62 | #define PARF_BDF_TRANSLATE_CFG 0x24c | 60 | #define PARF_BDF_TRANSLATE_CFG 0x24c |
| 63 | #define PARF_DBI_BASE_ADDR_V2 0x350 | 61 | #define PARF_DBI_BASE_ADDR_V2 0x350 |
| @@ -134,10 +132,6 @@ · 70 unmodified lines | |||
| 134 | /* PARF_LTSSM register fields */ | 132 | /* PARF_LTSSM register fields */ |
| 135 | #define LTSSM_EN BIT(8) | 133 | #define LTSSM_EN BIT(8) |
| 136 | 134 | ||
| 137 | /* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */ | ||
| 138 | #define PARF_INT_ALL_LINK_UP BIT(13) | ||
| 139 | #define PARF_INT_MSI_DEV_0_7 GENMASK(30, 23) | ||
| 140 | |||
| 141 | /* PARF_NO_SNOOP_OVERRIDE register fields */ | 135 | /* PARF_NO_SNOOP_OVERRIDE register fields */ |
| 142 | #define WR_NO_SNOOP_OVERRIDE_EN BIT(1) | 136 | #define WR_NO_SNOOP_OVERRIDE_EN BIT(1) |
| 143 | #define RD_NO_SNOOP_OVERRIDE_EN BIT(3) | 137 | #define RD_NO_SNOOP_OVERRIDE_EN BIT(3) |
| @@ -267,10 +261,15 @@ struct qcom_pcie_cfg { · 123 unmodified lines | |||
| 267 | bool no_l0s; | 261 | bool no_l0s; |
| 268 | }; | 262 | }; |
| 269 | 263 | ||
| 264 | struct qcom_pcie_perst { | ||
| 265 | struct list_head list; | ||
| 266 | struct gpio_desc *desc; | ||
| 267 | }; | ||
| 268 | |||
| 270 | struct qcom_pcie_port { | 269 | struct qcom_pcie_port { |
| 271 | struct list_head list; | 270 | struct list_head list; |
| 272 | struct gpio_desc *reset; | ||
| 273 | struct phy *phy; | 271 | struct phy *phy; |
| 272 | struct list_head perst; | ||
| 274 | }; | 273 | }; |
| 275 | 274 | ||
| 276 | struct qcom_pcie { | 275 | struct qcom_pcie { |
| @@ -289,27 +288,30 @@ struct qcom_pcie { · 12 unmodified lines | |||
| 289 | 288 | ||
| 290 | #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) | 289 | #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) |
| 291 | 290 | ||
| 292 | static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert) | 291 | static void __qcom_pcie_perst_assert(struct qcom_pcie *pcie, bool assert) |
| 293 | { | 292 | { |
| 293 | struct qcom_pcie_perst *perst; | ||
| 294 | struct qcom_pcie_port *port; | 294 | struct qcom_pcie_port *port; |
| 295 | int val = assert ? 1 : 0; | 295 | int val = assert ? 1 : 0; |
| 296 | 296 | ||
| 297 | list_for_each_entry(port, &pcie->ports, list) | 297 | list_for_each_entry(port, &pcie->ports, list) { |
| 298 | gpiod_set_value_cansleep(port->reset, val); | 298 | list_for_each_entry(perst, &port->perst, list) |
| 299 | gpiod_set_value_cansleep(perst->desc, val); | ||
| 300 | } | ||
| 299 | 301 | ||
| 300 | usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); | 302 | usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); |
| 301 | } | 303 | } |
| 302 | 304 | ||
| 303 | static void qcom_ep_reset_assert(struct qcom_pcie *pcie) | 305 | static void qcom_pcie_perst_assert(struct qcom_pcie *pcie) |
| 304 | { | 306 | { |
| 305 | qcom_perst_assert(pcie, true); | 307 | __qcom_pcie_perst_assert(pcie, true); |
| 306 | } | 308 | } |
| 307 | 309 | ||
| 308 | static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) | 310 | static void qcom_pcie_perst_deassert(struct qcom_pcie *pcie) |
| 309 | { | 311 | { |
| 310 | /* Ensure that PERST has been asserted for at least 100 ms */ | 312 | /* Ensure that PERST# has been asserted for at least 100 ms */ |
| 311 | msleep(PCIE_T_PVPERL_MS); | 313 | msleep(PCIE_T_PVPERL_MS); |
| 312 | qcom_perst_assert(pcie, false); | 314 | __qcom_pcie_perst_assert(pcie, false); |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 315 | static int qcom_pcie_start_link(struct dw_pcie *pci) | 317 | static int qcom_pcie_start_link(struct dw_pcie *pci) |
| @@ -641,18 +643,6 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) · 325 unmodified lines | |||
| 641 | return 0; | 643 | return 0; |
| 642 | } | 644 | } |
| 643 | 645 | ||
| 644 | static int qcom_pcie_assert_perst(struct dw_pcie *pci, bool assert) | ||
| 645 | { | ||
| 646 | struct qcom_pcie *pcie = to_qcom_pcie(pci); | ||
| 647 | |||
| 648 | if (assert) | ||
| 649 | qcom_ep_reset_assert(pcie); | ||
| 650 | else | ||
| 651 | qcom_ep_reset_deassert(pcie); | ||
| 652 | |||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | |||
| 656 | static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) | 646 | static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie) |
| 657 | { | 647 | { |
| 658 | u32 val; | 648 | u32 val; |
| @@ -1299,7 +1289,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) · 640 unmodified lines | |||
| 1299 | struct qcom_pcie *pcie = to_qcom_pcie(pci); | 1289 | struct qcom_pcie *pcie = to_qcom_pcie(pci); |
| 1300 | int ret; | 1290 | int ret; |
| 1301 | 1291 | ||
| 1302 | qcom_ep_reset_assert(pcie); | 1292 | qcom_pcie_perst_assert(pcie); |
| 1303 | 1293 | ||
| 1304 | ret = pcie->cfg->ops->init(pcie); | 1294 | ret = pcie->cfg->ops->init(pcie); |
| 1305 | if (ret) | 1295 | if (ret) |
| @@ -1309,15 +1299,25 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) · 3 unmodified lines | |||
| 1309 | if (ret) | 1299 | if (ret) |
| 1310 | goto err_deinit; | 1300 | goto err_deinit; |
| 1311 | 1301 | ||
| 1302 | ret = pci_pwrctrl_create_devices(pci->dev); | ||
| 1303 | if (ret) | ||
| 1304 | goto err_disable_phy; | ||
| 1305 | |||
| 1306 | ret = pci_pwrctrl_power_on_devices(pci->dev); | ||
| 1307 | if (ret) | ||
| 1308 | goto err_pwrctrl_destroy; | ||
| 1309 | |||
| 1312 | if (pcie->cfg->ops->post_init) { | 1310 | if (pcie->cfg->ops->post_init) { |
| 1313 | ret = pcie->cfg->ops->post_init(pcie); | 1311 | ret = pcie->cfg->ops->post_init(pcie); |
| 1314 | if (ret) | 1312 | if (ret) |
| 1315 | goto err_disable_phy; | 1313 | goto err_pwrctrl_power_off; |
| 1316 | } | 1314 | } |
| 1317 | 1315 | ||
| 1318 | qcom_pcie_clear_aspm_l0s(pcie->pci); | 1316 | qcom_pcie_clear_aspm_l0s(pcie->pci); |
| 1317 | dw_pcie_remove_capability(pcie->pci, PCI_CAP_ID_MSIX); | ||
| 1318 | dw_pcie_remove_ext_capability(pcie->pci, PCI_EXT_CAP_ID_DPC); | ||
| 1319 | 1319 | ||
| 1320 | qcom_ep_reset_deassert(pcie); | 1320 | qcom_pcie_perst_deassert(pcie); |
| 1321 | 1321 | ||
| 1322 | if (pcie->cfg->ops->config_sid) { | 1322 | if (pcie->cfg->ops->config_sid) { |
| 1323 | ret = pcie->cfg->ops->config_sid(pcie); | 1323 | ret = pcie->cfg->ops->config_sid(pcie); |
| @@ -1328,7 +1328,12 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) · 4 unmodified lines | |||
| 1328 | return 0; | 1328 | return 0; |
| 1329 | 1329 | ||
| 1330 | err_assert_reset: | 1330 | err_assert_reset: |
| 1331 | qcom_ep_reset_assert(pcie); | 1331 | qcom_pcie_perst_assert(pcie); |
| 1332 | err_pwrctrl_power_off: | ||
| 1333 | pci_pwrctrl_power_off_devices(pci->dev); | ||
| 1334 | err_pwrctrl_destroy: | ||
| 1335 | if (ret != -EPROBE_DEFER) | ||
| 1336 | pci_pwrctrl_destroy_devices(pci->dev); | ||
| 1332 | err_disable_phy: | 1337 | err_disable_phy: |
| 1333 | qcom_pcie_phy_power_off(pcie); | 1338 | qcom_pcie_phy_power_off(pcie); |
| 1334 | err_deinit: | 1339 | err_deinit: |
| @@ -1342,7 +1347,13 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp) · 7 unmodified lines | |||
| 1342 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | 1347 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
| 1343 | struct qcom_pcie *pcie = to_qcom_pcie(pci); | 1348 | struct qcom_pcie *pcie = to_qcom_pcie(pci); |
| 1344 | 1349 | ||
| 1345 | qcom_ep_reset_assert(pcie); | 1350 | qcom_pcie_perst_assert(pcie); |
| 1351 | |||
| 1352 | /* | ||
| 1353 | * No need to destroy pwrctrl devices as this function only gets called | ||
| 1354 | * during system suspend as of now. | ||
| 1355 | */ | ||
| 1356 | pci_pwrctrl_power_off_devices(pci->dev); | ||
| 1346 | qcom_pcie_phy_power_off(pcie); | 1357 | qcom_pcie_phy_power_off(pcie); |
| 1347 | pcie->cfg->ops->deinit(pcie); | 1358 | pcie->cfg->ops->deinit(pcie); |
| 1348 | } | 1359 | } |
| @@ -1496,7 +1507,6 @@ static const struct qcom_pcie_cfg cfg_fw_managed = { · 147 unmodified lines | |||
| 1496 | static const struct dw_pcie_ops dw_pcie_ops = { | 1507 | static const struct dw_pcie_ops dw_pcie_ops = { |
| 1497 | .link_up = qcom_pcie_link_up, | 1508 | .link_up = qcom_pcie_link_up, |
| 1498 | .start_link = qcom_pcie_start_link, | 1509 | .start_link = qcom_pcie_start_link, |
| 1499 | .assert_perst = qcom_pcie_assert_perst, | ||
| 1500 | }; | 1510 | }; |
| 1501 | 1511 | ||
| 1502 | static int qcom_pcie_icc_init(struct qcom_pcie *pcie) | 1512 | static int qcom_pcie_icc_init(struct qcom_pcie *pcie) |
| @@ -1635,37 +1645,11 @@ static void qcom_pcie_init_debugfs(struct qcom_pcie *pcie) · 132 unmodified lines | |||
| 1635 | qcom_pcie_link_transition_count); | 1645 | qcom_pcie_link_transition_count); |
| 1636 | } | 1646 | } |
| 1637 | 1647 | ||
| 1638 | static irqreturn_t qcom_pcie_global_irq_thread(int irq, void *data) | ||
| 1639 | { | ||
| 1640 | struct qcom_pcie *pcie = data; | ||
| 1641 | struct dw_pcie_rp *pp = &pcie->pci->pp; | ||
| 1642 | struct device *dev = pcie->pci->dev; | ||
| 1643 | u32 status = readl_relaxed(pcie->parf + PARF_INT_ALL_STATUS); | ||
| 1644 | |||
| 1645 | writel_relaxed(status, pcie->parf + PARF_INT_ALL_CLEAR); | ||
| 1646 | |||
| 1647 | if (FIELD_GET(PARF_INT_ALL_LINK_UP, status)) { | ||
| 1648 | msleep(PCIE_RESET_CONFIG_WAIT_MS); | ||
| 1649 | dev_dbg(dev, "Received Link up event. Starting enumeration!\n"); | ||
| 1650 | /* Rescan the bus to enumerate endpoint devices */ | ||
| 1651 | pci_lock_rescan_remove(); | ||
| 1652 | pci_rescan_bus(pp->bridge->bus); | ||
| 1653 | pci_unlock_rescan_remove(); | ||
| 1654 | |||
| 1655 | qcom_pcie_icc_opp_update(pcie); | ||
| 1656 | } else { | ||
| 1657 | dev_WARN_ONCE(dev, 1, "Received unknown event. INT_STATUS: 0x%08x\n", | ||
| 1658 | status); | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | return IRQ_HANDLED; | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | static void qcom_pci_free_msi(void *ptr) | 1648 | static void qcom_pci_free_msi(void *ptr) |
| 1665 | { | 1649 | { |
| 1666 | struct dw_pcie_rp *pp = (struct dw_pcie_rp *)ptr; | 1650 | struct dw_pcie_rp *pp = (struct dw_pcie_rp *)ptr; |
| 1667 | 1651 | ||
| 1668 | if (pp && pp->has_msi_ctrl) | 1652 | if (pp && pp->use_imsi_rx) |
| 1669 | dw_pcie_free_msi(pp); | 1653 | dw_pcie_free_msi(pp); |
| 1670 | } | 1654 | } |
| 1671 | 1655 | ||
| @@ -1689,7 +1673,7 @@ static int qcom_pcie_ecam_host_init(struct pci_config_window *cfg) · 17 unmodified lines | |||
| 1689 | if (ret) | 1673 | if (ret) |
| 1690 | return ret; | 1674 | return ret; |
| 1691 | 1675 | ||
| 1692 | pp->has_msi_ctrl = true; | 1676 | pp->use_imsi_rx = true; |
| 1693 | dw_pcie_msi_init(pp); | 1677 | dw_pcie_msi_init(pp); |
| 1694 | 1678 | ||
| 1695 | return devm_add_action_or_reset(dev, qcom_pci_free_msi, pp); | 1679 | return devm_add_action_or_reset(dev, qcom_pci_free_msi, pp); |
| @@ -1704,18 +1688,58 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = { · 8 unmodified lines | |||
| 1704 | } | 1688 | } |
| 1705 | }; | 1689 | }; |
| 1706 | 1690 | ||
| 1707 | static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node) | 1691 | /* Parse PERST# from all nodes in depth first manner starting from @np */ |
| 1692 | static int qcom_pcie_parse_perst(struct qcom_pcie *pcie, | ||
| 1693 | struct qcom_pcie_port *port, | ||
| 1694 | struct device_node *np) | ||
| 1708 | { | 1695 | { |
| 1709 | struct device *dev = pcie->pci->dev; | 1696 | struct device *dev = pcie->pci->dev; |
| 1710 | struct qcom_pcie_port *port; | 1697 | struct qcom_pcie_perst *perst; |
| 1711 | struct gpio_desc *reset; | 1698 | struct gpio_desc *reset; |
| 1712 | struct phy *phy; | ||
| 1713 | int ret; | 1699 | int ret; |
| 1714 | 1700 | ||
| 1715 | reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node), | 1701 | if (!of_find_property(np, "reset-gpios", NULL)) |
| 1716 | "reset", GPIOD_OUT_HIGH, "PERST#"); | 1702 | goto parse_child_node; |
| 1717 | if (IS_ERR(reset)) | 1703 | |
| 1704 | reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(np), "reset", | ||
| 1705 | GPIOD_OUT_HIGH, "PERST#"); | ||
| 1706 | if (IS_ERR(reset)) { | ||
| 1707 | /* | ||
| 1708 | * FIXME: GPIOLIB currently supports exclusive GPIO access only. | ||
| 1709 | * Non exclusive access is broken. But shared PERST# requires | ||
| 1710 | * non-exclusive access. So once GPIOLIB properly supports it, | ||
| 1711 | * implement it here. | ||
| 1712 | */ | ||
| 1713 | if (PTR_ERR(reset) == -EBUSY) | ||
| 1714 | dev_err(dev, "Shared PERST# is not supported\n"); | ||
| 1715 | |||
| 1718 | return PTR_ERR(reset); | 1716 | return PTR_ERR(reset); |
| 1717 | } | ||
| 1718 | |||
| 1719 | perst = devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); | ||
| 1720 | if (!perst) | ||
| 1721 | return -ENOMEM; | ||
| 1722 | |||
| 1723 | INIT_LIST_HEAD(&perst->list); | ||
| 1724 | perst->desc = reset; | ||
| 1725 | list_add_tail(&perst->list, &port->perst); | ||
| 1726 | |||
| 1727 | parse_child_node: | ||
| 1728 | for_each_available_child_of_node_scoped(np, child) { | ||
| 1729 | ret = qcom_pcie_parse_perst(pcie, port, child); | ||
| 1730 | if (ret) | ||
| 1731 | return ret; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | return 0; | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node) | ||
| 1738 | { | ||
| 1739 | struct device *dev = pcie->pci->dev; | ||
| 1740 | struct qcom_pcie_port *port; | ||
| 1741 | struct phy *phy; | ||
| 1742 | int ret; | ||
| 1719 | 1743 | ||
| 1720 | phy = devm_of_phy_get(dev, node, NULL); | 1744 | phy = devm_of_phy_get(dev, node, NULL); |
| 1721 | if (IS_ERR(phy)) | 1745 | if (IS_ERR(phy)) |
| @@ -1729,7 +1753,12 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node · 7 unmodified lines | |||
| 1729 | if (ret) | 1753 | if (ret) |
| 1730 | return ret; | 1754 | return ret; |
| 1731 | 1755 | ||
| 1732 | port->reset = reset; | 1756 | INIT_LIST_HEAD(&port->perst); |
| 1757 | |||
| 1758 | ret = qcom_pcie_parse_perst(pcie, port, node); | ||
| 1759 | if (ret) | ||
| 1760 | return ret; | ||
| 1761 | |||
| 1733 | port->phy = phy; | 1762 | port->phy = phy; |
| 1734 | INIT_LIST_HEAD(&port->list); | 1763 | INIT_LIST_HEAD(&port->list); |
| 1735 | list_add_tail(&port->list, &pcie->ports); | 1764 | list_add_tail(&port->list, &pcie->ports); |
| @@ -1739,9 +1768,10 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node · 3 unmodified lines | |||
| 1739 | 1768 | ||
| 1740 | static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) | 1769 | static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) |
| 1741 | { | 1770 | { |
| 1771 | struct qcom_pcie_perst *perst, *tmp_perst; | ||
| 1772 | struct qcom_pcie_port *port, *tmp_port; | ||
| 1742 | struct device *dev = pcie->pci->dev; | 1773 | struct device *dev = pcie->pci->dev; |
| 1743 | struct qcom_pcie_port *port, *tmp; | 1774 | int ret = -ENODEV; |
| 1744 | int ret = -ENOENT; | ||
| 1745 | 1775 | ||
| 1746 | for_each_available_child_of_node_scoped(dev->of_node, of_port) { | 1776 | for_each_available_child_of_node_scoped(dev->of_node, of_port) { |
| 1747 | if (!of_node_is_type(of_port, "pci")) | 1777 | if (!of_node_is_type(of_port, "pci")) |
| @@ -1754,7 +1784,9 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) · 6 unmodified lines | |||
| 1754 | return ret; | 1784 | return ret; |
| 1755 | 1785 | ||
| 1756 | err_port_del: | 1786 | err_port_del: |
| 1757 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) { | 1787 | list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { |
| 1788 | list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) | ||
| 1789 | list_del(&perst->list); | ||
| 1758 | phy_exit(port->phy); | 1790 | phy_exit(port->phy); |
| 1759 | list_del(&port->list); | 1791 | list_del(&port->list); |
| 1760 | } | 1792 | } |
| @@ -1765,6 +1797,7 @@ err_port_del: · 4 unmodified lines | |||
| 1765 | static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) | 1797 | static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) |
| 1766 | { | 1798 | { |
| 1767 | struct device *dev = pcie->pci->dev; | 1799 | struct device *dev = pcie->pci->dev; |
| 1800 | struct qcom_pcie_perst *perst; | ||
| 1768 | struct qcom_pcie_port *port; | 1801 | struct qcom_pcie_port *port; |
| 1769 | struct gpio_desc *reset; | 1802 | struct gpio_desc *reset; |
| 1770 | struct phy *phy; | 1803 | struct phy *phy; |
| @@ -1786,27 +1819,35 @@ static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie) · 15 unmodified lines | |||
| 1786 | if (!port) | 1819 | if (!port) |
| 1787 | return -ENOMEM; | 1820 | return -ENOMEM; |
| 1788 | 1821 | ||
| 1789 | port->reset = reset; | 1822 | perst = devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL); |
| 1823 | if (!perst) | ||
| 1824 | return -ENOMEM; | ||
| 1825 | |||
| 1790 | port->phy = phy; | 1826 | port->phy = phy; |
| 1791 | INIT_LIST_HEAD(&port->list); | 1827 | INIT_LIST_HEAD(&port->list); |
| 1792 | list_add_tail(&port->list, &pcie->ports); | 1828 | list_add_tail(&port->list, &pcie->ports); |
| 1793 | 1829 | ||
| 1830 | perst->desc = reset; | ||
| 1831 | INIT_LIST_HEAD(&port->perst); | ||
| 1832 | INIT_LIST_HEAD(&perst->list); | ||
| 1833 | list_add_tail(&perst->list, &port->perst); | ||
| 1834 | |||
| 1794 | return 0; | 1835 | return 0; |
| 1795 | } | 1836 | } |
| 1796 | 1837 | ||
| 1797 | static int qcom_pcie_probe(struct platform_device *pdev) | 1838 | static int qcom_pcie_probe(struct platform_device *pdev) |
| 1798 | { | 1839 | { |
| 1840 | struct qcom_pcie_perst *perst, *tmp_perst; | ||
| 1841 | struct qcom_pcie_port *port, *tmp_port; | ||
| 1799 | const struct qcom_pcie_cfg *pcie_cfg; | 1842 | const struct qcom_pcie_cfg *pcie_cfg; |
| 1800 | unsigned long max_freq = ULONG_MAX; | 1843 | unsigned long max_freq = ULONG_MAX; |
| 1801 | struct qcom_pcie_port *port, *tmp; | ||
| 1802 | struct device *dev = &pdev->dev; | 1844 | struct device *dev = &pdev->dev; |
| 1803 | struct dev_pm_opp *opp; | 1845 | struct dev_pm_opp *opp; |
| 1804 | struct qcom_pcie *pcie; | 1846 | struct qcom_pcie *pcie; |
| 1805 | struct dw_pcie_rp *pp; | 1847 | struct dw_pcie_rp *pp; |
| 1806 | struct resource *res; | 1848 | struct resource *res; |
| 1807 | struct dw_pcie *pci; | 1849 | struct dw_pcie *pci; |
| 1808 | int ret, irq; | 1850 | int ret; |
| 1809 | char *name; | ||
| 1810 | 1851 | ||
| 1811 | pcie_cfg = of_device_get_match_data(dev); | 1852 | pcie_cfg = of_device_get_match_data(dev); |
| 1812 | if (!pcie_cfg) { | 1853 | if (!pcie_cfg) { |
| @@ -1939,7 +1980,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) · 126 unmodified lines | |||
| 1939 | 1980 | ||
| 1940 | ret = qcom_pcie_parse_ports(pcie); | 1981 | ret = qcom_pcie_parse_ports(pcie); |
| 1941 | if (ret) { | 1982 | if (ret) { |
| 1942 | if (ret != -ENOENT) { | 1983 | if (ret != -ENODEV) { |
| 1943 | dev_err_probe(pci->dev, ret, | 1984 | dev_err_probe(pci->dev, ret, |
| 1944 | "Failed to parse Root Port: %d\n", ret); | 1985 | "Failed to parse Root Port: %d\n", ret); |
| 1945 | goto err_pm_runtime_put; | 1986 | goto err_pm_runtime_put; |
| @@ -1957,37 +1998,12 @@ static int qcom_pcie_probe(struct platform_device *pdev) · 11 unmodified lines | |||
| 1957 | 1998 | ||
| 1958 | platform_set_drvdata(pdev, pcie); | 1999 | platform_set_drvdata(pdev, pcie); |
| 1959 | 2000 | ||
| 1960 | irq = platform_get_irq_byname_optional(pdev, "global"); | ||
| 1961 | if (irq > 0) | ||
| 1962 | pp->use_linkup_irq = true; | ||
| 1963 | |||
| 1964 | ret = dw_pcie_host_init(pp); | 2001 | ret = dw_pcie_host_init(pp); |
| 1965 | if (ret) { | 2002 | if (ret) { |
| 1966 | dev_err(dev, "cannot initialize host\n"); | 2003 | dev_err_probe(dev, ret, "cannot initialize host\n"); |
| 1967 | goto err_phy_exit; | 2004 | goto err_phy_exit; |
| 1968 | } | 2005 | } |
| 1969 | 2006 | ||
| 1970 | name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq%d", | ||
| 1971 | pci_domain_nr(pp->bridge->bus)); | ||
| 1972 | if (!name) { | ||
| 1973 | ret = -ENOMEM; | ||
| 1974 | goto err_host_deinit; | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | if (irq > 0) { | ||
| 1978 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
| 1979 | qcom_pcie_global_irq_thread, | ||
| 1980 | IRQF_ONESHOT, name, pcie); | ||
| 1981 | if (ret) { | ||
| 1982 | dev_err_probe(&pdev->dev, ret, | ||
| 1983 | "Failed to request Global IRQ\n"); | ||
| 1984 | goto err_host_deinit; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | writel_relaxed(PARF_INT_ALL_LINK_UP | PARF_INT_MSI_DEV_0_7, | ||
| 1988 | pcie->parf + PARF_INT_ALL_MASK); | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | qcom_pcie_icc_opp_update(pcie); | 2007 | qcom_pcie_icc_opp_update(pcie); |
| 1992 | 2008 | ||
| 1993 | if (pcie->mhi) | 2009 | if (pcie->mhi) |
| @@ -1995,10 +2011,10 @@ static int qcom_pcie_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 1995 | 2011 | ||
| 1996 | return 0; | 2012 | return 0; |
| 1997 | 2013 | ||
| 1998 | err_host_deinit: | ||
| 1999 | dw_pcie_host_deinit(pp); | ||
| 2000 | err_phy_exit: | 2014 | err_phy_exit: |
| 2001 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) { | 2015 | list_for_each_entry_safe(port, tmp_port, &pcie->ports, list) { |
| 2016 | list_for_each_entry_safe(perst, tmp_perst, &port->perst, list) | ||
| 2017 | list_del(&perst->list); | ||
| 2002 | phy_exit(port->phy); | 2018 | phy_exit(port->phy); |
| 2003 | list_del(&port->list); | 2019 | list_del(&port->list); |
| 2004 | } | 2020 | } |
| @@ -420,6 +420,7 @@ static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 419 unmodified lines | |||
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | static const struct pci_epc_features rcar_gen4_pcie_epc_features = { | 422 | static const struct pci_epc_features rcar_gen4_pcie_epc_features = { |
| 423 | DWC_EPC_COMMON_FEATURES, | ||
| 423 | .msi_capable = true, | 424 | .msi_capable = true, |
| 424 | .bar[BAR_1] = { .type = BAR_RESERVED, }, | 425 | .bar[BAR_1] = { .type = BAR_RESERVED, }, |
| 425 | .bar[BAR_3] = { .type = BAR_RESERVED, }, | 426 | .bar[BAR_3] = { .type = BAR_RESERVED, }, |
| @@ -161,6 +161,22 @@ static void sophgo_pcie_msi_enable(struct dw_pcie_rp *pp) · 160 unmodified lines | |||
| 161 | raw_spin_unlock_irqrestore(&pp->lock, flags); | 161 | raw_spin_unlock_irqrestore(&pp->lock, flags); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static void sophgo_pcie_disable_l0s_l1(struct dw_pcie_rp *pp) | ||
| 165 | { | ||
| 166 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); | ||
| 167 | u32 offset, val; | ||
| 168 | |||
| 169 | offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); | ||
| 170 | |||
| 171 | dw_pcie_dbi_ro_wr_en(pci); | ||
| 172 | |||
| 173 | val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + offset); | ||
| 174 | val &= ~(PCI_EXP_LNKCAP_ASPM_L0S | PCI_EXP_LNKCAP_ASPM_L1); | ||
| 175 | dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + offset, val); | ||
| 176 | |||
| 177 | dw_pcie_dbi_ro_wr_dis(pci); | ||
| 178 | } | ||
| 179 | |||
| 164 | static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) | 180 | static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) |
| 165 | { | 181 | { |
| 166 | int irq; | 182 | int irq; |
| @@ -171,6 +187,8 @@ static int sophgo_pcie_host_init(struct dw_pcie_rp *pp) · 4 unmodified lines | |||
| 171 | 187 | ||
| 172 | irq_set_chained_handler_and_data(irq, sophgo_pcie_intx_handler, pp); | 188 | irq_set_chained_handler_and_data(irq, sophgo_pcie_intx_handler, pp); |
| 173 | 189 | ||
| 190 | sophgo_pcie_disable_l0s_l1(pp); | ||
| 191 | |||
| 174 | sophgo_pcie_msi_enable(pp); | 192 | sophgo_pcie_msi_enable(pp); |
| 175 | 193 | ||
| 176 | return 0; | 194 | return 0; |
| @@ -70,6 +70,7 @@ static int stm32_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 69 unmodified lines | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static const struct pci_epc_features stm32_pcie_epc_features = { | 72 | static const struct pci_epc_features stm32_pcie_epc_features = { |
| 73 | DWC_EPC_COMMON_FEATURES, | ||
| 73 | .msi_capable = true, | 74 | .msi_capable = true, |
| 74 | .align = SZ_64K, | 75 | .align = SZ_64K, |
| 75 | }; | 76 | }; |
| @@ -1988,6 +1988,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · 1987 unmodified lines | |||
| 1988 | } | 1988 | } |
| 1989 | 1989 | ||
| 1990 | static const struct pci_epc_features tegra_pcie_epc_features = { | 1990 | static const struct pci_epc_features tegra_pcie_epc_features = { |
| 1991 | DWC_EPC_COMMON_FEATURES, | ||
| 1991 | .linkup_notifier = true, | 1992 | .linkup_notifier = true, |
| 1992 | .msi_capable = true, | 1993 | .msi_capable = true, |
| 1993 | .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, | 1994 | .bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M, |
| @@ -420,6 +420,7 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = { · 419 unmodified lines | |||
| 420 | .init = uniphier_pcie_pro5_init_ep, | 420 | .init = uniphier_pcie_pro5_init_ep, |
| 421 | .wait = NULL, | 421 | .wait = NULL, |
| 422 | .features = { | 422 | .features = { |
| 423 | DWC_EPC_COMMON_FEATURES, | ||
| 423 | .linkup_notifier = false, | 424 | .linkup_notifier = false, |
| 424 | .msi_capable = true, | 425 | .msi_capable = true, |
| 425 | .msix_capable = false, | 426 | .msix_capable = false, |
| @@ -438,6 +439,7 @@ static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = { · 12 unmodified lines | |||
| 438 | .init = uniphier_pcie_nx1_init_ep, | 439 | .init = uniphier_pcie_nx1_init_ep, |
| 439 | .wait = uniphier_pcie_nx1_wait_ep, | 440 | .wait = uniphier_pcie_nx1_wait_ep, |
| 440 | .features = { | 441 | .features = { |
| 442 | DWC_EPC_COMMON_FEATURES, | ||
| 441 | .linkup_notifier = false, | 443 | .linkup_notifier = false, |
| 442 | .msi_capable = true, | 444 | .msi_capable = true, |
| 443 | .msix_capable = false, | 445 | .msix_capable = false, |
| @@ -32,7 +32,7 @@ struct pci_config_window *pci_host_common_ecam_create(struct device *dev, · 31 unmodified lines | |||
| 32 | 32 | ||
| 33 | err = of_address_to_resource(dev->of_node, 0, &cfgres); | 33 | err = of_address_to_resource(dev->of_node, 0, &cfgres); |
| 34 | if (err) { | 34 | if (err) { |
| 35 | dev_err(dev, "missing \"reg\" property\n"); | 35 | dev_err(dev, "missing or malformed \"reg\" property\n"); |
| 36 | return ERR_PTR(err); | 36 | return ERR_PTR(err); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| @@ -2545,12 +2545,6 @@ static const struct seq_operations tegra_pcie_ports_sops = { · 2544 unmodified lines | |||
| 2545 | 2545 | ||
| 2546 | DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports); | 2546 | DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports); |
| 2547 | 2547 | ||
| 2548 | static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie) | ||
| 2549 | { | ||
| 2550 | debugfs_remove_recursive(pcie->debugfs); | ||
| 2551 | pcie->debugfs = NULL; | ||
| 2552 | } | ||
| 2553 | |||
| 2554 | static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie) | 2548 | static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie) |
| 2555 | { | 2549 | { |
| 2556 | pcie->debugfs = debugfs_create_dir("pcie", NULL); | 2550 | pcie->debugfs = debugfs_create_dir("pcie", NULL); |
| @@ -2624,29 +2618,6 @@ put_resources: · 67 unmodified lines | |||
| 2624 | return err; | 2618 | return err; |
| 2625 | } | 2619 | } |
| 2626 | 2620 | ||
| 2627 | static void tegra_pcie_remove(struct platform_device *pdev) | ||
| 2628 | { | ||
| 2629 | struct tegra_pcie *pcie = platform_get_drvdata(pdev); | ||
| 2630 | struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); | ||
| 2631 | struct tegra_pcie_port *port, *tmp; | ||
| 2632 | |||
| 2633 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | ||
| 2634 | tegra_pcie_debugfs_exit(pcie); | ||
| 2635 | |||
| 2636 | pci_stop_root_bus(host->bus); | ||
| 2637 | pci_remove_root_bus(host->bus); | ||
| 2638 | pm_runtime_put_sync(pcie->dev); | ||
| 2639 | pm_runtime_disable(pcie->dev); | ||
| 2640 | |||
| 2641 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
| 2642 | tegra_pcie_msi_teardown(pcie); | ||
| 2643 | |||
| 2644 | tegra_pcie_put_resources(pcie); | ||
| 2645 | |||
| 2646 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) | ||
| 2647 | tegra_pcie_port_free(port); | ||
| 2648 | } | ||
| 2649 | |||
| 2650 | static int tegra_pcie_pm_suspend(struct device *dev) | 2621 | static int tegra_pcie_pm_suspend(struct device *dev) |
| 2651 | { | 2622 | { |
| 2652 | struct tegra_pcie *pcie = dev_get_drvdata(dev); | 2623 | struct tegra_pcie *pcie = dev_get_drvdata(dev); |
| @@ -2750,6 +2721,8 @@ static struct platform_driver tegra_pcie_driver = { · 97 unmodified lines | |||
| 2750 | .pm = &tegra_pcie_pm_ops, | 2721 | .pm = &tegra_pcie_pm_ops, |
| 2751 | }, | 2722 | }, |
| 2752 | .probe = tegra_pcie_probe, | 2723 | .probe = tegra_pcie_probe, |
| 2753 | .remove = tegra_pcie_remove, | ||
| 2754 | }; | 2724 | }; |
| 2755 | module_platform_driver(tegra_pcie_driver); | 2725 | builtin_platform_driver(tegra_pcie_driver); |
| 2726 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
| 2727 | MODULE_DESCRIPTION("NVIDIA PCI host controller driver"); | ||
| 2728 | MODULE_LICENSE("GPL"); | ||
| @@ -0,0 +1,1111 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright 2025 Aspeed Technology Inc. | ||
| 4 | */ | ||
| 5 | #include <linux/bitfield.h> | ||
| 6 | #include <linux/clk.h> | ||
| 7 | #include <linux/interrupt.h> | ||
| 8 | #include <linux/irq.h> | ||
| 9 | #include <linux/irqdomain.h> | ||
| 10 | #include <linux/irqchip/chained_irq.h> | ||
| 11 | #include <linux/irqchip/irq-msi-lib.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/mfd/syscon.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/msi.h> | ||
| 16 | #include <linux/mutex.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | #include <linux/of_address.h> | ||
| 19 | #include <linux/of_pci.h> | ||
| 20 | #include <linux/pci.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/phy/pcie.h> | ||
| 23 | #include <linux/phy/phy.h> | ||
| 24 | #include <linux/regmap.h> | ||
| 25 | #include <linux/reset.h> | ||
| 26 | |||
| 27 | #include "../pci.h" | ||
| 28 | |||
| 29 | #define MAX_MSI_HOST_IRQS 64 | ||
| 30 | #define ASPEED_RESET_RC_WAIT_MS 10 | ||
| 31 | |||
| 32 | /* AST2600 AHBC Registers */ | ||
| 33 | #define ASPEED_AHBC_KEY 0x00 | ||
| 34 | #define ASPEED_AHBC_UNLOCK_KEY 0xaeed1a03 | ||
| 35 | #define ASPEED_AHBC_UNLOCK 0x01 | ||
| 36 | #define ASPEED_AHBC_ADDR_MAPPING 0x8c | ||
| 37 | #define ASPEED_PCIE_RC_MEMORY_EN BIT(5) | ||
| 38 | |||
| 39 | /* AST2600 H2X Controller Registers */ | ||
| 40 | #define ASPEED_H2X_INT_STS 0x08 | ||
| 41 | #define ASPEED_PCIE_TX_IDLE_CLEAR BIT(0) | ||
| 42 | #define ASPEED_PCIE_INTX_STS GENMASK(3, 0) | ||
| 43 | #define ASPEED_H2X_HOST_RX_DESC_DATA 0x0c | ||
| 44 | #define ASPEED_H2X_TX_DESC0 0x10 | ||
| 45 | #define ASPEED_H2X_TX_DESC1 0x14 | ||
| 46 | #define ASPEED_H2X_TX_DESC2 0x18 | ||
| 47 | #define ASPEED_H2X_TX_DESC3 0x1c | ||
| 48 | #define ASPEED_H2X_TX_DESC_DATA 0x20 | ||
| 49 | #define ASPEED_H2X_STS 0x24 | ||
| 50 | #define ASPEED_PCIE_TX_IDLE BIT(31) | ||
| 51 | #define ASPEED_PCIE_STATUS_OF_TX GENMASK(25, 24) | ||
| 52 | #define ASPEED_PCIE_RC_H_TX_COMPLETE BIT(25) | ||
| 53 | #define ASPEED_PCIE_TRIGGER_TX BIT(0) | ||
| 54 | #define ASPEED_H2X_AHB_ADDR_CONFIG0 0x60 | ||
| 55 | #define ASPEED_AHB_REMAP_LO_ADDR(x) (x & GENMASK(15, 4)) | ||
| 56 | #define ASPEED_AHB_MASK_LO_ADDR(x) FIELD_PREP(GENMASK(31, 20), x) | ||
| 57 | #define ASPEED_H2X_AHB_ADDR_CONFIG1 0x64 | ||
| 58 | #define ASPEED_AHB_REMAP_HI_ADDR(x) (x) | ||
| 59 | #define ASPEED_H2X_AHB_ADDR_CONFIG2 0x68 | ||
| 60 | #define ASPEED_AHB_MASK_HI_ADDR(x) (x) | ||
| 61 | #define ASPEED_H2X_DEV_CTRL 0xc0 | ||
| 62 | #define ASPEED_PCIE_RX_DMA_EN BIT(9) | ||
| 63 | #define ASPEED_PCIE_RX_LINEAR BIT(8) | ||
| 64 | #define ASPEED_PCIE_RX_MSI_SEL BIT(7) | ||
| 65 | #define ASPEED_PCIE_RX_MSI_EN BIT(6) | ||
| 66 | #define ASPEED_PCIE_UNLOCK_RX_BUFF BIT(4) | ||
| 67 | #define ASPEED_PCIE_WAIT_RX_TLP_CLR BIT(2) | ||
| 68 | #define ASPEED_PCIE_RC_RX_ENABLE BIT(1) | ||
| 69 | #define ASPEED_PCIE_RC_ENABLE BIT(0) | ||
| 70 | #define ASPEED_H2X_DEV_STS 0xc8 | ||
| 71 | #define ASPEED_PCIE_RC_RX_DONE_ISR BIT(4) | ||
| 72 | #define ASPEED_H2X_DEV_RX_DESC_DATA 0xcc | ||
| 73 | #define ASPEED_H2X_DEV_RX_DESC1 0xd4 | ||
| 74 | #define ASPEED_H2X_DEV_TX_TAG 0xfc | ||
| 75 | #define ASPEED_RC_TLP_TX_TAG_NUM 0x28 | ||
| 76 | |||
| 77 | /* AST2700 H2X */ | ||
| 78 | #define ASPEED_H2X_CTRL 0x00 | ||
| 79 | #define ASPEED_H2X_BRIDGE_EN BIT(0) | ||
| 80 | #define ASPEED_H2X_BRIDGE_DIRECT_EN BIT(1) | ||
| 81 | #define ASPEED_H2X_CFGE_INT_STS 0x08 | ||
| 82 | #define ASPEED_CFGE_TX_IDLE BIT(0) | ||
| 83 | #define ASPEED_CFGE_RX_BUSY BIT(1) | ||
| 84 | #define ASPEED_H2X_CFGI_TLP 0x20 | ||
| 85 | #define ASPEED_CFGI_BYTE_EN_MASK GENMASK(19, 16) | ||
| 86 | #define ASPEED_CFGI_BYTE_EN(x) \ | ||
| 87 | FIELD_PREP(ASPEED_CFGI_BYTE_EN_MASK, (x)) | ||
| 88 | #define ASPEED_H2X_CFGI_WR_DATA 0x24 | ||
| 89 | #define ASPEED_CFGI_WRITE BIT(20) | ||
| 90 | #define ASPEED_H2X_CFGI_CTRL 0x28 | ||
| 91 | #define ASPEED_CFGI_TLP_FIRE BIT(0) | ||
| 92 | #define ASPEED_H2X_CFGI_RET_DATA 0x2c | ||
| 93 | #define ASPEED_H2X_CFGE_TLP_1ST 0x30 | ||
| 94 | #define ASPEED_H2X_CFGE_TLP_NEXT 0x34 | ||
| 95 | #define ASPEED_H2X_CFGE_CTRL 0x38 | ||
| 96 | #define ASPEED_CFGE_TLP_FIRE BIT(0) | ||
| 97 | #define ASPEED_H2X_CFGE_RET_DATA 0x3c | ||
| 98 | #define ASPEED_H2X_REMAP_PREF_ADDR 0x70 | ||
| 99 | #define ASPEED_REMAP_PREF_ADDR_63_32(x) (x) | ||
| 100 | #define ASPEED_H2X_REMAP_PCI_ADDR_HI 0x74 | ||
| 101 | #define ASPEED_REMAP_PCI_ADDR_63_32(x) (((x) >> 32) & GENMASK(31, 0)) | ||
| 102 | #define ASPEED_H2X_REMAP_PCI_ADDR_LO 0x78 | ||
| 103 | #define ASPEED_REMAP_PCI_ADDR_31_12(x) ((x) & GENMASK(31, 12)) | ||
| 104 | |||
| 105 | /* AST2700 SCU */ | ||
| 106 | #define ASPEED_SCU_60 0x60 | ||
| 107 | #define ASPEED_RC_E2M_PATH_EN BIT(0) | ||
| 108 | #define ASPEED_RC_H2XS_PATH_EN BIT(16) | ||
| 109 | #define ASPEED_RC_H2XD_PATH_EN BIT(17) | ||
| 110 | #define ASPEED_RC_H2XX_PATH_EN BIT(18) | ||
| 111 | #define ASPEED_RC_UPSTREAM_MEM_EN BIT(19) | ||
| 112 | #define ASPEED_SCU_64 0x64 | ||
| 113 | #define ASPEED_RC0_DECODE_DMA_BASE(x) FIELD_PREP(GENMASK(7, 0), x) | ||
| 114 | #define ASPEED_RC0_DECODE_DMA_LIMIT(x) FIELD_PREP(GENMASK(15, 8), x) | ||
| 115 | #define ASPEED_RC1_DECODE_DMA_BASE(x) FIELD_PREP(GENMASK(23, 16), x) | ||
| 116 | #define ASPEED_RC1_DECODE_DMA_LIMIT(x) FIELD_PREP(GENMASK(31, 24), x) | ||
| 117 | #define ASPEED_SCU_70 0x70 | ||
| 118 | #define ASPEED_DISABLE_EP_FUNC 0 | ||
| 119 | |||
| 120 | /* Macro to combine Fmt and Type into the 8-bit field */ | ||
| 121 | #define ASPEED_TLP_FMT_TYPE(fmt, type) ((((fmt) & 0x7) << 5) | ((type) & 0x1f)) | ||
| 122 | #define ASPEED_TLP_COMMON_FIELDS GENMASK(31, 24) | ||
| 123 | |||
| 124 | /* Completion status */ | ||
| 125 | #define CPL_STS(x) FIELD_GET(GENMASK(15, 13), (x)) | ||
| 126 | /* TLP configuration type 0 and type 1 */ | ||
| 127 | #define CFG0_READ_FMTTYPE \ | ||
| 128 | FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ | ||
| 129 | ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \ | ||
| 130 | PCIE_TLP_TYPE_CFG0_RD)) | ||
| 131 | #define CFG0_WRITE_FMTTYPE \ | ||
| 132 | FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ | ||
| 133 | ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \ | ||
| 134 | PCIE_TLP_TYPE_CFG0_WR)) | ||
| 135 | #define CFG1_READ_FMTTYPE \ | ||
| 136 | FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ | ||
| 137 | ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \ | ||
| 138 | PCIE_TLP_TYPE_CFG1_RD)) | ||
| 139 | #define CFG1_WRITE_FMTTYPE \ | ||
| 140 | FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ | ||
| 141 | ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \ | ||
| 142 | PCIE_TLP_TYPE_CFG1_WR)) | ||
| 143 | #define CFG_PAYLOAD_SIZE 0x01 /* 1 DWORD */ | ||
| 144 | #define TLP_HEADER_BYTE_EN(x, y) ((GENMASK((x) - 1, 0) << ((y) % 4))) | ||
| 145 | #define TLP_GET_VALUE(x, y, z) \ | ||
| 146 | (((x) >> ((((z) % 4)) * 8)) & GENMASK((8 * (y)) - 1, 0)) | ||
| 147 | #define TLP_SET_VALUE(x, y, z) \ | ||
| 148 | ((((x) & GENMASK((8 * (y)) - 1, 0)) << ((((z) % 4)) * 8))) | ||
| 149 | #define AST2600_TX_DESC1_VALUE 0x00002000 | ||
| 150 | #define AST2700_TX_DESC1_VALUE 0x00401000 | ||
| 151 | |||
| 152 | /** | ||
| 153 | * struct aspeed_pcie_port - PCIe port information | ||
| 154 | * @list: port list | ||
| 155 | * @pcie: pointer to PCIe host info | ||
| 156 | * @clk: pointer to the port clock gate | ||
| 157 | * @phy: pointer to PCIe PHY | ||
| 158 | * @perst: pointer to port reset control | ||
| 159 | * @slot: port slot | ||
| 160 | */ | ||
| 161 | struct aspeed_pcie_port { | ||
| 162 | struct list_head list; | ||
| 163 | struct aspeed_pcie *pcie; | ||
| 164 | struct clk *clk; | ||
| 165 | struct phy *phy; | ||
| 166 | struct reset_control *perst; | ||
| 167 | u32 slot; | ||
| 168 | }; | ||
| 169 | |||
| 170 | /** | ||
| 171 | * struct aspeed_pcie - PCIe RC information | ||
| 172 | * @host: pointer to PCIe host bridge | ||
| 173 | * @dev: pointer to device structure | ||
| 174 | * @reg: PCIe host register base address | ||
| 175 | * @ahbc: pointer to AHHC register map | ||
| 176 | * @cfg: pointer to Aspeed PCIe configuration register map | ||
| 177 | * @platform: platform specific information | ||
| 178 | * @ports: list of PCIe ports | ||
| 179 | * @tx_tag: current TX tag for the port | ||
| 180 | * @root_bus_nr: bus number of the host bridge | ||
| 181 | * @h2xrst: pointer to H2X reset control | ||
| 182 | * @intx_domain: IRQ domain for INTx interrupts | ||
| 183 | * @msi_domain: IRQ domain for MSI interrupts | ||
| 184 | * @lock: mutex to protect MSI bitmap variable | ||
| 185 | * @msi_irq_in_use: bitmap to track used MSI host IRQs | ||
| 186 | * @clear_msi_twice: AST2700 workaround to clear MSI status twice | ||
| 187 | */ | ||
| 188 | struct aspeed_pcie { | ||
| 189 | struct pci_host_bridge *host; | ||
| 190 | struct device *dev; | ||
| 191 | void __iomem *reg; | ||
| 192 | struct regmap *ahbc; | ||
| 193 | struct regmap *cfg; | ||
| 194 | const struct aspeed_pcie_rc_platform *platform; | ||
| 195 | struct list_head ports; | ||
| 196 | |||
| 197 | u8 tx_tag; | ||
| 198 | u8 root_bus_nr; | ||
| 199 | |||
| 200 | struct reset_control *h2xrst; | ||
| 201 | |||
| 202 | struct irq_domain *intx_domain; | ||
| 203 | struct irq_domain *msi_domain; | ||
| 204 | struct mutex lock; | ||
| 205 | DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); | ||
| 206 | |||
| 207 | bool clear_msi_twice; /* AST2700 workaround */ | ||
| 208 | }; | ||
| 209 | |||
| 210 | /** | ||
| 211 | * struct aspeed_pcie_rc_platform - Platform information | ||
| 212 | * @setup: initialization function | ||
| 213 | * @pcie_map_ranges: function to map PCIe address ranges | ||
| 214 | * @reg_intx_en: INTx enable register offset | ||
| 215 | * @reg_intx_sts: INTx status register offset | ||
| 216 | * @reg_msi_en: MSI enable register offset | ||
| 217 | * @reg_msi_sts: MSI enable register offset | ||
| 218 | * @msi_address: HW fixed MSI address | ||
| 219 | */ | ||
| 220 | struct aspeed_pcie_rc_platform { | ||
| 221 | int (*setup)(struct platform_device *pdev); | ||
| 222 | void (*pcie_map_ranges)(struct aspeed_pcie *pcie, u64 pci_addr); | ||
| 223 | int reg_intx_en; | ||
| 224 | int reg_intx_sts; | ||
| 225 | int reg_msi_en; | ||
| 226 | int reg_msi_sts; | ||
| 227 | u32 msi_address; | ||
| 228 | }; | ||
| 229 | |||
| 230 | static void aspeed_pcie_intx_irq_ack(struct irq_data *d) | ||
| 231 | { | ||
| 232 | struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); | ||
| 233 | int intx_en = pcie->platform->reg_intx_en; | ||
| 234 | u32 en; | ||
| 235 | |||
| 236 | en = readl(pcie->reg + intx_en); | ||
| 237 | en |= BIT(d->hwirq); | ||
| 238 | writel(en, pcie->reg + intx_en); | ||
| 239 | } | ||
| 240 | |||
| 241 | static void aspeed_pcie_intx_irq_mask(struct irq_data *d) | ||
| 242 | { | ||
| 243 | struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); | ||
| 244 | int intx_en = pcie->platform->reg_intx_en; | ||
| 245 | u32 en; | ||
| 246 | |||
| 247 | en = readl(pcie->reg + intx_en); | ||
| 248 | en &= ~BIT(d->hwirq); | ||
| 249 | writel(en, pcie->reg + intx_en); | ||
| 250 | } | ||
| 251 | |||
| 252 | static void aspeed_pcie_intx_irq_unmask(struct irq_data *d) | ||
| 253 | { | ||
| 254 | struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); | ||
| 255 | int intx_en = pcie->platform->reg_intx_en; | ||
| 256 | u32 en; | ||
| 257 | |||
| 258 | en = readl(pcie->reg + intx_en); | ||
| 259 | en |= BIT(d->hwirq); | ||
| 260 | writel(en, pcie->reg + intx_en); | ||
| 261 | } | ||
| 262 | |||
| 263 | static struct irq_chip aspeed_intx_irq_chip = { | ||
| 264 | .name = "INTx", | ||
| 265 | .irq_ack = aspeed_pcie_intx_irq_ack, | ||
| 266 | .irq_mask = aspeed_pcie_intx_irq_mask, | ||
| 267 | .irq_unmask = aspeed_pcie_intx_irq_unmask, | ||
| 268 | }; | ||
| 269 | |||
| 270 | static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq, | ||
| 271 | irq_hw_number_t hwirq) | ||
| 272 | { | ||
| 273 | irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq); | ||
| 274 | irq_set_chip_data(irq, domain->host_data); | ||
| 275 | irq_set_status_flags(irq, IRQ_LEVEL); | ||
| 276 | |||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static const struct irq_domain_ops aspeed_intx_domain_ops = { | ||
| 281 | .map = aspeed_pcie_intx_map, | ||
| 282 | }; | ||
| 283 | |||
| 284 | static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id) | ||
| 285 | { | ||
| 286 | struct aspeed_pcie *pcie = dev_id; | ||
| 287 | const struct aspeed_pcie_rc_platform *platform = pcie->platform; | ||
| 288 | unsigned long status; | ||
| 289 | unsigned long intx; | ||
| 290 | u32 bit; | ||
| 291 | int i; | ||
| 292 | |||
| 293 | intx = FIELD_GET(ASPEED_PCIE_INTX_STS, | ||
| 294 | readl(pcie->reg + platform->reg_intx_sts)); | ||
| 295 | for_each_set_bit(bit, &intx, PCI_NUM_INTX) | ||
| 296 | generic_handle_domain_irq(pcie->intx_domain, bit); | ||
| 297 | |||
| 298 | for (i = 0; i < 2; i++) { | ||
| 299 | int msi_sts_reg = platform->reg_msi_sts + (i * 4); | ||
| 300 | |||
| 301 | status = readl(pcie->reg + msi_sts_reg); | ||
| 302 | writel(status, pcie->reg + msi_sts_reg); | ||
| 303 | |||
| 304 | /* | ||
| 305 | * AST2700 workaround: | ||
| 306 | * The MSI status needs to clear one more time. | ||
| 307 | */ | ||
| 308 | if (pcie->clear_msi_twice) | ||
| 309 | writel(status, pcie->reg + msi_sts_reg); | ||
| 310 | |||
| 311 | for_each_set_bit(bit, &status, 32) { | ||
| 312 | bit += (i * 32); | ||
| 313 | generic_handle_domain_irq(pcie->msi_domain, bit); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | return IRQ_HANDLED; | ||
| 318 | } | ||
| 319 | |||
| 320 | static u32 aspeed_pcie_get_bdf_offset(struct pci_bus *bus, unsigned int devfn, | ||
| 321 | int where) | ||
| 322 | { | ||
| 323 | return ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | | ||
| 324 | (PCI_FUNC(devfn) << 16) | (where & ~3); | ||
| 325 | } | ||
| 326 | |||
| 327 | static int aspeed_ast2600_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 328 | int where, int size, u32 *val, u32 fmt_type, | ||
| 329 | bool write) | ||
| 330 | { | ||
| 331 | struct aspeed_pcie *pcie = bus->sysdata; | ||
| 332 | u32 bdf_offset, cfg_val, isr; | ||
| 333 | int ret; | ||
| 334 | |||
| 335 | bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where); | ||
| 336 | |||
| 337 | /* Driver may set unlock RX buffer before triggering next TX config */ | ||
| 338 | cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL); | ||
| 339 | writel(ASPEED_PCIE_UNLOCK_RX_BUFF | cfg_val, | ||
| 340 | pcie->reg + ASPEED_H2X_DEV_CTRL); | ||
| 341 | |||
| 342 | cfg_val = fmt_type | CFG_PAYLOAD_SIZE; | ||
| 343 | writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC0); | ||
| 344 | |||
| 345 | cfg_val = AST2600_TX_DESC1_VALUE | | ||
| 346 | FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) | | ||
| 347 | TLP_HEADER_BYTE_EN(size, where); | ||
| 348 | writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC1); | ||
| 349 | |||
| 350 | writel(bdf_offset, pcie->reg + ASPEED_H2X_TX_DESC2); | ||
| 351 | writel(0, pcie->reg + ASPEED_H2X_TX_DESC3); | ||
| 352 | if (write) | ||
| 353 | writel(TLP_SET_VALUE(*val, size, where), | ||
| 354 | pcie->reg + ASPEED_H2X_TX_DESC_DATA); | ||
| 355 | |||
| 356 | cfg_val = readl(pcie->reg + ASPEED_H2X_STS); | ||
| 357 | cfg_val |= ASPEED_PCIE_TRIGGER_TX; | ||
| 358 | writel(cfg_val, pcie->reg + ASPEED_H2X_STS); | ||
| 359 | |||
| 360 | ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_STS, cfg_val, | ||
| 361 | (cfg_val & ASPEED_PCIE_TX_IDLE), 0, 50); | ||
| 362 | if (ret) { | ||
| 363 | dev_err(pcie->dev, | ||
| 364 | "%02x:%02x.%d CR tx timeout sts: 0x%08x\n", | ||
| 365 | bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), cfg_val); | ||
| 366 | ret = PCIBIOS_SET_FAILED; | ||
| 367 | PCI_SET_ERROR_RESPONSE(val); | ||
| 368 | goto out; | ||
| 369 | } | ||
| 370 | |||
| 371 | cfg_val = readl(pcie->reg + ASPEED_H2X_INT_STS); | ||
| 372 | cfg_val |= ASPEED_PCIE_TX_IDLE_CLEAR; | ||
| 373 | writel(cfg_val, pcie->reg + ASPEED_H2X_INT_STS); | ||
| 374 | |||
| 375 | cfg_val = readl(pcie->reg + ASPEED_H2X_STS); | ||
| 376 | switch (cfg_val & ASPEED_PCIE_STATUS_OF_TX) { | ||
| 377 | case ASPEED_PCIE_RC_H_TX_COMPLETE: | ||
| 378 | ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_DEV_STS, isr, | ||
| 379 | (isr & ASPEED_PCIE_RC_RX_DONE_ISR), 0, | ||
| 380 | 50); | ||
| 381 | if (ret) { | ||
| 382 | dev_err(pcie->dev, | ||
| 383 | "%02x:%02x.%d CR rx timeout sts: 0x%08x\n", | ||
| 384 | bus->number, PCI_SLOT(devfn), | ||
| 385 | PCI_FUNC(devfn), isr); | ||
| 386 | ret = PCIBIOS_SET_FAILED; | ||
| 387 | PCI_SET_ERROR_RESPONSE(val); | ||
| 388 | goto out; | ||
| 389 | } | ||
| 390 | if (!write) { | ||
| 391 | cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_RX_DESC1); | ||
| 392 | if (CPL_STS(cfg_val) != PCIE_CPL_STS_SUCCESS) { | ||
| 393 | ret = PCIBIOS_SET_FAILED; | ||
| 394 | PCI_SET_ERROR_RESPONSE(val); | ||
| 395 | goto out; | ||
| 396 | } else { | ||
| 397 | *val = readl(pcie->reg + | ||
| 398 | ASPEED_H2X_DEV_RX_DESC_DATA); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | break; | ||
| 402 | case ASPEED_PCIE_STATUS_OF_TX: | ||
| 403 | ret = PCIBIOS_SET_FAILED; | ||
| 404 | PCI_SET_ERROR_RESPONSE(val); | ||
| 405 | goto out; | ||
| 406 | default: | ||
| 407 | *val = readl(pcie->reg + ASPEED_H2X_HOST_RX_DESC_DATA); | ||
| 408 | break; | ||
| 409 | } | ||
| 410 | |||
| 411 | cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL); | ||
| 412 | cfg_val |= ASPEED_PCIE_UNLOCK_RX_BUFF; | ||
| 413 | writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_CTRL); | ||
| 414 | |||
| 415 | *val = TLP_GET_VALUE(*val, size, where); | ||
| 416 | |||
| 417 | ret = PCIBIOS_SUCCESSFUL; | ||
| 418 | out: | ||
| 419 | cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_STS); | ||
| 420 | writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_STS); | ||
| 421 | pcie->tx_tag = (pcie->tx_tag + 1) % 0x8; | ||
| 422 | return ret; | ||
| 423 | } | ||
| 424 | |||
| 425 | static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 426 | int where, int size, u32 *val) | ||
| 427 | { | ||
| 428 | /* | ||
| 429 | * AST2600 has only one Root Port on the root bus. | ||
| 430 | */ | ||
| 431 | if (PCI_SLOT(devfn) != 8) | ||
| 432 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 433 | |||
| 434 | return aspeed_ast2600_conf(bus, devfn, where, size, val, | ||
| 435 | CFG0_READ_FMTTYPE, false); | ||
| 436 | } | ||
| 437 | |||
| 438 | static int aspeed_ast2600_child_rd_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 439 | int where, int size, u32 *val) | ||
| 440 | { | ||
| 441 | return aspeed_ast2600_conf(bus, devfn, where, size, val, | ||
| 442 | CFG1_READ_FMTTYPE, false); | ||
| 443 | } | ||
| 444 | |||
| 445 | static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 446 | int where, int size, u32 val) | ||
| 447 | { | ||
| 448 | /* | ||
| 449 | * AST2600 has only one Root Port on the root bus. | ||
| 450 | */ | ||
| 451 | if (PCI_SLOT(devfn) != 8) | ||
| 452 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 453 | |||
| 454 | return aspeed_ast2600_conf(bus, devfn, where, size, &val, | ||
| 455 | CFG0_WRITE_FMTTYPE, true); | ||
| 456 | } | ||
| 457 | |||
| 458 | static int aspeed_ast2600_child_wr_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 459 | int where, int size, u32 val) | ||
| 460 | { | ||
| 461 | return aspeed_ast2600_conf(bus, devfn, where, size, &val, | ||
| 462 | CFG1_WRITE_FMTTYPE, true); | ||
| 463 | } | ||
| 464 | |||
| 465 | static int aspeed_ast2700_config(struct pci_bus *bus, unsigned int devfn, | ||
| 466 | int where, int size, u32 *val, bool write) | ||
| 467 | { | ||
| 468 | struct aspeed_pcie *pcie = bus->sysdata; | ||
| 469 | u32 cfg_val; | ||
| 470 | |||
| 471 | cfg_val = ASPEED_CFGI_BYTE_EN(TLP_HEADER_BYTE_EN(size, where)) | | ||
| 472 | (where & ~3); | ||
| 473 | if (write) | ||
| 474 | cfg_val |= ASPEED_CFGI_WRITE; | ||
| 475 | writel(cfg_val, pcie->reg + ASPEED_H2X_CFGI_TLP); | ||
| 476 | |||
| 477 | writel(TLP_SET_VALUE(*val, size, where), | ||
| 478 | pcie->reg + ASPEED_H2X_CFGI_WR_DATA); | ||
| 479 | writel(ASPEED_CFGI_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGI_CTRL); | ||
| 480 | *val = readl(pcie->reg + ASPEED_H2X_CFGI_RET_DATA); | ||
| 481 | *val = TLP_GET_VALUE(*val, size, where); | ||
| 482 | |||
| 483 | return PCIBIOS_SUCCESSFUL; | ||
| 484 | } | ||
| 485 | |||
| 486 | static int aspeed_ast2700_child_config(struct pci_bus *bus, unsigned int devfn, | ||
| 487 | int where, int size, u32 *val, | ||
| 488 | bool write) | ||
| 489 | { | ||
| 490 | struct aspeed_pcie *pcie = bus->sysdata; | ||
| 491 | u32 bdf_offset, status, cfg_val; | ||
| 492 | int ret; | ||
| 493 | |||
| 494 | bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where); | ||
| 495 | |||
| 496 | cfg_val = CFG_PAYLOAD_SIZE; | ||
| 497 | if (write) | ||
| 498 | cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ? | ||
| 499 | CFG0_WRITE_FMTTYPE : | ||
| 500 | CFG1_WRITE_FMTTYPE; | ||
| 501 | else | ||
| 502 | cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ? | ||
| 503 | CFG0_READ_FMTTYPE : | ||
| 504 | CFG1_READ_FMTTYPE; | ||
| 505 | writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_1ST); | ||
| 506 | |||
| 507 | cfg_val = AST2700_TX_DESC1_VALUE | | ||
| 508 | FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) | | ||
| 509 | TLP_HEADER_BYTE_EN(size, where); | ||
| 510 | writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); | ||
| 511 | |||
| 512 | writel(bdf_offset, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); | ||
| 513 | if (write) | ||
| 514 | writel(TLP_SET_VALUE(*val, size, where), | ||
| 515 | pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); | ||
| 516 | writel(ASPEED_CFGE_TX_IDLE | ASPEED_CFGE_RX_BUSY, | ||
| 517 | pcie->reg + ASPEED_H2X_CFGE_INT_STS); | ||
| 518 | writel(ASPEED_CFGE_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGE_CTRL); | ||
| 519 | |||
| 520 | ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status, | ||
| 521 | (status & ASPEED_CFGE_TX_IDLE), 0, 50); | ||
| 522 | if (ret) { | ||
| 523 | dev_err(pcie->dev, | ||
| 524 | "%02x:%02x.%d CR tx timeout sts: 0x%08x\n", | ||
| 525 | bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status); | ||
| 526 | ret = PCIBIOS_SET_FAILED; | ||
| 527 | PCI_SET_ERROR_RESPONSE(val); | ||
| 528 | goto out; | ||
| 529 | } | ||
| 530 | |||
| 531 | ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status, | ||
| 532 | (status & ASPEED_CFGE_RX_BUSY), 0, 50); | ||
| 533 | if (ret) { | ||
| 534 | dev_err(pcie->dev, | ||
| 535 | "%02x:%02x.%d CR rx timeout sts: 0x%08x\n", | ||
| 536 | bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status); | ||
| 537 | ret = PCIBIOS_SET_FAILED; | ||
| 538 | PCI_SET_ERROR_RESPONSE(val); | ||
| 539 | goto out; | ||
| 540 | } | ||
| 541 | *val = readl(pcie->reg + ASPEED_H2X_CFGE_RET_DATA); | ||
| 542 | *val = TLP_GET_VALUE(*val, size, where); | ||
| 543 | |||
| 544 | ret = PCIBIOS_SUCCESSFUL; | ||
| 545 | out: | ||
| 546 | writel(status, pcie->reg + ASPEED_H2X_CFGE_INT_STS); | ||
| 547 | pcie->tx_tag = (pcie->tx_tag + 1) % 0xf; | ||
| 548 | return ret; | ||
| 549 | } | ||
| 550 | |||
| 551 | static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 552 | int where, int size, u32 *val) | ||
| 553 | { | ||
| 554 | /* | ||
| 555 | * AST2700 has only one Root Port on the root bus. | ||
| 556 | */ | ||
| 557 | if (devfn != 0) | ||
| 558 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 559 | |||
| 560 | return aspeed_ast2700_config(bus, devfn, where, size, val, false); | ||
| 561 | } | ||
| 562 | |||
| 563 | static int aspeed_ast2700_child_rd_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 564 | int where, int size, u32 *val) | ||
| 565 | { | ||
| 566 | return aspeed_ast2700_child_config(bus, devfn, where, size, val, false); | ||
| 567 | } | ||
| 568 | |||
| 569 | static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 570 | int where, int size, u32 val) | ||
| 571 | { | ||
| 572 | /* | ||
| 573 | * AST2700 has only one Root Port on the root bus. | ||
| 574 | */ | ||
| 575 | if (devfn != 0) | ||
| 576 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
| 577 | |||
| 578 | return aspeed_ast2700_config(bus, devfn, where, size, &val, true); | ||
| 579 | } | ||
| 580 | |||
| 581 | static int aspeed_ast2700_child_wr_conf(struct pci_bus *bus, unsigned int devfn, | ||
| 582 | int where, int size, u32 val) | ||
| 583 | { | ||
| 584 | return aspeed_ast2700_child_config(bus, devfn, where, size, &val, true); | ||
| 585 | } | ||
| 586 | |||
| 587 | static struct pci_ops aspeed_ast2600_pcie_ops = { | ||
| 588 | .read = aspeed_ast2600_rd_conf, | ||
| 589 | .write = aspeed_ast2600_wr_conf, | ||
| 590 | }; | ||
| 591 | |||
| 592 | static struct pci_ops aspeed_ast2600_pcie_child_ops = { | ||
| 593 | .read = aspeed_ast2600_child_rd_conf, | ||
| 594 | .write = aspeed_ast2600_child_wr_conf, | ||
| 595 | }; | ||
| 596 | |||
| 597 | static struct pci_ops aspeed_ast2700_pcie_ops = { | ||
| 598 | .read = aspeed_ast2700_rd_conf, | ||
| 599 | .write = aspeed_ast2700_wr_conf, | ||
| 600 | }; | ||
| 601 | |||
| 602 | static struct pci_ops aspeed_ast2700_pcie_child_ops = { | ||
| 603 | .read = aspeed_ast2700_child_rd_conf, | ||
| 604 | .write = aspeed_ast2700_child_wr_conf, | ||
| 605 | }; | ||
| 606 | |||
| 607 | static void aspeed_irq_compose_msi_msg(struct irq_data *data, | ||
| 608 | struct msi_msg *msg) | ||
| 609 | { | ||
| 610 | struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); | ||
| 611 | |||
| 612 | msg->address_hi = 0; | ||
| 613 | msg->address_lo = pcie->platform->msi_address; | ||
| 614 | msg->data = data->hwirq; | ||
| 615 | } | ||
| 616 | |||
| 617 | static struct irq_chip aspeed_msi_bottom_irq_chip = { | ||
| 618 | .name = "ASPEED MSI", | ||
| 619 | .irq_compose_msi_msg = aspeed_irq_compose_msi_msg, | ||
| 620 | }; | ||
| 621 | |||
| 622 | static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain, | ||
| 623 | unsigned int virq, unsigned int nr_irqs, | ||
| 624 | void *args) | ||
| 625 | { | ||
| 626 | struct aspeed_pcie *pcie = domain->host_data; | ||
| 627 | int bit; | ||
| 628 | int i; | ||
| 629 | |||
| 630 | guard(mutex)(&pcie->lock); | ||
| 631 | |||
| 632 | bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS, | ||
| 633 | get_count_order(nr_irqs)); | ||
| 634 | |||
| 635 | if (bit < 0) | ||
| 636 | return -ENOSPC; | ||
| 637 | |||
| 638 | for (i = 0; i < nr_irqs; i++) { | ||
| 639 | irq_domain_set_info(domain, virq + i, bit + i, | ||
| 640 | &aspeed_msi_bottom_irq_chip, | ||
| 641 | domain->host_data, handle_simple_irq, NULL, | ||
| 642 | NULL); | ||
| 643 | } | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | static void aspeed_irq_msi_domain_free(struct irq_domain *domain, | ||
| 649 | unsigned int virq, unsigned int nr_irqs) | ||
| 650 | { | ||
| 651 | struct irq_data *data = irq_domain_get_irq_data(domain, virq); | ||
| 652 | struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); | ||
| 653 | |||
| 654 | guard(mutex)(&pcie->lock); | ||
| 655 | |||
| 656 | bitmap_release_region(pcie->msi_irq_in_use, data->hwirq, | ||
| 657 | get_count_order(nr_irqs)); | ||
| 658 | } | ||
| 659 | |||
| 660 | static const struct irq_domain_ops aspeed_msi_domain_ops = { | ||
| 661 | .alloc = aspeed_irq_msi_domain_alloc, | ||
| 662 | .free = aspeed_irq_msi_domain_free, | ||
| 663 | }; | ||
| 664 | |||
| 665 | #define ASPEED_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ | ||
| 666 | MSI_FLAG_USE_DEF_CHIP_OPS | \ | ||
| 667 | MSI_FLAG_NO_AFFINITY) | ||
| 668 | |||
| 669 | #define ASPEED_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ | ||
| 670 | MSI_FLAG_MULTI_PCI_MSI | \ | ||
| 671 | MSI_FLAG_PCI_MSIX) | ||
| 672 | |||
| 673 | static const struct msi_parent_ops aspeed_msi_parent_ops = { | ||
| 674 | .required_flags = ASPEED_MSI_FLAGS_REQUIRED, | ||
| 675 | .supported_flags = ASPEED_MSI_FLAGS_SUPPORTED, | ||
| 676 | .bus_select_token = DOMAIN_BUS_PCI_MSI, | ||
| 677 | .chip_flags = MSI_CHIP_FLAG_SET_ACK, | ||
| 678 | .prefix = "ASPEED-", | ||
| 679 | .init_dev_msi_info = msi_lib_init_dev_msi_info, | ||
| 680 | }; | ||
| 681 | |||
| 682 | static int aspeed_pcie_msi_init(struct aspeed_pcie *pcie) | ||
| 683 | { | ||
| 684 | writel(~0, pcie->reg + pcie->platform->reg_msi_en); | ||
| 685 | writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04); | ||
| 686 | writel(~0, pcie->reg + pcie->platform->reg_msi_sts); | ||
| 687 | writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04); | ||
| 688 | |||
| 689 | struct irq_domain_info info = { | ||
| 690 | .fwnode = dev_fwnode(pcie->dev), | ||
| 691 | .ops = &aspeed_msi_domain_ops, | ||
| 692 | .host_data = pcie, | ||
| 693 | .size = MAX_MSI_HOST_IRQS, | ||
| 694 | }; | ||
| 695 | |||
| 696 | pcie->msi_domain = msi_create_parent_irq_domain(&info, | ||
| 697 | &aspeed_msi_parent_ops); | ||
| 698 | if (!pcie->msi_domain) | ||
| 699 | return dev_err_probe(pcie->dev, -ENOMEM, | ||
| 700 | "failed to create MSI domain\n"); | ||
| 701 | |||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | static void aspeed_pcie_msi_free(struct aspeed_pcie *pcie) | ||
| 706 | { | ||
| 707 | if (pcie->msi_domain) { | ||
| 708 | irq_domain_remove(pcie->msi_domain); | ||
| 709 | pcie->msi_domain = NULL; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 713 | static void aspeed_pcie_irq_domain_free(void *d) | ||
| 714 | { | ||
| 715 | struct aspeed_pcie *pcie = d; | ||
| 716 | |||
| 717 | if (pcie->intx_domain) { | ||
| 718 | irq_domain_remove(pcie->intx_domain); | ||
| 719 | pcie->intx_domain = NULL; | ||
| 720 | } | ||
| 721 | aspeed_pcie_msi_free(pcie); | ||
| 722 | } | ||
| 723 | |||
| 724 | static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie) | ||
| 725 | { | ||
| 726 | int ret; | ||
| 727 | |||
| 728 | pcie->intx_domain = irq_domain_add_linear(pcie->dev->of_node, | ||
| 729 | PCI_NUM_INTX, | ||
| 730 | &aspeed_intx_domain_ops, | ||
| 731 | pcie); | ||
| 732 | if (!pcie->intx_domain) { | ||
| 733 | ret = dev_err_probe(pcie->dev, -ENOMEM, | ||
| 734 | "failed to get INTx IRQ domain\n"); | ||
| 735 | goto err; | ||
| 736 | } | ||
| 737 | |||
| 738 | writel(0, pcie->reg + pcie->platform->reg_intx_en); | ||
| 739 | writel(~0, pcie->reg + pcie->platform->reg_intx_sts); | ||
| 740 | |||
| 741 | ret = aspeed_pcie_msi_init(pcie); | ||
| 742 | if (ret) | ||
| 743 | goto err; | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | err: | ||
| 747 | aspeed_pcie_irq_domain_free(pcie); | ||
| 748 | return ret; | ||
| 749 | } | ||
| 750 | |||
| 751 | static int aspeed_pcie_port_init(struct aspeed_pcie_port *port) | ||
| 752 | { | ||
| 753 | struct aspeed_pcie *pcie = port->pcie; | ||
| 754 | struct device *dev = pcie->dev; | ||
| 755 | int ret; | ||
| 756 | |||
| 757 | ret = clk_prepare_enable(port->clk); | ||
| 758 | if (ret) | ||
| 759 | return dev_err_probe(dev, ret, | ||
| 760 | "failed to set clock for slot (%d)\n", | ||
| 761 | port->slot); | ||
| 762 | |||
| 763 | ret = phy_init(port->phy); | ||
| 764 | if (ret) | ||
| 765 | return dev_err_probe(dev, ret, | ||
| 766 | "failed to init phy pcie for slot (%d)\n", | ||
| 767 | port->slot); | ||
| 768 | |||
| 769 | ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); | ||
| 770 | if (ret) | ||
| 771 | return dev_err_probe(dev, ret, | ||
| 772 | "failed to set phy mode for slot (%d)\n", | ||
| 773 | port->slot); | ||
| 774 | |||
| 775 | reset_control_deassert(port->perst); | ||
| 776 | msleep(PCIE_RESET_CONFIG_WAIT_MS); | ||
| 777 | |||
| 778 | return 0; | ||
| 779 | } | ||
| 780 | |||
| 781 | static void aspeed_host_reset(struct aspeed_pcie *pcie) | ||
| 782 | { | ||
| 783 | reset_control_assert(pcie->h2xrst); | ||
| 784 | mdelay(ASPEED_RESET_RC_WAIT_MS); | ||
| 785 | reset_control_deassert(pcie->h2xrst); | ||
| 786 | } | ||
| 787 | |||
| 788 | static void aspeed_pcie_map_ranges(struct aspeed_pcie *pcie) | ||
| 789 | { | ||
| 790 | struct pci_host_bridge *bridge = pcie->host; | ||
| 791 | struct resource_entry *window; | ||
| 792 | |||
| 793 | resource_list_for_each_entry(window, &bridge->windows) { | ||
| 794 | u64 pci_addr; | ||
| 795 | |||
| 796 | if (resource_type(window->res) != IORESOURCE_MEM) | ||
| 797 | continue; | ||
| 798 | |||
| 799 | pci_addr = window->res->start - window->offset; | ||
| 800 | pcie->platform->pcie_map_ranges(pcie, pci_addr); | ||
| 801 | break; | ||
| 802 | } | ||
| 803 | } | ||
| 804 | |||
| 805 | static void aspeed_ast2600_pcie_map_ranges(struct aspeed_pcie *pcie, | ||
| 806 | u64 pci_addr) | ||
| 807 | { | ||
| 808 | u32 pci_addr_lo = pci_addr & GENMASK(31, 0); | ||
| 809 | u32 pci_addr_hi = (pci_addr >> 32) & GENMASK(31, 0); | ||
| 810 | |||
| 811 | pci_addr_lo >>= 16; | ||
| 812 | writel(ASPEED_AHB_REMAP_LO_ADDR(pci_addr_lo) | | ||
| 813 | ASPEED_AHB_MASK_LO_ADDR(0xe00), | ||
| 814 | pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0); | ||
| 815 | writel(ASPEED_AHB_REMAP_HI_ADDR(pci_addr_hi), | ||
| 816 | pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1); | ||
| 817 | writel(ASPEED_AHB_MASK_HI_ADDR(~0), | ||
| 818 | pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2); | ||
| 819 | } | ||
| 820 | |||
| 821 | static int aspeed_ast2600_setup(struct platform_device *pdev) | ||
| 822 | { | ||
| 823 | struct aspeed_pcie *pcie = platform_get_drvdata(pdev); | ||
| 824 | struct device *dev = pcie->dev; | ||
| 825 | |||
| 826 | pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
| 827 | "aspeed,ahbc"); | ||
| 828 | if (IS_ERR(pcie->ahbc)) | ||
| 829 | return dev_err_probe(dev, PTR_ERR(pcie->ahbc), | ||
| 830 | "failed to map ahbc base\n"); | ||
| 831 | |||
| 832 | aspeed_host_reset(pcie); | ||
| 833 | |||
| 834 | regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK_KEY); | ||
| 835 | regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING, | ||
| 836 | ASPEED_PCIE_RC_MEMORY_EN, ASPEED_PCIE_RC_MEMORY_EN); | ||
| 837 | regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK); | ||
| 838 | |||
| 839 | writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL); | ||
| 840 | |||
| 841 | writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR | | ||
| 842 | ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN | | ||
| 843 | ASPEED_PCIE_WAIT_RX_TLP_CLR | ASPEED_PCIE_RC_RX_ENABLE | | ||
| 844 | ASPEED_PCIE_RC_ENABLE, | ||
| 845 | pcie->reg + ASPEED_H2X_DEV_CTRL); | ||
| 846 | |||
| 847 | writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg + ASPEED_H2X_DEV_TX_TAG); | ||
| 848 | |||
| 849 | pcie->host->ops = &aspeed_ast2600_pcie_ops; | ||
| 850 | pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops; | ||
| 851 | |||
| 852 | return 0; | ||
| 853 | } | ||
| 854 | |||
| 855 | static void aspeed_ast2700_pcie_map_ranges(struct aspeed_pcie *pcie, | ||
| 856 | u64 pci_addr) | ||
| 857 | { | ||
| 858 | writel(ASPEED_REMAP_PCI_ADDR_31_12(pci_addr), | ||
| 859 | pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO); | ||
| 860 | writel(ASPEED_REMAP_PCI_ADDR_63_32(pci_addr), | ||
| 861 | pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI); | ||
| 862 | } | ||
| 863 | |||
| 864 | static int aspeed_ast2700_setup(struct platform_device *pdev) | ||
| 865 | { | ||
| 866 | struct aspeed_pcie *pcie = platform_get_drvdata(pdev); | ||
| 867 | struct device *dev = pcie->dev; | ||
| 868 | |||
| 869 | pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
| 870 | "aspeed,pciecfg"); | ||
| 871 | if (IS_ERR(pcie->cfg)) | ||
| 872 | return dev_err_probe(dev, PTR_ERR(pcie->cfg), | ||
| 873 | "failed to map pciecfg base\n"); | ||
| 874 | |||
| 875 | regmap_update_bits(pcie->cfg, ASPEED_SCU_60, | ||
| 876 | ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN | | ||
| 877 | ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN | | ||
| 878 | ASPEED_RC_UPSTREAM_MEM_EN, | ||
| 879 | ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN | | ||
| 880 | ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN | | ||
| 881 | ASPEED_RC_UPSTREAM_MEM_EN); | ||
| 882 | regmap_write(pcie->cfg, ASPEED_SCU_64, | ||
| 883 | ASPEED_RC0_DECODE_DMA_BASE(0) | | ||
| 884 | ASPEED_RC0_DECODE_DMA_LIMIT(0xff) | | ||
| 885 | ASPEED_RC1_DECODE_DMA_BASE(0) | | ||
| 886 | ASPEED_RC1_DECODE_DMA_LIMIT(0xff)); | ||
| 887 | regmap_write(pcie->cfg, ASPEED_SCU_70, ASPEED_DISABLE_EP_FUNC); | ||
| 888 | |||
| 889 | aspeed_host_reset(pcie); | ||
| 890 | |||
| 891 | writel(0, pcie->reg + ASPEED_H2X_CTRL); | ||
| 892 | writel(ASPEED_H2X_BRIDGE_EN | ASPEED_H2X_BRIDGE_DIRECT_EN, | ||
| 893 | pcie->reg + ASPEED_H2X_CTRL); | ||
| 894 | |||
| 895 | /* Prepare for 64-bit BAR pref */ | ||
| 896 | writel(ASPEED_REMAP_PREF_ADDR_63_32(0x3), | ||
| 897 | pcie->reg + ASPEED_H2X_REMAP_PREF_ADDR); | ||
| 898 | |||
| 899 | pcie->host->ops = &aspeed_ast2700_pcie_ops; | ||
| 900 | pcie->host->child_ops = &aspeed_ast2700_pcie_child_ops; | ||
| 901 | pcie->clear_msi_twice = true; | ||
| 902 | |||
| 903 | return 0; | ||
| 904 | } | ||
| 905 | |||
| 906 | static void aspeed_pcie_reset_release(void *d) | ||
| 907 | { | ||
| 908 | struct reset_control *perst = d; | ||
| 909 | |||
| 910 | if (!perst) | ||
| 911 | return; | ||
| 912 | |||
| 913 | reset_control_put(perst); | ||
| 914 | } | ||
| 915 | |||
| 916 | static int aspeed_pcie_parse_port(struct aspeed_pcie *pcie, | ||
| 917 | struct device_node *node, | ||
| 918 | int slot) | ||
| 919 | { | ||
| 920 | struct aspeed_pcie_port *port; | ||
| 921 | struct device *dev = pcie->dev; | ||
| 922 | int ret; | ||
| 923 | |||
| 924 | port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); | ||
| 925 | if (!port) | ||
| 926 | return -ENOMEM; | ||
| 927 | |||
| 928 | port->clk = devm_get_clk_from_child(dev, node, NULL); | ||
| 929 | if (IS_ERR(port->clk)) | ||
| 930 | return dev_err_probe(dev, PTR_ERR(port->clk), | ||
| 931 | "failed to get pcie%d clock\n", slot); | ||
| 932 | |||
| 933 | port->phy = devm_of_phy_get(dev, node, NULL); | ||
| 934 | if (IS_ERR(port->phy)) | ||
| 935 | return dev_err_probe(dev, PTR_ERR(port->phy), | ||
| 936 | "failed to get phy pcie%d\n", slot); | ||
| 937 | |||
| 938 | port->perst = of_reset_control_get_exclusive(node, "perst"); | ||
| 939 | if (IS_ERR(port->perst)) | ||
| 940 | return dev_err_probe(dev, PTR_ERR(port->perst), | ||
| 941 | "failed to get pcie%d reset control\n", | ||
| 942 | slot); | ||
| 943 | ret = devm_add_action_or_reset(dev, aspeed_pcie_reset_release, | ||
| 944 | port->perst); | ||
| 945 | if (ret) | ||
| 946 | return ret; | ||
| 947 | reset_control_assert(port->perst); | ||
| 948 | |||
| 949 | port->slot = slot; | ||
| 950 | port->pcie = pcie; | ||
| 951 | |||
| 952 | INIT_LIST_HEAD(&port->list); | ||
| 953 | list_add_tail(&port->list, &pcie->ports); | ||
| 954 | |||
| 955 | ret = aspeed_pcie_port_init(port); | ||
| 956 | if (ret) | ||
| 957 | return ret; | ||
| 958 | |||
| 959 | return 0; | ||
| 960 | } | ||
| 961 | |||
| 962 | static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie) | ||
| 963 | { | ||
| 964 | struct device *dev = pcie->dev; | ||
| 965 | struct device_node *node = dev->of_node; | ||
| 966 | int ret; | ||
| 967 | |||
| 968 | for_each_available_child_of_node_scoped(node, child) { | ||
| 969 | int slot; | ||
| 970 | const char *type; | ||
| 971 | |||
| 972 | ret = of_property_read_string(child, "device_type", &type); | ||
| 973 | if (ret || strcmp(type, "pci")) | ||
| 974 | continue; | ||
| 975 | |||
| 976 | ret = of_pci_get_devfn(child); | ||
| 977 | if (ret < 0) | ||
| 978 | return dev_err_probe(dev, ret, | ||
| 979 | "failed to parse devfn\n"); | ||
| 980 | |||
| 981 | slot = PCI_SLOT(ret); | ||
| 982 | |||
| 983 | ret = aspeed_pcie_parse_port(pcie, child, slot); | ||
| 984 | if (ret) | ||
| 985 | return ret; | ||
| 986 | } | ||
| 987 | |||
| 988 | if (list_empty(&pcie->ports)) | ||
| 989 | return dev_err_probe(dev, -ENODEV, | ||
| 990 | "No PCIe port found in DT\n"); | ||
| 991 | |||
| 992 | return 0; | ||
| 993 | } | ||
| 994 | |||
| 995 | static int aspeed_pcie_probe(struct platform_device *pdev) | ||
| 996 | { | ||
| 997 | struct device *dev = &pdev->dev; | ||
| 998 | struct pci_host_bridge *host; | ||
| 999 | struct aspeed_pcie *pcie; | ||
| 1000 | struct resource_entry *entry; | ||
| 1001 | const struct aspeed_pcie_rc_platform *md; | ||
| 1002 | int irq, ret; | ||
| 1003 | |||
| 1004 | md = of_device_get_match_data(dev); | ||
| 1005 | if (!md) | ||
| 1006 | return -ENODEV; | ||
| 1007 | |||
| 1008 | host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); | ||
| 1009 | if (!host) | ||
| 1010 | return -ENOMEM; | ||
| 1011 | |||
| 1012 | pcie = pci_host_bridge_priv(host); | ||
| 1013 | pcie->dev = dev; | ||
| 1014 | pcie->tx_tag = 0; | ||
| 1015 | platform_set_drvdata(pdev, pcie); | ||
| 1016 | |||
| 1017 | pcie->platform = md; | ||
| 1018 | pcie->host = host; | ||
| 1019 | INIT_LIST_HEAD(&pcie->ports); | ||
| 1020 | |||
| 1021 | /* Get root bus num for cfg command to decide tlp type 0 or type 1 */ | ||
| 1022 | entry = resource_list_first_type(&host->windows, IORESOURCE_BUS); | ||
| 1023 | if (entry) | ||
| 1024 | pcie->root_bus_nr = entry->res->start; | ||
| 1025 | |||
| 1026 | pcie->reg = devm_platform_ioremap_resource(pdev, 0); | ||
| 1027 | if (IS_ERR(pcie->reg)) | ||
| 1028 | return PTR_ERR(pcie->reg); | ||
| 1029 | |||
| 1030 | pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x"); | ||
| 1031 | if (IS_ERR(pcie->h2xrst)) | ||
| 1032 | return dev_err_probe(dev, PTR_ERR(pcie->h2xrst), | ||
| 1033 | "failed to get h2x reset\n"); | ||
| 1034 | |||
| 1035 | ret = devm_mutex_init(dev, &pcie->lock); | ||
| 1036 | if (ret) | ||
| 1037 | return dev_err_probe(dev, ret, "failed to init mutex\n"); | ||
| 1038 | |||
| 1039 | ret = pcie->platform->setup(pdev); | ||
| 1040 | if (ret) | ||
| 1041 | return dev_err_probe(dev, ret, "failed to setup PCIe RC\n"); | ||
| 1042 | |||
| 1043 | aspeed_pcie_map_ranges(pcie); | ||
| 1044 | |||
| 1045 | ret = aspeed_pcie_parse_dt(pcie); | ||
| 1046 | if (ret) | ||
| 1047 | return ret; | ||
| 1048 | |||
| 1049 | host->sysdata = pcie; | ||
| 1050 | |||
| 1051 | ret = aspeed_pcie_init_irq_domain(pcie); | ||
| 1052 | if (ret) | ||
| 1053 | return ret; | ||
| 1054 | |||
| 1055 | irq = platform_get_irq(pdev, 0); | ||
| 1056 | if (irq < 0) | ||
| 1057 | return irq; | ||
| 1058 | |||
| 1059 | ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie); | ||
| 1060 | if (ret) | ||
| 1061 | return ret; | ||
| 1062 | |||
| 1063 | ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED, | ||
| 1064 | dev_name(dev), pcie); | ||
| 1065 | if (ret) | ||
| 1066 | return ret; | ||
| 1067 | |||
| 1068 | return pci_host_probe(host); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | static const struct aspeed_pcie_rc_platform pcie_rc_ast2600 = { | ||
| 1072 | .setup = aspeed_ast2600_setup, | ||
| 1073 | .pcie_map_ranges = aspeed_ast2600_pcie_map_ranges, | ||
| 1074 | .reg_intx_en = 0xc4, | ||
| 1075 | .reg_intx_sts = 0xc8, | ||
| 1076 | .reg_msi_en = 0xe0, | ||
| 1077 | .reg_msi_sts = 0xe8, | ||
| 1078 | .msi_address = 0x1e77005c, | ||
| 1079 | }; | ||
| 1080 | |||
| 1081 | static const struct aspeed_pcie_rc_platform pcie_rc_ast2700 = { | ||
| 1082 | .setup = aspeed_ast2700_setup, | ||
| 1083 | .pcie_map_ranges = aspeed_ast2700_pcie_map_ranges, | ||
| 1084 | .reg_intx_en = 0x40, | ||
| 1085 | .reg_intx_sts = 0x48, | ||
| 1086 | .reg_msi_en = 0x50, | ||
| 1087 | .reg_msi_sts = 0x58, | ||
| 1088 | .msi_address = 0x000000f0, | ||
| 1089 | }; | ||
| 1090 | |||
| 1091 | static const struct of_device_id aspeed_pcie_of_match[] = { | ||
| 1092 | { .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 }, | ||
| 1093 | { .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 }, | ||
| 1094 | {} | ||
| 1095 | }; | ||
| 1096 | |||
| 1097 | static struct platform_driver aspeed_pcie_driver = { | ||
| 1098 | .driver = { | ||
| 1099 | .name = "aspeed-pcie", | ||
| 1100 | .of_match_table = aspeed_pcie_of_match, | ||
| 1101 | .suppress_bind_attrs = true, | ||
| 1102 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
| 1103 | }, | ||
| 1104 | .probe = aspeed_pcie_probe, | ||
| 1105 | }; | ||
| 1106 | |||
| 1107 | builtin_platform_driver(aspeed_pcie_driver); | ||
| 1108 | |||
| 1109 | MODULE_AUTHOR("Jacky Chou <jacky_chou@aspeedtech.com>"); | ||
| 1110 | MODULE_DESCRIPTION("ASPEED PCIe Root Complex"); | ||
| 1111 | MODULE_LICENSE("GPL"); | ||
| @@ -585,8 +585,10 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, · 584 unmodified lines | |||
| 585 | 585 | ||
| 586 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | 586 | if (IS_ENABLED(CONFIG_PCI_MSI)) { |
| 587 | ret = mtk_pcie_allocate_msi_domains(port); | 587 | ret = mtk_pcie_allocate_msi_domains(port); |
| 588 | if (ret) | 588 | if (ret) { |
| 589 | irq_domain_remove(port->irq_domain); | ||
| 589 | return ret; | 590 | return ret; |
| 591 | } | ||
| 590 | } | 592 | } |
| 591 | 593 | ||
| 592 | return 0; | 594 | return 0; |
| @@ -73,6 +73,7 @@ · 72 unmodified lines | |||
| 73 | #define RZG3S_PCI_PINTRCVIE_INTX(i) BIT(i) | 73 | #define RZG3S_PCI_PINTRCVIE_INTX(i) BIT(i) |
| 74 | #define RZG3S_PCI_PINTRCVIE_MSI BIT(4) | 74 | #define RZG3S_PCI_PINTRCVIE_MSI BIT(4) |
| 75 | 75 | ||
| 76 | /* Register is R/W1C, it doesn't require locking. */ | ||
| 76 | #define RZG3S_PCI_PINTRCVIS 0x114 | 77 | #define RZG3S_PCI_PINTRCVIS 0x114 |
| 77 | #define RZG3S_PCI_PINTRCVIS_INTX(i) BIT(i) | 78 | #define RZG3S_PCI_PINTRCVIS_INTX(i) BIT(i) |
| 78 | #define RZG3S_PCI_PINTRCVIS_MSI BIT(4) | 79 | #define RZG3S_PCI_PINTRCVIS_MSI BIT(4) |
| @@ -114,6 +115,8 @@ · 35 unmodified lines | |||
| 114 | #define RZG3S_PCI_MSIRE_ENA BIT(0) | 115 | #define RZG3S_PCI_MSIRE_ENA BIT(0) |
| 115 | 116 | ||
| 116 | #define RZG3S_PCI_MSIRM(id) (0x608 + (id) * 0x10) | 117 | #define RZG3S_PCI_MSIRM(id) (0x608 + (id) * 0x10) |
| 118 | |||
| 119 | /* Register is R/W1C, it doesn't require locking. */ | ||
| 117 | #define RZG3S_PCI_MSIRS(id) (0x60c + (id) * 0x10) | 120 | #define RZG3S_PCI_MSIRS(id) (0x60c + (id) * 0x10) |
| 118 | 121 | ||
| 119 | #define RZG3S_PCI_AWBASEL(id) (0x1000 + (id) * 0x20) | 122 | #define RZG3S_PCI_AWBASEL(id) (0x1000 + (id) * 0x20) |
| @@ -439,28 +442,9 @@ static void __iomem *rzg3s_pcie_root_map_bus(struct pci_bus *bus, · 319 unmodified lines | |||
| 439 | return host->pcie + where; | 442 | return host->pcie + where; |
| 440 | } | 443 | } |
| 441 | 444 | ||
| 442 | /* Serialized by 'pci_lock' */ | ||
| 443 | static int rzg3s_pcie_root_write(struct pci_bus *bus, unsigned int devfn, | ||
| 444 | int where, int size, u32 val) | ||
| 445 | { | ||
| 446 | struct rzg3s_pcie_host *host = bus->sysdata; | ||
| 447 | int ret; | ||
| 448 | |||
| 449 | /* Enable access control to the CFGU */ | ||
| 450 | writel_relaxed(RZG3S_PCI_PERM_CFG_HWINIT_EN, | ||
| 451 | host->axi + RZG3S_PCI_PERM); | ||
| 452 | |||
| 453 | ret = pci_generic_config_write(bus, devfn, where, size, val); | ||
| 454 | |||
| 455 | /* Disable access control to the CFGU */ | ||
| 456 | writel_relaxed(0, host->axi + RZG3S_PCI_PERM); | ||
| 457 | |||
| 458 | return ret; | ||
| 459 | } | ||
| 460 | |||
| 461 | static struct pci_ops rzg3s_pcie_root_ops = { | 445 | static struct pci_ops rzg3s_pcie_root_ops = { |
| 462 | .read = pci_generic_config_read, | 446 | .read = pci_generic_config_read, |
| 463 | .write = rzg3s_pcie_root_write, | 447 | .write = pci_generic_config_write, |
| 464 | .map_bus = rzg3s_pcie_root_map_bus, | 448 | .map_bus = rzg3s_pcie_root_map_bus, |
| 465 | }; | 449 | }; |
| 466 | 450 | ||
| @@ -526,8 +510,6 @@ static void rzg3s_pcie_msi_irq_ack(struct irq_data *d) · 59 unmodified lines | |||
| 526 | u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG; | 510 | u8 reg_bit = d->hwirq % RZG3S_PCI_MSI_INT_PER_REG; |
| 527 | u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG; | 511 | u8 reg_id = d->hwirq / RZG3S_PCI_MSI_INT_PER_REG; |
| 528 | 512 | ||
| 529 | guard(raw_spinlock_irqsave)(&host->hw_lock); | ||
| 530 | |||
| 531 | writel_relaxed(BIT(reg_bit), host->axi + RZG3S_PCI_MSIRS(reg_id)); | 513 | writel_relaxed(BIT(reg_bit), host->axi + RZG3S_PCI_MSIRS(reg_id)); |
| 532 | } | 514 | } |
| 533 | 515 | ||
| @@ -859,8 +841,6 @@ static void rzg3s_pcie_intx_irq_ack(struct irq_data *d) · 325 unmodified lines | |||
| 859 | { | 841 | { |
| 860 | struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d); | 842 | struct rzg3s_pcie_host *host = irq_data_get_irq_chip_data(d); |
| 861 | 843 | ||
| 862 | guard(raw_spinlock_irqsave)(&host->hw_lock); | ||
| 863 | |||
| 864 | rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIS, | 844 | rzg3s_pcie_update_bits(host->axi, RZG3S_PCI_PINTRCVIS, |
| 865 | RZG3S_PCI_PINTRCVIS_INTX(d->hwirq), | 845 | RZG3S_PCI_PINTRCVIS_INTX(d->hwirq), |
| 866 | RZG3S_PCI_PINTRCVIS_INTX(d->hwirq)); | 846 | RZG3S_PCI_PINTRCVIS_INTX(d->hwirq)); |
| @@ -1065,14 +1045,14 @@ static int rzg3s_pcie_config_init(struct rzg3s_pcie_host *host) · 198 unmodified lines | |||
| 1065 | writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L); | 1045 | writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00L); |
| 1066 | writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U); | 1046 | writel_relaxed(0xffffffff, host->pcie + RZG3S_PCI_CFG_BARMSK00U); |
| 1067 | 1047 | ||
| 1048 | /* Disable access control to the CFGU */ | ||
| 1049 | writel_relaxed(0, host->axi + RZG3S_PCI_PERM); | ||
| 1050 | |||
| 1068 | /* Update bus info */ | 1051 | /* Update bus info */ |
| 1069 | writeb_relaxed(primary_bus, host->pcie + PCI_PRIMARY_BUS); | 1052 | writeb_relaxed(primary_bus, host->pcie + PCI_PRIMARY_BUS); |
| 1070 | writeb_relaxed(secondary_bus, host->pcie + PCI_SECONDARY_BUS); | 1053 | writeb_relaxed(secondary_bus, host->pcie + PCI_SECONDARY_BUS); |
| 1071 | writeb_relaxed(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS); | 1054 | writeb_relaxed(subordinate_bus, host->pcie + PCI_SUBORDINATE_BUS); |
| 1072 | 1055 | ||
| 1073 | /* Disable access control to the CFGU */ | ||
| 1074 | writel_relaxed(0, host->axi + RZG3S_PCI_PERM); | ||
| 1075 | |||
| 1076 | return 0; | 1056 | return 0; |
| 1077 | } | 1057 | } |
| 1078 | 1058 | ||
| @@ -1162,7 +1142,8 @@ static int rzg3s_pcie_resets_prepare_and_get(struct rzg3s_pcie_host *host) · 83 unmodified lines | |||
| 1162 | 1142 | ||
| 1163 | static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host) | 1143 | static int rzg3s_pcie_host_parse_port(struct rzg3s_pcie_host *host) |
| 1164 | { | 1144 | { |
| 1165 | struct device_node *of_port = of_get_next_child(host->dev->of_node, NULL); | 1145 | struct device_node *of_port __free(device_node) = |
| 1146 | of_get_next_child(host->dev->of_node, NULL); | ||
| 1166 | struct rzg3s_pcie_port *port = &host->port; | 1147 | struct rzg3s_pcie_port *port = &host->port; |
| 1167 | int ret; | 1148 | int ret; |
| 1168 | 1149 | ||
| @@ -302,9 +302,10 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie) · 301 unmodified lines | |||
| 302 | return 0; | 302 | return 0; |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | static void xilinx_free_msi_domains(struct xilinx_pcie *pcie) | 305 | static void xilinx_free_irq_domains(struct xilinx_pcie *pcie) |
| 306 | { | 306 | { |
| 307 | irq_domain_remove(pcie->msi_domain); | 307 | irq_domain_remove(pcie->msi_domain); |
| 308 | irq_domain_remove(pcie->leg_domain); | ||
| 308 | } | 309 | } |
| 309 | 310 | ||
| 310 | /* INTx Functions */ | 311 | /* INTx Functions */ |
| @@ -480,8 +481,10 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie) · 169 unmodified lines | |||
| 480 | phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K); | 481 | phys_addr_t pa = ALIGN_DOWN(virt_to_phys(pcie), SZ_4K); |
| 481 | 482 | ||
| 482 | ret = xilinx_allocate_msi_domains(pcie); | 483 | ret = xilinx_allocate_msi_domains(pcie); |
| 483 | if (ret) | 484 | if (ret) { |
| 485 | irq_domain_remove(pcie->leg_domain); | ||
| 484 | return ret; | 486 | return ret; |
| 487 | } | ||
| 485 | 488 | ||
| 486 | pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1); | 489 | pcie_write(pcie, upper_32_bits(pa), XILINX_PCIE_REG_MSIBASE1); |
| 487 | pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2); | 490 | pcie_write(pcie, lower_32_bits(pa), XILINX_PCIE_REG_MSIBASE2); |
| @@ -600,7 +603,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev) · 112 unmodified lines | |||
| 600 | 603 | ||
| 601 | err = pci_host_probe(bridge); | 604 | err = pci_host_probe(bridge); |
| 602 | if (err) | 605 | if (err) |
| 603 | xilinx_free_msi_domains(pcie); | 606 | xilinx_free_irq_domains(pcie); |
| 604 | 607 | ||
| 605 | return err; | 608 | return err; |
| 606 | } | 609 | } |
| @@ -55,7 +55,7 @@ struct starfive_jh7110_pcie { · 54 unmodified lines | |||
| 55 | struct reset_control *resets; | 55 | struct reset_control *resets; |
| 56 | struct clk_bulk_data *clks; | 56 | struct clk_bulk_data *clks; |
| 57 | struct regmap *reg_syscon; | 57 | struct regmap *reg_syscon; |
| 58 | struct gpio_desc *power_gpio; | 58 | struct regulator *vpcie3v3; |
| 59 | struct gpio_desc *reset_gpio; | 59 | struct gpio_desc *reset_gpio; |
| 60 | struct phy *phy; | 60 | struct phy *phy; |
| 61 | 61 | ||
| @@ -153,11 +153,13 @@ static int starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie, · 91 unmodified lines | |||
| 153 | return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio), | 153 | return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio), |
| 154 | "failed to get perst-gpio\n"); | 154 | "failed to get perst-gpio\n"); |
| 155 | 155 | ||
| 156 | pcie->power_gpio = devm_gpiod_get_optional(dev, "enable", | 156 | pcie->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); |
| 157 | GPIOD_OUT_LOW); | 157 | if (IS_ERR(pcie->vpcie3v3)) { |
| 158 | if (IS_ERR(pcie->power_gpio)) | 158 | if (PTR_ERR(pcie->vpcie3v3) != -ENODEV) |
| 159 | return dev_err_probe(dev, PTR_ERR(pcie->power_gpio), | 159 | return dev_err_probe(dev, PTR_ERR(pcie->vpcie3v3), |
| 160 | "failed to get power-gpio\n"); | 160 | "failed to get vpcie3v3 regulator\n"); |
| 161 | pcie->vpcie3v3 = NULL; | ||
| 162 | } | ||
| 161 | 163 | ||
| 162 | return 0; | 164 | return 0; |
| 163 | } | 165 | } |
| @@ -270,8 +272,8 @@ static void starfive_pcie_host_deinit(struct plda_pcie_rp *plda) · 106 unmodified lines | |||
| 270 | container_of(plda, struct starfive_jh7110_pcie, plda); | 272 | container_of(plda, struct starfive_jh7110_pcie, plda); |
| 271 | 273 | ||
| 272 | starfive_pcie_clk_rst_deinit(pcie); | 274 | starfive_pcie_clk_rst_deinit(pcie); |
| 273 | if (pcie->power_gpio) | 275 | if (pcie->vpcie3v3) |
| 274 | gpiod_set_value_cansleep(pcie->power_gpio, 0); | 276 | regulator_disable(pcie->vpcie3v3); |
| 275 | starfive_pcie_disable_phy(pcie); | 277 | starfive_pcie_disable_phy(pcie); |
| 276 | } | 278 | } |
| 277 | 279 | ||
| @@ -304,8 +306,11 @@ static int starfive_pcie_host_init(struct plda_pcie_rp *plda) · 26 unmodified lines | |||
| 304 | if (ret) | 306 | if (ret) |
| 305 | return ret; | 307 | return ret; |
| 306 | 308 | ||
| 307 | if (pcie->power_gpio) | 309 | if (pcie->vpcie3v3) { |
| 308 | gpiod_set_value_cansleep(pcie->power_gpio, 1); | 310 | ret = regulator_enable(pcie->vpcie3v3); |
| 311 | if (ret) | ||
| 312 | dev_err_probe(dev, ret, "failed to enable vpcie3v3 regulator\n"); | ||
| 313 | } | ||
| 309 | 314 | ||
| 310 | if (pcie->reset_gpio) | 315 | if (pcie->reset_gpio) |
| 311 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); | 316 | gpiod_set_value_cansleep(pcie->reset_gpio, 1); |
| @@ -469,9 +469,6 @@ static int pcim_add_mapping_to_legacy_table(struct pci_dev *pdev, · 468 unmodified lines | |||
| 469 | if (!legacy_iomap_table) | 469 | if (!legacy_iomap_table) |
| 470 | return -ENOMEM; | 470 | return -ENOMEM; |
| 471 | 471 | ||
| 472 | /* The legacy mechanism doesn't allow for duplicate mappings. */ | ||
| 473 | WARN_ON(legacy_iomap_table[bar]); | ||
| 474 | |||
| 475 | legacy_iomap_table[bar] = mapping; | 472 | legacy_iomap_table[bar] = mapping; |
| 476 | 473 | ||
| 477 | return 0; | 474 | return 0; |
| @@ -686,7 +686,7 @@ static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi) · 685 unmodified lines | |||
| 686 | goto err_release_tx; | 686 | goto err_release_tx; |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", 0, 0); | 689 | epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", WQ_PERCPU, 0); |
| 690 | if (!epf_mhi->dma_wq) { | 690 | if (!epf_mhi->dma_wq) { |
| 691 | ret = -ENOMEM; | 691 | ret = -ENOMEM; |
| 692 | goto err_release_rx; | 692 | goto err_release_rx; |
| @@ -2124,8 +2124,13 @@ static int __init epf_ntb_init(void) · 2123 unmodified lines | |||
| 2124 | { | 2124 | { |
| 2125 | int ret; | 2125 | int ret; |
| 2126 | 2126 | ||
| 2127 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | | 2127 | kpcintb_workqueue = alloc_workqueue("kpcintb", |
| 2128 | WQ_HIGHPRI, 0); | 2128 | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); |
| 2129 | if (!kpcintb_workqueue) { | ||
| 2130 | pr_err("Failed to allocate kpcintb workqueue\n"); | ||
| 2131 | return -ENOMEM; | ||
| 2132 | } | ||
| 2133 | |||
| 2129 | ret = pci_epf_register_driver(&epf_ntb_driver); | 2134 | ret = pci_epf_register_driver(&epf_ntb_driver); |
| 2130 | if (ret) { | 2135 | if (ret) { |
| 2131 | destroy_workqueue(kpcintb_workqueue); | 2136 | destroy_workqueue(kpcintb_workqueue); |
| @@ -33,6 +33,8 @@ · 32 unmodified lines | |||
| 33 | #define COMMAND_COPY BIT(5) | 33 | #define COMMAND_COPY BIT(5) |
| 34 | #define COMMAND_ENABLE_DOORBELL BIT(6) | 34 | #define COMMAND_ENABLE_DOORBELL BIT(6) |
| 35 | #define COMMAND_DISABLE_DOORBELL BIT(7) | 35 | #define COMMAND_DISABLE_DOORBELL BIT(7) |
| 36 | #define COMMAND_BAR_SUBRANGE_SETUP BIT(8) | ||
| 37 | #define COMMAND_BAR_SUBRANGE_CLEAR BIT(9) | ||
| 36 | 38 | ||
| 37 | #define STATUS_READ_SUCCESS BIT(0) | 39 | #define STATUS_READ_SUCCESS BIT(0) |
| 38 | #define STATUS_READ_FAIL BIT(1) | 40 | #define STATUS_READ_FAIL BIT(1) |
| @@ -48,6 +50,10 @@ · 9 unmodified lines | |||
| 48 | #define STATUS_DOORBELL_ENABLE_FAIL BIT(11) | 50 | #define STATUS_DOORBELL_ENABLE_FAIL BIT(11) |
| 49 | #define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12) | 51 | #define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12) |
| 50 | #define STATUS_DOORBELL_DISABLE_FAIL BIT(13) | 52 | #define STATUS_DOORBELL_DISABLE_FAIL BIT(13) |
| 53 | #define STATUS_BAR_SUBRANGE_SETUP_SUCCESS BIT(14) | ||
| 54 | #define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15) | ||
| 55 | #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16) | ||
| 56 | #define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17) | ||
| 51 | 57 | ||
| 52 | #define FLAG_USE_DMA BIT(0) | 58 | #define FLAG_USE_DMA BIT(0) |
| 53 | 59 | ||
| @@ -57,12 +63,16 @@ · 3 unmodified lines | |||
| 57 | #define CAP_MSI BIT(1) | 63 | #define CAP_MSI BIT(1) |
| 58 | #define CAP_MSIX BIT(2) | 64 | #define CAP_MSIX BIT(2) |
| 59 | #define CAP_INTX BIT(3) | 65 | #define CAP_INTX BIT(3) |
| 66 | #define CAP_SUBRANGE_MAPPING BIT(4) | ||
| 67 | |||
| 68 | #define PCI_EPF_TEST_BAR_SUBRANGE_NSUB 2 | ||
| 60 | 69 | ||
| 61 | static struct workqueue_struct *kpcitest_workqueue; | 70 | static struct workqueue_struct *kpcitest_workqueue; |
| 62 | 71 | ||
| 63 | struct pci_epf_test { | 72 | struct pci_epf_test { |
| 64 | void *reg[PCI_STD_NUM_BARS]; | 73 | void *reg[PCI_STD_NUM_BARS]; |
| 65 | struct pci_epf *epf; | 74 | struct pci_epf *epf; |
| 75 | struct config_group group; | ||
| 66 | enum pci_barno test_reg_bar; | 76 | enum pci_barno test_reg_bar; |
| 67 | size_t msix_table_offset; | 77 | size_t msix_table_offset; |
| 68 | struct delayed_work cmd_handler; | 78 | struct delayed_work cmd_handler; |
| @@ -76,6 +86,7 @@ struct pci_epf_test { · 7 unmodified lines | |||
| 76 | bool dma_private; | 86 | bool dma_private; |
| 77 | const struct pci_epc_features *epc_features; | 87 | const struct pci_epc_features *epc_features; |
| 78 | struct pci_epf_bar db_bar; | 88 | struct pci_epf_bar db_bar; |
| 89 | size_t bar_size[PCI_STD_NUM_BARS]; | ||
| 79 | }; | 90 | }; |
| 80 | 91 | ||
| 81 | struct pci_epf_test_reg { | 92 | struct pci_epf_test_reg { |
| @@ -102,7 +113,8 @@ static struct pci_epf_header test_header = { · 20 unmodified lines | |||
| 102 | .interrupt_pin = PCI_INTERRUPT_INTA, | 113 | .interrupt_pin = PCI_INTERRUPT_INTA, |
| 103 | }; | 114 | }; |
| 104 | 115 | ||
| 105 | static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 }; | 116 | /* default BAR sizes, can be overridden by the user using configfs */ |
| 117 | static size_t default_bar_size[] = { 131072, 131072, 131072, 131072, 131072, 1048576 }; | ||
| 106 | 118 | ||
| 107 | static void pci_epf_test_dma_callback(void *param) | 119 | static void pci_epf_test_dma_callback(void *param) |
| 108 | { | 120 | { |
| @@ -806,6 +818,155 @@ set_status_err: · 697 unmodified lines | |||
| 806 | reg->status = cpu_to_le32(status); | 818 | reg->status = cpu_to_le32(status); |
| 807 | } | 819 | } |
| 808 | 820 | ||
| 821 | static u8 pci_epf_test_subrange_sig_byte(enum pci_barno barno, | ||
| 822 | unsigned int subno) | ||
| 823 | { | ||
| 824 | return 0x50 + (barno * 8) + subno; | ||
| 825 | } | ||
| 826 | |||
| 827 | static void pci_epf_test_bar_subrange_setup(struct pci_epf_test *epf_test, | ||
| 828 | struct pci_epf_test_reg *reg) | ||
| 829 | { | ||
| 830 | struct pci_epf_bar_submap *submap, *old_submap; | ||
| 831 | struct pci_epf *epf = epf_test->epf; | ||
| 832 | struct pci_epc *epc = epf->epc; | ||
| 833 | struct pci_epf_bar *bar; | ||
| 834 | unsigned int nsub = PCI_EPF_TEST_BAR_SUBRANGE_NSUB, old_nsub; | ||
| 835 | /* reg->size carries BAR number for BAR_SUBRANGE_* commands. */ | ||
| 836 | enum pci_barno barno = le32_to_cpu(reg->size); | ||
| 837 | u32 status = le32_to_cpu(reg->status); | ||
| 838 | unsigned int i, phys_idx; | ||
| 839 | size_t sub_size; | ||
| 840 | u8 *addr; | ||
| 841 | int ret; | ||
| 842 | |||
| 843 | if (barno >= PCI_STD_NUM_BARS) { | ||
| 844 | dev_err(&epf->dev, "Invalid barno: %d\n", barno); | ||
| 845 | goto err; | ||
| 846 | } | ||
| 847 | |||
| 848 | /* Host side should've avoided test_reg_bar, this is a safeguard. */ | ||
| 849 | if (barno == epf_test->test_reg_bar) { | ||
| 850 | dev_err(&epf->dev, "test_reg_bar cannot be used for subrange test\n"); | ||
| 851 | goto err; | ||
| 852 | } | ||
| 853 | |||
| 854 | if (!epf_test->epc_features->dynamic_inbound_mapping || | ||
| 855 | !epf_test->epc_features->subrange_mapping) { | ||
| 856 | dev_err(&epf->dev, "epc driver does not support subrange mapping\n"); | ||
| 857 | goto err; | ||
| 858 | } | ||
| 859 | |||
| 860 | bar = &epf->bar[barno]; | ||
| 861 | if (!bar->size || !bar->addr) { | ||
| 862 | dev_err(&epf->dev, "bar size/addr (%zu/%p) is invalid\n", | ||
| 863 | bar->size, bar->addr); | ||
| 864 | goto err; | ||
| 865 | } | ||
| 866 | |||
| 867 | if (bar->size % nsub) { | ||
| 868 | dev_err(&epf->dev, "BAR size %zu is not divisible by %u\n", | ||
| 869 | bar->size, nsub); | ||
| 870 | goto err; | ||
| 871 | } | ||
| 872 | |||
| 873 | sub_size = bar->size / nsub; | ||
| 874 | |||
| 875 | submap = kcalloc(nsub, sizeof(*submap), GFP_KERNEL); | ||
| 876 | if (!submap) | ||
| 877 | goto err; | ||
| 878 | |||
| 879 | for (i = 0; i < nsub; i++) { | ||
| 880 | /* Swap the two halves so RC can verify ordering. */ | ||
| 881 | phys_idx = i ^ 1; | ||
| 882 | submap[i].phys_addr = bar->phys_addr + (phys_idx * sub_size); | ||
| 883 | submap[i].size = sub_size; | ||
| 884 | } | ||
| 885 | |||
| 886 | old_submap = bar->submap; | ||
| 887 | old_nsub = bar->num_submap; | ||
| 888 | |||
| 889 | bar->submap = submap; | ||
| 890 | bar->num_submap = nsub; | ||
| 891 | |||
| 892 | ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar); | ||
| 893 | if (ret) { | ||
| 894 | dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret); | ||
| 895 | bar->submap = old_submap; | ||
| 896 | bar->num_submap = old_nsub; | ||
| 897 | kfree(submap); | ||
| 898 | goto err; | ||
| 899 | } | ||
| 900 | kfree(old_submap); | ||
| 901 | |||
| 902 | /* | ||
| 903 | * Fill deterministic signatures into the physical regions that | ||
| 904 | * each BAR subrange maps to. RC verifies these to ensure the | ||
| 905 | * submap order is really applied. | ||
| 906 | */ | ||
| 907 | addr = (u8 *)bar->addr; | ||
| 908 | for (i = 0; i < nsub; i++) { | ||
| 909 | phys_idx = i ^ 1; | ||
| 910 | memset(addr + (phys_idx * sub_size), | ||
| 911 | pci_epf_test_subrange_sig_byte(barno, i), | ||
| 912 | sub_size); | ||
| 913 | } | ||
| 914 | |||
| 915 | status |= STATUS_BAR_SUBRANGE_SETUP_SUCCESS; | ||
| 916 | reg->status = cpu_to_le32(status); | ||
| 917 | return; | ||
| 918 | |||
| 919 | err: | ||
| 920 | status |= STATUS_BAR_SUBRANGE_SETUP_FAIL; | ||
| 921 | reg->status = cpu_to_le32(status); | ||
| 922 | } | ||
| 923 | |||
| 924 | static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test, | ||
| 925 | struct pci_epf_test_reg *reg) | ||
| 926 | { | ||
| 927 | struct pci_epf *epf = epf_test->epf; | ||
| 928 | struct pci_epf_bar_submap *submap; | ||
| 929 | struct pci_epc *epc = epf->epc; | ||
| 930 | /* reg->size carries BAR number for BAR_SUBRANGE_* commands. */ | ||
| 931 | enum pci_barno barno = le32_to_cpu(reg->size); | ||
| 932 | u32 status = le32_to_cpu(reg->status); | ||
| 933 | struct pci_epf_bar *bar; | ||
| 934 | unsigned int nsub; | ||
| 935 | int ret; | ||
| 936 | |||
| 937 | if (barno >= PCI_STD_NUM_BARS) { | ||
| 938 | dev_err(&epf->dev, "Invalid barno: %d\n", barno); | ||
| 939 | goto err; | ||
| 940 | } | ||
| 941 | |||
| 942 | bar = &epf->bar[barno]; | ||
| 943 | submap = bar->submap; | ||
| 944 | nsub = bar->num_submap; | ||
| 945 | |||
| 946 | if (!submap || !nsub) | ||
| 947 | goto err; | ||
| 948 | |||
| 949 | bar->submap = NULL; | ||
| 950 | bar->num_submap = 0; | ||
| 951 | |||
| 952 | ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar); | ||
| 953 | if (ret) { | ||
| 954 | bar->submap = submap; | ||
| 955 | bar->num_submap = nsub; | ||
| 956 | dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret); | ||
| 957 | goto err; | ||
| 958 | } | ||
| 959 | kfree(submap); | ||
| 960 | |||
| 961 | status |= STATUS_BAR_SUBRANGE_CLEAR_SUCCESS; | ||
| 962 | reg->status = cpu_to_le32(status); | ||
| 963 | return; | ||
| 964 | |||
| 965 | err: | ||
| 966 | status |= STATUS_BAR_SUBRANGE_CLEAR_FAIL; | ||
| 967 | reg->status = cpu_to_le32(status); | ||
| 968 | } | ||
| 969 | |||
| 809 | static void pci_epf_test_cmd_handler(struct work_struct *work) | 970 | static void pci_epf_test_cmd_handler(struct work_struct *work) |
| 810 | { | 971 | { |
| 811 | u32 command; | 972 | u32 command; |
| @@ -861,6 +1022,14 @@ static void pci_epf_test_cmd_handler(struct work_struct *work) · 49 unmodified lines | |||
| 861 | pci_epf_test_disable_doorbell(epf_test, reg); | 1022 | pci_epf_test_disable_doorbell(epf_test, reg); |
| 862 | pci_epf_test_raise_irq(epf_test, reg); | 1023 | pci_epf_test_raise_irq(epf_test, reg); |
| 863 | break; | 1024 | break; |
| 1025 | case COMMAND_BAR_SUBRANGE_SETUP: | ||
| 1026 | pci_epf_test_bar_subrange_setup(epf_test, reg); | ||
| 1027 | pci_epf_test_raise_irq(epf_test, reg); | ||
| 1028 | break; | ||
| 1029 | case COMMAND_BAR_SUBRANGE_CLEAR: | ||
| 1030 | pci_epf_test_bar_subrange_clear(epf_test, reg); | ||
| 1031 | pci_epf_test_raise_irq(epf_test, reg); | ||
| 1032 | break; | ||
| 864 | default: | 1033 | default: |
| 865 | dev_err(dev, "Invalid command 0x%x\n", command); | 1034 | dev_err(dev, "Invalid command 0x%x\n", command); |
| 866 | break; | 1035 | break; |
| @@ -933,6 +1102,10 @@ static void pci_epf_test_set_capabilities(struct pci_epf *epf) · 66 unmodified lines | |||
| 933 | if (epf_test->epc_features->intx_capable) | 1102 | if (epf_test->epc_features->intx_capable) |
| 934 | caps |= CAP_INTX; | 1103 | caps |= CAP_INTX; |
| 935 | 1104 | ||
| 1105 | if (epf_test->epc_features->dynamic_inbound_mapping && | ||
| 1106 | epf_test->epc_features->subrange_mapping) | ||
| 1107 | caps |= CAP_SUBRANGE_MAPPING; | ||
| 1108 | |||
| 936 | reg->caps = cpu_to_le32(caps); | 1109 | reg->caps = cpu_to_le32(caps); |
| 937 | } | 1110 | } |
| 938 | 1111 | ||
| @@ -1070,7 +1243,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) · 131 unmodified lines | |||
| 1070 | if (epc_features->bar[bar].type == BAR_FIXED) | 1243 | if (epc_features->bar[bar].type == BAR_FIXED) |
| 1071 | test_reg_size = epc_features->bar[bar].fixed_size; | 1244 | test_reg_size = epc_features->bar[bar].fixed_size; |
| 1072 | else | 1245 | else |
| 1073 | test_reg_size = bar_size[bar]; | 1246 | test_reg_size = epf_test->bar_size[bar]; |
| 1074 | 1247 | ||
| 1075 | base = pci_epf_alloc_space(epf, test_reg_size, bar, | 1248 | base = pci_epf_alloc_space(epf, test_reg_size, bar, |
| 1076 | epc_features, PRIMARY_INTERFACE); | 1249 | epc_features, PRIMARY_INTERFACE); |
| @@ -1142,6 +1315,94 @@ static void pci_epf_test_unbind(struct pci_epf *epf) · 65 unmodified lines | |||
| 1142 | pci_epf_test_free_space(epf); | 1315 | pci_epf_test_free_space(epf); |
| 1143 | } | 1316 | } |
| 1144 | 1317 | ||
| 1318 | #define PCI_EPF_TEST_BAR_SIZE_R(_name, _id) \ | ||
| 1319 | static ssize_t pci_epf_test_##_name##_show(struct config_item *item, \ | ||
| 1320 | char *page) \ | ||
| 1321 | { \ | ||
| 1322 | struct config_group *group = to_config_group(item); \ | ||
| 1323 | struct pci_epf_test *epf_test = \ | ||
| 1324 | container_of(group, struct pci_epf_test, group); \ | ||
| 1325 | \ | ||
| 1326 | return sysfs_emit(page, "%zu\n", epf_test->bar_size[_id]); \ | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | #define PCI_EPF_TEST_BAR_SIZE_W(_name, _id) \ | ||
| 1330 | static ssize_t pci_epf_test_##_name##_store(struct config_item *item, \ | ||
| 1331 | const char *page, \ | ||
| 1332 | size_t len) \ | ||
| 1333 | { \ | ||
| 1334 | struct config_group *group = to_config_group(item); \ | ||
| 1335 | struct pci_epf_test *epf_test = \ | ||
| 1336 | container_of(group, struct pci_epf_test, group); \ | ||
| 1337 | int val, ret; \ | ||
| 1338 | \ | ||
| 1339 | /* \ | ||
| 1340 | * BAR sizes can only be modified before binding to an EPC, \ | ||
| 1341 | * because pci_epf_test_alloc_space() is called in .bind(). \ | ||
| 1342 | */ \ | ||
| 1343 | if (epf_test->epf->epc) \ | ||
| 1344 | return -EOPNOTSUPP; \ | ||
| 1345 | \ | ||
| 1346 | ret = kstrtouint(page, 0, &val); \ | ||
| 1347 | if (ret) \ | ||
| 1348 | return ret; \ | ||
| 1349 | \ | ||
| 1350 | if (!is_power_of_2(val)) \ | ||
| 1351 | return -EINVAL; \ | ||
| 1352 | \ | ||
| 1353 | epf_test->bar_size[_id] = val; \ | ||
| 1354 | \ | ||
| 1355 | return len; \ | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | PCI_EPF_TEST_BAR_SIZE_R(bar0_size, BAR_0) | ||
| 1359 | PCI_EPF_TEST_BAR_SIZE_W(bar0_size, BAR_0) | ||
| 1360 | PCI_EPF_TEST_BAR_SIZE_R(bar1_size, BAR_1) | ||
| 1361 | PCI_EPF_TEST_BAR_SIZE_W(bar1_size, BAR_1) | ||
| 1362 | PCI_EPF_TEST_BAR_SIZE_R(bar2_size, BAR_2) | ||
| 1363 | PCI_EPF_TEST_BAR_SIZE_W(bar2_size, BAR_2) | ||
| 1364 | PCI_EPF_TEST_BAR_SIZE_R(bar3_size, BAR_3) | ||
| 1365 | PCI_EPF_TEST_BAR_SIZE_W(bar3_size, BAR_3) | ||
| 1366 | PCI_EPF_TEST_BAR_SIZE_R(bar4_size, BAR_4) | ||
| 1367 | PCI_EPF_TEST_BAR_SIZE_W(bar4_size, BAR_4) | ||
| 1368 | PCI_EPF_TEST_BAR_SIZE_R(bar5_size, BAR_5) | ||
| 1369 | PCI_EPF_TEST_BAR_SIZE_W(bar5_size, BAR_5) | ||
| 1370 | |||
| 1371 | CONFIGFS_ATTR(pci_epf_test_, bar0_size); | ||
| 1372 | CONFIGFS_ATTR(pci_epf_test_, bar1_size); | ||
| 1373 | CONFIGFS_ATTR(pci_epf_test_, bar2_size); | ||
| 1374 | CONFIGFS_ATTR(pci_epf_test_, bar3_size); | ||
| 1375 | CONFIGFS_ATTR(pci_epf_test_, bar4_size); | ||
| 1376 | CONFIGFS_ATTR(pci_epf_test_, bar5_size); | ||
| 1377 | |||
| 1378 | static struct configfs_attribute *pci_epf_test_attrs[] = { | ||
| 1379 | &pci_epf_test_attr_bar0_size, | ||
| 1380 | &pci_epf_test_attr_bar1_size, | ||
| 1381 | &pci_epf_test_attr_bar2_size, | ||
| 1382 | &pci_epf_test_attr_bar3_size, | ||
| 1383 | &pci_epf_test_attr_bar4_size, | ||
| 1384 | &pci_epf_test_attr_bar5_size, | ||
| 1385 | NULL, | ||
| 1386 | }; | ||
| 1387 | |||
| 1388 | static const struct config_item_type pci_epf_test_group_type = { | ||
| 1389 | .ct_attrs = pci_epf_test_attrs, | ||
| 1390 | .ct_owner = THIS_MODULE, | ||
| 1391 | }; | ||
| 1392 | |||
| 1393 | static struct config_group *pci_epf_test_add_cfs(struct pci_epf *epf, | ||
| 1394 | struct config_group *group) | ||
| 1395 | { | ||
| 1396 | struct pci_epf_test *epf_test = epf_get_drvdata(epf); | ||
| 1397 | struct config_group *epf_group = &epf_test->group; | ||
| 1398 | struct device *dev = &epf->dev; | ||
| 1399 | |||
| 1400 | config_group_init_type_name(epf_group, dev_name(dev), | ||
| 1401 | &pci_epf_test_group_type); | ||
| 1402 | |||
| 1403 | return epf_group; | ||
| 1404 | } | ||
| 1405 | |||
| 1145 | static const struct pci_epf_device_id pci_epf_test_ids[] = { | 1406 | static const struct pci_epf_device_id pci_epf_test_ids[] = { |
| 1146 | { | 1407 | { |
| 1147 | .name = "pci_epf_test", | 1408 | .name = "pci_epf_test", |
| @@ -1154,6 +1415,7 @@ static int pci_epf_test_probe(struct pci_epf *epf, · 6 unmodified lines | |||
| 1154 | { | 1415 | { |
| 1155 | struct pci_epf_test *epf_test; | 1416 | struct pci_epf_test *epf_test; |
| 1156 | struct device *dev = &epf->dev; | 1417 | struct device *dev = &epf->dev; |
| 1418 | enum pci_barno bar; | ||
| 1157 | 1419 | ||
| 1158 | epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL); | 1420 | epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL); |
| 1159 | if (!epf_test) | 1421 | if (!epf_test) |
| @@ -1161,6 +1423,8 @@ static int pci_epf_test_probe(struct pci_epf *epf, · 1 unmodified line | |||
| 1161 | 1423 | ||
| 1162 | epf->header = &test_header; | 1424 | epf->header = &test_header; |
| 1163 | epf_test->epf = epf; | 1425 | epf_test->epf = epf; |
| 1426 | for (bar = BAR_0; bar < PCI_STD_NUM_BARS; bar++) | ||
| 1427 | epf_test->bar_size[bar] = default_bar_size[bar]; | ||
| 1164 | 1428 | ||
| 1165 | INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler); | 1429 | INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler); |
| 1166 | 1430 | ||
| @@ -1173,6 +1437,7 @@ static int pci_epf_test_probe(struct pci_epf *epf, · 6 unmodified lines | |||
| 1173 | static const struct pci_epf_ops ops = { | 1437 | static const struct pci_epf_ops ops = { |
| 1174 | .unbind = pci_epf_test_unbind, | 1438 | .unbind = pci_epf_test_unbind, |
| 1175 | .bind = pci_epf_test_bind, | 1439 | .bind = pci_epf_test_bind, |
| 1440 | .add_cfs = pci_epf_test_add_cfs, | ||
| 1176 | }; | 1441 | }; |
| 1177 | 1442 | ||
| 1178 | static struct pci_epf_driver test_driver = { | 1443 | static struct pci_epf_driver test_driver = { |
| @@ -1188,7 +1453,7 @@ static int __init pci_epf_test_init(void) · 9 unmodified lines | |||
| 1188 | int ret; | 1453 | int ret; |
| 1189 | 1454 | ||
| 1190 | kpcitest_workqueue = alloc_workqueue("kpcitest", | 1455 | kpcitest_workqueue = alloc_workqueue("kpcitest", |
| 1191 | WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); | 1456 | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); |
| 1192 | if (!kpcitest_workqueue) { | 1457 | if (!kpcitest_workqueue) { |
| 1193 | pr_err("Failed to allocate the kpcitest work queue\n"); | 1458 | pr_err("Failed to allocate the kpcitest work queue\n"); |
| 1194 | return -ENOMEM; | 1459 | return -ENOMEM; |
| @@ -1651,8 +1651,13 @@ static int __init epf_ntb_init(void) · 1650 unmodified lines | |||
| 1651 | { | 1651 | { |
| 1652 | int ret; | 1652 | int ret; |
| 1653 | 1653 | ||
| 1654 | kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM | | 1654 | kpcintb_workqueue = alloc_workqueue("kpcintb", |
| 1655 | WQ_HIGHPRI, 0); | 1655 | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0); |
| 1656 | if (!kpcintb_workqueue) { | ||
| 1657 | pr_err("Failed to allocate kpcintb workqueue\n"); | ||
| 1658 | return -ENOMEM; | ||
| 1659 | } | ||
| 1660 | |||
| 1656 | ret = pci_epf_register_driver(&epf_ntb_driver); | 1661 | ret = pci_epf_register_driver(&epf_ntb_driver); |
| 1657 | if (ret) { | 1662 | if (ret) { |
| 1658 | destroy_workqueue(kpcintb_workqueue); | 1663 | destroy_workqueue(kpcintb_workqueue); |
| @@ -23,7 +23,6 @@ struct pci_epf_group { · 22 unmodified lines | |||
| 23 | struct config_group group; | 23 | struct config_group group; |
| 24 | struct config_group primary_epc_group; | 24 | struct config_group primary_epc_group; |
| 25 | struct config_group secondary_epc_group; | 25 | struct config_group secondary_epc_group; |
| 26 | struct delayed_work cfs_work; | ||
| 27 | struct pci_epf *epf; | 26 | struct pci_epf *epf; |
| 28 | int index; | 27 | int index; |
| 29 | }; | 28 | }; |
| @@ -69,8 +68,8 @@ static int pci_secondary_epc_epf_link(struct config_item *epf_item, · 39 unmodified lines | |||
| 69 | return 0; | 68 | return 0; |
| 70 | } | 69 | } |
| 71 | 70 | ||
| 72 | static void pci_secondary_epc_epf_unlink(struct config_item *epc_item, | 71 | static void pci_secondary_epc_epf_unlink(struct config_item *epf_item, |
| 73 | struct config_item *epf_item) | 72 | struct config_item *epc_item) |
| 74 | { | 73 | { |
| 75 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent); | 74 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent); |
| 76 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | 75 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); |
| @@ -103,7 +102,7 @@ static struct config_group · 26 unmodified lines | |||
| 103 | secondary_epc_group = &epf_group->secondary_epc_group; | 102 | secondary_epc_group = &epf_group->secondary_epc_group; |
| 104 | config_group_init_type_name(secondary_epc_group, "secondary", | 103 | config_group_init_type_name(secondary_epc_group, "secondary", |
| 105 | &pci_secondary_epc_type); | 104 | &pci_secondary_epc_type); |
| 106 | configfs_register_group(&epf_group->group, secondary_epc_group); | 105 | configfs_add_default_group(secondary_epc_group, &epf_group->group); |
| 107 | 106 | ||
| 108 | return secondary_epc_group; | 107 | return secondary_epc_group; |
| 109 | } | 108 | } |
| @@ -133,8 +132,8 @@ static int pci_primary_epc_epf_link(struct config_item *epf_item, · 23 unmodified lines | |||
| 133 | return 0; | 132 | return 0; |
| 134 | } | 133 | } |
| 135 | 134 | ||
| 136 | static void pci_primary_epc_epf_unlink(struct config_item *epc_item, | 135 | static void pci_primary_epc_epf_unlink(struct config_item *epf_item, |
| 137 | struct config_item *epf_item) | 136 | struct config_item *epc_item) |
| 138 | { | 137 | { |
| 139 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent); | 138 | struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent); |
| 140 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); | 139 | struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); |
| @@ -166,7 +165,7 @@ static struct config_group · 25 unmodified lines | |||
| 166 | 165 | ||
| 167 | config_group_init_type_name(primary_epc_group, "primary", | 166 | config_group_init_type_name(primary_epc_group, "primary", |
| 168 | &pci_primary_epc_type); | 167 | &pci_primary_epc_type); |
| 169 | configfs_register_group(&epf_group->group, primary_epc_group); | 168 | configfs_add_default_group(primary_epc_group, &epf_group->group); |
| 170 | 169 | ||
| 171 | return primary_epc_group; | 170 | return primary_epc_group; |
| 172 | } | 171 | } |
| @@ -570,15 +569,13 @@ static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group) · 397 unmodified lines | |||
| 570 | return; | 569 | return; |
| 571 | } | 570 | } |
| 572 | 571 | ||
| 573 | configfs_register_group(&epf_group->group, group); | 572 | configfs_add_default_group(group, &epf_group->group); |
| 574 | } | 573 | } |
| 575 | 574 | ||
| 576 | static void pci_epf_cfs_work(struct work_struct *work) | 575 | static void pci_epf_cfs_add_sub_groups(struct pci_epf_group *epf_group) |
| 577 | { | 576 | { |
| 578 | struct pci_epf_group *epf_group; | ||
| 579 | struct config_group *group; | 577 | struct config_group *group; |
| 580 | 578 | ||
| 581 | epf_group = container_of(work, struct pci_epf_group, cfs_work.work); | ||
| 582 | group = pci_ep_cfs_add_primary_group(epf_group); | 579 | group = pci_ep_cfs_add_primary_group(epf_group); |
| 583 | if (IS_ERR(group)) { | 580 | if (IS_ERR(group)) { |
| 584 | pr_err("failed to create 'primary' EPC interface\n"); | 581 | pr_err("failed to create 'primary' EPC interface\n"); |
| @@ -637,9 +634,7 @@ static struct config_group *pci_epf_make(struct config_group *group, · 52 unmodified lines | |||
| 637 | 634 | ||
| 638 | kfree(epf_name); | 635 | kfree(epf_name); |
| 639 | 636 | ||
| 640 | INIT_DELAYED_WORK(&epf_group->cfs_work, pci_epf_cfs_work); | 637 | pci_epf_cfs_add_sub_groups(epf_group); |
| 641 | queue_delayed_work(system_wq, &epf_group->cfs_work, | ||
| 642 | msecs_to_jiffies(1)); | ||
| 643 | 638 | ||
| 644 | return &epf_group->group; | 639 | return &epf_group->group; |
| 645 | 640 | ||
| @@ -596,6 +596,14 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, · 595 unmodified lines | |||
| 596 | if (!epc_features) | 596 | if (!epc_features) |
| 597 | return -EINVAL; | 597 | return -EINVAL; |
| 598 | 598 | ||
| 599 | if (epf_bar->num_submap && !epf_bar->submap) | ||
| 600 | return -EINVAL; | ||
| 601 | |||
| 602 | if (epf_bar->num_submap && | ||
| 603 | !(epc_features->dynamic_inbound_mapping && | ||
| 604 | epc_features->subrange_mapping)) | ||
| 605 | return -EINVAL; | ||
| 606 | |||
| 599 | if (epc_features->bar[bar].type == BAR_RESIZABLE && | 607 | if (epc_features->bar[bar].type == BAR_RESIZABLE && |
| 600 | (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024))) | 608 | (epf_bar->size < SZ_1M || (u64)epf_bar->size > (SZ_128G * 1024))) |
| 601 | return -EINVAL; | 609 | return -EINVAL; |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
| 20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
| 21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
| 22 | #include <trace/events/pci.h> | ||
| 22 | 23 | ||
| 23 | #include "../pci.h" | 24 | #include "../pci.h" |
| 24 | #include "pciehp.h" | 25 | #include "pciehp.h" |
| @@ -244,12 +245,20 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) · 219 unmodified lines | |||
| 244 | case ON_STATE: | 245 | case ON_STATE: |
| 245 | ctrl->state = POWEROFF_STATE; | 246 | ctrl->state = POWEROFF_STATE; |
| 246 | mutex_unlock(&ctrl->state_lock); | 247 | mutex_unlock(&ctrl->state_lock); |
| 247 | if (events & PCI_EXP_SLTSTA_DLLSC) | 248 | if (events & PCI_EXP_SLTSTA_DLLSC) { |
| 248 | ctrl_info(ctrl, "Slot(%s): Link Down\n", | 249 | ctrl_info(ctrl, "Slot(%s): Link Down\n", |
| 249 | slot_name(ctrl)); | 250 | slot_name(ctrl)); |
| 250 | if (events & PCI_EXP_SLTSTA_PDC) | 251 | trace_pci_hp_event(pci_name(ctrl->pcie->port), |
| 252 | slot_name(ctrl), | ||
| 253 | PCI_HOTPLUG_LINK_DOWN); | ||
| 254 | } | ||
| 255 | if (events & PCI_EXP_SLTSTA_PDC) { | ||
| 251 | ctrl_info(ctrl, "Slot(%s): Card not present\n", | 256 | ctrl_info(ctrl, "Slot(%s): Card not present\n", |
| 252 | slot_name(ctrl)); | 257 | slot_name(ctrl)); |
| 258 | trace_pci_hp_event(pci_name(ctrl->pcie->port), | ||
| 259 | slot_name(ctrl), | ||
| 260 | PCI_HOTPLUG_CARD_NOT_PRESENT); | ||
| 261 | } | ||
| 253 | pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); | 262 | pciehp_disable_slot(ctrl, SURPRISE_REMOVAL); |
| 254 | break; | 263 | break; |
| 255 | default: | 264 | default: |
| @@ -269,6 +278,9 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) · 13 unmodified lines | |||
| 269 | INDICATOR_NOOP); | 278 | INDICATOR_NOOP); |
| 270 | ctrl_info(ctrl, "Slot(%s): Card not present\n", | 279 | ctrl_info(ctrl, "Slot(%s): Card not present\n", |
| 271 | slot_name(ctrl)); | 280 | slot_name(ctrl)); |
| 281 | trace_pci_hp_event(pci_name(ctrl->pcie->port), | ||
| 282 | slot_name(ctrl), | ||
| 283 | PCI_HOTPLUG_CARD_NOT_PRESENT); | ||
| 272 | } | 284 | } |
| 273 | mutex_unlock(&ctrl->state_lock); | 285 | mutex_unlock(&ctrl->state_lock); |
| 274 | return; | 286 | return; |
| @@ -281,12 +293,19 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) · 6 unmodified lines | |||
| 281 | case OFF_STATE: | 293 | case OFF_STATE: |
| 282 | ctrl->state = POWERON_STATE; | 294 | ctrl->state = POWERON_STATE; |
| 283 | mutex_unlock(&ctrl->state_lock); | 295 | mutex_unlock(&ctrl->state_lock); |
| 284 | if (present) | 296 | if (present) { |
| 285 | ctrl_info(ctrl, "Slot(%s): Card present\n", | 297 | ctrl_info(ctrl, "Slot(%s): Card present\n", |
| 286 | slot_name(ctrl)); | 298 | slot_name(ctrl)); |
| 287 | if (link_active) | 299 | trace_pci_hp_event(pci_name(ctrl->pcie->port), |
| 288 | ctrl_info(ctrl, "Slot(%s): Link Up\n", | 300 | slot_name(ctrl), |
| 289 | slot_name(ctrl)); | 301 | PCI_HOTPLUG_CARD_PRESENT); |
| 302 | } | ||
| 303 | if (link_active) { | ||
| 304 | ctrl_info(ctrl, "Slot(%s): Link Up\n", slot_name(ctrl)); | ||
| 305 | trace_pci_hp_event(pci_name(ctrl->pcie->port), | ||
| 306 | slot_name(ctrl), | ||
| 307 | PCI_HOTPLUG_LINK_UP); | ||
| 308 | } | ||
| 290 | ctrl->request_result = pciehp_enable_slot(ctrl); | 309 | ctrl->request_result = pciehp_enable_slot(ctrl); |
| 291 | break; | 310 | break; |
| 292 | default: | 311 | default: |
| @@ -320,7 +320,8 @@ int pciehp_check_link_status(struct controller *ctrl) · 319 unmodified lines | |||
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &linksta2); | 322 | pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &linksta2); |
| 323 | __pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status, linksta2); | 323 | __pcie_update_link_speed(ctrl->pcie->port->subordinate, PCIE_HOTPLUG, |
| 324 | lnk_status, linksta2); | ||
| 324 | 325 | ||
| 325 | if (!found) { | 326 | if (!found) { |
| 326 | ctrl_info(ctrl, "Slot(%s): No device found\n", | 327 | ctrl_info(ctrl, "Slot(%s): No device found\n", |
| @@ -802,7 +802,7 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn) · 801 unmodified lines | |||
| 802 | } | 802 | } |
| 803 | 803 | ||
| 804 | /* Allocate workqueue for this slot's interrupt handling */ | 804 | /* Allocate workqueue for this slot's interrupt handling */ |
| 805 | php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); | 805 | php_slot->wq = alloc_workqueue("pciehp-%s", WQ_PERCPU, 0, php_slot->name); |
| 806 | if (!php_slot->wq) { | 806 | if (!php_slot->wq) { |
| 807 | SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); | 807 | SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); |
| 808 | kfree(php_slot->name); | 808 | kfree(php_slot->name); |
| @@ -80,7 +80,8 @@ static int init_slots(struct controller *ctrl) · 79 unmodified lines | |||
| 80 | slot->device = ctrl->slot_device_offset + i; | 80 | slot->device = ctrl->slot_device_offset + i; |
| 81 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); | 81 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); |
| 82 | 82 | ||
| 83 | slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number); | 83 | slot->wq = alloc_workqueue("shpchp-%d", WQ_PERCPU, 0, |
| 84 | slot->number); | ||
| 84 | if (!slot->wq) { | 85 | if (!slot->wq) { |
| 85 | retval = -ENOMEM; | 86 | retval = -ENOMEM; |
| 86 | goto error_slot; | 87 | goto error_slot; |
| @@ -495,7 +495,9 @@ static ssize_t sriov_numvfs_store(struct device *dev, · 494 unmodified lines | |||
| 495 | 495 | ||
| 496 | if (num_vfs == 0) { | 496 | if (num_vfs == 0) { |
| 497 | /* disable VFs */ | 497 | /* disable VFs */ |
| 498 | pci_lock_rescan_remove(); | ||
| 498 | ret = pdev->driver->sriov_configure(pdev, 0); | 499 | ret = pdev->driver->sriov_configure(pdev, 0); |
| 500 | pci_unlock_rescan_remove(); | ||
| 499 | goto exit; | 501 | goto exit; |
| 500 | } | 502 | } |
| 501 | 503 | ||
| @@ -507,7 +509,9 @@ static ssize_t sriov_numvfs_store(struct device *dev, · 5 unmodified lines | |||
| 507 | goto exit; | 509 | goto exit; |
| 508 | } | 510 | } |
| 509 | 511 | ||
| 512 | pci_lock_rescan_remove(); | ||
| 510 | ret = pdev->driver->sriov_configure(pdev, num_vfs); | 513 | ret = pdev->driver->sriov_configure(pdev, num_vfs); |
| 514 | pci_unlock_rescan_remove(); | ||
| 511 | if (ret < 0) | 515 | if (ret < 0) |
| 512 | goto exit; | 516 | goto exit; |
| 513 | 517 | ||
| @@ -629,18 +633,15 @@ static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs) · 115 unmodified lines | |||
| 629 | if (dev->no_vf_scan) | 633 | if (dev->no_vf_scan) |
| 630 | return 0; | 634 | return 0; |
| 631 | 635 | ||
| 632 | pci_lock_rescan_remove(); | ||
| 633 | for (i = 0; i < num_vfs; i++) { | 636 | for (i = 0; i < num_vfs; i++) { |
| 634 | rc = pci_iov_add_virtfn(dev, i); | 637 | rc = pci_iov_add_virtfn(dev, i); |
| 635 | if (rc) | 638 | if (rc) |
| 636 | goto failed; | 639 | goto failed; |
| 637 | } | 640 | } |
| 638 | pci_unlock_rescan_remove(); | ||
| 639 | return 0; | 641 | return 0; |
| 640 | failed: | 642 | failed: |
| 641 | while (i--) | 643 | while (i--) |
| 642 | pci_iov_remove_virtfn(dev, i); | 644 | pci_iov_remove_virtfn(dev, i); |
| 643 | pci_unlock_rescan_remove(); | ||
| 644 | 645 | ||
| 645 | return rc; | 646 | return rc; |
| 646 | } | 647 | } |
| @@ -765,10 +766,8 @@ static void sriov_del_vfs(struct pci_dev *dev) · 118 unmodified lines | |||
| 765 | struct pci_sriov *iov = dev->sriov; | 766 | struct pci_sriov *iov = dev->sriov; |
| 766 | int i; | 767 | int i; |
| 767 | 768 | ||
| 768 | pci_lock_rescan_remove(); | ||
| 769 | for (i = 0; i < iov->num_VFs; i++) | 769 | for (i = 0; i < iov->num_VFs; i++) |
| 770 | pci_iov_remove_virtfn(dev, i); | 770 | pci_iov_remove_virtfn(dev, i); |
| 771 | pci_unlock_rescan_remove(); | ||
| 772 | } | 771 | } |
| 773 | 772 | ||
| 774 | static void sriov_disable(struct pci_dev *dev) | 773 | static void sriov_disable(struct pci_dev *dev) |
| @@ -867,6 +867,7 @@ bool of_pci_supply_present(struct device_node *np) · 866 unmodified lines | |||
| 867 | 867 | ||
| 868 | return false; | 868 | return false; |
| 869 | } | 869 | } |
| 870 | EXPORT_SYMBOL_GPL(of_pci_supply_present); | ||
| 870 | 871 | ||
| 871 | #endif /* CONFIG_PCI */ | 872 | #endif /* CONFIG_PCI */ |
| 872 | 873 | ||
| @@ -147,11 +147,19 @@ static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, · 146 unmodified lines | |||
| 147 | * we have just allocated the page no one else should be | 147 | * we have just allocated the page no one else should be |
| 148 | * using it. | 148 | * using it. |
| 149 | */ | 149 | */ |
| 150 | VM_WARN_ON_ONCE_PAGE(!page_ref_count(page), page); | 150 | VM_WARN_ON_ONCE_PAGE(page_ref_count(page), page); |
| 151 | set_page_count(page, 1); | 151 | set_page_count(page, 1); |
| 152 | ret = vm_insert_page(vma, vaddr, page); | 152 | ret = vm_insert_page(vma, vaddr, page); |
| 153 | if (ret) { | 153 | if (ret) { |
| 154 | gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); | 154 | gen_pool_free(p2pdma->pool, (uintptr_t)kaddr, len); |
| 155 | |||
| 156 | /* | ||
| 157 | * Reset the page count. We don't use put_page() | ||
| 158 | * because we don't want to trigger the | ||
| 159 | * p2pdma_folio_free() path. | ||
| 160 | */ | ||
| 161 | set_page_count(page, 0); | ||
| 162 | percpu_ref_put(ref); | ||
| 155 | return ret; | 163 | return ret; |
| 156 | } | 164 | } |
| 157 | percpu_ref_get(ref); | 165 | percpu_ref_get(ref); |
| @@ -272,21 +272,6 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, · 271 unmodified lines | |||
| 272 | return AE_OK; | 272 | return AE_OK; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | static bool pcie_root_rcb_set(struct pci_dev *dev) | ||
| 276 | { | ||
| 277 | struct pci_dev *rp = pcie_find_root_port(dev); | ||
| 278 | u16 lnkctl; | ||
| 279 | |||
| 280 | if (!rp) | ||
| 281 | return false; | ||
| 282 | |||
| 283 | pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); | ||
| 284 | if (lnkctl & PCI_EXP_LNKCTL_RCB) | ||
| 285 | return true; | ||
| 286 | |||
| 287 | return false; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* _HPX PCI Express Setting Record (Type 2) */ | 275 | /* _HPX PCI Express Setting Record (Type 2) */ |
| 291 | struct hpx_type2 { | 276 | struct hpx_type2 { |
| 292 | u32 revision; | 277 | u32 revision; |
| @@ -312,6 +297,7 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) · 19 unmodified lines | |||
| 312 | { | 297 | { |
| 313 | int pos; | 298 | int pos; |
| 314 | u32 reg32; | 299 | u32 reg32; |
| 300 | const struct pci_host_bridge *host; | ||
| 315 | 301 | ||
| 316 | if (!hpx) | 302 | if (!hpx) |
| 317 | return; | 303 | return; |
| @@ -319,6 +305,15 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) · 1 unmodified line | |||
| 319 | if (!pci_is_pcie(dev)) | 305 | if (!pci_is_pcie(dev)) |
| 320 | return; | 306 | return; |
| 321 | 307 | ||
| 308 | host = pci_find_host_bridge(dev->bus); | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Only do the _HPX Type 2 programming if OS owns PCIe native | ||
| 312 | * hotplug but not AER. | ||
| 313 | */ | ||
| 314 | if (!host->native_pcie_hotplug || host->native_aer) | ||
| 315 | return; | ||
| 316 | |||
| 322 | if (hpx->revision > 1) { | 317 | if (hpx->revision > 1) { |
| 323 | pci_warn(dev, "PCIe settings rev %d not supported\n", | 318 | pci_warn(dev, "PCIe settings rev %d not supported\n", |
| 324 | hpx->revision); | 319 | hpx->revision); |
| @@ -326,33 +321,27 @@ static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) · 1 unmodified line | |||
| 326 | } | 321 | } |
| 327 | 322 | ||
| 328 | /* | 323 | /* |
| 329 | * Don't allow _HPX to change MPS or MRRS settings. We manage | 324 | * We only allow _HPX to program DEVCTL bits related to AER, namely |
| 330 | * those to make sure they're consistent with the rest of the | 325 | * PCI_EXP_DEVCTL_CERE, PCI_EXP_DEVCTL_NFERE, PCI_EXP_DEVCTL_FERE, |
| 331 | * platform. | 326 | * and PCI_EXP_DEVCTL_URRE. |
| 327 | * | ||
| 328 | * The rest of DEVCTL is managed by the OS to make sure it's | ||
| 329 | * consistent with the rest of the platform. | ||
| 332 | */ | 330 | */ |
| 333 | hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | | 331 | hpx->pci_exp_devctl_and |= ~PCI_EXP_AER_FLAGS; |
| 334 | PCI_EXP_DEVCTL_READRQ; | 332 | hpx->pci_exp_devctl_or &= PCI_EXP_AER_FLAGS; |
| 335 | hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | | ||
| 336 | PCI_EXP_DEVCTL_READRQ); | ||
| 337 | 333 | ||
| 338 | /* Initialize Device Control Register */ | 334 | /* Initialize Device Control Register */ |
| 339 | pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, | 335 | pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, |
| 340 | ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); | 336 | ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); |
| 341 | 337 | ||
| 342 | /* Initialize Link Control Register */ | 338 | /* Log if _HPX attempts to modify Link Control Register */ |
| 343 | if (pcie_cap_has_lnkctl(dev)) { | 339 | if (pcie_cap_has_lnkctl(dev)) { |
| 344 | 340 | if (hpx->pci_exp_lnkctl_and != 0xffff || | |
| 345 | /* | 341 | hpx->pci_exp_lnkctl_or != 0) |
| 346 | * If the Root Port supports Read Completion Boundary of | 342 | pci_info(dev, "_HPX attempts Link Control setting (AND %#06x OR %#06x)\n", |
| 347 | * 128, set RCB to 128. Otherwise, clear it. | 343 | hpx->pci_exp_lnkctl_and, |
| 348 | */ | 344 | hpx->pci_exp_lnkctl_or); |
| 349 | hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; | ||
| 350 | hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; | ||
| 351 | if (pcie_root_rcb_set(dev)) | ||
| 352 | hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; | ||
| 353 | |||
| 354 | pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, | ||
| 355 | ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); | ||
| 356 | } | 345 | } |
| 357 | 346 | ||
| 358 | /* Find Advanced Error Reporting Enhanced Capability */ | 347 | /* Find Advanced Error Reporting Enhanced Capability */ |
| @@ -1679,6 +1679,14 @@ static int pci_dma_configure(struct device *dev) · 1678 unmodified lines | |||
| 1679 | ret = acpi_dma_configure(dev, acpi_get_dma_attr(adev)); | 1679 | ret = acpi_dma_configure(dev, acpi_get_dma_attr(adev)); |
| 1680 | } | 1680 | } |
| 1681 | 1681 | ||
| 1682 | /* | ||
| 1683 | * Attempt to enable ACS regardless of capability because some Root | ||
| 1684 | * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have | ||
| 1685 | * the standard ACS capability but still support ACS via those | ||
| 1686 | * quirks. | ||
| 1687 | */ | ||
| 1688 | pci_enable_acs(to_pci_dev(dev)); | ||
| 1689 | |||
| 1682 | pci_put_host_bridge_device(bridge); | 1690 | pci_put_host_bridge_device(bridge); |
| 1683 | 1691 | ||
| 1684 | /* @drv may not be valid when we're called from the IOMMU layer */ | 1692 | /* @drv may not be valid when we're called from the IOMMU layer */ |
| @@ -1730,34 +1738,6 @@ const struct bus_type pci_bus_type = { · 45 unmodified lines | |||
| 1730 | }; | 1738 | }; |
| 1731 | EXPORT_SYMBOL(pci_bus_type); | 1739 | EXPORT_SYMBOL(pci_bus_type); |
| 1732 | 1740 | ||
| 1733 | #ifdef CONFIG_PCIEPORTBUS | ||
| 1734 | static int pcie_port_bus_match(struct device *dev, const struct device_driver *drv) | ||
| 1735 | { | ||
| 1736 | struct pcie_device *pciedev; | ||
| 1737 | const struct pcie_port_service_driver *driver; | ||
| 1738 | |||
| 1739 | if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) | ||
| 1740 | return 0; | ||
| 1741 | |||
| 1742 | pciedev = to_pcie_device(dev); | ||
| 1743 | driver = to_service_driver(drv); | ||
| 1744 | |||
| 1745 | if (driver->service != pciedev->service) | ||
| 1746 | return 0; | ||
| 1747 | |||
| 1748 | if (driver->port_type != PCIE_ANY_PORT && | ||
| 1749 | driver->port_type != pci_pcie_type(pciedev->port)) | ||
| 1750 | return 0; | ||
| 1751 | |||
| 1752 | return 1; | ||
| 1753 | } | ||
| 1754 | |||
| 1755 | const struct bus_type pcie_port_bus_type = { | ||
| 1756 | .name = "pci_express", | ||
| 1757 | .match = pcie_port_bus_match, | ||
| 1758 | }; | ||
| 1759 | #endif | ||
| 1760 | |||
| 1761 | static int __init pci_driver_init(void) | 1741 | static int __init pci_driver_init(void) |
| 1762 | { | 1742 | { |
| 1763 | int ret; | 1743 | int ret; |
| @@ -181,7 +181,7 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr, · 180 unmodified lines | |||
| 181 | struct resource zerores = {}; | 181 | struct resource zerores = {}; |
| 182 | 182 | ||
| 183 | /* For backwards compatibility */ | 183 | /* For backwards compatibility */ |
| 184 | if (i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END && | 184 | if (pci_resource_is_bridge_win(i) && |
| 185 | res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) | 185 | res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) |
| 186 | res = &zerores; | 186 | res = &zerores; |
| 187 | 187 | ||
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/dmi.h> | 14 | #include <linux/dmi.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/iommu.h> | 16 | #include <linux/iommu.h> |
| 17 | #include <linux/lockdep.h> | ||
| 17 | #include <linux/msi.h> | 18 | #include <linux/msi.h> |
| 18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| 19 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
| @@ -101,12 +102,6 @@ bool pci_reset_supported(struct pci_dev *dev) · 81 unmodified lines | |||
| 101 | int pci_domains_supported = 1; | 102 | int pci_domains_supported = 1; |
| 102 | #endif | 103 | #endif |
| 103 | 104 | ||
| 104 | #define DEFAULT_CARDBUS_IO_SIZE (256) | ||
| 105 | #define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) | ||
| 106 | /* pci=cbmemsize=nnM,cbiosize=nn can override this */ | ||
| 107 | unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; | ||
| 108 | unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; | ||
| 109 | |||
| 110 | #define DEFAULT_HOTPLUG_IO_SIZE (256) | 105 | #define DEFAULT_HOTPLUG_IO_SIZE (256) |
| 111 | #define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024) | 106 | #define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024) |
| 112 | #define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024) | 107 | #define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024) |
| @@ -428,7 +423,7 @@ found: · 315 unmodified lines | |||
| 428 | static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, | 423 | static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, |
| 429 | u8 pos, int cap) | 424 | u8 pos, int cap) |
| 430 | { | 425 | { |
| 431 | return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn); | 426 | return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, NULL, bus, devfn); |
| 432 | } | 427 | } |
| 433 | 428 | ||
| 434 | u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) | 429 | u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) |
| @@ -533,7 +528,7 @@ u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap) · 98 unmodified lines | |||
| 533 | return 0; | 528 | return 0; |
| 534 | 529 | ||
| 535 | return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap, | 530 | return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap, |
| 536 | dev->bus, dev->devfn); | 531 | NULL, dev->bus, dev->devfn); |
| 537 | } | 532 | } |
| 538 | EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); | 533 | EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); |
| 539 | 534 | ||
| @@ -602,7 +597,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) · 62 unmodified lines | |||
| 602 | mask = HT_5BIT_CAP_MASK; | 597 | mask = HT_5BIT_CAP_MASK; |
| 603 | 598 | ||
| 604 | pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, | 599 | pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, |
| 605 | PCI_CAP_ID_HT, dev->bus, dev->devfn); | 600 | PCI_CAP_ID_HT, NULL, dev->bus, dev->devfn); |
| 606 | while (pos) { | 601 | while (pos) { |
| 607 | rc = pci_read_config_byte(dev, pos + 3, &cap); | 602 | rc = pci_read_config_byte(dev, pos + 3, &cap); |
| 608 | if (rc != PCIBIOS_SUCCESSFUL) | 603 | if (rc != PCIBIOS_SUCCESSFUL) |
| @@ -613,7 +608,7 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap) · 4 unmodified lines | |||
| 613 | 608 | ||
| 614 | pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, | 609 | pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, |
| 615 | pos + PCI_CAP_LIST_NEXT, | 610 | pos + PCI_CAP_LIST_NEXT, |
| 616 | PCI_CAP_ID_HT, dev->bus, | 611 | PCI_CAP_ID_HT, NULL, dev->bus, |
| 617 | dev->devfn); | 612 | dev->devfn); |
| 618 | } | 613 | } |
| 619 | 614 | ||
| @@ -894,7 +889,6 @@ static const char *disable_acs_redir_param; · 274 unmodified lines | |||
| 894 | static const char *config_acs_param; | 889 | static const char *config_acs_param; |
| 895 | 890 | ||
| 896 | struct pci_acs { | 891 | struct pci_acs { |
| 897 | u16 cap; | ||
| 898 | u16 ctrl; | 892 | u16 ctrl; |
| 899 | u16 fw_ctrl; | 893 | u16 fw_ctrl; |
| 900 | }; | 894 | }; |
| @@ -997,27 +991,27 @@ static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps, · 96 unmodified lines | |||
| 997 | static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps) | 991 | static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps) |
| 998 | { | 992 | { |
| 999 | /* Source Validation */ | 993 | /* Source Validation */ |
| 1000 | caps->ctrl |= (caps->cap & PCI_ACS_SV); | 994 | caps->ctrl |= (dev->acs_capabilities & PCI_ACS_SV); |
| 1001 | 995 | ||
| 1002 | /* P2P Request Redirect */ | 996 | /* P2P Request Redirect */ |
| 1003 | caps->ctrl |= (caps->cap & PCI_ACS_RR); | 997 | caps->ctrl |= (dev->acs_capabilities & PCI_ACS_RR); |
| 1004 | 998 | ||
| 1005 | /* P2P Completion Redirect */ | 999 | /* P2P Completion Redirect */ |
| 1006 | caps->ctrl |= (caps->cap & PCI_ACS_CR); | 1000 | caps->ctrl |= (dev->acs_capabilities & PCI_ACS_CR); |
| 1007 | 1001 | ||
| 1008 | /* Upstream Forwarding */ | 1002 | /* Upstream Forwarding */ |
| 1009 | caps->ctrl |= (caps->cap & PCI_ACS_UF); | 1003 | caps->ctrl |= (dev->acs_capabilities & PCI_ACS_UF); |
| 1010 | 1004 | ||
| 1011 | /* Enable Translation Blocking for external devices and noats */ | 1005 | /* Enable Translation Blocking for external devices and noats */ |
| 1012 | if (pci_ats_disabled() || dev->external_facing || dev->untrusted) | 1006 | if (pci_ats_disabled() || dev->external_facing || dev->untrusted) |
| 1013 | caps->ctrl |= (caps->cap & PCI_ACS_TB); | 1007 | caps->ctrl |= (dev->acs_capabilities & PCI_ACS_TB); |
| 1014 | } | 1008 | } |
| 1015 | 1009 | ||
| 1016 | /** | 1010 | /** |
| 1017 | * pci_enable_acs - enable ACS if hardware support it | 1011 | * pci_enable_acs - enable ACS if hardware support it |
| 1018 | * @dev: the PCI device | 1012 | * @dev: the PCI device |
| 1019 | */ | 1013 | */ |
| 1020 | static void pci_enable_acs(struct pci_dev *dev) | 1014 | void pci_enable_acs(struct pci_dev *dev) |
| 1021 | { | 1015 | { |
| 1022 | struct pci_acs caps; | 1016 | struct pci_acs caps; |
| 1023 | bool enable_acs = false; | 1017 | bool enable_acs = false; |
| @@ -1033,7 +1027,6 @@ static void pci_enable_acs(struct pci_dev *dev) · 9 unmodified lines | |||
| 1033 | if (!pos) | 1027 | if (!pos) |
| 1034 | return; | 1028 | return; |
| 1035 | 1029 | ||
| 1036 | pci_read_config_word(dev, pos + PCI_ACS_CAP, &caps.cap); | ||
| 1037 | pci_read_config_word(dev, pos + PCI_ACS_CTRL, &caps.ctrl); | 1030 | pci_read_config_word(dev, pos + PCI_ACS_CTRL, &caps.ctrl); |
| 1038 | caps.fw_ctrl = caps.ctrl; | 1031 | caps.fw_ctrl = caps.ctrl; |
| 1039 | 1032 | ||
| @@ -1490,6 +1483,9 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool · 450 unmodified lines | |||
| 1490 | || (state == PCI_D2 && !dev->d2_support)) | 1483 | || (state == PCI_D2 && !dev->d2_support)) |
| 1491 | return -EIO; | 1484 | return -EIO; |
| 1492 | 1485 | ||
| 1486 | if (dev->current_state == state) | ||
| 1487 | return 0; | ||
| 1488 | |||
| 1493 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); | 1489 | pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); |
| 1494 | if (PCI_POSSIBLE_ERROR(pmcsr)) { | 1490 | if (PCI_POSSIBLE_ERROR(pmcsr)) { |
| 1495 | pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", | 1491 | pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n", |
| @@ -2258,7 +2254,7 @@ void pcie_clear_device_status(struct pci_dev *dev) · 762 unmodified lines | |||
| 2258 | */ | 2254 | */ |
| 2259 | void pcie_clear_root_pme_status(struct pci_dev *dev) | 2255 | void pcie_clear_root_pme_status(struct pci_dev *dev) |
| 2260 | { | 2256 | { |
| 2261 | pcie_capability_set_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME); | 2257 | pcie_capability_write_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME); |
| 2262 | } | 2258 | } |
| 2263 | 2259 | ||
| 2264 | /** | 2260 | /** |
| @@ -3198,8 +3194,14 @@ void pci_pm_init(struct pci_dev *dev) · 933 unmodified lines | |||
| 3198 | poweron: | 3194 | poweron: |
| 3199 | pci_pm_power_up_and_verify_state(dev); | 3195 | pci_pm_power_up_and_verify_state(dev); |
| 3200 | pm_runtime_forbid(&dev->dev); | 3196 | pm_runtime_forbid(&dev->dev); |
| 3197 | |||
| 3198 | /* | ||
| 3199 | * Runtime PM will be enabled for the device when it has been fully | ||
| 3200 | * configured, but since its parent and suppliers may suspend in | ||
| 3201 | * the meantime, prevent them from doing so by changing the | ||
| 3202 | * device's runtime PM status to "active". | ||
| 3203 | */ | ||
| 3201 | pm_runtime_set_active(&dev->dev); | 3204 | pm_runtime_set_active(&dev->dev); |
| 3202 | pm_runtime_enable(&dev->dev); | ||
| 3203 | } | 3205 | } |
| 3204 | 3206 | ||
| 3205 | static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop) | 3207 | static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop) |
| @@ -3516,7 +3518,7 @@ void pci_configure_ari(struct pci_dev *dev) · 310 unmodified lines | |||
| 3516 | static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) | 3518 | static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) |
| 3517 | { | 3519 | { |
| 3518 | int pos; | 3520 | int pos; |
| 3519 | u16 cap, ctrl; | 3521 | u16 ctrl; |
| 3520 | 3522 | ||
| 3521 | pos = pdev->acs_cap; | 3523 | pos = pdev->acs_cap; |
| 3522 | if (!pos) | 3524 | if (!pos) |
| @@ -3527,8 +3529,7 @@ static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) · 4 unmodified lines | |||
| 3527 | * or only required if controllable. Features missing from the | 3529 | * or only required if controllable. Features missing from the |
| 3528 | * capability field can therefore be assumed as hard-wired enabled. | 3530 | * capability field can therefore be assumed as hard-wired enabled. |
| 3529 | */ | 3531 | */ |
| 3530 | pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap); | 3532 | acs_flags &= (pdev->acs_capabilities | PCI_ACS_EC); |
| 3531 | acs_flags &= (cap | PCI_ACS_EC); | ||
| 3532 | 3533 | ||
| 3533 | pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); | 3534 | pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); |
| 3534 | return (ctrl & acs_flags) == acs_flags; | 3535 | return (ctrl & acs_flags) == acs_flags; |
| @@ -3649,15 +3650,15 @@ bool pci_acs_path_enabled(struct pci_dev *start, · 114 unmodified lines | |||
| 3649 | */ | 3650 | */ |
| 3650 | void pci_acs_init(struct pci_dev *dev) | 3651 | void pci_acs_init(struct pci_dev *dev) |
| 3651 | { | 3652 | { |
| 3653 | int pos; | ||
| 3654 | |||
| 3652 | dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); | 3655 | dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); |
| 3656 | pos = dev->acs_cap; | ||
| 3657 | if (!pos) | ||
| 3658 | return; | ||
| 3653 | 3659 | ||
| 3654 | /* | 3660 | pci_read_config_word(dev, pos + PCI_ACS_CAP, &dev->acs_capabilities); |
| 3655 | * Attempt to enable ACS regardless of capability because some Root | 3661 | pci_disable_broken_acs_cap(dev); |
| 3656 | * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have | ||
| 3657 | * the standard ACS capability but still support ACS via those | ||
| 3658 | * quirks. | ||
| 3659 | */ | ||
| 3660 | pci_enable_acs(dev); | ||
| 3661 | } | 3662 | } |
| 3662 | 3663 | ||
| 3663 | /** | 3664 | /** |
| @@ -4584,7 +4585,7 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) · 920 unmodified lines | |||
| 4584 | * Link Speed. | 4585 | * Link Speed. |
| 4585 | */ | 4586 | */ |
| 4586 | if (pdev->subordinate) | 4587 | if (pdev->subordinate) |
| 4587 | pcie_update_link_speed(pdev->subordinate); | 4588 | pcie_update_link_speed(pdev->subordinate, PCIE_LINK_RETRAIN); |
| 4588 | 4589 | ||
| 4589 | return rc; | 4590 | return rc; |
| 4590 | } | 4591 | } |
| @@ -4656,7 +4657,7 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active) · 65 unmodified lines | |||
| 4656 | * spec says 100 ms, but firmware can lower it and we allow drivers to | 4657 | * spec says 100 ms, but firmware can lower it and we allow drivers to |
| 4657 | * increase it as well. | 4658 | * increase it as well. |
| 4658 | * | 4659 | * |
| 4659 | * Called with @pci_bus_sem locked for reading. | 4660 | * Context: Called with @pci_bus_sem locked for reading. |
| 4660 | */ | 4661 | */ |
| 4661 | static int pci_bus_max_d3cold_delay(const struct pci_bus *bus) | 4662 | static int pci_bus_max_d3cold_delay(const struct pci_bus *bus) |
| 4662 | { | 4663 | { |
| @@ -4664,6 +4665,8 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus) · 1 unmodified line | |||
| 4664 | int min_delay = 100; | 4665 | int min_delay = 100; |
| 4665 | int max_delay = 0; | 4666 | int max_delay = 0; |
| 4666 | 4667 | ||
| 4668 | lockdep_assert_held(&pci_bus_sem); | ||
| 4669 | |||
| 4667 | list_for_each_entry(pdev, &bus->devices, bus_list) { | 4670 | list_for_each_entry(pdev, &bus->devices, bus_list) { |
| 4668 | if (pdev->d3cold_delay < min_delay) | 4671 | if (pdev->d3cold_delay < min_delay) |
| 4669 | min_delay = pdev->d3cold_delay; | 4672 | min_delay = pdev->d3cold_delay; |
| @@ -5018,6 +5021,7 @@ static void pci_dev_save_and_disable(struct pci_dev *dev) · 348 unmodified lines | |||
| 5018 | * races with ->remove() by the device lock, which must be held by | 5021 | * races with ->remove() by the device lock, which must be held by |
| 5019 | * the caller. | 5022 | * the caller. |
| 5020 | */ | 5023 | */ |
| 5024 | device_lock_assert(&dev->dev); | ||
| 5021 | if (err_handler && err_handler->reset_prepare) | 5025 | if (err_handler && err_handler->reset_prepare) |
| 5022 | err_handler->reset_prepare(dev); | 5026 | err_handler->reset_prepare(dev); |
| 5023 | else if (dev->driver) | 5027 | else if (dev->driver) |
| @@ -5088,7 +5092,9 @@ const struct pci_reset_fn_method pci_reset_fn_methods[] = { · 64 unmodified lines | |||
| 5088 | * device including MSI, bus mastering, BARs, decoding IO and memory spaces, | 5092 | * device including MSI, bus mastering, BARs, decoding IO and memory spaces, |
| 5089 | * etc. | 5093 | * etc. |
| 5090 | * | 5094 | * |
| 5091 | * Returns 0 if the device function was successfully reset or negative if the | 5095 | * Context: The caller must hold the device lock. |
| 5096 | * | ||
| 5097 | * Return: 0 if the device function was successfully reset or negative if the | ||
| 5092 | * device doesn't support resetting a single function. | 5098 | * device doesn't support resetting a single function. |
| 5093 | */ | 5099 | */ |
| 5094 | int __pci_reset_function_locked(struct pci_dev *dev) | 5100 | int __pci_reset_function_locked(struct pci_dev *dev) |
| @@ -5097,6 +5103,7 @@ int __pci_reset_function_locked(struct pci_dev *dev) · 2 unmodified lines | |||
| 5097 | const struct pci_reset_fn_method *method; | 5103 | const struct pci_reset_fn_method *method; |
| 5098 | 5104 | ||
| 5099 | might_sleep(); | 5105 | might_sleep(); |
| 5106 | device_lock_assert(&dev->dev); | ||
| 5100 | 5107 | ||
| 5101 | /* | 5108 | /* |
| 5102 | * A reset method returns -ENOTTY if it doesn't support this device and | 5109 | * A reset method returns -ENOTTY if it doesn't support this device and |
| @@ -5219,13 +5226,17 @@ EXPORT_SYMBOL_GPL(pci_reset_function); · 116 unmodified lines | |||
| 5219 | * over the reset. It also differs from pci_reset_function() in that it | 5226 | * over the reset. It also differs from pci_reset_function() in that it |
| 5220 | * requires the PCI device lock to be held. | 5227 | * requires the PCI device lock to be held. |
| 5221 | * | 5228 | * |
| 5222 | * Returns 0 if the device function was successfully reset or negative if the | 5229 | * Context: The caller must hold the device lock. |
| 5230 | * | ||
| 5231 | * Return: 0 if the device function was successfully reset or negative if the | ||
| 5223 | * device doesn't support resetting a single function. | 5232 | * device doesn't support resetting a single function. |
| 5224 | */ | 5233 | */ |
| 5225 | int pci_reset_function_locked(struct pci_dev *dev) | 5234 | int pci_reset_function_locked(struct pci_dev *dev) |
| 5226 | { | 5235 | { |
| 5227 | int rc; | 5236 | int rc; |
| 5228 | 5237 | ||
| 5238 | device_lock_assert(&dev->dev); | ||
| 5239 | |||
| 5229 | if (!pci_reset_supported(dev)) | 5240 | if (!pci_reset_supported(dev)) |
| 5230 | return -ENOTTY; | 5241 | return -ENOTTY; |
| 5231 | 5242 | ||
| @@ -5341,10 +5352,9 @@ unlock: · 109 unmodified lines | |||
| 5341 | /* Do any devices on or below this slot prevent a bus reset? */ | 5352 | /* Do any devices on or below this slot prevent a bus reset? */ |
| 5342 | static bool pci_slot_resettable(struct pci_slot *slot) | 5353 | static bool pci_slot_resettable(struct pci_slot *slot) |
| 5343 | { | 5354 | { |
| 5344 | struct pci_dev *dev; | 5355 | struct pci_dev *dev, *bridge = slot->bus->self; |
| 5345 | 5356 | ||
| 5346 | if (slot->bus->self && | 5357 | if (bridge && (bridge->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) |
| 5347 | (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) | ||
| 5348 | return false; | 5358 | return false; |
| 5349 | 5359 | ||
| 5350 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | 5360 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { |
| @@ -5361,7 +5371,10 @@ static bool pci_slot_resettable(struct pci_slot *slot) · 10 unmodified lines | |||
| 5361 | /* Lock devices from the top of the tree down */ | 5371 | /* Lock devices from the top of the tree down */ |
| 5362 | static void pci_slot_lock(struct pci_slot *slot) | 5372 | static void pci_slot_lock(struct pci_slot *slot) |
| 5363 | { | 5373 | { |
| 5364 | struct pci_dev *dev; | 5374 | struct pci_dev *dev, *bridge = slot->bus->self; |
| 5375 | |||
| 5376 | if (bridge) | ||
| 5377 | pci_dev_lock(bridge); | ||
| 5365 | 5378 | ||
| 5366 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | 5379 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { |
| 5367 | if (!dev->slot || dev->slot != slot) | 5380 | if (!dev->slot || dev->slot != slot) |
| @@ -5376,7 +5389,7 @@ static void pci_slot_lock(struct pci_slot *slot) · 8 unmodified lines | |||
| 5376 | /* Unlock devices from the bottom of the tree up */ | 5389 | /* Unlock devices from the bottom of the tree up */ |
| 5377 | static void pci_slot_unlock(struct pci_slot *slot) | 5390 | static void pci_slot_unlock(struct pci_slot *slot) |
| 5378 | { | 5391 | { |
| 5379 | struct pci_dev *dev; | 5392 | struct pci_dev *dev, *bridge = slot->bus->self; |
| 5380 | 5393 | ||
| 5381 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | 5394 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { |
| 5382 | if (!dev->slot || dev->slot != slot) | 5395 | if (!dev->slot || dev->slot != slot) |
| @@ -5386,21 +5399,25 @@ static void pci_slot_unlock(struct pci_slot *slot) · 3 unmodified lines | |||
| 5386 | else | 5399 | else |
| 5387 | pci_dev_unlock(dev); | 5400 | pci_dev_unlock(dev); |
| 5388 | } | 5401 | } |
| 5402 | |||
| 5403 | if (bridge) | ||
| 5404 | pci_dev_unlock(bridge); | ||
| 5389 | } | 5405 | } |
| 5390 | 5406 | ||
| 5391 | /* Return 1 on successful lock, 0 on contention */ | 5407 | /* Return 1 on successful lock, 0 on contention */ |
| 5392 | static int pci_slot_trylock(struct pci_slot *slot) | 5408 | static int pci_slot_trylock(struct pci_slot *slot) |
| 5393 | { | 5409 | { |
| 5394 | struct pci_dev *dev; | 5410 | struct pci_dev *dev, *bridge = slot->bus->self; |
| 5411 | |||
| 5412 | if (bridge && !pci_dev_trylock(bridge)) | ||
| 5413 | return 0; | ||
| 5395 | 5414 | ||
| 5396 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { | 5415 | list_for_each_entry(dev, &slot->bus->devices, bus_list) { |
| 5397 | if (!dev->slot || dev->slot != slot) | 5416 | if (!dev->slot || dev->slot != slot) |
| 5398 | continue; | 5417 | continue; |
| 5399 | if (dev->subordinate) { | 5418 | if (dev->subordinate) { |
| 5400 | if (!pci_bus_trylock(dev->subordinate)) { | 5419 | if (!pci_bus_trylock(dev->subordinate)) |
| 5401 | pci_dev_unlock(dev); | ||
| 5402 | goto unlock; | 5420 | goto unlock; |
| 5403 | } | ||
| 5404 | } else if (!pci_dev_trylock(dev)) | 5421 | } else if (!pci_dev_trylock(dev)) |
| 5405 | goto unlock; | 5422 | goto unlock; |
| 5406 | } | 5423 | } |
| @@ -5416,6 +5433,9 @@ unlock: · 9 unmodified lines | |||
| 5416 | else | 5433 | else |
| 5417 | pci_dev_unlock(dev); | 5434 | pci_dev_unlock(dev); |
| 5418 | } | 5435 | } |
| 5436 | |||
| 5437 | if (bridge) | ||
| 5438 | pci_dev_unlock(bridge); | ||
| 5419 | return 0; | 5439 | return 0; |
| 5420 | } | 5440 | } |
| 5421 | 5441 | ||
| @@ -6642,7 +6662,7 @@ static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) · 1220 unmodified lines | |||
| 6642 | return; | 6662 | return; |
| 6643 | 6663 | ||
| 6644 | /* Release domain from IDA where it was allocated. */ | 6664 | /* Release domain from IDA where it was allocated. */ |
| 6645 | if (of_get_pci_domain_nr(parent->of_node) == domain_nr) | 6665 | if (parent && of_get_pci_domain_nr(parent->of_node) == domain_nr) |
| 6646 | ida_free(&pci_domain_nr_static_ida, domain_nr); | 6666 | ida_free(&pci_domain_nr_static_ida, domain_nr); |
| 6647 | else | 6667 | else |
| 6648 | ida_free(&pci_domain_nr_dynamic_ida, domain_nr); | 6668 | ida_free(&pci_domain_nr_dynamic_ida, domain_nr); |
| @@ -6681,7 +6701,9 @@ static int __init pci_setup(char *str) · 32 unmodified lines | |||
| 6681 | if (k) | 6701 | if (k) |
| 6682 | *k++ = 0; | 6702 | *k++ = 0; |
| 6683 | if (*str && (str = pcibios_setup(str)) && *str) { | 6703 | if (*str && (str = pcibios_setup(str)) && *str) { |
| 6684 | if (!strcmp(str, "nomsi")) { | 6704 | if (!pci_setup_cardbus(str)) { |
| 6705 | /* Function handled the parameters */ | ||
| 6706 | } else if (!strcmp(str, "nomsi")) { | ||
| 6685 | pci_no_msi(); | 6707 | pci_no_msi(); |
| 6686 | } else if (!strncmp(str, "noats", 5)) { | 6708 | } else if (!strncmp(str, "noats", 5)) { |
| 6687 | pr_info("PCIe: ATS is disabled\n"); | 6709 | pr_info("PCIe: ATS is disabled\n"); |
| @@ -6700,10 +6722,6 @@ static int __init pci_setup(char *str) · 12 unmodified lines | |||
| 6700 | pcie_ari_disabled = true; | 6722 | pcie_ari_disabled = true; |
| 6701 | } else if (!strncmp(str, "notph", 5)) { | 6723 | } else if (!strncmp(str, "notph", 5)) { |
| 6702 | pci_no_tph(); | 6724 | pci_no_tph(); |
| 6703 | } else if (!strncmp(str, "cbiosize=", 9)) { | ||
| 6704 | pci_cardbus_io_size = memparse(str + 9, &str); | ||
| 6705 | } else if (!strncmp(str, "cbmemsize=", 10)) { | ||
| 6706 | pci_cardbus_mem_size = memparse(str + 10, &str); | ||
| 6707 | } else if (!strncmp(str, "resource_alignment=", 19)) { | 6725 | } else if (!strncmp(str, "resource_alignment=", 19)) { |
| 6708 | resource_alignment_param = str + 19; | 6726 | resource_alignment_param = str + 19; |
| 6709 | } else if (!strncmp(str, "ecrc=", 5)) { | 6727 | } else if (!strncmp(str, "ecrc=", 5)) { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | #include <linux/align.h> | 5 | #include <linux/align.h> |
| 6 | #include <linux/bitfield.h> | 6 | #include <linux/bitfield.h> |
| 7 | #include <linux/pci.h> | 7 | #include <linux/pci.h> |
| 8 | #include <trace/events/pci.h> | ||
| 8 | 9 | ||
| 9 | struct pcie_tlp_log; | 10 | struct pcie_tlp_log; |
| 10 | 11 | ||
| @@ -63,6 +64,18 @@ struct pcie_tlp_log; · 52 unmodified lines | |||
| 63 | #define PCIE_LINK_WAIT_MAX_RETRIES 10 | 64 | #define PCIE_LINK_WAIT_MAX_RETRIES 10 |
| 64 | #define PCIE_LINK_WAIT_SLEEP_MS 90 | 65 | #define PCIE_LINK_WAIT_SLEEP_MS 90 |
| 65 | 66 | ||
| 67 | /* Format of TLP; PCIe r7.0, sec 2.2.1 */ | ||
| 68 | #define PCIE_TLP_FMT_3DW_NO_DATA 0x00 /* 3DW header, no data */ | ||
| 69 | #define PCIE_TLP_FMT_4DW_NO_DATA 0x01 /* 4DW header, no data */ | ||
| 70 | #define PCIE_TLP_FMT_3DW_DATA 0x02 /* 3DW header, with data */ | ||
| 71 | #define PCIE_TLP_FMT_4DW_DATA 0x03 /* 4DW header, with data */ | ||
| 72 | |||
| 73 | /* Type of TLP; PCIe r7.0, sec 2.2.1 */ | ||
| 74 | #define PCIE_TLP_TYPE_CFG0_RD 0x04 /* Config Type 0 Read Request */ | ||
| 75 | #define PCIE_TLP_TYPE_CFG0_WR 0x04 /* Config Type 0 Write Request */ | ||
| 76 | #define PCIE_TLP_TYPE_CFG1_RD 0x05 /* Config Type 1 Read Request */ | ||
| 77 | #define PCIE_TLP_TYPE_CFG1_WR 0x05 /* Config Type 1 Write Request */ | ||
| 78 | |||
| 66 | /* Message Routing (r[2:0]); PCIe r6.0, sec 2.2.8 */ | 79 | /* Message Routing (r[2:0]); PCIe r6.0, sec 2.2.8 */ |
| 67 | #define PCIE_MSG_TYPE_R_RC 0 | 80 | #define PCIE_MSG_TYPE_R_RC 0 |
| 68 | #define PCIE_MSG_TYPE_R_ADDR 1 | 81 | #define PCIE_MSG_TYPE_R_ADDR 1 |
| @@ -84,10 +97,16 @@ struct pcie_tlp_log; · 15 unmodified lines | |||
| 84 | #define PCIE_MSG_CODE_DEASSERT_INTC 0x26 | 97 | #define PCIE_MSG_CODE_DEASSERT_INTC 0x26 |
| 85 | #define PCIE_MSG_CODE_DEASSERT_INTD 0x27 | 98 | #define PCIE_MSG_CODE_DEASSERT_INTD 0x27 |
| 86 | 99 | ||
| 100 | /* Cpl. status of Complete; PCIe r7.0, sec 2.2.9.1 */ | ||
| 101 | #define PCIE_CPL_STS_SUCCESS 0x00 /* Successful Completion */ | ||
| 102 | |||
| 87 | #define PCI_BUS_BRIDGE_IO_WINDOW 0 | 103 | #define PCI_BUS_BRIDGE_IO_WINDOW 0 |
| 88 | #define PCI_BUS_BRIDGE_MEM_WINDOW 1 | 104 | #define PCI_BUS_BRIDGE_MEM_WINDOW 1 |
| 89 | #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 | 105 | #define PCI_BUS_BRIDGE_PREF_MEM_WINDOW 2 |
| 90 | 106 | ||
| 107 | #define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ | ||
| 108 | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) | ||
| 109 | |||
| 91 | extern const unsigned char pcie_link_speed[]; | 110 | extern const unsigned char pcie_link_speed[]; |
| 92 | extern bool pci_early_dump; | 111 | extern bool pci_early_dump; |
| 93 | 112 | ||
| @@ -103,17 +122,21 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); · 9 unmodified lines | |||
| 103 | * @read_cfg: Function pointer for reading PCI config space | 122 | * @read_cfg: Function pointer for reading PCI config space |
| 104 | * @start: Starting position to begin search | 123 | * @start: Starting position to begin search |
| 105 | * @cap: Capability ID to find | 124 | * @cap: Capability ID to find |
| 125 | * @prev_ptr: Pointer to store position of preceding capability (optional) | ||
| 106 | * @args: Arguments to pass to read_cfg function | 126 | * @args: Arguments to pass to read_cfg function |
| 107 | * | 127 | * |
| 108 | * Search the capability list in PCI config space to find @cap. | 128 | * Search the capability list in PCI config space to find @cap. If |
| 129 | * found, update *prev_ptr with the position of the preceding capability | ||
| 130 | * (if prev_ptr != NULL) | ||
| 109 | * Implements TTL (time-to-live) protection against infinite loops. | 131 | * Implements TTL (time-to-live) protection against infinite loops. |
| 110 | * | 132 | * |
| 111 | * Return: Position of the capability if found, 0 otherwise. | 133 | * Return: Position of the capability if found, 0 otherwise. |
| 112 | */ | 134 | */ |
| 113 | #define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...) \ | 135 | #define PCI_FIND_NEXT_CAP(read_cfg, start, cap, prev_ptr, args...) \ |
| 114 | ({ \ | 136 | ({ \ |
| 115 | int __ttl = PCI_FIND_CAP_TTL; \ | 137 | int __ttl = PCI_FIND_CAP_TTL; \ |
| 116 | u8 __id, __found_pos = 0; \ | 138 | u8 __id, __found_pos = 0; \ |
| 139 | u8 __prev_pos = (start); \ | ||
| 117 | u8 __pos = (start); \ | 140 | u8 __pos = (start); \ |
| 118 | u16 __ent; \ | 141 | u16 __ent; \ |
| 119 | \ | 142 | \ |
| @@ -132,9 +155,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); · 12 unmodified lines | |||
| 132 | \ | 155 | \ |
| 133 | if (__id == (cap)) { \ | 156 | if (__id == (cap)) { \ |
| 134 | __found_pos = __pos; \ | 157 | __found_pos = __pos; \ |
| 158 | if (prev_ptr != NULL) \ | ||
| 159 | *(u8 *)prev_ptr = __prev_pos; \ | ||
| 135 | break; \ | 160 | break; \ |
| 136 | } \ | 161 | } \ |
| 137 | \ | 162 | \ |
| 163 | __prev_pos = __pos; \ | ||
| 138 | __pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \ | 164 | __pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \ |
| 139 | } \ | 165 | } \ |
| 140 | __found_pos; \ | 166 | __found_pos; \ |
| @@ -146,21 +172,26 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); · 5 unmodified lines | |||
| 146 | * @read_cfg: Function pointer for reading PCI config space | 172 | * @read_cfg: Function pointer for reading PCI config space |
| 147 | * @start: Starting position to begin search (0 for initial search) | 173 | * @start: Starting position to begin search (0 for initial search) |
| 148 | * @cap: Extended capability ID to find | 174 | * @cap: Extended capability ID to find |
| 175 | * @prev_ptr: Pointer to store position of preceding capability (optional) | ||
| 149 | * @args: Arguments to pass to read_cfg function | 176 | * @args: Arguments to pass to read_cfg function |
| 150 | * | 177 | * |
| 151 | * Search the extended capability list in PCI config space to find @cap. | 178 | * Search the extended capability list in PCI config space to find @cap. |
| 179 | * If found, update *prev_ptr with the position of the preceding capability | ||
| 180 | * (if prev_ptr != NULL) | ||
| 152 | * Implements TTL protection against infinite loops using a calculated | 181 | * Implements TTL protection against infinite loops using a calculated |
| 153 | * maximum search count. | 182 | * maximum search count. |
| 154 | * | 183 | * |
| 155 | * Return: Position of the capability if found, 0 otherwise. | 184 | * Return: Position of the capability if found, 0 otherwise. |
| 156 | */ | 185 | */ |
| 157 | #define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...) \ | 186 | #define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, prev_ptr, args...) \ |
| 158 | ({ \ | 187 | ({ \ |
| 159 | u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE; \ | 188 | u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE; \ |
| 160 | u16 __found_pos = 0; \ | 189 | u16 __found_pos = 0; \ |
| 190 | u16 __prev_pos; \ | ||
| 161 | int __ttl, __ret; \ | 191 | int __ttl, __ret; \ |
| 162 | u32 __header; \ | 192 | u32 __header; \ |
| 163 | \ | 193 | \ |
| 194 | __prev_pos = __pos; \ | ||
| 164 | __ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; \ | 195 | __ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; \ |
| 165 | while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) { \ | 196 | while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) { \ |
| 166 | __ret = read_cfg##_dword(args, __pos, &__header); \ | 197 | __ret = read_cfg##_dword(args, __pos, &__header); \ |
| @@ -172,9 +203,12 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev); · 5 unmodified lines | |||
| 172 | \ | 203 | \ |
| 173 | if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\ | 204 | if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\ |
| 174 | __found_pos = __pos; \ | 205 | __found_pos = __pos; \ |
| 206 | if (prev_ptr != NULL) \ | ||
| 207 | *(u16 *)prev_ptr = __prev_pos; \ | ||
| 175 | break; \ | 208 | break; \ |
| 176 | } \ | 209 | } \ |
| 177 | \ | 210 | \ |
| 211 | __prev_pos = __pos; \ | ||
| 178 | __pos = PCI_EXT_CAP_NEXT(__header); \ | 212 | __pos = PCI_EXT_CAP_NEXT(__header); \ |
| 179 | } \ | 213 | } \ |
| 180 | __found_pos; \ | 214 | __found_pos; \ |
| @@ -242,6 +276,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev); · 61 unmodified lines | |||
| 242 | void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev); | 276 | void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev); |
| 243 | void pci_pm_init(struct pci_dev *dev); | 277 | void pci_pm_init(struct pci_dev *dev); |
| 244 | void pci_ea_init(struct pci_dev *dev); | 278 | void pci_ea_init(struct pci_dev *dev); |
| 279 | bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub); | ||
| 245 | void pci_msi_init(struct pci_dev *dev); | 280 | void pci_msi_init(struct pci_dev *dev); |
| 246 | void pci_msix_init(struct pci_dev *dev); | 281 | void pci_msix_init(struct pci_dev *dev); |
| 247 | bool pci_bridge_d3_possible(struct pci_dev *dev); | 282 | bool pci_bridge_d3_possible(struct pci_dev *dev); |
| @@ -376,8 +411,40 @@ extern unsigned long pci_hotplug_io_size; · 128 unmodified lines | |||
| 376 | extern unsigned long pci_hotplug_mmio_size; | 411 | extern unsigned long pci_hotplug_mmio_size; |
| 377 | extern unsigned long pci_hotplug_mmio_pref_size; | 412 | extern unsigned long pci_hotplug_mmio_pref_size; |
| 378 | extern unsigned long pci_hotplug_bus_size; | 413 | extern unsigned long pci_hotplug_bus_size; |
| 379 | extern unsigned long pci_cardbus_io_size; | 414 | |
| 380 | extern unsigned long pci_cardbus_mem_size; | 415 | static inline bool pci_is_cardbus_bridge(struct pci_dev *dev) |
| 416 | { | ||
| 417 | return dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; | ||
| 418 | } | ||
| 419 | #ifdef CONFIG_CARDBUS | ||
| 420 | unsigned long pci_cardbus_resource_alignment(struct resource *res); | ||
| 421 | int pci_bus_size_cardbus_bridge(struct pci_bus *bus, | ||
| 422 | struct list_head *realloc_head); | ||
| 423 | int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, | ||
| 424 | u32 buses, int max, | ||
| 425 | unsigned int available_buses, int pass); | ||
| 426 | int pci_setup_cardbus(char *str); | ||
| 427 | |||
| 428 | #else | ||
| 429 | static inline unsigned long pci_cardbus_resource_alignment(struct resource *res) | ||
| 430 | { | ||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | static inline int pci_bus_size_cardbus_bridge(struct pci_bus *bus, | ||
| 434 | struct list_head *realloc_head) | ||
| 435 | { | ||
| 436 | return -EOPNOTSUPP; | ||
| 437 | } | ||
| 438 | static inline int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, | ||
| 439 | struct pci_dev *dev, | ||
| 440 | u32 buses, int max, | ||
| 441 | unsigned int available_buses, | ||
| 442 | int pass) | ||
| 443 | { | ||
| 444 | return max; | ||
| 445 | } | ||
| 446 | static inline int pci_setup_cardbus(char *str) { return -ENOENT; } | ||
| 447 | #endif /* CONFIG_CARDBUS */ | ||
| 381 | 448 | ||
| 382 | /** | 449 | /** |
| 383 | * pci_match_one_device - Tell if a PCI device structure has a matching | 450 | * pci_match_one_device - Tell if a PCI device structure has a matching |
| @@ -432,7 +499,6 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl, · 48 unmodified lines | |||
| 432 | int rrs_timeout); | 499 | int rrs_timeout); |
| 433 | bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl, | 500 | bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl, |
| 434 | int rrs_timeout); | 501 | int rrs_timeout); |
| 435 | int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *pl, int rrs_timeout); | ||
| 436 | 502 | ||
| 437 | int pci_setup_device(struct pci_dev *dev); | 503 | int pci_setup_device(struct pci_dev *dev); |
| 438 | void __pci_size_stdbars(struct pci_dev *dev, int count, | 504 | void __pci_size_stdbars(struct pci_dev *dev, int count, |
| @@ -440,6 +506,10 @@ void __pci_size_stdbars(struct pci_dev *dev, int count, · 1 unmodified line | |||
| 440 | int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | 506 | int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, |
| 441 | struct resource *res, unsigned int reg, u32 *sizes); | 507 | struct resource *res, unsigned int reg, u32 *sizes); |
| 442 | void pci_configure_ari(struct pci_dev *dev); | 508 | void pci_configure_ari(struct pci_dev *dev); |
| 509 | |||
| 510 | int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev, | ||
| 511 | struct resource *res, resource_size_t add_size, | ||
| 512 | resource_size_t min_align); | ||
| 443 | void __pci_bus_size_bridges(struct pci_bus *bus, | 513 | void __pci_bus_size_bridges(struct pci_bus *bus, |
| 444 | struct list_head *realloc_head); | 514 | struct list_head *realloc_head); |
| 445 | void __pci_bus_assign_resources(const struct pci_bus *bus, | 515 | void __pci_bus_assign_resources(const struct pci_bus *bus, |
| @@ -452,6 +522,11 @@ void pci_walk_bus_locked(struct pci_bus *top, · 6 unmodified lines | |||
| 452 | 522 | ||
| 453 | const char *pci_resource_name(struct pci_dev *dev, unsigned int i); | 523 | const char *pci_resource_name(struct pci_dev *dev, unsigned int i); |
| 454 | bool pci_resource_is_optional(const struct pci_dev *dev, int resno); | 524 | bool pci_resource_is_optional(const struct pci_dev *dev, int resno); |
| 525 | static inline bool pci_resource_is_bridge_win(int resno) | ||
| 526 | { | ||
| 527 | return resno >= PCI_BRIDGE_RESOURCES && | ||
| 528 | resno <= PCI_BRIDGE_RESOURCE_END; | ||
| 529 | } | ||
| 455 | 530 | ||
| 456 | /** | 531 | /** |
| 457 | * pci_resource_num - Reverse lookup resource number from device resources | 532 | * pci_resource_num - Reverse lookup resource number from device resources |
| @@ -475,6 +550,7 @@ static inline int pci_resource_num(const struct pci_dev *dev, · 17 unmodified lines | |||
| 475 | return resno; | 550 | return resno; |
| 476 | } | 551 | } |
| 477 | 552 | ||
| 553 | void pbus_validate_busn(struct pci_bus *bus); | ||
| 478 | struct resource *pbus_select_window(struct pci_bus *bus, | 554 | struct resource *pbus_select_window(struct pci_bus *bus, |
| 479 | const struct resource *res); | 555 | const struct resource *res); |
| 480 | void pci_reassigndev_resource_alignment(struct pci_dev *dev); | 556 | void pci_reassigndev_resource_alignment(struct pci_dev *dev); |
| @@ -555,12 +631,28 @@ const char *pci_speed_string(enum pci_bus_speed speed); · 74 unmodified lines | |||
| 555 | void __pcie_print_link_status(struct pci_dev *dev, bool verbose); | 631 | void __pcie_print_link_status(struct pci_dev *dev, bool verbose); |
| 556 | void pcie_report_downtraining(struct pci_dev *dev); | 632 | void pcie_report_downtraining(struct pci_dev *dev); |
| 557 | 633 | ||
| 558 | static inline void __pcie_update_link_speed(struct pci_bus *bus, u16 linksta, u16 linksta2) | 634 | enum pcie_link_change_reason { |
| 635 | PCIE_LINK_RETRAIN, | ||
| 636 | PCIE_ADD_BUS, | ||
| 637 | PCIE_BWCTRL_ENABLE, | ||
| 638 | PCIE_BWCTRL_IRQ, | ||
| 639 | PCIE_HOTPLUG, | ||
| 640 | }; | ||
| 641 | |||
| 642 | static inline void __pcie_update_link_speed(struct pci_bus *bus, | ||
| 643 | enum pcie_link_change_reason reason, | ||
| 644 | u16 linksta, u16 linksta2) | ||
| 559 | { | 645 | { |
| 560 | bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS]; | 646 | bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS]; |
| 561 | bus->flit_mode = (linksta2 & PCI_EXP_LNKSTA2_FLIT) ? 1 : 0; | 647 | bus->flit_mode = (linksta2 & PCI_EXP_LNKSTA2_FLIT) ? 1 : 0; |
| 648 | |||
| 649 | trace_pcie_link_event(bus, | ||
| 650 | reason, | ||
| 651 | FIELD_GET(PCI_EXP_LNKSTA_NLW, linksta), | ||
| 652 | linksta & PCI_EXP_LNKSTA_LINK_STATUS_MASK); | ||
| 562 | } | 653 | } |
| 563 | void pcie_update_link_speed(struct pci_bus *bus); | 654 | |
| 655 | void pcie_update_link_speed(struct pci_bus *bus, enum pcie_link_change_reason reason); | ||
| 564 | 656 | ||
| 565 | /* Single Root I/O Virtualization */ | 657 | /* Single Root I/O Virtualization */ |
| 566 | struct pci_sriov { | 658 | struct pci_sriov { |
| @@ -924,8 +1016,6 @@ static inline void pci_suspend_ptm(struct pci_dev *dev) { } · 357 unmodified lines | |||
| 924 | static inline void pci_resume_ptm(struct pci_dev *dev) { } | 1016 | static inline void pci_resume_ptm(struct pci_dev *dev) { } |
| 925 | #endif | 1017 | #endif |
| 926 | 1018 | ||
| 927 | unsigned long pci_cardbus_resource_alignment(struct resource *); | ||
| 928 | |||
| 929 | static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, | 1019 | static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, |
| 930 | struct resource *res) | 1020 | struct resource *res) |
| 931 | { | 1021 | { |
| @@ -939,10 +1029,12 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, · 7 unmodified lines | |||
| 939 | } | 1029 | } |
| 940 | 1030 | ||
| 941 | void pci_acs_init(struct pci_dev *dev); | 1031 | void pci_acs_init(struct pci_dev *dev); |
| 1032 | void pci_enable_acs(struct pci_dev *dev); | ||
| 942 | #ifdef CONFIG_PCI_QUIRKS | 1033 | #ifdef CONFIG_PCI_QUIRKS |
| 943 | int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); | 1034 | int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); |
| 944 | int pci_dev_specific_enable_acs(struct pci_dev *dev); | 1035 | int pci_dev_specific_enable_acs(struct pci_dev *dev); |
| 945 | int pci_dev_specific_disable_acs_redir(struct pci_dev *dev); | 1036 | int pci_dev_specific_disable_acs_redir(struct pci_dev *dev); |
| 1037 | void pci_disable_broken_acs_cap(struct pci_dev *pdev); | ||
| 946 | int pcie_failed_link_retrain(struct pci_dev *dev); | 1038 | int pcie_failed_link_retrain(struct pci_dev *dev); |
| 947 | #else | 1039 | #else |
| 948 | static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, | 1040 | static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, |
| @@ -958,6 +1050,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev) · 9 unmodified lines | |||
| 958 | { | 1050 | { |
| 959 | return -ENOTTY; | 1051 | return -ENOTTY; |
| 960 | } | 1052 | } |
| 1053 | static inline void pci_disable_broken_acs_cap(struct pci_dev *dev) { } | ||
| 961 | static inline int pcie_failed_link_retrain(struct pci_dev *dev) | 1054 | static inline int pcie_failed_link_retrain(struct pci_dev *dev) |
| 962 | { | 1055 | { |
| 963 | return -ENOTTY; | 1056 | return -ENOTTY; |
| @@ -239,9 +239,6 @@ void pcie_ecrc_get_policy(char *str) · 238 unmodified lines | |||
| 239 | } | 239 | } |
| 240 | #endif /* CONFIG_PCIE_ECRC */ | 240 | #endif /* CONFIG_PCIE_ECRC */ |
| 241 | 241 | ||
| 242 | #define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ | ||
| 243 | PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) | ||
| 244 | |||
| 245 | int pcie_aer_is_native(struct pci_dev *dev) | 242 | int pcie_aer_is_native(struct pci_dev *dev) |
| 246 | { | 243 | { |
| 247 | struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); | 244 | struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); |
| @@ -1608,6 +1605,20 @@ static void aer_disable_irq(struct pci_dev *pdev) · 1360 unmodified lines | |||
| 1608 | pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); | 1605 | pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32); |
| 1609 | } | 1606 | } |
| 1610 | 1607 | ||
| 1608 | static int clear_status_iter(struct pci_dev *dev, void *data) | ||
| 1609 | { | ||
| 1610 | u16 devctl; | ||
| 1611 | |||
| 1612 | /* Skip if pci_enable_pcie_error_reporting() hasn't been called yet */ | ||
| 1613 | pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &devctl); | ||
| 1614 | if (!(devctl & PCI_EXP_AER_FLAGS)) | ||
| 1615 | return 0; | ||
| 1616 | |||
| 1617 | pci_aer_clear_status(dev); | ||
| 1618 | pcie_clear_device_status(dev); | ||
| 1619 | return 0; | ||
| 1620 | } | ||
| 1621 | |||
| 1611 | /** | 1622 | /** |
| 1612 | * aer_enable_rootport - enable Root Port's interrupts when receiving messages | 1623 | * aer_enable_rootport - enable Root Port's interrupts when receiving messages |
| 1613 | * @rpc: pointer to a Root Port data structure | 1624 | * @rpc: pointer to a Root Port data structure |
| @@ -1629,9 +1640,19 @@ static void aer_enable_rootport(struct aer_rpc *rpc) · 15 unmodified lines | |||
| 1629 | pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, | 1640 | pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, |
| 1630 | SYSTEM_ERROR_INTR_ON_MESG_MASK); | 1641 | SYSTEM_ERROR_INTR_ON_MESG_MASK); |
| 1631 | 1642 | ||
| 1632 | /* Clear error status */ | 1643 | /* Clear error status of this Root Port or RCEC */ |
| 1633 | pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32); | 1644 | pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32); |
| 1634 | pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32); | 1645 | pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32); |
| 1646 | |||
| 1647 | /* Clear error status of agents reporting to this Root Port or RCEC */ | ||
| 1648 | if (reg32 & AER_ERR_STATUS_MASK) { | ||
| 1649 | if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC) | ||
| 1650 | pcie_walk_rcec(pdev, clear_status_iter, NULL); | ||
| 1651 | else if (pdev->subordinate) | ||
| 1652 | pci_walk_bus(pdev->subordinate, clear_status_iter, | ||
| 1653 | NULL); | ||
| 1654 | } | ||
| 1655 | |||
| 1635 | pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, ®32); | 1656 | pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, ®32); |
| 1636 | pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS, reg32); | 1657 | pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS, reg32); |
| 1637 | pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, ®32); | 1658 | pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, ®32); |
| @@ -199,7 +199,7 @@ static void pcie_bwnotif_enable(struct pcie_device *srv) · 198 unmodified lines | |||
| 199 | * Update after enabling notifications & clearing status bits ensures | 199 | * Update after enabling notifications & clearing status bits ensures |
| 200 | * link speed is up to date. | 200 | * link speed is up to date. |
| 201 | */ | 201 | */ |
| 202 | pcie_update_link_speed(port->subordinate); | 202 | pcie_update_link_speed(port->subordinate, PCIE_BWCTRL_ENABLE); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static void pcie_bwnotif_disable(struct pci_dev *port) | 205 | static void pcie_bwnotif_disable(struct pci_dev *port) |
| @@ -234,7 +234,7 @@ static irqreturn_t pcie_bwnotif_irq(int irq, void *context) · 28 unmodified lines | |||
| 234 | * speed (inside pcie_update_link_speed()) after LBMS has been | 234 | * speed (inside pcie_update_link_speed()) after LBMS has been |
| 235 | * cleared to avoid missing link speed changes. | 235 | * cleared to avoid missing link speed changes. |
| 236 | */ | 236 | */ |
| 237 | pcie_update_link_speed(port->subordinate); | 237 | pcie_update_link_speed(port->subordinate, PCIE_BWCTRL_IRQ); |
| 238 | 238 | ||
| 239 | return IRQ_HANDLED; | 239 | return IRQ_HANDLED; |
| 240 | } | 240 | } |
| @@ -250,6 +250,9 @@ static int pcie_bwnotif_probe(struct pcie_device *srv) · 9 unmodified lines | |||
| 250 | struct pci_dev *port = srv->port; | 250 | struct pci_dev *port = srv->port; |
| 251 | int ret; | 251 | int ret; |
| 252 | 252 | ||
| 253 | if (port->no_bw_notif) | ||
| 254 | return -ENODEV; | ||
| 255 | |||
| 253 | /* Can happen if we run out of bus numbers during enumeration. */ | 256 | /* Can happen if we run out of bus numbers during enumeration. */ |
| 254 | if (!port->subordinate) | 257 | if (!port->subordinate) |
| 255 | return -ENODEV; | 258 | return -ENODEV; |
| @@ -508,23 +508,35 @@ static void pcie_port_device_remove(struct pci_dev *dev) · 507 unmodified lines | |||
| 508 | pci_free_irq_vectors(dev); | 508 | pci_free_irq_vectors(dev); |
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | static int pcie_port_bus_match(struct device *dev, const struct device_driver *drv) | ||
| 512 | { | ||
| 513 | struct pcie_device *pciedev = to_pcie_device(dev); | ||
| 514 | const struct pcie_port_service_driver *driver = to_service_driver(drv); | ||
| 515 | |||
| 516 | if (driver->service != pciedev->service) | ||
| 517 | return 0; | ||
| 518 | |||
| 519 | if (driver->port_type != PCIE_ANY_PORT && | ||
| 520 | driver->port_type != pci_pcie_type(pciedev->port)) | ||
| 521 | return 0; | ||
| 522 | |||
| 523 | return 1; | ||
| 524 | } | ||
| 525 | |||
| 511 | /** | 526 | /** |
| 512 | * pcie_port_probe_service - probe driver for given PCI Express port service | 527 | * pcie_port_bus_probe - probe driver for given PCI Express port service |
| 513 | * @dev: PCI Express port service device to probe against | 528 | * @dev: PCI Express port service device to probe against |
| 514 | * | 529 | * |
| 515 | * If PCI Express port service driver is registered with | 530 | * If PCI Express port service driver is registered with |
| 516 | * pcie_port_service_register(), this function will be called by the driver core | 531 | * pcie_port_service_register(), this function will be called by the driver core |
| 517 | * whenever match is found between the driver and a port service device. | 532 | * whenever match is found between the driver and a port service device. |
| 518 | */ | 533 | */ |
| 519 | static int pcie_port_probe_service(struct device *dev) | 534 | static int pcie_port_bus_probe(struct device *dev) |
| 520 | { | 535 | { |
| 521 | struct pcie_device *pciedev; | 536 | struct pcie_device *pciedev; |
| 522 | struct pcie_port_service_driver *driver; | 537 | struct pcie_port_service_driver *driver; |
| 523 | int status; | 538 | int status; |
| 524 | 539 | ||
| 525 | if (!dev || !dev->driver) | ||
| 526 | return -ENODEV; | ||
| 527 | |||
| 528 | driver = to_service_driver(dev->driver); | 540 | driver = to_service_driver(dev->driver); |
| 529 | if (!driver || !driver->probe) | 541 | if (!driver || !driver->probe) |
| 530 | return -ENODEV; | 542 | return -ENODEV; |
| @@ -539,7 +551,7 @@ static int pcie_port_probe_service(struct device *dev) · 8 unmodified lines | |||
| 539 | } | 551 | } |
| 540 | 552 | ||
| 541 | /** | 553 | /** |
| 542 | * pcie_port_remove_service - detach driver from given PCI Express port service | 554 | * pcie_port_bus_remove - detach driver from given PCI Express port service |
| 543 | * @dev: PCI Express port service device to handle | 555 | * @dev: PCI Express port service device to handle |
| 544 | * | 556 | * |
| 545 | * If PCI Express port service driver is registered with | 557 | * If PCI Express port service driver is registered with |
| @@ -547,33 +559,25 @@ static int pcie_port_probe_service(struct device *dev) · 1 unmodified line | |||
| 547 | * when device_unregister() is called for the port service device associated | 559 | * when device_unregister() is called for the port service device associated |
| 548 | * with the driver. | 560 | * with the driver. |
| 549 | */ | 561 | */ |
| 550 | static int pcie_port_remove_service(struct device *dev) | 562 | static void pcie_port_bus_remove(struct device *dev) |
| 551 | { | 563 | { |
| 552 | struct pcie_device *pciedev; | 564 | struct pcie_device *pciedev; |
| 553 | struct pcie_port_service_driver *driver; | 565 | struct pcie_port_service_driver *driver; |
| 554 | 566 | ||
| 555 | if (!dev || !dev->driver) | ||
| 556 | return 0; | ||
| 557 | |||
| 558 | pciedev = to_pcie_device(dev); | 567 | pciedev = to_pcie_device(dev); |
| 559 | driver = to_service_driver(dev->driver); | 568 | driver = to_service_driver(dev->driver); |
| 560 | if (driver && driver->remove) { | 569 | if (driver && driver->remove) |
| 561 | driver->remove(pciedev); | 570 | driver->remove(pciedev); |
| 562 | put_device(dev); | 571 | |
| 563 | } | 572 | put_device(dev); |
| 564 | return 0; | ||
| 565 | } | 573 | } |
| 566 | 574 | ||
| 567 | /** | 575 | const struct bus_type pcie_port_bus_type = { |
| 568 | * pcie_port_shutdown_service - shut down given PCI Express port service | 576 | .name = "pci_express", |
| 569 | * @dev: PCI Express port service device to handle | 577 | .match = pcie_port_bus_match, |
| 570 | * | 578 | .probe = pcie_port_bus_probe, |
| 571 | * If PCI Express port service driver is registered with | 579 | .remove = pcie_port_bus_remove, |
| 572 | * pcie_port_service_register(), this function will be called by the driver core | 580 | }; |
| 573 | * when device_shutdown() is called for the port service device associated | ||
| 574 | * with the driver. | ||
| 575 | */ | ||
| 576 | static void pcie_port_shutdown_service(struct device *dev) {} | ||
| 577 | 581 | ||
| 578 | /** | 582 | /** |
| 579 | * pcie_port_service_register - register PCI Express port service driver | 583 | * pcie_port_service_register - register PCI Express port service driver |
| @@ -586,9 +590,6 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) · 6 unmodified lines | |||
| 586 | 590 | ||
| 587 | new->driver.name = new->name; | 591 | new->driver.name = new->name; |
| 588 | new->driver.bus = &pcie_port_bus_type; | 592 | new->driver.bus = &pcie_port_bus_type; |
| 589 | new->driver.probe = pcie_port_probe_service; | ||
| 590 | new->driver.remove = pcie_port_remove_service; | ||
| 591 | new->driver.shutdown = pcie_port_shutdown_service; | ||
| 592 | 593 | ||
| 593 | return driver_register(&new->driver); | 594 | return driver_register(&new->driver); |
| 594 | } | 595 | } |
| @@ -542,8 +542,10 @@ struct pci_ptm_debugfs *pcie_ptm_create_debugfs(struct device *dev, void *pdata, · 541 unmodified lines | |||
| 542 | return NULL; | 542 | return NULL; |
| 543 | 543 | ||
| 544 | dirname = devm_kasprintf(dev, GFP_KERNEL, "pcie_ptm_%s", dev_name(dev)); | 544 | dirname = devm_kasprintf(dev, GFP_KERNEL, "pcie_ptm_%s", dev_name(dev)); |
| 545 | if (!dirname) | 545 | if (!dirname) { |
| 546 | kfree(ptm_debugfs); | ||
| 546 | return NULL; | 547 | return NULL; |
| 548 | } | ||
| 547 | 549 | ||
| 548 | ptm_debugfs->debugfs = debugfs_create_dir(dirname, NULL); | 550 | ptm_debugfs->debugfs = debugfs_create_dir(dirname, NULL); |
| 549 | ptm_debugfs->pdata = pdata; | 551 | ptm_debugfs->pdata = pdata; |
| @@ -574,6 +576,7 @@ void pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs) · 24 unmodified lines | |||
| 574 | 576 | ||
| 575 | mutex_destroy(&ptm_debugfs->lock); | 577 | mutex_destroy(&ptm_debugfs->lock); |
| 576 | debugfs_remove_recursive(ptm_debugfs->debugfs); | 578 | debugfs_remove_recursive(ptm_debugfs->debugfs); |
| 579 | kfree(ptm_debugfs); | ||
| 577 | } | 580 | } |
| 578 | EXPORT_SYMBOL_GPL(pcie_ptm_destroy_debugfs); | 581 | EXPORT_SYMBOL_GPL(pcie_ptm_destroy_debugfs); |
| 579 | #endif | 582 | #endif |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 15 | #include <linux/pci_hotplug.h> | 15 | #include <linux/pci_hotplug.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/sprintf.h> | ||
| 17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 18 | #include <linux/cpumask.h> | 19 | #include <linux/cpumask.h> |
| 19 | #include <linux/aer.h> | 20 | #include <linux/aer.h> |
| @@ -22,11 +23,9 @@ · 2 unmodified lines | |||
| 22 | #include <linux/irqdomain.h> | 23 | #include <linux/irqdomain.h> |
| 23 | #include <linux/pm_runtime.h> | 24 | #include <linux/pm_runtime.h> |
| 24 | #include <linux/bitfield.h> | 25 | #include <linux/bitfield.h> |
| 26 | #include <trace/events/pci.h> | ||
| 25 | #include "pci.h" | 27 | #include "pci.h" |
| 26 | 28 | ||
| 27 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ | ||
| 28 | #define CARDBUS_RESERVE_BUSNR 3 | ||
| 29 | |||
| 30 | static struct resource busn_resource = { | 29 | static struct resource busn_resource = { |
| 31 | .name = "PCI busn", | 30 | .name = "PCI busn", |
| 32 | .start = 0, | 31 | .start = 0, |
| @@ -287,8 +286,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, · 254 unmodified lines | |||
| 287 | if ((sizeof(pci_bus_addr_t) < 8 || sizeof(resource_size_t) < 8) | 286 | if ((sizeof(pci_bus_addr_t) < 8 || sizeof(resource_size_t) < 8) |
| 288 | && sz64 > 0x100000000ULL) { | 287 | && sz64 > 0x100000000ULL) { |
| 289 | res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; | 288 | res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; |
| 290 | res->start = 0; | 289 | resource_set_range(res, 0, 0); |
| 291 | res->end = 0; | ||
| 292 | pci_err(dev, "%s: can't handle BAR larger than 4GB (size %#010llx)\n", | 290 | pci_err(dev, "%s: can't handle BAR larger than 4GB (size %#010llx)\n", |
| 293 | res_name, (unsigned long long)sz64); | 291 | res_name, (unsigned long long)sz64); |
| 294 | goto out; | 292 | goto out; |
| @@ -297,8 +295,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, · 2 unmodified lines | |||
| 297 | if ((sizeof(pci_bus_addr_t) < 8) && l) { | 295 | if ((sizeof(pci_bus_addr_t) < 8) && l) { |
| 298 | /* Above 32-bit boundary; try to reallocate */ | 296 | /* Above 32-bit boundary; try to reallocate */ |
| 299 | res->flags |= IORESOURCE_UNSET; | 297 | res->flags |= IORESOURCE_UNSET; |
| 300 | res->start = 0; | 298 | resource_set_range(res, 0, sz64); |
| 301 | res->end = sz64 - 1; | ||
| 302 | pci_info(dev, "%s: can't handle BAR above 4GB (bus address %#010llx)\n", | 299 | pci_info(dev, "%s: can't handle BAR above 4GB (bus address %#010llx)\n", |
| 303 | res_name, (unsigned long long)l64); | 300 | res_name, (unsigned long long)l64); |
| 304 | goto out; | 301 | goto out; |
| @@ -525,8 +522,8 @@ static void pci_read_bridge_windows(struct pci_dev *bridge) · 220 unmodified lines | |||
| 525 | 522 | ||
| 526 | pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses); | 523 | pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses); |
| 527 | res.flags = IORESOURCE_BUS; | 524 | res.flags = IORESOURCE_BUS; |
| 528 | res.start = (buses >> 8) & 0xff; | 525 | res.start = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses); |
| 529 | res.end = (buses >> 16) & 0xff; | 526 | res.end = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses); |
| 530 | pci_info(bridge, "PCI bridge to %pR%s\n", &res, | 527 | pci_info(bridge, "PCI bridge to %pR%s\n", &res, |
| 531 | bridge->transparent ? " (subtractive decode)" : ""); | 528 | bridge->transparent ? " (subtractive decode)" : ""); |
| 532 | 529 | ||
| @@ -824,14 +821,16 @@ const char *pci_speed_string(enum pci_bus_speed speed) · 291 unmodified lines | |||
| 824 | } | 821 | } |
| 825 | EXPORT_SYMBOL_GPL(pci_speed_string); | 822 | EXPORT_SYMBOL_GPL(pci_speed_string); |
| 826 | 823 | ||
| 827 | void pcie_update_link_speed(struct pci_bus *bus) | 824 | void pcie_update_link_speed(struct pci_bus *bus, |
| 825 | enum pcie_link_change_reason reason) | ||
| 828 | { | 826 | { |
| 829 | struct pci_dev *bridge = bus->self; | 827 | struct pci_dev *bridge = bus->self; |
| 830 | u16 linksta, linksta2; | 828 | u16 linksta, linksta2; |
| 831 | 829 | ||
| 832 | pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); | 830 | pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); |
| 833 | pcie_capability_read_word(bridge, PCI_EXP_LNKSTA2, &linksta2); | 831 | pcie_capability_read_word(bridge, PCI_EXP_LNKSTA2, &linksta2); |
| 834 | __pcie_update_link_speed(bus, linksta, linksta2); | 832 | |
| 833 | __pcie_update_link_speed(bus, reason, linksta, linksta2); | ||
| 835 | } | 834 | } |
| 836 | EXPORT_SYMBOL_GPL(pcie_update_link_speed); | 835 | EXPORT_SYMBOL_GPL(pcie_update_link_speed); |
| 837 | 836 | ||
| @@ -918,7 +917,7 @@ static void pci_set_bus_speed(struct pci_bus *bus) · 80 unmodified lines | |||
| 918 | pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap); | 917 | pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap); |
| 919 | bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS]; | 918 | bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS]; |
| 920 | 919 | ||
| 921 | pcie_update_link_speed(bus); | 920 | pcie_update_link_speed(bus, PCIE_ADD_BUS); |
| 922 | } | 921 | } |
| 923 | } | 922 | } |
| 924 | 923 | ||
| @@ -1313,6 +1312,26 @@ static void pci_enable_rrs_sv(struct pci_dev *pdev) · 388 unmodified lines | |||
| 1313 | 1312 | ||
| 1314 | static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, | 1313 | static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, |
| 1315 | unsigned int available_buses); | 1314 | unsigned int available_buses); |
| 1315 | |||
| 1316 | void pbus_validate_busn(struct pci_bus *bus) | ||
| 1317 | { | ||
| 1318 | struct pci_bus *upstream = bus->parent; | ||
| 1319 | struct pci_dev *bridge = bus->self; | ||
| 1320 | |||
| 1321 | /* Check that all devices are accessible */ | ||
| 1322 | while (upstream->parent) { | ||
| 1323 | if ((bus->busn_res.end > upstream->busn_res.end) || | ||
| 1324 | (bus->number > upstream->busn_res.end) || | ||
| 1325 | (bus->number < upstream->number) || | ||
| 1326 | (bus->busn_res.end < upstream->number)) { | ||
| 1327 | pci_info(bridge, "devices behind bridge are unusable because %pR cannot be assigned for them\n", | ||
| 1328 | &bus->busn_res); | ||
| 1329 | break; | ||
| 1330 | } | ||
| 1331 | upstream = upstream->parent; | ||
| 1332 | } | ||
| 1333 | } | ||
| 1334 | |||
| 1316 | /** | 1335 | /** |
| 1317 | * pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus | 1336 | * pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus |
| 1318 | * numbers from EA capability. | 1337 | * numbers from EA capability. |
| @@ -1324,7 +1343,7 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, · 5 unmodified lines | |||
| 1324 | * and subordinate bus numbers, return true with the bus numbers in @sec | 1343 | * and subordinate bus numbers, return true with the bus numbers in @sec |
| 1325 | * and @sub. Otherwise return false. | 1344 | * and @sub. Otherwise return false. |
| 1326 | */ | 1345 | */ |
| 1327 | static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) | 1346 | bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) |
| 1328 | { | 1347 | { |
| 1329 | int ea, offset; | 1348 | int ea, offset; |
| 1330 | u32 dw; | 1349 | u32 dw; |
| @@ -1378,8 +1397,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 47 unmodified lines | |||
| 1378 | int pass) | 1397 | int pass) |
| 1379 | { | 1398 | { |
| 1380 | struct pci_bus *child; | 1399 | struct pci_bus *child; |
| 1381 | int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); | 1400 | u32 buses; |
| 1382 | u32 buses, i, j = 0; | ||
| 1383 | u16 bctl; | 1401 | u16 bctl; |
| 1384 | u8 primary, secondary, subordinate; | 1402 | u8 primary, secondary, subordinate; |
| 1385 | int broken = 0; | 1403 | int broken = 0; |
| @@ -1394,9 +1412,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 8 unmodified lines | |||
| 1394 | pm_runtime_get_sync(&dev->dev); | 1412 | pm_runtime_get_sync(&dev->dev); |
| 1395 | 1413 | ||
| 1396 | pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); | 1414 | pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); |
| 1397 | primary = buses & 0xFF; | 1415 | primary = FIELD_GET(PCI_PRIMARY_BUS_MASK, buses); |
| 1398 | secondary = (buses >> 8) & 0xFF; | 1416 | secondary = FIELD_GET(PCI_SECONDARY_BUS_MASK, buses); |
| 1399 | subordinate = (buses >> 16) & 0xFF; | 1417 | subordinate = FIELD_GET(PCI_SUBORDINATE_BUS_MASK, buses); |
| 1400 | 1418 | ||
| 1401 | pci_dbg(dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", | 1419 | pci_dbg(dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", |
| 1402 | secondary, subordinate, pass); | 1420 | secondary, subordinate, pass); |
| @@ -1423,8 +1441,15 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 20 unmodified lines | |||
| 1423 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, | 1441 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, |
| 1424 | bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); | 1442 | bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); |
| 1425 | 1443 | ||
| 1426 | if ((secondary || subordinate) && !pcibios_assign_all_busses() && | 1444 | if (pci_is_cardbus_bridge(dev)) { |
| 1427 | !is_cardbus && !broken) { | 1445 | max = pci_cardbus_scan_bridge_extend(bus, dev, buses, max, |
| 1446 | available_buses, | ||
| 1447 | pass); | ||
| 1448 | goto out; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | if ((secondary || subordinate) && | ||
| 1452 | !pcibios_assign_all_busses() && !broken) { | ||
| 1428 | unsigned int cmax, buses; | 1453 | unsigned int cmax, buses; |
| 1429 | 1454 | ||
| 1430 | /* | 1455 | /* |
| @@ -1466,7 +1491,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 35 unmodified lines | |||
| 1466 | * do in the second pass. | 1491 | * do in the second pass. |
| 1467 | */ | 1492 | */ |
| 1468 | if (!pass) { | 1493 | if (!pass) { |
| 1469 | if (pcibios_assign_all_busses() || broken || is_cardbus) | 1494 | if (pcibios_assign_all_busses() || broken) |
| 1470 | 1495 | ||
| 1471 | /* | 1496 | /* |
| 1472 | * Temporarily disable forwarding of the | 1497 | * Temporarily disable forwarding of the |
| @@ -1477,7 +1502,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 4 unmodified lines | |||
| 1477 | * ranges. | 1502 | * ranges. |
| 1478 | */ | 1503 | */ |
| 1479 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, | 1504 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, |
| 1480 | buses & ~0xffffff); | 1505 | buses & PCI_SEC_LATENCY_TIMER_MASK); |
| 1481 | goto out; | 1506 | goto out; |
| 1482 | } | 1507 | } |
| 1483 | 1508 | ||
| @@ -1508,59 +1533,16 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 24 unmodified lines | |||
| 1508 | if (available_buses) | 1533 | if (available_buses) |
| 1509 | available_buses--; | 1534 | available_buses--; |
| 1510 | 1535 | ||
| 1511 | buses = (buses & 0xff000000) | 1536 | buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) | |
| 1512 | | ((unsigned int)(child->primary) << 0) | 1537 | FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) | |
| 1513 | | ((unsigned int)(child->busn_res.start) << 8) | 1538 | FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) | |
| 1514 | | ((unsigned int)(child->busn_res.end) << 16); | 1539 | FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end); |
| 1515 | |||
| 1516 | /* | ||
| 1517 | * yenta.c forces a secondary latency timer of 176. | ||
| 1518 | * Copy that behaviour here. | ||
| 1519 | */ | ||
| 1520 | if (is_cardbus) { | ||
| 1521 | buses &= ~0xff000000; | ||
| 1522 | buses |= CARDBUS_LATENCY_TIMER << 24; | ||
| 1523 | } | ||
| 1524 | 1540 | ||
| 1525 | /* We need to blast all three values with a single write */ | 1541 | /* We need to blast all three values with a single write */ |
| 1526 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); | 1542 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); |
| 1527 | 1543 | ||
| 1528 | if (!is_cardbus) { | 1544 | child->bridge_ctl = bctl; |
| 1529 | child->bridge_ctl = bctl; | 1545 | max = pci_scan_child_bus_extend(child, available_buses); |
| 1530 | max = pci_scan_child_bus_extend(child, available_buses); | ||
| 1531 | } else { | ||
| 1532 | |||
| 1533 | /* | ||
| 1534 | * For CardBus bridges, we leave 4 bus numbers as | ||
| 1535 | * cards with a PCI-to-PCI bridge can be inserted | ||
| 1536 | * later. | ||
| 1537 | */ | ||
| 1538 | for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) { | ||
| 1539 | struct pci_bus *parent = bus; | ||
| 1540 | if (pci_find_bus(pci_domain_nr(bus), | ||
| 1541 | max+i+1)) | ||
| 1542 | break; | ||
| 1543 | while (parent->parent) { | ||
| 1544 | if ((!pcibios_assign_all_busses()) && | ||
| 1545 | (parent->busn_res.end > max) && | ||
| 1546 | (parent->busn_res.end <= max+i)) { | ||
| 1547 | j = 1; | ||
| 1548 | } | ||
| 1549 | parent = parent->parent; | ||
| 1550 | } | ||
| 1551 | if (j) { | ||
| 1552 | |||
| 1553 | /* | ||
| 1554 | * Often, there are two CardBus | ||
| 1555 | * bridges -- try to leave one | ||
| 1556 | * valid bus number for each one. | ||
| 1557 | */ | ||
| 1558 | i /= 2; | ||
| 1559 | break; | ||
| 1560 | } | ||
| 1561 | } | ||
| 1562 | max += i; | ||
| 1563 | } | ||
| 1564 | 1546 | ||
| 1565 | /* | 1547 | /* |
| 1566 | * Set subordinate bus number to its real value. | 1548 | * Set subordinate bus number to its real value. |
| @@ -1572,23 +1554,10 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · 5 unmodified lines | |||
| 1572 | pci_bus_update_busn_res_end(child, max); | 1554 | pci_bus_update_busn_res_end(child, max); |
| 1573 | pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); | 1555 | pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); |
| 1574 | } | 1556 | } |
| 1557 | scnprintf(child->name, sizeof(child->name), "PCI Bus %04x:%02x", | ||
| 1558 | pci_domain_nr(bus), child->number); | ||
| 1575 | 1559 | ||
| 1576 | sprintf(child->name, | 1560 | pbus_validate_busn(child); |
| 1577 | (is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"), | ||
| 1578 | pci_domain_nr(bus), child->number); | ||
| 1579 | |||
| 1580 | /* Check that all devices are accessible */ | ||
| 1581 | while (bus->parent) { | ||
| 1582 | if ((child->busn_res.end > bus->busn_res.end) || | ||
| 1583 | (child->number > bus->busn_res.end) || | ||
| 1584 | (child->number < bus->number) || | ||
| 1585 | (child->busn_res.end < bus->number)) { | ||
| 1586 | dev_info(&dev->dev, "devices behind bridge are unusable because %pR cannot be assigned for them\n", | ||
| 1587 | &child->busn_res); | ||
| 1588 | break; | ||
| 1589 | } | ||
| 1590 | bus = bus->parent; | ||
| 1591 | } | ||
| 1592 | 1561 | ||
| 1593 | out: | 1562 | out: |
| 1594 | /* Clear errors in the Secondary Status Register */ | 1563 | /* Clear errors in the Secondary Status Register */ |
| @@ -2277,7 +2246,8 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign) · 682 unmodified lines | |||
| 2277 | u16 ctl; | 2246 | u16 ctl; |
| 2278 | int ret; | 2247 | int ret; |
| 2279 | 2248 | ||
| 2280 | if (!pci_is_pcie(dev)) | 2249 | /* PCI_EXP_DEVCTL_EXT_TAG is RsvdP in VFs */ |
| 2250 | if (!pci_is_pcie(dev) || dev->is_virtfn) | ||
| 2281 | return 0; | 2251 | return 0; |
| 2282 | 2252 | ||
| 2283 | ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); | 2253 | ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap); |
| @@ -2417,6 +2387,37 @@ static void pci_configure_serr(struct pci_dev *dev) · 133 unmodified lines | |||
| 2417 | } | 2387 | } |
| 2418 | } | 2388 | } |
| 2419 | 2389 | ||
| 2390 | static void pci_configure_rcb(struct pci_dev *dev) | ||
| 2391 | { | ||
| 2392 | struct pci_dev *rp; | ||
| 2393 | u16 rp_lnkctl; | ||
| 2394 | |||
| 2395 | /* | ||
| 2396 | * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports | ||
| 2397 | * (where it is read-only), Endpoints, and Bridges. It may only be | ||
| 2398 | * set for Endpoints and Bridges if it is set in the Root Port. For | ||
| 2399 | * Endpoints, it is 'RsvdP' for Virtual Functions. | ||
| 2400 | */ | ||
| 2401 | if (!pci_is_pcie(dev) || | ||
| 2402 | pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || | ||
| 2403 | pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM || | ||
| 2404 | pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || | ||
| 2405 | pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC || | ||
| 2406 | dev->is_virtfn) | ||
| 2407 | return; | ||
| 2408 | |||
| 2409 | /* Root Port often not visible to virtualized guests */ | ||
| 2410 | rp = pcie_find_root_port(dev); | ||
| 2411 | if (!rp) | ||
| 2412 | return; | ||
| 2413 | |||
| 2414 | pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl); | ||
| 2415 | pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, | ||
| 2416 | PCI_EXP_LNKCTL_RCB, | ||
| 2417 | (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ? | ||
| 2418 | PCI_EXP_LNKCTL_RCB : 0); | ||
| 2419 | } | ||
| 2420 | |||
| 2420 | static void pci_configure_device(struct pci_dev *dev) | 2421 | static void pci_configure_device(struct pci_dev *dev) |
| 2421 | { | 2422 | { |
| 2422 | pci_configure_mps(dev); | 2423 | pci_configure_mps(dev); |
| @@ -2426,6 +2427,7 @@ static void pci_configure_device(struct pci_dev *dev) · 3 unmodified lines | |||
| 2426 | pci_configure_aspm_l1ss(dev); | 2427 | pci_configure_aspm_l1ss(dev); |
| 2427 | pci_configure_eetlp_prefix(dev); | 2428 | pci_configure_eetlp_prefix(dev); |
| 2428 | pci_configure_serr(dev); | 2429 | pci_configure_serr(dev); |
| 2430 | pci_configure_rcb(dev); | ||
| 2429 | 2431 | ||
| 2430 | pci_acpi_program_hp_params(dev); | 2432 | pci_acpi_program_hp_params(dev); |
| 2431 | } | 2433 | } |
| @@ -2554,72 +2556,10 @@ bool pci_bus_generic_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, · 122 unmodified lines | |||
| 2554 | bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, | 2556 | bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, |
| 2555 | int timeout) | 2557 | int timeout) |
| 2556 | { | 2558 | { |
| 2557 | #ifdef CONFIG_PCI_QUIRKS | ||
| 2558 | struct pci_dev *bridge = bus->self; | ||
| 2559 | |||
| 2560 | /* | ||
| 2561 | * Certain IDT switches have an issue where they improperly trigger | ||
| 2562 | * ACS Source Validation errors on completions for config reads. | ||
| 2563 | */ | ||
| 2564 | if (bridge && bridge->vendor == PCI_VENDOR_ID_IDT && | ||
| 2565 | bridge->device == 0x80b5) | ||
| 2566 | return pci_idt_bus_quirk(bus, devfn, l, timeout); | ||
| 2567 | #endif | ||
| 2568 | |||
| 2569 | return pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout); | 2559 | return pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout); |
| 2570 | } | 2560 | } |
| 2571 | EXPORT_SYMBOL(pci_bus_read_dev_vendor_id); | 2561 | EXPORT_SYMBOL(pci_bus_read_dev_vendor_id); |
| 2572 | 2562 | ||
| 2573 | #if IS_ENABLED(CONFIG_PCI_PWRCTRL) | ||
| 2574 | static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, int devfn) | ||
| 2575 | { | ||
| 2576 | struct pci_host_bridge *host = pci_find_host_bridge(bus); | ||
| 2577 | struct platform_device *pdev; | ||
| 2578 | struct device_node *np; | ||
| 2579 | |||
| 2580 | np = of_pci_find_child_device(dev_of_node(&bus->dev), devfn); | ||
| 2581 | if (!np) | ||
| 2582 | return NULL; | ||
| 2583 | |||
| 2584 | pdev = of_find_device_by_node(np); | ||
| 2585 | if (pdev) { | ||
| 2586 | put_device(&pdev->dev); | ||
| 2587 | goto err_put_of_node; | ||
| 2588 | } | ||
| 2589 | |||
| 2590 | /* | ||
| 2591 | * First check whether the pwrctrl device really needs to be created or | ||
| 2592 | * not. This is decided based on at least one of the power supplies | ||
| 2593 | * being defined in the devicetree node of the device. | ||
| 2594 | */ | ||
| 2595 | if (!of_pci_supply_present(np)) { | ||
| 2596 | pr_debug("PCI/pwrctrl: Skipping OF node: %s\n", np->name); | ||
| 2597 | goto err_put_of_node; | ||
| 2598 | } | ||
| 2599 | |||
| 2600 | /* Now create the pwrctrl device */ | ||
| 2601 | pdev = of_platform_device_create(np, NULL, &host->dev); | ||
| 2602 | if (!pdev) { | ||
| 2603 | pr_err("PCI/pwrctrl: Failed to create pwrctrl device for node: %s\n", np->name); | ||
| 2604 | goto err_put_of_node; | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | of_node_put(np); | ||
| 2608 | |||
| 2609 | return pdev; | ||
| 2610 | |||
| 2611 | err_put_of_node: | ||
| 2612 | of_node_put(np); | ||
| 2613 | |||
| 2614 | return NULL; | ||
| 2615 | } | ||
| 2616 | #else | ||
| 2617 | static struct platform_device *pci_pwrctrl_create_device(struct pci_bus *bus, int devfn) | ||
| 2618 | { | ||
| 2619 | return NULL; | ||
| 2620 | } | ||
| 2621 | #endif | ||
| 2622 | |||
| 2623 | /* | 2563 | /* |
| 2624 | * Read the config data for a PCI device, sanity-check it, | 2564 | * Read the config data for a PCI device, sanity-check it, |
| 2625 | * and fill in the dev structure. | 2565 | * and fill in the dev structure. |
| @@ -2629,15 +2569,6 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) · 3 unmodified lines | |||
| 2629 | struct pci_dev *dev; | 2569 | struct pci_dev *dev; |
| 2630 | u32 l; | 2570 | u32 l; |
| 2631 | 2571 | ||
| 2632 | /* | ||
| 2633 | * Create pwrctrl device (if required) for the PCI device to handle the | ||
| 2634 | * power state. If the pwrctrl device is created, then skip scanning | ||
| 2635 | * further as the pwrctrl core will rescan the bus after powering on | ||
| 2636 | * the device. | ||
| 2637 | */ | ||
| 2638 | if (pci_pwrctrl_create_device(bus, devfn)) | ||
| 2639 | return NULL; | ||
| 2640 | |||
| 2641 | if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) | 2572 | if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) |
| 2642 | return NULL; | 2573 | return NULL; |
| 2643 | 2574 | ||
| @@ -13,6 +13,7 @@ config PCI_PWRCTRL_PWRSEQ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | config PCI_PWRCTRL_SLOT | 14 | config PCI_PWRCTRL_SLOT |
| 15 | tristate "PCI Power Control driver for PCI slots" | 15 | tristate "PCI Power Control driver for PCI slots" |
| 16 | select POWER_SEQUENCING | ||
| 16 | select PCI_PWRCTRL | 17 | select PCI_PWRCTRL |
| 17 | help | 18 | help |
| 18 | Say Y here to enable the PCI Power Control driver to control the power | 19 | Say Y here to enable the PCI Power Control driver to control the power |
| @@ -3,14 +3,22 @@ · 2 unmodified lines | |||
| 3 | * Copyright (C) 2024 Linaro Ltd. | 3 | * Copyright (C) 2024 Linaro Ltd. |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #define dev_fmt(fmt) "pwrctrl: " fmt | ||
| 7 | |||
| 6 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 7 | #include <linux/export.h> | 9 | #include <linux/export.h> |
| 8 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/of.h> | ||
| 12 | #include <linux/of_graph.h> | ||
| 13 | #include <linux/of_platform.h> | ||
| 9 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
| 10 | #include <linux/pci-pwrctrl.h> | 15 | #include <linux/pci-pwrctrl.h> |
| 16 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/property.h> | 17 | #include <linux/property.h> |
| 12 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 13 | 19 | ||
| 20 | #include "../pci.h" | ||
| 21 | |||
| 14 | static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, | 22 | static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, |
| 15 | void *data) | 23 | void *data) |
| 16 | { | 24 | { |
| @@ -38,16 +46,6 @@ static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, · 21 unmodified lines | |||
| 38 | return NOTIFY_DONE; | 46 | return NOTIFY_DONE; |
| 39 | } | 47 | } |
| 40 | 48 | ||
| 41 | static void rescan_work_func(struct work_struct *work) | ||
| 42 | { | ||
| 43 | struct pci_pwrctrl *pwrctrl = container_of(work, | ||
| 44 | struct pci_pwrctrl, work); | ||
| 45 | |||
| 46 | pci_lock_rescan_remove(); | ||
| 47 | pci_rescan_bus(to_pci_host_bridge(pwrctrl->dev->parent)->bus); | ||
| 48 | pci_unlock_rescan_remove(); | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | 49 | /** |
| 52 | * pci_pwrctrl_init() - Initialize the PCI power control context struct | 50 | * pci_pwrctrl_init() - Initialize the PCI power control context struct |
| 53 | * | 51 | * |
| @@ -57,7 +55,7 @@ static void rescan_work_func(struct work_struct *work) · 3 unmodified lines | |||
| 57 | void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) | 55 | void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) |
| 58 | { | 56 | { |
| 59 | pwrctrl->dev = dev; | 57 | pwrctrl->dev = dev; |
| 60 | INIT_WORK(&pwrctrl->work, rescan_work_func); | 58 | dev_set_drvdata(dev, pwrctrl); |
| 61 | } | 59 | } |
| 62 | EXPORT_SYMBOL_GPL(pci_pwrctrl_init); | 60 | EXPORT_SYMBOL_GPL(pci_pwrctrl_init); |
| 63 | 61 | ||
| @@ -87,8 +85,6 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl) · 23 unmodified lines | |||
| 87 | if (ret) | 85 | if (ret) |
| 88 | return ret; | 86 | return ret; |
| 89 | 87 | ||
| 90 | schedule_work(&pwrctrl->work); | ||
| 91 | |||
| 92 | return 0; | 88 | return 0; |
| 93 | } | 89 | } |
| 94 | EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); | 90 | EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); |
| @@ -101,8 +97,6 @@ EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); · 6 unmodified lines | |||
| 101 | */ | 97 | */ |
| 102 | void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) | 98 | void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) |
| 103 | { | 99 | { |
| 104 | cancel_work_sync(&pwrctrl->work); | ||
| 105 | |||
| 106 | /* | 100 | /* |
| 107 | * We don't have to delete the link here. Typically, this function | 101 | * We don't have to delete the link here. Typically, this function |
| 108 | * is only called when the power control device is being detached. If | 102 | * is only called when the power control device is being detached. If |
| @@ -145,6 +139,242 @@ int devm_pci_pwrctrl_device_set_ready(struct device *dev, · 36 unmodified lines | |||
| 145 | } | 139 | } |
| 146 | EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); | 140 | EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); |
| 147 | 141 | ||
| 142 | static int __pci_pwrctrl_power_off_device(struct device *dev) | ||
| 143 | { | ||
| 144 | struct pci_pwrctrl *pwrctrl = dev_get_drvdata(dev); | ||
| 145 | |||
| 146 | if (!pwrctrl) | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | return pwrctrl->power_off(pwrctrl); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void pci_pwrctrl_power_off_device(struct device_node *np) | ||
| 153 | { | ||
| 154 | struct platform_device *pdev; | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | for_each_available_child_of_node_scoped(np, child) | ||
| 158 | pci_pwrctrl_power_off_device(child); | ||
| 159 | |||
| 160 | pdev = of_find_device_by_node(np); | ||
| 161 | if (!pdev) | ||
| 162 | return; | ||
| 163 | |||
| 164 | if (device_is_bound(&pdev->dev)) { | ||
| 165 | ret = __pci_pwrctrl_power_off_device(&pdev->dev); | ||
| 166 | if (ret) | ||
| 167 | dev_err(&pdev->dev, "Failed to power off device: %d", ret); | ||
| 168 | } | ||
| 169 | |||
| 170 | platform_device_put(pdev); | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | ||
| 174 | * pci_pwrctrl_power_off_devices - Power off pwrctrl devices | ||
| 175 | * | ||
| 176 | * @parent: PCI host controller device | ||
| 177 | * | ||
| 178 | * Recursively traverse all pwrctrl devices for the devicetree hierarchy | ||
| 179 | * below the specified PCI host controller and power them off in a depth | ||
| 180 | * first manner. | ||
| 181 | */ | ||
| 182 | void pci_pwrctrl_power_off_devices(struct device *parent) | ||
| 183 | { | ||
| 184 | struct device_node *np = parent->of_node; | ||
| 185 | |||
| 186 | for_each_available_child_of_node_scoped(np, child) | ||
| 187 | pci_pwrctrl_power_off_device(child); | ||
| 188 | } | ||
| 189 | EXPORT_SYMBOL_GPL(pci_pwrctrl_power_off_devices); | ||
| 190 | |||
| 191 | static int __pci_pwrctrl_power_on_device(struct device *dev) | ||
| 192 | { | ||
| 193 | struct pci_pwrctrl *pwrctrl = dev_get_drvdata(dev); | ||
| 194 | |||
| 195 | if (!pwrctrl) | ||
| 196 | return 0; | ||
| 197 | |||
| 198 | return pwrctrl->power_on(pwrctrl); | ||
| 199 | } | ||
| 200 | |||
| 201 | /* | ||
| 202 | * Power on the devices in a depth first manner. Before powering on the device, | ||
| 203 | * make sure its driver is bound. | ||
| 204 | */ | ||
| 205 | static int pci_pwrctrl_power_on_device(struct device_node *np) | ||
| 206 | { | ||
| 207 | struct platform_device *pdev; | ||
| 208 | int ret; | ||
| 209 | |||
| 210 | for_each_available_child_of_node_scoped(np, child) { | ||
| 211 | ret = pci_pwrctrl_power_on_device(child); | ||
| 212 | if (ret) | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | pdev = of_find_device_by_node(np); | ||
| 217 | if (!pdev) | ||
| 218 | return 0; | ||
| 219 | |||
| 220 | if (device_is_bound(&pdev->dev)) { | ||
| 221 | ret = __pci_pwrctrl_power_on_device(&pdev->dev); | ||
| 222 | } else { | ||
| 223 | /* FIXME: Use blocking wait instead of probe deferral */ | ||
| 224 | dev_dbg(&pdev->dev, "driver is not bound\n"); | ||
| 225 | ret = -EPROBE_DEFER; | ||
| 226 | } | ||
| 227 | |||
| 228 | platform_device_put(pdev); | ||
| 229 | |||
| 230 | return ret; | ||
| 231 | } | ||
| 232 | |||
| 233 | /** | ||
| 234 | * pci_pwrctrl_power_on_devices - Power on pwrctrl devices | ||
| 235 | * | ||
| 236 | * @parent: PCI host controller device | ||
| 237 | * | ||
| 238 | * Recursively traverse all pwrctrl devices for the devicetree hierarchy | ||
| 239 | * below the specified PCI host controller and power them on in a depth | ||
| 240 | * first manner. On error, all powered on devices will be powered off. | ||
| 241 | * | ||
| 242 | * Return: 0 on success, -EPROBE_DEFER if any pwrctrl driver is not bound, an | ||
| 243 | * appropriate error code otherwise. | ||
| 244 | */ | ||
| 245 | int pci_pwrctrl_power_on_devices(struct device *parent) | ||
| 246 | { | ||
| 247 | struct device_node *np = parent->of_node; | ||
| 248 | struct device_node *child = NULL; | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | for_each_available_child_of_node(np, child) { | ||
| 252 | ret = pci_pwrctrl_power_on_device(child); | ||
| 253 | if (ret) | ||
| 254 | goto err_power_off; | ||
| 255 | } | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | |||
| 259 | err_power_off: | ||
| 260 | for_each_available_child_of_node_scoped(np, tmp) { | ||
| 261 | if (tmp == child) | ||
| 262 | break; | ||
| 263 | pci_pwrctrl_power_off_device(tmp); | ||
| 264 | } | ||
| 265 | of_node_put(child); | ||
| 266 | |||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | EXPORT_SYMBOL_GPL(pci_pwrctrl_power_on_devices); | ||
| 270 | |||
| 271 | static int pci_pwrctrl_create_device(struct device_node *np, | ||
| 272 | struct device *parent) | ||
| 273 | { | ||
| 274 | struct platform_device *pdev; | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | for_each_available_child_of_node_scoped(np, child) { | ||
| 278 | ret = pci_pwrctrl_create_device(child, parent); | ||
| 279 | if (ret) | ||
| 280 | return ret; | ||
| 281 | } | ||
| 282 | |||
| 283 | /* Bail out if the platform device is already available for the node */ | ||
| 284 | pdev = of_find_device_by_node(np); | ||
| 285 | if (pdev) { | ||
| 286 | platform_device_put(pdev); | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* | ||
| 291 | * Sanity check to make sure that the node has the compatible property | ||
| 292 | * to allow driver binding. | ||
| 293 | */ | ||
| 294 | if (!of_property_present(np, "compatible")) | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | /* | ||
| 298 | * Check whether the pwrctrl device really needs to be created or not. | ||
| 299 | * This is decided based on at least one of the power supplies defined | ||
| 300 | * in the devicetree node of the device or the graph property. | ||
| 301 | */ | ||
| 302 | if (!of_pci_supply_present(np) && !of_graph_is_present(np)) { | ||
| 303 | dev_dbg(parent, "Skipping OF node: %s\n", np->name); | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* Now create the pwrctrl device */ | ||
| 308 | pdev = of_platform_device_create(np, NULL, parent); | ||
| 309 | if (!pdev) { | ||
| 310 | dev_err(parent, "Failed to create pwrctrl device for node: %s\n", np->name); | ||
| 311 | return -EINVAL; | ||
| 312 | } | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * pci_pwrctrl_create_devices - Create pwrctrl devices | ||
| 319 | * | ||
| 320 | * @parent: PCI host controller device | ||
| 321 | * | ||
| 322 | * Recursively create pwrctrl devices for the devicetree hierarchy below | ||
| 323 | * the specified PCI host controller in a depth first manner. On error, all | ||
| 324 | * created devices will be destroyed. | ||
| 325 | * | ||
| 326 | * Return: 0 on success, negative error number on error. | ||
| 327 | */ | ||
| 328 | int pci_pwrctrl_create_devices(struct device *parent) | ||
| 329 | { | ||
| 330 | int ret; | ||
| 331 | |||
| 332 | for_each_available_child_of_node_scoped(parent->of_node, child) { | ||
| 333 | ret = pci_pwrctrl_create_device(child, parent); | ||
| 334 | if (ret) { | ||
| 335 | pci_pwrctrl_destroy_devices(parent); | ||
| 336 | return ret; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | EXPORT_SYMBOL_GPL(pci_pwrctrl_create_devices); | ||
| 343 | |||
| 344 | static void pci_pwrctrl_destroy_device(struct device_node *np) | ||
| 345 | { | ||
| 346 | struct platform_device *pdev; | ||
| 347 | |||
| 348 | for_each_available_child_of_node_scoped(np, child) | ||
| 349 | pci_pwrctrl_destroy_device(child); | ||
| 350 | |||
| 351 | pdev = of_find_device_by_node(np); | ||
| 352 | if (!pdev) | ||
| 353 | return; | ||
| 354 | |||
| 355 | of_device_unregister(pdev); | ||
| 356 | platform_device_put(pdev); | ||
| 357 | |||
| 358 | of_node_clear_flag(np, OF_POPULATED); | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * pci_pwrctrl_destroy_devices - Destroy pwrctrl devices | ||
| 363 | * | ||
| 364 | * @parent: PCI host controller device | ||
| 365 | * | ||
| 366 | * Recursively destroy pwrctrl devices for the devicetree hierarchy below | ||
| 367 | * the specified PCI host controller in a depth first manner. | ||
| 368 | */ | ||
| 369 | void pci_pwrctrl_destroy_devices(struct device *parent) | ||
| 370 | { | ||
| 371 | struct device_node *np = parent->of_node; | ||
| 372 | |||
| 373 | for_each_available_child_of_node_scoped(np, child) | ||
| 374 | pci_pwrctrl_destroy_device(child); | ||
| 375 | } | ||
| 376 | EXPORT_SYMBOL_GPL(pci_pwrctrl_destroy_devices); | ||
| 377 | |||
| 148 | MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>"); | 378 | MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>"); |
| 149 | MODULE_DESCRIPTION("PCI Device Power Control core driver"); | 379 | MODULE_DESCRIPTION("PCI Device Power Control core driver"); |
| 150 | MODULE_LICENSE("GPL"); | 380 | MODULE_LICENSE("GPL"); |
| @@ -13,12 +13,12 @@ · 12 unmodified lines | |||
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 15 | 15 | ||
| 16 | struct pci_pwrctrl_pwrseq_data { | 16 | struct pwrseq_pwrctrl { |
| 17 | struct pci_pwrctrl ctx; | 17 | struct pci_pwrctrl pwrctrl; |
| 18 | struct pwrseq_desc *pwrseq; | 18 | struct pwrseq_desc *pwrseq; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | struct pci_pwrctrl_pwrseq_pdata { | 21 | struct pwrseq_pwrctrl_pdata { |
| 22 | const char *target; | 22 | const char *target; |
| 23 | /* | 23 | /* |
| 24 | * Called before doing anything else to perform device-specific | 24 | * Called before doing anything else to perform device-specific |
| @@ -27,7 +27,7 @@ struct pci_pwrctrl_pwrseq_pdata { · 2 unmodified lines | |||
| 27 | int (*validate_device)(struct device *dev); | 27 | int (*validate_device)(struct device *dev); |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | static int pci_pwrctrl_pwrseq_qcm_wcn_validate_device(struct device *dev) | 30 | static int pwrseq_pwrctrl_qcm_wcn_validate_device(struct device *dev) |
| 31 | { | 31 | { |
| 32 | /* | 32 | /* |
| 33 | * Old device trees for some platforms already define wifi nodes for | 33 | * Old device trees for some platforms already define wifi nodes for |
| @@ -47,22 +47,38 @@ static int pci_pwrctrl_pwrseq_qcm_wcn_validate_device(struct device *dev) · 13 unmodified lines | |||
| 47 | return 0; | 47 | return 0; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static const struct pci_pwrctrl_pwrseq_pdata pci_pwrctrl_pwrseq_qcom_wcn_pdata = { | 50 | static const struct pwrseq_pwrctrl_pdata pwrseq_pwrctrl_qcom_wcn_pdata = { |
| 51 | .target = "wlan", | 51 | .target = "wlan", |
| 52 | .validate_device = pci_pwrctrl_pwrseq_qcm_wcn_validate_device, | 52 | .validate_device = pwrseq_pwrctrl_qcm_wcn_validate_device, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | static void devm_pci_pwrctrl_pwrseq_power_off(void *data) | 55 | static int pwrseq_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) |
| 56 | { | 56 | { |
| 57 | struct pwrseq_desc *pwrseq = data; | 57 | struct pwrseq_pwrctrl *pwrseq = container_of(pwrctrl, |
| 58 | struct pwrseq_pwrctrl, pwrctrl); | ||
| 58 | 59 | ||
| 59 | pwrseq_power_off(pwrseq); | 60 | return pwrseq_power_on(pwrseq->pwrseq); |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) | 63 | static int pwrseq_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) |
| 63 | { | 64 | { |
| 64 | const struct pci_pwrctrl_pwrseq_pdata *pdata; | 65 | struct pwrseq_pwrctrl *pwrseq = container_of(pwrctrl, |
| 65 | struct pci_pwrctrl_pwrseq_data *data; | 66 | struct pwrseq_pwrctrl, pwrctrl); |
| 67 | |||
| 68 | return pwrseq_power_off(pwrseq->pwrseq); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void devm_pwrseq_pwrctrl_power_off(void *data) | ||
| 72 | { | ||
| 73 | struct pwrseq_pwrctrl *pwrseq = data; | ||
| 74 | |||
| 75 | pwrseq_pwrctrl_power_off(&pwrseq->pwrctrl); | ||
| 76 | } | ||
| 77 | |||
| 78 | static int pwrseq_pwrctrl_probe(struct platform_device *pdev) | ||
| 79 | { | ||
| 80 | const struct pwrseq_pwrctrl_pdata *pdata; | ||
| 81 | struct pwrseq_pwrctrl *pwrseq; | ||
| 66 | struct device *dev = &pdev->dev; | 82 | struct device *dev = &pdev->dev; |
| 67 | int ret; | 83 | int ret; |
| 68 | 84 | ||
| @@ -76,28 +92,26 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 76 | return ret; | 92 | return ret; |
| 77 | } | 93 | } |
| 78 | 94 | ||
| 79 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | 95 | pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); |
| 80 | if (!data) | 96 | if (!pwrseq) |
| 81 | return -ENOMEM; | 97 | return -ENOMEM; |
| 82 | 98 | ||
| 83 | data->pwrseq = devm_pwrseq_get(dev, pdata->target); | 99 | pwrseq->pwrseq = devm_pwrseq_get(dev, pdata->target); |
| 84 | if (IS_ERR(data->pwrseq)) | 100 | if (IS_ERR(pwrseq->pwrseq)) |
| 85 | return dev_err_probe(dev, PTR_ERR(data->pwrseq), | 101 | return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq), |
| 86 | "Failed to get the power sequencer\n"); | 102 | "Failed to get the power sequencer\n"); |
| 87 | 103 | ||
| 88 | ret = pwrseq_power_on(data->pwrseq); | 104 | ret = devm_add_action_or_reset(dev, devm_pwrseq_pwrctrl_power_off, |
| 89 | if (ret) | 105 | pwrseq); |
| 90 | return dev_err_probe(dev, ret, | ||
| 91 | "Failed to power-on the device\n"); | ||
| 92 | |||
| 93 | ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, | ||
| 94 | data->pwrseq); | ||
| 95 | if (ret) | 106 | if (ret) |
| 96 | return ret; | 107 | return ret; |
| 97 | 108 | ||
| 98 | pci_pwrctrl_init(&data->ctx, dev); | 109 | pwrseq->pwrctrl.power_on = pwrseq_pwrctrl_power_on; |
| 110 | pwrseq->pwrctrl.power_off = pwrseq_pwrctrl_power_off; | ||
| 111 | |||
| 112 | pci_pwrctrl_init(&pwrseq->pwrctrl, dev); | ||
| 99 | 113 | ||
| 100 | ret = devm_pci_pwrctrl_device_set_ready(dev, &data->ctx); | 114 | ret = devm_pci_pwrctrl_device_set_ready(dev, &pwrseq->pwrctrl); |
| 101 | if (ret) | 115 | if (ret) |
| 102 | return dev_err_probe(dev, ret, | 116 | return dev_err_probe(dev, ret, |
| 103 | "Failed to register the pwrctrl wrapper\n"); | 117 | "Failed to register the pwrctrl wrapper\n"); |
| @@ -105,34 +119,34 @@ static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 105 | return 0; | 119 | return 0; |
| 106 | } | 120 | } |
| 107 | 121 | ||
| 108 | static const struct of_device_id pci_pwrctrl_pwrseq_of_match[] = { | 122 | static const struct of_device_id pwrseq_pwrctrl_of_match[] = { |
| 109 | { | 123 | { |
| 110 | /* ATH11K in QCA6390 package. */ | 124 | /* ATH11K in QCA6390 package. */ |
| 111 | .compatible = "pci17cb,1101", | 125 | .compatible = "pci17cb,1101", |
| 112 | .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, | 126 | .data = &pwrseq_pwrctrl_qcom_wcn_pdata, |
| 113 | }, | 127 | }, |
| 114 | { | 128 | { |
| 115 | /* ATH11K in WCN6855 package. */ | 129 | /* ATH11K in WCN6855 package. */ |
| 116 | .compatible = "pci17cb,1103", | 130 | .compatible = "pci17cb,1103", |
| 117 | .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, | 131 | .data = &pwrseq_pwrctrl_qcom_wcn_pdata, |
| 118 | }, | 132 | }, |
| 119 | { | 133 | { |
| 120 | /* ATH12K in WCN7850 package. */ | 134 | /* ATH12K in WCN7850 package. */ |
| 121 | .compatible = "pci17cb,1107", | 135 | .compatible = "pci17cb,1107", |
| 122 | .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, | 136 | .data = &pwrseq_pwrctrl_qcom_wcn_pdata, |
| 123 | }, | 137 | }, |
| 124 | { } | 138 | { } |
| 125 | }; | 139 | }; |
| 126 | MODULE_DEVICE_TABLE(of, pci_pwrctrl_pwrseq_of_match); | 140 | MODULE_DEVICE_TABLE(of, pwrseq_pwrctrl_of_match); |
| 127 | 141 | ||
| 128 | static struct platform_driver pci_pwrctrl_pwrseq_driver = { | 142 | static struct platform_driver pwrseq_pwrctrl_driver = { |
| 129 | .driver = { | 143 | .driver = { |
| 130 | .name = "pci-pwrctrl-pwrseq", | 144 | .name = "pci-pwrctrl-pwrseq", |
| 131 | .of_match_table = pci_pwrctrl_pwrseq_of_match, | 145 | .of_match_table = pwrseq_pwrctrl_of_match, |
| 132 | }, | 146 | }, |
| 133 | .probe = pci_pwrctrl_pwrseq_probe, | 147 | .probe = pwrseq_pwrctrl_probe, |
| 134 | }; | 148 | }; |
| 135 | module_platform_driver(pci_pwrctrl_pwrseq_driver); | 149 | module_platform_driver(pwrseq_pwrctrl_driver); |
| 136 | 150 | ||
| 137 | MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>"); | 151 | MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>"); |
| 138 | MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices"); | 152 | MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices"); |
| @@ -59,7 +59,7 @@ · 58 unmodified lines | |||
| 59 | #define TC9563_POWER_CONTROL_OVREN 0x82b2c8 | 59 | #define TC9563_POWER_CONTROL_OVREN 0x82b2c8 |
| 60 | 60 | ||
| 61 | #define TC9563_GPIO_MASK 0xfffffff3 | 61 | #define TC9563_GPIO_MASK 0xfffffff3 |
| 62 | #define TC9563_GPIO_DEASSERT_BITS 0xc /* Bits to clear for GPIO deassert */ | 62 | #define TC9563_GPIO_DEASSERT_BITS 0xc /* Clear to deassert GPIO */ |
| 63 | 63 | ||
| 64 | #define TC9563_TX_MARGIN_MIN_UA 400000 | 64 | #define TC9563_TX_MARGIN_MIN_UA 400000 |
| 65 | 65 | ||
| @@ -69,7 +69,7 @@ · 3 unmodified lines | |||
| 69 | */ | 69 | */ |
| 70 | #define TC9563_OSC_STAB_DELAY_US (10 * USEC_PER_MSEC) | 70 | #define TC9563_OSC_STAB_DELAY_US (10 * USEC_PER_MSEC) |
| 71 | 71 | ||
| 72 | #define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 nanoseconds */ | 72 | #define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 ns */ |
| 73 | 73 | ||
| 74 | struct tc9563_pwrctrl_reg_setting { | 74 | struct tc9563_pwrctrl_reg_setting { |
| 75 | unsigned int offset; | 75 | unsigned int offset; |
| @@ -105,13 +105,13 @@ static const char *const tc9563_supply_names[TC9563_PWRCTL_MAX_SUPPLY] = { · 29 unmodified lines | |||
| 105 | "vddio18", | 105 | "vddio18", |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | struct tc9563_pwrctrl_ctx { | 108 | struct tc9563_pwrctrl { |
| 109 | struct pci_pwrctrl pwrctrl; | ||
| 109 | struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; | 110 | struct regulator_bulk_data supplies[TC9563_PWRCTL_MAX_SUPPLY]; |
| 110 | struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; | 111 | struct tc9563_pwrctrl_cfg cfg[TC9563_MAX]; |
| 111 | struct gpio_desc *reset_gpio; | 112 | struct gpio_desc *reset_gpio; |
| 112 | struct i2c_adapter *adapter; | 113 | struct i2c_adapter *adapter; |
| 113 | struct i2c_client *client; | 114 | struct i2c_client *client; |
| 114 | struct pci_pwrctrl pwrctrl; | ||
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | /* | 117 | /* |
| @@ -217,7 +217,8 @@ static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, · 99 unmodified lines | |||
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, | 219 | static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, |
| 220 | const struct tc9563_pwrctrl_reg_setting *seq, int len) | 220 | const struct tc9563_pwrctrl_reg_setting *seq, |
| 221 | int len) | ||
| 221 | { | 222 | { |
| 222 | int ret, i; | 223 | int ret, i; |
| 223 | 224 | ||
| @@ -230,10 +231,10 @@ static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, · 6 unmodified lines | |||
| 230 | return 0; | 231 | return 0; |
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, | 234 | static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl *tc9563, |
| 234 | enum tc9563_pwrctrl_ports port) | 235 | enum tc9563_pwrctrl_ports port) |
| 235 | { | 236 | { |
| 236 | struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; | 237 | struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; |
| 237 | const struct tc9563_pwrctrl_reg_setting *seq; | 238 | const struct tc9563_pwrctrl_reg_setting *seq; |
| 238 | int ret, len; | 239 | int ret, len; |
| 239 | 240 | ||
| @@ -248,16 +249,17 @@ static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl_ctx *ctx, · 8 unmodified lines | |||
| 248 | len = ARRAY_SIZE(dsp2_pwroff_seq); | 249 | len = ARRAY_SIZE(dsp2_pwroff_seq); |
| 249 | } | 250 | } |
| 250 | 251 | ||
| 251 | ret = tc9563_pwrctrl_i2c_bulk_write(ctx->client, seq, len); | 252 | ret = tc9563_pwrctrl_i2c_bulk_write(tc9563->client, seq, len); |
| 252 | if (ret) | 253 | if (ret) |
| 253 | return ret; | 254 | return ret; |
| 254 | 255 | ||
| 255 | return tc9563_pwrctrl_i2c_bulk_write(ctx->client, | 256 | return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, common_pwroff_seq, |
| 256 | common_pwroff_seq, ARRAY_SIZE(common_pwroff_seq)); | 257 | ARRAY_SIZE(common_pwroff_seq)); |
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, | 260 | static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc9563, |
| 260 | enum tc9563_pwrctrl_ports port, bool is_l1, u32 ns) | 261 | enum tc9563_pwrctrl_ports port, |
| 262 | bool is_l1, u32 ns) | ||
| 261 | { | 263 | { |
| 262 | u32 rd_val, units; | 264 | u32 rd_val, units; |
| 263 | int ret; | 265 | int ret; |
| @@ -269,30 +271,38 @@ static int tc9563_pwrctrl_set_l0s_l1_entry_delay(struct tc9563_pwrctrl_ctx *ctx, · 5 unmodified lines | |||
| 269 | units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; | 271 | units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; |
| 270 | 272 | ||
| 271 | if (port == TC9563_ETHERNET) { | 273 | if (port == TC9563_ETHERNET) { |
| 272 | ret = tc9563_pwrctrl_i2c_read(ctx->client, TC9563_EMBEDDED_ETH_DELAY, &rd_val); | 274 | ret = tc9563_pwrctrl_i2c_read(tc9563->client, |
| 275 | TC9563_EMBEDDED_ETH_DELAY, | ||
| 276 | &rd_val); | ||
| 273 | if (ret) | 277 | if (ret) |
| 274 | return ret; | 278 | return ret; |
| 275 | 279 | ||
| 276 | if (is_l1) | 280 | if (is_l1) |
| 277 | rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L1_DELAY_MASK); | 281 | rd_val = u32_replace_bits(rd_val, units, |
| 282 | TC9563_ETH_L1_DELAY_MASK); | ||
| 278 | else | 283 | else |
| 279 | rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); | 284 | rd_val = u32_replace_bits(rd_val, units, |
| 285 | TC9563_ETH_L0S_DELAY_MASK); | ||
| 280 | 286 | ||
| 281 | return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_EMBEDDED_ETH_DELAY, rd_val); | 287 | return tc9563_pwrctrl_i2c_write(tc9563->client, |
| 288 | TC9563_EMBEDDED_ETH_DELAY, | ||
| 289 | rd_val); | ||
| 282 | } | 290 | } |
| 283 | 291 | ||
| 284 | ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); | 292 | ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, |
| 293 | BIT(port)); | ||
| 285 | if (ret) | 294 | if (ret) |
| 286 | return ret; | 295 | return ret; |
| 287 | 296 | ||
| 288 | return tc9563_pwrctrl_i2c_write(ctx->client, | 297 | return tc9563_pwrctrl_i2c_write(tc9563->client, |
| 289 | is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, units); | 298 | is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, |
| 299 | units); | ||
| 290 | } | 300 | } |
| 291 | 301 | ||
| 292 | static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, | 302 | static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl *tc9563, |
| 293 | enum tc9563_pwrctrl_ports port) | 303 | enum tc9563_pwrctrl_ports port) |
| 294 | { | 304 | { |
| 295 | u32 amp = ctx->cfg[port].tx_amp; | 305 | u32 amp = tc9563->cfg[port].tx_amp; |
| 296 | int port_access; | 306 | int port_access; |
| 297 | 307 | ||
| 298 | if (amp < TC9563_TX_MARGIN_MIN_UA) | 308 | if (amp < TC9563_TX_MARGIN_MIN_UA) |
| @@ -321,13 +331,14 @@ static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl_ctx *ctx, · 22 unmodified lines | |||
| 321 | {TC9563_TX_MARGIN, amp}, | 331 | {TC9563_TX_MARGIN, amp}, |
| 322 | }; | 332 | }; |
| 323 | 333 | ||
| 324 | return tc9563_pwrctrl_i2c_bulk_write(ctx->client, tx_amp_seq, ARRAY_SIZE(tx_amp_seq)); | 334 | return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, tx_amp_seq, |
| 335 | ARRAY_SIZE(tx_amp_seq)); | ||
| 325 | } | 336 | } |
| 326 | 337 | ||
| 327 | static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, | 338 | static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl *tc9563, |
| 328 | enum tc9563_pwrctrl_ports port) | 339 | enum tc9563_pwrctrl_ports port) |
| 329 | { | 340 | { |
| 330 | struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; | 341 | struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; |
| 331 | int port_access, lane_access = 0x3; | 342 | int port_access, lane_access = 0x3; |
| 332 | u32 phy_rate = 0x21; | 343 | u32 phy_rate = 0x21; |
| 333 | 344 | ||
| @@ -364,14 +375,14 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl_ctx *ctx, · 30 unmodified lines | |||
| 364 | {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, | 375 | {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, |
| 365 | }; | 376 | }; |
| 366 | 377 | ||
| 367 | return tc9563_pwrctrl_i2c_bulk_write(ctx->client, | 378 | return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, disable_dfe_seq, |
| 368 | disable_dfe_seq, ARRAY_SIZE(disable_dfe_seq)); | 379 | ARRAY_SIZE(disable_dfe_seq)); |
| 369 | } | 380 | } |
| 370 | 381 | ||
| 371 | static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, | 382 | static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl *tc9563, |
| 372 | enum tc9563_pwrctrl_ports port) | 383 | enum tc9563_pwrctrl_ports port) |
| 373 | { | 384 | { |
| 374 | u8 *nfts = ctx->cfg[port].nfts; | 385 | u8 *nfts = tc9563->cfg[port].nfts; |
| 375 | struct tc9563_pwrctrl_reg_setting nfts_seq[] = { | 386 | struct tc9563_pwrctrl_reg_setting nfts_seq[] = { |
| 376 | {TC9563_NFTS_2_5_GT, nfts[0]}, | 387 | {TC9563_NFTS_2_5_GT, nfts[0]}, |
| 377 | {TC9563_NFTS_5_GT, nfts[1]}, | 388 | {TC9563_NFTS_5_GT, nfts[1]}, |
| @@ -381,30 +392,35 @@ static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl_ctx *ctx, · 3 unmodified lines | |||
| 381 | if (!nfts[0]) | 392 | if (!nfts[0]) |
| 382 | return 0; | 393 | return 0; |
| 383 | 394 | ||
| 384 | ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_PORT_SELECT, BIT(port)); | 395 | ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, |
| 396 | BIT(port)); | ||
| 385 | if (ret) | 397 | if (ret) |
| 386 | return ret; | 398 | return ret; |
| 387 | 399 | ||
| 388 | return tc9563_pwrctrl_i2c_bulk_write(ctx->client, nfts_seq, ARRAY_SIZE(nfts_seq)); | 400 | return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, nfts_seq, |
| 401 | ARRAY_SIZE(nfts_seq)); | ||
| 389 | } | 402 | } |
| 390 | 403 | ||
| 391 | static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl_ctx *ctx, bool deassert) | 404 | static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl *tc9563, |
| 405 | bool deassert) | ||
| 392 | { | 406 | { |
| 393 | int ret, val; | 407 | int ret, val; |
| 394 | 408 | ||
| 395 | ret = tc9563_pwrctrl_i2c_write(ctx->client, TC9563_GPIO_CONFIG, TC9563_GPIO_MASK); | 409 | ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_GPIO_CONFIG, |
| 410 | TC9563_GPIO_MASK); | ||
| 396 | if (ret) | 411 | if (ret) |
| 397 | return ret; | 412 | return ret; |
| 398 | 413 | ||
| 399 | val = deassert ? TC9563_GPIO_DEASSERT_BITS : 0; | 414 | val = deassert ? TC9563_GPIO_DEASSERT_BITS : 0; |
| 400 | 415 | ||
| 401 | return tc9563_pwrctrl_i2c_write(ctx->client, TC9563_RESET_GPIO, val); | 416 | return tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_RESET_GPIO, val); |
| 402 | } | 417 | } |
| 403 | 418 | ||
| 404 | static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct device_node *node, | 419 | static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl *tc9563, |
| 420 | struct device_node *node, | ||
| 405 | enum tc9563_pwrctrl_ports port) | 421 | enum tc9563_pwrctrl_ports port) |
| 406 | { | 422 | { |
| 407 | struct tc9563_pwrctrl_cfg *cfg = &ctx->cfg[port]; | 423 | struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; |
| 408 | int ret; | 424 | int ret; |
| 409 | 425 | ||
| 410 | /* Disable port if the status of the port is disabled. */ | 426 | /* Disable port if the status of the port is disabled. */ |
| @@ -434,128 +450,137 @@ static int tc9563_pwrctrl_parse_device_dt(struct tc9563_pwrctrl_ctx *ctx, struct · 23 unmodified lines | |||
| 434 | return 0; | 450 | return 0; |
| 435 | } | 451 | } |
| 436 | 452 | ||
| 437 | static void tc9563_pwrctrl_power_off(struct tc9563_pwrctrl_ctx *ctx) | 453 | static int tc9563_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) |
| 438 | { | 454 | { |
| 439 | gpiod_set_value(ctx->reset_gpio, 1); | 455 | struct tc9563_pwrctrl *tc9563 = container_of(pwrctrl, |
| 456 | struct tc9563_pwrctrl, pwrctrl); | ||
| 457 | |||
| 458 | gpiod_set_value(tc9563->reset_gpio, 1); | ||
| 459 | |||
| 460 | regulator_bulk_disable(ARRAY_SIZE(tc9563->supplies), tc9563->supplies); | ||
| 440 | 461 | ||
| 441 | regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 462 | return 0; |
| 442 | } | 463 | } |
| 443 | 464 | ||
| 444 | static int tc9563_pwrctrl_bring_up(struct tc9563_pwrctrl_ctx *ctx) | 465 | static int tc9563_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) |
| 445 | { | 466 | { |
| 467 | struct tc9563_pwrctrl *tc9563 = container_of(pwrctrl, | ||
| 468 | struct tc9563_pwrctrl, pwrctrl); | ||
| 469 | struct device *dev = tc9563->pwrctrl.dev; | ||
| 446 | struct tc9563_pwrctrl_cfg *cfg; | 470 | struct tc9563_pwrctrl_cfg *cfg; |
| 447 | int ret, i; | 471 | int ret, i; |
| 448 | 472 | ||
| 449 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 473 | ret = regulator_bulk_enable(ARRAY_SIZE(tc9563->supplies), |
| 474 | tc9563->supplies); | ||
| 450 | if (ret < 0) | 475 | if (ret < 0) |
| 451 | return dev_err_probe(ctx->pwrctrl.dev, ret, "cannot enable regulators\n"); | 476 | return dev_err_probe(dev, ret, "cannot enable regulators\n"); |
| 452 | 477 | ||
| 453 | gpiod_set_value(ctx->reset_gpio, 0); | 478 | gpiod_set_value(tc9563->reset_gpio, 0); |
| 454 | 479 | ||
| 455 | fsleep(TC9563_OSC_STAB_DELAY_US); | 480 | fsleep(TC9563_OSC_STAB_DELAY_US); |
| 456 | 481 | ||
| 457 | ret = tc9563_pwrctrl_assert_deassert_reset(ctx, false); | 482 | ret = tc9563_pwrctrl_assert_deassert_reset(tc9563, false); |
| 458 | if (ret) | 483 | if (ret) |
| 459 | goto power_off; | 484 | goto power_off; |
| 460 | 485 | ||
| 461 | for (i = 0; i < TC9563_MAX; i++) { | 486 | for (i = 0; i < TC9563_MAX; i++) { |
| 462 | cfg = &ctx->cfg[i]; | 487 | cfg = &tc9563->cfg[i]; |
| 463 | ret = tc9563_pwrctrl_disable_port(ctx, i); | 488 | ret = tc9563_pwrctrl_disable_port(tc9563, i); |
| 464 | if (ret) { | 489 | if (ret) { |
| 465 | dev_err(ctx->pwrctrl.dev, "Disabling port failed\n"); | 490 | dev_err(dev, "Disabling port failed\n"); |
| 466 | goto power_off; | 491 | goto power_off; |
| 467 | } | 492 | } |
| 468 | 493 | ||
| 469 | ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, false, cfg->l0s_delay); | 494 | ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(tc9563, i, false, cfg->l0s_delay); |
| 470 | if (ret) { | 495 | if (ret) { |
| 471 | dev_err(ctx->pwrctrl.dev, "Setting L0s entry delay failed\n"); | 496 | dev_err(dev, "Setting L0s entry delay failed\n"); |
| 472 | goto power_off; | 497 | goto power_off; |
| 473 | } | 498 | } |
| 474 | 499 | ||
| 475 | ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(ctx, i, true, cfg->l1_delay); | 500 | ret = tc9563_pwrctrl_set_l0s_l1_entry_delay(tc9563, i, true, cfg->l1_delay); |
| 476 | if (ret) { | 501 | if (ret) { |
| 477 | dev_err(ctx->pwrctrl.dev, "Setting L1 entry delay failed\n"); | 502 | dev_err(dev, "Setting L1 entry delay failed\n"); |
| 478 | goto power_off; | 503 | goto power_off; |
| 479 | } | 504 | } |
| 480 | 505 | ||
| 481 | ret = tc9563_pwrctrl_set_tx_amplitude(ctx, i); | 506 | ret = tc9563_pwrctrl_set_tx_amplitude(tc9563, i); |
| 482 | if (ret) { | 507 | if (ret) { |
| 483 | dev_err(ctx->pwrctrl.dev, "Setting Tx amplitude failed\n"); | 508 | dev_err(dev, "Setting Tx amplitude failed\n"); |
| 484 | goto power_off; | 509 | goto power_off; |
| 485 | } | 510 | } |
| 486 | 511 | ||
| 487 | ret = tc9563_pwrctrl_set_nfts(ctx, i); | 512 | ret = tc9563_pwrctrl_set_nfts(tc9563, i); |
| 488 | if (ret) { | 513 | if (ret) { |
| 489 | dev_err(ctx->pwrctrl.dev, "Setting N_FTS failed\n"); | 514 | dev_err(dev, "Setting N_FTS failed\n"); |
| 490 | goto power_off; | 515 | goto power_off; |
| 491 | } | 516 | } |
| 492 | 517 | ||
| 493 | ret = tc9563_pwrctrl_disable_dfe(ctx, i); | 518 | ret = tc9563_pwrctrl_disable_dfe(tc9563, i); |
| 494 | if (ret) { | 519 | if (ret) { |
| 495 | dev_err(ctx->pwrctrl.dev, "Disabling DFE failed\n"); | 520 | dev_err(dev, "Disabling DFE failed\n"); |
| 496 | goto power_off; | 521 | goto power_off; |
| 497 | } | 522 | } |
| 498 | } | 523 | } |
| 499 | 524 | ||
| 500 | ret = tc9563_pwrctrl_assert_deassert_reset(ctx, true); | 525 | ret = tc9563_pwrctrl_assert_deassert_reset(tc9563, true); |
| 501 | if (!ret) | 526 | if (!ret) |
| 502 | return 0; | 527 | return 0; |
| 503 | 528 | ||
| 504 | power_off: | 529 | power_off: |
| 505 | tc9563_pwrctrl_power_off(ctx); | 530 | tc9563_pwrctrl_power_off(&tc9563->pwrctrl); |
| 506 | return ret; | 531 | return ret; |
| 507 | } | 532 | } |
| 508 | 533 | ||
| 509 | static int tc9563_pwrctrl_probe(struct platform_device *pdev) | 534 | static int tc9563_pwrctrl_probe(struct platform_device *pdev) |
| 510 | { | 535 | { |
| 511 | struct pci_host_bridge *bridge = to_pci_host_bridge(pdev->dev.parent); | 536 | struct device_node *node = pdev->dev.of_node; |
| 512 | struct pci_bus *bus = bridge->bus; | ||
| 513 | struct device *dev = &pdev->dev; | 537 | struct device *dev = &pdev->dev; |
| 514 | enum tc9563_pwrctrl_ports port; | 538 | enum tc9563_pwrctrl_ports port; |
| 515 | struct tc9563_pwrctrl_ctx *ctx; | 539 | struct tc9563_pwrctrl *tc9563; |
| 516 | struct device_node *i2c_node; | 540 | struct device_node *i2c_node; |
| 517 | int ret, addr; | 541 | int ret, addr; |
| 518 | 542 | ||
| 519 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 543 | tc9563 = devm_kzalloc(dev, sizeof(*tc9563), GFP_KERNEL); |
| 520 | if (!ctx) | 544 | if (!tc9563) |
| 521 | return -ENOMEM; | 545 | return -ENOMEM; |
| 522 | 546 | ||
| 523 | ret = of_property_read_u32_index(pdev->dev.of_node, "i2c-parent", 1, &addr); | 547 | ret = of_property_read_u32_index(node, "i2c-parent", 1, &addr); |
| 524 | if (ret) | 548 | if (ret) |
| 525 | return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); | 549 | return dev_err_probe(dev, ret, "Failed to read i2c-parent property\n"); |
| 526 | 550 | ||
| 527 | i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); | 551 | i2c_node = of_parse_phandle(dev->of_node, "i2c-parent", 0); |
| 528 | ctx->adapter = of_find_i2c_adapter_by_node(i2c_node); | 552 | tc9563->adapter = of_find_i2c_adapter_by_node(i2c_node); |
| 529 | of_node_put(i2c_node); | 553 | of_node_put(i2c_node); |
| 530 | if (!ctx->adapter) | 554 | if (!tc9563->adapter) |
| 531 | return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); | 555 | return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find I2C adapter\n"); |
| 532 | 556 | ||
| 533 | ctx->client = i2c_new_dummy_device(ctx->adapter, addr); | 557 | tc9563->client = i2c_new_dummy_device(tc9563->adapter, addr); |
| 534 | if (IS_ERR(ctx->client)) { | 558 | if (IS_ERR(tc9563->client)) { |
| 535 | dev_err(dev, "Failed to create I2C client\n"); | 559 | dev_err(dev, "Failed to create I2C client\n"); |
| 536 | i2c_put_adapter(ctx->adapter); | 560 | put_device(&tc9563->adapter->dev); |
| 537 | return PTR_ERR(ctx->client); | 561 | return PTR_ERR(tc9563->client); |
| 538 | } | 562 | } |
| 539 | 563 | ||
| 540 | for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) | 564 | for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) |
| 541 | ctx->supplies[i].supply = tc9563_supply_names[i]; | 565 | tc9563->supplies[i].supply = tc9563_supply_names[i]; |
| 542 | 566 | ||
| 543 | ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, ctx->supplies); | 567 | ret = devm_regulator_bulk_get(dev, TC9563_PWRCTL_MAX_SUPPLY, |
| 568 | tc9563->supplies); | ||
| 544 | if (ret) { | 569 | if (ret) { |
| 545 | dev_err_probe(dev, ret, "failed to get supply regulator\n"); | 570 | dev_err_probe(dev, ret, "failed to get supply regulator\n"); |
| 546 | goto remove_i2c; | 571 | goto remove_i2c; |
| 547 | } | 572 | } |
| 548 | 573 | ||
| 549 | ctx->reset_gpio = devm_gpiod_get(dev, "resx", GPIOD_OUT_HIGH); | 574 | tc9563->reset_gpio = devm_gpiod_get(dev, "resx", GPIOD_OUT_HIGH); |
| 550 | if (IS_ERR(ctx->reset_gpio)) { | 575 | if (IS_ERR(tc9563->reset_gpio)) { |
| 551 | ret = dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "failed to get resx GPIO\n"); | 576 | ret = dev_err_probe(dev, PTR_ERR(tc9563->reset_gpio), "failed to get resx GPIO\n"); |
| 552 | goto remove_i2c; | 577 | goto remove_i2c; |
| 553 | } | 578 | } |
| 554 | 579 | ||
| 555 | pci_pwrctrl_init(&ctx->pwrctrl, dev); | 580 | pci_pwrctrl_init(&tc9563->pwrctrl, dev); |
| 556 | 581 | ||
| 557 | port = TC9563_USP; | 582 | port = TC9563_USP; |
| 558 | ret = tc9563_pwrctrl_parse_device_dt(ctx, pdev->dev.of_node, port); | 583 | ret = tc9563_pwrctrl_parse_device_dt(tc9563, node, port); |
| 559 | if (ret) { | 584 | if (ret) { |
| 560 | dev_err(dev, "failed to parse device tree properties: %d\n", ret); | 585 | dev_err(dev, "failed to parse device tree properties: %d\n", ret); |
| 561 | goto remove_i2c; | 586 | goto remove_i2c; |
| @@ -563,18 +588,20 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 563 | 588 | ||
| 564 | /* | 589 | /* |
| 565 | * Downstream ports are always children of the upstream port. | 590 | * Downstream ports are always children of the upstream port. |
| 566 | * The first node represents DSP1, the second node represents DSP2, and so on. | 591 | * The first node represents DSP1, the second node represents DSP2, |
| 592 | * and so on. | ||
| 567 | */ | 593 | */ |
| 568 | for_each_child_of_node_scoped(pdev->dev.of_node, child) { | 594 | for_each_child_of_node_scoped(node, child) { |
| 569 | port++; | 595 | port++; |
| 570 | ret = tc9563_pwrctrl_parse_device_dt(ctx, child, port); | 596 | ret = tc9563_pwrctrl_parse_device_dt(tc9563, child, port); |
| 571 | if (ret) | 597 | if (ret) |
| 572 | break; | 598 | break; |
| 573 | /* Embedded ethernet device are under DSP3 */ | 599 | /* Embedded ethernet device are under DSP3 */ |
| 574 | if (port == TC9563_DSP3) { | 600 | if (port == TC9563_DSP3) { |
| 575 | for_each_child_of_node_scoped(child, child1) { | 601 | for_each_child_of_node_scoped(child, child1) { |
| 576 | port++; | 602 | port++; |
| 577 | ret = tc9563_pwrctrl_parse_device_dt(ctx, child1, port); | 603 | ret = tc9563_pwrctrl_parse_device_dt(tc9563, |
| 604 | child1, port); | ||
| 578 | if (ret) | 605 | if (ret) |
| 579 | break; | 606 | break; |
| 580 | } | 607 | } |
| @@ -585,45 +612,32 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 585 | goto remove_i2c; | 612 | goto remove_i2c; |
| 586 | } | 613 | } |
| 587 | 614 | ||
| 588 | if (bridge->ops->assert_perst) { | 615 | tc9563->pwrctrl.power_on = tc9563_pwrctrl_power_on; |
| 589 | ret = bridge->ops->assert_perst(bus, true); | 616 | tc9563->pwrctrl.power_off = tc9563_pwrctrl_power_off; |
| 590 | if (ret) | ||
| 591 | goto remove_i2c; | ||
| 592 | } | ||
| 593 | 617 | ||
| 594 | ret = tc9563_pwrctrl_bring_up(ctx); | 618 | ret = devm_pci_pwrctrl_device_set_ready(dev, &tc9563->pwrctrl); |
| 595 | if (ret) | ||
| 596 | goto remove_i2c; | ||
| 597 | |||
| 598 | if (bridge->ops->assert_perst) { | ||
| 599 | ret = bridge->ops->assert_perst(bus, false); | ||
| 600 | if (ret) | ||
| 601 | goto power_off; | ||
| 602 | } | ||
| 603 | |||
| 604 | ret = devm_pci_pwrctrl_device_set_ready(dev, &ctx->pwrctrl); | ||
| 605 | if (ret) | 619 | if (ret) |
| 606 | goto power_off; | 620 | goto power_off; |
| 607 | 621 | ||
| 608 | platform_set_drvdata(pdev, ctx); | ||
| 609 | |||
| 610 | return 0; | 622 | return 0; |
| 611 | 623 | ||
| 612 | power_off: | 624 | power_off: |
| 613 | tc9563_pwrctrl_power_off(ctx); | 625 | tc9563_pwrctrl_power_off(&tc9563->pwrctrl); |
| 614 | remove_i2c: | 626 | remove_i2c: |
| 615 | i2c_unregister_device(ctx->client); | 627 | i2c_unregister_device(tc9563->client); |
| 616 | i2c_put_adapter(ctx->adapter); | 628 | put_device(&tc9563->adapter->dev); |
| 617 | return ret; | 629 | return ret; |
| 618 | } | 630 | } |
| 619 | 631 | ||
| 620 | static void tc9563_pwrctrl_remove(struct platform_device *pdev) | 632 | static void tc9563_pwrctrl_remove(struct platform_device *pdev) |
| 621 | { | 633 | { |
| 622 | struct tc9563_pwrctrl_ctx *ctx = platform_get_drvdata(pdev); | 634 | struct pci_pwrctrl *pwrctrl = dev_get_drvdata(&pdev->dev); |
| 635 | struct tc9563_pwrctrl *tc9563 = container_of(pwrctrl, | ||
| 636 | struct tc9563_pwrctrl, pwrctrl); | ||
| 623 | 637 | ||
| 624 | tc9563_pwrctrl_power_off(ctx); | 638 | tc9563_pwrctrl_power_off(&tc9563->pwrctrl); |
| 625 | i2c_unregister_device(ctx->client); | 639 | i2c_unregister_device(tc9563->client); |
| 626 | i2c_put_adapter(ctx->adapter); | 640 | put_device(&tc9563->adapter->dev); |
| 627 | } | 641 | } |
| 628 | 642 | ||
| 629 | static const struct of_device_id tc9563_pwrctrl_of_match[] = { | 643 | static const struct of_device_id tc9563_pwrctrl_of_match[] = { |
| @@ -8,36 +8,84 @@ · 7 unmodified lines | |||
| 8 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 9 | #include <linux/mod_devicetable.h> | 9 | #include <linux/mod_devicetable.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/of_graph.h> | ||
| 11 | #include <linux/pci-pwrctrl.h> | 12 | #include <linux/pci-pwrctrl.h> |
| 12 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
| 14 | #include <linux/pwrseq/consumer.h> | ||
| 13 | #include <linux/regulator/consumer.h> | 15 | #include <linux/regulator/consumer.h> |
| 14 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 15 | 17 | ||
| 16 | struct pci_pwrctrl_slot_data { | 18 | struct slot_pwrctrl { |
| 17 | struct pci_pwrctrl ctx; | 19 | struct pci_pwrctrl pwrctrl; |
| 18 | struct regulator_bulk_data *supplies; | 20 | struct regulator_bulk_data *supplies; |
| 19 | int num_supplies; | 21 | int num_supplies; |
| 22 | struct clk *clk; | ||
| 23 | struct pwrseq_desc *pwrseq; | ||
| 20 | }; | 24 | }; |
| 21 | 25 | ||
| 22 | static void devm_pci_pwrctrl_slot_power_off(void *data) | 26 | static int slot_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) |
| 23 | { | 27 | { |
| 24 | struct pci_pwrctrl_slot_data *slot = data; | 28 | struct slot_pwrctrl *slot = container_of(pwrctrl, |
| 29 | struct slot_pwrctrl, pwrctrl); | ||
| 30 | int ret; | ||
| 31 | |||
| 32 | if (slot->pwrseq) { | ||
| 33 | pwrseq_power_on(slot->pwrseq); | ||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); | ||
| 38 | if (ret < 0) { | ||
| 39 | dev_err(slot->pwrctrl.dev, "Failed to enable slot regulators\n"); | ||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | return clk_prepare_enable(slot->clk); | ||
| 44 | } | ||
| 45 | |||
| 46 | static int slot_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) | ||
| 47 | { | ||
| 48 | struct slot_pwrctrl *slot = container_of(pwrctrl, | ||
| 49 | struct slot_pwrctrl, pwrctrl); | ||
| 50 | |||
| 51 | if (slot->pwrseq) { | ||
| 52 | pwrseq_power_off(slot->pwrseq); | ||
| 53 | return 0; | ||
| 54 | } | ||
| 25 | 55 | ||
| 26 | regulator_bulk_disable(slot->num_supplies, slot->supplies); | 56 | regulator_bulk_disable(slot->num_supplies, slot->supplies); |
| 57 | clk_disable_unprepare(slot->clk); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void devm_slot_pwrctrl_release(void *data) | ||
| 63 | { | ||
| 64 | struct slot_pwrctrl *slot = data; | ||
| 65 | |||
| 66 | slot_pwrctrl_power_off(&slot->pwrctrl); | ||
| 27 | regulator_bulk_free(slot->num_supplies, slot->supplies); | 67 | regulator_bulk_free(slot->num_supplies, slot->supplies); |
| 28 | } | 68 | } |
| 29 | 69 | ||
| 30 | static int pci_pwrctrl_slot_probe(struct platform_device *pdev) | 70 | static int slot_pwrctrl_probe(struct platform_device *pdev) |
| 31 | { | 71 | { |
| 32 | struct pci_pwrctrl_slot_data *slot; | 72 | struct slot_pwrctrl *slot; |
| 33 | struct device *dev = &pdev->dev; | 73 | struct device *dev = &pdev->dev; |
| 34 | struct clk *clk; | ||
| 35 | int ret; | 74 | int ret; |
| 36 | 75 | ||
| 37 | slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); | 76 | slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); |
| 38 | if (!slot) | 77 | if (!slot) |
| 39 | return -ENOMEM; | 78 | return -ENOMEM; |
| 40 | 79 | ||
| 80 | if (of_graph_is_present(dev_of_node(dev))) { | ||
| 81 | slot->pwrseq = devm_pwrseq_get(dev, "pcie"); | ||
| 82 | if (IS_ERR(slot->pwrseq)) | ||
| 83 | return dev_err_probe(dev, PTR_ERR(slot->pwrseq), | ||
| 84 | "Failed to get the power sequencer\n"); | ||
| 85 | |||
| 86 | goto skip_resources; | ||
| 87 | } | ||
| 88 | |||
| 41 | ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), | 89 | ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), |
| 42 | &slot->supplies); | 90 | &slot->supplies); |
| 43 | if (ret < 0) { | 91 | if (ret < 0) { |
| @@ -46,49 +94,46 @@ static int pci_pwrctrl_slot_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 46 | } | 94 | } |
| 47 | 95 | ||
| 48 | slot->num_supplies = ret; | 96 | slot->num_supplies = ret; |
| 49 | ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); | 97 | |
| 50 | if (ret < 0) { | 98 | slot->clk = devm_clk_get_optional(dev, NULL); |
| 51 | dev_err_probe(dev, ret, "Failed to enable slot regulators\n"); | 99 | if (IS_ERR(slot->clk)) { |
| 52 | regulator_bulk_free(slot->num_supplies, slot->supplies); | 100 | return dev_err_probe(dev, PTR_ERR(slot->clk), |
| 53 | return ret; | 101 | "Failed to enable slot clock\n"); |
| 54 | } | 102 | } |
| 55 | 103 | ||
| 56 | ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, | 104 | skip_resources: |
| 57 | slot); | 105 | slot->pwrctrl.power_on = slot_pwrctrl_power_on; |
| 106 | slot->pwrctrl.power_off = slot_pwrctrl_power_off; | ||
| 107 | |||
| 108 | ret = devm_add_action_or_reset(dev, devm_slot_pwrctrl_release, slot); | ||
| 58 | if (ret) | 109 | if (ret) |
| 59 | return ret; | 110 | return ret; |
| 60 | 111 | ||
| 61 | clk = devm_clk_get_optional_enabled(dev, NULL); | 112 | pci_pwrctrl_init(&slot->pwrctrl, dev); |
| 62 | if (IS_ERR(clk)) { | ||
| 63 | return dev_err_probe(dev, PTR_ERR(clk), | ||
| 64 | "Failed to enable slot clock\n"); | ||
| 65 | } | ||
| 66 | |||
| 67 | pci_pwrctrl_init(&slot->ctx, dev); | ||
| 68 | 113 | ||
| 69 | ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx); | 114 | ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->pwrctrl); |
| 70 | if (ret) | 115 | if (ret) |
| 71 | return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); | 116 | return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); |
| 72 | 117 | ||
| 73 | return 0; | 118 | return 0; |
| 74 | } | 119 | } |
| 75 | 120 | ||
| 76 | static const struct of_device_id pci_pwrctrl_slot_of_match[] = { | 121 | static const struct of_device_id slot_pwrctrl_of_match[] = { |
| 77 | { | 122 | { |
| 78 | .compatible = "pciclass,0604", | 123 | .compatible = "pciclass,0604", |
| 79 | }, | 124 | }, |
| 80 | { } | 125 | { } |
| 81 | }; | 126 | }; |
| 82 | MODULE_DEVICE_TABLE(of, pci_pwrctrl_slot_of_match); | 127 | MODULE_DEVICE_TABLE(of, slot_pwrctrl_of_match); |
| 83 | 128 | ||
| 84 | static struct platform_driver pci_pwrctrl_slot_driver = { | 129 | static struct platform_driver slot_pwrctrl_driver = { |
| 85 | .driver = { | 130 | .driver = { |
| 86 | .name = "pci-pwrctrl-slot", | 131 | .name = "pci-pwrctrl-slot", |
| 87 | .of_match_table = pci_pwrctrl_slot_of_match, | 132 | .of_match_table = slot_pwrctrl_of_match, |
| 88 | }, | 133 | }, |
| 89 | .probe = pci_pwrctrl_slot_probe, | 134 | .probe = slot_pwrctrl_probe, |
| 90 | }; | 135 | }; |
| 91 | module_platform_driver(pci_pwrctrl_slot_driver); | 136 | module_platform_driver(slot_pwrctrl_driver); |
| 92 | 137 | ||
| 93 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); | 138 | MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); |
| 94 | MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots"); | 139 | MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots"); |
| @@ -1360,6 +1360,16 @@ static void quirk_transparent_bridge(struct pci_dev *dev) · 1359 unmodified lines | |||
| 1360 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge); | 1360 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge); |
| 1361 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge); | 1361 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge); |
| 1362 | 1362 | ||
| 1363 | /* | ||
| 1364 | * Enabling Link Bandwidth Management Interrupts (BW notifications) can cause | ||
| 1365 | * boot hangs on P45. | ||
| 1366 | */ | ||
| 1367 | static void quirk_p45_bw_notifications(struct pci_dev *dev) | ||
| 1368 | { | ||
| 1369 | dev->no_bw_notif = 1; | ||
| 1370 | } | ||
| 1371 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e21, quirk_p45_bw_notifications); | ||
| 1372 | |||
| 1363 | /* | 1373 | /* |
| 1364 | * Common misconfiguration of the MediaGX/Geode PCI master that will reduce | 1374 | * Common misconfiguration of the MediaGX/Geode PCI master that will reduce |
| 1365 | * PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1 datasheets | 1375 | * PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1 datasheets |
| @@ -3749,6 +3759,14 @@ static void quirk_no_bus_reset(struct pci_dev *dev) · 2383 unmodified lines | |||
| 3749 | dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; | 3759 | dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; |
| 3750 | } | 3760 | } |
| 3751 | 3761 | ||
| 3762 | /* | ||
| 3763 | * After asserting Secondary Bus Reset to downstream devices via a GB10 | ||
| 3764 | * Root Port, the link may not retrain correctly. | ||
| 3765 | * https://lore.kernel.org/r/20251113084441.2124737-1-Johnny-CC.Chang@mediatek.com | ||
| 3766 | */ | ||
| 3767 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x22CE, quirk_no_bus_reset); | ||
| 3768 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x22D0, quirk_no_bus_reset); | ||
| 3769 | |||
| 3752 | /* | 3770 | /* |
| 3753 | * Some NVIDIA GPU devices do not work with bus reset, SBR needs to be | 3771 | * Some NVIDIA GPU devices do not work with bus reset, SBR needs to be |
| 3754 | * prevented for those affected devices. | 3772 | * prevented for those affected devices. |
| @@ -3792,6 +3810,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset); · 37 unmodified lines | |||
| 3792 | */ | 3810 | */ |
| 3793 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0xb005, quirk_no_bus_reset); | 3811 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0xb005, quirk_no_bus_reset); |
| 3794 | 3812 | ||
| 3813 | /* | ||
| 3814 | * Reports from users making use of PCI device assignment with ASM1164 | ||
| 3815 | * controllers indicate an issue with bus reset where the device fails to | ||
| 3816 | * retrain. The issue appears more common in configurations with multiple | ||
| 3817 | * controllers. The device does indicate PM reset support (NoSoftRst-), | ||
| 3818 | * therefore this still leaves a viable reset method. | ||
| 3819 | * https://forum.proxmox.com/threads/problems-with-pcie-passthrough-with-two-identical-devices.149003/ | ||
| 3820 | */ | ||
| 3821 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1164, quirk_no_bus_reset); | ||
| 3822 | |||
| 3795 | static void quirk_no_pm_reset(struct pci_dev *dev) | 3823 | static void quirk_no_pm_reset(struct pci_dev *dev) |
| 3796 | { | 3824 | { |
| 3797 | /* | 3825 | /* |
| @@ -4470,6 +4498,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, 0x9000, · 672 unmodified lines | |||
| 4470 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, 0x9084, | 4498 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, 0x9084, |
| 4471 | quirk_bridge_cavm_thrx2_pcie_root); | 4499 | quirk_bridge_cavm_thrx2_pcie_root); |
| 4472 | 4500 | ||
| 4501 | /* | ||
| 4502 | * AST1150 doesn't use a real PCI bus and always forwards the requester ID | ||
| 4503 | * from downstream devices. | ||
| 4504 | */ | ||
| 4505 | static void quirk_aspeed_pci_bridge_no_alias(struct pci_dev *pdev) | ||
| 4506 | { | ||
| 4507 | pdev->dev_flags |= PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS; | ||
| 4508 | } | ||
| 4509 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASPEED, 0x1150, quirk_aspeed_pci_bridge_no_alias); | ||
| 4510 | |||
| 4473 | /* | 4511 | /* |
| 4474 | * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) | 4512 | * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) |
| 4475 | * class code. Fix it. | 4513 | * class code. Fix it. |
| @@ -5124,6 +5162,10 @@ static const struct pci_dev_acs_enabled { · 648 unmodified lines | |||
| 5124 | { PCI_VENDOR_ID_QCOM, 0x0401, pci_quirk_qcom_rp_acs }, | 5162 | { PCI_VENDOR_ID_QCOM, 0x0401, pci_quirk_qcom_rp_acs }, |
| 5125 | /* QCOM SA8775P root port */ | 5163 | /* QCOM SA8775P root port */ |
| 5126 | { PCI_VENDOR_ID_QCOM, 0x0115, pci_quirk_qcom_rp_acs }, | 5164 | { PCI_VENDOR_ID_QCOM, 0x0115, pci_quirk_qcom_rp_acs }, |
| 5165 | /* QCOM Hamoa root port */ | ||
| 5166 | { PCI_VENDOR_ID_QCOM, 0x0111, pci_quirk_qcom_rp_acs }, | ||
| 5167 | /* QCOM Glymur root port */ | ||
| 5168 | { PCI_VENDOR_ID_QCOM, 0x0120, pci_quirk_qcom_rp_acs }, | ||
| 5127 | /* HXT SD4800 root ports. The ACS design is same as QCOM QDF2xxx */ | 5169 | /* HXT SD4800 root ports. The ACS design is same as QCOM QDF2xxx */ |
| 5128 | { PCI_VENDOR_ID_HXT, 0x0401, pci_quirk_qcom_rp_acs }, | 5170 | { PCI_VENDOR_ID_HXT, 0x0401, pci_quirk_qcom_rp_acs }, |
| 5129 | /* Intel PCH root ports */ | 5171 | /* Intel PCH root ports */ |
| @@ -5598,6 +5640,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) · 468 unmodified lines | |||
| 5598 | pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); | 5640 | pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); |
| 5599 | } | 5641 | } |
| 5600 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); | 5642 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); |
| 5643 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1005, quirk_no_ext_tags); | ||
| 5601 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); | 5644 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); |
| 5602 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); | 5645 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); |
| 5603 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); | 5646 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); |
| @@ -5796,7 +5839,7 @@ DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, · 192 unmodified lines | |||
| 5796 | 5839 | ||
| 5797 | /* | 5840 | /* |
| 5798 | * Some IDT switches incorrectly flag an ACS Source Validation error on | 5841 | * Some IDT switches incorrectly flag an ACS Source Validation error on |
| 5799 | * completions for config read requests even though PCIe r4.0, sec | 5842 | * completions for config read requests even though PCIe r7.0, sec |
| 5800 | * 6.12.1.1, says that completions are never affected by ACS Source | 5843 | * 6.12.1.1, says that completions are never affected by ACS Source |
| 5801 | * Validation. Here's the text of IDT 89H32H8G3-YC, erratum #36: | 5844 | * Validation. Here's the text of IDT 89H32H8G3-YC, erratum #36: |
| 5802 | * | 5845 | * |
| @@ -5809,44 +5852,20 @@ DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, · 6 unmodified lines | |||
| 5809 | * | 5852 | * |
| 5810 | * The workaround suggested by IDT is to issue a config write to the | 5853 | * The workaround suggested by IDT is to issue a config write to the |
| 5811 | * downstream device before issuing the first config read. This allows the | 5854 | * downstream device before issuing the first config read. This allows the |
| 5812 | * downstream device to capture its bus and device numbers (see PCIe r4.0, | 5855 | * downstream device to capture its bus and device numbers (see PCIe r7.0, |
| 5813 | * sec 2.2.9), thus avoiding the ACS error on the completion. | 5856 | * sec 2.2.9.1), thus avoiding the ACS error on the completion. |
| 5814 | * | 5857 | * |
| 5815 | * However, we don't know when the device is ready to accept the config | 5858 | * However, we don't know when the device is ready to accept the config |
| 5816 | * write, so we do config reads until we receive a non-Config Request Retry | 5859 | * write, and the issue affects resets of the switch as well as enumeration, |
| 5817 | * Status, then do the config write. | 5860 | * so disable use of ACS SV for these devices altogether. |
| 5818 | * | ||
| 5819 | * To avoid hitting the erratum when doing the config reads, we disable ACS | ||
| 5820 | * SV around this process. | ||
| 5821 | */ | 5861 | */ |
| 5822 | int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout) | 5862 | void pci_disable_broken_acs_cap(struct pci_dev *pdev) |
| 5823 | { | 5863 | { |
| 5824 | int pos; | 5864 | if (pdev->vendor == PCI_VENDOR_ID_IDT && |
| 5825 | u16 ctrl = 0; | 5865 | (pdev->device == 0x80b5 || pdev->device == 0x8090)) { |
| 5826 | bool found; | 5866 | pci_info(pdev, "Disabling broken ACS SV; downstream device isolation reduced\n"); |
| 5827 | struct pci_dev *bridge = bus->self; | 5867 | pdev->acs_capabilities &= ~PCI_ACS_SV; |
| 5828 | |||
| 5829 | pos = bridge->acs_cap; | ||
| 5830 | |||
| 5831 | /* Disable ACS SV before initial config reads */ | ||
| 5832 | if (pos) { | ||
| 5833 | pci_read_config_word(bridge, pos + PCI_ACS_CTRL, &ctrl); | ||
| 5834 | if (ctrl & PCI_ACS_SV) | ||
| 5835 | pci_write_config_word(bridge, pos + PCI_ACS_CTRL, | ||
| 5836 | ctrl & ~PCI_ACS_SV); | ||
| 5837 | } | 5868 | } |
| 5838 | |||
| 5839 | found = pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout); | ||
| 5840 | |||
| 5841 | /* Write Vendor ID (read-only) so the endpoint latches its bus/dev */ | ||
| 5842 | if (found) | ||
| 5843 | pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0); | ||
| 5844 | |||
| 5845 | /* Re-enable ACS_SV if it was previously enabled */ | ||
| 5846 | if (ctrl & PCI_ACS_SV) | ||
| 5847 | pci_write_config_word(bridge, pos + PCI_ACS_CTRL, ctrl); | ||
| 5848 | |||
| 5849 | return found; | ||
| 5850 | } | 5869 | } |
| 5851 | 5870 | ||
| 5852 | /* | 5871 | /* |
| @@ -6205,6 +6224,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303, · 352 unmodified lines | |||
| 6205 | pci_fixup_pericom_acs_store_forward); | 6224 | pci_fixup_pericom_acs_store_forward); |
| 6206 | DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, | 6225 | DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303, |
| 6207 | pci_fixup_pericom_acs_store_forward); | 6226 | pci_fixup_pericom_acs_store_forward); |
| 6227 | DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404, | ||
| 6228 | pci_fixup_pericom_acs_store_forward); | ||
| 6229 | DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404, | ||
| 6230 | pci_fixup_pericom_acs_store_forward); | ||
| 6208 | 6231 | ||
| 6209 | static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) | 6232 | static void nvidia_ion_ahci_fixup(struct pci_dev *pdev) |
| 6210 | { | 6233 | { |
| @@ -17,25 +17,6 @@ static void pci_free_resources(struct pci_dev *dev) · 16 unmodified lines | |||
| 17 | } | 17 | } |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | static void pci_pwrctrl_unregister(struct device *dev) | ||
| 21 | { | ||
| 22 | struct device_node *np; | ||
| 23 | struct platform_device *pdev; | ||
| 24 | |||
| 25 | np = dev_of_node(dev); | ||
| 26 | if (!np) | ||
| 27 | return; | ||
| 28 | |||
| 29 | pdev = of_find_device_by_node(np); | ||
| 30 | if (!pdev) | ||
| 31 | return; | ||
| 32 | |||
| 33 | of_device_unregister(pdev); | ||
| 34 | put_device(&pdev->dev); | ||
| 35 | |||
| 36 | of_node_clear_flag(np, OF_POPULATED); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void pci_stop_dev(struct pci_dev *dev) | 20 | static void pci_stop_dev(struct pci_dev *dev) |
| 40 | { | 21 | { |
| 41 | pci_pme_active(dev, false); | 22 | pci_pme_active(dev, false); |
| @@ -73,7 +54,6 @@ static void pci_destroy_dev(struct pci_dev *dev) · 31 unmodified lines | |||
| 73 | pci_ide_destroy(dev); | 54 | pci_ide_destroy(dev); |
| 74 | pcie_aspm_exit_link_state(dev); | 55 | pcie_aspm_exit_link_state(dev); |
| 75 | pci_bridge_d3_update(dev); | 56 | pci_bridge_d3_update(dev); |
| 76 | pci_pwrctrl_unregister(&dev->dev); | ||
| 77 | pci_free_resources(dev); | 57 | pci_free_resources(dev); |
| 78 | put_device(&dev->dev); | 58 | put_device(&dev->dev); |
| 79 | } | 59 | } |
| @@ -86,6 +86,8 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, · 85 unmodified lines | |||
| 86 | case PCI_EXP_TYPE_DOWNSTREAM: | 86 | case PCI_EXP_TYPE_DOWNSTREAM: |
| 87 | continue; | 87 | continue; |
| 88 | case PCI_EXP_TYPE_PCI_BRIDGE: | 88 | case PCI_EXP_TYPE_PCI_BRIDGE: |
| 89 | if (tmp->dev_flags & PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS) | ||
| 90 | continue; | ||
| 89 | ret = fn(tmp, | 91 | ret = fn(tmp, |
| 90 | PCI_DEVID(tmp->subordinate->number, | 92 | PCI_DEVID(tmp->subordinate->number, |
| 91 | PCI_DEVFN(0, 0)), data); | 93 | PCI_DEVFN(0, 0)), data); |
| @@ -14,10 +14,12 @@ · 13 unmodified lines | |||
| 14 | * tighter packing. Prefetchable range support. | 14 | * tighter packing. Prefetchable range support. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/align.h> | ||
| 17 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
| 18 | #include <linux/bug.h> | 19 | #include <linux/bug.h> |
| 19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/minmax.h> | ||
| 21 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 22 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
| 23 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
| @@ -47,7 +49,7 @@ struct pci_dev_resource { · 23 unmodified lines | |||
| 47 | unsigned long flags; | 49 | unsigned long flags; |
| 48 | }; | 50 | }; |
| 49 | 51 | ||
| 50 | static void free_list(struct list_head *head) | 52 | static void pci_dev_res_free_list(struct list_head *head) |
| 51 | { | 53 | { |
| 52 | struct pci_dev_resource *dev_res, *tmp; | 54 | struct pci_dev_resource *dev_res, *tmp; |
| 53 | 55 | ||
| @@ -58,16 +60,16 @@ static void free_list(struct list_head *head) · 4 unmodified lines | |||
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | /** | 62 | /** |
| 61 | * add_to_list() - Add a new resource tracker to the list | 63 | * pci_dev_res_add_to_list() - Add a new resource tracker to the list |
| 62 | * @head: Head of the list | 64 | * @head: Head of the list |
| 63 | * @dev: Device to which the resource belongs | 65 | * @dev: Device to which the resource belongs |
| 64 | * @res: Resource to be tracked | 66 | * @res: Resource to be tracked |
| 65 | * @add_size: Additional size to be optionally added to the resource | 67 | * @add_size: Additional size to be optionally added to the resource |
| 66 | * @min_align: Minimum memory window alignment | 68 | * @min_align: Minimum memory window alignment |
| 67 | */ | 69 | */ |
| 68 | static int add_to_list(struct list_head *head, struct pci_dev *dev, | 70 | int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev, |
| 69 | struct resource *res, resource_size_t add_size, | 71 | struct resource *res, resource_size_t add_size, |
| 70 | resource_size_t min_align) | 72 | resource_size_t min_align) |
| 71 | { | 73 | { |
| 72 | struct pci_dev_resource *tmp; | 74 | struct pci_dev_resource *tmp; |
| 73 | 75 | ||
| @@ -88,7 +90,8 @@ static int add_to_list(struct list_head *head, struct pci_dev *dev, · 14 unmodified lines | |||
| 88 | return 0; | 90 | return 0; |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | static void remove_from_list(struct list_head *head, struct resource *res) | 93 | static void pci_dev_res_remove_from_list(struct list_head *head, |
| 94 | struct resource *res) | ||
| 92 | { | 95 | { |
| 93 | struct pci_dev_resource *dev_res, *tmp; | 96 | struct pci_dev_resource *dev_res, *tmp; |
| 94 | 97 | ||
| @@ -123,25 +126,21 @@ static resource_size_t get_res_add_size(struct list_head *head, · 28 unmodified lines | |||
| 123 | return dev_res ? dev_res->add_size : 0; | 126 | return dev_res ? dev_res->add_size : 0; |
| 124 | } | 127 | } |
| 125 | 128 | ||
| 126 | static resource_size_t get_res_add_align(struct list_head *head, | 129 | static void pci_dev_res_restore(struct pci_dev_resource *dev_res) |
| 127 | struct resource *res) | ||
| 128 | { | ||
| 129 | struct pci_dev_resource *dev_res; | ||
| 130 | |||
| 131 | dev_res = res_to_dev_res(head, res); | ||
| 132 | return dev_res ? dev_res->min_align : 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static void restore_dev_resource(struct pci_dev_resource *dev_res) | ||
| 136 | { | 130 | { |
| 137 | struct resource *res = dev_res->res; | 131 | struct resource *res = dev_res->res; |
| 132 | struct pci_dev *dev = dev_res->dev; | ||
| 133 | int idx = pci_resource_num(dev, res); | ||
| 134 | const char *res_name = pci_resource_name(dev, idx); | ||
| 138 | 135 | ||
| 139 | if (WARN_ON_ONCE(res->parent)) | 136 | if (WARN_ON_ONCE(resource_assigned(res))) |
| 140 | return; | 137 | return; |
| 141 | 138 | ||
| 142 | res->start = dev_res->start; | 139 | res->start = dev_res->start; |
| 143 | res->end = dev_res->end; | 140 | res->end = dev_res->end; |
| 144 | res->flags = dev_res->flags; | 141 | res->flags = dev_res->flags; |
| 142 | |||
| 143 | pci_dbg(dev, "%s %pR: resource restored\n", res_name, res); | ||
| 145 | } | 144 | } |
| 146 | 145 | ||
| 147 | /* | 146 | /* |
| @@ -168,7 +167,7 @@ static struct resource *find_bus_resource_of_type(struct pci_bus *bus, · 20 unmodified lines | |||
| 168 | if ((r->flags & type_mask) != type) | 167 | if ((r->flags & type_mask) != type) |
| 169 | continue; | 168 | continue; |
| 170 | 169 | ||
| 171 | if (!r->parent) | 170 | if (!resource_assigned(r)) |
| 172 | return r; | 171 | return r; |
| 173 | if (!r_assigned) | 172 | if (!r_assigned) |
| 174 | r_assigned = r; | 173 | r_assigned = r; |
| @@ -271,7 +270,7 @@ static struct resource *pbus_select_window_for_type(struct pci_bus *bus, · 96 unmodified lines | |||
| 271 | struct resource *pbus_select_window(struct pci_bus *bus, | 270 | struct resource *pbus_select_window(struct pci_bus *bus, |
| 272 | const struct resource *res) | 271 | const struct resource *res) |
| 273 | { | 272 | { |
| 274 | if (res->parent) | 273 | if (resource_assigned(res)) |
| 275 | return res->parent; | 274 | return res->parent; |
| 276 | 275 | ||
| 277 | return pbus_select_window_for_type(bus, res->flags); | 276 | return pbus_select_window_for_type(bus, res->flags); |
| @@ -302,8 +301,7 @@ static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res) · 24 unmodified lines | |||
| 302 | if (!res->flags) | 301 | if (!res->flags) |
| 303 | return false; | 302 | return false; |
| 304 | 303 | ||
| 305 | if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END && | 304 | if (pci_resource_is_bridge_win(idx) && res->flags & IORESOURCE_DISABLED) |
| 306 | res->flags & IORESOURCE_DISABLED) | ||
| 307 | return false; | 305 | return false; |
| 308 | 306 | ||
| 309 | return true; | 307 | return true; |
| @@ -311,7 +309,7 @@ static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res) · 1 unmodified line | |||
| 311 | 309 | ||
| 312 | static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res) | 310 | static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res) |
| 313 | { | 311 | { |
| 314 | if (res->parent) | 312 | if (resource_assigned(res)) |
| 315 | return false; | 313 | return false; |
| 316 | 314 | ||
| 317 | if (res->flags & IORESOURCE_PCI_FIXED) | 315 | if (res->flags & IORESOURCE_PCI_FIXED) |
| @@ -380,19 +378,24 @@ bool pci_resource_is_optional(const struct pci_dev *dev, int resno) · 62 unmodified lines | |||
| 380 | return true; | 378 | return true; |
| 381 | if (resno == PCI_ROM_RESOURCE && !(res->flags & IORESOURCE_ROM_ENABLE)) | 379 | if (resno == PCI_ROM_RESOURCE && !(res->flags & IORESOURCE_ROM_ENABLE)) |
| 382 | return true; | 380 | return true; |
| 381 | if (pci_resource_is_bridge_win(resno) && !resource_size(res)) | ||
| 382 | return true; | ||
| 383 | 383 | ||
| 384 | return false; | 384 | return false; |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | static inline void reset_resource(struct pci_dev *dev, struct resource *res) | 387 | static void reset_resource(struct pci_dev *dev, struct resource *res) |
| 388 | { | 388 | { |
| 389 | int idx = pci_resource_num(dev, res); | 389 | int idx = pci_resource_num(dev, res); |
| 390 | const char *res_name = pci_resource_name(dev, idx); | ||
| 390 | 391 | ||
| 391 | if (idx >= PCI_BRIDGE_RESOURCES && idx <= PCI_BRIDGE_RESOURCE_END) { | 392 | if (pci_resource_is_bridge_win(idx)) { |
| 392 | res->flags |= IORESOURCE_UNSET; | 393 | res->flags |= IORESOURCE_UNSET; |
| 393 | return; | 394 | return; |
| 394 | } | 395 | } |
| 395 | 396 | ||
| 397 | pci_dbg(dev, "%s %pR: resetting resource\n", res_name, res); | ||
| 398 | |||
| 396 | res->start = 0; | 399 | res->start = 0; |
| 397 | res->end = 0; | 400 | res->end = 0; |
| 398 | res->flags = 0; | 401 | res->flags = 0; |
| @@ -413,7 +416,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, · 14 unmodified lines | |||
| 413 | struct list_head *head) | 416 | struct list_head *head) |
| 414 | { | 417 | { |
| 415 | struct pci_dev_resource *add_res, *tmp; | 418 | struct pci_dev_resource *add_res, *tmp; |
| 416 | struct pci_dev_resource *dev_res; | ||
| 417 | struct pci_dev *dev; | 419 | struct pci_dev *dev; |
| 418 | struct resource *res; | 420 | struct resource *res; |
| 419 | const char *res_name; | 421 | const char *res_name; |
| @@ -421,8 +423,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, · 1 unmodified line | |||
| 421 | int idx; | 423 | int idx; |
| 422 | 424 | ||
| 423 | list_for_each_entry_safe(add_res, tmp, realloc_head, list) { | 425 | list_for_each_entry_safe(add_res, tmp, realloc_head, list) { |
| 424 | bool found_match = false; | ||
| 425 | |||
| 426 | res = add_res->res; | 426 | res = add_res->res; |
| 427 | dev = add_res->dev; | 427 | dev = add_res->dev; |
| 428 | idx = pci_resource_num(dev, res); | 428 | idx = pci_resource_num(dev, res); |
| @@ -431,24 +431,18 @@ static void reassign_resources_sorted(struct list_head *realloc_head, · 2 unmodified lines | |||
| 431 | * Skip resource that failed the earlier assignment and is | 431 | * Skip resource that failed the earlier assignment and is |
| 432 | * not optional as it would just fail again. | 432 | * not optional as it would just fail again. |
| 433 | */ | 433 | */ |
| 434 | if (!res->parent && resource_size(res) && | 434 | if (!resource_assigned(res) && resource_size(res) && |
| 435 | !pci_resource_is_optional(dev, idx)) | 435 | !pci_resource_is_optional(dev, idx)) |
| 436 | goto out; | 436 | goto out; |
| 437 | 437 | ||
| 438 | /* Skip this resource if not found in head list */ | 438 | /* Skip this resource if not found in head list */ |
| 439 | list_for_each_entry(dev_res, head, list) { | 439 | if (!res_to_dev_res(head, res)) |
| 440 | if (dev_res->res == res) { | ||
| 441 | found_match = true; | ||
| 442 | break; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | if (!found_match) /* Just skip */ | ||
| 446 | continue; | 440 | continue; |
| 447 | 441 | ||
| 448 | res_name = pci_resource_name(dev, idx); | 442 | res_name = pci_resource_name(dev, idx); |
| 449 | add_size = add_res->add_size; | 443 | add_size = add_res->add_size; |
| 450 | align = add_res->min_align; | 444 | align = add_res->min_align; |
| 451 | if (!res->parent) { | 445 | if (!resource_assigned(res)) { |
| 452 | resource_set_range(res, align, | 446 | resource_set_range(res, align, |
| 453 | resource_size(res) + add_size); | 447 | resource_size(res) + add_size); |
| 454 | if (pci_assign_resource(dev, idx)) { | 448 | if (pci_assign_resource(dev, idx)) { |
| @@ -456,7 +450,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head, · 1 unmodified line | |||
| 456 | "%s %pR: ignoring failure in optional allocation\n", | 450 | "%s %pR: ignoring failure in optional allocation\n", |
| 457 | res_name, res); | 451 | res_name, res); |
| 458 | } | 452 | } |
| 459 | } else if (add_size > 0) { | 453 | } else if (add_size > 0 || !IS_ALIGNED(res->start, align)) { |
| 460 | res->flags |= add_res->flags & | 454 | res->flags |= add_res->flags & |
| 461 | (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); | 455 | (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); |
| 462 | if (pci_reassign_resource(dev, idx, add_size, align)) | 456 | if (pci_reassign_resource(dev, idx, add_size, align)) |
| @@ -505,9 +499,9 @@ static void assign_requested_resources_sorted(struct list_head *head, · 42 unmodified lines | |||
| 505 | 499 | ||
| 506 | if (pci_assign_resource(dev, idx)) { | 500 | if (pci_assign_resource(dev, idx)) { |
| 507 | if (fail_head) { | 501 | if (fail_head) { |
| 508 | add_to_list(fail_head, dev, res, | 502 | pci_dev_res_add_to_list(fail_head, dev, res, |
| 509 | 0 /* don't care */, | 503 | 0 /* don't care */, |
| 510 | 0 /* don't care */); | 504 | 0 /* don't care */); |
| 511 | } | 505 | } |
| 512 | } | 506 | } |
| 513 | } | 507 | } |
| @@ -604,11 +598,11 @@ static void __assign_resources_sorted(struct list_head *head, · 90 unmodified lines | |||
| 604 | LIST_HEAD(local_fail_head); | 598 | LIST_HEAD(local_fail_head); |
| 605 | LIST_HEAD(dummy_head); | 599 | LIST_HEAD(dummy_head); |
| 606 | struct pci_dev_resource *save_res; | 600 | struct pci_dev_resource *save_res; |
| 607 | struct pci_dev_resource *dev_res, *tmp_res, *dev_res2; | 601 | struct pci_dev_resource *dev_res, *tmp_res, *dev_res2, *addsize_res; |
| 608 | struct resource *res; | 602 | struct resource *res; |
| 609 | struct pci_dev *dev; | 603 | struct pci_dev *dev; |
| 610 | unsigned long fail_type; | 604 | unsigned long fail_type; |
| 611 | resource_size_t add_align, align; | 605 | resource_size_t align; |
| 612 | 606 | ||
| 613 | if (!realloc_head) | 607 | if (!realloc_head) |
| 614 | realloc_head = &dummy_head; | 608 | realloc_head = &dummy_head; |
| @@ -619,8 +613,9 @@ static void __assign_resources_sorted(struct list_head *head, · 4 unmodified lines | |||
| 619 | 613 | ||
| 620 | /* Save original start, end, flags etc at first */ | 614 | /* Save original start, end, flags etc at first */ |
| 621 | list_for_each_entry(dev_res, head, list) { | 615 | list_for_each_entry(dev_res, head, list) { |
| 622 | if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) { | 616 | if (pci_dev_res_add_to_list(&save_head, dev_res->dev, |
| 623 | free_list(&save_head); | 617 | dev_res->res, 0, 0)) { |
| 618 | pci_dev_res_free_list(&save_head); | ||
| 624 | goto assign; | 619 | goto assign; |
| 625 | } | 620 | } |
| 626 | } | 621 | } |
| @@ -629,8 +624,11 @@ static void __assign_resources_sorted(struct list_head *head, · 2 unmodified lines | |||
| 629 | list_for_each_entry_safe(dev_res, tmp_res, head, list) { | 624 | list_for_each_entry_safe(dev_res, tmp_res, head, list) { |
| 630 | res = dev_res->res; | 625 | res = dev_res->res; |
| 631 | 626 | ||
| 632 | res->end += get_res_add_size(realloc_head, res); | 627 | addsize_res = res_to_dev_res(realloc_head, res); |
| 628 | if (!addsize_res) | ||
| 629 | continue; | ||
| 633 | 630 | ||
| 631 | res->end += addsize_res->add_size; | ||
| 634 | /* | 632 | /* |
| 635 | * There are two kinds of additional resources in the list: | 633 | * There are two kinds of additional resources in the list: |
| 636 | * 1. bridge resource -- IORESOURCE_STARTALIGN | 634 | * 1. bridge resource -- IORESOURCE_STARTALIGN |
| @@ -640,8 +638,8 @@ static void __assign_resources_sorted(struct list_head *head, · 3 unmodified lines | |||
| 640 | if (!(res->flags & IORESOURCE_STARTALIGN)) | 638 | if (!(res->flags & IORESOURCE_STARTALIGN)) |
| 641 | continue; | 639 | continue; |
| 642 | 640 | ||
| 643 | add_align = get_res_add_align(realloc_head, res); | 641 | if (addsize_res->min_align <= res->start) |
| 644 | 642 | continue; | |
| 645 | /* | 643 | /* |
| 646 | * The "head" list is sorted by alignment so resources with | 644 | * The "head" list is sorted by alignment so resources with |
| 647 | * bigger alignment will be assigned first. After we | 645 | * bigger alignment will be assigned first. After we |
| @@ -649,17 +647,15 @@ static void __assign_resources_sorted(struct list_head *head, · 1 unmodified line | |||
| 649 | * need to reorder the list by alignment to make it | 647 | * need to reorder the list by alignment to make it |
| 650 | * consistent. | 648 | * consistent. |
| 651 | */ | 649 | */ |
| 652 | if (add_align > res->start) { | 650 | resource_set_range(res, addsize_res->min_align, |
| 653 | resource_set_range(res, add_align, resource_size(res)); | 651 | resource_size(res)); |
| 654 | 652 | ||
| 655 | list_for_each_entry(dev_res2, head, list) { | 653 | list_for_each_entry(dev_res2, head, list) { |
| 656 | align = pci_resource_alignment(dev_res2->dev, | 654 | align = pci_resource_alignment(dev_res2->dev, |
| 657 | dev_res2->res); | 655 | dev_res2->res); |
| 658 | if (add_align > align) { | 656 | if (addsize_res->min_align > align) { |
| 659 | list_move_tail(&dev_res->list, | 657 | list_move_tail(&dev_res->list, &dev_res2->list); |
| 660 | &dev_res2->list); | 658 | break; |
| 661 | break; | ||
| 662 | } | ||
| 663 | } | 659 | } |
| 664 | } | 660 | } |
| 665 | 661 | ||
| @@ -672,8 +668,9 @@ assign: · 6 unmodified lines | |||
| 672 | if (list_empty(&local_fail_head)) { | 668 | if (list_empty(&local_fail_head)) { |
| 673 | /* Remove head list from realloc_head list */ | 669 | /* Remove head list from realloc_head list */ |
| 674 | list_for_each_entry(dev_res, head, list) | 670 | list_for_each_entry(dev_res, head, list) |
| 675 | remove_from_list(realloc_head, dev_res->res); | 671 | pci_dev_res_remove_from_list(realloc_head, |
| 676 | free_list(&save_head); | 672 | dev_res->res); |
| 673 | pci_dev_res_free_list(&save_head); | ||
| 677 | goto out; | 674 | goto out; |
| 678 | } | 675 | } |
| 679 | 676 | ||
| @@ -683,13 +680,13 @@ assign: · 3 unmodified lines | |||
| 683 | list_for_each_entry(save_res, &save_head, list) { | 680 | list_for_each_entry(save_res, &save_head, list) { |
| 684 | struct resource *res = save_res->res; | 681 | struct resource *res = save_res->res; |
| 685 | 682 | ||
| 686 | if (res->parent) | 683 | if (resource_assigned(res)) |
| 687 | continue; | 684 | continue; |
| 688 | 685 | ||
| 689 | restore_dev_resource(save_res); | 686 | pci_dev_res_restore(save_res); |
| 690 | } | 687 | } |
| 691 | free_list(&local_fail_head); | 688 | pci_dev_res_free_list(&local_fail_head); |
| 692 | free_list(&save_head); | 689 | pci_dev_res_free_list(&save_head); |
| 693 | goto out; | 690 | goto out; |
| 694 | } | 691 | } |
| 695 | 692 | ||
| @@ -699,28 +696,29 @@ assign: · 3 unmodified lines | |||
| 699 | list_for_each_entry_safe(dev_res, tmp_res, head, list) { | 696 | list_for_each_entry_safe(dev_res, tmp_res, head, list) { |
| 700 | res = dev_res->res; | 697 | res = dev_res->res; |
| 701 | 698 | ||
| 702 | if (res->parent && !pci_need_to_release(fail_type, res)) { | 699 | if (resource_assigned(res) && |
| 700 | !pci_need_to_release(fail_type, res)) { | ||
| 703 | /* Remove it from realloc_head list */ | 701 | /* Remove it from realloc_head list */ |
| 704 | remove_from_list(realloc_head, res); | 702 | pci_dev_res_remove_from_list(realloc_head, res); |
| 705 | remove_from_list(&save_head, res); | 703 | pci_dev_res_remove_from_list(&save_head, res); |
| 706 | list_del(&dev_res->list); | 704 | list_del(&dev_res->list); |
| 707 | kfree(dev_res); | 705 | kfree(dev_res); |
| 708 | } | 706 | } |
| 709 | } | 707 | } |
| 710 | 708 | ||
| 711 | free_list(&local_fail_head); | 709 | pci_dev_res_free_list(&local_fail_head); |
| 712 | /* Release assigned resource */ | 710 | /* Release assigned resource */ |
| 713 | list_for_each_entry(dev_res, head, list) { | 711 | list_for_each_entry(dev_res, head, list) { |
| 714 | res = dev_res->res; | 712 | res = dev_res->res; |
| 715 | dev = dev_res->dev; | 713 | dev = dev_res->dev; |
| 716 | 714 | ||
| 717 | pci_release_resource(dev, pci_resource_num(dev, res)); | 715 | pci_release_resource(dev, pci_resource_num(dev, res)); |
| 718 | restore_dev_resource(dev_res); | 716 | pci_dev_res_restore(dev_res); |
| 719 | } | 717 | } |
| 720 | /* Restore start/end/flags from saved list */ | 718 | /* Restore start/end/flags from saved list */ |
| 721 | list_for_each_entry(save_res, &save_head, list) | 719 | list_for_each_entry(save_res, &save_head, list) |
| 722 | restore_dev_resource(save_res); | 720 | pci_dev_res_restore(save_res); |
| 723 | free_list(&save_head); | 721 | pci_dev_res_free_list(&save_head); |
| 724 | 722 | ||
| 725 | /* Satisfy the must-have resource requests */ | 723 | /* Satisfy the must-have resource requests */ |
| 726 | assign_requested_resources_sorted(head, NULL, false); | 724 | assign_requested_resources_sorted(head, NULL, false); |
| @@ -735,19 +733,19 @@ out: · 8 unmodified lines | |||
| 735 | res = dev_res->res; | 733 | res = dev_res->res; |
| 736 | dev = dev_res->dev; | 734 | dev = dev_res->dev; |
| 737 | 735 | ||
| 738 | if (res->parent) | 736 | if (resource_assigned(res)) |
| 739 | continue; | 737 | continue; |
| 740 | 738 | ||
| 741 | if (fail_head) { | 739 | if (fail_head) { |
| 742 | add_to_list(fail_head, dev, res, | 740 | pci_dev_res_add_to_list(fail_head, dev, res, |
| 743 | 0 /* don't care */, | 741 | 0 /* don't care */, |
| 744 | 0 /* don't care */); | 742 | 0 /* don't care */); |
| 745 | } | 743 | } |
| 746 | 744 | ||
| 747 | reset_resource(dev, res); | 745 | reset_resource(dev, res); |
| 748 | } | 746 | } |
| 749 | 747 | ||
| 750 | free_list(head); | 748 | pci_dev_res_free_list(head); |
| 751 | } | 749 | } |
| 752 | 750 | ||
| 753 | static void pdev_assign_resources_sorted(struct pci_dev *dev, | 751 | static void pdev_assign_resources_sorted(struct pci_dev *dev, |
| @@ -774,61 +772,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, · 20 unmodified lines | |||
| 774 | __assign_resources_sorted(&head, realloc_head, fail_head); | 772 | __assign_resources_sorted(&head, realloc_head, fail_head); |
| 775 | } | 773 | } |
| 776 | 774 | ||
| 777 | void pci_setup_cardbus(struct pci_bus *bus) | ||
| 778 | { | ||
| 779 | struct pci_dev *bridge = bus->self; | ||
| 780 | struct resource *res; | ||
| 781 | struct pci_bus_region region; | ||
| 782 | |||
| 783 | pci_info(bridge, "CardBus bridge to %pR\n", | ||
| 784 | &bus->busn_res); | ||
| 785 | |||
| 786 | res = bus->resource[0]; | ||
| 787 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 788 | if (res->parent && res->flags & IORESOURCE_IO) { | ||
| 789 | /* | ||
| 790 | * The IO resource is allocated a range twice as large as it | ||
| 791 | * would normally need. This allows us to set both IO regs. | ||
| 792 | */ | ||
| 793 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 794 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, | ||
| 795 | region.start); | ||
| 796 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, | ||
| 797 | region.end); | ||
| 798 | } | ||
| 799 | |||
| 800 | res = bus->resource[1]; | ||
| 801 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 802 | if (res->parent && res->flags & IORESOURCE_IO) { | ||
| 803 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 804 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, | ||
| 805 | region.start); | ||
| 806 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, | ||
| 807 | region.end); | ||
| 808 | } | ||
| 809 | |||
| 810 | res = bus->resource[2]; | ||
| 811 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 812 | if (res->parent && res->flags & IORESOURCE_MEM) { | ||
| 813 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 814 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, | ||
| 815 | region.start); | ||
| 816 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, | ||
| 817 | region.end); | ||
| 818 | } | ||
| 819 | |||
| 820 | res = bus->resource[3]; | ||
| 821 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 822 | if (res->parent && res->flags & IORESOURCE_MEM) { | ||
| 823 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 824 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, | ||
| 825 | region.start); | ||
| 826 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, | ||
| 827 | region.end); | ||
| 828 | } | ||
| 829 | } | ||
| 830 | EXPORT_SYMBOL(pci_setup_cardbus); | ||
| 831 | |||
| 832 | /* | 775 | /* |
| 833 | * Initialize bridges with base/limit values we have collected. PCI-to-PCI | 776 | * Initialize bridges with base/limit values we have collected. PCI-to-PCI |
| 834 | * Bridge Architecture Specification rev. 1.1 (1998) requires that if there | 777 | * Bridge Architecture Specification rev. 1.1 (1998) requires that if there |
| @@ -860,7 +803,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) · 25 unmodified lines | |||
| 860 | res = &bridge->resource[PCI_BRIDGE_IO_WINDOW]; | 803 | res = &bridge->resource[PCI_BRIDGE_IO_WINDOW]; |
| 861 | res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW); | 804 | res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW); |
| 862 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 805 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 863 | if (res->parent && res->flags & IORESOURCE_IO) { | 806 | if (resource_assigned(res) && res->flags & IORESOURCE_IO) { |
| 864 | pci_read_config_word(bridge, PCI_IO_BASE, &l); | 807 | pci_read_config_word(bridge, PCI_IO_BASE, &l); |
| 865 | io_base_lo = (region.start >> 8) & io_mask; | 808 | io_base_lo = (region.start >> 8) & io_mask; |
| 866 | io_limit_lo = (region.end >> 8) & io_mask; | 809 | io_limit_lo = (region.end >> 8) & io_mask; |
| @@ -892,7 +835,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge) · 25 unmodified lines | |||
| 892 | res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW]; | 835 | res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW]; |
| 893 | res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW); | 836 | res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW); |
| 894 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 837 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 895 | if (res->parent && res->flags & IORESOURCE_MEM) { | 838 | if (resource_assigned(res) && res->flags & IORESOURCE_MEM) { |
| 896 | l = (region.start >> 16) & 0xfff0; | 839 | l = (region.start >> 16) & 0xfff0; |
| 897 | l |= region.end & 0xfff00000; | 840 | l |= region.end & 0xfff00000; |
| 898 | pci_info(bridge, " %s %pR\n", res_name, res); | 841 | pci_info(bridge, " %s %pR\n", res_name, res); |
| @@ -921,7 +864,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) · 22 unmodified lines | |||
| 921 | res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; | 864 | res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; |
| 922 | res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW); | 865 | res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW); |
| 923 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | 866 | pcibios_resource_to_bus(bridge->bus, ®ion, res); |
| 924 | if (res->parent && res->flags & IORESOURCE_PREFETCH) { | 867 | if (resource_assigned(res) && res->flags & IORESOURCE_PREFETCH) { |
| 925 | l = (region.start >> 16) & 0xfff0; | 868 | l = (region.start >> 16) & 0xfff0; |
| 926 | l |= region.end & 0xfff00000; | 869 | l |= region.end & 0xfff00000; |
| 927 | if (res->flags & IORESOURCE_MEM_64) { | 870 | if (res->flags & IORESOURCE_MEM_64) { |
| @@ -992,7 +935,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) · 64 unmodified lines | |||
| 992 | { | 935 | { |
| 993 | int ret = -EINVAL; | 936 | int ret = -EINVAL; |
| 994 | 937 | ||
| 995 | if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END) | 938 | if (!pci_resource_is_bridge_win(i)) |
| 996 | return 0; | 939 | return 0; |
| 997 | 940 | ||
| 998 | if (pci_claim_resource(bridge, i) == 0) | 941 | if (pci_claim_resource(bridge, i) == 0) |
| @@ -1068,18 +1011,11 @@ static resource_size_t calculate_iosize(resource_size_t size, · 69 unmodified lines | |||
| 1068 | 1011 | ||
| 1069 | static resource_size_t calculate_memsize(resource_size_t size, | 1012 | static resource_size_t calculate_memsize(resource_size_t size, |
| 1070 | resource_size_t min_size, | 1013 | resource_size_t min_size, |
| 1071 | resource_size_t add_size, | ||
| 1072 | resource_size_t children_add_size, | 1014 | resource_size_t children_add_size, |
| 1073 | resource_size_t old_size, | ||
| 1074 | resource_size_t align) | 1015 | resource_size_t align) |
| 1075 | { | 1016 | { |
| 1076 | if (size < min_size) | 1017 | size = max(size, min_size) + children_add_size; |
| 1077 | size = min_size; | 1018 | return ALIGN(size, align); |
| 1078 | if (old_size == 1) | ||
| 1079 | old_size = 0; | ||
| 1080 | |||
| 1081 | size = max(size, add_size) + children_add_size; | ||
| 1082 | return ALIGN(max(size, old_size), align); | ||
| 1083 | } | 1019 | } |
| 1084 | 1020 | ||
| 1085 | resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, | 1021 | resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, |
| @@ -1117,8 +1053,7 @@ static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type) · 31 unmodified lines | |||
| 1117 | * pbus_size_io() - Size the I/O window of a given bus | 1053 | * pbus_size_io() - Size the I/O window of a given bus |
| 1118 | * | 1054 | * |
| 1119 | * @bus: The bus | 1055 | * @bus: The bus |
| 1120 | * @min_size: The minimum I/O window that must be allocated | 1056 | * @add_size: Additional I/O window |
| 1121 | * @add_size: Additional optional I/O window | ||
| 1122 | * @realloc_head: Track the additional I/O window on this list | 1057 | * @realloc_head: Track the additional I/O window on this list |
| 1123 | * | 1058 | * |
| 1124 | * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these | 1059 | * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these |
| @@ -1126,8 +1061,7 @@ static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type) · 1 unmodified line | |||
| 1126 | * devices are limited to 256 bytes. We must be careful with the ISA | 1061 | * devices are limited to 256 bytes. We must be careful with the ISA |
| 1127 | * aliasing though. | 1062 | * aliasing though. |
| 1128 | */ | 1063 | */ |
| 1129 | static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | 1064 | static void pbus_size_io(struct pci_bus *bus, resource_size_t add_size, |
| 1130 | resource_size_t add_size, | ||
| 1131 | struct list_head *realloc_head) | 1065 | struct list_head *realloc_head) |
| 1132 | { | 1066 | { |
| 1133 | struct pci_dev *dev; | 1067 | struct pci_dev *dev; |
| @@ -1140,7 +1074,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, · 6 unmodified lines | |||
| 1140 | return; | 1074 | return; |
| 1141 | 1075 | ||
| 1142 | /* If resource is already assigned, nothing more to do */ | 1076 | /* If resource is already assigned, nothing more to do */ |
| 1143 | if (b_res->parent) | 1077 | if (resource_assigned(b_res)) |
| 1144 | return; | 1078 | return; |
| 1145 | 1079 | ||
| 1146 | min_align = window_alignment(bus, IORESOURCE_IO); | 1080 | min_align = window_alignment(bus, IORESOURCE_IO); |
| @@ -1150,7 +1084,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, · 3 unmodified lines | |||
| 1150 | pci_dev_for_each_resource(dev, r) { | 1084 | pci_dev_for_each_resource(dev, r) { |
| 1151 | unsigned long r_size; | 1085 | unsigned long r_size; |
| 1152 | 1086 | ||
| 1153 | if (r->parent || !(r->flags & IORESOURCE_IO)) | 1087 | if (resource_assigned(r) || !(r->flags & IORESOURCE_IO)) |
| 1154 | continue; | 1088 | continue; |
| 1155 | 1089 | ||
| 1156 | if (!pdev_resource_assignable(dev, r)) | 1090 | if (!pdev_resource_assignable(dev, r)) |
| @@ -1172,7 +1106,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, · 15 unmodified lines | |||
| 1172 | } | 1106 | } |
| 1173 | } | 1107 | } |
| 1174 | 1108 | ||
| 1175 | size0 = calculate_iosize(size, min_size, size1, 0, 0, | 1109 | size0 = calculate_iosize(size, realloc_head ? 0 : add_size, size1, 0, 0, |
| 1176 | resource_size(b_res), min_align); | 1110 | resource_size(b_res), min_align); |
| 1177 | 1111 | ||
| 1178 | if (size0) | 1112 | if (size0) |
| @@ -1180,7 +1114,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, · 1 unmodified line | |||
| 1180 | 1114 | ||
| 1181 | size1 = size0; | 1115 | size1 = size0; |
| 1182 | if (realloc_head && (add_size > 0 || children_add_size > 0)) { | 1116 | if (realloc_head && (add_size > 0 || children_add_size > 0)) { |
| 1183 | size1 = calculate_iosize(size, min_size, size1, add_size, | 1117 | size1 = calculate_iosize(size, 0, size1, add_size, |
| 1184 | children_add_size, resource_size(b_res), | 1118 | children_add_size, resource_size(b_res), |
| 1185 | min_align); | 1119 | min_align); |
| 1186 | } | 1120 | } |
| @@ -1197,8 +1131,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, · 10 unmodified lines | |||
| 1197 | b_res->flags |= IORESOURCE_STARTALIGN; | 1131 | b_res->flags |= IORESOURCE_STARTALIGN; |
| 1198 | if (bus->self && size1 > size0 && realloc_head) { | 1132 | if (bus->self && size1 > size0 && realloc_head) { |
| 1199 | b_res->flags &= ~IORESOURCE_DISABLED; | 1133 | b_res->flags &= ~IORESOURCE_DISABLED; |
| 1200 | add_to_list(realloc_head, bus->self, b_res, size1-size0, | 1134 | pci_dev_res_add_to_list(realloc_head, bus->self, b_res, |
| 1201 | min_align); | 1135 | size1 - size0, min_align); |
| 1202 | pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n", | 1136 | pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n", |
| 1203 | b_res, &bus->busn_res, | 1137 | b_res, &bus->busn_res, |
| 1204 | (unsigned long long) size1 - size0); | 1138 | (unsigned long long) size1 - size0); |
| @@ -1227,65 +1161,90 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, · 22 unmodified lines | |||
| 1227 | return min_align; | 1161 | return min_align; |
| 1228 | } | 1162 | } |
| 1229 | 1163 | ||
| 1230 | /** | 1164 | /* |
| 1231 | * pbus_upstream_space_available - Check no upstream resource limits allocation | 1165 | * Calculate bridge window head alignment that leaves no gaps in between |
| 1232 | * @bus: The bus | ||
| 1233 | * @res: The resource to help select the correct bridge window | ||
| 1234 | * @size: The size required from the bridge window | ||
| 1235 | * @align: Required alignment for the resource | ||
| 1236 | * | ||
| 1237 | * Check that @size can fit inside the upstream bridge resources that are | ||
| 1238 | * already assigned. Select the upstream bridge window based on the type of | ||
| 1239 | * @res. | ||
| 1240 | * | ||
| 1241 | * Return: %true if enough space is available on all assigned upstream | ||
| 1242 | * resources. | 1166 | * resources. |
| 1243 | */ | 1167 | */ |
| 1244 | static bool pbus_upstream_space_available(struct pci_bus *bus, | 1168 | static resource_size_t calculate_head_align(resource_size_t *aligns, |
| 1245 | struct resource *res, | 1169 | int max_order) |
| 1246 | resource_size_t size, | 1170 | { |
| 1247 | resource_size_t align) | 1171 | resource_size_t head_align = 1; |
| 1248 | { | 1172 | resource_size_t remainder = 0; |
| 1249 | struct resource_constraint constraint = { | 1173 | int order; |
| 1250 | .max = RESOURCE_SIZE_MAX, | ||
| 1251 | .align = align, | ||
| 1252 | }; | ||
| 1253 | struct pci_bus *downstream = bus; | ||
| 1254 | |||
| 1255 | while ((bus = bus->parent)) { | ||
| 1256 | if (pci_is_root_bus(bus)) | ||
| 1257 | break; | ||
| 1258 | 1174 | ||
| 1259 | res = pbus_select_window(bus, res); | 1175 | /* Take the largest alignment as the starting point. */ |
| 1260 | if (!res) | 1176 | head_align <<= max_order + __ffs(SZ_1M); |
| 1261 | return false; | ||
| 1262 | if (!res->parent) | ||
| 1263 | continue; | ||
| 1264 | 1177 | ||
| 1265 | if (resource_size(res) >= size) { | 1178 | for (order = max_order - 1; order >= 0; order--) { |
| 1266 | struct resource gap = {}; | 1179 | resource_size_t align1 = 1; |
| 1267 | 1180 | ||
| 1268 | if (find_resource_space(res, &gap, size, &constraint) == 0) { | 1181 | align1 <<= order + __ffs(SZ_1M); |
| 1269 | gap.flags = res->flags; | 1182 | |
| 1270 | pci_dbg(bus->self, | 1183 | /* |
| 1271 | "Assigned bridge window %pR to %pR free space at %pR\n", | 1184 | * Account smaller resources with alignment < max_order that |
| 1272 | res, &bus->busn_res, &gap); | 1185 | * could be used to fill head room if alignment less than |
| 1273 | return true; | 1186 | * max_order is used. |
| 1274 | } | 1187 | */ |
| 1188 | remainder += aligns[order]; | ||
| 1189 | |||
| 1190 | /* | ||
| 1191 | * Test if head fill is enough to satisfy the alignment of | ||
| 1192 | * the larger resources after reducing the alignment. | ||
| 1193 | */ | ||
| 1194 | while ((head_align > align1) && (remainder >= head_align / 2)) { | ||
| 1195 | head_align /= 2; | ||
| 1196 | remainder -= head_align; | ||
| 1275 | } | 1197 | } |
| 1198 | } | ||
| 1199 | |||
| 1200 | return head_align; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | /* | ||
| 1204 | * pbus_size_mem_optional - Account optional resources in bridge window | ||
| 1205 | * | ||
| 1206 | * Account an optional resource or the optional part of the resource in bridge | ||
| 1207 | * window size. | ||
| 1208 | * | ||
| 1209 | * Return: %true if the resource is entirely optional. | ||
| 1210 | */ | ||
| 1211 | static bool pbus_size_mem_optional(struct pci_dev *dev, int resno, | ||
| 1212 | resource_size_t align, | ||
| 1213 | struct list_head *realloc_head, | ||
| 1214 | resource_size_t *add_align, | ||
| 1215 | resource_size_t *children_add_size) | ||
| 1216 | { | ||
| 1217 | struct resource *res = pci_resource_n(dev, resno); | ||
| 1218 | bool optional = pci_resource_is_optional(dev, resno); | ||
| 1219 | resource_size_t r_size = resource_size(res); | ||
| 1220 | struct pci_dev_resource *dev_res; | ||
| 1276 | 1221 | ||
| 1277 | if (bus->self) { | 1222 | if (!realloc_head) |
| 1278 | pci_info(bus->self, | 1223 | return false; |
| 1279 | "Assigned bridge window %pR to %pR cannot fit 0x%llx required for %s bridging to %pR\n", | 1224 | |
| 1280 | res, &bus->busn_res, | 1225 | if (!optional) { |
| 1281 | (unsigned long long)size, | 1226 | /* |
| 1282 | pci_name(downstream->self), | 1227 | * Only bridges have optional sizes in realloc_head at this |
| 1283 | &downstream->busn_res); | 1228 | * point. As res_to_dev_res() walks the entire realloc_head |
| 1229 | * list, skip calling it when known unnecessary. | ||
| 1230 | */ | ||
| 1231 | if (!pci_resource_is_bridge_win(resno)) | ||
| 1232 | return false; | ||
| 1233 | |||
| 1234 | dev_res = res_to_dev_res(realloc_head, res); | ||
| 1235 | if (dev_res) { | ||
| 1236 | *children_add_size += dev_res->add_size; | ||
| 1237 | *add_align = max(*add_align, dev_res->min_align); | ||
| 1284 | } | 1238 | } |
| 1285 | 1239 | ||
| 1286 | return false; | 1240 | return false; |
| 1287 | } | 1241 | } |
| 1288 | 1242 | ||
| 1243 | /* Put SRIOV requested res to the optional list */ | ||
| 1244 | pci_dev_res_add_to_list(realloc_head, dev, res, 0, align); | ||
| 1245 | *children_add_size += r_size; | ||
| 1246 | *add_align = max(align, *add_align); | ||
| 1247 | |||
| 1289 | return true; | 1248 | return true; |
| 1290 | } | 1249 | } |
| 1291 | 1250 | ||
| @@ -1293,12 +1252,11 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, · 1 unmodified line | |||
| 1293 | * pbus_size_mem() - Size the memory window of a given bus | 1252 | * pbus_size_mem() - Size the memory window of a given bus |
| 1294 | * | 1253 | * |
| 1295 | * @bus: The bus | 1254 | * @bus: The bus |
| 1296 | * @type: The type of bridge resource | 1255 | * @b_res: The bridge window resource |
| 1297 | * @min_size: The minimum memory window that must be allocated | 1256 | * @add_size: Additional memory window |
| 1298 | * @add_size: Additional optional memory window | ||
| 1299 | * @realloc_head: Track the additional memory window on this list | 1257 | * @realloc_head: Track the additional memory window on this list |
| 1300 | * | 1258 | * |
| 1301 | * Calculate the size of the bus resource for @type and minimal alignment | 1259 | * Calculate the size of the bridge window @b_res and minimal alignment |
| 1302 | * which guarantees that all child resources fit in this size. | 1260 | * which guarantees that all child resources fit in this size. |
| 1303 | * | 1261 | * |
| 1304 | * Set the bus resource start/end to indicate the required size if there an | 1262 | * Set the bus resource start/end to indicate the required size if there an |
| @@ -1307,30 +1265,24 @@ static bool pbus_upstream_space_available(struct pci_bus *bus, · 2 unmodified lines | |||
| 1307 | * Add optional resource requests to the @realloc_head list if it is | 1265 | * Add optional resource requests to the @realloc_head list if it is |
| 1308 | * supplied. | 1266 | * supplied. |
| 1309 | */ | 1267 | */ |
| 1310 | static void pbus_size_mem(struct pci_bus *bus, unsigned long type, | 1268 | static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res, |
| 1311 | resource_size_t min_size, | 1269 | resource_size_t add_size, |
| 1312 | resource_size_t add_size, | 1270 | struct list_head *realloc_head) |
| 1313 | struct list_head *realloc_head) | ||
| 1314 | { | 1271 | { |
| 1315 | struct pci_dev *dev; | 1272 | struct pci_dev *dev; |
| 1316 | resource_size_t min_align, win_align, align, size, size0, size1 = 0; | 1273 | resource_size_t min_align, win_align, align, size, size0, size1 = 0; |
| 1317 | resource_size_t aligns[28]; /* Alignments from 1MB to 128TB */ | 1274 | resource_size_t aligns[28] = {}; /* Alignments from 1MB to 128TB */ |
| 1318 | int order, max_order; | 1275 | int order, max_order; |
| 1319 | struct resource *b_res = pbus_select_window_for_type(bus, type); | ||
| 1320 | resource_size_t children_add_size = 0; | 1276 | resource_size_t children_add_size = 0; |
| 1321 | resource_size_t children_add_align = 0; | ||
| 1322 | resource_size_t add_align = 0; | 1277 | resource_size_t add_align = 0; |
| 1323 | resource_size_t relaxed_align; | ||
| 1324 | resource_size_t old_size; | ||
| 1325 | 1278 | ||
| 1326 | if (!b_res) | 1279 | if (!b_res) |
| 1327 | return; | 1280 | return; |
| 1328 | 1281 | ||
| 1329 | /* If resource is already assigned, nothing more to do */ | 1282 | /* If resource is already assigned, nothing more to do */ |
| 1330 | if (b_res->parent) | 1283 | if (resource_assigned(b_res)) |
| 1331 | return; | 1284 | return; |
| 1332 | 1285 | ||
| 1333 | memset(aligns, 0, sizeof(aligns)); | ||
| 1334 | max_order = 0; | 1286 | max_order = 0; |
| 1335 | size = 0; | 1287 | size = 0; |
| 1336 | 1288 | ||
| @@ -1348,88 +1300,50 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, · 11 unmodified lines | |||
| 1348 | if (b_res != pbus_select_window(bus, r)) | 1300 | if (b_res != pbus_select_window(bus, r)) |
| 1349 | continue; | 1301 | continue; |
| 1350 | 1302 | ||
| 1351 | r_size = resource_size(r); | 1303 | align = pci_resource_alignment(dev, r); |
| 1352 | |||
| 1353 | /* Put SRIOV requested res to the optional list */ | ||
| 1354 | if (realloc_head && pci_resource_is_optional(dev, i)) { | ||
| 1355 | add_align = max(pci_resource_alignment(dev, r), add_align); | ||
| 1356 | add_to_list(realloc_head, dev, r, 0, 0 /* Don't care */); | ||
| 1357 | children_add_size += r_size; | ||
| 1358 | continue; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | /* | 1304 | /* |
| 1362 | * aligns[0] is for 1MB (since bridge memory | 1305 | * aligns[0] is for 1MB (since bridge memory |
| 1363 | * windows are always at least 1MB aligned), so | 1306 | * windows are always at least 1MB aligned), so |
| 1364 | * keep "order" from being negative for smaller | 1307 | * keep "order" from being negative for smaller |
| 1365 | * resources. | 1308 | * resources. |
| 1366 | */ | 1309 | */ |
| 1367 | align = pci_resource_alignment(dev, r); | 1310 | order = max_t(int, __ffs(align) - __ffs(SZ_1M), 0); |
| 1368 | order = __ffs(align) - __ffs(SZ_1M); | ||
| 1369 | if (order < 0) | ||
| 1370 | order = 0; | ||
| 1371 | if (order >= ARRAY_SIZE(aligns)) { | 1311 | if (order >= ARRAY_SIZE(aligns)) { |
| 1372 | pci_warn(dev, "%s %pR: disabling; bad alignment %#llx\n", | 1312 | pci_warn(dev, "%s %pR: disabling; bad alignment %#llx\n", |
| 1373 | r_name, r, (unsigned long long) align); | 1313 | r_name, r, (unsigned long long) align); |
| 1374 | r->flags = 0; | 1314 | r->flags = 0; |
| 1375 | continue; | 1315 | continue; |
| 1376 | } | 1316 | } |
| 1317 | |||
| 1318 | if (pbus_size_mem_optional(dev, i, align, | ||
| 1319 | realloc_head, &add_align, | ||
| 1320 | &children_add_size)) | ||
| 1321 | continue; | ||
| 1322 | |||
| 1323 | r_size = resource_size(r); | ||
| 1377 | size += max(r_size, align); | 1324 | size += max(r_size, align); |
| 1378 | /* | 1325 | |
| 1379 | * Exclude ranges with size > align from calculation of | 1326 | aligns[order] += align; |
| 1380 | * the alignment. | ||
| 1381 | */ | ||
| 1382 | if (r_size <= align) | ||
| 1383 | aligns[order] += align; | ||
| 1384 | if (order > max_order) | 1327 | if (order > max_order) |
| 1385 | max_order = order; | 1328 | max_order = order; |
| 1386 | |||
| 1387 | if (realloc_head) { | ||
| 1388 | children_add_size += get_res_add_size(realloc_head, r); | ||
| 1389 | children_add_align = get_res_add_align(realloc_head, r); | ||
| 1390 | add_align = max(add_align, children_add_align); | ||
| 1391 | } | ||
| 1392 | } | 1329 | } |
| 1393 | } | 1330 | } |
| 1394 | 1331 | ||
| 1395 | old_size = resource_size(b_res); | ||
| 1396 | win_align = window_alignment(bus, b_res->flags); | 1332 | win_align = window_alignment(bus, b_res->flags); |
| 1397 | min_align = calculate_mem_align(aligns, max_order); | 1333 | min_align = calculate_head_align(aligns, max_order); |
| 1398 | min_align = max(min_align, win_align); | 1334 | min_align = max(min_align, win_align); |
| 1399 | size0 = calculate_memsize(size, min_size, 0, 0, old_size, min_align); | 1335 | size0 = calculate_memsize(size, realloc_head ? 0 : add_size, |
| 1336 | 0, win_align); | ||
| 1400 | 1337 | ||
| 1401 | if (size0) { | 1338 | if (size0) { |
| 1402 | resource_set_range(b_res, min_align, size0); | 1339 | resource_set_range(b_res, min_align, size0); |
| 1403 | b_res->flags &= ~IORESOURCE_DISABLED; | 1340 | b_res->flags &= ~IORESOURCE_DISABLED; |
| 1404 | } | 1341 | } |
| 1405 | 1342 | ||
| 1406 | if (bus->self && size0 && | ||
| 1407 | !pbus_upstream_space_available(bus, b_res, size0, min_align)) { | ||
| 1408 | relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); | ||
| 1409 | relaxed_align = max(relaxed_align, win_align); | ||
| 1410 | min_align = min(min_align, relaxed_align); | ||
| 1411 | size0 = calculate_memsize(size, min_size, 0, 0, old_size, win_align); | ||
| 1412 | resource_set_range(b_res, min_align, size0); | ||
| 1413 | pci_info(bus->self, "bridge window %pR to %pR requires relaxed alignment rules\n", | ||
| 1414 | b_res, &bus->busn_res); | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | if (realloc_head && (add_size > 0 || children_add_size > 0)) { | 1343 | if (realloc_head && (add_size > 0 || children_add_size > 0)) { |
| 1418 | add_align = max(min_align, add_align); | 1344 | add_align = max(min_align, add_align); |
| 1419 | size1 = calculate_memsize(size, min_size, add_size, children_add_size, | 1345 | size1 = calculate_memsize(size, add_size, children_add_size, |
| 1420 | old_size, add_align); | 1346 | win_align); |
| 1421 | |||
| 1422 | if (bus->self && size1 && | ||
| 1423 | !pbus_upstream_space_available(bus, b_res, size1, add_align)) { | ||
| 1424 | relaxed_align = 1ULL << (max_order + __ffs(SZ_1M)); | ||
| 1425 | relaxed_align = max(relaxed_align, win_align); | ||
| 1426 | min_align = min(min_align, relaxed_align); | ||
| 1427 | size1 = calculate_memsize(size, min_size, add_size, children_add_size, | ||
| 1428 | old_size, win_align); | ||
| 1429 | pci_info(bus->self, | ||
| 1430 | "bridge window %pR to %pR requires relaxed alignment rules\n", | ||
| 1431 | b_res, &bus->busn_res); | ||
| 1432 | } | ||
| 1433 | } | 1347 | } |
| 1434 | 1348 | ||
| 1435 | if (!size0 && !size1) { | 1349 | if (!size0 && !size1) { |
| @@ -1442,121 +1356,24 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, · 6 unmodified lines | |||
| 1442 | 1356 | ||
| 1443 | resource_set_range(b_res, min_align, size0); | 1357 | resource_set_range(b_res, min_align, size0); |
| 1444 | b_res->flags |= IORESOURCE_STARTALIGN; | 1358 | b_res->flags |= IORESOURCE_STARTALIGN; |
| 1445 | if (bus->self && size1 > size0 && realloc_head) { | 1359 | if (bus->self && realloc_head && (size1 > size0 || add_align > min_align)) { |
| 1446 | b_res->flags &= ~IORESOURCE_DISABLED; | 1360 | b_res->flags &= ~IORESOURCE_DISABLED; |
| 1447 | add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align); | 1361 | add_size = size1 > size0 ? size1 - size0 : 0; |
| 1362 | pci_dev_res_add_to_list(realloc_head, bus->self, b_res, | ||
| 1363 | add_size, add_align); | ||
| 1448 | pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n", | 1364 | pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n", |
| 1449 | b_res, &bus->busn_res, | 1365 | b_res, &bus->busn_res, |
| 1450 | (unsigned long long) (size1 - size0), | 1366 | (unsigned long long) add_size, |
| 1451 | (unsigned long long) add_align); | 1367 | (unsigned long long) add_align); |
| 1452 | } | 1368 | } |
| 1453 | } | 1369 | } |
| 1454 | 1370 | ||
| 1455 | unsigned long pci_cardbus_resource_alignment(struct resource *res) | ||
| 1456 | { | ||
| 1457 | if (res->flags & IORESOURCE_IO) | ||
| 1458 | return pci_cardbus_io_size; | ||
| 1459 | if (res->flags & IORESOURCE_MEM) | ||
| 1460 | return pci_cardbus_mem_size; | ||
| 1461 | return 0; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | static void pci_bus_size_cardbus(struct pci_bus *bus, | ||
| 1465 | struct list_head *realloc_head) | ||
| 1466 | { | ||
| 1467 | struct pci_dev *bridge = bus->self; | ||
| 1468 | struct resource *b_res; | ||
| 1469 | resource_size_t b_res_3_size = pci_cardbus_mem_size * 2; | ||
| 1470 | u16 ctrl; | ||
| 1471 | |||
| 1472 | b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW]; | ||
| 1473 | if (b_res->parent) | ||
| 1474 | goto handle_b_res_1; | ||
| 1475 | /* | ||
| 1476 | * Reserve some resources for CardBus. We reserve a fixed amount | ||
| 1477 | * of bus space for CardBus bridges. | ||
| 1478 | */ | ||
| 1479 | resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); | ||
| 1480 | b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | ||
| 1481 | if (realloc_head) { | ||
| 1482 | b_res->end -= pci_cardbus_io_size; | ||
| 1483 | add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, | ||
| 1484 | pci_cardbus_io_size); | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | handle_b_res_1: | ||
| 1488 | b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW]; | ||
| 1489 | if (b_res->parent) | ||
| 1490 | goto handle_b_res_2; | ||
| 1491 | resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); | ||
| 1492 | b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | ||
| 1493 | if (realloc_head) { | ||
| 1494 | b_res->end -= pci_cardbus_io_size; | ||
| 1495 | add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, | ||
| 1496 | pci_cardbus_io_size); | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | handle_b_res_2: | ||
| 1500 | /* MEM1 must not be pref MMIO */ | ||
| 1501 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 1502 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) { | ||
| 1503 | ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; | ||
| 1504 | pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); | ||
| 1505 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | /* Check whether prefetchable memory is supported by this bridge. */ | ||
| 1509 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 1510 | if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) { | ||
| 1511 | ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; | ||
| 1512 | pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); | ||
| 1513 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW]; | ||
| 1517 | if (b_res->parent) | ||
| 1518 | goto handle_b_res_3; | ||
| 1519 | /* | ||
| 1520 | * If we have prefetchable memory support, allocate two regions. | ||
| 1521 | * Otherwise, allocate one region of twice the size. | ||
| 1522 | */ | ||
| 1523 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { | ||
| 1524 | resource_set_range(b_res, pci_cardbus_mem_size, | ||
| 1525 | pci_cardbus_mem_size); | ||
| 1526 | b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | | ||
| 1527 | IORESOURCE_STARTALIGN; | ||
| 1528 | if (realloc_head) { | ||
| 1529 | b_res->end -= pci_cardbus_mem_size; | ||
| 1530 | add_to_list(realloc_head, bridge, b_res, | ||
| 1531 | pci_cardbus_mem_size, pci_cardbus_mem_size); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | /* Reduce that to half */ | ||
| 1535 | b_res_3_size = pci_cardbus_mem_size; | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | handle_b_res_3: | ||
| 1539 | b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW]; | ||
| 1540 | if (b_res->parent) | ||
| 1541 | goto handle_done; | ||
| 1542 | resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size); | ||
| 1543 | b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN; | ||
| 1544 | if (realloc_head) { | ||
| 1545 | b_res->end -= b_res_3_size; | ||
| 1546 | add_to_list(realloc_head, bridge, b_res, b_res_3_size, | ||
| 1547 | pci_cardbus_mem_size); | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | handle_done: | ||
| 1551 | ; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) | 1371 | void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) |
| 1555 | { | 1372 | { |
| 1556 | struct pci_dev *dev; | 1373 | struct pci_dev *dev; |
| 1557 | resource_size_t additional_io_size = 0, additional_mmio_size = 0, | 1374 | resource_size_t additional_io_size = 0, additional_mmio_size = 0, |
| 1558 | additional_mmio_pref_size = 0; | 1375 | additional_mmio_pref_size = 0; |
| 1559 | struct resource *pref; | 1376 | struct resource *b_res; |
| 1560 | struct pci_host_bridge *host; | 1377 | struct pci_host_bridge *host; |
| 1561 | int hdr_type; | 1378 | int hdr_type; |
| 1562 | 1379 | ||
| @@ -1567,7 +1384,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) · 4 unmodified lines | |||
| 1567 | 1384 | ||
| 1568 | switch (dev->hdr_type) { | 1385 | switch (dev->hdr_type) { |
| 1569 | case PCI_HEADER_TYPE_CARDBUS: | 1386 | case PCI_HEADER_TYPE_CARDBUS: |
| 1570 | pci_bus_size_cardbus(b, realloc_head); | 1387 | if (pci_bus_size_cardbus_bridge(b, realloc_head)) |
| 1388 | continue; | ||
| 1571 | break; | 1389 | break; |
| 1572 | 1390 | ||
| 1573 | case PCI_HEADER_TYPE_BRIDGE: | 1391 | case PCI_HEADER_TYPE_BRIDGE: |
| @@ -1582,12 +1400,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) · 8 unmodified lines | |||
| 1582 | host = to_pci_host_bridge(bus->bridge); | 1400 | host = to_pci_host_bridge(bus->bridge); |
| 1583 | if (!host->size_windows) | 1401 | if (!host->size_windows) |
| 1584 | return; | 1402 | return; |
| 1585 | pci_bus_for_each_resource(bus, pref) | ||
| 1586 | if (pref && (pref->flags & IORESOURCE_PREFETCH)) | ||
| 1587 | break; | ||
| 1588 | hdr_type = -1; /* Intentionally invalid - not a PCI device. */ | 1403 | hdr_type = -1; /* Intentionally invalid - not a PCI device. */ |
| 1589 | } else { | 1404 | } else { |
| 1590 | pref = &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; | ||
| 1591 | hdr_type = bus->self->hdr_type; | 1405 | hdr_type = bus->self->hdr_type; |
| 1592 | } | 1406 | } |
| 1593 | 1407 | ||
| @@ -1605,20 +1419,21 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) · 11 unmodified lines | |||
| 1605 | } | 1419 | } |
| 1606 | fallthrough; | 1420 | fallthrough; |
| 1607 | default: | 1421 | default: |
| 1608 | pbus_size_io(bus, realloc_head ? 0 : additional_io_size, | 1422 | pbus_size_io(bus, additional_io_size, realloc_head); |
| 1609 | additional_io_size, realloc_head); | 1423 | |
| 1610 | 1424 | b_res = pbus_select_window_for_type(bus, IORESOURCE_MEM | | |
| 1611 | if (pref && (pref->flags & IORESOURCE_PREFETCH)) { | 1425 | IORESOURCE_PREFETCH | |
| 1612 | pbus_size_mem(bus, | 1426 | IORESOURCE_MEM_64); |
| 1613 | IORESOURCE_MEM | IORESOURCE_PREFETCH | | 1427 | if (b_res && (b_res->flags & IORESOURCE_PREFETCH)) { |
| 1614 | (pref->flags & IORESOURCE_MEM_64), | 1428 | pbus_size_mem(bus, b_res, additional_mmio_pref_size, |
| 1615 | realloc_head ? 0 : additional_mmio_pref_size, | 1429 | realloc_head); |
| 1616 | additional_mmio_pref_size, realloc_head); | ||
| 1617 | } | 1430 | } |
| 1618 | 1431 | ||
| 1619 | pbus_size_mem(bus, IORESOURCE_MEM, | 1432 | b_res = pbus_select_window_for_type(bus, IORESOURCE_MEM); |
| 1620 | realloc_head ? 0 : additional_mmio_size, | 1433 | if (b_res) { |
| 1621 | additional_mmio_size, realloc_head); | 1434 | pbus_size_mem(bus, b_res, additional_mmio_size, |
| 1435 | realloc_head); | ||
| 1436 | } | ||
| 1622 | break; | 1437 | break; |
| 1623 | } | 1438 | } |
| 1624 | } | 1439 | } |
| @@ -1656,12 +1471,13 @@ static void pdev_assign_fixed_resources(struct pci_dev *dev) · 31 unmodified lines | |||
| 1656 | pci_dev_for_each_resource(dev, r) { | 1471 | pci_dev_for_each_resource(dev, r) { |
| 1657 | struct pci_bus *b; | 1472 | struct pci_bus *b; |
| 1658 | 1473 | ||
| 1659 | if (r->parent || !(r->flags & IORESOURCE_PCI_FIXED) || | 1474 | if (resource_assigned(r) || |
| 1475 | !(r->flags & IORESOURCE_PCI_FIXED) || | ||
| 1660 | !(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) | 1476 | !(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) |
| 1661 | continue; | 1477 | continue; |
| 1662 | 1478 | ||
| 1663 | b = dev->bus; | 1479 | b = dev->bus; |
| 1664 | while (b && !r->parent) { | 1480 | while (b && !resource_assigned(r)) { |
| 1665 | assign_fixed_resource_on_bus(b, r); | 1481 | assign_fixed_resource_on_bus(b, r); |
| 1666 | b = b->parent; | 1482 | b = b->parent; |
| 1667 | } | 1483 | } |
| @@ -1693,7 +1509,7 @@ void __pci_bus_assign_resources(const struct pci_bus *bus, · 25 unmodified lines | |||
| 1693 | break; | 1509 | break; |
| 1694 | 1510 | ||
| 1695 | case PCI_HEADER_TYPE_CARDBUS: | 1511 | case PCI_HEADER_TYPE_CARDBUS: |
| 1696 | pci_setup_cardbus(b); | 1512 | pci_setup_cardbus_bridge(b); |
| 1697 | break; | 1513 | break; |
| 1698 | 1514 | ||
| 1699 | default: | 1515 | default: |
| @@ -1717,7 +1533,7 @@ static void pci_claim_device_resources(struct pci_dev *dev) · 17 unmodified lines | |||
| 1717 | for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { | 1533 | for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { |
| 1718 | struct resource *r = &dev->resource[i]; | 1534 | struct resource *r = &dev->resource[i]; |
| 1719 | 1535 | ||
| 1720 | if (!r->flags || r->parent) | 1536 | if (!r->flags || resource_assigned(r)) |
| 1721 | continue; | 1537 | continue; |
| 1722 | 1538 | ||
| 1723 | pci_claim_resource(dev, i); | 1539 | pci_claim_resource(dev, i); |
| @@ -1731,7 +1547,9 @@ static void pci_claim_bridge_resources(struct pci_dev *dev) · 7 unmodified lines | |||
| 1731 | for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { | 1547 | for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { |
| 1732 | struct resource *r = &dev->resource[i]; | 1548 | struct resource *r = &dev->resource[i]; |
| 1733 | 1549 | ||
| 1734 | if (!r->flags || r->parent) | 1550 | if (!r->flags || resource_assigned(r)) |
| 1551 | continue; | ||
| 1552 | if (r->flags & IORESOURCE_DISABLED) | ||
| 1735 | continue; | 1553 | continue; |
| 1736 | 1554 | ||
| 1737 | pci_claim_bridge_resource(dev, i); | 1555 | pci_claim_bridge_resource(dev, i); |
| @@ -1798,7 +1616,7 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge, · 60 unmodified lines | |||
| 1798 | break; | 1616 | break; |
| 1799 | 1617 | ||
| 1800 | case PCI_CLASS_BRIDGE_CARDBUS: | 1618 | case PCI_CLASS_BRIDGE_CARDBUS: |
| 1801 | pci_setup_cardbus(b); | 1619 | pci_setup_cardbus_bridge(b); |
| 1802 | break; | 1620 | break; |
| 1803 | 1621 | ||
| 1804 | default: | 1622 | default: |
| @@ -1814,7 +1632,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus, · 9 unmodified lines | |||
| 1814 | struct pci_dev *dev = bus->self; | 1632 | struct pci_dev *dev = bus->self; |
| 1815 | int idx, ret; | 1633 | int idx, ret; |
| 1816 | 1634 | ||
| 1817 | if (!b_win->parent) | 1635 | if (!resource_assigned(b_win)) |
| 1818 | return; | 1636 | return; |
| 1819 | 1637 | ||
| 1820 | idx = pci_resource_num(dev, b_win); | 1638 | idx = pci_resource_num(dev, b_win); |
| @@ -2010,7 +1828,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, · 189 unmodified lines | |||
| 2010 | { | 1828 | { |
| 2011 | resource_size_t add_size, size = resource_size(res); | 1829 | resource_size_t add_size, size = resource_size(res); |
| 2012 | 1830 | ||
| 2013 | if (res->parent) | 1831 | if (resource_assigned(res)) |
| 2014 | return; | 1832 | return; |
| 2015 | 1833 | ||
| 2016 | if (!new_size) | 1834 | if (!new_size) |
| @@ -2032,7 +1850,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, · 15 unmodified lines | |||
| 2032 | 1850 | ||
| 2033 | /* If the resource is part of the add_list, remove it now */ | 1851 | /* If the resource is part of the add_list, remove it now */ |
| 2034 | if (add_list) | 1852 | if (add_list) |
| 2035 | remove_from_list(add_list, res); | 1853 | pci_dev_res_remove_from_list(add_list, res); |
| 2036 | } | 1854 | } |
| 2037 | 1855 | ||
| 2038 | static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, | 1856 | static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, |
| @@ -2100,7 +1918,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, · 61 unmodified lines | |||
| 2100 | * window. | 1918 | * window. |
| 2101 | */ | 1919 | */ |
| 2102 | align = pci_resource_alignment(bridge, res); | 1920 | align = pci_resource_alignment(bridge, res); |
| 2103 | if (!res->parent && align) | 1921 | if (!resource_assigned(res) && align) |
| 2104 | available[i].start = min(ALIGN(available[i].start, align), | 1922 | available[i].start = min(ALIGN(available[i].start, align), |
| 2105 | available[i].end + 1); | 1923 | available[i].end + 1); |
| 2106 | 1924 | ||
| @@ -2284,9 +2102,9 @@ static void pci_prepare_next_assign_round(struct list_head *fail_head, · 177 unmodified lines | |||
| 2284 | 2102 | ||
| 2285 | /* Restore size and flags */ | 2103 | /* Restore size and flags */ |
| 2286 | list_for_each_entry(fail_res, fail_head, list) | 2104 | list_for_each_entry(fail_res, fail_head, list) |
| 2287 | restore_dev_resource(fail_res); | 2105 | pci_dev_res_restore(fail_res); |
| 2288 | 2106 | ||
| 2289 | free_list(fail_head); | 2107 | pci_dev_res_free_list(fail_head); |
| 2290 | } | 2108 | } |
| 2291 | 2109 | ||
| 2292 | /* | 2110 | /* |
| @@ -2333,7 +2151,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) · 40 unmodified lines | |||
| 2333 | /* Depth last, allocate resources and update the hardware. */ | 2151 | /* Depth last, allocate resources and update the hardware. */ |
| 2334 | __pci_bus_assign_resources(bus, add_list, &fail_head); | 2152 | __pci_bus_assign_resources(bus, add_list, &fail_head); |
| 2335 | if (WARN_ON_ONCE(add_list && !list_empty(add_list))) | 2153 | if (WARN_ON_ONCE(add_list && !list_empty(add_list))) |
| 2336 | free_list(add_list); | 2154 | pci_dev_res_free_list(add_list); |
| 2337 | tried_times++; | 2155 | tried_times++; |
| 2338 | 2156 | ||
| 2339 | /* Any device complain? */ | 2157 | /* Any device complain? */ |
| @@ -2348,7 +2166,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) · 8 unmodified lines | |||
| 2348 | dev_info(&bus->dev, | 2166 | dev_info(&bus->dev, |
| 2349 | "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); | 2167 | "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); |
| 2350 | } | 2168 | } |
| 2351 | free_list(&fail_head); | 2169 | pci_dev_res_free_list(&fail_head); |
| 2352 | break; | 2170 | break; |
| 2353 | } | 2171 | } |
| 2354 | 2172 | ||
| @@ -2396,7 +2214,7 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) · 41 unmodified lines | |||
| 2396 | 2214 | ||
| 2397 | __pci_bridge_assign_resources(bridge, &add_list, &fail_head); | 2215 | __pci_bridge_assign_resources(bridge, &add_list, &fail_head); |
| 2398 | if (WARN_ON_ONCE(!list_empty(&add_list))) | 2216 | if (WARN_ON_ONCE(!list_empty(&add_list))) |
| 2399 | free_list(&add_list); | 2217 | pci_dev_res_free_list(&add_list); |
| 2400 | tried_times++; | 2218 | tried_times++; |
| 2401 | 2219 | ||
| 2402 | if (list_empty(&fail_head)) | 2220 | if (list_empty(&fail_head)) |
| @@ -2404,7 +2222,7 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) · 1 unmodified line | |||
| 2404 | 2222 | ||
| 2405 | if (tried_times >= 2) { | 2223 | if (tried_times >= 2) { |
| 2406 | /* Still fail, don't need to try more */ | 2224 | /* Still fail, don't need to try more */ |
| 2407 | free_list(&fail_head); | 2225 | pci_dev_res_free_list(&fail_head); |
| 2408 | break; | 2226 | break; |
| 2409 | } | 2227 | } |
| 2410 | 2228 | ||
| @@ -2445,7 +2263,7 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource * · 34 unmodified lines | |||
| 2445 | 2263 | ||
| 2446 | /* Ignore BARs which are still in use */ | 2264 | /* Ignore BARs which are still in use */ |
| 2447 | if (!res->child) { | 2265 | if (!res->child) { |
| 2448 | ret = add_to_list(saved, bridge, res, 0, 0); | 2266 | ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0); |
| 2449 | if (ret) | 2267 | if (ret) |
| 2450 | return ret; | 2268 | return ret; |
| 2451 | 2269 | ||
| @@ -2467,12 +2285,12 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource * · 15 unmodified lines | |||
| 2467 | __pci_bus_size_bridges(bridge->subordinate, &added); | 2285 | __pci_bus_size_bridges(bridge->subordinate, &added); |
| 2468 | __pci_bridge_assign_resources(bridge, &added, &failed); | 2286 | __pci_bridge_assign_resources(bridge, &added, &failed); |
| 2469 | if (WARN_ON_ONCE(!list_empty(&added))) | 2287 | if (WARN_ON_ONCE(!list_empty(&added))) |
| 2470 | free_list(&added); | 2288 | pci_dev_res_free_list(&added); |
| 2471 | 2289 | ||
| 2472 | if (!list_empty(&failed)) { | 2290 | if (!list_empty(&failed)) { |
| 2473 | if (pci_required_resource_failed(&failed, type)) | 2291 | if (pci_required_resource_failed(&failed, type)) |
| 2474 | ret = -ENOSPC; | 2292 | ret = -ENOSPC; |
| 2475 | free_list(&failed); | 2293 | pci_dev_res_free_list(&failed); |
| 2476 | if (ret) | 2294 | if (ret) |
| 2477 | return ret; | 2295 | return ret; |
| 2478 | 2296 | ||
| @@ -2528,7 +2346,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size · 49 unmodified lines | |||
| 2528 | if (b_win != pbus_select_window(bus, r)) | 2346 | if (b_win != pbus_select_window(bus, r)) |
| 2529 | continue; | 2347 | continue; |
| 2530 | 2348 | ||
| 2531 | ret = add_to_list(&saved, pdev, r, 0, 0); | 2349 | ret = pci_dev_res_add_to_list(&saved, pdev, r, 0, 0); |
| 2532 | if (ret) | 2350 | if (ret) |
| 2533 | goto restore; | 2351 | goto restore; |
| 2534 | pci_release_resource(pdev, i); | 2352 | pci_release_resource(pdev, i); |
| @@ -2546,7 +2364,7 @@ int pci_do_resource_release_and_resize(struct pci_dev *pdev, int resno, int size · 11 unmodified lines | |||
| 2546 | 2364 | ||
| 2547 | out: | 2365 | out: |
| 2548 | up_read(&pci_bus_sem); | 2366 | up_read(&pci_bus_sem); |
| 2549 | free_list(&saved); | 2367 | pci_dev_res_free_list(&saved); |
| 2550 | return ret; | 2368 | return ret; |
| 2551 | 2369 | ||
| 2552 | restore: | 2370 | restore: |
| @@ -2565,12 +2383,12 @@ restore: · 12 unmodified lines | |||
| 2565 | 2383 | ||
| 2566 | i = pci_resource_num(dev, res); | 2384 | i = pci_resource_num(dev, res); |
| 2567 | 2385 | ||
| 2568 | if (res->parent) { | 2386 | if (resource_assigned(res)) { |
| 2569 | release_child_resources(res); | 2387 | release_child_resources(res); |
| 2570 | pci_release_resource(dev, i); | 2388 | pci_release_resource(dev, i); |
| 2571 | } | 2389 | } |
| 2572 | 2390 | ||
| 2573 | restore_dev_resource(dev_res); | 2391 | pci_dev_res_restore(dev_res); |
| 2574 | 2392 | ||
| 2575 | if (pci_claim_resource(dev, i)) | 2393 | if (pci_claim_resource(dev, i)) |
| 2576 | continue; | 2394 | continue; |
| @@ -2601,6 +2419,6 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) · 24 unmodified lines | |||
| 2601 | up_read(&pci_bus_sem); | 2419 | up_read(&pci_bus_sem); |
| 2602 | __pci_bus_assign_resources(bus, &add_list, NULL); | 2420 | __pci_bus_assign_resources(bus, &add_list, NULL); |
| 2603 | if (WARN_ON_ONCE(!list_empty(&add_list))) | 2421 | if (WARN_ON_ONCE(!list_empty(&add_list))) |
| 2604 | free_list(&add_list); | 2422 | pci_dev_res_free_list(&add_list); |
| 2605 | } | 2423 | } |
| 2606 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bus_resources); | 2424 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bus_resources); |
| @@ -0,0 +1,306 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Cardbus bridge setup routines. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/bitfield.h> | ||
| 7 | #include <linux/errno.h> | ||
| 8 | #include <linux/ioport.h> | ||
| 9 | #include <linux/pci.h> | ||
| 10 | #include <linux/sizes.h> | ||
| 11 | #include <linux/sprintf.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | |||
| 14 | #include "pci.h" | ||
| 15 | |||
| 16 | #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ | ||
| 17 | #define CARDBUS_RESERVE_BUSNR 3 | ||
| 18 | |||
| 19 | #define DEFAULT_CARDBUS_IO_SIZE SZ_256 | ||
| 20 | #define DEFAULT_CARDBUS_MEM_SIZE SZ_64M | ||
| 21 | /* pci=cbmemsize=nnM,cbiosize=nn can override this */ | ||
| 22 | static unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE; | ||
| 23 | static unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; | ||
| 24 | |||
| 25 | unsigned long pci_cardbus_resource_alignment(struct resource *res) | ||
| 26 | { | ||
| 27 | if (res->flags & IORESOURCE_IO) | ||
| 28 | return pci_cardbus_io_size; | ||
| 29 | if (res->flags & IORESOURCE_MEM) | ||
| 30 | return pci_cardbus_mem_size; | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | int pci_bus_size_cardbus_bridge(struct pci_bus *bus, | ||
| 35 | struct list_head *realloc_head) | ||
| 36 | { | ||
| 37 | struct pci_dev *bridge = bus->self; | ||
| 38 | struct resource *b_res; | ||
| 39 | resource_size_t b_res_3_size = pci_cardbus_mem_size * 2; | ||
| 40 | u16 ctrl; | ||
| 41 | |||
| 42 | b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW]; | ||
| 43 | if (resource_assigned(b_res)) | ||
| 44 | goto handle_b_res_1; | ||
| 45 | /* | ||
| 46 | * Reserve some resources for CardBus. We reserve a fixed amount | ||
| 47 | * of bus space for CardBus bridges. | ||
| 48 | */ | ||
| 49 | resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); | ||
| 50 | b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | ||
| 51 | if (realloc_head) { | ||
| 52 | b_res->end -= pci_cardbus_io_size; | ||
| 53 | pci_dev_res_add_to_list(realloc_head, bridge, b_res, | ||
| 54 | pci_cardbus_io_size, | ||
| 55 | pci_cardbus_io_size); | ||
| 56 | } | ||
| 57 | |||
| 58 | handle_b_res_1: | ||
| 59 | b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW]; | ||
| 60 | if (resource_assigned(b_res)) | ||
| 61 | goto handle_b_res_2; | ||
| 62 | resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); | ||
| 63 | b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; | ||
| 64 | if (realloc_head) { | ||
| 65 | b_res->end -= pci_cardbus_io_size; | ||
| 66 | pci_dev_res_add_to_list(realloc_head, bridge, b_res, | ||
| 67 | pci_cardbus_io_size, | ||
| 68 | pci_cardbus_io_size); | ||
| 69 | } | ||
| 70 | |||
| 71 | handle_b_res_2: | ||
| 72 | /* MEM1 must not be pref MMIO */ | ||
| 73 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 74 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) { | ||
| 75 | ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; | ||
| 76 | pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); | ||
| 77 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* Check whether prefetchable memory is supported by this bridge. */ | ||
| 81 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 82 | if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) { | ||
| 83 | ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; | ||
| 84 | pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl); | ||
| 85 | pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); | ||
| 86 | } | ||
| 87 | |||
| 88 | b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW]; | ||
| 89 | if (resource_assigned(b_res)) | ||
| 90 | goto handle_b_res_3; | ||
| 91 | /* | ||
| 92 | * If we have prefetchable memory support, allocate two regions. | ||
| 93 | * Otherwise, allocate one region of twice the size. | ||
| 94 | */ | ||
| 95 | if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { | ||
| 96 | resource_set_range(b_res, pci_cardbus_mem_size, | ||
| 97 | pci_cardbus_mem_size); | ||
| 98 | b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | | ||
| 99 | IORESOURCE_STARTALIGN; | ||
| 100 | if (realloc_head) { | ||
| 101 | b_res->end -= pci_cardbus_mem_size; | ||
| 102 | pci_dev_res_add_to_list(realloc_head, bridge, b_res, | ||
| 103 | pci_cardbus_mem_size, | ||
| 104 | pci_cardbus_mem_size); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* Reduce that to half */ | ||
| 108 | b_res_3_size = pci_cardbus_mem_size; | ||
| 109 | } | ||
| 110 | |||
| 111 | handle_b_res_3: | ||
| 112 | b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW]; | ||
| 113 | if (resource_assigned(b_res)) | ||
| 114 | goto handle_done; | ||
| 115 | resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size); | ||
| 116 | b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN; | ||
| 117 | if (realloc_head) { | ||
| 118 | b_res->end -= b_res_3_size; | ||
| 119 | pci_dev_res_add_to_list(realloc_head, bridge, b_res, | ||
| 120 | b_res_3_size, pci_cardbus_mem_size); | ||
| 121 | } | ||
| 122 | |||
| 123 | handle_done: | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | void pci_setup_cardbus_bridge(struct pci_bus *bus) | ||
| 128 | { | ||
| 129 | struct pci_dev *bridge = bus->self; | ||
| 130 | struct resource *res; | ||
| 131 | struct pci_bus_region region; | ||
| 132 | |||
| 133 | pci_info(bridge, "CardBus bridge to %pR\n", | ||
| 134 | &bus->busn_res); | ||
| 135 | |||
| 136 | res = bus->resource[0]; | ||
| 137 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 138 | if (resource_assigned(res) && res->flags & IORESOURCE_IO) { | ||
| 139 | /* | ||
| 140 | * The IO resource is allocated a range twice as large as it | ||
| 141 | * would normally need. This allows us to set both IO regs. | ||
| 142 | */ | ||
| 143 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 144 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, | ||
| 145 | region.start); | ||
| 146 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, | ||
| 147 | region.end); | ||
| 148 | } | ||
| 149 | |||
| 150 | res = bus->resource[1]; | ||
| 151 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 152 | if (resource_assigned(res) && res->flags & IORESOURCE_IO) { | ||
| 153 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 154 | pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, | ||
| 155 | region.start); | ||
| 156 | pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, | ||
| 157 | region.end); | ||
| 158 | } | ||
| 159 | |||
| 160 | res = bus->resource[2]; | ||
| 161 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 162 | if (resource_assigned(res) && res->flags & IORESOURCE_MEM) { | ||
| 163 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 164 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, | ||
| 165 | region.start); | ||
| 166 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, | ||
| 167 | region.end); | ||
| 168 | } | ||
| 169 | |||
| 170 | res = bus->resource[3]; | ||
| 171 | pcibios_resource_to_bus(bridge->bus, ®ion, res); | ||
| 172 | if (resource_assigned(res) && res->flags & IORESOURCE_MEM) { | ||
| 173 | pci_info(bridge, " bridge window %pR\n", res); | ||
| 174 | pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, | ||
| 175 | region.start); | ||
| 176 | pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, | ||
| 177 | region.end); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | EXPORT_SYMBOL(pci_setup_cardbus_bridge); | ||
| 181 | |||
| 182 | int pci_setup_cardbus(char *str) | ||
| 183 | { | ||
| 184 | if (!strncmp(str, "cbiosize=", 9)) { | ||
| 185 | pci_cardbus_io_size = memparse(str + 9, &str); | ||
| 186 | return 0; | ||
| 187 | } else if (!strncmp(str, "cbmemsize=", 10)) { | ||
| 188 | pci_cardbus_mem_size = memparse(str + 10, &str); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | return -ENOENT; | ||
| 193 | } | ||
| 194 | |||
| 195 | int pci_cardbus_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, | ||
| 196 | u32 buses, int max, | ||
| 197 | unsigned int available_buses, int pass) | ||
| 198 | { | ||
| 199 | struct pci_bus *child; | ||
| 200 | bool fixed_buses; | ||
| 201 | u8 fixed_sec, fixed_sub; | ||
| 202 | int next_busnr; | ||
| 203 | u32 i, j = 0; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * We need to assign a number to this bus which we always do in the | ||
| 207 | * second pass. | ||
| 208 | */ | ||
| 209 | if (!pass) { | ||
| 210 | /* | ||
| 211 | * Temporarily disable forwarding of the configuration | ||
| 212 | * cycles on all bridges in this bus segment to avoid | ||
| 213 | * possible conflicts in the second pass between two bridges | ||
| 214 | * programmed with overlapping bus ranges. | ||
| 215 | */ | ||
| 216 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, | ||
| 217 | buses & PCI_SEC_LATENCY_TIMER_MASK); | ||
| 218 | return max; | ||
| 219 | } | ||
| 220 | |||
| 221 | /* Clear errors */ | ||
| 222 | pci_write_config_word(dev, PCI_STATUS, 0xffff); | ||
| 223 | |||
| 224 | /* Read bus numbers from EA Capability (if present) */ | ||
| 225 | fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub); | ||
| 226 | if (fixed_buses) | ||
| 227 | next_busnr = fixed_sec; | ||
| 228 | else | ||
| 229 | next_busnr = max + 1; | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Prevent assigning a bus number that already exists. This can | ||
| 233 | * happen when a bridge is hot-plugged, so in this case we only | ||
| 234 | * re-scan this bus. | ||
| 235 | */ | ||
| 236 | child = pci_find_bus(pci_domain_nr(bus), next_busnr); | ||
| 237 | if (!child) { | ||
| 238 | child = pci_add_new_bus(bus, dev, next_busnr); | ||
| 239 | if (!child) | ||
| 240 | return max; | ||
| 241 | pci_bus_insert_busn_res(child, next_busnr, bus->busn_res.end); | ||
| 242 | } | ||
| 243 | max++; | ||
| 244 | if (available_buses) | ||
| 245 | available_buses--; | ||
| 246 | |||
| 247 | buses = (buses & PCI_SEC_LATENCY_TIMER_MASK) | | ||
| 248 | FIELD_PREP(PCI_PRIMARY_BUS_MASK, child->primary) | | ||
| 249 | FIELD_PREP(PCI_SECONDARY_BUS_MASK, child->busn_res.start) | | ||
| 250 | FIELD_PREP(PCI_SUBORDINATE_BUS_MASK, child->busn_res.end); | ||
| 251 | |||
| 252 | /* | ||
| 253 | * yenta.c forces a secondary latency timer of 176. | ||
| 254 | * Copy that behaviour here. | ||
| 255 | */ | ||
| 256 | buses &= ~PCI_SEC_LATENCY_TIMER_MASK; | ||
| 257 | buses |= FIELD_PREP(PCI_SEC_LATENCY_TIMER_MASK, CARDBUS_LATENCY_TIMER); | ||
| 258 | |||
| 259 | /* We need to blast all three values with a single write */ | ||
| 260 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); | ||
| 261 | |||
| 262 | /* | ||
| 263 | * For CardBus bridges, we leave 4 bus numbers as cards with a | ||
| 264 | * PCI-to-PCI bridge can be inserted later. | ||
| 265 | */ | ||
| 266 | for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) { | ||
| 267 | struct pci_bus *parent = bus; | ||
| 268 | |||
| 269 | if (pci_find_bus(pci_domain_nr(bus), max + i + 1)) | ||
| 270 | break; | ||
| 271 | |||
| 272 | while (parent->parent) { | ||
| 273 | if (!pcibios_assign_all_busses() && | ||
| 274 | (parent->busn_res.end > max) && | ||
| 275 | (parent->busn_res.end <= max + i)) { | ||
| 276 | j = 1; | ||
| 277 | } | ||
| 278 | parent = parent->parent; | ||
| 279 | } | ||
| 280 | if (j) { | ||
| 281 | /* | ||
| 282 | * Often, there are two CardBus bridges -- try to | ||
| 283 | * leave one valid bus number for each one. | ||
| 284 | */ | ||
| 285 | i /= 2; | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | max += i; | ||
| 290 | |||
| 291 | /* | ||
| 292 | * Set subordinate bus number to its real value. If fixed | ||
| 293 | * subordinate bus number exists from EA capability then use it. | ||
| 294 | */ | ||
| 295 | if (fixed_buses) | ||
| 296 | max = fixed_sub; | ||
| 297 | pci_bus_update_busn_res_end(child, max); | ||
| 298 | pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); | ||
| 299 | |||
| 300 | scnprintf(child->name, sizeof(child->name), "PCI CardBus %04x:%02x", | ||
| 301 | pci_domain_nr(bus), child->number); | ||
| 302 | |||
| 303 | pbus_validate_busn(child); | ||
| 304 | |||
| 305 | return max; | ||
| 306 | } | ||
| @@ -359,7 +359,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) · 358 unmodified lines | |||
| 359 | 359 | ||
| 360 | res->flags &= ~IORESOURCE_UNSET; | 360 | res->flags &= ~IORESOURCE_UNSET; |
| 361 | res->flags &= ~IORESOURCE_STARTALIGN; | 361 | res->flags &= ~IORESOURCE_STARTALIGN; |
| 362 | if (resno >= PCI_BRIDGE_RESOURCES && resno <= PCI_BRIDGE_RESOURCE_END) | 362 | if (pci_resource_is_bridge_win(resno)) |
| 363 | res->flags &= ~IORESOURCE_DISABLED; | 363 | res->flags &= ~IORESOURCE_DISABLED; |
| 364 | 364 | ||
| 365 | pci_info(dev, "%s %pR: assigned\n", res_name, res); | 365 | pci_info(dev, "%s %pR: assigned\n", res_name, res); |
| @@ -0,0 +1,11 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Tracepoints for PCI system | ||
| 4 | * | ||
| 5 | * Copyright (C) 2025 Alibaba Corporation | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | |||
| 10 | #define CREATE_TRACE_POINTS | ||
| 11 | #include <trace/events/pci.h> | ||
| @@ -779,7 +779,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket) · 778 unmodified lines | |||
| 779 | IORESOURCE_MEM, | 779 | IORESOURCE_MEM, |
| 780 | PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); | 780 | PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); |
| 781 | if (program) | 781 | if (program) |
| 782 | pci_setup_cardbus(socket->dev->subordinate); | 782 | pci_setup_cardbus_bridge(socket->dev->subordinate); |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | 785 | ||
| @@ -21,7 +21,6 @@ static const char hcd_name[] = "ehci-pci"; · 20 unmodified lines | |||
| 21 | /* defined here to avoid adding to pci_ids.h for single instance use */ | 21 | /* defined here to avoid adding to pci_ids.h for single instance use */ |
| 22 | #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 | 22 | #define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 |
| 23 | 23 | ||
| 24 | #define PCI_VENDOR_ID_ASPEED 0x1a03 | ||
| 25 | #define PCI_DEVICE_ID_ASPEED_EHCI 0x2603 | 24 | #define PCI_DEVICE_ID_ASPEED_EHCI 0x2603 |
| 26 | 25 | ||
| 27 | /*-------------------------------------------------------------------------*/ | 26 | /*-------------------------------------------------------------------------*/ |
| @@ -338,7 +338,7 @@ static inline bool resource_union(const struct resource *r1, const struct resour · 337 unmodified lines | |||
| 338 | * Check if this resource is added to a resource tree or detached. Caller is | 338 | * Check if this resource is added to a resource tree or detached. Caller is |
| 339 | * responsible for not racing assignment. | 339 | * responsible for not racing assignment. |
| 340 | */ | 340 | */ |
| 341 | static inline bool resource_assigned(struct resource *res) | 341 | static inline bool resource_assigned(const struct resource *res) |
| 342 | { | 342 | { |
| 343 | return res->parent; | 343 | return res->parent; |
| 344 | } | 344 | } |
| @@ -223,6 +223,13 @@ struct pci_epc_bar_desc { · 222 unmodified lines | |||
| 223 | /** | 223 | /** |
| 224 | * struct pci_epc_features - features supported by a EPC device per function | 224 | * struct pci_epc_features - features supported by a EPC device per function |
| 225 | * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up | 225 | * @linkup_notifier: indicate if the EPC device can notify EPF driver on link up |
| 226 | * @dynamic_inbound_mapping: indicate if the EPC device supports updating | ||
| 227 | * inbound mappings for an already configured BAR | ||
| 228 | * (i.e. allow calling pci_epc_set_bar() again | ||
| 229 | * without first calling pci_epc_clear_bar()) | ||
| 230 | * @subrange_mapping: indicate if the EPC device can map inbound subranges for a | ||
| 231 | * BAR. This feature depends on @dynamic_inbound_mapping | ||
| 232 | * feature. | ||
| 226 | * @msi_capable: indicate if the endpoint function has MSI capability | 233 | * @msi_capable: indicate if the endpoint function has MSI capability |
| 227 | * @msix_capable: indicate if the endpoint function has MSI-X capability | 234 | * @msix_capable: indicate if the endpoint function has MSI-X capability |
| 228 | * @intx_capable: indicate if the endpoint can raise INTx interrupts | 235 | * @intx_capable: indicate if the endpoint can raise INTx interrupts |
| @@ -231,6 +238,8 @@ struct pci_epc_bar_desc { · 2 unmodified lines | |||
| 231 | */ | 238 | */ |
| 232 | struct pci_epc_features { | 239 | struct pci_epc_features { |
| 233 | unsigned int linkup_notifier : 1; | 240 | unsigned int linkup_notifier : 1; |
| 241 | unsigned int dynamic_inbound_mapping : 1; | ||
| 242 | unsigned int subrange_mapping : 1; | ||
| 234 | unsigned int msi_capable : 1; | 243 | unsigned int msi_capable : 1; |
| 235 | unsigned int msix_capable : 1; | 244 | unsigned int msix_capable : 1; |
| 236 | unsigned int intx_capable : 1; | 245 | unsigned int intx_capable : 1; |
| @@ -110,6 +110,22 @@ struct pci_epf_driver { · 109 unmodified lines | |||
| 110 | 110 | ||
| 111 | #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver) | 111 | #define to_pci_epf_driver(drv) container_of_const((drv), struct pci_epf_driver, driver) |
| 112 | 112 | ||
| 113 | /** | ||
| 114 | * struct pci_epf_bar_submap - BAR subrange for inbound mapping | ||
| 115 | * @phys_addr: target physical/DMA address for this subrange | ||
| 116 | * @size: the size of the subrange to be mapped | ||
| 117 | * | ||
| 118 | * When pci_epf_bar.num_submap is >0, pci_epf_bar.submap describes the | ||
| 119 | * complete BAR layout. This allows an EPC driver to program multiple | ||
| 120 | * inbound translation windows for a single BAR when supported by the | ||
| 121 | * controller. The array order defines the BAR layout (submap[0] at offset | ||
| 122 | * 0, and each immediately follows the previous one). | ||
| 123 | */ | ||
| 124 | struct pci_epf_bar_submap { | ||
| 125 | dma_addr_t phys_addr; | ||
| 126 | size_t size; | ||
| 127 | }; | ||
| 128 | |||
| 113 | /** | 129 | /** |
| 114 | * struct pci_epf_bar - represents the BAR of EPF device | 130 | * struct pci_epf_bar - represents the BAR of EPF device |
| 115 | * @phys_addr: physical address that should be mapped to the BAR | 131 | * @phys_addr: physical address that should be mapped to the BAR |
| @@ -119,6 +135,9 @@ struct pci_epf_driver { · 3 unmodified lines | |||
| 119 | * requirement | 135 | * requirement |
| 120 | * @barno: BAR number | 136 | * @barno: BAR number |
| 121 | * @flags: flags that are set for the BAR | 137 | * @flags: flags that are set for the BAR |
| 138 | * @num_submap: number of entries in @submap | ||
| 139 | * @submap: array of subrange descriptors allocated by the caller. See | ||
| 140 | * struct pci_epf_bar_submap for the semantics in detail. | ||
| 122 | */ | 141 | */ |
| 123 | struct pci_epf_bar { | 142 | struct pci_epf_bar { |
| 124 | dma_addr_t phys_addr; | 143 | dma_addr_t phys_addr; |
| @@ -127,6 +146,10 @@ struct pci_epf_bar { · 2 unmodified lines | |||
| 127 | size_t mem_size; | 146 | size_t mem_size; |
| 128 | enum pci_barno barno; | 147 | enum pci_barno barno; |
| 129 | int flags; | 148 | int flags; |
| 149 | |||
| 150 | /* Optional sub-range mapping */ | ||
| 151 | unsigned int num_submap; | ||
| 152 | struct pci_epf_bar_submap *submap; | ||
| 130 | }; | 153 | }; |
| 131 | 154 | ||
| 132 | /** | 155 | /** |
| @@ -20,6 +20,8 @@ struct scatterlist; · 19 unmodified lines | |||
| 20 | * struct p2pdma_provider | 20 | * struct p2pdma_provider |
| 21 | * | 21 | * |
| 22 | * A p2pdma provider is a range of MMIO address space available to the CPU. | 22 | * A p2pdma provider is a range of MMIO address space available to the CPU. |
| 23 | * @owner: Device to which this provider belongs. | ||
| 24 | * @bus_offset: Bus offset for p2p communication. | ||
| 23 | */ | 25 | */ |
| 24 | struct p2pdma_provider { | 26 | struct p2pdma_provider { |
| 25 | struct device *owner; | 27 | struct device *owner; |
| @@ -31,6 +31,8 @@ struct device_link; · 30 unmodified lines | |||
| 31 | /** | 31 | /** |
| 32 | * struct pci_pwrctrl - PCI device power control context. | 32 | * struct pci_pwrctrl - PCI device power control context. |
| 33 | * @dev: Address of the power controlling device. | 33 | * @dev: Address of the power controlling device. |
| 34 | * @power_on: Callback to power on the power controlling device. | ||
| 35 | * @power_off: Callback to power off the power controlling device. | ||
| 34 | * | 36 | * |
| 35 | * An object of this type must be allocated by the PCI power control device and | 37 | * An object of this type must be allocated by the PCI power control device and |
| 36 | * passed to the pwrctrl subsystem to trigger a bus rescan and setup a device | 38 | * passed to the pwrctrl subsystem to trigger a bus rescan and setup a device |
| @@ -38,6 +40,8 @@ struct device_link; · 1 unmodified line | |||
| 38 | */ | 40 | */ |
| 39 | struct pci_pwrctrl { | 41 | struct pci_pwrctrl { |
| 40 | struct device *dev; | 42 | struct device *dev; |
| 43 | int (*power_on)(struct pci_pwrctrl *pwrctrl); | ||
| 44 | int (*power_off)(struct pci_pwrctrl *pwrctrl); | ||
| 41 | 45 | ||
| 42 | /* private: internal use only */ | 46 | /* private: internal use only */ |
| 43 | struct notifier_block nb; | 47 | struct notifier_block nb; |
| @@ -50,5 +54,15 @@ int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl); · 6 unmodified lines | |||
| 50 | void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl); | 54 | void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl); |
| 51 | int devm_pci_pwrctrl_device_set_ready(struct device *dev, | 55 | int devm_pci_pwrctrl_device_set_ready(struct device *dev, |
| 52 | struct pci_pwrctrl *pwrctrl); | 56 | struct pci_pwrctrl *pwrctrl); |
| 53 | 57 | #if IS_ENABLED(CONFIG_PCI_PWRCTRL) | |
| 58 | int pci_pwrctrl_create_devices(struct device *parent); | ||
| 59 | void pci_pwrctrl_destroy_devices(struct device *parent); | ||
| 60 | int pci_pwrctrl_power_on_devices(struct device *parent); | ||
| 61 | void pci_pwrctrl_power_off_devices(struct device *parent); | ||
| 62 | #else | ||
| 63 | static inline int pci_pwrctrl_create_devices(struct device *parent) { return 0; } | ||
| 64 | static void pci_pwrctrl_destroy_devices(struct device *parent) { } | ||
| 65 | static inline int pci_pwrctrl_power_on_devices(struct device *parent) { return 0; } | ||
| 66 | static void pci_pwrctrl_power_off_devices(struct device *parent) { } | ||
| 67 | #endif | ||
| 54 | #endif /* __PCI_PWRCTRL_H__ */ | 68 | #endif /* __PCI_PWRCTRL_H__ */ |
| @@ -248,6 +248,11 @@ enum pci_dev_flags { · 247 unmodified lines | |||
| 248 | PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12), | 248 | PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12), |
| 249 | /* Device requires write to PCI_MSIX_ENTRY_DATA before any MSIX reads */ | 249 | /* Device requires write to PCI_MSIX_ENTRY_DATA before any MSIX reads */ |
| 250 | PCI_DEV_FLAGS_MSIX_TOUCH_ENTRY_DATA_FIRST = (__force pci_dev_flags_t) (1 << 13), | 250 | PCI_DEV_FLAGS_MSIX_TOUCH_ENTRY_DATA_FIRST = (__force pci_dev_flags_t) (1 << 13), |
| 251 | /* | ||
| 252 | * PCIe to PCI bridge does not create RID aliases because the bridge is | ||
| 253 | * integrated with the downstream devices and doesn't use real PCI. | ||
| 254 | */ | ||
| 255 | PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS = (__force pci_dev_flags_t) (1 << 14), | ||
| 251 | }; | 256 | }; |
| 252 | 257 | ||
| 253 | enum pci_irq_reroute_variant { | 258 | enum pci_irq_reroute_variant { |
| @@ -413,6 +418,7 @@ struct pci_dev { · 159 unmodified lines | |||
| 413 | user sysfs */ | 418 | user sysfs */ |
| 414 | unsigned int clear_retrain_link:1; /* Need to clear Retrain Link | 419 | unsigned int clear_retrain_link:1; /* Need to clear Retrain Link |
| 415 | bit manually */ | 420 | bit manually */ |
| 421 | unsigned int no_bw_notif:1; /* BW notifications may cause issues */ | ||
| 416 | unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */ | 422 | unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */ |
| 417 | unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */ | 423 | unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */ |
| 418 | 424 | ||
| @@ -564,6 +570,7 @@ struct pci_dev { · 145 unmodified lines | |||
| 564 | struct pci_tsm *tsm; /* TSM operation state */ | 570 | struct pci_tsm *tsm; /* TSM operation state */ |
| 565 | #endif | 571 | #endif |
| 566 | u16 acs_cap; /* ACS Capability offset */ | 572 | u16 acs_cap; /* ACS Capability offset */ |
| 573 | u16 acs_capabilities; /* ACS Capabilities */ | ||
| 567 | u8 supported_speeds; /* Supported Link Speeds Vector */ | 574 | u8 supported_speeds; /* Supported Link Speeds Vector */ |
| 568 | phys_addr_t rom; /* Physical address if not from BAR */ | 575 | phys_addr_t rom; /* Physical address if not from BAR */ |
| 569 | size_t romlen; /* Length if not from BAR */ | 576 | size_t romlen; /* Length if not from BAR */ |
| @@ -860,7 +867,6 @@ struct pci_ops { · 290 unmodified lines | |||
| 860 | void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); | 867 | void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); |
| 861 | int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); | 868 | int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); |
| 862 | int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); | 869 | int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); |
| 863 | int (*assert_perst)(struct pci_bus *bus, bool assert); | ||
| 864 | }; | 870 | }; |
| 865 | 871 | ||
| 866 | /* | 872 | /* |
| @@ -1250,7 +1256,11 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev); · 383 unmodified lines | |||
| 1250 | void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev); | 1256 | void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev); |
| 1251 | void pci_stop_root_bus(struct pci_bus *bus); | 1257 | void pci_stop_root_bus(struct pci_bus *bus); |
| 1252 | void pci_remove_root_bus(struct pci_bus *bus); | 1258 | void pci_remove_root_bus(struct pci_bus *bus); |
| 1253 | void pci_setup_cardbus(struct pci_bus *bus); | 1259 | #ifdef CONFIG_CARDBUS |
| 1260 | void pci_setup_cardbus_bridge(struct pci_bus *bus); | ||
| 1261 | #else | ||
| 1262 | static inline void pci_setup_cardbus_bridge(struct pci_bus *bus) { } | ||
| 1263 | #endif | ||
| 1254 | void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type); | 1264 | void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type); |
| 1255 | void pci_sort_breadthfirst(void); | 1265 | void pci_sort_breadthfirst(void); |
| 1256 | #define dev_is_pci(d) ((d)->bus == &pci_bus_type) | 1266 | #define dev_is_pci(d) ((d)->bus == &pci_bus_type) |
| @@ -2583,6 +2583,8 @@ · 2582 unmodified lines | |||
| 2583 | #define PCI_DEVICE_ID_NETRONOME_NFP3800_VF 0x3803 | 2583 | #define PCI_DEVICE_ID_NETRONOME_NFP3800_VF 0x3803 |
| 2584 | #define PCI_DEVICE_ID_NETRONOME_NFP6000_VF 0x6003 | 2584 | #define PCI_DEVICE_ID_NETRONOME_NFP6000_VF 0x6003 |
| 2585 | 2585 | ||
| 2586 | #define PCI_VENDOR_ID_ASPEED 0x1a03 | ||
| 2587 | |||
| 2586 | #define PCI_VENDOR_ID_QMI 0x1a32 | 2588 | #define PCI_VENDOR_ID_QMI 0x1a32 |
| 2587 | 2589 | ||
| 2588 | #define PCI_VENDOR_ID_AZWAVE 0x1a3b | 2590 | #define PCI_VENDOR_ID_AZWAVE 0x1a3b |
| @@ -0,0 +1,129 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #undef TRACE_SYSTEM | ||
| 3 | #define TRACE_SYSTEM pci | ||
| 4 | |||
| 5 | #if !defined(_TRACE_HW_EVENT_PCI_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 6 | #define _TRACE_HW_EVENT_PCI_H | ||
| 7 | |||
| 8 | #include <uapi/linux/pci_regs.h> | ||
| 9 | #include <linux/tracepoint.h> | ||
| 10 | |||
| 11 | #define PCI_HOTPLUG_EVENT \ | ||
| 12 | EM(PCI_HOTPLUG_LINK_UP, "LINK_UP") \ | ||
| 13 | EM(PCI_HOTPLUG_LINK_DOWN, "LINK_DOWN") \ | ||
| 14 | EM(PCI_HOTPLUG_CARD_PRESENT, "CARD_PRESENT") \ | ||
| 15 | EMe(PCI_HOTPLUG_CARD_NOT_PRESENT, "CARD_NOT_PRESENT") | ||
| 16 | |||
| 17 | /* Enums require being exported to userspace, for user tool parsing */ | ||
| 18 | #undef EM | ||
| 19 | #undef EMe | ||
| 20 | #define EM(a, b) TRACE_DEFINE_ENUM(a); | ||
| 21 | #define EMe(a, b) TRACE_DEFINE_ENUM(a); | ||
| 22 | |||
| 23 | PCI_HOTPLUG_EVENT | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Now redefine the EM() and EMe() macros to map the enums to the strings | ||
| 27 | * that will be printed in the output. | ||
| 28 | */ | ||
| 29 | #undef EM | ||
| 30 | #undef EMe | ||
| 31 | #define EM(a, b) {a, b}, | ||
| 32 | #define EMe(a, b) {a, b} | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Note: For generic PCI hotplug events, we pass already-resolved strings | ||
| 36 | * (port_name, slot) instead of driver-specific structures like 'struct | ||
| 37 | * controller'. This is because different PCI hotplug drivers (pciehp, cpqphp, | ||
| 38 | * ibmphp, shpchp) define their own versions of 'struct controller' with | ||
| 39 | * different fields and helper functions. Using driver-specific structures would | ||
| 40 | * make the tracepoint interface non-generic and cause compatibility issues | ||
| 41 | * across different drivers. | ||
| 42 | */ | ||
| 43 | TRACE_EVENT(pci_hp_event, | ||
| 44 | |||
| 45 | TP_PROTO(const char *port_name, | ||
| 46 | const char *slot, | ||
| 47 | const int event), | ||
| 48 | |||
| 49 | TP_ARGS(port_name, slot, event), | ||
| 50 | |||
| 51 | TP_STRUCT__entry( | ||
| 52 | __string( port_name, port_name ) | ||
| 53 | __string( slot, slot ) | ||
| 54 | __field( int, event ) | ||
| 55 | ), | ||
| 56 | |||
| 57 | TP_fast_assign( | ||
| 58 | __assign_str(port_name); | ||
| 59 | __assign_str(slot); | ||
| 60 | __entry->event = event; | ||
| 61 | ), | ||
| 62 | |||
| 63 | TP_printk("%s slot:%s, event:%s\n", | ||
| 64 | __get_str(port_name), | ||
| 65 | __get_str(slot), | ||
| 66 | __print_symbolic(__entry->event, PCI_HOTPLUG_EVENT) | ||
| 67 | ) | ||
| 68 | ); | ||
| 69 | |||
| 70 | #define PCI_EXP_LNKSTA_LINK_STATUS_MASK (PCI_EXP_LNKSTA_LBMS | \ | ||
| 71 | PCI_EXP_LNKSTA_LABS | \ | ||
| 72 | PCI_EXP_LNKSTA_LT | \ | ||
| 73 | PCI_EXP_LNKSTA_DLLLA) | ||
| 74 | |||
| 75 | #define LNKSTA_FLAGS \ | ||
| 76 | { PCI_EXP_LNKSTA_LT, "LT"}, \ | ||
| 77 | { PCI_EXP_LNKSTA_DLLLA, "DLLLA"}, \ | ||
| 78 | { PCI_EXP_LNKSTA_LBMS, "LBMS"}, \ | ||
| 79 | { PCI_EXP_LNKSTA_LABS, "LABS"} | ||
| 80 | |||
| 81 | TRACE_EVENT(pcie_link_event, | ||
| 82 | |||
| 83 | TP_PROTO(struct pci_bus *bus, | ||
| 84 | unsigned int reason, | ||
| 85 | unsigned int width, | ||
| 86 | unsigned int status | ||
| 87 | ), | ||
| 88 | |||
| 89 | TP_ARGS(bus, reason, width, status), | ||
| 90 | |||
| 91 | TP_STRUCT__entry( | ||
| 92 | __string( port_name, pci_name(bus->self)) | ||
| 93 | __field( unsigned int, type ) | ||
| 94 | __field( unsigned int, reason ) | ||
| 95 | __field( unsigned int, cur_bus_speed ) | ||
| 96 | __field( unsigned int, max_bus_speed ) | ||
| 97 | __field( unsigned int, width ) | ||
| 98 | __field( unsigned int, flit_mode ) | ||
| 99 | __field( unsigned int, link_status ) | ||
| 100 | ), | ||
| 101 | |||
| 102 | TP_fast_assign( | ||
| 103 | __assign_str(port_name); | ||
| 104 | __entry->type = pci_pcie_type(bus->self); | ||
| 105 | __entry->reason = reason; | ||
| 106 | __entry->cur_bus_speed = bus->cur_bus_speed; | ||
| 107 | __entry->max_bus_speed = bus->max_bus_speed; | ||
| 108 | __entry->width = width; | ||
| 109 | __entry->flit_mode = bus->flit_mode; | ||
| 110 | __entry->link_status = status; | ||
| 111 | ), | ||
| 112 | |||
| 113 | TP_printk("%s type:%d, reason:%d, cur_bus_speed:%d, max_bus_speed:%d, width:%u, flit_mode:%u, status:%s\n", | ||
| 114 | __get_str(port_name), | ||
| 115 | __entry->type, | ||
| 116 | __entry->reason, | ||
| 117 | __entry->cur_bus_speed, | ||
| 118 | __entry->max_bus_speed, | ||
| 119 | __entry->width, | ||
| 120 | __entry->flit_mode, | ||
| 121 | __print_flags((unsigned long)__entry->link_status, "|", | ||
| 122 | LNKSTA_FLAGS) | ||
| 123 | ) | ||
| 124 | ); | ||
| 125 | |||
| 126 | #endif /* _TRACE_HW_EVENT_PCI_H */ | ||
| 127 | |||
| 128 | /* This part must be outside protection */ | ||
| 129 | #include <trace/define_trace.h> | ||
| @@ -39,4 +39,11 @@ · 38 unmodified lines | |||
| 39 | #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ | 39 | #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ |
| 40 | #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ | 40 | #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ |
| 41 | 41 | ||
| 42 | enum pci_hotplug_event { | ||
| 43 | PCI_HOTPLUG_LINK_UP, | ||
| 44 | PCI_HOTPLUG_LINK_DOWN, | ||
| 45 | PCI_HOTPLUG_CARD_PRESENT, | ||
| 46 | PCI_HOTPLUG_CARD_NOT_PRESENT, | ||
| 47 | }; | ||
| 48 | |||
| 42 | #endif /* _UAPILINUX_PCI_H */ | 49 | #endif /* _UAPILINUX_PCI_H */ |
| @@ -132,6 +132,11 @@ · 131 unmodified lines | |||
| 132 | #define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ | 132 | #define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ |
| 133 | #define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ | 133 | #define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ |
| 134 | #define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ | 134 | #define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ |
| 135 | /* Masks for dword-sized processing of Bus Number and Sec Latency Timer fields */ | ||
| 136 | #define PCI_PRIMARY_BUS_MASK 0x000000ff | ||
| 137 | #define PCI_SECONDARY_BUS_MASK 0x0000ff00 | ||
| 138 | #define PCI_SUBORDINATE_BUS_MASK 0x00ff0000 | ||
| 139 | #define PCI_SEC_LATENCY_TIMER_MASK 0xff000000 | ||
| 135 | #define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ | 140 | #define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ |
| 136 | #define PCI_IO_LIMIT 0x1d | 141 | #define PCI_IO_LIMIT 0x1d |
| 137 | #define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ | 142 | #define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | |||
| 22 | #define PCITEST_GET_IRQTYPE _IO('P', 0x9) | 22 | #define PCITEST_GET_IRQTYPE _IO('P', 0x9) |
| 23 | #define PCITEST_BARS _IO('P', 0xa) | 23 | #define PCITEST_BARS _IO('P', 0xa) |
| 24 | #define PCITEST_DOORBELL _IO('P', 0xb) | 24 | #define PCITEST_DOORBELL _IO('P', 0xb) |
| 25 | #define PCITEST_BAR_SUBRANGE _IO('P', 0xc) | ||
| 25 | #define PCITEST_CLEAR_IRQ _IO('P', 0x10) | 26 | #define PCITEST_CLEAR_IRQ _IO('P', 0x10) |
| 26 | 27 | ||
| 27 | #define PCITEST_IRQ_TYPE_UNDEFINED -1 | 28 | #define PCITEST_IRQ_TYPE_UNDEFINED -1 |
| @@ -1913,6 +1913,7 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) · 1912 unmodified lines | |||
| 1913 | irq_domain_free_irq_data(virq, nr_irqs); | 1913 | irq_domain_free_irq_data(virq, nr_irqs); |
| 1914 | irq_free_descs(virq, nr_irqs); | 1914 | irq_free_descs(virq, nr_irqs); |
| 1915 | } | 1915 | } |
| 1916 | EXPORT_SYMBOL_GPL(irq_domain_free_irqs); | ||
| 1916 | 1917 | ||
| 1917 | static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq) | 1918 | static void irq_domain_free_one_irq(struct irq_domain *domain, unsigned int virq) |
| 1918 | { | 1919 | { |
| @@ -82,7 +82,7 @@ static struct resource *next_resource(struct resource *p, bool skip_children, · 81 unmodified lines | |||
| 82 | 82 | ||
| 83 | #ifdef CONFIG_PROC_FS | 83 | #ifdef CONFIG_PROC_FS |
| 84 | 84 | ||
| 85 | enum { MAX_IORES_LEVEL = 5 }; | 85 | enum { MAX_IORES_LEVEL = 8 }; |
| 86 | 86 | ||
| 87 | static void *r_start(struct seq_file *m, loff_t *pos) | 87 | static void *r_start(struct seq_file *m, loff_t *pos) |
| 88 | __acquires(resource_lock) | 88 | __acquires(resource_lock) |
| @@ -70,6 +70,23 @@ TEST_F(pci_ep_bar, BAR_TEST) · 69 unmodified lines | |||
| 70 | EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno); | 70 | EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | TEST_F(pci_ep_bar, BAR_SUBRANGE_TEST) | ||
| 74 | { | ||
| 75 | int ret; | ||
| 76 | |||
| 77 | pci_ep_ioctl(PCITEST_SET_IRQTYPE, PCITEST_IRQ_TYPE_AUTO); | ||
| 78 | ASSERT_EQ(0, ret) TH_LOG("Can't set AUTO IRQ type"); | ||
| 79 | |||
| 80 | pci_ep_ioctl(PCITEST_BAR_SUBRANGE, variant->barno); | ||
| 81 | if (ret == -ENODATA) | ||
| 82 | SKIP(return, "BAR is disabled"); | ||
| 83 | if (ret == -EBUSY) | ||
| 84 | SKIP(return, "BAR is test register space"); | ||
| 85 | if (ret == -EOPNOTSUPP) | ||
| 86 | SKIP(return, "Subrange map is not supported"); | ||
| 87 | EXPECT_FALSE(ret) TH_LOG("Test failed for BAR%d", variant->barno); | ||
| 88 | } | ||
| 89 | |||
| 73 | FIXTURE(pci_ep_basic) | 90 | FIXTURE(pci_ep_basic) |
| 74 | { | 91 | { |
| 75 | int fd; | 92 | int fd; |