18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Greybus Module code 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Google Inc. 68c2ecf20Sopenharmony_ci * Copyright 2016 Linaro Ltd. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/greybus.h> 108c2ecf20Sopenharmony_ci#include "greybus_trace.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic ssize_t eject_store(struct device *dev, 138c2ecf20Sopenharmony_ci struct device_attribute *attr, 148c2ecf20Sopenharmony_ci const char *buf, size_t len) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct gb_module *module = to_gb_module(dev); 178c2ecf20Sopenharmony_ci struct gb_interface *intf; 188c2ecf20Sopenharmony_ci size_t i; 198c2ecf20Sopenharmony_ci long val; 208c2ecf20Sopenharmony_ci int ret; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci ret = kstrtol(buf, 0, &val); 238c2ecf20Sopenharmony_ci if (ret) 248c2ecf20Sopenharmony_ci return ret; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (!val) 278c2ecf20Sopenharmony_ci return len; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci for (i = 0; i < module->num_interfaces; ++i) { 308c2ecf20Sopenharmony_ci intf = module->interfaces[i]; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci mutex_lock(&intf->mutex); 338c2ecf20Sopenharmony_ci /* Set flag to prevent concurrent activation. */ 348c2ecf20Sopenharmony_ci intf->ejected = true; 358c2ecf20Sopenharmony_ci gb_interface_disable(intf); 368c2ecf20Sopenharmony_ci gb_interface_deactivate(intf); 378c2ecf20Sopenharmony_ci mutex_unlock(&intf->mutex); 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* Tell the SVC to eject the primary interface. */ 418c2ecf20Sopenharmony_ci ret = gb_svc_intf_eject(module->hd->svc, module->module_id); 428c2ecf20Sopenharmony_ci if (ret) 438c2ecf20Sopenharmony_ci return ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return len; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(eject); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic ssize_t module_id_show(struct device *dev, 508c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct gb_module *module = to_gb_module(dev); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", module->module_id); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(module_id); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic ssize_t num_interfaces_show(struct device *dev, 598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct gb_module *module = to_gb_module(dev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return sprintf(buf, "%zu\n", module->num_interfaces); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(num_interfaces); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct attribute *module_attrs[] = { 688c2ecf20Sopenharmony_ci &dev_attr_eject.attr, 698c2ecf20Sopenharmony_ci &dev_attr_module_id.attr, 708c2ecf20Sopenharmony_ci &dev_attr_num_interfaces.attr, 718c2ecf20Sopenharmony_ci NULL, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(module); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void gb_module_release(struct device *dev) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct gb_module *module = to_gb_module(dev); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci trace_gb_module_release(module); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci kfree(module); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct device_type greybus_module_type = { 858c2ecf20Sopenharmony_ci .name = "greybus_module", 868c2ecf20Sopenharmony_ci .release = gb_module_release, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id, 908c2ecf20Sopenharmony_ci size_t num_interfaces) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct gb_interface *intf; 938c2ecf20Sopenharmony_ci struct gb_module *module; 948c2ecf20Sopenharmony_ci int i; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci module = kzalloc(struct_size(module, interfaces, num_interfaces), 978c2ecf20Sopenharmony_ci GFP_KERNEL); 988c2ecf20Sopenharmony_ci if (!module) 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci module->hd = hd; 1028c2ecf20Sopenharmony_ci module->module_id = module_id; 1038c2ecf20Sopenharmony_ci module->num_interfaces = num_interfaces; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci module->dev.parent = &hd->dev; 1068c2ecf20Sopenharmony_ci module->dev.bus = &greybus_bus_type; 1078c2ecf20Sopenharmony_ci module->dev.type = &greybus_module_type; 1088c2ecf20Sopenharmony_ci module->dev.groups = module_groups; 1098c2ecf20Sopenharmony_ci module->dev.dma_mask = hd->dev.dma_mask; 1108c2ecf20Sopenharmony_ci device_initialize(&module->dev); 1118c2ecf20Sopenharmony_ci dev_set_name(&module->dev, "%d-%u", hd->bus_id, module_id); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci trace_gb_module_create(module); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci for (i = 0; i < num_interfaces; ++i) { 1168c2ecf20Sopenharmony_ci intf = gb_interface_create(module, module_id + i); 1178c2ecf20Sopenharmony_ci if (!intf) { 1188c2ecf20Sopenharmony_ci dev_err(&module->dev, "failed to create interface %u\n", 1198c2ecf20Sopenharmony_ci module_id + i); 1208c2ecf20Sopenharmony_ci goto err_put_interfaces; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci module->interfaces[i] = intf; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return module; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cierr_put_interfaces: 1288c2ecf20Sopenharmony_ci for (--i; i >= 0; --i) 1298c2ecf20Sopenharmony_ci gb_interface_put(module->interfaces[i]); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci put_device(&module->dev); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return NULL; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * Register and enable an interface after first attempting to activate it. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cistatic void gb_module_register_interface(struct gb_interface *intf) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct gb_module *module = intf->module; 1428c2ecf20Sopenharmony_ci u8 intf_id = intf->interface_id; 1438c2ecf20Sopenharmony_ci int ret; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mutex_lock(&intf->mutex); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ret = gb_interface_activate(intf); 1488c2ecf20Sopenharmony_ci if (ret) { 1498c2ecf20Sopenharmony_ci if (intf->type != GB_INTERFACE_TYPE_DUMMY) { 1508c2ecf20Sopenharmony_ci dev_err(&module->dev, 1518c2ecf20Sopenharmony_ci "failed to activate interface %u: %d\n", 1528c2ecf20Sopenharmony_ci intf_id, ret); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci gb_interface_add(intf); 1568c2ecf20Sopenharmony_ci goto err_unlock; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = gb_interface_add(intf); 1608c2ecf20Sopenharmony_ci if (ret) 1618c2ecf20Sopenharmony_ci goto err_interface_deactivate; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ret = gb_interface_enable(intf); 1648c2ecf20Sopenharmony_ci if (ret) { 1658c2ecf20Sopenharmony_ci dev_err(&module->dev, "failed to enable interface %u: %d\n", 1668c2ecf20Sopenharmony_ci intf_id, ret); 1678c2ecf20Sopenharmony_ci goto err_interface_deactivate; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mutex_unlock(&intf->mutex); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cierr_interface_deactivate: 1758c2ecf20Sopenharmony_ci gb_interface_deactivate(intf); 1768c2ecf20Sopenharmony_cierr_unlock: 1778c2ecf20Sopenharmony_ci mutex_unlock(&intf->mutex); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void gb_module_deregister_interface(struct gb_interface *intf) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci /* Mark as disconnected to prevent I/O during disable. */ 1838c2ecf20Sopenharmony_ci if (intf->module->disconnected) 1848c2ecf20Sopenharmony_ci intf->disconnected = true; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci mutex_lock(&intf->mutex); 1878c2ecf20Sopenharmony_ci intf->removed = true; 1888c2ecf20Sopenharmony_ci gb_interface_disable(intf); 1898c2ecf20Sopenharmony_ci gb_interface_deactivate(intf); 1908c2ecf20Sopenharmony_ci mutex_unlock(&intf->mutex); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci gb_interface_del(intf); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* Register a module and its interfaces. */ 1968c2ecf20Sopenharmony_ciint gb_module_add(struct gb_module *module) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci size_t i; 1998c2ecf20Sopenharmony_ci int ret; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci ret = device_add(&module->dev); 2028c2ecf20Sopenharmony_ci if (ret) { 2038c2ecf20Sopenharmony_ci dev_err(&module->dev, "failed to register module: %d\n", ret); 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci trace_gb_module_add(module); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci for (i = 0; i < module->num_interfaces; ++i) 2108c2ecf20Sopenharmony_ci gb_module_register_interface(module->interfaces[i]); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Deregister a module and its interfaces. */ 2168c2ecf20Sopenharmony_civoid gb_module_del(struct gb_module *module) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci size_t i; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci for (i = 0; i < module->num_interfaces; ++i) 2218c2ecf20Sopenharmony_ci gb_module_deregister_interface(module->interfaces[i]); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci trace_gb_module_del(module); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci device_del(&module->dev); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_civoid gb_module_put(struct gb_module *module) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci size_t i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < module->num_interfaces; ++i) 2338c2ecf20Sopenharmony_ci gb_interface_put(module->interfaces[i]); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci put_device(&module->dev); 2368c2ecf20Sopenharmony_ci} 237