1 /*
2  * dice_transaction.c - a part of driver for Dice based devices
3  *
4  * Copyright (c) Clemens Ladisch
5  * Copyright (c) 2014 Takashi Sakamoto
6  *
7  * Licensed under the terms of the GNU General Public License, version 2.
8  */
9 
10 #include "dice.h"
11 
12 #define NOTIFICATION_TIMEOUT_MS	(2 * MSEC_PER_SEC)
13 
14 static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
15 		       u64 offset)
16 {
17 	switch (type) {
18 	case SND_DICE_ADDR_TYPE_TX:
19 		offset += dice->tx_offset;
20 		break;
21 	case SND_DICE_ADDR_TYPE_RX:
22 		offset += dice->rx_offset;
23 		break;
24 	case SND_DICE_ADDR_TYPE_SYNC:
25 		offset += dice->sync_offset;
26 		break;
27 	case SND_DICE_ADDR_TYPE_RSRV:
28 		offset += dice->rsrv_offset;
29 		break;
30 	case SND_DICE_ADDR_TYPE_GLOBAL:
31 	default:
32 		offset += dice->global_offset;
33 		break;
34 	}
35 	offset += DICE_PRIVATE_SPACE;
36 	return offset;
37 }
38 
39 int snd_dice_transaction_write(struct snd_dice *dice,
40 			       enum snd_dice_addr_type type,
41 			       unsigned int offset, void *buf, unsigned int len)
42 {
43 	return snd_fw_transaction(dice->unit,
44 				  (len == 4) ? TCODE_WRITE_QUADLET_REQUEST :
45 					       TCODE_WRITE_BLOCK_REQUEST,
46 				  get_subaddr(dice, type, offset), buf, len, 0);
47 }
48 
49 int snd_dice_transaction_read(struct snd_dice *dice,
50 			      enum snd_dice_addr_type type, unsigned int offset,
51 			      void *buf, unsigned int len)
52 {
53 	return snd_fw_transaction(dice->unit,
54 				  (len == 4) ? TCODE_READ_QUADLET_REQUEST :
55 					       TCODE_READ_BLOCK_REQUEST,
56 				  get_subaddr(dice, type, offset), buf, len, 0);
57 }
58 
59 static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
60 {
61 	return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
62 						info, 4);
63 }
64 
65 static int set_clock_info(struct snd_dice *dice,
66 			  unsigned int rate, unsigned int source)
67 {
68 	unsigned int i;
69 	__be32 info;
70 	u32 mask;
71 	u32 clock;
72 	int err;
73 
74 	err = get_clock_info(dice, &info);
75 	if (err < 0)
76 		return err;
77 
78 	clock = be32_to_cpu(info);
79 	if (source != UINT_MAX) {
80 		mask = CLOCK_SOURCE_MASK;
81 		clock &= ~mask;
82 		clock |= source;
83 	}
84 	if (rate != UINT_MAX) {
85 		for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
86 			if (snd_dice_rates[i] == rate)
87 				break;
88 		}
89 		if (i == ARRAY_SIZE(snd_dice_rates))
90 			return -EINVAL;
91 
92 		mask = CLOCK_RATE_MASK;
93 		clock &= ~mask;
94 		clock |= i << CLOCK_RATE_SHIFT;
95 	}
96 	info = cpu_to_be32(clock);
97 
98 	if (completion_done(&dice->clock_accepted))
99 		reinit_completion(&dice->clock_accepted);
100 
101 	err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
102 						&info, 4);
103 	if (err < 0)
104 		return err;
105 
106 	if (wait_for_completion_timeout(&dice->clock_accepted,
107 			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
108 		return -ETIMEDOUT;
109 
110 	return 0;
111 }
112 
113 int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
114 					  unsigned int *source)
115 {
116 	__be32 info;
117 	int err;
118 
119 	err = get_clock_info(dice, &info);
120 	if (err >= 0)
121 		*source = be32_to_cpu(info) & CLOCK_SOURCE_MASK;
122 
123 	return err;
124 }
125 
126 int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
127 {
128 	__be32 info;
129 	unsigned int index;
130 	int err;
131 
132 	err = get_clock_info(dice, &info);
133 	if (err < 0)
134 		goto end;
135 
136 	index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
137 	if (index >= SND_DICE_RATES_COUNT) {
138 		err = -ENOSYS;
139 		goto end;
140 	}
141 
142 	*rate = snd_dice_rates[index];
143 end:
144 	return err;
145 }
146 int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate)
147 {
148 	return set_clock_info(dice, rate, UINT_MAX);
149 }
150 
151 int snd_dice_transaction_set_enable(struct snd_dice *dice)
152 {
153 	__be32 value;
154 	int err = 0;
155 
156 	if (dice->global_enabled)
157 		goto end;
158 
159 	value = cpu_to_be32(1);
160 	err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
161 				 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
162 					     GLOBAL_ENABLE),
163 				 &value, 4,
164 				 FW_FIXED_GENERATION | dice->owner_generation);
165 	if (err < 0)
166 		goto end;
167 
168 	dice->global_enabled = true;
169 end:
170 	return err;
171 }
172 
173 void snd_dice_transaction_clear_enable(struct snd_dice *dice)
174 {
175 	__be32 value;
176 
177 	value = 0;
178 	snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
179 			   get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
180 				       GLOBAL_ENABLE),
181 			   &value, 4, FW_QUIET |
182 			   FW_FIXED_GENERATION | dice->owner_generation);
183 
184 	dice->global_enabled = false;
185 }
186 
187 static void dice_notification(struct fw_card *card, struct fw_request *request,
188 			      int tcode, int destination, int source,
189 			      int generation, unsigned long long offset,
190 			      void *data, size_t length, void *callback_data)
191 {
192 	struct snd_dice *dice = callback_data;
193 	u32 bits;
194 	unsigned long flags;
195 
196 	if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
197 		fw_send_response(card, request, RCODE_TYPE_ERROR);
198 		return;
199 	}
200 	if ((offset & 3) != 0) {
201 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
202 		return;
203 	}
204 
205 	bits = be32_to_cpup(data);
206 
207 	spin_lock_irqsave(&dice->lock, flags);
208 	dice->notification_bits |= bits;
209 	spin_unlock_irqrestore(&dice->lock, flags);
210 
211 	fw_send_response(card, request, RCODE_COMPLETE);
212 
213 	if (bits & NOTIFY_CLOCK_ACCEPTED)
214 		complete(&dice->clock_accepted);
215 	wake_up(&dice->hwdep_wait);
216 }
217 
218 static int register_notification_address(struct snd_dice *dice, bool retry)
219 {
220 	struct fw_device *device = fw_parent_device(dice->unit);
221 	__be64 *buffer;
222 	unsigned int retries;
223 	int err;
224 
225 	retries = (retry) ? 3 : 0;
226 
227 	buffer = kmalloc(2 * 8, GFP_KERNEL);
228 	if (!buffer)
229 		return -ENOMEM;
230 
231 	for (;;) {
232 		buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
233 		buffer[1] = cpu_to_be64(
234 			((u64)device->card->node_id << OWNER_NODE_SHIFT) |
235 			dice->notification_handler.offset);
236 
237 		dice->owner_generation = device->generation;
238 		smp_rmb(); /* node_id vs. generation */
239 		err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
240 					 get_subaddr(dice,
241 						     SND_DICE_ADDR_TYPE_GLOBAL,
242 						     GLOBAL_OWNER),
243 					 buffer, 2 * 8,
244 					 FW_FIXED_GENERATION |
245 							dice->owner_generation);
246 		if (err == 0) {
247 			/* success */
248 			if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER))
249 				break;
250 			/* The address seems to be already registered. */
251 			if (buffer[0] == buffer[1])
252 				break;
253 
254 			dev_err(&dice->unit->device,
255 				"device is already in use\n");
256 			err = -EBUSY;
257 		}
258 		if (err != -EAGAIN || retries-- > 0)
259 			break;
260 
261 		msleep(20);
262 	}
263 
264 	kfree(buffer);
265 
266 	if (err < 0)
267 		dice->owner_generation = -1;
268 
269 	return err;
270 }
271 
272 static void unregister_notification_address(struct snd_dice *dice)
273 {
274 	struct fw_device *device = fw_parent_device(dice->unit);
275 	__be64 *buffer;
276 
277 	buffer = kmalloc(2 * 8, GFP_KERNEL);
278 	if (buffer == NULL)
279 		return;
280 
281 	buffer[0] = cpu_to_be64(
282 		((u64)device->card->node_id << OWNER_NODE_SHIFT) |
283 		dice->notification_handler.offset);
284 	buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
285 	snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
286 			   get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
287 				       GLOBAL_OWNER),
288 			   buffer, 2 * 8, FW_QUIET |
289 			   FW_FIXED_GENERATION | dice->owner_generation);
290 
291 	kfree(buffer);
292 
293 	dice->owner_generation = -1;
294 }
295 
296 void snd_dice_transaction_destroy(struct snd_dice *dice)
297 {
298 	struct fw_address_handler *handler = &dice->notification_handler;
299 
300 	if (handler->callback_data == NULL)
301 		return;
302 
303 	unregister_notification_address(dice);
304 
305 	fw_core_remove_address_handler(handler);
306 	handler->callback_data = NULL;
307 }
308 
309 int snd_dice_transaction_reinit(struct snd_dice *dice)
310 {
311 	struct fw_address_handler *handler = &dice->notification_handler;
312 
313 	if (handler->callback_data == NULL)
314 		return -EINVAL;
315 
316 	return register_notification_address(dice, false);
317 }
318 
319 static int get_subaddrs(struct snd_dice *dice)
320 {
321 	static const int min_values[10] = {
322 		10, 0x64 / 4,
323 		10, 0x18 / 4,
324 		10, 0x18 / 4,
325 		0, 0,
326 		0, 0,
327 	};
328 	__be32 *pointers;
329 	__be32 version;
330 	u32 data;
331 	unsigned int i;
332 	int err;
333 
334 	pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
335 				 GFP_KERNEL);
336 	if (pointers == NULL)
337 		return -ENOMEM;
338 
339 	/*
340 	 * Check that the sub address spaces exist and are located inside the
341 	 * private address space.  The minimum values are chosen so that all
342 	 * minimally required registers are included.
343 	 */
344 	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
345 				 DICE_PRIVATE_SPACE, pointers,
346 				 sizeof(__be32) * ARRAY_SIZE(min_values), 0);
347 	if (err < 0)
348 		goto end;
349 
350 	for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
351 		data = be32_to_cpu(pointers[i]);
352 		if (data < min_values[i] || data >= 0x40000) {
353 			err = -ENODEV;
354 			goto end;
355 		}
356 	}
357 
358 	/*
359 	 * Check that the implemented DICE driver specification major version
360 	 * number matches.
361 	 */
362 	err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
363 				 DICE_PRIVATE_SPACE +
364 				 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
365 				 &version, sizeof(version), 0);
366 	if (err < 0)
367 		goto end;
368 
369 	if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
370 		dev_err(&dice->unit->device,
371 			"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
372 		err = -ENODEV;
373 		goto end;
374 	}
375 
376 	dice->global_offset = be32_to_cpu(pointers[0]) * 4;
377 	dice->tx_offset = be32_to_cpu(pointers[2]) * 4;
378 	dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
379 	dice->sync_offset = be32_to_cpu(pointers[6]) * 4;
380 	dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4;
381 
382 	/* Set up later. */
383 	if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4)
384 		dice->clock_caps = 1;
385 end:
386 	kfree(pointers);
387 	return err;
388 }
389 
390 int snd_dice_transaction_init(struct snd_dice *dice)
391 {
392 	struct fw_address_handler *handler = &dice->notification_handler;
393 	int err;
394 
395 	err = get_subaddrs(dice);
396 	if (err < 0)
397 		return err;
398 
399 	/* Allocation callback in address space over host controller */
400 	handler->length = 4;
401 	handler->address_callback = dice_notification;
402 	handler->callback_data = dice;
403 	err = fw_core_add_address_handler(handler, &fw_high_memory_region);
404 	if (err < 0) {
405 		handler->callback_data = NULL;
406 		return err;
407 	}
408 
409 	/* Register the address space */
410 	err = register_notification_address(dice, true);
411 	if (err < 0) {
412 		fw_core_remove_address_handler(handler);
413 		handler->callback_data = NULL;
414 	}
415 
416 	return err;
417 }
418