12e3cf97fSAlex Elder // SPDX-License-Identifier: GPL-2.0
22e3cf97fSAlex Elder
3a4388da5SAlex Elder /* Copyright (C) 2021-2022 Linaro Ltd. */
42e3cf97fSAlex Elder
52e3cf97fSAlex Elder #include <linux/kernel.h>
62e3cf97fSAlex Elder #include <linux/types.h>
72e3cf97fSAlex Elder #include <linux/device.h>
82e3cf97fSAlex Elder #include <linux/sysfs.h>
92e3cf97fSAlex Elder
102e3cf97fSAlex Elder #include "ipa.h"
112e3cf97fSAlex Elder #include "ipa_version.h"
122e3cf97fSAlex Elder #include "ipa_sysfs.h"
132e3cf97fSAlex Elder
ipa_version_string(struct ipa * ipa)142e3cf97fSAlex Elder static const char *ipa_version_string(struct ipa *ipa)
152e3cf97fSAlex Elder {
162e3cf97fSAlex Elder switch (ipa->version) {
172e3cf97fSAlex Elder case IPA_VERSION_3_0:
182e3cf97fSAlex Elder return "3.0";
192e3cf97fSAlex Elder case IPA_VERSION_3_1:
202e3cf97fSAlex Elder return "3.1";
212e3cf97fSAlex Elder case IPA_VERSION_3_5:
222e3cf97fSAlex Elder return "3.5";
232e3cf97fSAlex Elder case IPA_VERSION_3_5_1:
242e3cf97fSAlex Elder return "3.5.1";
252e3cf97fSAlex Elder case IPA_VERSION_4_0:
262e3cf97fSAlex Elder return "4.0";
272e3cf97fSAlex Elder case IPA_VERSION_4_1:
282e3cf97fSAlex Elder return "4.1";
292e3cf97fSAlex Elder case IPA_VERSION_4_2:
302e3cf97fSAlex Elder return "4.2";
312e3cf97fSAlex Elder case IPA_VERSION_4_5:
322e3cf97fSAlex Elder return "4.5";
332e3cf97fSAlex Elder case IPA_VERSION_4_7:
342e3cf97fSAlex Elder return "4.7";
352e3cf97fSAlex Elder case IPA_VERSION_4_9:
362e3cf97fSAlex Elder return "4.9";
372e3cf97fSAlex Elder case IPA_VERSION_4_11:
382e3cf97fSAlex Elder return "4.11";
39*0c04328cSAlex Elder case IPA_VERSION_5_0:
40*0c04328cSAlex Elder return "5.0";
412e3cf97fSAlex Elder default:
422e3cf97fSAlex Elder return "0.0"; /* Won't happen (checked at probe time) */
432e3cf97fSAlex Elder }
442e3cf97fSAlex Elder }
452e3cf97fSAlex Elder
462e3cf97fSAlex Elder static ssize_t
version_show(struct device * dev,struct device_attribute * attr,char * buf)472e3cf97fSAlex Elder version_show(struct device *dev, struct device_attribute *attr, char *buf)
482e3cf97fSAlex Elder {
492e3cf97fSAlex Elder struct ipa *ipa = dev_get_drvdata(dev);
502e3cf97fSAlex Elder
5138db82e2Sye xingchen return sysfs_emit(buf, "%s\n", ipa_version_string(ipa));
522e3cf97fSAlex Elder }
532e3cf97fSAlex Elder
542e3cf97fSAlex Elder static DEVICE_ATTR_RO(version);
552e3cf97fSAlex Elder
562e3cf97fSAlex Elder static struct attribute *ipa_attrs[] = {
572e3cf97fSAlex Elder &dev_attr_version.attr,
582e3cf97fSAlex Elder NULL
592e3cf97fSAlex Elder };
602e3cf97fSAlex Elder
612e3cf97fSAlex Elder const struct attribute_group ipa_attribute_group = {
622e3cf97fSAlex Elder .attrs = ipa_attrs,
632e3cf97fSAlex Elder };
642e3cf97fSAlex Elder
ipa_offload_string(struct ipa * ipa)652e3cf97fSAlex Elder static const char *ipa_offload_string(struct ipa *ipa)
662e3cf97fSAlex Elder {
672e3cf97fSAlex Elder return ipa->version < IPA_VERSION_4_5 ? "MAPv4" : "MAPv5";
682e3cf97fSAlex Elder }
692e3cf97fSAlex Elder
rx_offload_show(struct device * dev,struct device_attribute * attr,char * buf)702e3cf97fSAlex Elder static ssize_t rx_offload_show(struct device *dev,
712e3cf97fSAlex Elder struct device_attribute *attr, char *buf)
722e3cf97fSAlex Elder {
732e3cf97fSAlex Elder struct ipa *ipa = dev_get_drvdata(dev);
742e3cf97fSAlex Elder
7538db82e2Sye xingchen return sysfs_emit(buf, "%s\n", ipa_offload_string(ipa));
762e3cf97fSAlex Elder }
772e3cf97fSAlex Elder
782e3cf97fSAlex Elder static DEVICE_ATTR_RO(rx_offload);
792e3cf97fSAlex Elder
tx_offload_show(struct device * dev,struct device_attribute * attr,char * buf)802e3cf97fSAlex Elder static ssize_t tx_offload_show(struct device *dev,
812e3cf97fSAlex Elder struct device_attribute *attr, char *buf)
822e3cf97fSAlex Elder {
832e3cf97fSAlex Elder struct ipa *ipa = dev_get_drvdata(dev);
842e3cf97fSAlex Elder
8538db82e2Sye xingchen return sysfs_emit(buf, "%s\n", ipa_offload_string(ipa));
862e3cf97fSAlex Elder }
872e3cf97fSAlex Elder
882e3cf97fSAlex Elder static DEVICE_ATTR_RO(tx_offload);
892e3cf97fSAlex Elder
902e3cf97fSAlex Elder static struct attribute *ipa_feature_attrs[] = {
912e3cf97fSAlex Elder &dev_attr_rx_offload.attr,
922e3cf97fSAlex Elder &dev_attr_tx_offload.attr,
932e3cf97fSAlex Elder NULL
942e3cf97fSAlex Elder };
952e3cf97fSAlex Elder
962e3cf97fSAlex Elder const struct attribute_group ipa_feature_attribute_group = {
972e3cf97fSAlex Elder .name = "feature",
982e3cf97fSAlex Elder .attrs = ipa_feature_attrs,
992e3cf97fSAlex Elder };
1002e3cf97fSAlex Elder
ipa_endpoint_id_is_visible(struct kobject * kobj,struct attribute * attr,int n)101d79e4164SAlex Elder static umode_t ipa_endpoint_id_is_visible(struct kobject *kobj,
102d79e4164SAlex Elder struct attribute *attr, int n)
1032e3cf97fSAlex Elder {
104d79e4164SAlex Elder struct ipa *ipa = dev_get_drvdata(kobj_to_dev(kobj));
105d79e4164SAlex Elder struct device_attribute *dev_attr;
106d79e4164SAlex Elder struct dev_ext_attribute *ea;
107d79e4164SAlex Elder bool visible;
1082e3cf97fSAlex Elder
109d79e4164SAlex Elder /* An endpoint id attribute is only visible if it's defined */
110d79e4164SAlex Elder dev_attr = container_of(attr, struct device_attribute, attr);
111d79e4164SAlex Elder ea = container_of(dev_attr, struct dev_ext_attribute, attr);
112d79e4164SAlex Elder
113d79e4164SAlex Elder visible = !!ipa->name_map[(enum ipa_endpoint_name)(uintptr_t)ea->var];
114d79e4164SAlex Elder
115d79e4164SAlex Elder return visible ? attr->mode : 0;
1162e3cf97fSAlex Elder }
1172e3cf97fSAlex Elder
endpoint_id_attr_show(struct device * dev,struct device_attribute * attr,char * buf)118d79e4164SAlex Elder static ssize_t endpoint_id_attr_show(struct device *dev,
1192e3cf97fSAlex Elder struct device_attribute *attr, char *buf)
1202e3cf97fSAlex Elder {
1212e3cf97fSAlex Elder struct ipa *ipa = dev_get_drvdata(dev);
122d79e4164SAlex Elder struct ipa_endpoint *endpoint;
123d79e4164SAlex Elder struct dev_ext_attribute *ea;
1242e3cf97fSAlex Elder
125d79e4164SAlex Elder ea = container_of(attr, struct dev_ext_attribute, attr);
126d79e4164SAlex Elder endpoint = ipa->name_map[(enum ipa_endpoint_name)(uintptr_t)ea->var];
127d79e4164SAlex Elder
128d79e4164SAlex Elder return sysfs_emit(buf, "%u\n", endpoint->endpoint_id);
1292e3cf97fSAlex Elder }
1302e3cf97fSAlex Elder
131d79e4164SAlex Elder #define ENDPOINT_ID_ATTR(_n, _endpoint_name) \
132d79e4164SAlex Elder static struct dev_ext_attribute dev_attr_endpoint_id_ ## _n = { \
133d79e4164SAlex Elder .attr = __ATTR(_n, 0444, endpoint_id_attr_show, NULL), \
134d79e4164SAlex Elder .var = (void *)(_endpoint_name), \
1352e3cf97fSAlex Elder }
1362e3cf97fSAlex Elder
137d79e4164SAlex Elder ENDPOINT_ID_ATTR(modem_rx, IPA_ENDPOINT_AP_MODEM_RX);
138d79e4164SAlex Elder ENDPOINT_ID_ATTR(modem_tx, IPA_ENDPOINT_AP_MODEM_TX);
139d79e4164SAlex Elder
140d79e4164SAlex Elder static struct attribute *ipa_endpoint_id_attrs[] = {
141d79e4164SAlex Elder &dev_attr_endpoint_id_modem_rx.attr.attr,
142d79e4164SAlex Elder &dev_attr_endpoint_id_modem_tx.attr.attr,
143d79e4164SAlex Elder NULL
144d79e4164SAlex Elder };
145d79e4164SAlex Elder
146d79e4164SAlex Elder const struct attribute_group ipa_endpoint_id_attribute_group = {
147d79e4164SAlex Elder .name = "endpoint_id",
148d79e4164SAlex Elder .is_visible = ipa_endpoint_id_is_visible,
149d79e4164SAlex Elder .attrs = ipa_endpoint_id_attrs,
150d79e4164SAlex Elder };
151d79e4164SAlex Elder
152d79e4164SAlex Elder /* Reuse endpoint ID attributes for the legacy modem endpoint IDs */
153d79e4164SAlex Elder #define MODEM_ATTR(_n, _endpoint_name) \
154d79e4164SAlex Elder static struct dev_ext_attribute dev_attr_modem_ ## _n = { \
155d79e4164SAlex Elder .attr = __ATTR(_n, 0444, endpoint_id_attr_show, NULL), \
156d79e4164SAlex Elder .var = (void *)(_endpoint_name), \
157d79e4164SAlex Elder }
158d79e4164SAlex Elder
159d79e4164SAlex Elder MODEM_ATTR(rx_endpoint_id, IPA_ENDPOINT_AP_MODEM_RX);
160d79e4164SAlex Elder MODEM_ATTR(tx_endpoint_id, IPA_ENDPOINT_AP_MODEM_TX);
1612e3cf97fSAlex Elder
1622e3cf97fSAlex Elder static struct attribute *ipa_modem_attrs[] = {
163d79e4164SAlex Elder &dev_attr_modem_rx_endpoint_id.attr.attr,
164d79e4164SAlex Elder &dev_attr_modem_tx_endpoint_id.attr.attr,
165d79e4164SAlex Elder NULL,
1662e3cf97fSAlex Elder };
1672e3cf97fSAlex Elder
1682e3cf97fSAlex Elder const struct attribute_group ipa_modem_attribute_group = {
1692e3cf97fSAlex Elder .name = "modem",
1702e3cf97fSAlex Elder .attrs = ipa_modem_attrs,
1712e3cf97fSAlex Elder };
172