| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * Copyright (C) 2017 - Cambridge Greys Limited |
|---|
| 3 | + * Copyright (C) 2017 - 2019 Cambridge Greys Limited |
|---|
| 3 | 4 | * Copyright (C) 2011 - 2014 Cisco Systems Inc |
|---|
| 4 | 5 | * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
|---|
| 5 | 6 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and |
|---|
| 6 | 7 | * James Leu (jleu@mindspring.net). |
|---|
| 7 | 8 | * Copyright (C) 2001 by various other people who didn't put their name here. |
|---|
| 8 | | - * Licensed under the GPL. |
|---|
| 9 | 9 | */ |
|---|
| 10 | 10 | |
|---|
| 11 | 11 | #include <linux/version.h> |
|---|
| 12 | | -#include <linux/bootmem.h> |
|---|
| 12 | +#include <linux/memblock.h> |
|---|
| 13 | 13 | #include <linux/etherdevice.h> |
|---|
| 14 | 14 | #include <linux/ethtool.h> |
|---|
| 15 | 15 | #include <linux/inetdevice.h> |
|---|
| .. | .. |
|---|
| 21 | 21 | #include <linux/skbuff.h> |
|---|
| 22 | 22 | #include <linux/slab.h> |
|---|
| 23 | 23 | #include <linux/interrupt.h> |
|---|
| 24 | +#include <linux/firmware.h> |
|---|
| 25 | +#include <linux/fs.h> |
|---|
| 26 | +#include <uapi/linux/filter.h> |
|---|
| 24 | 27 | #include <init.h> |
|---|
| 25 | 28 | #include <irq_kern.h> |
|---|
| 26 | 29 | #include <irq_user.h> |
|---|
| .. | .. |
|---|
| 43 | 46 | |
|---|
| 44 | 47 | |
|---|
| 45 | 48 | #define DRIVER_NAME "uml-vector" |
|---|
| 46 | | -#define DRIVER_VERSION "01" |
|---|
| 47 | 49 | struct vector_cmd_line_arg { |
|---|
| 48 | 50 | struct list_head list; |
|---|
| 49 | 51 | int unit; |
|---|
| .. | .. |
|---|
| 76 | 78 | #define DEFAULT_VECTOR_SIZE 64 |
|---|
| 77 | 79 | #define TX_SMALL_PACKET 128 |
|---|
| 78 | 80 | #define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1) |
|---|
| 81 | +#define MAX_ITERATIONS 64 |
|---|
| 79 | 82 | |
|---|
| 80 | 83 | static const struct { |
|---|
| 81 | 84 | const char string[ETH_GSTRING_LEN]; |
|---|
| .. | .. |
|---|
| 121 | 124 | |
|---|
| 122 | 125 | if (mtu != NULL) { |
|---|
| 123 | 126 | if (kstrtoul(mtu, 10, &result) == 0) |
|---|
| 124 | | - return result; |
|---|
| 127 | + if ((result < (1 << 16) - 1) && (result >= 576)) |
|---|
| 128 | + return result; |
|---|
| 125 | 129 | } |
|---|
| 126 | 130 | return ETH_MAX_PACKET; |
|---|
| 131 | +} |
|---|
| 132 | + |
|---|
| 133 | +static char *get_bpf_file(struct arglist *def) |
|---|
| 134 | +{ |
|---|
| 135 | + return uml_vector_fetch_arg(def, "bpffile"); |
|---|
| 136 | +} |
|---|
| 137 | + |
|---|
| 138 | +static bool get_bpf_flash(struct arglist *def) |
|---|
| 139 | +{ |
|---|
| 140 | + char *allow = uml_vector_fetch_arg(def, "bpfflash"); |
|---|
| 141 | + long result; |
|---|
| 142 | + |
|---|
| 143 | + if (allow != NULL) { |
|---|
| 144 | + if (kstrtoul(allow, 10, &result) == 0) |
|---|
| 145 | + return (allow > 0); |
|---|
| 146 | + } |
|---|
| 147 | + return false; |
|---|
| 127 | 148 | } |
|---|
| 128 | 149 | |
|---|
| 129 | 150 | static int get_depth(struct arglist *def) |
|---|
| .. | .. |
|---|
| 174 | 195 | int vec_rx = VECTOR_RX; |
|---|
| 175 | 196 | int vec_tx = VECTOR_TX; |
|---|
| 176 | 197 | long parsed; |
|---|
| 198 | + int result = 0; |
|---|
| 199 | + |
|---|
| 200 | + if (transport == NULL) |
|---|
| 201 | + return -EINVAL; |
|---|
| 177 | 202 | |
|---|
| 178 | 203 | if (vector != NULL) { |
|---|
| 179 | 204 | if (kstrtoul(vector, 10, &parsed) == 0) { |
|---|
| .. | .. |
|---|
| 184 | 209 | } |
|---|
| 185 | 210 | } |
|---|
| 186 | 211 | |
|---|
| 212 | + if (get_bpf_flash(def)) |
|---|
| 213 | + result = VECTOR_BPF_FLASH; |
|---|
| 187 | 214 | |
|---|
| 188 | 215 | if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) |
|---|
| 189 | | - return (vec_rx | VECTOR_BPF); |
|---|
| 216 | + return result; |
|---|
| 217 | + if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) |
|---|
| 218 | + return (result | vec_rx | VECTOR_BPF); |
|---|
| 190 | 219 | if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) |
|---|
| 191 | | - return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS); |
|---|
| 192 | | - return (vec_rx | vec_tx); |
|---|
| 220 | + return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS); |
|---|
| 221 | + return (result | vec_rx | vec_tx); |
|---|
| 193 | 222 | } |
|---|
| 194 | 223 | |
|---|
| 195 | 224 | |
|---|
| .. | .. |
|---|
| 415 | 444 | if (net_ratelimit()) |
|---|
| 416 | 445 | netdev_err(vp->dev, "sendmmsg err=%i\n", |
|---|
| 417 | 446 | result); |
|---|
| 447 | + vp->in_error = true; |
|---|
| 418 | 448 | result = send_len; |
|---|
| 419 | 449 | } |
|---|
| 420 | 450 | if (result > 0) { |
|---|
| .. | .. |
|---|
| 741 | 771 | |
|---|
| 742 | 772 | if (parsed == NULL) { |
|---|
| 743 | 773 | *error_out = "vector_config failed to parse parameters"; |
|---|
| 774 | + kfree(params); |
|---|
| 744 | 775 | return -EINVAL; |
|---|
| 745 | 776 | } |
|---|
| 746 | 777 | |
|---|
| .. | .. |
|---|
| 842 | 873 | } |
|---|
| 843 | 874 | |
|---|
| 844 | 875 | pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0); |
|---|
| 876 | + if (pkt_len < 0) { |
|---|
| 877 | + vp->in_error = true; |
|---|
| 878 | + return pkt_len; |
|---|
| 879 | + } |
|---|
| 845 | 880 | |
|---|
| 846 | 881 | if (skb != NULL) { |
|---|
| 847 | 882 | if (pkt_len > vp->header_size) { |
|---|
| .. | .. |
|---|
| 888 | 923 | |
|---|
| 889 | 924 | if (iov_count < 1) |
|---|
| 890 | 925 | goto drop; |
|---|
| 926 | + |
|---|
| 891 | 927 | pkt_len = uml_vector_writev( |
|---|
| 892 | 928 | vp->fds->tx_fd, |
|---|
| 893 | 929 | (struct iovec *) &iov, |
|---|
| 894 | 930 | iov_count |
|---|
| 895 | 931 | ); |
|---|
| 932 | + |
|---|
| 933 | + if (pkt_len < 0) |
|---|
| 934 | + goto drop; |
|---|
| 896 | 935 | |
|---|
| 897 | 936 | netif_trans_update(vp->dev); |
|---|
| 898 | 937 | netif_wake_queue(vp->dev); |
|---|
| .. | .. |
|---|
| 908 | 947 | drop: |
|---|
| 909 | 948 | vp->dev->stats.tx_dropped++; |
|---|
| 910 | 949 | consume_skb(skb); |
|---|
| 950 | + if (pkt_len < 0) |
|---|
| 951 | + vp->in_error = true; |
|---|
| 911 | 952 | return pkt_len; |
|---|
| 912 | 953 | } |
|---|
| 913 | 954 | |
|---|
| .. | .. |
|---|
| 935 | 976 | |
|---|
| 936 | 977 | packet_count = uml_vector_recvmmsg( |
|---|
| 937 | 978 | vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0); |
|---|
| 979 | + |
|---|
| 980 | + if (packet_count < 0) |
|---|
| 981 | + vp->in_error = true; |
|---|
| 938 | 982 | |
|---|
| 939 | 983 | if (packet_count <= 0) |
|---|
| 940 | 984 | return packet_count; |
|---|
| .. | .. |
|---|
| 1005 | 1049 | static void vector_rx(struct vector_private *vp) |
|---|
| 1006 | 1050 | { |
|---|
| 1007 | 1051 | int err; |
|---|
| 1052 | + int iter = 0; |
|---|
| 1008 | 1053 | |
|---|
| 1009 | 1054 | if ((vp->options & VECTOR_RX) > 0) |
|---|
| 1010 | | - while ((err = vector_mmsg_rx(vp)) > 0) |
|---|
| 1011 | | - ; |
|---|
| 1055 | + while (((err = vector_mmsg_rx(vp)) > 0) && (iter < MAX_ITERATIONS)) |
|---|
| 1056 | + iter++; |
|---|
| 1012 | 1057 | else |
|---|
| 1013 | | - while ((err = vector_legacy_rx(vp)) > 0) |
|---|
| 1014 | | - ; |
|---|
| 1058 | + while (((err = vector_legacy_rx(vp)) > 0) && (iter < MAX_ITERATIONS)) |
|---|
| 1059 | + iter++; |
|---|
| 1015 | 1060 | if ((err != 0) && net_ratelimit()) |
|---|
| 1016 | 1061 | netdev_err(vp->dev, "vector_rx: error(%d)\n", err); |
|---|
| 1062 | + if (iter == MAX_ITERATIONS) |
|---|
| 1063 | + netdev_err(vp->dev, "vector_rx: device stuck, remote end may have closed the connection\n"); |
|---|
| 1017 | 1064 | } |
|---|
| 1018 | 1065 | |
|---|
| 1019 | 1066 | static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev) |
|---|
| 1020 | 1067 | { |
|---|
| 1021 | 1068 | struct vector_private *vp = netdev_priv(dev); |
|---|
| 1022 | 1069 | int queue_depth = 0; |
|---|
| 1070 | + |
|---|
| 1071 | + if (vp->in_error) { |
|---|
| 1072 | + deactivate_fd(vp->fds->rx_fd, vp->rx_irq); |
|---|
| 1073 | + if ((vp->fds->rx_fd != vp->fds->tx_fd) && (vp->tx_irq != 0)) |
|---|
| 1074 | + deactivate_fd(vp->fds->tx_fd, vp->tx_irq); |
|---|
| 1075 | + return NETDEV_TX_BUSY; |
|---|
| 1076 | + } |
|---|
| 1023 | 1077 | |
|---|
| 1024 | 1078 | if ((vp->options & VECTOR_TX) == 0) { |
|---|
| 1025 | 1079 | writev_tx(vp, skb); |
|---|
| .. | .. |
|---|
| 1043 | 1097 | vector_send(vp->tx_queue); |
|---|
| 1044 | 1098 | return NETDEV_TX_OK; |
|---|
| 1045 | 1099 | } |
|---|
| 1046 | | - if (skb->xmit_more) { |
|---|
| 1100 | + if (netdev_xmit_more()) { |
|---|
| 1047 | 1101 | mod_timer(&vp->tl, vp->coalesce); |
|---|
| 1048 | 1102 | return NETDEV_TX_OK; |
|---|
| 1049 | 1103 | } |
|---|
| .. | .. |
|---|
| 1111 | 1165 | } |
|---|
| 1112 | 1166 | tasklet_kill(&vp->tx_poll); |
|---|
| 1113 | 1167 | if (vp->fds->rx_fd > 0) { |
|---|
| 1168 | + if (vp->bpf) |
|---|
| 1169 | + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); |
|---|
| 1114 | 1170 | os_close_file(vp->fds->rx_fd); |
|---|
| 1115 | 1171 | vp->fds->rx_fd = -1; |
|---|
| 1116 | 1172 | } |
|---|
| .. | .. |
|---|
| 1119 | 1175 | vp->fds->tx_fd = -1; |
|---|
| 1120 | 1176 | } |
|---|
| 1121 | 1177 | if (vp->bpf != NULL) |
|---|
| 1122 | | - kfree(vp->bpf); |
|---|
| 1123 | | - if (vp->fds->remote_addr != NULL) |
|---|
| 1124 | | - kfree(vp->fds->remote_addr); |
|---|
| 1125 | | - if (vp->transport_data != NULL) |
|---|
| 1126 | | - kfree(vp->transport_data); |
|---|
| 1127 | | - if (vp->header_rxbuffer != NULL) |
|---|
| 1128 | | - kfree(vp->header_rxbuffer); |
|---|
| 1129 | | - if (vp->header_txbuffer != NULL) |
|---|
| 1130 | | - kfree(vp->header_txbuffer); |
|---|
| 1178 | + kfree(vp->bpf->filter); |
|---|
| 1179 | + kfree(vp->bpf); |
|---|
| 1180 | + vp->bpf = NULL; |
|---|
| 1181 | + kfree(vp->fds->remote_addr); |
|---|
| 1182 | + kfree(vp->transport_data); |
|---|
| 1183 | + kfree(vp->header_rxbuffer); |
|---|
| 1184 | + kfree(vp->header_txbuffer); |
|---|
| 1131 | 1185 | if (vp->rx_queue != NULL) |
|---|
| 1132 | 1186 | destroy_queue(vp->rx_queue); |
|---|
| 1133 | 1187 | if (vp->tx_queue != NULL) |
|---|
| .. | .. |
|---|
| 1136 | 1190 | vp->fds = NULL; |
|---|
| 1137 | 1191 | spin_lock_irqsave(&vp->lock, flags); |
|---|
| 1138 | 1192 | vp->opened = false; |
|---|
| 1193 | + vp->in_error = false; |
|---|
| 1139 | 1194 | spin_unlock_irqrestore(&vp->lock, flags); |
|---|
| 1140 | 1195 | return 0; |
|---|
| 1141 | 1196 | } |
|---|
| .. | .. |
|---|
| 1157 | 1212 | netif_start_queue(vp->dev); |
|---|
| 1158 | 1213 | netif_wake_queue(vp->dev); |
|---|
| 1159 | 1214 | } |
|---|
| 1215 | + |
|---|
| 1160 | 1216 | static int vector_net_open(struct net_device *dev) |
|---|
| 1161 | 1217 | { |
|---|
| 1162 | 1218 | struct vector_private *vp = netdev_priv(dev); |
|---|
| .. | .. |
|---|
| 1171 | 1227 | } |
|---|
| 1172 | 1228 | vp->opened = true; |
|---|
| 1173 | 1229 | spin_unlock_irqrestore(&vp->lock, flags); |
|---|
| 1230 | + |
|---|
| 1231 | + vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed)); |
|---|
| 1174 | 1232 | |
|---|
| 1175 | 1233 | vp->fds = uml_vector_user_open(vp->unit, vp->parsed); |
|---|
| 1176 | 1234 | |
|---|
| .. | .. |
|---|
| 1243 | 1301 | if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd)) |
|---|
| 1244 | 1302 | vp->options |= VECTOR_BPF; |
|---|
| 1245 | 1303 | } |
|---|
| 1246 | | - if ((vp->options & VECTOR_BPF) != 0) |
|---|
| 1247 | | - vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr); |
|---|
| 1304 | + if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL)) |
|---|
| 1305 | + vp->bpf = uml_vector_default_bpf(dev->dev_addr); |
|---|
| 1306 | + |
|---|
| 1307 | + if (vp->bpf != NULL) |
|---|
| 1308 | + uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); |
|---|
| 1248 | 1309 | |
|---|
| 1249 | 1310 | netif_start_queue(dev); |
|---|
| 1250 | 1311 | |
|---|
| .. | .. |
|---|
| 1274 | 1335 | return; |
|---|
| 1275 | 1336 | } |
|---|
| 1276 | 1337 | |
|---|
| 1277 | | -static void vector_net_tx_timeout(struct net_device *dev) |
|---|
| 1338 | +static void vector_net_tx_timeout(struct net_device *dev, unsigned int txqueue) |
|---|
| 1278 | 1339 | { |
|---|
| 1279 | 1340 | struct vector_private *vp = netdev_priv(dev); |
|---|
| 1280 | 1341 | |
|---|
| .. | .. |
|---|
| 1320 | 1381 | struct ethtool_drvinfo *info) |
|---|
| 1321 | 1382 | { |
|---|
| 1322 | 1383 | strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); |
|---|
| 1323 | | - strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); |
|---|
| 1384 | +} |
|---|
| 1385 | + |
|---|
| 1386 | +static int vector_net_load_bpf_flash(struct net_device *dev, |
|---|
| 1387 | + struct ethtool_flash *efl) |
|---|
| 1388 | +{ |
|---|
| 1389 | + struct vector_private *vp = netdev_priv(dev); |
|---|
| 1390 | + struct vector_device *vdevice; |
|---|
| 1391 | + const struct firmware *fw; |
|---|
| 1392 | + int result = 0; |
|---|
| 1393 | + |
|---|
| 1394 | + if (!(vp->options & VECTOR_BPF_FLASH)) { |
|---|
| 1395 | + netdev_err(dev, "loading firmware not permitted: %s\n", efl->data); |
|---|
| 1396 | + return -1; |
|---|
| 1397 | + } |
|---|
| 1398 | + |
|---|
| 1399 | + spin_lock(&vp->lock); |
|---|
| 1400 | + |
|---|
| 1401 | + if (vp->bpf != NULL) { |
|---|
| 1402 | + if (vp->opened) |
|---|
| 1403 | + uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); |
|---|
| 1404 | + kfree(vp->bpf->filter); |
|---|
| 1405 | + vp->bpf->filter = NULL; |
|---|
| 1406 | + } else { |
|---|
| 1407 | + vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_ATOMIC); |
|---|
| 1408 | + if (vp->bpf == NULL) { |
|---|
| 1409 | + netdev_err(dev, "failed to allocate memory for firmware\n"); |
|---|
| 1410 | + goto flash_fail; |
|---|
| 1411 | + } |
|---|
| 1412 | + } |
|---|
| 1413 | + |
|---|
| 1414 | + vdevice = find_device(vp->unit); |
|---|
| 1415 | + |
|---|
| 1416 | + if (request_firmware(&fw, efl->data, &vdevice->pdev.dev)) |
|---|
| 1417 | + goto flash_fail; |
|---|
| 1418 | + |
|---|
| 1419 | + vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_ATOMIC); |
|---|
| 1420 | + if (!vp->bpf->filter) |
|---|
| 1421 | + goto free_buffer; |
|---|
| 1422 | + |
|---|
| 1423 | + vp->bpf->len = fw->size / sizeof(struct sock_filter); |
|---|
| 1424 | + release_firmware(fw); |
|---|
| 1425 | + |
|---|
| 1426 | + if (vp->opened) |
|---|
| 1427 | + result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); |
|---|
| 1428 | + |
|---|
| 1429 | + spin_unlock(&vp->lock); |
|---|
| 1430 | + |
|---|
| 1431 | + return result; |
|---|
| 1432 | + |
|---|
| 1433 | +free_buffer: |
|---|
| 1434 | + release_firmware(fw); |
|---|
| 1435 | + |
|---|
| 1436 | +flash_fail: |
|---|
| 1437 | + spin_unlock(&vp->lock); |
|---|
| 1438 | + if (vp->bpf != NULL) |
|---|
| 1439 | + kfree(vp->bpf->filter); |
|---|
| 1440 | + kfree(vp->bpf); |
|---|
| 1441 | + vp->bpf = NULL; |
|---|
| 1442 | + return -1; |
|---|
| 1324 | 1443 | } |
|---|
| 1325 | 1444 | |
|---|
| 1326 | 1445 | static void vector_get_ringparam(struct net_device *netdev, |
|---|
| .. | .. |
|---|
| 1391 | 1510 | } |
|---|
| 1392 | 1511 | |
|---|
| 1393 | 1512 | static const struct ethtool_ops vector_net_ethtool_ops = { |
|---|
| 1513 | + .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS, |
|---|
| 1394 | 1514 | .get_drvinfo = vector_net_get_drvinfo, |
|---|
| 1395 | 1515 | .get_link = ethtool_op_get_link, |
|---|
| 1396 | 1516 | .get_ts_info = ethtool_op_get_ts_info, |
|---|
| .. | .. |
|---|
| 1400 | 1520 | .get_ethtool_stats = vector_get_ethtool_stats, |
|---|
| 1401 | 1521 | .get_coalesce = vector_get_coalesce, |
|---|
| 1402 | 1522 | .set_coalesce = vector_set_coalesce, |
|---|
| 1523 | + .flash_device = vector_net_load_bpf_flash, |
|---|
| 1403 | 1524 | }; |
|---|
| 1404 | 1525 | |
|---|
| 1405 | 1526 | |
|---|
| .. | .. |
|---|
| 1503 | 1624 | .transport_data = NULL, |
|---|
| 1504 | 1625 | .in_write_poll = false, |
|---|
| 1505 | 1626 | .coalesce = 2, |
|---|
| 1506 | | - .req_size = get_req_size(def) |
|---|
| 1507 | | - }); |
|---|
| 1627 | + .req_size = get_req_size(def), |
|---|
| 1628 | + .in_error = false, |
|---|
| 1629 | + .bpf = NULL |
|---|
| 1630 | + }); |
|---|
| 1508 | 1631 | |
|---|
| 1509 | 1632 | dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST); |
|---|
| 1510 | 1633 | tasklet_init(&vp->tx_poll, vector_tx_poll, (unsigned long)vp); |
|---|
| .. | .. |
|---|
| 1580 | 1703 | str, error); |
|---|
| 1581 | 1704 | return 1; |
|---|
| 1582 | 1705 | } |
|---|
| 1583 | | - new = alloc_bootmem(sizeof(*new)); |
|---|
| 1706 | + new = memblock_alloc(sizeof(*new), SMP_CACHE_BYTES); |
|---|
| 1707 | + if (!new) |
|---|
| 1708 | + panic("%s: Failed to allocate %zu bytes\n", __func__, |
|---|
| 1709 | + sizeof(*new)); |
|---|
| 1584 | 1710 | INIT_LIST_HEAD(&new->list); |
|---|
| 1585 | 1711 | new->unit = n; |
|---|
| 1586 | 1712 | new->arguments = str; |
|---|