brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · ef6df0e Raw
504 lines · c
1/*2 * This file is provided under a dual BSD/GPLv2 license.  When using or3 *   redistributing this file, you may do so under either license.4 *5 *   GPL LICENSE SUMMARY6 *7 *   Copyright(c) 2012 Intel Corporation. All rights reserved.8 *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.9 *10 *   This program is free software; you can redistribute it and/or modify11 *   it under the terms of version 2 of the GNU General Public License as12 *   published by the Free Software Foundation.13 *14 *   BSD LICENSE15 *16 *   Copyright(c) 2012 Intel Corporation. All rights reserved.17 *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.18 *19 *   Redistribution and use in source and binary forms, with or without20 *   modification, are permitted provided that the following conditions21 *   are met:22 *23 *     * Redistributions of source code must retain the above copyright24 *       notice, this list of conditions and the following disclaimer.25 *     * Redistributions in binary form must reproduce the above copy26 *       notice, this list of conditions and the following disclaimer in27 *       the documentation and/or other materials provided with the28 *       distribution.29 *     * Neither the name of Intel Corporation nor the names of its30 *       contributors may be used to endorse or promote products derived31 *       from this software without specific prior written permission.32 *33 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS34 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT35 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR36 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT37 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,38 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT39 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,40 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY41 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT42 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE43 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.44 *45 * PCIe NTB Network Linux driver46 *47 * Contact Information:48 * Jon Mason <jon.mason@intel.com>49 */50#include <linux/etherdevice.h>51#include <linux/ethtool.h>52#include <linux/module.h>53#include <linux/pci.h>54#include <linux/ntb.h>55#include <linux/ntb_transport.h>56 57#define NTB_NETDEV_VER	"0.7"58 59MODULE_DESCRIPTION(KBUILD_MODNAME);60MODULE_VERSION(NTB_NETDEV_VER);61MODULE_LICENSE("Dual BSD/GPL");62MODULE_AUTHOR("Intel Corporation");63 64/* Time in usecs for tx resource reaper */65static unsigned int tx_time = 1;66 67/* Number of descriptors to free before resuming tx */68static unsigned int tx_start = 10;69 70/* Number of descriptors still available before stop upper layer tx */71static unsigned int tx_stop = 5;72 73struct ntb_netdev {74	struct pci_dev *pdev;75	struct net_device *ndev;76	struct ntb_transport_qp *qp;77	struct timer_list tx_timer;78};79 80#define	NTB_TX_TIMEOUT_MS	100081#define	NTB_RXQ_SIZE		10082 83static void ntb_netdev_event_handler(void *data, int link_is_up)84{85	struct net_device *ndev = data;86	struct ntb_netdev *dev = netdev_priv(ndev);87 88	netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up,89		   ntb_transport_link_query(dev->qp));90 91	if (link_is_up) {92		if (ntb_transport_link_query(dev->qp))93			netif_carrier_on(ndev);94	} else {95		netif_carrier_off(ndev);96	}97}98 99static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,100				  void *data, int len)101{102	struct net_device *ndev = qp_data;103	struct sk_buff *skb;104	int rc;105 106	skb = data;107	if (!skb)108		return;109 110	netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);111 112	if (len < 0) {113		ndev->stats.rx_errors++;114		ndev->stats.rx_length_errors++;115		goto enqueue_again;116	}117 118	skb_put(skb, len);119	skb->protocol = eth_type_trans(skb, ndev);120	skb->ip_summed = CHECKSUM_NONE;121 122	if (netif_rx(skb) == NET_RX_DROP) {123		ndev->stats.rx_errors++;124		ndev->stats.rx_dropped++;125	} else {126		ndev->stats.rx_packets++;127		ndev->stats.rx_bytes += len;128	}129 130	skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);131	if (!skb) {132		ndev->stats.rx_errors++;133		ndev->stats.rx_frame_errors++;134		return;135	}136 137enqueue_again:138	rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);139	if (rc) {140		dev_kfree_skb_any(skb);141		ndev->stats.rx_errors++;142		ndev->stats.rx_fifo_errors++;143	}144}145 146static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,147				      struct ntb_transport_qp *qp, int size)148{149	struct ntb_netdev *dev = netdev_priv(netdev);150 151	netif_stop_queue(netdev);152	/* Make sure to see the latest value of ntb_transport_tx_free_entry()153	 * since the queue was last started.154	 */155	smp_mb();156 157	if (likely(ntb_transport_tx_free_entry(qp) < size)) {158		mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));159		return -EBUSY;160	}161 162	netif_start_queue(netdev);163	return 0;164}165 166static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,167				    struct ntb_transport_qp *qp, int size)168{169	if (netif_queue_stopped(ndev) ||170	    (ntb_transport_tx_free_entry(qp) >= size))171		return 0;172 173	return __ntb_netdev_maybe_stop_tx(ndev, qp, size);174}175 176static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,177				  void *data, int len)178{179	struct net_device *ndev = qp_data;180	struct sk_buff *skb;181	struct ntb_netdev *dev = netdev_priv(ndev);182 183	skb = data;184	if (!skb || !ndev)185		return;186 187	if (len > 0) {188		ndev->stats.tx_packets++;189		ndev->stats.tx_bytes += skb->len;190	} else {191		ndev->stats.tx_errors++;192		ndev->stats.tx_aborted_errors++;193	}194 195	dev_kfree_skb_any(skb);196 197	if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {198		/* Make sure anybody stopping the queue after this sees the new199		 * value of ntb_transport_tx_free_entry()200		 */201		smp_mb();202		if (netif_queue_stopped(ndev))203			netif_wake_queue(ndev);204	}205}206 207static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,208					 struct net_device *ndev)209{210	struct ntb_netdev *dev = netdev_priv(ndev);211	int rc;212 213	ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);214 215	rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);216	if (rc)217		goto err;218 219	/* check for next submit */220	ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);221 222	return NETDEV_TX_OK;223 224err:225	ndev->stats.tx_dropped++;226	ndev->stats.tx_errors++;227	return NETDEV_TX_BUSY;228}229 230static void ntb_netdev_tx_timer(struct timer_list *t)231{232	struct ntb_netdev *dev = from_timer(dev, t, tx_timer);233	struct net_device *ndev = dev->ndev;234 235	if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {236		mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));237	} else {238		/* Make sure anybody stopping the queue after this sees the new239		 * value of ntb_transport_tx_free_entry()240		 */241		smp_mb();242		if (netif_queue_stopped(ndev))243			netif_wake_queue(ndev);244	}245}246 247static int ntb_netdev_open(struct net_device *ndev)248{249	struct ntb_netdev *dev = netdev_priv(ndev);250	struct sk_buff *skb;251	int rc, i, len;252 253	/* Add some empty rx bufs */254	for (i = 0; i < NTB_RXQ_SIZE; i++) {255		skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);256		if (!skb) {257			rc = -ENOMEM;258			goto err;259		}260 261		rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,262					      ndev->mtu + ETH_HLEN);263		if (rc) {264			dev_kfree_skb(skb);265			goto err;266		}267	}268 269	timer_setup(&dev->tx_timer, ntb_netdev_tx_timer, 0);270 271	netif_carrier_off(ndev);272	ntb_transport_link_up(dev->qp);273	netif_start_queue(ndev);274 275	return 0;276 277err:278	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))279		dev_kfree_skb(skb);280	return rc;281}282 283static int ntb_netdev_close(struct net_device *ndev)284{285	struct ntb_netdev *dev = netdev_priv(ndev);286	struct sk_buff *skb;287	int len;288 289	ntb_transport_link_down(dev->qp);290 291	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))292		dev_kfree_skb(skb);293 294	del_timer_sync(&dev->tx_timer);295 296	return 0;297}298 299static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)300{301	struct ntb_netdev *dev = netdev_priv(ndev);302	struct sk_buff *skb;303	int len, rc;304 305	if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)306		return -EINVAL;307 308	if (!netif_running(ndev)) {309		WRITE_ONCE(ndev->mtu, new_mtu);310		return 0;311	}312 313	/* Bring down the link and dispose of posted rx entries */314	ntb_transport_link_down(dev->qp);315 316	if (ndev->mtu < new_mtu) {317		int i;318 319		for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)320			dev_kfree_skb(skb);321 322		for (; i; i--) {323			skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);324			if (!skb) {325				rc = -ENOMEM;326				goto err;327			}328 329			rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,330						      new_mtu + ETH_HLEN);331			if (rc) {332				dev_kfree_skb(skb);333				goto err;334			}335		}336	}337 338	WRITE_ONCE(ndev->mtu, new_mtu);339 340	ntb_transport_link_up(dev->qp);341 342	return 0;343 344err:345	ntb_transport_link_down(dev->qp);346 347	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))348		dev_kfree_skb(skb);349 350	netdev_err(ndev, "Error changing MTU, device inoperable\n");351	return rc;352}353 354static const struct net_device_ops ntb_netdev_ops = {355	.ndo_open = ntb_netdev_open,356	.ndo_stop = ntb_netdev_close,357	.ndo_start_xmit = ntb_netdev_start_xmit,358	.ndo_change_mtu = ntb_netdev_change_mtu,359	.ndo_set_mac_address = eth_mac_addr,360};361 362static void ntb_get_drvinfo(struct net_device *ndev,363			    struct ethtool_drvinfo *info)364{365	struct ntb_netdev *dev = netdev_priv(ndev);366 367	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));368	strscpy(info->version, NTB_NETDEV_VER, sizeof(info->version));369	strscpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));370}371 372static int ntb_get_link_ksettings(struct net_device *dev,373				  struct ethtool_link_ksettings *cmd)374{375	ethtool_link_ksettings_zero_link_mode(cmd, supported);376	ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);377	ethtool_link_ksettings_zero_link_mode(cmd, advertising);378	ethtool_link_ksettings_add_link_mode(cmd, advertising, Backplane);379 380	cmd->base.speed = SPEED_UNKNOWN;381	cmd->base.duplex = DUPLEX_FULL;382	cmd->base.port = PORT_OTHER;383	cmd->base.phy_address = 0;384	cmd->base.autoneg = AUTONEG_ENABLE;385 386	return 0;387}388 389static const struct ethtool_ops ntb_ethtool_ops = {390	.get_drvinfo = ntb_get_drvinfo,391	.get_link = ethtool_op_get_link,392	.get_link_ksettings = ntb_get_link_ksettings,393};394 395static const struct ntb_queue_handlers ntb_netdev_handlers = {396	.tx_handler = ntb_netdev_tx_handler,397	.rx_handler = ntb_netdev_rx_handler,398	.event_handler = ntb_netdev_event_handler,399};400 401static int ntb_netdev_probe(struct device *client_dev)402{403	struct ntb_dev *ntb;404	struct net_device *ndev;405	struct pci_dev *pdev;406	struct ntb_netdev *dev;407	int rc;408 409	ntb = dev_ntb(client_dev->parent);410	pdev = ntb->pdev;411	if (!pdev)412		return -ENODEV;413 414	ndev = alloc_etherdev(sizeof(*dev));415	if (!ndev)416		return -ENOMEM;417 418	SET_NETDEV_DEV(ndev, client_dev);419 420	dev = netdev_priv(ndev);421	dev->ndev = ndev;422	dev->pdev = pdev;423	ndev->features = NETIF_F_HIGHDMA;424 425	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;426 427	ndev->hw_features = ndev->features;428	ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);429 430	eth_random_addr(ndev->perm_addr);431	dev_addr_set(ndev, ndev->perm_addr);432 433	ndev->netdev_ops = &ntb_netdev_ops;434	ndev->ethtool_ops = &ntb_ethtool_ops;435 436	ndev->min_mtu = 0;437	ndev->max_mtu = ETH_MAX_MTU;438 439	dev->qp = ntb_transport_create_queue(ndev, client_dev,440					     &ntb_netdev_handlers);441	if (!dev->qp) {442		rc = -EIO;443		goto err;444	}445 446	ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;447 448	rc = register_netdev(ndev);449	if (rc)450		goto err1;451 452	dev_set_drvdata(client_dev, ndev);453	dev_info(&pdev->dev, "%s created\n", ndev->name);454	return 0;455 456err1:457	ntb_transport_free_queue(dev->qp);458err:459	free_netdev(ndev);460	return rc;461}462 463static void ntb_netdev_remove(struct device *client_dev)464{465	struct net_device *ndev = dev_get_drvdata(client_dev);466	struct ntb_netdev *dev = netdev_priv(ndev);467 468	unregister_netdev(ndev);469	ntb_transport_free_queue(dev->qp);470	free_netdev(ndev);471}472 473static struct ntb_transport_client ntb_netdev_client = {474	.driver.name = KBUILD_MODNAME,475	.driver.owner = THIS_MODULE,476	.probe = ntb_netdev_probe,477	.remove = ntb_netdev_remove,478};479 480static int __init ntb_netdev_init_module(void)481{482	int rc;483 484	rc = ntb_transport_register_client_dev(KBUILD_MODNAME);485	if (rc)486		return rc;487 488	rc = ntb_transport_register_client(&ntb_netdev_client);489	if (rc) {490		ntb_transport_unregister_client_dev(KBUILD_MODNAME);491		return rc;492	}493 494	return 0;495}496late_initcall(ntb_netdev_init_module);497 498static void __exit ntb_netdev_exit_module(void)499{500	ntb_transport_unregister_client(&ntb_netdev_client);501	ntb_transport_unregister_client_dev(KBUILD_MODNAME);502}503module_exit(ntb_netdev_exit_module);504