aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/usb/cdc_ncm.c54
-rw-r--r--include/linux/usb/cdc_ncm.h3
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
92static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset) 94static 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;