b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From e89db675171a7a12f19b6ec0089a9cc62807cdf1 Mon Sep 17 00:00:00 2001 |
| 2 | From: Camelia Groza <camelia.groza@nxp.com> |
| 3 | Date: Tue, 29 Oct 2019 16:34:08 +0200 |
| 4 | Subject: [PATCH] sdk_dpaa: ls1043a errata: update and optimize the |
| 5 | restrictions |
| 6 | |
| 7 | An skb is in no danger of triggering the errata under the following |
| 8 | conditions: |
| 9 | - the paged data doesn't cross a 4K page boundary OR the linear data |
| 10 | is aligned to 256 bytes when crossing a 4K page boundary |
| 11 | - the linear and the paged data are 16 byte aligned |
| 12 | - the paged data is a multiple of 16 bytes in size |
| 13 | |
| 14 | Optimize the detection for each skb that might trigger the errata. Parse |
| 15 | the skb twice, at most, and realign it only once. |
| 16 | |
| 17 | Signed-off-by: Camelia Groza <camelia.groza@nxp.com> |
| 18 | --- |
| 19 | drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h | 2 +- |
| 20 | .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 147 +++++++++++++++------ |
| 21 | 2 files changed, 111 insertions(+), 38 deletions(-) |
| 22 | |
| 23 | --- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |
| 24 | +++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h |
| 25 | @@ -662,7 +662,7 @@ static inline void _dpa_bp_free_pf(void |
| 26 | #ifndef CONFIG_PPC |
| 27 | extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */ |
| 28 | #define NONREC_MARK 0x01 |
| 29 | -#define HAS_DMA_ISSUE(start, size) \ |
| 30 | +#define CROSS_4K(start, size) \ |
| 31 | (((uintptr_t)(start) + (size)) > \ |
| 32 | (((uintptr_t)(start) + 0x1000) & ~0xFFF)) |
| 33 | /* The headroom needs to accommodate our private data (64 bytes) but |
| 34 | --- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c |
| 35 | +++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c |
| 36 | @@ -771,32 +771,73 @@ int __hot skb_to_contig_fd(struct dpa_pr |
| 37 | EXPORT_SYMBOL(skb_to_contig_fd); |
| 38 | |
| 39 | #ifndef CONFIG_PPC |
| 40 | -/* Verify the conditions that trigger the A010022 errata: data unaligned to |
| 41 | - * 16 bytes, 4K memory address crossings and S/G fragments. |
| 42 | +/* Verify the conditions that trigger the A010022 errata: |
| 43 | + * - 4K memory address boundary crossings when the data/SG fragments aren't |
| 44 | + * aligned to 256 bytes |
| 45 | + * - data and SG fragments that aren't aligned to 16 bytes |
| 46 | + * - SG fragments that aren't mod 16 bytes in size (except for the last |
| 47 | + * fragment) |
| 48 | */ |
| 49 | static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv) |
| 50 | { |
| 51 | - /* Check if the headroom is aligned */ |
| 52 | - if (((uintptr_t)skb->data - priv->tx_headroom) % |
| 53 | - priv->buf_layout[TX].data_align != 0) |
| 54 | - return true; |
| 55 | + skb_frag_t *frag; |
| 56 | + int i, nr_frags; |
| 57 | |
| 58 | - /* Check for paged data in the skb. We do not support S/G fragments */ |
| 59 | - if (skb_is_nonlinear(skb)) |
| 60 | + nr_frags = skb_shinfo(skb)->nr_frags; |
| 61 | + |
| 62 | + /* Check if the linear data is 16 byte aligned */ |
| 63 | + if ((uintptr_t)skb->data % 16) |
| 64 | return true; |
| 65 | |
| 66 | - /* Check if the headroom crosses a boundary */ |
| 67 | - if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb))) |
| 68 | + /* Check if the needed headroom crosses a 4K address boundary without |
| 69 | + * being 256 byte aligned |
| 70 | + */ |
| 71 | + if (CROSS_4K(skb->data - priv->tx_headroom, priv->tx_headroom) && |
| 72 | + (((uintptr_t)skb->data - priv->tx_headroom) % 256)) |
| 73 | return true; |
| 74 | |
| 75 | - /* Check if the non-paged data crosses a boundary */ |
| 76 | - if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb))) |
| 77 | + /* Check if the linear data crosses a 4K address boundary without |
| 78 | + * being 256 byte aligned |
| 79 | + */ |
| 80 | + if (CROSS_4K(skb->data, skb_headlen(skb)) && |
| 81 | + ((uintptr_t)skb->data % 256)) |
| 82 | return true; |
| 83 | |
| 84 | - /* Check if the entire linear skb crosses a boundary */ |
| 85 | - if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb))) |
| 86 | + /* When using Scatter/Gather, the linear data becomes the first |
| 87 | + * fragment in the list and must follow the same restrictions as the |
| 88 | + * other fragments. |
| 89 | + * |
| 90 | + * Check if the linear data is mod 16 bytes in size. |
| 91 | + */ |
| 92 | + if (nr_frags && (skb_headlen(skb) % 16)) |
| 93 | return true; |
| 94 | |
| 95 | + /* Check the SG fragments. They must follow the same rules as the |
| 96 | + * linear data with and additional restriction: they must be multiple |
| 97 | + * of 16 bytes in size to account for the hardware carryover effect. |
| 98 | + */ |
| 99 | + for (i = 0; i < nr_frags; i++) { |
| 100 | + frag = &skb_shinfo(skb)->frags[i]; |
| 101 | + |
| 102 | + /* Check if the fragment is a multiple of 16 bytes in size. |
| 103 | + * The last fragment is exempt from this restriction. |
| 104 | + */ |
| 105 | + if ((i != (nr_frags - 1)) && (skb_frag_size(frag) % 16)) |
| 106 | + return true; |
| 107 | + |
| 108 | + /* Check if the fragment is 16 byte aligned */ |
| 109 | + if (skb_frag_off(frag) % 16) |
| 110 | + return true; |
| 111 | + |
| 112 | + /* Check if the fragment crosses a 4K address boundary. Since |
| 113 | + * the alignment of previous fragments can influence the |
| 114 | + * current fragment, checking for the 256 byte alignment |
| 115 | + * isn't relevant. |
| 116 | + */ |
| 117 | + if (CROSS_4K(skb_frag_off(frag), skb_frag_size(frag))) |
| 118 | + return true; |
| 119 | + } |
| 120 | + |
| 121 | return false; |
| 122 | } |
| 123 | |
| 124 | @@ -1062,10 +1103,24 @@ int __hot dpa_tx_extended(struct sk_buff |
| 125 | struct dpa_percpu_priv_s *percpu_priv; |
| 126 | struct rtnl_link_stats64 *percpu_stats; |
| 127 | int err = 0; |
| 128 | - bool nonlinear; |
| 129 | + bool nonlinear, skb_changed, skb_need_wa; |
| 130 | int *countptr, offset = 0; |
| 131 | struct sk_buff *nskb; |
| 132 | |
| 133 | + /* Flags to help optimize the A010022 errata restriction checks. |
| 134 | + * |
| 135 | + * First flag marks if the skb changed between the first A010022 check |
| 136 | + * and the moment it's converted to an FD. |
| 137 | + * |
| 138 | + * The second flag marks if the skb needs to be realigned in order to |
| 139 | + * avoid the errata. |
| 140 | + * |
| 141 | + * The flags should have minimal impact on platforms not impacted by |
| 142 | + * the errata. |
| 143 | + */ |
| 144 | + skb_changed = false; |
| 145 | + skb_need_wa = false; |
| 146 | + |
| 147 | priv = netdev_priv(net_dev); |
| 148 | /* Non-migratable context, safe to use raw_cpu_ptr */ |
| 149 | percpu_priv = raw_cpu_ptr(priv->percpu_priv); |
| 150 | @@ -1075,13 +1130,8 @@ int __hot dpa_tx_extended(struct sk_buff |
| 151 | clear_fd(&fd); |
| 152 | |
| 153 | #ifndef CONFIG_PPC |
| 154 | - if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) { |
| 155 | - nskb = a010022_realign_skb(skb, priv); |
| 156 | - if (!nskb) |
| 157 | - goto skb_to_fd_failed; |
| 158 | - dev_kfree_skb(skb); |
| 159 | - skb = nskb; |
| 160 | - } |
| 161 | + if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) |
| 162 | + skb_need_wa = true; |
| 163 | #endif |
| 164 | |
| 165 | nonlinear = skb_is_nonlinear(skb); |
| 166 | @@ -1102,8 +1152,8 @@ int __hot dpa_tx_extended(struct sk_buff |
| 167 | * Btw, we're using the first sgt entry to store the linear part of |
| 168 | * the skb, so we're one extra frag short. |
| 169 | */ |
| 170 | - if (nonlinear && |
| 171 | - likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) { |
| 172 | + if (nonlinear && !skb_need_wa && |
| 173 | + likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) { |
| 174 | /* Just create a S/G fd based on the skb */ |
| 175 | err = skb_to_sg_fd(priv, skb, &fd); |
| 176 | percpu_priv->tx_frag_skbuffs++; |
| 177 | @@ -1128,39 +1178,62 @@ int __hot dpa_tx_extended(struct sk_buff |
| 178 | |
| 179 | dev_kfree_skb(skb); |
| 180 | skb = skb_new; |
| 181 | + skb_changed = true; |
| 182 | } |
| 183 | |
| 184 | /* We're going to store the skb backpointer at the beginning |
| 185 | * of the data buffer, so we need a privately owned skb |
| 186 | + * |
| 187 | + * Under the A010022 errata, we are going to have a privately |
| 188 | + * owned skb after realigning the current one, so no point in |
| 189 | + * copying it here in that case. |
| 190 | */ |
| 191 | |
| 192 | /* Code borrowed from skb_unshare(). */ |
| 193 | - if (skb_cloned(skb)) { |
| 194 | + if (skb_cloned(skb) && !skb_need_wa) { |
| 195 | nskb = skb_copy(skb, GFP_ATOMIC); |
| 196 | kfree_skb(skb); |
| 197 | skb = nskb; |
| 198 | -#ifndef CONFIG_PPC |
| 199 | - if (unlikely(dpaa_errata_a010022) && |
| 200 | - a010022_check_skb(skb, priv)) { |
| 201 | - nskb = a010022_realign_skb(skb, priv); |
| 202 | - if (!nskb) |
| 203 | - goto skb_to_fd_failed; |
| 204 | - dev_kfree_skb(skb); |
| 205 | - skb = nskb; |
| 206 | - } |
| 207 | -#endif |
| 208 | + skb_changed = true; |
| 209 | + |
| 210 | /* skb_copy() has now linearized the skbuff. */ |
| 211 | - } else if (unlikely(nonlinear)) { |
| 212 | + } else if (unlikely(nonlinear) && !skb_need_wa) { |
| 213 | /* We are here because the egress skb contains |
| 214 | * more fragments than we support. In this case, |
| 215 | * we have no choice but to linearize it ourselves. |
| 216 | */ |
| 217 | - err = __skb_linearize(skb); |
| 218 | +#ifndef CONFIG_PPC |
| 219 | + /* No point in linearizing the skb now if we are going |
| 220 | + * to realign and linearize it again further down due |
| 221 | + * to the A010022 errata |
| 222 | + */ |
| 223 | + if (unlikely(dpaa_errata_a010022)) |
| 224 | + skb_need_wa = true; |
| 225 | + else |
| 226 | +#endif |
| 227 | + err = __skb_linearize(skb); |
| 228 | } |
| 229 | if (unlikely(!skb || err < 0)) |
| 230 | /* Common out-of-memory error path */ |
| 231 | goto enomem; |
| 232 | |
| 233 | +#ifndef CONFIG_PPC |
| 234 | + /* Verify the skb a second time if it has been updated since |
| 235 | + * the previous check |
| 236 | + */ |
| 237 | + if (unlikely(dpaa_errata_a010022) && skb_changed && |
| 238 | + a010022_check_skb(skb, priv)) |
| 239 | + skb_need_wa = true; |
| 240 | + |
| 241 | + if (unlikely(dpaa_errata_a010022) && skb_need_wa) { |
| 242 | + nskb = a010022_realign_skb(skb, priv); |
| 243 | + if (!nskb) |
| 244 | + goto skb_to_fd_failed; |
| 245 | + dev_kfree_skb(skb); |
| 246 | + skb = nskb; |
| 247 | + } |
| 248 | +#endif |
| 249 | + |
| 250 | err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset); |
| 251 | } |
| 252 | if (unlikely(err < 0)) |