Skip to content

Commit 0c9e762

Browse files
Tomasz Bursztykanashif
authored andcommitted
drivers/pcie: Add VC/TC mapping and VC enablement
Note that only the the hardware round robin port arbitration capability is being used. Signed-off-by: Tomasz Bursztyka <[email protected]>
1 parent 6a1e19c commit 0c9e762

File tree

4 files changed

+221
-5
lines changed

4 files changed

+221
-5
lines changed

drivers/pcie/host/shell.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <zephyr/drivers/pcie/cap.h>
1616

17+
#include <zephyr/drivers/pcie/vc.h>
1718
#include "vc.h"
1819

1920
struct pcie_cap_id_to_str {

drivers/pcie/host/vc.c

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66

77
#include <errno.h>
88

9-
#include <zephyr/kernel.h>
10-
11-
#include <zephyr/drivers/pcie/pcie.h>
9+
#include <zephyr/drivers/pcie/vc.h>
1210
#include <zephyr/drivers/pcie/cap.h>
1311

1412
#include "vc.h"
@@ -55,3 +53,120 @@ void pcie_vc_load_resources_regs(pcie_bdf_t bdf,
5553
regs++;
5654
}
5755
}
56+
57+
static int get_vc_registers(pcie_bdf_t bdf,
58+
struct pcie_vc_regs *regs,
59+
struct pcie_vc_resource_regs *res_regs)
60+
{
61+
uint32_t base;
62+
63+
base = pcie_vc_cap_lookup(bdf, regs);
64+
if (base == 0) {
65+
return -ENOTSUP;
66+
}
67+
68+
if (regs->cap_reg_1.vc_count == 0) {
69+
/* Having only VC0 is like having no real VC */
70+
return -ENOTSUP;
71+
}
72+
73+
pcie_vc_load_resources_regs(bdf, base, res_regs,
74+
regs->cap_reg_1.vc_count + 1);
75+
76+
return 0;
77+
}
78+
79+
80+
int pcie_vc_enable(pcie_bdf_t bdf)
81+
{
82+
struct pcie_vc_regs regs;
83+
struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT];
84+
int idx;
85+
86+
if (get_vc_registers(bdf, &regs, res_regs) != 0) {
87+
return -ENOTSUP;
88+
}
89+
90+
/* We do not touch VC0: it is always on */
91+
for (idx = 1; idx < regs.cap_reg_1.vc_count + 1; idx++) {
92+
if (idx > 0 && res_regs[idx].ctrl_reg.vc_enable == 1) {
93+
/*
94+
* VC has not been disabled properly, if at all?
95+
*/
96+
return -EALREADY;
97+
}
98+
99+
res_regs[idx].ctrl_reg.vc_enable = 1;
100+
}
101+
102+
return 0;
103+
}
104+
105+
int pcie_vc_disable(pcie_bdf_t bdf)
106+
{
107+
struct pcie_vc_regs regs;
108+
struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT];
109+
int idx;
110+
111+
if (get_vc_registers(bdf, &regs, res_regs) != 0) {
112+
return -ENOTSUP;
113+
}
114+
115+
/* We do not touch VC0: it is always on */
116+
for (idx = 1; idx < regs.cap_reg_1.vc_count + 1; idx++) {
117+
/* Let's wait for the pending negotiation to end */
118+
while (res_regs[idx].status_reg.vc_negocation_pending == 1) {
119+
k_msleep(10);
120+
}
121+
122+
res_regs[idx].ctrl_reg.vc_enable = 0;
123+
}
124+
125+
return 0;
126+
}
127+
128+
int pcie_vc_map_tc(pcie_bdf_t bdf, struct pcie_vctc_map *map)
129+
{
130+
struct pcie_vc_regs regs;
131+
struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT];
132+
int idx;
133+
uint8_t tc_mapped = 0;
134+
135+
if (get_vc_registers(bdf, &regs, res_regs) != 0) {
136+
return -ENOTSUP;
137+
}
138+
139+
/* Map must relate to the actual VC count */
140+
if (regs.cap_reg_1.vc_count != map->vc_count) {
141+
return -EINVAL;
142+
}
143+
144+
/* Veryfying that map is sane */
145+
for (idx = 0; idx < map->vc_count; idx++) {
146+
if (idx == 0 && !(map->vc_tc[idx] & PCIE_VC_SET_TC0)) {
147+
/* TC0 is on VC0 and cannot be unset */
148+
return -EINVAL;
149+
}
150+
151+
/* Each TC must appear only once in the map */
152+
if (tc_mapped & map->vc_tc[idx]) {
153+
return -EINVAL;
154+
}
155+
156+
tc_mapped |= map->vc_tc[idx];
157+
}
158+
159+
for (idx = 0; idx < regs.cap_reg_1.vc_count + 1; idx++) {
160+
/* Let's just set the VC ID to related index for now */
161+
if (idx > 0) {
162+
res_regs[idx].ctrl_reg.vc_id = idx;
163+
}
164+
165+
/* Currently, only HW round robin is used */
166+
res_regs[idx].ctrl_reg.pa_select = PCIE_VC_PA_RR;
167+
168+
res_regs[idx].ctrl_reg.tc_vc_map = map->vc_tc[idx];
169+
}
170+
171+
return 0;
172+
}

drivers/pcie/host/vc.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
#ifndef ZEPHYR_DRIVERS_PCIE_HOST_VC_H_
88
#define ZEPHYR_DRIVERS_PCIE_HOST_VC_H_
99

10-
#define PCIE_VC_MAX_COUNT 8
11-
1210
#define PCIE_VC_CAP_REG_1_OFFSET 0x04U
1311
#define PCIE_VC_CAP_REG_2_OFFSET 0x08U
1412
#define PCIE_VC_CTRL_STATUS_REG_OFFSET 0x0CU
@@ -62,6 +60,13 @@ struct pcie_vc_regs {
6260
#define PCIE_VC_RES_CTRL_REG_OFFSET(_vc) (0x14U + _vc * 0X0CU)
6361
#define PCIE_VC_RES_STATUS_REG_OFFSET(_vc) (0x18U + _vc * 0X0CU)
6462

63+
#define PCIE_VC_PA_RR BIT(0)
64+
#define PCIE_VC_PA_WRR BIT(1)
65+
#define PCIE_VC_PA_WRR64 BIT(2)
66+
#define PCIE_VC_PA_WRR128 BIT(3)
67+
#define PCIE_VC_PA_TMWRR128 BIT(4)
68+
#define PCIE_VC_PA_WRR256 BIT(5)
69+
6570
/** Virtual Channel Resource Registers */
6671
struct pcie_vc_resource_regs {
6772
union {

include/zephyr/drivers/pcie/vc.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2023 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_
8+
#define ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_
9+
10+
/**
11+
* @brief PCIe Virtual Channel Host Interface
12+
* @defgroup pcie_vc_host_interface PCIe Virtual Channel Host Interface
13+
* @ingroup pcie_host_interface
14+
* @{
15+
*/
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
#include <zephyr/kernel.h>
22+
#include <zephyr/types.h>
23+
#include <stdbool.h>
24+
25+
#include <zephyr/drivers/pcie/pcie.h>
26+
27+
/*
28+
* 1 default VC + 7 extended VCs
29+
*/
30+
#define PCIE_VC_MAX_COUNT 8U
31+
32+
#define PCIE_VC_SET_TC0 BIT(0)
33+
#define PCIE_VC_SET_TC1 BIT(1)
34+
#define PCIE_VC_SET_TC2 BIT(2)
35+
#define PCIE_VC_SET_TC3 BIT(3)
36+
#define PCIE_VC_SET_TC4 BIT(4)
37+
#define PCIE_VC_SET_TC5 BIT(5)
38+
#define PCIE_VC_SET_TC6 BIT(6)
39+
#define PCIE_VC_SET_TC7 BIT(7)
40+
41+
struct pcie_vctc_map {
42+
/*
43+
* Map the TCs for each VC by setting bits relevantly
44+
* Note: one bit cannot be set more than once among the VCs
45+
*/
46+
uint8_t vc_tc[PCIE_VC_MAX_COUNT];
47+
/*
48+
* Number of VCs being addressed
49+
*/
50+
int vc_count;
51+
};
52+
53+
/**
54+
* @brief Enable PCIe Virtual Channel handling
55+
* @param bdf the target PCI endpoint
56+
* @return 0 on success, a negative error code otherwise
57+
*
58+
* Note: Not being able to enable such feature is a non-fatal error
59+
* and any code using it should behave accordingly (displaying some info,
60+
* and ignoring it for instance).
61+
*/
62+
int pcie_vc_enable(pcie_bdf_t bdf);
63+
64+
/**
65+
* @brief Disable PCIe Virtual Channel handling
66+
* @param bdf the target PCI endpoint
67+
* @return 0 on success, a negative error code otherwise
68+
*/
69+
int pcie_vc_disable(pcie_bdf_t bdf);
70+
71+
/**
72+
* @brief Map PCIe TC/VC
73+
* @param bdf the target PCI endpoint
74+
* @param map the tc/vc map to apply
75+
* @return 0 on success, a negative error code otherwise
76+
*
77+
* Note: VC must be disabled prior to call this function and
78+
* enabled afterward in order for the endpoint to take advandage of the map.
79+
*
80+
* Note: Not being able to enable such feature is a non-fatal error
81+
* and any code using it should behave accordingly (displaying some info,
82+
* and ignoring it for instance).
83+
*/
84+
int pcie_vc_map_tc(pcie_bdf_t bdf, struct pcie_vctc_map *map);
85+
86+
87+
#ifdef __cplusplus
88+
}
89+
#endif
90+
91+
/**
92+
* @}
93+
*/
94+
95+
#endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_ */

0 commit comments

Comments
 (0)