1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2022, Linaro Ltd.
*
*/
#ifndef _MHI_EP_H_
#define _MHI_EP_H_
#include <linux/dma-direction.h>
#include <linux/mhi.h>
#define MHI_EP_DEFAULT_MTU 0x8000
/**
* struct mhi_ep_channel_config - Channel configuration structure for controller
* @name: The name of this channel
* @num: The number assigned to this channel
* @num_elements: The number of elements that can be queued to this channel
* @dir: Direction that data may flow on this channel
*/
struct mhi_ep_channel_config {
char *name;
u32 num;
u32 num_elements;
enum dma_data_direction dir;
};
/**
* struct mhi_ep_cntrl_config - MHI Endpoint controller configuration
* @mhi_version: MHI spec version supported by the controller
* @max_channels: Maximum number of channels supported
* @num_channels: Number of channels defined in @ch_cfg
* @ch_cfg: Array of defined channels
*/
struct mhi_ep_cntrl_config {
u32 mhi_version;
u32 max_channels;
u32 num_channels;
const struct mhi_ep_channel_config *ch_cfg;
};
/**
* struct mhi_ep_db_info - MHI Endpoint doorbell info
* @mask: Mask of the doorbell interrupt
* @status: Status of the doorbell interrupt
*/
struct mhi_ep_db_info {
u32 mask;
u32 status;
};
/**
* struct mhi_ep_buf_info - MHI Endpoint transfer buffer info
* @mhi_dev: MHI device associated with this buffer
* @dev_addr: Address of the buffer in endpoint
* @host_addr: Address of the bufffer in host
* @size: Size of the buffer
* @code: Transfer completion code
* @cb: Callback to be executed by controller drivers after transfer completion (async)
* @cb_buf: Opaque buffer to be passed to the callback
*/
struct mhi_ep_buf_info {
struct mhi_ep_device *mhi_dev;
void *dev_addr;
u64 host_addr;
size_t size;
int code;
void (*cb)(struct mhi_ep_buf_info *buf_info);
void *cb_buf;
};
/**
* struct mhi_ep_cntrl - MHI Endpoint controller structure
* @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI
* Endpoint controller
* @mhi_dev: MHI Endpoint device instance for the controller
* @mmio: MMIO region containing the MHI registers
* @mhi_chan: Points to the channel configuration table
* @mhi_event: Points to the event ring configurations table
* @mhi_cmd: Points to the command ring configurations table
* @sm: MHI Endpoint state machine
* @ch_ctx_cache: Cache of host channel context data structure
* @ev_ctx_cache: Cache of host event context data structure
* @cmd_ctx_cache: Cache of host command context data structure
* @ch_ctx_host_pa: Physical address of host channel context data structure
* @ev_ctx_host_pa: Physical address of host event context data structure
* @cmd_ctx_host_pa: Physical address of host command context data structure
* @ch_ctx_cache_phys: Physical address of the host channel context cache
* @ev_ctx_cache_phys: Physical address of the host event context cache
* @cmd_ctx_cache_phys: Physical address of the host command context cache
* @chdb: Array of channel doorbell interrupt info
* @event_lock: Lock for protecting event rings
* @state_lock: Lock for protecting state transitions
* @list_lock: Lock for protecting state transition and channel doorbell lists
* @st_transition_list: List of state transitions
* @ch_db_list: List of queued channel doorbells
* @wq: Dedicated workqueue for handling rings and state changes
* @state_work: State transition worker
* @reset_work: Worker for MHI Endpoint reset
* @cmd_ring_work: Worker for processing command rings
* @ch_ring_work: Worker for processing channel rings
* @raise_irq: CB function for raising IRQ to the host
* @alloc_map: CB function for allocating memory in endpoint for storing host context and mapping it
* @unmap_free: CB function to unmap and free the allocated memory in endpoint for storing host context
* @read_sync: CB function for reading from host memory synchronously
* @write_sync: CB function for writing to host memory synchronously
* @read_async: CB function for reading from host memory asynchronously
* @write_async: CB function for writing to host memory asynchronously
* @mhi_state: MHI Endpoint state
* @max_chan: Maximum channels supported by the endpoint controller
* @mru: MRU (Maximum Receive Unit) value of the endpoint controller
* @event_rings: Number of event rings supported by the endpoint controller
* @hw_event_rings: Number of hardware event rings supported by the endpoint controller
* @chdb_offset: Channel doorbell offset set by the host
* @erdb_offset: Event ring doorbell offset set by the host
* @index: MHI Endpoint controller index
* @irq: IRQ used by the endpoint controller
* @enabled: Check if the endpoint controller is enabled or not
*/
struct mhi_ep_cntrl {
struct device *cntrl_dev;
struct mhi_ep_device *mhi_dev;
void __iomem *mmio;
struct mhi_ep_chan *mhi_chan;
struct mhi_ep_event *mhi_event;
struct mhi_ep_cmd *mhi_cmd;
struct mhi_ep_sm *sm;
struct mhi_chan_ctxt *ch_ctx_cache;
struct mhi_event_ctxt *ev_ctx_cache;
struct mhi_cmd_ctxt *cmd_ctx_cache;
u64 ch_ctx_host_pa;
u64 ev_ctx_host_pa;
u64 cmd_ctx_host_pa;
phys_addr_t ch_ctx_cache_phys;
phys_addr_t ev_ctx_cache_phys;
phys_addr_t cmd_ctx_cache_phys;
struct mhi_ep_db_info chdb[4];
struct mutex event_lock;
struct mutex state_lock;
spinlock_t list_lock;
struct list_head st_transition_list;
struct list_head ch_db_list;
struct workqueue_struct *wq;
struct work_struct state_work;
struct work_struct reset_work;
struct work_struct cmd_ring_work;
struct work_struct ch_ring_work;
struct kmem_cache *ring_item_cache;
struct kmem_cache *ev_ring_el_cache;
struct kmem_cache *tre_buf_cache;
void (*raise_irq)(struct mhi_ep_cntrl *mhi_cntrl, u32 vector);
int (*alloc_map)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t *phys_ptr,
void __iomem **virt, size_t size);
void (*unmap_free)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t phys,
void __iomem *virt, size_t size);
int (*read_sync)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
int (*write_sync)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
int (*read_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
int (*write_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
enum mhi_state mhi_state;
u32 max_chan;
u32 mru;
u32 event_rings;
u32 hw_event_rings;
u32 chdb_offset;
u32 erdb_offset;
u32 index;
int irq;
bool enabled;
};
/**
* struct mhi_ep_device - Structure representing an MHI Endpoint device that binds
* to channels or is associated with controllers
* @dev: Driver model device node for the MHI Endpoint device
* @mhi_cntrl: Controller the device belongs to
* @id: Pointer to MHI Endpoint device ID struct
* @name: Name of the associated MHI Endpoint device
* @ul_chan: UL (from host to endpoint) channel for the device
* @dl_chan: DL (from endpoint to host) channel for the device
* @dev_type: MHI device type
*/
struct mhi_ep_device {
struct device dev;
struct mhi_ep_cntrl *mhi_cntrl;
const struct mhi_device_id *id;
const char *name;
struct mhi_ep_chan *ul_chan;
struct mhi_ep_chan *dl_chan;
enum mhi_device_type dev_type;
};
/**
* struct mhi_ep_driver - Structure representing a MHI Endpoint client driver
* @id_table: Pointer to MHI Endpoint device ID table
* @driver: Device driver model driver
* @probe: CB function for client driver probe function
* @remove: CB function for client driver remove function
* @ul_xfer_cb: CB function for UL (from host to endpoint) data transfer
* @dl_xfer_cb: CB function for DL (from endpoint to host) data transfer
*/
struct mhi_ep_driver {
const struct mhi_device_id *id_table;
struct device_driver driver;
int (*probe)(struct mhi_ep_device *mhi_ep,
const struct mhi_device_id *id);
void (*remove)(struct mhi_ep_device *mhi_ep);
void (*ul_xfer_cb)(struct mhi_ep_device *mhi_dev,
struct mhi_result *result);
void (*dl_xfer_cb)(struct mhi_ep_device *mhi_dev,
struct mhi_result *result);
};
#define to_mhi_ep_device(dev) container_of(dev, struct mhi_ep_device, dev)
#define to_mhi_ep_driver(drv) container_of_const(drv, struct mhi_ep_driver, driver)
/*
* module_mhi_ep_driver() - Helper macro for drivers that don't do
* anything special other than using default mhi_ep_driver_register() and
* mhi_ep_driver_unregister(). This eliminates a lot of boilerplate.
* Each module may only use this macro once.
*/
#define module_mhi_ep_driver(mhi_drv) \
module_driver(mhi_drv, mhi_ep_driver_register, \
mhi_ep_driver_unregister)
/*
* Macro to avoid include chaining to get THIS_MODULE
*/
#define mhi_ep_driver_register(mhi_drv) \
__mhi_ep_driver_register(mhi_drv, THIS_MODULE)
/**
* __mhi_ep_driver_register - Register a driver with MHI Endpoint bus
* @mhi_drv: Driver to be associated with the device
* @owner: The module owner
*
* Return: 0 if driver registrations succeeds, a negative error code otherwise.
*/
int __mhi_ep_driver_register(struct mhi_ep_driver *mhi_drv, struct module *owner);
/**
* mhi_ep_driver_unregister - Unregister a driver from MHI Endpoint bus
* @mhi_drv: Driver associated with the device
*/
void mhi_ep_driver_unregister(struct mhi_ep_driver *mhi_drv);
/**
* mhi_ep_register_controller - Register MHI Endpoint controller
* @mhi_cntrl: MHI Endpoint controller to register
* @config: Configuration to use for the controller
*
* Return: 0 if controller registrations succeeds, a negative error code otherwise.
*/
int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
const struct mhi_ep_cntrl_config *config);
/**
* mhi_ep_unregister_controller - Unregister MHI Endpoint controller
* @mhi_cntrl: MHI Endpoint controller to unregister
*/
void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl);
/**
* mhi_ep_power_up - Power up the MHI endpoint stack
* @mhi_cntrl: MHI Endpoint controller
*
* Return: 0 if power up succeeds, a negative error code otherwise.
*/
int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl);
/**
* mhi_ep_power_down - Power down the MHI endpoint stack
* @mhi_cntrl: MHI controller
*/
void mhi_ep_power_down(struct mhi_ep_cntrl *mhi_cntrl);
/**
* mhi_ep_queue_is_empty - Determine whether the transfer queue is empty
* @mhi_dev: Device associated with the channels
* @dir: DMA direction for the channel
*
* Return: true if the queue is empty, false otherwise.
*/
bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_direction dir);
/**
* mhi_ep_queue_skb - Send SKBs to host over MHI Endpoint
* @mhi_dev: Device associated with the DL channel
* @skb: SKBs to be queued
*
* Return: 0 if the SKBs has been sent successfully, a negative error code otherwise.
*/
int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb);
#endif
|