xref: /openbmc/linux/drivers/net/fjes/fjes_main.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1dcc4086dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2658d439bSTaku Izumi /*
3658d439bSTaku Izumi  *  FUJITSU Extended Socket Network Device driver
4658d439bSTaku Izumi  *  Copyright (c) 2015 FUJITSU LIMITED
5658d439bSTaku Izumi  */
6658d439bSTaku Izumi 
7658d439bSTaku Izumi #include <linux/module.h>
8658d439bSTaku Izumi #include <linux/types.h>
9658d439bSTaku Izumi #include <linux/nls.h>
10658d439bSTaku Izumi #include <linux/platform_device.h>
112fcbca68STaku Izumi #include <linux/netdevice.h>
12e5d486dcSTaku Izumi #include <linux/interrupt.h>
13658d439bSTaku Izumi 
14658d439bSTaku Izumi #include "fjes.h"
1582f6aea8STaku Izumi #include "fjes_trace.h"
16658d439bSTaku Izumi 
17658d439bSTaku Izumi #define MAJ 1
188f87d775STaku Izumi #define MIN 2
19658d439bSTaku Izumi #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN)
20658d439bSTaku Izumi #define DRV_NAME	"fjes"
21658d439bSTaku Izumi char fjes_driver_name[] = DRV_NAME;
22658d439bSTaku Izumi char fjes_driver_version[] = DRV_VERSION;
23658d439bSTaku Izumi static const char fjes_driver_string[] =
24658d439bSTaku Izumi 		"FUJITSU Extended Socket Network Device Driver";
25658d439bSTaku Izumi static const char fjes_copyright[] =
26658d439bSTaku Izumi 		"Copyright (c) 2015 FUJITSU LIMITED";
27658d439bSTaku Izumi 
28658d439bSTaku Izumi MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>");
29658d439bSTaku Izumi MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver");
30658d439bSTaku Izumi MODULE_LICENSE("GPL");
31658d439bSTaku Izumi MODULE_VERSION(DRV_VERSION);
32658d439bSTaku Izumi 
33ac23d3caSYasuaki Ishimatsu #define ACPI_MOTHERBOARD_RESOURCE_HID "PNP0C02"
34ac23d3caSYasuaki Ishimatsu 
35658d439bSTaku Izumi static const struct acpi_device_id fjes_acpi_ids[] = {
36ac23d3caSYasuaki Ishimatsu 	{ACPI_MOTHERBOARD_RESOURCE_HID, 0},
37658d439bSTaku Izumi 	{"", 0},
38658d439bSTaku Izumi };
39658d439bSTaku Izumi MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids);
40658d439bSTaku Izumi 
is_extended_socket_device(struct acpi_device * device)41ac23d3caSYasuaki Ishimatsu static bool is_extended_socket_device(struct acpi_device *device)
42658d439bSTaku Izumi {
43658d439bSTaku Izumi 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
44658d439bSTaku Izumi 	char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1];
45658d439bSTaku Izumi 	union acpi_object *str;
46658d439bSTaku Izumi 	acpi_status status;
47658d439bSTaku Izumi 	int result;
48658d439bSTaku Izumi 
49658d439bSTaku Izumi 	status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer);
50658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
51ac23d3caSYasuaki Ishimatsu 		return false;
52658d439bSTaku Izumi 
53658d439bSTaku Izumi 	str = buffer.pointer;
54658d439bSTaku Izumi 	result = utf16s_to_utf8s((wchar_t *)str->string.pointer,
55658d439bSTaku Izumi 				 str->string.length, UTF16_LITTLE_ENDIAN,
56658d439bSTaku Izumi 				 str_buf, sizeof(str_buf) - 1);
57658d439bSTaku Izumi 	str_buf[result] = 0;
58658d439bSTaku Izumi 
59658d439bSTaku Izumi 	if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) {
60658d439bSTaku Izumi 		kfree(buffer.pointer);
61ac23d3caSYasuaki Ishimatsu 		return false;
62658d439bSTaku Izumi 	}
63658d439bSTaku Izumi 	kfree(buffer.pointer);
64658d439bSTaku Izumi 
65ac23d3caSYasuaki Ishimatsu 	return true;
66ac23d3caSYasuaki Ishimatsu }
67ac23d3caSYasuaki Ishimatsu 
acpi_check_extended_socket_status(struct acpi_device * device)682b396d30SYasuaki Ishimatsu static int acpi_check_extended_socket_status(struct acpi_device *device)
692b396d30SYasuaki Ishimatsu {
702b396d30SYasuaki Ishimatsu 	unsigned long long sta;
712b396d30SYasuaki Ishimatsu 	acpi_status status;
722b396d30SYasuaki Ishimatsu 
732b396d30SYasuaki Ishimatsu 	status = acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
742b396d30SYasuaki Ishimatsu 	if (ACPI_FAILURE(status))
752b396d30SYasuaki Ishimatsu 		return -ENODEV;
762b396d30SYasuaki Ishimatsu 
772b396d30SYasuaki Ishimatsu 	if (!((sta & ACPI_STA_DEVICE_PRESENT) &&
782b396d30SYasuaki Ishimatsu 	      (sta & ACPI_STA_DEVICE_ENABLED) &&
792b396d30SYasuaki Ishimatsu 	      (sta & ACPI_STA_DEVICE_UI) &&
802b396d30SYasuaki Ishimatsu 	      (sta & ACPI_STA_DEVICE_FUNCTIONING)))
812b396d30SYasuaki Ishimatsu 		return -ENODEV;
822b396d30SYasuaki Ishimatsu 
832b396d30SYasuaki Ishimatsu 	return 0;
842b396d30SYasuaki Ishimatsu }
852b396d30SYasuaki Ishimatsu 
86fa2aee65SUwe Kleine-König static acpi_status
fjes_get_acpi_resource(struct acpi_resource * acpi_res,void * data)87fa2aee65SUwe Kleine-König fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
88fa2aee65SUwe Kleine-König {
89fa2aee65SUwe Kleine-König 	struct acpi_resource_address32 *addr;
90fa2aee65SUwe Kleine-König 	struct acpi_resource_irq *irq;
91fa2aee65SUwe Kleine-König 	struct resource *res = data;
92fa2aee65SUwe Kleine-König 
93fa2aee65SUwe Kleine-König 	switch (acpi_res->type) {
94fa2aee65SUwe Kleine-König 	case ACPI_RESOURCE_TYPE_ADDRESS32:
95fa2aee65SUwe Kleine-König 		addr = &acpi_res->data.address32;
96fa2aee65SUwe Kleine-König 		res[0].start = addr->address.minimum;
97fa2aee65SUwe Kleine-König 		res[0].end = addr->address.minimum +
98fa2aee65SUwe Kleine-König 			addr->address.address_length - 1;
99fa2aee65SUwe Kleine-König 		break;
100fa2aee65SUwe Kleine-König 
101fa2aee65SUwe Kleine-König 	case ACPI_RESOURCE_TYPE_IRQ:
102fa2aee65SUwe Kleine-König 		irq = &acpi_res->data.irq;
103fa2aee65SUwe Kleine-König 		if (irq->interrupt_count != 1)
104fa2aee65SUwe Kleine-König 			return AE_ERROR;
105fa2aee65SUwe Kleine-König 		res[1].start = irq->interrupts[0];
106fa2aee65SUwe Kleine-König 		res[1].end = irq->interrupts[0];
107fa2aee65SUwe Kleine-König 		break;
108fa2aee65SUwe Kleine-König 
109fa2aee65SUwe Kleine-König 	default:
110fa2aee65SUwe Kleine-König 		break;
111fa2aee65SUwe Kleine-König 	}
112fa2aee65SUwe Kleine-König 
113fa2aee65SUwe Kleine-König 	return AE_OK;
114fa2aee65SUwe Kleine-König }
115fa2aee65SUwe Kleine-König 
116fa2aee65SUwe Kleine-König static struct resource fjes_resource[] = {
117fa2aee65SUwe Kleine-König 	DEFINE_RES_MEM(0, 1),
118fa2aee65SUwe Kleine-König 	DEFINE_RES_IRQ(0)
119fa2aee65SUwe Kleine-König };
120fa2aee65SUwe Kleine-König 
fjes_acpi_add(struct acpi_device * device)121ac23d3caSYasuaki Ishimatsu static int fjes_acpi_add(struct acpi_device *device)
122ac23d3caSYasuaki Ishimatsu {
123ac23d3caSYasuaki Ishimatsu 	struct platform_device *plat_dev;
124ac23d3caSYasuaki Ishimatsu 	acpi_status status;
125ac23d3caSYasuaki Ishimatsu 
126ac23d3caSYasuaki Ishimatsu 	if (!is_extended_socket_device(device))
127ac23d3caSYasuaki Ishimatsu 		return -ENODEV;
128ac23d3caSYasuaki Ishimatsu 
1292b396d30SYasuaki Ishimatsu 	if (acpi_check_extended_socket_status(device))
1302b396d30SYasuaki Ishimatsu 		return -ENODEV;
1312b396d30SYasuaki Ishimatsu 
132658d439bSTaku Izumi 	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
133658d439bSTaku Izumi 				     fjes_get_acpi_resource, fjes_resource);
134658d439bSTaku Izumi 	if (ACPI_FAILURE(status))
135658d439bSTaku Izumi 		return -ENODEV;
136658d439bSTaku Izumi 
137658d439bSTaku Izumi 	/* create platform_device */
138658d439bSTaku Izumi 	plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
139658d439bSTaku Izumi 						   ARRAY_SIZE(fjes_resource));
140a288f105SChuhong Yuan 	if (IS_ERR(plat_dev))
141a288f105SChuhong Yuan 		return PTR_ERR(plat_dev);
142a288f105SChuhong Yuan 
143658d439bSTaku Izumi 	device->driver_data = plat_dev;
144658d439bSTaku Izumi 
145658d439bSTaku Izumi 	return 0;
146658d439bSTaku Izumi }
147658d439bSTaku Izumi 
fjes_acpi_remove(struct acpi_device * device)148*6c0eb5baSDawei Li static void fjes_acpi_remove(struct acpi_device *device)
149658d439bSTaku Izumi {
150658d439bSTaku Izumi 	struct platform_device *plat_dev;
151658d439bSTaku Izumi 
152658d439bSTaku Izumi 	plat_dev = (struct platform_device *)acpi_driver_data(device);
153658d439bSTaku Izumi 	platform_device_unregister(plat_dev);
154658d439bSTaku Izumi }
155658d439bSTaku Izumi 
156fa2aee65SUwe Kleine-König static struct acpi_driver fjes_acpi_driver = {
157fa2aee65SUwe Kleine-König 	.name = DRV_NAME,
158fa2aee65SUwe Kleine-König 	.class = DRV_NAME,
159fa2aee65SUwe Kleine-König 	.owner = THIS_MODULE,
160fa2aee65SUwe Kleine-König 	.ids = fjes_acpi_ids,
161fa2aee65SUwe Kleine-König 	.ops = {
162fa2aee65SUwe Kleine-König 		.add = fjes_acpi_add,
163fa2aee65SUwe Kleine-König 		.remove = fjes_acpi_remove,
164fa2aee65SUwe Kleine-König 	},
165fa2aee65SUwe Kleine-König };
166fa2aee65SUwe Kleine-König 
fjes_setup_resources(struct fjes_adapter * adapter)167fa2aee65SUwe Kleine-König static int fjes_setup_resources(struct fjes_adapter *adapter)
168658d439bSTaku Izumi {
169fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
170fa2aee65SUwe Kleine-König 	struct ep_share_mem_info *buf_pair;
171fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
172fa2aee65SUwe Kleine-König 	unsigned long flags;
173fa2aee65SUwe Kleine-König 	int result;
174fa2aee65SUwe Kleine-König 	int epidx;
175658d439bSTaku Izumi 
176fa2aee65SUwe Kleine-König 	mutex_lock(&hw->hw_info.lock);
177fa2aee65SUwe Kleine-König 	result = fjes_hw_request_info(hw);
178fa2aee65SUwe Kleine-König 	switch (result) {
179fa2aee65SUwe Kleine-König 	case 0:
180fa2aee65SUwe Kleine-König 		for (epidx = 0; epidx < hw->max_epid; epidx++) {
181fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epidx].es_status =
182fa2aee65SUwe Kleine-König 			    hw->hw_info.res_buf->info.info[epidx].es_status;
183fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epidx].zone =
184fa2aee65SUwe Kleine-König 			    hw->hw_info.res_buf->info.info[epidx].zone;
185fa2aee65SUwe Kleine-König 		}
186658d439bSTaku Izumi 		break;
187658d439bSTaku Izumi 	default:
188fa2aee65SUwe Kleine-König 	case -ENOMSG:
189fa2aee65SUwe Kleine-König 	case -EBUSY:
190fa2aee65SUwe Kleine-König 		adapter->force_reset = true;
191fa2aee65SUwe Kleine-König 
192fa2aee65SUwe Kleine-König 		mutex_unlock(&hw->hw_info.lock);
193fa2aee65SUwe Kleine-König 		return result;
194fa2aee65SUwe Kleine-König 	}
195fa2aee65SUwe Kleine-König 	mutex_unlock(&hw->hw_info.lock);
196fa2aee65SUwe Kleine-König 
197fa2aee65SUwe Kleine-König 	for (epidx = 0; epidx < (hw->max_epid); epidx++) {
198fa2aee65SUwe Kleine-König 		if ((epidx != hw->my_epid) &&
199fa2aee65SUwe Kleine-König 		    (hw->ep_shm_info[epidx].es_status ==
200fa2aee65SUwe Kleine-König 		     FJES_ZONING_STATUS_ENABLE)) {
201fa2aee65SUwe Kleine-König 			fjes_hw_raise_interrupt(hw, epidx,
202fa2aee65SUwe Kleine-König 						REG_ICTL_MASK_INFO_UPDATE);
203fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epidx].ep_stats
204fa2aee65SUwe Kleine-König 				.send_intr_zoneupdate += 1;
205fa2aee65SUwe Kleine-König 		}
206658d439bSTaku Izumi 	}
207658d439bSTaku Izumi 
208fa2aee65SUwe Kleine-König 	msleep(FJES_OPEN_ZONE_UPDATE_WAIT * hw->max_epid);
209fa2aee65SUwe Kleine-König 
210fa2aee65SUwe Kleine-König 	for (epidx = 0; epidx < (hw->max_epid); epidx++) {
211fa2aee65SUwe Kleine-König 		if (epidx == hw->my_epid)
212fa2aee65SUwe Kleine-König 			continue;
213fa2aee65SUwe Kleine-König 
214fa2aee65SUwe Kleine-König 		buf_pair = &hw->ep_shm_info[epidx];
215fa2aee65SUwe Kleine-König 
216fa2aee65SUwe Kleine-König 		spin_lock_irqsave(&hw->rx_status_lock, flags);
217fa2aee65SUwe Kleine-König 		fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr,
218fa2aee65SUwe Kleine-König 				    netdev->mtu);
219fa2aee65SUwe Kleine-König 		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
220fa2aee65SUwe Kleine-König 
221fa2aee65SUwe Kleine-König 		if (fjes_hw_epid_is_same_zone(hw, epidx)) {
222fa2aee65SUwe Kleine-König 			mutex_lock(&hw->hw_info.lock);
223fa2aee65SUwe Kleine-König 			result =
224fa2aee65SUwe Kleine-König 			fjes_hw_register_buff_addr(hw, epidx, buf_pair);
225fa2aee65SUwe Kleine-König 			mutex_unlock(&hw->hw_info.lock);
226fa2aee65SUwe Kleine-König 
227fa2aee65SUwe Kleine-König 			switch (result) {
228fa2aee65SUwe Kleine-König 			case 0:
229fa2aee65SUwe Kleine-König 				break;
230fa2aee65SUwe Kleine-König 			case -ENOMSG:
231fa2aee65SUwe Kleine-König 			case -EBUSY:
232fa2aee65SUwe Kleine-König 			default:
233fa2aee65SUwe Kleine-König 				adapter->force_reset = true;
234fa2aee65SUwe Kleine-König 				return result;
235fa2aee65SUwe Kleine-König 			}
236fa2aee65SUwe Kleine-König 
237fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epidx].ep_stats
238fa2aee65SUwe Kleine-König 				.com_regist_buf_exec += 1;
239fa2aee65SUwe Kleine-König 		}
240fa2aee65SUwe Kleine-König 	}
241fa2aee65SUwe Kleine-König 
242fa2aee65SUwe Kleine-König 	return 0;
243fa2aee65SUwe Kleine-König }
244fa2aee65SUwe Kleine-König 
fjes_rx_irq(struct fjes_adapter * adapter,int src_epid)245fa2aee65SUwe Kleine-König static void fjes_rx_irq(struct fjes_adapter *adapter, int src_epid)
246fa2aee65SUwe Kleine-König {
247fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
248fa2aee65SUwe Kleine-König 
249fa2aee65SUwe Kleine-König 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, true);
250fa2aee65SUwe Kleine-König 
251fa2aee65SUwe Kleine-König 	adapter->unset_rx_last = true;
252fa2aee65SUwe Kleine-König 	napi_schedule(&adapter->napi);
253fa2aee65SUwe Kleine-König }
254fa2aee65SUwe Kleine-König 
fjes_stop_req_irq(struct fjes_adapter * adapter,int src_epid)255fa2aee65SUwe Kleine-König static void fjes_stop_req_irq(struct fjes_adapter *adapter, int src_epid)
256fa2aee65SUwe Kleine-König {
257fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
258fa2aee65SUwe Kleine-König 	enum ep_partner_status status;
259fa2aee65SUwe Kleine-König 	unsigned long flags;
260fa2aee65SUwe Kleine-König 
261fa2aee65SUwe Kleine-König 	set_bit(src_epid, &hw->hw_info.buffer_unshare_reserve_bit);
262fa2aee65SUwe Kleine-König 
263fa2aee65SUwe Kleine-König 	status = fjes_hw_get_partner_ep_status(hw, src_epid);
264fa2aee65SUwe Kleine-König 	trace_fjes_stop_req_irq_pre(hw, src_epid, status);
265fa2aee65SUwe Kleine-König 	switch (status) {
266fa2aee65SUwe Kleine-König 	case EP_PARTNER_WAITING:
267fa2aee65SUwe Kleine-König 		spin_lock_irqsave(&hw->rx_status_lock, flags);
268fa2aee65SUwe Kleine-König 		hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |=
269fa2aee65SUwe Kleine-König 				FJES_RX_STOP_REQ_DONE;
270fa2aee65SUwe Kleine-König 		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
271fa2aee65SUwe Kleine-König 		clear_bit(src_epid, &hw->txrx_stop_req_bit);
272fa2aee65SUwe Kleine-König 		fallthrough;
273fa2aee65SUwe Kleine-König 	case EP_PARTNER_UNSHARE:
274fa2aee65SUwe Kleine-König 	case EP_PARTNER_COMPLETE:
275fa2aee65SUwe Kleine-König 	default:
276fa2aee65SUwe Kleine-König 		set_bit(src_epid, &adapter->unshare_watch_bitmask);
277fa2aee65SUwe Kleine-König 		if (!work_pending(&adapter->unshare_watch_task))
278fa2aee65SUwe Kleine-König 			queue_work(adapter->control_wq,
279fa2aee65SUwe Kleine-König 				   &adapter->unshare_watch_task);
280fa2aee65SUwe Kleine-König 		break;
281fa2aee65SUwe Kleine-König 	case EP_PARTNER_SHARED:
282fa2aee65SUwe Kleine-König 		set_bit(src_epid, &hw->epstop_req_bit);
283fa2aee65SUwe Kleine-König 
284fa2aee65SUwe Kleine-König 		if (!work_pending(&hw->epstop_task))
285fa2aee65SUwe Kleine-König 			queue_work(adapter->control_wq, &hw->epstop_task);
286fa2aee65SUwe Kleine-König 		break;
287fa2aee65SUwe Kleine-König 	}
288fa2aee65SUwe Kleine-König 	trace_fjes_stop_req_irq_post(hw, src_epid);
289fa2aee65SUwe Kleine-König }
290fa2aee65SUwe Kleine-König 
fjes_txrx_stop_req_irq(struct fjes_adapter * adapter,int src_epid)291fa2aee65SUwe Kleine-König static void fjes_txrx_stop_req_irq(struct fjes_adapter *adapter,
292fa2aee65SUwe Kleine-König 				   int src_epid)
293fa2aee65SUwe Kleine-König {
294fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
295fa2aee65SUwe Kleine-König 	enum ep_partner_status status;
296fa2aee65SUwe Kleine-König 	unsigned long flags;
297fa2aee65SUwe Kleine-König 
298fa2aee65SUwe Kleine-König 	status = fjes_hw_get_partner_ep_status(hw, src_epid);
299fa2aee65SUwe Kleine-König 	trace_fjes_txrx_stop_req_irq_pre(hw, src_epid, status);
300fa2aee65SUwe Kleine-König 	switch (status) {
301fa2aee65SUwe Kleine-König 	case EP_PARTNER_UNSHARE:
302fa2aee65SUwe Kleine-König 	case EP_PARTNER_COMPLETE:
303fa2aee65SUwe Kleine-König 	default:
304fa2aee65SUwe Kleine-König 		break;
305fa2aee65SUwe Kleine-König 	case EP_PARTNER_WAITING:
306fa2aee65SUwe Kleine-König 		if (src_epid < hw->my_epid) {
307fa2aee65SUwe Kleine-König 			spin_lock_irqsave(&hw->rx_status_lock, flags);
308fa2aee65SUwe Kleine-König 			hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |=
309fa2aee65SUwe Kleine-König 				FJES_RX_STOP_REQ_DONE;
310fa2aee65SUwe Kleine-König 			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
311fa2aee65SUwe Kleine-König 
312fa2aee65SUwe Kleine-König 			clear_bit(src_epid, &hw->txrx_stop_req_bit);
313fa2aee65SUwe Kleine-König 			set_bit(src_epid, &adapter->unshare_watch_bitmask);
314fa2aee65SUwe Kleine-König 
315fa2aee65SUwe Kleine-König 			if (!work_pending(&adapter->unshare_watch_task))
316fa2aee65SUwe Kleine-König 				queue_work(adapter->control_wq,
317fa2aee65SUwe Kleine-König 					   &adapter->unshare_watch_task);
318fa2aee65SUwe Kleine-König 		}
319fa2aee65SUwe Kleine-König 		break;
320fa2aee65SUwe Kleine-König 	case EP_PARTNER_SHARED:
321fa2aee65SUwe Kleine-König 		if (hw->ep_shm_info[src_epid].rx.info->v1i.rx_status &
322fa2aee65SUwe Kleine-König 		    FJES_RX_STOP_REQ_REQUEST) {
323fa2aee65SUwe Kleine-König 			set_bit(src_epid, &hw->epstop_req_bit);
324fa2aee65SUwe Kleine-König 			if (!work_pending(&hw->epstop_task))
325fa2aee65SUwe Kleine-König 				queue_work(adapter->control_wq,
326fa2aee65SUwe Kleine-König 					   &hw->epstop_task);
327fa2aee65SUwe Kleine-König 		}
328fa2aee65SUwe Kleine-König 		break;
329fa2aee65SUwe Kleine-König 	}
330fa2aee65SUwe Kleine-König 	trace_fjes_txrx_stop_req_irq_post(hw, src_epid);
331fa2aee65SUwe Kleine-König }
332fa2aee65SUwe Kleine-König 
fjes_update_zone_irq(struct fjes_adapter * adapter,int src_epid)333fa2aee65SUwe Kleine-König static void fjes_update_zone_irq(struct fjes_adapter *adapter,
334fa2aee65SUwe Kleine-König 				 int src_epid)
335fa2aee65SUwe Kleine-König {
336fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
337fa2aee65SUwe Kleine-König 
338fa2aee65SUwe Kleine-König 	if (!work_pending(&hw->update_zone_task))
339fa2aee65SUwe Kleine-König 		queue_work(adapter->control_wq, &hw->update_zone_task);
340fa2aee65SUwe Kleine-König }
341fa2aee65SUwe Kleine-König 
fjes_intr(int irq,void * data)342fa2aee65SUwe Kleine-König static irqreturn_t fjes_intr(int irq, void *data)
343fa2aee65SUwe Kleine-König {
344fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter = data;
345fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
346fa2aee65SUwe Kleine-König 	irqreturn_t ret;
347fa2aee65SUwe Kleine-König 	u32 icr;
348fa2aee65SUwe Kleine-König 
349fa2aee65SUwe Kleine-König 	icr = fjes_hw_capture_interrupt_status(hw);
350fa2aee65SUwe Kleine-König 
351fa2aee65SUwe Kleine-König 	if (icr & REG_IS_MASK_IS_ASSERT) {
352fa2aee65SUwe Kleine-König 		if (icr & REG_ICTL_MASK_RX_DATA) {
353fa2aee65SUwe Kleine-König 			fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID);
354fa2aee65SUwe Kleine-König 			hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats
355fa2aee65SUwe Kleine-König 				.recv_intr_rx += 1;
356fa2aee65SUwe Kleine-König 		}
357fa2aee65SUwe Kleine-König 
358fa2aee65SUwe Kleine-König 		if (icr & REG_ICTL_MASK_DEV_STOP_REQ) {
359fa2aee65SUwe Kleine-König 			fjes_stop_req_irq(adapter, icr & REG_IS_MASK_EPID);
360fa2aee65SUwe Kleine-König 			hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats
361fa2aee65SUwe Kleine-König 				.recv_intr_stop += 1;
362fa2aee65SUwe Kleine-König 		}
363fa2aee65SUwe Kleine-König 
364fa2aee65SUwe Kleine-König 		if (icr & REG_ICTL_MASK_TXRX_STOP_REQ) {
365fa2aee65SUwe Kleine-König 			fjes_txrx_stop_req_irq(adapter, icr & REG_IS_MASK_EPID);
366fa2aee65SUwe Kleine-König 			hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats
367fa2aee65SUwe Kleine-König 				.recv_intr_unshare += 1;
368fa2aee65SUwe Kleine-König 		}
369fa2aee65SUwe Kleine-König 
370fa2aee65SUwe Kleine-König 		if (icr & REG_ICTL_MASK_TXRX_STOP_DONE)
371fa2aee65SUwe Kleine-König 			fjes_hw_set_irqmask(hw,
372fa2aee65SUwe Kleine-König 					    REG_ICTL_MASK_TXRX_STOP_DONE, true);
373fa2aee65SUwe Kleine-König 
374fa2aee65SUwe Kleine-König 		if (icr & REG_ICTL_MASK_INFO_UPDATE) {
375fa2aee65SUwe Kleine-König 			fjes_update_zone_irq(adapter, icr & REG_IS_MASK_EPID);
376fa2aee65SUwe Kleine-König 			hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats
377fa2aee65SUwe Kleine-König 				.recv_intr_zoneupdate += 1;
378fa2aee65SUwe Kleine-König 		}
379fa2aee65SUwe Kleine-König 
380fa2aee65SUwe Kleine-König 		ret = IRQ_HANDLED;
381fa2aee65SUwe Kleine-König 	} else {
382fa2aee65SUwe Kleine-König 		ret = IRQ_NONE;
383fa2aee65SUwe Kleine-König 	}
384fa2aee65SUwe Kleine-König 
385fa2aee65SUwe Kleine-König 	return ret;
386658d439bSTaku Izumi }
387658d439bSTaku Izumi 
fjes_request_irq(struct fjes_adapter * adapter)388e5d486dcSTaku Izumi static int fjes_request_irq(struct fjes_adapter *adapter)
389e5d486dcSTaku Izumi {
390e5d486dcSTaku Izumi 	struct net_device *netdev = adapter->netdev;
391e5d486dcSTaku Izumi 	int result = -1;
392e5d486dcSTaku Izumi 
3938edb62a8STaku Izumi 	adapter->interrupt_watch_enable = true;
3948edb62a8STaku Izumi 	if (!delayed_work_pending(&adapter->interrupt_watch_task)) {
3958edb62a8STaku Izumi 		queue_delayed_work(adapter->control_wq,
3968edb62a8STaku Izumi 				   &adapter->interrupt_watch_task,
3978edb62a8STaku Izumi 				   FJES_IRQ_WATCH_DELAY);
3988edb62a8STaku Izumi 	}
3998edb62a8STaku Izumi 
400e5d486dcSTaku Izumi 	if (!adapter->irq_registered) {
401e5d486dcSTaku Izumi 		result = request_irq(adapter->hw.hw_res.irq, fjes_intr,
402e5d486dcSTaku Izumi 				     IRQF_SHARED, netdev->name, adapter);
403e5d486dcSTaku Izumi 		if (result)
404e5d486dcSTaku Izumi 			adapter->irq_registered = false;
405e5d486dcSTaku Izumi 		else
406e5d486dcSTaku Izumi 			adapter->irq_registered = true;
407e5d486dcSTaku Izumi 	}
408e5d486dcSTaku Izumi 
409e5d486dcSTaku Izumi 	return result;
410e5d486dcSTaku Izumi }
411e5d486dcSTaku Izumi 
fjes_free_irq(struct fjes_adapter * adapter)412e5d486dcSTaku Izumi static void fjes_free_irq(struct fjes_adapter *adapter)
413e5d486dcSTaku Izumi {
414e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
415e5d486dcSTaku Izumi 
4168edb62a8STaku Izumi 	adapter->interrupt_watch_enable = false;
4178edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
4188edb62a8STaku Izumi 
419e5d486dcSTaku Izumi 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);
420e5d486dcSTaku Izumi 
421e5d486dcSTaku Izumi 	if (adapter->irq_registered) {
422e5d486dcSTaku Izumi 		free_irq(adapter->hw.hw_res.irq, adapter);
423e5d486dcSTaku Izumi 		adapter->irq_registered = false;
424e5d486dcSTaku Izumi 	}
425e5d486dcSTaku Izumi }
426e5d486dcSTaku Izumi 
fjes_free_resources(struct fjes_adapter * adapter)427fa2aee65SUwe Kleine-König static void fjes_free_resources(struct fjes_adapter *adapter)
428fa2aee65SUwe Kleine-König {
429fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
430fa2aee65SUwe Kleine-König 	struct fjes_device_command_param param;
431fa2aee65SUwe Kleine-König 	struct ep_share_mem_info *buf_pair;
432fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
433fa2aee65SUwe Kleine-König 	bool reset_flag = false;
434fa2aee65SUwe Kleine-König 	unsigned long flags;
435fa2aee65SUwe Kleine-König 	int result;
436fa2aee65SUwe Kleine-König 	int epidx;
437fa2aee65SUwe Kleine-König 
438fa2aee65SUwe Kleine-König 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
439fa2aee65SUwe Kleine-König 		if (epidx == hw->my_epid)
440fa2aee65SUwe Kleine-König 			continue;
441fa2aee65SUwe Kleine-König 
442fa2aee65SUwe Kleine-König 		mutex_lock(&hw->hw_info.lock);
443fa2aee65SUwe Kleine-König 		result = fjes_hw_unregister_buff_addr(hw, epidx);
444fa2aee65SUwe Kleine-König 		mutex_unlock(&hw->hw_info.lock);
445fa2aee65SUwe Kleine-König 
446fa2aee65SUwe Kleine-König 		hw->ep_shm_info[epidx].ep_stats.com_unregist_buf_exec += 1;
447fa2aee65SUwe Kleine-König 
448fa2aee65SUwe Kleine-König 		if (result)
449fa2aee65SUwe Kleine-König 			reset_flag = true;
450fa2aee65SUwe Kleine-König 
451fa2aee65SUwe Kleine-König 		buf_pair = &hw->ep_shm_info[epidx];
452fa2aee65SUwe Kleine-König 
453fa2aee65SUwe Kleine-König 		spin_lock_irqsave(&hw->rx_status_lock, flags);
454fa2aee65SUwe Kleine-König 		fjes_hw_setup_epbuf(&buf_pair->tx,
455fa2aee65SUwe Kleine-König 				    netdev->dev_addr, netdev->mtu);
456fa2aee65SUwe Kleine-König 		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
457fa2aee65SUwe Kleine-König 
458fa2aee65SUwe Kleine-König 		clear_bit(epidx, &hw->txrx_stop_req_bit);
459fa2aee65SUwe Kleine-König 	}
460fa2aee65SUwe Kleine-König 
461fa2aee65SUwe Kleine-König 	if (reset_flag || adapter->force_reset) {
462fa2aee65SUwe Kleine-König 		result = fjes_hw_reset(hw);
463fa2aee65SUwe Kleine-König 
464fa2aee65SUwe Kleine-König 		adapter->force_reset = false;
465fa2aee65SUwe Kleine-König 
466fa2aee65SUwe Kleine-König 		if (result)
467fa2aee65SUwe Kleine-König 			adapter->open_guard = true;
468fa2aee65SUwe Kleine-König 
469fa2aee65SUwe Kleine-König 		hw->hw_info.buffer_share_bit = 0;
470fa2aee65SUwe Kleine-König 
471fa2aee65SUwe Kleine-König 		memset((void *)&param, 0, sizeof(param));
472fa2aee65SUwe Kleine-König 
473fa2aee65SUwe Kleine-König 		param.req_len = hw->hw_info.req_buf_size;
474fa2aee65SUwe Kleine-König 		param.req_start = __pa(hw->hw_info.req_buf);
475fa2aee65SUwe Kleine-König 		param.res_len = hw->hw_info.res_buf_size;
476fa2aee65SUwe Kleine-König 		param.res_start = __pa(hw->hw_info.res_buf);
477fa2aee65SUwe Kleine-König 		param.share_start = __pa(hw->hw_info.share->ep_status);
478fa2aee65SUwe Kleine-König 
479fa2aee65SUwe Kleine-König 		fjes_hw_init_command_registers(hw, &param);
480fa2aee65SUwe Kleine-König 	}
481fa2aee65SUwe Kleine-König }
4822fcbca68STaku Izumi 
483e5d486dcSTaku Izumi /* fjes_open - Called when a network interface is made active */
fjes_open(struct net_device * netdev)484e5d486dcSTaku Izumi static int fjes_open(struct net_device *netdev)
485e5d486dcSTaku Izumi {
486e5d486dcSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
487e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
488e5d486dcSTaku Izumi 	int result;
489e5d486dcSTaku Izumi 
490e5d486dcSTaku Izumi 	if (adapter->open_guard)
491e5d486dcSTaku Izumi 		return -ENXIO;
492e5d486dcSTaku Izumi 
493e5d486dcSTaku Izumi 	result = fjes_setup_resources(adapter);
494e5d486dcSTaku Izumi 	if (result)
495e5d486dcSTaku Izumi 		goto err_setup_res;
496e5d486dcSTaku Izumi 
497e5d486dcSTaku Izumi 	hw->txrx_stop_req_bit = 0;
498e5d486dcSTaku Izumi 	hw->epstop_req_bit = 0;
499e5d486dcSTaku Izumi 
50026585930STaku Izumi 	napi_enable(&adapter->napi);
50126585930STaku Izumi 
502e5d486dcSTaku Izumi 	fjes_hw_capture_interrupt_status(hw);
503e5d486dcSTaku Izumi 
504e5d486dcSTaku Izumi 	result = fjes_request_irq(adapter);
505e5d486dcSTaku Izumi 	if (result)
506e5d486dcSTaku Izumi 		goto err_req_irq;
507e5d486dcSTaku Izumi 
508e5d486dcSTaku Izumi 	fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, false);
509e5d486dcSTaku Izumi 
510e5d486dcSTaku Izumi 	netif_tx_start_all_queues(netdev);
511e5d486dcSTaku Izumi 	netif_carrier_on(netdev);
512e5d486dcSTaku Izumi 
513e5d486dcSTaku Izumi 	return 0;
514e5d486dcSTaku Izumi 
515e5d486dcSTaku Izumi err_req_irq:
516e5d486dcSTaku Izumi 	fjes_free_irq(adapter);
51726585930STaku Izumi 	napi_disable(&adapter->napi);
518e5d486dcSTaku Izumi 
519e5d486dcSTaku Izumi err_setup_res:
520e5d486dcSTaku Izumi 	fjes_free_resources(adapter);
521e5d486dcSTaku Izumi 	return result;
522e5d486dcSTaku Izumi }
523e5d486dcSTaku Izumi 
524e5d486dcSTaku Izumi /* fjes_close - Disables a network interface */
fjes_close(struct net_device * netdev)525e5d486dcSTaku Izumi static int fjes_close(struct net_device *netdev)
526e5d486dcSTaku Izumi {
527e5d486dcSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
528e5d486dcSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
529bd5a2569STaku Izumi 	unsigned long flags;
530e5d486dcSTaku Izumi 	int epidx;
531e5d486dcSTaku Izumi 
532e5d486dcSTaku Izumi 	netif_tx_stop_all_queues(netdev);
533e5d486dcSTaku Izumi 	netif_carrier_off(netdev);
534e5d486dcSTaku Izumi 
535e5d486dcSTaku Izumi 	fjes_hw_raise_epstop(hw);
536e5d486dcSTaku Izumi 
53726585930STaku Izumi 	napi_disable(&adapter->napi);
53826585930STaku Izumi 
539bd5a2569STaku Izumi 	spin_lock_irqsave(&hw->rx_status_lock, flags);
540e5d486dcSTaku Izumi 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
541e5d486dcSTaku Izumi 		if (epidx == hw->my_epid)
542e5d486dcSTaku Izumi 			continue;
543e5d486dcSTaku Izumi 
544bd5a2569STaku Izumi 		if (fjes_hw_get_partner_ep_status(hw, epidx) ==
545bd5a2569STaku Izumi 		    EP_PARTNER_SHARED)
546bd5a2569STaku Izumi 			adapter->hw.ep_shm_info[epidx]
547bd5a2569STaku Izumi 				   .tx.info->v1i.rx_status &=
548e5d486dcSTaku Izumi 				~FJES_RX_POLL_WORK;
549e5d486dcSTaku Izumi 	}
550bd5a2569STaku Izumi 	spin_unlock_irqrestore(&hw->rx_status_lock, flags);
551e5d486dcSTaku Izumi 
552e5d486dcSTaku Izumi 	fjes_free_irq(adapter);
553e5d486dcSTaku Izumi 
5548edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
5558fc4cadbSTaku Izumi 	cancel_work_sync(&adapter->unshare_watch_task);
5568fc4cadbSTaku Izumi 	adapter->unshare_watch_bitmask = 0;
557b772b9dcSTaku Izumi 	cancel_work_sync(&adapter->raise_intr_rxdata_task);
558ac63b947STaku Izumi 	cancel_work_sync(&adapter->tx_stall_task);
559b772b9dcSTaku Izumi 
560785f28e0STaku Izumi 	cancel_work_sync(&hw->update_zone_task);
561b5a9152dSTaku Izumi 	cancel_work_sync(&hw->epstop_task);
562785f28e0STaku Izumi 
563e5d486dcSTaku Izumi 	fjes_hw_wait_epstop(hw);
564e5d486dcSTaku Izumi 
565e5d486dcSTaku Izumi 	fjes_free_resources(adapter);
566e5d486dcSTaku Izumi 
567e5d486dcSTaku Izumi 	return 0;
568e5d486dcSTaku Izumi }
569e5d486dcSTaku Izumi 
fjes_tx_send(struct fjes_adapter * adapter,int dest,void * data,size_t len)5709acf51cbSTaku Izumi static int fjes_tx_send(struct fjes_adapter *adapter, int dest,
5719acf51cbSTaku Izumi 			void *data, size_t len)
5729acf51cbSTaku Izumi {
5739acf51cbSTaku Izumi 	int retval;
5749acf51cbSTaku Izumi 
5759acf51cbSTaku Izumi 	retval = fjes_hw_epbuf_tx_pkt_send(&adapter->hw.ep_shm_info[dest].tx,
5769acf51cbSTaku Izumi 					   data, len);
5779acf51cbSTaku Izumi 	if (retval)
5789acf51cbSTaku Izumi 		return retval;
5799acf51cbSTaku Izumi 
5809acf51cbSTaku Izumi 	adapter->hw.ep_shm_info[dest].tx.info->v1i.tx_status =
5819acf51cbSTaku Izumi 		FJES_TX_DELAY_SEND_PENDING;
582b772b9dcSTaku Izumi 	if (!work_pending(&adapter->raise_intr_rxdata_task))
583b772b9dcSTaku Izumi 		queue_work(adapter->txrx_wq,
584b772b9dcSTaku Izumi 			   &adapter->raise_intr_rxdata_task);
5859acf51cbSTaku Izumi 
5869acf51cbSTaku Izumi 	retval = 0;
5879acf51cbSTaku Izumi 	return retval;
5889acf51cbSTaku Izumi }
5899acf51cbSTaku Izumi 
5909acf51cbSTaku Izumi static netdev_tx_t
fjes_xmit_frame(struct sk_buff * skb,struct net_device * netdev)5919acf51cbSTaku Izumi fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
5929acf51cbSTaku Izumi {
5939acf51cbSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
5949acf51cbSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
5959acf51cbSTaku Izumi 
5969acf51cbSTaku Izumi 	int max_epid, my_epid, dest_epid;
5979acf51cbSTaku Izumi 	enum ep_partner_status pstatus;
5989acf51cbSTaku Izumi 	struct netdev_queue *cur_queue;
5999acf51cbSTaku Izumi 	char shortpkt[VLAN_ETH_HLEN];
6009acf51cbSTaku Izumi 	bool is_multi, vlan;
6019acf51cbSTaku Izumi 	struct ethhdr *eth;
6029acf51cbSTaku Izumi 	u16 queue_no = 0;
6039acf51cbSTaku Izumi 	u16 vlan_id = 0;
6049acf51cbSTaku Izumi 	netdev_tx_t ret;
6059acf51cbSTaku Izumi 	char *data;
6069acf51cbSTaku Izumi 	int len;
6079acf51cbSTaku Izumi 
6089acf51cbSTaku Izumi 	ret = NETDEV_TX_OK;
6099acf51cbSTaku Izumi 	is_multi = false;
6109acf51cbSTaku Izumi 	cur_queue = netdev_get_tx_queue(netdev, queue_no);
6119acf51cbSTaku Izumi 
6129acf51cbSTaku Izumi 	eth = (struct ethhdr *)skb->data;
6139acf51cbSTaku Izumi 	my_epid = hw->my_epid;
6149acf51cbSTaku Izumi 
6159acf51cbSTaku Izumi 	vlan = (vlan_get_tag(skb, &vlan_id) == 0) ? true : false;
6169acf51cbSTaku Izumi 
6179acf51cbSTaku Izumi 	data = skb->data;
6189acf51cbSTaku Izumi 	len = skb->len;
6199acf51cbSTaku Izumi 
6209acf51cbSTaku Izumi 	if (is_multicast_ether_addr(eth->h_dest)) {
6219acf51cbSTaku Izumi 		dest_epid = 0;
6229acf51cbSTaku Izumi 		max_epid = hw->max_epid;
6239acf51cbSTaku Izumi 		is_multi = true;
6249acf51cbSTaku Izumi 	} else if (is_local_ether_addr(eth->h_dest)) {
6259acf51cbSTaku Izumi 		dest_epid = eth->h_dest[ETH_ALEN - 1];
6269acf51cbSTaku Izumi 		max_epid = dest_epid + 1;
6279acf51cbSTaku Izumi 
6289acf51cbSTaku Izumi 		if ((eth->h_dest[0] == 0x02) &&
6299acf51cbSTaku Izumi 		    (0x00 == (eth->h_dest[1] | eth->h_dest[2] |
6309acf51cbSTaku Izumi 			      eth->h_dest[3] | eth->h_dest[4])) &&
6319acf51cbSTaku Izumi 		    (dest_epid < hw->max_epid)) {
6329acf51cbSTaku Izumi 			;
6339acf51cbSTaku Izumi 		} else {
6349acf51cbSTaku Izumi 			dest_epid = 0;
6359acf51cbSTaku Izumi 			max_epid = 0;
6369acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6379acf51cbSTaku Izumi 
6389acf51cbSTaku Izumi 			adapter->stats64.tx_packets += 1;
6399acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
6409acf51cbSTaku Izumi 			adapter->stats64.tx_bytes += len;
6419acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
6429acf51cbSTaku Izumi 		}
6439acf51cbSTaku Izumi 	} else {
6449acf51cbSTaku Izumi 		dest_epid = 0;
6459acf51cbSTaku Izumi 		max_epid = 0;
6469acf51cbSTaku Izumi 		ret = NETDEV_TX_OK;
6479acf51cbSTaku Izumi 
6489acf51cbSTaku Izumi 		adapter->stats64.tx_packets += 1;
6499acf51cbSTaku Izumi 		hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
6509acf51cbSTaku Izumi 		adapter->stats64.tx_bytes += len;
6519acf51cbSTaku Izumi 		hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
6529acf51cbSTaku Izumi 	}
6539acf51cbSTaku Izumi 
6549acf51cbSTaku Izumi 	for (; dest_epid < max_epid; dest_epid++) {
6559acf51cbSTaku Izumi 		if (my_epid == dest_epid)
6569acf51cbSTaku Izumi 			continue;
6579acf51cbSTaku Izumi 
6589acf51cbSTaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, dest_epid);
6599acf51cbSTaku Izumi 		if (pstatus != EP_PARTNER_SHARED) {
66021b7efbcSTaku Izumi 			if (!is_multi)
66121b7efbcSTaku Izumi 				hw->ep_shm_info[dest_epid].ep_stats
66221b7efbcSTaku Izumi 					.tx_dropped_not_shared += 1;
6639acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6649acf51cbSTaku Izumi 		} else if (!fjes_hw_check_epbuf_version(
6659acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx, 0)) {
6669acf51cbSTaku Izumi 			/* version is NOT 0 */
6679acf51cbSTaku Izumi 			adapter->stats64.tx_carrier_errors += 1;
6683c3bd4a9STaku Izumi 			hw->ep_shm_info[dest_epid].net_stats
6699acf51cbSTaku Izumi 						.tx_carrier_errors += 1;
67021b7efbcSTaku Izumi 			hw->ep_shm_info[dest_epid].ep_stats
67121b7efbcSTaku Izumi 					.tx_dropped_ver_mismatch += 1;
6729acf51cbSTaku Izumi 
6739acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6749acf51cbSTaku Izumi 		} else if (!fjes_hw_check_mtu(
6759acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx,
6769acf51cbSTaku Izumi 				netdev->mtu)) {
6779acf51cbSTaku Izumi 			adapter->stats64.tx_dropped += 1;
6783c3bd4a9STaku Izumi 			hw->ep_shm_info[dest_epid].net_stats.tx_dropped += 1;
6799acf51cbSTaku Izumi 			adapter->stats64.tx_errors += 1;
6803c3bd4a9STaku Izumi 			hw->ep_shm_info[dest_epid].net_stats.tx_errors += 1;
68121b7efbcSTaku Izumi 			hw->ep_shm_info[dest_epid].ep_stats
68221b7efbcSTaku Izumi 					.tx_dropped_buf_size_mismatch += 1;
6839acf51cbSTaku Izumi 
6849acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6859acf51cbSTaku Izumi 		} else if (vlan &&
6869acf51cbSTaku Izumi 			   !fjes_hw_check_vlan_id(
6879acf51cbSTaku Izumi 				&adapter->hw.ep_shm_info[dest_epid].rx,
6889acf51cbSTaku Izumi 				vlan_id)) {
68921b7efbcSTaku Izumi 			hw->ep_shm_info[dest_epid].ep_stats
69021b7efbcSTaku Izumi 				.tx_dropped_vlanid_mismatch += 1;
6919acf51cbSTaku Izumi 			ret = NETDEV_TX_OK;
6929acf51cbSTaku Izumi 		} else {
6939acf51cbSTaku Izumi 			if (len < VLAN_ETH_HLEN) {
6949acf51cbSTaku Izumi 				memset(shortpkt, 0, VLAN_ETH_HLEN);
6959acf51cbSTaku Izumi 				memcpy(shortpkt, skb->data, skb->len);
6969acf51cbSTaku Izumi 				len = VLAN_ETH_HLEN;
6979acf51cbSTaku Izumi 				data = shortpkt;
6989acf51cbSTaku Izumi 			}
6999acf51cbSTaku Izumi 
7009acf51cbSTaku Izumi 			if (adapter->tx_retry_count == 0) {
7019acf51cbSTaku Izumi 				adapter->tx_start_jiffies = jiffies;
7029acf51cbSTaku Izumi 				adapter->tx_retry_count = 1;
7039acf51cbSTaku Izumi 			} else {
7049acf51cbSTaku Izumi 				adapter->tx_retry_count++;
7059acf51cbSTaku Izumi 			}
7069acf51cbSTaku Izumi 
7079acf51cbSTaku Izumi 			if (fjes_tx_send(adapter, dest_epid, data, len)) {
7089acf51cbSTaku Izumi 				if (is_multi) {
7099acf51cbSTaku Izumi 					ret = NETDEV_TX_OK;
7109acf51cbSTaku Izumi 				} else if (
7119acf51cbSTaku Izumi 					   ((long)jiffies -
7129acf51cbSTaku Izumi 					    (long)adapter->tx_start_jiffies) >=
7139acf51cbSTaku Izumi 					    FJES_TX_RETRY_TIMEOUT) {
7149acf51cbSTaku Izumi 					adapter->stats64.tx_fifo_errors += 1;
7153c3bd4a9STaku Izumi 					hw->ep_shm_info[dest_epid].net_stats
7169acf51cbSTaku Izumi 								.tx_fifo_errors += 1;
7179acf51cbSTaku Izumi 					adapter->stats64.tx_errors += 1;
7183c3bd4a9STaku Izumi 					hw->ep_shm_info[dest_epid].net_stats
7199acf51cbSTaku Izumi 								.tx_errors += 1;
7209acf51cbSTaku Izumi 
7219acf51cbSTaku Izumi 					ret = NETDEV_TX_OK;
7229acf51cbSTaku Izumi 				} else {
723860e9538SFlorian Westphal 					netif_trans_update(netdev);
72421b7efbcSTaku Izumi 					hw->ep_shm_info[dest_epid].ep_stats
72521b7efbcSTaku Izumi 						.tx_buffer_full += 1;
7269acf51cbSTaku Izumi 					netif_tx_stop_queue(cur_queue);
7279acf51cbSTaku Izumi 
728ac63b947STaku Izumi 					if (!work_pending(&adapter->tx_stall_task))
729ac63b947STaku Izumi 						queue_work(adapter->txrx_wq,
730ac63b947STaku Izumi 							   &adapter->tx_stall_task);
731ac63b947STaku Izumi 
7329acf51cbSTaku Izumi 					ret = NETDEV_TX_BUSY;
7339acf51cbSTaku Izumi 				}
7349acf51cbSTaku Izumi 			} else {
7359acf51cbSTaku Izumi 				if (!is_multi) {
7369acf51cbSTaku Izumi 					adapter->stats64.tx_packets += 1;
7373c3bd4a9STaku Izumi 					hw->ep_shm_info[dest_epid].net_stats
7389acf51cbSTaku Izumi 								.tx_packets += 1;
7399acf51cbSTaku Izumi 					adapter->stats64.tx_bytes += len;
7403c3bd4a9STaku Izumi 					hw->ep_shm_info[dest_epid].net_stats
7419acf51cbSTaku Izumi 								.tx_bytes += len;
7429acf51cbSTaku Izumi 				}
7439acf51cbSTaku Izumi 
7449acf51cbSTaku Izumi 				adapter->tx_retry_count = 0;
7459acf51cbSTaku Izumi 				ret = NETDEV_TX_OK;
7469acf51cbSTaku Izumi 			}
7479acf51cbSTaku Izumi 		}
7489acf51cbSTaku Izumi 	}
7499acf51cbSTaku Izumi 
7509acf51cbSTaku Izumi 	if (ret == NETDEV_TX_OK) {
7519acf51cbSTaku Izumi 		dev_kfree_skb(skb);
7529acf51cbSTaku Izumi 		if (is_multi) {
7539acf51cbSTaku Izumi 			adapter->stats64.tx_packets += 1;
7549acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_packets += 1;
7559acf51cbSTaku Izumi 			adapter->stats64.tx_bytes += 1;
7569acf51cbSTaku Izumi 			hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
7579acf51cbSTaku Izumi 		}
7589acf51cbSTaku Izumi 	}
7599acf51cbSTaku Izumi 
7609acf51cbSTaku Izumi 	return ret;
7619acf51cbSTaku Izumi }
7629acf51cbSTaku Izumi 
763bc1f4470Sstephen hemminger static void
fjes_get_stats64(struct net_device * netdev,struct rtnl_link_stats64 * stats)764879bc9a3STaku Izumi fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
765879bc9a3STaku Izumi {
766879bc9a3STaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
767879bc9a3STaku Izumi 
768879bc9a3STaku Izumi 	memcpy(stats, &adapter->stats64, sizeof(struct rtnl_link_stats64));
769879bc9a3STaku Izumi }
770879bc9a3STaku Izumi 
fjes_change_mtu(struct net_device * netdev,int new_mtu)771b9e23a67STaku Izumi static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
772b9e23a67STaku Izumi {
77316bbec3aSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
774b9e23a67STaku Izumi 	bool running = netif_running(netdev);
77516bbec3aSTaku Izumi 	struct fjes_hw *hw = &adapter->hw;
776bd5a2569STaku Izumi 	unsigned long flags;
77716bbec3aSTaku Izumi 	int ret = -EINVAL;
77816bbec3aSTaku Izumi 	int idx, epidx;
779b9e23a67STaku Izumi 
780b9e23a67STaku Izumi 	for (idx = 0; fjes_support_mtu[idx] != 0; idx++) {
781b9e23a67STaku Izumi 		if (new_mtu <= fjes_support_mtu[idx]) {
782b9e23a67STaku Izumi 			new_mtu = fjes_support_mtu[idx];
783b9e23a67STaku Izumi 			if (new_mtu == netdev->mtu)
784b9e23a67STaku Izumi 				return 0;
785b9e23a67STaku Izumi 
78616bbec3aSTaku Izumi 			ret = 0;
78716bbec3aSTaku Izumi 			break;
78816bbec3aSTaku Izumi 		}
78916bbec3aSTaku Izumi 	}
79016bbec3aSTaku Izumi 
79116bbec3aSTaku Izumi 	if (ret)
79216bbec3aSTaku Izumi 		return ret;
79316bbec3aSTaku Izumi 
79416bbec3aSTaku Izumi 	if (running) {
795bd5a2569STaku Izumi 		spin_lock_irqsave(&hw->rx_status_lock, flags);
79616bbec3aSTaku Izumi 		for (epidx = 0; epidx < hw->max_epid; epidx++) {
79716bbec3aSTaku Izumi 			if (epidx == hw->my_epid)
79816bbec3aSTaku Izumi 				continue;
79916bbec3aSTaku Izumi 			hw->ep_shm_info[epidx].tx.info->v1i.rx_status &=
80016bbec3aSTaku Izumi 				~FJES_RX_MTU_CHANGING_DONE;
80116bbec3aSTaku Izumi 		}
802bd5a2569STaku Izumi 		spin_unlock_irqrestore(&hw->rx_status_lock, flags);
803bd5a2569STaku Izumi 
80416bbec3aSTaku Izumi 		netif_tx_stop_all_queues(netdev);
80516bbec3aSTaku Izumi 		netif_carrier_off(netdev);
80616bbec3aSTaku Izumi 		cancel_work_sync(&adapter->tx_stall_task);
80716bbec3aSTaku Izumi 		napi_disable(&adapter->napi);
80816bbec3aSTaku Izumi 
80916bbec3aSTaku Izumi 		msleep(1000);
81016bbec3aSTaku Izumi 
81116bbec3aSTaku Izumi 		netif_tx_stop_all_queues(netdev);
81216bbec3aSTaku Izumi 	}
813b9e23a67STaku Izumi 
814b9e23a67STaku Izumi 	netdev->mtu = new_mtu;
815b9e23a67STaku Izumi 
81616bbec3aSTaku Izumi 	if (running) {
81716bbec3aSTaku Izumi 		for (epidx = 0; epidx < hw->max_epid; epidx++) {
81816bbec3aSTaku Izumi 			if (epidx == hw->my_epid)
81916bbec3aSTaku Izumi 				continue;
82016bbec3aSTaku Izumi 
821bd5a2569STaku Izumi 			spin_lock_irqsave(&hw->rx_status_lock, flags);
82216bbec3aSTaku Izumi 			fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
82316bbec3aSTaku Izumi 					    netdev->dev_addr,
82416bbec3aSTaku Izumi 					    netdev->mtu);
82516bbec3aSTaku Izumi 
82616bbec3aSTaku Izumi 			hw->ep_shm_info[epidx].tx.info->v1i.rx_status |=
82716bbec3aSTaku Izumi 				FJES_RX_MTU_CHANGING_DONE;
828bd5a2569STaku Izumi 			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
82916bbec3aSTaku Izumi 		}
83016bbec3aSTaku Izumi 
83116bbec3aSTaku Izumi 		netif_tx_wake_all_queues(netdev);
83216bbec3aSTaku Izumi 		netif_carrier_on(netdev);
83316bbec3aSTaku Izumi 		napi_enable(&adapter->napi);
834bd5a2569STaku Izumi 		napi_schedule(&adapter->napi);
83516bbec3aSTaku Izumi 	}
836b9e23a67STaku Izumi 
837b9e23a67STaku Izumi 	return ret;
838b9e23a67STaku Izumi }
839b9e23a67STaku Izumi 
fjes_tx_retry(struct net_device * netdev,unsigned int txqueue)840fa2aee65SUwe Kleine-König static void fjes_tx_retry(struct net_device *netdev, unsigned int txqueue)
841fa2aee65SUwe Kleine-König {
842fa2aee65SUwe Kleine-König 	struct netdev_queue *queue = netdev_get_tx_queue(netdev, 0);
843fa2aee65SUwe Kleine-König 
844fa2aee65SUwe Kleine-König 	netif_tx_wake_queue(queue);
845fa2aee65SUwe Kleine-König }
846fa2aee65SUwe Kleine-König 
fjes_vlan_rx_add_vid(struct net_device * netdev,__be16 proto,u16 vid)8473e3feddaSTaku Izumi static int fjes_vlan_rx_add_vid(struct net_device *netdev,
8483e3feddaSTaku Izumi 				__be16 proto, u16 vid)
8493e3feddaSTaku Izumi {
8503e3feddaSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
8513e3feddaSTaku Izumi 	bool ret = true;
8523e3feddaSTaku Izumi 	int epid;
8533e3feddaSTaku Izumi 
8543e3feddaSTaku Izumi 	for (epid = 0; epid < adapter->hw.max_epid; epid++) {
8553e3feddaSTaku Izumi 		if (epid == adapter->hw.my_epid)
8563e3feddaSTaku Izumi 			continue;
8573e3feddaSTaku Izumi 
8583e3feddaSTaku Izumi 		if (!fjes_hw_check_vlan_id(
8593e3feddaSTaku Izumi 			&adapter->hw.ep_shm_info[epid].tx, vid))
8603e3feddaSTaku Izumi 			ret = fjes_hw_set_vlan_id(
8613e3feddaSTaku Izumi 				&adapter->hw.ep_shm_info[epid].tx, vid);
8623e3feddaSTaku Izumi 	}
8633e3feddaSTaku Izumi 
8643e3feddaSTaku Izumi 	return ret ? 0 : -ENOSPC;
8653e3feddaSTaku Izumi }
8663e3feddaSTaku Izumi 
fjes_vlan_rx_kill_vid(struct net_device * netdev,__be16 proto,u16 vid)8673e3feddaSTaku Izumi static int fjes_vlan_rx_kill_vid(struct net_device *netdev,
8683e3feddaSTaku Izumi 				 __be16 proto, u16 vid)
8693e3feddaSTaku Izumi {
8703e3feddaSTaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
8713e3feddaSTaku Izumi 	int epid;
8723e3feddaSTaku Izumi 
8733e3feddaSTaku Izumi 	for (epid = 0; epid < adapter->hw.max_epid; epid++) {
8743e3feddaSTaku Izumi 		if (epid == adapter->hw.my_epid)
8753e3feddaSTaku Izumi 			continue;
8763e3feddaSTaku Izumi 
8773e3feddaSTaku Izumi 		fjes_hw_del_vlan_id(&adapter->hw.ep_shm_info[epid].tx, vid);
8783e3feddaSTaku Izumi 	}
8793e3feddaSTaku Izumi 
8803e3feddaSTaku Izumi 	return 0;
8813e3feddaSTaku Izumi }
8823e3feddaSTaku Izumi 
883fa2aee65SUwe Kleine-König static const struct net_device_ops fjes_netdev_ops = {
884fa2aee65SUwe Kleine-König 	.ndo_open		= fjes_open,
885fa2aee65SUwe Kleine-König 	.ndo_stop		= fjes_close,
886fa2aee65SUwe Kleine-König 	.ndo_start_xmit		= fjes_xmit_frame,
887fa2aee65SUwe Kleine-König 	.ndo_get_stats64	= fjes_get_stats64,
888fa2aee65SUwe Kleine-König 	.ndo_change_mtu		= fjes_change_mtu,
889fa2aee65SUwe Kleine-König 	.ndo_tx_timeout		= fjes_tx_retry,
890fa2aee65SUwe Kleine-König 	.ndo_vlan_rx_add_vid	= fjes_vlan_rx_add_vid,
891fa2aee65SUwe Kleine-König 	.ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid,
892fa2aee65SUwe Kleine-König };
893fa2aee65SUwe Kleine-König 
894fa2aee65SUwe Kleine-König /* fjes_netdev_setup - netdevice initialization routine */
fjes_netdev_setup(struct net_device * netdev)895fa2aee65SUwe Kleine-König static void fjes_netdev_setup(struct net_device *netdev)
896cb79eaaeSTaku Izumi {
897fa2aee65SUwe Kleine-König 	ether_setup(netdev);
898cb79eaaeSTaku Izumi 
899fa2aee65SUwe Kleine-König 	netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL;
900fa2aee65SUwe Kleine-König 	netdev->netdev_ops = &fjes_netdev_ops;
901fa2aee65SUwe Kleine-König 	fjes_set_ethtool_ops(netdev);
902fa2aee65SUwe Kleine-König 	netdev->mtu = fjes_support_mtu[3];
903fa2aee65SUwe Kleine-König 	netdev->min_mtu = fjes_support_mtu[0];
904fa2aee65SUwe Kleine-König 	netdev->max_mtu = fjes_support_mtu[3];
905fa2aee65SUwe Kleine-König 	netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
906e5d486dcSTaku Izumi }
907e5d486dcSTaku Izumi 
fjes_rxframe_search_exist(struct fjes_adapter * adapter,int start_epid)90826585930STaku Izumi static int fjes_rxframe_search_exist(struct fjes_adapter *adapter,
90926585930STaku Izumi 				     int start_epid)
91026585930STaku Izumi {
91126585930STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
91226585930STaku Izumi 	enum ep_partner_status pstatus;
91326585930STaku Izumi 	int max_epid, cur_epid;
91426585930STaku Izumi 	int i;
91526585930STaku Izumi 
91626585930STaku Izumi 	max_epid = hw->max_epid;
91726585930STaku Izumi 	start_epid = (start_epid + 1 + max_epid) % max_epid;
91826585930STaku Izumi 
91926585930STaku Izumi 	for (i = 0; i < max_epid; i++) {
92026585930STaku Izumi 		cur_epid = (start_epid + i) % max_epid;
92126585930STaku Izumi 		if (cur_epid == hw->my_epid)
92226585930STaku Izumi 			continue;
92326585930STaku Izumi 
92426585930STaku Izumi 		pstatus = fjes_hw_get_partner_ep_status(hw, cur_epid);
92526585930STaku Izumi 		if (pstatus == EP_PARTNER_SHARED) {
92626585930STaku Izumi 			if (!fjes_hw_epbuf_rx_is_empty(
92726585930STaku Izumi 				&hw->ep_shm_info[cur_epid].rx))
92826585930STaku Izumi 				return cur_epid;
92926585930STaku Izumi 		}
93026585930STaku Izumi 	}
93126585930STaku Izumi 	return -1;
93226585930STaku Izumi }
93326585930STaku Izumi 
fjes_rxframe_get(struct fjes_adapter * adapter,size_t * psize,int * cur_epid)93426585930STaku Izumi static void *fjes_rxframe_get(struct fjes_adapter *adapter, size_t *psize,
93526585930STaku Izumi 			      int *cur_epid)
93626585930STaku Izumi {
93726585930STaku Izumi 	void *frame;
93826585930STaku Izumi 
93926585930STaku Izumi 	*cur_epid = fjes_rxframe_search_exist(adapter, *cur_epid);
94026585930STaku Izumi 	if (*cur_epid < 0)
94126585930STaku Izumi 		return NULL;
94226585930STaku Izumi 
94326585930STaku Izumi 	frame =
94426585930STaku Izumi 	fjes_hw_epbuf_rx_curpkt_get_addr(
94526585930STaku Izumi 		&adapter->hw.ep_shm_info[*cur_epid].rx, psize);
94626585930STaku Izumi 
94726585930STaku Izumi 	return frame;
94826585930STaku Izumi }
94926585930STaku Izumi 
fjes_rxframe_release(struct fjes_adapter * adapter,int cur_epid)95026585930STaku Izumi static void fjes_rxframe_release(struct fjes_adapter *adapter, int cur_epid)
95126585930STaku Izumi {
95226585930STaku Izumi 	fjes_hw_epbuf_rx_curpkt_drop(&adapter->hw.ep_shm_info[cur_epid].rx);
95326585930STaku Izumi }
95426585930STaku Izumi 
fjes_poll(struct napi_struct * napi,int budget)95526585930STaku Izumi static int fjes_poll(struct napi_struct *napi, int budget)
95626585930STaku Izumi {
95726585930STaku Izumi 	struct fjes_adapter *adapter =
95826585930STaku Izumi 			container_of(napi, struct fjes_adapter, napi);
95926585930STaku Izumi 	struct net_device *netdev = napi->dev;
96026585930STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
96126585930STaku Izumi 	struct sk_buff *skb;
96226585930STaku Izumi 	int work_done = 0;
96326585930STaku Izumi 	int cur_epid = 0;
96426585930STaku Izumi 	int epidx;
96526585930STaku Izumi 	size_t frame_len;
96626585930STaku Izumi 	void *frame;
96726585930STaku Izumi 
968bd5a2569STaku Izumi 	spin_lock(&hw->rx_status_lock);
96926585930STaku Izumi 	for (epidx = 0; epidx < hw->max_epid; epidx++) {
97026585930STaku Izumi 		if (epidx == hw->my_epid)
97126585930STaku Izumi 			continue;
97226585930STaku Izumi 
973bd5a2569STaku Izumi 		if (fjes_hw_get_partner_ep_status(hw, epidx) ==
974bd5a2569STaku Izumi 		    EP_PARTNER_SHARED)
975bd5a2569STaku Izumi 			adapter->hw.ep_shm_info[epidx]
976bd5a2569STaku Izumi 				   .tx.info->v1i.rx_status |= FJES_RX_POLL_WORK;
97726585930STaku Izumi 	}
978bd5a2569STaku Izumi 	spin_unlock(&hw->rx_status_lock);
97926585930STaku Izumi 
98026585930STaku Izumi 	while (work_done < budget) {
98126585930STaku Izumi 		prefetch(&adapter->hw);
98226585930STaku Izumi 		frame = fjes_rxframe_get(adapter, &frame_len, &cur_epid);
98326585930STaku Izumi 
98426585930STaku Izumi 		if (frame) {
98526585930STaku Izumi 			skb = napi_alloc_skb(napi, frame_len);
98626585930STaku Izumi 			if (!skb) {
98726585930STaku Izumi 				adapter->stats64.rx_dropped += 1;
98826585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
98926585930STaku Izumi 							 .rx_dropped += 1;
99026585930STaku Izumi 				adapter->stats64.rx_errors += 1;
99126585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
99226585930STaku Izumi 							 .rx_errors += 1;
99326585930STaku Izumi 			} else {
99459ae1d12SJohannes Berg 				skb_put_data(skb, frame, frame_len);
99526585930STaku Izumi 				skb->protocol = eth_type_trans(skb, netdev);
99626585930STaku Izumi 				skb->ip_summed = CHECKSUM_UNNECESSARY;
99726585930STaku Izumi 
99826585930STaku Izumi 				netif_receive_skb(skb);
99926585930STaku Izumi 
100026585930STaku Izumi 				work_done++;
100126585930STaku Izumi 
100226585930STaku Izumi 				adapter->stats64.rx_packets += 1;
100326585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
100426585930STaku Izumi 							 .rx_packets += 1;
100526585930STaku Izumi 				adapter->stats64.rx_bytes += frame_len;
100626585930STaku Izumi 				hw->ep_shm_info[cur_epid].net_stats
100726585930STaku Izumi 							 .rx_bytes += frame_len;
100826585930STaku Izumi 
100926585930STaku Izumi 				if (is_multicast_ether_addr(
101026585930STaku Izumi 					((struct ethhdr *)frame)->h_dest)) {
101126585930STaku Izumi 					adapter->stats64.multicast += 1;
101226585930STaku Izumi 					hw->ep_shm_info[cur_epid].net_stats
101326585930STaku Izumi 								 .multicast += 1;
101426585930STaku Izumi 				}
101526585930STaku Izumi 			}
101626585930STaku Izumi 
101726585930STaku Izumi 			fjes_rxframe_release(adapter, cur_epid);
101826585930STaku Izumi 			adapter->unset_rx_last = true;
101926585930STaku Izumi 		} else {
102026585930STaku Izumi 			break;
102126585930STaku Izumi 		}
102226585930STaku Izumi 	}
102326585930STaku Izumi 
102426585930STaku Izumi 	if (work_done < budget) {
10256ad20165SEric Dumazet 		napi_complete_done(napi, work_done);
102626585930STaku Izumi 
102726585930STaku Izumi 		if (adapter->unset_rx_last) {
102826585930STaku Izumi 			adapter->rx_last_jiffies = jiffies;
102926585930STaku Izumi 			adapter->unset_rx_last = false;
103026585930STaku Izumi 		}
103126585930STaku Izumi 
103226585930STaku Izumi 		if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) {
103326585930STaku Izumi 			napi_reschedule(napi);
103426585930STaku Izumi 		} else {
1035bd5a2569STaku Izumi 			spin_lock(&hw->rx_status_lock);
103626585930STaku Izumi 			for (epidx = 0; epidx < hw->max_epid; epidx++) {
103726585930STaku Izumi 				if (epidx == hw->my_epid)
103826585930STaku Izumi 					continue;
1039bd5a2569STaku Izumi 				if (fjes_hw_get_partner_ep_status(hw, epidx) ==
1040bd5a2569STaku Izumi 				    EP_PARTNER_SHARED)
1041bd5a2569STaku Izumi 					adapter->hw.ep_shm_info[epidx].tx
1042bd5a2569STaku Izumi 						   .info->v1i.rx_status &=
104326585930STaku Izumi 						~FJES_RX_POLL_WORK;
104426585930STaku Izumi 			}
1045bd5a2569STaku Izumi 			spin_unlock(&hw->rx_status_lock);
104626585930STaku Izumi 
104726585930STaku Izumi 			fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false);
104826585930STaku Izumi 		}
104926585930STaku Izumi 	}
105026585930STaku Izumi 
105126585930STaku Izumi 	return work_done;
105226585930STaku Izumi }
105326585930STaku Izumi 
fjes_sw_init(struct fjes_adapter * adapter)1054fa2aee65SUwe Kleine-König static int fjes_sw_init(struct fjes_adapter *adapter)
1055fa2aee65SUwe Kleine-König {
1056fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
1057fa2aee65SUwe Kleine-König 
1058b48b89f9SJakub Kicinski 	netif_napi_add(netdev, &adapter->napi, fjes_poll);
1059fa2aee65SUwe Kleine-König 
1060fa2aee65SUwe Kleine-König 	return 0;
1061fa2aee65SUwe Kleine-König }
1062fa2aee65SUwe Kleine-König 
fjes_force_close_task(struct work_struct * work)1063fa2aee65SUwe Kleine-König static void fjes_force_close_task(struct work_struct *work)
1064fa2aee65SUwe Kleine-König {
1065fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter = container_of(work,
1066fa2aee65SUwe Kleine-König 			struct fjes_adapter, force_close_task);
1067fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
1068fa2aee65SUwe Kleine-König 
1069fa2aee65SUwe Kleine-König 	rtnl_lock();
1070fa2aee65SUwe Kleine-König 	dev_close(netdev);
1071fa2aee65SUwe Kleine-König 	rtnl_unlock();
1072fa2aee65SUwe Kleine-König }
1073fa2aee65SUwe Kleine-König 
fjes_tx_stall_task(struct work_struct * work)1074fa2aee65SUwe Kleine-König static void fjes_tx_stall_task(struct work_struct *work)
1075fa2aee65SUwe Kleine-König {
1076fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter = container_of(work,
1077fa2aee65SUwe Kleine-König 			struct fjes_adapter, tx_stall_task);
1078fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
1079fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
1080fa2aee65SUwe Kleine-König 	int all_queue_available, sendable;
1081fa2aee65SUwe Kleine-König 	enum ep_partner_status pstatus;
1082fa2aee65SUwe Kleine-König 	int max_epid, my_epid, epid;
1083fa2aee65SUwe Kleine-König 	union ep_buffer_info *info;
1084fa2aee65SUwe Kleine-König 	int i;
1085fa2aee65SUwe Kleine-König 
1086fa2aee65SUwe Kleine-König 	if (((long)jiffies -
1087fa2aee65SUwe Kleine-König 		dev_trans_start(netdev)) > FJES_TX_TX_STALL_TIMEOUT) {
1088fa2aee65SUwe Kleine-König 		netif_wake_queue(netdev);
1089fa2aee65SUwe Kleine-König 		return;
1090fa2aee65SUwe Kleine-König 	}
1091fa2aee65SUwe Kleine-König 
1092fa2aee65SUwe Kleine-König 	my_epid = hw->my_epid;
1093fa2aee65SUwe Kleine-König 	max_epid = hw->max_epid;
1094fa2aee65SUwe Kleine-König 
1095fa2aee65SUwe Kleine-König 	for (i = 0; i < 5; i++) {
1096fa2aee65SUwe Kleine-König 		all_queue_available = 1;
1097fa2aee65SUwe Kleine-König 
1098fa2aee65SUwe Kleine-König 		for (epid = 0; epid < max_epid; epid++) {
1099fa2aee65SUwe Kleine-König 			if (my_epid == epid)
1100fa2aee65SUwe Kleine-König 				continue;
1101fa2aee65SUwe Kleine-König 
1102fa2aee65SUwe Kleine-König 			pstatus = fjes_hw_get_partner_ep_status(hw, epid);
1103fa2aee65SUwe Kleine-König 			sendable = (pstatus == EP_PARTNER_SHARED);
1104fa2aee65SUwe Kleine-König 			if (!sendable)
1105fa2aee65SUwe Kleine-König 				continue;
1106fa2aee65SUwe Kleine-König 
1107fa2aee65SUwe Kleine-König 			info = adapter->hw.ep_shm_info[epid].tx.info;
1108fa2aee65SUwe Kleine-König 
1109fa2aee65SUwe Kleine-König 			if (!(info->v1i.rx_status & FJES_RX_MTU_CHANGING_DONE))
1110fa2aee65SUwe Kleine-König 				return;
1111fa2aee65SUwe Kleine-König 
1112fa2aee65SUwe Kleine-König 			if (EP_RING_FULL(info->v1i.head, info->v1i.tail,
1113fa2aee65SUwe Kleine-König 					 info->v1i.count_max)) {
1114fa2aee65SUwe Kleine-König 				all_queue_available = 0;
1115fa2aee65SUwe Kleine-König 				break;
1116fa2aee65SUwe Kleine-König 			}
1117fa2aee65SUwe Kleine-König 		}
1118fa2aee65SUwe Kleine-König 
1119fa2aee65SUwe Kleine-König 		if (all_queue_available) {
1120fa2aee65SUwe Kleine-König 			netif_wake_queue(netdev);
1121fa2aee65SUwe Kleine-König 			return;
1122fa2aee65SUwe Kleine-König 		}
1123fa2aee65SUwe Kleine-König 	}
1124fa2aee65SUwe Kleine-König 
1125fa2aee65SUwe Kleine-König 	usleep_range(50, 100);
1126fa2aee65SUwe Kleine-König 
1127fa2aee65SUwe Kleine-König 	queue_work(adapter->txrx_wq, &adapter->tx_stall_task);
1128fa2aee65SUwe Kleine-König }
1129fa2aee65SUwe Kleine-König 
fjes_raise_intr_rxdata_task(struct work_struct * work)1130fa2aee65SUwe Kleine-König static void fjes_raise_intr_rxdata_task(struct work_struct *work)
1131fa2aee65SUwe Kleine-König {
1132fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter = container_of(work,
1133fa2aee65SUwe Kleine-König 			struct fjes_adapter, raise_intr_rxdata_task);
1134fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
1135fa2aee65SUwe Kleine-König 	enum ep_partner_status pstatus;
1136fa2aee65SUwe Kleine-König 	int max_epid, my_epid, epid;
1137fa2aee65SUwe Kleine-König 
1138fa2aee65SUwe Kleine-König 	my_epid = hw->my_epid;
1139fa2aee65SUwe Kleine-König 	max_epid = hw->max_epid;
1140fa2aee65SUwe Kleine-König 
1141fa2aee65SUwe Kleine-König 	for (epid = 0; epid < max_epid; epid++)
1142fa2aee65SUwe Kleine-König 		hw->ep_shm_info[epid].tx_status_work = 0;
1143fa2aee65SUwe Kleine-König 
1144fa2aee65SUwe Kleine-König 	for (epid = 0; epid < max_epid; epid++) {
1145fa2aee65SUwe Kleine-König 		if (epid == my_epid)
1146fa2aee65SUwe Kleine-König 			continue;
1147fa2aee65SUwe Kleine-König 
1148fa2aee65SUwe Kleine-König 		pstatus = fjes_hw_get_partner_ep_status(hw, epid);
1149fa2aee65SUwe Kleine-König 		if (pstatus == EP_PARTNER_SHARED) {
1150fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epid].tx_status_work =
1151fa2aee65SUwe Kleine-König 				hw->ep_shm_info[epid].tx.info->v1i.tx_status;
1152fa2aee65SUwe Kleine-König 
1153fa2aee65SUwe Kleine-König 			if (hw->ep_shm_info[epid].tx_status_work ==
1154fa2aee65SUwe Kleine-König 				FJES_TX_DELAY_SEND_PENDING) {
1155fa2aee65SUwe Kleine-König 				hw->ep_shm_info[epid].tx.info->v1i.tx_status =
1156fa2aee65SUwe Kleine-König 					FJES_TX_DELAY_SEND_NONE;
1157fa2aee65SUwe Kleine-König 			}
1158fa2aee65SUwe Kleine-König 		}
1159fa2aee65SUwe Kleine-König 	}
1160fa2aee65SUwe Kleine-König 
1161fa2aee65SUwe Kleine-König 	for (epid = 0; epid < max_epid; epid++) {
1162fa2aee65SUwe Kleine-König 		if (epid == my_epid)
1163fa2aee65SUwe Kleine-König 			continue;
1164fa2aee65SUwe Kleine-König 
1165fa2aee65SUwe Kleine-König 		pstatus = fjes_hw_get_partner_ep_status(hw, epid);
1166fa2aee65SUwe Kleine-König 		if ((hw->ep_shm_info[epid].tx_status_work ==
1167fa2aee65SUwe Kleine-König 		     FJES_TX_DELAY_SEND_PENDING) &&
1168fa2aee65SUwe Kleine-König 		    (pstatus == EP_PARTNER_SHARED) &&
1169fa2aee65SUwe Kleine-König 		    !(hw->ep_shm_info[epid].rx.info->v1i.rx_status &
1170fa2aee65SUwe Kleine-König 		      FJES_RX_POLL_WORK)) {
1171fa2aee65SUwe Kleine-König 			fjes_hw_raise_interrupt(hw, epid,
1172fa2aee65SUwe Kleine-König 						REG_ICTL_MASK_RX_DATA);
1173fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epid].ep_stats.send_intr_rx += 1;
1174fa2aee65SUwe Kleine-König 		}
1175fa2aee65SUwe Kleine-König 	}
1176fa2aee65SUwe Kleine-König 
1177fa2aee65SUwe Kleine-König 	usleep_range(500, 1000);
1178fa2aee65SUwe Kleine-König }
1179fa2aee65SUwe Kleine-König 
fjes_watch_unshare_task(struct work_struct * work)1180fa2aee65SUwe Kleine-König static void fjes_watch_unshare_task(struct work_struct *work)
1181fa2aee65SUwe Kleine-König {
1182fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter =
1183fa2aee65SUwe Kleine-König 	container_of(work, struct fjes_adapter, unshare_watch_task);
1184fa2aee65SUwe Kleine-König 
1185fa2aee65SUwe Kleine-König 	struct net_device *netdev = adapter->netdev;
1186fa2aee65SUwe Kleine-König 	struct fjes_hw *hw = &adapter->hw;
1187fa2aee65SUwe Kleine-König 
1188fa2aee65SUwe Kleine-König 	int unshare_watch, unshare_reserve;
1189fa2aee65SUwe Kleine-König 	int max_epid, my_epid, epidx;
1190fa2aee65SUwe Kleine-König 	int stop_req, stop_req_done;
1191fa2aee65SUwe Kleine-König 	ulong unshare_watch_bitmask;
1192fa2aee65SUwe Kleine-König 	unsigned long flags;
1193fa2aee65SUwe Kleine-König 	int wait_time = 0;
1194fa2aee65SUwe Kleine-König 	int is_shared;
1195fa2aee65SUwe Kleine-König 	int ret;
1196fa2aee65SUwe Kleine-König 
1197fa2aee65SUwe Kleine-König 	my_epid = hw->my_epid;
1198fa2aee65SUwe Kleine-König 	max_epid = hw->max_epid;
1199fa2aee65SUwe Kleine-König 
1200fa2aee65SUwe Kleine-König 	unshare_watch_bitmask = adapter->unshare_watch_bitmask;
1201fa2aee65SUwe Kleine-König 	adapter->unshare_watch_bitmask = 0;
1202fa2aee65SUwe Kleine-König 
1203fa2aee65SUwe Kleine-König 	while ((unshare_watch_bitmask || hw->txrx_stop_req_bit) &&
1204fa2aee65SUwe Kleine-König 	       (wait_time < 3000)) {
1205fa2aee65SUwe Kleine-König 		for (epidx = 0; epidx < max_epid; epidx++) {
1206fa2aee65SUwe Kleine-König 			if (epidx == my_epid)
1207fa2aee65SUwe Kleine-König 				continue;
1208fa2aee65SUwe Kleine-König 
1209fa2aee65SUwe Kleine-König 			is_shared = fjes_hw_epid_is_shared(hw->hw_info.share,
1210fa2aee65SUwe Kleine-König 							   epidx);
1211fa2aee65SUwe Kleine-König 
1212fa2aee65SUwe Kleine-König 			stop_req = test_bit(epidx, &hw->txrx_stop_req_bit);
1213fa2aee65SUwe Kleine-König 
1214fa2aee65SUwe Kleine-König 			stop_req_done = hw->ep_shm_info[epidx].rx.info->v1i.rx_status &
1215fa2aee65SUwe Kleine-König 					FJES_RX_STOP_REQ_DONE;
1216fa2aee65SUwe Kleine-König 
1217fa2aee65SUwe Kleine-König 			unshare_watch = test_bit(epidx, &unshare_watch_bitmask);
1218fa2aee65SUwe Kleine-König 
1219fa2aee65SUwe Kleine-König 			unshare_reserve = test_bit(epidx,
1220fa2aee65SUwe Kleine-König 						   &hw->hw_info.buffer_unshare_reserve_bit);
1221fa2aee65SUwe Kleine-König 
1222fa2aee65SUwe Kleine-König 			if ((!stop_req ||
1223fa2aee65SUwe Kleine-König 			     (is_shared && (!is_shared || !stop_req_done))) &&
1224fa2aee65SUwe Kleine-König 			    (is_shared || !unshare_watch || !unshare_reserve))
1225fa2aee65SUwe Kleine-König 				continue;
1226fa2aee65SUwe Kleine-König 
1227fa2aee65SUwe Kleine-König 			mutex_lock(&hw->hw_info.lock);
1228fa2aee65SUwe Kleine-König 			ret = fjes_hw_unregister_buff_addr(hw, epidx);
1229fa2aee65SUwe Kleine-König 			switch (ret) {
1230fa2aee65SUwe Kleine-König 			case 0:
1231fa2aee65SUwe Kleine-König 				break;
1232fa2aee65SUwe Kleine-König 			case -ENOMSG:
1233fa2aee65SUwe Kleine-König 			case -EBUSY:
1234fa2aee65SUwe Kleine-König 			default:
1235fa2aee65SUwe Kleine-König 				if (!work_pending(
1236fa2aee65SUwe Kleine-König 					&adapter->force_close_task)) {
1237fa2aee65SUwe Kleine-König 					adapter->force_reset = true;
1238fa2aee65SUwe Kleine-König 					schedule_work(
1239fa2aee65SUwe Kleine-König 						&adapter->force_close_task);
1240fa2aee65SUwe Kleine-König 				}
1241fa2aee65SUwe Kleine-König 				break;
1242fa2aee65SUwe Kleine-König 			}
1243fa2aee65SUwe Kleine-König 			mutex_unlock(&hw->hw_info.lock);
1244fa2aee65SUwe Kleine-König 			hw->ep_shm_info[epidx].ep_stats
1245fa2aee65SUwe Kleine-König 					.com_unregist_buf_exec += 1;
1246fa2aee65SUwe Kleine-König 
1247fa2aee65SUwe Kleine-König 			spin_lock_irqsave(&hw->rx_status_lock, flags);
1248fa2aee65SUwe Kleine-König 			fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
1249fa2aee65SUwe Kleine-König 					    netdev->dev_addr, netdev->mtu);
1250fa2aee65SUwe Kleine-König 			spin_unlock_irqrestore(&hw->rx_status_lock, flags);
1251fa2aee65SUwe Kleine-König 
1252fa2aee65SUwe Kleine-König 			clear_bit(epidx, &hw->txrx_stop_req_bit);
1253fa2aee65SUwe Kleine-König 			clear_bit(epidx, &unshare_watch_bitmask);
1254fa2aee65SUwe Kleine-König 			clear_bit(epidx,
1255fa2aee65SUwe Kleine-König 				  &hw->hw_info.buffer_unshare_reserve_bit);
1256fa2aee65SUwe Kleine-König 		}
1257fa2aee65SUwe Kleine-König 
1258fa2aee65SUwe Kleine-König 		msleep(100);
1259fa2aee65SUwe Kleine-König 		wait_time += 100;
1260fa2aee65SUwe Kleine-König 	}
1261fa2aee65SUwe Kleine-König 
1262fa2aee65SUwe Kleine-König 	if (hw->hw_info.buffer_unshare_reserve_bit) {
1263fa2aee65SUwe Kleine-König 		for (epidx = 0; epidx < max_epid; epidx++) {
1264fa2aee65SUwe Kleine-König 			if (epidx == my_epid)
1265fa2aee65SUwe Kleine-König 				continue;
1266fa2aee65SUwe Kleine-König 
1267fa2aee65SUwe Kleine-König 			if (test_bit(epidx,
1268fa2aee65SUwe Kleine-König 				     &hw->hw_info.buffer_unshare_reserve_bit)) {
1269fa2aee65SUwe Kleine-König 				mutex_lock(&hw->hw_info.lock);
1270fa2aee65SUwe Kleine-König 
1271fa2aee65SUwe Kleine-König 				ret = fjes_hw_unregister_buff_addr(hw, epidx);
1272fa2aee65SUwe Kleine-König 				switch (ret) {
1273fa2aee65SUwe Kleine-König 				case 0:
1274fa2aee65SUwe Kleine-König 					break;
1275fa2aee65SUwe Kleine-König 				case -ENOMSG:
1276fa2aee65SUwe Kleine-König 				case -EBUSY:
1277fa2aee65SUwe Kleine-König 				default:
1278fa2aee65SUwe Kleine-König 					if (!work_pending(
1279fa2aee65SUwe Kleine-König 						&adapter->force_close_task)) {
1280fa2aee65SUwe Kleine-König 						adapter->force_reset = true;
1281fa2aee65SUwe Kleine-König 						schedule_work(
1282fa2aee65SUwe Kleine-König 							&adapter->force_close_task);
1283fa2aee65SUwe Kleine-König 					}
1284fa2aee65SUwe Kleine-König 					break;
1285fa2aee65SUwe Kleine-König 				}
1286fa2aee65SUwe Kleine-König 				mutex_unlock(&hw->hw_info.lock);
1287fa2aee65SUwe Kleine-König 
1288fa2aee65SUwe Kleine-König 				hw->ep_shm_info[epidx].ep_stats
1289fa2aee65SUwe Kleine-König 					.com_unregist_buf_exec += 1;
1290fa2aee65SUwe Kleine-König 
1291fa2aee65SUwe Kleine-König 				spin_lock_irqsave(&hw->rx_status_lock, flags);
1292fa2aee65SUwe Kleine-König 				fjes_hw_setup_epbuf(
1293fa2aee65SUwe Kleine-König 					&hw->ep_shm_info[epidx].tx,
1294fa2aee65SUwe Kleine-König 					netdev->dev_addr, netdev->mtu);
1295fa2aee65SUwe Kleine-König 				spin_unlock_irqrestore(&hw->rx_status_lock,
1296fa2aee65SUwe Kleine-König 						       flags);
1297fa2aee65SUwe Kleine-König 
1298fa2aee65SUwe Kleine-König 				clear_bit(epidx, &hw->txrx_stop_req_bit);
1299fa2aee65SUwe Kleine-König 				clear_bit(epidx, &unshare_watch_bitmask);
1300fa2aee65SUwe Kleine-König 				clear_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
1301fa2aee65SUwe Kleine-König 			}
1302fa2aee65SUwe Kleine-König 
1303fa2aee65SUwe Kleine-König 			if (test_bit(epidx, &unshare_watch_bitmask)) {
1304fa2aee65SUwe Kleine-König 				spin_lock_irqsave(&hw->rx_status_lock, flags);
1305fa2aee65SUwe Kleine-König 				hw->ep_shm_info[epidx].tx.info->v1i.rx_status &=
1306fa2aee65SUwe Kleine-König 						~FJES_RX_STOP_REQ_DONE;
1307fa2aee65SUwe Kleine-König 				spin_unlock_irqrestore(&hw->rx_status_lock,
1308fa2aee65SUwe Kleine-König 						       flags);
1309fa2aee65SUwe Kleine-König 			}
1310fa2aee65SUwe Kleine-König 		}
1311fa2aee65SUwe Kleine-König 	}
1312fa2aee65SUwe Kleine-König }
1313fa2aee65SUwe Kleine-König 
fjes_irq_watch_task(struct work_struct * work)1314fa2aee65SUwe Kleine-König static void fjes_irq_watch_task(struct work_struct *work)
1315fa2aee65SUwe Kleine-König {
1316fa2aee65SUwe Kleine-König 	struct fjes_adapter *adapter = container_of(to_delayed_work(work),
1317fa2aee65SUwe Kleine-König 			struct fjes_adapter, interrupt_watch_task);
1318fa2aee65SUwe Kleine-König 
1319fa2aee65SUwe Kleine-König 	local_irq_disable();
1320fa2aee65SUwe Kleine-König 	fjes_intr(adapter->hw.hw_res.irq, adapter);
1321fa2aee65SUwe Kleine-König 	local_irq_enable();
1322fa2aee65SUwe Kleine-König 
1323fa2aee65SUwe Kleine-König 	if (fjes_rxframe_search_exist(adapter, 0) >= 0)
1324fa2aee65SUwe Kleine-König 		napi_schedule(&adapter->napi);
1325fa2aee65SUwe Kleine-König 
1326fa2aee65SUwe Kleine-König 	if (adapter->interrupt_watch_enable) {
1327fa2aee65SUwe Kleine-König 		if (!delayed_work_pending(&adapter->interrupt_watch_task))
1328fa2aee65SUwe Kleine-König 			queue_delayed_work(adapter->control_wq,
1329fa2aee65SUwe Kleine-König 					   &adapter->interrupt_watch_task,
1330fa2aee65SUwe Kleine-König 					   FJES_IRQ_WATCH_DELAY);
1331fa2aee65SUwe Kleine-König 	}
1332fa2aee65SUwe Kleine-König }
1333fa2aee65SUwe Kleine-König 
1334658d439bSTaku Izumi /* fjes_probe - Device Initialization Routine */
fjes_probe(struct platform_device * plat_dev)1335658d439bSTaku Izumi static int fjes_probe(struct platform_device *plat_dev)
1336658d439bSTaku Izumi {
13372fcbca68STaku Izumi 	struct fjes_adapter *adapter;
13382fcbca68STaku Izumi 	struct net_device *netdev;
13392fcbca68STaku Izumi 	struct resource *res;
13402fcbca68STaku Izumi 	struct fjes_hw *hw;
1341ed088907SJakub Kicinski 	u8 addr[ETH_ALEN];
13422fcbca68STaku Izumi 	int err;
13432fcbca68STaku Izumi 
13442fcbca68STaku Izumi 	err = -ENOMEM;
13452fcbca68STaku Izumi 	netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d",
13462fcbca68STaku Izumi 				 NET_NAME_UNKNOWN, fjes_netdev_setup,
13472fcbca68STaku Izumi 				 FJES_MAX_QUEUES);
13482fcbca68STaku Izumi 
13492fcbca68STaku Izumi 	if (!netdev)
13502fcbca68STaku Izumi 		goto err_out;
13512fcbca68STaku Izumi 
13522fcbca68STaku Izumi 	SET_NETDEV_DEV(netdev, &plat_dev->dev);
13532fcbca68STaku Izumi 
13542fcbca68STaku Izumi 	dev_set_drvdata(&plat_dev->dev, netdev);
13552fcbca68STaku Izumi 	adapter = netdev_priv(netdev);
13562fcbca68STaku Izumi 	adapter->netdev = netdev;
13572fcbca68STaku Izumi 	adapter->plat_dev = plat_dev;
13582fcbca68STaku Izumi 	hw = &adapter->hw;
13592fcbca68STaku Izumi 	hw->back = adapter;
13602fcbca68STaku Izumi 
13612fcbca68STaku Izumi 	/* setup the private structure */
13622fcbca68STaku Izumi 	err = fjes_sw_init(adapter);
13632fcbca68STaku Izumi 	if (err)
13642fcbca68STaku Izumi 		goto err_free_netdev;
13652fcbca68STaku Izumi 
1366ff5b4210STaku Izumi 	INIT_WORK(&adapter->force_close_task, fjes_force_close_task);
13672fcbca68STaku Izumi 	adapter->force_reset = false;
13682fcbca68STaku Izumi 	adapter->open_guard = false;
13692fcbca68STaku Izumi 
1370f2edc4e1SBhaktipriya Shridhar 	adapter->txrx_wq = alloc_workqueue(DRV_NAME "/txrx", WQ_MEM_RECLAIM, 0);
137185ac30faSWill Deacon 	if (unlikely(!adapter->txrx_wq)) {
137285ac30faSWill Deacon 		err = -ENOMEM;
137385ac30faSWill Deacon 		goto err_free_netdev;
137485ac30faSWill Deacon 	}
137585ac30faSWill Deacon 
1376f2edc4e1SBhaktipriya Shridhar 	adapter->control_wq = alloc_workqueue(DRV_NAME "/control",
1377f2edc4e1SBhaktipriya Shridhar 					      WQ_MEM_RECLAIM, 0);
137885ac30faSWill Deacon 	if (unlikely(!adapter->control_wq)) {
137985ac30faSWill Deacon 		err = -ENOMEM;
138085ac30faSWill Deacon 		goto err_free_txrx_wq;
138185ac30faSWill Deacon 	}
1382b772b9dcSTaku Izumi 
1383ac63b947STaku Izumi 	INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task);
1384b772b9dcSTaku Izumi 	INIT_WORK(&adapter->raise_intr_rxdata_task,
1385b772b9dcSTaku Izumi 		  fjes_raise_intr_rxdata_task);
13868fc4cadbSTaku Izumi 	INIT_WORK(&adapter->unshare_watch_task, fjes_watch_unshare_task);
13878fc4cadbSTaku Izumi 	adapter->unshare_watch_bitmask = 0;
1388b772b9dcSTaku Izumi 
13898edb62a8STaku Izumi 	INIT_DELAYED_WORK(&adapter->interrupt_watch_task, fjes_irq_watch_task);
13908edb62a8STaku Izumi 	adapter->interrupt_watch_enable = false;
13918edb62a8STaku Izumi 
13922fcbca68STaku Izumi 	res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
1393f18c1181SYang Yingliang 	if (!res) {
1394f18c1181SYang Yingliang 		err = -EINVAL;
1395f18c1181SYang Yingliang 		goto err_free_control_wq;
1396f18c1181SYang Yingliang 	}
13972fcbca68STaku Izumi 	hw->hw_res.start = res->start;
1398e0897ae3SVaishali Thakkar 	hw->hw_res.size = resource_size(res);
13992fcbca68STaku Izumi 	hw->hw_res.irq = platform_get_irq(plat_dev, 0);
1400db6d6afeSJiasheng Jiang 	if (hw->hw_res.irq < 0) {
1401db6d6afeSJiasheng Jiang 		err = hw->hw_res.irq;
1402db6d6afeSJiasheng Jiang 		goto err_free_control_wq;
1403db6d6afeSJiasheng Jiang 	}
1404db6d6afeSJiasheng Jiang 
14052fcbca68STaku Izumi 	err = fjes_hw_init(&adapter->hw);
14062fcbca68STaku Izumi 	if (err)
140785ac30faSWill Deacon 		goto err_free_control_wq;
14082fcbca68STaku Izumi 
14092fcbca68STaku Izumi 	/* setup MAC address (02:00:00:00:00:[epid])*/
1410ed088907SJakub Kicinski 	addr[0] = 2;
1411ed088907SJakub Kicinski 	addr[1] = 0;
1412ed088907SJakub Kicinski 	addr[2] = 0;
1413ed088907SJakub Kicinski 	addr[3] = 0;
1414ed088907SJakub Kicinski 	addr[4] = 0;
1415ed088907SJakub Kicinski 	addr[5] = hw->my_epid; /* EPID */
1416ed088907SJakub Kicinski 	eth_hw_addr_set(netdev, addr);
14172fcbca68STaku Izumi 
14182fcbca68STaku Izumi 	err = register_netdev(netdev);
14192fcbca68STaku Izumi 	if (err)
14202fcbca68STaku Izumi 		goto err_hw_exit;
14212fcbca68STaku Izumi 
14222fcbca68STaku Izumi 	netif_carrier_off(netdev);
14232fcbca68STaku Izumi 
1424c753119eSTaku Izumi 	fjes_dbg_adapter_init(adapter);
1425c753119eSTaku Izumi 
1426658d439bSTaku Izumi 	return 0;
14272fcbca68STaku Izumi 
14282fcbca68STaku Izumi err_hw_exit:
14292fcbca68STaku Izumi 	fjes_hw_exit(&adapter->hw);
143085ac30faSWill Deacon err_free_control_wq:
143185ac30faSWill Deacon 	destroy_workqueue(adapter->control_wq);
143285ac30faSWill Deacon err_free_txrx_wq:
143385ac30faSWill Deacon 	destroy_workqueue(adapter->txrx_wq);
14342fcbca68STaku Izumi err_free_netdev:
14352fcbca68STaku Izumi 	free_netdev(netdev);
14362fcbca68STaku Izumi err_out:
14372fcbca68STaku Izumi 	return err;
1438658d439bSTaku Izumi }
1439658d439bSTaku Izumi 
1440658d439bSTaku Izumi /* fjes_remove - Device Removal Routine */
fjes_remove(struct platform_device * plat_dev)1441658d439bSTaku Izumi static int fjes_remove(struct platform_device *plat_dev)
1442658d439bSTaku Izumi {
14432fcbca68STaku Izumi 	struct net_device *netdev = dev_get_drvdata(&plat_dev->dev);
14442fcbca68STaku Izumi 	struct fjes_adapter *adapter = netdev_priv(netdev);
14452fcbca68STaku Izumi 	struct fjes_hw *hw = &adapter->hw;
14462fcbca68STaku Izumi 
1447c753119eSTaku Izumi 	fjes_dbg_adapter_exit(adapter);
1448c753119eSTaku Izumi 
14498edb62a8STaku Izumi 	cancel_delayed_work_sync(&adapter->interrupt_watch_task);
14508fc4cadbSTaku Izumi 	cancel_work_sync(&adapter->unshare_watch_task);
1451b772b9dcSTaku Izumi 	cancel_work_sync(&adapter->raise_intr_rxdata_task);
1452ac63b947STaku Izumi 	cancel_work_sync(&adapter->tx_stall_task);
14538edb62a8STaku Izumi 	if (adapter->control_wq)
14548edb62a8STaku Izumi 		destroy_workqueue(adapter->control_wq);
1455b772b9dcSTaku Izumi 	if (adapter->txrx_wq)
1456b772b9dcSTaku Izumi 		destroy_workqueue(adapter->txrx_wq);
1457b772b9dcSTaku Izumi 
14582fcbca68STaku Izumi 	unregister_netdev(netdev);
14592fcbca68STaku Izumi 
14602fcbca68STaku Izumi 	fjes_hw_exit(hw);
14612fcbca68STaku Izumi 
146226585930STaku Izumi 	netif_napi_del(&adapter->napi);
146326585930STaku Izumi 
14642fcbca68STaku Izumi 	free_netdev(netdev);
14652fcbca68STaku Izumi 
1466658d439bSTaku Izumi 	return 0;
1467658d439bSTaku Izumi }
1468658d439bSTaku Izumi 
1469fa2aee65SUwe Kleine-König static struct platform_driver fjes_driver = {
1470fa2aee65SUwe Kleine-König 	.driver = {
1471fa2aee65SUwe Kleine-König 		.name = DRV_NAME,
1472fa2aee65SUwe Kleine-König 	},
1473fa2aee65SUwe Kleine-König 	.probe = fjes_probe,
1474fa2aee65SUwe Kleine-König 	.remove = fjes_remove,
1475fa2aee65SUwe Kleine-König };
14768fc4cadbSTaku Izumi 
1477ac23d3caSYasuaki Ishimatsu static acpi_status
acpi_find_extended_socket_device(acpi_handle obj_handle,u32 level,void * context,void ** return_value)1478ac23d3caSYasuaki Ishimatsu acpi_find_extended_socket_device(acpi_handle obj_handle, u32 level,
1479ac23d3caSYasuaki Ishimatsu 				 void *context, void **return_value)
1480ac23d3caSYasuaki Ishimatsu {
1481ac23d3caSYasuaki Ishimatsu 	struct acpi_device *device;
1482ac23d3caSYasuaki Ishimatsu 	bool *found = context;
1483ac23d3caSYasuaki Ishimatsu 
148452dae93fSRafael J. Wysocki 	device = acpi_fetch_acpi_dev(obj_handle);
148552dae93fSRafael J. Wysocki 	if (!device)
1486ac23d3caSYasuaki Ishimatsu 		return AE_OK;
1487ac23d3caSYasuaki Ishimatsu 
1488ac23d3caSYasuaki Ishimatsu 	if (strcmp(acpi_device_hid(device), ACPI_MOTHERBOARD_RESOURCE_HID))
1489ac23d3caSYasuaki Ishimatsu 		return AE_OK;
1490ac23d3caSYasuaki Ishimatsu 
1491ac23d3caSYasuaki Ishimatsu 	if (!is_extended_socket_device(device))
1492ac23d3caSYasuaki Ishimatsu 		return AE_OK;
1493ac23d3caSYasuaki Ishimatsu 
14942b396d30SYasuaki Ishimatsu 	if (acpi_check_extended_socket_status(device))
14952b396d30SYasuaki Ishimatsu 		return AE_OK;
14962b396d30SYasuaki Ishimatsu 
1497ac23d3caSYasuaki Ishimatsu 	*found = true;
1498ac23d3caSYasuaki Ishimatsu 	return AE_CTRL_TERMINATE;
1499ac23d3caSYasuaki Ishimatsu }
1500ac23d3caSYasuaki Ishimatsu 
1501658d439bSTaku Izumi /* fjes_init_module - Driver Registration Routine */
fjes_init_module(void)1502658d439bSTaku Izumi static int __init fjes_init_module(void)
1503658d439bSTaku Izumi {
1504ac23d3caSYasuaki Ishimatsu 	bool found = false;
1505658d439bSTaku Izumi 	int result;
1506658d439bSTaku Izumi 
1507ac23d3caSYasuaki Ishimatsu 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
1508ac23d3caSYasuaki Ishimatsu 			    acpi_find_extended_socket_device, NULL, &found,
1509ac23d3caSYasuaki Ishimatsu 			    NULL);
1510ac23d3caSYasuaki Ishimatsu 
1511ac23d3caSYasuaki Ishimatsu 	if (!found)
1512ac23d3caSYasuaki Ishimatsu 		return -ENODEV;
1513ac23d3caSYasuaki Ishimatsu 
1514658d439bSTaku Izumi 	pr_info("%s - version %s - %s\n",
1515658d439bSTaku Izumi 		fjes_driver_string, fjes_driver_version, fjes_copyright);
1516658d439bSTaku Izumi 
1517c753119eSTaku Izumi 	fjes_dbg_init();
1518c753119eSTaku Izumi 
1519658d439bSTaku Izumi 	result = platform_driver_register(&fjes_driver);
1520c753119eSTaku Izumi 	if (result < 0) {
1521c753119eSTaku Izumi 		fjes_dbg_exit();
1522658d439bSTaku Izumi 		return result;
1523c753119eSTaku Izumi 	}
1524658d439bSTaku Izumi 
1525658d439bSTaku Izumi 	result = acpi_bus_register_driver(&fjes_acpi_driver);
1526658d439bSTaku Izumi 	if (result < 0)
1527658d439bSTaku Izumi 		goto fail_acpi_driver;
1528658d439bSTaku Izumi 
1529658d439bSTaku Izumi 	return 0;
1530658d439bSTaku Izumi 
1531658d439bSTaku Izumi fail_acpi_driver:
1532658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
1533c753119eSTaku Izumi 	fjes_dbg_exit();
1534658d439bSTaku Izumi 	return result;
1535658d439bSTaku Izumi }
1536658d439bSTaku Izumi 
1537658d439bSTaku Izumi module_init(fjes_init_module);
1538658d439bSTaku Izumi 
1539658d439bSTaku Izumi /* fjes_exit_module - Driver Exit Cleanup Routine */
fjes_exit_module(void)1540658d439bSTaku Izumi static void __exit fjes_exit_module(void)
1541658d439bSTaku Izumi {
1542658d439bSTaku Izumi 	acpi_bus_unregister_driver(&fjes_acpi_driver);
1543658d439bSTaku Izumi 	platform_driver_unregister(&fjes_driver);
1544c753119eSTaku Izumi 	fjes_dbg_exit();
1545658d439bSTaku Izumi }
1546658d439bSTaku Izumi 
1547658d439bSTaku Izumi module_exit(fjes_exit_module);
1548