Pcie: phytium: update phytium Pcie controller driver support to 6.6.0.4#1677
Pcie: phytium: update phytium Pcie controller driver support to 6.6.0.4#1677zhangfuxiang123 wants to merge 10 commits into
Conversation
Some PCI devices have IO space access limit and only supporting 16 bit addresses. We update upper 16 bits of I/O base/limit according to the bridge and the RC root port. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Xiao Cong <xiaocong1866@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
When the PCIe device is unplugged or under hotreset, the PCIe controller's protrction mechanism is triggered, which will make the link inaccessible. This patch disables the protection after the link is up and makes the PCIe hotplug or hotreset process work well. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Long Shixiang <longshixiang1718@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
The phytium PCIe root ports and X100 switch do not support ACS at this point. However, the hardware provides isolation and source validation through the SMMU. The stream ID generated by the PCIe ports contain both the bus/device/function number as well as the port ID in its 3 most significant bits. Turn on ACS but disable all the peer-to-peer features. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Xiao Cong <xiaocong1866@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
In the phytium ps2308 platforms, when host PCIe bridge operate hotreset, then host pcie bridge config register will restore default value. So before hotreset, it need save host PCIe bridge config register. Then after hotreset, it need restore save host PCIe bridge config register. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Xiao Cong <xiaocong1866@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
Some Phytium-based systems can come up with reduced PCIe link speed or lane count after a hotreset. A second reset attempt often restores the original link characteristics. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Li Tongfeng <litongfeng1497@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
On Phytium 24080 platform, reading the PCIe Link Status (LNKSTA) register through the standard PCIe capability interface may return an incorrect value for the Data Link Layer Link Active (DLLLA) bit. This causes the kernel to report wrong link state after a device is hot-unplugged. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Li Tongfeng <litongfeng1497@phytium.com.cn>
Add the device tree binding schema for phytium,pe2201-pcie-ep. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Li Tongfeng <litongfeng1497@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
Add phytium ep driver DMA Controller support and add function_num_map to the configfs of EPC. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Li Tongfeng <litongfeng1497@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
On PD2308 platform, it only setup root bridge I/O BAR address, and don't modify other bridge I/O BAR address after root. Signed-off-by: Zhang Fuxiang <zhangfuxiang2144@phytium.com.cn> Signed-off-by: Li Wencheng <liwencheng@phytium.com.cn> Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
Reviewer's GuideUpdates the Phytium PCIe endpoint controller driver and generic PCI core for Phytium SoCs to 6.6.0.4 by adding endpoint DMA support, refining BAR/ATR handling, introducing SoC‑specific HPB register layouts, centralizing Phytium PCIe SMC handling and link checks, and adding Phytium‑specific EPC configfs and bridge quirks, plus a new DT binding for the PE2201 endpoint controller. Sequence diagram for starting Phytium endpoint DMA via EPC coresequenceDiagram
actor UserSpace
participant EPF_driver as pci_epf_driver
participant EPC_core as pci_epc_core_helpers
participant EPC as pci_epc
participant EPC_ops as pci_epc_ops
participant EP_hw as phytium_pcie_ep_driver
participant DMA_regs as DMA_registers
UserSpace->>EPF_driver: request DMA transfer(cpu_addr, pci_addr, size, mode)
EPF_driver->>EPC_core: pci_epc_start_dma(epc, func_no, cpu_addr, pci_addr, size, mode)
EPC_core->>EPC: validate epc and ops
alt start_dma not implemented
EPC_core-->>EPF_driver: return 0
else start_dma implemented
EPC_core->>EPC_core: acquire epc_dma_lock
EPC_core->>EPC_ops: start_dma(epc, func_no, cpu_addr, pci_addr, size, mode)
activate EP_hw
EPC_ops->>EP_hw: phytium_pcie_ep_start_dma(epc, func_no, cpu_addr, pci_addr, size, mode)
EP_hw->>EP_hw: func_no++ and debug log
EP_hw->>DMA_regs: program HPB window for cpu_addr (upper and lower)
EP_hw->>DMA_regs: configure DMA_SHARE_ACCESS(mode)
alt mode == DMA_READ_ENGINE
EP_hw->>DMA_regs: set DMA_SRCPARAM(mode) to PCIE interface
EP_hw->>DMA_regs: set DMA_DSTPARAM(mode) to AXI master
EP_hw->>DMA_regs: set DMA_SRCADDR_LO/UP from pci_addr
EP_hw->>DMA_regs: set DMA_DESTADDR_LO/UP from cpu_addr
else mode == DMA_WRITE_ENGINE
EP_hw->>DMA_regs: set DMA_SRCPARAM(mode) to AXI master
EP_hw->>DMA_regs: set DMA_DSTPARAM(mode) to PCIE interface
EP_hw->>DMA_regs: set DMA_SRCADDR_LO/UP from cpu_addr
EP_hw->>DMA_regs: set DMA_DESTADDR_LO/UP from pci_addr
end
EP_hw->>DMA_regs: write DMA_LENGTH(mode)
EP_hw->>DMA_regs: write DMA_CONTROL(mode) start value
EP_hw-->>EPC_ops: return 0
deactivate EP_hw
EPC_ops-->>EPC_core: return 0
EPC_core->>EPC_core: release epc_dma_lock
EPC_core-->>EPF_driver: return 0
end
Note over EPF_driver,EPC_core: PCIe EP function may poll pci_epc_dma_status() to read DMA_STATUS(mode)
Sequence diagram for Phytium PCIe SMC control and link status usagesequenceDiagram
participant Core as pci_core_or_pciehp
participant RP as pci_root_port_dev
participant FW as firmware_SMC
Core->>RP: call phytium_pcie_ctrl_smc_op(pdev, op)
alt device not Phytium root port
Core-->>Core: return -ENOENT
else Phytium root port
Core->>RP: dev_to_node(&pdev->dev)
alt socket < 0
Core-->>Core: return -ENOENT
else valid socket
Core->>FW: arm_smccc_smc(PHYTIUM_PCIE_CTRL_SMC_FUNC_ID, sbdf_arg, op, ...)
alt res.a0 != 0
Core-->>Core: return -ENOENT
else success
alt op == PHYTIUM_PCIE_GET_LNKSTA
Core->>Core: map res.a1 to link_status bit PCI_EXP_LNKSTA_DLLLA
Core-->>Core: return link_status
else op is PHYTIUM_PCIE_HOTRESET or PHYTIUM_PCIE_HOTPLUG
Core-->>Core: return 0
end
end
end
end
rect rgb(230,230,250)
participant HP as pciehp_check_link_active
participant Port as pciehp_port_pci_dev
HP->>Port: pci_read_config_word(PCI_EXP_LNKSTA)
Note over HP,Port: generic link_status read
HP->>Port: is_ps24080()
alt Phytium PS24080
HP->>Port: phytium_pcie_ctrl_smc_op(Port, PHYTIUM_PCIE_GET_LNKSTA)
HP->>HP: if lnksta >= 0, update DLLLA bit
end
HP-->>HP: return !!(lnk_status & PCI_EXP_LNKSTA_DLLLA)
end
Class diagram for updated Phytium PCIe endpoint controller and EPC DMA opsclassDiagram
class phytium_pcie_ep {
<<struct>>
void __iomem *reg_base
void __iomem *hpb_base
struct resource *mem_res
unsigned long irq_pci_addr
u8 irq_pci_fn
struct pci_epc *epc
struct platform_device *pdev
}
class pci_epc_ops {
<<struct>>
int (*write_header)(struct pci_epc *epc, unsigned char fn, u8 vfn, struct pci_epf_header *hdr)
int (*set_bar)(struct pci_epc *epc, u8 fn, u8 vfn, struct pci_epf_bar *epf_bar)
void (*clear_bar)(struct pci_epc *epc, u8 fn, u8 vfn, struct pci_epf_bar *epf_bar)
int (*map_addr)(struct pci_epc *epc, u8 fn, u8 vfn, phys_addr_t phys_addr, u64 pci_addr, size_t size)
void (*unmap_addr)(struct pci_epc *epc, u8 fn, u8 vfn, phys_addr_t phys_addr)
int (*set_msi)(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc)
int (*get_msi)(struct pci_epc *epc, u8 fn, u8 vfn)
int (*raise_irq)(struct pci_epc *epc, u8 fn, u8 vfn, enum pci_epc_irq_type type, u16 interrupt_num)
int (*start)(struct pci_epc *epc)
void (*stop)(struct pci_epc *epc)
int (*start_dma)(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, size_t size, u8 mode)
int (*dma_status)(struct pci_epc *epc, u8 func_no, u8 mode)
const struct pci_epc_features* (*get_features)(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
struct module *owner
}
class pci_epc {
<<struct>>
const struct pci_epc_ops *ops
struct pci_epc_mem *mem
u8 max_functions
unsigned long function_num_map
}
class pci_epc_core_helpers {
<<functions>>
int pci_epc_start(struct pci_epc *epc)
int pci_epc_start_dma(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, size_t size, u8 mode)
int pci_epc_dma_status(struct pci_epc *epc, u8 func_no, u8 mode)
}
class phytium_pcie_ep_driver {
<<driver>>
int phytium_pcie_ep_write_header(struct pci_epc *epc, unsigned char fn, u8 vfn, struct pci_epf_header *hdr)
int phytium_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn, struct pci_epf_bar *epf_bar)
void phytium_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, struct pci_epf_bar *epf_bar)
int phytium_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, phys_addr_t phys_addr, u64 pci_addr, size_t size)
void phytium_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, phys_addr_t phys_addr)
int phytium_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc)
int phytium_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn)
int phytium_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn, enum pci_epc_irq_type type, u16 interrupt_num)
int phytium_pcie_ep_start(struct pci_epc *epc)
int phytium_pcie_ep_start_dma(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, size_t size, u8 mode)
int phytium_pcie_ep_dma_status(struct pci_epc *epc, u8 func_no, u8 mode)
int phytium_pcie_ep_probe(struct platform_device *pdev)
int phytium_pcie_ep_remove(struct platform_device *pdev)
}
phytium_pcie_ep_driver --> phytium_pcie_ep : uses
phytium_pcie_ep_driver --> pci_epc_ops : fills
pci_epc --> pci_epc_ops : has ops
pci_epc_core_helpers ..> pci_epc : operates on
pci_epc_core_helpers ..> pci_epc_ops : calls via ops
class pci_epc_group {
<<struct>>
struct config_group group
struct pci_epc *epc
bool start
unsigned long function_num_map
}
pci_epc_group --> pci_epc : references
class DMA_registers {
<<macros>>
int DMA_READ_ENGINE
int DMA_WRITE_ENGINE
int DMA_ENGINE0_BASE
int DMA_SHARE_ACCESS(int engnum)
int DMA_SRCPARAM(int engnum)
int DMA_DSTPARAM(int engnum)
int DMA_SRCADDR_LO(int engnum)
int DMA_SRCADDR_UP(int engnum)
int DMA_DESTADDR_LO(int engnum)
int DMA_DESTADDR_UP(int engnum)
int DMA_LENGTH(int engnum)
int DMA_CONTROL(int engnum)
int DMA_STATUS(int engnum)
}
phytium_pcie_ep_driver ..> DMA_registers : programs DMA
class HPB_register_layouts {
<<macros>>
int PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT
int PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT
int PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT_UP32
int PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT_UP32
}
phytium_pcie_ep_driver ..> HPB_register_layouts : SoC specific selection
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @zhangfuxiang123. Thanks for your PR. I'm waiting for a deepin-community member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
pciehp_check_link_active(), the Phytium-specific path stores the return value ofphytium_pcie_ctrl_smc_op()(which can be negative) into au16and then testslnksta >= 0, which will always be true for an unsigned type; consider using a signed type for the return, checking for errors explicitly, and only updatinglnk_statuswhen the SMC call succeeds. - The new
pci_epc_start_dma()andpci_epc_dma_status()helpers inpci-epc-core.cuseIS_ERR(epc)to validate theepcpointer even thoughepcis a normal struct pointer, not an ERR_PTR; changing this to a simpleif (!epc)(or removing the check if callers guarantee non-NULL) would be more appropriate and avoid misleading error handling. - In
phytium_pcie_ep_probe(), usingof_get_property(np, "compatible", NULL)andstrcmp()assumes a single, null-terminated compatible string and ignores the standard multi-string semantics; it would be more robust to rely on the OF match table (e.g.of_device_get_match_data()orof_device_is_compatible()) to select the SoC-specifichpb_c0_pref_base_limitvalues.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `pciehp_check_link_active()`, the Phytium-specific path stores the return value of `phytium_pcie_ctrl_smc_op()` (which can be negative) into a `u16` and then tests `lnksta >= 0`, which will always be true for an unsigned type; consider using a signed type for the return, checking for errors explicitly, and only updating `lnk_status` when the SMC call succeeds.
- The new `pci_epc_start_dma()` and `pci_epc_dma_status()` helpers in `pci-epc-core.c` use `IS_ERR(epc)` to validate the `epc` pointer even though `epc` is a normal struct pointer, not an ERR_PTR; changing this to a simple `if (!epc)` (or removing the check if callers guarantee non-NULL) would be more appropriate and avoid misleading error handling.
- In `phytium_pcie_ep_probe()`, using `of_get_property(np, "compatible", NULL)` and `strcmp()` assumes a single, null-terminated compatible string and ignores the standard multi-string semantics; it would be more robust to rely on the OF match table (e.g. `of_device_get_match_data()` or `of_device_is_compatible()`) to select the SoC-specific `hpb_c0_pref_base_limit` values.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Pull request overview
Updates Phytium PCIe root-port and endpoint support by extending the PCIe endpoint controller (EPC) core with Phytium-specific DMA and function mapping controls, adding a new PE2201 endpoint variant, and refining Phytium platform reset/hotplug/link handling in the generic PCI hotplug/reset paths.
Changes:
- Add Phytium-specific EPC DMA hooks and a configfs knob for EPC function bitmap handling.
- Extend Phytium PCIe endpoint controller driver for PE2201 (incl. HPB base/limit offsets) and add a new DT binding.
- Adjust Phytium platform behavior in core PCI code (ACS quirks, bridge resets, hotplug link-status overrides, IO window programming quirk).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 27 comments.
Show a summary per file
| File | Description |
|---|---|
| MAINTAINERS | Add DT binding file entry for the new PE2201 EP binding. |
| include/linux/pci-epc.h | Extend EPC ops/API with Phytium-only DMA hooks. |
| drivers/pci/setup-bus.c | Add Phytium-specific override for bridge I/O upper bits via firmware node property. |
| drivers/pci/quirks.c | Expand ACS quirks matching by vendor IDs (Phytium-related devices). |
| drivers/pci/pci.h | Replace Phytium PCIe SMC helper with a more general op helper, add link-status query op. |
| drivers/pci/pci.c | Add Phytium CPU-specific secondary bus reset policies and switch to new SMC helper. |
| drivers/pci/hotplug/pciehp_hpc.c | Add Phytium platform link-status validation via firmware for hotplug. |
| drivers/pci/hotplug/pciehp_ctrl.c | Switch hotplug protection-clear path to new SMC helper. |
| drivers/pci/endpoint/pci-epc-core.c | Add EPC-core exported DMA wrappers (Phytium-gated). |
| drivers/pci/endpoint/pci-ep-cfs.c | Add Phytium-gated configfs attribute to set EPC function bitmap. |
| drivers/pci/controller/pcie-phytium-register.h | Add PE2201 HPB offsets and define EP DMA register macros. |
| drivers/pci/controller/pcie-phytium-ep.h | Track platform device pointer in EP private data. |
| drivers/pci/controller/pcie-phytium-ep.c | Add PE2201 compatible, BAR/ATR programming changes, and EP DMA engine ops. |
| drivers/pci/controller/Kconfig | Restrict Phytium EP controller driver to ARCH_PHYTIUM. |
| Documentation/devicetree/bindings/pci/phytium,pe2201-pcie-ep.yaml | Introduce DT binding for PE2201 EP controller. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return sprintf(page, "%ld\n", | ||
| to_pci_epc_group(item)->function_num_map); |
| #include "../pci.h" | ||
| #include "pciehp.h" | ||
| #ifdef CONFIG_ARCH_PHYTIUM | ||
| #include <asm/phytium_cputype.h> |
| EXPORT_SYMBOL(isa_dma_bridge_buggy); | ||
| #endif | ||
| #ifdef CONFIG_ARCH_PHYTIUM | ||
| #include <asm/phytium_cputype.h> |
| { 0x10b5, PCI_ANY_ID, pci_quirk_xgene_acs }, | ||
| { 0x17cd, PCI_ANY_ID, pci_quirk_xgene_acs }, | ||
| { 0x1db7, PCI_ANY_ID, pci_quirk_xgene_acs }, |
|
|
||
| #ifdef CONFIG_ARCH_PHYTIUM | ||
| int (*start_dma)(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, | ||
| size_t size, u8 mode); | ||
| int (*dma_status)(struct pci_epc *epc, u8 func_no, u8 mode); | ||
| #endif |
| phytium_hpb_writel(priv, base, upper_32_bits(cpu_addr)); | ||
| phytium_hpb_writel(priv, (base + 0x4), | ||
| (lower_32_bits(cpu_addr) & (~0x3f)) | (fls64(size - 1))); | ||
| cpu_addr = 0x40000000000 | (cpu_addr & 0x3f); |
| phytium_pcie_writel(priv, func_no, DMA_SHARE_ACCESS(mode), | ||
| PHYTIUM_PCIE_EP_DMA_SHARE_ACCESS); | ||
| if (mode == DMA_READ_ENGINE) { |
| compatible = of_get_property(np, "compatible", NULL); | ||
| if (!compatible) { | ||
| dev_err(dev, "Compatible property not found\n"); | ||
| return -EINVAL; | ||
| } |
| #define C0_PREF_BASE_MASK 0xfff | ||
| #define C0_PREF_BASE_SHIFT 4 | ||
| #define C0_PREF_VALUE_SHIFT 20 | ||
| #define PHYTIUM_HPB_C0_PREF_BASE_LIMIT_UP32 0xa34 |
| #define DMA_SHARE_ACCESS(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x28) // 0x468 | ||
| #define DMA_SRCPARAM(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x0) // 0x440 | ||
| #define DMA_DSTPARAM(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x4) // 0x444 | ||
| #define DMA_SRCADDR_LO(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x8) // 0x448 | ||
| #define DMA_SRCADDR_UP(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0xc) // 0x44C | ||
| #define DMA_DESTADDR_LO(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x10) // 0x450 | ||
| #define DMA_DESTADDR_UP(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x14) // 0x454 | ||
| #define DMA_LENGTH(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x18) // 0x458 | ||
| #define DMA_CONTROL(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x1c) // 0x45C | ||
| #define DMA_STATUS(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x20) // 0x460 |
These patches updates the support for phytium Pcie controller driver.
Summary by Sourcery
Update Phytium PCIe endpoint and controller support, including new SoC compatibility, DMA support, platform-specific reset/link handling, and configfs controls.
New Features:
Bug Fixes:
Enhancements: