- while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
- {
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- /* if we already allocated the writing code, but failed to get a
- * buffer, free the algorithm */
- if (stm32x_info->write_algorithm)
- target_free_working_area(target, stm32x_info->write_algorithm);
-
- LOG_WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- };
+ buffer_size = target_get_working_area_avail(target);
+ buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256));
+ /* Normally we allocate all available working area.
+ * MIN shrinks buffer_size if the size of the written block is smaller.
+ * MAX prevents using async algo if the available working area is smaller
+ * than 256, the following allocation fails with
+ * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place.
+ */
+
+ retval = target_alloc_working_area(target, buffer_size, &source);
+ /* Allocated size is always 32-bit word aligned */
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ /* target_alloc_working_area() may return ERROR_FAIL if area backup fails:
+ * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE
+ */
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ struct reg_param reg_params[5];
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */
+ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
+
+ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
+ buf_set_u32(reg_params[1].value, 0, 32, hwords_count);
+ buf_set_u32(reg_params[2].value, 0, 32, source->address);
+ buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
+ buf_set_u32(reg_params[4].value, 0, 32, address);