diff options
| -rw-r--r-- | drivers/net/usb/cdc_ncm.c | 54 | ||||
| -rw-r--r-- | include/linux/usb/cdc_ncm.h | 3 |
2 files changed, 45 insertions, 12 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 2067743f51ca..d103a1d4fb36 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
| @@ -89,6 +89,8 @@ static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = { | |||
| 89 | CDC_NCM_SIMPLE_STAT(rx_ntbs), | 89 | CDC_NCM_SIMPLE_STAT(rx_ntbs), |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | #define CDC_NCM_LOW_MEM_MAX_CNT 10 | ||
| 93 | |||
| 92 | static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset) | 94 | static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset) |
| 93 | { | 95 | { |
| 94 | switch (sset) { | 96 | switch (sset) { |
| @@ -1055,10 +1057,10 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ | |||
| 1055 | 1057 | ||
| 1056 | /* align new NDP */ | 1058 | /* align new NDP */ |
| 1057 | if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) | 1059 | if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) |
| 1058 | cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); | 1060 | cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size); |
| 1059 | 1061 | ||
| 1060 | /* verify that there is room for the NDP and the datagram (reserve) */ | 1062 | /* verify that there is room for the NDP and the datagram (reserve) */ |
| 1061 | if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) | 1063 | if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size) |
| 1062 | return NULL; | 1064 | return NULL; |
| 1063 | 1065 | ||
| 1064 | /* link to it */ | 1066 | /* link to it */ |
| @@ -1111,13 +1113,41 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) | |||
| 1111 | 1113 | ||
| 1112 | /* allocate a new OUT skb */ | 1114 | /* allocate a new OUT skb */ |
| 1113 | if (!skb_out) { | 1115 | if (!skb_out) { |
| 1114 | skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC); | 1116 | if (ctx->tx_low_mem_val == 0) { |
| 1117 | ctx->tx_curr_size = ctx->tx_max; | ||
| 1118 | skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC); | ||
| 1119 | /* If the memory allocation fails we will wait longer | ||
| 1120 | * each time before attempting another full size | ||
| 1121 | * allocation again to not overload the system | ||
| 1122 | * further. | ||
| 1123 | */ | ||
| 1124 | if (skb_out == NULL) { | ||
| 1125 | ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1, | ||
| 1126 | (unsigned)CDC_NCM_LOW_MEM_MAX_CNT); | ||
| 1127 | ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt; | ||
| 1128 | } | ||
| 1129 | } | ||
| 1115 | if (skb_out == NULL) { | 1130 | if (skb_out == NULL) { |
| 1116 | if (skb != NULL) { | 1131 | /* See if a very small allocation is possible. |
| 1117 | dev_kfree_skb_any(skb); | 1132 | * We will send this packet immediately and hope |
| 1118 | dev->net->stats.tx_dropped++; | 1133 | * that there is more memory available later. |
| 1134 | */ | ||
| 1135 | if (skb) | ||
| 1136 | ctx->tx_curr_size = max(skb->len, | ||
| 1137 | (u32)USB_CDC_NCM_NTB_MIN_OUT_SIZE); | ||
| 1138 | else | ||
| 1139 | ctx->tx_curr_size = USB_CDC_NCM_NTB_MIN_OUT_SIZE; | ||
| 1140 | skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC); | ||
| 1141 | |||
| 1142 | /* No allocation possible so we will abort */ | ||
| 1143 | if (skb_out == NULL) { | ||
| 1144 | if (skb != NULL) { | ||
| 1145 | dev_kfree_skb_any(skb); | ||
| 1146 | dev->net->stats.tx_dropped++; | ||
| 1147 | } | ||
| 1148 | goto exit_no_skb; | ||
| 1119 | } | 1149 | } |
| 1120 | goto exit_no_skb; | 1150 | ctx->tx_low_mem_val--; |
| 1121 | } | 1151 | } |
| 1122 | /* fill out the initial 16-bit NTB header */ | 1152 | /* fill out the initial 16-bit NTB header */ |
| 1123 | nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16)); | 1153 | nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16)); |
| @@ -1148,10 +1178,10 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) | |||
| 1148 | ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder); | 1178 | ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder); |
| 1149 | 1179 | ||
| 1150 | /* align beginning of next frame */ | 1180 | /* align beginning of next frame */ |
| 1151 | cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); | 1181 | cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_curr_size); |
| 1152 | 1182 | ||
| 1153 | /* check if we had enough room left for both NDP and frame */ | 1183 | /* check if we had enough room left for both NDP and frame */ |
| 1154 | if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { | 1184 | if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) { |
| 1155 | if (n == 0) { | 1185 | if (n == 0) { |
| 1156 | /* won't fit, MTU problem? */ | 1186 | /* won't fit, MTU problem? */ |
| 1157 | dev_kfree_skb_any(skb); | 1187 | dev_kfree_skb_any(skb); |
| @@ -1227,7 +1257,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) | |||
| 1227 | /* If requested, put NDP at end of frame. */ | 1257 | /* If requested, put NDP at end of frame. */ |
| 1228 | if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { | 1258 | if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { |
| 1229 | nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; | 1259 | nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; |
| 1230 | cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); | 1260 | cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size); |
| 1231 | nth16->wNdpIndex = cpu_to_le16(skb_out->len); | 1261 | nth16->wNdpIndex = cpu_to_le16(skb_out->len); |
| 1232 | skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size); | 1262 | skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size); |
| 1233 | 1263 | ||
| @@ -1246,9 +1276,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) | |||
| 1246 | */ | 1276 | */ |
| 1247 | if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && | 1277 | if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && |
| 1248 | skb_out->len > ctx->min_tx_pkt) { | 1278 | skb_out->len > ctx->min_tx_pkt) { |
| 1249 | padding_count = ctx->tx_max - skb_out->len; | 1279 | padding_count = ctx->tx_curr_size - skb_out->len; |
| 1250 | skb_put_zero(skb_out, padding_count); | 1280 | skb_put_zero(skb_out, padding_count); |
| 1251 | } else if (skb_out->len < ctx->tx_max && | 1281 | } else if (skb_out->len < ctx->tx_curr_size && |
| 1252 | (skb_out->len % dev->maxpacket) == 0) { | 1282 | (skb_out->len % dev->maxpacket) == 0) { |
| 1253 | skb_put_u8(skb_out, 0); /* force short packet */ | 1283 | skb_put_u8(skb_out, 0); /* force short packet */ |
| 1254 | } | 1284 | } |
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h index 00d232406f18..021f7a88f52c 100644 --- a/include/linux/usb/cdc_ncm.h +++ b/include/linux/usb/cdc_ncm.h | |||
| @@ -117,6 +117,9 @@ struct cdc_ncm_ctx { | |||
| 117 | u32 tx_curr_frame_num; | 117 | u32 tx_curr_frame_num; |
| 118 | u32 rx_max; | 118 | u32 rx_max; |
| 119 | u32 tx_max; | 119 | u32 tx_max; |
| 120 | u32 tx_curr_size; | ||
| 121 | u32 tx_low_mem_max_cnt; | ||
| 122 | u32 tx_low_mem_val; | ||
| 120 | u32 max_datagram_size; | 123 | u32 max_datagram_size; |
| 121 | u16 tx_max_datagrams; | 124 | u16 tx_max_datagrams; |
| 122 | u16 tx_remainder; | 125 | u16 tx_remainder; |
