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