Skip to content

Commit b80a7b4

Browse files
mpillai-cadenceMani-Sadhasivam
authored andcommitted
PCI: cadence: Move PCIe RP common functions to a separate file
Move the Cadence PCIe controller RP common functions into a separate file. The common library functions are split from legacy PCIe RP controller functions to a separate file. Signed-off-by: Manikandan K Pillai <mpillai@cadence.com> [mani: removed the unused variable] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Link: https://patch.msgid.link/20251108140305.1120117-4-hans.zhang@cixtech.com
1 parent 3977be2 commit b80a7b4

4 files changed

Lines changed: 349 additions & 273 deletions

File tree

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# SPDX-License-Identifier: GPL-2.0
2-
obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
3-
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
4-
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
2+
pcie-cadence-mod-y := pcie-cadence.o
3+
pcie-cadence-host-mod-y := pcie-cadence-host-common.o pcie-cadence-host.o
4+
pcie-cadence-ep-mod-y := pcie-cadence-ep.o
5+
6+
obj-$(CONFIG_PCIE_CADENCE) = pcie-cadence-mod.o
7+
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host-mod.o
8+
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep-mod.o
59
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
610
obj-$(CONFIG_PCI_J721E) += pci-j721e.o
711
obj-$(CONFIG_PCIE_SG2042_HOST) += pcie-sg2042.o
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Cadence PCIe host controller library.
4+
*
5+
* Copyright (c) 2017 Cadence
6+
* Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
7+
*/
8+
#include <linux/delay.h>
9+
#include <linux/kernel.h>
10+
#include <linux/list_sort.h>
11+
#include <linux/of_address.h>
12+
#include <linux/of_pci.h>
13+
#include <linux/platform_device.h>
14+
15+
#include "pcie-cadence.h"
16+
#include "pcie-cadence-host-common.h"
17+
18+
#define LINK_RETRAIN_TIMEOUT HZ
19+
20+
u64 bar_max_size[] = {
21+
[RP_BAR0] = _ULL(128 * SZ_2G),
22+
[RP_BAR1] = SZ_2G,
23+
[RP_NO_BAR] = _BITULL(63),
24+
};
25+
EXPORT_SYMBOL_GPL(bar_max_size);
26+
27+
int cdns_pcie_host_training_complete(struct cdns_pcie *pcie)
28+
{
29+
u32 pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
30+
unsigned long end_jiffies;
31+
u16 lnk_stat;
32+
33+
/* Wait for link training to complete. Exit after timeout. */
34+
end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
35+
do {
36+
lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
37+
if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
38+
break;
39+
usleep_range(0, 1000);
40+
} while (time_before(jiffies, end_jiffies));
41+
42+
if (!(lnk_stat & PCI_EXP_LNKSTA_LT))
43+
return 0;
44+
45+
return -ETIMEDOUT;
46+
}
47+
EXPORT_SYMBOL_GPL(cdns_pcie_host_training_complete);
48+
49+
int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie,
50+
cdns_pcie_linkup_func pcie_link_up)
51+
{
52+
struct device *dev = pcie->dev;
53+
int retries;
54+
55+
/* Check if the link is up or not */
56+
for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
57+
if (pcie_link_up(pcie)) {
58+
dev_info(dev, "Link up\n");
59+
return 0;
60+
}
61+
usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
62+
}
63+
64+
return -ETIMEDOUT;
65+
}
66+
EXPORT_SYMBOL_GPL(cdns_pcie_host_wait_for_link);
67+
68+
int cdns_pcie_retrain(struct cdns_pcie *pcie,
69+
cdns_pcie_linkup_func pcie_link_up)
70+
{
71+
u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
72+
u16 lnk_stat, lnk_ctl;
73+
int ret = 0;
74+
75+
/*
76+
* Set retrain bit if current speed is 2.5 GB/s,
77+
* but the PCIe root port support is > 2.5 GB/s.
78+
*/
79+
80+
lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
81+
PCI_EXP_LNKCAP));
82+
if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
83+
return ret;
84+
85+
lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
86+
if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
87+
lnk_ctl = cdns_pcie_rp_readw(pcie,
88+
pcie_cap_off + PCI_EXP_LNKCTL);
89+
lnk_ctl |= PCI_EXP_LNKCTL_RL;
90+
cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
91+
lnk_ctl);
92+
93+
ret = cdns_pcie_host_training_complete(pcie);
94+
if (ret)
95+
return ret;
96+
97+
ret = cdns_pcie_host_wait_for_link(pcie, pcie_link_up);
98+
}
99+
return ret;
100+
}
101+
EXPORT_SYMBOL_GPL(cdns_pcie_retrain);
102+
103+
int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc,
104+
cdns_pcie_linkup_func pcie_link_up)
105+
{
106+
struct cdns_pcie *pcie = &rc->pcie;
107+
int ret;
108+
109+
ret = cdns_pcie_host_wait_for_link(pcie, pcie_link_up);
110+
111+
/*
112+
* Retrain link for Gen2 training defect
113+
* if quirk flag is set.
114+
*/
115+
if (!ret && rc->quirk_retrain_flag)
116+
ret = cdns_pcie_retrain(pcie, pcie_link_up);
117+
118+
return ret;
119+
}
120+
EXPORT_SYMBOL_GPL(cdns_pcie_host_start_link);
121+
122+
enum cdns_pcie_rp_bar
123+
cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
124+
{
125+
enum cdns_pcie_rp_bar bar, sel_bar;
126+
127+
sel_bar = RP_BAR_UNDEFINED;
128+
for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
129+
if (!rc->avail_ib_bar[bar])
130+
continue;
131+
132+
if (size <= bar_max_size[bar]) {
133+
if (sel_bar == RP_BAR_UNDEFINED) {
134+
sel_bar = bar;
135+
continue;
136+
}
137+
138+
if (bar_max_size[bar] < bar_max_size[sel_bar])
139+
sel_bar = bar;
140+
}
141+
}
142+
143+
return sel_bar;
144+
}
145+
EXPORT_SYMBOL_GPL(cdns_pcie_host_find_min_bar);
146+
147+
enum cdns_pcie_rp_bar
148+
cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
149+
{
150+
enum cdns_pcie_rp_bar bar, sel_bar;
151+
152+
sel_bar = RP_BAR_UNDEFINED;
153+
for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
154+
if (!rc->avail_ib_bar[bar])
155+
continue;
156+
157+
if (size >= bar_max_size[bar]) {
158+
if (sel_bar == RP_BAR_UNDEFINED) {
159+
sel_bar = bar;
160+
continue;
161+
}
162+
163+
if (bar_max_size[bar] > bar_max_size[sel_bar])
164+
sel_bar = bar;
165+
}
166+
}
167+
168+
return sel_bar;
169+
}
170+
EXPORT_SYMBOL_GPL(cdns_pcie_host_find_max_bar);
171+
172+
int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
173+
const struct list_head *b)
174+
{
175+
struct resource_entry *entry1, *entry2;
176+
177+
entry1 = container_of(a, struct resource_entry, node);
178+
entry2 = container_of(b, struct resource_entry, node);
179+
180+
return resource_size(entry2->res) - resource_size(entry1->res);
181+
}
182+
EXPORT_SYMBOL_GPL(cdns_pcie_host_dma_ranges_cmp);
183+
184+
int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
185+
struct resource_entry *entry,
186+
cdns_pcie_host_bar_ib_cfg pci_host_ib_config)
187+
{
188+
struct cdns_pcie *pcie = &rc->pcie;
189+
struct device *dev = pcie->dev;
190+
u64 cpu_addr, size, winsize;
191+
enum cdns_pcie_rp_bar bar;
192+
unsigned long flags;
193+
int ret;
194+
195+
cpu_addr = entry->res->start;
196+
flags = entry->res->flags;
197+
size = resource_size(entry->res);
198+
199+
while (size > 0) {
200+
/*
201+
* Try to find a minimum BAR whose size is greater than
202+
* or equal to the remaining resource_entry size. This will
203+
* fail if the size of each of the available BARs is less than
204+
* the remaining resource_entry size.
205+
*
206+
* If a minimum BAR is found, IB ATU will be configured and
207+
* exited.
208+
*/
209+
bar = cdns_pcie_host_find_min_bar(rc, size);
210+
if (bar != RP_BAR_UNDEFINED) {
211+
ret = pci_host_ib_config(rc, bar, cpu_addr, size, flags);
212+
if (ret)
213+
dev_err(dev, "IB BAR: %d config failed\n", bar);
214+
return ret;
215+
}
216+
217+
/*
218+
* If the control reaches here, it would mean the remaining
219+
* resource_entry size cannot be fitted in a single BAR. So we
220+
* find a maximum BAR whose size is less than or equal to the
221+
* remaining resource_entry size and split the resource entry
222+
* so that part of resource entry is fitted inside the maximum
223+
* BAR. The remaining size would be fitted during the next
224+
* iteration of the loop.
225+
*
226+
* If a maximum BAR is not found, there is no way we can fit
227+
* this resource_entry, so we error out.
228+
*/
229+
bar = cdns_pcie_host_find_max_bar(rc, size);
230+
if (bar == RP_BAR_UNDEFINED) {
231+
dev_err(dev, "No free BAR to map cpu_addr %llx\n",
232+
cpu_addr);
233+
return -EINVAL;
234+
}
235+
236+
winsize = bar_max_size[bar];
237+
ret = pci_host_ib_config(rc, bar, cpu_addr, winsize, flags);
238+
if (ret) {
239+
dev_err(dev, "IB BAR: %d config failed\n", bar);
240+
return ret;
241+
}
242+
243+
size -= winsize;
244+
cpu_addr += winsize;
245+
}
246+
247+
return 0;
248+
}
249+
250+
int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc,
251+
cdns_pcie_host_bar_ib_cfg pci_host_ib_config)
252+
{
253+
struct cdns_pcie *pcie = &rc->pcie;
254+
struct device *dev = pcie->dev;
255+
struct device_node *np = dev->of_node;
256+
struct pci_host_bridge *bridge;
257+
struct resource_entry *entry;
258+
u32 no_bar_nbits = 32;
259+
int err;
260+
261+
bridge = pci_host_bridge_from_priv(rc);
262+
if (!bridge)
263+
return -ENOMEM;
264+
265+
if (list_empty(&bridge->dma_ranges)) {
266+
of_property_read_u32(np, "cdns,no-bar-match-nbits",
267+
&no_bar_nbits);
268+
err = pci_host_ib_config(rc, RP_NO_BAR, 0x0, (u64)1 << no_bar_nbits, 0);
269+
if (err)
270+
dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
271+
return err;
272+
}
273+
274+
list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
275+
276+
resource_list_for_each_entry(entry, &bridge->dma_ranges) {
277+
err = cdns_pcie_host_bar_config(rc, entry, pci_host_ib_config);
278+
if (err) {
279+
dev_err(dev, "Fail to configure IB using dma-ranges\n");
280+
return err;
281+
}
282+
}
283+
284+
return 0;
285+
}
286+
287+
MODULE_LICENSE("GPL");
288+
MODULE_DESCRIPTION("Cadence PCIe host controller driver");
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Cadence PCIe Host controller driver.
4+
*
5+
* Copyright (c) 2017 Cadence
6+
* Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
7+
*/
8+
#ifndef _PCIE_CADENCE_HOST_COMMON_H
9+
#define _PCIE_CADENCE_HOST_COMMON_H
10+
11+
#include <linux/kernel.h>
12+
#include <linux/pci.h>
13+
14+
extern u64 bar_max_size[];
15+
16+
typedef int (*cdns_pcie_host_bar_ib_cfg)(struct cdns_pcie_rc *,
17+
enum cdns_pcie_rp_bar,
18+
u64,
19+
u64,
20+
unsigned long);
21+
typedef bool (*cdns_pcie_linkup_func)(struct cdns_pcie *);
22+
23+
int cdns_pcie_host_training_complete(struct cdns_pcie *pcie);
24+
int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie,
25+
cdns_pcie_linkup_func pcie_link_up);
26+
int cdns_pcie_retrain(struct cdns_pcie *pcie, cdns_pcie_linkup_func pcie_linkup_func);
27+
int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc,
28+
cdns_pcie_linkup_func pcie_link_up);
29+
enum cdns_pcie_rp_bar
30+
cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size);
31+
enum cdns_pcie_rp_bar
32+
cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size);
33+
int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
34+
const struct list_head *b);
35+
int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
36+
enum cdns_pcie_rp_bar bar,
37+
u64 cpu_addr,
38+
u64 size,
39+
unsigned long flags);
40+
int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
41+
struct resource_entry *entry,
42+
cdns_pcie_host_bar_ib_cfg pci_host_ib_config);
43+
int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc,
44+
cdns_pcie_host_bar_ib_cfg pci_host_ib_config);
45+
46+
#endif /* _PCIE_CADENCE_HOST_COMMON_H */

0 commit comments

Comments
 (0)