1e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Copyright 2011 Tilera Corporation. All Rights Reserved.
3e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
4e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   This program is free software; you can redistribute it and/or
5e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   modify it under the terms of the GNU General Public License
6e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   as published by the Free Software Foundation, version 2.
7e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
8e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   This program is distributed in the hope that it will be useful, but
9e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   WITHOUT ANY WARRANTY; without even the implied warranty of
10e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   NON INFRINGEMENT.  See the GNU General Public License for
12e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *   more details.
13e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
14e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
15e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/module.h>
16e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/init.h>
17e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/moduleparam.h>
18e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/sched.h>
19e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/kernel.h>      /* printk() */
20e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/slab.h>        /* kmalloc() */
21e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/errno.h>       /* error codes */
22e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/types.h>       /* size_t */
23e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/interrupt.h>
24e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/in.h>
25e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/netdevice.h>   /* struct device, and other headers */
26e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/etherdevice.h> /* eth_type_trans */
27e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/skbuff.h>
28e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/ioctl.h>
29e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/cdev.h>
30e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/hugetlb.h>
31e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/in6.h>
32e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/timer.h>
33e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/io.h>
34e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <asm/checksum.h>
35e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <asm/homecache.h>
36e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
37e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <hv/drv_xgbe_intf.h>
38e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <hv/drv_xgbe_impl.h>
39e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <hv/hypervisor.h>
40e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <hv/netio_intf.h>
41e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
42e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* For TSO */
43e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/ip.h>
44e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#include <linux/tcp.h>
45e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
46e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
47e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
48e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * First, "tile_net_init_module()" initializes all four "devices" which
49e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * can be used by linux.
50e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
51e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Then, "ifconfig DEVICE up" calls "tile_net_open()", which analyzes
52e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * the network cpus, then uses "tile_net_open_aux()" to initialize
53e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * LIPP/LEPP, and then uses "tile_net_open_inner()" to register all
54e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * the tiles, provide buffers to LIPP, allow ingress to start, and
55e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * turn on hypervisor interrupt handling (and NAPI) on all tiles.
56e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
57e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * If registration fails due to the link being down, then "retry_work"
58e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * is used to keep calling "tile_net_open_inner()" until it succeeds.
59e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
60e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * If "ifconfig DEVICE down" is called, it uses "tile_net_stop()" to
61e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * stop egress, drain the LIPP buffers, unregister all the tiles, stop
62e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * LIPP/LEPP, and wipe the LEPP queue.
63e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
64e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * We start out with the ingress interrupt enabled on each CPU.  When
65e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * this interrupt fires, we disable it, and call "napi_schedule()".
66e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This will cause "tile_net_poll()" to be called, which will pull
67e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * packets from the netio queue, filtering them out, or passing them
68e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * to "netif_receive_skb()".  If our budget is exhausted, we will
69e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * return, knowing we will be called again later.  Otherwise, we
70e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * reenable the ingress interrupt, and call "napi_complete()".
71e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
72d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * HACK: Since disabling the ingress interrupt is not reliable, we
73d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ignore the interrupt if the global "active" flag is false.
74d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
75e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
76e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * NOTE: The use of "native_driver" ensures that EPP exists, and that
77d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * we are using "LIPP" and "LEPP".
78e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
79e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * NOTE: Failing to free completions for an arbitrarily long time
80e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * (which is defined to be illegal) does in fact cause bizarre
81e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * problems.  The "egress_timer" helps prevent this from happening.
82e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
83e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
84e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
85e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* HACK: Allow use of "jumbo" packets. */
86e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* This should be 1500 if "jumbo" is not set in LIPP. */
87e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* This should be at most 10226 (10240 - 14) if "jumbo" is set in LIPP. */
88e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* ISSUE: This has not been thoroughly tested (except at 1500). */
89e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define TILE_NET_MTU 1500
90e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
91e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* HACK: Define to support GSO. */
92e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* ISSUE: This may actually hurt performance of the TCP blaster. */
93e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define TILE_NET_GSO */
94e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
95e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Define this to collapse "duplicate" acks. */
96e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define IGNORE_DUP_ACKS */
97e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
98e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* HACK: Define this to verify incoming packets. */
99e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define TILE_NET_VERIFY_INGRESS */
100e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
101e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Use 3000 to enable the Linux Traffic Control (QoS) layer, else 0. */
102e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define TILE_NET_TX_QUEUE_LEN 0
103e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
104e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Define to dump packets (prints out the whole packet on tx and rx). */
105e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define TILE_NET_DUMP_PACKETS */
106e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
107e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Define to enable debug spew (all PDEBUG's are enabled). */
108e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define TILE_NET_DEBUG */
109e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
110e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
111e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Define to activate paranoia checks. */
112e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* #define TILE_NET_PARANOIA */
113e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
114e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Default transmit lockup timeout period, in jiffies. */
115e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define TILE_NET_TIMEOUT (5 * HZ)
116e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
117e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Default retry interval for bringing up the NetIO interface, in jiffies. */
118e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define TILE_NET_RETRY_INTERVAL (5 * HZ)
119e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
120e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Number of ports (xgbe0, xgbe1, gbe0, gbe1). */
121e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define TILE_NET_DEVS 4
122e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
123e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
124e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
125e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Paranoia. */
126e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#if NET_IP_ALIGN != LIPP_PACKET_PADDING
127e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#error "NET_IP_ALIGN must match LIPP_PACKET_PADDING."
128e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
129e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
130e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
131e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/* Debug print. */
132e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DEBUG
133e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define PDEBUG(fmt, args...) net_printk(fmt, ## args)
134e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#else
135e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#define PDEBUG(fmt, args...)
136e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
137e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
138e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
139e5a06939736277c54a68ae275433db55b99d187cChris MetcalfMODULE_AUTHOR("Tilera");
140e5a06939736277c54a68ae275433db55b99d187cChris MetcalfMODULE_LICENSE("GPL");
141e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
142d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
143e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
144e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Queue of incoming packets for a specific cpu and device.
145e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
146e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Includes a pointer to the "system" data, and the actual "user" data.
147e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
148e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstruct tile_netio_queue {
149e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_impl_t *__system_part;
150e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_user_impl_t __user_part;
151e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
152e5a06939736277c54a68ae275433db55b99d187cChris Metcalf};
153e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
154e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
155e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
156e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Statistics counters for a specific cpu and device.
157e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
158e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstruct tile_net_stats_t {
159e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 rx_packets;
160e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 rx_bytes;
161e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 tx_packets;
162e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 tx_bytes;
163e5a06939736277c54a68ae275433db55b99d187cChris Metcalf};
164e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
165e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
166e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
167e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Info for a specific cpu and device.
168e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
169e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ISSUE: There is a "dev" pointer in "napi" as well.
170e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
171e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstruct tile_net_cpu {
172e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The NAPI struct. */
173e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct napi_struct napi;
174e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Packet queue. */
175e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue queue;
176e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Statistics. */
177e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_stats_t stats;
178d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* True iff NAPI is enabled. */
179e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	bool napi_enabled;
180bfb9035c98906aafcd3cf22694fba2550997bf53Joe Perches	/* True if this tile has successfully registered with the IPP. */
181e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	bool registered;
182e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* True if the link was down last time we tried to register. */
183e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	bool link_down;
184e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* True if "egress_timer" is scheduled. */
185e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	bool egress_timer_scheduled;
186e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Number of small sk_buffs which must still be provided. */
187e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int num_needed_small_buffers;
188e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Number of large sk_buffs which must still be provided. */
189e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int num_needed_large_buffers;
190e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* A timer for handling egress completions. */
191e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct timer_list egress_timer;
192e5a06939736277c54a68ae275433db55b99d187cChris Metcalf};
193e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
194e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
195e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
196e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Info for a specific device.
197e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
198e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstruct tile_net_priv {
199e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Our network device. */
200e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev;
201d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Pages making up the egress queue. */
202d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct page *eq_pages;
203d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Address of the actual egress queue. */
204d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	lepp_queue_t *eq;
205d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Protects "eq". */
206d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spinlock_t eq_lock;
207e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The hypervisor handle for this interface. */
208e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int hv_devhdl;
209e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The intr bit mask that IDs this device. */
210e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 intr_id;
211e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* True iff "tile_net_open_aux()" has succeeded. */
212d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	bool partly_opened;
213d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* True iff the device is "active". */
214d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	bool active;
215e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Effective network cpus. */
216e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct cpumask network_cpus_map;
217e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Number of network cpus. */
218e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int network_cpus_count;
219e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Credits per network cpu. */
220e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int network_cpus_credits;
221e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Network stats. */
222e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device_stats stats;
223e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* For NetIO bringup retries. */
224e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct delayed_work retry_work;
225e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Quick access to per cpu data. */
226e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *cpu[NR_CPUS];
227e5a06939736277c54a68ae275433db55b99d187cChris Metcalf};
228e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
229d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf/* Log2 of the number of small pages needed for the egress queue. */
230d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#define EQ_ORDER  get_order(sizeof(lepp_queue_t))
231d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf/* Size of the egress queue's pages. */
232d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#define EQ_SIZE   (1 << (PAGE_SHIFT + EQ_ORDER))
233e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
234e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
235e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The actual devices (xgbe0, xgbe1, gbe0, gbe1).
236e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
237e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic struct net_device *tile_net_devs[TILE_NET_DEVS];
238e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
239e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
240e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The "tile_net_cpu" structures for each device.
241e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
242e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe0);
243e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe1);
244e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe0);
245e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe1);
246e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
247e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
248e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
249e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * True if "network_cpus" was specified.
250e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
251e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic bool network_cpus_used;
252e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
253e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
254e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The actual cpus in "network_cpus".
255e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
256e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic struct cpumask network_cpus_map;
257e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
258e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
259e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
260e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DEBUG
261e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
262e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * printk with extra stuff.
263e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
264e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * We print the CPU we're running in brackets.
265e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
266e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void net_printk(char *fmt, ...)
267e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
268e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int i;
269e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int len;
270e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	va_list args;
271e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	static char buf[256];
272e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
273e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	len = sprintf(buf, "tile_net[%2.2d]: ", smp_processor_id());
274e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	va_start(args, fmt);
275e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	i = vscnprintf(buf + len, sizeof(buf) - len - 1, fmt, args);
276e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	va_end(args);
277e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	buf[255] = '\0';
278e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	pr_notice(buf);
279e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
280e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
281e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
282e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
283e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DUMP_PACKETS
284e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
285e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Dump a packet.
286e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
287e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void dump_packet(unsigned char *data, unsigned long length, char *s)
288e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
289d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int my_cpu = smp_processor_id();
290d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
291e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned long i;
292d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	char buf[128];
293d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
294e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	static unsigned int count;
295e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
296e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	pr_info("dump_packet(data %p, length 0x%lx s %s count 0x%x)\n",
297e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       data, length, s, count++);
298e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
299e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	pr_info("\n");
300e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
301e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < length; i++) {
302e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if ((i & 0xf) == 0)
303d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			sprintf(buf, "[%02d] %8.8lx:", my_cpu, i);
304e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		sprintf(buf + strlen(buf), " %2.2x", data[i]);
305d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if ((i & 0xf) == 0xf || i == length - 1) {
306d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			strcat(buf, "\n");
307d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			pr_info("%s", buf);
308d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		}
309e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
310e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
311e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
312e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
313e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
314e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
315e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Provide support for the __netio_fastio1() swint
316e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * (see <hv/drv_xgbe_intf.h> for how it is used).
317e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
318e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The fastio swint2 call may clobber all the caller-saved registers.
319e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * It rarely clobbers memory, but we allow for the possibility in
320e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * the signature just to be on the safe side.
321e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
322e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Also, gcc doesn't seem to allow an input operand to be
323e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * clobbered, so we fake it with dummy outputs.
324e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
325e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This function can't be static because of the way it is declared
326e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * in the netio header.
327e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
328e5a06939736277c54a68ae275433db55b99d187cChris Metcalfinline int __netio_fastio1(u32 fastio_index, u32 arg0)
329e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
330e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	long result, clobber_r1, clobber_r10;
331e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	asm volatile("swint2"
332e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		     : "=R00" (result),
333e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "=R01" (clobber_r1), "=R10" (clobber_r10)
334e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		     : "R10" (fastio_index), "R01" (arg0)
335e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		     : "memory", "r2", "r3", "r4",
336e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "r5", "r6", "r7", "r8", "r9",
337e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "r11", "r12", "r13", "r14",
338e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "r15", "r16", "r17", "r18", "r19",
339e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "r20", "r21", "r22", "r23", "r24",
340e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       "r25", "r26", "r27", "r28", "r29");
341e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return result;
342e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
343e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
344e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
34592795672898d5ee1faa557c498c078123d20e827Chris Metcalfstatic void tile_net_return_credit(struct tile_net_cpu *info)
34692795672898d5ee1faa557c498c078123d20e827Chris Metcalf{
34792795672898d5ee1faa557c498c078123d20e827Chris Metcalf	struct tile_netio_queue *queue = &info->queue;
34892795672898d5ee1faa557c498c078123d20e827Chris Metcalf	netio_queue_user_impl_t *qup = &queue->__user_part;
34992795672898d5ee1faa557c498c078123d20e827Chris Metcalf
35092795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* Return four credits after every fourth packet. */
35192795672898d5ee1faa557c498c078123d20e827Chris Metcalf	if (--qup->__receive_credit_remaining == 0) {
35292795672898d5ee1faa557c498c078123d20e827Chris Metcalf		u32 interval = qup->__receive_credit_interval;
35392795672898d5ee1faa557c498c078123d20e827Chris Metcalf		qup->__receive_credit_remaining = interval;
35492795672898d5ee1faa557c498c078123d20e827Chris Metcalf		__netio_fastio_return_credits(qup->__fastio_index, interval);
35592795672898d5ee1faa557c498c078123d20e827Chris Metcalf	}
35692795672898d5ee1faa557c498c078123d20e827Chris Metcalf}
35792795672898d5ee1faa557c498c078123d20e827Chris Metcalf
35892795672898d5ee1faa557c498c078123d20e827Chris Metcalf
35992795672898d5ee1faa557c498c078123d20e827Chris Metcalf
360e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
361e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Provide a linux buffer to LIPP.
362e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
363e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_provide_linux_buffer(struct tile_net_cpu *info,
364e5a06939736277c54a68ae275433db55b99d187cChris Metcalf					  void *va, bool small)
365e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
366e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue = &info->queue;
367e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
368e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Convert "va" and "small" to "linux_buffer_t". */
369e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int buffer = ((unsigned int)(__pa(va) >> 7) << 1) + small;
370e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
371e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	__netio_fastio_free_buffer(queue->__user_part.__fastio_index, buffer);
372e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
373e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
374e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
375e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
376e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Provide a linux buffer for LIPP.
377d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
378d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Note that the ACTUAL allocation for each buffer is a "struct sk_buff",
379d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * plus a chunk of memory that includes not only the requested bytes, but
380d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * also NET_SKB_PAD bytes of initial padding, and a "struct skb_shared_info".
381d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
382d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Note that "struct skb_shared_info" is 88 bytes with 64K pages and
383d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * 268 bytes with 4K pages (since the frags[] array needs 18 entries).
384d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
385d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Without jumbo packets, the maximum packet size will be 1536 bytes,
386d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * and we use 2 bytes (NET_IP_ALIGN) of padding.  ISSUE: If we told
387d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * the hardware to clip at 1518 bytes instead of 1536 bytes, then we
388d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * could save an entire cache line, but in practice, we don't need it.
389d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
390d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Since CPAs are 38 bits, and we can only encode the high 31 bits in
391d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * a "linux_buffer_t", the low 7 bits must be zero, and thus, we must
392d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * align the actual "va" mod 128.
393d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
394d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * We assume that the underlying "head" will be aligned mod 64.  Note
395d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * that in practice, we have seen "head" NOT aligned mod 128 even when
396d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * using 2048 byte allocations, which is surprising.
397d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
398d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * If "head" WAS always aligned mod 128, we could change LIPP to
399d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * assume that the low SIX bits are zero, and the 7th bit is one, that
400d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * is, align the actual "va" mod 128 plus 64, which would be "free".
401d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
402d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * For now, the actual "head" pointer points at NET_SKB_PAD bytes of
403d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * padding, plus 28 or 92 bytes of extra padding, plus the sk_buff
404d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * pointer, plus the NET_IP_ALIGN padding, plus 126 or 1536 bytes for
405d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * the actual packet, plus 62 bytes of empty padding, plus some
406d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * padding and the "struct skb_shared_info".
407d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
408d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * With 64K pages, a large buffer thus needs 32+92+4+2+1536+62+88
409d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * bytes, or 1816 bytes, which fits comfortably into 2048 bytes.
410d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
411d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * With 64K pages, a small buffer thus needs 32+92+4+2+126+88
412d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * bytes, or 344 bytes, which means we are wasting 64+ bytes, and
413d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * could presumably increase the size of small buffers.
414d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
415d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * With 4K pages, a large buffer thus needs 32+92+4+2+1536+62+268
416d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * bytes, or 1996 bytes, which fits comfortably into 2048 bytes.
417d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
418d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * With 4K pages, a small buffer thus needs 32+92+4+2+126+268
419d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * bytes, or 524 bytes, which is annoyingly wasteful.
420d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
421d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Maybe we should increase LIPP_SMALL_PACKET_SIZE to 192?
422d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
423d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ISSUE: Maybe we should increase "NET_SKB_PAD" to 64?
424e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
425e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
426e5a06939736277c54a68ae275433db55b99d187cChris Metcalf					   bool small)
427e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
428d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#if TILE_NET_MTU <= 1536
429d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Without "jumbo", 2 + 1536 should be sufficient. */
430d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int large_size = NET_IP_ALIGN + 1536;
431d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#else
432d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: This has not been tested. */
433e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int large_size = NET_IP_ALIGN + TILE_NET_MTU + 100;
434d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#endif
435e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
436d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Avoid "false sharing" with last cache line. */
437dae2e9f430c46c29e3f771110094bd3da3625aa4Pradeep A. Dalvi	/* ISSUE: This is already done by "netdev_alloc_skb()". */
438d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int len =
439e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 (((small ? LIPP_SMALL_PACKET_SIZE : large_size) +
440e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		   CHIP_L2_LINE_SIZE() - 1) & -CHIP_L2_LINE_SIZE());
441e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
442d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int padding = 128 - NET_SKB_PAD;
443d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int align;
444e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
445e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct sk_buff *skb;
446e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	void *va;
447e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
448e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct sk_buff **skb_ptr;
449e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
450d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Request 96 extra bytes for alignment purposes. */
45100a62d4bc9b9a0388abee5c5ea946b9631b149d5Chris Metcalf	skb = netdev_alloc_skb(info->napi.dev, len + padding);
452d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (skb == NULL)
453d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		return false;
454e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
455d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Skip 32 or 96 bytes to align "data" mod 128. */
456d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	align = -(long)skb->data & (128 - 1);
457d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	BUG_ON(align > padding);
458d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	skb_reserve(skb, align);
459e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
460d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* This address is given to IPP. */
461d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	va = skb->data;
462e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
463d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Buffers must not span a huge page. */
464d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	BUG_ON(((((long)va & ~HPAGE_MASK) + len) & HPAGE_MASK) != 0);
465e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
466d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#ifdef TILE_NET_PARANOIA
467d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#if CHIP_HAS_CBOX_HOME_MAP()
468d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (hash_default) {
469d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va);
470d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
471d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			panic("Non-HFH ingress buffer! VA=%p Mode=%d PTE=%llx",
472d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			      va, hv_pte_get_mode(pte), hv_pte_val(pte));
473e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
474d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#endif
475d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#endif
476d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
477d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Invalidate the packet buffer. */
478d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (!hash_default)
479d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		__inv_buffer(va, len);
480e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
481e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Skip two bytes to satisfy LIPP assumptions. */
482e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Note that this aligns IP on a 16 byte boundary. */
483e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: Do this when the packet arrives? */
484e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	skb_reserve(skb, NET_IP_ALIGN);
485e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
486e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Save a back-pointer to 'skb'. */
487e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	skb_ptr = va - sizeof(*skb_ptr);
488e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	*skb_ptr = skb;
489e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
490e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Make sure "skb_ptr" has been flushed. */
491e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	__insn_mf();
492e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
493e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Provide the new buffer. */
494e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_provide_linux_buffer(info, va, small);
495e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
496e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return true;
497e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
498e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
499e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
500e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
501e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Provide linux buffers for LIPP.
502e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
503e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_provide_needed_buffers(struct tile_net_cpu *info)
504e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
505e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	while (info->num_needed_small_buffers != 0) {
506e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (!tile_net_provide_needed_buffer(info, true))
507e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			goto oops;
508e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->num_needed_small_buffers--;
509e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
510e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
511e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	while (info->num_needed_large_buffers != 0) {
512e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (!tile_net_provide_needed_buffer(info, false))
513e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			goto oops;
514e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->num_needed_large_buffers--;
515e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
516e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
517e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return;
518e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
519e5a06939736277c54a68ae275433db55b99d187cChris Metcalfoops:
520e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
521e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Add a description to the page allocation failure dump. */
522e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	pr_notice("Could not provide a linux buffer to LIPP.\n");
523e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
524e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
525e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
526e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
527e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Grab some LEPP completions, and store them in "comps", of size
528e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * "comps_size", and return the number of completions which were
529e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * stored, so the caller can free them.
530e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
531d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic unsigned int tile_net_lepp_grab_comps(lepp_queue_t *eq,
532e5a06939736277c54a68ae275433db55b99d187cChris Metcalf					     struct sk_buff *comps[],
533e5a06939736277c54a68ae275433db55b99d187cChris Metcalf					     unsigned int comps_size,
534d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf					     unsigned int min_size)
535e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
536e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int n = 0;
537e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
538d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int comp_head = eq->comp_head;
539d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int comp_busy = eq->comp_busy;
540e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
541e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	while (comp_head != comp_busy && n < comps_size) {
542e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		comps[n++] = eq->comps[comp_head];
543e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		LEPP_QINC(comp_head);
544e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
545e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
546d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (n < min_size)
547d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		return 0;
548e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
549e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->comp_head = comp_head;
550e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
551e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return n;
552e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
553e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
554e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
555e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
556d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Free some comps, and return true iff there are still some pending.
557d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf */
558d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic bool tile_net_lepp_free_comps(struct net_device *dev, bool all)
559d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf{
560d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
561d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
562d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	lepp_queue_t *eq = priv->eq;
563d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
564d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct sk_buff *olds[64];
565d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int wanted = 64;
566d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int i, n;
567d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	bool pending;
568d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
569d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_lock(&priv->eq_lock);
570d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
571d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (all)
572d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		eq->comp_busy = eq->comp_tail;
573d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
574d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	n = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
575d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
576d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	pending = (eq->comp_head != eq->comp_tail);
577d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
578d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_unlock(&priv->eq_lock);
579d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
580d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	for (i = 0; i < n; i++)
581d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		kfree_skb(olds[i]);
582d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
583d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	return pending;
584d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf}
585d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
586d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
587d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf/*
588e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Make sure the egress timer is scheduled.
589e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
590e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Note that we use "schedule if not scheduled" logic instead of the more
591e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * obvious "reschedule" logic, because "reschedule" is fairly expensive.
592e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
593e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_schedule_egress_timer(struct tile_net_cpu *info)
594e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
595e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!info->egress_timer_scheduled) {
596e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		mod_timer_pinned(&info->egress_timer, jiffies + 1);
597e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->egress_timer_scheduled = true;
598e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
599e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
600e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
601e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
602e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
603e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The "function" for "info->egress_timer".
604e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
605e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This timer will reschedule itself as long as there are any pending
606e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * completions expected (on behalf of any tile).
607e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
608e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ISSUE: Realistically, will the timer ever stop scheduling itself?
609e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
610e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ISSUE: This timer is almost never actually needed, so just use a global
611e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * timer that can run on any tile.
612e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
613e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ISSUE: Maybe instead track number of expected completions, and free
614e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * only that many, resetting to zero if "pending" is ever false.
615e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
616e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_handle_egress_timer(unsigned long arg)
617e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
618e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = (struct tile_net_cpu *)arg;
619e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = info->napi.dev;
620e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
621e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The timer is no longer scheduled. */
622e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->egress_timer_scheduled = false;
623e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
624d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Free comps, and reschedule timer if more are pending. */
625d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (tile_net_lepp_free_comps(dev, false))
626e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		tile_net_schedule_egress_timer(info);
627e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
628e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
629e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
630e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef IGNORE_DUP_ACKS
631e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
632e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
633e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Help detect "duplicate" ACKs.  These are sequential packets (for a
634e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * given flow) which are exactly 66 bytes long, sharing everything but
635e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32,
636e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Tstamps=10@0x38.  The ID's are +1, the Hsum's are -1, the Ack's are
637e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * +N, and the Tstamps are usually identical.
638e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
639e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * NOTE: Apparently truly duplicate acks (with identical "ack" values),
640e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * should not be collapsed, as they are used for some kind of flow control.
641e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
642e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic bool is_dup_ack(char *s1, char *s2, unsigned int len)
643e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
644e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int i;
645e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
646e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned long long ignorable = 0;
647e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
648e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Identification. */
649e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x12);
650e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x13);
651e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
652e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Header checksum. */
653e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x18);
654e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x19);
655e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
656e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ACK. */
657e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x2a);
658e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x2b);
659e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x2c);
660e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x2d);
661e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
662e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* WinSize. */
663e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x30);
664e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x31);
665e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
666e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Checksum. */
667e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x32);
668e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ignorable |= (1ULL << 0x33);
669e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
670e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < len; i++, ignorable >>= 1) {
671e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
672e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if ((ignorable & 1) || (s1[i] == s2[i]))
673e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			continue;
674e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
675e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DEBUG
676e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* HACK: Mention non-timestamp diffs. */
677e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (i < 0x38 && i != 0x2f &&
678e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		    net_ratelimit())
679e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			pr_info("Diff at 0x%x\n", i);
680e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
681e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
682e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return false;
683e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
684e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
685e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS
686e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* HACK: Do not suppress truly duplicate ACKs. */
687e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: Is this actually necessary or helpful? */
688e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (s1[0x2a] == s2[0x2a] &&
689e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	    s1[0x2b] == s2[0x2b] &&
690e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	    s1[0x2c] == s2[0x2c] &&
691e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	    s1[0x2d] == s2[0x2d]) {
692e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return false;
693e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
694e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
695e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
696e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return true;
697e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
698e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
699e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
700e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
701e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
702e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
703d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic void tile_net_discard_aux(struct tile_net_cpu *info, int index)
704d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf{
705d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct tile_netio_queue *queue = &info->queue;
706d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	netio_queue_impl_t *qsp = queue->__system_part;
707d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	netio_queue_user_impl_t *qup = &queue->__user_part;
708d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
709d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int index2_aux = index + sizeof(netio_pkt_t);
710d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int index2 =
711d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		((index2_aux ==
712d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		  qsp->__packet_receive_queue.__last_packet_plus_one) ?
713d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 0 : index2_aux);
714d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
715d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
716d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
717d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Extract the "linux_buffer_t". */
718d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int buffer = pkt->__packet.word;
719d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
720d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Convert "linux_buffer_t" to "va". */
721d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	void *va = __va((phys_addr_t)(buffer >> 1) << 7);
722d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
723d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Acquire the associated "skb". */
724d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
725d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct sk_buff *skb = *skb_ptr;
726d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
727d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	kfree_skb(skb);
728d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
729d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Consume this packet. */
730d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	qup->__packet_receive_read = index2;
731d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf}
732d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
733d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
734e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
735d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Like "tile_net_poll()", but just discard packets.
736e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
737e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_discard_packets(struct net_device *dev)
738e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
739e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
740e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
741e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
742e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue = &info->queue;
743e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_impl_t *qsp = queue->__system_part;
744e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_user_impl_t *qup = &queue->__user_part;
745e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
746e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	while (qup->__packet_receive_read !=
747e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       qsp->__packet_receive_queue.__packet_write) {
748e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int index = qup->__packet_receive_read;
749d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		tile_net_discard_aux(info, index);
750e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
751e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
752e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
753e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
754e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
755e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Handle the next packet.  Return true if "processed", false if "filtered".
756e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
757e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
758e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
759e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = info->napi.dev;
760e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
761e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue = &info->queue;
762e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_impl_t *qsp = queue->__system_part;
763e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_user_impl_t *qup = &queue->__user_part;
764e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_stats_t *stats = &info->stats;
765e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
766e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int filter;
767e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
768e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int index2_aux = index + sizeof(netio_pkt_t);
769e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int index2 =
770e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		((index2_aux ==
771e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		  qsp->__packet_receive_queue.__last_packet_plus_one) ?
772e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 0 : index2_aux);
773e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
774e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
775e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
776e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt);
777e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
778d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Extract the packet size.  FIXME: Shouldn't the second line */
779d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* get subtracted?  Mostly moot, since it should be "zero". */
780e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned long len =
781e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		(NETIO_PKT_CUSTOM_LENGTH(pkt) +
782e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 NET_IP_ALIGN - NETIO_PACKET_PADDING);
783e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
784e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Extract the "linux_buffer_t". */
785e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int buffer = pkt->__packet.word;
786e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
787e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Extract "small" (vs "large"). */
788e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	bool small = ((buffer & 1) != 0);
789e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
790e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Convert "linux_buffer_t" to "va". */
791e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	void *va = __va((phys_addr_t)(buffer >> 1) << 7);
792e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
793e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Extract the packet data pointer. */
794e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
795e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned char *buf = va + NET_IP_ALIGN;
796e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
797e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Invalidate the packet buffer. */
798e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!hash_default)
799e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		__inv_buffer(buf, len);
800e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
801e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: Is this needed? */
802e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->last_rx = jiffies;
803e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
804e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DUMP_PACKETS
805e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dump_packet(buf, len, "rx");
806e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif /* TILE_NET_DUMP_PACKETS */
807e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
808e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_VERIFY_INGRESS
809e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) &&
810e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	    NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) {
811d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* Bug 6624: Includes UDP packets with a "zero" checksum. */
812e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_warning("Bad L4 checksum on %d byte packet.\n", len);
813e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
814e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) &&
815e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	    NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) {
816e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		dump_packet(buf, len, "rx");
817e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		panic("Bad L3 checksum.");
818e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
819e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	switch (NETIO_PKT_STATUS_M(metadata, pkt)) {
820e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	case NETIO_PKT_STATUS_OVERSIZE:
821e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (len >= 64) {
822e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			dump_packet(buf, len, "rx");
823e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			panic("Unexpected OVERSIZE.");
824e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
825e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		break;
826e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	case NETIO_PKT_STATUS_BAD:
827d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		pr_warning("Unexpected BAD %ld byte packet.\n", len);
828e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
829e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
830e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
831e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	filter = 0;
832e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
833d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: Filter TCP packets with "bad" checksums? */
834d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
835e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!(dev->flags & IFF_UP)) {
836e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Filter packets received before we're up. */
837e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		filter = 1;
838d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	} else if (NETIO_PKT_STATUS_M(metadata, pkt) == NETIO_PKT_STATUS_BAD) {
839d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* Filter "truncated" packets. */
840d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		filter = 1;
841e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	} else if (!(dev->flags & IFF_PROMISC)) {
842d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* FIXME: Implement HW multicast filter. */
843d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (!is_multicast_ether_addr(buf)) {
844e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			/* Filter packets not for our address. */
845e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			const u8 *mine = dev->dev_addr;
846e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			filter = compare_ether_addr(mine, buf);
847e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
848e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
849e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
850e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (filter) {
851e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
852e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* ISSUE: Update "drop" statistics? */
853e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
854e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		tile_net_provide_linux_buffer(info, va, small);
855e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
856e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	} else {
857e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
858e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Acquire the associated "skb". */
859e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
860e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		struct sk_buff *skb = *skb_ptr;
861e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
862e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Paranoia. */
863e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (skb->data != buf)
864e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			panic("Corrupt linux buffer from LIPP! "
865e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			      "VA=%p, skb=%p, skb->data=%p\n",
866e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			      va, skb, skb->data);
867e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
868e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Encode the actual packet length. */
869e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		skb_put(skb, len);
870e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
871e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* NOTE: This call also sets "skb->dev = dev". */
872e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		skb->protocol = eth_type_trans(skb, dev);
873e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
874d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* Avoid recomputing "good" TCP/UDP checksums. */
875e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt))
876e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			skb->ip_summed = CHECKSUM_UNNECESSARY;
877e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
878e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		netif_receive_skb(skb);
879e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
880e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		stats->rx_packets++;
881e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		stats->rx_bytes += len;
882e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
883e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
88492795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* ISSUE: It would be nice to defer this until the packet has */
88592795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* actually been processed. */
88692795672898d5ee1faa557c498c078123d20e827Chris Metcalf	tile_net_return_credit(info);
887e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
888e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Consume this packet. */
889e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	qup->__packet_receive_read = index2;
890e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
891e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return !filter;
892e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
893e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
894e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
895e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
896e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Handle some packets for the given device on the current CPU.
897e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
898d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * If "tile_net_stop()" is called on some other tile while this
899d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * function is running, we will return, hopefully before that
900d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * other tile asks us to call "napi_disable()".
901d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
902d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * The "rotting packet" race condition occurs if a packet arrives
903d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * during the extremely narrow window between the queue appearing to
904d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * be empty, and the ingress interrupt being re-enabled.  This happens
905d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * a LOT under heavy network load.
906e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
907e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_poll(struct napi_struct *napi, int budget)
908e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
909e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = napi->dev;
910e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
911e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
912e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
913e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue = &info->queue;
914e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_impl_t *qsp = queue->__system_part;
915e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_user_impl_t *qup = &queue->__user_part;
916e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
917e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int work = 0;
918e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
919d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	while (priv->active) {
920e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int index = qup->__packet_receive_read;
921e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (index == qsp->__packet_receive_queue.__packet_write)
922e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			break;
923e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
924e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (tile_net_poll_aux(info, index)) {
925e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			if (++work >= budget)
926e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				goto done;
927e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
928e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
929e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
930e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	napi_complete(&info->napi);
931e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
932d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (!priv->active)
933d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		goto done;
934d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
935d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Re-enable the ingress interrupt. */
9360c90547b4a3fcee184db4d54ffc1a4fb17fd54d6Chris Metcalf	enable_percpu_irq(priv->intr_id, 0);
937e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
938d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* HACK: Avoid the "rotting packet" problem (see above). */
939e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (qup->__packet_receive_read !=
940d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	    qsp->__packet_receive_queue.__packet_write) {
941d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* ISSUE: Sometimes this returns zero, presumably */
942d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* because an interrupt was handled for this tile. */
943d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		(void)napi_reschedule(&info->napi);
944d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
945e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
946e5a06939736277c54a68ae275433db55b99d187cChris Metcalfdone:
947e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
948d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (priv->active)
949d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		tile_net_provide_needed_buffers(info);
950e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
951e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return work;
952e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
953e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
954e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
955e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
956e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Handle an ingress interrupt for the given device on the current cpu.
957d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
958d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ISSUE: Sometimes this gets called after "disable_percpu_irq()" has
959d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * been called!  This is probably due to "pending hypervisor downcalls".
960d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
961d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ISSUE: Is there any race condition between the "napi_schedule()" here
962d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * and the "napi_complete()" call above?
963e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
964e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr)
965e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
966e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
967e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
968e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
969e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
970e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
971d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Disable the ingress interrupt. */
972e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	disable_percpu_irq(priv->intr_id);
973e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
974d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Ignore unwanted interrupts. */
975d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (!priv->active)
976d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		return IRQ_HANDLED;
977d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
978d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: Sometimes "info->napi_enabled" is false here. */
979d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
980e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	napi_schedule(&info->napi);
981e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
982e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return IRQ_HANDLED;
983e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
984e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
985e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
986e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
987e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * One time initialization per interface.
988e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
989e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_open_aux(struct net_device *dev)
990e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
991e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
992e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
993e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int ret;
994e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int dummy;
995e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int epp_lotar;
996e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
997e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
998e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Find out where EPP memory should be homed.
999e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1000e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pread(priv->hv_devhdl, 0,
1001e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   (HV_VirtAddr)&epp_lotar, sizeof(epp_lotar),
1002e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   NETIO_EPP_SHM_OFF);
1003e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret < 0) {
1004e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_err("could not read epp_shm_queue lotar.\n");
1005e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return -EIO;
1006e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1007e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1008e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1009e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Home the page on the EPP.
1010e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1011e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	{
1012e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int epp_home = hv_lotar_to_cpu(epp_lotar);
1013d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		homecache_change_page_home(priv->eq_pages, EQ_ORDER, epp_home);
1014e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1015e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1016e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1017e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Register the EPP shared memory queue.
1018e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1019e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	{
1020e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		netio_ipp_address_t ea = {
1021e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.va = 0,
1022d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			.pa = __pa(priv->eq),
1023e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.pte = hv_pte(0),
1024d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			.size = EQ_SIZE,
1025e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		};
1026e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		ea.pte = hv_pte_set_lotar(ea.pte, epp_lotar);
1027e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		ea.pte = hv_pte_set_mode(ea.pte, HV_PTE_MODE_CACHE_TILE_L3);
1028e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		ret = hv_dev_pwrite(priv->hv_devhdl, 0,
1029e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				    (HV_VirtAddr)&ea,
1030e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				    sizeof(ea),
1031e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				    NETIO_EPP_SHM_OFF);
1032e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (ret < 0)
1033e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			return -EIO;
1034e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1035e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1036e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1037e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Start LIPP/LEPP.
1038e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1039e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
1040e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			  sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) {
1041e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_warning("Failed to start LIPP/LEPP.\n");
1042e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return -EIO;
1043e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1044e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1045e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
1046e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1047e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1048e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1049e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1050d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Register with hypervisor on the current CPU.
1051e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1052e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Strangely, this function does important things even if it "fails",
1053e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * which is especially common if the link is not up yet.  Hopefully
1054e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * these things are all "harmless" if done twice!
1055e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1056e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_register(void *dev_ptr)
1057e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1058e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
1059e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1060e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1061e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info;
1062e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1063e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue;
1064e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1065e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Only network cpus can receive packets. */
1066e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int queue_id =
1067e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cpumask_test_cpu(my_cpu, &priv->network_cpus_map) ? 0 : 255;
1068e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1069e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_input_config_t config = {
1070e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.flags = 0,
1071e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.num_receive_packets = priv->network_cpus_credits,
1072e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.queue_id = queue_id
1073e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	};
1074e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1075e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int ret = 0;
1076e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netio_queue_impl_t *queuep;
1077e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1078e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("tile_net_register(queue_id %d)\n", queue_id);
1079e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1080e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!strcmp(dev->name, "xgbe0"))
1081e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info = &__get_cpu_var(hv_xgbe0);
1082e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	else if (!strcmp(dev->name, "xgbe1"))
1083e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info = &__get_cpu_var(hv_xgbe1);
1084e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	else if (!strcmp(dev->name, "gbe0"))
1085e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info = &__get_cpu_var(hv_gbe0);
1086e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	else if (!strcmp(dev->name, "gbe1"))
1087e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info = &__get_cpu_var(hv_gbe1);
1088e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	else
1089e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		BUG();
1090e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1091e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Initialize the egress timer. */
1092e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	init_timer(&info->egress_timer);
1093e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->egress_timer.data = (long)info;
1094e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->egress_timer.function = tile_net_handle_egress_timer;
1095e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1096e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->cpu[my_cpu] = info;
1097e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1098e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1099d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * Register ourselves with LIPP.  This does a lot of stuff,
1100d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * including invoking the LIPP registration code.
1101e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1102e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pwrite(priv->hv_devhdl, 0,
1103e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			    (HV_VirtAddr)&config,
1104e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			    sizeof(netio_input_config_t),
1105e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			    NETIO_IPP_INPUT_REGISTER_OFF);
1106e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
1107e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       ret);
1108e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret < 0) {
1109d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (ret != NETIO_LINK_DOWN) {
1110d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			printk(KERN_DEBUG "hv_dev_pwrite "
1111d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			       "NETIO_IPP_INPUT_REGISTER_OFF failure %d\n",
1112d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			       ret);
1113d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		}
1114e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->link_down = (ret == NETIO_LINK_DOWN);
1115e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return;
1116e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1117e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1118e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1119e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Get the pointer to our queue's system part.
1120e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1121e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1122e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pread(priv->hv_devhdl, 0,
1123e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   (HV_VirtAddr)&queuep,
1124e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   sizeof(netio_queue_impl_t *),
1125e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   NETIO_IPP_INPUT_REGISTER_OFF);
1126e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("hv_dev_pread(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
1127e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       ret);
1128e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("queuep %p\n", queuep);
1129e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret <= 0) {
1130e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* ISSUE: Shouldn't this be a fatal error? */
1131e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_err("hv_dev_pread NETIO_IPP_INPUT_REGISTER_OFF failure\n");
1132e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return;
1133e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1134e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1135e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	queue = &info->queue;
1136e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1137e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	queue->__system_part = queuep;
1138e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1139e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	memset(&queue->__user_part, 0, sizeof(netio_queue_user_impl_t));
1140e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1141e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* This is traditionally "config.num_receive_packets / 2". */
1142e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	queue->__user_part.__receive_credit_interval = 4;
1143e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	queue->__user_part.__receive_credit_remaining =
1144e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		queue->__user_part.__receive_credit_interval;
1145e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1146e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1147e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Get a fastio index from the hypervisor.
1148e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * ISSUE: Shouldn't this check the result?
1149e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1150e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pread(priv->hv_devhdl, 0,
1151e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   (HV_VirtAddr)&queue->__user_part.__fastio_index,
1152e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   sizeof(queue->__user_part.__fastio_index),
1153e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   NETIO_IPP_GET_FASTIO_OFF);
1154e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("hv_dev_pread(NETIO_IPP_GET_FASTIO_OFF) returned %d\n", ret);
1155e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1156e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Now we are registered. */
1157e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->registered = true;
1158e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1159e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1160e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1161e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1162d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Deregister with hypervisor on the current CPU.
1163d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1164d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * This simply discards all our credits, so no more packets will be
1165d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * delivered to this tile.  There may still be packets in our queue.
1166d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1167d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Also, disable the ingress interrupt.
1168d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf */
1169d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic void tile_net_deregister(void *dev_ptr)
1170d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf{
1171d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
1172d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1173d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int my_cpu = smp_processor_id();
1174d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1175d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1176d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Disable the ingress interrupt. */
1177d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	disable_percpu_irq(priv->intr_id);
1178d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1179d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Do nothing else if not registered. */
1180d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (info == NULL || !info->registered)
1181d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		return;
1182d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1183d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	{
1184d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		struct tile_netio_queue *queue = &info->queue;
1185d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		netio_queue_user_impl_t *qup = &queue->__user_part;
1186d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1187d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* Discard all our credits. */
1188d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		__netio_fastio_return_credits(qup->__fastio_index, -1);
1189d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
1190d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf}
1191d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1192d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1193d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf/*
1194d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Unregister with hypervisor on the current CPU.
1195d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1196d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Also, disable the ingress interrupt.
1197e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1198e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_unregister(void *dev_ptr)
1199e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1200e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
1201e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1202e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1203e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1204e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1205d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int ret;
1206e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int dummy = 0;
1207e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1208d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Disable the ingress interrupt. */
1209d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	disable_percpu_irq(priv->intr_id);
1210e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1211d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Do nothing else if not registered. */
1212d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (info == NULL || !info->registered)
1213e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return;
1214e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1215d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Unregister ourselves with LIPP/LEPP. */
1216e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
1217e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			    sizeof(dummy), NETIO_IPP_INPUT_UNREGISTER_OFF);
1218d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (ret < 0)
1219d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		panic("Failed to unregister with LIPP/LEPP!\n");
1220e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1221d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Discard all packets still in our NetIO queue. */
1222e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_discard_packets(dev);
1223e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1224e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Reset state. */
1225e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->num_needed_small_buffers = 0;
1226e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->num_needed_large_buffers = 0;
1227e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1228e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Cancel egress timer. */
1229e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	del_timer(&info->egress_timer);
1230e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->egress_timer_scheduled = false;
1231e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1232e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1233e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1234e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1235e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Helper function for "tile_net_stop()".
1236e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1237e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Also used to handle registration failure in "tile_net_open_inner()",
1238d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * when the various extra steps in "tile_net_stop()" are not necessary.
1239e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1240e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_stop_aux(struct net_device *dev)
1241e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1242e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1243d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int i;
1244e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1245e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int dummy = 0;
1246e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1247d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/*
1248d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * Unregister all tiles, so LIPP will stop delivering packets.
1249d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * Also, delete all the "napi" objects (sequentially, to protect
1250d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * "dev->napi_list").
1251d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 */
1252e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	on_each_cpu(tile_net_unregister, (void *)dev, 1);
1253d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	for_each_online_cpu(i) {
1254d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		struct tile_net_cpu *info = priv->cpu[i];
1255d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (info != NULL && info->registered) {
1256d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			netif_napi_del(&info->napi);
1257d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			info->registered = false;
1258d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		}
1259d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
1260e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1261e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Stop LIPP/LEPP. */
1262e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
1263e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			  sizeof(dummy), NETIO_IPP_STOP_SHIM_OFF) < 0)
1264e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		panic("Failed to stop LIPP/LEPP!\n");
1265e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
12663db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell	priv->partly_opened = false;
1267e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1268e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1269e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1270e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1271d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Disable NAPI for the given device on the current cpu.
1272e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1273d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic void tile_net_stop_disable(void *dev_ptr)
1274e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1275e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
1276e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1277e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1278e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1279e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1280e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Disable NAPI if needed. */
1281e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (info != NULL && info->napi_enabled) {
1282e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		napi_disable(&info->napi);
1283e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->napi_enabled = false;
1284e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1285e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1286e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1287e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1288e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1289d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Enable NAPI and the ingress interrupt for the given device
1290d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * on the current cpu.
1291d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1292d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ISSUE: Only do this for "network cpus"?
1293e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1294d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic void tile_net_open_enable(void *dev_ptr)
1295e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1296e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev = (struct net_device *)dev_ptr;
1297e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1298e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1299e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1300e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1301e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Enable NAPI. */
1302e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	napi_enable(&info->napi);
1303e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info->napi_enabled = true;
1304d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1305d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Enable the ingress interrupt. */
13060c90547b4a3fcee184db4d54ffc1a4fb17fd54d6Chris Metcalf	enable_percpu_irq(priv->intr_id, 0);
1307e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1308e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1309e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1310e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1311e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * tile_net_open_inner does most of the work of bringing up the interface.
1312e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * It's called from tile_net_open(), and also from tile_net_retry_open().
1313e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The return value is 0 if the interface was brought up, < 0 if
1314e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * tile_net_open() should return the return value as an error, and > 0 if
1315e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * tile_net_open() should return success and schedule a work item to
1316e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * periodically retry the bringup.
1317e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1318e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_open_inner(struct net_device *dev)
1319e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1320e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1321e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1322e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info;
1323e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_netio_queue *queue;
1324d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int result = 0;
1325e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int i;
1326d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int dummy = 0;
1327e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1328e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1329e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * First try to register just on the local CPU, and handle any
1330e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * semi-expected "link down" failure specially.  Note that we
1331e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * do NOT call "tile_net_stop_aux()", unlike below.
1332e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1333e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_register(dev);
1334e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	info = priv->cpu[my_cpu];
1335e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!info->registered) {
1336e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (info->link_down)
1337e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			return 1;
1338e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return -EAGAIN;
1339e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1340e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1341e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1342e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Now register everywhere else.  If any registration fails,
1343e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * even for "link down" (which might not be possible), we
1344d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * clean up using "tile_net_stop_aux()".  Also, add all the
1345d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * "napi" objects (sequentially, to protect "dev->napi_list").
1346d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * ISSUE: Only use "netif_napi_add()" for "network cpus"?
1347e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1348e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	smp_call_function(tile_net_register, (void *)dev, 1);
1349e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for_each_online_cpu(i) {
1350d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		struct tile_net_cpu *info = priv->cpu[i];
1351d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (info->registered)
1352d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			netif_napi_add(dev, &info->napi, tile_net_poll, 64);
1353d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		else
1354d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			result = -EAGAIN;
1355d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
1356d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (result != 0) {
1357d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		tile_net_stop_aux(dev);
1358d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		return result;
1359e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1360e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1361e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	queue = &info->queue;
1362e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1363d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (priv->intr_id == 0) {
1364d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		unsigned int irq;
1365e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1366d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/*
1367d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * Acquire the irq allocated by the hypervisor.  Every
1368d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * queue gets the same irq.  The "__intr_id" field is
1369d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * "1 << irq", so we use "__ffs()" to extract "irq".
1370d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 */
1371d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		priv->intr_id = queue->__system_part->__intr_id;
1372d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		BUG_ON(priv->intr_id == 0);
1373d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		irq = __ffs(priv->intr_id);
1374e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1375d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/*
1376d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * Register the ingress interrupt handler for this
1377d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * device, permanently.
1378d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 *
1379d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * We used to call "free_irq()" in "tile_net_stop()",
1380d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * and then re-register the handler here every time,
1381d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * but that caused DNP errors in "handle_IRQ_event()"
1382d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 * because "desc->action" was NULL.  See bug 9143.
1383d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		 */
1384d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		tile_irq_activate(irq, TILE_IRQ_PERCPU);
1385d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt,
1386d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf				   0, dev->name, (void *)dev) != 0);
1387d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
1388e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1389d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	{
1390e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Allocate initial buffers. */
1391e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1392e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int max_buffers =
1393e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			priv->network_cpus_count * priv->network_cpus_credits;
1394e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1395e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->num_needed_small_buffers =
1396e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			min(LIPP_SMALL_BUFFERS, max_buffers);
1397e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1398e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		info->num_needed_large_buffers =
1399e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			min(LIPP_LARGE_BUFFERS, max_buffers);
1400e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1401e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		tile_net_provide_needed_buffers(info);
1402e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1403e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (info->num_needed_small_buffers != 0 ||
1404e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		    info->num_needed_large_buffers != 0)
1405e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			panic("Insufficient memory for buffer stack!");
1406d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	}
1407e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1408d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* We are about to be active. */
1409d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	priv->active = true;
1410e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1411d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Make sure "active" is visible to all tiles. */
1412d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	mb();
1413e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1414d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* On each tile, enable NAPI and the ingress interrupt. */
1415d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	on_each_cpu(tile_net_open_enable, (void *)dev, 1);
1416d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1417d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Start LIPP/LEPP and activate "ingress" at the shim. */
1418d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
1419d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			  sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0)
1420d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		panic("Failed to activate the LIPP Shim!\n");
1421e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1422e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Start our transmit queue. */
1423e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netif_start_queue(dev);
1424e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1425e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
1426e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1427e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1428e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1429e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1430e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Called periodically to retry bringing up the NetIO interface,
1431e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * if it doesn't come up cleanly during tile_net_open().
1432e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1433e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_open_retry(struct work_struct *w)
1434e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1435e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct delayed_work *dw =
1436e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		container_of(w, struct delayed_work, work);
1437e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1438e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv =
1439e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		container_of(dw, struct tile_net_priv, retry_work);
1440e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1441e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1442e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Try to bring the NetIO interface up.  If it fails, reschedule
1443e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * ourselves to try again later; otherwise, tell Linux we now have
1444e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * a working link.  ISSUE: What if the return value is negative?
1445e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1446d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (tile_net_open_inner(priv->dev) != 0)
1447d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		schedule_delayed_work(&priv->retry_work,
1448d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf				      TILE_NET_RETRY_INTERVAL);
1449e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	else
1450e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		netif_carrier_on(priv->dev);
1451e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1452e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1453e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1454e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1455e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Called when a network interface is made active.
1456e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1457e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Returns 0 on success, negative value on failure.
1458e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1459e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The open entry point is called when a network interface is made
1460e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * active by the system (IFF_UP).  At this point all resources needed
1461e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * for transmit and receive operations are allocated, the interrupt
1462d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * handler is registered with the OS (if needed), the watchdog timer
1463d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * is started, and the stack is notified that the interface is ready.
1464e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1465e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * If the actual link is not available yet, then we tell Linux that
1466e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * we have no carrier, and we keep checking until the link comes up.
1467e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1468e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_open(struct net_device *dev)
1469e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1470e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int ret = 0;
1471e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1472e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1473e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1474e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * We rely on priv->partly_opened to tell us if this is the
1475e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * first time this interface is being brought up. If it is
1476e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * set, the IPP was already initialized and should not be
1477e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * initialized again.
1478e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1479e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!priv->partly_opened) {
1480e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1481e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int count;
1482e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int credits;
1483e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1484e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Initialize LIPP/LEPP, and start the Shim. */
1485e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		ret = tile_net_open_aux(dev);
1486e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (ret < 0) {
1487e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			pr_err("tile_net_open_aux failed: %d\n", ret);
1488e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			return ret;
1489e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
1490e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1491e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Analyze the network cpus. */
1492e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1493e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (network_cpus_used)
1494e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cpumask_copy(&priv->network_cpus_map,
1495e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				     &network_cpus_map);
1496e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		else
1497e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cpumask_copy(&priv->network_cpus_map, cpu_online_mask);
1498e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1499e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1500e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		count = cpumask_weight(&priv->network_cpus_map);
1501e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1502e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Limit credits to available buffers, and apply min. */
1503e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		credits = max(16, (LIPP_LARGE_BUFFERS / count) & ~1);
1504e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1505e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Apply "GBE" max limit. */
1506e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* ISSUE: Use higher limit for XGBE? */
1507e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		credits = min(NETIO_MAX_RECEIVE_PKTS, credits);
1508e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1509e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		priv->network_cpus_count = count;
1510e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		priv->network_cpus_credits = credits;
1511e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1512e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DEBUG
1513e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_info("Using %d network cpus, with %d credits each\n",
1514e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       priv->network_cpus_count, priv->network_cpus_credits);
1515e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
1516e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
15173db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell		priv->partly_opened = true;
1518d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1519d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	} else {
1520d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* FIXME: Is this possible? */
1521d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* printk("Already partly opened.\n"); */
1522e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1523e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1524e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1525e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Attempt to bring up the link.
1526e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1527e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = tile_net_open_inner(dev);
1528e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret <= 0) {
1529e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (ret == 0)
1530e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			netif_carrier_on(dev);
1531e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return ret;
1532e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1533e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1534e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1535e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * We were unable to bring up the NetIO interface, but we want to
1536e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * try again in a little bit.  Tell Linux that we have no carrier
1537e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * so it doesn't try to use the interface before the link comes up
1538e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * and then remember to try again later.
1539e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1540e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netif_carrier_off(dev);
1541d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	schedule_delayed_work(&priv->retry_work, TILE_NET_RETRY_INTERVAL);
1542e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1543e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
1544e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1545e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1546e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1547d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic int tile_net_drain_lipp_buffers(struct tile_net_priv *priv)
1548e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1549d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	int n = 0;
1550e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1551d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Drain all the LIPP buffers. */
1552e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	while (true) {
155392795672898d5ee1faa557c498c078123d20e827Chris Metcalf		unsigned int buffer;
1554e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1555e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* NOTE: This should never fail. */
1556e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer,
1557e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				 sizeof(buffer), NETIO_IPP_DRAIN_OFF) < 0)
1558e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			break;
1559e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1560e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Stop when done. */
1561e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (buffer == 0)
1562e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			break;
1563e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1564e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		{
1565e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			/* Convert "linux_buffer_t" to "va". */
1566e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			void *va = __va((phys_addr_t)(buffer >> 1) << 7);
1567e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1568e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			/* Acquire the associated "skb". */
1569e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
1570e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			struct sk_buff *skb = *skb_ptr;
1571e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1572e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			kfree_skb(skb);
1573e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
1574d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1575d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		n++;
1576e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1577e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1578d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	return n;
1579d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf}
1580e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1581e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1582d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf/*
1583d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Disables a network interface.
1584d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1585d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Returns 0, this is not allowed to fail.
1586d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1587d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * The close entry point is called when an interface is de-activated
1588d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * by the OS.  The hardware is still under the drivers control, but
1589d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * needs to be disabled.  A global MAC reset is issued to stop the
1590d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * hardware, and all transmit and receive resources are freed.
1591d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1592d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * ISSUE: How closely does "netif_running(dev)" mirror "priv->active"?
1593d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1594d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Before we are called by "__dev_close()", "netif_running()" will
1595d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * have been cleared, so no NEW calls to "tile_net_poll()" will be
1596d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * made by "netpoll_poll_dev()".
1597d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1598d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Often, this can cause some tiles to still have packets in their
1599d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * queues, so we must call "tile_net_discard_packets()" later.
1600d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1601d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Note that some other tile may still be INSIDE "tile_net_poll()",
1602d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * and in fact, many will be, if there is heavy network load.
1603d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1604d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * Calling "on_each_cpu(tile_net_stop_disable, (void *)dev, 1)" when
1605d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * any tile is still "napi_schedule()"'d will induce a horrible crash
1606d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * when "msleep()" is called.  This includes tiles which are inside
1607d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * "tile_net_poll()" which have not yet called "napi_complete()".
1608d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
1609d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * So, we must first try to wait long enough for other tiles to finish
1610d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * with any current "tile_net_poll()" call, and, hopefully, to clear
1611d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * the "scheduled" flag.  ISSUE: It is unclear what happens to tiles
1612d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * which have called "napi_schedule()" but which had not yet tried to
1613d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * call "tile_net_poll()", or which exhausted their budget inside
1614d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * "tile_net_poll()" just before this function was called.
1615d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf */
1616d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfstatic int tile_net_stop(struct net_device *dev)
1617d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf{
1618d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1619d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1620d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	PDEBUG("tile_net_stop()\n");
1621e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1622d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Start discarding packets. */
1623d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	priv->active = false;
1624d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1625d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Make sure "active" is visible to all tiles. */
1626d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	mb();
1627e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1628e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1629d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * On each tile, make sure no NEW packets get delivered, and
1630d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * disable the ingress interrupt.
1631d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 *
1632d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * Note that the ingress interrupt can fire AFTER this,
1633d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * presumably due to packets which were recently delivered,
1634d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * but it will have no effect.
1635e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1636d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	on_each_cpu(tile_net_deregister, (void *)dev, 1);
1637e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1638d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Optimistically drain LIPP buffers. */
1639d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	(void)tile_net_drain_lipp_buffers(priv);
1640e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1641d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: Only needed if not yet fully open. */
1642d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	cancel_delayed_work_sync(&priv->retry_work);
1643e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1644d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Can't transmit any more. */
1645d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	netif_stop_queue(dev);
1646e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1647d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Disable NAPI on each tile. */
1648d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	on_each_cpu(tile_net_stop_disable, (void *)dev, 1);
1649d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1650d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/*
1651d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * Drain any remaining LIPP buffers.  NOTE: This "printk()"
1652d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * has never been observed, but in theory it could happen.
1653d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 */
1654d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (tile_net_drain_lipp_buffers(priv) != 0)
1655d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		printk("Had to drain some extra LIPP buffers!\n");
1656e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1657d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Stop LIPP/LEPP. */
1658d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	tile_net_stop_aux(dev);
1659d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1660d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/*
1661d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * ISSUE: It appears that, in practice anyway, by the time we
1662d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * get here, there are no pending completions, but just in case,
1663d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 * we free (all of) them anyway.
1664d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	 */
1665d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	while (tile_net_lepp_free_comps(dev, true))
1666d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		/* loop */;
1667e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1668d07bd86d82622247dba8cc29974d3860f857ea33Chris Metcalf	/* Wipe the EPP queue, and wait till the stores hit the EPP. */
1669d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	memset(priv->eq, 0, sizeof(lepp_queue_t));
1670d07bd86d82622247dba8cc29974d3860f857ea33Chris Metcalf	mb();
1671e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1672e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
1673e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1674e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1675e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1676e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1677e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Prepare the "frags" info for the resulting LEPP command.
1678e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1679e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * If needed, flush the memory used by the frags.
1680e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1681e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic unsigned int tile_net_tx_frags(lepp_frag_t *frags,
1682e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				      struct sk_buff *skb,
1683e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				      void *b_data, unsigned int b_len)
1684e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1685e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int i, n = 0;
1686e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1687e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct skb_shared_info *sh = skb_shinfo(skb);
1688e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1689e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	phys_addr_t cpa;
1690e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1691e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (b_len != 0) {
1692e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1693e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (!hash_default)
169463b7ca6b04427aea9075d6f5f5f15b82e115bce4Chris Metcalf			finv_buffer_remote(b_data, b_len, 0);
1695e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1696e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cpa = __pa(b_data);
1697e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].cpa_lo = cpa;
1698e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].cpa_hi = cpa >> 32;
1699e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].length = b_len;
1700e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].hash_for_home = hash_default;
1701e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		n++;
1702e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1703e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1704e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < sh->nr_frags; i++) {
1705e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1706e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		skb_frag_t *f = &sh->frags[i];
1707781a5e92bc3b666bc5752e3ce7e977978c2f64e9Chris Metcalf		unsigned long pfn = page_to_pfn(skb_frag_page(f));
1708e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1709e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* FIXME: Compute "hash_for_home" properly. */
1710e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* ISSUE: The hypervisor checks CHIP_HAS_REV1_DMA_PACKETS(). */
1711e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		int hash_for_home = hash_default;
1712e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1713e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* FIXME: Hmmm. */
1714e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (!hash_default) {
1715e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			void *va = pfn_to_kaddr(pfn) + f->page_offset;
1716781a5e92bc3b666bc5752e3ce7e977978c2f64e9Chris Metcalf			BUG_ON(PageHighMem(skb_frag_page(f)));
171792795672898d5ee1faa557c498c078123d20e827Chris Metcalf			finv_buffer_remote(va, skb_frag_size(f), 0);
1718e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
1719e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1720e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
1721e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].cpa_lo = cpa;
1722e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].cpa_hi = cpa >> 32;
17239e903e085262ffbf1fc44a17ac06058aca03524aEric Dumazet		frags[n].length = skb_frag_size(f);
1724e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		frags[n].hash_for_home = hash_for_home;
1725e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		n++;
1726e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1727e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1728e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return n;
1729e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1730e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1731e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1732e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1733e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This function takes "skb", consisting of a header template and a
1734e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * payload, and hands it to LEPP, to emit as one or more segments,
1735e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * each consisting of a possibly modified header, plus a piece of the
1736e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * payload, via a process known as "tcp segmentation offload".
1737e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1738e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Usually, "data" will contain the header template, of size "sh_len",
1739e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * and "sh->frags" will contain "skb->data_len" bytes of payload, and
1740e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * there will be "sh->gso_segs" segments.
1741e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1742e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Sometimes, if "sendfile()" requires copying, we will be called with
1743e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * "data" containing the header and payload, with "frags" being empty.
1744e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
174592795672898d5ee1faa557c498c078123d20e827Chris Metcalf * Sometimes, for example when using NFS over TCP, a single segment can
174692795672898d5ee1faa557c498c078123d20e827Chris Metcalf * span 3 fragments, which must be handled carefully in LEPP.
1747e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1748e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * See "emulate_large_send_offload()" for some reference code, which
1749e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * does not handle checksumming.
1750e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
1751e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * ISSUE: How do we make sure that high memory DMA does not migrate?
1752e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1753e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
1754e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1755e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1756e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1757e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1758e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_stats_t *stats = &info->stats;
1759e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1760e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct skb_shared_info *sh = skb_shinfo(skb);
1761e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1762e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned char *data = skb->data;
1763e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1764e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The ip header follows the ethernet header. */
1765e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct iphdr *ih = ip_hdr(skb);
1766e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int ih_len = ih->ihl * 4;
1767e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1768e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Note that "nh == ih", by definition. */
1769e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned char *nh = skb_network_header(skb);
1770e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int eh_len = nh - data;
1771e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1772e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The tcp header follows the ip header. */
1773e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tcphdr *th = (struct tcphdr *)(nh + ih_len);
1774e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int th_len = th->doff * 4;
1775e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1776e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The total number of header bytes. */
1777e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* NOTE: This may be less than skb_headlen(skb). */
1778e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int sh_len = eh_len + ih_len + th_len;
1779e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1780e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The number of payload bytes at "skb->data + sh_len". */
1781e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* This is non-zero for sendfile() without HIGHDMA. */
1782e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int b_len = skb_headlen(skb) - sh_len;
1783e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1784e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The total number of payload bytes. */
1785e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int d_len = b_len + skb->data_len;
1786e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1787e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The maximum payload size. */
1788e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int p_len = sh->gso_size;
1789e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1790e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The total number of segments. */
1791e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int num_segs = sh->gso_segs;
1792e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1793e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The temporary copy of the command. */
1794e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 cmd_body[(LEPP_MAX_CMD_SIZE + 3) / 4];
1795e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	lepp_tso_cmd_t *cmd = (lepp_tso_cmd_t *)cmd_body;
1796e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1797e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Analyze the "frags". */
1798e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int num_frags =
1799e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		tile_net_tx_frags(cmd->frags, skb, data + sh_len, b_len);
1800e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1801e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The size of the command, including frags and header. */
1802e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	size_t cmd_size = LEPP_TSO_CMD_SIZE(num_frags, sh_len);
1803e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1804e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* The command header. */
1805e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	lepp_tso_cmd_t cmd_init = {
1806e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.tso = true,
1807e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.header_size = sh_len,
1808e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.ip_offset = eh_len,
1809e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.tcp_offset = eh_len + ih_len,
1810e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.payload_size = p_len,
1811e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		.num_frags = num_frags,
1812e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	};
1813e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1814e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned long irqflags;
1815e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1816d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	lepp_queue_t *eq = priv->eq;
1817e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1818d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct sk_buff *olds[8];
1819d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int wanted = 8;
1820e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int i, nolds = 0;
1821e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1822e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int cmd_head, cmd_tail, cmd_next;
1823e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int comp_tail;
1824e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1825e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1826e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Paranoia. */
1827e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	BUG_ON(skb->protocol != htons(ETH_P_IP));
1828e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	BUG_ON(ih->protocol != IPPROTO_TCP);
1829e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	BUG_ON(skb->ip_summed != CHECKSUM_PARTIAL);
1830e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	BUG_ON(num_frags > LEPP_MAX_FRAGS);
1831e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*--BUG_ON(num_segs != (d_len + (p_len - 1)) / p_len); */
1832e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	BUG_ON(num_segs <= 1);
1833e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1834e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1835e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Finish preparing the command. */
1836e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1837e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Copy the command header. */
1838e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	*cmd = cmd_init;
1839e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1840e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Copy the "header". */
1841e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	memcpy(&cmd->frags[num_frags], data, sh_len);
1842e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1843e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1844e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Prefetch and wait, to minimize time spent holding the spinlock. */
1845e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	prefetch_L1(&eq->comp_tail);
1846e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	prefetch_L1(&eq->cmd_tail);
1847e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	mb();
1848e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1849e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1850e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Enqueue the command. */
1851e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1852d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_lock_irqsave(&priv->eq_lock, irqflags);
1853e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
185492795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* Handle completions if needed to make room. */
185592795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* NOTE: Return NETDEV_TX_BUSY if there is still no room. */
1856d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (lepp_num_free_comp_slots(eq) == 0) {
1857d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
1858d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (nolds == 0) {
1859d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfbusy:
1860d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			spin_unlock_irqrestore(&priv->eq_lock, irqflags);
1861d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			return NETDEV_TX_BUSY;
1862d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		}
1863e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1864e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1865e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_head = eq->cmd_head;
1866e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_tail = eq->cmd_tail;
1867e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1868e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Prepare to advance, detecting full queue. */
186992795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* NOTE: Return NETDEV_TX_BUSY if the queue is full. */
1870e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_next = cmd_tail + cmd_size;
1871e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (cmd_tail < cmd_head && cmd_next >= cmd_head)
1872d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		goto busy;
1873e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (cmd_next > LEPP_CMD_LIMIT) {
1874e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cmd_next = 0;
1875e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (cmd_next == cmd_head)
1876d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			goto busy;
1877e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1878e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1879e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Copy the command. */
1880e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	memcpy(&eq->cmds[cmd_tail], cmd, cmd_size);
1881e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1882e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Advance. */
1883e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_tail = cmd_next;
1884e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1885e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Record "skb" for eventual freeing. */
1886e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	comp_tail = eq->comp_tail;
1887e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->comps[comp_tail] = skb;
1888e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	LEPP_QINC(comp_tail);
1889e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->comp_tail = comp_tail;
1890e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1891e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Flush before allowing LEPP to handle the command. */
1892d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: Is this the optimal location for the flush? */
1893e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	__insn_mf();
1894e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1895e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->cmd_tail = cmd_tail;
1896e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1897d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* NOTE: Using "4" here is more efficient than "0" or "2", */
1898d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* and, strangely, more efficient than pre-checking the number */
1899d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* of available completions, and comparing it to 4. */
1900e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (nolds == 0)
1901d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 4);
1902d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
1903d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_unlock_irqrestore(&priv->eq_lock, irqflags);
1904e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1905e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Handle completions. */
1906e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < nolds; i++)
1907e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		kfree_skb(olds[i]);
1908e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1909e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Update stats. */
1910e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	stats->tx_packets += num_segs;
1911e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	stats->tx_bytes += (num_segs * sh_len) + d_len;
1912e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1913e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Make sure the egress timer is scheduled. */
1914e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_schedule_egress_timer(info);
1915e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1916e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return NETDEV_TX_OK;
1917e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
1918e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1919e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1920e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
1921e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Transmit a packet (called by the kernel via "hard_start_xmit" hook).
1922e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
1923e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
1924e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
1925e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
1926e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int my_cpu = smp_processor_id();
1927e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_cpu *info = priv->cpu[my_cpu];
1928e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_stats_t *stats = &info->stats;
1929e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1930e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned long irqflags;
1931e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1932e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct skb_shared_info *sh = skb_shinfo(skb);
1933e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1934e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int len = skb->len;
1935e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned char *data = skb->data;
1936e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
193796339d6c490a32de35fa798ca7922d13a8538ecdShan Wei	unsigned int csum_start = skb_checksum_start_offset(skb);
1938e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1939e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	lepp_frag_t frags[LEPP_MAX_FRAGS];
1940e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1941e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int num_frags;
1942e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1943d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	lepp_queue_t *eq = priv->eq;
1944e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1945d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	struct sk_buff *olds[8];
1946d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	unsigned int wanted = 8;
1947e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int i, nolds = 0;
1948e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1949e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int cmd_size = sizeof(lepp_cmd_t);
1950e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1951e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int cmd_head, cmd_tail, cmd_next;
1952e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	unsigned int comp_tail;
1953e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1954e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	lepp_cmd_t cmds[LEPP_MAX_FRAGS];
1955e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1956e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1957e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
1958e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * This is paranoia, since we think that if the link doesn't come
1959e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * up, telling Linux we have no carrier will keep it from trying
1960e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * to transmit.  If it does, though, we can't execute this routine,
1961e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * since data structures we depend on aren't set up yet.
1962e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
1963e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!info->registered)
1964e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return NETDEV_TX_BUSY;
1965e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1966e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1967e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Save the timestamp. */
1968e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->trans_start = jiffies;
1969e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1970e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1971e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_PARANOIA
1972e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#if CHIP_HAS_CBOX_HOME_MAP()
1973e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (hash_default) {
1974e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)data);
1975e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
1976d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			panic("Non-HFH egress buffer! VA=%p Mode=%d PTE=%llx",
1977d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			      data, hv_pte_get_mode(pte), hv_pte_val(pte));
1978e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
1979e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
1980e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
1981e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1982e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1983e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_DUMP_PACKETS
1984e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: Does not dump the "frags". */
1985e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dump_packet(data, skb_headlen(skb), "tx");
1986e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif /* TILE_NET_DUMP_PACKETS */
1987e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1988e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1989e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (sh->gso_size != 0)
1990e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return tile_net_tx_tso(skb, dev);
1991e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1992e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1993e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Prepare the commands. */
1994e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1995e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	num_frags = tile_net_tx_frags(frags, skb, data, skb_headlen(skb));
1996e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1997e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < num_frags; i++) {
1998e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
1999e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		bool final = (i == num_frags - 1);
2000e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2001e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		lepp_cmd_t cmd = {
2002e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.cpa_lo = frags[i].cpa_lo,
2003e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.cpa_hi = frags[i].cpa_hi,
2004e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.length = frags[i].length,
2005e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.hash_for_home = frags[i].hash_for_home,
2006e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.send_completion = final,
2007e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			.end_of_packet = final
2008e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		};
2009e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2010e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (i == 0 && skb->ip_summed == CHECKSUM_PARTIAL) {
2011e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cmd.compute_checksum = 1;
2012e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cmd.checksum_data.bits.start_byte = csum_start;
2013e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cmd.checksum_data.bits.count = len - csum_start;
2014e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cmd.checksum_data.bits.destination_byte =
2015e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				csum_start + skb->csum_offset;
2016e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
2017e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2018e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cmds[i] = cmd;
2019e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2020e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2021e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2022e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Prefetch and wait, to minimize time spent holding the spinlock. */
2023e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	prefetch_L1(&eq->comp_tail);
2024e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	prefetch_L1(&eq->cmd_tail);
2025e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	mb();
2026e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2027e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2028e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Enqueue the commands. */
2029e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2030d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_lock_irqsave(&priv->eq_lock, irqflags);
2031e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
203292795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* Handle completions if needed to make room. */
203392795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* NOTE: Return NETDEV_TX_BUSY if there is still no room. */
2034d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (lepp_num_free_comp_slots(eq) == 0) {
2035d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
2036d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		if (nolds == 0) {
2037d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfbusy:
2038d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			spin_unlock_irqrestore(&priv->eq_lock, irqflags);
2039d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			return NETDEV_TX_BUSY;
2040d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		}
2041e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2042e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2043e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_head = eq->cmd_head;
2044e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	cmd_tail = eq->cmd_tail;
2045e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2046e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Copy the commands, or fail. */
204792795672898d5ee1faa557c498c078123d20e827Chris Metcalf	/* NOTE: Return NETDEV_TX_BUSY if the queue is full. */
2048e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < num_frags; i++) {
2049e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2050e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Prepare to advance, detecting full queue. */
2051e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cmd_next = cmd_tail + cmd_size;
2052e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (cmd_tail < cmd_head && cmd_next >= cmd_head)
2053d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			goto busy;
2054e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (cmd_next > LEPP_CMD_LIMIT) {
2055e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cmd_next = 0;
2056e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			if (cmd_next == cmd_head)
2057d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf				goto busy;
2058e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
2059e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2060e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Copy the command. */
2061e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		*(lepp_cmd_t *)&eq->cmds[cmd_tail] = cmds[i];
2062e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2063e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Advance. */
2064e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cmd_tail = cmd_next;
2065e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2066e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2067e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Record "skb" for eventual freeing. */
2068e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	comp_tail = eq->comp_tail;
2069e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->comps[comp_tail] = skb;
2070e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	LEPP_QINC(comp_tail);
2071e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->comp_tail = comp_tail;
2072e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2073e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Flush before allowing LEPP to handle the command. */
2074d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* ISSUE: Is this the optimal location for the flush? */
2075e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	__insn_mf();
2076e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2077e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	eq->cmd_tail = cmd_tail;
2078e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2079d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* NOTE: Using "4" here is more efficient than "0" or "2", */
2080d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* and, strangely, more efficient than pre-checking the number */
2081d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* of available completions, and comparing it to 4. */
2082e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (nolds == 0)
2083d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 4);
2084d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
2085d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_unlock_irqrestore(&priv->eq_lock, irqflags);
2086e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2087e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Handle completions. */
2088e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < nolds; i++)
2089e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		kfree_skb(olds[i]);
2090e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2091e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
2092e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	stats->tx_packets++;
2093e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN);
2094e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2095e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Make sure the egress timer is scheduled. */
2096e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_schedule_egress_timer(info);
2097e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2098e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return NETDEV_TX_OK;
2099e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2100e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2101e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2102e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2103e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Deal with a transmit timeout.
2104e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2105e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_tx_timeout(struct net_device *dev)
2106e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2107e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("tile_net_tx_timeout()\n");
2108e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies,
2109e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       jiffies - dev->trans_start);
2110e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2111e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* XXX: ISSUE: This doesn't seem useful for us. */
2112e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	netif_wake_queue(dev);
2113e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2114e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2115e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2116e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2117e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Ioctl commands.
2118e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2119e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
2120e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2121e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return -EOPNOTSUPP;
2122e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2123e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2124e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2125e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2126e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Get System Network Statistics.
2127e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2128e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Returns the address of the device statistics structure.
2129e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2130e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic struct net_device_stats *tile_net_get_stats(struct net_device *dev)
2131e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2132e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
2133e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 rx_packets = 0;
2134e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 tx_packets = 0;
2135e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 rx_bytes = 0;
2136e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	u32 tx_bytes = 0;
2137e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int i;
2138e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2139e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for_each_online_cpu(i) {
2140e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (priv->cpu[i]) {
2141e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			rx_packets += priv->cpu[i]->stats.rx_packets;
2142e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			rx_bytes += priv->cpu[i]->stats.rx_bytes;
2143e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			tx_packets += priv->cpu[i]->stats.tx_packets;
2144e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			tx_bytes += priv->cpu[i]->stats.tx_bytes;
2145e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
2146e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2147e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2148e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->stats.rx_packets = rx_packets;
2149e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->stats.rx_bytes = rx_bytes;
2150e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->stats.tx_packets = tx_packets;
2151e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->stats.tx_bytes = tx_bytes;
2152e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2153e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return &priv->stats;
2154e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2155e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2156e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2157e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2158e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Change the "mtu".
2159e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2160e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The "change_mtu" method is usually not needed.
2161e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * If you need it, it must be like this.
2162e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2163e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_change_mtu(struct net_device *dev, int new_mtu)
2164e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2165e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("tile_net_change_mtu()\n");
2166e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2167e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Check ranges. */
2168e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if ((new_mtu < 68) || (new_mtu > 1500))
2169e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return -EINVAL;
2170e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2171e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Accept the value. */
2172e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->mtu = new_mtu;
2173e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2174e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
2175e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2176e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2177e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2178e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2179e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Change the Ethernet Address of the NIC.
2180e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2181e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The hypervisor driver does not support changing MAC address.  However,
2182e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * the IPP does not do anything with the MAC address, so the address which
2183e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * gets used on outgoing packets, and which is accepted on incoming packets,
2184e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * is completely up to the NetIO program or kernel driver which is actually
2185e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * handling them.
2186e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2187e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Returns 0 on success, negative on failure.
2188e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2189e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_set_mac_address(struct net_device *dev, void *p)
2190e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2191e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct sockaddr *addr = p;
2192e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2193e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!is_valid_ether_addr(addr->sa_data))
2194504f9b5a6bb5336ad434438d0cdd61a16db80129Danny Kukawka		return -EADDRNOTAVAIL;
2195e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2196e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: Note that "dev_addr" is now a pointer. */
2197e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
21987ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
2199e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2200e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
2201e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2202e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2203e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2204e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2205e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Obtain the MAC address from the hypervisor.
2206e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This must be done before opening the device.
2207e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2208e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_get_mac(struct net_device *dev)
2209e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2210e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
2211e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2212e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	char hv_dev_name[32];
2213e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int len;
2214e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2215e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	__netio_getset_offset_t offset = { .word = NETIO_IPP_PARAM_OFF };
2216e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2217e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int ret;
2218e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2219e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* For example, "xgbe0". */
2220e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	strcpy(hv_dev_name, dev->name);
2221e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	len = strlen(hv_dev_name);
2222e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2223e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* For example, "xgbe/0". */
2224e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	hv_dev_name[len] = hv_dev_name[len - 1];
2225e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	hv_dev_name[len - 1] = '/';
2226e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	len++;
2227e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2228e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* For example, "xgbe/0/native_hash". */
2229e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	strcpy(hv_dev_name + len, hash_default ? "/native_hash" : "/native");
2230e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2231e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Get the hypervisor handle for this device. */
2232e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->hv_devhdl = hv_dev_open((HV_VirtAddr)hv_dev_name, 0);
2233e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("hv_dev_open(%s) returned %d %p\n",
2234e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	       hv_dev_name, priv->hv_devhdl, &priv->hv_devhdl);
2235e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (priv->hv_devhdl < 0) {
2236e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (priv->hv_devhdl == HV_ENODEV)
2237e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			printk(KERN_DEBUG "Ignoring unconfigured device %s\n",
2238e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				 hv_dev_name);
2239e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		else
2240e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			printk(KERN_DEBUG "hv_dev_open(%s) returned %d\n",
2241e5a06939736277c54a68ae275433db55b99d187cChris Metcalf				 hv_dev_name, priv->hv_devhdl);
2242e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return -1;
2243e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2244e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2245e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
2246e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Read the hardware address from the hypervisor.
2247e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * ISSUE: Note that "dev_addr" is now a pointer.
2248e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
2249e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	offset.bits.class = NETIO_PARAM;
2250e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	offset.bits.addr = NETIO_PARAM_MAC;
2251e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = hv_dev_pread(priv->hv_devhdl, 0,
2252e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   (HV_VirtAddr)dev->dev_addr, dev->addr_len,
2253e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			   offset.word);
2254e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("hv_dev_pread(NETIO_PARAM_MAC) returned %d\n", ret);
2255e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret <= 0) {
2256e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		printk(KERN_DEBUG "hv_dev_pread(NETIO_PARAM_MAC) %s failed\n",
2257e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       dev->name);
2258e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/*
2259e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 * Since the device is configured by the hypervisor but we
2260e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 * can't get its MAC address, we are most likely running
2261e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 * the simulator, so let's generate a random MAC address.
2262e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		 */
22637ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka		eth_hw_addr_random(dev);
2264e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2265e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2266e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
2267e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2268e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
226992795672898d5ee1faa557c498c078123d20e827Chris Metcalf
227092795672898d5ee1faa557c498c078123d20e827Chris Metcalf#ifdef CONFIG_NET_POLL_CONTROLLER
227192795672898d5ee1faa557c498c078123d20e827Chris Metcalf/*
227292795672898d5ee1faa557c498c078123d20e827Chris Metcalf * Polling 'interrupt' - used by things like netconsole to send skbs
227392795672898d5ee1faa557c498c078123d20e827Chris Metcalf * without having to re-enable interrupts. It's not called while
227492795672898d5ee1faa557c498c078123d20e827Chris Metcalf * the interrupt routine is executing.
227592795672898d5ee1faa557c498c078123d20e827Chris Metcalf */
227692795672898d5ee1faa557c498c078123d20e827Chris Metcalfstatic void tile_net_netpoll(struct net_device *dev)
227792795672898d5ee1faa557c498c078123d20e827Chris Metcalf{
227892795672898d5ee1faa557c498c078123d20e827Chris Metcalf	struct tile_net_priv *priv = netdev_priv(dev);
227992795672898d5ee1faa557c498c078123d20e827Chris Metcalf	disable_percpu_irq(priv->intr_id);
228092795672898d5ee1faa557c498c078123d20e827Chris Metcalf	tile_net_handle_ingress_interrupt(priv->intr_id, dev);
228192795672898d5ee1faa557c498c078123d20e827Chris Metcalf	enable_percpu_irq(priv->intr_id, 0);
228292795672898d5ee1faa557c498c078123d20e827Chris Metcalf}
228392795672898d5ee1faa557c498c078123d20e827Chris Metcalf#endif
228492795672898d5ee1faa557c498c078123d20e827Chris Metcalf
228592795672898d5ee1faa557c498c078123d20e827Chris Metcalf
2286e5686ad82ca2aeed7a8f24ffca115c0b7478dec9stephen hemmingerstatic const struct net_device_ops tile_net_ops = {
2287e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_open = tile_net_open,
2288e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_stop = tile_net_stop,
2289e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_start_xmit = tile_net_tx,
2290e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_do_ioctl = tile_net_ioctl,
2291e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_get_stats = tile_net_get_stats,
2292e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_change_mtu = tile_net_change_mtu,
2293e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	.ndo_tx_timeout = tile_net_tx_timeout,
229492795672898d5ee1faa557c498c078123d20e827Chris Metcalf	.ndo_set_mac_address = tile_net_set_mac_address,
229592795672898d5ee1faa557c498c078123d20e827Chris Metcalf#ifdef CONFIG_NET_POLL_CONTROLLER
229692795672898d5ee1faa557c498c078123d20e827Chris Metcalf	.ndo_poll_controller = tile_net_netpoll,
229792795672898d5ee1faa557c498c078123d20e827Chris Metcalf#endif
2298e5a06939736277c54a68ae275433db55b99d187cChris Metcalf};
2299e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2300e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2301e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2302e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The setup function.
2303e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2304e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * This uses ether_setup() to assign various fields in dev, including
2305e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * setting IFF_BROADCAST and IFF_MULTICAST, then sets some extra fields.
2306e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2307e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_setup(struct net_device *dev)
2308e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2309e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	PDEBUG("tile_net_setup()\n");
2310e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2311e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ether_setup(dev);
2312e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2313e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->netdev_ops = &tile_net_ops;
2314e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2315e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->watchdog_timeo = TILE_NET_TIMEOUT;
2316e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2317e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* We want lockless xmit. */
2318e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->features |= NETIF_F_LLTX;
2319e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2320e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* We support hardware tx checksums. */
2321e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->features |= NETIF_F_HW_CSUM;
2322e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2323e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* We support scatter/gather. */
2324e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->features |= NETIF_F_SG;
2325e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2326e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* We support TSO. */
2327e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->features |= NETIF_F_TSO;
2328e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2329e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifdef TILE_NET_GSO
2330e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* We support GSO. */
2331e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->features |= NETIF_F_GSO;
2332e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#endif
2333e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2334e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (hash_default)
2335e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		dev->features |= NETIF_F_HIGHDMA;
2336e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2337e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* ISSUE: We should support NETIF_F_UFO. */
2338e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2339e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
2340e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2341e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev->mtu = TILE_NET_MTU;
2342e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2343e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2344e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2345e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2346e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Allocate the device structure, register the device, and obtain the
2347e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * MAC address from the hypervisor.
2348e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2349e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic struct net_device *tile_net_dev_init(const char *name)
2350e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2351e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int ret;
2352e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct net_device *dev;
2353e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	struct tile_net_priv *priv;
2354e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2355e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/*
2356e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * Allocate the device structure.  This allocates "priv", calls
2357e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * tile_net_setup(), and saves "name".  Normally, "name" is a
2358e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 * template, instantiated by register_netdev(), but not for us.
2359e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	 */
2360e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	dev = alloc_netdev(sizeof(*priv), name, tile_net_setup);
2361e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (!dev) {
2362e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_err("alloc_netdev(%s) failed\n", name);
2363e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return NULL;
2364e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2365e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2366e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv = netdev_priv(dev);
2367e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2368e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Initialize "priv". */
2369e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2370e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	memset(priv, 0, sizeof(*priv));
2371e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2372e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Save "dev" for "tile_net_open_retry()". */
2373e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	priv->dev = dev;
2374e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2375e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	INIT_DELAYED_WORK(&priv->retry_work, tile_net_open_retry);
2376e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2377d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	spin_lock_init(&priv->eq_lock);
2378e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2379d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	/* Allocate "eq". */
2380d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	priv->eq_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, EQ_ORDER);
2381d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	if (!priv->eq_pages) {
2382e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		free_netdev(dev);
2383e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return NULL;
2384e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2385d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf	priv->eq = page_address(priv->eq_pages);
2386e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2387e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Register the network device. */
2388e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = register_netdev(dev);
2389e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret) {
2390e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_err("register_netdev %s failed %d\n", dev->name, ret);
2391d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		__free_pages(priv->eq_pages, EQ_ORDER);
2392e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		free_netdev(dev);
2393e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return NULL;
2394e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2395e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2396e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	/* Get the MAC address. */
2397e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	ret = tile_net_get_mac(dev);
2398e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (ret < 0) {
2399e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		unregister_netdev(dev);
2400d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf		__free_pages(priv->eq_pages, EQ_ORDER);
2401e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		free_netdev(dev);
2402e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		return NULL;
2403e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2404e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2405e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return dev;
2406e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2407e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2408e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2409e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2410e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Module cleanup.
2411d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf *
2412d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * FIXME: If compiled as a module, this module cannot be "unloaded",
2413d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf * because the "ingress interrupt handler" is registered permanently.
2414e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2415e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic void tile_net_cleanup(void)
2416e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2417e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int i;
2418e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2419e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	for (i = 0; i < TILE_NET_DEVS; i++) {
2420e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (tile_net_devs[i]) {
2421e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			struct net_device *dev = tile_net_devs[i];
2422e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			struct tile_net_priv *priv = netdev_priv(dev);
2423e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			unregister_netdev(dev);
2424d07bd86d82622247dba8cc29974d3860f857ea33Chris Metcalf			finv_buffer_remote(priv->eq, EQ_SIZE, 0);
2425d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf			__free_pages(priv->eq_pages, EQ_ORDER);
2426e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			free_netdev(dev);
2427e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
2428e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2429e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2430e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2431e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2432e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2433e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * Module initialization.
2434e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2435e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int tile_net_init_module(void)
2436e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
243792795672898d5ee1faa557c498c078123d20e827Chris Metcalf	pr_info("Tilera Network Driver\n");
2438e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2439e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_devs[0] = tile_net_dev_init("xgbe0");
2440e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_devs[1] = tile_net_dev_init("xgbe1");
2441e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_devs[2] = tile_net_dev_init("gbe0");
2442e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	tile_net_devs[3] = tile_net_dev_init("gbe1");
2443e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2444e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
2445e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2446e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2447e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2448d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfmodule_init(tile_net_init_module);
2449d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalfmodule_exit(tile_net_cleanup);
2450d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
2451d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
2452e5a06939736277c54a68ae275433db55b99d187cChris Metcalf#ifndef MODULE
2453d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf
2454e5a06939736277c54a68ae275433db55b99d187cChris Metcalf/*
2455e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The "network_cpus" boot argument specifies the cpus that are dedicated
2456e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * to handle ingress packets.
2457e5a06939736277c54a68ae275433db55b99d187cChris Metcalf *
2458e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * The parameter should be in the form "network_cpus=m-n[,x-y]", where
2459e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * m, n, x, y are integer numbers that represent the cpus that can be
2460e5a06939736277c54a68ae275433db55b99d187cChris Metcalf * neither a dedicated cpu nor a dataplane cpu.
2461e5a06939736277c54a68ae275433db55b99d187cChris Metcalf */
2462e5a06939736277c54a68ae275433db55b99d187cChris Metcalfstatic int __init network_cpus_setup(char *str)
2463e5a06939736277c54a68ae275433db55b99d187cChris Metcalf{
2464e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	int rc = cpulist_parse_crop(str, &network_cpus_map);
2465e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	if (rc != 0) {
2466e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		pr_warning("network_cpus=%s: malformed cpu list\n",
2467e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		       str);
2468e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	} else {
2469e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2470e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		/* Remove dedicated cpus. */
2471e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		cpumask_and(&network_cpus_map, &network_cpus_map,
2472e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			    cpu_possible_mask);
2473e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2474e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2475e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		if (cpumask_empty(&network_cpus_map)) {
2476e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			pr_warning("Ignoring network_cpus='%s'.\n",
2477e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			       str);
2478e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		} else {
2479e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			char buf[1024];
2480e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
2481e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			pr_info("Linux network CPUs: %s\n", buf);
2482e5a06939736277c54a68ae275433db55b99d187cChris Metcalf			network_cpus_used = true;
2483e5a06939736277c54a68ae275433db55b99d187cChris Metcalf		}
2484e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	}
2485e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2486e5a06939736277c54a68ae275433db55b99d187cChris Metcalf	return 0;
2487e5a06939736277c54a68ae275433db55b99d187cChris Metcalf}
2488e5a06939736277c54a68ae275433db55b99d187cChris Metcalf__setup("network_cpus=", network_cpus_setup);
2489e5a06939736277c54a68ae275433db55b99d187cChris Metcalf
2490d91c641233ae09fcccec75313b7f55992668bf8dChris Metcalf#endif
2491