xref: /openbmc/linux/drivers/net/fjes/fjes_main.c (revision ff5b42103227c01c4082f27b06a43758efbf5ab8)
1658d439bSTaku Izumi /*
2658d439bSTaku Izumi  *  FUJITSU Extended Socket Network Device driver
3658d439bSTaku Izumi  *  Copyright (c) 2015 FUJITSU LIMITED
4658d439bSTaku Izumi  *
5658d439bSTaku Izumi  * This program is free software; you can redistribute it and/or modify it
6658d439bSTaku Izumi  * under the terms and conditions of the GNU General Public License,
7658d439bSTaku Izumi  * version 2, as published by the Free Software Foundation.
8658d439bSTaku Izumi  *
9658d439bSTaku Izumi  * This program is distributed in the hope it will be useful, but WITHOUT
10658d439bSTaku Izumi  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11658d439bSTaku Izumi  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12658d439bSTaku Izumi  * more details.
13658d439bSTaku Izumi  *
14658d439bSTaku Izumi  * You should have received a copy of the GNU General Public License along with
15658d439bSTaku Izumi  * this program; if not, see <http://www.gnu.org/licenses/>.
16658d439bSTaku Izumi  *
17658d439bSTaku Izumi  * The full GNU General Public License is included in this distribution in
18658d439bSTaku Izumi  * the file called "COPYING".
19658d439bSTaku Izumi  *
20658d439bSTaku Izumi  */
21658d439bSTaku Izumi 
22658d439bSTaku Izumi #include <linux/module.h>
23658d439bSTaku Izumi #include <linux/types.h>
24658d439bSTaku Izumi #include <linux/nls.h>
25658d439bSTaku Izumi #include <linux/platform_device.h>
262fcbca68STaku Izumi #include <linux/netdevice.h>
27e5d486dcSTaku Izumi #include <linux/interrupt.h>
28658d439bSTaku Izumi 
29658d439bSTaku Izumi #include "fjes.h"
30658d439bSTaku Izumi 
31658d439bSTaku Izumi #define MAJ 1
32658d439bSTaku Izumi #define MIN 0
33658d439bSTaku Izumi #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN)
34658d439bSTaku Izumi #define DRV_NAME	"fjes"
35658d439bSTaku Izumi char fjes_driver_name[] = DRV_NAME;
36658d439bSTaku Izumi char fjes_driver_version[] = DRV_VERSION;
37658d439bSTaku Izumi static const char fjes_driver_string[] =
38658d439bSTaku Izumi 		"FUJITSU Extended Socket Network Device Driver";
39658d439bSTaku Izumi static const char fjes_copyright[] =
40658d439bSTaku Izumi 		"Copyright (c) 2015 FUJITSU LIMITED";
41658d439bSTaku Izumi 
42658d439bSTaku Izumi MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>");
43658d439bSTaku Izumi MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver");
44658d439bSTaku Izumi MODULE_LICENSE("GPL");
45658d439bSTaku Izumi MODULE_VERSION(DRV_VERSION);
46658d439bSTaku Izumi 
47e5d486dcSTaku Izumi static int fjes_request_irq(struct fjes_adapter *);
48e5d486dcSTaku Izumi static void fjes_free_irq(struct fjes_adapter *);
49e5d486dcSTaku Izumi 
50e5d486dcSTaku Izumi static int fjes_open(struct net_device *);
51e5d486dcSTaku Izumi static int fjes_close(struct net_device *);
52e5d486dcSTaku Izumi static int fjes_setup_resources(struct fjes_adapter *);
53e5d486dcSTaku Izumi static void fjes_free_resources(struct fjes_adapter *);
549acf51cbSTaku Izumi static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *);
55b772b9dcSTaku Izumi static void fjes_raise_intr_rxdata_task(struct work_struct *);
56ac63b947STaku Izumi static void fjes_tx_stall_task(struct work_struct *);
57*ff5b4210STaku Izumi static void fjes_force_close_task(struct work_struct *);
58e5d486dcSTaku Izumi static irqreturn_t fjes_intr(int, void*);
59879bc9a3STaku Izumi static struct rtnl_link_stats64 *
60879bc9a3STaku Izumi fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *);
61b9e23a67STaku Izumi static int fjes_change_mtu(struct net_device *, int);
623e3feddaSTaku Izumi static int fjes_vlan_rx_add_vid(struct net_device *, __be16 proto, u16);
633e3feddaSTaku Izumi static int fjes_vlan_rx_kill_vid(struct net_device *, __be16 proto, u16);
644393e767STaku Izumi static void fjes_tx_retry(struct net_device *);
65e5d486dcSTaku Izumi 
66658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *);
67658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *);
68658d439bSTaku Izumi static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*);
69658d439bSTaku Izumi 
70658d439bSTaku Izumi static int fjes_probe(struct platform_device *);
71658d439bSTaku Izumi static int fjes_remove(struct platform_device *);
72658d439bSTaku Izumi 
732fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *);
742fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *);
758edb62a8STaku Izumi static void fjes_irq_watch_task(struct work_struct *);
7626585930STaku Izumi static void fjes_rx_irq(struct fjes_adapter *, int);
7726585930STaku Izumi static int fjes_poll(struct napi_struct *, int);
7826585930STaku Izumi 
79658d439bSTaku Izumi static const struct acpi_device_id fjes_acpi_ids[] = {
80658d439bSTaku Izumi 	{"PNP0C02", 0},
81658d439bSTaku Izumi 	{"", 0},
82658d439bSTaku Izumi };
83658d439bSTaku Izumi MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids);
84658d439bSTaku Izumi 
85658d439bSTaku Izumi static struct acpi_driver fjes_acpi_driver = {
86658d439bSTaku Izumi 	.name = DRV_NAME,
87658d439bSTaku Izumi 	.class = DRV_NAME,
88658d439bSTaku Izumi 	.owner = THIS_MODULE,
89658d439bSTaku Izumi 	.ids = fjes_acpi_ids,
90658d439bSTaku Izumi 	.ops = {
91658d439bSTaku Izumi 		.add = fjes_acpi_add,
92658d439bSTaku Izumi 		.remove = fjes_acpi_remove,
93658d439bSTaku Izumi 	},
94658d439bSTaku Izumi };
95658d439bSTaku Izumi 
96658d439bSTaku Izumi static struct platform_driver fjes_driver = {
97658d439bSTaku Izumi 	.driver = {
98658d439bSTaku Izumi 		.name = DRV_NAME,
99658d439bSTaku Izumi 		.owner = THIS_MODULE,
100658d439bSTaku Izumi 	},
101658d439bSTaku Izumi 	.probe = fjes_probe,
102658d439bSTaku Izumi 	.remove = fjes_remove,
103658d439bSTaku Izumi };
104658d439bSTaku Izumi 
105658d439bSTaku Izumi static struct resource fjes_resource[] = {
106658d439bSTaku Izumi 	{
107658d439bSTaku Izumi 		.flags = IORESOURCE_MEM,
108658d439bSTaku Izumi 		.start = 0,
109658d439bSTaku Izumi 		.end = 0,
110658d439bSTaku Izumi 	},
111658d439bSTaku Izumi 	{
112658d439bSTaku Izumi 		.flags = IORESOURCE_IRQ,
113658d439bSTaku Izumi 		.start = 0,
114658d439bSTaku Izumi 		.end = 0,
115658d439bSTaku Izumi 	},
116658d439bSTaku Izumi };
117658d439bSTaku Izumi 
118658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *device)
119658d439bSTaku Izumi {
120658d439bSTaku Izumi 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
121658d439bSTaku Izumi 	char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1];
122658d439bSTaku Izumi 	struct platform_device *plat_dev;
123658d439bSTaku Izumi 	union acpi_object *str;
124658d439bSTaku Izumi 	acpi_status status;
125658d439bSTaku Izumi 	int result;
126658d439bSTaku Izumi 
127658d439bSTaku Izumi 	status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer);
128658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
129658d439bSTaku Izumi 		return -ENODEV;
130658d439bSTaku Izumi 
131658d439bSTaku Izumi 	str = buffer.pointer;
132658d439bSTaku Izumi 	result = utf16s_to_utf8s((wchar_t *)str->string.pointer,
133658d439bSTaku Izumi 				 str->string.length, UTF16_LITTLE_ENDIAN,
134658d439bSTaku Izumi 				 str_buf, sizeof(str_buf) - 1);
135658d439bSTaku Izumi 	str_buf[result] = 0;
136658d439bSTaku Izumi 
137658d439bSTaku Izumi 	if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) {
138658d439bSTaku Izumi 		kfree(buffer.pointer);
139658d439bSTaku Izumi 		return -ENODEV;
140658d439bSTaku Izumi 	}
141658d439bSTaku Izumi 	kfree(buffer.pointer);
142658d439bSTaku Izumi 
143658d439bSTaku Izumi 	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
144658d439bSTaku Izumi 				     fjes_get_acpi_resource, fjes_resource);
145658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
146658d439bSTaku Izumi 		return -ENODEV;
147658d439bSTaku Izumi 
148658d439bSTaku Izumi 	/* create platform_device */
149658d439bSTaku Izumi 	plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
150658d439bSTaku Izumi 						   ARRAY_SIZE(fjes_resource));
151658d439bSTaku Izumi 	device->driver_data = plat_dev;
152658d439bSTaku Izumi 
153658d439bSTaku Izumi 	return 0;
154658d439bSTaku Izumi }
155658d439bSTaku Izumi 
156658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *device)
157658d439bSTaku Izumi {
158658d439bSTaku Izumi 	struct platform_device *plat_dev;
159658d439bSTaku Izumi 
160658d439bSTaku Izumi 	plat_dev = (struct platform_device *)acpi_driver_data(device);
161658d439bSTaku Izumi 	platform_device_unregister(plat_dev);
162658d439bSTaku Izumi 
163658d439bSTaku Izumi 	return 0;
164658d439bSTaku Izumi }
165658d439bSTaku Izumi 
166658d439bSTaku Izumi static acpi_status
167658d439bSTaku Izumi fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
168658d439bSTaku Izumi {
169658d439bSTaku Izumi 	struct acpi_resource_address32 *addr;
170658d439bSTaku Izumi 	struct acpi_resource_irq *irq;
171658d439bSTaku Izumi 	struct resource *res = data;
172658d439bSTaku Izumi 
173658d439bSTaku Izumi 	switch (acpi_res->type) {
174658d439bSTaku Izumi 	case ACPI_RESOURCE_TYPE_ADDRESS32:
175658d439bSTaku Izumi 		addr = &acpi_res->data.address32;
176658d439bSTaku Izumi 		res[0].start = addr->address.minimum;
177658d439bSTaku Izumi 		res[0].end = addr->address.minimum +
178658d439bSTaku Izumi 			addr->address.address_length - 1;
179658d439bSTaku Izumi 		break;
180658d439bSTaku Izumi 
181658d439bSTaku Izumi 	case ACPI_RESOURCE_TYPE_IRQ:
182658d439bSTaku Izumi 		irq = &acpi_res->data.irq;
183658d439bSTaku Izumi 		if (irq->interrupt_count != 1)
184658d439bSTaku Izumi 			return AE_ERROR;
185658d439bSTaku Izumi 		res[1].start = irq->interrupts[0];
186658d439bSTaku Izumi 		res[1].end = irq->interrupts[0];
187658d439bSTaku Izumi 		break;
188658d439bSTaku Izumi 
189658d439bSTaku Izumi 	default:
190658d439bSTaku Izumi 		break;
191658d439bSTaku Izumi 	}
192658d439bSTaku Izumi 
193658d439bSTaku Izumi 	return AE_OK;
194658d439bSTaku Izumi }
195658d439bSTaku Izumi 
196e5d486dcSTaku Izumi static int fjes_request_irq(struct fjes_adapter *adapter)
197e5d486dcSTaku Izumi {
198e5d486dcSTaku Izumi 	struct net_device *netdev = adapter->netdev;
199e5d486dcSTaku Izumi 	int result = -1;
200e5d486dcSTaku Izumi 
2018edb62a8STaku Izumi 	adapter->interrupt_watch_enable = true;
2028edb62a8STaku Izumi 	if (!delayed_work_pending(&adapter->interrupt_watch_task)) {
2038edb62a8STaku Izumi 		queue_delayed_work(adapter->control_wq,
2048edb62a8STaku Izumi 				   &adapter->interrupt_watch_task,
2058edb62a8STaku Izumi 				   FJES_IRQ_WATCH_DELAY);
2068edb62a8STaku Izumi 	}
2078edb62a8STaku Izumi 
208e5d486dcSTaku Izumi 	if (!adapter->irq_registered) {
209e5d486dcSTaku Izumi 		result = request_irq(adapter->hw.hw_res.irq, fjes_intr,
210e5d486dcSTaku Izumi 				     IRQF_SHARED, netdev->name, adapter);
211e5d486dcSTaku Izumi 		if (result)
212e5d486dcSTaku Izumi 			adapter->irq_registered = false;
213e5d486dcSTaku Izumi 		else
214e5d486dcSTaku Izumi 			adapter->irq_registered = true;
215e5d486dcSTaku Izumi 	}
216e5d486dcSTaku Izumi 
217e5d486dcSTaku Izumi 	return result;
218e5d486dcSTaku Izumi }
219e5d486dcSTaku Izumi 
220e5d486dcSTaku Izumi static void fjes_free_irq(struct fjes_adapter *adapter)
221e5d486dcSTaku Izumi {
222e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
223e5d486dcSTaku Izumi 
2248edb62a8STaku Izumi 	adapter->interrupt_watch_enable = false;
2258edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
2268edb62a8STaku Izumi 
227e5d486dcSTaku Izumi 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);
228e5d486dcSTaku Izumi 
229e5d486dcSTaku Izumi 	if (adapter->irq_registered) {
230e5d486dcSTaku Izumi 		free_irq(adapter->hw.hw_res.irq, adapter);
231e5d486dcSTaku Izumi 		adapter->irq_registered = false;
232e5d486dcSTaku Izumi 	}
233e5d486dcSTaku Izumi }
234e5d486dcSTaku Izumi 
2352fcbca68STaku Izumi static const struct net_device_ops fjes_netdev_ops = {
236e5d486dcSTaku Izumi 	.ndo_open		= fjes_open,
237e5d486dcSTaku Izumi 	.ndo_stop		= fjes_close,
2389acf51cbSTaku Izumi 	.ndo_start_xmit		= fjes_xmit_frame,
239879bc9a3STaku Izumi 	.ndo_get_stats64	= fjes_get_stats64,
240b9e23a67STaku Izumi 	.ndo_change_mtu		= fjes_change_mtu,
2414393e767STaku Izumi 	.ndo_tx_timeout		= fjes_tx_retry,
2423e3feddaSTaku Izumi 	.ndo_vlan_rx_add_vid	= fjes_vlan_rx_add_vid,
2433e3feddaSTaku Izumi 	.ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid,
2442fcbca68STaku Izumi };
2452fcbca68STaku Izumi 
246e5d486dcSTaku Izumi /* fjes_open - Called when a network interface is made active */
247e5d486dcSTaku Izumi static int fjes_open(struct net_device *netdev)
248e5d486dcSTaku Izumi {
249e5d486dcSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
250e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
251e5d486dcSTaku Izumi 	int result;
252e5d486dcSTaku Izumi 
253e5d486dcSTaku Izumi 	if (adapter->open_guard)
254e5d486dcSTaku Izumi 		return -ENXIO;
255e5d486dcSTaku Izumi 
256e5d486dcSTaku Izumi 	result = fjes_setup_resources(adapter);
257e5d486dcSTaku Izumi 	if (result)
258e5d486dcSTaku Izumi 		goto err_setup_res;
259e5d486dcSTaku Izumi 
260e5d486dcSTaku Izumi 	hw->txrx_stop_req_bit = 0;
261e5d486dcSTaku Izumi 	hw->epstop_req_bit = 0;
262e5d486dcSTaku Izumi 
26326585930STaku Izumi 	napi_enable(&adapter->napi);
26426585930STaku Izumi 
265e5d486dcSTaku Izumi 	fjes_hw_capture_interrupt_status(hw);
266e5d486dcSTaku Izumi 
267e5d486dcSTaku Izumi 	result = fjes_request_irq(adapter);
268e5d486dcSTaku Izumi 	if (result)
269e5d486dcSTaku Izumi 		goto err_req_irq;
270e5d486dcSTaku Izumi 
271e5d486dcSTaku Izumi 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, false);
272e5d486dcSTaku Izumi 
273e5d486dcSTaku Izumi 	netif_tx_start_all_queues(netdev);
274e5d486dcSTaku Izumi 	netif_carrier_on(netdev);
275e5d486dcSTaku Izumi 
276e5d486dcSTaku Izumi 	return 0;
277e5d486dcSTaku Izumi 
278e5d486dcSTaku Izumi err_req_irq:
279e5d486dcSTaku Izumi 	fjes_free_irq(adapter);
28026585930STaku Izumi 	napi_disable(&adapter->napi);
281e5d486dcSTaku Izumi 
282e5d486dcSTaku Izumi err_setup_res:
283e5d486dcSTaku Izumi 	fjes_free_resources(adapter);
284e5d486dcSTaku Izumi 	return result;
285e5d486dcSTaku Izumi }
286e5d486dcSTaku Izumi 
287e5d486dcSTaku Izumi /* fjes_close - Disables a network interface */
288e5d486dcSTaku Izumi static int fjes_close(struct net_device *netdev)
289e5d486dcSTaku Izumi {
290e5d486dcSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
291e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
292e5d486dcSTaku Izumi 	int epidx;
293e5d486dcSTaku Izumi 
294e5d486dcSTaku Izumi 	netif_tx_stop_all_queues(netdev);
295e5d486dcSTaku Izumi 	netif_carrier_off(netdev);
296e5d486dcSTaku Izumi 
297e5d486dcSTaku Izumi 	fjes_hw_raise_epstop(hw);
298e5d486dcSTaku Izumi 
29926585930STaku Izumi 	napi_disable(&adapter->napi);
30026585930STaku Izumi 
301e5d486dcSTaku Izumi 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
302e5d486dcSTaku Izumi 		if (epidx == hw->my_epid)
303e5d486dcSTaku Izumi 			continue;
304e5d486dcSTaku Izumi 
305e5d486dcSTaku Izumi 		adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status &=
306e5d486dcSTaku Izumi 			~FJES_RX_POLL_WORK;
307e5d486dcSTaku Izumi 	}
308e5d486dcSTaku Izumi 
309e5d486dcSTaku Izumi 	fjes_free_irq(adapter);
310e5d486dcSTaku Izumi 
3118edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
312b772b9dcSTaku Izumi 	cancel_work_sync(&adapter->raise_intr_rxdata_task);
313ac63b947STaku Izumi 	cancel_work_sync(&adapter->tx_stall_task);
314b772b9dcSTaku Izumi 
315e5d486dcSTaku Izumi 	fjes_hw_wait_epstop(hw);
316e5d486dcSTaku Izumi 
317e5d486dcSTaku Izumi 	fjes_free_resources(adapter);
318e5d486dcSTaku Izumi 
319e5d486dcSTaku Izumi 	return 0;
320e5d486dcSTaku Izumi }
321e5d486dcSTaku Izumi 
322e5d486dcSTaku Izumi static int fjes_setup_resources(struct fjes_adapter *adapter)
323e5d486dcSTaku Izumi {
324e5d486dcSTaku Izumi 	struct net_device *netdev = adapter->netdev;
325e5d486dcSTaku Izumi 	struct ep_share_mem_info *buf_pair;
326e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
327e5d486dcSTaku Izumi 	int result;
328e5d486dcSTaku Izumi 	int epidx;
329e5d486dcSTaku Izumi 
330e5d486dcSTaku Izumi 	mutex_lock(&hw->hw_info.lock);
331e5d486dcSTaku Izumi 	result = fjes_hw_request_info(hw);
332e5d486dcSTaku Izumi 	switch (result) {
333e5d486dcSTaku Izumi 	case 0:
334e5d486dcSTaku Izumi 		for (epidx = 0; epidx < hw->max_epid; epidx++) {
335e5d486dcSTaku Izumi 			hw->ep_shm_info[epidx].es_status =
336e5d486dcSTaku Izumi 			    hw->hw_info.res_buf->info.info[epidx].es_status;
337e5d486dcSTaku Izumi 			hw->ep_shm_info[epidx].zone =
338e5d486dcSTaku Izumi 			    hw->hw_info.res_buf->info.info[epidx].zone;
339e5d486dcSTaku Izumi 		}
340e5d486dcSTaku Izumi 		break;
341e5d486dcSTaku Izumi 	default:
342e5d486dcSTaku Izumi 	case -ENOMSG:
343e5d486dcSTaku Izumi 	case -EBUSY:
344e5d486dcSTaku Izumi 		adapter->force_reset = true;
345e5d486dcSTaku Izumi 
346e5d486dcSTaku Izumi 		mutex_unlock(&hw->hw_info.lock);
347e5d486dcSTaku Izumi 		return result;
348e5d486dcSTaku Izumi 	}
349e5d486dcSTaku Izumi 	mutex_unlock(&hw->hw_info.lock);
350e5d486dcSTaku Izumi 
351e5d486dcSTaku Izumi 	for (epidx = 0; epidx < (hw->max_epid); epidx++) {
352e5d486dcSTaku Izumi 		if ((epidx != hw->my_epid) &&
353e5d486dcSTaku Izumi 		    (hw->ep_shm_info[epidx].es_status ==
354e5d486dcSTaku Izumi 		     FJES_ZONING_STATUS_ENABLE)) {
355e5d486dcSTaku Izumi 			fjes_hw_raise_interrupt(hw, epidx,
356e5d486dcSTaku Izumi 						REG_ICTL_MASK_INFO_UPDATE);
357e5d486dcSTaku Izumi 		}
358e5d486dcSTaku Izumi 	}
359e5d486dcSTaku Izumi 
360e5d486dcSTaku Izumi 	msleep(FJES_OPEN_ZONE_UPDATE_WAIT * hw->max_epid);
361e5d486dcSTaku Izumi 
362e5d486dcSTaku Izumi 	for (epidx = 0; epidx < (hw->max_epid); epidx++) {
363e5d486dcSTaku Izumi 		if (epidx == hw->my_epid)
364e5d486dcSTaku Izumi 			continue;
365e5d486dcSTaku Izumi 
366e5d486dcSTaku Izumi 		buf_pair = &hw->ep_shm_info[epidx];
367e5d486dcSTaku Izumi 
368e5d486dcSTaku Izumi 		fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr,
369e5d486dcSTaku Izumi 				    netdev->mtu);
370e5d486dcSTaku Izumi 
371e5d486dcSTaku Izumi 		if (fjes_hw_epid_is_same_zone(hw, epidx)) {
372e5d486dcSTaku Izumi 			mutex_lock(&hw->hw_info.lock);
373e5d486dcSTaku Izumi 			result =
374e5d486dcSTaku Izumi 			fjes_hw_register_buff_addr(hw, epidx, buf_pair);
375e5d486dcSTaku Izumi 			mutex_unlock(&hw->hw_info.lock);
376e5d486dcSTaku Izumi 
377e5d486dcSTaku Izumi 			switch (result) {
378e5d486dcSTaku Izumi 			case 0:
379e5d486dcSTaku Izumi 				break;
380e5d486dcSTaku Izumi 			case -ENOMSG:
381e5d486dcSTaku Izumi 			case -EBUSY:
382e5d486dcSTaku Izumi 			default:
383e5d486dcSTaku Izumi 				adapter->force_reset = true;
384e5d486dcSTaku Izumi 				return result;
385e5d486dcSTaku Izumi 			}
386e5d486dcSTaku Izumi 		}
387e5d486dcSTaku Izumi 	}
388e5d486dcSTaku Izumi 
389e5d486dcSTaku Izumi 	return 0;
390e5d486dcSTaku Izumi }
391e5d486dcSTaku Izumi 
392e5d486dcSTaku Izumi static void fjes_free_resources(struct fjes_adapter *adapter)
393e5d486dcSTaku Izumi {
394e5d486dcSTaku Izumi 	struct net_device *netdev = adapter->netdev;
395e5d486dcSTaku Izumi 	struct fjes_device_command_param param;
396e5d486dcSTaku Izumi 	struct ep_share_mem_info *buf_pair;
397e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
398e5d486dcSTaku Izumi 	bool reset_flag = false;
399e5d486dcSTaku Izumi 	int result;
400e5d486dcSTaku Izumi 	int epidx;
401e5d486dcSTaku Izumi 
402e5d486dcSTaku Izumi 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
403e5d486dcSTaku Izumi 		if (epidx == hw->my_epid)
404e5d486dcSTaku Izumi 			continue;
405e5d486dcSTaku Izumi 
406e5d486dcSTaku Izumi 		mutex_lock(&hw->hw_info.lock);
407e5d486dcSTaku Izumi 		result = fjes_hw_unregister_buff_addr(hw, epidx);
408e5d486dcSTaku Izumi 		mutex_unlock(&hw->hw_info.lock);
409e5d486dcSTaku Izumi 
410e5d486dcSTaku Izumi 		if (result)
411e5d486dcSTaku Izumi 			reset_flag = true;
412e5d486dcSTaku Izumi 
413e5d486dcSTaku Izumi 		buf_pair = &hw->ep_shm_info[epidx];
414e5d486dcSTaku Izumi 
415e5d486dcSTaku Izumi 		fjes_hw_setup_epbuf(&buf_pair->tx,
416e5d486dcSTaku Izumi 				    netdev->dev_addr, netdev->mtu);
417e5d486dcSTaku Izumi 
418e5d486dcSTaku Izumi 		clear_bit(epidx, &hw->txrx_stop_req_bit);
419e5d486dcSTaku Izumi 	}
420e5d486dcSTaku Izumi 
421e5d486dcSTaku Izumi 	if (reset_flag || adapter->force_reset) {
422e5d486dcSTaku Izumi 		result = fjes_hw_reset(hw);
423e5d486dcSTaku Izumi 
424e5d486dcSTaku Izumi 		adapter->force_reset = false;
425e5d486dcSTaku Izumi 
426e5d486dcSTaku Izumi 		if (result)
427e5d486dcSTaku Izumi 			adapter->open_guard = true;
428e5d486dcSTaku Izumi 
429e5d486dcSTaku Izumi 		hw->hw_info.buffer_share_bit = 0;
430e5d486dcSTaku Izumi 
431e5d486dcSTaku Izumi 		memset((void *)&param, 0, sizeof(param));
432e5d486dcSTaku Izumi 
433e5d486dcSTaku Izumi 		param.req_len = hw->hw_info.req_buf_size;
434e5d486dcSTaku Izumi 		param.req_start = __pa(hw->hw_info.req_buf);
435e5d486dcSTaku Izumi 		param.res_len = hw->hw_info.res_buf_size;
436e5d486dcSTaku Izumi 		param.res_start = __pa(hw->hw_info.res_buf);
437e5d486dcSTaku Izumi 		param.share_start = __pa(hw->hw_info.share->ep_status);
438e5d486dcSTaku Izumi 
439e5d486dcSTaku Izumi 		fjes_hw_init_command_registers(hw, &param);
440e5d486dcSTaku Izumi 	}
441e5d486dcSTaku Izumi }
442e5d486dcSTaku Izumi 
443ac63b947STaku Izumi static void fjes_tx_stall_task(struct work_struct *work)
444ac63b947STaku Izumi {
445ac63b947STaku Izumi 	struct fjes_adapter *adapter = container_of(work,
446ac63b947STaku Izumi 			struct fjes_adapter, tx_stall_task);
447ac63b947STaku Izumi 	struct net_device *netdev = adapter->netdev;
448ac63b947STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
449ac63b947STaku Izumi 	int all_queue_available, sendable;
450ac63b947STaku Izumi 	enum ep_partner_status pstatus;
451ac63b947STaku Izumi 	int max_epid, my_epid, epid;
452ac63b947STaku Izumi 	union ep_buffer_info *info;
453ac63b947STaku Izumi 	int i;
454ac63b947STaku Izumi 
455ac63b947STaku Izumi 	if (((long)jiffies -
456ac63b947STaku Izumi 		(long)(netdev->trans_start)) > FJES_TX_TX_STALL_TIMEOUT) {
457ac63b947STaku Izumi 		netif_wake_queue(netdev);
458ac63b947STaku Izumi 		return;
459ac63b947STaku Izumi 	}
460ac63b947STaku Izumi 
461ac63b947STaku Izumi 	my_epid = hw->my_epid;
462ac63b947STaku Izumi 	max_epid = hw->max_epid;
463ac63b947STaku Izumi 
464ac63b947STaku Izumi 	for (i = 0; i < 5; i++) {
465ac63b947STaku Izumi 		all_queue_available = 1;
466ac63b947STaku Izumi 
467ac63b947STaku Izumi 		for (epid = 0; epid < max_epid; epid++) {
468ac63b947STaku Izumi 			if (my_epid == epid)
469ac63b947STaku Izumi 				continue;
470ac63b947STaku Izumi 
471ac63b947STaku Izumi 			pstatus = fjes_hw_get_partner_ep_status(hw, epid);
472ac63b947STaku Izumi 			sendable = (pstatus == EP_PARTNER_SHARED);
473ac63b947STaku Izumi 			if (!sendable)
474ac63b947STaku Izumi 				continue;
475ac63b947STaku Izumi 
476ac63b947STaku Izumi 			info = adapter->hw.ep_shm_info[epid].tx.info;
477ac63b947STaku Izumi 
478ac63b947STaku Izumi 			if (EP_RING_FULL(info->v1i.head, info->v1i.tail,
479ac63b947STaku Izumi 					 info->v1i.count_max)) {
480ac63b947STaku Izumi 				all_queue_available = 0;
481ac63b947STaku Izumi 				break;
482ac63b947STaku Izumi 			}
483ac63b947STaku Izumi 		}
484ac63b947STaku Izumi 
485ac63b947STaku Izumi 		if (all_queue_available) {
486ac63b947STaku Izumi 			netif_wake_queue(netdev);
487ac63b947STaku Izumi 			return;
488ac63b947STaku Izumi 		}
489ac63b947STaku Izumi 	}
490ac63b947STaku Izumi 
491ac63b947STaku Izumi 	usleep_range(50, 100);
492ac63b947STaku Izumi 
493ac63b947STaku Izumi 	queue_work(adapter->txrx_wq, &adapter->tx_stall_task);
494ac63b947STaku Izumi }
495ac63b947STaku Izumi 
496*ff5b4210STaku Izumi static void fjes_force_close_task(struct work_struct *work)
497*ff5b4210STaku Izumi {
498*ff5b4210STaku Izumi 	struct fjes_adapter *adapter = container_of(work,
499*ff5b4210STaku Izumi 			struct fjes_adapter, force_close_task);
500*ff5b4210STaku Izumi 	struct net_device *netdev = adapter->netdev;
501*ff5b4210STaku Izumi 
502*ff5b4210STaku Izumi 	rtnl_lock();
503*ff5b4210STaku Izumi 	dev_close(netdev);
504*ff5b4210STaku Izumi 	rtnl_unlock();
505*ff5b4210STaku Izumi }
506*ff5b4210STaku Izumi 
507b772b9dcSTaku Izumi static void fjes_raise_intr_rxdata_task(struct work_struct *work)
508b772b9dcSTaku Izumi {
509b772b9dcSTaku Izumi 	struct fjes_adapter *adapter = container_of(work,
510b772b9dcSTaku Izumi 			struct fjes_adapter, raise_intr_rxdata_task);
511b772b9dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
512b772b9dcSTaku Izumi 	enum ep_partner_status pstatus;
513b772b9dcSTaku Izumi 	int max_epid, my_epid, epid;
514b772b9dcSTaku Izumi 
515b772b9dcSTaku Izumi 	my_epid = hw->my_epid;
516b772b9dcSTaku Izumi 	max_epid = hw->max_epid;
517b772b9dcSTaku Izumi 
518b772b9dcSTaku Izumi 	for (epid = 0; epid < max_epid; epid++)
519b772b9dcSTaku Izumi 		hw->ep_shm_info[epid].tx_status_work = 0;
520b772b9dcSTaku Izumi 
521b772b9dcSTaku Izumi 	for (epid = 0; epid < max_epid; epid++) {
522b772b9dcSTaku Izumi 		if (epid == my_epid)
523b772b9dcSTaku Izumi 			continue;
524b772b9dcSTaku Izumi 
525b772b9dcSTaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, epid);
526b772b9dcSTaku Izumi 		if (pstatus == EP_PARTNER_SHARED) {
527b772b9dcSTaku Izumi 			hw->ep_shm_info[epid].tx_status_work =
528b772b9dcSTaku Izumi 				hw->ep_shm_info[epid].tx.info->v1i.tx_status;
529b772b9dcSTaku Izumi 
530b772b9dcSTaku Izumi 			if (hw->ep_shm_info[epid].tx_status_work ==
531b772b9dcSTaku Izumi 				FJES_TX_DELAY_SEND_PENDING) {
532b772b9dcSTaku Izumi 				hw->ep_shm_info[epid].tx.info->v1i.tx_status =
533b772b9dcSTaku Izumi 					FJES_TX_DELAY_SEND_NONE;
534b772b9dcSTaku Izumi 			}
535b772b9dcSTaku Izumi 		}
536b772b9dcSTaku Izumi 	}
537b772b9dcSTaku Izumi 
538b772b9dcSTaku Izumi 	for (epid = 0; epid < max_epid; epid++) {
539b772b9dcSTaku Izumi 		if (epid == my_epid)
540b772b9dcSTaku Izumi 			continue;
541b772b9dcSTaku Izumi 
542b772b9dcSTaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, epid);
543b772b9dcSTaku Izumi 		if ((hw->ep_shm_info[epid].tx_status_work ==
544b772b9dcSTaku Izumi 		     FJES_TX_DELAY_SEND_PENDING) &&
545b772b9dcSTaku Izumi 		    (pstatus == EP_PARTNER_SHARED) &&
546b772b9dcSTaku Izumi 		    !(hw->ep_shm_info[epid].rx.info->v1i.rx_status)) {
547b772b9dcSTaku Izumi 			fjes_hw_raise_interrupt(hw, epid,
548b772b9dcSTaku Izumi 						REG_ICTL_MASK_RX_DATA);
549b772b9dcSTaku Izumi 		}
550b772b9dcSTaku Izumi 	}
551b772b9dcSTaku Izumi 
552b772b9dcSTaku Izumi 	usleep_range(500, 1000);
553b772b9dcSTaku Izumi }
554b772b9dcSTaku Izumi 
5559acf51cbSTaku Izumi static int fjes_tx_send(struct fjes_adapter *adapter, int dest,
5569acf51cbSTaku Izumi 			void *data, size_t len)
5579acf51cbSTaku Izumi {
5589acf51cbSTaku Izumi 	int retval;
5599acf51cbSTaku Izumi 
5609acf51cbSTaku Izumi 	retval = fjes_hw_epbuf_tx_pkt_send(&adapter->hw.ep_shm_info[dest].tx,
5619acf51cbSTaku Izumi 					   data, len);
5629acf51cbSTaku Izumi 	if (retval)
5639acf51cbSTaku Izumi 		return retval;
5649acf51cbSTaku Izumi 
5659acf51cbSTaku Izumi 	adapter->hw.ep_shm_info[dest].tx.info->v1i.tx_status =
5669acf51cbSTaku Izumi 		FJES_TX_DELAY_SEND_PENDING;
567b772b9dcSTaku Izumi 	if (!work_pending(&adapter->raise_intr_rxdata_task))
568b772b9dcSTaku Izumi 		queue_work(adapter->txrx_wq,
569b772b9dcSTaku Izumi 			   &adapter->raise_intr_rxdata_task);
5709acf51cbSTaku Izumi 
5719acf51cbSTaku Izumi 	retval = 0;
5729acf51cbSTaku Izumi 	return retval;
5739acf51cbSTaku Izumi }
5749acf51cbSTaku Izumi 
5759acf51cbSTaku Izumi static netdev_tx_t
5769acf51cbSTaku Izumi fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
5779acf51cbSTaku Izumi {
5789acf51cbSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
5799acf51cbSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
5809acf51cbSTaku Izumi 
5819acf51cbSTaku Izumi 	int max_epid, my_epid, dest_epid;
5829acf51cbSTaku Izumi 	enum ep_partner_status pstatus;
5839acf51cbSTaku Izumi 	struct netdev_queue *cur_queue;
5849acf51cbSTaku Izumi 	char shortpkt[VLAN_ETH_HLEN];
5859acf51cbSTaku Izumi 	bool is_multi, vlan;
5869acf51cbSTaku Izumi 	struct ethhdr *eth;
5879acf51cbSTaku Izumi 	u16 queue_no = 0;
5889acf51cbSTaku Izumi 	u16 vlan_id = 0;
5899acf51cbSTaku Izumi 	netdev_tx_t ret;
5909acf51cbSTaku Izumi 	char *data;
5919acf51cbSTaku Izumi 	int len;
5929acf51cbSTaku Izumi 
5939acf51cbSTaku Izumi 	ret = NETDEV_TX_OK;
5949acf51cbSTaku Izumi 	is_multi = false;
5959acf51cbSTaku Izumi 	cur_queue = netdev_get_tx_queue(netdev, queue_no);
5969acf51cbSTaku Izumi 
5979acf51cbSTaku Izumi 	eth = (struct ethhdr *)skb->data;
5989acf51cbSTaku Izumi 	my_epid = hw->my_epid;
5999acf51cbSTaku Izumi 
6009acf51cbSTaku Izumi 	vlan = (vlan_get_tag(skb, &vlan_id) == 0) ? true : false;
6019acf51cbSTaku Izumi 
6029acf51cbSTaku Izumi 	data = skb->data;
6039acf51cbSTaku Izumi 	len = skb->len;
6049acf51cbSTaku Izumi 
6059acf51cbSTaku Izumi 	if (is_multicast_ether_addr(eth->h_dest)) {
6069acf51cbSTaku Izumi 		dest_epid = 0;
6079acf51cbSTaku Izumi 		max_epid = hw->max_epid;
6089acf51cbSTaku Izumi 		is_multi = true;
6099acf51cbSTaku Izumi 	} else if (is_local_ether_addr(eth->h_dest)) {
6109acf51cbSTaku Izumi 		dest_epid = eth->h_dest[ETH_ALEN - 1];
6119acf51cbSTaku Izumi 		max_epid = dest_epid + 1;
6129acf51cbSTaku Izumi 
6139acf51cbSTaku Izumi 		if ((eth->h_dest[0] == 0x02) &&
6149acf51cbSTaku Izumi 		    (0x00 == (eth->h_dest[1] | eth->h_dest[2] |
6159acf51cbSTaku Izumi 			      eth->h_dest[3] | eth->h_dest[4])) &&
6169acf51cbSTaku Izumi 		    (dest_epid < hw->max_epid)) {
6179acf51cbSTaku Izumi 			;
6189acf51cbSTaku Izumi 		} else {
6199acf51cbSTaku Izumi 			dest_epid = 0;
6209acf51cbSTaku Izumi 			max_epid = 0;
6219acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6229acf51cbSTaku Izumi 
6239acf51cbSTaku Izumi 			adapter->stats64.tx_packets += 1;
6249acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
6259acf51cbSTaku Izumi 			adapter->stats64.tx_bytes += len;
6269acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
6279acf51cbSTaku Izumi 		}
6289acf51cbSTaku Izumi 	} else {
6299acf51cbSTaku Izumi 		dest_epid = 0;
6309acf51cbSTaku Izumi 		max_epid = 0;
6319acf51cbSTaku Izumi 		ret = NETDEV_TX_OK;
6329acf51cbSTaku Izumi 
6339acf51cbSTaku Izumi 		adapter->stats64.tx_packets += 1;
6349acf51cbSTaku Izumi 		hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
6359acf51cbSTaku Izumi 		adapter->stats64.tx_bytes += len;
6369acf51cbSTaku Izumi 		hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
6379acf51cbSTaku Izumi 	}
6389acf51cbSTaku Izumi 
6399acf51cbSTaku Izumi 	for (; dest_epid < max_epid; dest_epid++) {
6409acf51cbSTaku Izumi 		if (my_epid == dest_epid)
6419acf51cbSTaku Izumi 			continue;
6429acf51cbSTaku Izumi 
6439acf51cbSTaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, dest_epid);
6449acf51cbSTaku Izumi 		if (pstatus != EP_PARTNER_SHARED) {
6459acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6469acf51cbSTaku Izumi 		} else if (!fjes_hw_check_epbuf_version(
6479acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx, 0)) {
6489acf51cbSTaku Izumi 			/* version is NOT 0 */
6499acf51cbSTaku Izumi 			adapter->stats64.tx_carrier_errors += 1;
6509acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats
6519acf51cbSTaku Izumi 						.tx_carrier_errors += 1;
6529acf51cbSTaku Izumi 
6539acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6549acf51cbSTaku Izumi 		} else if (!fjes_hw_check_mtu(
6559acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx,
6569acf51cbSTaku Izumi 				netdev->mtu)) {
6579acf51cbSTaku Izumi 			adapter->stats64.tx_dropped += 1;
6589acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_dropped += 1;
6599acf51cbSTaku Izumi 			adapter->stats64.tx_errors += 1;
6609acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_errors += 1;
6619acf51cbSTaku Izumi 
6629acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6639acf51cbSTaku Izumi 		} else if (vlan &&
6649acf51cbSTaku Izumi 			   !fjes_hw_check_vlan_id(
6659acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx,
6669acf51cbSTaku Izumi 				vlan_id)) {
6679acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6689acf51cbSTaku Izumi 		} else {
6699acf51cbSTaku Izumi 			if (len < VLAN_ETH_HLEN) {
6709acf51cbSTaku Izumi 				memset(shortpkt, 0, VLAN_ETH_HLEN);
6719acf51cbSTaku Izumi 				memcpy(shortpkt, skb->data, skb->len);
6729acf51cbSTaku Izumi 				len = VLAN_ETH_HLEN;
6739acf51cbSTaku Izumi 				data = shortpkt;
6749acf51cbSTaku Izumi 			}
6759acf51cbSTaku Izumi 
6769acf51cbSTaku Izumi 			if (adapter->tx_retry_count == 0) {
6779acf51cbSTaku Izumi 				adapter->tx_start_jiffies = jiffies;
6789acf51cbSTaku Izumi 				adapter->tx_retry_count = 1;
6799acf51cbSTaku Izumi 			} else {
6809acf51cbSTaku Izumi 				adapter->tx_retry_count++;
6819acf51cbSTaku Izumi 			}
6829acf51cbSTaku Izumi 
6839acf51cbSTaku Izumi 			if (fjes_tx_send(adapter, dest_epid, data, len)) {
6849acf51cbSTaku Izumi 				if (is_multi) {
6859acf51cbSTaku Izumi 					ret = NETDEV_TX_OK;
6869acf51cbSTaku Izumi 				} else if (
6879acf51cbSTaku Izumi 					   ((long)jiffies -
6889acf51cbSTaku Izumi 					    (long)adapter->tx_start_jiffies) >=
6899acf51cbSTaku Izumi 					    FJES_TX_RETRY_TIMEOUT) {
6909acf51cbSTaku Izumi 					adapter->stats64.tx_fifo_errors += 1;
6919acf51cbSTaku Izumi 					hw->ep_shm_info[my_epid].net_stats
6929acf51cbSTaku Izumi 								.tx_fifo_errors += 1;
6939acf51cbSTaku Izumi 					adapter->stats64.tx_errors += 1;
6949acf51cbSTaku Izumi 					hw->ep_shm_info[my_epid].net_stats
6959acf51cbSTaku Izumi 								.tx_errors += 1;
6969acf51cbSTaku Izumi 
6979acf51cbSTaku Izumi 					ret = NETDEV_TX_OK;
6989acf51cbSTaku Izumi 				} else {
6999acf51cbSTaku Izumi 					netdev->trans_start = jiffies;
7009acf51cbSTaku Izumi 					netif_tx_stop_queue(cur_queue);
7019acf51cbSTaku Izumi 
702ac63b947STaku Izumi 					if (!work_pending(&adapter->tx_stall_task))
703ac63b947STaku Izumi 						queue_work(adapter->txrx_wq,
704ac63b947STaku Izumi 							   &adapter->tx_stall_task);
705ac63b947STaku Izumi 
7069acf51cbSTaku Izumi 					ret = NETDEV_TX_BUSY;
7079acf51cbSTaku Izumi 				}
7089acf51cbSTaku Izumi 			} else {
7099acf51cbSTaku Izumi 				if (!is_multi) {
7109acf51cbSTaku Izumi 					adapter->stats64.tx_packets += 1;
7119acf51cbSTaku Izumi 					hw->ep_shm_info[my_epid].net_stats
7129acf51cbSTaku Izumi 								.tx_packets += 1;
7139acf51cbSTaku Izumi 					adapter->stats64.tx_bytes += len;
7149acf51cbSTaku Izumi 					hw->ep_shm_info[my_epid].net_stats
7159acf51cbSTaku Izumi 								.tx_bytes += len;
7169acf51cbSTaku Izumi 				}
7179acf51cbSTaku Izumi 
7189acf51cbSTaku Izumi 				adapter->tx_retry_count = 0;
7199acf51cbSTaku Izumi 				ret = NETDEV_TX_OK;
7209acf51cbSTaku Izumi 			}
7219acf51cbSTaku Izumi 		}
7229acf51cbSTaku Izumi 	}
7239acf51cbSTaku Izumi 
7249acf51cbSTaku Izumi 	if (ret == NETDEV_TX_OK) {
7259acf51cbSTaku Izumi 		dev_kfree_skb(skb);
7269acf51cbSTaku Izumi 		if (is_multi) {
7279acf51cbSTaku Izumi 			adapter->stats64.tx_packets += 1;
7289acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
7299acf51cbSTaku Izumi 			adapter->stats64.tx_bytes += 1;
7309acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
7319acf51cbSTaku Izumi 		}
7329acf51cbSTaku Izumi 	}
7339acf51cbSTaku Izumi 
7349acf51cbSTaku Izumi 	return ret;
7359acf51cbSTaku Izumi }
7369acf51cbSTaku Izumi 
7374393e767STaku Izumi static void fjes_tx_retry(struct net_device *netdev)
7384393e767STaku Izumi {
7394393e767STaku Izumi 	struct netdev_queue *queue = netdev_get_tx_queue(netdev, 0);
7404393e767STaku Izumi 
7414393e767STaku Izumi 	netif_tx_wake_queue(queue);
7424393e767STaku Izumi }
7434393e767STaku Izumi 
744879bc9a3STaku Izumi static struct rtnl_link_stats64 *
745879bc9a3STaku Izumi fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
746879bc9a3STaku Izumi {
747879bc9a3STaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
748879bc9a3STaku Izumi 
749879bc9a3STaku Izumi 	memcpy(stats, &adapter->stats64, sizeof(struct rtnl_link_stats64));
750879bc9a3STaku Izumi 
751879bc9a3STaku Izumi 	return stats;
752879bc9a3STaku Izumi }
753879bc9a3STaku Izumi 
754b9e23a67STaku Izumi static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
755b9e23a67STaku Izumi {
756b9e23a67STaku Izumi 	bool running = netif_running(netdev);
757b9e23a67STaku Izumi 	int ret = 0;
758b9e23a67STaku Izumi 	int idx;
759b9e23a67STaku Izumi 
760b9e23a67STaku Izumi 	for (idx = 0; fjes_support_mtu[idx] != 0; idx++) {
761b9e23a67STaku Izumi 		if (new_mtu <= fjes_support_mtu[idx]) {
762b9e23a67STaku Izumi 			new_mtu = fjes_support_mtu[idx];
763b9e23a67STaku Izumi 			if (new_mtu == netdev->mtu)
764b9e23a67STaku Izumi 				return 0;
765b9e23a67STaku Izumi 
766b9e23a67STaku Izumi 			if (running)
767b9e23a67STaku Izumi 				fjes_close(netdev);
768b9e23a67STaku Izumi 
769b9e23a67STaku Izumi 			netdev->mtu = new_mtu;
770b9e23a67STaku Izumi 
771b9e23a67STaku Izumi 			if (running)
772b9e23a67STaku Izumi 				ret = fjes_open(netdev);
773b9e23a67STaku Izumi 
774b9e23a67STaku Izumi 			return ret;
775b9e23a67STaku Izumi 		}
776b9e23a67STaku Izumi 	}
777b9e23a67STaku Izumi 
778b9e23a67STaku Izumi 	return -EINVAL;
779b9e23a67STaku Izumi }
780b9e23a67STaku Izumi 
7813e3feddaSTaku Izumi static int fjes_vlan_rx_add_vid(struct net_device *netdev,
7823e3feddaSTaku Izumi 				__be16 proto, u16 vid)
7833e3feddaSTaku Izumi {
7843e3feddaSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
7853e3feddaSTaku Izumi 	bool ret = true;
7863e3feddaSTaku Izumi 	int epid;
7873e3feddaSTaku Izumi 
7883e3feddaSTaku Izumi 	for (epid = 0; epid < adapter->hw.max_epid; epid++) {
7893e3feddaSTaku Izumi 		if (epid == adapter->hw.my_epid)
7903e3feddaSTaku Izumi 			continue;
7913e3feddaSTaku Izumi 
7923e3feddaSTaku Izumi 		if (!fjes_hw_check_vlan_id(
7933e3feddaSTaku Izumi 			&adapter->hw.ep_shm_info[epid].tx, vid))
7943e3feddaSTaku Izumi 			ret = fjes_hw_set_vlan_id(
7953e3feddaSTaku Izumi 				&adapter->hw.ep_shm_info[epid].tx, vid);
7963e3feddaSTaku Izumi 	}
7973e3feddaSTaku Izumi 
7983e3feddaSTaku Izumi 	return ret ? 0 : -ENOSPC;
7993e3feddaSTaku Izumi }
8003e3feddaSTaku Izumi 
8013e3feddaSTaku Izumi static int fjes_vlan_rx_kill_vid(struct net_device *netdev,
8023e3feddaSTaku Izumi 				 __be16 proto, u16 vid)
8033e3feddaSTaku Izumi {
8043e3feddaSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
8053e3feddaSTaku Izumi 	int epid;
8063e3feddaSTaku Izumi 
8073e3feddaSTaku Izumi 	for (epid = 0; epid < adapter->hw.max_epid; epid++) {
8083e3feddaSTaku Izumi 		if (epid == adapter->hw.my_epid)
8093e3feddaSTaku Izumi 			continue;
8103e3feddaSTaku Izumi 
8113e3feddaSTaku Izumi 		fjes_hw_del_vlan_id(&adapter->hw.ep_shm_info[epid].tx, vid);
8123e3feddaSTaku Izumi 	}
8133e3feddaSTaku Izumi 
8143e3feddaSTaku Izumi 	return 0;
8153e3feddaSTaku Izumi }
8163e3feddaSTaku Izumi 
817e5d486dcSTaku Izumi static irqreturn_t fjes_intr(int irq, void *data)
818e5d486dcSTaku Izumi {
819e5d486dcSTaku Izumi 	struct fjes_adapter *adapter = data;
820e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
821e5d486dcSTaku Izumi 	irqreturn_t ret;
822e5d486dcSTaku Izumi 	u32 icr;
823e5d486dcSTaku Izumi 
824e5d486dcSTaku Izumi 	icr = fjes_hw_capture_interrupt_status(hw);
825e5d486dcSTaku Izumi 
82626585930STaku Izumi 	if (icr & REG_IS_MASK_IS_ASSERT) {
82726585930STaku Izumi 		if (icr & REG_ICTL_MASK_RX_DATA)
82826585930STaku Izumi 			fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID);
82926585930STaku Izumi 
830e5d486dcSTaku Izumi 		ret = IRQ_HANDLED;
83126585930STaku Izumi 	} else {
832e5d486dcSTaku Izumi 		ret = IRQ_NONE;
83326585930STaku Izumi 	}
834e5d486dcSTaku Izumi 
835e5d486dcSTaku Izumi 	return ret;
836e5d486dcSTaku Izumi }
837e5d486dcSTaku Izumi 
83826585930STaku Izumi static int fjes_rxframe_search_exist(struct fjes_adapter *adapter,
83926585930STaku Izumi 				     int start_epid)
84026585930STaku Izumi {
84126585930STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
84226585930STaku Izumi 	enum ep_partner_status pstatus;
84326585930STaku Izumi 	int max_epid, cur_epid;
84426585930STaku Izumi 	int i;
84526585930STaku Izumi 
84626585930STaku Izumi 	max_epid = hw->max_epid;
84726585930STaku Izumi 	start_epid = (start_epid + 1 + max_epid) % max_epid;
84826585930STaku Izumi 
84926585930STaku Izumi 	for (i = 0; i < max_epid; i++) {
85026585930STaku Izumi 		cur_epid = (start_epid + i) % max_epid;
85126585930STaku Izumi 		if (cur_epid == hw->my_epid)
85226585930STaku Izumi 			continue;
85326585930STaku Izumi 
85426585930STaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, cur_epid);
85526585930STaku Izumi 		if (pstatus == EP_PARTNER_SHARED) {
85626585930STaku Izumi 			if (!fjes_hw_epbuf_rx_is_empty(
85726585930STaku Izumi 				&hw->ep_shm_info[cur_epid].rx))
85826585930STaku Izumi 				return cur_epid;
85926585930STaku Izumi 		}
86026585930STaku Izumi 	}
86126585930STaku Izumi 	return -1;
86226585930STaku Izumi }
86326585930STaku Izumi 
86426585930STaku Izumi static void *fjes_rxframe_get(struct fjes_adapter *adapter, size_t *psize,
86526585930STaku Izumi 			      int *cur_epid)
86626585930STaku Izumi {
86726585930STaku Izumi 	void *frame;
86826585930STaku Izumi 
86926585930STaku Izumi 	*cur_epid = fjes_rxframe_search_exist(adapter, *cur_epid);
87026585930STaku Izumi 	if (*cur_epid < 0)
87126585930STaku Izumi 		return NULL;
87226585930STaku Izumi 
87326585930STaku Izumi 	frame =
87426585930STaku Izumi 	fjes_hw_epbuf_rx_curpkt_get_addr(
87526585930STaku Izumi 		&adapter->hw.ep_shm_info[*cur_epid].rx, psize);
87626585930STaku Izumi 
87726585930STaku Izumi 	return frame;
87826585930STaku Izumi }
87926585930STaku Izumi 
88026585930STaku Izumi static void fjes_rxframe_release(struct fjes_adapter *adapter, int cur_epid)
88126585930STaku Izumi {
88226585930STaku Izumi 	fjes_hw_epbuf_rx_curpkt_drop(&adapter->hw.ep_shm_info[cur_epid].rx);
88326585930STaku Izumi }
88426585930STaku Izumi 
88526585930STaku Izumi static void fjes_rx_irq(struct fjes_adapter *adapter, int src_epid)
88626585930STaku Izumi {
88726585930STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
88826585930STaku Izumi 
88926585930STaku Izumi 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, true);
89026585930STaku Izumi 
89126585930STaku Izumi 	adapter->unset_rx_last = true;
89226585930STaku Izumi 	napi_schedule(&adapter->napi);
89326585930STaku Izumi }
89426585930STaku Izumi 
89526585930STaku Izumi static int fjes_poll(struct napi_struct *napi, int budget)
89626585930STaku Izumi {
89726585930STaku Izumi 	struct fjes_adapter *adapter =
89826585930STaku Izumi 			container_of(napi, struct fjes_adapter, napi);
89926585930STaku Izumi 	struct net_device *netdev = napi->dev;
90026585930STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
90126585930STaku Izumi 	struct sk_buff *skb;
90226585930STaku Izumi 	int work_done = 0;
90326585930STaku Izumi 	int cur_epid = 0;
90426585930STaku Izumi 	int epidx;
90526585930STaku Izumi 	size_t frame_len;
90626585930STaku Izumi 	void *frame;
90726585930STaku Izumi 
90826585930STaku Izumi 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
90926585930STaku Izumi 		if (epidx == hw->my_epid)
91026585930STaku Izumi 			continue;
91126585930STaku Izumi 
91226585930STaku Izumi 		adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status |=
91326585930STaku Izumi 			FJES_RX_POLL_WORK;
91426585930STaku Izumi 	}
91526585930STaku Izumi 
91626585930STaku Izumi 	while (work_done < budget) {
91726585930STaku Izumi 		prefetch(&adapter->hw);
91826585930STaku Izumi 		frame = fjes_rxframe_get(adapter, &frame_len, &cur_epid);
91926585930STaku Izumi 
92026585930STaku Izumi 		if (frame) {
92126585930STaku Izumi 			skb = napi_alloc_skb(napi, frame_len);
92226585930STaku Izumi 			if (!skb) {
92326585930STaku Izumi 				adapter->stats64.rx_dropped += 1;
92426585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
92526585930STaku Izumi 							 .rx_dropped += 1;
92626585930STaku Izumi 				adapter->stats64.rx_errors += 1;
92726585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
92826585930STaku Izumi 							 .rx_errors += 1;
92926585930STaku Izumi 			} else {
93026585930STaku Izumi 				memcpy(skb_put(skb, frame_len),
93126585930STaku Izumi 				       frame, frame_len);
93226585930STaku Izumi 				skb->protocol = eth_type_trans(skb, netdev);
93326585930STaku Izumi 				skb->ip_summed = CHECKSUM_UNNECESSARY;
93426585930STaku Izumi 
93526585930STaku Izumi 				netif_receive_skb(skb);
93626585930STaku Izumi 
93726585930STaku Izumi 				work_done++;
93826585930STaku Izumi 
93926585930STaku Izumi 				adapter->stats64.rx_packets += 1;
94026585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
94126585930STaku Izumi 							 .rx_packets += 1;
94226585930STaku Izumi 				adapter->stats64.rx_bytes += frame_len;
94326585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
94426585930STaku Izumi 							 .rx_bytes += frame_len;
94526585930STaku Izumi 
94626585930STaku Izumi 				if (is_multicast_ether_addr(
94726585930STaku Izumi 					((struct ethhdr *)frame)->h_dest)) {
94826585930STaku Izumi 					adapter->stats64.multicast += 1;
94926585930STaku Izumi 					hw->ep_shm_info[cur_epid].net_stats
95026585930STaku Izumi 								 .multicast += 1;
95126585930STaku Izumi 				}
95226585930STaku Izumi 			}
95326585930STaku Izumi 
95426585930STaku Izumi 			fjes_rxframe_release(adapter, cur_epid);
95526585930STaku Izumi 			adapter->unset_rx_last = true;
95626585930STaku Izumi 		} else {
95726585930STaku Izumi 			break;
95826585930STaku Izumi 		}
95926585930STaku Izumi 	}
96026585930STaku Izumi 
96126585930STaku Izumi 	if (work_done < budget) {
96226585930STaku Izumi 		napi_complete(napi);
96326585930STaku Izumi 
96426585930STaku Izumi 		if (adapter->unset_rx_last) {
96526585930STaku Izumi 			adapter->rx_last_jiffies = jiffies;
96626585930STaku Izumi 			adapter->unset_rx_last = false;
96726585930STaku Izumi 		}
96826585930STaku Izumi 
96926585930STaku Izumi 		if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) {
97026585930STaku Izumi 			napi_reschedule(napi);
97126585930STaku Izumi 		} else {
97226585930STaku Izumi 			for (epidx = 0; epidx < hw->max_epid; epidx++) {
97326585930STaku Izumi 				if (epidx == hw->my_epid)
97426585930STaku Izumi 					continue;
97526585930STaku Izumi 				adapter->hw.ep_shm_info[epidx]
97626585930STaku Izumi 					   .tx.info->v1i.rx_status &=
97726585930STaku Izumi 						~FJES_RX_POLL_WORK;
97826585930STaku Izumi 			}
97926585930STaku Izumi 
98026585930STaku Izumi 			fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false);
98126585930STaku Izumi 		}
98226585930STaku Izumi 	}
98326585930STaku Izumi 
98426585930STaku Izumi 	return work_done;
98526585930STaku Izumi }
98626585930STaku Izumi 
987658d439bSTaku Izumi /* fjes_probe - Device Initialization Routine */
988658d439bSTaku Izumi static int fjes_probe(struct platform_device *plat_dev)
989658d439bSTaku Izumi {
9902fcbca68STaku Izumi 	struct fjes_adapter *adapter;
9912fcbca68STaku Izumi 	struct net_device *netdev;
9922fcbca68STaku Izumi 	struct resource *res;
9932fcbca68STaku Izumi 	struct fjes_hw *hw;
9942fcbca68STaku Izumi 	int err;
9952fcbca68STaku Izumi 
9962fcbca68STaku Izumi 	err = -ENOMEM;
9972fcbca68STaku Izumi 	netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d",
9982fcbca68STaku Izumi 				 NET_NAME_UNKNOWN, fjes_netdev_setup,
9992fcbca68STaku Izumi 				 FJES_MAX_QUEUES);
10002fcbca68STaku Izumi 
10012fcbca68STaku Izumi 	if (!netdev)
10022fcbca68STaku Izumi 		goto err_out;
10032fcbca68STaku Izumi 
10042fcbca68STaku Izumi 	SET_NETDEV_DEV(netdev, &plat_dev->dev);
10052fcbca68STaku Izumi 
10062fcbca68STaku Izumi 	dev_set_drvdata(&plat_dev->dev, netdev);
10072fcbca68STaku Izumi 	adapter = netdev_priv(netdev);
10082fcbca68STaku Izumi 	adapter->netdev = netdev;
10092fcbca68STaku Izumi 	adapter->plat_dev = plat_dev;
10102fcbca68STaku Izumi 	hw = &adapter->hw;
10112fcbca68STaku Izumi 	hw->back = adapter;
10122fcbca68STaku Izumi 
10132fcbca68STaku Izumi 	/* setup the private structure */
10142fcbca68STaku Izumi 	err = fjes_sw_init(adapter);
10152fcbca68STaku Izumi 	if (err)
10162fcbca68STaku Izumi 		goto err_free_netdev;
10172fcbca68STaku Izumi 
1018*ff5b4210STaku Izumi 	INIT_WORK(&adapter->force_close_task, fjes_force_close_task);
10192fcbca68STaku Izumi 	adapter->force_reset = false;
10202fcbca68STaku Izumi 	adapter->open_guard = false;
10212fcbca68STaku Izumi 
1022b772b9dcSTaku Izumi 	adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx");
10238edb62a8STaku Izumi 	adapter->control_wq = create_workqueue(DRV_NAME "/control");
1024b772b9dcSTaku Izumi 
1025ac63b947STaku Izumi 	INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task);
1026b772b9dcSTaku Izumi 	INIT_WORK(&adapter->raise_intr_rxdata_task,
1027b772b9dcSTaku Izumi 		  fjes_raise_intr_rxdata_task);
1028b772b9dcSTaku Izumi 
10298edb62a8STaku Izumi 	INIT_DELAYED_WORK(&adapter->interrupt_watch_task, fjes_irq_watch_task);
10308edb62a8STaku Izumi 	adapter->interrupt_watch_enable = false;
10318edb62a8STaku Izumi 
10322fcbca68STaku Izumi 	res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
10332fcbca68STaku Izumi 	hw->hw_res.start = res->start;
10342fcbca68STaku Izumi 	hw->hw_res.size = res->end - res->start + 1;
10352fcbca68STaku Izumi 	hw->hw_res.irq = platform_get_irq(plat_dev, 0);
10362fcbca68STaku Izumi 	err = fjes_hw_init(&adapter->hw);
10372fcbca68STaku Izumi 	if (err)
10382fcbca68STaku Izumi 		goto err_free_netdev;
10392fcbca68STaku Izumi 
10402fcbca68STaku Izumi 	/* setup MAC address (02:00:00:00:00:[epid])*/
10412fcbca68STaku Izumi 	netdev->dev_addr[0] = 2;
10422fcbca68STaku Izumi 	netdev->dev_addr[1] = 0;
10432fcbca68STaku Izumi 	netdev->dev_addr[2] = 0;
10442fcbca68STaku Izumi 	netdev->dev_addr[3] = 0;
10452fcbca68STaku Izumi 	netdev->dev_addr[4] = 0;
10462fcbca68STaku Izumi 	netdev->dev_addr[5] = hw->my_epid; /* EPID */
10472fcbca68STaku Izumi 
10482fcbca68STaku Izumi 	err = register_netdev(netdev);
10492fcbca68STaku Izumi 	if (err)
10502fcbca68STaku Izumi 		goto err_hw_exit;
10512fcbca68STaku Izumi 
10522fcbca68STaku Izumi 	netif_carrier_off(netdev);
10532fcbca68STaku Izumi 
1054658d439bSTaku Izumi 	return 0;
10552fcbca68STaku Izumi 
10562fcbca68STaku Izumi err_hw_exit:
10572fcbca68STaku Izumi 	fjes_hw_exit(&adapter->hw);
10582fcbca68STaku Izumi err_free_netdev:
10592fcbca68STaku Izumi 	free_netdev(netdev);
10602fcbca68STaku Izumi err_out:
10612fcbca68STaku Izumi 	return err;
1062658d439bSTaku Izumi }
1063658d439bSTaku Izumi 
1064658d439bSTaku Izumi /* fjes_remove - Device Removal Routine */
1065658d439bSTaku Izumi static int fjes_remove(struct platform_device *plat_dev)
1066658d439bSTaku Izumi {
10672fcbca68STaku Izumi 	struct net_device *netdev = dev_get_drvdata(&plat_dev->dev);
10682fcbca68STaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
10692fcbca68STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
10702fcbca68STaku Izumi 
10718edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
1072b772b9dcSTaku Izumi 	cancel_work_sync(&adapter->raise_intr_rxdata_task);
1073ac63b947STaku Izumi 	cancel_work_sync(&adapter->tx_stall_task);
10748edb62a8STaku Izumi 	if (adapter->control_wq)
10758edb62a8STaku Izumi 		destroy_workqueue(adapter->control_wq);
1076b772b9dcSTaku Izumi 	if (adapter->txrx_wq)
1077b772b9dcSTaku Izumi 		destroy_workqueue(adapter->txrx_wq);
1078b772b9dcSTaku Izumi 
10792fcbca68STaku Izumi 	unregister_netdev(netdev);
10802fcbca68STaku Izumi 
10812fcbca68STaku Izumi 	fjes_hw_exit(hw);
10822fcbca68STaku Izumi 
108326585930STaku Izumi 	netif_napi_del(&adapter->napi);
108426585930STaku Izumi 
10852fcbca68STaku Izumi 	free_netdev(netdev);
10862fcbca68STaku Izumi 
1087658d439bSTaku Izumi 	return 0;
1088658d439bSTaku Izumi }
1089658d439bSTaku Izumi 
10902fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *adapter)
10912fcbca68STaku Izumi {
109226585930STaku Izumi 	struct net_device *netdev = adapter->netdev;
109326585930STaku Izumi 
109426585930STaku Izumi 	netif_napi_add(netdev, &adapter->napi, fjes_poll, 64);
109526585930STaku Izumi 
10962fcbca68STaku Izumi 	return 0;
10972fcbca68STaku Izumi }
10982fcbca68STaku Izumi 
10992fcbca68STaku Izumi /* fjes_netdev_setup - netdevice initialization routine */
11002fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *netdev)
11012fcbca68STaku Izumi {
11022fcbca68STaku Izumi 	ether_setup(netdev);
11032fcbca68STaku Izumi 
11042fcbca68STaku Izumi 	netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL;
11052fcbca68STaku Izumi 	netdev->netdev_ops = &fjes_netdev_ops;
11062fcbca68STaku Izumi 	netdev->mtu = fjes_support_mtu[0];
11072fcbca68STaku Izumi 	netdev->flags |= IFF_BROADCAST;
11082fcbca68STaku Izumi 	netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER;
11092fcbca68STaku Izumi }
11102fcbca68STaku Izumi 
11118edb62a8STaku Izumi static void fjes_irq_watch_task(struct work_struct *work)
11128edb62a8STaku Izumi {
11138edb62a8STaku Izumi 	struct fjes_adapter *adapter = container_of(to_delayed_work(work),
11148edb62a8STaku Izumi 			struct fjes_adapter, interrupt_watch_task);
11158edb62a8STaku Izumi 
11168edb62a8STaku Izumi 	local_irq_disable();
11178edb62a8STaku Izumi 	fjes_intr(adapter->hw.hw_res.irq, adapter);
11188edb62a8STaku Izumi 	local_irq_enable();
11198edb62a8STaku Izumi 
11208edb62a8STaku Izumi 	if (fjes_rxframe_search_exist(adapter, 0) >= 0)
11218edb62a8STaku Izumi 		napi_schedule(&adapter->napi);
11228edb62a8STaku Izumi 
11238edb62a8STaku Izumi 	if (adapter->interrupt_watch_enable) {
11248edb62a8STaku Izumi 		if (!delayed_work_pending(&adapter->interrupt_watch_task))
11258edb62a8STaku Izumi 			queue_delayed_work(adapter->control_wq,
11268edb62a8STaku Izumi 					   &adapter->interrupt_watch_task,
11278edb62a8STaku Izumi 					   FJES_IRQ_WATCH_DELAY);
11288edb62a8STaku Izumi 	}
11298edb62a8STaku Izumi }
11308edb62a8STaku Izumi 
1131658d439bSTaku Izumi /* fjes_init_module - Driver Registration Routine */
1132658d439bSTaku Izumi static int __init fjes_init_module(void)
1133658d439bSTaku Izumi {
1134658d439bSTaku Izumi 	int result;
1135658d439bSTaku Izumi 
1136658d439bSTaku Izumi 	pr_info("%s - version %s - %s\n",
1137658d439bSTaku Izumi 		fjes_driver_string, fjes_driver_version, fjes_copyright);
1138658d439bSTaku Izumi 
1139658d439bSTaku Izumi 	result = platform_driver_register(&fjes_driver);
1140658d439bSTaku Izumi 	if (result < 0)
1141658d439bSTaku Izumi 		return result;
1142658d439bSTaku Izumi 
1143658d439bSTaku Izumi 	result = acpi_bus_register_driver(&fjes_acpi_driver);
1144658d439bSTaku Izumi 	if (result < 0)
1145658d439bSTaku Izumi 		goto fail_acpi_driver;
1146658d439bSTaku Izumi 
1147658d439bSTaku Izumi 	return 0;
1148658d439bSTaku Izumi 
1149658d439bSTaku Izumi fail_acpi_driver:
1150658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
1151658d439bSTaku Izumi 	return result;
1152658d439bSTaku Izumi }
1153658d439bSTaku Izumi 
1154658d439bSTaku Izumi module_init(fjes_init_module);
1155658d439bSTaku Izumi 
1156658d439bSTaku Izumi /* fjes_exit_module - Driver Exit Cleanup Routine */
1157658d439bSTaku Izumi static void __exit fjes_exit_module(void)
1158658d439bSTaku Izumi {
1159658d439bSTaku Izumi 	acpi_bus_unregister_driver(&fjes_acpi_driver);
1160658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
1161658d439bSTaku Izumi }
1162658d439bSTaku Izumi 
1163658d439bSTaku Izumi module_exit(fjes_exit_module);
1164