1 /*
2 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <string.h>
8 #include <metal/assert.h>
9 #include <metal/device.h>
10 #include <metal/errno.h>
11 #include <metal/list.h>
12 #include <metal/log.h>
13 #include <metal/sys.h>
14 #include <metal/utilities.h>
15 #include <metal/dma.h>
16 #include <metal/cache.h>
17
metal_bus_register(struct metal_bus * bus)18 int metal_bus_register(struct metal_bus *bus)
19 {
20 if (!bus || !bus->name || !strlen(bus->name))
21 return -EINVAL;
22 if (metal_bus_find(bus->name, NULL) == 0)
23 return -EEXIST;
24 metal_list_init(&bus->devices);
25 metal_list_add_tail(&_metal.common.bus_list, &bus->node);
26 metal_log(METAL_LOG_DEBUG, "registered %s bus\n", bus->name);
27 return 0;
28 }
29
metal_bus_unregister(struct metal_bus * bus)30 int metal_bus_unregister(struct metal_bus *bus)
31 {
32 metal_list_del(&bus->node);
33 if (bus->ops.bus_close)
34 bus->ops.bus_close(bus);
35 metal_log(METAL_LOG_DEBUG, "unregistered %s bus\n", bus->name);
36 return 0;
37 }
38
metal_bus_find(const char * name,struct metal_bus ** result)39 int metal_bus_find(const char *name, struct metal_bus **result)
40 {
41 struct metal_list *node;
42 struct metal_bus *bus;
43
44 metal_list_for_each(&_metal.common.bus_list, node) {
45 bus = metal_container_of(node, struct metal_bus, node);
46 if (strcmp(bus->name, name) == 0 && result) {
47 *result = bus;
48 return 0;
49 }
50 }
51 return -ENOENT;
52 }
53
metal_device_open(const char * bus_name,const char * dev_name,struct metal_device ** device)54 int metal_device_open(const char *bus_name, const char *dev_name,
55 struct metal_device **device)
56 {
57 struct metal_bus *bus;
58 int error;
59
60 if (!bus_name || !strlen(bus_name) ||
61 !dev_name || !strlen(dev_name) ||
62 !device)
63 return -EINVAL;
64
65 error = metal_bus_find(bus_name, &bus);
66 if (error)
67 return error;
68
69 if (!bus->ops.dev_open)
70 return -ENODEV;
71
72 error = (*bus->ops.dev_open)(bus, dev_name, device);
73 if (error)
74 return error;
75
76 return 0;
77 }
78
metal_device_close(struct metal_device * device)79 void metal_device_close(struct metal_device *device)
80 {
81 metal_assert(device && device->bus);
82 if (device->bus->ops.dev_close)
83 device->bus->ops.dev_close(device->bus, device);
84 }
85
metal_register_generic_device(struct metal_device * device)86 int metal_register_generic_device(struct metal_device *device)
87 {
88 if (!device->name || !strlen(device->name) ||
89 device->num_regions > METAL_MAX_DEVICE_REGIONS)
90 return -EINVAL;
91
92 device->bus = &metal_generic_bus;
93 metal_list_add_tail(&_metal.common.generic_device_list,
94 &device->node);
95 return 0;
96 }
97
metal_generic_dev_open(struct metal_bus * bus,const char * dev_name,struct metal_device ** device)98 int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
99 struct metal_device **device)
100 {
101 struct metal_list *node;
102 struct metal_device *dev;
103
104 (void)bus;
105
106 metal_list_for_each(&_metal.common.generic_device_list, node) {
107 dev = metal_container_of(node, struct metal_device, node);
108 if (strcmp(dev->name, dev_name) == 0) {
109 *device = dev;
110 return metal_generic_dev_sys_open(dev);
111 }
112 }
113
114 return -ENODEV;
115 }
116
metal_generic_dev_dma_map(struct metal_bus * bus,struct metal_device * device,uint32_t dir,struct metal_sg * sg_in,int nents_in,struct metal_sg * sg_out)117 int metal_generic_dev_dma_map(struct metal_bus *bus,
118 struct metal_device *device,
119 uint32_t dir,
120 struct metal_sg *sg_in,
121 int nents_in,
122 struct metal_sg *sg_out)
123 {
124 int i;
125 (void)bus;
126 (void)device;
127
128 if (sg_out != sg_in)
129 memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg)));
130 for (i = 0; i < nents_in; i++) {
131 if (dir == METAL_DMA_DEV_W) {
132 metal_cache_flush(sg_out[i].virt, sg_out[i].len);
133 }
134 metal_cache_invalidate(sg_out[i].virt, sg_out[i].len);
135 }
136
137 return nents_in;
138 }
139
metal_generic_dev_dma_unmap(struct metal_bus * bus,struct metal_device * device,uint32_t dir,struct metal_sg * sg,int nents)140 void metal_generic_dev_dma_unmap(struct metal_bus *bus,
141 struct metal_device *device,
142 uint32_t dir,
143 struct metal_sg *sg,
144 int nents)
145 {
146 int i;
147 (void)bus;
148 (void)device;
149 (void)dir;
150
151 for (i = 0; i < nents; i++) {
152 metal_cache_invalidate(sg[i].virt, sg[i].len);
153 }
154 }
155
156 struct metal_bus metal_weak metal_generic_bus = {
157 .name = "generic",
158 .ops = {
159 .bus_close = NULL,
160 .dev_open = metal_generic_dev_open,
161 .dev_close = NULL,
162 .dev_irq_ack = NULL,
163 .dev_dma_map = metal_generic_dev_dma_map,
164 .dev_dma_unmap = metal_generic_dev_dma_unmap,
165 },
166 };
167