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 unsigned long flags; 140 141 if (tcode != TCODE_WRITE_QUADLET_REQUEST) { 142 fw_send_response(card, request, RCODE_TYPE_ERROR); 143 return; 144 } 145 if ((offset & 3) != 0) { 146 fw_send_response(card, request, RCODE_ADDRESS_ERROR); 147 return; 148 } 149 150 bits = be32_to_cpup(data); 151 152 spin_lock_irqsave(&dice->lock, flags); 153 dice->notification_bits |= bits; 154 spin_unlock_irqrestore(&dice->lock, flags); 155 156 fw_send_response(card, request, RCODE_COMPLETE); 157 158 if (bits & NOTIFY_LOCK_CHG) 159 complete(&dice->clock_accepted); 160 wake_up(&dice->hwdep_wait); 161 } 162 163 static int register_notification_address(struct snd_dice *dice, bool retry) 164 { 165 struct fw_device *device = fw_parent_device(dice->unit); 166 __be64 *buffer; 167 unsigned int retries; 168 int err; 169 170 retries = (retry) ? 3 : 0; 171 172 buffer = kmalloc(2 * 8, GFP_KERNEL); 173 if (!buffer) 174 return -ENOMEM; 175 176 for (;;) { 177 buffer[0] = cpu_to_be64(OWNER_NO_OWNER); 178 buffer[1] = cpu_to_be64( 179 ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 180 dice->notification_handler.offset); 181 182 dice->owner_generation = device->generation; 183 smp_rmb(); /* node_id vs. generation */ 184 err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, 185 get_subaddr(dice, 186 SND_DICE_ADDR_TYPE_GLOBAL, 187 GLOBAL_OWNER), 188 buffer, 2 * 8, 189 FW_FIXED_GENERATION | 190 dice->owner_generation); 191 if (err == 0) { 192 /* success */ 193 if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) 194 break; 195 /* The address seems to be already registered. */ 196 if (buffer[0] == buffer[1]) 197 break; 198 199 dev_err(&dice->unit->device, 200 "device is already in use\n"); 201 err = -EBUSY; 202 } 203 if (err != -EAGAIN || retries-- > 0) 204 break; 205 206 msleep(20); 207 } 208 209 kfree(buffer); 210 211 if (err < 0) 212 dice->owner_generation = -1; 213 214 return err; 215 } 216 217 static void unregister_notification_address(struct snd_dice *dice) 218 { 219 struct fw_device *device = fw_parent_device(dice->unit); 220 __be64 *buffer; 221 222 buffer = kmalloc(2 * 8, GFP_KERNEL); 223 if (buffer == NULL) 224 return; 225 226 buffer[0] = cpu_to_be64( 227 ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 228 dice->notification_handler.offset); 229 buffer[1] = cpu_to_be64(OWNER_NO_OWNER); 230 snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, 231 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, 232 GLOBAL_OWNER), 233 buffer, 2 * 8, FW_QUIET | 234 FW_FIXED_GENERATION | dice->owner_generation); 235 236 kfree(buffer); 237 238 dice->owner_generation = -1; 239 } 240 241 void snd_dice_transaction_destroy(struct snd_dice *dice) 242 { 243 struct fw_address_handler *handler = &dice->notification_handler; 244 245 if (handler->callback_data == NULL) 246 return; 247 248 unregister_notification_address(dice); 249 250 fw_core_remove_address_handler(handler); 251 handler->callback_data = NULL; 252 } 253 254 int snd_dice_transaction_reinit(struct snd_dice *dice) 255 { 256 struct fw_address_handler *handler = &dice->notification_handler; 257 258 if (handler->callback_data == NULL) 259 return -EINVAL; 260 261 return register_notification_address(dice, false); 262 } 263 264 static int get_subaddrs(struct snd_dice *dice) 265 { 266 static const int min_values[10] = { 267 10, 0x60 / 4, 268 10, 0x18 / 4, 269 10, 0x18 / 4, 270 0, 0, 271 0, 0, 272 }; 273 __be32 *pointers; 274 __be32 version; 275 u32 data; 276 unsigned int i; 277 int err; 278 279 pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), 280 GFP_KERNEL); 281 if (pointers == NULL) 282 return -ENOMEM; 283 284 /* 285 * Check that the sub address spaces exist and are located inside the 286 * private address space. The minimum values are chosen so that all 287 * minimally required registers are included. 288 */ 289 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, 290 DICE_PRIVATE_SPACE, pointers, 291 sizeof(__be32) * ARRAY_SIZE(min_values), 0); 292 if (err < 0) 293 goto end; 294 295 for (i = 0; i < ARRAY_SIZE(min_values); ++i) { 296 data = be32_to_cpu(pointers[i]); 297 if (data < min_values[i] || data >= 0x40000) { 298 err = -ENODEV; 299 goto end; 300 } 301 } 302 303 if (be32_to_cpu(pointers[1]) > 0x18) { 304 /* 305 * Check that the implemented DICE driver specification major 306 * version number matches. 307 */ 308 err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, 309 DICE_PRIVATE_SPACE + 310 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, 311 &version, sizeof(version), 0); 312 if (err < 0) 313 goto end; 314 315 if ((version & cpu_to_be32(0xff000000)) != 316 cpu_to_be32(0x01000000)) { 317 dev_err(&dice->unit->device, 318 "unknown DICE version: 0x%08x\n", 319 be32_to_cpu(version)); 320 err = -ENODEV; 321 goto end; 322 } 323 324 /* Set up later. */ 325 dice->clock_caps = 1; 326 } 327 328 dice->global_offset = be32_to_cpu(pointers[0]) * 4; 329 dice->tx_offset = be32_to_cpu(pointers[2]) * 4; 330 dice->rx_offset = be32_to_cpu(pointers[4]) * 4; 331 332 /* Old firmware doesn't support these fields. */ 333 if (pointers[7]) 334 dice->sync_offset = be32_to_cpu(pointers[6]) * 4; 335 if (pointers[9]) 336 dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4; 337 end: 338 kfree(pointers); 339 return err; 340 } 341 342 int snd_dice_transaction_init(struct snd_dice *dice) 343 { 344 struct fw_address_handler *handler = &dice->notification_handler; 345 int err; 346 347 err = get_subaddrs(dice); 348 if (err < 0) 349 return err; 350 351 /* Allocation callback in address space over host controller */ 352 handler->length = 4; 353 handler->address_callback = dice_notification; 354 handler->callback_data = dice; 355 err = fw_core_add_address_handler(handler, &fw_high_memory_region); 356 if (err < 0) { 357 handler->callback_data = NULL; 358 return err; 359 } 360 361 /* Register the address space */ 362 err = register_notification_address(dice, true); 363 if (err < 0) { 364 fw_core_remove_address_handler(handler); 365 handler->callback_data = NULL; 366 } 367 368 return err; 369 } 370