if (flush) { /* flush write with read access */
ioread32(addr);
}
}
static u64 tsnep_change_duration(struct tsnep_gcl *gcl, int index)
{
u64 duration; int count;
/* change needs to be triggered one or two operations before start of * new gate control list * - change is triggered at start of operation (minimum one operation) * - operation with adjusted interval is inserted on demand to exactly * meet the start of the new gate control list (optional) * * additionally properties are read directly after start of previous * operation * * therefore, three operations needs to be considered for the limit
*/
duration = 0;
count = 3; while (count) {
duration += gcl->operation[index].interval;
for (i = 0; i < qopt->num_entries; i++) {
properties = qopt->entries[i].gate_mask; if (i == (qopt->num_entries - 1))
properties |= TSNEP_GCL_LAST;
tsnep_write_gcl_operation(gcl, i, properties,
qopt->entries[i].interval, true);
}
gcl->count = qopt->num_entries;
/* calculate change limit; i.e., the time needed between enable and * start of new gate control list
*/
/* case 1: extend cycle time for change * - change duration of last operation * - cycle time extension
*/
extend = tsnep_change_duration(gcl, gcl->count - 1);
extend += gcl->cycle_time_extension;
/* case 2: cut cycle time for change * - maximum change duration
*/
cut = 0; for (i = 0; i < gcl->count; i++)
cut = max(cut, tsnep_change_duration(gcl, i));
/* use maximum, because the actual case (extend or cut) can be * determined only after limit is known (chicken-and-egg problem)
*/
gcl->change_limit = max(extend, cut);
}
n = div64_u64(limit - start, gcl->cycle_time);
start += n * gcl->cycle_time; if (start == limit)
start -= gcl->cycle_time;
return start;
}
static u64 tsnep_set_gcl_change(struct tsnep_gcl *gcl, int index, u64 change, bool insert)
{ /* previous operation triggers change and properties are evaluated at * start of operation
*/ if (index == 0)
index = gcl->count - 1; else
index = index - 1;
change -= gcl->operation[index].interval;
/* optionally change to new list with additional operation in between */ if (insert) { void __iomem *addr = gcl->addr + sizeof(struct tsnep_gcl_operation) * index;
properties = gcl->operation[ref].properties & TSNEP_GCL_MASK; /* change to new list directly after inserted operation */
properties |= TSNEP_GCL_CHANGE;
/* last operation of list is reserved to insert operation */
tsnep_write_gcl_operation(gcl, TSNEP_GCL_COUNT - 1, properties,
interval, false);
static u64 tsnep_cut_gcl(struct tsnep_gcl *gcl, u64 start, u64 cycle_time)
{
u64 sum = 0; int i;
/* find operation which shall be cutted */ for (i = 0; i < gcl->count; i++) {
u64 sum_tmp = sum + gcl->operation[i].interval;
u64 interval;
/* sum up operations as long as cycle time is not exceeded */ if (sum_tmp > cycle_time) break;
/* remaining interval must be big enough for hardware */
interval = cycle_time - sum_tmp; if (interval > 0 && interval < TSNEP_GCL_MIN_INTERVAL) break;
sum = sum_tmp;
} if (sum == cycle_time) { /* no need to cut operation itself or whole cycle * => change exactly at operation
*/ return tsnep_set_gcl_change(gcl, i, start + sum, false);
} return tsnep_insert_gcl_operation(gcl, i, start + sum,
cycle_time - sum);
}
/* estimate timeout limit after timeout enable, actually timeout limit * in hardware will be earlier than estimate so we are on the safe side
*/
tsnep_get_system_time(adapter, &system_time);
timeout = system_time + TSNEP_GC_TIMEOUT;
/* gate control time register is only 32bit => time shall be in the near * future (no driver support for far future implemented)
*/ if ((gcl->start_time - system_time) >= U32_MAX) return -EAGAIN;
if (curr) { /* change gate control list */
u64 last;
u64 change;
last = tsnep_gcl_start_before(curr, gcl->start_time); if ((last + curr->cycle_time) == gcl->start_time)
change = tsnep_cut_gcl(curr, last,
gcl->start_time - last); elseif (((gcl->start_time - last) <=
curr->cycle_time_extension) ||
((gcl->start_time - last) <= TSNEP_GCL_MIN_INTERVAL))
change = tsnep_extend_gcl(curr, last,
gcl->start_time - last); else
change = tsnep_cut_gcl(curr, last,
gcl->start_time - last);
/* select current gate control list if active */ if (adapter->gate_control_active) { if (adapter->next_gcl == 0)
curr = &adapter->gcl[1]; else
curr = &adapter->gcl[0];
} else {
curr = NULL;
}
for (;;) { /* start timeout which discards late enable, this helps ensuring * that start/change time are in the future at enable
*/
iowrite8(TSNEP_GC_ENABLE_TIMEOUT, adapter->addr + TSNEP_GC);
retval = tsnep_enable_gcl(adapter, gcl, curr); if (retval) {
mutex_unlock(&adapter->gate_control_lock);
return retval;
}
/* enable gate control list */ if (adapter->next_gcl == 0)
iowrite8(TSNEP_GC_ENABLE_A, adapter->addr + TSNEP_GC); else
iowrite8(TSNEP_GC_ENABLE_B, adapter->addr + TSNEP_GC);
/* done if timeout did not happen */ if (!(ioread32(adapter->addr + TSNEP_GC) &
TSNEP_GC_TIMEOUT_SIGNAL)) break;
/* timeout is acknowledged with any enable */
iowrite8(TSNEP_GC_ENABLE_A, adapter->addr + TSNEP_GC);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.