Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/537195/?format=api
{ "id": 537195, "url": "http://patchwork.ozlabs.org/api/patches/537195/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/1446010391-14421-3-git-send-email-gangfeng.huang@ni.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1446010391-14421-3-git-send-email-gangfeng.huang@ni.com>", "list_archive_url": null, "date": "2015-10-28T05:33:11", "name": "[net-next,2/2] igb: add a character device to support AVB", "commit_ref": null, "pull_url": null, "state": "rejected", "archived": false, "hash": "d6e84cbe22e743960df4ff27f8b3ccefa031167d", "submitter": { "id": 67513, "url": "http://patchwork.ozlabs.org/api/people/67513/?format=api", "name": "Gangfeng Huang", "email": "gangfeng.huang@ni.com" }, "delegate": { "id": 68, "url": "http://patchwork.ozlabs.org/api/users/68/?format=api", "username": "jtkirshe", "first_name": "Jeff", "last_name": "Kirsher", "email": "jeffrey.t.kirsher@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/1446010391-14421-3-git-send-email-gangfeng.huang@ni.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/537195/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/537195/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@lists.osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Received": [ "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ozlabs.org (Postfix) with ESMTP id 8DD9214090A\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 28 Oct 2015 16:33:53 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id CE58D2FBFF;\n\tWed, 28 Oct 2015 05:33:52 +0000 (UTC)", "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 8Qy-bDHETa5e; Wed, 28 Oct 2015 05:33:49 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id CC94D30A4B;\n\tWed, 28 Oct 2015 05:33:49 +0000 (UTC)", "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ash.osuosl.org (Postfix) with ESMTP id 4B6511C44B1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 28 Oct 2015 05:33:48 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 40AD330A4B\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 28 Oct 2015 05:33:48 +0000 (UTC)", "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id YltV2+AZPtpo for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 28 Oct 2015 05:33:45 +0000 (UTC)", "from ni.com (skprod3.natinst.com [130.164.80.24])\n\tby silver.osuosl.org (Postfix) with ESMTPS id 53CA330A25\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 28 Oct 2015 05:33:45 +0000 (UTC)", "from us-aus-mgwout2.amer.corp.natinst.com\n\t(nb-chan1-1338.natinst.com [130.164.19.134])\n\tby us-aus-skprod3.natinst.com (8.15.0.59/8.15.0.59) with ESMTP id\n\tt9S5XiAP024953 for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 28 Oct 2015 00:33:44 -0500", "from ni.com ([130.164.14.198])\n\tby us-aus-mgwout2.amer.corp.natinst.com (Lotus Domino Release\n\t8.5.3FP6 HF1218) with ESMTP id 2015102800334400-912704 ;\n\tWed, 28 Oct 2015 00:33:44 -0500 " ], "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "From": "Gangfeng Huang <gangfeng.huang@ni.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Wed, 28 Oct 2015 13:33:11 +0800", "Message-Id": "<1446010391-14421-3-git-send-email-gangfeng.huang@ni.com>", "X-Mailer": "git-send-email 1.7.9.5", "In-Reply-To": "<1446010391-14421-1-git-send-email-gangfeng.huang@ni.com>", "References": "<1446010391-14421-1-git-send-email-gangfeng.huang@ni.com>", "X-MIMETrack": "Itemize by SMTP Server on US-AUS-MGWOut2/AUS/H/NIC(Release\n\t8.5.3FP6 HF1218|December 12, 2014) at 10/28/2015 12:33:44 AM,\n\tSerialize by Router on US-AUS-MGWOut2/AUS/H/NIC(Release 8.5.3FP6\n\tHF1218|December 12, 2014) at 10/28/2015 12:33:44 AM,\n\tSerialize complete at 10/28/2015 12:33:44 AM", "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2015-10-28_05:, , signatures=0", "Subject": "[Intel-wired-lan] [PATCH net-next 2/2] igb: add a character device\n\tto support AVB", "X-BeenThere": "intel-wired-lan@lists.osuosl.org", "X-Mailman-Version": "2.1.18-1", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.lists.osuosl.org>", "List-Unsubscribe": "<http://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@lists.osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@lists.osuosl.org?subject=help>", "List-Subscribe": "<http://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@lists.osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@lists.osuosl.org>" }, "content": "This patch create a character device for Intel I210 Ethernet controller,\nit can be used for developing Audio/Video Bridging applications,Industrial\nEthernet applications which require precise timing control over frame\ntransmission, or test harneses for measuring system latencies and samping\nevents.\n\nAs the AVB queues (0,1) are mapped to a user-space application, typical\nLAN traffic must be steered away from these queues. For transmit, this\ndriver implements one method registering an ndo_select_queue handler to\nmap traffic to queue[3]. and set the register MRQC to receive all BE\ntraffic to Rx queue[3].\n\nThis patch is reference to the Intel Open-AVB project:\nhttp://github.com/AVnu/Open-AVB/tree/master/kmod/igb\n\nSigned-off-by: Gangfeng Huang <gangfeng.huang@ni.com>\n---\n drivers/net/ethernet/intel/igb/Makefile | 2 +-\n drivers/net/ethernet/intel/igb/e1000_defines.h | 1 +\n drivers/net/ethernet/intel/igb/igb.h | 14 +-\n drivers/net/ethernet/intel/igb/igb_cdev.c | 511 ++++++++++++++++++++++++\n drivers/net/ethernet/intel/igb/igb_cdev.h | 45 +++\n drivers/net/ethernet/intel/igb/igb_main.c | 104 ++++-\n 6 files changed, 664 insertions(+), 13 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/igb/igb_cdev.c\n create mode 100644 drivers/net/ethernet/intel/igb/igb_cdev.h", "diff": "diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile\nindex 5bcb2de..3fee429 100644\n--- a/drivers/net/ethernet/intel/igb/Makefile\n+++ b/drivers/net/ethernet/intel/igb/Makefile\n@@ -33,4 +33,4 @@ obj-$(CONFIG_IGB) += igb.o\n \n igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \\\n \t e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \\\n-\t e1000_i210.o igb_ptp.o igb_hwmon.o\n+\t e1000_i210.o igb_ptp.o igb_hwmon.o igb_cdev.o\ndiff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h\nindex f09d016..6bf0e56 100644\n--- a/drivers/net/ethernet/intel/igb/e1000_defines.h\n+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h\n@@ -112,6 +112,7 @@\n #define E1000_MRQC_RSS_FIELD_IPV6 0x00100000\n #define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000\n \n+#define E1000_MRQC_DEF_QUEUE_OFFSET 0x3\n \n /* Management Control */\n #define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */\ndiff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h\nindex b84a266..f661729 100644\n--- a/drivers/net/ethernet/intel/igb/igb.h\n+++ b/drivers/net/ethernet/intel/igb/igb.h\n@@ -38,6 +38,8 @@\n #include <linux/i2c-algo-bit.h>\n #include <linux/pci.h>\n #include <linux/mdio.h>\n+#include <linux/types.h>\n+#include <linux/cdev.h>\n \n struct igb_adapter;\n \n@@ -50,12 +52,12 @@ struct igb_adapter;\n #define IGB_70K_ITR\t\t56\n \n /* TX/RX descriptor defines */\n-#define IGB_DEFAULT_TXD\t\t256\n+#define IGB_DEFAULT_TXD\t\t1024\n #define IGB_DEFAULT_TX_WORK\t128\n #define IGB_MIN_TXD\t\t80\n #define IGB_MAX_TXD\t\t4096\n \n-#define IGB_DEFAULT_RXD\t\t256\n+#define IGB_DEFAULT_RXD\t\t1024\n #define IGB_MIN_RXD\t\t80\n #define IGB_MAX_RXD\t\t4096\n \n@@ -468,6 +470,14 @@ struct igb_adapter {\n \tu16 eee_advert;\n \n \tbool qav_mode;\n+\tstruct cdev char_dev;\n+\tstruct list_head user_page_list;\n+\tstruct mutex user_page_mutex; /* protect user_page_list */\n+\tunsigned long tx_uring_init;\n+\tunsigned long rx_uring_init;\n+\tstruct mutex user_ring_mutex; /* protect tx/rx_uring_init */\n+\tbool cdev_in_use;\n+\tstruct mutex cdev_mutex; /* protect cdev_in_use */\n };\n \n #define IGB_FLAG_HAS_MSI\t\t(1 << 0)\ndiff --git a/drivers/net/ethernet/intel/igb/igb_cdev.c b/drivers/net/ethernet/intel/igb/igb_cdev.c\nnew file mode 100644\nindex 0000000..df237c6\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igb/igb_cdev.c\n@@ -0,0 +1,511 @@\n+#include \"igb.h\"\n+#include \"igb_cdev.h\"\n+\n+#include <linux/pagemap.h>\n+#include <linux/bitops.h>\n+#include <linux/types.h>\n+#include <linux/cdev.h>\n+\n+/* TSN char dev */\n+static DECLARE_BITMAP(cdev_minors, IGB_MAX_DEV_NUM);\n+\n+static int igb_major;\n+static struct class *igb_class;\n+static const char * const igb_class_name = \"igb_tsn\";\n+static const char * const igb_dev_name = \"igb_tsn_%s\";\n+\n+/* user-mode API forward definitions */\n+static int igb_open_file(struct inode *inode, struct file *file);\n+static int igb_close_file(struct inode *inode, struct file *file);\n+static int igb_mmap(struct file *file, struct vm_area_struct *vma);\n+static long igb_ioctl_file(struct file *file, unsigned int cmd,\n+\t\t\t unsigned long arg);\n+\n+/* user-mode IO API registrations */\n+static const struct file_operations igb_fops = {\n+\t\t.owner = THIS_MODULE,\n+\t\t.llseek = no_llseek,\n+\t\t.open\t= igb_open_file,\n+\t\t.release = igb_close_file,\n+\t\t.mmap\t= igb_mmap,\n+\t\t.unlocked_ioctl = igb_ioctl_file,\n+};\n+\n+int igb_tsn_setup_all_tx_resources(struct igb_adapter *adapter)\n+{\n+\tstruct pci_dev *pdev = adapter->pdev;\n+\tint i, err = 0;\n+\n+\tfor (i = 0; i < IGB_USER_TX_QUEUES; i++) {\n+\t\terr = igb_setup_tx_resources(adapter->tx_ring[i]);\n+\t\tif (err) {\n+\t\t\tdev_err(&pdev->dev,\n+\t\t\t\t\"Allocation for Tx Queue %u failed\\n\", i);\n+\t\t\tfor (i--; i >= 0; i--)\n+\t\t\t\tigb_free_tx_resources(adapter->tx_ring[i]);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn err;\n+}\n+\n+int igb_tsn_setup_all_rx_resources(struct igb_adapter *adapter)\n+{\n+\tstruct pci_dev *pdev = adapter->pdev;\n+\tint i, err = 0;\n+\n+\tfor (i = 0; i < IGB_USER_RX_QUEUES; i++) {\n+\t\terr = igb_setup_rx_resources(adapter->rx_ring[i]);\n+\t\tif (err) {\n+\t\t\tdev_err(&pdev->dev,\n+\t\t\t\t\"Allocation for Rx Queue %u failed\\n\", i);\n+\t\t\tfor (i--; i >= 0; i--)\n+\t\t\t\tigb_free_rx_resources(adapter->rx_ring[i]);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn err;\n+}\n+\n+void igb_tsn_free_all_tx_resources(struct igb_adapter *adapter)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < IGB_USER_TX_QUEUES; i++)\n+\t\tigb_free_tx_resources(adapter->tx_ring[i]);\n+}\n+\n+void igb_tsn_free_all_rx_resources(struct igb_adapter *adapter)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < IGB_USER_RX_QUEUES; i++)\n+\t\tigb_free_rx_resources(adapter->rx_ring[i]);\n+}\n+\n+static int igb_bind(struct file *file, void __user *argp)\n+{\n+\tstruct igb_adapter *adapter;\n+\tu32 mmap_size;\n+\n+\tadapter = (struct igb_adapter *)file->private_data;\n+\n+\tif (NULL == adapter)\n+\t\treturn -ENOENT;\n+\n+\tmmap_size = pci_resource_len(adapter->pdev, 0);\n+\n+\tif (copy_to_user(argp, &mmap_size, sizeof(mmap_size)))\n+\t\treturn -EFAULT;\n+\n+\treturn 0;\n+}\n+\n+static long igb_mapring(struct file *file, void __user *arg)\n+{\n+\tstruct igb_adapter *adapter;\n+\tstruct igb_buf_cmd req;\n+\tint queue_size;\n+\tunsigned long *uring_init;\n+\tstruct igb_ring *ring;\n+\tint err;\n+\n+\tif (copy_from_user(&req, arg, sizeof(req)))\n+\t\treturn -EFAULT;\n+\n+\tif (req.flags != 0 && req.flags != 1)\n+\t\treturn -EINVAL;\n+\n+\tadapter = file->private_data;\n+\tif (NULL == adapter) {\n+\t\tdev_err(&adapter->pdev->dev, \"map to unbound device!\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\t/* Req flags, Tx: 0, Rx: 1 */\n+\tif (req.flags == 0) {\n+\t\tqueue_size = IGB_USER_TX_QUEUES;\n+\t\turing_init = &adapter->tx_uring_init;\n+\t\tring = adapter->tx_ring[req.queue];\n+\t} else {\n+\t\tqueue_size = IGB_USER_RX_QUEUES;\n+\t\turing_init = &adapter->rx_uring_init;\n+\t\tring = adapter->rx_ring[req.queue];\n+\t}\n+\n+\tmutex_lock(&adapter->user_ring_mutex);\n+\tif (test_bit(req.queue, uring_init)) {\n+\t\tdev_err(&adapter->pdev->dev, \"the queue is in using\\n\");\n+\t\terr = -EBUSY;\n+\t\tgoto failed;\n+\t}\n+\n+\tif (req.queue >= queue_size) {\n+\t\terr = -EINVAL;\n+\t\tgoto failed;\n+\t}\n+\n+\tset_pages_uc(virt_to_page(ring->desc), ring->size >> PAGE_SHIFT);\n+\tset_bit(req.queue, uring_init);\n+\tmutex_unlock(&adapter->user_ring_mutex);\n+\n+\treq.physaddr = ring->dma;\n+\treq.mmap_size = ring->size;\n+\n+\tif (copy_to_user(arg, &req, sizeof(req))) {\n+\t\tdev_err(&adapter->pdev->dev, \"copyout to user failed\\n\");\n+\t\treturn -EFAULT;\n+\t}\n+\n+\treturn 0;\n+failed:\n+\tmutex_unlock(&adapter->user_ring_mutex);\n+\treturn err;\n+}\n+\n+static long igb_mapbuf(struct file *file, void __user *arg)\n+{\n+\tstruct igb_adapter *adapter;\n+\tstruct igb_buf_cmd req;\n+\tstruct page *page;\n+\tdma_addr_t page_dma;\n+\tstruct igb_user_page *userpage;\n+\tint err = 0;\n+\tint direction;\n+\n+\tif (copy_from_user(&req, arg, sizeof(req)))\n+\t\treturn -EFAULT;\n+\n+\tif (req.flags != 0 && req.flags != 1)\n+\t\treturn -EINVAL;\n+\n+\tadapter = file->private_data;\n+\tif (NULL == adapter) {\n+\t\tdev_err(&adapter->pdev->dev, \"map to unbound device!\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tuserpage = kzalloc(sizeof(*userpage), GFP_KERNEL);\n+\tif (unlikely(!userpage))\n+\t\treturn -ENOMEM;\n+\n+\tpage = alloc_page(GFP_KERNEL | __GFP_COLD);\n+\tif (unlikely(!page)) {\n+\t\terr = -ENOMEM;\n+\t\tgoto failed;\n+\t}\n+\n+\tdirection = req.flags ? DMA_FROM_DEVICE : DMA_TO_DEVICE;\n+\tpage_dma = dma_map_page(&adapter->pdev->dev, page,\n+\t\t\t\t0, PAGE_SIZE, direction);\n+\n+\tif (dma_mapping_error(&adapter->pdev->dev, page_dma)) {\n+\t\tput_page(page);\n+\t\terr = -ENOMEM;\n+\t\tgoto failed;\n+\t}\n+\n+\tset_pages_uc(page, 1);\n+\tuserpage->page = page;\n+\tuserpage->page_dma = page_dma;\n+\tuserpage->flags = req.flags;\n+\n+\tmutex_lock(&adapter->user_page_mutex);\n+\tlist_add_tail(&userpage->page_node, &adapter->user_page_list);\n+\tmutex_unlock(&adapter->user_page_mutex);\n+\n+\treq.physaddr = page_dma;\n+\treq.mmap_size = PAGE_SIZE;\n+\n+\tif (copy_to_user(arg, &req, sizeof(req))) {\n+\t\tdev_err(&adapter->pdev->dev, \"copyout to user failed\\n\");\n+\t\treturn -EFAULT;\n+\t}\n+\treturn 0;\n+\n+failed:\n+\tkfree(userpage);\n+\treturn err;\n+}\n+\n+static long igb_unmapring(struct file *file, void __user *arg)\n+{\n+\tstruct igb_adapter *adapter;\n+\tstruct igb_buf_cmd req;\n+\tstruct igb_ring *ring;\n+\tint queue_size;\n+\tunsigned long *uring_init;\n+\tint err;\n+\n+\tif (copy_from_user(&req, arg, sizeof(req)))\n+\t\treturn -EFAULT;\n+\n+\tif (req.flags != 0 && req.flags != 1)\n+\t\treturn -EINVAL;\n+\n+\tadapter = file->private_data;\n+\tif (NULL == adapter) {\n+\t\tdev_err(&adapter->pdev->dev, \"map to unbound device!\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tif (req.flags == 0) {\n+\t\tqueue_size = IGB_USER_TX_QUEUES;\n+\t\turing_init = &adapter->tx_uring_init;\n+\t\tring = adapter->tx_ring[req.queue];\n+\t} else {\n+\t\tqueue_size = IGB_USER_RX_QUEUES;\n+\t\turing_init = &adapter->rx_uring_init;\n+\t\tring = adapter->rx_ring[req.queue];\n+\t}\n+\n+\tif (req.queue >= queue_size)\n+\t\treturn -EINVAL;\n+\n+\tmutex_lock(&adapter->user_ring_mutex);\n+\tif (!test_bit(req.queue, uring_init)) {\n+\t\tdev_err(&adapter->pdev->dev,\n+\t\t\t\"the ring is already unmap\\n\");\n+\t\terr = -EINVAL;\n+\t\tgoto failed;\n+\t}\n+\n+\tset_pages_wb(virt_to_page(ring->desc), ring->size >> PAGE_SHIFT);\n+\tclear_bit(req.queue, uring_init);\n+\tmutex_unlock(&adapter->user_ring_mutex);\n+\n+\treturn 0;\n+failed:\n+\tmutex_unlock(&adapter->user_ring_mutex);\n+\treturn err;\n+}\n+\n+static void igb_free_page(struct igb_adapter *adapter,\n+\t\t\t struct igb_user_page *userpage)\n+{\n+\tint direction = userpage->flags ? DMA_FROM_DEVICE : DMA_TO_DEVICE;\n+\n+\tset_pages_wb(userpage->page, 1);\n+\tdma_unmap_page(&adapter->pdev->dev,\n+\t\t userpage->page_dma,\n+\t\t PAGE_SIZE,\n+\t\t direction);\n+\n+\tput_page(userpage->page);\n+\tlist_del(&userpage->page_node);\n+\tkfree(userpage);\n+\tuserpage = NULL;\n+}\n+\n+static long igb_unmapbuf(struct file *file, void __user *arg)\n+{\n+\tint err = 0;\n+\tstruct igb_adapter *adapter;\n+\tstruct igb_buf_cmd req;\n+\tstruct igb_user_page *userpage, *tmp;\n+\n+\tif (copy_from_user(&req, arg, sizeof(req)))\n+\t\treturn -EFAULT;\n+\n+\tadapter = file->private_data;\n+\tif (NULL == adapter) {\n+\t\tdev_err(&adapter->pdev->dev, \"map to unbound device!\\n\");\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tmutex_lock(&adapter->user_page_mutex);\n+\tif (list_empty(&adapter->user_page_list)) {\n+\t\terr = -EINVAL;\n+\t\tgoto failed;\n+\t}\n+\n+\tlist_for_each_entry_safe(userpage, tmp, &adapter->user_page_list,\n+\t\t\t\t page_node) {\n+\t\tif (req.physaddr == userpage->page_dma) {\n+\t\t\tigb_free_page(adapter, userpage);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tmutex_unlock(&adapter->user_page_mutex);\n+\n+\treturn 0;\n+failed:\n+\tmutex_unlock(&adapter->user_page_mutex);\n+\treturn err;\n+}\n+\n+static long igb_ioctl_file(struct file *file, unsigned int cmd,\n+\t\t\t unsigned long arg)\n+{\n+\tvoid __user *argp = (void __user *)arg;\n+\tint err;\n+\n+\tswitch (cmd) {\n+\tcase IGB_BIND:\n+\t\terr = igb_bind(file, argp);\n+\t\tbreak;\n+\tcase IGB_MAPRING:\n+\t\terr = igb_mapring(file, argp);\n+\t\tbreak;\n+\tcase IGB_MAPBUF:\n+\t\terr = igb_mapbuf(file, argp);\n+\t\tbreak;\n+\tcase IGB_UNMAPRING:\n+\t\terr = igb_unmapring(file, argp);\n+\t\tbreak;\n+\tcase IGB_UNMAPBUF:\n+\t\terr = igb_unmapbuf(file, argp);\n+\t\tbreak;\n+\tdefault:\n+\t\terr = -EINVAL;\n+\t\tbreak;\n+\t};\n+\n+\treturn err;\n+}\n+\n+static int igb_open_file(struct inode *inode, struct file *file)\n+{\n+\tstruct igb_adapter *adapter;\n+\tint err = 0;\n+\n+\tadapter = container_of(inode->i_cdev, struct igb_adapter, char_dev);\n+\tif (!adapter)\n+\t\treturn -ENOENT;\n+\n+\tif (!adapter->qav_mode)\n+\t\treturn -EPERM;\n+\n+\tmutex_lock(&adapter->cdev_mutex);\n+\tif (adapter->cdev_in_use) {\n+\t\terr = -EBUSY;\n+\t\tgoto failed;\n+\t}\n+\n+\tfile->private_data = adapter;\n+\tadapter->cdev_in_use = true;\n+\tmutex_unlock(&adapter->cdev_mutex);\n+\n+\treturn 0;\n+failed:\n+\tmutex_unlock(&adapter->cdev_mutex);\n+\treturn err;\n+}\n+\n+static int igb_close_file(struct inode *inode, struct file *file)\n+{\n+\tstruct igb_adapter *adapter = file->private_data;\n+\n+\tif (NULL == adapter)\n+\t\treturn 0;\n+\n+\tmutex_lock(&adapter->cdev_mutex);\n+\tif (!adapter->cdev_in_use)\n+\t\tgoto out;\n+\n+\tmutex_lock(&adapter->user_page_mutex);\n+\tif (!list_empty(&adapter->user_page_list)) {\n+\t\tstruct igb_user_page *userpage, *tmp;\n+\n+\t\tlist_for_each_entry_safe(userpage, tmp,\n+\t\t\t\t\t &adapter->user_page_list, page_node) {\n+\t\t\tif (userpage)\n+\t\t\t\tigb_free_page(adapter, userpage);\n+\t\t}\n+\t}\n+\tmutex_unlock(&adapter->user_page_mutex);\n+\n+\tfile->private_data = NULL;\n+\tadapter->cdev_in_use = false;\n+\tadapter->tx_uring_init = 0;\n+\tadapter->rx_uring_init = 0;\n+\n+out:\n+\tmutex_unlock(&adapter->cdev_mutex);\n+\treturn 0;\n+}\n+\n+static int igb_mmap(struct file *file, struct vm_area_struct *vma)\n+{\n+\tstruct igb_adapter *adapter = file->private_data;\n+\tunsigned long size = vma->vm_end - vma->vm_start;\n+\tdma_addr_t pgoff = vma->vm_pgoff;\n+\tdma_addr_t physaddr;\n+\n+\tif (NULL == adapter)\n+\t\treturn -ENODEV;\n+\n+\tif (pgoff == 0)\n+\t\tphysaddr = pci_resource_start(adapter->pdev, 0) >> PAGE_SHIFT;\n+\telse\n+\t\tphysaddr = pgoff;\n+\n+\tvma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);\n+\n+\tif (remap_pfn_range(vma, vma->vm_start,\n+\t\t\t physaddr, size, vma->vm_page_prot))\n+\t\treturn -EAGAIN;\n+\n+\treturn 0;\n+}\n+\n+int igb_add_cdev(struct igb_adapter *adapter)\n+{\n+\tint result = 0;\n+\tdev_t dev_num;\n+\tint igb_minor;\n+\n+\tigb_minor = find_first_zero_bit(cdev_minors, IGB_MAX_DEV_NUM);\n+\tif (igb_minor >= IGB_MAX_DEV_NUM)\n+\t\treturn -EBUSY;\n+\tset_bit(igb_minor, cdev_minors);\n+\n+\tdev_num = MKDEV(igb_major, igb_minor);\n+\tcdev_init(&adapter->char_dev, &igb_fops);\n+\tadapter->char_dev.owner = THIS_MODULE;\n+\tadapter->char_dev.ops = &igb_fops;\n+\tresult = cdev_add(&adapter->char_dev, dev_num, 1);\n+\n+\tif (result) {\n+\t\tdev_err(&adapter->pdev->dev,\n+\t\t\t\"igb_tsn: add character device failed\\n\");\n+\t\treturn result;\n+\t}\n+\n+\tdevice_create(igb_class, NULL, dev_num, NULL, igb_dev_name,\n+\t\t adapter->netdev->name);\n+\n+\treturn 0;\n+}\n+\n+void igb_remove_cdev(struct igb_adapter *adapter)\n+{\n+\tdevice_destroy(igb_class, adapter->char_dev.dev);\n+\tcdev_del(&adapter->char_dev);\n+}\n+\n+int igb_cdev_init(char *igb_driver_name)\n+{\n+\tdev_t dev_num;\n+\tint ret;\n+\n+\tret = alloc_chrdev_region(&dev_num, 0, IGB_MAX_DEV_NUM,\n+\t\t\t\t igb_driver_name);\n+\tif (ret)\n+\t\treturn ret;\n+\tigb_major = MAJOR(dev_num);\n+\n+\tigb_class = class_create(THIS_MODULE, igb_class_name);\n+\tif (IS_ERR(igb_class))\n+\t\tpr_info(\"igb_tsn: create device class failed\\n\");\n+\n+\treturn ret;\n+}\n+\n+void igb_cdev_destroy(void)\n+{\n+\tclass_destroy(igb_class);\n+\tunregister_chrdev_region(MKDEV(igb_major, 0), IGB_MAX_DEV_NUM);\n+}\ndiff --git a/drivers/net/ethernet/intel/igb/igb_cdev.h b/drivers/net/ethernet/intel/igb/igb_cdev.h\nnew file mode 100644\nindex 0000000..07fc0b6\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/igb/igb_cdev.h\n@@ -0,0 +1,45 @@\n+#ifndef _IGB_CDEV_H_\n+#define _IGB_CDEV_H_\n+\n+#include <asm/page.h>\n+#include <asm/ioctl.h>\n+\n+struct igb_adapter;\n+/* queues reserved for user mode */\n+#define IGB_USER_TX_QUEUES 2\n+#define IGB_USER_RX_QUEUES 2\n+#define IGB_MAX_DEV_NUM 64\n+\n+/* TSN char dev ioctls */\n+#define IGB_BIND _IOW('E', 200, int)\n+#define IGB_MAPRING _IOW('E', 201, int)\n+#define IGB_UNMAPRING _IOW('E', 202, int)\n+#define IGB_MAPBUF _IOW('E', 203, int)\n+#define IGB_UNMAPBUF _IOW('E', 204, int)\n+\n+/* Used with both map/unmap ring & buf ioctls */\n+struct igb_buf_cmd {\n+\tu64\t\tphysaddr;\n+\tu32\t\tqueue;\n+\tu32\t\tmmap_size;\n+\tu32\t\tflags;\n+};\n+\n+struct igb_user_page {\n+\tstruct list_head page_node;\n+\tstruct page *page;\n+\tdma_addr_t page_dma;\n+\tu32 flags;\n+};\n+\n+int igb_tsn_setup_all_tx_resources(struct igb_adapter *);\n+int igb_tsn_setup_all_rx_resources(struct igb_adapter *);\n+void igb_tsn_free_all_tx_resources(struct igb_adapter *);\n+void igb_tsn_free_all_rx_resources(struct igb_adapter *);\n+\n+int igb_add_cdev(struct igb_adapter *adapter);\n+void igb_remove_cdev(struct igb_adapter *adapter);\n+int igb_cdev_init(char *igb_driver_name);\n+void igb_cdev_destroy(void);\n+\n+#endif\ndiff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c\nindex 1d00f41..4193e58 100644\n--- a/drivers/net/ethernet/intel/igb/igb_main.c\n+++ b/drivers/net/ethernet/intel/igb/igb_main.c\n@@ -55,6 +55,7 @@\n #endif\n #include <linux/i2c.h>\n #include \"igb.h\"\n+#include \"igb_cdev.h\"\n \n #define MAJ 5\n #define MIN 3\n@@ -688,6 +689,11 @@ static int __init igb_init_module(void)\n #ifdef CONFIG_IGB_DCA\n \tdca_register_notify(&dca_notifier);\n #endif\n+\n+\tret = igb_cdev_init(igb_driver_name);\n+\tif (ret)\n+\t\treturn ret;\n+\n \tret = pci_register_driver(&igb_driver);\n \treturn ret;\n }\n@@ -706,6 +712,8 @@ static void __exit igb_exit_module(void)\n \tdca_unregister_notify(&dca_notifier);\n #endif\n \tpci_unregister_driver(&igb_driver);\n+\n+\tigb_cdev_destroy();\n }\n \n module_exit(igb_exit_module);\n@@ -1629,7 +1637,8 @@ static void igb_configure(struct igb_adapter *adapter)\n \t * at least 1 descriptor unused to make sure\n \t * next_to_use != next_to_clean\n \t */\n-\tfor (i = 0; i < adapter->num_rx_queues; i++) {\n+\ti = adapter->qav_mode ? IGB_USER_RX_QUEUES : 0;\n+\tfor (; i < adapter->num_rx_queues; i++) {\n \t\tstruct igb_ring *ring = adapter->rx_ring[i];\n \t\tigb_alloc_rx_buffers(ring, igb_desc_unused(ring));\n \t}\n@@ -2077,10 +2086,24 @@ static int igb_set_features(struct net_device *netdev,\n \treturn 0;\n }\n \n+static u16 igb_select_queue(struct net_device *netdev,\n+\t\t\t struct sk_buff *skb,\n+\t\t\t void *accel_priv,\n+\t\t\t select_queue_fallback_t fallback)\n+{\n+\tstruct igb_adapter *adapter = netdev_priv(netdev);\n+\n+\tif (adapter->qav_mode)\n+\t\treturn adapter->num_tx_queues - 1;\n+\telse\n+\t\treturn fallback(netdev, skb);\n+}\n+\n static const struct net_device_ops igb_netdev_ops = {\n \t.ndo_open\t\t= igb_open,\n \t.ndo_stop\t\t= igb_close,\n \t.ndo_start_xmit\t\t= igb_xmit_frame,\n+\t.ndo_select_queue\t= igb_select_queue,\n \t.ndo_get_stats64\t= igb_get_stats64,\n \t.ndo_set_rx_mode\t= igb_set_rx_mode,\n \t.ndo_set_mac_address\t= igb_set_mac,\n@@ -2306,6 +2329,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \tadapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);\n \tadapter->qav_mode = false;\n \n+\tadapter->tx_uring_init = 0;\n+\tadapter->rx_uring_init = 0;\n+\tadapter->cdev_in_use = false;\n+\n \terr = -EIO;\n \thw->hw_addr = pci_iomap(pdev, 0, 0);\n \tif (!hw->hw_addr)\n@@ -2559,6 +2586,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\t}\n \t}\n \n+\terr = igb_add_cdev(adapter);\n+\tif (err)\n+\t\tgoto err_register;\n+\n \t/* carrier off reporting is important to ethtool even BEFORE open */\n \tnetif_carrier_off(netdev);\n \n@@ -2803,6 +2834,8 @@ static void igb_remove(struct pci_dev *pdev)\n \tstruct igb_adapter *adapter = netdev_priv(netdev);\n \tstruct e1000_hw *hw = &adapter->hw;\n \n+\tigb_remove_cdev(adapter);\n+\n \tpm_runtime_get_noresume(&pdev->dev);\n #ifdef CONFIG_IGB_HWMON\n \tigb_sysfs_exit(adapter);\n@@ -2985,6 +3018,12 @@ static int igb_sw_init(struct igb_adapter *adapter)\n \tadapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;\n \n \tspin_lock_init(&adapter->stats64_lock);\n+\n+\tINIT_LIST_HEAD(&adapter->user_page_list);\n+\tmutex_init(&adapter->user_page_mutex);\n+\tmutex_init(&adapter->user_ring_mutex);\n+\tmutex_init(&adapter->cdev_mutex);\n+\n #ifdef CONFIG_PCI_IOV\n \tswitch (hw->mac.type) {\n \tcase e1000_82576:\n@@ -3231,7 +3270,8 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter)\n \tstruct pci_dev *pdev = adapter->pdev;\n \tint i, err = 0;\n \n-\tfor (i = 0; i < adapter->num_tx_queues; i++) {\n+\ti = adapter->qav_mode ? IGB_USER_TX_QUEUES : 0;\n+\tfor (; i < adapter->num_tx_queues; i++) {\n \t\terr = igb_setup_tx_resources(adapter->tx_ring[i]);\n \t\tif (err) {\n \t\t\tdev_err(&pdev->dev,\n@@ -3319,7 +3359,8 @@ static void igb_configure_tx(struct igb_adapter *adapter)\n {\n \tint i;\n \n-\tfor (i = 0; i < adapter->num_tx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_TX_QUEUES : 0;\n+\tfor (; i < adapter->num_tx_queues; i++)\n \t\tigb_configure_tx_ring(adapter, adapter->tx_ring[i]);\n }\n \n@@ -3374,7 +3415,8 @@ static int igb_setup_all_rx_resources(struct igb_adapter *adapter)\n \tstruct pci_dev *pdev = adapter->pdev;\n \tint i, err = 0;\n \n-\tfor (i = 0; i < adapter->num_rx_queues; i++) {\n+\ti = adapter->qav_mode ? IGB_USER_RX_QUEUES : 0;\n+\tfor (; i < adapter->num_rx_queues; i++) {\n \t\terr = igb_setup_rx_resources(adapter->rx_ring[i]);\n \t\tif (err) {\n \t\t\tdev_err(&pdev->dev,\n@@ -3399,6 +3441,15 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)\n \tu32 j, num_rx_queues;\n \tu32 rss_key[10];\n \n+\t/* For TSN, kernel driver only create buffer for queue 2 and queue 3,\n+\t * by default receive all BE packets from queue 3.\n+\t */\n+\tif (adapter->qav_mode) {\n+\t\twr32(E1000_MRQC, (adapter->num_rx_queues - 1)\n+\t\t << E1000_MRQC_DEF_QUEUE_OFFSET);\n+\t\treturn;\n+\t}\n+\n \tnetdev_rss_key_fill(rss_key, sizeof(rss_key));\n \tfor (j = 0; j < 10; j++)\n \t\twr32(E1000_RSSRK(j), rss_key[j]);\n@@ -3474,6 +3525,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)\n \t\tif (hw->mac.type != e1000_i211)\n \t\t\tmrqc |= E1000_MRQC_ENABLE_RSS_4Q;\n \t}\n+\n \tigb_vmm_control(adapter);\n \n \twr32(E1000_MRQC, mrqc);\n@@ -3701,7 +3753,8 @@ static void igb_configure_rx(struct igb_adapter *adapter)\n \t/* Setup the HW Rx Head and Tail Descriptor Pointers and\n \t * the Base and Length of the Rx Descriptor Ring\n \t */\n-\tfor (i = 0; i < adapter->num_rx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_RX_QUEUES : 0;\n+\tfor (; i < adapter->num_rx_queues; i++)\n \t\tigb_configure_rx_ring(adapter, adapter->rx_ring[i]);\n }\n \n@@ -3737,8 +3790,8 @@ void igb_free_tx_resources(struct igb_ring *tx_ring)\n static void igb_free_all_tx_resources(struct igb_adapter *adapter)\n {\n \tint i;\n-\n-\tfor (i = 0; i < adapter->num_tx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_TX_QUEUES : 0;\n+\tfor (; i < adapter->num_tx_queues; i++)\n \t\tif (adapter->tx_ring[i])\n \t\t\tigb_free_tx_resources(adapter->tx_ring[i]);\n }\n@@ -3804,7 +3857,8 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter)\n {\n \tint i;\n \n-\tfor (i = 0; i < adapter->num_tx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_TX_QUEUES : 0;\n+\tfor (; i < adapter->num_tx_queues; i++)\n \t\tif (adapter->tx_ring[i])\n \t\t\tigb_clean_tx_ring(adapter->tx_ring[i]);\n }\n@@ -3842,7 +3896,8 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter)\n {\n \tint i;\n \n-\tfor (i = 0; i < adapter->num_rx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_RX_QUEUES : 0;\n+\tfor (; i < adapter->num_rx_queues; i++)\n \t\tif (adapter->rx_ring[i])\n \t\t\tigb_free_rx_resources(adapter->rx_ring[i]);\n }\n@@ -3898,7 +3953,8 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter)\n {\n \tint i;\n \n-\tfor (i = 0; i < adapter->num_rx_queues; i++)\n+\ti = adapter->qav_mode ? IGB_USER_TX_QUEUES : 0;\n+\tfor (; i < adapter->num_rx_queues; i++)\n \t\tif (adapter->rx_ring[i])\n \t\t\tigb_clean_rx_ring(adapter->rx_ring[i]);\n }\n@@ -6928,6 +6984,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)\n \tstruct sk_buff *skb = rx_ring->skb;\n \tunsigned int total_bytes = 0, total_packets = 0;\n \tu16 cleaned_count = igb_desc_unused(rx_ring);\n+\tstruct igb_adapter *adapter = netdev_priv(rx_ring->netdev);\n+\n+\t/* Don't service user (AVB) queues */\n+\tif (adapter->qav_mode && rx_ring->queue_index < IGB_USER_RX_QUEUES)\n+\t\treturn true;\n \n \twhile (likely(total_packets < budget)) {\n \t\tunion e1000_adv_rx_desc *rx_desc;\n@@ -7127,6 +7188,9 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)\n \treturn 0;\n }\n \n+#define SIOSTXQUEUESELECT SIOCDEVPRIVATE\n+#define SIOSRXQUEUESELECT (SIOCDEVPRIVATE + 1)\n+\n /**\n * igb_ioctl -\n * @netdev:\n@@ -8188,6 +8252,9 @@ static int igb_change_mode(struct igb_adapter *adapter, int request_mode)\n \tif (request_mode == current_mode)\n \t\treturn 0;\n \n+\tif (adapter->cdev_in_use)\n+\t\treturn -EBUSY;\n+\n \tnetdev = adapter->netdev;\n \n \trtnl_lock();\n@@ -8197,6 +8264,11 @@ static int igb_change_mode(struct igb_adapter *adapter, int request_mode)\n \telse\n \t\tigb_reset(adapter);\n \n+\tif (current_mode) {\n+\t\tigb_tsn_free_all_rx_resources(adapter);\n+\t\tigb_tsn_free_all_tx_resources(adapter);\n+\t}\n+\n \tigb_clear_interrupt_scheme(adapter);\n \n \tadapter->qav_mode = request_mode;\n@@ -8210,12 +8282,23 @@ static int igb_change_mode(struct igb_adapter *adapter, int request_mode)\n \t\tgoto err_out;\n \t}\n \n+\tif (request_mode) {\n+\t\terr = igb_tsn_setup_all_tx_resources(adapter);\n+\t\tif (err)\n+\t\t\tgoto err_out;\n+\t\terr = igb_tsn_setup_all_rx_resources(adapter);\n+\t\tif (err)\n+\t\t\tgoto err_tsn_setup_rx;\n+\t}\n+\n \tif (netif_running(netdev))\n \t\tigb_open(netdev);\n \n \trtnl_unlock();\n \n \treturn err;\n+err_tsn_setup_rx:\n+\tigb_tsn_free_all_tx_resources(adapter);\n err_out:\n \trtnl_unlock();\n \treturn err;\n@@ -8253,4 +8336,5 @@ static ssize_t igb_set_qav_mode(struct device *dev,\n \n \treturn len;\n }\n+\n /* igb_main.c */\n", "prefixes": [ "net-next", "2/2" ] }