18465def4SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
28465def4SGreg Kroah-Hartman /*
38465def4SGreg Kroah-Hartman * SVC Greybus driver.
48465def4SGreg Kroah-Hartman *
58465def4SGreg Kroah-Hartman * Copyright 2015 Google Inc.
68465def4SGreg Kroah-Hartman * Copyright 2015 Linaro Ltd.
78465def4SGreg Kroah-Hartman */
88465def4SGreg Kroah-Hartman
98465def4SGreg Kroah-Hartman #include <linux/debugfs.h>
100d4a030bSChristophe JAILLET #include <linux/kstrtox.h>
118465def4SGreg Kroah-Hartman #include <linux/workqueue.h>
128465def4SGreg Kroah-Hartman #include <linux/greybus.h>
138465def4SGreg Kroah-Hartman
148465def4SGreg Kroah-Hartman #define SVC_INTF_EJECT_TIMEOUT 9000
158465def4SGreg Kroah-Hartman #define SVC_INTF_ACTIVATE_TIMEOUT 6000
168465def4SGreg Kroah-Hartman #define SVC_INTF_RESUME_TIMEOUT 3000
178465def4SGreg Kroah-Hartman
188465def4SGreg Kroah-Hartman struct gb_svc_deferred_request {
198465def4SGreg Kroah-Hartman struct work_struct work;
208465def4SGreg Kroah-Hartman struct gb_operation *operation;
218465def4SGreg Kroah-Hartman };
228465def4SGreg Kroah-Hartman
238465def4SGreg Kroah-Hartman static int gb_svc_queue_deferred_request(struct gb_operation *operation);
248465def4SGreg Kroah-Hartman
endo_id_show(struct device * dev,struct device_attribute * attr,char * buf)258465def4SGreg Kroah-Hartman static ssize_t endo_id_show(struct device *dev,
268465def4SGreg Kroah-Hartman struct device_attribute *attr, char *buf)
278465def4SGreg Kroah-Hartman {
288465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
298465def4SGreg Kroah-Hartman
308465def4SGreg Kroah-Hartman return sprintf(buf, "0x%04x\n", svc->endo_id);
318465def4SGreg Kroah-Hartman }
328465def4SGreg Kroah-Hartman static DEVICE_ATTR_RO(endo_id);
338465def4SGreg Kroah-Hartman
ap_intf_id_show(struct device * dev,struct device_attribute * attr,char * buf)348465def4SGreg Kroah-Hartman static ssize_t ap_intf_id_show(struct device *dev,
358465def4SGreg Kroah-Hartman struct device_attribute *attr, char *buf)
368465def4SGreg Kroah-Hartman {
378465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
388465def4SGreg Kroah-Hartman
398465def4SGreg Kroah-Hartman return sprintf(buf, "%u\n", svc->ap_intf_id);
408465def4SGreg Kroah-Hartman }
418465def4SGreg Kroah-Hartman static DEVICE_ATTR_RO(ap_intf_id);
428465def4SGreg Kroah-Hartman
438465def4SGreg Kroah-Hartman // FIXME
448465def4SGreg Kroah-Hartman // This is a hack, we need to do this "right" and clean the interface up
458465def4SGreg Kroah-Hartman // properly, not just forcibly yank the thing out of the system and hope for the
468465def4SGreg Kroah-Hartman // best. But for now, people want their modules to come out without having to
478465def4SGreg Kroah-Hartman // throw the thing to the ground or get out a screwdriver.
intf_eject_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)488465def4SGreg Kroah-Hartman static ssize_t intf_eject_store(struct device *dev,
498465def4SGreg Kroah-Hartman struct device_attribute *attr, const char *buf,
508465def4SGreg Kroah-Hartman size_t len)
518465def4SGreg Kroah-Hartman {
528465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
538465def4SGreg Kroah-Hartman unsigned short intf_id;
548465def4SGreg Kroah-Hartman int ret;
558465def4SGreg Kroah-Hartman
568465def4SGreg Kroah-Hartman ret = kstrtou16(buf, 10, &intf_id);
578465def4SGreg Kroah-Hartman if (ret < 0)
588465def4SGreg Kroah-Hartman return ret;
598465def4SGreg Kroah-Hartman
608465def4SGreg Kroah-Hartman dev_warn(dev, "Forcibly trying to eject interface %d\n", intf_id);
618465def4SGreg Kroah-Hartman
628465def4SGreg Kroah-Hartman ret = gb_svc_intf_eject(svc, intf_id);
638465def4SGreg Kroah-Hartman if (ret < 0)
648465def4SGreg Kroah-Hartman return ret;
658465def4SGreg Kroah-Hartman
668465def4SGreg Kroah-Hartman return len;
678465def4SGreg Kroah-Hartman }
688465def4SGreg Kroah-Hartman static DEVICE_ATTR_WO(intf_eject);
698465def4SGreg Kroah-Hartman
watchdog_show(struct device * dev,struct device_attribute * attr,char * buf)708465def4SGreg Kroah-Hartman static ssize_t watchdog_show(struct device *dev, struct device_attribute *attr,
718465def4SGreg Kroah-Hartman char *buf)
728465def4SGreg Kroah-Hartman {
738465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
748465def4SGreg Kroah-Hartman
758465def4SGreg Kroah-Hartman return sprintf(buf, "%s\n",
768465def4SGreg Kroah-Hartman gb_svc_watchdog_enabled(svc) ? "enabled" : "disabled");
778465def4SGreg Kroah-Hartman }
788465def4SGreg Kroah-Hartman
watchdog_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)798465def4SGreg Kroah-Hartman static ssize_t watchdog_store(struct device *dev,
808465def4SGreg Kroah-Hartman struct device_attribute *attr, const char *buf,
818465def4SGreg Kroah-Hartman size_t len)
828465def4SGreg Kroah-Hartman {
838465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
848465def4SGreg Kroah-Hartman int retval;
858465def4SGreg Kroah-Hartman bool user_request;
868465def4SGreg Kroah-Hartman
870d4a030bSChristophe JAILLET retval = kstrtobool(buf, &user_request);
888465def4SGreg Kroah-Hartman if (retval)
898465def4SGreg Kroah-Hartman return retval;
908465def4SGreg Kroah-Hartman
918465def4SGreg Kroah-Hartman if (user_request)
928465def4SGreg Kroah-Hartman retval = gb_svc_watchdog_enable(svc);
938465def4SGreg Kroah-Hartman else
948465def4SGreg Kroah-Hartman retval = gb_svc_watchdog_disable(svc);
958465def4SGreg Kroah-Hartman if (retval)
968465def4SGreg Kroah-Hartman return retval;
978465def4SGreg Kroah-Hartman return len;
988465def4SGreg Kroah-Hartman }
998465def4SGreg Kroah-Hartman static DEVICE_ATTR_RW(watchdog);
1008465def4SGreg Kroah-Hartman
watchdog_action_show(struct device * dev,struct device_attribute * attr,char * buf)1018465def4SGreg Kroah-Hartman static ssize_t watchdog_action_show(struct device *dev,
1028465def4SGreg Kroah-Hartman struct device_attribute *attr, char *buf)
1038465def4SGreg Kroah-Hartman {
1048465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
1058465def4SGreg Kroah-Hartman
1068465def4SGreg Kroah-Hartman if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL)
1078465def4SGreg Kroah-Hartman return sprintf(buf, "panic\n");
1088465def4SGreg Kroah-Hartman else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO)
1098465def4SGreg Kroah-Hartman return sprintf(buf, "reset\n");
1108465def4SGreg Kroah-Hartman
1118465def4SGreg Kroah-Hartman return -EINVAL;
1128465def4SGreg Kroah-Hartman }
1138465def4SGreg Kroah-Hartman
watchdog_action_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1148465def4SGreg Kroah-Hartman static ssize_t watchdog_action_store(struct device *dev,
1158465def4SGreg Kroah-Hartman struct device_attribute *attr,
1168465def4SGreg Kroah-Hartman const char *buf, size_t len)
1178465def4SGreg Kroah-Hartman {
1188465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
1198465def4SGreg Kroah-Hartman
1208465def4SGreg Kroah-Hartman if (sysfs_streq(buf, "panic"))
1218465def4SGreg Kroah-Hartman svc->action = GB_SVC_WATCHDOG_BITE_PANIC_KERNEL;
1228465def4SGreg Kroah-Hartman else if (sysfs_streq(buf, "reset"))
1238465def4SGreg Kroah-Hartman svc->action = GB_SVC_WATCHDOG_BITE_RESET_UNIPRO;
1248465def4SGreg Kroah-Hartman else
1258465def4SGreg Kroah-Hartman return -EINVAL;
1268465def4SGreg Kroah-Hartman
1278465def4SGreg Kroah-Hartman return len;
1288465def4SGreg Kroah-Hartman }
1298465def4SGreg Kroah-Hartman static DEVICE_ATTR_RW(watchdog_action);
1308465def4SGreg Kroah-Hartman
gb_svc_pwrmon_rail_count_get(struct gb_svc * svc,u8 * value)1318465def4SGreg Kroah-Hartman static int gb_svc_pwrmon_rail_count_get(struct gb_svc *svc, u8 *value)
1328465def4SGreg Kroah-Hartman {
1338465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_rail_count_get_response response;
1348465def4SGreg Kroah-Hartman int ret;
1358465def4SGreg Kroah-Hartman
1368465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection,
1378465def4SGreg Kroah-Hartman GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET, NULL, 0,
1388465def4SGreg Kroah-Hartman &response, sizeof(response));
1398465def4SGreg Kroah-Hartman if (ret) {
1408465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get rail count: %d\n", ret);
1418465def4SGreg Kroah-Hartman return ret;
1428465def4SGreg Kroah-Hartman }
1438465def4SGreg Kroah-Hartman
1448465def4SGreg Kroah-Hartman *value = response.rail_count;
1458465def4SGreg Kroah-Hartman
1468465def4SGreg Kroah-Hartman return 0;
1478465def4SGreg Kroah-Hartman }
1488465def4SGreg Kroah-Hartman
gb_svc_pwrmon_rail_names_get(struct gb_svc * svc,struct gb_svc_pwrmon_rail_names_get_response * response,size_t bufsize)1498465def4SGreg Kroah-Hartman static int gb_svc_pwrmon_rail_names_get(struct gb_svc *svc,
1508465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_rail_names_get_response *response,
1518465def4SGreg Kroah-Hartman size_t bufsize)
1528465def4SGreg Kroah-Hartman {
1538465def4SGreg Kroah-Hartman int ret;
1548465def4SGreg Kroah-Hartman
1558465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection,
1568465def4SGreg Kroah-Hartman GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET, NULL, 0,
1578465def4SGreg Kroah-Hartman response, bufsize);
1588465def4SGreg Kroah-Hartman if (ret) {
1598465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get rail names: %d\n", ret);
1608465def4SGreg Kroah-Hartman return ret;
1618465def4SGreg Kroah-Hartman }
1628465def4SGreg Kroah-Hartman
1638465def4SGreg Kroah-Hartman if (response->status != GB_SVC_OP_SUCCESS) {
1648465def4SGreg Kroah-Hartman dev_err(&svc->dev,
1658465def4SGreg Kroah-Hartman "SVC error while getting rail names: %u\n",
1668465def4SGreg Kroah-Hartman response->status);
1678465def4SGreg Kroah-Hartman return -EREMOTEIO;
1688465def4SGreg Kroah-Hartman }
1698465def4SGreg Kroah-Hartman
1708465def4SGreg Kroah-Hartman return 0;
1718465def4SGreg Kroah-Hartman }
1728465def4SGreg Kroah-Hartman
gb_svc_pwrmon_sample_get(struct gb_svc * svc,u8 rail_id,u8 measurement_type,u32 * value)1738465def4SGreg Kroah-Hartman static int gb_svc_pwrmon_sample_get(struct gb_svc *svc, u8 rail_id,
1748465def4SGreg Kroah-Hartman u8 measurement_type, u32 *value)
1758465def4SGreg Kroah-Hartman {
1768465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_sample_get_request request;
1778465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_sample_get_response response;
1788465def4SGreg Kroah-Hartman int ret;
1798465def4SGreg Kroah-Hartman
1808465def4SGreg Kroah-Hartman request.rail_id = rail_id;
1818465def4SGreg Kroah-Hartman request.measurement_type = measurement_type;
1828465def4SGreg Kroah-Hartman
1838465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_PWRMON_SAMPLE_GET,
1848465def4SGreg Kroah-Hartman &request, sizeof(request),
1858465def4SGreg Kroah-Hartman &response, sizeof(response));
1868465def4SGreg Kroah-Hartman if (ret) {
1878465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get rail sample: %d\n", ret);
1888465def4SGreg Kroah-Hartman return ret;
1898465def4SGreg Kroah-Hartman }
1908465def4SGreg Kroah-Hartman
1918465def4SGreg Kroah-Hartman if (response.result) {
1928465def4SGreg Kroah-Hartman dev_err(&svc->dev,
1938465def4SGreg Kroah-Hartman "UniPro error while getting rail power sample (%d %d): %d\n",
1948465def4SGreg Kroah-Hartman rail_id, measurement_type, response.result);
1958465def4SGreg Kroah-Hartman switch (response.result) {
1968465def4SGreg Kroah-Hartman case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
1978465def4SGreg Kroah-Hartman return -EINVAL;
1988465def4SGreg Kroah-Hartman case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
1998465def4SGreg Kroah-Hartman return -ENOMSG;
2008465def4SGreg Kroah-Hartman default:
2018465def4SGreg Kroah-Hartman return -EREMOTEIO;
2028465def4SGreg Kroah-Hartman }
2038465def4SGreg Kroah-Hartman }
2048465def4SGreg Kroah-Hartman
2058465def4SGreg Kroah-Hartman *value = le32_to_cpu(response.measurement);
2068465def4SGreg Kroah-Hartman
2078465def4SGreg Kroah-Hartman return 0;
2088465def4SGreg Kroah-Hartman }
2098465def4SGreg Kroah-Hartman
gb_svc_pwrmon_intf_sample_get(struct gb_svc * svc,u8 intf_id,u8 measurement_type,u32 * value)2108465def4SGreg Kroah-Hartman int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
2118465def4SGreg Kroah-Hartman u8 measurement_type, u32 *value)
2128465def4SGreg Kroah-Hartman {
2138465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_intf_sample_get_request request;
2148465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_intf_sample_get_response response;
2158465def4SGreg Kroah-Hartman int ret;
2168465def4SGreg Kroah-Hartman
2178465def4SGreg Kroah-Hartman request.intf_id = intf_id;
2188465def4SGreg Kroah-Hartman request.measurement_type = measurement_type;
2198465def4SGreg Kroah-Hartman
2208465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection,
2218465def4SGreg Kroah-Hartman GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET,
2228465def4SGreg Kroah-Hartman &request, sizeof(request),
2238465def4SGreg Kroah-Hartman &response, sizeof(response));
2248465def4SGreg Kroah-Hartman if (ret) {
2258465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get intf sample: %d\n", ret);
2268465def4SGreg Kroah-Hartman return ret;
2278465def4SGreg Kroah-Hartman }
2288465def4SGreg Kroah-Hartman
2298465def4SGreg Kroah-Hartman if (response.result) {
2308465def4SGreg Kroah-Hartman dev_err(&svc->dev,
2318465def4SGreg Kroah-Hartman "UniPro error while getting intf power sample (%d %d): %d\n",
2328465def4SGreg Kroah-Hartman intf_id, measurement_type, response.result);
2338465def4SGreg Kroah-Hartman switch (response.result) {
2348465def4SGreg Kroah-Hartman case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
2358465def4SGreg Kroah-Hartman return -EINVAL;
2368465def4SGreg Kroah-Hartman case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
2378465def4SGreg Kroah-Hartman return -ENOMSG;
2388465def4SGreg Kroah-Hartman default:
2398465def4SGreg Kroah-Hartman return -EREMOTEIO;
2408465def4SGreg Kroah-Hartman }
2418465def4SGreg Kroah-Hartman }
2428465def4SGreg Kroah-Hartman
2438465def4SGreg Kroah-Hartman *value = le32_to_cpu(response.measurement);
2448465def4SGreg Kroah-Hartman
2458465def4SGreg Kroah-Hartman return 0;
2468465def4SGreg Kroah-Hartman }
2478465def4SGreg Kroah-Hartman
2488465def4SGreg Kroah-Hartman static struct attribute *svc_attrs[] = {
2498465def4SGreg Kroah-Hartman &dev_attr_endo_id.attr,
2508465def4SGreg Kroah-Hartman &dev_attr_ap_intf_id.attr,
2518465def4SGreg Kroah-Hartman &dev_attr_intf_eject.attr,
2528465def4SGreg Kroah-Hartman &dev_attr_watchdog.attr,
2538465def4SGreg Kroah-Hartman &dev_attr_watchdog_action.attr,
2548465def4SGreg Kroah-Hartman NULL,
2558465def4SGreg Kroah-Hartman };
2568465def4SGreg Kroah-Hartman ATTRIBUTE_GROUPS(svc);
2578465def4SGreg Kroah-Hartman
gb_svc_intf_device_id(struct gb_svc * svc,u8 intf_id,u8 device_id)2588465def4SGreg Kroah-Hartman int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
2598465def4SGreg Kroah-Hartman {
2608465def4SGreg Kroah-Hartman struct gb_svc_intf_device_id_request request;
2618465def4SGreg Kroah-Hartman
2628465def4SGreg Kroah-Hartman request.intf_id = intf_id;
2638465def4SGreg Kroah-Hartman request.device_id = device_id;
2648465def4SGreg Kroah-Hartman
2658465def4SGreg Kroah-Hartman return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
2668465def4SGreg Kroah-Hartman &request, sizeof(request), NULL, 0);
2678465def4SGreg Kroah-Hartman }
2688465def4SGreg Kroah-Hartman
gb_svc_intf_eject(struct gb_svc * svc,u8 intf_id)2698465def4SGreg Kroah-Hartman int gb_svc_intf_eject(struct gb_svc *svc, u8 intf_id)
2708465def4SGreg Kroah-Hartman {
2718465def4SGreg Kroah-Hartman struct gb_svc_intf_eject_request request;
2728465def4SGreg Kroah-Hartman int ret;
2738465def4SGreg Kroah-Hartman
2748465def4SGreg Kroah-Hartman request.intf_id = intf_id;
2758465def4SGreg Kroah-Hartman
2768465def4SGreg Kroah-Hartman /*
2778465def4SGreg Kroah-Hartman * The pulse width for module release in svc is long so we need to
2788465def4SGreg Kroah-Hartman * increase the timeout so the operation will not return to soon.
2798465def4SGreg Kroah-Hartman */
2808465def4SGreg Kroah-Hartman ret = gb_operation_sync_timeout(svc->connection,
2818465def4SGreg Kroah-Hartman GB_SVC_TYPE_INTF_EJECT, &request,
2828465def4SGreg Kroah-Hartman sizeof(request), NULL, 0,
2838465def4SGreg Kroah-Hartman SVC_INTF_EJECT_TIMEOUT);
2848465def4SGreg Kroah-Hartman if (ret) {
2858465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to eject interface %u\n", intf_id);
2868465def4SGreg Kroah-Hartman return ret;
2878465def4SGreg Kroah-Hartman }
2888465def4SGreg Kroah-Hartman
2898465def4SGreg Kroah-Hartman return 0;
2908465def4SGreg Kroah-Hartman }
2918465def4SGreg Kroah-Hartman
gb_svc_intf_vsys_set(struct gb_svc * svc,u8 intf_id,bool enable)2928465def4SGreg Kroah-Hartman int gb_svc_intf_vsys_set(struct gb_svc *svc, u8 intf_id, bool enable)
2938465def4SGreg Kroah-Hartman {
2948465def4SGreg Kroah-Hartman struct gb_svc_intf_vsys_request request;
2958465def4SGreg Kroah-Hartman struct gb_svc_intf_vsys_response response;
2968465def4SGreg Kroah-Hartman int type, ret;
2978465def4SGreg Kroah-Hartman
2988465def4SGreg Kroah-Hartman request.intf_id = intf_id;
2998465def4SGreg Kroah-Hartman
3008465def4SGreg Kroah-Hartman if (enable)
3018465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_VSYS_ENABLE;
3028465def4SGreg Kroah-Hartman else
3038465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_VSYS_DISABLE;
3048465def4SGreg Kroah-Hartman
3058465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, type,
3068465def4SGreg Kroah-Hartman &request, sizeof(request),
3078465def4SGreg Kroah-Hartman &response, sizeof(response));
3088465def4SGreg Kroah-Hartman if (ret < 0)
3098465def4SGreg Kroah-Hartman return ret;
3108465def4SGreg Kroah-Hartman if (response.result_code != GB_SVC_INTF_VSYS_OK)
3118465def4SGreg Kroah-Hartman return -EREMOTEIO;
3128465def4SGreg Kroah-Hartman return 0;
3138465def4SGreg Kroah-Hartman }
3148465def4SGreg Kroah-Hartman
gb_svc_intf_refclk_set(struct gb_svc * svc,u8 intf_id,bool enable)3158465def4SGreg Kroah-Hartman int gb_svc_intf_refclk_set(struct gb_svc *svc, u8 intf_id, bool enable)
3168465def4SGreg Kroah-Hartman {
3178465def4SGreg Kroah-Hartman struct gb_svc_intf_refclk_request request;
3188465def4SGreg Kroah-Hartman struct gb_svc_intf_refclk_response response;
3198465def4SGreg Kroah-Hartman int type, ret;
3208465def4SGreg Kroah-Hartman
3218465def4SGreg Kroah-Hartman request.intf_id = intf_id;
3228465def4SGreg Kroah-Hartman
3238465def4SGreg Kroah-Hartman if (enable)
3248465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_REFCLK_ENABLE;
3258465def4SGreg Kroah-Hartman else
3268465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_REFCLK_DISABLE;
3278465def4SGreg Kroah-Hartman
3288465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, type,
3298465def4SGreg Kroah-Hartman &request, sizeof(request),
3308465def4SGreg Kroah-Hartman &response, sizeof(response));
3318465def4SGreg Kroah-Hartman if (ret < 0)
3328465def4SGreg Kroah-Hartman return ret;
3338465def4SGreg Kroah-Hartman if (response.result_code != GB_SVC_INTF_REFCLK_OK)
3348465def4SGreg Kroah-Hartman return -EREMOTEIO;
3358465def4SGreg Kroah-Hartman return 0;
3368465def4SGreg Kroah-Hartman }
3378465def4SGreg Kroah-Hartman
gb_svc_intf_unipro_set(struct gb_svc * svc,u8 intf_id,bool enable)3388465def4SGreg Kroah-Hartman int gb_svc_intf_unipro_set(struct gb_svc *svc, u8 intf_id, bool enable)
3398465def4SGreg Kroah-Hartman {
3408465def4SGreg Kroah-Hartman struct gb_svc_intf_unipro_request request;
3418465def4SGreg Kroah-Hartman struct gb_svc_intf_unipro_response response;
3428465def4SGreg Kroah-Hartman int type, ret;
3438465def4SGreg Kroah-Hartman
3448465def4SGreg Kroah-Hartman request.intf_id = intf_id;
3458465def4SGreg Kroah-Hartman
3468465def4SGreg Kroah-Hartman if (enable)
3478465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_UNIPRO_ENABLE;
3488465def4SGreg Kroah-Hartman else
3498465def4SGreg Kroah-Hartman type = GB_SVC_TYPE_INTF_UNIPRO_DISABLE;
3508465def4SGreg Kroah-Hartman
3518465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, type,
3528465def4SGreg Kroah-Hartman &request, sizeof(request),
3538465def4SGreg Kroah-Hartman &response, sizeof(response));
3548465def4SGreg Kroah-Hartman if (ret < 0)
3558465def4SGreg Kroah-Hartman return ret;
3568465def4SGreg Kroah-Hartman if (response.result_code != GB_SVC_INTF_UNIPRO_OK)
3578465def4SGreg Kroah-Hartman return -EREMOTEIO;
3588465def4SGreg Kroah-Hartman return 0;
3598465def4SGreg Kroah-Hartman }
3608465def4SGreg Kroah-Hartman
gb_svc_intf_activate(struct gb_svc * svc,u8 intf_id,u8 * intf_type)3618465def4SGreg Kroah-Hartman int gb_svc_intf_activate(struct gb_svc *svc, u8 intf_id, u8 *intf_type)
3628465def4SGreg Kroah-Hartman {
3638465def4SGreg Kroah-Hartman struct gb_svc_intf_activate_request request;
3648465def4SGreg Kroah-Hartman struct gb_svc_intf_activate_response response;
3658465def4SGreg Kroah-Hartman int ret;
3668465def4SGreg Kroah-Hartman
3678465def4SGreg Kroah-Hartman request.intf_id = intf_id;
3688465def4SGreg Kroah-Hartman
3698465def4SGreg Kroah-Hartman ret = gb_operation_sync_timeout(svc->connection,
3708465def4SGreg Kroah-Hartman GB_SVC_TYPE_INTF_ACTIVATE,
3718465def4SGreg Kroah-Hartman &request, sizeof(request),
3728465def4SGreg Kroah-Hartman &response, sizeof(response),
3738465def4SGreg Kroah-Hartman SVC_INTF_ACTIVATE_TIMEOUT);
3748465def4SGreg Kroah-Hartman if (ret < 0)
3758465def4SGreg Kroah-Hartman return ret;
3768465def4SGreg Kroah-Hartman if (response.status != GB_SVC_OP_SUCCESS) {
3778465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to activate interface %u: %u\n",
3788465def4SGreg Kroah-Hartman intf_id, response.status);
3798465def4SGreg Kroah-Hartman return -EREMOTEIO;
3808465def4SGreg Kroah-Hartman }
3818465def4SGreg Kroah-Hartman
3828465def4SGreg Kroah-Hartman *intf_type = response.intf_type;
3838465def4SGreg Kroah-Hartman
3848465def4SGreg Kroah-Hartman return 0;
3858465def4SGreg Kroah-Hartman }
3868465def4SGreg Kroah-Hartman
gb_svc_intf_resume(struct gb_svc * svc,u8 intf_id)3878465def4SGreg Kroah-Hartman int gb_svc_intf_resume(struct gb_svc *svc, u8 intf_id)
3888465def4SGreg Kroah-Hartman {
3898465def4SGreg Kroah-Hartman struct gb_svc_intf_resume_request request;
3908465def4SGreg Kroah-Hartman struct gb_svc_intf_resume_response response;
3918465def4SGreg Kroah-Hartman int ret;
3928465def4SGreg Kroah-Hartman
3938465def4SGreg Kroah-Hartman request.intf_id = intf_id;
3948465def4SGreg Kroah-Hartman
3958465def4SGreg Kroah-Hartman ret = gb_operation_sync_timeout(svc->connection,
3968465def4SGreg Kroah-Hartman GB_SVC_TYPE_INTF_RESUME,
3978465def4SGreg Kroah-Hartman &request, sizeof(request),
3988465def4SGreg Kroah-Hartman &response, sizeof(response),
3998465def4SGreg Kroah-Hartman SVC_INTF_RESUME_TIMEOUT);
4008465def4SGreg Kroah-Hartman if (ret < 0) {
4018465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to send interface resume %u: %d\n",
4028465def4SGreg Kroah-Hartman intf_id, ret);
4038465def4SGreg Kroah-Hartman return ret;
4048465def4SGreg Kroah-Hartman }
4058465def4SGreg Kroah-Hartman
4068465def4SGreg Kroah-Hartman if (response.status != GB_SVC_OP_SUCCESS) {
4078465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to resume interface %u: %u\n",
4088465def4SGreg Kroah-Hartman intf_id, response.status);
4098465def4SGreg Kroah-Hartman return -EREMOTEIO;
4108465def4SGreg Kroah-Hartman }
4118465def4SGreg Kroah-Hartman
4128465def4SGreg Kroah-Hartman return 0;
4138465def4SGreg Kroah-Hartman }
4148465def4SGreg Kroah-Hartman
gb_svc_dme_peer_get(struct gb_svc * svc,u8 intf_id,u16 attr,u16 selector,u32 * value)4158465def4SGreg Kroah-Hartman int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
4168465def4SGreg Kroah-Hartman u32 *value)
4178465def4SGreg Kroah-Hartman {
4188465def4SGreg Kroah-Hartman struct gb_svc_dme_peer_get_request request;
4198465def4SGreg Kroah-Hartman struct gb_svc_dme_peer_get_response response;
4208465def4SGreg Kroah-Hartman u16 result;
4218465def4SGreg Kroah-Hartman int ret;
4228465def4SGreg Kroah-Hartman
4238465def4SGreg Kroah-Hartman request.intf_id = intf_id;
4248465def4SGreg Kroah-Hartman request.attr = cpu_to_le16(attr);
4258465def4SGreg Kroah-Hartman request.selector = cpu_to_le16(selector);
4268465def4SGreg Kroah-Hartman
4278465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_GET,
4288465def4SGreg Kroah-Hartman &request, sizeof(request),
4298465def4SGreg Kroah-Hartman &response, sizeof(response));
4308465def4SGreg Kroah-Hartman if (ret) {
4318465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get DME attribute (%u 0x%04x %u): %d\n",
4328465def4SGreg Kroah-Hartman intf_id, attr, selector, ret);
4338465def4SGreg Kroah-Hartman return ret;
4348465def4SGreg Kroah-Hartman }
4358465def4SGreg Kroah-Hartman
4368465def4SGreg Kroah-Hartman result = le16_to_cpu(response.result_code);
4378465def4SGreg Kroah-Hartman if (result) {
4388465def4SGreg Kroah-Hartman dev_err(&svc->dev, "UniPro error while getting DME attribute (%u 0x%04x %u): %u\n",
4398465def4SGreg Kroah-Hartman intf_id, attr, selector, result);
4408465def4SGreg Kroah-Hartman return -EREMOTEIO;
4418465def4SGreg Kroah-Hartman }
4428465def4SGreg Kroah-Hartman
4438465def4SGreg Kroah-Hartman if (value)
4448465def4SGreg Kroah-Hartman *value = le32_to_cpu(response.attr_value);
4458465def4SGreg Kroah-Hartman
4468465def4SGreg Kroah-Hartman return 0;
4478465def4SGreg Kroah-Hartman }
4488465def4SGreg Kroah-Hartman
gb_svc_dme_peer_set(struct gb_svc * svc,u8 intf_id,u16 attr,u16 selector,u32 value)4498465def4SGreg Kroah-Hartman int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
4508465def4SGreg Kroah-Hartman u32 value)
4518465def4SGreg Kroah-Hartman {
4528465def4SGreg Kroah-Hartman struct gb_svc_dme_peer_set_request request;
4538465def4SGreg Kroah-Hartman struct gb_svc_dme_peer_set_response response;
4548465def4SGreg Kroah-Hartman u16 result;
4558465def4SGreg Kroah-Hartman int ret;
4568465def4SGreg Kroah-Hartman
4578465def4SGreg Kroah-Hartman request.intf_id = intf_id;
4588465def4SGreg Kroah-Hartman request.attr = cpu_to_le16(attr);
4598465def4SGreg Kroah-Hartman request.selector = cpu_to_le16(selector);
4608465def4SGreg Kroah-Hartman request.value = cpu_to_le32(value);
4618465def4SGreg Kroah-Hartman
4628465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_SET,
4638465def4SGreg Kroah-Hartman &request, sizeof(request),
4648465def4SGreg Kroah-Hartman &response, sizeof(response));
4658465def4SGreg Kroah-Hartman if (ret) {
4668465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to set DME attribute (%u 0x%04x %u %u): %d\n",
4678465def4SGreg Kroah-Hartman intf_id, attr, selector, value, ret);
4688465def4SGreg Kroah-Hartman return ret;
4698465def4SGreg Kroah-Hartman }
4708465def4SGreg Kroah-Hartman
4718465def4SGreg Kroah-Hartman result = le16_to_cpu(response.result_code);
4728465def4SGreg Kroah-Hartman if (result) {
4738465def4SGreg Kroah-Hartman dev_err(&svc->dev, "UniPro error while setting DME attribute (%u 0x%04x %u %u): %u\n",
4748465def4SGreg Kroah-Hartman intf_id, attr, selector, value, result);
4758465def4SGreg Kroah-Hartman return -EREMOTEIO;
4768465def4SGreg Kroah-Hartman }
4778465def4SGreg Kroah-Hartman
4788465def4SGreg Kroah-Hartman return 0;
4798465def4SGreg Kroah-Hartman }
4808465def4SGreg Kroah-Hartman
gb_svc_connection_create(struct gb_svc * svc,u8 intf1_id,u16 cport1_id,u8 intf2_id,u16 cport2_id,u8 cport_flags)4818465def4SGreg Kroah-Hartman int gb_svc_connection_create(struct gb_svc *svc,
4828465def4SGreg Kroah-Hartman u8 intf1_id, u16 cport1_id,
4838465def4SGreg Kroah-Hartman u8 intf2_id, u16 cport2_id,
4848465def4SGreg Kroah-Hartman u8 cport_flags)
4858465def4SGreg Kroah-Hartman {
4868465def4SGreg Kroah-Hartman struct gb_svc_conn_create_request request;
4878465def4SGreg Kroah-Hartman
4888465def4SGreg Kroah-Hartman request.intf1_id = intf1_id;
4898465def4SGreg Kroah-Hartman request.cport1_id = cpu_to_le16(cport1_id);
4908465def4SGreg Kroah-Hartman request.intf2_id = intf2_id;
4918465def4SGreg Kroah-Hartman request.cport2_id = cpu_to_le16(cport2_id);
4928465def4SGreg Kroah-Hartman request.tc = 0; /* TC0 */
4938465def4SGreg Kroah-Hartman request.flags = cport_flags;
4948465def4SGreg Kroah-Hartman
4958465def4SGreg Kroah-Hartman return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
4968465def4SGreg Kroah-Hartman &request, sizeof(request), NULL, 0);
4978465def4SGreg Kroah-Hartman }
4988465def4SGreg Kroah-Hartman
gb_svc_connection_destroy(struct gb_svc * svc,u8 intf1_id,u16 cport1_id,u8 intf2_id,u16 cport2_id)4998465def4SGreg Kroah-Hartman void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
5008465def4SGreg Kroah-Hartman u8 intf2_id, u16 cport2_id)
5018465def4SGreg Kroah-Hartman {
5028465def4SGreg Kroah-Hartman struct gb_svc_conn_destroy_request request;
5038465def4SGreg Kroah-Hartman struct gb_connection *connection = svc->connection;
5048465def4SGreg Kroah-Hartman int ret;
5058465def4SGreg Kroah-Hartman
5068465def4SGreg Kroah-Hartman request.intf1_id = intf1_id;
5078465def4SGreg Kroah-Hartman request.cport1_id = cpu_to_le16(cport1_id);
5088465def4SGreg Kroah-Hartman request.intf2_id = intf2_id;
5098465def4SGreg Kroah-Hartman request.cport2_id = cpu_to_le16(cport2_id);
5108465def4SGreg Kroah-Hartman
5118465def4SGreg Kroah-Hartman ret = gb_operation_sync(connection, GB_SVC_TYPE_CONN_DESTROY,
5128465def4SGreg Kroah-Hartman &request, sizeof(request), NULL, 0);
5138465def4SGreg Kroah-Hartman if (ret) {
5148465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to destroy connection (%u:%u %u:%u): %d\n",
5158465def4SGreg Kroah-Hartman intf1_id, cport1_id, intf2_id, cport2_id, ret);
5168465def4SGreg Kroah-Hartman }
5178465def4SGreg Kroah-Hartman }
5188465def4SGreg Kroah-Hartman
5198465def4SGreg Kroah-Hartman /* Creates bi-directional routes between the devices */
gb_svc_route_create(struct gb_svc * svc,u8 intf1_id,u8 dev1_id,u8 intf2_id,u8 dev2_id)5208465def4SGreg Kroah-Hartman int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
5218465def4SGreg Kroah-Hartman u8 intf2_id, u8 dev2_id)
5228465def4SGreg Kroah-Hartman {
5238465def4SGreg Kroah-Hartman struct gb_svc_route_create_request request;
5248465def4SGreg Kroah-Hartman
5258465def4SGreg Kroah-Hartman request.intf1_id = intf1_id;
5268465def4SGreg Kroah-Hartman request.dev1_id = dev1_id;
5278465def4SGreg Kroah-Hartman request.intf2_id = intf2_id;
5288465def4SGreg Kroah-Hartman request.dev2_id = dev2_id;
5298465def4SGreg Kroah-Hartman
5308465def4SGreg Kroah-Hartman return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
5318465def4SGreg Kroah-Hartman &request, sizeof(request), NULL, 0);
5328465def4SGreg Kroah-Hartman }
5338465def4SGreg Kroah-Hartman
5348465def4SGreg Kroah-Hartman /* Destroys bi-directional routes between the devices */
gb_svc_route_destroy(struct gb_svc * svc,u8 intf1_id,u8 intf2_id)5358465def4SGreg Kroah-Hartman void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id)
5368465def4SGreg Kroah-Hartman {
5378465def4SGreg Kroah-Hartman struct gb_svc_route_destroy_request request;
5388465def4SGreg Kroah-Hartman int ret;
5398465def4SGreg Kroah-Hartman
5408465def4SGreg Kroah-Hartman request.intf1_id = intf1_id;
5418465def4SGreg Kroah-Hartman request.intf2_id = intf2_id;
5428465def4SGreg Kroah-Hartman
5438465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_DESTROY,
5448465def4SGreg Kroah-Hartman &request, sizeof(request), NULL, 0);
5458465def4SGreg Kroah-Hartman if (ret) {
5468465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to destroy route (%u %u): %d\n",
5478465def4SGreg Kroah-Hartman intf1_id, intf2_id, ret);
5488465def4SGreg Kroah-Hartman }
5498465def4SGreg Kroah-Hartman }
5508465def4SGreg Kroah-Hartman
gb_svc_intf_set_power_mode(struct gb_svc * svc,u8 intf_id,u8 hs_series,u8 tx_mode,u8 tx_gear,u8 tx_nlanes,u8 tx_amplitude,u8 tx_hs_equalizer,u8 rx_mode,u8 rx_gear,u8 rx_nlanes,u8 flags,u32 quirks,struct gb_svc_l2_timer_cfg * local,struct gb_svc_l2_timer_cfg * remote)5518465def4SGreg Kroah-Hartman int gb_svc_intf_set_power_mode(struct gb_svc *svc, u8 intf_id, u8 hs_series,
5528465def4SGreg Kroah-Hartman u8 tx_mode, u8 tx_gear, u8 tx_nlanes,
5538465def4SGreg Kroah-Hartman u8 tx_amplitude, u8 tx_hs_equalizer,
5548465def4SGreg Kroah-Hartman u8 rx_mode, u8 rx_gear, u8 rx_nlanes,
5558465def4SGreg Kroah-Hartman u8 flags, u32 quirks,
5568465def4SGreg Kroah-Hartman struct gb_svc_l2_timer_cfg *local,
5578465def4SGreg Kroah-Hartman struct gb_svc_l2_timer_cfg *remote)
5588465def4SGreg Kroah-Hartman {
5598465def4SGreg Kroah-Hartman struct gb_svc_intf_set_pwrm_request request;
5608465def4SGreg Kroah-Hartman struct gb_svc_intf_set_pwrm_response response;
5618465def4SGreg Kroah-Hartman int ret;
5628465def4SGreg Kroah-Hartman u16 result_code;
5638465def4SGreg Kroah-Hartman
5648465def4SGreg Kroah-Hartman memset(&request, 0, sizeof(request));
5658465def4SGreg Kroah-Hartman
5668465def4SGreg Kroah-Hartman request.intf_id = intf_id;
5678465def4SGreg Kroah-Hartman request.hs_series = hs_series;
5688465def4SGreg Kroah-Hartman request.tx_mode = tx_mode;
5698465def4SGreg Kroah-Hartman request.tx_gear = tx_gear;
5708465def4SGreg Kroah-Hartman request.tx_nlanes = tx_nlanes;
5718465def4SGreg Kroah-Hartman request.tx_amplitude = tx_amplitude;
5728465def4SGreg Kroah-Hartman request.tx_hs_equalizer = tx_hs_equalizer;
5738465def4SGreg Kroah-Hartman request.rx_mode = rx_mode;
5748465def4SGreg Kroah-Hartman request.rx_gear = rx_gear;
5758465def4SGreg Kroah-Hartman request.rx_nlanes = rx_nlanes;
5768465def4SGreg Kroah-Hartman request.flags = flags;
5778465def4SGreg Kroah-Hartman request.quirks = cpu_to_le32(quirks);
5788465def4SGreg Kroah-Hartman if (local)
5798465def4SGreg Kroah-Hartman request.local_l2timerdata = *local;
5808465def4SGreg Kroah-Hartman if (remote)
5818465def4SGreg Kroah-Hartman request.remote_l2timerdata = *remote;
5828465def4SGreg Kroah-Hartman
5838465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
5848465def4SGreg Kroah-Hartman &request, sizeof(request),
5858465def4SGreg Kroah-Hartman &response, sizeof(response));
5868465def4SGreg Kroah-Hartman if (ret < 0)
5878465def4SGreg Kroah-Hartman return ret;
5888465def4SGreg Kroah-Hartman
5898465def4SGreg Kroah-Hartman result_code = response.result_code;
5908465def4SGreg Kroah-Hartman if (result_code != GB_SVC_SETPWRM_PWR_LOCAL) {
5918465def4SGreg Kroah-Hartman dev_err(&svc->dev, "set power mode = %d\n", result_code);
5928465def4SGreg Kroah-Hartman return -EIO;
5938465def4SGreg Kroah-Hartman }
5948465def4SGreg Kroah-Hartman
5958465def4SGreg Kroah-Hartman return 0;
5968465def4SGreg Kroah-Hartman }
5978465def4SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(gb_svc_intf_set_power_mode);
5988465def4SGreg Kroah-Hartman
gb_svc_intf_set_power_mode_hibernate(struct gb_svc * svc,u8 intf_id)5998465def4SGreg Kroah-Hartman int gb_svc_intf_set_power_mode_hibernate(struct gb_svc *svc, u8 intf_id)
6008465def4SGreg Kroah-Hartman {
6018465def4SGreg Kroah-Hartman struct gb_svc_intf_set_pwrm_request request;
6028465def4SGreg Kroah-Hartman struct gb_svc_intf_set_pwrm_response response;
6038465def4SGreg Kroah-Hartman int ret;
6048465def4SGreg Kroah-Hartman u16 result_code;
6058465def4SGreg Kroah-Hartman
6068465def4SGreg Kroah-Hartman memset(&request, 0, sizeof(request));
6078465def4SGreg Kroah-Hartman
6088465def4SGreg Kroah-Hartman request.intf_id = intf_id;
6098465def4SGreg Kroah-Hartman request.hs_series = GB_SVC_UNIPRO_HS_SERIES_A;
6108465def4SGreg Kroah-Hartman request.tx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
6118465def4SGreg Kroah-Hartman request.rx_mode = GB_SVC_UNIPRO_HIBERNATE_MODE;
6128465def4SGreg Kroah-Hartman
6138465def4SGreg Kroah-Hartman ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_SET_PWRM,
6148465def4SGreg Kroah-Hartman &request, sizeof(request),
6158465def4SGreg Kroah-Hartman &response, sizeof(response));
6168465def4SGreg Kroah-Hartman if (ret < 0) {
6178465def4SGreg Kroah-Hartman dev_err(&svc->dev,
6188465def4SGreg Kroah-Hartman "failed to send set power mode operation to interface %u: %d\n",
6198465def4SGreg Kroah-Hartman intf_id, ret);
6208465def4SGreg Kroah-Hartman return ret;
6218465def4SGreg Kroah-Hartman }
6228465def4SGreg Kroah-Hartman
6238465def4SGreg Kroah-Hartman result_code = response.result_code;
6248465def4SGreg Kroah-Hartman if (result_code != GB_SVC_SETPWRM_PWR_OK) {
6258465def4SGreg Kroah-Hartman dev_err(&svc->dev,
6268465def4SGreg Kroah-Hartman "failed to hibernate the link for interface %u: %u\n",
6278465def4SGreg Kroah-Hartman intf_id, result_code);
6288465def4SGreg Kroah-Hartman return -EIO;
6298465def4SGreg Kroah-Hartman }
6308465def4SGreg Kroah-Hartman
6318465def4SGreg Kroah-Hartman return 0;
6328465def4SGreg Kroah-Hartman }
6338465def4SGreg Kroah-Hartman
gb_svc_ping(struct gb_svc * svc)6348465def4SGreg Kroah-Hartman int gb_svc_ping(struct gb_svc *svc)
6358465def4SGreg Kroah-Hartman {
6368465def4SGreg Kroah-Hartman return gb_operation_sync_timeout(svc->connection, GB_SVC_TYPE_PING,
6378465def4SGreg Kroah-Hartman NULL, 0, NULL, 0,
6388465def4SGreg Kroah-Hartman GB_OPERATION_TIMEOUT_DEFAULT * 2);
6398465def4SGreg Kroah-Hartman }
6408465def4SGreg Kroah-Hartman
gb_svc_version_request(struct gb_operation * op)6418465def4SGreg Kroah-Hartman static int gb_svc_version_request(struct gb_operation *op)
6428465def4SGreg Kroah-Hartman {
6438465def4SGreg Kroah-Hartman struct gb_connection *connection = op->connection;
6448465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
6458465def4SGreg Kroah-Hartman struct gb_svc_version_request *request;
6468465def4SGreg Kroah-Hartman struct gb_svc_version_response *response;
6478465def4SGreg Kroah-Hartman
6488465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*request)) {
6498465def4SGreg Kroah-Hartman dev_err(&svc->dev, "short version request (%zu < %zu)\n",
6508465def4SGreg Kroah-Hartman op->request->payload_size,
6518465def4SGreg Kroah-Hartman sizeof(*request));
6528465def4SGreg Kroah-Hartman return -EINVAL;
6538465def4SGreg Kroah-Hartman }
6548465def4SGreg Kroah-Hartman
6558465def4SGreg Kroah-Hartman request = op->request->payload;
6568465def4SGreg Kroah-Hartman
6578465def4SGreg Kroah-Hartman if (request->major > GB_SVC_VERSION_MAJOR) {
6588465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unsupported major version (%u > %u)\n",
6598465def4SGreg Kroah-Hartman request->major, GB_SVC_VERSION_MAJOR);
6608465def4SGreg Kroah-Hartman return -ENOTSUPP;
6618465def4SGreg Kroah-Hartman }
6628465def4SGreg Kroah-Hartman
6638465def4SGreg Kroah-Hartman svc->protocol_major = request->major;
6648465def4SGreg Kroah-Hartman svc->protocol_minor = request->minor;
6658465def4SGreg Kroah-Hartman
6668465def4SGreg Kroah-Hartman if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL))
6678465def4SGreg Kroah-Hartman return -ENOMEM;
6688465def4SGreg Kroah-Hartman
6698465def4SGreg Kroah-Hartman response = op->response->payload;
6708465def4SGreg Kroah-Hartman response->major = svc->protocol_major;
6718465def4SGreg Kroah-Hartman response->minor = svc->protocol_minor;
6728465def4SGreg Kroah-Hartman
6738465def4SGreg Kroah-Hartman return 0;
6748465def4SGreg Kroah-Hartman }
6758465def4SGreg Kroah-Hartman
pwr_debugfs_voltage_read(struct file * file,char __user * buf,size_t len,loff_t * offset)6768465def4SGreg Kroah-Hartman static ssize_t pwr_debugfs_voltage_read(struct file *file, char __user *buf,
6778465def4SGreg Kroah-Hartman size_t len, loff_t *offset)
6788465def4SGreg Kroah-Hartman {
6798465def4SGreg Kroah-Hartman struct svc_debugfs_pwrmon_rail *pwrmon_rails =
6808465def4SGreg Kroah-Hartman file_inode(file)->i_private;
6818465def4SGreg Kroah-Hartman struct gb_svc *svc = pwrmon_rails->svc;
6828465def4SGreg Kroah-Hartman int ret, desc;
6838465def4SGreg Kroah-Hartman u32 value;
6848465def4SGreg Kroah-Hartman char buff[16];
6858465def4SGreg Kroah-Hartman
6868465def4SGreg Kroah-Hartman ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
6878465def4SGreg Kroah-Hartman GB_SVC_PWRMON_TYPE_VOL, &value);
6888465def4SGreg Kroah-Hartman if (ret) {
6898465def4SGreg Kroah-Hartman dev_err(&svc->dev,
6908465def4SGreg Kroah-Hartman "failed to get voltage sample %u: %d\n",
6918465def4SGreg Kroah-Hartman pwrmon_rails->id, ret);
6928465def4SGreg Kroah-Hartman return ret;
6938465def4SGreg Kroah-Hartman }
6948465def4SGreg Kroah-Hartman
6958465def4SGreg Kroah-Hartman desc = scnprintf(buff, sizeof(buff), "%u\n", value);
6968465def4SGreg Kroah-Hartman
6978465def4SGreg Kroah-Hartman return simple_read_from_buffer(buf, len, offset, buff, desc);
6988465def4SGreg Kroah-Hartman }
6998465def4SGreg Kroah-Hartman
pwr_debugfs_current_read(struct file * file,char __user * buf,size_t len,loff_t * offset)7008465def4SGreg Kroah-Hartman static ssize_t pwr_debugfs_current_read(struct file *file, char __user *buf,
7018465def4SGreg Kroah-Hartman size_t len, loff_t *offset)
7028465def4SGreg Kroah-Hartman {
7038465def4SGreg Kroah-Hartman struct svc_debugfs_pwrmon_rail *pwrmon_rails =
7048465def4SGreg Kroah-Hartman file_inode(file)->i_private;
7058465def4SGreg Kroah-Hartman struct gb_svc *svc = pwrmon_rails->svc;
7068465def4SGreg Kroah-Hartman int ret, desc;
7078465def4SGreg Kroah-Hartman u32 value;
7088465def4SGreg Kroah-Hartman char buff[16];
7098465def4SGreg Kroah-Hartman
7108465def4SGreg Kroah-Hartman ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
7118465def4SGreg Kroah-Hartman GB_SVC_PWRMON_TYPE_CURR, &value);
7128465def4SGreg Kroah-Hartman if (ret) {
7138465def4SGreg Kroah-Hartman dev_err(&svc->dev,
7148465def4SGreg Kroah-Hartman "failed to get current sample %u: %d\n",
7158465def4SGreg Kroah-Hartman pwrmon_rails->id, ret);
7168465def4SGreg Kroah-Hartman return ret;
7178465def4SGreg Kroah-Hartman }
7188465def4SGreg Kroah-Hartman
7198465def4SGreg Kroah-Hartman desc = scnprintf(buff, sizeof(buff), "%u\n", value);
7208465def4SGreg Kroah-Hartman
7218465def4SGreg Kroah-Hartman return simple_read_from_buffer(buf, len, offset, buff, desc);
7228465def4SGreg Kroah-Hartman }
7238465def4SGreg Kroah-Hartman
pwr_debugfs_power_read(struct file * file,char __user * buf,size_t len,loff_t * offset)7248465def4SGreg Kroah-Hartman static ssize_t pwr_debugfs_power_read(struct file *file, char __user *buf,
7258465def4SGreg Kroah-Hartman size_t len, loff_t *offset)
7268465def4SGreg Kroah-Hartman {
7278465def4SGreg Kroah-Hartman struct svc_debugfs_pwrmon_rail *pwrmon_rails =
7288465def4SGreg Kroah-Hartman file_inode(file)->i_private;
7298465def4SGreg Kroah-Hartman struct gb_svc *svc = pwrmon_rails->svc;
7308465def4SGreg Kroah-Hartman int ret, desc;
7318465def4SGreg Kroah-Hartman u32 value;
7328465def4SGreg Kroah-Hartman char buff[16];
7338465def4SGreg Kroah-Hartman
7348465def4SGreg Kroah-Hartman ret = gb_svc_pwrmon_sample_get(svc, pwrmon_rails->id,
7358465def4SGreg Kroah-Hartman GB_SVC_PWRMON_TYPE_PWR, &value);
7368465def4SGreg Kroah-Hartman if (ret) {
7378465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to get power sample %u: %d\n",
7388465def4SGreg Kroah-Hartman pwrmon_rails->id, ret);
7398465def4SGreg Kroah-Hartman return ret;
7408465def4SGreg Kroah-Hartman }
7418465def4SGreg Kroah-Hartman
7428465def4SGreg Kroah-Hartman desc = scnprintf(buff, sizeof(buff), "%u\n", value);
7438465def4SGreg Kroah-Hartman
7448465def4SGreg Kroah-Hartman return simple_read_from_buffer(buf, len, offset, buff, desc);
7458465def4SGreg Kroah-Hartman }
7468465def4SGreg Kroah-Hartman
7478465def4SGreg Kroah-Hartman static const struct file_operations pwrmon_debugfs_voltage_fops = {
7488465def4SGreg Kroah-Hartman .read = pwr_debugfs_voltage_read,
7498465def4SGreg Kroah-Hartman };
7508465def4SGreg Kroah-Hartman
7518465def4SGreg Kroah-Hartman static const struct file_operations pwrmon_debugfs_current_fops = {
7528465def4SGreg Kroah-Hartman .read = pwr_debugfs_current_read,
7538465def4SGreg Kroah-Hartman };
7548465def4SGreg Kroah-Hartman
7558465def4SGreg Kroah-Hartman static const struct file_operations pwrmon_debugfs_power_fops = {
7568465def4SGreg Kroah-Hartman .read = pwr_debugfs_power_read,
7578465def4SGreg Kroah-Hartman };
7588465def4SGreg Kroah-Hartman
gb_svc_pwrmon_debugfs_init(struct gb_svc * svc)7598465def4SGreg Kroah-Hartman static void gb_svc_pwrmon_debugfs_init(struct gb_svc *svc)
7608465def4SGreg Kroah-Hartman {
7618465def4SGreg Kroah-Hartman int i;
7628465def4SGreg Kroah-Hartman size_t bufsize;
7638465def4SGreg Kroah-Hartman struct dentry *dent;
7648465def4SGreg Kroah-Hartman struct gb_svc_pwrmon_rail_names_get_response *rail_names;
7658465def4SGreg Kroah-Hartman u8 rail_count;
7668465def4SGreg Kroah-Hartman
7678465def4SGreg Kroah-Hartman dent = debugfs_create_dir("pwrmon", svc->debugfs_dentry);
7688465def4SGreg Kroah-Hartman if (IS_ERR_OR_NULL(dent))
7698465def4SGreg Kroah-Hartman return;
7708465def4SGreg Kroah-Hartman
7718465def4SGreg Kroah-Hartman if (gb_svc_pwrmon_rail_count_get(svc, &rail_count))
7728465def4SGreg Kroah-Hartman goto err_pwrmon_debugfs;
7738465def4SGreg Kroah-Hartman
7748465def4SGreg Kroah-Hartman if (!rail_count || rail_count > GB_SVC_PWRMON_MAX_RAIL_COUNT)
7758465def4SGreg Kroah-Hartman goto err_pwrmon_debugfs;
7768465def4SGreg Kroah-Hartman
7778465def4SGreg Kroah-Hartman bufsize = sizeof(*rail_names) +
7788465def4SGreg Kroah-Hartman GB_SVC_PWRMON_RAIL_NAME_BUFSIZE * rail_count;
7798465def4SGreg Kroah-Hartman
7808465def4SGreg Kroah-Hartman rail_names = kzalloc(bufsize, GFP_KERNEL);
7818465def4SGreg Kroah-Hartman if (!rail_names)
7828465def4SGreg Kroah-Hartman goto err_pwrmon_debugfs;
7838465def4SGreg Kroah-Hartman
7848465def4SGreg Kroah-Hartman svc->pwrmon_rails = kcalloc(rail_count, sizeof(*svc->pwrmon_rails),
7858465def4SGreg Kroah-Hartman GFP_KERNEL);
7868465def4SGreg Kroah-Hartman if (!svc->pwrmon_rails)
7878465def4SGreg Kroah-Hartman goto err_pwrmon_debugfs_free;
7888465def4SGreg Kroah-Hartman
7898465def4SGreg Kroah-Hartman if (gb_svc_pwrmon_rail_names_get(svc, rail_names, bufsize))
7908465def4SGreg Kroah-Hartman goto err_pwrmon_debugfs_free;
7918465def4SGreg Kroah-Hartman
7928465def4SGreg Kroah-Hartman for (i = 0; i < rail_count; i++) {
7938465def4SGreg Kroah-Hartman struct dentry *dir;
7948465def4SGreg Kroah-Hartman struct svc_debugfs_pwrmon_rail *rail = &svc->pwrmon_rails[i];
7958465def4SGreg Kroah-Hartman char fname[GB_SVC_PWRMON_RAIL_NAME_BUFSIZE];
7968465def4SGreg Kroah-Hartman
7978465def4SGreg Kroah-Hartman snprintf(fname, sizeof(fname), "%s",
7988465def4SGreg Kroah-Hartman (char *)&rail_names->name[i]);
7998465def4SGreg Kroah-Hartman
8008465def4SGreg Kroah-Hartman rail->id = i;
8018465def4SGreg Kroah-Hartman rail->svc = svc;
8028465def4SGreg Kroah-Hartman
8038465def4SGreg Kroah-Hartman dir = debugfs_create_dir(fname, dent);
8048465def4SGreg Kroah-Hartman debugfs_create_file("voltage_now", 0444, dir, rail,
8058465def4SGreg Kroah-Hartman &pwrmon_debugfs_voltage_fops);
8068465def4SGreg Kroah-Hartman debugfs_create_file("current_now", 0444, dir, rail,
8078465def4SGreg Kroah-Hartman &pwrmon_debugfs_current_fops);
8088465def4SGreg Kroah-Hartman debugfs_create_file("power_now", 0444, dir, rail,
8098465def4SGreg Kroah-Hartman &pwrmon_debugfs_power_fops);
8108465def4SGreg Kroah-Hartman }
8118465def4SGreg Kroah-Hartman
8128465def4SGreg Kroah-Hartman kfree(rail_names);
8138465def4SGreg Kroah-Hartman return;
8148465def4SGreg Kroah-Hartman
8158465def4SGreg Kroah-Hartman err_pwrmon_debugfs_free:
8168465def4SGreg Kroah-Hartman kfree(rail_names);
8178465def4SGreg Kroah-Hartman kfree(svc->pwrmon_rails);
8188465def4SGreg Kroah-Hartman svc->pwrmon_rails = NULL;
8198465def4SGreg Kroah-Hartman
8208465def4SGreg Kroah-Hartman err_pwrmon_debugfs:
8218465def4SGreg Kroah-Hartman debugfs_remove(dent);
8228465def4SGreg Kroah-Hartman }
8238465def4SGreg Kroah-Hartman
gb_svc_debugfs_init(struct gb_svc * svc)8248465def4SGreg Kroah-Hartman static void gb_svc_debugfs_init(struct gb_svc *svc)
8258465def4SGreg Kroah-Hartman {
8268465def4SGreg Kroah-Hartman svc->debugfs_dentry = debugfs_create_dir(dev_name(&svc->dev),
8278465def4SGreg Kroah-Hartman gb_debugfs_get());
8288465def4SGreg Kroah-Hartman gb_svc_pwrmon_debugfs_init(svc);
8298465def4SGreg Kroah-Hartman }
8308465def4SGreg Kroah-Hartman
gb_svc_debugfs_exit(struct gb_svc * svc)8318465def4SGreg Kroah-Hartman static void gb_svc_debugfs_exit(struct gb_svc *svc)
8328465def4SGreg Kroah-Hartman {
8338465def4SGreg Kroah-Hartman debugfs_remove_recursive(svc->debugfs_dentry);
8348465def4SGreg Kroah-Hartman kfree(svc->pwrmon_rails);
8358465def4SGreg Kroah-Hartman svc->pwrmon_rails = NULL;
8368465def4SGreg Kroah-Hartman }
8378465def4SGreg Kroah-Hartman
gb_svc_hello(struct gb_operation * op)8388465def4SGreg Kroah-Hartman static int gb_svc_hello(struct gb_operation *op)
8398465def4SGreg Kroah-Hartman {
8408465def4SGreg Kroah-Hartman struct gb_connection *connection = op->connection;
8418465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
8428465def4SGreg Kroah-Hartman struct gb_svc_hello_request *hello_request;
8438465def4SGreg Kroah-Hartman int ret;
8448465def4SGreg Kroah-Hartman
8458465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*hello_request)) {
8468465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short hello request (%zu < %zu)\n",
8478465def4SGreg Kroah-Hartman op->request->payload_size,
8488465def4SGreg Kroah-Hartman sizeof(*hello_request));
8498465def4SGreg Kroah-Hartman return -EINVAL;
8508465def4SGreg Kroah-Hartman }
8518465def4SGreg Kroah-Hartman
8528465def4SGreg Kroah-Hartman hello_request = op->request->payload;
8538465def4SGreg Kroah-Hartman svc->endo_id = le16_to_cpu(hello_request->endo_id);
8548465def4SGreg Kroah-Hartman svc->ap_intf_id = hello_request->interface_id;
8558465def4SGreg Kroah-Hartman
8568465def4SGreg Kroah-Hartman ret = device_add(&svc->dev);
8578465def4SGreg Kroah-Hartman if (ret) {
8588465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to register svc device: %d\n", ret);
8598465def4SGreg Kroah-Hartman return ret;
8608465def4SGreg Kroah-Hartman }
8618465def4SGreg Kroah-Hartman
8628465def4SGreg Kroah-Hartman ret = gb_svc_watchdog_create(svc);
8638465def4SGreg Kroah-Hartman if (ret) {
8648465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to create watchdog: %d\n", ret);
8655f648e00SJohan Hovold goto err_deregister_svc;
8668465def4SGreg Kroah-Hartman }
8678465def4SGreg Kroah-Hartman
868a74e7263SJohan Hovold /*
869a74e7263SJohan Hovold * FIXME: This is a temporary hack to reconfigure the link at HELLO
870a74e7263SJohan Hovold * (which abuses the deferred request processing mechanism).
871a74e7263SJohan Hovold */
8725f8583a3SDan Carpenter ret = gb_svc_queue_deferred_request(op);
8735f8583a3SDan Carpenter if (ret)
874a74e7263SJohan Hovold goto err_destroy_watchdog;
875a74e7263SJohan Hovold
876a74e7263SJohan Hovold gb_svc_debugfs_init(svc);
8778465def4SGreg Kroah-Hartman
8785f8583a3SDan Carpenter return 0;
8795f8583a3SDan Carpenter
880a74e7263SJohan Hovold err_destroy_watchdog:
8818465def4SGreg Kroah-Hartman gb_svc_watchdog_destroy(svc);
8825f648e00SJohan Hovold err_deregister_svc:
8838465def4SGreg Kroah-Hartman device_del(&svc->dev);
8845f648e00SJohan Hovold
8858465def4SGreg Kroah-Hartman return ret;
8868465def4SGreg Kroah-Hartman }
8878465def4SGreg Kroah-Hartman
gb_svc_interface_lookup(struct gb_svc * svc,u8 intf_id)8888465def4SGreg Kroah-Hartman static struct gb_interface *gb_svc_interface_lookup(struct gb_svc *svc,
8898465def4SGreg Kroah-Hartman u8 intf_id)
8908465def4SGreg Kroah-Hartman {
8918465def4SGreg Kroah-Hartman struct gb_host_device *hd = svc->hd;
8928465def4SGreg Kroah-Hartman struct gb_module *module;
8938465def4SGreg Kroah-Hartman size_t num_interfaces;
8948465def4SGreg Kroah-Hartman u8 module_id;
8958465def4SGreg Kroah-Hartman
8968465def4SGreg Kroah-Hartman list_for_each_entry(module, &hd->modules, hd_node) {
8978465def4SGreg Kroah-Hartman module_id = module->module_id;
8988465def4SGreg Kroah-Hartman num_interfaces = module->num_interfaces;
8998465def4SGreg Kroah-Hartman
9008465def4SGreg Kroah-Hartman if (intf_id >= module_id &&
9018465def4SGreg Kroah-Hartman intf_id < module_id + num_interfaces) {
9028465def4SGreg Kroah-Hartman return module->interfaces[intf_id - module_id];
9038465def4SGreg Kroah-Hartman }
9048465def4SGreg Kroah-Hartman }
9058465def4SGreg Kroah-Hartman
9068465def4SGreg Kroah-Hartman return NULL;
9078465def4SGreg Kroah-Hartman }
9088465def4SGreg Kroah-Hartman
gb_svc_module_lookup(struct gb_svc * svc,u8 module_id)9098465def4SGreg Kroah-Hartman static struct gb_module *gb_svc_module_lookup(struct gb_svc *svc, u8 module_id)
9108465def4SGreg Kroah-Hartman {
9118465def4SGreg Kroah-Hartman struct gb_host_device *hd = svc->hd;
9128465def4SGreg Kroah-Hartman struct gb_module *module;
9138465def4SGreg Kroah-Hartman
9148465def4SGreg Kroah-Hartman list_for_each_entry(module, &hd->modules, hd_node) {
9158465def4SGreg Kroah-Hartman if (module->module_id == module_id)
9168465def4SGreg Kroah-Hartman return module;
9178465def4SGreg Kroah-Hartman }
9188465def4SGreg Kroah-Hartman
9198465def4SGreg Kroah-Hartman return NULL;
9208465def4SGreg Kroah-Hartman }
9218465def4SGreg Kroah-Hartman
gb_svc_process_hello_deferred(struct gb_operation * operation)9228465def4SGreg Kroah-Hartman static void gb_svc_process_hello_deferred(struct gb_operation *operation)
9238465def4SGreg Kroah-Hartman {
9248465def4SGreg Kroah-Hartman struct gb_connection *connection = operation->connection;
9258465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
9268465def4SGreg Kroah-Hartman int ret;
9278465def4SGreg Kroah-Hartman
9288465def4SGreg Kroah-Hartman /*
9298465def4SGreg Kroah-Hartman * XXX This is a hack/work-around to reconfigure the APBridgeA-Switch
9308465def4SGreg Kroah-Hartman * link to PWM G2, 1 Lane, Slow Auto, so that it has sufficient
9318465def4SGreg Kroah-Hartman * bandwidth for 3 audio streams plus boot-over-UniPro of a hot-plugged
9328465def4SGreg Kroah-Hartman * module.
9338465def4SGreg Kroah-Hartman *
9348465def4SGreg Kroah-Hartman * The code should be removed once SW-2217, Heuristic for UniPro
9358465def4SGreg Kroah-Hartman * Power Mode Changes is resolved.
9368465def4SGreg Kroah-Hartman */
9378465def4SGreg Kroah-Hartman ret = gb_svc_intf_set_power_mode(svc, svc->ap_intf_id,
9388465def4SGreg Kroah-Hartman GB_SVC_UNIPRO_HS_SERIES_A,
9398465def4SGreg Kroah-Hartman GB_SVC_UNIPRO_SLOW_AUTO_MODE,
9408465def4SGreg Kroah-Hartman 2, 1,
9418465def4SGreg Kroah-Hartman GB_SVC_SMALL_AMPLITUDE,
9428465def4SGreg Kroah-Hartman GB_SVC_NO_DE_EMPHASIS,
9438465def4SGreg Kroah-Hartman GB_SVC_UNIPRO_SLOW_AUTO_MODE,
9448465def4SGreg Kroah-Hartman 2, 1,
9458465def4SGreg Kroah-Hartman 0, 0,
9468465def4SGreg Kroah-Hartman NULL, NULL);
9478465def4SGreg Kroah-Hartman
9488465def4SGreg Kroah-Hartman if (ret)
9498465def4SGreg Kroah-Hartman dev_warn(&svc->dev,
9508465def4SGreg Kroah-Hartman "power mode change failed on AP to switch link: %d\n",
9518465def4SGreg Kroah-Hartman ret);
9528465def4SGreg Kroah-Hartman }
9538465def4SGreg Kroah-Hartman
gb_svc_process_module_inserted(struct gb_operation * operation)9548465def4SGreg Kroah-Hartman static void gb_svc_process_module_inserted(struct gb_operation *operation)
9558465def4SGreg Kroah-Hartman {
9568465def4SGreg Kroah-Hartman struct gb_svc_module_inserted_request *request;
9578465def4SGreg Kroah-Hartman struct gb_connection *connection = operation->connection;
9588465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
9598465def4SGreg Kroah-Hartman struct gb_host_device *hd = svc->hd;
9608465def4SGreg Kroah-Hartman struct gb_module *module;
9618465def4SGreg Kroah-Hartman size_t num_interfaces;
9628465def4SGreg Kroah-Hartman u8 module_id;
9638465def4SGreg Kroah-Hartman u16 flags;
9648465def4SGreg Kroah-Hartman int ret;
9658465def4SGreg Kroah-Hartman
9668465def4SGreg Kroah-Hartman /* The request message size has already been verified. */
9678465def4SGreg Kroah-Hartman request = operation->request->payload;
9688465def4SGreg Kroah-Hartman module_id = request->primary_intf_id;
9698465def4SGreg Kroah-Hartman num_interfaces = request->intf_count;
9708465def4SGreg Kroah-Hartman flags = le16_to_cpu(request->flags);
9718465def4SGreg Kroah-Hartman
9728465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u, num_interfaces = %zu, flags = 0x%04x\n",
9738465def4SGreg Kroah-Hartman __func__, module_id, num_interfaces, flags);
9748465def4SGreg Kroah-Hartman
9758465def4SGreg Kroah-Hartman if (flags & GB_SVC_MODULE_INSERTED_FLAG_NO_PRIMARY) {
9768465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "no primary interface detected on module %u\n",
9778465def4SGreg Kroah-Hartman module_id);
9788465def4SGreg Kroah-Hartman }
9798465def4SGreg Kroah-Hartman
9808465def4SGreg Kroah-Hartman module = gb_svc_module_lookup(svc, module_id);
9818465def4SGreg Kroah-Hartman if (module) {
9828465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unexpected module-inserted event %u\n",
9838465def4SGreg Kroah-Hartman module_id);
9848465def4SGreg Kroah-Hartman return;
9858465def4SGreg Kroah-Hartman }
9868465def4SGreg Kroah-Hartman
9878465def4SGreg Kroah-Hartman module = gb_module_create(hd, module_id, num_interfaces);
9888465def4SGreg Kroah-Hartman if (!module) {
9898465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to create module\n");
9908465def4SGreg Kroah-Hartman return;
9918465def4SGreg Kroah-Hartman }
9928465def4SGreg Kroah-Hartman
9938465def4SGreg Kroah-Hartman ret = gb_module_add(module);
9948465def4SGreg Kroah-Hartman if (ret) {
9958465def4SGreg Kroah-Hartman gb_module_put(module);
9968465def4SGreg Kroah-Hartman return;
9978465def4SGreg Kroah-Hartman }
9988465def4SGreg Kroah-Hartman
9998465def4SGreg Kroah-Hartman list_add(&module->hd_node, &hd->modules);
10008465def4SGreg Kroah-Hartman }
10018465def4SGreg Kroah-Hartman
gb_svc_process_module_removed(struct gb_operation * operation)10028465def4SGreg Kroah-Hartman static void gb_svc_process_module_removed(struct gb_operation *operation)
10038465def4SGreg Kroah-Hartman {
10048465def4SGreg Kroah-Hartman struct gb_svc_module_removed_request *request;
10058465def4SGreg Kroah-Hartman struct gb_connection *connection = operation->connection;
10068465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
10078465def4SGreg Kroah-Hartman struct gb_module *module;
10088465def4SGreg Kroah-Hartman u8 module_id;
10098465def4SGreg Kroah-Hartman
10108465def4SGreg Kroah-Hartman /* The request message size has already been verified. */
10118465def4SGreg Kroah-Hartman request = operation->request->payload;
10128465def4SGreg Kroah-Hartman module_id = request->primary_intf_id;
10138465def4SGreg Kroah-Hartman
10148465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u\n", __func__, module_id);
10158465def4SGreg Kroah-Hartman
10168465def4SGreg Kroah-Hartman module = gb_svc_module_lookup(svc, module_id);
10178465def4SGreg Kroah-Hartman if (!module) {
10188465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unexpected module-removed event %u\n",
10198465def4SGreg Kroah-Hartman module_id);
10208465def4SGreg Kroah-Hartman return;
10218465def4SGreg Kroah-Hartman }
10228465def4SGreg Kroah-Hartman
10238465def4SGreg Kroah-Hartman module->disconnected = true;
10248465def4SGreg Kroah-Hartman
10258465def4SGreg Kroah-Hartman gb_module_del(module);
10268465def4SGreg Kroah-Hartman list_del(&module->hd_node);
10278465def4SGreg Kroah-Hartman gb_module_put(module);
10288465def4SGreg Kroah-Hartman }
10298465def4SGreg Kroah-Hartman
gb_svc_process_intf_oops(struct gb_operation * operation)10308465def4SGreg Kroah-Hartman static void gb_svc_process_intf_oops(struct gb_operation *operation)
10318465def4SGreg Kroah-Hartman {
10328465def4SGreg Kroah-Hartman struct gb_svc_intf_oops_request *request;
10338465def4SGreg Kroah-Hartman struct gb_connection *connection = operation->connection;
10348465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
10358465def4SGreg Kroah-Hartman struct gb_interface *intf;
10368465def4SGreg Kroah-Hartman u8 intf_id;
10378465def4SGreg Kroah-Hartman u8 reason;
10388465def4SGreg Kroah-Hartman
10398465def4SGreg Kroah-Hartman /* The request message size has already been verified. */
10408465def4SGreg Kroah-Hartman request = operation->request->payload;
10418465def4SGreg Kroah-Hartman intf_id = request->intf_id;
10428465def4SGreg Kroah-Hartman reason = request->reason;
10438465def4SGreg Kroah-Hartman
10448465def4SGreg Kroah-Hartman intf = gb_svc_interface_lookup(svc, intf_id);
10458465def4SGreg Kroah-Hartman if (!intf) {
10468465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unexpected interface-oops event %u\n",
10478465def4SGreg Kroah-Hartman intf_id);
10488465def4SGreg Kroah-Hartman return;
10498465def4SGreg Kroah-Hartman }
10508465def4SGreg Kroah-Hartman
10518465def4SGreg Kroah-Hartman dev_info(&svc->dev, "Deactivating interface %u, interface oops reason = %u\n",
10528465def4SGreg Kroah-Hartman intf_id, reason);
10538465def4SGreg Kroah-Hartman
10548465def4SGreg Kroah-Hartman mutex_lock(&intf->mutex);
10558465def4SGreg Kroah-Hartman intf->disconnected = true;
10568465def4SGreg Kroah-Hartman gb_interface_disable(intf);
10578465def4SGreg Kroah-Hartman gb_interface_deactivate(intf);
10588465def4SGreg Kroah-Hartman mutex_unlock(&intf->mutex);
10598465def4SGreg Kroah-Hartman }
10608465def4SGreg Kroah-Hartman
gb_svc_process_intf_mailbox_event(struct gb_operation * operation)10618465def4SGreg Kroah-Hartman static void gb_svc_process_intf_mailbox_event(struct gb_operation *operation)
10628465def4SGreg Kroah-Hartman {
10638465def4SGreg Kroah-Hartman struct gb_svc_intf_mailbox_event_request *request;
10648465def4SGreg Kroah-Hartman struct gb_connection *connection = operation->connection;
10658465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
10668465def4SGreg Kroah-Hartman struct gb_interface *intf;
10678465def4SGreg Kroah-Hartman u8 intf_id;
10688465def4SGreg Kroah-Hartman u16 result_code;
10698465def4SGreg Kroah-Hartman u32 mailbox;
10708465def4SGreg Kroah-Hartman
10718465def4SGreg Kroah-Hartman /* The request message size has already been verified. */
10728465def4SGreg Kroah-Hartman request = operation->request->payload;
10738465def4SGreg Kroah-Hartman intf_id = request->intf_id;
10748465def4SGreg Kroah-Hartman result_code = le16_to_cpu(request->result_code);
10758465def4SGreg Kroah-Hartman mailbox = le32_to_cpu(request->mailbox);
10768465def4SGreg Kroah-Hartman
10778465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u, result = 0x%04x, mailbox = 0x%08x\n",
10788465def4SGreg Kroah-Hartman __func__, intf_id, result_code, mailbox);
10798465def4SGreg Kroah-Hartman
10808465def4SGreg Kroah-Hartman intf = gb_svc_interface_lookup(svc, intf_id);
10818465def4SGreg Kroah-Hartman if (!intf) {
10828465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unexpected mailbox event %u\n", intf_id);
10838465def4SGreg Kroah-Hartman return;
10848465def4SGreg Kroah-Hartman }
10858465def4SGreg Kroah-Hartman
10868465def4SGreg Kroah-Hartman gb_interface_mailbox_event(intf, result_code, mailbox);
10878465def4SGreg Kroah-Hartman }
10888465def4SGreg Kroah-Hartman
gb_svc_process_deferred_request(struct work_struct * work)10898465def4SGreg Kroah-Hartman static void gb_svc_process_deferred_request(struct work_struct *work)
10908465def4SGreg Kroah-Hartman {
10918465def4SGreg Kroah-Hartman struct gb_svc_deferred_request *dr;
10928465def4SGreg Kroah-Hartman struct gb_operation *operation;
10938465def4SGreg Kroah-Hartman struct gb_svc *svc;
10948465def4SGreg Kroah-Hartman u8 type;
10958465def4SGreg Kroah-Hartman
10968465def4SGreg Kroah-Hartman dr = container_of(work, struct gb_svc_deferred_request, work);
10978465def4SGreg Kroah-Hartman operation = dr->operation;
10988465def4SGreg Kroah-Hartman svc = gb_connection_get_data(operation->connection);
10998465def4SGreg Kroah-Hartman type = operation->request->header->type;
11008465def4SGreg Kroah-Hartman
11018465def4SGreg Kroah-Hartman switch (type) {
11028465def4SGreg Kroah-Hartman case GB_SVC_TYPE_SVC_HELLO:
11038465def4SGreg Kroah-Hartman gb_svc_process_hello_deferred(operation);
11048465def4SGreg Kroah-Hartman break;
11058465def4SGreg Kroah-Hartman case GB_SVC_TYPE_MODULE_INSERTED:
11068465def4SGreg Kroah-Hartman gb_svc_process_module_inserted(operation);
11078465def4SGreg Kroah-Hartman break;
11088465def4SGreg Kroah-Hartman case GB_SVC_TYPE_MODULE_REMOVED:
11098465def4SGreg Kroah-Hartman gb_svc_process_module_removed(operation);
11108465def4SGreg Kroah-Hartman break;
11118465def4SGreg Kroah-Hartman case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
11128465def4SGreg Kroah-Hartman gb_svc_process_intf_mailbox_event(operation);
11138465def4SGreg Kroah-Hartman break;
11148465def4SGreg Kroah-Hartman case GB_SVC_TYPE_INTF_OOPS:
11158465def4SGreg Kroah-Hartman gb_svc_process_intf_oops(operation);
11168465def4SGreg Kroah-Hartman break;
11178465def4SGreg Kroah-Hartman default:
11188465def4SGreg Kroah-Hartman dev_err(&svc->dev, "bad deferred request type: 0x%02x\n", type);
11198465def4SGreg Kroah-Hartman }
11208465def4SGreg Kroah-Hartman
11218465def4SGreg Kroah-Hartman gb_operation_put(operation);
11228465def4SGreg Kroah-Hartman kfree(dr);
11238465def4SGreg Kroah-Hartman }
11248465def4SGreg Kroah-Hartman
gb_svc_queue_deferred_request(struct gb_operation * operation)11258465def4SGreg Kroah-Hartman static int gb_svc_queue_deferred_request(struct gb_operation *operation)
11268465def4SGreg Kroah-Hartman {
11278465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(operation->connection);
11288465def4SGreg Kroah-Hartman struct gb_svc_deferred_request *dr;
11298465def4SGreg Kroah-Hartman
11308465def4SGreg Kroah-Hartman dr = kmalloc(sizeof(*dr), GFP_KERNEL);
11318465def4SGreg Kroah-Hartman if (!dr)
11328465def4SGreg Kroah-Hartman return -ENOMEM;
11338465def4SGreg Kroah-Hartman
11348465def4SGreg Kroah-Hartman gb_operation_get(operation);
11358465def4SGreg Kroah-Hartman
11368465def4SGreg Kroah-Hartman dr->operation = operation;
11378465def4SGreg Kroah-Hartman INIT_WORK(&dr->work, gb_svc_process_deferred_request);
11388465def4SGreg Kroah-Hartman
11398465def4SGreg Kroah-Hartman queue_work(svc->wq, &dr->work);
11408465def4SGreg Kroah-Hartman
11418465def4SGreg Kroah-Hartman return 0;
11428465def4SGreg Kroah-Hartman }
11438465def4SGreg Kroah-Hartman
gb_svc_intf_reset_recv(struct gb_operation * op)11448465def4SGreg Kroah-Hartman static int gb_svc_intf_reset_recv(struct gb_operation *op)
11458465def4SGreg Kroah-Hartman {
11468465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(op->connection);
11478465def4SGreg Kroah-Hartman struct gb_message *request = op->request;
11488465def4SGreg Kroah-Hartman struct gb_svc_intf_reset_request *reset;
11498465def4SGreg Kroah-Hartman
11508465def4SGreg Kroah-Hartman if (request->payload_size < sizeof(*reset)) {
11518465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short reset request received (%zu < %zu)\n",
11528465def4SGreg Kroah-Hartman request->payload_size, sizeof(*reset));
11538465def4SGreg Kroah-Hartman return -EINVAL;
11548465def4SGreg Kroah-Hartman }
11558465def4SGreg Kroah-Hartman reset = request->payload;
11568465def4SGreg Kroah-Hartman
11578465def4SGreg Kroah-Hartman /* FIXME Reset the interface here */
11588465def4SGreg Kroah-Hartman
11598465def4SGreg Kroah-Hartman return 0;
11608465def4SGreg Kroah-Hartman }
11618465def4SGreg Kroah-Hartman
gb_svc_module_inserted_recv(struct gb_operation * op)11628465def4SGreg Kroah-Hartman static int gb_svc_module_inserted_recv(struct gb_operation *op)
11638465def4SGreg Kroah-Hartman {
11648465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(op->connection);
11658465def4SGreg Kroah-Hartman struct gb_svc_module_inserted_request *request;
11668465def4SGreg Kroah-Hartman
11678465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*request)) {
11688465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short module-inserted request received (%zu < %zu)\n",
11698465def4SGreg Kroah-Hartman op->request->payload_size, sizeof(*request));
11708465def4SGreg Kroah-Hartman return -EINVAL;
11718465def4SGreg Kroah-Hartman }
11728465def4SGreg Kroah-Hartman
11738465def4SGreg Kroah-Hartman request = op->request->payload;
11748465def4SGreg Kroah-Hartman
11758465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
11768465def4SGreg Kroah-Hartman request->primary_intf_id);
11778465def4SGreg Kroah-Hartman
11788465def4SGreg Kroah-Hartman return gb_svc_queue_deferred_request(op);
11798465def4SGreg Kroah-Hartman }
11808465def4SGreg Kroah-Hartman
gb_svc_module_removed_recv(struct gb_operation * op)11818465def4SGreg Kroah-Hartman static int gb_svc_module_removed_recv(struct gb_operation *op)
11828465def4SGreg Kroah-Hartman {
11838465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(op->connection);
11848465def4SGreg Kroah-Hartman struct gb_svc_module_removed_request *request;
11858465def4SGreg Kroah-Hartman
11868465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*request)) {
11878465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short module-removed request received (%zu < %zu)\n",
11888465def4SGreg Kroah-Hartman op->request->payload_size, sizeof(*request));
11898465def4SGreg Kroah-Hartman return -EINVAL;
11908465def4SGreg Kroah-Hartman }
11918465def4SGreg Kroah-Hartman
11928465def4SGreg Kroah-Hartman request = op->request->payload;
11938465def4SGreg Kroah-Hartman
11948465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u\n", __func__,
11958465def4SGreg Kroah-Hartman request->primary_intf_id);
11968465def4SGreg Kroah-Hartman
11978465def4SGreg Kroah-Hartman return gb_svc_queue_deferred_request(op);
11988465def4SGreg Kroah-Hartman }
11998465def4SGreg Kroah-Hartman
gb_svc_intf_oops_recv(struct gb_operation * op)12008465def4SGreg Kroah-Hartman static int gb_svc_intf_oops_recv(struct gb_operation *op)
12018465def4SGreg Kroah-Hartman {
12028465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(op->connection);
12038465def4SGreg Kroah-Hartman struct gb_svc_intf_oops_request *request;
12048465def4SGreg Kroah-Hartman
12058465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*request)) {
12068465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short intf-oops request received (%zu < %zu)\n",
12078465def4SGreg Kroah-Hartman op->request->payload_size, sizeof(*request));
12088465def4SGreg Kroah-Hartman return -EINVAL;
12098465def4SGreg Kroah-Hartman }
12108465def4SGreg Kroah-Hartman
12118465def4SGreg Kroah-Hartman return gb_svc_queue_deferred_request(op);
12128465def4SGreg Kroah-Hartman }
12138465def4SGreg Kroah-Hartman
gb_svc_intf_mailbox_event_recv(struct gb_operation * op)12148465def4SGreg Kroah-Hartman static int gb_svc_intf_mailbox_event_recv(struct gb_operation *op)
12158465def4SGreg Kroah-Hartman {
12168465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(op->connection);
12178465def4SGreg Kroah-Hartman struct gb_svc_intf_mailbox_event_request *request;
12188465def4SGreg Kroah-Hartman
12198465def4SGreg Kroah-Hartman if (op->request->payload_size < sizeof(*request)) {
12208465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "short mailbox request received (%zu < %zu)\n",
12218465def4SGreg Kroah-Hartman op->request->payload_size, sizeof(*request));
12228465def4SGreg Kroah-Hartman return -EINVAL;
12238465def4SGreg Kroah-Hartman }
12248465def4SGreg Kroah-Hartman
12258465def4SGreg Kroah-Hartman request = op->request->payload;
12268465def4SGreg Kroah-Hartman
12278465def4SGreg Kroah-Hartman dev_dbg(&svc->dev, "%s - id = %u\n", __func__, request->intf_id);
12288465def4SGreg Kroah-Hartman
12298465def4SGreg Kroah-Hartman return gb_svc_queue_deferred_request(op);
12308465def4SGreg Kroah-Hartman }
12318465def4SGreg Kroah-Hartman
gb_svc_request_handler(struct gb_operation * op)12328465def4SGreg Kroah-Hartman static int gb_svc_request_handler(struct gb_operation *op)
12338465def4SGreg Kroah-Hartman {
12348465def4SGreg Kroah-Hartman struct gb_connection *connection = op->connection;
12358465def4SGreg Kroah-Hartman struct gb_svc *svc = gb_connection_get_data(connection);
12368465def4SGreg Kroah-Hartman u8 type = op->type;
12378465def4SGreg Kroah-Hartman int ret = 0;
12388465def4SGreg Kroah-Hartman
12398465def4SGreg Kroah-Hartman /*
12408465def4SGreg Kroah-Hartman * SVC requests need to follow a specific order (at least initially) and
12418465def4SGreg Kroah-Hartman * below code takes care of enforcing that. The expected order is:
12428465def4SGreg Kroah-Hartman * - PROTOCOL_VERSION
12438465def4SGreg Kroah-Hartman * - SVC_HELLO
12448465def4SGreg Kroah-Hartman * - Any other request, but the earlier two.
12458465def4SGreg Kroah-Hartman *
12468465def4SGreg Kroah-Hartman * Incoming requests are guaranteed to be serialized and so we don't
12478465def4SGreg Kroah-Hartman * need to protect 'state' for any races.
12488465def4SGreg Kroah-Hartman */
12498465def4SGreg Kroah-Hartman switch (type) {
12508465def4SGreg Kroah-Hartman case GB_SVC_TYPE_PROTOCOL_VERSION:
12518465def4SGreg Kroah-Hartman if (svc->state != GB_SVC_STATE_RESET)
12528465def4SGreg Kroah-Hartman ret = -EINVAL;
12538465def4SGreg Kroah-Hartman break;
12548465def4SGreg Kroah-Hartman case GB_SVC_TYPE_SVC_HELLO:
12558465def4SGreg Kroah-Hartman if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
12568465def4SGreg Kroah-Hartman ret = -EINVAL;
12578465def4SGreg Kroah-Hartman break;
12588465def4SGreg Kroah-Hartman default:
12598465def4SGreg Kroah-Hartman if (svc->state != GB_SVC_STATE_SVC_HELLO)
12608465def4SGreg Kroah-Hartman ret = -EINVAL;
12618465def4SGreg Kroah-Hartman break;
12628465def4SGreg Kroah-Hartman }
12638465def4SGreg Kroah-Hartman
12648465def4SGreg Kroah-Hartman if (ret) {
12658465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unexpected request 0x%02x received (state %u)\n",
12668465def4SGreg Kroah-Hartman type, svc->state);
12678465def4SGreg Kroah-Hartman return ret;
12688465def4SGreg Kroah-Hartman }
12698465def4SGreg Kroah-Hartman
12708465def4SGreg Kroah-Hartman switch (type) {
12718465def4SGreg Kroah-Hartman case GB_SVC_TYPE_PROTOCOL_VERSION:
12728465def4SGreg Kroah-Hartman ret = gb_svc_version_request(op);
12738465def4SGreg Kroah-Hartman if (!ret)
12748465def4SGreg Kroah-Hartman svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
12758465def4SGreg Kroah-Hartman return ret;
12768465def4SGreg Kroah-Hartman case GB_SVC_TYPE_SVC_HELLO:
12778465def4SGreg Kroah-Hartman ret = gb_svc_hello(op);
12788465def4SGreg Kroah-Hartman if (!ret)
12798465def4SGreg Kroah-Hartman svc->state = GB_SVC_STATE_SVC_HELLO;
12808465def4SGreg Kroah-Hartman return ret;
12818465def4SGreg Kroah-Hartman case GB_SVC_TYPE_INTF_RESET:
12828465def4SGreg Kroah-Hartman return gb_svc_intf_reset_recv(op);
12838465def4SGreg Kroah-Hartman case GB_SVC_TYPE_MODULE_INSERTED:
12848465def4SGreg Kroah-Hartman return gb_svc_module_inserted_recv(op);
12858465def4SGreg Kroah-Hartman case GB_SVC_TYPE_MODULE_REMOVED:
12868465def4SGreg Kroah-Hartman return gb_svc_module_removed_recv(op);
12878465def4SGreg Kroah-Hartman case GB_SVC_TYPE_INTF_MAILBOX_EVENT:
12888465def4SGreg Kroah-Hartman return gb_svc_intf_mailbox_event_recv(op);
12898465def4SGreg Kroah-Hartman case GB_SVC_TYPE_INTF_OOPS:
12908465def4SGreg Kroah-Hartman return gb_svc_intf_oops_recv(op);
12918465def4SGreg Kroah-Hartman default:
12928465def4SGreg Kroah-Hartman dev_warn(&svc->dev, "unsupported request 0x%02x\n", type);
12938465def4SGreg Kroah-Hartman return -EINVAL;
12948465def4SGreg Kroah-Hartman }
12958465def4SGreg Kroah-Hartman }
12968465def4SGreg Kroah-Hartman
gb_svc_release(struct device * dev)12978465def4SGreg Kroah-Hartman static void gb_svc_release(struct device *dev)
12988465def4SGreg Kroah-Hartman {
12998465def4SGreg Kroah-Hartman struct gb_svc *svc = to_gb_svc(dev);
13008465def4SGreg Kroah-Hartman
13018465def4SGreg Kroah-Hartman if (svc->connection)
13028465def4SGreg Kroah-Hartman gb_connection_destroy(svc->connection);
13038465def4SGreg Kroah-Hartman ida_destroy(&svc->device_id_map);
13048465def4SGreg Kroah-Hartman destroy_workqueue(svc->wq);
13058465def4SGreg Kroah-Hartman kfree(svc);
13068465def4SGreg Kroah-Hartman }
13078465def4SGreg Kroah-Hartman
13088465def4SGreg Kroah-Hartman struct device_type greybus_svc_type = {
13098465def4SGreg Kroah-Hartman .name = "greybus_svc",
13108465def4SGreg Kroah-Hartman .release = gb_svc_release,
13118465def4SGreg Kroah-Hartman };
13128465def4SGreg Kroah-Hartman
gb_svc_create(struct gb_host_device * hd)13138465def4SGreg Kroah-Hartman struct gb_svc *gb_svc_create(struct gb_host_device *hd)
13148465def4SGreg Kroah-Hartman {
13158465def4SGreg Kroah-Hartman struct gb_svc *svc;
13168465def4SGreg Kroah-Hartman
13178465def4SGreg Kroah-Hartman svc = kzalloc(sizeof(*svc), GFP_KERNEL);
13188465def4SGreg Kroah-Hartman if (!svc)
13198465def4SGreg Kroah-Hartman return NULL;
13208465def4SGreg Kroah-Hartman
1321*44d69dd9STejun Heo svc->wq = alloc_ordered_workqueue("%s:svc", 0, dev_name(&hd->dev));
13228465def4SGreg Kroah-Hartman if (!svc->wq) {
13238465def4SGreg Kroah-Hartman kfree(svc);
13248465def4SGreg Kroah-Hartman return NULL;
13258465def4SGreg Kroah-Hartman }
13268465def4SGreg Kroah-Hartman
13278465def4SGreg Kroah-Hartman svc->dev.parent = &hd->dev;
13288465def4SGreg Kroah-Hartman svc->dev.bus = &greybus_bus_type;
13298465def4SGreg Kroah-Hartman svc->dev.type = &greybus_svc_type;
13308465def4SGreg Kroah-Hartman svc->dev.groups = svc_groups;
13318465def4SGreg Kroah-Hartman svc->dev.dma_mask = svc->dev.parent->dma_mask;
13328465def4SGreg Kroah-Hartman device_initialize(&svc->dev);
13338465def4SGreg Kroah-Hartman
13348465def4SGreg Kroah-Hartman dev_set_name(&svc->dev, "%d-svc", hd->bus_id);
13358465def4SGreg Kroah-Hartman
13368465def4SGreg Kroah-Hartman ida_init(&svc->device_id_map);
13378465def4SGreg Kroah-Hartman svc->state = GB_SVC_STATE_RESET;
13388465def4SGreg Kroah-Hartman svc->hd = hd;
13398465def4SGreg Kroah-Hartman
13408465def4SGreg Kroah-Hartman svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
13418465def4SGreg Kroah-Hartman gb_svc_request_handler);
13428465def4SGreg Kroah-Hartman if (IS_ERR(svc->connection)) {
13438465def4SGreg Kroah-Hartman dev_err(&svc->dev, "failed to create connection: %ld\n",
13448465def4SGreg Kroah-Hartman PTR_ERR(svc->connection));
13458465def4SGreg Kroah-Hartman goto err_put_device;
13468465def4SGreg Kroah-Hartman }
13478465def4SGreg Kroah-Hartman
13488465def4SGreg Kroah-Hartman gb_connection_set_data(svc->connection, svc);
13498465def4SGreg Kroah-Hartman
13508465def4SGreg Kroah-Hartman return svc;
13518465def4SGreg Kroah-Hartman
13528465def4SGreg Kroah-Hartman err_put_device:
13538465def4SGreg Kroah-Hartman put_device(&svc->dev);
13548465def4SGreg Kroah-Hartman return NULL;
13558465def4SGreg Kroah-Hartman }
13568465def4SGreg Kroah-Hartman
gb_svc_add(struct gb_svc * svc)13578465def4SGreg Kroah-Hartman int gb_svc_add(struct gb_svc *svc)
13588465def4SGreg Kroah-Hartman {
13598465def4SGreg Kroah-Hartman int ret;
13608465def4SGreg Kroah-Hartman
13618465def4SGreg Kroah-Hartman /*
13628465def4SGreg Kroah-Hartman * The SVC protocol is currently driven by the SVC, so the SVC device
13638465def4SGreg Kroah-Hartman * is added from the connection request handler when enough
13648465def4SGreg Kroah-Hartman * information has been received.
13658465def4SGreg Kroah-Hartman */
13668465def4SGreg Kroah-Hartman ret = gb_connection_enable(svc->connection);
13678465def4SGreg Kroah-Hartman if (ret)
13688465def4SGreg Kroah-Hartman return ret;
13698465def4SGreg Kroah-Hartman
13708465def4SGreg Kroah-Hartman return 0;
13718465def4SGreg Kroah-Hartman }
13728465def4SGreg Kroah-Hartman
gb_svc_remove_modules(struct gb_svc * svc)13738465def4SGreg Kroah-Hartman static void gb_svc_remove_modules(struct gb_svc *svc)
13748465def4SGreg Kroah-Hartman {
13758465def4SGreg Kroah-Hartman struct gb_host_device *hd = svc->hd;
13768465def4SGreg Kroah-Hartman struct gb_module *module, *tmp;
13778465def4SGreg Kroah-Hartman
13788465def4SGreg Kroah-Hartman list_for_each_entry_safe(module, tmp, &hd->modules, hd_node) {
13798465def4SGreg Kroah-Hartman gb_module_del(module);
13808465def4SGreg Kroah-Hartman list_del(&module->hd_node);
13818465def4SGreg Kroah-Hartman gb_module_put(module);
13828465def4SGreg Kroah-Hartman }
13838465def4SGreg Kroah-Hartman }
13848465def4SGreg Kroah-Hartman
gb_svc_del(struct gb_svc * svc)13858465def4SGreg Kroah-Hartman void gb_svc_del(struct gb_svc *svc)
13868465def4SGreg Kroah-Hartman {
13878465def4SGreg Kroah-Hartman gb_connection_disable_rx(svc->connection);
13888465def4SGreg Kroah-Hartman
13898465def4SGreg Kroah-Hartman /*
13908465def4SGreg Kroah-Hartman * The SVC device may have been registered from the request handler.
13918465def4SGreg Kroah-Hartman */
13928465def4SGreg Kroah-Hartman if (device_is_registered(&svc->dev)) {
13938465def4SGreg Kroah-Hartman gb_svc_debugfs_exit(svc);
13948465def4SGreg Kroah-Hartman gb_svc_watchdog_destroy(svc);
13958465def4SGreg Kroah-Hartman device_del(&svc->dev);
13968465def4SGreg Kroah-Hartman }
13978465def4SGreg Kroah-Hartman
13988465def4SGreg Kroah-Hartman flush_workqueue(svc->wq);
13998465def4SGreg Kroah-Hartman
14008465def4SGreg Kroah-Hartman gb_svc_remove_modules(svc);
14018465def4SGreg Kroah-Hartman
14028465def4SGreg Kroah-Hartman gb_connection_disable(svc->connection);
14038465def4SGreg Kroah-Hartman }
14048465def4SGreg Kroah-Hartman
gb_svc_put(struct gb_svc * svc)14058465def4SGreg Kroah-Hartman void gb_svc_put(struct gb_svc *svc)
14068465def4SGreg Kroah-Hartman {
14078465def4SGreg Kroah-Hartman put_device(&svc->dev);
14088465def4SGreg Kroah-Hartman }
1409