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 *)¶m, 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, ¶m);
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