1 /*-
2  * GPL LICENSE SUMMARY
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of version 2 of the GNU General Public License as
8  *   published by the Free Software Foundation.
9  *
10  *   This program is distributed in the hope that it will be useful, but
11  *   WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *   General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  *   The full GNU General Public License is included in this distribution
19  *   in the file called LICENSE.GPL.
20  *
21  *   Contact Information:
22  *   Intel Corporation
23  */
24 /*--------------------------------------------------------------------------*/
25 #include <linux/device.h>
26 #include <linux/module.h>
27 #include <linux/version.h>
28 #include <linux/slab.h>
29 #include <linux/uaccess.h>
30 #include <linux/if_ether.h>
31 #include <linux/etherdevice.h>
32 #include "dpdk_iface.h"
33 /*--------------------------------------------------------------------------*/
34 struct stats_struct sarrays[MAX_DEVICES][MAX_QID] = {{{0, 0, 0, 0, 0, 0, 0, 0, 0}}};
35 struct stats_struct old_sarrays[MAX_DEVICES][MAX_QID] = {{{0, 0, 0, 0, 0, 0, 0, 0, 0}}};
36 static int major_no = -1;
37 /*--------------------------------------------------------------------------*/
38 static int
update_stats(struct stats_struct * stats)39 update_stats(struct stats_struct *stats)
40 {
41 	uint8_t qid = stats->qid;
42 	uint8_t device = stats->dev;
43 	struct stats_struct *old_sarray = &old_sarrays[device][qid];
44 	struct stats_struct *sarray = &sarrays[device][qid];
45 
46 	if (unlikely(sarrays[device][qid].rx_bytes > stats->rx_bytes ||
47 		     sarrays[device][qid].tx_bytes > stats->tx_bytes)) {
48 		/* mTCP app restarted?? */
49 		old_sarray->rx_bytes += sarray->rx_bytes;
50 		old_sarray->rx_pkts += sarray->rx_pkts;
51 		old_sarray->tx_bytes += sarray->tx_bytes;
52 		old_sarray->tx_pkts += sarray->tx_pkts;
53 		old_sarray->rmiss += sarray->rmiss;
54 		old_sarray->rerr += sarray->rerr;
55 		old_sarray->terr += sarray->terr;
56 	}
57 
58 	sarray->rx_bytes = stats->rx_bytes;
59 	sarray->rx_pkts = stats->rx_pkts;
60 	sarray->tx_bytes = stats->tx_bytes;
61 	sarray->tx_pkts = stats->tx_pkts;
62 	sarray->rmiss = stats->rmiss;
63 	sarray->rerr = stats->rerr;
64 	sarray->terr = stats->terr;
65 
66 #if 0
67 	printk(KERN_ALERT "%s: Dev: %d, Qid: %d, RXP: %llu, "
68 	       "RXB: %llu, TXP: %llu, TXB: %llu\n",
69 	       device, qid,
70 	       THIS_MODULE->name,
71 	       (long long unsigned int)sarray->rx_pkts,
72 	       (long long unsigned int)sarray->rx_bytes,
73 	       (long long unsigned int)sarray->tx_pkts,
74 	       (long long unsigned int)sarray->tx_bytes);
75 #endif
76 	return 0;
77 }
78 /*--------------------------------------------------------------------------*/
79 static void
clear_all_netdevices(void)80 clear_all_netdevices(void)
81 {
82 	struct net_device *netdev, *dpdk_netdev;
83 	uint8_t freed;
84 
85 	do {
86 		dpdk_netdev = NULL;
87 		freed = 0;
88 		write_lock(&dev_base_lock);
89 		netdev = first_net_device(&init_net);
90 		while (netdev) {
91 			if (strncmp(netdev->name, IFACE_PREFIX,
92 				    strlen(IFACE_PREFIX)) == 0) {
93 				dpdk_netdev = netdev;
94 				break;
95 			}
96 			netdev = next_net_device(netdev);
97 		}
98 		write_unlock(&dev_base_lock);
99 		if (dpdk_netdev) {
100 			unregister_netdev(dpdk_netdev);
101 			free_netdev(dpdk_netdev);
102 			freed = 1;
103 		}
104 	} while (freed);
105 }
106 /*--------------------------------------------------------------------------*/
107 int
igb_net_open(struct inode * inode,struct file * filp)108 igb_net_open(struct inode *inode, struct file *filp)
109 {
110 	return 0;
111 }
112 /*--------------------------------------------------------------------------*/
113 int
igb_net_release(struct inode * inode,struct file * filp)114 igb_net_release(struct inode *inode, struct file *filp)
115 {
116 	return 0;
117 }
118 /*--------------------------------------------------------------------------*/
119 long
igb_net_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)120 igb_net_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
121 {
122 	int ret = 0;
123 	unsigned char mac_addr[ETH_ALEN];
124 	struct net_device *netdev;
125 	struct stats_struct ss;
126 	struct net_adapter *adapter = NULL;
127 	struct PciDevice pd;
128 
129 	switch (cmd) {
130 	case SEND_STATS:
131 		ret = copy_from_user(&ss,
132 				     (struct stats_struct __user *)arg,
133 				     sizeof(struct stats_struct));
134 		if (ret)
135 			return -EFAULT;
136 		ret = update_stats(&ss);
137 		break;
138 	case CREATE_IFACE:
139 		ret = copy_from_user(&pd,
140 				     (PciDevice __user *)arg,
141 				     sizeof(PciDevice));
142 		ret = copy_from_user(mac_addr,
143 				     (unsigned char __user *)pd.ports_eth_addr,
144 				     ETH_ALEN);
145 		if (!ret) {
146 			/* first check whether the entry does not exist */
147 			read_lock(&dev_base_lock);
148 			netdev = first_net_device(&init_net);
149 			while (netdev) {
150 				if (memcmp(netdev->dev_addr, mac_addr, ETH_ALEN) == 0) {
151 					read_unlock(&dev_base_lock);
152 					printk(KERN_ERR "%s: port already registered!\n", THIS_MODULE->name);
153 					return -EINVAL;
154 				}
155 				netdev = next_net_device(netdev);
156 			}
157 			read_unlock(&dev_base_lock);
158 
159 			/* initialize the corresponding netdev */
160 			netdev = alloc_etherdev(sizeof(struct net_adapter));
161 			if (!netdev) {
162 				ret = -ENOMEM;
163 			} else {
164 				SET_NETDEV_DEV(netdev, NULL);
165 				adapter = netdev_priv(netdev);
166 				adapter->netdev = netdev;
167 				netdev_assign_netdev_ops(netdev);
168 				memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
169 				strcpy(netdev->name, IFACE_PREFIX"%d");
170 				ret = register_netdev(netdev);
171 				if (ret)
172 					goto fail_ioremap;
173 				adapter->netdev_registered = true;
174 
175 				if ((ret=sscanf(netdev->name, IFACE_PREFIX"%hu", &adapter->bd_number)) <= 0)
176 					goto fail_bdnumber;
177 
178 				printk(KERN_INFO "%s: ifindex picked: %hu\n",
179 				       THIS_MODULE->name, adapter->bd_number);
180 				/* reset nstats */
181 				memset(&adapter->nstats, 0, sizeof(struct net_device_stats));
182 				/* set 'fake' pci address */
183 				memcpy(&adapter->pa, &pd.pa, sizeof(struct PciAddress));
184 				ret = copy_to_user((unsigned char __user *)arg,
185 						   netdev->name,
186 						   IFNAMSIZ);
187 				if (ret) {
188 					printk(KERN_INFO "%s: Interface %s copy to user failed!\n",
189 					       THIS_MODULE->name, netdev->name);
190 					ret = -1;
191 					goto fail_pciaddr;
192 				}
193 				/* set numa locality */
194 				adapter->numa_socket = pd.numa_socket;
195 			}
196 		}
197 		break;
198 	case CLEAR_IFACE:
199 		clear_all_netdevices();
200 		break;
201 
202 	case FETCH_PCI_ADDRESS:
203 		ret = copy_from_user(&pd,
204 				     (PciDevice __user *)arg,
205 				     sizeof(PciDevice));
206 		if (!ret) {
207 			read_lock(&dev_base_lock);
208 			netdev = first_net_device(&init_net);
209 			while (netdev) {
210 				if (strcmp(netdev->name, pd.ifname) == 0) {
211 					read_unlock(&dev_base_lock);
212 					printk(KERN_INFO "%s: Passing PCI info of %s to user\n",
213 					       THIS_MODULE->name, pd.ifname);
214 					adapter = netdev_priv(netdev);
215 					ret = copy_to_user(&((PciDevice __user *)arg)->pa,
216 							   &adapter->pa,
217 							   sizeof(struct PciAddress));
218 					if (ret) return -1;
219 					ret = copy_to_user(&((PciDevice __user *)arg)->numa_socket,
220 							   &adapter->numa_socket,
221 							   sizeof(adapter->numa_socket));
222 					if (ret) return -1;
223 					return 0;
224 				}
225 				netdev = next_net_device(netdev);
226 			}
227 			read_unlock(&dev_base_lock);
228 			ret = -1;
229 		}
230 		break;
231 	default:
232 		ret = -ENOTTY;
233 		break;
234 	}
235 
236 
237 	return ret;
238  fail_pciaddr:
239  fail_bdnumber:
240 	unregister_netdev(netdev);
241  fail_ioremap:
242 	free_netdev(netdev);
243 	return ret;
244 }
245 /*--------------------------------------------------------------------------*/
246 static struct file_operations igb_net_fops = {
247 	.open = 		igb_net_open,
248 	.release = 		igb_net_release,
249 	.unlocked_ioctl = 	igb_net_ioctl,
250 };
251 /*--------------------------------------------------------------------------*/
252 static int __init
iface_pci_init_module(void)253 iface_pci_init_module(void)
254 {
255 	int ret;
256 
257 	ret = register_chrdev(0 /* MAJOR */,
258 			      DEV_NAME /*NAME*/,
259 			      &igb_net_fops);
260 	if (ret < 0) {
261 		printk(KERN_ERR "%s: register_chrdev failed\n",
262 		       THIS_MODULE->name);
263 		return ret;
264 	}
265 
266 	printk(KERN_INFO "%s: Loaded\n",
267 	       THIS_MODULE->name);
268 
269 	/* record major number */
270 	major_no = ret;
271 
272 	return 0;
273 }
274 /*--------------------------------------------------------------------------*/
275 static void __exit
iface_pci_exit_module(void)276 iface_pci_exit_module(void)
277 {
278 	clear_all_netdevices();
279 	unregister_chrdev(major_no, DEV_NAME);
280 }
281 /*--------------------------------------------------------------------------*/
282 module_init(iface_pci_init_module);
283 module_exit(iface_pci_exit_module);
284 
285 MODULE_DESCRIPTION("Interface driver for DPDK devices");
286 MODULE_LICENSE("BSD");
287 MODULE_AUTHOR("[email protected]");
288 /*--------------------------------------------------------------------------*/
289