Skip to content

Commit 4d09dd1

Browse files
emuslnjgunthorpe
authored andcommitted
pds_fwctl: initial driver framework
Initial files for adding a new fwctl driver for the AMD/Pensando PDS devices. This sets up a simple auxiliary_bus driver that registers with fwctl subsystem. It expects that a pds_core device has set up the auxiliary_device pds_core.fwctl Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Leon Romanovsky <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Shannon Nelson <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 7e9dd0d commit 4d09dd1

File tree

8 files changed

+306
-0
lines changed

8 files changed

+306
-0
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9576,6 +9576,13 @@ L: [email protected]
95769576
S: Maintained
95779577
F: drivers/fwctl/mlx5/
95789578

9579+
FWCTL PDS DRIVER
9580+
M: Brett Creeley <[email protected]>
9581+
R: Shannon Nelson <[email protected]>
9582+
9583+
S: Maintained
9584+
F: drivers/fwctl/pds/
9585+
95799586
GALAXYCORE GC0308 CAMERA SENSOR DRIVER
95809587
M: Sebastian Reichel <[email protected]>
95819588

drivers/fwctl/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,15 @@ config FWCTL_MLX5
1919
This will allow configuration and debug tools to work out of the box on
2020
mainstream kernel.
2121

22+
If you don't know what to do here, say N.
23+
24+
config FWCTL_PDS
25+
tristate "AMD/Pensando pds fwctl driver"
26+
depends on PDS_CORE
27+
help
28+
The pds_fwctl driver provides an fwctl interface for a user process
29+
to access the debug and configuration information of the AMD/Pensando
30+
DSC hardware family.
31+
2232
If you don't know what to do here, say N.
2333
endif

drivers/fwctl/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_FWCTL) += fwctl.o
33
obj-$(CONFIG_FWCTL_MLX5) += mlx5/
4+
obj-$(CONFIG_FWCTL_PDS) += pds/
45

56
fwctl-y += main.o

drivers/fwctl/pds/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
obj-$(CONFIG_FWCTL_PDS) += pds_fwctl.o
3+
4+
pds_fwctl-y += main.o

drivers/fwctl/pds/main.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright(c) Advanced Micro Devices, Inc */
3+
4+
#include <linux/module.h>
5+
#include <linux/auxiliary_bus.h>
6+
#include <linux/pci.h>
7+
#include <linux/vmalloc.h>
8+
9+
#include <uapi/fwctl/fwctl.h>
10+
#include <uapi/fwctl/pds.h>
11+
#include <linux/fwctl.h>
12+
13+
#include <linux/pds/pds_common.h>
14+
#include <linux/pds/pds_core_if.h>
15+
#include <linux/pds/pds_adminq.h>
16+
#include <linux/pds/pds_auxbus.h>
17+
18+
struct pdsfc_uctx {
19+
struct fwctl_uctx uctx;
20+
u32 uctx_caps;
21+
};
22+
23+
struct pdsfc_dev {
24+
struct fwctl_device fwctl;
25+
struct pds_auxiliary_dev *padev;
26+
u32 caps;
27+
struct pds_fwctl_ident ident;
28+
};
29+
30+
static int pdsfc_open_uctx(struct fwctl_uctx *uctx)
31+
{
32+
struct pdsfc_dev *pdsfc = container_of(uctx->fwctl, struct pdsfc_dev, fwctl);
33+
struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
34+
35+
pdsfc_uctx->uctx_caps = pdsfc->caps;
36+
37+
return 0;
38+
}
39+
40+
static void pdsfc_close_uctx(struct fwctl_uctx *uctx)
41+
{
42+
}
43+
44+
static void *pdsfc_info(struct fwctl_uctx *uctx, size_t *length)
45+
{
46+
struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
47+
struct fwctl_info_pds *info;
48+
49+
info = kzalloc(sizeof(*info), GFP_KERNEL);
50+
if (!info)
51+
return ERR_PTR(-ENOMEM);
52+
53+
info->uctx_caps = pdsfc_uctx->uctx_caps;
54+
55+
return info;
56+
}
57+
58+
static int pdsfc_identify(struct pdsfc_dev *pdsfc)
59+
{
60+
struct device *dev = &pdsfc->fwctl.dev;
61+
union pds_core_adminq_comp comp = {0};
62+
union pds_core_adminq_cmd cmd;
63+
struct pds_fwctl_ident *ident;
64+
dma_addr_t ident_pa;
65+
int err;
66+
67+
ident = dma_alloc_coherent(dev->parent, sizeof(*ident), &ident_pa, GFP_KERNEL);
68+
if (!ident) {
69+
dev_err(dev, "Failed to map ident buffer\n");
70+
return -ENOMEM;
71+
}
72+
73+
cmd = (union pds_core_adminq_cmd) {
74+
.fwctl_ident = {
75+
.opcode = PDS_FWCTL_CMD_IDENT,
76+
.version = 0,
77+
.len = cpu_to_le32(sizeof(*ident)),
78+
.ident_pa = cpu_to_le64(ident_pa),
79+
}
80+
};
81+
82+
err = pds_client_adminq_cmd(pdsfc->padev, &cmd, sizeof(cmd), &comp, 0);
83+
if (err)
84+
dev_err(dev, "Failed to send adminq cmd opcode: %u err: %d\n",
85+
cmd.fwctl_ident.opcode, err);
86+
else
87+
pdsfc->ident = *ident;
88+
89+
dma_free_coherent(dev->parent, sizeof(*ident), ident, ident_pa);
90+
91+
return err;
92+
}
93+
94+
static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
95+
void *in, size_t in_len, size_t *out_len)
96+
{
97+
return NULL;
98+
}
99+
100+
static const struct fwctl_ops pdsfc_ops = {
101+
.device_type = FWCTL_DEVICE_TYPE_PDS,
102+
.uctx_size = sizeof(struct pdsfc_uctx),
103+
.open_uctx = pdsfc_open_uctx,
104+
.close_uctx = pdsfc_close_uctx,
105+
.info = pdsfc_info,
106+
.fw_rpc = pdsfc_fw_rpc,
107+
};
108+
109+
static int pdsfc_probe(struct auxiliary_device *adev,
110+
const struct auxiliary_device_id *id)
111+
{
112+
struct pds_auxiliary_dev *padev =
113+
container_of(adev, struct pds_auxiliary_dev, aux_dev);
114+
struct device *dev = &adev->dev;
115+
struct pdsfc_dev *pdsfc;
116+
int err;
117+
118+
pdsfc = fwctl_alloc_device(&padev->vf_pdev->dev, &pdsfc_ops,
119+
struct pdsfc_dev, fwctl);
120+
if (!pdsfc)
121+
return dev_err_probe(dev, -ENOMEM, "Failed to allocate fwctl device struct\n");
122+
pdsfc->padev = padev;
123+
124+
err = pdsfc_identify(pdsfc);
125+
if (err) {
126+
fwctl_put(&pdsfc->fwctl);
127+
return dev_err_probe(dev, err, "Failed to identify device\n");
128+
}
129+
130+
err = fwctl_register(&pdsfc->fwctl);
131+
if (err) {
132+
fwctl_put(&pdsfc->fwctl);
133+
return dev_err_probe(dev, err, "Failed to register device\n");
134+
}
135+
136+
auxiliary_set_drvdata(adev, pdsfc);
137+
138+
return 0;
139+
}
140+
141+
static void pdsfc_remove(struct auxiliary_device *adev)
142+
{
143+
struct pdsfc_dev *pdsfc = auxiliary_get_drvdata(adev);
144+
145+
fwctl_unregister(&pdsfc->fwctl);
146+
fwctl_put(&pdsfc->fwctl);
147+
}
148+
149+
static const struct auxiliary_device_id pdsfc_id_table[] = {
150+
{.name = PDS_CORE_DRV_NAME "." PDS_DEV_TYPE_FWCTL_STR },
151+
{}
152+
};
153+
MODULE_DEVICE_TABLE(auxiliary, pdsfc_id_table);
154+
155+
static struct auxiliary_driver pdsfc_driver = {
156+
.name = "pds_fwctl",
157+
.probe = pdsfc_probe,
158+
.remove = pdsfc_remove,
159+
.id_table = pdsfc_id_table,
160+
};
161+
162+
module_auxiliary_driver(pdsfc_driver);
163+
164+
MODULE_IMPORT_NS("FWCTL");
165+
MODULE_DESCRIPTION("pds fwctl driver");
166+
MODULE_AUTHOR("Shannon Nelson <[email protected]>");
167+
MODULE_AUTHOR("Brett Creeley <[email protected]>");
168+
MODULE_LICENSE("GPL");

include/linux/pds/pds_adminq.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,84 @@ struct pds_lm_host_vf_status_cmd {
11791179
u8 status;
11801180
};
11811181

1182+
enum pds_fwctl_cmd_opcode {
1183+
PDS_FWCTL_CMD_IDENT = 70,
1184+
};
1185+
1186+
/**
1187+
* struct pds_fwctl_cmd - Firmware control command structure
1188+
* @opcode: Opcode
1189+
* @rsvd: Reserved
1190+
* @ep: Endpoint identifier
1191+
* @op: Operation identifier
1192+
*/
1193+
struct pds_fwctl_cmd {
1194+
u8 opcode;
1195+
u8 rsvd[3];
1196+
__le32 ep;
1197+
__le32 op;
1198+
} __packed;
1199+
1200+
/**
1201+
* struct pds_fwctl_comp - Firmware control completion structure
1202+
* @status: Status of the firmware control operation
1203+
* @rsvd: Reserved
1204+
* @comp_index: Completion index in little-endian format
1205+
* @rsvd2: Reserved
1206+
* @color: Color bit indicating the state of the completion
1207+
*/
1208+
struct pds_fwctl_comp {
1209+
u8 status;
1210+
u8 rsvd;
1211+
__le16 comp_index;
1212+
u8 rsvd2[11];
1213+
u8 color;
1214+
} __packed;
1215+
1216+
/**
1217+
* struct pds_fwctl_ident_cmd - Firmware control identification command structure
1218+
* @opcode: Operation code for the command
1219+
* @rsvd: Reserved
1220+
* @version: Interface version
1221+
* @rsvd2: Reserved
1222+
* @len: Length of the identification data
1223+
* @ident_pa: Physical address of the identification data
1224+
*/
1225+
struct pds_fwctl_ident_cmd {
1226+
u8 opcode;
1227+
u8 rsvd;
1228+
u8 version;
1229+
u8 rsvd2;
1230+
__le32 len;
1231+
__le64 ident_pa;
1232+
} __packed;
1233+
1234+
/* future feature bits here
1235+
* enum pds_fwctl_features {
1236+
* };
1237+
* (compilers don't like empty enums)
1238+
*/
1239+
1240+
/**
1241+
* struct pds_fwctl_ident - Firmware control identification structure
1242+
* @features: Supported features (enum pds_fwctl_features)
1243+
* @version: Interface version
1244+
* @rsvd: Reserved
1245+
* @max_req_sz: Maximum request size
1246+
* @max_resp_sz: Maximum response size
1247+
* @max_req_sg_elems: Maximum number of request SGs
1248+
* @max_resp_sg_elems: Maximum number of response SGs
1249+
*/
1250+
struct pds_fwctl_ident {
1251+
__le64 features;
1252+
u8 version;
1253+
u8 rsvd[3];
1254+
__le32 max_req_sz;
1255+
__le32 max_resp_sz;
1256+
u8 max_req_sg_elems;
1257+
u8 max_resp_sg_elems;
1258+
} __packed;
1259+
11821260
union pds_core_adminq_cmd {
11831261
u8 opcode;
11841262
u8 bytes[64];
@@ -1216,6 +1294,9 @@ union pds_core_adminq_cmd {
12161294
struct pds_lm_dirty_enable_cmd lm_dirty_enable;
12171295
struct pds_lm_dirty_disable_cmd lm_dirty_disable;
12181296
struct pds_lm_dirty_seq_ack_cmd lm_dirty_seq_ack;
1297+
1298+
struct pds_fwctl_cmd fwctl;
1299+
struct pds_fwctl_ident_cmd fwctl_ident;
12191300
};
12201301

12211302
union pds_core_adminq_comp {
@@ -1243,6 +1324,8 @@ union pds_core_adminq_comp {
12431324

12441325
struct pds_lm_state_size_comp lm_state_size;
12451326
struct pds_lm_dirty_status_comp lm_dirty_status;
1327+
1328+
struct pds_fwctl_comp fwctl;
12461329
};
12471330

12481331
#ifndef __CHECKER__

include/uapi/fwctl/fwctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum fwctl_device_type {
4444
FWCTL_DEVICE_TYPE_ERROR = 0,
4545
FWCTL_DEVICE_TYPE_MLX5 = 1,
4646
FWCTL_DEVICE_TYPE_CXL = 2,
47+
FWCTL_DEVICE_TYPE_PDS = 4,
4748
};
4849

4950
/**

include/uapi/fwctl/pds.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
/* Copyright(c) Advanced Micro Devices, Inc */
3+
4+
/*
5+
* fwctl interface info for pds_fwctl
6+
*/
7+
8+
#ifndef _UAPI_FWCTL_PDS_H_
9+
#define _UAPI_FWCTL_PDS_H_
10+
11+
#include <linux/types.h>
12+
13+
/**
14+
* struct fwctl_info_pds
15+
* @uctx_caps: bitmap of firmware capabilities
16+
*
17+
* Return basic information about the FW interface available.
18+
*/
19+
struct fwctl_info_pds {
20+
__u32 uctx_caps;
21+
};
22+
23+
/**
24+
* enum pds_fwctl_capabilities
25+
* @PDS_FWCTL_QUERY_CAP: firmware can be queried for information
26+
* @PDS_FWCTL_SEND_CAP: firmware can be sent commands
27+
*/
28+
enum pds_fwctl_capabilities {
29+
PDS_FWCTL_QUERY_CAP = 0,
30+
PDS_FWCTL_SEND_CAP,
31+
};
32+
#endif /* _UAPI_FWCTL_PDS_H_ */

0 commit comments

Comments
 (0)