void bcom_set_initiator(int task, int initiator) { int i; int num_descs; u32 *desc; int next_drd_has_initiator; bcom_set_tcr_initiator(task, initiator); /* Just setting tcr is apparently not enough due to some problem */ /* with it. So we just go thru all the microcode and replace in */ /* the DRD directly */ desc = bcom_task_desc(task); next_drd_has_initiator = 1; num_descs = bcom_task_num_descs(task); for (i=0; i<num_descs; i++, desc++) { if (!bcom_desc_is_drd(*desc)) continue; if (next_drd_has_initiator) if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) bcom_set_desc_initiator(desc, initiator); next_drd_has_initiator = !bcom_drd_is_extended(*desc); } }
/* This is an ugly hack, but at least it's only done once at initialization */ static u32 *self_modified_drd(int tasknum) { u32 *desc; int num_descs; int drd_count; int i; num_descs = bcom_task_num_descs(tasknum); desc = bcom_task_desc(tasknum) + num_descs - 1; drd_count = 0; for (i=0; i<num_descs; i++, desc--) if (bcom_desc_is_drd(*desc) && ++drd_count == 3) break; return desc; }
int bcom_load_image(int task, u32 *task_image) { struct bcom_task_header *hdr = (struct bcom_task_header *)task_image; struct bcom_tdt *tdt; u32 *desc, *var, *inc; u32 *desc_src, *var_src, *inc_src; /* Safety checks */ if (hdr->magic != BCOM_TASK_MAGIC) { printk(KERN_ERR DRIVER_NAME ": Trying to load invalid microcode\n"); return -EINVAL; } if ((task < 0) || (task >= BCOM_MAX_TASKS)) { printk(KERN_ERR DRIVER_NAME ": Trying to load invalid task %d\n", task); return -EINVAL; } /* Initial load or reload */ tdt = &bcom_eng->tdt[task]; if (tdt->start) { desc = bcom_task_desc(task); if (hdr->desc_size != bcom_task_num_descs(task)) { printk(KERN_ERR DRIVER_NAME ": Trying to reload wrong task image " "(%d size %d/%d)!\n", task, hdr->desc_size, bcom_task_num_descs(task)); return -EINVAL; } } else { phys_addr_t start_pa; desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); if (!desc) return -ENOMEM; tdt->start = start_pa; tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); } var = bcom_task_var(task); inc = bcom_task_inc(task); /* Clear & copy */ memset(var, 0x00, BCOM_VAR_SIZE); memset(inc, 0x00, BCOM_INC_SIZE); desc_src = (u32 *)(hdr + 1); var_src = desc_src + hdr->desc_size; inc_src = var_src + hdr->var_size; memcpy(desc, desc_src, hdr->desc_size * sizeof(u32)); memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); memcpy(inc, inc_src, hdr->inc_size * sizeof(u32)); return 0; }