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 100 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 retries = 3; 69 unsigned int i; 70 __be32 info; 71 u32 mask; 72 u32 clock; 73 int err; 74 retry: 75 err = get_clock_info(dice, &info); 76 if (err < 0) 77 goto end; 78 79 clock = be32_to_cpu(info); 80 if (source != UINT_MAX) { 81 mask = CLOCK_SOURCE_MASK; 82 clock &= ~mask; 83 clock |= source; 84 } 85 if (rate != UINT_MAX) { 86 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { 87 if (snd_dice_rates[i] == rate) 88 break; 89 } 90 if (i == ARRAY_SIZE(snd_dice_rates)) { 91 err = -EINVAL; 92 goto end; 93 } 94 95 mask = CLOCK_RATE_MASK; 96 clock &= ~mask; 97 clock |= i << CLOCK_RATE_SHIFT; 98 } 99 info = cpu_to_be32(clock); 100 101 if (completion_done(&dice->clock_accepted)) 102 reinit_completion(&dice->clock_accepted); 103 104 err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, 105 &info, 4); 106 if (err < 0) 107 goto end; 108 109 /* Timeout means it's invalid request, probably bus reset occurred. */ 110 if (wait_for_completion_timeout(&dice->clock_accepted, 111 msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { 112 if (retries-- == 0) { 113 err = -ETIMEDOUT; 114 goto end; 115 } 116 117 err = snd_dice_transaction_reinit(dice); 118 if (err < 0) 119 goto end; 120 121 msleep(500); /* arbitrary */ 122 goto retry; 123 } 124 end: 125 return err; 126 } 127 128 int snd_dice_transaction_get_clock_source(struct snd_dice *dice, 129 unsigned int *source) 130 { 131 __be32 info; 132 int err; 133 134 err = get_clock_info(dice, &info); 135 if (err >= 0) 136 *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK; 137 138 return err; 139 } 140 int snd_dice_transaction_set_clock_source(struct snd_dice *dice, 141 unsigned int source) 142 { 143 return set_clock_info(dice, UINT_MAX, source); 144 } 145 146 int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate) 147 { 148 __be32 info; 149 unsigned int index; 150 int err; 151 152 err = get_clock_info(dice, &info); 153 if (err < 0) 154 goto end; 155 156 index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; 157 if (index >= SND_DICE_RATES_COUNT) { 158 err = -ENOSYS; 159 goto end; 160 } 161 162 *rate = snd_dice_rates[index]; 163 end: 164 return err; 165 } 166 int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate) 167 { 168 return set_clock_info(dice, rate, UINT_MAX); 169 } 170 171 int snd_dice_transaction_set_enable(struct snd_dice *dice) 172 { 173 __be32 value; 174 int err = 0; 175 176 if (dice->global_enabled) 177 goto end; 178 179 value = cpu_to_be32(1); 180 err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, 181 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, 182 GLOBAL_ENABLE), 183 &value, 4, 184 FW_FIXED_GENERATION | dice->owner_generation); 185 if (err < 0) 186 goto end; 187 188 dice->global_enabled = true; 189 end: 190 return err; 191 } 192 193 void snd_dice_transaction_clear_enable(struct snd_dice *dice) 194 { 195 __be32 value; 196 197 value = 0; 198 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, 199 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, 200 GLOBAL_ENABLE), 201 &value, 4, FW_QUIET | 202 FW_FIXED_GENERATION | dice->owner_generation); 203 204 dice->global_enabled = false; 205 } 206 207 static void dice_notification(struct fw_card *card, struct fw_request *request, 208 int tcode, int destination, int source, 209 int generation, unsigned long long offset, 210 void *data, size_t length, void *callback_data) 211 { 212 struct snd_dice *dice = callback_data; 213 u32 bits; 214 unsigned long flags; 215 216 if (tcode != TCODE_WRITE_QUADLET_REQUEST) { 217 fw_send_response(card, request, RCODE_TYPE_ERROR); 218 return; 219 } 220 if ((offset & 3) != 0) { 221 fw_send_response(card, request, RCODE_ADDRESS_ERROR); 222 return; 223 } 224 225 bits = be32_to_cpup(data); 226 227 spin_lock_irqsave(&dice->lock, flags); 228 dice->notification_bits |= bits; 229 spin_unlock_irqrestore(&dice->lock, flags); 230 231 fw_send_response(card, request, RCODE_COMPLETE); 232 233 if (bits & NOTIFY_CLOCK_ACCEPTED) 234 complete(&dice->clock_accepted); 235 wake_up(&dice->hwdep_wait); 236 } 237 238 static int register_notification_address(struct snd_dice *dice, bool retry) 239 { 240 struct fw_device *device = fw_parent_device(dice->unit); 241 __be64 *buffer; 242 unsigned int retries; 243 int err; 244 245 retries = (retry) ? 3 : 0; 246 247 buffer = kmalloc(2 * 8, GFP_KERNEL); 248 if (!buffer) 249 return -ENOMEM; 250 251 for (;;) { 252 buffer[0] = cpu_to_be64(OWNER_NO_OWNER); 253 buffer[1] = cpu_to_be64( 254 ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 255 dice->notification_handler.offset); 256 257 dice->owner_generation = device->generation; 258 smp_rmb(); /* node_id vs. generation */ 259 err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, 260 get_subaddr(dice, 261 SND_DICE_ADDR_TYPE_GLOBAL, 262 GLOBAL_OWNER), 263 buffer, 2 * 8, 264 FW_FIXED_GENERATION | 265 dice->owner_generation); 266 if (err == 0) { 267 /* success */ 268 if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) 269 break; 270 /* The address seems to be already registered. */ 271 if (buffer[0] == buffer[1]) 272 break; 273 274 dev_err(&dice->unit->device, 275 "device is already in use\n"); 276 err = -EBUSY; 277 } 278 if (err != -EAGAIN || retries-- > 0) 279 break; 280 281 msleep(20); 282 } 283 284 kfree(buffer); 285 286 if (err < 0) 287 dice->owner_generation = -1; 288 289 return err; 290 } 291 292 static void unregister_notification_address(struct snd_dice *dice) 293 { 294 struct fw_device *device = fw_parent_device(dice->unit); 295 __be64 *buffer; 296 297 buffer = kmalloc(2 * 8, GFP_KERNEL); 298 if (buffer == NULL) 299 return; 300 301 buffer[0] = cpu_to_be64( 302 ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 303 dice->notification_handler.offset); 304 buffer[1] = cpu_to_be64(OWNER_NO_OWNER); 305 snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, 306 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, 307 GLOBAL_OWNER), 308 buffer, 2 * 8, FW_QUIET | 309 FW_FIXED_GENERATION | dice->owner_generation); 310 311 kfree(buffer); 312 313 dice->owner_generation = -1; 314 } 315 316 void snd_dice_transaction_destroy(struct snd_dice *dice) 317 { 318 struct fw_address_handler *handler = &dice->notification_handler; 319 320 if (handler->callback_data == NULL) 321 return; 322 323 unregister_notification_address(dice); 324 325 fw_core_remove_address_handler(handler); 326 handler->callback_data = NULL; 327 } 328 329 int snd_dice_transaction_reinit(struct snd_dice *dice) 330 { 331 struct fw_address_handler *handler = &dice->notification_handler; 332 333 if (handler->callback_data == NULL) 334 return -EINVAL; 335 336 return register_notification_address(dice, false); 337 } 338 339 int snd_dice_transaction_init(struct snd_dice *dice) 340 { 341 struct fw_address_handler *handler = &dice->notification_handler; 342 __be32 *pointers; 343 int err; 344 345 /* Use the same way which dice_interface_check() does. */ 346 pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL); 347 if (pointers == NULL) 348 return -ENOMEM; 349 350 /* Get offsets for sub-addresses */ 351 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, 352 DICE_PRIVATE_SPACE, 353 pointers, sizeof(__be32) * 10, 0); 354 if (err < 0) 355 goto end; 356 357 /* Allocation callback in address space over host controller */ 358 handler->length = 4; 359 handler->address_callback = dice_notification; 360 handler->callback_data = dice; 361 err = fw_core_add_address_handler(handler, &fw_high_memory_region); 362 if (err < 0) { 363 handler->callback_data = NULL; 364 goto end; 365 } 366 367 /* Register the address space */ 368 err = register_notification_address(dice, true); 369 if (err < 0) { 370 fw_core_remove_address_handler(handler); 371 handler->callback_data = NULL; 372 goto end; 373 } 374 375 dice->global_offset = be32_to_cpu(pointers[0]) * 4; 376 dice->tx_offset = be32_to_cpu(pointers[2]) * 4; 377 dice->rx_offset = be32_to_cpu(pointers[4]) * 4; 378 dice->sync_offset = be32_to_cpu(pointers[6]) * 4; 379 dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4; 380 381 /* Set up later. */ 382 if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) 383 dice->clock_caps = 1; 384 end: 385 kfree(pointers); 386 return err; 387 } 388