xref: /aosp_15_r20/external/flashrom/action_descriptor.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /* Copyright 2018 The Chromium OS Authors. All rights reserved.
2*0d6140beSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
3*0d6140beSAndroid Build Coastguard Worker  * found in the LICENSE file.
4*0d6140beSAndroid Build Coastguard Worker  */
5*0d6140beSAndroid Build Coastguard Worker 
6*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
7*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
8*0d6140beSAndroid Build Coastguard Worker #include <string.h>
9*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
10*0d6140beSAndroid Build Coastguard Worker 
11*0d6140beSAndroid Build Coastguard Worker #include "action_descriptor.h"
12*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
13*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
14*0d6140beSAndroid Build Coastguard Worker #include "layout.h"
15*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
16*0d6140beSAndroid Build Coastguard Worker 
17*0d6140beSAndroid Build Coastguard Worker /**
18*0d6140beSAndroid Build Coastguard Worker  * action_descriptor is DEPRECATED !
19*0d6140beSAndroid Build Coastguard Worker  * Allow for easy toggling off for the eventual removal from the tree.
20*0d6140beSAndroid Build Coastguard Worker  *
21*0d6140beSAndroid Build Coastguard Worker  * TRUE  := action_descriptor is not used.
22*0d6140beSAndroid Build Coastguard Worker  * FALSE := action_descriptor is used on Intel.
23*0d6140beSAndroid Build Coastguard Worker  */
24*0d6140beSAndroid Build Coastguard Worker static bool deprecate_ad = false;
25*0d6140beSAndroid Build Coastguard Worker 
26*0d6140beSAndroid Build Coastguard Worker /*
27*0d6140beSAndroid Build Coastguard Worker  * This global variable is used to communicate the type of ICH found on the
28*0d6140beSAndroid Build Coastguard Worker  * device. When running on non-intel platforms default value of
29*0d6140beSAndroid Build Coastguard Worker  * CHIPSET_ICH_UNKNOWN is used.
30*0d6140beSAndroid Build Coastguard Worker */
31*0d6140beSAndroid Build Coastguard Worker extern enum ich_chipset ich_generation;
32*0d6140beSAndroid Build Coastguard Worker 
33*0d6140beSAndroid Build Coastguard Worker /*
34*0d6140beSAndroid Build Coastguard Worker  * Unfortunate global state.
35*0d6140beSAndroid Build Coastguard Worker  */
36*0d6140beSAndroid Build Coastguard Worker static bool dry_run = false;
37*0d6140beSAndroid Build Coastguard Worker 
38*0d6140beSAndroid Build Coastguard Worker /*
39*0d6140beSAndroid Build Coastguard Worker  * This module analyses the contents of 'before' and 'after' flash images and
40*0d6140beSAndroid Build Coastguard Worker  * based on the images' differences prepares a list of processing actions to
41*0d6140beSAndroid Build Coastguard Worker  * take.
42*0d6140beSAndroid Build Coastguard Worker  *
43*0d6140beSAndroid Build Coastguard Worker  * The goal is to prepare actions using the chip's erase capability in a most
44*0d6140beSAndroid Build Coastguard Worker  * efficient way: erasing smallest possible portions of the chip gives the
45*0d6140beSAndroid Build Coastguard Worker  * highest granularity, but if many small areas need to be erased, erasing a
46*0d6140beSAndroid Build Coastguard Worker  * larger area, even if re-writing it completely, is more efficient. The
47*0d6140beSAndroid Build Coastguard Worker  * breakdown is somewhere at 60%.
48*0d6140beSAndroid Build Coastguard Worker  *
49*0d6140beSAndroid Build Coastguard Worker  * Each flash chip description in flash.c includes a set of erase command
50*0d6140beSAndroid Build Coastguard Worker  * descriptors, different commands allowing to erase blocks of fixed different
51*0d6140beSAndroid Build Coastguard Worker  * sizes. Sometimes the erase command for a certain block size does not cover
52*0d6140beSAndroid Build Coastguard Worker  * the entire chip. This module preprocesses the flash chip description to
53*0d6140beSAndroid Build Coastguard Worker  * compile an array of erase commands with their block size indices such that
54*0d6140beSAndroid Build Coastguard Worker  * it is guaranteed that the command can be used to erase anywhere in the chip
55*0d6140beSAndroid Build Coastguard Worker  * where erase is required based on the differences between 'before' and
56*0d6140beSAndroid Build Coastguard Worker  * 'after' images.
57*0d6140beSAndroid Build Coastguard Worker  *
58*0d6140beSAndroid Build Coastguard Worker  * 'eraser_index' below is the index into the 'block_erasers' array of the
59*0d6140beSAndroid Build Coastguard Worker  * flash chip descriptor, points to the function to use to erase the block of
60*0d6140beSAndroid Build Coastguard Worker  * a certain size.
61*0d6140beSAndroid Build Coastguard Worker  *
62*0d6140beSAndroid Build Coastguard Worker  * The erase command could potentially operate on blocks of different sizes,
63*0d6140beSAndroid Build Coastguard Worker  * 'region_index' is the index into the 'block_erasers.eraseblocks' array
64*0d6140beSAndroid Build Coastguard Worker  * which defines what block size would be used by this erase command.
65*0d6140beSAndroid Build Coastguard Worker  */
66*0d6140beSAndroid Build Coastguard Worker struct eraser {
67*0d6140beSAndroid Build Coastguard Worker 	int eraser_index;
68*0d6140beSAndroid Build Coastguard Worker 	int region_index;
69*0d6140beSAndroid Build Coastguard Worker };
70*0d6140beSAndroid Build Coastguard Worker 
71*0d6140beSAndroid Build Coastguard Worker /*
72*0d6140beSAndroid Build Coastguard Worker  * A helper structure which holds information about blocks of a given size
73*0d6140beSAndroid Build Coastguard Worker  * which require writing and or erasing.
74*0d6140beSAndroid Build Coastguard Worker  *
75*0d6140beSAndroid Build Coastguard Worker  * The actual map of the blocks is pointed at by the 'block_map' field, one
76*0d6140beSAndroid Build Coastguard Worker  * byte per block. Block might need an erase, or just a write, depending on
77*0d6140beSAndroid Build Coastguard Worker  * the contents of 'before' and 'after' flash images.
78*0d6140beSAndroid Build Coastguard Worker  *
79*0d6140beSAndroid Build Coastguard Worker  * The 'limit' field holds the number of blocks of this size, which is
80*0d6140beSAndroid Build Coastguard Worker  * equivalent to one block of the next larger size in term of time required
81*0d6140beSAndroid Build Coastguard Worker  * for erasing/programming.
82*0d6140beSAndroid Build Coastguard Worker  */
83*0d6140beSAndroid Build Coastguard Worker struct range_map {
84*0d6140beSAndroid Build Coastguard Worker 	size_t block_size;
85*0d6140beSAndroid Build Coastguard Worker 	int limit;
86*0d6140beSAndroid Build Coastguard Worker 	struct b_map {
87*0d6140beSAndroid Build Coastguard Worker 		uint8_t need_change:1;
88*0d6140beSAndroid Build Coastguard Worker 		uint8_t need_erase:1;
89*0d6140beSAndroid Build Coastguard Worker 	} *block_map;
90*0d6140beSAndroid Build Coastguard Worker };
91*0d6140beSAndroid Build Coastguard Worker 
92*0d6140beSAndroid Build Coastguard Worker /*
93*0d6140beSAndroid Build Coastguard Worker  * A debug function printing out the array or processing units from an the
94*0d6140beSAndroid Build Coastguard Worker  * action descriptor.
95*0d6140beSAndroid Build Coastguard Worker  */
dump_descriptor(struct action_descriptor * descriptor)96*0d6140beSAndroid Build Coastguard Worker static void dump_descriptor(struct action_descriptor *descriptor)
97*0d6140beSAndroid Build Coastguard Worker {
98*0d6140beSAndroid Build Coastguard Worker 	struct processing_unit *pu = descriptor->processing_units;
99*0d6140beSAndroid Build Coastguard Worker 
100*0d6140beSAndroid Build Coastguard Worker 	while (pu->num_blocks) {
101*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%06zx..%06zx %6zx x %zd eraser %d\n", pu->offset,
102*0d6140beSAndroid Build Coastguard Worker 			 pu->offset + pu->num_blocks * pu->block_size - 1,
103*0d6140beSAndroid Build Coastguard Worker 			 pu->block_size, pu->num_blocks,
104*0d6140beSAndroid Build Coastguard Worker 			 pu->block_eraser_index);
105*0d6140beSAndroid Build Coastguard Worker 		pu++;
106*0d6140beSAndroid Build Coastguard Worker 	}
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker 
109*0d6140beSAndroid Build Coastguard Worker /*
110*0d6140beSAndroid Build Coastguard Worker  * Do not allow use of unsupported erasers functions.
111*0d6140beSAndroid Build Coastguard Worker  *
112*0d6140beSAndroid Build Coastguard Worker  * On some Intel platforms the ICH SPI controller is restricting the set of
113*0d6140beSAndroid Build Coastguard Worker  * SPI command codes the AP can issue, in particular limiting the set of erase
114*0d6140beSAndroid Build Coastguard Worker  * functions to just two of them.
115*0d6140beSAndroid Build Coastguard Worker  *
116*0d6140beSAndroid Build Coastguard Worker  * This function creates a local copy of the flash chip descriptor found in
117*0d6140beSAndroid Build Coastguard Worker  * the main table, filtering out unsupported erase function pointers, when
118*0d6140beSAndroid Build Coastguard Worker  * necessary.
119*0d6140beSAndroid Build Coastguard Worker  *
120*0d6140beSAndroid Build Coastguard Worker  * flash: pointer to the master flash context, including the original chip
121*0d6140beSAndroid Build Coastguard Worker  *        descriptor.
122*0d6140beSAndroid Build Coastguard Worker  * chip: pointer to a flash chip descriptor copy, potentially with just a
123*0d6140beSAndroid Build Coastguard Worker  *            subset of erasers included.
124*0d6140beSAndroid Build Coastguard Worker  */
fix_erasers_if_needed(struct flashchip * chip,struct flashctx * flash)125*0d6140beSAndroid Build Coastguard Worker static void fix_erasers_if_needed(struct flashchip *chip,
126*0d6140beSAndroid Build Coastguard Worker 				  struct flashctx *flash)
127*0d6140beSAndroid Build Coastguard Worker {
128*0d6140beSAndroid Build Coastguard Worker 	int i;
129*0d6140beSAndroid Build Coastguard Worker 
130*0d6140beSAndroid Build Coastguard Worker 	if (deprecate_ad)
131*0d6140beSAndroid Build Coastguard Worker 		return;
132*0d6140beSAndroid Build Coastguard Worker 
133*0d6140beSAndroid Build Coastguard Worker 	/* Need to copy no matter what. */
134*0d6140beSAndroid Build Coastguard Worker 	*chip = *flash->chip;
135*0d6140beSAndroid Build Coastguard Worker 
136*0d6140beSAndroid Build Coastguard Worker #if ((defined (__i386__) || defined (__x86_64__) || defined(__amd64__))) && CONFIG_INTERNAL
137*0d6140beSAndroid Build Coastguard Worker 	/*
138*0d6140beSAndroid Build Coastguard Worker 	 * ich_generation is set to the chipset type when running on an x86
139*0d6140beSAndroid Build Coastguard Worker 	 * device, even when flashrom was invoked to program the EC.
140*0d6140beSAndroid Build Coastguard Worker 	 *
141*0d6140beSAndroid Build Coastguard Worker 	 * But ICH type does not affect EC programming path, so no need to
142*0d6140beSAndroid Build Coastguard Worker 	 * check if the eraser is supported in that case.
143*0d6140beSAndroid Build Coastguard Worker 	 */
144*0d6140beSAndroid Build Coastguard Worker 	if ((ich_generation == CHIPSET_ICH_UNKNOWN) || programming_ec()) {
145*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%s: kept all erasers\n",  __func__);
146*0d6140beSAndroid Build Coastguard Worker 		return;
147*0d6140beSAndroid Build Coastguard Worker 	}
148*0d6140beSAndroid Build Coastguard Worker #else
149*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("%s: kept all erasers on non-x86\n",  __func__);
150*0d6140beSAndroid Build Coastguard Worker 	return;
151*0d6140beSAndroid Build Coastguard Worker #endif /* !IS_X86 */
152*0d6140beSAndroid Build Coastguard Worker 
153*0d6140beSAndroid Build Coastguard Worker 	/*
154*0d6140beSAndroid Build Coastguard Worker 	 * We are dealing with an Intel controller; different chipsets allow
155*0d6140beSAndroid Build Coastguard Worker 	 * different erase commands. Let's check the commands and allow only
156*0d6140beSAndroid Build Coastguard Worker 	 * those which the controller accepts.
157*0d6140beSAndroid Build Coastguard Worker 	 */
158*0d6140beSAndroid Build Coastguard Worker 	dry_run = true;
159*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
160*0d6140beSAndroid Build Coastguard Worker 		erasefunc_t *erase_func = lookup_erase_func_ptr(&chip->block_erasers[i]);
161*0d6140beSAndroid Build Coastguard Worker 		/* Assume it is not allowed. */
162*0d6140beSAndroid Build Coastguard Worker 		if (!erase_func)
163*0d6140beSAndroid Build Coastguard Worker 			continue;
164*0d6140beSAndroid Build Coastguard Worker 
165*0d6140beSAndroid Build Coastguard Worker 		if (!erase_func(flash, 0, flash->chip->total_size * 1024)) {
166*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("%s: kept eraser at %d\n",  __func__, i);
167*0d6140beSAndroid Build Coastguard Worker 			continue;
168*0d6140beSAndroid Build Coastguard Worker 		}
169*0d6140beSAndroid Build Coastguard Worker 
170*0d6140beSAndroid Build Coastguard Worker 		chip->block_erasers[i].block_erase = NO_BLOCK_ERASE_FUNC;
171*0d6140beSAndroid Build Coastguard Worker 	}
172*0d6140beSAndroid Build Coastguard Worker 	dry_run = false;
173*0d6140beSAndroid Build Coastguard Worker }
174*0d6140beSAndroid Build Coastguard Worker 
175*0d6140beSAndroid Build Coastguard Worker /*
176*0d6140beSAndroid Build Coastguard Worker  * Prepare a list of erasers available on this chip, sorted by the block size,
177*0d6140beSAndroid Build Coastguard Worker  * from lower to higher.
178*0d6140beSAndroid Build Coastguard Worker  *
179*0d6140beSAndroid Build Coastguard Worker  * @flash	    pointer to the flash context
180*0d6140beSAndroid Build Coastguard Worker  * @erase_size	    maximum offset which needs to be erased
181*0d6140beSAndroid Build Coastguard Worker  * @sorted_erasers  pointer to the array of eraser structures, large enough to
182*0d6140beSAndroid Build Coastguard Worker  *                  fit NUM_ERASEFUNCTIONS elements.
183*0d6140beSAndroid Build Coastguard Worker  *
184*0d6140beSAndroid Build Coastguard Worker  * Returns number of elements put into the 'sorted_erasers' array.
185*0d6140beSAndroid Build Coastguard Worker  */
fill_sorted_erasers(struct flashctx * flash,size_t erase_size,struct eraser * sorted_erasers)186*0d6140beSAndroid Build Coastguard Worker static size_t fill_sorted_erasers(struct flashctx *flash,
187*0d6140beSAndroid Build Coastguard Worker 				  size_t erase_size,
188*0d6140beSAndroid Build Coastguard Worker 				  struct eraser *sorted_erasers)
189*0d6140beSAndroid Build Coastguard Worker {
190*0d6140beSAndroid Build Coastguard Worker 	size_t j, k;
191*0d6140beSAndroid Build Coastguard Worker 	size_t chip_eraser;
192*0d6140beSAndroid Build Coastguard Worker 	size_t chip_region;
193*0d6140beSAndroid Build Coastguard Worker 	struct flashchip chip; /* Local copy, potentially altered. */
194*0d6140beSAndroid Build Coastguard Worker 	/*
195*0d6140beSAndroid Build Coastguard Worker 	 * In case chip description does not include any functions covering
196*0d6140beSAndroid Build Coastguard Worker 	 * the entire space (this could happen when the description comes from
197*0d6140beSAndroid Build Coastguard Worker 	 * the Chrome OS TP driver for instance), use the best effort.
198*0d6140beSAndroid Build Coastguard Worker 	 *
199*0d6140beSAndroid Build Coastguard Worker 	 * The structure below saves information about the eraser which covers
200*0d6140beSAndroid Build Coastguard Worker 	 * the most of the chip space, it is used if no valid functions were
201*0d6140beSAndroid Build Coastguard Worker 	 * found, which allows programming to succeed.
202*0d6140beSAndroid Build Coastguard Worker 	 *
203*0d6140beSAndroid Build Coastguard Worker 	 * The issue be further investigated under b/110474116.
204*0d6140beSAndroid Build Coastguard Worker 	 */
205*0d6140beSAndroid Build Coastguard Worker 	struct {
206*0d6140beSAndroid Build Coastguard Worker 		int max_total;
207*0d6140beSAndroid Build Coastguard Worker 		int alt_function;
208*0d6140beSAndroid Build Coastguard Worker 		int alt_region;
209*0d6140beSAndroid Build Coastguard Worker 	} fallback = {};
210*0d6140beSAndroid Build Coastguard Worker 
211*0d6140beSAndroid Build Coastguard Worker 	fix_erasers_if_needed(&chip, flash);
212*0d6140beSAndroid Build Coastguard Worker 
213*0d6140beSAndroid Build Coastguard Worker 	/* Iterate over all available erase functions/block sizes. */
214*0d6140beSAndroid Build Coastguard Worker 	for (j = k = 0; k < NUM_ERASEFUNCTIONS; k++) {
215*0d6140beSAndroid Build Coastguard Worker 		size_t new_block_size;
216*0d6140beSAndroid Build Coastguard Worker 		size_t m, n;
217*0d6140beSAndroid Build Coastguard Worker 
218*0d6140beSAndroid Build Coastguard Worker 		/* Make sure there is a function in is slot */
219*0d6140beSAndroid Build Coastguard Worker 		if (!chip.block_erasers[k].block_erase)
220*0d6140beSAndroid Build Coastguard Worker 			continue;
221*0d6140beSAndroid Build Coastguard Worker 
222*0d6140beSAndroid Build Coastguard Worker 		/*
223*0d6140beSAndroid Build Coastguard Worker 		 * Make sure there is a (block size * count) combination which
224*0d6140beSAndroid Build Coastguard Worker 		 * would erase up to required offset into the chip.
225*0d6140beSAndroid Build Coastguard Worker 		 *
226*0d6140beSAndroid Build Coastguard Worker 		 * If this is not the case, but the current total size exceeds
227*0d6140beSAndroid Build Coastguard Worker 		 * the previously saved fallback total size, make the current
228*0d6140beSAndroid Build Coastguard Worker 		 * block the best available fallback case.
229*0d6140beSAndroid Build Coastguard Worker 		 */
230*0d6140beSAndroid Build Coastguard Worker 		for (n = 0; n < NUM_ERASEREGIONS; n++) {
231*0d6140beSAndroid Build Coastguard Worker 			const struct eraseblock *eb =
232*0d6140beSAndroid Build Coastguard Worker 				chip.block_erasers[k].eraseblocks + n;
233*0d6140beSAndroid Build Coastguard Worker 			size_t total = eb->size * eb->count;
234*0d6140beSAndroid Build Coastguard Worker 
235*0d6140beSAndroid Build Coastguard Worker 			if (total >= erase_size)
236*0d6140beSAndroid Build Coastguard Worker 				break;
237*0d6140beSAndroid Build Coastguard Worker 
238*0d6140beSAndroid Build Coastguard Worker 			if (total > (size_t)fallback.max_total) {
239*0d6140beSAndroid Build Coastguard Worker 				fallback.max_total = total;
240*0d6140beSAndroid Build Coastguard Worker 				fallback.alt_region = n;
241*0d6140beSAndroid Build Coastguard Worker 				fallback.alt_function = k;
242*0d6140beSAndroid Build Coastguard Worker 			}
243*0d6140beSAndroid Build Coastguard Worker 		}
244*0d6140beSAndroid Build Coastguard Worker 
245*0d6140beSAndroid Build Coastguard Worker 		if (n == NUM_ERASEREGIONS) {
246*0d6140beSAndroid Build Coastguard Worker 			 /*
247*0d6140beSAndroid Build Coastguard Worker 			  * This function will not erase far enough into the
248*0d6140beSAndroid Build Coastguard Worker 			  * chip.
249*0d6140beSAndroid Build Coastguard Worker 			  */
250*0d6140beSAndroid Build Coastguard Worker 			continue;
251*0d6140beSAndroid Build Coastguard Worker 		}
252*0d6140beSAndroid Build Coastguard Worker 
253*0d6140beSAndroid Build Coastguard Worker 		new_block_size = chip.block_erasers[k].eraseblocks[n].size;
254*0d6140beSAndroid Build Coastguard Worker 
255*0d6140beSAndroid Build Coastguard Worker 		/*
256*0d6140beSAndroid Build Coastguard Worker 		 * Place this block in the sorted position in the
257*0d6140beSAndroid Build Coastguard Worker 		 * sorted_erasers array.
258*0d6140beSAndroid Build Coastguard Worker 		 */
259*0d6140beSAndroid Build Coastguard Worker 		for (m = 0; m < j; m++) {
260*0d6140beSAndroid Build Coastguard Worker 			size_t old_block_size;
261*0d6140beSAndroid Build Coastguard Worker 
262*0d6140beSAndroid Build Coastguard Worker 			chip_eraser = sorted_erasers[m].eraser_index;
263*0d6140beSAndroid Build Coastguard Worker 			chip_region = sorted_erasers[m].region_index;
264*0d6140beSAndroid Build Coastguard Worker 
265*0d6140beSAndroid Build Coastguard Worker 			old_block_size = chip.block_erasers
266*0d6140beSAndroid Build Coastguard Worker 				[chip_eraser].eraseblocks[chip_region].size;
267*0d6140beSAndroid Build Coastguard Worker 
268*0d6140beSAndroid Build Coastguard Worker 			if (old_block_size < new_block_size)
269*0d6140beSAndroid Build Coastguard Worker 				continue;
270*0d6140beSAndroid Build Coastguard Worker 
271*0d6140beSAndroid Build Coastguard Worker 			/* Do not keep duplicates in the sorted array. */
272*0d6140beSAndroid Build Coastguard Worker 			if (old_block_size == new_block_size) {
273*0d6140beSAndroid Build Coastguard Worker 				j--;
274*0d6140beSAndroid Build Coastguard Worker 				break;
275*0d6140beSAndroid Build Coastguard Worker 			}
276*0d6140beSAndroid Build Coastguard Worker 
277*0d6140beSAndroid Build Coastguard Worker 			memmove(sorted_erasers + m + 1,
278*0d6140beSAndroid Build Coastguard Worker 				sorted_erasers + m,
279*0d6140beSAndroid Build Coastguard Worker 				sizeof(sorted_erasers[0]) * (j - m));
280*0d6140beSAndroid Build Coastguard Worker                         break;
281*0d6140beSAndroid Build Coastguard Worker                 }
282*0d6140beSAndroid Build Coastguard Worker 		sorted_erasers[m].eraser_index = k;
283*0d6140beSAndroid Build Coastguard Worker 		sorted_erasers[m].region_index = n;
284*0d6140beSAndroid Build Coastguard Worker 		j++;
285*0d6140beSAndroid Build Coastguard Worker         }
286*0d6140beSAndroid Build Coastguard Worker 
287*0d6140beSAndroid Build Coastguard Worker 	if (j) {
288*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("%s: found %zd valid erasers\n", __func__, j);
289*0d6140beSAndroid Build Coastguard Worker 		return j;
290*0d6140beSAndroid Build Coastguard Worker 	}
291*0d6140beSAndroid Build Coastguard Worker 
292*0d6140beSAndroid Build Coastguard Worker 	if (!fallback.max_total) {
293*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("No erasers found for this chip (%s:%s)!\n",
294*0d6140beSAndroid Build Coastguard Worker 			 chip.vendor, chip.name);
295*0d6140beSAndroid Build Coastguard Worker 		exit(1);
296*0d6140beSAndroid Build Coastguard Worker 	}
297*0d6140beSAndroid Build Coastguard Worker 
298*0d6140beSAndroid Build Coastguard Worker 	sorted_erasers[0].eraser_index = fallback.alt_function;
299*0d6140beSAndroid Build Coastguard Worker 	sorted_erasers[0].region_index = fallback.alt_region;
300*0d6140beSAndroid Build Coastguard Worker 	msg_pwarn("%s: using fallback eraser: "
301*0d6140beSAndroid Build Coastguard Worker 		  "region %d, function %d total %#x vs %#zx\n",
302*0d6140beSAndroid Build Coastguard Worker 		  __func__, fallback.alt_region, fallback.alt_function,
303*0d6140beSAndroid Build Coastguard Worker 		  fallback.max_total, erase_size);
304*0d6140beSAndroid Build Coastguard Worker 
305*0d6140beSAndroid Build Coastguard Worker 	return 1;
306*0d6140beSAndroid Build Coastguard Worker }
307*0d6140beSAndroid Build Coastguard Worker 
308*0d6140beSAndroid Build Coastguard Worker /*
309*0d6140beSAndroid Build Coastguard Worker  * When it is determined that the larger block will have to be erased because
310*0d6140beSAndroid Build Coastguard Worker  * a large enough number of the blocks of the previous smaller size need to be
311*0d6140beSAndroid Build Coastguard Worker  * erased, all blocks of smaller sizes falling into the range of addresses of
312*0d6140beSAndroid Build Coastguard Worker  * this larger block will not have to be erased/written individually, so they
313*0d6140beSAndroid Build Coastguard Worker  * need to be unmarked for erase/change.
314*0d6140beSAndroid Build Coastguard Worker  *
315*0d6140beSAndroid Build Coastguard Worker  * This function recursively invokes itself to clean all smaller size blocks
316*0d6140beSAndroid Build Coastguard Worker  * which are in the range of the current larger block.
317*0d6140beSAndroid Build Coastguard Worker  *
318*0d6140beSAndroid Build Coastguard Worker  * @upper_level_map  pointer to the element of the range map array where the
319*0d6140beSAndroid Build Coastguard Worker  *                   current block belongs.
320*0d6140beSAndroid Build Coastguard Worker  * @block_index      index of the current block in the map of the blocks of
321*0d6140beSAndroid Build Coastguard Worker  *                   the current range map element.
322*0d6140beSAndroid Build Coastguard Worker  * @i		     index of this range map in the array of range maps,
323*0d6140beSAndroid Build Coastguard Worker  *                   guaranteed to be 1 or above, so that there is always a
324*0d6140beSAndroid Build Coastguard Worker  *                   smaller block size range map at i - 1.
325*0d6140beSAndroid Build Coastguard Worker  */
clear_all_nested(struct range_map * upper_level_map,size_t block_index,unsigned i)326*0d6140beSAndroid Build Coastguard Worker static void clear_all_nested(struct range_map *upper_level_map,
327*0d6140beSAndroid Build Coastguard Worker 			     size_t block_index,
328*0d6140beSAndroid Build Coastguard Worker 			     unsigned i)
329*0d6140beSAndroid Build Coastguard Worker {
330*0d6140beSAndroid Build Coastguard Worker 	struct range_map *this_level_map = upper_level_map - 1;
331*0d6140beSAndroid Build Coastguard Worker 	size_t range_start;
332*0d6140beSAndroid Build Coastguard Worker 	size_t range_end;
333*0d6140beSAndroid Build Coastguard Worker 	size_t j;
334*0d6140beSAndroid Build Coastguard Worker 
335*0d6140beSAndroid Build Coastguard Worker 	range_start = upper_level_map->block_size * block_index;
336*0d6140beSAndroid Build Coastguard Worker 	range_end = range_start + upper_level_map->block_size;
337*0d6140beSAndroid Build Coastguard Worker 
338*0d6140beSAndroid Build Coastguard Worker 	for (j = range_start / this_level_map->block_size;
339*0d6140beSAndroid Build Coastguard Worker 	     j < range_end / this_level_map->block_size;
340*0d6140beSAndroid Build Coastguard Worker 	     j++) {
341*0d6140beSAndroid Build Coastguard Worker 		this_level_map->block_map[j].need_change = 0;
342*0d6140beSAndroid Build Coastguard Worker 		this_level_map->block_map[j].need_erase = 0;
343*0d6140beSAndroid Build Coastguard Worker 		if (i > 1)
344*0d6140beSAndroid Build Coastguard Worker 			clear_all_nested(this_level_map, j, i - 1);
345*0d6140beSAndroid Build Coastguard Worker 	}
346*0d6140beSAndroid Build Coastguard Worker }
347*0d6140beSAndroid Build Coastguard Worker 
348*0d6140beSAndroid Build Coastguard Worker /*
349*0d6140beSAndroid Build Coastguard Worker  * Once all lowest range size blocks which need to be erased have been
350*0d6140beSAndroid Build Coastguard Worker  * identified, we need to see if there are so many of them that they maybe be
351*0d6140beSAndroid Build Coastguard Worker  * folded into larger size blocks, so that a single larger erase operation is
352*0d6140beSAndroid Build Coastguard Worker  * required instead of many smaller ones.
353*0d6140beSAndroid Build Coastguard Worker  *
354*0d6140beSAndroid Build Coastguard Worker  * @maps       pointer to the array of range_map structures, sorted by block
355*0d6140beSAndroid Build Coastguard Worker  *	       size from lower to higher, only the lower size bock map has
356*0d6140beSAndroid Build Coastguard Worker  *	       been filled up.
357*0d6140beSAndroid Build Coastguard Worker  * @num_maps   number of elements in the maps array.
358*0d6140beSAndroid Build Coastguard Worker  * @chip_size  size of the flash chip, in bytes.
359*0d6140beSAndroid Build Coastguard Worker  */
fold_range_maps(struct range_map * maps,size_t num_maps,size_t chip_size)360*0d6140beSAndroid Build Coastguard Worker static void fold_range_maps(struct range_map *maps,
361*0d6140beSAndroid Build Coastguard Worker 			    size_t num_maps,
362*0d6140beSAndroid Build Coastguard Worker 			    size_t chip_size)
363*0d6140beSAndroid Build Coastguard Worker {
364*0d6140beSAndroid Build Coastguard Worker 	size_t block_index;
365*0d6140beSAndroid Build Coastguard Worker 	unsigned i;
366*0d6140beSAndroid Build Coastguard Worker 	struct range_map *map;
367*0d6140beSAndroid Build Coastguard Worker 
368*0d6140beSAndroid Build Coastguard Worker 	/*
369*0d6140beSAndroid Build Coastguard Worker 	 * First go from bottom to top, marking higher size blocks which need
370*0d6140beSAndroid Build Coastguard Worker 	 * to be erased based on the count of lower size blocks marked for
371*0d6140beSAndroid Build Coastguard Worker 	 * erasing which fall into the range of addresses covered by the
372*0d6140beSAndroid Build Coastguard Worker 	 * larger size block.
373*0d6140beSAndroid Build Coastguard Worker 	 *
374*0d6140beSAndroid Build Coastguard Worker 	 * Starting from the second element of the array, as the first element
375*0d6140beSAndroid Build Coastguard Worker 	 * is the only one filled up so far.
376*0d6140beSAndroid Build Coastguard Worker 	 */
377*0d6140beSAndroid Build Coastguard Worker 	for (i = 1; i < num_maps; i++) {
378*0d6140beSAndroid Build Coastguard Worker 		int block_mult;
379*0d6140beSAndroid Build Coastguard Worker 
380*0d6140beSAndroid Build Coastguard Worker 		map = maps + i;
381*0d6140beSAndroid Build Coastguard Worker 
382*0d6140beSAndroid Build Coastguard Worker 		/* How many lower size blocks fit into this block. */
383*0d6140beSAndroid Build Coastguard Worker 		block_mult = map->block_size / map[-1].block_size;
384*0d6140beSAndroid Build Coastguard Worker 
385*0d6140beSAndroid Build Coastguard Worker 		for (block_index = 0;
386*0d6140beSAndroid Build Coastguard Worker 		     block_index < (chip_size/map->block_size);
387*0d6140beSAndroid Build Coastguard Worker 		     block_index++) {
388*0d6140beSAndroid Build Coastguard Worker 			int lower_start;
389*0d6140beSAndroid Build Coastguard Worker 			int lower_end;
390*0d6140beSAndroid Build Coastguard Worker 			int lower_index;
391*0d6140beSAndroid Build Coastguard Worker 			int erase_marked_blocks;
392*0d6140beSAndroid Build Coastguard Worker 			int change_marked_blocks;
393*0d6140beSAndroid Build Coastguard Worker 
394*0d6140beSAndroid Build Coastguard Worker 			lower_start = block_index * block_mult;
395*0d6140beSAndroid Build Coastguard Worker 			lower_end = lower_start + block_mult;
396*0d6140beSAndroid Build Coastguard Worker 			erase_marked_blocks = 0;
397*0d6140beSAndroid Build Coastguard Worker 			change_marked_blocks = 0;
398*0d6140beSAndroid Build Coastguard Worker 
399*0d6140beSAndroid Build Coastguard Worker 			for (lower_index = lower_start;
400*0d6140beSAndroid Build Coastguard Worker 			     lower_index < lower_end;
401*0d6140beSAndroid Build Coastguard Worker 			     lower_index++) {
402*0d6140beSAndroid Build Coastguard Worker 
403*0d6140beSAndroid Build Coastguard Worker 				if (map[-1].block_map[lower_index].need_erase)
404*0d6140beSAndroid Build Coastguard Worker 					erase_marked_blocks++;
405*0d6140beSAndroid Build Coastguard Worker 
406*0d6140beSAndroid Build Coastguard Worker 				if (map[-1].block_map[lower_index].need_change)
407*0d6140beSAndroid Build Coastguard Worker 					change_marked_blocks++;
408*0d6140beSAndroid Build Coastguard Worker 			}
409*0d6140beSAndroid Build Coastguard Worker 
410*0d6140beSAndroid Build Coastguard Worker 			/*
411*0d6140beSAndroid Build Coastguard Worker 			 * Mark larger block for erasing; if any of the
412*0d6140beSAndroid Build Coastguard Worker 			 * smaller size blocks was marked as 'need_change',
413*0d6140beSAndroid Build Coastguard Worker 			 * mark the larger size block as well.
414*0d6140beSAndroid Build Coastguard Worker 			 */
415*0d6140beSAndroid Build Coastguard Worker 			if (erase_marked_blocks > map[-1].limit) {
416*0d6140beSAndroid Build Coastguard Worker 				map->block_map[block_index].need_erase = 1;
417*0d6140beSAndroid Build Coastguard Worker 				map->block_map[block_index].need_change =
418*0d6140beSAndroid Build Coastguard Worker 					change_marked_blocks ? 1 : 0;
419*0d6140beSAndroid Build Coastguard Worker 			}
420*0d6140beSAndroid Build Coastguard Worker 		}
421*0d6140beSAndroid Build Coastguard Worker 	}
422*0d6140beSAndroid Build Coastguard Worker 
423*0d6140beSAndroid Build Coastguard Worker 	/*
424*0d6140beSAndroid Build Coastguard Worker 	 * Now let's go larger to smaller block sizes, to make sure that all
425*0d6140beSAndroid Build Coastguard Worker 	 * nested blocks of a bigger block marked for erasing are not marked
426*0d6140beSAndroid Build Coastguard Worker 	 * for erasing any more; erasing the encompassing block will sure
427*0d6140beSAndroid Build Coastguard Worker 	 * erase all nested blocks of all smaller sizes.
428*0d6140beSAndroid Build Coastguard Worker 	 */
429*0d6140beSAndroid Build Coastguard Worker 	for (i = num_maps - 1; i > 0; i--) {
430*0d6140beSAndroid Build Coastguard Worker 		map = maps + i;
431*0d6140beSAndroid Build Coastguard Worker 
432*0d6140beSAndroid Build Coastguard Worker 		for (block_index = 0;
433*0d6140beSAndroid Build Coastguard Worker 		     block_index < (chip_size/map->block_size);
434*0d6140beSAndroid Build Coastguard Worker 		     block_index++) {
435*0d6140beSAndroid Build Coastguard Worker 			if (!map->block_map[block_index].need_erase)
436*0d6140beSAndroid Build Coastguard Worker 				continue;
437*0d6140beSAndroid Build Coastguard Worker 
438*0d6140beSAndroid Build Coastguard Worker 			clear_all_nested(map, block_index, i);
439*0d6140beSAndroid Build Coastguard Worker 		}
440*0d6140beSAndroid Build Coastguard Worker 	}
441*0d6140beSAndroid Build Coastguard Worker }
442*0d6140beSAndroid Build Coastguard Worker 
443*0d6140beSAndroid Build Coastguard Worker /*
444*0d6140beSAndroid Build Coastguard Worker  * A function to fill the processing_units array of the action descriptor with
445*0d6140beSAndroid Build Coastguard Worker  * a set of processing units, which describe flash chip blocks which need to
446*0d6140beSAndroid Build Coastguard Worker  * be erased/programmed to to accomplish the action requested by user when
447*0d6140beSAndroid Build Coastguard Worker  * invoking flashrom.
448*0d6140beSAndroid Build Coastguard Worker  *
449*0d6140beSAndroid Build Coastguard Worker  * This set of processing units is determined based on comparing old and new
450*0d6140beSAndroid Build Coastguard Worker  * flashrom contents.
451*0d6140beSAndroid Build Coastguard Worker  *
452*0d6140beSAndroid Build Coastguard Worker  * First, blocks which are required to be erased and/or written are identified
453*0d6140beSAndroid Build Coastguard Worker  * at the finest block size granularity.
454*0d6140beSAndroid Build Coastguard Worker  *
455*0d6140beSAndroid Build Coastguard Worker  * Then the distribution of those blocks is analyzed, and if enough of smaller
456*0d6140beSAndroid Build Coastguard Worker  * blocks in a single larger block address range need to be erased, the larger
457*0d6140beSAndroid Build Coastguard Worker  * block is marked for erasing.
458*0d6140beSAndroid Build Coastguard Worker  *
459*0d6140beSAndroid Build Coastguard Worker  * This same process is applied again to increasingly larger block sizes until
460*0d6140beSAndroid Build Coastguard Worker  * the largest granularity blocks are marked as appropriate.
461*0d6140beSAndroid Build Coastguard Worker  *
462*0d6140beSAndroid Build Coastguard Worker  * After this the range map array is scanned from larger block sizes to
463*0d6140beSAndroid Build Coastguard Worker  * smaller; each time when a larger block marked for erasing is detected, all
464*0d6140beSAndroid Build Coastguard Worker  * smaller size blocks in the same address range are unmarked for erasing.
465*0d6140beSAndroid Build Coastguard Worker  *
466*0d6140beSAndroid Build Coastguard Worker  * In the end only blocks which need to be modified remain marked, and at the
467*0d6140beSAndroid Build Coastguard Worker  * finest possible granularity. The list of these blocks is added to the
468*0d6140beSAndroid Build Coastguard Worker  * 'processing_units' array of the descriptor and becomes the list of actions
469*0d6140beSAndroid Build Coastguard Worker  * to be take to program the flash chip.
470*0d6140beSAndroid Build Coastguard Worker  *
471*0d6140beSAndroid Build Coastguard Worker  * @descriptor		descriptor structure to fill, allocated by the caller.
472*0d6140beSAndroid Build Coastguard Worker  * @sorted_erasers      pointer to an array of eraser descriptors, sorted by
473*0d6140beSAndroid Build Coastguard Worker  *			block size.
474*0d6140beSAndroid Build Coastguard Worker  * @chip_erasers	pointer to the array of erasers from this flash
475*0d6140beSAndroid Build Coastguard Worker  * 			chip's descriptor.
476*0d6140beSAndroid Build Coastguard Worker  * @chip_size		size of this chip in bytes
477*0d6140beSAndroid Build Coastguard Worker  * @num_sorted_erasers  size of the sorted_erasers array
478*0d6140beSAndroid Build Coastguard Worker  * @erased_value	value contained in all bytes of the erased flash
479*0d6140beSAndroid Build Coastguard Worker  */
fill_action_descriptor(struct action_descriptor * descriptor,struct eraser * sorted_erasers,struct block_eraser * chip_erasers,size_t chip_size,size_t num_sorted_erasers,unsigned erased_value)480*0d6140beSAndroid Build Coastguard Worker static void fill_action_descriptor(struct action_descriptor *descriptor,
481*0d6140beSAndroid Build Coastguard Worker 				   struct eraser *sorted_erasers,
482*0d6140beSAndroid Build Coastguard Worker 				   struct block_eraser* chip_erasers,
483*0d6140beSAndroid Build Coastguard Worker 				   size_t chip_size,
484*0d6140beSAndroid Build Coastguard Worker 				   size_t num_sorted_erasers,
485*0d6140beSAndroid Build Coastguard Worker 				   unsigned erased_value)
486*0d6140beSAndroid Build Coastguard Worker {
487*0d6140beSAndroid Build Coastguard Worker 	const uint8_t *newc;
488*0d6140beSAndroid Build Coastguard Worker 	const uint8_t *oldc;
489*0d6140beSAndroid Build Coastguard Worker 	int consecutive_blocks;
490*0d6140beSAndroid Build Coastguard Worker 	size_t block_size;
491*0d6140beSAndroid Build Coastguard Worker 	struct b_map *block_map;
492*0d6140beSAndroid Build Coastguard Worker 	struct range_map range_maps[num_sorted_erasers];
493*0d6140beSAndroid Build Coastguard Worker 	unsigned i;
494*0d6140beSAndroid Build Coastguard Worker 	unsigned pu_index;
495*0d6140beSAndroid Build Coastguard Worker 
496*0d6140beSAndroid Build Coastguard Worker 	/*
497*0d6140beSAndroid Build Coastguard Worker 	 * This array has enough room to hold helper structures, one for each
498*0d6140beSAndroid Build Coastguard Worker 	 * available block size.
499*0d6140beSAndroid Build Coastguard Worker 	 */
500*0d6140beSAndroid Build Coastguard Worker 	memset(range_maps, 0, sizeof(range_maps));
501*0d6140beSAndroid Build Coastguard Worker 
502*0d6140beSAndroid Build Coastguard Worker 	/*
503*0d6140beSAndroid Build Coastguard Worker 	 * Initialize range_maps array: allocate space for block_map arrays on
504*0d6140beSAndroid Build Coastguard Worker 	 * every entry (block maps are used to keep track of blocks which need
505*0d6140beSAndroid Build Coastguard Worker 	 * to be erased/written) and calculate the limit where smaller blocks
506*0d6140beSAndroid Build Coastguard Worker 	 * should be replaced by the next larger size block.
507*0d6140beSAndroid Build Coastguard Worker 	 */
508*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < num_sorted_erasers; i++) {
509*0d6140beSAndroid Build Coastguard Worker 		size_t larger_block_size;
510*0d6140beSAndroid Build Coastguard Worker 		size_t map_size;
511*0d6140beSAndroid Build Coastguard Worker 		size_t num_blocks;
512*0d6140beSAndroid Build Coastguard Worker 		unsigned function;
513*0d6140beSAndroid Build Coastguard Worker 		unsigned region;
514*0d6140beSAndroid Build Coastguard Worker 
515*0d6140beSAndroid Build Coastguard Worker 		function = sorted_erasers[i].eraser_index;
516*0d6140beSAndroid Build Coastguard Worker 		region  = sorted_erasers[i].region_index;
517*0d6140beSAndroid Build Coastguard Worker 		block_size =  chip_erasers[function].eraseblocks[region].size;
518*0d6140beSAndroid Build Coastguard Worker 
519*0d6140beSAndroid Build Coastguard Worker 		range_maps[i].block_size = block_size;
520*0d6140beSAndroid Build Coastguard Worker 
521*0d6140beSAndroid Build Coastguard Worker 		/*
522*0d6140beSAndroid Build Coastguard Worker 		 * Allocate room for the map where blocks which require
523*0d6140beSAndroid Build Coastguard Worker 		 * writing/erasing will be marked.
524*0d6140beSAndroid Build Coastguard Worker 		 */
525*0d6140beSAndroid Build Coastguard Worker 		num_blocks = chip_size/block_size;
526*0d6140beSAndroid Build Coastguard Worker 		map_size = num_blocks * sizeof(struct b_map);
527*0d6140beSAndroid Build Coastguard Worker 		range_maps[i].block_map = malloc(map_size);
528*0d6140beSAndroid Build Coastguard Worker 		if (!range_maps[i].block_map) {
529*0d6140beSAndroid Build Coastguard Worker 			msg_cerr("%s: Failed to allocate %zd bytes\n",
530*0d6140beSAndroid Build Coastguard Worker 				 __func__, map_size);
531*0d6140beSAndroid Build Coastguard Worker 			exit(1);
532*0d6140beSAndroid Build Coastguard Worker 		}
533*0d6140beSAndroid Build Coastguard Worker 		memset(range_maps[i].block_map, 0, map_size);
534*0d6140beSAndroid Build Coastguard Worker 
535*0d6140beSAndroid Build Coastguard Worker 		/*
536*0d6140beSAndroid Build Coastguard Worker 		 * Limit is calculated for all block sizes but the largest
537*0d6140beSAndroid Build Coastguard Worker 		 * one, because there is no way to further consolidate the
538*0d6140beSAndroid Build Coastguard Worker 		 * largest blocks.
539*0d6140beSAndroid Build Coastguard Worker 		 */
540*0d6140beSAndroid Build Coastguard Worker 		if (i < (num_sorted_erasers - 1)) {
541*0d6140beSAndroid Build Coastguard Worker 			function = sorted_erasers[i + 1].eraser_index;
542*0d6140beSAndroid Build Coastguard Worker 			region  = sorted_erasers[i + 1].region_index;
543*0d6140beSAndroid Build Coastguard Worker 			larger_block_size = chip_erasers
544*0d6140beSAndroid Build Coastguard Worker 				[function].eraseblocks[region].size;
545*0d6140beSAndroid Build Coastguard Worker 
546*0d6140beSAndroid Build Coastguard Worker 			/*
547*0d6140beSAndroid Build Coastguard Worker 			 * How many of the lower size blocks need to be have
548*0d6140beSAndroid Build Coastguard Worker 			 * to be erased before it is worth moving to the
549*0d6140beSAndroid Build Coastguard Worker 			 * larger size.
550*0d6140beSAndroid Build Coastguard Worker 			 *
551*0d6140beSAndroid Build Coastguard Worker 			 * The admittedly arbitrary rule of thumb here is if
552*0d6140beSAndroid Build Coastguard Worker 			 * 70% or more of the lower size blocks need to be
553*0d6140beSAndroid Build Coastguard Worker 			 * erased, forget the lower size blocks and move to
554*0d6140beSAndroid Build Coastguard Worker 			 * the higher size one.
555*0d6140beSAndroid Build Coastguard Worker 			 */
556*0d6140beSAndroid Build Coastguard Worker 			range_maps[i].limit = ((larger_block_size /
557*0d6140beSAndroid Build Coastguard Worker 						block_size) * 7) / 10;
558*0d6140beSAndroid Build Coastguard Worker 		}
559*0d6140beSAndroid Build Coastguard Worker 	}
560*0d6140beSAndroid Build Coastguard Worker 
561*0d6140beSAndroid Build Coastguard Worker 	/* Cache pointers to 'before' and 'after' contents. */
562*0d6140beSAndroid Build Coastguard Worker 	oldc = descriptor->oldcontents;
563*0d6140beSAndroid Build Coastguard Worker 	newc = descriptor->newcontents;
564*0d6140beSAndroid Build Coastguard Worker 
565*0d6140beSAndroid Build Coastguard Worker 	/* Now, let's fill up the map for the smallest bock size. */
566*0d6140beSAndroid Build Coastguard Worker 	block_size = range_maps[0].block_size;
567*0d6140beSAndroid Build Coastguard Worker 	block_map = range_maps[0].block_map;
568*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < chip_size; i++) {
569*0d6140beSAndroid Build Coastguard Worker 		int block_index;
570*0d6140beSAndroid Build Coastguard Worker 
571*0d6140beSAndroid Build Coastguard Worker 		if (oldc[i] == newc[i])
572*0d6140beSAndroid Build Coastguard Worker 			continue;
573*0d6140beSAndroid Build Coastguard Worker 
574*0d6140beSAndroid Build Coastguard Worker 		block_index = i/block_size;
575*0d6140beSAndroid Build Coastguard Worker 
576*0d6140beSAndroid Build Coastguard Worker 		if (oldc[i] != erased_value)
577*0d6140beSAndroid Build Coastguard Worker 			block_map[block_index].need_erase = 1;
578*0d6140beSAndroid Build Coastguard Worker 
579*0d6140beSAndroid Build Coastguard Worker 		if (newc[i] != erased_value)
580*0d6140beSAndroid Build Coastguard Worker 			block_map[block_index].need_change = 1;
581*0d6140beSAndroid Build Coastguard Worker 
582*0d6140beSAndroid Build Coastguard Worker 		if (block_map[block_index].need_erase &&
583*0d6140beSAndroid Build Coastguard Worker 		    block_map[block_index].need_change) {
584*0d6140beSAndroid Build Coastguard Worker 			/* Can move to the next block. */
585*0d6140beSAndroid Build Coastguard Worker 			i += range_maps[0].block_size;
586*0d6140beSAndroid Build Coastguard Worker 			i &= ~(range_maps[0].block_size - 1);
587*0d6140beSAndroid Build Coastguard Worker 			i--; /* adjust for increment in the for loop */
588*0d6140beSAndroid Build Coastguard Worker 		}
589*0d6140beSAndroid Build Coastguard Worker 	}
590*0d6140beSAndroid Build Coastguard Worker 
591*0d6140beSAndroid Build Coastguard Worker 	/* Now let's see what can be folded into larger blocks. */
592*0d6140beSAndroid Build Coastguard Worker 	fold_range_maps(range_maps, num_sorted_erasers, chip_size);
593*0d6140beSAndroid Build Coastguard Worker 
594*0d6140beSAndroid Build Coastguard Worker 	/* Finally we can fill the action descriptor. */
595*0d6140beSAndroid Build Coastguard Worker 	consecutive_blocks = 0;
596*0d6140beSAndroid Build Coastguard Worker 	pu_index = 0;  /* Number of initialized processing units. */
597*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < num_sorted_erasers; i++) {
598*0d6140beSAndroid Build Coastguard Worker 		size_t j;
599*0d6140beSAndroid Build Coastguard Worker 		struct processing_unit *pu;
600*0d6140beSAndroid Build Coastguard Worker 		size_t map_size = chip_size/range_maps[i].block_size;
601*0d6140beSAndroid Build Coastguard Worker 
602*0d6140beSAndroid Build Coastguard Worker 		for (j = 0; j < map_size; j++) {
603*0d6140beSAndroid Build Coastguard Worker 
604*0d6140beSAndroid Build Coastguard Worker 			block_map = range_maps[i].block_map + j;
605*0d6140beSAndroid Build Coastguard Worker 
606*0d6140beSAndroid Build Coastguard Worker 			if (block_map->need_erase || block_map->need_change) {
607*0d6140beSAndroid Build Coastguard Worker 				consecutive_blocks++;
608*0d6140beSAndroid Build Coastguard Worker 				continue;
609*0d6140beSAndroid Build Coastguard Worker 			}
610*0d6140beSAndroid Build Coastguard Worker 
611*0d6140beSAndroid Build Coastguard Worker 			if (!consecutive_blocks)
612*0d6140beSAndroid Build Coastguard Worker 				continue;
613*0d6140beSAndroid Build Coastguard Worker 
614*0d6140beSAndroid Build Coastguard Worker 			/* Add programming/erasing uint. */
615*0d6140beSAndroid Build Coastguard Worker 			pu = descriptor->processing_units + pu_index++;
616*0d6140beSAndroid Build Coastguard Worker 
617*0d6140beSAndroid Build Coastguard Worker 			pu->block_size = range_maps[i].block_size;
618*0d6140beSAndroid Build Coastguard Worker 			pu->offset = (j - consecutive_blocks) * pu->block_size;
619*0d6140beSAndroid Build Coastguard Worker 			pu->num_blocks = consecutive_blocks;
620*0d6140beSAndroid Build Coastguard Worker 			pu->block_eraser_index = sorted_erasers[i].eraser_index;
621*0d6140beSAndroid Build Coastguard Worker 			pu->block_region_index = sorted_erasers[i].region_index;
622*0d6140beSAndroid Build Coastguard Worker 
623*0d6140beSAndroid Build Coastguard Worker 			consecutive_blocks = 0;
624*0d6140beSAndroid Build Coastguard Worker 		}
625*0d6140beSAndroid Build Coastguard Worker 
626*0d6140beSAndroid Build Coastguard Worker 		free(range_maps[i].block_map);
627*0d6140beSAndroid Build Coastguard Worker 
628*0d6140beSAndroid Build Coastguard Worker 		if (!consecutive_blocks)
629*0d6140beSAndroid Build Coastguard Worker 			continue;
630*0d6140beSAndroid Build Coastguard Worker 
631*0d6140beSAndroid Build Coastguard Worker 		/*
632*0d6140beSAndroid Build Coastguard Worker 		 * Add last programming/erasing unit for current block
633*0d6140beSAndroid Build Coastguard Worker 		 * size.
634*0d6140beSAndroid Build Coastguard Worker 		 */
635*0d6140beSAndroid Build Coastguard Worker 		pu = descriptor->processing_units + pu_index++;
636*0d6140beSAndroid Build Coastguard Worker 
637*0d6140beSAndroid Build Coastguard Worker 		pu->block_size = range_maps[i].block_size;
638*0d6140beSAndroid Build Coastguard Worker 		pu->offset = (j - consecutive_blocks) * pu->block_size;
639*0d6140beSAndroid Build Coastguard Worker 		pu->num_blocks = consecutive_blocks;
640*0d6140beSAndroid Build Coastguard Worker 		pu->block_eraser_index = sorted_erasers[i].eraser_index;
641*0d6140beSAndroid Build Coastguard Worker 		pu->block_region_index = sorted_erasers[i].region_index;
642*0d6140beSAndroid Build Coastguard Worker 		consecutive_blocks = 0;
643*0d6140beSAndroid Build Coastguard Worker 	}
644*0d6140beSAndroid Build Coastguard Worker 
645*0d6140beSAndroid Build Coastguard Worker 	descriptor->processing_units[pu_index].num_blocks = 0;
646*0d6140beSAndroid Build Coastguard Worker }
647*0d6140beSAndroid Build Coastguard Worker 
is_dry_run(void)648*0d6140beSAndroid Build Coastguard Worker bool is_dry_run(void)
649*0d6140beSAndroid Build Coastguard Worker {
650*0d6140beSAndroid Build Coastguard Worker 	return dry_run;
651*0d6140beSAndroid Build Coastguard Worker }
652*0d6140beSAndroid Build Coastguard Worker 
prepare_action_descriptor(struct flashctx * flash,void * oldcontents,void * newcontents)653*0d6140beSAndroid Build Coastguard Worker struct action_descriptor *prepare_action_descriptor(struct flashctx *flash,
654*0d6140beSAndroid Build Coastguard Worker 						    void *oldcontents,
655*0d6140beSAndroid Build Coastguard Worker 						    void *newcontents)
656*0d6140beSAndroid Build Coastguard Worker {
657*0d6140beSAndroid Build Coastguard Worker 	struct eraser sorted_erasers[NUM_ERASEFUNCTIONS];
658*0d6140beSAndroid Build Coastguard Worker 	size_t i;
659*0d6140beSAndroid Build Coastguard Worker 	size_t num_erasers;
660*0d6140beSAndroid Build Coastguard Worker 	int max_units;
661*0d6140beSAndroid Build Coastguard Worker 	size_t block_size = 0;
662*0d6140beSAndroid Build Coastguard Worker 	struct action_descriptor *descriptor;
663*0d6140beSAndroid Build Coastguard Worker 	size_t chip_size = flash->chip->total_size * 1024;
664*0d6140beSAndroid Build Coastguard Worker 
665*0d6140beSAndroid Build Coastguard Worker 	/*
666*0d6140beSAndroid Build Coastguard Worker 	 * Find the maximum size of the area which might have to be erased,
667*0d6140beSAndroid Build Coastguard Worker 	 * this is needed to ensure that the picked erase function can go all
668*0d6140beSAndroid Build Coastguard Worker 	 * the way to the requred offset, as some of the erase functions
669*0d6140beSAndroid Build Coastguard Worker 	 * operate only on part of the chip starting at offset zero.
670*0d6140beSAndroid Build Coastguard Worker 	 *
671*0d6140beSAndroid Build Coastguard Worker 	 * Not an efficient way to do it, but this is acceptable on the host.
672*0d6140beSAndroid Build Coastguard Worker 	 *
673*0d6140beSAndroid Build Coastguard Worker 	 * Look for the largest offset where the difference is, this is the
674*0d6140beSAndroid Build Coastguard Worker 	 * highest offset which might need to be erased.
675*0d6140beSAndroid Build Coastguard Worker 	 */
676*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < chip_size; i++)
677*0d6140beSAndroid Build Coastguard Worker 		if (((uint8_t *)newcontents)[i] !=
678*0d6140beSAndroid Build Coastguard Worker 		    ((uint8_t *)oldcontents)[i])
679*0d6140beSAndroid Build Coastguard Worker 			block_size = i + 1;
680*0d6140beSAndroid Build Coastguard Worker 
681*0d6140beSAndroid Build Coastguard Worker 	num_erasers = fill_sorted_erasers(flash, block_size, sorted_erasers);
682*0d6140beSAndroid Build Coastguard Worker 
683*0d6140beSAndroid Build Coastguard Worker 	/*
684*0d6140beSAndroid Build Coastguard Worker 	 * Let's allocate enough memory for the worst case action descriptor
685*0d6140beSAndroid Build Coastguard Worker 	 * size, when we need to program half the chip using the smallest block
686*0d6140beSAndroid Build Coastguard Worker 	 * size.
687*0d6140beSAndroid Build Coastguard Worker 	 */
688*0d6140beSAndroid Build Coastguard Worker 	block_size = flash->chip->block_erasers
689*0d6140beSAndroid Build Coastguard Worker 		[sorted_erasers[0].eraser_index].eraseblocks
690*0d6140beSAndroid Build Coastguard Worker 		[sorted_erasers[0].region_index].size;
691*0d6140beSAndroid Build Coastguard Worker 	max_units = max( chip_size / (2 * block_size), 1 ) + 1;
692*0d6140beSAndroid Build Coastguard Worker 	descriptor = malloc(sizeof(struct action_descriptor) +
693*0d6140beSAndroid Build Coastguard Worker 			    sizeof(struct processing_unit) * max_units);
694*0d6140beSAndroid Build Coastguard Worker 	if (!descriptor) {
695*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("Failed to allocate room for %d processing units!\n",
696*0d6140beSAndroid Build Coastguard Worker 			 max_units);
697*0d6140beSAndroid Build Coastguard Worker 		exit(1);
698*0d6140beSAndroid Build Coastguard Worker 	}
699*0d6140beSAndroid Build Coastguard Worker 
700*0d6140beSAndroid Build Coastguard Worker 	descriptor->newcontents = newcontents;
701*0d6140beSAndroid Build Coastguard Worker 	descriptor->oldcontents = oldcontents;
702*0d6140beSAndroid Build Coastguard Worker 
703*0d6140beSAndroid Build Coastguard Worker 	fill_action_descriptor(descriptor, sorted_erasers,
704*0d6140beSAndroid Build Coastguard Worker 			       flash->chip->block_erasers, chip_size,
705*0d6140beSAndroid Build Coastguard Worker 			       num_erasers, ERASED_VALUE(flash));
706*0d6140beSAndroid Build Coastguard Worker 
707*0d6140beSAndroid Build Coastguard Worker 	dump_descriptor(descriptor);
708*0d6140beSAndroid Build Coastguard Worker 
709*0d6140beSAndroid Build Coastguard Worker 	return descriptor;
710*0d6140beSAndroid Build Coastguard Worker }
711