Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * dice_transaction.c - a part of driver for Dice based devices
0004  *
0005  * Copyright (c) Clemens Ladisch
0006  * Copyright (c) 2014 Takashi Sakamoto
0007  */
0008 
0009 #include "dice.h"
0010 
0011 static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
0012                u64 offset)
0013 {
0014     switch (type) {
0015     case SND_DICE_ADDR_TYPE_TX:
0016         offset += dice->tx_offset;
0017         break;
0018     case SND_DICE_ADDR_TYPE_RX:
0019         offset += dice->rx_offset;
0020         break;
0021     case SND_DICE_ADDR_TYPE_SYNC:
0022         offset += dice->sync_offset;
0023         break;
0024     case SND_DICE_ADDR_TYPE_RSRV:
0025         offset += dice->rsrv_offset;
0026         break;
0027     case SND_DICE_ADDR_TYPE_GLOBAL:
0028     default:
0029         offset += dice->global_offset;
0030         break;
0031     }
0032     offset += DICE_PRIVATE_SPACE;
0033     return offset;
0034 }
0035 
0036 int snd_dice_transaction_write(struct snd_dice *dice,
0037                    enum snd_dice_addr_type type,
0038                    unsigned int offset, void *buf, unsigned int len)
0039 {
0040     return snd_fw_transaction(dice->unit,
0041                   (len == 4) ? TCODE_WRITE_QUADLET_REQUEST :
0042                            TCODE_WRITE_BLOCK_REQUEST,
0043                   get_subaddr(dice, type, offset), buf, len, 0);
0044 }
0045 
0046 int snd_dice_transaction_read(struct snd_dice *dice,
0047                   enum snd_dice_addr_type type, unsigned int offset,
0048                   void *buf, unsigned int len)
0049 {
0050     return snd_fw_transaction(dice->unit,
0051                   (len == 4) ? TCODE_READ_QUADLET_REQUEST :
0052                            TCODE_READ_BLOCK_REQUEST,
0053                   get_subaddr(dice, type, offset), buf, len, 0);
0054 }
0055 
0056 static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
0057 {
0058     return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
0059                         info, 4);
0060 }
0061 
0062 int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
0063                       unsigned int *source)
0064 {
0065     __be32 info;
0066     int err;
0067 
0068     err = get_clock_info(dice, &info);
0069     if (err >= 0)
0070         *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK;
0071 
0072     return err;
0073 }
0074 
0075 int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
0076 {
0077     __be32 info;
0078     unsigned int index;
0079     int err;
0080 
0081     err = get_clock_info(dice, &info);
0082     if (err < 0)
0083         goto end;
0084 
0085     index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
0086     if (index >= SND_DICE_RATES_COUNT) {
0087         err = -ENOSYS;
0088         goto end;
0089     }
0090 
0091     *rate = snd_dice_rates[index];
0092 end:
0093     return err;
0094 }
0095 
0096 int snd_dice_transaction_set_enable(struct snd_dice *dice)
0097 {
0098     __be32 value;
0099     int err = 0;
0100 
0101     if (dice->global_enabled)
0102         goto end;
0103 
0104     value = cpu_to_be32(1);
0105     err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
0106                  get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0107                          GLOBAL_ENABLE),
0108                  &value, 4,
0109                  FW_FIXED_GENERATION | dice->owner_generation);
0110     if (err < 0)
0111         goto end;
0112 
0113     dice->global_enabled = true;
0114 end:
0115     return err;
0116 }
0117 
0118 void snd_dice_transaction_clear_enable(struct snd_dice *dice)
0119 {
0120     __be32 value;
0121 
0122     value = 0;
0123     snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
0124                get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0125                        GLOBAL_ENABLE),
0126                &value, 4, FW_QUIET |
0127                FW_FIXED_GENERATION | dice->owner_generation);
0128 
0129     dice->global_enabled = false;
0130 }
0131 
0132 static void dice_notification(struct fw_card *card, struct fw_request *request,
0133                   int tcode, int destination, int source,
0134                   int generation, unsigned long long offset,
0135                   void *data, size_t length, void *callback_data)
0136 {
0137     struct snd_dice *dice = callback_data;
0138     u32 bits;
0139     unsigned long flags;
0140 
0141     if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
0142         fw_send_response(card, request, RCODE_TYPE_ERROR);
0143         return;
0144     }
0145     if ((offset & 3) != 0) {
0146         fw_send_response(card, request, RCODE_ADDRESS_ERROR);
0147         return;
0148     }
0149 
0150     bits = be32_to_cpup(data);
0151 
0152     spin_lock_irqsave(&dice->lock, flags);
0153     dice->notification_bits |= bits;
0154     spin_unlock_irqrestore(&dice->lock, flags);
0155 
0156     fw_send_response(card, request, RCODE_COMPLETE);
0157 
0158     if (bits & NOTIFY_CLOCK_ACCEPTED)
0159         complete(&dice->clock_accepted);
0160     wake_up(&dice->hwdep_wait);
0161 }
0162 
0163 static int register_notification_address(struct snd_dice *dice, bool retry)
0164 {
0165     struct fw_device *device = fw_parent_device(dice->unit);
0166     __be64 *buffer;
0167     unsigned int retries;
0168     int err;
0169 
0170     retries = (retry) ? 3 : 0;
0171 
0172     buffer = kmalloc(2 * 8, GFP_KERNEL);
0173     if (!buffer)
0174         return -ENOMEM;
0175 
0176     for (;;) {
0177         buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
0178         buffer[1] = cpu_to_be64(
0179             ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
0180             dice->notification_handler.offset);
0181 
0182         dice->owner_generation = device->generation;
0183         smp_rmb(); /* node_id vs. generation */
0184         err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
0185                      get_subaddr(dice,
0186                              SND_DICE_ADDR_TYPE_GLOBAL,
0187                              GLOBAL_OWNER),
0188                      buffer, 2 * 8,
0189                      FW_FIXED_GENERATION |
0190                             dice->owner_generation);
0191         if (err == 0) {
0192             /* success */
0193             if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER))
0194                 break;
0195             /* The address seems to be already registered. */
0196             if (buffer[0] == buffer[1])
0197                 break;
0198 
0199             dev_err(&dice->unit->device,
0200                 "device is already in use\n");
0201             err = -EBUSY;
0202         }
0203         if (err != -EAGAIN || retries-- > 0)
0204             break;
0205 
0206         msleep(20);
0207     }
0208 
0209     kfree(buffer);
0210 
0211     if (err < 0)
0212         dice->owner_generation = -1;
0213 
0214     return err;
0215 }
0216 
0217 static void unregister_notification_address(struct snd_dice *dice)
0218 {
0219     struct fw_device *device = fw_parent_device(dice->unit);
0220     __be64 *buffer;
0221 
0222     buffer = kmalloc(2 * 8, GFP_KERNEL);
0223     if (buffer == NULL)
0224         return;
0225 
0226     buffer[0] = cpu_to_be64(
0227         ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
0228         dice->notification_handler.offset);
0229     buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
0230     snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
0231                get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0232                        GLOBAL_OWNER),
0233                buffer, 2 * 8, FW_QUIET |
0234                FW_FIXED_GENERATION | dice->owner_generation);
0235 
0236     kfree(buffer);
0237 
0238     dice->owner_generation = -1;
0239 }
0240 
0241 void snd_dice_transaction_destroy(struct snd_dice *dice)
0242 {
0243     struct fw_address_handler *handler = &dice->notification_handler;
0244 
0245     if (handler->callback_data == NULL)
0246         return;
0247 
0248     unregister_notification_address(dice);
0249 
0250     fw_core_remove_address_handler(handler);
0251     handler->callback_data = NULL;
0252 }
0253 
0254 int snd_dice_transaction_reinit(struct snd_dice *dice)
0255 {
0256     struct fw_address_handler *handler = &dice->notification_handler;
0257 
0258     if (handler->callback_data == NULL)
0259         return -EINVAL;
0260 
0261     return register_notification_address(dice, false);
0262 }
0263 
0264 static int get_subaddrs(struct snd_dice *dice)
0265 {
0266     static const int min_values[10] = {
0267         10, 0x60 / 4,
0268         10, 0x18 / 4,
0269         10, 0x18 / 4,
0270         0, 0,
0271         0, 0,
0272     };
0273     __be32 *pointers;
0274     __be32 version;
0275     u32 data;
0276     unsigned int i;
0277     int err;
0278 
0279     pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
0280                  GFP_KERNEL);
0281     if (pointers == NULL)
0282         return -ENOMEM;
0283 
0284     /*
0285      * Check that the sub address spaces exist and are located inside the
0286      * private address space.  The minimum values are chosen so that all
0287      * minimally required registers are included.
0288      */
0289     err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
0290                  DICE_PRIVATE_SPACE, pointers,
0291                  sizeof(__be32) * ARRAY_SIZE(min_values), 0);
0292     if (err < 0)
0293         goto end;
0294 
0295     for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
0296         data = be32_to_cpu(pointers[i]);
0297         if (data < min_values[i] || data >= 0x40000) {
0298             err = -ENODEV;
0299             goto end;
0300         }
0301     }
0302 
0303     if (be32_to_cpu(pointers[1]) > 0x18) {
0304         /*
0305          * Check that the implemented DICE driver specification major
0306          * version number matches.
0307          */
0308         err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
0309                 DICE_PRIVATE_SPACE +
0310                 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
0311                 &version, sizeof(version), 0);
0312         if (err < 0)
0313             goto end;
0314 
0315         if ((version & cpu_to_be32(0xff000000)) !=
0316                         cpu_to_be32(0x01000000)) {
0317             dev_err(&dice->unit->device,
0318                 "unknown DICE version: 0x%08x\n",
0319                 be32_to_cpu(version));
0320             err = -ENODEV;
0321             goto end;
0322         }
0323 
0324         /* Set up later. */
0325         dice->clock_caps = 1;
0326     }
0327 
0328     dice->global_offset = be32_to_cpu(pointers[0]) * 4;
0329     dice->tx_offset = be32_to_cpu(pointers[2]) * 4;
0330     dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
0331 
0332     /* Old firmware doesn't support these fields. */
0333     if (pointers[7])
0334         dice->sync_offset = be32_to_cpu(pointers[6]) * 4;
0335     if (pointers[9])
0336         dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4;
0337 end:
0338     kfree(pointers);
0339     return err;
0340 }
0341 
0342 int snd_dice_transaction_init(struct snd_dice *dice)
0343 {
0344     struct fw_address_handler *handler = &dice->notification_handler;
0345     int err;
0346 
0347     err = get_subaddrs(dice);
0348     if (err < 0)
0349         return err;
0350 
0351     /* Allocation callback in address space over host controller */
0352     handler->length = 4;
0353     handler->address_callback = dice_notification;
0354     handler->callback_data = dice;
0355     err = fw_core_add_address_handler(handler, &fw_high_memory_region);
0356     if (err < 0) {
0357         handler->callback_data = NULL;
0358         return err;
0359     }
0360 
0361     /* Register the address space */
0362     err = register_notification_address(dice, true);
0363     if (err < 0) {
0364         fw_core_remove_address_handler(handler);
0365         handler->callback_data = NULL;
0366     }
0367 
0368     return err;
0369 }