1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3
4 #include <linux/unaligned.h>
5 #include <linux/pci.h>
6 #include <linux/types.h>
7 #include <net/devlink.h>
8
9 #include "fbnic.h"
10
11 #define FBNIC_SN_STR_LEN 24
12
fbnic_version_running_put(struct devlink_info_req * req,struct fbnic_fw_ver * fw_ver,char * ver_name)13 static int fbnic_version_running_put(struct devlink_info_req *req,
14 struct fbnic_fw_ver *fw_ver,
15 char *ver_name)
16 {
17 char running_ver[FBNIC_FW_VER_MAX_SIZE];
18 int err;
19
20 fbnic_mk_fw_ver_str(fw_ver->version, running_ver);
21 err = devlink_info_version_running_put(req, ver_name, running_ver);
22 if (err)
23 return err;
24
25 if (strlen(fw_ver->commit) > 0) {
26 char commit_name[FBNIC_SN_STR_LEN];
27
28 snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
29 err = devlink_info_version_running_put(req, commit_name,
30 fw_ver->commit);
31 if (err)
32 return err;
33 }
34
35 return 0;
36 }
37
fbnic_version_stored_put(struct devlink_info_req * req,struct fbnic_fw_ver * fw_ver,char * ver_name)38 static int fbnic_version_stored_put(struct devlink_info_req *req,
39 struct fbnic_fw_ver *fw_ver,
40 char *ver_name)
41 {
42 char stored_ver[FBNIC_FW_VER_MAX_SIZE];
43 int err;
44
45 fbnic_mk_fw_ver_str(fw_ver->version, stored_ver);
46 err = devlink_info_version_stored_put(req, ver_name, stored_ver);
47 if (err)
48 return err;
49
50 if (strlen(fw_ver->commit) > 0) {
51 char commit_name[FBNIC_SN_STR_LEN];
52
53 snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
54 err = devlink_info_version_stored_put(req, commit_name,
55 fw_ver->commit);
56 if (err)
57 return err;
58 }
59
60 return 0;
61 }
62
fbnic_devlink_info_get(struct devlink * devlink,struct devlink_info_req * req,struct netlink_ext_ack * extack)63 static int fbnic_devlink_info_get(struct devlink *devlink,
64 struct devlink_info_req *req,
65 struct netlink_ext_ack *extack)
66 {
67 struct fbnic_dev *fbd = devlink_priv(devlink);
68 int err;
69
70 err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt,
71 DEVLINK_INFO_VERSION_GENERIC_FW);
72 if (err)
73 return err;
74
75 err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader,
76 DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
77 if (err)
78 return err;
79
80 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt,
81 DEVLINK_INFO_VERSION_GENERIC_FW);
82 if (err)
83 return err;
84
85 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader,
86 DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
87 if (err)
88 return err;
89
90 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi,
91 DEVLINK_INFO_VERSION_GENERIC_FW_UNDI);
92 if (err)
93 return err;
94
95 if (fbd->dsn) {
96 unsigned char serial[FBNIC_SN_STR_LEN];
97 u8 dsn[8];
98
99 put_unaligned_be64(fbd->dsn, dsn);
100 err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn);
101 if (err < 0)
102 return err;
103
104 err = devlink_info_serial_number_put(req, serial);
105 if (err)
106 return err;
107 }
108
109 return 0;
110 }
111
112 static const struct devlink_ops fbnic_devlink_ops = {
113 .info_get = fbnic_devlink_info_get,
114 };
115
fbnic_devlink_free(struct fbnic_dev * fbd)116 void fbnic_devlink_free(struct fbnic_dev *fbd)
117 {
118 struct devlink *devlink = priv_to_devlink(fbd);
119
120 devlink_free(devlink);
121 }
122
fbnic_devlink_alloc(struct pci_dev * pdev)123 struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
124 {
125 void __iomem * const *iomap_table;
126 struct devlink *devlink;
127 struct fbnic_dev *fbd;
128
129 devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
130 &pdev->dev);
131 if (!devlink)
132 return NULL;
133
134 fbd = devlink_priv(devlink);
135 pci_set_drvdata(pdev, fbd);
136 fbd->dev = &pdev->dev;
137
138 iomap_table = pcim_iomap_table(pdev);
139 fbd->uc_addr0 = iomap_table[0];
140 fbd->uc_addr4 = iomap_table[4];
141
142 fbd->dsn = pci_get_dsn(pdev);
143 fbd->mps = pcie_get_mps(pdev);
144 fbd->readrq = pcie_get_readrq(pdev);
145
146 fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
147
148 return fbd;
149 }
150
fbnic_devlink_register(struct fbnic_dev * fbd)151 void fbnic_devlink_register(struct fbnic_dev *fbd)
152 {
153 struct devlink *devlink = priv_to_devlink(fbd);
154
155 devlink_register(devlink);
156 }
157
fbnic_devlink_unregister(struct fbnic_dev * fbd)158 void fbnic_devlink_unregister(struct fbnic_dev *fbd)
159 {
160 struct devlink *devlink = priv_to_devlink(fbd);
161
162 devlink_unregister(devlink);
163 }
164