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