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