0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/device.h>
0009 #include <linux/firewire.h>
0010 #include <linux/firewire-constants.h>
0011 #include <linux/export.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/mutex.h>
0014 #include <linux/sched.h>
0015 #include <linux/spinlock.h>
0016 #include "iso-resources.h"
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
0027 {
0028 r->channels_mask = ~0uLL;
0029 r->unit = unit;
0030 mutex_init(&r->mutex);
0031 r->allocated = false;
0032
0033 return 0;
0034 }
0035 EXPORT_SYMBOL(fw_iso_resources_init);
0036
0037
0038
0039
0040
0041 void fw_iso_resources_destroy(struct fw_iso_resources *r)
0042 {
0043 WARN_ON(r->allocated);
0044 mutex_destroy(&r->mutex);
0045 }
0046 EXPORT_SYMBOL(fw_iso_resources_destroy);
0047
0048 static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
0049 {
0050 unsigned int bytes, s400_bytes;
0051
0052
0053 bytes = 3 * 4 + ALIGN(max_payload_bytes, 4);
0054
0055
0056 if (speed <= SCODE_400)
0057 s400_bytes = bytes * (1 << (SCODE_400 - speed));
0058 else
0059 s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400));
0060
0061 return s400_bytes;
0062 }
0063
0064 static int current_bandwidth_overhead(struct fw_card *card)
0065 {
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512;
0077 }
0078
0079 static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card)
0080 {
0081 for (;;) {
0082 s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64();
0083 if (delay <= 0)
0084 return 0;
0085 if (schedule_timeout_interruptible(delay) > 0)
0086 return -ERESTARTSYS;
0087 }
0088 }
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 int fw_iso_resources_allocate(struct fw_iso_resources *r,
0106 unsigned int max_payload_bytes, int speed)
0107 {
0108 struct fw_card *card = fw_parent_device(r->unit)->card;
0109 int bandwidth, channel, err;
0110
0111 if (WARN_ON(r->allocated))
0112 return -EBADFD;
0113
0114 r->bandwidth = packet_bandwidth(max_payload_bytes, speed);
0115
0116 retry_after_bus_reset:
0117 spin_lock_irq(&card->lock);
0118 r->generation = card->generation;
0119 r->bandwidth_overhead = current_bandwidth_overhead(card);
0120 spin_unlock_irq(&card->lock);
0121
0122 err = wait_isoch_resource_delay_after_bus_reset(card);
0123 if (err < 0)
0124 return err;
0125
0126 mutex_lock(&r->mutex);
0127
0128 bandwidth = r->bandwidth + r->bandwidth_overhead;
0129 fw_iso_resource_manage(card, r->generation, r->channels_mask,
0130 &channel, &bandwidth, true);
0131 if (channel == -EAGAIN) {
0132 mutex_unlock(&r->mutex);
0133 goto retry_after_bus_reset;
0134 }
0135 if (channel >= 0) {
0136 r->channel = channel;
0137 r->allocated = true;
0138 } else {
0139 if (channel == -EBUSY)
0140 dev_err(&r->unit->device,
0141 "isochronous resources exhausted\n");
0142 else
0143 dev_err(&r->unit->device,
0144 "isochronous resource allocation failed\n");
0145 }
0146
0147 mutex_unlock(&r->mutex);
0148
0149 return channel;
0150 }
0151 EXPORT_SYMBOL(fw_iso_resources_allocate);
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164 int fw_iso_resources_update(struct fw_iso_resources *r)
0165 {
0166 struct fw_card *card = fw_parent_device(r->unit)->card;
0167 int bandwidth, channel;
0168
0169 mutex_lock(&r->mutex);
0170
0171 if (!r->allocated) {
0172 mutex_unlock(&r->mutex);
0173 return 0;
0174 }
0175
0176 spin_lock_irq(&card->lock);
0177 r->generation = card->generation;
0178 r->bandwidth_overhead = current_bandwidth_overhead(card);
0179 spin_unlock_irq(&card->lock);
0180
0181 bandwidth = r->bandwidth + r->bandwidth_overhead;
0182
0183 fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
0184 &channel, &bandwidth, true);
0185
0186
0187
0188
0189 if (channel < 0 && channel != -EAGAIN) {
0190 r->allocated = false;
0191 if (channel == -EBUSY)
0192 dev_err(&r->unit->device,
0193 "isochronous resources exhausted\n");
0194 else
0195 dev_err(&r->unit->device,
0196 "isochronous resource allocation failed\n");
0197 }
0198
0199 mutex_unlock(&r->mutex);
0200
0201 return channel;
0202 }
0203 EXPORT_SYMBOL(fw_iso_resources_update);
0204
0205
0206
0207
0208
0209
0210
0211 void fw_iso_resources_free(struct fw_iso_resources *r)
0212 {
0213 struct fw_card *card;
0214 int bandwidth, channel;
0215
0216
0217 if (r->unit == NULL)
0218 return;
0219 card = fw_parent_device(r->unit)->card;
0220
0221 mutex_lock(&r->mutex);
0222
0223 if (r->allocated) {
0224 bandwidth = r->bandwidth + r->bandwidth_overhead;
0225 fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
0226 &channel, &bandwidth, false);
0227 if (channel < 0)
0228 dev_err(&r->unit->device,
0229 "isochronous resource deallocation failed\n");
0230
0231 r->allocated = false;
0232 }
0233
0234 mutex_unlock(&r->mutex);
0235 }
0236 EXPORT_SYMBOL(fw_iso_resources_free);