^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * isochronous resources helper functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/firewire.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/firewire-constants.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "iso-resources.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * fw_iso_resources_init - initializes a &struct fw_iso_resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * @r: the resource manager to initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * @unit: the device unit for which the resources will be needed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * If the device does not support all channel numbers, change @r->channels_mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * after calling this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) r->channels_mask = ~0uLL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) r->unit = unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) mutex_init(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) r->allocated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) EXPORT_SYMBOL(fw_iso_resources_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * fw_iso_resources_destroy - destroy a resource manager
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * @r: the resource manager that is no longer needed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) void fw_iso_resources_destroy(struct fw_iso_resources *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) WARN_ON(r->allocated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) mutex_destroy(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) EXPORT_SYMBOL(fw_iso_resources_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned int bytes, s400_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* iso packets have three header quadlets and quadlet-aligned payload */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) bytes = 3 * 4 + ALIGN(max_payload_bytes, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* convert to bandwidth units (quadlets at S1600 = bytes at S400) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (speed <= SCODE_400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) s400_bytes = bytes * (1 << (SCODE_400 - speed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return s400_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int current_bandwidth_overhead(struct fw_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Under the usual pessimistic assumption (cable length 4.5 m), the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * isochronous overhead for N cables is 1.797 µs + N * 0.494 µs, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * 88.3 + N * 24.3 in bandwidth units.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * The calculation below tries to deduce N from the current gap count.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * If the gap count has been optimized by measuring the actual packet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * transmission time, this derived overhead should be near the actual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * overhead as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (delay <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (schedule_timeout_interruptible(delay) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * fw_iso_resources_allocate - allocate isochronous channel and bandwidth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * @r: the resource manager
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * @max_payload_bytes: the amount of data (including CIP headers) per packet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * @speed: the speed (e.g., SCODE_400) at which the packets will be sent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * This function allocates one isochronous channel and enough bandwidth for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * specified packet size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Returns the channel number that the caller must use for streaming, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * a negative error code. Due to potentionally long delays, this function is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * interruptible and can return -ERESTARTSYS. On success, the caller is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * responsible for calling fw_iso_resources_update() on bus resets, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * fw_iso_resources_free() when the resources are not longer needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int fw_iso_resources_allocate(struct fw_iso_resources *r,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) unsigned int max_payload_bytes, int speed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct fw_card *card = fw_parent_device(r->unit)->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int bandwidth, channel, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (WARN_ON(r->allocated))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EBADFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) r->bandwidth = packet_bandwidth(max_payload_bytes, speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) retry_after_bus_reset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) spin_lock_irq(&card->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) r->generation = card->generation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) r->bandwidth_overhead = current_bandwidth_overhead(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) spin_unlock_irq(&card->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) err = wait_isoch_resource_delay_after_bus_reset(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) mutex_lock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) bandwidth = r->bandwidth + r->bandwidth_overhead;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) fw_iso_resource_manage(card, r->generation, r->channels_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) &channel, &bandwidth, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (channel == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) mutex_unlock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) goto retry_after_bus_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (channel >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) r->channel = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) r->allocated = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (channel == -EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) dev_err(&r->unit->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) "isochronous resources exhausted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) dev_err(&r->unit->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) "isochronous resource allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) mutex_unlock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) EXPORT_SYMBOL(fw_iso_resources_allocate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * fw_iso_resources_update - update resource allocations after a bus reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * @r: the resource manager
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * This function must be called from the driver's .update handler to reallocate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * any resources that were allocated before the bus reset. It is safe to call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * this function if no resources are currently allocated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * Returns a negative error code on failure. If this happens, the caller must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * stop streaming.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int fw_iso_resources_update(struct fw_iso_resources *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct fw_card *card = fw_parent_device(r->unit)->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int bandwidth, channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) mutex_lock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!r->allocated) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) mutex_unlock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) spin_lock_irq(&card->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) r->generation = card->generation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) r->bandwidth_overhead = current_bandwidth_overhead(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) spin_unlock_irq(&card->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) bandwidth = r->bandwidth + r->bandwidth_overhead;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) &channel, &bandwidth, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * When another bus reset happens, pretend that the allocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * succeeded; we will try again for the new generation later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (channel < 0 && channel != -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) r->allocated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (channel == -EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) dev_err(&r->unit->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) "isochronous resources exhausted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) dev_err(&r->unit->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) "isochronous resource allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) mutex_unlock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) EXPORT_SYMBOL(fw_iso_resources_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * fw_iso_resources_free - frees allocated resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * @r: the resource manager
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * This function deallocates the channel and bandwidth, if allocated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) void fw_iso_resources_free(struct fw_iso_resources *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct fw_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int bandwidth, channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Not initialized. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (r->unit == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) card = fw_parent_device(r->unit)->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) mutex_lock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (r->allocated) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) bandwidth = r->bandwidth + r->bandwidth_overhead;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) &channel, &bandwidth, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (channel < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) dev_err(&r->unit->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) "isochronous resource deallocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) r->allocated = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) mutex_unlock(&r->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) EXPORT_SYMBOL(fw_iso_resources_free);