修訂 | 49f3a42edf097fbaca76aef9bfcd98d871b442cb (tree) |
---|---|
時間 | 2022-07-19 20:46:28 |
作者 | Rasmus Villemoes <rasmus.villemoes@prev...> |
Commiter | Heiko Schocher |
i2c: avoid dynamic stack use in dm_i2c_write
The size of the dynamic stack allocation here is bounded by the if()
statement. However, just allocating the maximum size up-front and
doing malloc() if necessary avoids code duplication (the
i2c_setup_offset() until the invocation of ->xfer), and generates much
better (smaller) code:
bloat-o-meter drivers/i2c/i2c-uclass.o.{0,1}
add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-144 (-144)
Function old new delta
dm_i2c_write 552 408 -144
Total: Before=3828, After=3684, chg -3.76%
It also makes static analysis of maximum stack usage (using the .su
files that are automatically generated during build) easier if there
are no lines saying "dynamic".
[This is not entirely equivalent to the existing code; this now uses
the stack for len <= 64 rather than len <= 63, but that seems like a
more natural limit.]
Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Reviewed-by: Heiko Schocher <hs@denx.de>
@@ -168,6 +168,9 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, | ||
168 | 168 | struct udevice *bus = dev_get_parent(dev); |
169 | 169 | struct dm_i2c_ops *ops = i2c_get_ops(bus); |
170 | 170 | struct i2c_msg msg[1]; |
171 | + uint8_t _buf[I2C_MAX_OFFSET_LEN + 64]; | |
172 | + uint8_t *buf = _buf; | |
173 | + int ret; | |
171 | 174 | |
172 | 175 | if (!ops->xfer) |
173 | 176 | return -ENOSYS; |
@@ -192,29 +195,20 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, | ||
192 | 195 | * need to allow space for the offset (up to 4 bytes) and the message |
193 | 196 | * itself. |
194 | 197 | */ |
195 | - if (len < 64) { | |
196 | - uint8_t buf[I2C_MAX_OFFSET_LEN + len]; | |
197 | - | |
198 | - i2c_setup_offset(chip, offset, buf, msg); | |
199 | - msg->len += len; | |
200 | - memcpy(buf + chip->offset_len, buffer, len); | |
201 | - | |
202 | - return ops->xfer(bus, msg, 1); | |
203 | - } else { | |
204 | - uint8_t *buf; | |
205 | - int ret; | |
206 | - | |
198 | + if (len > sizeof(_buf) - I2C_MAX_OFFSET_LEN) { | |
207 | 199 | buf = malloc(I2C_MAX_OFFSET_LEN + len); |
208 | 200 | if (!buf) |
209 | 201 | return -ENOMEM; |
210 | - i2c_setup_offset(chip, offset, buf, msg); | |
211 | - msg->len += len; | |
212 | - memcpy(buf + chip->offset_len, buffer, len); | |
202 | + } | |
213 | 203 | |
214 | - ret = ops->xfer(bus, msg, 1); | |
204 | + i2c_setup_offset(chip, offset, buf, msg); | |
205 | + msg->len += len; | |
206 | + memcpy(buf + chip->offset_len, buffer, len); | |
207 | + | |
208 | + ret = ops->xfer(bus, msg, 1); | |
209 | + if (buf != _buf) | |
215 | 210 | free(buf); |
216 | - return ret; | |
217 | - } | |
211 | + return ret; | |
218 | 212 | } |
219 | 213 | |
220 | 214 | int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) |