18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FUJITSU Extended Socket Network Device driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2015 FUJITSU LIMITED 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/nls.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "fjes.h" 158c2ecf20Sopenharmony_ci#include "fjes_trace.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define MAJ 1 188c2ecf20Sopenharmony_ci#define MIN 2 198c2ecf20Sopenharmony_ci#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) 208c2ecf20Sopenharmony_ci#define DRV_NAME "fjes" 218c2ecf20Sopenharmony_cichar fjes_driver_name[] = DRV_NAME; 228c2ecf20Sopenharmony_cichar fjes_driver_version[] = DRV_VERSION; 238c2ecf20Sopenharmony_cistatic const char fjes_driver_string[] = 248c2ecf20Sopenharmony_ci "FUJITSU Extended Socket Network Device Driver"; 258c2ecf20Sopenharmony_cistatic const char fjes_copyright[] = 268c2ecf20Sopenharmony_ci "Copyright (c) 2015 FUJITSU LIMITED"; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>"); 298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); 308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 318c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define ACPI_MOTHERBOARD_RESOURCE_HID "PNP0C02" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int fjes_request_irq(struct fjes_adapter *); 368c2ecf20Sopenharmony_cistatic void fjes_free_irq(struct fjes_adapter *); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int fjes_open(struct net_device *); 398c2ecf20Sopenharmony_cistatic int fjes_close(struct net_device *); 408c2ecf20Sopenharmony_cistatic int fjes_setup_resources(struct fjes_adapter *); 418c2ecf20Sopenharmony_cistatic void fjes_free_resources(struct fjes_adapter *); 428c2ecf20Sopenharmony_cistatic netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); 438c2ecf20Sopenharmony_cistatic void fjes_raise_intr_rxdata_task(struct work_struct *); 448c2ecf20Sopenharmony_cistatic void fjes_tx_stall_task(struct work_struct *); 458c2ecf20Sopenharmony_cistatic void fjes_force_close_task(struct work_struct *); 468c2ecf20Sopenharmony_cistatic irqreturn_t fjes_intr(int, void*); 478c2ecf20Sopenharmony_cistatic void fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); 488c2ecf20Sopenharmony_cistatic int fjes_change_mtu(struct net_device *, int); 498c2ecf20Sopenharmony_cistatic int fjes_vlan_rx_add_vid(struct net_device *, __be16 proto, u16); 508c2ecf20Sopenharmony_cistatic int fjes_vlan_rx_kill_vid(struct net_device *, __be16 proto, u16); 518c2ecf20Sopenharmony_cistatic void fjes_tx_retry(struct net_device *, unsigned int txqueue); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int fjes_acpi_add(struct acpi_device *); 548c2ecf20Sopenharmony_cistatic int fjes_acpi_remove(struct acpi_device *); 558c2ecf20Sopenharmony_cistatic acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int fjes_probe(struct platform_device *); 588c2ecf20Sopenharmony_cistatic int fjes_remove(struct platform_device *); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int fjes_sw_init(struct fjes_adapter *); 618c2ecf20Sopenharmony_cistatic void fjes_netdev_setup(struct net_device *); 628c2ecf20Sopenharmony_cistatic void fjes_irq_watch_task(struct work_struct *); 638c2ecf20Sopenharmony_cistatic void fjes_watch_unshare_task(struct work_struct *); 648c2ecf20Sopenharmony_cistatic void fjes_rx_irq(struct fjes_adapter *, int); 658c2ecf20Sopenharmony_cistatic int fjes_poll(struct napi_struct *, int); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const struct acpi_device_id fjes_acpi_ids[] = { 688c2ecf20Sopenharmony_ci {ACPI_MOTHERBOARD_RESOURCE_HID, 0}, 698c2ecf20Sopenharmony_ci {"", 0}, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, fjes_acpi_ids); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic struct acpi_driver fjes_acpi_driver = { 748c2ecf20Sopenharmony_ci .name = DRV_NAME, 758c2ecf20Sopenharmony_ci .class = DRV_NAME, 768c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 778c2ecf20Sopenharmony_ci .ids = fjes_acpi_ids, 788c2ecf20Sopenharmony_ci .ops = { 798c2ecf20Sopenharmony_ci .add = fjes_acpi_add, 808c2ecf20Sopenharmony_ci .remove = fjes_acpi_remove, 818c2ecf20Sopenharmony_ci }, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic struct platform_driver fjes_driver = { 858c2ecf20Sopenharmony_ci .driver = { 868c2ecf20Sopenharmony_ci .name = DRV_NAME, 878c2ecf20Sopenharmony_ci }, 888c2ecf20Sopenharmony_ci .probe = fjes_probe, 898c2ecf20Sopenharmony_ci .remove = fjes_remove, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct resource fjes_resource[] = { 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 958c2ecf20Sopenharmony_ci .start = 0, 968c2ecf20Sopenharmony_ci .end = 0, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 1008c2ecf20Sopenharmony_ci .start = 0, 1018c2ecf20Sopenharmony_ci .end = 0, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic bool is_extended_socket_device(struct acpi_device *device) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 1088c2ecf20Sopenharmony_ci char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1]; 1098c2ecf20Sopenharmony_ci union acpi_object *str; 1108c2ecf20Sopenharmony_ci acpi_status status; 1118c2ecf20Sopenharmony_ci int result; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer); 1148c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1158c2ecf20Sopenharmony_ci return false; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci str = buffer.pointer; 1188c2ecf20Sopenharmony_ci result = utf16s_to_utf8s((wchar_t *)str->string.pointer, 1198c2ecf20Sopenharmony_ci str->string.length, UTF16_LITTLE_ENDIAN, 1208c2ecf20Sopenharmony_ci str_buf, sizeof(str_buf) - 1); 1218c2ecf20Sopenharmony_ci str_buf[result] = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) { 1248c2ecf20Sopenharmony_ci kfree(buffer.pointer); 1258c2ecf20Sopenharmony_ci return false; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci kfree(buffer.pointer); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return true; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int acpi_check_extended_socket_status(struct acpi_device *device) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci unsigned long long sta; 1358c2ecf20Sopenharmony_ci acpi_status status; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(device->handle, "_STA", NULL, &sta); 1388c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1398c2ecf20Sopenharmony_ci return -ENODEV; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!((sta & ACPI_STA_DEVICE_PRESENT) && 1428c2ecf20Sopenharmony_ci (sta & ACPI_STA_DEVICE_ENABLED) && 1438c2ecf20Sopenharmony_ci (sta & ACPI_STA_DEVICE_UI) && 1448c2ecf20Sopenharmony_ci (sta & ACPI_STA_DEVICE_FUNCTIONING))) 1458c2ecf20Sopenharmony_ci return -ENODEV; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int fjes_acpi_add(struct acpi_device *device) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct platform_device *plat_dev; 1538c2ecf20Sopenharmony_ci acpi_status status; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!is_extended_socket_device(device)) 1568c2ecf20Sopenharmony_ci return -ENODEV; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (acpi_check_extended_socket_status(device)) 1598c2ecf20Sopenharmony_ci return -ENODEV; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, 1628c2ecf20Sopenharmony_ci fjes_get_acpi_resource, fjes_resource); 1638c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1648c2ecf20Sopenharmony_ci return -ENODEV; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* create platform_device */ 1678c2ecf20Sopenharmony_ci plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource, 1688c2ecf20Sopenharmony_ci ARRAY_SIZE(fjes_resource)); 1698c2ecf20Sopenharmony_ci if (IS_ERR(plat_dev)) 1708c2ecf20Sopenharmony_ci return PTR_ERR(plat_dev); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci device->driver_data = plat_dev; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int fjes_acpi_remove(struct acpi_device *device) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct platform_device *plat_dev; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci plat_dev = (struct platform_device *)acpi_driver_data(device); 1828c2ecf20Sopenharmony_ci platform_device_unregister(plat_dev); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic acpi_status 1888c2ecf20Sopenharmony_cifjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct acpi_resource_address32 *addr; 1918c2ecf20Sopenharmony_ci struct acpi_resource_irq *irq; 1928c2ecf20Sopenharmony_ci struct resource *res = data; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci switch (acpi_res->type) { 1958c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 1968c2ecf20Sopenharmony_ci addr = &acpi_res->data.address32; 1978c2ecf20Sopenharmony_ci res[0].start = addr->address.minimum; 1988c2ecf20Sopenharmony_ci res[0].end = addr->address.minimum + 1998c2ecf20Sopenharmony_ci addr->address.address_length - 1; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 2038c2ecf20Sopenharmony_ci irq = &acpi_res->data.irq; 2048c2ecf20Sopenharmony_ci if (irq->interrupt_count != 1) 2058c2ecf20Sopenharmony_ci return AE_ERROR; 2068c2ecf20Sopenharmony_ci res[1].start = irq->interrupts[0]; 2078c2ecf20Sopenharmony_ci res[1].end = irq->interrupts[0]; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci default: 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return AE_OK; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int fjes_request_irq(struct fjes_adapter *adapter) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 2208c2ecf20Sopenharmony_ci int result = -1; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci adapter->interrupt_watch_enable = true; 2238c2ecf20Sopenharmony_ci if (!delayed_work_pending(&adapter->interrupt_watch_task)) { 2248c2ecf20Sopenharmony_ci queue_delayed_work(adapter->control_wq, 2258c2ecf20Sopenharmony_ci &adapter->interrupt_watch_task, 2268c2ecf20Sopenharmony_ci FJES_IRQ_WATCH_DELAY); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!adapter->irq_registered) { 2308c2ecf20Sopenharmony_ci result = request_irq(adapter->hw.hw_res.irq, fjes_intr, 2318c2ecf20Sopenharmony_ci IRQF_SHARED, netdev->name, adapter); 2328c2ecf20Sopenharmony_ci if (result) 2338c2ecf20Sopenharmony_ci adapter->irq_registered = false; 2348c2ecf20Sopenharmony_ci else 2358c2ecf20Sopenharmony_ci adapter->irq_registered = true; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return result; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void fjes_free_irq(struct fjes_adapter *adapter) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci adapter->interrupt_watch_enable = false; 2468c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->interrupt_watch_task); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (adapter->irq_registered) { 2518c2ecf20Sopenharmony_ci free_irq(adapter->hw.hw_res.irq, adapter); 2528c2ecf20Sopenharmony_ci adapter->irq_registered = false; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct net_device_ops fjes_netdev_ops = { 2578c2ecf20Sopenharmony_ci .ndo_open = fjes_open, 2588c2ecf20Sopenharmony_ci .ndo_stop = fjes_close, 2598c2ecf20Sopenharmony_ci .ndo_start_xmit = fjes_xmit_frame, 2608c2ecf20Sopenharmony_ci .ndo_get_stats64 = fjes_get_stats64, 2618c2ecf20Sopenharmony_ci .ndo_change_mtu = fjes_change_mtu, 2628c2ecf20Sopenharmony_ci .ndo_tx_timeout = fjes_tx_retry, 2638c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = fjes_vlan_rx_add_vid, 2648c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid, 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* fjes_open - Called when a network interface is made active */ 2688c2ecf20Sopenharmony_cistatic int fjes_open(struct net_device *netdev) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 2718c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 2728c2ecf20Sopenharmony_ci int result; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (adapter->open_guard) 2758c2ecf20Sopenharmony_ci return -ENXIO; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci result = fjes_setup_resources(adapter); 2788c2ecf20Sopenharmony_ci if (result) 2798c2ecf20Sopenharmony_ci goto err_setup_res; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci hw->txrx_stop_req_bit = 0; 2828c2ecf20Sopenharmony_ci hw->epstop_req_bit = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci napi_enable(&adapter->napi); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci fjes_hw_capture_interrupt_status(hw); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci result = fjes_request_irq(adapter); 2898c2ecf20Sopenharmony_ci if (result) 2908c2ecf20Sopenharmony_ci goto err_req_irq; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, false); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci netif_tx_start_all_queues(netdev); 2958c2ecf20Sopenharmony_ci netif_carrier_on(netdev); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cierr_req_irq: 3008c2ecf20Sopenharmony_ci fjes_free_irq(adapter); 3018c2ecf20Sopenharmony_ci napi_disable(&adapter->napi); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cierr_setup_res: 3048c2ecf20Sopenharmony_ci fjes_free_resources(adapter); 3058c2ecf20Sopenharmony_ci return result; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* fjes_close - Disables a network interface */ 3098c2ecf20Sopenharmony_cistatic int fjes_close(struct net_device *netdev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 3128c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 3138c2ecf20Sopenharmony_ci unsigned long flags; 3148c2ecf20Sopenharmony_ci int epidx; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(netdev); 3178c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci fjes_hw_raise_epstop(hw); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci napi_disable(&adapter->napi); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 3248c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 3258c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 3268c2ecf20Sopenharmony_ci continue; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (fjes_hw_get_partner_ep_status(hw, epidx) == 3298c2ecf20Sopenharmony_ci EP_PARTNER_SHARED) 3308c2ecf20Sopenharmony_ci adapter->hw.ep_shm_info[epidx] 3318c2ecf20Sopenharmony_ci .tx.info->v1i.rx_status &= 3328c2ecf20Sopenharmony_ci ~FJES_RX_POLL_WORK; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci fjes_free_irq(adapter); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->interrupt_watch_task); 3398c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->unshare_watch_task); 3408c2ecf20Sopenharmony_ci adapter->unshare_watch_bitmask = 0; 3418c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->raise_intr_rxdata_task); 3428c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->tx_stall_task); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci cancel_work_sync(&hw->update_zone_task); 3458c2ecf20Sopenharmony_ci cancel_work_sync(&hw->epstop_task); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci fjes_hw_wait_epstop(hw); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci fjes_free_resources(adapter); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int fjes_setup_resources(struct fjes_adapter *adapter) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 3578c2ecf20Sopenharmony_ci struct ep_share_mem_info *buf_pair; 3588c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 3598c2ecf20Sopenharmony_ci unsigned long flags; 3608c2ecf20Sopenharmony_ci int result; 3618c2ecf20Sopenharmony_ci int epidx; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mutex_lock(&hw->hw_info.lock); 3648c2ecf20Sopenharmony_ci result = fjes_hw_request_info(hw); 3658c2ecf20Sopenharmony_ci switch (result) { 3668c2ecf20Sopenharmony_ci case 0: 3678c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 3688c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].es_status = 3698c2ecf20Sopenharmony_ci hw->hw_info.res_buf->info.info[epidx].es_status; 3708c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].zone = 3718c2ecf20Sopenharmony_ci hw->hw_info.res_buf->info.info[epidx].zone; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci default: 3758c2ecf20Sopenharmony_ci case -ENOMSG: 3768c2ecf20Sopenharmony_ci case -EBUSY: 3778c2ecf20Sopenharmony_ci adapter->force_reset = true; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 3808c2ecf20Sopenharmony_ci return result; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci for (epidx = 0; epidx < (hw->max_epid); epidx++) { 3858c2ecf20Sopenharmony_ci if ((epidx != hw->my_epid) && 3868c2ecf20Sopenharmony_ci (hw->ep_shm_info[epidx].es_status == 3878c2ecf20Sopenharmony_ci FJES_ZONING_STATUS_ENABLE)) { 3888c2ecf20Sopenharmony_ci fjes_hw_raise_interrupt(hw, epidx, 3898c2ecf20Sopenharmony_ci REG_ICTL_MASK_INFO_UPDATE); 3908c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].ep_stats 3918c2ecf20Sopenharmony_ci .send_intr_zoneupdate += 1; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci msleep(FJES_OPEN_ZONE_UPDATE_WAIT * hw->max_epid); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci for (epidx = 0; epidx < (hw->max_epid); epidx++) { 3988c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 3998c2ecf20Sopenharmony_ci continue; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci buf_pair = &hw->ep_shm_info[epidx]; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 4048c2ecf20Sopenharmony_ci fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr, 4058c2ecf20Sopenharmony_ci netdev->mtu); 4068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (fjes_hw_epid_is_same_zone(hw, epidx)) { 4098c2ecf20Sopenharmony_ci mutex_lock(&hw->hw_info.lock); 4108c2ecf20Sopenharmony_ci result = 4118c2ecf20Sopenharmony_ci fjes_hw_register_buff_addr(hw, epidx, buf_pair); 4128c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci switch (result) { 4158c2ecf20Sopenharmony_ci case 0: 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case -ENOMSG: 4188c2ecf20Sopenharmony_ci case -EBUSY: 4198c2ecf20Sopenharmony_ci default: 4208c2ecf20Sopenharmony_ci adapter->force_reset = true; 4218c2ecf20Sopenharmony_ci return result; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].ep_stats 4258c2ecf20Sopenharmony_ci .com_regist_buf_exec += 1; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void fjes_free_resources(struct fjes_adapter *adapter) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 4358c2ecf20Sopenharmony_ci struct fjes_device_command_param param; 4368c2ecf20Sopenharmony_ci struct ep_share_mem_info *buf_pair; 4378c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 4388c2ecf20Sopenharmony_ci bool reset_flag = false; 4398c2ecf20Sopenharmony_ci unsigned long flags; 4408c2ecf20Sopenharmony_ci int result; 4418c2ecf20Sopenharmony_ci int epidx; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 4448c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 4458c2ecf20Sopenharmony_ci continue; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci mutex_lock(&hw->hw_info.lock); 4488c2ecf20Sopenharmony_ci result = fjes_hw_unregister_buff_addr(hw, epidx); 4498c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].ep_stats.com_unregist_buf_exec += 1; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (result) 4548c2ecf20Sopenharmony_ci reset_flag = true; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci buf_pair = &hw->ep_shm_info[epidx]; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 4598c2ecf20Sopenharmony_ci fjes_hw_setup_epbuf(&buf_pair->tx, 4608c2ecf20Sopenharmony_ci netdev->dev_addr, netdev->mtu); 4618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci clear_bit(epidx, &hw->txrx_stop_req_bit); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (reset_flag || adapter->force_reset) { 4678c2ecf20Sopenharmony_ci result = fjes_hw_reset(hw); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci adapter->force_reset = false; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (result) 4728c2ecf20Sopenharmony_ci adapter->open_guard = true; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci hw->hw_info.buffer_share_bit = 0; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci memset((void *)¶m, 0, sizeof(param)); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci param.req_len = hw->hw_info.req_buf_size; 4798c2ecf20Sopenharmony_ci param.req_start = __pa(hw->hw_info.req_buf); 4808c2ecf20Sopenharmony_ci param.res_len = hw->hw_info.res_buf_size; 4818c2ecf20Sopenharmony_ci param.res_start = __pa(hw->hw_info.res_buf); 4828c2ecf20Sopenharmony_ci param.share_start = __pa(hw->hw_info.share->ep_status); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci fjes_hw_init_command_registers(hw, ¶m); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void fjes_tx_stall_task(struct work_struct *work) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = container_of(work, 4918c2ecf20Sopenharmony_ci struct fjes_adapter, tx_stall_task); 4928c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 4938c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 4948c2ecf20Sopenharmony_ci int all_queue_available, sendable; 4958c2ecf20Sopenharmony_ci enum ep_partner_status pstatus; 4968c2ecf20Sopenharmony_ci int max_epid, my_epid, epid; 4978c2ecf20Sopenharmony_ci union ep_buffer_info *info; 4988c2ecf20Sopenharmony_ci int i; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (((long)jiffies - 5018c2ecf20Sopenharmony_ci dev_trans_start(netdev)) > FJES_TX_TX_STALL_TIMEOUT) { 5028c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci my_epid = hw->my_epid; 5078c2ecf20Sopenharmony_ci max_epid = hw->max_epid; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 5108c2ecf20Sopenharmony_ci all_queue_available = 1; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci for (epid = 0; epid < max_epid; epid++) { 5138c2ecf20Sopenharmony_ci if (my_epid == epid) 5148c2ecf20Sopenharmony_ci continue; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci pstatus = fjes_hw_get_partner_ep_status(hw, epid); 5178c2ecf20Sopenharmony_ci sendable = (pstatus == EP_PARTNER_SHARED); 5188c2ecf20Sopenharmony_ci if (!sendable) 5198c2ecf20Sopenharmony_ci continue; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci info = adapter->hw.ep_shm_info[epid].tx.info; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (!(info->v1i.rx_status & FJES_RX_MTU_CHANGING_DONE)) 5248c2ecf20Sopenharmony_ci return; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (EP_RING_FULL(info->v1i.head, info->v1i.tail, 5278c2ecf20Sopenharmony_ci info->v1i.count_max)) { 5288c2ecf20Sopenharmony_ci all_queue_available = 0; 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (all_queue_available) { 5348c2ecf20Sopenharmony_ci netif_wake_queue(netdev); 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci usleep_range(50, 100); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci queue_work(adapter->txrx_wq, &adapter->tx_stall_task); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void fjes_force_close_task(struct work_struct *work) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = container_of(work, 5478c2ecf20Sopenharmony_ci struct fjes_adapter, force_close_task); 5488c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci rtnl_lock(); 5518c2ecf20Sopenharmony_ci dev_close(netdev); 5528c2ecf20Sopenharmony_ci rtnl_unlock(); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void fjes_raise_intr_rxdata_task(struct work_struct *work) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = container_of(work, 5588c2ecf20Sopenharmony_ci struct fjes_adapter, raise_intr_rxdata_task); 5598c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 5608c2ecf20Sopenharmony_ci enum ep_partner_status pstatus; 5618c2ecf20Sopenharmony_ci int max_epid, my_epid, epid; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci my_epid = hw->my_epid; 5648c2ecf20Sopenharmony_ci max_epid = hw->max_epid; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci for (epid = 0; epid < max_epid; epid++) 5678c2ecf20Sopenharmony_ci hw->ep_shm_info[epid].tx_status_work = 0; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci for (epid = 0; epid < max_epid; epid++) { 5708c2ecf20Sopenharmony_ci if (epid == my_epid) 5718c2ecf20Sopenharmony_ci continue; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci pstatus = fjes_hw_get_partner_ep_status(hw, epid); 5748c2ecf20Sopenharmony_ci if (pstatus == EP_PARTNER_SHARED) { 5758c2ecf20Sopenharmony_ci hw->ep_shm_info[epid].tx_status_work = 5768c2ecf20Sopenharmony_ci hw->ep_shm_info[epid].tx.info->v1i.tx_status; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (hw->ep_shm_info[epid].tx_status_work == 5798c2ecf20Sopenharmony_ci FJES_TX_DELAY_SEND_PENDING) { 5808c2ecf20Sopenharmony_ci hw->ep_shm_info[epid].tx.info->v1i.tx_status = 5818c2ecf20Sopenharmony_ci FJES_TX_DELAY_SEND_NONE; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci for (epid = 0; epid < max_epid; epid++) { 5878c2ecf20Sopenharmony_ci if (epid == my_epid) 5888c2ecf20Sopenharmony_ci continue; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci pstatus = fjes_hw_get_partner_ep_status(hw, epid); 5918c2ecf20Sopenharmony_ci if ((hw->ep_shm_info[epid].tx_status_work == 5928c2ecf20Sopenharmony_ci FJES_TX_DELAY_SEND_PENDING) && 5938c2ecf20Sopenharmony_ci (pstatus == EP_PARTNER_SHARED) && 5948c2ecf20Sopenharmony_ci !(hw->ep_shm_info[epid].rx.info->v1i.rx_status & 5958c2ecf20Sopenharmony_ci FJES_RX_POLL_WORK)) { 5968c2ecf20Sopenharmony_ci fjes_hw_raise_interrupt(hw, epid, 5978c2ecf20Sopenharmony_ci REG_ICTL_MASK_RX_DATA); 5988c2ecf20Sopenharmony_ci hw->ep_shm_info[epid].ep_stats.send_intr_rx += 1; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci usleep_range(500, 1000); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int fjes_tx_send(struct fjes_adapter *adapter, int dest, 6068c2ecf20Sopenharmony_ci void *data, size_t len) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci int retval; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci retval = fjes_hw_epbuf_tx_pkt_send(&adapter->hw.ep_shm_info[dest].tx, 6118c2ecf20Sopenharmony_ci data, len); 6128c2ecf20Sopenharmony_ci if (retval) 6138c2ecf20Sopenharmony_ci return retval; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci adapter->hw.ep_shm_info[dest].tx.info->v1i.tx_status = 6168c2ecf20Sopenharmony_ci FJES_TX_DELAY_SEND_PENDING; 6178c2ecf20Sopenharmony_ci if (!work_pending(&adapter->raise_intr_rxdata_task)) 6188c2ecf20Sopenharmony_ci queue_work(adapter->txrx_wq, 6198c2ecf20Sopenharmony_ci &adapter->raise_intr_rxdata_task); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci retval = 0; 6228c2ecf20Sopenharmony_ci return retval; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic netdev_tx_t 6268c2ecf20Sopenharmony_cifjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 6298c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci int max_epid, my_epid, dest_epid; 6328c2ecf20Sopenharmony_ci enum ep_partner_status pstatus; 6338c2ecf20Sopenharmony_ci struct netdev_queue *cur_queue; 6348c2ecf20Sopenharmony_ci char shortpkt[VLAN_ETH_HLEN]; 6358c2ecf20Sopenharmony_ci bool is_multi, vlan; 6368c2ecf20Sopenharmony_ci struct ethhdr *eth; 6378c2ecf20Sopenharmony_ci u16 queue_no = 0; 6388c2ecf20Sopenharmony_ci u16 vlan_id = 0; 6398c2ecf20Sopenharmony_ci netdev_tx_t ret; 6408c2ecf20Sopenharmony_ci char *data; 6418c2ecf20Sopenharmony_ci int len; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 6448c2ecf20Sopenharmony_ci is_multi = false; 6458c2ecf20Sopenharmony_ci cur_queue = netdev_get_tx_queue(netdev, queue_no); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci eth = (struct ethhdr *)skb->data; 6488c2ecf20Sopenharmony_ci my_epid = hw->my_epid; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci vlan = (vlan_get_tag(skb, &vlan_id) == 0) ? true : false; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci data = skb->data; 6538c2ecf20Sopenharmony_ci len = skb->len; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(eth->h_dest)) { 6568c2ecf20Sopenharmony_ci dest_epid = 0; 6578c2ecf20Sopenharmony_ci max_epid = hw->max_epid; 6588c2ecf20Sopenharmony_ci is_multi = true; 6598c2ecf20Sopenharmony_ci } else if (is_local_ether_addr(eth->h_dest)) { 6608c2ecf20Sopenharmony_ci dest_epid = eth->h_dest[ETH_ALEN - 1]; 6618c2ecf20Sopenharmony_ci max_epid = dest_epid + 1; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if ((eth->h_dest[0] == 0x02) && 6648c2ecf20Sopenharmony_ci (0x00 == (eth->h_dest[1] | eth->h_dest[2] | 6658c2ecf20Sopenharmony_ci eth->h_dest[3] | eth->h_dest[4])) && 6668c2ecf20Sopenharmony_ci (dest_epid < hw->max_epid)) { 6678c2ecf20Sopenharmony_ci ; 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci dest_epid = 0; 6708c2ecf20Sopenharmony_ci max_epid = 0; 6718c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci adapter->stats64.tx_packets += 1; 6748c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; 6758c2ecf20Sopenharmony_ci adapter->stats64.tx_bytes += len; 6768c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci } else { 6798c2ecf20Sopenharmony_ci dest_epid = 0; 6808c2ecf20Sopenharmony_ci max_epid = 0; 6818c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci adapter->stats64.tx_packets += 1; 6848c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; 6858c2ecf20Sopenharmony_ci adapter->stats64.tx_bytes += len; 6868c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci for (; dest_epid < max_epid; dest_epid++) { 6908c2ecf20Sopenharmony_ci if (my_epid == dest_epid) 6918c2ecf20Sopenharmony_ci continue; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci pstatus = fjes_hw_get_partner_ep_status(hw, dest_epid); 6948c2ecf20Sopenharmony_ci if (pstatus != EP_PARTNER_SHARED) { 6958c2ecf20Sopenharmony_ci if (!is_multi) 6968c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].ep_stats 6978c2ecf20Sopenharmony_ci .tx_dropped_not_shared += 1; 6988c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 6998c2ecf20Sopenharmony_ci } else if (!fjes_hw_check_epbuf_version( 7008c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[dest_epid].rx, 0)) { 7018c2ecf20Sopenharmony_ci /* version is NOT 0 */ 7028c2ecf20Sopenharmony_ci adapter->stats64.tx_carrier_errors += 1; 7038c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats 7048c2ecf20Sopenharmony_ci .tx_carrier_errors += 1; 7058c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].ep_stats 7068c2ecf20Sopenharmony_ci .tx_dropped_ver_mismatch += 1; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7098c2ecf20Sopenharmony_ci } else if (!fjes_hw_check_mtu( 7108c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[dest_epid].rx, 7118c2ecf20Sopenharmony_ci netdev->mtu)) { 7128c2ecf20Sopenharmony_ci adapter->stats64.tx_dropped += 1; 7138c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats.tx_dropped += 1; 7148c2ecf20Sopenharmony_ci adapter->stats64.tx_errors += 1; 7158c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats.tx_errors += 1; 7168c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].ep_stats 7178c2ecf20Sopenharmony_ci .tx_dropped_buf_size_mismatch += 1; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7208c2ecf20Sopenharmony_ci } else if (vlan && 7218c2ecf20Sopenharmony_ci !fjes_hw_check_vlan_id( 7228c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[dest_epid].rx, 7238c2ecf20Sopenharmony_ci vlan_id)) { 7248c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].ep_stats 7258c2ecf20Sopenharmony_ci .tx_dropped_vlanid_mismatch += 1; 7268c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7278c2ecf20Sopenharmony_ci } else { 7288c2ecf20Sopenharmony_ci if (len < VLAN_ETH_HLEN) { 7298c2ecf20Sopenharmony_ci memset(shortpkt, 0, VLAN_ETH_HLEN); 7308c2ecf20Sopenharmony_ci memcpy(shortpkt, skb->data, skb->len); 7318c2ecf20Sopenharmony_ci len = VLAN_ETH_HLEN; 7328c2ecf20Sopenharmony_ci data = shortpkt; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (adapter->tx_retry_count == 0) { 7368c2ecf20Sopenharmony_ci adapter->tx_start_jiffies = jiffies; 7378c2ecf20Sopenharmony_ci adapter->tx_retry_count = 1; 7388c2ecf20Sopenharmony_ci } else { 7398c2ecf20Sopenharmony_ci adapter->tx_retry_count++; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (fjes_tx_send(adapter, dest_epid, data, len)) { 7438c2ecf20Sopenharmony_ci if (is_multi) { 7448c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7458c2ecf20Sopenharmony_ci } else if ( 7468c2ecf20Sopenharmony_ci ((long)jiffies - 7478c2ecf20Sopenharmony_ci (long)adapter->tx_start_jiffies) >= 7488c2ecf20Sopenharmony_ci FJES_TX_RETRY_TIMEOUT) { 7498c2ecf20Sopenharmony_ci adapter->stats64.tx_fifo_errors += 1; 7508c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats 7518c2ecf20Sopenharmony_ci .tx_fifo_errors += 1; 7528c2ecf20Sopenharmony_ci adapter->stats64.tx_errors += 1; 7538c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats 7548c2ecf20Sopenharmony_ci .tx_errors += 1; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7578c2ecf20Sopenharmony_ci } else { 7588c2ecf20Sopenharmony_ci netif_trans_update(netdev); 7598c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].ep_stats 7608c2ecf20Sopenharmony_ci .tx_buffer_full += 1; 7618c2ecf20Sopenharmony_ci netif_tx_stop_queue(cur_queue); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (!work_pending(&adapter->tx_stall_task)) 7648c2ecf20Sopenharmony_ci queue_work(adapter->txrx_wq, 7658c2ecf20Sopenharmony_ci &adapter->tx_stall_task); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci ret = NETDEV_TX_BUSY; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } else { 7708c2ecf20Sopenharmony_ci if (!is_multi) { 7718c2ecf20Sopenharmony_ci adapter->stats64.tx_packets += 1; 7728c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats 7738c2ecf20Sopenharmony_ci .tx_packets += 1; 7748c2ecf20Sopenharmony_ci adapter->stats64.tx_bytes += len; 7758c2ecf20Sopenharmony_ci hw->ep_shm_info[dest_epid].net_stats 7768c2ecf20Sopenharmony_ci .tx_bytes += len; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci adapter->tx_retry_count = 0; 7808c2ecf20Sopenharmony_ci ret = NETDEV_TX_OK; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (ret == NETDEV_TX_OK) { 7868c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 7878c2ecf20Sopenharmony_ci if (is_multi) { 7888c2ecf20Sopenharmony_ci adapter->stats64.tx_packets += 1; 7898c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; 7908c2ecf20Sopenharmony_ci adapter->stats64.tx_bytes += 1; 7918c2ecf20Sopenharmony_ci hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return ret; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic void fjes_tx_retry(struct net_device *netdev, unsigned int txqueue) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct netdev_queue *queue = netdev_get_tx_queue(netdev, 0); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci netif_tx_wake_queue(queue); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic void 8068c2ecf20Sopenharmony_cifjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci memcpy(stats, &adapter->stats64, sizeof(struct rtnl_link_stats64)); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int fjes_change_mtu(struct net_device *netdev, int new_mtu) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 8168c2ecf20Sopenharmony_ci bool running = netif_running(netdev); 8178c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 8188c2ecf20Sopenharmony_ci unsigned long flags; 8198c2ecf20Sopenharmony_ci int ret = -EINVAL; 8208c2ecf20Sopenharmony_ci int idx, epidx; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci for (idx = 0; fjes_support_mtu[idx] != 0; idx++) { 8238c2ecf20Sopenharmony_ci if (new_mtu <= fjes_support_mtu[idx]) { 8248c2ecf20Sopenharmony_ci new_mtu = fjes_support_mtu[idx]; 8258c2ecf20Sopenharmony_ci if (new_mtu == netdev->mtu) 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci ret = 0; 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (ret) 8348c2ecf20Sopenharmony_ci return ret; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (running) { 8378c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 8388c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 8398c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 8408c2ecf20Sopenharmony_ci continue; 8418c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].tx.info->v1i.rx_status &= 8428c2ecf20Sopenharmony_ci ~FJES_RX_MTU_CHANGING_DONE; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(netdev); 8478c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 8488c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->tx_stall_task); 8498c2ecf20Sopenharmony_ci napi_disable(&adapter->napi); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci msleep(1000); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(netdev); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci netdev->mtu = new_mtu; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (running) { 8598c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 8608c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 8618c2ecf20Sopenharmony_ci continue; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 8648c2ecf20Sopenharmony_ci fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx, 8658c2ecf20Sopenharmony_ci netdev->dev_addr, 8668c2ecf20Sopenharmony_ci netdev->mtu); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].tx.info->v1i.rx_status |= 8698c2ecf20Sopenharmony_ci FJES_RX_MTU_CHANGING_DONE; 8708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(netdev); 8748c2ecf20Sopenharmony_ci netif_carrier_on(netdev); 8758c2ecf20Sopenharmony_ci napi_enable(&adapter->napi); 8768c2ecf20Sopenharmony_ci napi_schedule(&adapter->napi); 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci return ret; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic int fjes_vlan_rx_add_vid(struct net_device *netdev, 8838c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 8868c2ecf20Sopenharmony_ci bool ret = true; 8878c2ecf20Sopenharmony_ci int epid; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci for (epid = 0; epid < adapter->hw.max_epid; epid++) { 8908c2ecf20Sopenharmony_ci if (epid == adapter->hw.my_epid) 8918c2ecf20Sopenharmony_ci continue; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (!fjes_hw_check_vlan_id( 8948c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[epid].tx, vid)) 8958c2ecf20Sopenharmony_ci ret = fjes_hw_set_vlan_id( 8968c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[epid].tx, vid); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return ret ? 0 : -ENOSPC; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic int fjes_vlan_rx_kill_vid(struct net_device *netdev, 9038c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 9068c2ecf20Sopenharmony_ci int epid; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci for (epid = 0; epid < adapter->hw.max_epid; epid++) { 9098c2ecf20Sopenharmony_ci if (epid == adapter->hw.my_epid) 9108c2ecf20Sopenharmony_ci continue; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci fjes_hw_del_vlan_id(&adapter->hw.ep_shm_info[epid].tx, vid); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic void fjes_txrx_stop_req_irq(struct fjes_adapter *adapter, 9198c2ecf20Sopenharmony_ci int src_epid) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 9228c2ecf20Sopenharmony_ci enum ep_partner_status status; 9238c2ecf20Sopenharmony_ci unsigned long flags; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci status = fjes_hw_get_partner_ep_status(hw, src_epid); 9268c2ecf20Sopenharmony_ci trace_fjes_txrx_stop_req_irq_pre(hw, src_epid, status); 9278c2ecf20Sopenharmony_ci switch (status) { 9288c2ecf20Sopenharmony_ci case EP_PARTNER_UNSHARE: 9298c2ecf20Sopenharmony_ci case EP_PARTNER_COMPLETE: 9308c2ecf20Sopenharmony_ci default: 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci case EP_PARTNER_WAITING: 9338c2ecf20Sopenharmony_ci if (src_epid < hw->my_epid) { 9348c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 9358c2ecf20Sopenharmony_ci hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |= 9368c2ecf20Sopenharmony_ci FJES_RX_STOP_REQ_DONE; 9378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci clear_bit(src_epid, &hw->txrx_stop_req_bit); 9408c2ecf20Sopenharmony_ci set_bit(src_epid, &adapter->unshare_watch_bitmask); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (!work_pending(&adapter->unshare_watch_task)) 9438c2ecf20Sopenharmony_ci queue_work(adapter->control_wq, 9448c2ecf20Sopenharmony_ci &adapter->unshare_watch_task); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci break; 9478c2ecf20Sopenharmony_ci case EP_PARTNER_SHARED: 9488c2ecf20Sopenharmony_ci if (hw->ep_shm_info[src_epid].rx.info->v1i.rx_status & 9498c2ecf20Sopenharmony_ci FJES_RX_STOP_REQ_REQUEST) { 9508c2ecf20Sopenharmony_ci set_bit(src_epid, &hw->epstop_req_bit); 9518c2ecf20Sopenharmony_ci if (!work_pending(&hw->epstop_task)) 9528c2ecf20Sopenharmony_ci queue_work(adapter->control_wq, 9538c2ecf20Sopenharmony_ci &hw->epstop_task); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci trace_fjes_txrx_stop_req_irq_post(hw, src_epid); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void fjes_stop_req_irq(struct fjes_adapter *adapter, int src_epid) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 9638c2ecf20Sopenharmony_ci enum ep_partner_status status; 9648c2ecf20Sopenharmony_ci unsigned long flags; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci set_bit(src_epid, &hw->hw_info.buffer_unshare_reserve_bit); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci status = fjes_hw_get_partner_ep_status(hw, src_epid); 9698c2ecf20Sopenharmony_ci trace_fjes_stop_req_irq_pre(hw, src_epid, status); 9708c2ecf20Sopenharmony_ci switch (status) { 9718c2ecf20Sopenharmony_ci case EP_PARTNER_WAITING: 9728c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 9738c2ecf20Sopenharmony_ci hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |= 9748c2ecf20Sopenharmony_ci FJES_RX_STOP_REQ_DONE; 9758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 9768c2ecf20Sopenharmony_ci clear_bit(src_epid, &hw->txrx_stop_req_bit); 9778c2ecf20Sopenharmony_ci fallthrough; 9788c2ecf20Sopenharmony_ci case EP_PARTNER_UNSHARE: 9798c2ecf20Sopenharmony_ci case EP_PARTNER_COMPLETE: 9808c2ecf20Sopenharmony_ci default: 9818c2ecf20Sopenharmony_ci set_bit(src_epid, &adapter->unshare_watch_bitmask); 9828c2ecf20Sopenharmony_ci if (!work_pending(&adapter->unshare_watch_task)) 9838c2ecf20Sopenharmony_ci queue_work(adapter->control_wq, 9848c2ecf20Sopenharmony_ci &adapter->unshare_watch_task); 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci case EP_PARTNER_SHARED: 9878c2ecf20Sopenharmony_ci set_bit(src_epid, &hw->epstop_req_bit); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (!work_pending(&hw->epstop_task)) 9908c2ecf20Sopenharmony_ci queue_work(adapter->control_wq, &hw->epstop_task); 9918c2ecf20Sopenharmony_ci break; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci trace_fjes_stop_req_irq_post(hw, src_epid); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void fjes_update_zone_irq(struct fjes_adapter *adapter, 9978c2ecf20Sopenharmony_ci int src_epid) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (!work_pending(&hw->update_zone_task)) 10028c2ecf20Sopenharmony_ci queue_work(adapter->control_wq, &hw->update_zone_task); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic irqreturn_t fjes_intr(int irq, void *data) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = data; 10088c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 10098c2ecf20Sopenharmony_ci irqreturn_t ret; 10108c2ecf20Sopenharmony_ci u32 icr; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci icr = fjes_hw_capture_interrupt_status(hw); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (icr & REG_IS_MASK_IS_ASSERT) { 10158c2ecf20Sopenharmony_ci if (icr & REG_ICTL_MASK_RX_DATA) { 10168c2ecf20Sopenharmony_ci fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID); 10178c2ecf20Sopenharmony_ci hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats 10188c2ecf20Sopenharmony_ci .recv_intr_rx += 1; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (icr & REG_ICTL_MASK_DEV_STOP_REQ) { 10228c2ecf20Sopenharmony_ci fjes_stop_req_irq(adapter, icr & REG_IS_MASK_EPID); 10238c2ecf20Sopenharmony_ci hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats 10248c2ecf20Sopenharmony_ci .recv_intr_stop += 1; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (icr & REG_ICTL_MASK_TXRX_STOP_REQ) { 10288c2ecf20Sopenharmony_ci fjes_txrx_stop_req_irq(adapter, icr & REG_IS_MASK_EPID); 10298c2ecf20Sopenharmony_ci hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats 10308c2ecf20Sopenharmony_ci .recv_intr_unshare += 1; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (icr & REG_ICTL_MASK_TXRX_STOP_DONE) 10348c2ecf20Sopenharmony_ci fjes_hw_set_irqmask(hw, 10358c2ecf20Sopenharmony_ci REG_ICTL_MASK_TXRX_STOP_DONE, true); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (icr & REG_ICTL_MASK_INFO_UPDATE) { 10388c2ecf20Sopenharmony_ci fjes_update_zone_irq(adapter, icr & REG_IS_MASK_EPID); 10398c2ecf20Sopenharmony_ci hw->ep_shm_info[icr & REG_IS_MASK_EPID].ep_stats 10408c2ecf20Sopenharmony_ci .recv_intr_zoneupdate += 1; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10448c2ecf20Sopenharmony_ci } else { 10458c2ecf20Sopenharmony_ci ret = IRQ_NONE; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return ret; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic int fjes_rxframe_search_exist(struct fjes_adapter *adapter, 10528c2ecf20Sopenharmony_ci int start_epid) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 10558c2ecf20Sopenharmony_ci enum ep_partner_status pstatus; 10568c2ecf20Sopenharmony_ci int max_epid, cur_epid; 10578c2ecf20Sopenharmony_ci int i; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci max_epid = hw->max_epid; 10608c2ecf20Sopenharmony_ci start_epid = (start_epid + 1 + max_epid) % max_epid; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci for (i = 0; i < max_epid; i++) { 10638c2ecf20Sopenharmony_ci cur_epid = (start_epid + i) % max_epid; 10648c2ecf20Sopenharmony_ci if (cur_epid == hw->my_epid) 10658c2ecf20Sopenharmony_ci continue; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci pstatus = fjes_hw_get_partner_ep_status(hw, cur_epid); 10688c2ecf20Sopenharmony_ci if (pstatus == EP_PARTNER_SHARED) { 10698c2ecf20Sopenharmony_ci if (!fjes_hw_epbuf_rx_is_empty( 10708c2ecf20Sopenharmony_ci &hw->ep_shm_info[cur_epid].rx)) 10718c2ecf20Sopenharmony_ci return cur_epid; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci return -1; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic void *fjes_rxframe_get(struct fjes_adapter *adapter, size_t *psize, 10788c2ecf20Sopenharmony_ci int *cur_epid) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci void *frame; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci *cur_epid = fjes_rxframe_search_exist(adapter, *cur_epid); 10838c2ecf20Sopenharmony_ci if (*cur_epid < 0) 10848c2ecf20Sopenharmony_ci return NULL; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci frame = 10878c2ecf20Sopenharmony_ci fjes_hw_epbuf_rx_curpkt_get_addr( 10888c2ecf20Sopenharmony_ci &adapter->hw.ep_shm_info[*cur_epid].rx, psize); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci return frame; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic void fjes_rxframe_release(struct fjes_adapter *adapter, int cur_epid) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci fjes_hw_epbuf_rx_curpkt_drop(&adapter->hw.ep_shm_info[cur_epid].rx); 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic void fjes_rx_irq(struct fjes_adapter *adapter, int src_epid) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, true); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci adapter->unset_rx_last = true; 11058c2ecf20Sopenharmony_ci napi_schedule(&adapter->napi); 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int fjes_poll(struct napi_struct *napi, int budget) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = 11118c2ecf20Sopenharmony_ci container_of(napi, struct fjes_adapter, napi); 11128c2ecf20Sopenharmony_ci struct net_device *netdev = napi->dev; 11138c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 11148c2ecf20Sopenharmony_ci struct sk_buff *skb; 11158c2ecf20Sopenharmony_ci int work_done = 0; 11168c2ecf20Sopenharmony_ci int cur_epid = 0; 11178c2ecf20Sopenharmony_ci int epidx; 11188c2ecf20Sopenharmony_ci size_t frame_len; 11198c2ecf20Sopenharmony_ci void *frame; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci spin_lock(&hw->rx_status_lock); 11228c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 11238c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 11248c2ecf20Sopenharmony_ci continue; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (fjes_hw_get_partner_ep_status(hw, epidx) == 11278c2ecf20Sopenharmony_ci EP_PARTNER_SHARED) 11288c2ecf20Sopenharmony_ci adapter->hw.ep_shm_info[epidx] 11298c2ecf20Sopenharmony_ci .tx.info->v1i.rx_status |= FJES_RX_POLL_WORK; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci spin_unlock(&hw->rx_status_lock); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci while (work_done < budget) { 11348c2ecf20Sopenharmony_ci prefetch(&adapter->hw); 11358c2ecf20Sopenharmony_ci frame = fjes_rxframe_get(adapter, &frame_len, &cur_epid); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (frame) { 11388c2ecf20Sopenharmony_ci skb = napi_alloc_skb(napi, frame_len); 11398c2ecf20Sopenharmony_ci if (!skb) { 11408c2ecf20Sopenharmony_ci adapter->stats64.rx_dropped += 1; 11418c2ecf20Sopenharmony_ci hw->ep_shm_info[cur_epid].net_stats 11428c2ecf20Sopenharmony_ci .rx_dropped += 1; 11438c2ecf20Sopenharmony_ci adapter->stats64.rx_errors += 1; 11448c2ecf20Sopenharmony_ci hw->ep_shm_info[cur_epid].net_stats 11458c2ecf20Sopenharmony_ci .rx_errors += 1; 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci skb_put_data(skb, frame, frame_len); 11488c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 11498c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci netif_receive_skb(skb); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci work_done++; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci adapter->stats64.rx_packets += 1; 11568c2ecf20Sopenharmony_ci hw->ep_shm_info[cur_epid].net_stats 11578c2ecf20Sopenharmony_ci .rx_packets += 1; 11588c2ecf20Sopenharmony_ci adapter->stats64.rx_bytes += frame_len; 11598c2ecf20Sopenharmony_ci hw->ep_shm_info[cur_epid].net_stats 11608c2ecf20Sopenharmony_ci .rx_bytes += frame_len; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (is_multicast_ether_addr( 11638c2ecf20Sopenharmony_ci ((struct ethhdr *)frame)->h_dest)) { 11648c2ecf20Sopenharmony_ci adapter->stats64.multicast += 1; 11658c2ecf20Sopenharmony_ci hw->ep_shm_info[cur_epid].net_stats 11668c2ecf20Sopenharmony_ci .multicast += 1; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci fjes_rxframe_release(adapter, cur_epid); 11718c2ecf20Sopenharmony_ci adapter->unset_rx_last = true; 11728c2ecf20Sopenharmony_ci } else { 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (work_done < budget) { 11788c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (adapter->unset_rx_last) { 11818c2ecf20Sopenharmony_ci adapter->rx_last_jiffies = jiffies; 11828c2ecf20Sopenharmony_ci adapter->unset_rx_last = false; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) { 11868c2ecf20Sopenharmony_ci napi_reschedule(napi); 11878c2ecf20Sopenharmony_ci } else { 11888c2ecf20Sopenharmony_ci spin_lock(&hw->rx_status_lock); 11898c2ecf20Sopenharmony_ci for (epidx = 0; epidx < hw->max_epid; epidx++) { 11908c2ecf20Sopenharmony_ci if (epidx == hw->my_epid) 11918c2ecf20Sopenharmony_ci continue; 11928c2ecf20Sopenharmony_ci if (fjes_hw_get_partner_ep_status(hw, epidx) == 11938c2ecf20Sopenharmony_ci EP_PARTNER_SHARED) 11948c2ecf20Sopenharmony_ci adapter->hw.ep_shm_info[epidx].tx 11958c2ecf20Sopenharmony_ci .info->v1i.rx_status &= 11968c2ecf20Sopenharmony_ci ~FJES_RX_POLL_WORK; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci spin_unlock(&hw->rx_status_lock); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci return work_done; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci/* fjes_probe - Device Initialization Routine */ 12088c2ecf20Sopenharmony_cistatic int fjes_probe(struct platform_device *plat_dev) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct fjes_adapter *adapter; 12118c2ecf20Sopenharmony_ci struct net_device *netdev; 12128c2ecf20Sopenharmony_ci struct resource *res; 12138c2ecf20Sopenharmony_ci struct fjes_hw *hw; 12148c2ecf20Sopenharmony_ci int err; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci err = -ENOMEM; 12178c2ecf20Sopenharmony_ci netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d", 12188c2ecf20Sopenharmony_ci NET_NAME_UNKNOWN, fjes_netdev_setup, 12198c2ecf20Sopenharmony_ci FJES_MAX_QUEUES); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (!netdev) 12228c2ecf20Sopenharmony_ci goto err_out; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &plat_dev->dev); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci dev_set_drvdata(&plat_dev->dev, netdev); 12278c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 12288c2ecf20Sopenharmony_ci adapter->netdev = netdev; 12298c2ecf20Sopenharmony_ci adapter->plat_dev = plat_dev; 12308c2ecf20Sopenharmony_ci hw = &adapter->hw; 12318c2ecf20Sopenharmony_ci hw->back = adapter; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* setup the private structure */ 12348c2ecf20Sopenharmony_ci err = fjes_sw_init(adapter); 12358c2ecf20Sopenharmony_ci if (err) 12368c2ecf20Sopenharmony_ci goto err_free_netdev; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci INIT_WORK(&adapter->force_close_task, fjes_force_close_task); 12398c2ecf20Sopenharmony_ci adapter->force_reset = false; 12408c2ecf20Sopenharmony_ci adapter->open_guard = false; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci adapter->txrx_wq = alloc_workqueue(DRV_NAME "/txrx", WQ_MEM_RECLAIM, 0); 12438c2ecf20Sopenharmony_ci if (unlikely(!adapter->txrx_wq)) { 12448c2ecf20Sopenharmony_ci err = -ENOMEM; 12458c2ecf20Sopenharmony_ci goto err_free_netdev; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci adapter->control_wq = alloc_workqueue(DRV_NAME "/control", 12498c2ecf20Sopenharmony_ci WQ_MEM_RECLAIM, 0); 12508c2ecf20Sopenharmony_ci if (unlikely(!adapter->control_wq)) { 12518c2ecf20Sopenharmony_ci err = -ENOMEM; 12528c2ecf20Sopenharmony_ci goto err_free_txrx_wq; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task); 12568c2ecf20Sopenharmony_ci INIT_WORK(&adapter->raise_intr_rxdata_task, 12578c2ecf20Sopenharmony_ci fjes_raise_intr_rxdata_task); 12588c2ecf20Sopenharmony_ci INIT_WORK(&adapter->unshare_watch_task, fjes_watch_unshare_task); 12598c2ecf20Sopenharmony_ci adapter->unshare_watch_bitmask = 0; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adapter->interrupt_watch_task, fjes_irq_watch_task); 12628c2ecf20Sopenharmony_ci adapter->interrupt_watch_enable = false; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); 12658c2ecf20Sopenharmony_ci if (!res) { 12668c2ecf20Sopenharmony_ci err = -EINVAL; 12678c2ecf20Sopenharmony_ci goto err_free_control_wq; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci hw->hw_res.start = res->start; 12708c2ecf20Sopenharmony_ci hw->hw_res.size = resource_size(res); 12718c2ecf20Sopenharmony_ci hw->hw_res.irq = platform_get_irq(plat_dev, 0); 12728c2ecf20Sopenharmony_ci if (hw->hw_res.irq < 0) { 12738c2ecf20Sopenharmony_ci err = hw->hw_res.irq; 12748c2ecf20Sopenharmony_ci goto err_free_control_wq; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci err = fjes_hw_init(&adapter->hw); 12788c2ecf20Sopenharmony_ci if (err) 12798c2ecf20Sopenharmony_ci goto err_free_control_wq; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* setup MAC address (02:00:00:00:00:[epid])*/ 12828c2ecf20Sopenharmony_ci netdev->dev_addr[0] = 2; 12838c2ecf20Sopenharmony_ci netdev->dev_addr[1] = 0; 12848c2ecf20Sopenharmony_ci netdev->dev_addr[2] = 0; 12858c2ecf20Sopenharmony_ci netdev->dev_addr[3] = 0; 12868c2ecf20Sopenharmony_ci netdev->dev_addr[4] = 0; 12878c2ecf20Sopenharmony_ci netdev->dev_addr[5] = hw->my_epid; /* EPID */ 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci err = register_netdev(netdev); 12908c2ecf20Sopenharmony_ci if (err) 12918c2ecf20Sopenharmony_ci goto err_hw_exit; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci fjes_dbg_adapter_init(adapter); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci return 0; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cierr_hw_exit: 13008c2ecf20Sopenharmony_ci fjes_hw_exit(&adapter->hw); 13018c2ecf20Sopenharmony_cierr_free_control_wq: 13028c2ecf20Sopenharmony_ci destroy_workqueue(adapter->control_wq); 13038c2ecf20Sopenharmony_cierr_free_txrx_wq: 13048c2ecf20Sopenharmony_ci destroy_workqueue(adapter->txrx_wq); 13058c2ecf20Sopenharmony_cierr_free_netdev: 13068c2ecf20Sopenharmony_ci free_netdev(netdev); 13078c2ecf20Sopenharmony_cierr_out: 13088c2ecf20Sopenharmony_ci return err; 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci/* fjes_remove - Device Removal Routine */ 13128c2ecf20Sopenharmony_cistatic int fjes_remove(struct platform_device *plat_dev) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(&plat_dev->dev); 13158c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = netdev_priv(netdev); 13168c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci fjes_dbg_adapter_exit(adapter); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->interrupt_watch_task); 13218c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->unshare_watch_task); 13228c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->raise_intr_rxdata_task); 13238c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->tx_stall_task); 13248c2ecf20Sopenharmony_ci if (adapter->control_wq) 13258c2ecf20Sopenharmony_ci destroy_workqueue(adapter->control_wq); 13268c2ecf20Sopenharmony_ci if (adapter->txrx_wq) 13278c2ecf20Sopenharmony_ci destroy_workqueue(adapter->txrx_wq); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci unregister_netdev(netdev); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci fjes_hw_exit(hw); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci netif_napi_del(&adapter->napi); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci free_netdev(netdev); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return 0; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int fjes_sw_init(struct fjes_adapter *adapter) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci netif_napi_add(netdev, &adapter->napi, fjes_poll, 64); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci return 0; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci/* fjes_netdev_setup - netdevice initialization routine */ 13508c2ecf20Sopenharmony_cistatic void fjes_netdev_setup(struct net_device *netdev) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci ether_setup(netdev); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL; 13558c2ecf20Sopenharmony_ci netdev->netdev_ops = &fjes_netdev_ops; 13568c2ecf20Sopenharmony_ci fjes_set_ethtool_ops(netdev); 13578c2ecf20Sopenharmony_ci netdev->mtu = fjes_support_mtu[3]; 13588c2ecf20Sopenharmony_ci netdev->min_mtu = fjes_support_mtu[0]; 13598c2ecf20Sopenharmony_ci netdev->max_mtu = fjes_support_mtu[3]; 13608c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic void fjes_irq_watch_task(struct work_struct *work) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = container_of(to_delayed_work(work), 13668c2ecf20Sopenharmony_ci struct fjes_adapter, interrupt_watch_task); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci local_irq_disable(); 13698c2ecf20Sopenharmony_ci fjes_intr(adapter->hw.hw_res.irq, adapter); 13708c2ecf20Sopenharmony_ci local_irq_enable(); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (fjes_rxframe_search_exist(adapter, 0) >= 0) 13738c2ecf20Sopenharmony_ci napi_schedule(&adapter->napi); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (adapter->interrupt_watch_enable) { 13768c2ecf20Sopenharmony_ci if (!delayed_work_pending(&adapter->interrupt_watch_task)) 13778c2ecf20Sopenharmony_ci queue_delayed_work(adapter->control_wq, 13788c2ecf20Sopenharmony_ci &adapter->interrupt_watch_task, 13798c2ecf20Sopenharmony_ci FJES_IRQ_WATCH_DELAY); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic void fjes_watch_unshare_task(struct work_struct *work) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct fjes_adapter *adapter = 13868c2ecf20Sopenharmony_ci container_of(work, struct fjes_adapter, unshare_watch_task); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 13898c2ecf20Sopenharmony_ci struct fjes_hw *hw = &adapter->hw; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci int unshare_watch, unshare_reserve; 13928c2ecf20Sopenharmony_ci int max_epid, my_epid, epidx; 13938c2ecf20Sopenharmony_ci int stop_req, stop_req_done; 13948c2ecf20Sopenharmony_ci ulong unshare_watch_bitmask; 13958c2ecf20Sopenharmony_ci unsigned long flags; 13968c2ecf20Sopenharmony_ci int wait_time = 0; 13978c2ecf20Sopenharmony_ci int is_shared; 13988c2ecf20Sopenharmony_ci int ret; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci my_epid = hw->my_epid; 14018c2ecf20Sopenharmony_ci max_epid = hw->max_epid; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci unshare_watch_bitmask = adapter->unshare_watch_bitmask; 14048c2ecf20Sopenharmony_ci adapter->unshare_watch_bitmask = 0; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci while ((unshare_watch_bitmask || hw->txrx_stop_req_bit) && 14078c2ecf20Sopenharmony_ci (wait_time < 3000)) { 14088c2ecf20Sopenharmony_ci for (epidx = 0; epidx < max_epid; epidx++) { 14098c2ecf20Sopenharmony_ci if (epidx == my_epid) 14108c2ecf20Sopenharmony_ci continue; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci is_shared = fjes_hw_epid_is_shared(hw->hw_info.share, 14138c2ecf20Sopenharmony_ci epidx); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci stop_req = test_bit(epidx, &hw->txrx_stop_req_bit); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci stop_req_done = hw->ep_shm_info[epidx].rx.info->v1i.rx_status & 14188c2ecf20Sopenharmony_ci FJES_RX_STOP_REQ_DONE; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci unshare_watch = test_bit(epidx, &unshare_watch_bitmask); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci unshare_reserve = test_bit(epidx, 14238c2ecf20Sopenharmony_ci &hw->hw_info.buffer_unshare_reserve_bit); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if ((!stop_req || 14268c2ecf20Sopenharmony_ci (is_shared && (!is_shared || !stop_req_done))) && 14278c2ecf20Sopenharmony_ci (is_shared || !unshare_watch || !unshare_reserve)) 14288c2ecf20Sopenharmony_ci continue; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci mutex_lock(&hw->hw_info.lock); 14318c2ecf20Sopenharmony_ci ret = fjes_hw_unregister_buff_addr(hw, epidx); 14328c2ecf20Sopenharmony_ci switch (ret) { 14338c2ecf20Sopenharmony_ci case 0: 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci case -ENOMSG: 14368c2ecf20Sopenharmony_ci case -EBUSY: 14378c2ecf20Sopenharmony_ci default: 14388c2ecf20Sopenharmony_ci if (!work_pending( 14398c2ecf20Sopenharmony_ci &adapter->force_close_task)) { 14408c2ecf20Sopenharmony_ci adapter->force_reset = true; 14418c2ecf20Sopenharmony_ci schedule_work( 14428c2ecf20Sopenharmony_ci &adapter->force_close_task); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 14478c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].ep_stats 14488c2ecf20Sopenharmony_ci .com_unregist_buf_exec += 1; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 14518c2ecf20Sopenharmony_ci fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx, 14528c2ecf20Sopenharmony_ci netdev->dev_addr, netdev->mtu); 14538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, flags); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci clear_bit(epidx, &hw->txrx_stop_req_bit); 14568c2ecf20Sopenharmony_ci clear_bit(epidx, &unshare_watch_bitmask); 14578c2ecf20Sopenharmony_ci clear_bit(epidx, 14588c2ecf20Sopenharmony_ci &hw->hw_info.buffer_unshare_reserve_bit); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci msleep(100); 14628c2ecf20Sopenharmony_ci wait_time += 100; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (hw->hw_info.buffer_unshare_reserve_bit) { 14668c2ecf20Sopenharmony_ci for (epidx = 0; epidx < max_epid; epidx++) { 14678c2ecf20Sopenharmony_ci if (epidx == my_epid) 14688c2ecf20Sopenharmony_ci continue; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (test_bit(epidx, 14718c2ecf20Sopenharmony_ci &hw->hw_info.buffer_unshare_reserve_bit)) { 14728c2ecf20Sopenharmony_ci mutex_lock(&hw->hw_info.lock); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci ret = fjes_hw_unregister_buff_addr(hw, epidx); 14758c2ecf20Sopenharmony_ci switch (ret) { 14768c2ecf20Sopenharmony_ci case 0: 14778c2ecf20Sopenharmony_ci break; 14788c2ecf20Sopenharmony_ci case -ENOMSG: 14798c2ecf20Sopenharmony_ci case -EBUSY: 14808c2ecf20Sopenharmony_ci default: 14818c2ecf20Sopenharmony_ci if (!work_pending( 14828c2ecf20Sopenharmony_ci &adapter->force_close_task)) { 14838c2ecf20Sopenharmony_ci adapter->force_reset = true; 14848c2ecf20Sopenharmony_ci schedule_work( 14858c2ecf20Sopenharmony_ci &adapter->force_close_task); 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci break; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci mutex_unlock(&hw->hw_info.lock); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].ep_stats 14928c2ecf20Sopenharmony_ci .com_unregist_buf_exec += 1; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 14958c2ecf20Sopenharmony_ci fjes_hw_setup_epbuf( 14968c2ecf20Sopenharmony_ci &hw->ep_shm_info[epidx].tx, 14978c2ecf20Sopenharmony_ci netdev->dev_addr, netdev->mtu); 14988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, 14998c2ecf20Sopenharmony_ci flags); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci clear_bit(epidx, &hw->txrx_stop_req_bit); 15028c2ecf20Sopenharmony_ci clear_bit(epidx, &unshare_watch_bitmask); 15038c2ecf20Sopenharmony_ci clear_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit); 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (test_bit(epidx, &unshare_watch_bitmask)) { 15078c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->rx_status_lock, flags); 15088c2ecf20Sopenharmony_ci hw->ep_shm_info[epidx].tx.info->v1i.rx_status &= 15098c2ecf20Sopenharmony_ci ~FJES_RX_STOP_REQ_DONE; 15108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->rx_status_lock, 15118c2ecf20Sopenharmony_ci flags); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_cistatic acpi_status 15188c2ecf20Sopenharmony_ciacpi_find_extended_socket_device(acpi_handle obj_handle, u32 level, 15198c2ecf20Sopenharmony_ci void *context, void **return_value) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci struct acpi_device *device; 15228c2ecf20Sopenharmony_ci bool *found = context; 15238c2ecf20Sopenharmony_ci int result; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci result = acpi_bus_get_device(obj_handle, &device); 15268c2ecf20Sopenharmony_ci if (result) 15278c2ecf20Sopenharmony_ci return AE_OK; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (strcmp(acpi_device_hid(device), ACPI_MOTHERBOARD_RESOURCE_HID)) 15308c2ecf20Sopenharmony_ci return AE_OK; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (!is_extended_socket_device(device)) 15338c2ecf20Sopenharmony_ci return AE_OK; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (acpi_check_extended_socket_status(device)) 15368c2ecf20Sopenharmony_ci return AE_OK; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci *found = true; 15398c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci/* fjes_init_module - Driver Registration Routine */ 15438c2ecf20Sopenharmony_cistatic int __init fjes_init_module(void) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci bool found = false; 15468c2ecf20Sopenharmony_ci int result; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 15498c2ecf20Sopenharmony_ci acpi_find_extended_socket_device, NULL, &found, 15508c2ecf20Sopenharmony_ci NULL); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (!found) 15538c2ecf20Sopenharmony_ci return -ENODEV; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci pr_info("%s - version %s - %s\n", 15568c2ecf20Sopenharmony_ci fjes_driver_string, fjes_driver_version, fjes_copyright); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci fjes_dbg_init(); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci result = platform_driver_register(&fjes_driver); 15618c2ecf20Sopenharmony_ci if (result < 0) { 15628c2ecf20Sopenharmony_ci fjes_dbg_exit(); 15638c2ecf20Sopenharmony_ci return result; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci result = acpi_bus_register_driver(&fjes_acpi_driver); 15678c2ecf20Sopenharmony_ci if (result < 0) 15688c2ecf20Sopenharmony_ci goto fail_acpi_driver; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci return 0; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cifail_acpi_driver: 15738c2ecf20Sopenharmony_ci platform_driver_unregister(&fjes_driver); 15748c2ecf20Sopenharmony_ci fjes_dbg_exit(); 15758c2ecf20Sopenharmony_ci return result; 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_cimodule_init(fjes_init_module); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci/* fjes_exit_module - Driver Exit Cleanup Routine */ 15818c2ecf20Sopenharmony_cistatic void __exit fjes_exit_module(void) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&fjes_acpi_driver); 15848c2ecf20Sopenharmony_ci platform_driver_unregister(&fjes_driver); 15858c2ecf20Sopenharmony_ci fjes_dbg_exit(); 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_cimodule_exit(fjes_exit_module); 1589