| 1 | |
| 2 | |
| 3 | * PCIe NTB Network Linux driver
|
| 4 |
|
| 5 | #include <linux/etherdevice.h>
|
| 6 | #include <linux/ethtool.h>
|
| 7 | #include <linux/module.h>
|
| 8 | #include <linux/pci.h>
|
| 9 | #include <linux/ntb.h>
|
| 10 | #include <linux/ntb_transport.h>
|
| 11 | #include <linux/slab.h>
|
| 12 |
|
| 13 | #define NTB_NETDEV_VER "0.7"
|
| 14 |
|
| 15 | MODULE_DESCRIPTION(KBUILD_MODNAME);
|
| 16 | MODULE_VERSION(NTB_NETDEV_VER);
|
| 17 | MODULE_LICENSE("Dual BSD/GPL");
|
| 18 | MODULE_AUTHOR("Intel Corporation");
|
| 19 |
|
| 20 |
|
| 21 | static unsigned int tx_time = 1;
|
| 22 |
|
| 23 |
|
| 24 | static unsigned int tx_start = 10;
|
| 25 |
|
| 26 |
|
| 27 | static unsigned int tx_stop = 5;
|
| 28 |
|
| 29 | #define NTB_NETDEV_MAX_QUEUES 64
|
| 30 | #define NTB_NETDEV_DEFAULT_QUEUES 1
|
| 31 |
|
| 32 | struct ntb_netdev;
|
| 33 |
|
| 34 | struct ntb_netdev_queue {
|
| 35 | struct ntb_netdev *ntdev;
|
| 36 | struct ntb_transport_qp *qp;
|
| 37 | struct timer_list tx_timer;
|
| 38 | u16 qid;
|
| 39 | };
|
| 40 |
|
| 41 | struct ntb_netdev {
|
| 42 | struct pci_dev *pdev;
|
| 43 | struct device *client_dev;
|
| 44 | struct net_device *ndev;
|
| 45 | unsigned int num_queues;
|
| 46 | struct ntb_netdev_queue *queues;
|
| 47 | };
|
| 48 |
|
| 49 | #define NTB_TX_TIMEOUT_MS 1000
|
| 50 | #define NTB_RXQ_SIZE 100
|
| 51 |
|
| 52 | static void ntb_netdev_update_carrier(struct ntb_netdev *dev)
|
| 53 | {
|
| 54 | struct net_device *ndev;
|
| 55 | bool any_up = false;
|
| 56 | unsigned int i;
|
| 57 |
|
| 58 | ndev = dev->ndev;
|
| 59 |
|
| 60 | for (i = 0; i < dev->num_queues; i++) {
|
| 61 | if (ntb_transport_link_query(dev->queues[i].qp)) {
|
| 62 | any_up = true;
|
| 63 | break;
|
| 64 | }
|
| 65 | }
|
| 66 |
|
| 67 | if (any_up)
|
| 68 | netif_carrier_on(ndev);
|
| 69 | else
|
| 70 | netif_carrier_off(ndev);
|
| 71 | }
|
| 72 |
|
| 73 | static void ntb_netdev_queue_rx_drain(struct ntb_netdev_queue *queue)
|
| 74 | {
|
| 75 | struct sk_buff *skb;
|
| 76 | int len;
|
| 77 |
|
| 78 | while ((skb = ntb_transport_rx_remove(queue->qp, &len)))
|
| 79 | dev_kfree_skb(skb);
|
| 80 | }
|
| 81 |
|
| 82 | static int ntb_netdev_queue_rx_fill(struct net_device *ndev,
|
| 83 | struct ntb_netdev_queue *queue)
|
| 84 | {
|
| 85 | struct sk_buff *skb;
|
| 86 | int rc, i;
|
| 87 |
|
| 88 | for (i = 0; i < NTB_RXQ_SIZE; i++) {
|
| 89 | skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
|
| 90 | if (!skb)
|
| 91 | return -ENOMEM;
|
| 92 |
|
| 93 | rc = ntb_transport_rx_enqueue(queue->qp, skb, skb->data,
|
| 94 | ndev->mtu + ETH_HLEN);
|
| 95 | if (rc) {
|
| 96 | dev_kfree_skb(skb);
|
| 97 | return rc;
|
| 98 | }
|
| 99 | }
|
| 100 |
|
| 101 | return 0;
|
| 102 | }
|
| 103 |
|
| 104 | static void ntb_netdev_event_handler(void *data, int link_is_up)
|
| 105 | {
|
| 106 | struct ntb_netdev_queue *q = data;
|
| 107 | struct ntb_netdev *dev = q->ntdev;
|
| 108 | struct net_device *ndev;
|
| 109 |
|
| 110 | ndev = dev->ndev;
|
| 111 |
|
| 112 | netdev_dbg(ndev, "Event %x, Link %x, qp %u\n", link_is_up,
|
| 113 | ntb_transport_link_query(q->qp), q->qid);
|
| 114 |
|
| 115 | if (netif_running(ndev)) {
|
| 116 | if (link_is_up)
|
| 117 | netif_wake_subqueue(ndev, q->qid);
|
| 118 | else
|
| 119 | netif_stop_subqueue(ndev, q->qid);
|
| 120 | }
|
| 121 |
|
| 122 | ntb_netdev_update_carrier(dev);
|
| 123 | }
|
| 124 |
|
| 125 | static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
|
| 126 | void *data, int len)
|
| 127 | {
|
| 128 | struct ntb_netdev_queue *q = qp_data;
|
| 129 | struct ntb_netdev *dev = q->ntdev;
|
| 130 | struct pcpu_sw_netstats *tstats;
|
| 131 | struct sk_buff *skb, *new_skb;
|
| 132 | struct net_device *ndev;
|
| 133 | unsigned long flags;
|
| 134 | int rc;
|
| 135 |
|
| 136 | ndev = dev->ndev;
|
| 137 | skb = data;
|
| 138 | if (!skb)
|
| 139 | return;
|
| 140 |
|
| 141 | netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
|
| 142 |
|
| 143 | if (len < 0) {
|
| 144 | DEV_STATS_INC(ndev, rx_errors);
|
| 145 | DEV_STATS_INC(ndev, rx_length_errors);
|
| 146 | goto enqueue_again;
|
| 147 | }
|
| 148 |
|
| 149 | tstats = this_cpu_ptr(ndev->tstats);
|
| 150 | flags = u64_stats_update_begin_irqsave(&tstats->syncp);
|
| 151 | u64_stats_inc(&tstats->rx_packets);
|
| 152 | u64_stats_add(&tstats->rx_bytes, len);
|
| 153 | u64_stats_update_end_irqrestore(&tstats->syncp, flags);
|
| 154 |
|
| 155 | new_skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
|
| 156 | if (!new_skb) {
|
| 157 | DEV_STATS_INC(ndev, rx_dropped);
|
| 158 | goto enqueue_again;
|
| 159 | }
|
| 160 |
|
| 161 | skb_put(skb, len);
|
| 162 | skb->protocol = eth_type_trans(skb, ndev);
|
| 163 | skb->ip_summed = CHECKSUM_NONE;
|
| 164 | skb_record_rx_queue(skb, q->qid);
|
| 165 |
|
| 166 | netif_rx(skb);
|
| 167 |
|
| 168 | skb = new_skb;
|
| 169 |
|
| 170 | enqueue_again:
|
| 171 | rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
|
| 172 | if (rc) {
|
| 173 | dev_kfree_skb_any(skb);
|
| 174 | DEV_STATS_INC(ndev, rx_errors);
|
| 175 | DEV_STATS_INC(ndev, rx_fifo_errors);
|
| 176 | }
|
| 177 | }
|
| 178 |
|
| 179 | static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,
|
| 180 | struct ntb_netdev_queue *q, int size)
|
| 181 | {
|
| 182 | netif_stop_subqueue(netdev, q->qid);
|
| 183 |
|
| 184 | |
| 185 | * since the queue was last started.
|
| 186 |
|
| 187 | smp_mb();
|
| 188 |
|
| 189 | if (likely(ntb_transport_tx_free_entry(q->qp) < size)) {
|
| 190 | mod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));
|
| 191 | return -EBUSY;
|
| 192 | }
|
| 193 |
|
| 194 |
|
| 195 | if (ntb_transport_link_query(q->qp))
|
| 196 | netif_start_subqueue(netdev, q->qid);
|
| 197 |
|
| 198 | return 0;
|
| 199 | }
|
| 200 |
|
| 201 | static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,
|
| 202 | struct ntb_netdev_queue *q, int size)
|
| 203 | {
|
| 204 | if (__netif_subqueue_stopped(ndev, q->qid))
|
| 205 | return -EBUSY;
|
| 206 |
|
| 207 | if (ntb_transport_tx_free_entry(q->qp) >= size)
|
| 208 | return 0;
|
| 209 |
|
| 210 | return __ntb_netdev_maybe_stop_tx(ndev, q, size);
|
| 211 | }
|
| 212 |
|
| 213 | static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
|
| 214 | void *data, int len)
|
| 215 | {
|
| 216 | struct ntb_netdev_queue *q = qp_data;
|
| 217 | struct ntb_netdev *dev = q->ntdev;
|
| 218 | struct pcpu_sw_netstats *tstats;
|
| 219 | struct net_device *ndev;
|
| 220 | struct sk_buff *skb;
|
| 221 | unsigned long flags;
|
| 222 | bool registered;
|
| 223 |
|
| 224 | ndev = dev->ndev;
|
| 225 | skb = data;
|
| 226 | if (!skb || !ndev)
|
| 227 | return;
|
| 228 |
|
| 229 | rcu_read_lock();
|
| 230 | registered = READ_ONCE(ndev->reg_state) == NETREG_REGISTERED;
|
| 231 | if (!registered)
|
| 232 | goto free_skb;
|
| 233 |
|
| 234 | if (len > 0) {
|
| 235 |
|
| 236 | tstats = get_cpu_ptr(ndev->tstats);
|
| 237 | flags = u64_stats_update_begin_irqsave(&tstats->syncp);
|
| 238 | u64_stats_inc(&tstats->tx_packets);
|
| 239 | u64_stats_add(&tstats->tx_bytes, skb->len);
|
| 240 | u64_stats_update_end_irqrestore(&tstats->syncp, flags);
|
| 241 | put_cpu_ptr(ndev->tstats);
|
| 242 | } else {
|
| 243 | DEV_STATS_INC(ndev, tx_errors);
|
| 244 | DEV_STATS_INC(ndev, tx_aborted_errors);
|
| 245 | }
|
| 246 |
|
| 247 | free_skb:
|
| 248 | dev_kfree_skb_any(skb);
|
| 249 |
|
| 250 | if (registered && ntb_transport_tx_free_entry(qp) >= tx_start) {
|
| 251 | |
| 252 | * value of ntb_transport_tx_free_entry()
|
| 253 |
|
| 254 | smp_mb();
|
| 255 | if (__netif_subqueue_stopped(ndev, q->qid) &&
|
| 256 | ntb_transport_link_query(q->qp))
|
| 257 | netif_wake_subqueue(ndev, q->qid);
|
| 258 | }
|
| 259 | rcu_read_unlock();
|
| 260 | }
|
| 261 |
|
| 262 | static const struct ntb_queue_handlers ntb_netdev_handlers = {
|
| 263 | .tx_handler = ntb_netdev_tx_handler,
|
| 264 | .rx_handler = ntb_netdev_rx_handler,
|
| 265 | .event_handler = ntb_netdev_event_handler,
|
| 266 | };
|
| 267 |
|
| 268 | static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
|
| 269 | struct net_device *ndev)
|
| 270 | {
|
| 271 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 272 | u16 qid = skb_get_queue_mapping(skb);
|
| 273 | struct ntb_netdev_queue *q;
|
| 274 | int rc;
|
| 275 |
|
| 276 | q = &dev->queues[qid];
|
| 277 |
|
| 278 | if (unlikely(ntb_netdev_maybe_stop_tx(ndev, q, tx_stop)))
|
| 279 | return NETDEV_TX_BUSY;
|
| 280 |
|
| 281 | rc = ntb_transport_tx_enqueue(q->qp, skb, skb->data, skb->len);
|
| 282 | if (rc) {
|
| 283 | if (rc == -EAGAIN || rc == -EBUSY) {
|
| 284 | netif_stop_subqueue(ndev, q->qid);
|
| 285 | mod_timer(&q->tx_timer,
|
| 286 | jiffies + usecs_to_jiffies(tx_time));
|
| 287 | return NETDEV_TX_BUSY;
|
| 288 | }
|
| 289 |
|
| 290 | goto drop;
|
| 291 | }
|
| 292 |
|
| 293 |
|
| 294 | ntb_netdev_maybe_stop_tx(ndev, q, tx_stop);
|
| 295 |
|
| 296 | return NETDEV_TX_OK;
|
| 297 |
|
| 298 | drop:
|
| 299 | dev_kfree_skb_any(skb);
|
| 300 | DEV_STATS_INC(ndev, tx_dropped);
|
| 301 | return NETDEV_TX_OK;
|
| 302 | }
|
| 303 |
|
| 304 | static void ntb_netdev_tx_timer(struct timer_list *t)
|
| 305 | {
|
| 306 | struct ntb_netdev_queue *q = timer_container_of(q, t, tx_timer);
|
| 307 | struct ntb_netdev *dev = q->ntdev;
|
| 308 | struct net_device *ndev;
|
| 309 |
|
| 310 | ndev = dev->ndev;
|
| 311 |
|
| 312 | if (ntb_transport_tx_free_entry(q->qp) < tx_stop) {
|
| 313 | mod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));
|
| 314 | } else {
|
| 315 | |
| 316 | * value of ntb_transport_tx_free_entry()
|
| 317 |
|
| 318 | smp_mb();
|
| 319 |
|
| 320 |
|
| 321 | if (__netif_subqueue_stopped(ndev, q->qid) &&
|
| 322 | ntb_transport_link_query(q->qp))
|
| 323 | netif_wake_subqueue(ndev, q->qid);
|
| 324 | }
|
| 325 | }
|
| 326 |
|
| 327 | static int ntb_netdev_open(struct net_device *ndev)
|
| 328 | {
|
| 329 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 330 | struct ntb_netdev_queue *queue;
|
| 331 | unsigned int q;
|
| 332 | int rc = 0;
|
| 333 |
|
| 334 |
|
| 335 | for (q = 0; q < dev->num_queues; q++) {
|
| 336 | queue = &dev->queues[q];
|
| 337 |
|
| 338 | rc = ntb_netdev_queue_rx_fill(ndev, queue);
|
| 339 | if (rc)
|
| 340 | goto err;
|
| 341 |
|
| 342 | timer_setup(&queue->tx_timer, ntb_netdev_tx_timer, 0);
|
| 343 | }
|
| 344 |
|
| 345 | netif_carrier_off(ndev);
|
| 346 | netif_tx_stop_all_queues(ndev);
|
| 347 |
|
| 348 | for (q = 0; q < dev->num_queues; q++)
|
| 349 | ntb_transport_link_up(dev->queues[q].qp);
|
| 350 |
|
| 351 | return 0;
|
| 352 |
|
| 353 | err:
|
| 354 | for (q = 0; q < dev->num_queues; q++) {
|
| 355 | queue = &dev->queues[q];
|
| 356 | ntb_netdev_queue_rx_drain(queue);
|
| 357 | }
|
| 358 | return rc;
|
| 359 | }
|
| 360 |
|
| 361 | static int ntb_netdev_close(struct net_device *ndev)
|
| 362 | {
|
| 363 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 364 | struct ntb_netdev_queue *queue;
|
| 365 | unsigned int q;
|
| 366 |
|
| 367 | netif_tx_stop_all_queues(ndev);
|
| 368 | netif_carrier_off(ndev);
|
| 369 |
|
| 370 | for (q = 0; q < dev->num_queues; q++) {
|
| 371 | queue = &dev->queues[q];
|
| 372 |
|
| 373 | ntb_transport_link_down(queue->qp);
|
| 374 | ntb_netdev_queue_rx_drain(queue);
|
| 375 | timer_delete_sync(&queue->tx_timer);
|
| 376 | }
|
| 377 |
|
| 378 | return 0;
|
| 379 | }
|
| 380 |
|
| 381 | static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
|
| 382 | {
|
| 383 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 384 | struct ntb_netdev_queue *queue;
|
| 385 | struct sk_buff *skb;
|
| 386 | unsigned int q, i;
|
| 387 | int len, rc = 0;
|
| 388 |
|
| 389 | if (new_mtu > ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN)
|
| 390 | return -EINVAL;
|
| 391 |
|
| 392 | if (!netif_running(ndev)) {
|
| 393 | WRITE_ONCE(ndev->mtu, new_mtu);
|
| 394 | return 0;
|
| 395 | }
|
| 396 |
|
| 397 |
|
| 398 | for (q = 0; q < dev->num_queues; q++)
|
| 399 | ntb_transport_link_down(dev->queues[q].qp);
|
| 400 |
|
| 401 | if (ndev->mtu < new_mtu) {
|
| 402 | for (q = 0; q < dev->num_queues; q++) {
|
| 403 | queue = &dev->queues[q];
|
| 404 |
|
| 405 | for (i = 0;
|
| 406 | (skb = ntb_transport_rx_remove(queue->qp, &len));
|
| 407 | i++)
|
| 408 | dev_kfree_skb(skb);
|
| 409 |
|
| 410 | for (; i; i--) {
|
| 411 | skb = netdev_alloc_skb(ndev,
|
| 412 | new_mtu + ETH_HLEN);
|
| 413 | if (!skb) {
|
| 414 | rc = -ENOMEM;
|
| 415 | goto err;
|
| 416 | }
|
| 417 |
|
| 418 | rc = ntb_transport_rx_enqueue(queue->qp, skb,
|
| 419 | skb->data,
|
| 420 | new_mtu +
|
| 421 | ETH_HLEN);
|
| 422 | if (rc) {
|
| 423 | dev_kfree_skb(skb);
|
| 424 | goto err;
|
| 425 | }
|
| 426 | }
|
| 427 | }
|
| 428 | }
|
| 429 |
|
| 430 | WRITE_ONCE(ndev->mtu, new_mtu);
|
| 431 |
|
| 432 | for (q = 0; q < dev->num_queues; q++)
|
| 433 | ntb_transport_link_up(dev->queues[q].qp);
|
| 434 |
|
| 435 | return 0;
|
| 436 |
|
| 437 | err:
|
| 438 | for (q = 0; q < dev->num_queues; q++) {
|
| 439 | struct ntb_netdev_queue *queue = &dev->queues[q];
|
| 440 |
|
| 441 | ntb_transport_link_down(queue->qp);
|
| 442 |
|
| 443 | ntb_netdev_queue_rx_drain(queue);
|
| 444 | }
|
| 445 |
|
| 446 | netdev_err(ndev, "Error changing MTU, device inoperable\n");
|
| 447 | return rc;
|
| 448 | }
|
| 449 |
|
| 450 | static const struct net_device_ops ntb_netdev_ops = {
|
| 451 | .ndo_open = ntb_netdev_open,
|
| 452 | .ndo_stop = ntb_netdev_close,
|
| 453 | .ndo_start_xmit = ntb_netdev_start_xmit,
|
| 454 | .ndo_change_mtu = ntb_netdev_change_mtu,
|
| 455 | .ndo_set_mac_address = eth_mac_addr,
|
| 456 | };
|
| 457 |
|
| 458 | static void ntb_get_drvinfo(struct net_device *ndev,
|
| 459 | struct ethtool_drvinfo *info)
|
| 460 | {
|
| 461 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 462 |
|
| 463 | strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
|
| 464 | strscpy(info->version, NTB_NETDEV_VER, sizeof(info->version));
|
| 465 | strscpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));
|
| 466 | }
|
| 467 |
|
| 468 | static int ntb_get_link_ksettings(struct net_device *dev,
|
| 469 | struct ethtool_link_ksettings *cmd)
|
| 470 | {
|
| 471 | ethtool_link_ksettings_zero_link_mode(cmd, supported);
|
| 472 | ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
|
| 473 | ethtool_link_ksettings_zero_link_mode(cmd, advertising);
|
| 474 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Backplane);
|
| 475 |
|
| 476 | cmd->base.speed = SPEED_UNKNOWN;
|
| 477 | cmd->base.duplex = DUPLEX_FULL;
|
| 478 | cmd->base.port = PORT_OTHER;
|
| 479 | cmd->base.phy_address = 0;
|
| 480 | cmd->base.autoneg = AUTONEG_ENABLE;
|
| 481 |
|
| 482 | return 0;
|
| 483 | }
|
| 484 |
|
| 485 | static void ntb_get_channels(struct net_device *ndev,
|
| 486 | struct ethtool_channels *channels)
|
| 487 | {
|
| 488 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 489 |
|
| 490 | channels->combined_count = dev->num_queues;
|
| 491 | channels->max_combined = ndev->num_tx_queues;
|
| 492 | }
|
| 493 |
|
| 494 | static int ntb_inc_channels(struct net_device *ndev,
|
| 495 | unsigned int old, unsigned int new)
|
| 496 | {
|
| 497 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 498 | bool running = netif_running(ndev);
|
| 499 | struct ntb_netdev_queue *queue;
|
| 500 | unsigned int q, created;
|
| 501 | int rc;
|
| 502 |
|
| 503 | created = old;
|
| 504 | for (q = old; q < new; q++) {
|
| 505 | queue = &dev->queues[q];
|
| 506 |
|
| 507 | queue->ntdev = dev;
|
| 508 | queue->qid = q;
|
| 509 | queue->qp = ntb_transport_create_queue(queue, dev->client_dev,
|
| 510 | &ntb_netdev_handlers);
|
| 511 | if (!queue->qp) {
|
| 512 | rc = -ENOSPC;
|
| 513 | goto err_new;
|
| 514 | }
|
| 515 | created++;
|
| 516 |
|
| 517 | if (!running)
|
| 518 | continue;
|
| 519 |
|
| 520 | timer_setup(&queue->tx_timer, ntb_netdev_tx_timer, 0);
|
| 521 |
|
| 522 | rc = ntb_netdev_queue_rx_fill(ndev, queue);
|
| 523 | if (rc)
|
| 524 | goto err_new;
|
| 525 |
|
| 526 | |
| 527 | * Carrier may already be on due to other QPs. Keep the new
|
| 528 | * subqueue stopped until we get a Link Up event for this QP.
|
| 529 |
|
| 530 | netif_stop_subqueue(ndev, q);
|
| 531 | }
|
| 532 |
|
| 533 | rc = netif_set_real_num_queues(ndev, new, new);
|
| 534 | if (rc)
|
| 535 | goto err_new;
|
| 536 |
|
| 537 | dev->num_queues = new;
|
| 538 |
|
| 539 | if (running)
|
| 540 | for (q = old; q < new; q++)
|
| 541 | ntb_transport_link_up(dev->queues[q].qp);
|
| 542 |
|
| 543 | return 0;
|
| 544 |
|
| 545 | err_new:
|
| 546 | if (running) {
|
| 547 | unsigned int rollback = created;
|
| 548 |
|
| 549 | while (rollback-- > old) {
|
| 550 | queue = &dev->queues[rollback];
|
| 551 | ntb_transport_link_down(queue->qp);
|
| 552 | ntb_netdev_queue_rx_drain(queue);
|
| 553 | timer_delete_sync(&queue->tx_timer);
|
| 554 | }
|
| 555 | }
|
| 556 | while (created-- > old) {
|
| 557 | queue = &dev->queues[created];
|
| 558 | ntb_transport_free_queue(queue->qp);
|
| 559 | queue->qp = NULL;
|
| 560 | }
|
| 561 | return rc;
|
| 562 | }
|
| 563 |
|
| 564 | static int ntb_dec_channels(struct net_device *ndev,
|
| 565 | unsigned int old, unsigned int new)
|
| 566 | {
|
| 567 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 568 | bool running = netif_running(ndev);
|
| 569 | struct ntb_netdev_queue *queue;
|
| 570 | unsigned int q;
|
| 571 | int rc;
|
| 572 |
|
| 573 | if (running)
|
| 574 | for (q = new; q < old; q++)
|
| 575 | netif_stop_subqueue(ndev, q);
|
| 576 |
|
| 577 | rc = netif_set_real_num_queues(ndev, new, new);
|
| 578 | if (rc)
|
| 579 | goto err;
|
| 580 |
|
| 581 |
|
| 582 | dev->num_queues = new;
|
| 583 |
|
| 584 | for (q = new; q < old; q++) {
|
| 585 | queue = &dev->queues[q];
|
| 586 |
|
| 587 | if (running) {
|
| 588 | ntb_transport_link_down(queue->qp);
|
| 589 | ntb_netdev_queue_rx_drain(queue);
|
| 590 | timer_delete_sync(&queue->tx_timer);
|
| 591 | }
|
| 592 |
|
| 593 | ntb_transport_free_queue(queue->qp);
|
| 594 | queue->qp = NULL;
|
| 595 | }
|
| 596 |
|
| 597 | |
| 598 | * It might be the case that the removed queues are the only queues that
|
| 599 | * were up, so see if the global carrier needs to change.
|
| 600 |
|
| 601 | ntb_netdev_update_carrier(dev);
|
| 602 | return 0;
|
| 603 |
|
| 604 | err:
|
| 605 | if (running) {
|
| 606 | for (q = new; q < old; q++)
|
| 607 | netif_wake_subqueue(ndev, q);
|
| 608 | }
|
| 609 | return rc;
|
| 610 | }
|
| 611 |
|
| 612 | static int ntb_set_channels(struct net_device *ndev,
|
| 613 | struct ethtool_channels *channels)
|
| 614 | {
|
| 615 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 616 | unsigned int new = channels->combined_count;
|
| 617 | unsigned int old = dev->num_queues;
|
| 618 |
|
| 619 | if (new == old)
|
| 620 | return 0;
|
| 621 |
|
| 622 | if (new < old)
|
| 623 | return ntb_dec_channels(ndev, old, new);
|
| 624 | else
|
| 625 | return ntb_inc_channels(ndev, old, new);
|
| 626 | }
|
| 627 |
|
| 628 | static const struct ethtool_ops ntb_ethtool_ops = {
|
| 629 | .get_drvinfo = ntb_get_drvinfo,
|
| 630 | .get_link = ethtool_op_get_link,
|
| 631 | .get_link_ksettings = ntb_get_link_ksettings,
|
| 632 | .get_channels = ntb_get_channels,
|
| 633 | .set_channels = ntb_set_channels,
|
| 634 | };
|
| 635 |
|
| 636 | static int ntb_netdev_probe(struct device *client_dev)
|
| 637 | {
|
| 638 | struct ntb_dev *ntb;
|
| 639 | struct net_device *ndev;
|
| 640 | struct pci_dev *pdev;
|
| 641 | struct ntb_netdev *dev;
|
| 642 | unsigned int q;
|
| 643 | int rc;
|
| 644 |
|
| 645 | ntb = dev_ntb(client_dev->parent);
|
| 646 | pdev = ntb->pdev;
|
| 647 | if (!pdev)
|
| 648 | return -ENODEV;
|
| 649 |
|
| 650 | ndev = alloc_etherdev_mq(sizeof(*dev), NTB_NETDEV_MAX_QUEUES);
|
| 651 | if (!ndev)
|
| 652 | return -ENOMEM;
|
| 653 |
|
| 654 | SET_NETDEV_DEV(ndev, client_dev);
|
| 655 |
|
| 656 | dev = netdev_priv(ndev);
|
| 657 | dev->ndev = ndev;
|
| 658 | dev->pdev = pdev;
|
| 659 | dev->client_dev = client_dev;
|
| 660 | dev->num_queues = 0;
|
| 661 |
|
| 662 | dev->queues = kzalloc_objs(*dev->queues, NTB_NETDEV_MAX_QUEUES);
|
| 663 | if (!dev->queues) {
|
| 664 | rc = -ENOMEM;
|
| 665 | goto err_free_netdev;
|
| 666 | }
|
| 667 |
|
| 668 | ndev->features = NETIF_F_HIGHDMA;
|
| 669 | ndev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
|
| 670 |
|
| 671 | ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
| 672 |
|
| 673 | ndev->hw_features = ndev->features;
|
| 674 | ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);
|
| 675 |
|
| 676 | eth_random_addr(ndev->perm_addr);
|
| 677 | dev_addr_set(ndev, ndev->perm_addr);
|
| 678 |
|
| 679 | ndev->netdev_ops = &ntb_netdev_ops;
|
| 680 | ndev->ethtool_ops = &ntb_ethtool_ops;
|
| 681 |
|
| 682 | ndev->min_mtu = 0;
|
| 683 | ndev->max_mtu = ETH_MAX_MTU;
|
| 684 |
|
| 685 | for (q = 0; q < NTB_NETDEV_DEFAULT_QUEUES; q++) {
|
| 686 | struct ntb_netdev_queue *queue = &dev->queues[q];
|
| 687 |
|
| 688 | queue->ntdev = dev;
|
| 689 | queue->qid = q;
|
| 690 | queue->qp = ntb_transport_create_queue(queue, client_dev,
|
| 691 | &ntb_netdev_handlers);
|
| 692 | if (!queue->qp)
|
| 693 | break;
|
| 694 |
|
| 695 | dev->num_queues++;
|
| 696 | }
|
| 697 |
|
| 698 | if (!dev->num_queues) {
|
| 699 | rc = -EIO;
|
| 700 | goto err_free_queues;
|
| 701 | }
|
| 702 |
|
| 703 | rc = netif_set_real_num_queues(ndev, dev->num_queues, dev->num_queues);
|
| 704 | if (rc)
|
| 705 | goto err_free_qps;
|
| 706 |
|
| 707 | ndev->mtu = ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN;
|
| 708 |
|
| 709 | rc = register_netdev(ndev);
|
| 710 | if (rc)
|
| 711 | goto err_free_qps;
|
| 712 |
|
| 713 | dev_set_drvdata(client_dev, ndev);
|
| 714 | dev_info(&pdev->dev, "%s created with %u queue pairs\n",
|
| 715 | ndev->name, dev->num_queues);
|
| 716 | return 0;
|
| 717 |
|
| 718 | err_free_qps:
|
| 719 | for (q = 0; q < dev->num_queues; q++)
|
| 720 | ntb_transport_free_queue(dev->queues[q].qp);
|
| 721 |
|
| 722 | err_free_queues:
|
| 723 | kfree(dev->queues);
|
| 724 |
|
| 725 | err_free_netdev:
|
| 726 | free_netdev(ndev);
|
| 727 | return rc;
|
| 728 | }
|
| 729 |
|
| 730 | static void ntb_netdev_remove(struct device *client_dev)
|
| 731 | {
|
| 732 | struct net_device *ndev = dev_get_drvdata(client_dev);
|
| 733 | struct ntb_netdev *dev = netdev_priv(ndev);
|
| 734 | unsigned int q;
|
| 735 |
|
| 736 | unregister_netdev(ndev);
|
| 737 | for (q = 0; q < dev->num_queues; q++)
|
| 738 | ntb_transport_free_queue(dev->queues[q].qp);
|
| 739 |
|
| 740 | kfree(dev->queues);
|
| 741 | free_netdev(ndev);
|
| 742 | }
|
| 743 |
|
| 744 | static struct ntb_transport_client ntb_netdev_client = {
|
| 745 | .driver.name = KBUILD_MODNAME,
|
| 746 | .driver.owner = THIS_MODULE,
|
| 747 | .probe = ntb_netdev_probe,
|
| 748 | .remove = ntb_netdev_remove,
|
| 749 | };
|
| 750 |
|
| 751 | static int __init ntb_netdev_init_module(void)
|
| 752 | {
|
| 753 | int rc;
|
| 754 |
|
| 755 | rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
|
| 756 | if (rc)
|
| 757 | return rc;
|
| 758 |
|
| 759 | rc = ntb_transport_register_client(&ntb_netdev_client);
|
| 760 | if (rc) {
|
| 761 | ntb_transport_unregister_client_dev(KBUILD_MODNAME);
|
| 762 | return rc;
|
| 763 | }
|
| 764 |
|
| 765 | return 0;
|
| 766 | }
|
| 767 | late_initcall(ntb_netdev_init_module);
|
| 768 |
|
| 769 | static void __exit ntb_netdev_exit_module(void)
|
| 770 | {
|
| 771 | ntb_transport_unregister_client(&ntb_netdev_client);
|
| 772 | ntb_transport_unregister_client_dev(KBUILD_MODNAME);
|
| 773 | }
|
| 774 | module_exit(ntb_netdev_exit_module);
|