uint mod_num_sdma;
module_param_named(num_sdma, mod_num_sdma, uint, S_IRUGO);
MODULE_PARM_DESC(num_sdma, "Set max number SDMA engines to use");
static uint sdma_desct_intr = SDMA_DESC_INTR;
module_param_named(desct_intr, sdma_desct_intr, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(desct_intr, "Number of SDMA descriptor before interrupt");
#define SDMA_WAIT_BATCH_SIZE 20 /* max wait time for a SDMA engine to indicate it has halted */ #define SDMA_ERR_HALT_TIMEOUT 10/* ms */ /* all SDMA engine errors that cause a halt */
/* flush from head to tail */
sdma_flush_descq(sde);
spin_lock_irqsave(&sde->flushlist_lock, flags); /* copy flush list */
list_splice_init(&sde->flushlist, &flushlist);
spin_unlock_irqrestore(&sde->flushlist_lock, flags); /* flush from flush list */
list_for_each_entry_safe(txp, txp_next, &flushlist, list)
complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED); /* wakeup QPs orphaned on the dmawait list */ do { struct iowait *w, *nw;
seq = read_seqbegin(&sde->waitlock); if (!list_empty(&sde->dmawait)) {
write_seqlock(&sde->waitlock);
list_for_each_entry_safe(w, nw, &sde->dmawait, list) { if (w->wakeup) {
w->wakeup(w, SDMA_AVAIL_REASON);
list_del_init(&w->list);
}
}
write_sequnlock(&sde->waitlock);
}
} while (read_seqretry(&sde->waitlock, seq));
}
/* check progress on each engine except the current one */ if (curr_sde == sde) continue; /* *Wemustlockinterruptswhenacquiringsde->lock, *toavoidadeadlockifinterrupttriggersandspinson *thesamelockonsameCPU
*/
spin_lock_irqsave(&curr_sde->tail_lock, flags);
write_seqlock(&curr_sde->head_lock);
/* The reason for some of the complexity of this code is that *notalldescriptorshavecorrespondingtxps.So,wehaveto *beabletoskipoverdescsuntilwewanderintotherangeof *thenexttxponthelist.
*/
head = sde->descq_head & sde->sdma_mask;
tail = sde->descq_tail & sde->sdma_mask; while (head != tail) { /* advance head, wrap if needed */
head = ++sde->descq_head & sde->sdma_mask; /* if now past this txp's descs, do the callback */ if (txp && txp->next_descq_idx == head) { /* remove from list */
sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
trace_hfi1_sdma_progress(sde, head, tail, txp);
txp = get_txhead(sde);
}
progress++;
} if (progress)
sdma_desc_avail(sde, sdma_descq_freecnt(sde));
}
/* Releasing this reference means the state machine has stopped. */
sdma_put(ss);
/* stop waiting for all unfreeze events to complete */
atomic_set(&sde->dd->sdma_unfreeze_count, -1);
wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
}
if (!count) return SDMA_DESCQ_CNT; /* count must be a power of 2 greater than 64 and less than *32768.Otherwisereturndefault.
*/ if (!is_power_of_2(count)) return SDMA_DESCQ_CNT; if (count < 64 || count > 32768) return SDMA_DESCQ_CNT; return count;
}
/* NOTE This should only happen if SC->VL changed after the initial *checksontheQP/AH *Defaultwillreturnengine0below
*/ if (vl >= num_vls) {
rval = NULL; goto done;
}
rcu_read_lock();
m = rcu_dereference(dd->sdma_map); if (unlikely(!m)) {
rcu_read_unlock(); return &dd->per_sdma[0];
}
e = m->map[vl & m->mask];
rval = e->sde[selector & e->mask];
rcu_read_unlock();
/* only need to check the first ctr entries for a match */ for (i = 0; i < map->ctr; i++) { if (map->sde[i] == sde) {
memmove(&map->sde[i], &map->sde[i + 1],
(map->ctr - i - 1) * sizeof(map->sde[0]));
map->ctr--;
pow = roundup_pow_of_two(map->ctr ? : 1);
map->mask = pow - 1;
sdma_populate_sde_map(map); break;
}
}
}
ret = zalloc_cpumask_var(&mask, GFP_KERNEL); if (!ret) return -ENOMEM;
ret = zalloc_cpumask_var(&new_mask, GFP_KERNEL); if (!ret) {
free_cpumask_var(mask); return -ENOMEM;
}
ret = cpulist_parse(buf, mask); if (ret) goto out_free;
if (!cpumask_subset(mask, cpu_online_mask)) {
dd_dev_warn(sde->dd, "Invalid CPU mask\n");
ret = -EINVAL; goto out_free;
}
for_each_cpu(cpu, mask) { /* Check if we have this already mapped */ if (cpumask_test_cpu(cpu, &sde->cpu_mask)) {
cpumask_set_cpu(cpu, new_mask); continue;
}
rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu,
sdma_rht_params); if (!rht_node) {
rht_node = kzalloc(sizeof(*rht_node), GFP_KERNEL); if (!rht_node) {
ret = -ENOMEM; goto out;
}
ret = rhashtable_insert_fast(dd->sdma_rht,
&rht_node->node,
sdma_rht_params); if (ret) {
kfree(rht_node->map[vl]);
kfree(rht_node);
dd_dev_err(sde->dd, "Failed to set process to sde affinity for cpu %lu\n",
cpu); goto out;
}
} else { int ctr, pow;
/* Add new user mappings */ if (!rht_node->map[vl])
rht_node->map[vl] = kzalloc(sz, GFP_KERNEL);
if (!rht_node->map[vl]) {
ret = -ENOMEM; goto out;
}
spin_unlock_irq(&dd->sde_map_lock); /* success, free any old map after grace period */ if (oldmap)
call_rcu(&oldmap->list, sdma_map_rcu_callback); return0;
bail: /* free any partial allocation */
sdma_map_free(newmap); return -ENOMEM;
}
/* Create a mask specifically for each interrupt source */
sde->int_mask = (u64)1 << (0 * TXE_NUM_SDMA_ENGINES +
this_idx);
sde->progress_mask = (u64)1 << (1 * TXE_NUM_SDMA_ENGINES +
this_idx);
sde->idle_mask = (u64)1 << (2 * TXE_NUM_SDMA_ENGINES +
this_idx); /* Create a combined mask to cover all 3 interrupt sources */
sde->imask = sde->int_mask | sde->progress_mask |
sde->idle_mask;
spin_lock_init(&sde->tail_lock);
seqlock_init(&sde->head_lock);
spin_lock_init(&sde->senddmactrl_lock);
spin_lock_init(&sde->flushlist_lock);
seqlock_init(&sde->waitlock); /* insure there is always a zero bit */
sde->ahg_bits = 0xfffffffe00000000ULL;
sdma_set_state(sde, sdma_state_s00_hw_down);
/* set up reference counting */
kref_init(&sde->state.kref);
init_completion(&sde->state.comp);
dd->sdma_heads_size = L1_CACHE_BYTES * num_engines; /* Allocate memory for DMA of head registers to memory */
dd->sdma_heads_dma = dma_alloc_coherent(&dd->pcidev->dev,
dd->sdma_heads_size,
&dd->sdma_heads_phys,
GFP_KERNEL); if (!dd->sdma_heads_dma) {
dd_dev_err(dd, "failed to allocate SendDMA head memory\n"); goto bail;
}
/* Allocate memory for pad */
dd->sdma_pad_dma = dma_alloc_coherent(&dd->pcidev->dev, SDMA_PAD,
&dd->sdma_pad_phys, GFP_KERNEL); if (!dd->sdma_pad_dma) {
dd_dev_err(dd, "failed to allocate SendDMA pad memory\n"); goto bail;
}
/* assign each engine to different cacheline and init registers */
curr_head = (void *)dd->sdma_heads_dma; for (this_idx = 0; this_idx < num_engines; ++this_idx) { unsignedlong phys_offset;
/* kick off the engines state processing */ for (i = 0; i < dd->num_sdma; ++i) {
sde = &dd->per_sdma[i];
sdma_process_event(sde, sdma_event_e10_go_hw_start);
}
}
if (unlikely(HFI1_CAP_IS_KSET(SDMA_HEAD_CHECK))) {
u16 cnt;
u16 swtail;
u16 swhead; int sane;
swhead = sde->descq_head & sde->sdma_mask; /* this code is really bad for cache line trading */
swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
cnt = sde->descq_cnt;
if (unlikely(!sane)) {
dd_dev_err(dd, "SDMA(%u) bad head (%s) hwhd=%u swhd=%u swtl=%u cnt=%u\n",
sde->this_idx,
use_dmahead ? "dma" : "kreg",
hwhead, swhead, swtail, cnt); if (use_dmahead) { /* try one more time, using csr */
use_dmahead = 0; goto retry;
} /* proceed as if no progress */
hwhead = swhead;
}
} return hwhead;
}
do {
seq = read_seqbegin(&sde->waitlock); if (!list_empty(&sde->dmawait)) { /* at least one item */
write_seqlock(&sde->waitlock); /* Harvest waiters wanting DMA descriptors */
list_for_each_entry_safe(
wait,
nw,
&sde->dmawait,
list) {
u32 num_desc;
if (!wait->wakeup) continue; if (n == ARRAY_SIZE(waits)) break;
iowait_init_priority(wait);
num_desc = iowait_get_all_desc(wait); if (num_desc > avail) break;
avail -= num_desc; /* Find the top-priority wait memeber */ if (n) {
twait = waits[tidx];
tidx =
iowait_priority_update_top(wait,
twait,
n,
tidx);
}
list_del_init(&wait->list);
waits[n++] = wait;
}
write_sequnlock(&sde->waitlock); break;
}
} while (read_seqretry(&sde->waitlock, seq));
/* Schedule the top-priority entry first */ if (n)
waits[tidx]->wakeup(waits[tidx], SDMA_AVAIL_REASON);
for (i = 0; i < n; i++) if (i != tidx)
waits[i]->wakeup(waits[i], SDMA_AVAIL_REASON);
}
/* head_lock must be held */ staticvoid sdma_make_progress(struct sdma_engine *sde, u64 status)
{ struct sdma_txreq *txp = NULL; int progress = 0;
u16 hwhead, swhead; int idle_check_done = 0;
hwhead = sdma_gethead(sde);
/* The reason for some of the complexity of this code is that *notalldescriptorshavecorrespondingtxps.So,wehaveto *beabletoskipoverdescsuntilwewanderintotherangeof *thenexttxponthelist.
*/
/* if now past this txp's descs, do the callback */ if (txp && txp->next_descq_idx == swhead) { /* remove from list */
sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
complete_tx(sde, txp, SDMA_TXREQ_S_OK); /* see if there is another txp */
txp = get_txhead(sde);
}
trace_hfi1_sdma_progress(sde, hwhead, swhead, txp);
progress++;
}
staticinlinevoid sdma_update_tail(struct sdma_engine *sde, u16 tail)
{ /* Commit writes to memory and advance the tail on the chip */
smp_wmb(); /* see get_txhead() */
writeq(tail, sde->tail_csr);
}
for (i = 0; i < CCE_NUM_INT_CSRS; ++i) {
sdma_dumpstate_helper2(CCE_INT_STATUS);
sdma_dumpstate_helper2(CCE_INT_MASK);
sdma_dumpstate_helper2(CCE_INT_BLOCKED);
}
switch (ss->current_state) { case sdma_state_s00_hw_down: switch (event) { case sdma_event_e00_go_hw_down: break; case sdma_event_e30_go_running: /* *Ifdown,butrunningrequested(usuallyresult *oflinkup,thenweneedtostartup. *Thiscanhappenwhenhwdownisrequestedwhile *bringingthelinkupwithtrafficactiveon *7220,e.g.
*/
ss->go_s99_running = 1;
fallthrough; /* and start dma engine */ case sdma_event_e10_go_hw_start: /* This reference means the state machine is started */
sdma_get(&sde->state);
sdma_set_state(sde,
sdma_state_s10_hw_start_up_halt_wait); break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e40_sw_cleaned:
sdma_sw_tear_down(sde); break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle: break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s10_hw_start_up_halt_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
sdma_sw_tear_down(sde); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done:
sdma_set_state(sde,
sdma_state_s15_hw_start_up_clean_wait);
sdma_start_hw_clean_up(sde); break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted:
schedule_work(&sde->err_halt_worker); break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s15_hw_start_up_clean_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
sdma_sw_tear_down(sde); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done:
sdma_hw_start_up(sde);
sdma_set_state(sde, ss->go_s99_running ?
sdma_state_s99_running :
sdma_state_s20_idle); break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s20_idle: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
sdma_sw_tear_down(sde); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
sdma_set_state(sde, sdma_state_s99_running);
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted:
sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
schedule_work(&sde->err_halt_worker); break; case sdma_event_e70_go_idle: break; case sdma_event_e85_link_down: case sdma_event_e80_hw_freeze:
sdma_set_state(sde, sdma_state_s80_hw_freeze);
atomic_dec(&sde->dd->sdma_unfreeze_count);
wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s30_sw_clean_up_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned:
sdma_set_state(sde, sdma_state_s40_hw_clean_up_wait);
sdma_start_hw_clean_up(sde); break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down:
ss->go_s99_running = 0; break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s40_hw_clean_up_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done:
sdma_hw_start_up(sde);
sdma_set_state(sde, ss->go_s99_running ?
sdma_state_s99_running :
sdma_state_s20_idle); break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down:
ss->go_s99_running = 0; break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s50_hw_halt_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done:
sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted:
schedule_work(&sde->err_halt_worker); break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down:
ss->go_s99_running = 0; break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s60_idle_halt_wait: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done:
sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted:
schedule_work(&sde->err_halt_worker); break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s80_hw_freeze: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen:
sdma_set_state(sde, sdma_state_s82_freeze_sw_clean);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e82_hw_unfreeze: break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s82_freeze_sw_clean: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running:
ss->go_s99_running = 1; break; case sdma_event_e40_sw_cleaned: /* notify caller this engine is done cleaning */
atomic_dec(&sde->dd->sdma_unfreeze_count);
wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted: break; case sdma_event_e70_go_idle:
ss->go_s99_running = 0; break; case sdma_event_e80_hw_freeze: break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze:
sdma_hw_start_up(sde);
sdma_set_state(sde, ss->go_s99_running ?
sdma_state_s99_running :
sdma_state_s20_idle); break; case sdma_event_e85_link_down: break; case sdma_event_e90_sw_halted: break;
} break;
case sdma_state_s99_running: switch (event) { case sdma_event_e00_go_hw_down:
sdma_set_state(sde, sdma_state_s00_hw_down);
tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); break; case sdma_event_e10_go_hw_start: break; case sdma_event_e15_hw_halt_done: break; case sdma_event_e25_hw_clean_up_done: break; case sdma_event_e30_go_running: break; case sdma_event_e40_sw_cleaned: break; case sdma_event_e50_hw_cleaned: break; case sdma_event_e60_hw_halted:
need_progress = 1;
sdma_err_progress_check_schedule(sde);
fallthrough; case sdma_event_e90_sw_halted: /* *SWinitiatedhaltdoesnotperformengines *progresscheck
*/
sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
schedule_work(&sde->err_halt_worker); break; case sdma_event_e70_go_idle:
sdma_set_state(sde, sdma_state_s60_idle_halt_wait); break; case sdma_event_e85_link_down:
ss->go_s99_running = 0;
fallthrough; case sdma_event_e80_hw_freeze:
sdma_set_state(sde, sdma_state_s80_hw_freeze);
atomic_dec(&sde->dd->sdma_unfreeze_count);
wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); break; case sdma_event_e81_hw_frozen: break; case sdma_event_e82_hw_unfreeze: break;
} break;
}
ss->last_event = event; if (need_progress)
sdma_make_progress(sde, 0);
}
/* Handle last descriptor */ if (unlikely((tx->num_desc == (MAX_DESC - 1)))) { /* if tlen is 0, it is for padding, release last descriptor */ if (!tx->tlen) {
tx->desc_limit = MAX_DESC;
} elseif (!tx->coalesce_buf) { /* allocate coalesce buffer with space for padding */
tx->coalesce_buf = kmalloc(tx->tlen + sizeof(u32),
GFP_ATOMIC); if (!tx->coalesce_buf) goto enomem;
tx->coalesce_idx = 0;
} return0;
}
if (unlikely(tx->num_desc == MAX_DESC)) goto enomem;
/* If coalesce buffer is allocated, copy data into it */ if (tx->coalesce_buf) { if (type == SDMA_MAP_NONE) {
__sdma_txclean(dd, tx); return -EINVAL;
}
/* set up the wait but do not wait here */
atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
/* tell all engines to stop running and wait */ for (i = 0; i < dd->num_sdma; i++)
sdma_process_event(&dd->per_sdma[i], event);
/* sdma_freeze() will wait for all engines to have stopped */
}
/* *SPCfreezehandlingforSDMAengines.Calledwhenthedriverknows *theSPCisfullyfrozen.
*/ void sdma_freeze(struct hfi1_devdata *dd)
{ int i; int ret;
/* *Makesureallengineshavemovedoutoftherunningstatebefore *continuing.
*/
ret = wait_event_interruptible(dd->sdma_unfreeze_wq,
atomic_read(&dd->sdma_unfreeze_count) <= 0); /* interrupted or count is negative, then unloading - just exit */ if (ret || atomic_read(&dd->sdma_unfreeze_count) < 0) return;
/* set up the count for the next wait */
atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
/* tell all engines that the SPC is frozen, they can start cleaning */ for (i = 0; i < dd->num_sdma; i++)
sdma_process_event(&dd->per_sdma[i], sdma_event_e81_hw_frozen);
/* *Waitforeveryonetofinishsoftwarecleanbeforeexiting.The *softwarecleanwillreadengineCSRs,somustbecompletedbefore *thenextstep,whichwillcleartheengineCSRs.
*/
(void)wait_event_interruptible(dd->sdma_unfreeze_wq,
atomic_read(&dd->sdma_unfreeze_count) <= 0); /* no need to check results - done no matter what */
}
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.