184640e27SKaricheri, Muralidharan /* 284640e27SKaricheri, Muralidharan * Keystone NetCP Core driver 384640e27SKaricheri, Muralidharan * 484640e27SKaricheri, Muralidharan * Copyright (C) 2014 Texas Instruments Incorporated 584640e27SKaricheri, Muralidharan * Authors: Sandeep Nair <sandeep_n@ti.com> 684640e27SKaricheri, Muralidharan * Sandeep Paulraj <s-paulraj@ti.com> 784640e27SKaricheri, Muralidharan * Cyril Chemparathy <cyril@ti.com> 884640e27SKaricheri, Muralidharan * Santosh Shilimkar <santosh.shilimkar@ti.com> 984640e27SKaricheri, Muralidharan * Murali Karicheri <m-karicheri2@ti.com> 1084640e27SKaricheri, Muralidharan * Wingman Kwok <w-kwok2@ti.com> 1184640e27SKaricheri, Muralidharan * 1284640e27SKaricheri, Muralidharan * This program is free software; you can redistribute it and/or 1384640e27SKaricheri, Muralidharan * modify it under the terms of the GNU General Public License as 1484640e27SKaricheri, Muralidharan * published by the Free Software Foundation version 2. 1584640e27SKaricheri, Muralidharan * 1684640e27SKaricheri, Muralidharan * This program is distributed "as is" WITHOUT ANY WARRANTY of any 1784640e27SKaricheri, Muralidharan * kind, whether express or implied; without even the implied warranty 1884640e27SKaricheri, Muralidharan * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1984640e27SKaricheri, Muralidharan * GNU General Public License for more details. 2084640e27SKaricheri, Muralidharan */ 2184640e27SKaricheri, Muralidharan 2284640e27SKaricheri, Muralidharan #include <linux/io.h> 2384640e27SKaricheri, Muralidharan #include <linux/module.h> 2484640e27SKaricheri, Muralidharan #include <linux/of_net.h> 2584640e27SKaricheri, Muralidharan #include <linux/of_address.h> 2684640e27SKaricheri, Muralidharan #include <linux/if_vlan.h> 2784640e27SKaricheri, Muralidharan #include <linux/pm_runtime.h> 2884640e27SKaricheri, Muralidharan #include <linux/platform_device.h> 2984640e27SKaricheri, Muralidharan #include <linux/soc/ti/knav_qmss.h> 3084640e27SKaricheri, Muralidharan #include <linux/soc/ti/knav_dma.h> 3184640e27SKaricheri, Muralidharan 3284640e27SKaricheri, Muralidharan #include "netcp.h" 3384640e27SKaricheri, Muralidharan 3484640e27SKaricheri, Muralidharan #define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD) 3584640e27SKaricheri, Muralidharan #define NETCP_NAPI_WEIGHT 64 3684640e27SKaricheri, Muralidharan #define NETCP_TX_TIMEOUT (5 * HZ) 37866b8b18SWingMan Kwok #define NETCP_PACKET_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN) 3884640e27SKaricheri, Muralidharan #define NETCP_MIN_PACKET_SIZE ETH_ZLEN 3984640e27SKaricheri, Muralidharan #define NETCP_MAX_MCAST_ADDR 16 4084640e27SKaricheri, Muralidharan 4184640e27SKaricheri, Muralidharan #define NETCP_EFUSE_REG_INDEX 0 4284640e27SKaricheri, Muralidharan 4384640e27SKaricheri, Muralidharan #define NETCP_MOD_PROBE_SKIPPED 1 4484640e27SKaricheri, Muralidharan #define NETCP_MOD_PROBE_FAILED 2 4584640e27SKaricheri, Muralidharan 4684640e27SKaricheri, Muralidharan #define NETCP_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \ 4784640e27SKaricheri, Muralidharan NETIF_MSG_DRV | NETIF_MSG_LINK | \ 4884640e27SKaricheri, Muralidharan NETIF_MSG_IFUP | NETIF_MSG_INTR | \ 4984640e27SKaricheri, Muralidharan NETIF_MSG_PROBE | NETIF_MSG_TIMER | \ 5084640e27SKaricheri, Muralidharan NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR | \ 5184640e27SKaricheri, Muralidharan NETIF_MSG_TX_ERR | NETIF_MSG_TX_DONE | \ 5284640e27SKaricheri, Muralidharan NETIF_MSG_PKTDATA | NETIF_MSG_TX_QUEUED | \ 5384640e27SKaricheri, Muralidharan NETIF_MSG_RX_STATUS) 5484640e27SKaricheri, Muralidharan 5571382bc0SWingMan Kwok #define NETCP_EFUSE_ADDR_SWAP 2 5671382bc0SWingMan Kwok 5784640e27SKaricheri, Muralidharan #define knav_queue_get_id(q) knav_queue_device_control(q, \ 5884640e27SKaricheri, Muralidharan KNAV_QUEUE_GET_ID, (unsigned long)NULL) 5984640e27SKaricheri, Muralidharan 6084640e27SKaricheri, Muralidharan #define knav_queue_enable_notify(q) knav_queue_device_control(q, \ 6184640e27SKaricheri, Muralidharan KNAV_QUEUE_ENABLE_NOTIFY, \ 6284640e27SKaricheri, Muralidharan (unsigned long)NULL) 6384640e27SKaricheri, Muralidharan 6484640e27SKaricheri, Muralidharan #define knav_queue_disable_notify(q) knav_queue_device_control(q, \ 6584640e27SKaricheri, Muralidharan KNAV_QUEUE_DISABLE_NOTIFY, \ 6684640e27SKaricheri, Muralidharan (unsigned long)NULL) 6784640e27SKaricheri, Muralidharan 6884640e27SKaricheri, Muralidharan #define knav_queue_get_count(q) knav_queue_device_control(q, \ 6984640e27SKaricheri, Muralidharan KNAV_QUEUE_GET_COUNT, (unsigned long)NULL) 7084640e27SKaricheri, Muralidharan 7184640e27SKaricheri, Muralidharan #define for_each_netcp_module(module) \ 7284640e27SKaricheri, Muralidharan list_for_each_entry(module, &netcp_modules, module_list) 7384640e27SKaricheri, Muralidharan 7484640e27SKaricheri, Muralidharan #define for_each_netcp_device_module(netcp_device, inst_modpriv) \ 7584640e27SKaricheri, Muralidharan list_for_each_entry(inst_modpriv, \ 7684640e27SKaricheri, Muralidharan &((netcp_device)->modpriv_head), inst_list) 7784640e27SKaricheri, Muralidharan 7884640e27SKaricheri, Muralidharan #define for_each_module(netcp, intf_modpriv) \ 7984640e27SKaricheri, Muralidharan list_for_each_entry(intf_modpriv, &netcp->module_head, intf_list) 8084640e27SKaricheri, Muralidharan 8184640e27SKaricheri, Muralidharan /* Module management structures */ 8284640e27SKaricheri, Muralidharan struct netcp_device { 8384640e27SKaricheri, Muralidharan struct list_head device_list; 8484640e27SKaricheri, Muralidharan struct list_head interface_head; 8584640e27SKaricheri, Muralidharan struct list_head modpriv_head; 8684640e27SKaricheri, Muralidharan struct device *device; 8784640e27SKaricheri, Muralidharan }; 8884640e27SKaricheri, Muralidharan 8984640e27SKaricheri, Muralidharan struct netcp_inst_modpriv { 9084640e27SKaricheri, Muralidharan struct netcp_device *netcp_device; 9184640e27SKaricheri, Muralidharan struct netcp_module *netcp_module; 9284640e27SKaricheri, Muralidharan struct list_head inst_list; 9384640e27SKaricheri, Muralidharan void *module_priv; 9484640e27SKaricheri, Muralidharan }; 9584640e27SKaricheri, Muralidharan 9684640e27SKaricheri, Muralidharan struct netcp_intf_modpriv { 9784640e27SKaricheri, Muralidharan struct netcp_intf *netcp_priv; 9884640e27SKaricheri, Muralidharan struct netcp_module *netcp_module; 9984640e27SKaricheri, Muralidharan struct list_head intf_list; 10084640e27SKaricheri, Muralidharan void *module_priv; 10184640e27SKaricheri, Muralidharan }; 10284640e27SKaricheri, Muralidharan 10384640e27SKaricheri, Muralidharan static LIST_HEAD(netcp_devices); 10484640e27SKaricheri, Muralidharan static LIST_HEAD(netcp_modules); 10584640e27SKaricheri, Muralidharan static DEFINE_MUTEX(netcp_modules_lock); 10684640e27SKaricheri, Muralidharan 10784640e27SKaricheri, Muralidharan static int netcp_debug_level = -1; 10884640e27SKaricheri, Muralidharan module_param(netcp_debug_level, int, 0); 10984640e27SKaricheri, Muralidharan MODULE_PARM_DESC(netcp_debug_level, "Netcp debug level (NETIF_MSG bits) (0=none,...,16=all)"); 11084640e27SKaricheri, Muralidharan 11184640e27SKaricheri, Muralidharan /* Helper functions - Get/Set */ 11289907779SArnd Bergmann static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc, 11384640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 11484640e27SKaricheri, Muralidharan { 11589907779SArnd Bergmann *buff_len = le32_to_cpu(desc->buff_len); 11689907779SArnd Bergmann *buff = le32_to_cpu(desc->buff); 11789907779SArnd Bergmann *ndesc = le32_to_cpu(desc->next_desc); 11884640e27SKaricheri, Muralidharan } 11984640e27SKaricheri, Muralidharan 120b1cb86aeSKaricheri, Muralidharan static void get_sw_data(u32 *data0, u32 *data1, struct knav_dma_desc *desc) 12184640e27SKaricheri, Muralidharan { 122b1cb86aeSKaricheri, Muralidharan /* No Endian conversion needed as this data is untouched by hw */ 123b1cb86aeSKaricheri, Muralidharan *data0 = desc->sw_data[0]; 124b1cb86aeSKaricheri, Muralidharan *data1 = desc->sw_data[1]; 12589907779SArnd Bergmann } 12689907779SArnd Bergmann 12789907779SArnd Bergmann static void get_org_pkt_info(dma_addr_t *buff, u32 *buff_len, 12884640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 12984640e27SKaricheri, Muralidharan { 13089907779SArnd Bergmann *buff = le32_to_cpu(desc->orig_buff); 13189907779SArnd Bergmann *buff_len = le32_to_cpu(desc->orig_len); 13284640e27SKaricheri, Muralidharan } 13384640e27SKaricheri, Muralidharan 13489907779SArnd Bergmann static void get_words(dma_addr_t *words, int num_words, __le32 *desc) 13584640e27SKaricheri, Muralidharan { 13684640e27SKaricheri, Muralidharan int i; 13784640e27SKaricheri, Muralidharan 13884640e27SKaricheri, Muralidharan for (i = 0; i < num_words; i++) 13989907779SArnd Bergmann words[i] = le32_to_cpu(desc[i]); 14084640e27SKaricheri, Muralidharan } 14184640e27SKaricheri, Muralidharan 14289907779SArnd Bergmann static void set_pkt_info(dma_addr_t buff, u32 buff_len, u32 ndesc, 14384640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 14484640e27SKaricheri, Muralidharan { 14589907779SArnd Bergmann desc->buff_len = cpu_to_le32(buff_len); 14689907779SArnd Bergmann desc->buff = cpu_to_le32(buff); 14789907779SArnd Bergmann desc->next_desc = cpu_to_le32(ndesc); 14884640e27SKaricheri, Muralidharan } 14984640e27SKaricheri, Muralidharan 15084640e27SKaricheri, Muralidharan static void set_desc_info(u32 desc_info, u32 pkt_info, 15184640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 15284640e27SKaricheri, Muralidharan { 15389907779SArnd Bergmann desc->desc_info = cpu_to_le32(desc_info); 15489907779SArnd Bergmann desc->packet_info = cpu_to_le32(pkt_info); 15584640e27SKaricheri, Muralidharan } 15684640e27SKaricheri, Muralidharan 157b1cb86aeSKaricheri, Muralidharan static void set_sw_data(u32 data0, u32 data1, struct knav_dma_desc *desc) 15884640e27SKaricheri, Muralidharan { 159b1cb86aeSKaricheri, Muralidharan /* No Endian conversion needed as this data is untouched by hw */ 160b1cb86aeSKaricheri, Muralidharan desc->sw_data[0] = data0; 161b1cb86aeSKaricheri, Muralidharan desc->sw_data[1] = data1; 16284640e27SKaricheri, Muralidharan } 16384640e27SKaricheri, Muralidharan 16489907779SArnd Bergmann static void set_org_pkt_info(dma_addr_t buff, u32 buff_len, 16584640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 16684640e27SKaricheri, Muralidharan { 16789907779SArnd Bergmann desc->orig_buff = cpu_to_le32(buff); 16889907779SArnd Bergmann desc->orig_len = cpu_to_le32(buff_len); 16984640e27SKaricheri, Muralidharan } 17084640e27SKaricheri, Muralidharan 17189907779SArnd Bergmann static void set_words(u32 *words, int num_words, __le32 *desc) 17284640e27SKaricheri, Muralidharan { 17384640e27SKaricheri, Muralidharan int i; 17484640e27SKaricheri, Muralidharan 17584640e27SKaricheri, Muralidharan for (i = 0; i < num_words; i++) 17689907779SArnd Bergmann desc[i] = cpu_to_le32(words[i]); 17784640e27SKaricheri, Muralidharan } 17884640e27SKaricheri, Muralidharan 17984640e27SKaricheri, Muralidharan /* Read the e-fuse value as 32 bit values to be endian independent */ 18071382bc0SWingMan Kwok static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac, u32 swap) 18184640e27SKaricheri, Muralidharan { 18284640e27SKaricheri, Muralidharan unsigned int addr0, addr1; 18384640e27SKaricheri, Muralidharan 18484640e27SKaricheri, Muralidharan addr1 = readl(efuse_mac + 4); 18584640e27SKaricheri, Muralidharan addr0 = readl(efuse_mac); 18684640e27SKaricheri, Muralidharan 18771382bc0SWingMan Kwok switch (swap) { 18871382bc0SWingMan Kwok case NETCP_EFUSE_ADDR_SWAP: 18971382bc0SWingMan Kwok addr0 = addr1; 19071382bc0SWingMan Kwok addr1 = readl(efuse_mac); 19171382bc0SWingMan Kwok break; 19271382bc0SWingMan Kwok default: 19371382bc0SWingMan Kwok break; 19471382bc0SWingMan Kwok } 19571382bc0SWingMan Kwok 19684640e27SKaricheri, Muralidharan x[0] = (addr1 & 0x0000ff00) >> 8; 19784640e27SKaricheri, Muralidharan x[1] = addr1 & 0x000000ff; 19884640e27SKaricheri, Muralidharan x[2] = (addr0 & 0xff000000) >> 24; 19984640e27SKaricheri, Muralidharan x[3] = (addr0 & 0x00ff0000) >> 16; 20084640e27SKaricheri, Muralidharan x[4] = (addr0 & 0x0000ff00) >> 8; 20184640e27SKaricheri, Muralidharan x[5] = addr0 & 0x000000ff; 20284640e27SKaricheri, Muralidharan 20384640e27SKaricheri, Muralidharan return 0; 20484640e27SKaricheri, Muralidharan } 20584640e27SKaricheri, Muralidharan 20684640e27SKaricheri, Muralidharan static const char *netcp_node_name(struct device_node *node) 20784640e27SKaricheri, Muralidharan { 20884640e27SKaricheri, Muralidharan const char *name; 20984640e27SKaricheri, Muralidharan 21084640e27SKaricheri, Muralidharan if (of_property_read_string(node, "label", &name) < 0) 21184640e27SKaricheri, Muralidharan name = node->name; 21284640e27SKaricheri, Muralidharan if (!name) 21384640e27SKaricheri, Muralidharan name = "unknown"; 21484640e27SKaricheri, Muralidharan return name; 21584640e27SKaricheri, Muralidharan } 21684640e27SKaricheri, Muralidharan 21784640e27SKaricheri, Muralidharan /* Module management routines */ 21884640e27SKaricheri, Muralidharan static int netcp_register_interface(struct netcp_intf *netcp) 21984640e27SKaricheri, Muralidharan { 22084640e27SKaricheri, Muralidharan int ret; 22184640e27SKaricheri, Muralidharan 22284640e27SKaricheri, Muralidharan ret = register_netdev(netcp->ndev); 22384640e27SKaricheri, Muralidharan if (!ret) 22484640e27SKaricheri, Muralidharan netcp->netdev_registered = true; 22584640e27SKaricheri, Muralidharan return ret; 22684640e27SKaricheri, Muralidharan } 22784640e27SKaricheri, Muralidharan 22884640e27SKaricheri, Muralidharan static int netcp_module_probe(struct netcp_device *netcp_device, 22984640e27SKaricheri, Muralidharan struct netcp_module *module) 23084640e27SKaricheri, Muralidharan { 23184640e27SKaricheri, Muralidharan struct device *dev = netcp_device->device; 23284640e27SKaricheri, Muralidharan struct device_node *devices, *interface, *node = dev->of_node; 23384640e27SKaricheri, Muralidharan struct device_node *child; 23484640e27SKaricheri, Muralidharan struct netcp_inst_modpriv *inst_modpriv; 23584640e27SKaricheri, Muralidharan struct netcp_intf *netcp_intf; 23684640e27SKaricheri, Muralidharan struct netcp_module *tmp; 23784640e27SKaricheri, Muralidharan bool primary_module_registered = false; 23884640e27SKaricheri, Muralidharan int ret; 23984640e27SKaricheri, Muralidharan 24084640e27SKaricheri, Muralidharan /* Find this module in the sub-tree for this device */ 24184640e27SKaricheri, Muralidharan devices = of_get_child_by_name(node, "netcp-devices"); 24284640e27SKaricheri, Muralidharan if (!devices) { 24384640e27SKaricheri, Muralidharan dev_err(dev, "could not find netcp-devices node\n"); 24484640e27SKaricheri, Muralidharan return NETCP_MOD_PROBE_SKIPPED; 24584640e27SKaricheri, Muralidharan } 24684640e27SKaricheri, Muralidharan 24784640e27SKaricheri, Muralidharan for_each_available_child_of_node(devices, child) { 24884640e27SKaricheri, Muralidharan const char *name = netcp_node_name(child); 24984640e27SKaricheri, Muralidharan 25084640e27SKaricheri, Muralidharan if (!strcasecmp(module->name, name)) 25184640e27SKaricheri, Muralidharan break; 25284640e27SKaricheri, Muralidharan } 25384640e27SKaricheri, Muralidharan 25484640e27SKaricheri, Muralidharan of_node_put(devices); 25584640e27SKaricheri, Muralidharan /* If module not used for this device, skip it */ 25684640e27SKaricheri, Muralidharan if (!child) { 25784640e27SKaricheri, Muralidharan dev_warn(dev, "module(%s) not used for device\n", module->name); 25884640e27SKaricheri, Muralidharan return NETCP_MOD_PROBE_SKIPPED; 25984640e27SKaricheri, Muralidharan } 26084640e27SKaricheri, Muralidharan 26184640e27SKaricheri, Muralidharan inst_modpriv = devm_kzalloc(dev, sizeof(*inst_modpriv), GFP_KERNEL); 26284640e27SKaricheri, Muralidharan if (!inst_modpriv) { 26384640e27SKaricheri, Muralidharan of_node_put(child); 26484640e27SKaricheri, Muralidharan return -ENOMEM; 26584640e27SKaricheri, Muralidharan } 26684640e27SKaricheri, Muralidharan 26784640e27SKaricheri, Muralidharan inst_modpriv->netcp_device = netcp_device; 26884640e27SKaricheri, Muralidharan inst_modpriv->netcp_module = module; 26984640e27SKaricheri, Muralidharan list_add_tail(&inst_modpriv->inst_list, &netcp_device->modpriv_head); 27084640e27SKaricheri, Muralidharan 27184640e27SKaricheri, Muralidharan ret = module->probe(netcp_device, dev, child, 27284640e27SKaricheri, Muralidharan &inst_modpriv->module_priv); 27384640e27SKaricheri, Muralidharan of_node_put(child); 27484640e27SKaricheri, Muralidharan if (ret) { 27584640e27SKaricheri, Muralidharan dev_err(dev, "Probe of module(%s) failed with %d\n", 27684640e27SKaricheri, Muralidharan module->name, ret); 27784640e27SKaricheri, Muralidharan list_del(&inst_modpriv->inst_list); 27884640e27SKaricheri, Muralidharan devm_kfree(dev, inst_modpriv); 27984640e27SKaricheri, Muralidharan return NETCP_MOD_PROBE_FAILED; 28084640e27SKaricheri, Muralidharan } 28184640e27SKaricheri, Muralidharan 28284640e27SKaricheri, Muralidharan /* Attach modules only if the primary module is probed */ 28384640e27SKaricheri, Muralidharan for_each_netcp_module(tmp) { 28484640e27SKaricheri, Muralidharan if (tmp->primary) 28584640e27SKaricheri, Muralidharan primary_module_registered = true; 28684640e27SKaricheri, Muralidharan } 28784640e27SKaricheri, Muralidharan 28884640e27SKaricheri, Muralidharan if (!primary_module_registered) 28984640e27SKaricheri, Muralidharan return 0; 29084640e27SKaricheri, Muralidharan 29184640e27SKaricheri, Muralidharan /* Attach module to interfaces */ 29284640e27SKaricheri, Muralidharan list_for_each_entry(netcp_intf, &netcp_device->interface_head, 29384640e27SKaricheri, Muralidharan interface_list) { 29484640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 29584640e27SKaricheri, Muralidharan 29684640e27SKaricheri, Muralidharan intf_modpriv = devm_kzalloc(dev, sizeof(*intf_modpriv), 29784640e27SKaricheri, Muralidharan GFP_KERNEL); 29884640e27SKaricheri, Muralidharan if (!intf_modpriv) 29984640e27SKaricheri, Muralidharan return -ENOMEM; 30084640e27SKaricheri, Muralidharan 30184640e27SKaricheri, Muralidharan interface = of_parse_phandle(netcp_intf->node_interface, 30284640e27SKaricheri, Muralidharan module->name, 0); 30384640e27SKaricheri, Muralidharan 304915c5857SKaricheri, Muralidharan if (!interface) { 305915c5857SKaricheri, Muralidharan devm_kfree(dev, intf_modpriv); 306915c5857SKaricheri, Muralidharan continue; 307915c5857SKaricheri, Muralidharan } 308915c5857SKaricheri, Muralidharan 30984640e27SKaricheri, Muralidharan intf_modpriv->netcp_priv = netcp_intf; 31084640e27SKaricheri, Muralidharan intf_modpriv->netcp_module = module; 31184640e27SKaricheri, Muralidharan list_add_tail(&intf_modpriv->intf_list, 31284640e27SKaricheri, Muralidharan &netcp_intf->module_head); 31384640e27SKaricheri, Muralidharan 31484640e27SKaricheri, Muralidharan ret = module->attach(inst_modpriv->module_priv, 31584640e27SKaricheri, Muralidharan netcp_intf->ndev, interface, 31684640e27SKaricheri, Muralidharan &intf_modpriv->module_priv); 31784640e27SKaricheri, Muralidharan of_node_put(interface); 31884640e27SKaricheri, Muralidharan if (ret) { 31984640e27SKaricheri, Muralidharan dev_dbg(dev, "Attach of module %s declined with %d\n", 32084640e27SKaricheri, Muralidharan module->name, ret); 32184640e27SKaricheri, Muralidharan list_del(&intf_modpriv->intf_list); 32284640e27SKaricheri, Muralidharan devm_kfree(dev, intf_modpriv); 32384640e27SKaricheri, Muralidharan continue; 32484640e27SKaricheri, Muralidharan } 32584640e27SKaricheri, Muralidharan } 326736532a0SKaricheri, Muralidharan 327736532a0SKaricheri, Muralidharan /* Now register the interface with netdev */ 328736532a0SKaricheri, Muralidharan list_for_each_entry(netcp_intf, 329736532a0SKaricheri, Muralidharan &netcp_device->interface_head, 330736532a0SKaricheri, Muralidharan interface_list) { 331736532a0SKaricheri, Muralidharan /* If interface not registered then register now */ 332736532a0SKaricheri, Muralidharan if (!netcp_intf->netdev_registered) { 333736532a0SKaricheri, Muralidharan ret = netcp_register_interface(netcp_intf); 334736532a0SKaricheri, Muralidharan if (ret) 335736532a0SKaricheri, Muralidharan return -ENODEV; 336736532a0SKaricheri, Muralidharan } 337736532a0SKaricheri, Muralidharan } 33884640e27SKaricheri, Muralidharan return 0; 33984640e27SKaricheri, Muralidharan } 34084640e27SKaricheri, Muralidharan 34184640e27SKaricheri, Muralidharan int netcp_register_module(struct netcp_module *module) 34284640e27SKaricheri, Muralidharan { 34384640e27SKaricheri, Muralidharan struct netcp_device *netcp_device; 34484640e27SKaricheri, Muralidharan struct netcp_module *tmp; 34584640e27SKaricheri, Muralidharan int ret; 34684640e27SKaricheri, Muralidharan 34784640e27SKaricheri, Muralidharan if (!module->name) { 34884640e27SKaricheri, Muralidharan WARN(1, "error registering netcp module: no name\n"); 34984640e27SKaricheri, Muralidharan return -EINVAL; 35084640e27SKaricheri, Muralidharan } 35184640e27SKaricheri, Muralidharan 35284640e27SKaricheri, Muralidharan if (!module->probe) { 35384640e27SKaricheri, Muralidharan WARN(1, "error registering netcp module: no probe\n"); 35484640e27SKaricheri, Muralidharan return -EINVAL; 35584640e27SKaricheri, Muralidharan } 35684640e27SKaricheri, Muralidharan 35784640e27SKaricheri, Muralidharan mutex_lock(&netcp_modules_lock); 35884640e27SKaricheri, Muralidharan 35984640e27SKaricheri, Muralidharan for_each_netcp_module(tmp) { 36084640e27SKaricheri, Muralidharan if (!strcasecmp(tmp->name, module->name)) { 36184640e27SKaricheri, Muralidharan mutex_unlock(&netcp_modules_lock); 36284640e27SKaricheri, Muralidharan return -EEXIST; 36384640e27SKaricheri, Muralidharan } 36484640e27SKaricheri, Muralidharan } 36584640e27SKaricheri, Muralidharan list_add_tail(&module->module_list, &netcp_modules); 36684640e27SKaricheri, Muralidharan 36784640e27SKaricheri, Muralidharan list_for_each_entry(netcp_device, &netcp_devices, device_list) { 36884640e27SKaricheri, Muralidharan ret = netcp_module_probe(netcp_device, module); 36984640e27SKaricheri, Muralidharan if (ret < 0) 37084640e27SKaricheri, Muralidharan goto fail; 37184640e27SKaricheri, Muralidharan } 37284640e27SKaricheri, Muralidharan mutex_unlock(&netcp_modules_lock); 37384640e27SKaricheri, Muralidharan return 0; 37484640e27SKaricheri, Muralidharan 37584640e27SKaricheri, Muralidharan fail: 37684640e27SKaricheri, Muralidharan mutex_unlock(&netcp_modules_lock); 37784640e27SKaricheri, Muralidharan netcp_unregister_module(module); 37884640e27SKaricheri, Muralidharan return ret; 37984640e27SKaricheri, Muralidharan } 38058c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_register_module); 38184640e27SKaricheri, Muralidharan 38284640e27SKaricheri, Muralidharan static void netcp_release_module(struct netcp_device *netcp_device, 38384640e27SKaricheri, Muralidharan struct netcp_module *module) 38484640e27SKaricheri, Muralidharan { 38584640e27SKaricheri, Muralidharan struct netcp_inst_modpriv *inst_modpriv, *inst_tmp; 38684640e27SKaricheri, Muralidharan struct netcp_intf *netcp_intf, *netcp_tmp; 38784640e27SKaricheri, Muralidharan struct device *dev = netcp_device->device; 38884640e27SKaricheri, Muralidharan 38984640e27SKaricheri, Muralidharan /* Release the module from each interface */ 39084640e27SKaricheri, Muralidharan list_for_each_entry_safe(netcp_intf, netcp_tmp, 39184640e27SKaricheri, Muralidharan &netcp_device->interface_head, 39284640e27SKaricheri, Muralidharan interface_list) { 39384640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv, *intf_tmp; 39484640e27SKaricheri, Muralidharan 39584640e27SKaricheri, Muralidharan list_for_each_entry_safe(intf_modpriv, intf_tmp, 39684640e27SKaricheri, Muralidharan &netcp_intf->module_head, 39784640e27SKaricheri, Muralidharan intf_list) { 39884640e27SKaricheri, Muralidharan if (intf_modpriv->netcp_module == module) { 39984640e27SKaricheri, Muralidharan module->release(intf_modpriv->module_priv); 40084640e27SKaricheri, Muralidharan list_del(&intf_modpriv->intf_list); 40184640e27SKaricheri, Muralidharan devm_kfree(dev, intf_modpriv); 40284640e27SKaricheri, Muralidharan break; 40384640e27SKaricheri, Muralidharan } 40484640e27SKaricheri, Muralidharan } 40584640e27SKaricheri, Muralidharan } 40684640e27SKaricheri, Muralidharan 40784640e27SKaricheri, Muralidharan /* Remove the module from each instance */ 40884640e27SKaricheri, Muralidharan list_for_each_entry_safe(inst_modpriv, inst_tmp, 40984640e27SKaricheri, Muralidharan &netcp_device->modpriv_head, inst_list) { 41084640e27SKaricheri, Muralidharan if (inst_modpriv->netcp_module == module) { 41184640e27SKaricheri, Muralidharan module->remove(netcp_device, 41284640e27SKaricheri, Muralidharan inst_modpriv->module_priv); 41384640e27SKaricheri, Muralidharan list_del(&inst_modpriv->inst_list); 41484640e27SKaricheri, Muralidharan devm_kfree(dev, inst_modpriv); 41584640e27SKaricheri, Muralidharan break; 41684640e27SKaricheri, Muralidharan } 41784640e27SKaricheri, Muralidharan } 41884640e27SKaricheri, Muralidharan } 41984640e27SKaricheri, Muralidharan 42084640e27SKaricheri, Muralidharan void netcp_unregister_module(struct netcp_module *module) 42184640e27SKaricheri, Muralidharan { 42284640e27SKaricheri, Muralidharan struct netcp_device *netcp_device; 42384640e27SKaricheri, Muralidharan struct netcp_module *module_tmp; 42484640e27SKaricheri, Muralidharan 42584640e27SKaricheri, Muralidharan mutex_lock(&netcp_modules_lock); 42684640e27SKaricheri, Muralidharan 42784640e27SKaricheri, Muralidharan list_for_each_entry(netcp_device, &netcp_devices, device_list) { 42884640e27SKaricheri, Muralidharan netcp_release_module(netcp_device, module); 42984640e27SKaricheri, Muralidharan } 43084640e27SKaricheri, Muralidharan 43184640e27SKaricheri, Muralidharan /* Remove the module from the module list */ 43284640e27SKaricheri, Muralidharan for_each_netcp_module(module_tmp) { 43384640e27SKaricheri, Muralidharan if (module == module_tmp) { 43484640e27SKaricheri, Muralidharan list_del(&module->module_list); 43584640e27SKaricheri, Muralidharan break; 43684640e27SKaricheri, Muralidharan } 43784640e27SKaricheri, Muralidharan } 43884640e27SKaricheri, Muralidharan 43984640e27SKaricheri, Muralidharan mutex_unlock(&netcp_modules_lock); 44084640e27SKaricheri, Muralidharan } 44158c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_unregister_module); 44284640e27SKaricheri, Muralidharan 44384640e27SKaricheri, Muralidharan void *netcp_module_get_intf_data(struct netcp_module *module, 44484640e27SKaricheri, Muralidharan struct netcp_intf *intf) 44584640e27SKaricheri, Muralidharan { 44684640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 44784640e27SKaricheri, Muralidharan 44884640e27SKaricheri, Muralidharan list_for_each_entry(intf_modpriv, &intf->module_head, intf_list) 44984640e27SKaricheri, Muralidharan if (intf_modpriv->netcp_module == module) 45084640e27SKaricheri, Muralidharan return intf_modpriv->module_priv; 45184640e27SKaricheri, Muralidharan return NULL; 45284640e27SKaricheri, Muralidharan } 45358c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_module_get_intf_data); 45484640e27SKaricheri, Muralidharan 45584640e27SKaricheri, Muralidharan /* Module TX and RX Hook management */ 45684640e27SKaricheri, Muralidharan struct netcp_hook_list { 45784640e27SKaricheri, Muralidharan struct list_head list; 45884640e27SKaricheri, Muralidharan netcp_hook_rtn *hook_rtn; 45984640e27SKaricheri, Muralidharan void *hook_data; 46084640e27SKaricheri, Muralidharan int order; 46184640e27SKaricheri, Muralidharan }; 46284640e27SKaricheri, Muralidharan 46384640e27SKaricheri, Muralidharan int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, 46484640e27SKaricheri, Muralidharan netcp_hook_rtn *hook_rtn, void *hook_data) 46584640e27SKaricheri, Muralidharan { 46684640e27SKaricheri, Muralidharan struct netcp_hook_list *entry; 46784640e27SKaricheri, Muralidharan struct netcp_hook_list *next; 46884640e27SKaricheri, Muralidharan unsigned long flags; 46984640e27SKaricheri, Muralidharan 47084640e27SKaricheri, Muralidharan entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); 47184640e27SKaricheri, Muralidharan if (!entry) 47284640e27SKaricheri, Muralidharan return -ENOMEM; 47384640e27SKaricheri, Muralidharan 47484640e27SKaricheri, Muralidharan entry->hook_rtn = hook_rtn; 47584640e27SKaricheri, Muralidharan entry->hook_data = hook_data; 47684640e27SKaricheri, Muralidharan entry->order = order; 47784640e27SKaricheri, Muralidharan 47884640e27SKaricheri, Muralidharan spin_lock_irqsave(&netcp_priv->lock, flags); 47984640e27SKaricheri, Muralidharan list_for_each_entry(next, &netcp_priv->txhook_list_head, list) { 48084640e27SKaricheri, Muralidharan if (next->order > order) 48184640e27SKaricheri, Muralidharan break; 48284640e27SKaricheri, Muralidharan } 48384640e27SKaricheri, Muralidharan __list_add(&entry->list, next->list.prev, &next->list); 48484640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 48584640e27SKaricheri, Muralidharan 48684640e27SKaricheri, Muralidharan return 0; 48784640e27SKaricheri, Muralidharan } 48858c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_register_txhook); 48984640e27SKaricheri, Muralidharan 49084640e27SKaricheri, Muralidharan int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, 49184640e27SKaricheri, Muralidharan netcp_hook_rtn *hook_rtn, void *hook_data) 49284640e27SKaricheri, Muralidharan { 49384640e27SKaricheri, Muralidharan struct netcp_hook_list *next, *n; 49484640e27SKaricheri, Muralidharan unsigned long flags; 49584640e27SKaricheri, Muralidharan 49684640e27SKaricheri, Muralidharan spin_lock_irqsave(&netcp_priv->lock, flags); 49784640e27SKaricheri, Muralidharan list_for_each_entry_safe(next, n, &netcp_priv->txhook_list_head, list) { 49884640e27SKaricheri, Muralidharan if ((next->order == order) && 49984640e27SKaricheri, Muralidharan (next->hook_rtn == hook_rtn) && 50084640e27SKaricheri, Muralidharan (next->hook_data == hook_data)) { 50184640e27SKaricheri, Muralidharan list_del(&next->list); 50284640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 50384640e27SKaricheri, Muralidharan devm_kfree(netcp_priv->dev, next); 50484640e27SKaricheri, Muralidharan return 0; 50584640e27SKaricheri, Muralidharan } 50684640e27SKaricheri, Muralidharan } 50784640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 50884640e27SKaricheri, Muralidharan return -ENOENT; 50984640e27SKaricheri, Muralidharan } 51058c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_unregister_txhook); 51184640e27SKaricheri, Muralidharan 51284640e27SKaricheri, Muralidharan int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, 51384640e27SKaricheri, Muralidharan netcp_hook_rtn *hook_rtn, void *hook_data) 51484640e27SKaricheri, Muralidharan { 51584640e27SKaricheri, Muralidharan struct netcp_hook_list *entry; 51684640e27SKaricheri, Muralidharan struct netcp_hook_list *next; 51784640e27SKaricheri, Muralidharan unsigned long flags; 51884640e27SKaricheri, Muralidharan 51984640e27SKaricheri, Muralidharan entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); 52084640e27SKaricheri, Muralidharan if (!entry) 52184640e27SKaricheri, Muralidharan return -ENOMEM; 52284640e27SKaricheri, Muralidharan 52384640e27SKaricheri, Muralidharan entry->hook_rtn = hook_rtn; 52484640e27SKaricheri, Muralidharan entry->hook_data = hook_data; 52584640e27SKaricheri, Muralidharan entry->order = order; 52684640e27SKaricheri, Muralidharan 52784640e27SKaricheri, Muralidharan spin_lock_irqsave(&netcp_priv->lock, flags); 52884640e27SKaricheri, Muralidharan list_for_each_entry(next, &netcp_priv->rxhook_list_head, list) { 52984640e27SKaricheri, Muralidharan if (next->order > order) 53084640e27SKaricheri, Muralidharan break; 53184640e27SKaricheri, Muralidharan } 53284640e27SKaricheri, Muralidharan __list_add(&entry->list, next->list.prev, &next->list); 53384640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 53484640e27SKaricheri, Muralidharan 53584640e27SKaricheri, Muralidharan return 0; 53684640e27SKaricheri, Muralidharan } 53784640e27SKaricheri, Muralidharan 53884640e27SKaricheri, Muralidharan int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, 53984640e27SKaricheri, Muralidharan netcp_hook_rtn *hook_rtn, void *hook_data) 54084640e27SKaricheri, Muralidharan { 54184640e27SKaricheri, Muralidharan struct netcp_hook_list *next, *n; 54284640e27SKaricheri, Muralidharan unsigned long flags; 54384640e27SKaricheri, Muralidharan 54484640e27SKaricheri, Muralidharan spin_lock_irqsave(&netcp_priv->lock, flags); 54584640e27SKaricheri, Muralidharan list_for_each_entry_safe(next, n, &netcp_priv->rxhook_list_head, list) { 54684640e27SKaricheri, Muralidharan if ((next->order == order) && 54784640e27SKaricheri, Muralidharan (next->hook_rtn == hook_rtn) && 54884640e27SKaricheri, Muralidharan (next->hook_data == hook_data)) { 54984640e27SKaricheri, Muralidharan list_del(&next->list); 55084640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 55184640e27SKaricheri, Muralidharan devm_kfree(netcp_priv->dev, next); 55284640e27SKaricheri, Muralidharan return 0; 55384640e27SKaricheri, Muralidharan } 55484640e27SKaricheri, Muralidharan } 55584640e27SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp_priv->lock, flags); 55684640e27SKaricheri, Muralidharan 55784640e27SKaricheri, Muralidharan return -ENOENT; 55884640e27SKaricheri, Muralidharan } 55984640e27SKaricheri, Muralidharan 56084640e27SKaricheri, Muralidharan static void netcp_frag_free(bool is_frag, void *ptr) 56184640e27SKaricheri, Muralidharan { 56284640e27SKaricheri, Muralidharan if (is_frag) 5637d525c4eSAlexander Duyck skb_free_frag(ptr); 56484640e27SKaricheri, Muralidharan else 56584640e27SKaricheri, Muralidharan kfree(ptr); 56684640e27SKaricheri, Muralidharan } 56784640e27SKaricheri, Muralidharan 56884640e27SKaricheri, Muralidharan static void netcp_free_rx_desc_chain(struct netcp_intf *netcp, 56984640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 57084640e27SKaricheri, Muralidharan { 57184640e27SKaricheri, Muralidharan struct knav_dma_desc *ndesc; 57284640e27SKaricheri, Muralidharan dma_addr_t dma_desc, dma_buf; 57384640e27SKaricheri, Muralidharan unsigned int buf_len, dma_sz = sizeof(*ndesc); 57484640e27SKaricheri, Muralidharan void *buf_ptr; 575958d104eSArnd Bergmann u32 tmp; 57684640e27SKaricheri, Muralidharan 57784640e27SKaricheri, Muralidharan get_words(&dma_desc, 1, &desc->next_desc); 57884640e27SKaricheri, Muralidharan 57984640e27SKaricheri, Muralidharan while (dma_desc) { 58084640e27SKaricheri, Muralidharan ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); 58184640e27SKaricheri, Muralidharan if (unlikely(!ndesc)) { 58284640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); 58384640e27SKaricheri, Muralidharan break; 58484640e27SKaricheri, Muralidharan } 585958d104eSArnd Bergmann get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc); 586b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&buf_ptr, &buf_len, ndesc); 58784640e27SKaricheri, Muralidharan dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE); 58884640e27SKaricheri, Muralidharan __free_page(buf_ptr); 58984640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 59084640e27SKaricheri, Muralidharan } 591b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&buf_ptr, &buf_len, desc); 59289907779SArnd Bergmann 59384640e27SKaricheri, Muralidharan if (buf_ptr) 59484640e27SKaricheri, Muralidharan netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr); 59584640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 59684640e27SKaricheri, Muralidharan } 59784640e27SKaricheri, Muralidharan 59884640e27SKaricheri, Muralidharan static void netcp_empty_rx_queue(struct netcp_intf *netcp) 59984640e27SKaricheri, Muralidharan { 60084640e27SKaricheri, Muralidharan struct knav_dma_desc *desc; 60184640e27SKaricheri, Muralidharan unsigned int dma_sz; 60284640e27SKaricheri, Muralidharan dma_addr_t dma; 60384640e27SKaricheri, Muralidharan 60484640e27SKaricheri, Muralidharan for (; ;) { 60584640e27SKaricheri, Muralidharan dma = knav_queue_pop(netcp->rx_queue, &dma_sz); 60684640e27SKaricheri, Muralidharan if (!dma) 60784640e27SKaricheri, Muralidharan break; 60884640e27SKaricheri, Muralidharan 60984640e27SKaricheri, Muralidharan desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); 61084640e27SKaricheri, Muralidharan if (unlikely(!desc)) { 61184640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n", 61284640e27SKaricheri, Muralidharan __func__); 61384640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_errors++; 61484640e27SKaricheri, Muralidharan continue; 61584640e27SKaricheri, Muralidharan } 61684640e27SKaricheri, Muralidharan netcp_free_rx_desc_chain(netcp, desc); 61784640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_dropped++; 61884640e27SKaricheri, Muralidharan } 61984640e27SKaricheri, Muralidharan } 62084640e27SKaricheri, Muralidharan 62184640e27SKaricheri, Muralidharan static int netcp_process_one_rx_packet(struct netcp_intf *netcp) 62284640e27SKaricheri, Muralidharan { 62384640e27SKaricheri, Muralidharan unsigned int dma_sz, buf_len, org_buf_len; 62484640e27SKaricheri, Muralidharan struct knav_dma_desc *desc, *ndesc; 62584640e27SKaricheri, Muralidharan unsigned int pkt_sz = 0, accum_sz; 62684640e27SKaricheri, Muralidharan struct netcp_hook_list *rx_hook; 62784640e27SKaricheri, Muralidharan dma_addr_t dma_desc, dma_buff; 62884640e27SKaricheri, Muralidharan struct netcp_packet p_info; 62984640e27SKaricheri, Muralidharan struct sk_buff *skb; 63084640e27SKaricheri, Muralidharan void *org_buf_ptr; 6319ecfe875SKaricheri, Muralidharan u32 tmp; 63284640e27SKaricheri, Muralidharan 63384640e27SKaricheri, Muralidharan dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz); 63484640e27SKaricheri, Muralidharan if (!dma_desc) 63584640e27SKaricheri, Muralidharan return -1; 63684640e27SKaricheri, Muralidharan 63784640e27SKaricheri, Muralidharan desc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); 63884640e27SKaricheri, Muralidharan if (unlikely(!desc)) { 63984640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); 64084640e27SKaricheri, Muralidharan return 0; 64184640e27SKaricheri, Muralidharan } 64284640e27SKaricheri, Muralidharan 64384640e27SKaricheri, Muralidharan get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc); 644b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&org_buf_ptr, &org_buf_len, desc); 64584640e27SKaricheri, Muralidharan 64684640e27SKaricheri, Muralidharan if (unlikely(!org_buf_ptr)) { 64784640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); 64884640e27SKaricheri, Muralidharan goto free_desc; 64984640e27SKaricheri, Muralidharan } 65084640e27SKaricheri, Muralidharan 65184640e27SKaricheri, Muralidharan pkt_sz &= KNAV_DMA_DESC_PKT_LEN_MASK; 65284640e27SKaricheri, Muralidharan accum_sz = buf_len; 65384640e27SKaricheri, Muralidharan dma_unmap_single(netcp->dev, dma_buff, buf_len, DMA_FROM_DEVICE); 65484640e27SKaricheri, Muralidharan 65584640e27SKaricheri, Muralidharan /* Build a new sk_buff for the primary buffer */ 65684640e27SKaricheri, Muralidharan skb = build_skb(org_buf_ptr, org_buf_len); 65784640e27SKaricheri, Muralidharan if (unlikely(!skb)) { 65884640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "build_skb() failed\n"); 65984640e27SKaricheri, Muralidharan goto free_desc; 66084640e27SKaricheri, Muralidharan } 66184640e27SKaricheri, Muralidharan 66284640e27SKaricheri, Muralidharan /* update data, tail and len */ 66384640e27SKaricheri, Muralidharan skb_reserve(skb, NETCP_SOP_OFFSET); 66484640e27SKaricheri, Muralidharan __skb_put(skb, buf_len); 66584640e27SKaricheri, Muralidharan 66684640e27SKaricheri, Muralidharan /* Fill in the page fragment list */ 66784640e27SKaricheri, Muralidharan while (dma_desc) { 66884640e27SKaricheri, Muralidharan struct page *page; 66984640e27SKaricheri, Muralidharan 67084640e27SKaricheri, Muralidharan ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); 67184640e27SKaricheri, Muralidharan if (unlikely(!ndesc)) { 67284640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); 67384640e27SKaricheri, Muralidharan goto free_desc; 67484640e27SKaricheri, Muralidharan } 67584640e27SKaricheri, Muralidharan 67684640e27SKaricheri, Muralidharan get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc); 677b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&page, &tmp, ndesc); 67884640e27SKaricheri, Muralidharan 67984640e27SKaricheri, Muralidharan if (likely(dma_buff && buf_len && page)) { 68084640e27SKaricheri, Muralidharan dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE, 68184640e27SKaricheri, Muralidharan DMA_FROM_DEVICE); 68284640e27SKaricheri, Muralidharan } else { 68389907779SArnd Bergmann dev_err(netcp->ndev_dev, "Bad Rx desc dma_buff(%pad), len(%d), page(%p)\n", 68489907779SArnd Bergmann &dma_buff, buf_len, page); 68584640e27SKaricheri, Muralidharan goto free_desc; 68684640e27SKaricheri, Muralidharan } 68784640e27SKaricheri, Muralidharan 68884640e27SKaricheri, Muralidharan skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 68984640e27SKaricheri, Muralidharan offset_in_page(dma_buff), buf_len, PAGE_SIZE); 69084640e27SKaricheri, Muralidharan accum_sz += buf_len; 69184640e27SKaricheri, Muralidharan 69284640e27SKaricheri, Muralidharan /* Free the descriptor */ 69384640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, ndesc); 69484640e27SKaricheri, Muralidharan } 69584640e27SKaricheri, Muralidharan 69684640e27SKaricheri, Muralidharan /* Free the primary descriptor */ 69784640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 69884640e27SKaricheri, Muralidharan 69984640e27SKaricheri, Muralidharan /* check for packet len and warn */ 70084640e27SKaricheri, Muralidharan if (unlikely(pkt_sz != accum_sz)) 70184640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n", 70284640e27SKaricheri, Muralidharan pkt_sz, accum_sz); 70384640e27SKaricheri, Muralidharan 70484640e27SKaricheri, Muralidharan /* Remove ethernet FCS from the packet */ 70584640e27SKaricheri, Muralidharan __pskb_trim(skb, skb->len - ETH_FCS_LEN); 70684640e27SKaricheri, Muralidharan 70784640e27SKaricheri, Muralidharan /* Call each of the RX hooks */ 70884640e27SKaricheri, Muralidharan p_info.skb = skb; 70984640e27SKaricheri, Muralidharan p_info.rxtstamp_complete = false; 71084640e27SKaricheri, Muralidharan list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) { 71184640e27SKaricheri, Muralidharan int ret; 71284640e27SKaricheri, Muralidharan 71384640e27SKaricheri, Muralidharan ret = rx_hook->hook_rtn(rx_hook->order, rx_hook->hook_data, 71484640e27SKaricheri, Muralidharan &p_info); 71584640e27SKaricheri, Muralidharan if (unlikely(ret)) { 71684640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n", 71784640e27SKaricheri, Muralidharan rx_hook->order, ret); 71884640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_errors++; 71984640e27SKaricheri, Muralidharan dev_kfree_skb(skb); 72084640e27SKaricheri, Muralidharan return 0; 72184640e27SKaricheri, Muralidharan } 72284640e27SKaricheri, Muralidharan } 72384640e27SKaricheri, Muralidharan 72484640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_packets++; 72584640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_bytes += skb->len; 72684640e27SKaricheri, Muralidharan 72784640e27SKaricheri, Muralidharan /* push skb up the stack */ 72884640e27SKaricheri, Muralidharan skb->protocol = eth_type_trans(skb, netcp->ndev); 72984640e27SKaricheri, Muralidharan netif_receive_skb(skb); 73084640e27SKaricheri, Muralidharan return 0; 73184640e27SKaricheri, Muralidharan 73284640e27SKaricheri, Muralidharan free_desc: 73384640e27SKaricheri, Muralidharan netcp_free_rx_desc_chain(netcp, desc); 73484640e27SKaricheri, Muralidharan netcp->ndev->stats.rx_errors++; 73584640e27SKaricheri, Muralidharan return 0; 73684640e27SKaricheri, Muralidharan } 73784640e27SKaricheri, Muralidharan 73884640e27SKaricheri, Muralidharan static int netcp_process_rx_packets(struct netcp_intf *netcp, 73984640e27SKaricheri, Muralidharan unsigned int budget) 74084640e27SKaricheri, Muralidharan { 74184640e27SKaricheri, Muralidharan int i; 74284640e27SKaricheri, Muralidharan 74384640e27SKaricheri, Muralidharan for (i = 0; (i < budget) && !netcp_process_one_rx_packet(netcp); i++) 74484640e27SKaricheri, Muralidharan ; 74584640e27SKaricheri, Muralidharan return i; 74684640e27SKaricheri, Muralidharan } 74784640e27SKaricheri, Muralidharan 74884640e27SKaricheri, Muralidharan /* Release descriptors and attached buffers from Rx FDQ */ 74984640e27SKaricheri, Muralidharan static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq) 75084640e27SKaricheri, Muralidharan { 75184640e27SKaricheri, Muralidharan struct knav_dma_desc *desc; 75284640e27SKaricheri, Muralidharan unsigned int buf_len, dma_sz; 75384640e27SKaricheri, Muralidharan dma_addr_t dma; 75484640e27SKaricheri, Muralidharan void *buf_ptr; 7559ecfe875SKaricheri, Muralidharan u32 tmp; 75684640e27SKaricheri, Muralidharan 75784640e27SKaricheri, Muralidharan /* Allocate descriptor */ 75884640e27SKaricheri, Muralidharan while ((dma = knav_queue_pop(netcp->rx_fdq[fdq], &dma_sz))) { 75984640e27SKaricheri, Muralidharan desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); 76084640e27SKaricheri, Muralidharan if (unlikely(!desc)) { 76184640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); 76284640e27SKaricheri, Muralidharan continue; 76384640e27SKaricheri, Muralidharan } 76484640e27SKaricheri, Muralidharan 76584640e27SKaricheri, Muralidharan get_org_pkt_info(&dma, &buf_len, desc); 766b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&buf_ptr, &tmp, desc); 76784640e27SKaricheri, Muralidharan 76884640e27SKaricheri, Muralidharan if (unlikely(!dma)) { 76984640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n"); 77084640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 77184640e27SKaricheri, Muralidharan continue; 77284640e27SKaricheri, Muralidharan } 77384640e27SKaricheri, Muralidharan 77484640e27SKaricheri, Muralidharan if (unlikely(!buf_ptr)) { 77584640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); 77684640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 77784640e27SKaricheri, Muralidharan continue; 77884640e27SKaricheri, Muralidharan } 77984640e27SKaricheri, Muralidharan 78084640e27SKaricheri, Muralidharan if (fdq == 0) { 78184640e27SKaricheri, Muralidharan dma_unmap_single(netcp->dev, dma, buf_len, 78284640e27SKaricheri, Muralidharan DMA_FROM_DEVICE); 78384640e27SKaricheri, Muralidharan netcp_frag_free((buf_len <= PAGE_SIZE), buf_ptr); 78484640e27SKaricheri, Muralidharan } else { 78584640e27SKaricheri, Muralidharan dma_unmap_page(netcp->dev, dma, buf_len, 78684640e27SKaricheri, Muralidharan DMA_FROM_DEVICE); 78784640e27SKaricheri, Muralidharan __free_page(buf_ptr); 78884640e27SKaricheri, Muralidharan } 78984640e27SKaricheri, Muralidharan 79084640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, desc); 79184640e27SKaricheri, Muralidharan } 79284640e27SKaricheri, Muralidharan } 79384640e27SKaricheri, Muralidharan 79484640e27SKaricheri, Muralidharan static void netcp_rxpool_free(struct netcp_intf *netcp) 79584640e27SKaricheri, Muralidharan { 79684640e27SKaricheri, Muralidharan int i; 79784640e27SKaricheri, Muralidharan 79884640e27SKaricheri, Muralidharan for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && 79984640e27SKaricheri, Muralidharan !IS_ERR_OR_NULL(netcp->rx_fdq[i]); i++) 80084640e27SKaricheri, Muralidharan netcp_free_rx_buf(netcp, i); 80184640e27SKaricheri, Muralidharan 80284640e27SKaricheri, Muralidharan if (knav_pool_count(netcp->rx_pool) != netcp->rx_pool_size) 80384640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Lost Rx (%d) descriptors\n", 80484640e27SKaricheri, Muralidharan netcp->rx_pool_size - knav_pool_count(netcp->rx_pool)); 80584640e27SKaricheri, Muralidharan 80684640e27SKaricheri, Muralidharan knav_pool_destroy(netcp->rx_pool); 80784640e27SKaricheri, Muralidharan netcp->rx_pool = NULL; 80884640e27SKaricheri, Muralidharan } 80984640e27SKaricheri, Muralidharan 810e558b1fbSKaricheri, Muralidharan static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq) 81184640e27SKaricheri, Muralidharan { 81284640e27SKaricheri, Muralidharan struct knav_dma_desc *hwdesc; 81384640e27SKaricheri, Muralidharan unsigned int buf_len, dma_sz; 81484640e27SKaricheri, Muralidharan u32 desc_info, pkt_info; 81584640e27SKaricheri, Muralidharan struct page *page; 81684640e27SKaricheri, Muralidharan dma_addr_t dma; 81784640e27SKaricheri, Muralidharan void *bufptr; 818b1cb86aeSKaricheri, Muralidharan u32 sw_data[2]; 81984640e27SKaricheri, Muralidharan 82084640e27SKaricheri, Muralidharan /* Allocate descriptor */ 82184640e27SKaricheri, Muralidharan hwdesc = knav_pool_desc_get(netcp->rx_pool); 82284640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(hwdesc)) { 82384640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "out of rx pool desc\n"); 824e558b1fbSKaricheri, Muralidharan return -ENOMEM; 82584640e27SKaricheri, Muralidharan } 82684640e27SKaricheri, Muralidharan 82784640e27SKaricheri, Muralidharan if (likely(fdq == 0)) { 82884640e27SKaricheri, Muralidharan unsigned int primary_buf_len; 82984640e27SKaricheri, Muralidharan /* Allocate a primary receive queue entry */ 830866b8b18SWingMan Kwok buf_len = NETCP_PACKET_SIZE + NETCP_SOP_OFFSET; 83184640e27SKaricheri, Muralidharan primary_buf_len = SKB_DATA_ALIGN(buf_len) + 83284640e27SKaricheri, Muralidharan SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 83384640e27SKaricheri, Muralidharan 83484640e27SKaricheri, Muralidharan bufptr = netdev_alloc_frag(primary_buf_len); 835b1cb86aeSKaricheri, Muralidharan sw_data[1] = primary_buf_len; 83684640e27SKaricheri, Muralidharan 83784640e27SKaricheri, Muralidharan if (unlikely(!bufptr)) { 838866b8b18SWingMan Kwok dev_warn_ratelimited(netcp->ndev_dev, 839866b8b18SWingMan Kwok "Primary RX buffer alloc failed\n"); 84084640e27SKaricheri, Muralidharan goto fail; 84184640e27SKaricheri, Muralidharan } 84284640e27SKaricheri, Muralidharan dma = dma_map_single(netcp->dev, bufptr, buf_len, 84384640e27SKaricheri, Muralidharan DMA_TO_DEVICE); 844866b8b18SWingMan Kwok if (unlikely(dma_mapping_error(netcp->dev, dma))) 845866b8b18SWingMan Kwok goto fail; 846866b8b18SWingMan Kwok 847b1cb86aeSKaricheri, Muralidharan sw_data[0] = (u32)bufptr; 84884640e27SKaricheri, Muralidharan } else { 84984640e27SKaricheri, Muralidharan /* Allocate a secondary receive queue entry */ 850866b8b18SWingMan Kwok page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD); 85184640e27SKaricheri, Muralidharan if (unlikely(!page)) { 85284640e27SKaricheri, Muralidharan dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n"); 85384640e27SKaricheri, Muralidharan goto fail; 85484640e27SKaricheri, Muralidharan } 85584640e27SKaricheri, Muralidharan buf_len = PAGE_SIZE; 85684640e27SKaricheri, Muralidharan dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE); 857b1cb86aeSKaricheri, Muralidharan sw_data[0] = (u32)page; 858b1cb86aeSKaricheri, Muralidharan sw_data[1] = 0; 85984640e27SKaricheri, Muralidharan } 86084640e27SKaricheri, Muralidharan 86184640e27SKaricheri, Muralidharan desc_info = KNAV_DMA_DESC_PS_INFO_IN_DESC; 86284640e27SKaricheri, Muralidharan desc_info |= buf_len & KNAV_DMA_DESC_PKT_LEN_MASK; 86384640e27SKaricheri, Muralidharan pkt_info = KNAV_DMA_DESC_HAS_EPIB; 86484640e27SKaricheri, Muralidharan pkt_info |= KNAV_DMA_NUM_PS_WORDS << KNAV_DMA_DESC_PSLEN_SHIFT; 86584640e27SKaricheri, Muralidharan pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) << 86684640e27SKaricheri, Muralidharan KNAV_DMA_DESC_RETQ_SHIFT; 86784640e27SKaricheri, Muralidharan set_org_pkt_info(dma, buf_len, hwdesc); 868b1cb86aeSKaricheri, Muralidharan set_sw_data(sw_data[0], sw_data[1], hwdesc); 86984640e27SKaricheri, Muralidharan set_desc_info(desc_info, pkt_info, hwdesc); 87084640e27SKaricheri, Muralidharan 87184640e27SKaricheri, Muralidharan /* Push to FDQs */ 87284640e27SKaricheri, Muralidharan knav_pool_desc_map(netcp->rx_pool, hwdesc, sizeof(*hwdesc), &dma, 87384640e27SKaricheri, Muralidharan &dma_sz); 87484640e27SKaricheri, Muralidharan knav_queue_push(netcp->rx_fdq[fdq], dma, sizeof(*hwdesc), 0); 875e558b1fbSKaricheri, Muralidharan return 0; 87684640e27SKaricheri, Muralidharan 87784640e27SKaricheri, Muralidharan fail: 87884640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->rx_pool, hwdesc); 879e558b1fbSKaricheri, Muralidharan return -ENOMEM; 88084640e27SKaricheri, Muralidharan } 88184640e27SKaricheri, Muralidharan 88284640e27SKaricheri, Muralidharan /* Refill Rx FDQ with descriptors & attached buffers */ 88384640e27SKaricheri, Muralidharan static void netcp_rxpool_refill(struct netcp_intf *netcp) 88484640e27SKaricheri, Muralidharan { 88584640e27SKaricheri, Muralidharan u32 fdq_deficit[KNAV_DMA_FDQ_PER_CHAN] = {0}; 886e558b1fbSKaricheri, Muralidharan int i, ret = 0; 88784640e27SKaricheri, Muralidharan 88884640e27SKaricheri, Muralidharan /* Calculate the FDQ deficit and refill */ 88984640e27SKaricheri, Muralidharan for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_fdq[i]; i++) { 89084640e27SKaricheri, Muralidharan fdq_deficit[i] = netcp->rx_queue_depths[i] - 89184640e27SKaricheri, Muralidharan knav_queue_get_count(netcp->rx_fdq[i]); 89284640e27SKaricheri, Muralidharan 893e558b1fbSKaricheri, Muralidharan while (fdq_deficit[i]-- && !ret) 894e558b1fbSKaricheri, Muralidharan ret = netcp_allocate_rx_buf(netcp, i); 89584640e27SKaricheri, Muralidharan } /* end for fdqs */ 89684640e27SKaricheri, Muralidharan } 89784640e27SKaricheri, Muralidharan 89884640e27SKaricheri, Muralidharan /* NAPI poll */ 89984640e27SKaricheri, Muralidharan static int netcp_rx_poll(struct napi_struct *napi, int budget) 90084640e27SKaricheri, Muralidharan { 90184640e27SKaricheri, Muralidharan struct netcp_intf *netcp = container_of(napi, struct netcp_intf, 90284640e27SKaricheri, Muralidharan rx_napi); 90384640e27SKaricheri, Muralidharan unsigned int packets; 90484640e27SKaricheri, Muralidharan 90584640e27SKaricheri, Muralidharan packets = netcp_process_rx_packets(netcp, budget); 90684640e27SKaricheri, Muralidharan 90799f8ef5dSKaricheri, Muralidharan netcp_rxpool_refill(netcp); 90884640e27SKaricheri, Muralidharan if (packets < budget) { 90984640e27SKaricheri, Muralidharan napi_complete(&netcp->rx_napi); 91084640e27SKaricheri, Muralidharan knav_queue_enable_notify(netcp->rx_queue); 91184640e27SKaricheri, Muralidharan } 91284640e27SKaricheri, Muralidharan 91384640e27SKaricheri, Muralidharan return packets; 91484640e27SKaricheri, Muralidharan } 91584640e27SKaricheri, Muralidharan 91684640e27SKaricheri, Muralidharan static void netcp_rx_notify(void *arg) 91784640e27SKaricheri, Muralidharan { 91884640e27SKaricheri, Muralidharan struct netcp_intf *netcp = arg; 91984640e27SKaricheri, Muralidharan 92084640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->rx_queue); 92184640e27SKaricheri, Muralidharan napi_schedule(&netcp->rx_napi); 92284640e27SKaricheri, Muralidharan } 92384640e27SKaricheri, Muralidharan 92484640e27SKaricheri, Muralidharan static void netcp_free_tx_desc_chain(struct netcp_intf *netcp, 92584640e27SKaricheri, Muralidharan struct knav_dma_desc *desc, 92684640e27SKaricheri, Muralidharan unsigned int desc_sz) 92784640e27SKaricheri, Muralidharan { 92884640e27SKaricheri, Muralidharan struct knav_dma_desc *ndesc = desc; 92984640e27SKaricheri, Muralidharan dma_addr_t dma_desc, dma_buf; 93084640e27SKaricheri, Muralidharan unsigned int buf_len; 93184640e27SKaricheri, Muralidharan 93284640e27SKaricheri, Muralidharan while (ndesc) { 93384640e27SKaricheri, Muralidharan get_pkt_info(&dma_buf, &buf_len, &dma_desc, ndesc); 93484640e27SKaricheri, Muralidharan 93584640e27SKaricheri, Muralidharan if (dma_buf && buf_len) 93684640e27SKaricheri, Muralidharan dma_unmap_single(netcp->dev, dma_buf, buf_len, 93784640e27SKaricheri, Muralidharan DMA_TO_DEVICE); 93884640e27SKaricheri, Muralidharan else 93989907779SArnd Bergmann dev_warn(netcp->ndev_dev, "bad Tx desc buf(%pad), len(%d)\n", 94089907779SArnd Bergmann &dma_buf, buf_len); 94184640e27SKaricheri, Muralidharan 94284640e27SKaricheri, Muralidharan knav_pool_desc_put(netcp->tx_pool, ndesc); 94384640e27SKaricheri, Muralidharan ndesc = NULL; 94484640e27SKaricheri, Muralidharan if (dma_desc) { 94584640e27SKaricheri, Muralidharan ndesc = knav_pool_desc_unmap(netcp->tx_pool, dma_desc, 94684640e27SKaricheri, Muralidharan desc_sz); 94784640e27SKaricheri, Muralidharan if (!ndesc) 94884640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); 94984640e27SKaricheri, Muralidharan } 95084640e27SKaricheri, Muralidharan } 95184640e27SKaricheri, Muralidharan } 95284640e27SKaricheri, Muralidharan 95384640e27SKaricheri, Muralidharan static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, 95484640e27SKaricheri, Muralidharan unsigned int budget) 95584640e27SKaricheri, Muralidharan { 95684640e27SKaricheri, Muralidharan struct knav_dma_desc *desc; 95784640e27SKaricheri, Muralidharan struct sk_buff *skb; 95884640e27SKaricheri, Muralidharan unsigned int dma_sz; 95984640e27SKaricheri, Muralidharan dma_addr_t dma; 96084640e27SKaricheri, Muralidharan int pkts = 0; 9619ecfe875SKaricheri, Muralidharan u32 tmp; 96284640e27SKaricheri, Muralidharan 96384640e27SKaricheri, Muralidharan while (budget--) { 96484640e27SKaricheri, Muralidharan dma = knav_queue_pop(netcp->tx_compl_q, &dma_sz); 96584640e27SKaricheri, Muralidharan if (!dma) 96684640e27SKaricheri, Muralidharan break; 96784640e27SKaricheri, Muralidharan desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz); 96884640e27SKaricheri, Muralidharan if (unlikely(!desc)) { 96984640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); 97084640e27SKaricheri, Muralidharan netcp->ndev->stats.tx_errors++; 97184640e27SKaricheri, Muralidharan continue; 97284640e27SKaricheri, Muralidharan } 97384640e27SKaricheri, Muralidharan 974b1cb86aeSKaricheri, Muralidharan get_sw_data((u32 *)&skb, &tmp, desc); 97584640e27SKaricheri, Muralidharan netcp_free_tx_desc_chain(netcp, desc, dma_sz); 97684640e27SKaricheri, Muralidharan if (!skb) { 97784640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "No skb in Tx desc\n"); 97884640e27SKaricheri, Muralidharan netcp->ndev->stats.tx_errors++; 97984640e27SKaricheri, Muralidharan continue; 98084640e27SKaricheri, Muralidharan } 98184640e27SKaricheri, Muralidharan 98284640e27SKaricheri, Muralidharan if (netif_subqueue_stopped(netcp->ndev, skb) && 98384640e27SKaricheri, Muralidharan netif_running(netcp->ndev) && 98484640e27SKaricheri, Muralidharan (knav_pool_count(netcp->tx_pool) > 98584640e27SKaricheri, Muralidharan netcp->tx_resume_threshold)) { 98684640e27SKaricheri, Muralidharan u16 subqueue = skb_get_queue_mapping(skb); 98784640e27SKaricheri, Muralidharan 98884640e27SKaricheri, Muralidharan netif_wake_subqueue(netcp->ndev, subqueue); 98984640e27SKaricheri, Muralidharan } 99084640e27SKaricheri, Muralidharan 99184640e27SKaricheri, Muralidharan netcp->ndev->stats.tx_packets++; 99284640e27SKaricheri, Muralidharan netcp->ndev->stats.tx_bytes += skb->len; 99384640e27SKaricheri, Muralidharan dev_kfree_skb(skb); 99484640e27SKaricheri, Muralidharan pkts++; 99584640e27SKaricheri, Muralidharan } 99684640e27SKaricheri, Muralidharan return pkts; 99784640e27SKaricheri, Muralidharan } 99884640e27SKaricheri, Muralidharan 99984640e27SKaricheri, Muralidharan static int netcp_tx_poll(struct napi_struct *napi, int budget) 100084640e27SKaricheri, Muralidharan { 100184640e27SKaricheri, Muralidharan int packets; 100284640e27SKaricheri, Muralidharan struct netcp_intf *netcp = container_of(napi, struct netcp_intf, 100384640e27SKaricheri, Muralidharan tx_napi); 100484640e27SKaricheri, Muralidharan 100584640e27SKaricheri, Muralidharan packets = netcp_process_tx_compl_packets(netcp, budget); 100684640e27SKaricheri, Muralidharan if (packets < budget) { 100784640e27SKaricheri, Muralidharan napi_complete(&netcp->tx_napi); 100884640e27SKaricheri, Muralidharan knav_queue_enable_notify(netcp->tx_compl_q); 100984640e27SKaricheri, Muralidharan } 101084640e27SKaricheri, Muralidharan 101184640e27SKaricheri, Muralidharan return packets; 101284640e27SKaricheri, Muralidharan } 101384640e27SKaricheri, Muralidharan 101484640e27SKaricheri, Muralidharan static void netcp_tx_notify(void *arg) 101584640e27SKaricheri, Muralidharan { 101684640e27SKaricheri, Muralidharan struct netcp_intf *netcp = arg; 101784640e27SKaricheri, Muralidharan 101884640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->tx_compl_q); 101984640e27SKaricheri, Muralidharan napi_schedule(&netcp->tx_napi); 102084640e27SKaricheri, Muralidharan } 102184640e27SKaricheri, Muralidharan 102284640e27SKaricheri, Muralidharan static struct knav_dma_desc* 102384640e27SKaricheri, Muralidharan netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp) 102484640e27SKaricheri, Muralidharan { 102584640e27SKaricheri, Muralidharan struct knav_dma_desc *desc, *ndesc, *pdesc; 102684640e27SKaricheri, Muralidharan unsigned int pkt_len = skb_headlen(skb); 102784640e27SKaricheri, Muralidharan struct device *dev = netcp->dev; 102884640e27SKaricheri, Muralidharan dma_addr_t dma_addr; 102984640e27SKaricheri, Muralidharan unsigned int dma_sz; 103084640e27SKaricheri, Muralidharan int i; 103184640e27SKaricheri, Muralidharan 103284640e27SKaricheri, Muralidharan /* Map the linear buffer */ 103384640e27SKaricheri, Muralidharan dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE); 1034866b8b18SWingMan Kwok if (unlikely(dma_mapping_error(dev, dma_addr))) { 103584640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Failed to map skb buffer\n"); 103684640e27SKaricheri, Muralidharan return NULL; 103784640e27SKaricheri, Muralidharan } 103884640e27SKaricheri, Muralidharan 103984640e27SKaricheri, Muralidharan desc = knav_pool_desc_get(netcp->tx_pool); 1040bf69a3b6SViresh Kumar if (IS_ERR_OR_NULL(desc)) { 104184640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "out of TX desc\n"); 104284640e27SKaricheri, Muralidharan dma_unmap_single(dev, dma_addr, pkt_len, DMA_TO_DEVICE); 104384640e27SKaricheri, Muralidharan return NULL; 104484640e27SKaricheri, Muralidharan } 104584640e27SKaricheri, Muralidharan 104684640e27SKaricheri, Muralidharan set_pkt_info(dma_addr, pkt_len, 0, desc); 104784640e27SKaricheri, Muralidharan if (skb_is_nonlinear(skb)) { 104884640e27SKaricheri, Muralidharan prefetchw(skb_shinfo(skb)); 104984640e27SKaricheri, Muralidharan } else { 105084640e27SKaricheri, Muralidharan desc->next_desc = 0; 105184640e27SKaricheri, Muralidharan goto upd_pkt_len; 105284640e27SKaricheri, Muralidharan } 105384640e27SKaricheri, Muralidharan 105484640e27SKaricheri, Muralidharan pdesc = desc; 105584640e27SKaricheri, Muralidharan 105684640e27SKaricheri, Muralidharan /* Handle the case where skb is fragmented in pages */ 105784640e27SKaricheri, Muralidharan for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 105884640e27SKaricheri, Muralidharan skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 105984640e27SKaricheri, Muralidharan struct page *page = skb_frag_page(frag); 106084640e27SKaricheri, Muralidharan u32 page_offset = frag->page_offset; 106184640e27SKaricheri, Muralidharan u32 buf_len = skb_frag_size(frag); 106284640e27SKaricheri, Muralidharan dma_addr_t desc_dma; 106389907779SArnd Bergmann u32 desc_dma_32; 106484640e27SKaricheri, Muralidharan u32 pkt_info; 106584640e27SKaricheri, Muralidharan 106684640e27SKaricheri, Muralidharan dma_addr = dma_map_page(dev, page, page_offset, buf_len, 106784640e27SKaricheri, Muralidharan DMA_TO_DEVICE); 106884640e27SKaricheri, Muralidharan if (unlikely(!dma_addr)) { 106984640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Failed to map skb page\n"); 107084640e27SKaricheri, Muralidharan goto free_descs; 107184640e27SKaricheri, Muralidharan } 107284640e27SKaricheri, Muralidharan 107384640e27SKaricheri, Muralidharan ndesc = knav_pool_desc_get(netcp->tx_pool); 1074bf69a3b6SViresh Kumar if (IS_ERR_OR_NULL(ndesc)) { 107584640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "out of TX desc for frags\n"); 107684640e27SKaricheri, Muralidharan dma_unmap_page(dev, dma_addr, buf_len, DMA_TO_DEVICE); 107784640e27SKaricheri, Muralidharan goto free_descs; 107884640e27SKaricheri, Muralidharan } 107984640e27SKaricheri, Muralidharan 108089907779SArnd Bergmann desc_dma = knav_pool_desc_virt_to_dma(netcp->tx_pool, ndesc); 108184640e27SKaricheri, Muralidharan pkt_info = 108284640e27SKaricheri, Muralidharan (netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << 108384640e27SKaricheri, Muralidharan KNAV_DMA_DESC_RETQ_SHIFT; 108484640e27SKaricheri, Muralidharan set_pkt_info(dma_addr, buf_len, 0, ndesc); 108589907779SArnd Bergmann desc_dma_32 = (u32)desc_dma; 108689907779SArnd Bergmann set_words(&desc_dma_32, 1, &pdesc->next_desc); 108784640e27SKaricheri, Muralidharan pkt_len += buf_len; 108884640e27SKaricheri, Muralidharan if (pdesc != desc) 108984640e27SKaricheri, Muralidharan knav_pool_desc_map(netcp->tx_pool, pdesc, 109084640e27SKaricheri, Muralidharan sizeof(*pdesc), &desc_dma, &dma_sz); 109184640e27SKaricheri, Muralidharan pdesc = ndesc; 109284640e27SKaricheri, Muralidharan } 109384640e27SKaricheri, Muralidharan if (pdesc != desc) 109484640e27SKaricheri, Muralidharan knav_pool_desc_map(netcp->tx_pool, pdesc, sizeof(*pdesc), 109584640e27SKaricheri, Muralidharan &dma_addr, &dma_sz); 109684640e27SKaricheri, Muralidharan 109784640e27SKaricheri, Muralidharan /* frag list based linkage is not supported for now. */ 109884640e27SKaricheri, Muralidharan if (skb_shinfo(skb)->frag_list) { 109984640e27SKaricheri, Muralidharan dev_err_ratelimited(netcp->ndev_dev, "NETIF_F_FRAGLIST not supported\n"); 110084640e27SKaricheri, Muralidharan goto free_descs; 110184640e27SKaricheri, Muralidharan } 110284640e27SKaricheri, Muralidharan 110384640e27SKaricheri, Muralidharan upd_pkt_len: 110484640e27SKaricheri, Muralidharan WARN_ON(pkt_len != skb->len); 110584640e27SKaricheri, Muralidharan 110684640e27SKaricheri, Muralidharan pkt_len &= KNAV_DMA_DESC_PKT_LEN_MASK; 110784640e27SKaricheri, Muralidharan set_words(&pkt_len, 1, &desc->desc_info); 110884640e27SKaricheri, Muralidharan return desc; 110984640e27SKaricheri, Muralidharan 111084640e27SKaricheri, Muralidharan free_descs: 111184640e27SKaricheri, Muralidharan netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); 111284640e27SKaricheri, Muralidharan return NULL; 111384640e27SKaricheri, Muralidharan } 111484640e27SKaricheri, Muralidharan 111584640e27SKaricheri, Muralidharan static int netcp_tx_submit_skb(struct netcp_intf *netcp, 111684640e27SKaricheri, Muralidharan struct sk_buff *skb, 111784640e27SKaricheri, Muralidharan struct knav_dma_desc *desc) 111884640e27SKaricheri, Muralidharan { 111984640e27SKaricheri, Muralidharan struct netcp_tx_pipe *tx_pipe = NULL; 112084640e27SKaricheri, Muralidharan struct netcp_hook_list *tx_hook; 112184640e27SKaricheri, Muralidharan struct netcp_packet p_info; 112284640e27SKaricheri, Muralidharan unsigned int dma_sz; 112384640e27SKaricheri, Muralidharan dma_addr_t dma; 1124e170f409SKaricheri, Muralidharan u32 tmp = 0; 112584640e27SKaricheri, Muralidharan int ret = 0; 112684640e27SKaricheri, Muralidharan 112784640e27SKaricheri, Muralidharan p_info.netcp = netcp; 112884640e27SKaricheri, Muralidharan p_info.skb = skb; 112984640e27SKaricheri, Muralidharan p_info.tx_pipe = NULL; 113084640e27SKaricheri, Muralidharan p_info.psdata_len = 0; 113184640e27SKaricheri, Muralidharan p_info.ts_context = NULL; 113284640e27SKaricheri, Muralidharan p_info.txtstamp_complete = NULL; 113384640e27SKaricheri, Muralidharan p_info.epib = desc->epib; 11349dd2d6c5SArnd Bergmann p_info.psdata = (u32 __force *)desc->psdata; 11359dd2d6c5SArnd Bergmann memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(__le32)); 113684640e27SKaricheri, Muralidharan 113784640e27SKaricheri, Muralidharan /* Find out where to inject the packet for transmission */ 113884640e27SKaricheri, Muralidharan list_for_each_entry(tx_hook, &netcp->txhook_list_head, list) { 113984640e27SKaricheri, Muralidharan ret = tx_hook->hook_rtn(tx_hook->order, tx_hook->hook_data, 114084640e27SKaricheri, Muralidharan &p_info); 114184640e27SKaricheri, Muralidharan if (unlikely(ret != 0)) { 114284640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "TX hook %d rejected the packet with reason(%d)\n", 114384640e27SKaricheri, Muralidharan tx_hook->order, ret); 114484640e27SKaricheri, Muralidharan ret = (ret < 0) ? ret : NETDEV_TX_OK; 114584640e27SKaricheri, Muralidharan goto out; 114684640e27SKaricheri, Muralidharan } 114784640e27SKaricheri, Muralidharan } 114884640e27SKaricheri, Muralidharan 114984640e27SKaricheri, Muralidharan /* Make sure some TX hook claimed the packet */ 115084640e27SKaricheri, Muralidharan tx_pipe = p_info.tx_pipe; 115184640e27SKaricheri, Muralidharan if (!tx_pipe) { 115284640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "No TX hook claimed the packet!\n"); 115384640e27SKaricheri, Muralidharan ret = -ENXIO; 115484640e27SKaricheri, Muralidharan goto out; 115584640e27SKaricheri, Muralidharan } 115684640e27SKaricheri, Muralidharan 115784640e27SKaricheri, Muralidharan /* update descriptor */ 115884640e27SKaricheri, Muralidharan if (p_info.psdata_len) { 11599dd2d6c5SArnd Bergmann /* psdata points to both native-endian and device-endian data */ 11609dd2d6c5SArnd Bergmann __le32 *psdata = (void __force *)p_info.psdata; 116184640e27SKaricheri, Muralidharan 116284640e27SKaricheri, Muralidharan memmove(p_info.psdata, p_info.psdata + p_info.psdata_len, 116384640e27SKaricheri, Muralidharan p_info.psdata_len); 11649dd2d6c5SArnd Bergmann set_words(p_info.psdata, p_info.psdata_len, psdata); 1165e170f409SKaricheri, Muralidharan tmp |= (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) << 116684640e27SKaricheri, Muralidharan KNAV_DMA_DESC_PSLEN_SHIFT; 116784640e27SKaricheri, Muralidharan } 116884640e27SKaricheri, Muralidharan 1169e170f409SKaricheri, Muralidharan tmp |= KNAV_DMA_DESC_HAS_EPIB | 117084640e27SKaricheri, Muralidharan ((netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << 1171e170f409SKaricheri, Muralidharan KNAV_DMA_DESC_RETQ_SHIFT); 117284640e27SKaricheri, Muralidharan 1173e170f409SKaricheri, Muralidharan if (!(tx_pipe->flags & SWITCH_TO_PORT_IN_TAGINFO)) { 1174e170f409SKaricheri, Muralidharan tmp |= ((tx_pipe->switch_to_port & KNAV_DMA_DESC_PSFLAG_MASK) << 1175e170f409SKaricheri, Muralidharan KNAV_DMA_DESC_PSFLAG_SHIFT); 1176e170f409SKaricheri, Muralidharan } 1177e170f409SKaricheri, Muralidharan 1178e170f409SKaricheri, Muralidharan set_words(&tmp, 1, &desc->packet_info); 1179b1cb86aeSKaricheri, Muralidharan set_sw_data((u32)skb, 0, desc); 118084640e27SKaricheri, Muralidharan 1181e170f409SKaricheri, Muralidharan if (tx_pipe->flags & SWITCH_TO_PORT_IN_TAGINFO) { 1182e170f409SKaricheri, Muralidharan tmp = tx_pipe->switch_to_port; 118389907779SArnd Bergmann set_words(&tmp, 1, &desc->tag_info); 1184e170f409SKaricheri, Muralidharan } 1185e170f409SKaricheri, Muralidharan 118684640e27SKaricheri, Muralidharan /* submit packet descriptor */ 118784640e27SKaricheri, Muralidharan ret = knav_pool_desc_map(netcp->tx_pool, desc, sizeof(*desc), &dma, 118884640e27SKaricheri, Muralidharan &dma_sz); 118984640e27SKaricheri, Muralidharan if (unlikely(ret)) { 119084640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "%s() failed to map desc\n", __func__); 119184640e27SKaricheri, Muralidharan ret = -ENOMEM; 119284640e27SKaricheri, Muralidharan goto out; 119384640e27SKaricheri, Muralidharan } 119484640e27SKaricheri, Muralidharan skb_tx_timestamp(skb); 119584640e27SKaricheri, Muralidharan knav_queue_push(tx_pipe->dma_queue, dma, dma_sz, 0); 119684640e27SKaricheri, Muralidharan 119784640e27SKaricheri, Muralidharan out: 119884640e27SKaricheri, Muralidharan return ret; 119984640e27SKaricheri, Muralidharan } 120084640e27SKaricheri, Muralidharan 120184640e27SKaricheri, Muralidharan /* Submit the packet */ 120284640e27SKaricheri, Muralidharan static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) 120384640e27SKaricheri, Muralidharan { 120484640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 120584640e27SKaricheri, Muralidharan int subqueue = skb_get_queue_mapping(skb); 120684640e27SKaricheri, Muralidharan struct knav_dma_desc *desc; 120784640e27SKaricheri, Muralidharan int desc_count, ret = 0; 120884640e27SKaricheri, Muralidharan 120984640e27SKaricheri, Muralidharan if (unlikely(skb->len <= 0)) { 121084640e27SKaricheri, Muralidharan dev_kfree_skb(skb); 121184640e27SKaricheri, Muralidharan return NETDEV_TX_OK; 121284640e27SKaricheri, Muralidharan } 121384640e27SKaricheri, Muralidharan 121484640e27SKaricheri, Muralidharan if (unlikely(skb->len < NETCP_MIN_PACKET_SIZE)) { 121584640e27SKaricheri, Muralidharan ret = skb_padto(skb, NETCP_MIN_PACKET_SIZE); 121684640e27SKaricheri, Muralidharan if (ret < 0) { 121784640e27SKaricheri, Muralidharan /* If we get here, the skb has already been dropped */ 121884640e27SKaricheri, Muralidharan dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n", 121984640e27SKaricheri, Muralidharan ret); 122084640e27SKaricheri, Muralidharan ndev->stats.tx_dropped++; 122184640e27SKaricheri, Muralidharan return ret; 122284640e27SKaricheri, Muralidharan } 122384640e27SKaricheri, Muralidharan skb->len = NETCP_MIN_PACKET_SIZE; 122484640e27SKaricheri, Muralidharan } 122584640e27SKaricheri, Muralidharan 122684640e27SKaricheri, Muralidharan desc = netcp_tx_map_skb(skb, netcp); 122784640e27SKaricheri, Muralidharan if (unlikely(!desc)) { 122884640e27SKaricheri, Muralidharan netif_stop_subqueue(ndev, subqueue); 122984640e27SKaricheri, Muralidharan ret = -ENOBUFS; 123084640e27SKaricheri, Muralidharan goto drop; 123184640e27SKaricheri, Muralidharan } 123284640e27SKaricheri, Muralidharan 123384640e27SKaricheri, Muralidharan ret = netcp_tx_submit_skb(netcp, skb, desc); 123484640e27SKaricheri, Muralidharan if (ret) 123584640e27SKaricheri, Muralidharan goto drop; 123684640e27SKaricheri, Muralidharan 123784640e27SKaricheri, Muralidharan ndev->trans_start = jiffies; 123884640e27SKaricheri, Muralidharan 123984640e27SKaricheri, Muralidharan /* Check Tx pool count & stop subqueue if needed */ 124084640e27SKaricheri, Muralidharan desc_count = knav_pool_count(netcp->tx_pool); 124184640e27SKaricheri, Muralidharan if (desc_count < netcp->tx_pause_threshold) { 124284640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "pausing tx, count(%d)\n", desc_count); 124384640e27SKaricheri, Muralidharan netif_stop_subqueue(ndev, subqueue); 124484640e27SKaricheri, Muralidharan } 124584640e27SKaricheri, Muralidharan return NETDEV_TX_OK; 124684640e27SKaricheri, Muralidharan 124784640e27SKaricheri, Muralidharan drop: 124884640e27SKaricheri, Muralidharan ndev->stats.tx_dropped++; 124984640e27SKaricheri, Muralidharan if (desc) 125084640e27SKaricheri, Muralidharan netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); 125184640e27SKaricheri, Muralidharan dev_kfree_skb(skb); 125284640e27SKaricheri, Muralidharan return ret; 125384640e27SKaricheri, Muralidharan } 125484640e27SKaricheri, Muralidharan 125584640e27SKaricheri, Muralidharan int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe) 125684640e27SKaricheri, Muralidharan { 125784640e27SKaricheri, Muralidharan if (tx_pipe->dma_channel) { 125884640e27SKaricheri, Muralidharan knav_dma_close_channel(tx_pipe->dma_channel); 125984640e27SKaricheri, Muralidharan tx_pipe->dma_channel = NULL; 126084640e27SKaricheri, Muralidharan } 126184640e27SKaricheri, Muralidharan return 0; 126284640e27SKaricheri, Muralidharan } 126358c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_txpipe_close); 126484640e27SKaricheri, Muralidharan 126584640e27SKaricheri, Muralidharan int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) 126684640e27SKaricheri, Muralidharan { 126784640e27SKaricheri, Muralidharan struct device *dev = tx_pipe->netcp_device->device; 126884640e27SKaricheri, Muralidharan struct knav_dma_cfg config; 126984640e27SKaricheri, Muralidharan int ret = 0; 127084640e27SKaricheri, Muralidharan u8 name[16]; 127184640e27SKaricheri, Muralidharan 127284640e27SKaricheri, Muralidharan memset(&config, 0, sizeof(config)); 127384640e27SKaricheri, Muralidharan config.direction = DMA_MEM_TO_DEV; 127484640e27SKaricheri, Muralidharan config.u.tx.filt_einfo = false; 127584640e27SKaricheri, Muralidharan config.u.tx.filt_pswords = false; 127684640e27SKaricheri, Muralidharan config.u.tx.priority = DMA_PRIO_MED_L; 127784640e27SKaricheri, Muralidharan 127884640e27SKaricheri, Muralidharan tx_pipe->dma_channel = knav_dma_open_channel(dev, 127984640e27SKaricheri, Muralidharan tx_pipe->dma_chan_name, &config); 128084640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(tx_pipe->dma_channel)) { 128184640e27SKaricheri, Muralidharan dev_err(dev, "failed opening tx chan(%s)\n", 128284640e27SKaricheri, Muralidharan tx_pipe->dma_chan_name); 128384640e27SKaricheri, Muralidharan goto err; 128484640e27SKaricheri, Muralidharan } 128584640e27SKaricheri, Muralidharan 128684640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "tx-pipe-%s", dev_name(dev)); 128784640e27SKaricheri, Muralidharan tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id, 128884640e27SKaricheri, Muralidharan KNAV_QUEUE_SHARED); 128984640e27SKaricheri, Muralidharan if (IS_ERR(tx_pipe->dma_queue)) { 129084640e27SKaricheri, Muralidharan dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n", 129184640e27SKaricheri, Muralidharan name, ret); 129284640e27SKaricheri, Muralidharan ret = PTR_ERR(tx_pipe->dma_queue); 129384640e27SKaricheri, Muralidharan goto err; 129484640e27SKaricheri, Muralidharan } 129584640e27SKaricheri, Muralidharan 129684640e27SKaricheri, Muralidharan dev_dbg(dev, "opened tx pipe %s\n", name); 129784640e27SKaricheri, Muralidharan return 0; 129884640e27SKaricheri, Muralidharan 129984640e27SKaricheri, Muralidharan err: 130084640e27SKaricheri, Muralidharan if (!IS_ERR_OR_NULL(tx_pipe->dma_channel)) 130184640e27SKaricheri, Muralidharan knav_dma_close_channel(tx_pipe->dma_channel); 130284640e27SKaricheri, Muralidharan tx_pipe->dma_channel = NULL; 130384640e27SKaricheri, Muralidharan return ret; 130484640e27SKaricheri, Muralidharan } 130558c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_txpipe_open); 130684640e27SKaricheri, Muralidharan 130784640e27SKaricheri, Muralidharan int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, 130884640e27SKaricheri, Muralidharan struct netcp_device *netcp_device, 130984640e27SKaricheri, Muralidharan const char *dma_chan_name, unsigned int dma_queue_id) 131084640e27SKaricheri, Muralidharan { 131184640e27SKaricheri, Muralidharan memset(tx_pipe, 0, sizeof(*tx_pipe)); 131284640e27SKaricheri, Muralidharan tx_pipe->netcp_device = netcp_device; 131384640e27SKaricheri, Muralidharan tx_pipe->dma_chan_name = dma_chan_name; 131484640e27SKaricheri, Muralidharan tx_pipe->dma_queue_id = dma_queue_id; 131584640e27SKaricheri, Muralidharan return 0; 131684640e27SKaricheri, Muralidharan } 131758c11b5fSKaricheri, Muralidharan EXPORT_SYMBOL_GPL(netcp_txpipe_init); 131884640e27SKaricheri, Muralidharan 131984640e27SKaricheri, Muralidharan static struct netcp_addr *netcp_addr_find(struct netcp_intf *netcp, 132084640e27SKaricheri, Muralidharan const u8 *addr, 132184640e27SKaricheri, Muralidharan enum netcp_addr_type type) 132284640e27SKaricheri, Muralidharan { 132384640e27SKaricheri, Muralidharan struct netcp_addr *naddr; 132484640e27SKaricheri, Muralidharan 132584640e27SKaricheri, Muralidharan list_for_each_entry(naddr, &netcp->addr_list, node) { 132684640e27SKaricheri, Muralidharan if (naddr->type != type) 132784640e27SKaricheri, Muralidharan continue; 132884640e27SKaricheri, Muralidharan if (addr && memcmp(addr, naddr->addr, ETH_ALEN)) 132984640e27SKaricheri, Muralidharan continue; 133084640e27SKaricheri, Muralidharan return naddr; 133184640e27SKaricheri, Muralidharan } 133284640e27SKaricheri, Muralidharan 133384640e27SKaricheri, Muralidharan return NULL; 133484640e27SKaricheri, Muralidharan } 133584640e27SKaricheri, Muralidharan 133684640e27SKaricheri, Muralidharan static struct netcp_addr *netcp_addr_add(struct netcp_intf *netcp, 133784640e27SKaricheri, Muralidharan const u8 *addr, 133884640e27SKaricheri, Muralidharan enum netcp_addr_type type) 133984640e27SKaricheri, Muralidharan { 134084640e27SKaricheri, Muralidharan struct netcp_addr *naddr; 134184640e27SKaricheri, Muralidharan 134284640e27SKaricheri, Muralidharan naddr = devm_kmalloc(netcp->dev, sizeof(*naddr), GFP_ATOMIC); 134384640e27SKaricheri, Muralidharan if (!naddr) 134484640e27SKaricheri, Muralidharan return NULL; 134584640e27SKaricheri, Muralidharan 134684640e27SKaricheri, Muralidharan naddr->type = type; 134784640e27SKaricheri, Muralidharan naddr->flags = 0; 134884640e27SKaricheri, Muralidharan naddr->netcp = netcp; 134984640e27SKaricheri, Muralidharan if (addr) 135084640e27SKaricheri, Muralidharan ether_addr_copy(naddr->addr, addr); 135184640e27SKaricheri, Muralidharan else 1352c7bf7169SJoe Perches eth_zero_addr(naddr->addr); 135384640e27SKaricheri, Muralidharan list_add_tail(&naddr->node, &netcp->addr_list); 135484640e27SKaricheri, Muralidharan 135584640e27SKaricheri, Muralidharan return naddr; 135684640e27SKaricheri, Muralidharan } 135784640e27SKaricheri, Muralidharan 135884640e27SKaricheri, Muralidharan static void netcp_addr_del(struct netcp_intf *netcp, struct netcp_addr *naddr) 135984640e27SKaricheri, Muralidharan { 136084640e27SKaricheri, Muralidharan list_del(&naddr->node); 136184640e27SKaricheri, Muralidharan devm_kfree(netcp->dev, naddr); 136284640e27SKaricheri, Muralidharan } 136384640e27SKaricheri, Muralidharan 136484640e27SKaricheri, Muralidharan static void netcp_addr_clear_mark(struct netcp_intf *netcp) 136584640e27SKaricheri, Muralidharan { 136684640e27SKaricheri, Muralidharan struct netcp_addr *naddr; 136784640e27SKaricheri, Muralidharan 136884640e27SKaricheri, Muralidharan list_for_each_entry(naddr, &netcp->addr_list, node) 136984640e27SKaricheri, Muralidharan naddr->flags = 0; 137084640e27SKaricheri, Muralidharan } 137184640e27SKaricheri, Muralidharan 137284640e27SKaricheri, Muralidharan static void netcp_addr_add_mark(struct netcp_intf *netcp, const u8 *addr, 137384640e27SKaricheri, Muralidharan enum netcp_addr_type type) 137484640e27SKaricheri, Muralidharan { 137584640e27SKaricheri, Muralidharan struct netcp_addr *naddr; 137684640e27SKaricheri, Muralidharan 137784640e27SKaricheri, Muralidharan naddr = netcp_addr_find(netcp, addr, type); 137884640e27SKaricheri, Muralidharan if (naddr) { 137984640e27SKaricheri, Muralidharan naddr->flags |= ADDR_VALID; 138084640e27SKaricheri, Muralidharan return; 138184640e27SKaricheri, Muralidharan } 138284640e27SKaricheri, Muralidharan 138384640e27SKaricheri, Muralidharan naddr = netcp_addr_add(netcp, addr, type); 138484640e27SKaricheri, Muralidharan if (!WARN_ON(!naddr)) 138584640e27SKaricheri, Muralidharan naddr->flags |= ADDR_NEW; 138684640e27SKaricheri, Muralidharan } 138784640e27SKaricheri, Muralidharan 138884640e27SKaricheri, Muralidharan static void netcp_addr_sweep_del(struct netcp_intf *netcp) 138984640e27SKaricheri, Muralidharan { 139084640e27SKaricheri, Muralidharan struct netcp_addr *naddr, *tmp; 139184640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *priv; 139284640e27SKaricheri, Muralidharan struct netcp_module *module; 139384640e27SKaricheri, Muralidharan int error; 139484640e27SKaricheri, Muralidharan 139584640e27SKaricheri, Muralidharan list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { 139684640e27SKaricheri, Muralidharan if (naddr->flags & (ADDR_VALID | ADDR_NEW)) 139784640e27SKaricheri, Muralidharan continue; 139884640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "deleting address %pM, type %x\n", 139984640e27SKaricheri, Muralidharan naddr->addr, naddr->type); 140084640e27SKaricheri, Muralidharan for_each_module(netcp, priv) { 140184640e27SKaricheri, Muralidharan module = priv->netcp_module; 140284640e27SKaricheri, Muralidharan if (!module->del_addr) 140384640e27SKaricheri, Muralidharan continue; 140484640e27SKaricheri, Muralidharan error = module->del_addr(priv->module_priv, 140584640e27SKaricheri, Muralidharan naddr); 140684640e27SKaricheri, Muralidharan WARN_ON(error); 140784640e27SKaricheri, Muralidharan } 140884640e27SKaricheri, Muralidharan netcp_addr_del(netcp, naddr); 140984640e27SKaricheri, Muralidharan } 141084640e27SKaricheri, Muralidharan } 141184640e27SKaricheri, Muralidharan 141284640e27SKaricheri, Muralidharan static void netcp_addr_sweep_add(struct netcp_intf *netcp) 141384640e27SKaricheri, Muralidharan { 141484640e27SKaricheri, Muralidharan struct netcp_addr *naddr, *tmp; 141584640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *priv; 141684640e27SKaricheri, Muralidharan struct netcp_module *module; 141784640e27SKaricheri, Muralidharan int error; 141884640e27SKaricheri, Muralidharan 141984640e27SKaricheri, Muralidharan list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { 142084640e27SKaricheri, Muralidharan if (!(naddr->flags & ADDR_NEW)) 142184640e27SKaricheri, Muralidharan continue; 142284640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "adding address %pM, type %x\n", 142384640e27SKaricheri, Muralidharan naddr->addr, naddr->type); 14248ceaf361SKaricheri, Muralidharan 142584640e27SKaricheri, Muralidharan for_each_module(netcp, priv) { 142684640e27SKaricheri, Muralidharan module = priv->netcp_module; 142784640e27SKaricheri, Muralidharan if (!module->add_addr) 142884640e27SKaricheri, Muralidharan continue; 142984640e27SKaricheri, Muralidharan error = module->add_addr(priv->module_priv, naddr); 143084640e27SKaricheri, Muralidharan WARN_ON(error); 143184640e27SKaricheri, Muralidharan } 143284640e27SKaricheri, Muralidharan } 143384640e27SKaricheri, Muralidharan } 143484640e27SKaricheri, Muralidharan 143584640e27SKaricheri, Muralidharan static void netcp_set_rx_mode(struct net_device *ndev) 143684640e27SKaricheri, Muralidharan { 143784640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 143884640e27SKaricheri, Muralidharan struct netdev_hw_addr *ndev_addr; 143984640e27SKaricheri, Muralidharan bool promisc; 144084640e27SKaricheri, Muralidharan 144184640e27SKaricheri, Muralidharan promisc = (ndev->flags & IFF_PROMISC || 144284640e27SKaricheri, Muralidharan ndev->flags & IFF_ALLMULTI || 144384640e27SKaricheri, Muralidharan netdev_mc_count(ndev) > NETCP_MAX_MCAST_ADDR); 144484640e27SKaricheri, Muralidharan 14458ceaf361SKaricheri, Muralidharan spin_lock(&netcp->lock); 144684640e27SKaricheri, Muralidharan /* first clear all marks */ 144784640e27SKaricheri, Muralidharan netcp_addr_clear_mark(netcp); 144884640e27SKaricheri, Muralidharan 144984640e27SKaricheri, Muralidharan /* next add new entries, mark existing ones */ 145084640e27SKaricheri, Muralidharan netcp_addr_add_mark(netcp, ndev->broadcast, ADDR_BCAST); 145184640e27SKaricheri, Muralidharan for_each_dev_addr(ndev, ndev_addr) 145284640e27SKaricheri, Muralidharan netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_DEV); 145384640e27SKaricheri, Muralidharan netdev_for_each_uc_addr(ndev_addr, ndev) 145484640e27SKaricheri, Muralidharan netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_UCAST); 145584640e27SKaricheri, Muralidharan netdev_for_each_mc_addr(ndev_addr, ndev) 145684640e27SKaricheri, Muralidharan netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_MCAST); 145784640e27SKaricheri, Muralidharan 145884640e27SKaricheri, Muralidharan if (promisc) 145984640e27SKaricheri, Muralidharan netcp_addr_add_mark(netcp, NULL, ADDR_ANY); 146084640e27SKaricheri, Muralidharan 146184640e27SKaricheri, Muralidharan /* finally sweep and callout into modules */ 146284640e27SKaricheri, Muralidharan netcp_addr_sweep_del(netcp); 146384640e27SKaricheri, Muralidharan netcp_addr_sweep_add(netcp); 14648ceaf361SKaricheri, Muralidharan spin_unlock(&netcp->lock); 146584640e27SKaricheri, Muralidharan } 146684640e27SKaricheri, Muralidharan 146784640e27SKaricheri, Muralidharan static void netcp_free_navigator_resources(struct netcp_intf *netcp) 146884640e27SKaricheri, Muralidharan { 146984640e27SKaricheri, Muralidharan int i; 147084640e27SKaricheri, Muralidharan 147184640e27SKaricheri, Muralidharan if (netcp->rx_channel) { 147284640e27SKaricheri, Muralidharan knav_dma_close_channel(netcp->rx_channel); 147384640e27SKaricheri, Muralidharan netcp->rx_channel = NULL; 147484640e27SKaricheri, Muralidharan } 147584640e27SKaricheri, Muralidharan 147684640e27SKaricheri, Muralidharan if (!IS_ERR_OR_NULL(netcp->rx_pool)) 147784640e27SKaricheri, Muralidharan netcp_rxpool_free(netcp); 147884640e27SKaricheri, Muralidharan 147984640e27SKaricheri, Muralidharan if (!IS_ERR_OR_NULL(netcp->rx_queue)) { 148084640e27SKaricheri, Muralidharan knav_queue_close(netcp->rx_queue); 148184640e27SKaricheri, Muralidharan netcp->rx_queue = NULL; 148284640e27SKaricheri, Muralidharan } 148384640e27SKaricheri, Muralidharan 148484640e27SKaricheri, Muralidharan for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && 148584640e27SKaricheri, Muralidharan !IS_ERR_OR_NULL(netcp->rx_fdq[i]) ; ++i) { 148684640e27SKaricheri, Muralidharan knav_queue_close(netcp->rx_fdq[i]); 148784640e27SKaricheri, Muralidharan netcp->rx_fdq[i] = NULL; 148884640e27SKaricheri, Muralidharan } 148984640e27SKaricheri, Muralidharan 149084640e27SKaricheri, Muralidharan if (!IS_ERR_OR_NULL(netcp->tx_compl_q)) { 149184640e27SKaricheri, Muralidharan knav_queue_close(netcp->tx_compl_q); 149284640e27SKaricheri, Muralidharan netcp->tx_compl_q = NULL; 149384640e27SKaricheri, Muralidharan } 149484640e27SKaricheri, Muralidharan 149584640e27SKaricheri, Muralidharan if (!IS_ERR_OR_NULL(netcp->tx_pool)) { 149684640e27SKaricheri, Muralidharan knav_pool_destroy(netcp->tx_pool); 149784640e27SKaricheri, Muralidharan netcp->tx_pool = NULL; 149884640e27SKaricheri, Muralidharan } 149984640e27SKaricheri, Muralidharan } 150084640e27SKaricheri, Muralidharan 150184640e27SKaricheri, Muralidharan static int netcp_setup_navigator_resources(struct net_device *ndev) 150284640e27SKaricheri, Muralidharan { 150384640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 150484640e27SKaricheri, Muralidharan struct knav_queue_notify_config notify_cfg; 150584640e27SKaricheri, Muralidharan struct knav_dma_cfg config; 150684640e27SKaricheri, Muralidharan u32 last_fdq = 0; 150784640e27SKaricheri, Muralidharan u8 name[16]; 150884640e27SKaricheri, Muralidharan int ret; 150984640e27SKaricheri, Muralidharan int i; 151084640e27SKaricheri, Muralidharan 151184640e27SKaricheri, Muralidharan /* Create Rx/Tx descriptor pools */ 151284640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "rx-pool-%s", ndev->name); 151384640e27SKaricheri, Muralidharan netcp->rx_pool = knav_pool_create(name, netcp->rx_pool_size, 151484640e27SKaricheri, Muralidharan netcp->rx_pool_region_id); 151584640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->rx_pool)) { 151684640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Couldn't create rx pool\n"); 151784640e27SKaricheri, Muralidharan ret = PTR_ERR(netcp->rx_pool); 151884640e27SKaricheri, Muralidharan goto fail; 151984640e27SKaricheri, Muralidharan } 152084640e27SKaricheri, Muralidharan 152184640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "tx-pool-%s", ndev->name); 152284640e27SKaricheri, Muralidharan netcp->tx_pool = knav_pool_create(name, netcp->tx_pool_size, 152384640e27SKaricheri, Muralidharan netcp->tx_pool_region_id); 152484640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->tx_pool)) { 152584640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Couldn't create tx pool\n"); 152684640e27SKaricheri, Muralidharan ret = PTR_ERR(netcp->tx_pool); 152784640e27SKaricheri, Muralidharan goto fail; 152884640e27SKaricheri, Muralidharan } 152984640e27SKaricheri, Muralidharan 153084640e27SKaricheri, Muralidharan /* open Tx completion queue */ 153184640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "tx-compl-%s", ndev->name); 153284640e27SKaricheri, Muralidharan netcp->tx_compl_q = knav_queue_open(name, netcp->tx_compl_qid, 0); 153384640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->tx_compl_q)) { 153484640e27SKaricheri, Muralidharan ret = PTR_ERR(netcp->tx_compl_q); 153584640e27SKaricheri, Muralidharan goto fail; 153684640e27SKaricheri, Muralidharan } 153784640e27SKaricheri, Muralidharan netcp->tx_compl_qid = knav_queue_get_id(netcp->tx_compl_q); 153884640e27SKaricheri, Muralidharan 153984640e27SKaricheri, Muralidharan /* Set notification for Tx completion */ 154084640e27SKaricheri, Muralidharan notify_cfg.fn = netcp_tx_notify; 154184640e27SKaricheri, Muralidharan notify_cfg.fn_arg = netcp; 154284640e27SKaricheri, Muralidharan ret = knav_queue_device_control(netcp->tx_compl_q, 154384640e27SKaricheri, Muralidharan KNAV_QUEUE_SET_NOTIFIER, 154484640e27SKaricheri, Muralidharan (unsigned long)¬ify_cfg); 154584640e27SKaricheri, Muralidharan if (ret) 154684640e27SKaricheri, Muralidharan goto fail; 154784640e27SKaricheri, Muralidharan 154884640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->tx_compl_q); 154984640e27SKaricheri, Muralidharan 155084640e27SKaricheri, Muralidharan /* open Rx completion queue */ 155184640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "rx-compl-%s", ndev->name); 155284640e27SKaricheri, Muralidharan netcp->rx_queue = knav_queue_open(name, netcp->rx_queue_id, 0); 155384640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->rx_queue)) { 155484640e27SKaricheri, Muralidharan ret = PTR_ERR(netcp->rx_queue); 155584640e27SKaricheri, Muralidharan goto fail; 155684640e27SKaricheri, Muralidharan } 155784640e27SKaricheri, Muralidharan netcp->rx_queue_id = knav_queue_get_id(netcp->rx_queue); 155884640e27SKaricheri, Muralidharan 155984640e27SKaricheri, Muralidharan /* Set notification for Rx completion */ 156084640e27SKaricheri, Muralidharan notify_cfg.fn = netcp_rx_notify; 156184640e27SKaricheri, Muralidharan notify_cfg.fn_arg = netcp; 156284640e27SKaricheri, Muralidharan ret = knav_queue_device_control(netcp->rx_queue, 156384640e27SKaricheri, Muralidharan KNAV_QUEUE_SET_NOTIFIER, 156484640e27SKaricheri, Muralidharan (unsigned long)¬ify_cfg); 156584640e27SKaricheri, Muralidharan if (ret) 156684640e27SKaricheri, Muralidharan goto fail; 156784640e27SKaricheri, Muralidharan 156884640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->rx_queue); 156984640e27SKaricheri, Muralidharan 157084640e27SKaricheri, Muralidharan /* open Rx FDQs */ 1571866b8b18SWingMan Kwok for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_queue_depths[i]; 1572866b8b18SWingMan Kwok ++i) { 157384640e27SKaricheri, Muralidharan snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i); 157484640e27SKaricheri, Muralidharan netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0); 157584640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) { 157684640e27SKaricheri, Muralidharan ret = PTR_ERR(netcp->rx_fdq[i]); 157784640e27SKaricheri, Muralidharan goto fail; 157884640e27SKaricheri, Muralidharan } 157984640e27SKaricheri, Muralidharan } 158084640e27SKaricheri, Muralidharan 158184640e27SKaricheri, Muralidharan memset(&config, 0, sizeof(config)); 158284640e27SKaricheri, Muralidharan config.direction = DMA_DEV_TO_MEM; 158384640e27SKaricheri, Muralidharan config.u.rx.einfo_present = true; 158484640e27SKaricheri, Muralidharan config.u.rx.psinfo_present = true; 158584640e27SKaricheri, Muralidharan config.u.rx.err_mode = DMA_DROP; 158684640e27SKaricheri, Muralidharan config.u.rx.desc_type = DMA_DESC_HOST; 158784640e27SKaricheri, Muralidharan config.u.rx.psinfo_at_sop = false; 158884640e27SKaricheri, Muralidharan config.u.rx.sop_offset = NETCP_SOP_OFFSET; 158984640e27SKaricheri, Muralidharan config.u.rx.dst_q = netcp->rx_queue_id; 159084640e27SKaricheri, Muralidharan config.u.rx.thresh = DMA_THRESH_NONE; 159184640e27SKaricheri, Muralidharan 159284640e27SKaricheri, Muralidharan for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN; ++i) { 159384640e27SKaricheri, Muralidharan if (netcp->rx_fdq[i]) 159484640e27SKaricheri, Muralidharan last_fdq = knav_queue_get_id(netcp->rx_fdq[i]); 159584640e27SKaricheri, Muralidharan config.u.rx.fdq[i] = last_fdq; 159684640e27SKaricheri, Muralidharan } 159784640e27SKaricheri, Muralidharan 159884640e27SKaricheri, Muralidharan netcp->rx_channel = knav_dma_open_channel(netcp->netcp_device->device, 159984640e27SKaricheri, Muralidharan netcp->dma_chan_name, &config); 160084640e27SKaricheri, Muralidharan if (IS_ERR_OR_NULL(netcp->rx_channel)) { 160184640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "failed opening rx chan(%s\n", 160284640e27SKaricheri, Muralidharan netcp->dma_chan_name); 160384640e27SKaricheri, Muralidharan goto fail; 160484640e27SKaricheri, Muralidharan } 160584640e27SKaricheri, Muralidharan 160684640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "opened RX channel: %p\n", netcp->rx_channel); 160784640e27SKaricheri, Muralidharan return 0; 160884640e27SKaricheri, Muralidharan 160984640e27SKaricheri, Muralidharan fail: 161084640e27SKaricheri, Muralidharan netcp_free_navigator_resources(netcp); 161184640e27SKaricheri, Muralidharan return ret; 161284640e27SKaricheri, Muralidharan } 161384640e27SKaricheri, Muralidharan 161484640e27SKaricheri, Muralidharan /* Open the device */ 161584640e27SKaricheri, Muralidharan static int netcp_ndo_open(struct net_device *ndev) 161684640e27SKaricheri, Muralidharan { 161784640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 161884640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 161984640e27SKaricheri, Muralidharan struct netcp_module *module; 162084640e27SKaricheri, Muralidharan int ret; 162184640e27SKaricheri, Muralidharan 162284640e27SKaricheri, Muralidharan netif_carrier_off(ndev); 162384640e27SKaricheri, Muralidharan ret = netcp_setup_navigator_resources(ndev); 162484640e27SKaricheri, Muralidharan if (ret) { 162584640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Failed to setup navigator resources\n"); 162684640e27SKaricheri, Muralidharan goto fail; 162784640e27SKaricheri, Muralidharan } 162884640e27SKaricheri, Muralidharan 162984640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 163084640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 163184640e27SKaricheri, Muralidharan if (module->open) { 163284640e27SKaricheri, Muralidharan ret = module->open(intf_modpriv->module_priv, ndev); 163384640e27SKaricheri, Muralidharan if (ret != 0) { 163484640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "module open failed\n"); 163584640e27SKaricheri, Muralidharan goto fail_open; 163684640e27SKaricheri, Muralidharan } 163784640e27SKaricheri, Muralidharan } 163884640e27SKaricheri, Muralidharan } 163984640e27SKaricheri, Muralidharan 164084640e27SKaricheri, Muralidharan napi_enable(&netcp->rx_napi); 164184640e27SKaricheri, Muralidharan napi_enable(&netcp->tx_napi); 164284640e27SKaricheri, Muralidharan knav_queue_enable_notify(netcp->tx_compl_q); 164384640e27SKaricheri, Muralidharan knav_queue_enable_notify(netcp->rx_queue); 1644194ac06eSKaricheri, Muralidharan netcp_rxpool_refill(netcp); 164584640e27SKaricheri, Muralidharan netif_tx_wake_all_queues(ndev); 164684640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name); 164784640e27SKaricheri, Muralidharan return 0; 164884640e27SKaricheri, Muralidharan 164984640e27SKaricheri, Muralidharan fail_open: 165084640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 165184640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 165284640e27SKaricheri, Muralidharan if (module->close) 165384640e27SKaricheri, Muralidharan module->close(intf_modpriv->module_priv, ndev); 165484640e27SKaricheri, Muralidharan } 165584640e27SKaricheri, Muralidharan 165684640e27SKaricheri, Muralidharan fail: 165784640e27SKaricheri, Muralidharan netcp_free_navigator_resources(netcp); 165884640e27SKaricheri, Muralidharan return ret; 165984640e27SKaricheri, Muralidharan } 166084640e27SKaricheri, Muralidharan 166184640e27SKaricheri, Muralidharan /* Close the device */ 166284640e27SKaricheri, Muralidharan static int netcp_ndo_stop(struct net_device *ndev) 166384640e27SKaricheri, Muralidharan { 166484640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 166584640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 166684640e27SKaricheri, Muralidharan struct netcp_module *module; 166784640e27SKaricheri, Muralidharan int err = 0; 166884640e27SKaricheri, Muralidharan 166984640e27SKaricheri, Muralidharan netif_tx_stop_all_queues(ndev); 167084640e27SKaricheri, Muralidharan netif_carrier_off(ndev); 167184640e27SKaricheri, Muralidharan netcp_addr_clear_mark(netcp); 167284640e27SKaricheri, Muralidharan netcp_addr_sweep_del(netcp); 167384640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->rx_queue); 167484640e27SKaricheri, Muralidharan knav_queue_disable_notify(netcp->tx_compl_q); 167584640e27SKaricheri, Muralidharan napi_disable(&netcp->rx_napi); 167684640e27SKaricheri, Muralidharan napi_disable(&netcp->tx_napi); 167784640e27SKaricheri, Muralidharan 167884640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 167984640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 168084640e27SKaricheri, Muralidharan if (module->close) { 168184640e27SKaricheri, Muralidharan err = module->close(intf_modpriv->module_priv, ndev); 168284640e27SKaricheri, Muralidharan if (err != 0) 168384640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Close failed\n"); 168484640e27SKaricheri, Muralidharan } 168584640e27SKaricheri, Muralidharan } 168684640e27SKaricheri, Muralidharan 168784640e27SKaricheri, Muralidharan /* Recycle Rx descriptors from completion queue */ 168884640e27SKaricheri, Muralidharan netcp_empty_rx_queue(netcp); 168984640e27SKaricheri, Muralidharan 169084640e27SKaricheri, Muralidharan /* Recycle Tx descriptors from completion queue */ 169184640e27SKaricheri, Muralidharan netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); 169284640e27SKaricheri, Muralidharan 169384640e27SKaricheri, Muralidharan if (knav_pool_count(netcp->tx_pool) != netcp->tx_pool_size) 169484640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Lost (%d) Tx descs\n", 169584640e27SKaricheri, Muralidharan netcp->tx_pool_size - knav_pool_count(netcp->tx_pool)); 169684640e27SKaricheri, Muralidharan 169784640e27SKaricheri, Muralidharan netcp_free_navigator_resources(netcp); 169884640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "netcp device %s stopped\n", ndev->name); 169984640e27SKaricheri, Muralidharan return 0; 170084640e27SKaricheri, Muralidharan } 170184640e27SKaricheri, Muralidharan 170284640e27SKaricheri, Muralidharan static int netcp_ndo_ioctl(struct net_device *ndev, 170384640e27SKaricheri, Muralidharan struct ifreq *req, int cmd) 170484640e27SKaricheri, Muralidharan { 170584640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 170684640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 170784640e27SKaricheri, Muralidharan struct netcp_module *module; 170884640e27SKaricheri, Muralidharan int ret = -1, err = -EOPNOTSUPP; 170984640e27SKaricheri, Muralidharan 171084640e27SKaricheri, Muralidharan if (!netif_running(ndev)) 171184640e27SKaricheri, Muralidharan return -EINVAL; 171284640e27SKaricheri, Muralidharan 171384640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 171484640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 171584640e27SKaricheri, Muralidharan if (!module->ioctl) 171684640e27SKaricheri, Muralidharan continue; 171784640e27SKaricheri, Muralidharan 171884640e27SKaricheri, Muralidharan err = module->ioctl(intf_modpriv->module_priv, req, cmd); 171984640e27SKaricheri, Muralidharan if ((err < 0) && (err != -EOPNOTSUPP)) { 172084640e27SKaricheri, Muralidharan ret = err; 172184640e27SKaricheri, Muralidharan goto out; 172284640e27SKaricheri, Muralidharan } 172384640e27SKaricheri, Muralidharan if (err == 0) 172484640e27SKaricheri, Muralidharan ret = err; 172584640e27SKaricheri, Muralidharan } 172684640e27SKaricheri, Muralidharan 172784640e27SKaricheri, Muralidharan out: 172884640e27SKaricheri, Muralidharan return (ret == 0) ? 0 : err; 172984640e27SKaricheri, Muralidharan } 173084640e27SKaricheri, Muralidharan 173184640e27SKaricheri, Muralidharan static int netcp_ndo_change_mtu(struct net_device *ndev, int new_mtu) 173284640e27SKaricheri, Muralidharan { 173384640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 173484640e27SKaricheri, Muralidharan 173584640e27SKaricheri, Muralidharan /* MTU < 68 is an error for IPv4 traffic */ 173684640e27SKaricheri, Muralidharan if ((new_mtu < 68) || 173784640e27SKaricheri, Muralidharan (new_mtu > (NETCP_MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN))) { 173884640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Invalid mtu size = %d\n", new_mtu); 173984640e27SKaricheri, Muralidharan return -EINVAL; 174084640e27SKaricheri, Muralidharan } 174184640e27SKaricheri, Muralidharan 174284640e27SKaricheri, Muralidharan ndev->mtu = new_mtu; 174384640e27SKaricheri, Muralidharan return 0; 174484640e27SKaricheri, Muralidharan } 174584640e27SKaricheri, Muralidharan 174684640e27SKaricheri, Muralidharan static void netcp_ndo_tx_timeout(struct net_device *ndev) 174784640e27SKaricheri, Muralidharan { 174884640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 174984640e27SKaricheri, Muralidharan unsigned int descs = knav_pool_count(netcp->tx_pool); 175084640e27SKaricheri, Muralidharan 175184640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "transmit timed out tx descs(%d)\n", descs); 175284640e27SKaricheri, Muralidharan netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); 175384640e27SKaricheri, Muralidharan ndev->trans_start = jiffies; 175484640e27SKaricheri, Muralidharan netif_tx_wake_all_queues(ndev); 175584640e27SKaricheri, Muralidharan } 175684640e27SKaricheri, Muralidharan 175784640e27SKaricheri, Muralidharan static int netcp_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) 175884640e27SKaricheri, Muralidharan { 175984640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 176084640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 176184640e27SKaricheri, Muralidharan struct netcp_module *module; 17628ceaf361SKaricheri, Muralidharan unsigned long flags; 176384640e27SKaricheri, Muralidharan int err = 0; 176484640e27SKaricheri, Muralidharan 176584640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "adding rx vlan id: %d\n", vid); 176684640e27SKaricheri, Muralidharan 17678ceaf361SKaricheri, Muralidharan spin_lock_irqsave(&netcp->lock, flags); 176884640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 176984640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 177084640e27SKaricheri, Muralidharan if ((module->add_vid) && (vid != 0)) { 177184640e27SKaricheri, Muralidharan err = module->add_vid(intf_modpriv->module_priv, vid); 177284640e27SKaricheri, Muralidharan if (err != 0) { 177384640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Could not add vlan id = %d\n", 177484640e27SKaricheri, Muralidharan vid); 177584640e27SKaricheri, Muralidharan break; 177684640e27SKaricheri, Muralidharan } 177784640e27SKaricheri, Muralidharan } 177884640e27SKaricheri, Muralidharan } 17798ceaf361SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp->lock, flags); 17808ceaf361SKaricheri, Muralidharan 178184640e27SKaricheri, Muralidharan return err; 178284640e27SKaricheri, Muralidharan } 178384640e27SKaricheri, Muralidharan 178484640e27SKaricheri, Muralidharan static int netcp_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) 178584640e27SKaricheri, Muralidharan { 178684640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 178784640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv; 178884640e27SKaricheri, Muralidharan struct netcp_module *module; 17898ceaf361SKaricheri, Muralidharan unsigned long flags; 179084640e27SKaricheri, Muralidharan int err = 0; 179184640e27SKaricheri, Muralidharan 179284640e27SKaricheri, Muralidharan dev_dbg(netcp->ndev_dev, "removing rx vlan id: %d\n", vid); 179384640e27SKaricheri, Muralidharan 17948ceaf361SKaricheri, Muralidharan spin_lock_irqsave(&netcp->lock, flags); 179584640e27SKaricheri, Muralidharan for_each_module(netcp, intf_modpriv) { 179684640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 179784640e27SKaricheri, Muralidharan if (module->del_vid) { 179884640e27SKaricheri, Muralidharan err = module->del_vid(intf_modpriv->module_priv, vid); 179984640e27SKaricheri, Muralidharan if (err != 0) { 180084640e27SKaricheri, Muralidharan dev_err(netcp->ndev_dev, "Could not delete vlan id = %d\n", 180184640e27SKaricheri, Muralidharan vid); 180284640e27SKaricheri, Muralidharan break; 180384640e27SKaricheri, Muralidharan } 180484640e27SKaricheri, Muralidharan } 180584640e27SKaricheri, Muralidharan } 18068ceaf361SKaricheri, Muralidharan spin_unlock_irqrestore(&netcp->lock, flags); 180784640e27SKaricheri, Muralidharan return err; 180884640e27SKaricheri, Muralidharan } 180984640e27SKaricheri, Muralidharan 181084640e27SKaricheri, Muralidharan static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb, 181184640e27SKaricheri, Muralidharan void *accel_priv, 181284640e27SKaricheri, Muralidharan select_queue_fallback_t fallback) 181384640e27SKaricheri, Muralidharan { 181484640e27SKaricheri, Muralidharan return 0; 181584640e27SKaricheri, Muralidharan } 181684640e27SKaricheri, Muralidharan 181784640e27SKaricheri, Muralidharan static int netcp_setup_tc(struct net_device *dev, u8 num_tc) 181884640e27SKaricheri, Muralidharan { 181984640e27SKaricheri, Muralidharan int i; 182084640e27SKaricheri, Muralidharan 182184640e27SKaricheri, Muralidharan /* setup tc must be called under rtnl lock */ 182284640e27SKaricheri, Muralidharan ASSERT_RTNL(); 182384640e27SKaricheri, Muralidharan 182484640e27SKaricheri, Muralidharan /* Sanity-check the number of traffic classes requested */ 182584640e27SKaricheri, Muralidharan if ((dev->real_num_tx_queues <= 1) || 182684640e27SKaricheri, Muralidharan (dev->real_num_tx_queues < num_tc)) 182784640e27SKaricheri, Muralidharan return -EINVAL; 182884640e27SKaricheri, Muralidharan 182984640e27SKaricheri, Muralidharan /* Configure traffic class to queue mappings */ 183084640e27SKaricheri, Muralidharan if (num_tc) { 183184640e27SKaricheri, Muralidharan netdev_set_num_tc(dev, num_tc); 183284640e27SKaricheri, Muralidharan for (i = 0; i < num_tc; i++) 183384640e27SKaricheri, Muralidharan netdev_set_tc_queue(dev, i, 1, i); 183484640e27SKaricheri, Muralidharan } else { 183584640e27SKaricheri, Muralidharan netdev_reset_tc(dev); 183684640e27SKaricheri, Muralidharan } 183784640e27SKaricheri, Muralidharan 183884640e27SKaricheri, Muralidharan return 0; 183984640e27SKaricheri, Muralidharan } 184084640e27SKaricheri, Muralidharan 184184640e27SKaricheri, Muralidharan static const struct net_device_ops netcp_netdev_ops = { 184284640e27SKaricheri, Muralidharan .ndo_open = netcp_ndo_open, 184384640e27SKaricheri, Muralidharan .ndo_stop = netcp_ndo_stop, 184484640e27SKaricheri, Muralidharan .ndo_start_xmit = netcp_ndo_start_xmit, 184584640e27SKaricheri, Muralidharan .ndo_set_rx_mode = netcp_set_rx_mode, 184684640e27SKaricheri, Muralidharan .ndo_do_ioctl = netcp_ndo_ioctl, 184784640e27SKaricheri, Muralidharan .ndo_change_mtu = netcp_ndo_change_mtu, 184884640e27SKaricheri, Muralidharan .ndo_set_mac_address = eth_mac_addr, 184984640e27SKaricheri, Muralidharan .ndo_validate_addr = eth_validate_addr, 185084640e27SKaricheri, Muralidharan .ndo_vlan_rx_add_vid = netcp_rx_add_vid, 185184640e27SKaricheri, Muralidharan .ndo_vlan_rx_kill_vid = netcp_rx_kill_vid, 185284640e27SKaricheri, Muralidharan .ndo_tx_timeout = netcp_ndo_tx_timeout, 185384640e27SKaricheri, Muralidharan .ndo_select_queue = netcp_select_queue, 185484640e27SKaricheri, Muralidharan .ndo_setup_tc = netcp_setup_tc, 185584640e27SKaricheri, Muralidharan }; 185684640e27SKaricheri, Muralidharan 185784640e27SKaricheri, Muralidharan static int netcp_create_interface(struct netcp_device *netcp_device, 185884640e27SKaricheri, Muralidharan struct device_node *node_interface) 185984640e27SKaricheri, Muralidharan { 186084640e27SKaricheri, Muralidharan struct device *dev = netcp_device->device; 186184640e27SKaricheri, Muralidharan struct device_node *node = dev->of_node; 186284640e27SKaricheri, Muralidharan struct netcp_intf *netcp; 186384640e27SKaricheri, Muralidharan struct net_device *ndev; 186484640e27SKaricheri, Muralidharan resource_size_t size; 186584640e27SKaricheri, Muralidharan struct resource res; 186684640e27SKaricheri, Muralidharan void __iomem *efuse = NULL; 186784640e27SKaricheri, Muralidharan u32 efuse_mac = 0; 186884640e27SKaricheri, Muralidharan const void *mac_addr; 186984640e27SKaricheri, Muralidharan u8 efuse_mac_addr[6]; 187084640e27SKaricheri, Muralidharan u32 temp[2]; 187184640e27SKaricheri, Muralidharan int ret = 0; 187284640e27SKaricheri, Muralidharan 187384640e27SKaricheri, Muralidharan ndev = alloc_etherdev_mqs(sizeof(*netcp), 1, 1); 187484640e27SKaricheri, Muralidharan if (!ndev) { 187584640e27SKaricheri, Muralidharan dev_err(dev, "Error allocating netdev\n"); 187684640e27SKaricheri, Muralidharan return -ENOMEM; 187784640e27SKaricheri, Muralidharan } 187884640e27SKaricheri, Muralidharan 187984640e27SKaricheri, Muralidharan ndev->features |= NETIF_F_SG; 188084640e27SKaricheri, Muralidharan ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 188184640e27SKaricheri, Muralidharan ndev->hw_features = ndev->features; 188284640e27SKaricheri, Muralidharan ndev->vlan_features |= NETIF_F_SG; 188384640e27SKaricheri, Muralidharan 188484640e27SKaricheri, Muralidharan netcp = netdev_priv(ndev); 188584640e27SKaricheri, Muralidharan spin_lock_init(&netcp->lock); 188684640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp->module_head); 188784640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp->txhook_list_head); 188884640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp->rxhook_list_head); 188984640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp->addr_list); 189084640e27SKaricheri, Muralidharan netcp->netcp_device = netcp_device; 189184640e27SKaricheri, Muralidharan netcp->dev = netcp_device->device; 189284640e27SKaricheri, Muralidharan netcp->ndev = ndev; 189384640e27SKaricheri, Muralidharan netcp->ndev_dev = &ndev->dev; 189484640e27SKaricheri, Muralidharan netcp->msg_enable = netif_msg_init(netcp_debug_level, NETCP_DEBUG); 189584640e27SKaricheri, Muralidharan netcp->tx_pause_threshold = MAX_SKB_FRAGS; 189684640e27SKaricheri, Muralidharan netcp->tx_resume_threshold = netcp->tx_pause_threshold; 189784640e27SKaricheri, Muralidharan netcp->node_interface = node_interface; 189884640e27SKaricheri, Muralidharan 189984640e27SKaricheri, Muralidharan ret = of_property_read_u32(node_interface, "efuse-mac", &efuse_mac); 190084640e27SKaricheri, Muralidharan if (efuse_mac) { 190184640e27SKaricheri, Muralidharan if (of_address_to_resource(node, NETCP_EFUSE_REG_INDEX, &res)) { 190284640e27SKaricheri, Muralidharan dev_err(dev, "could not find efuse-mac reg resource\n"); 190384640e27SKaricheri, Muralidharan ret = -ENODEV; 190484640e27SKaricheri, Muralidharan goto quit; 190584640e27SKaricheri, Muralidharan } 190684640e27SKaricheri, Muralidharan size = resource_size(&res); 190784640e27SKaricheri, Muralidharan 190884640e27SKaricheri, Muralidharan if (!devm_request_mem_region(dev, res.start, size, 190984640e27SKaricheri, Muralidharan dev_name(dev))) { 191084640e27SKaricheri, Muralidharan dev_err(dev, "could not reserve resource\n"); 191184640e27SKaricheri, Muralidharan ret = -ENOMEM; 191284640e27SKaricheri, Muralidharan goto quit; 191384640e27SKaricheri, Muralidharan } 191484640e27SKaricheri, Muralidharan 191584640e27SKaricheri, Muralidharan efuse = devm_ioremap_nocache(dev, res.start, size); 191684640e27SKaricheri, Muralidharan if (!efuse) { 191784640e27SKaricheri, Muralidharan dev_err(dev, "could not map resource\n"); 191884640e27SKaricheri, Muralidharan devm_release_mem_region(dev, res.start, size); 191984640e27SKaricheri, Muralidharan ret = -ENOMEM; 192084640e27SKaricheri, Muralidharan goto quit; 192184640e27SKaricheri, Muralidharan } 192284640e27SKaricheri, Muralidharan 192371382bc0SWingMan Kwok emac_arch_get_mac_addr(efuse_mac_addr, efuse, efuse_mac); 192484640e27SKaricheri, Muralidharan if (is_valid_ether_addr(efuse_mac_addr)) 192584640e27SKaricheri, Muralidharan ether_addr_copy(ndev->dev_addr, efuse_mac_addr); 192684640e27SKaricheri, Muralidharan else 192784640e27SKaricheri, Muralidharan random_ether_addr(ndev->dev_addr); 192884640e27SKaricheri, Muralidharan 192984640e27SKaricheri, Muralidharan devm_iounmap(dev, efuse); 193084640e27SKaricheri, Muralidharan devm_release_mem_region(dev, res.start, size); 193184640e27SKaricheri, Muralidharan } else { 193284640e27SKaricheri, Muralidharan mac_addr = of_get_mac_address(node_interface); 193384640e27SKaricheri, Muralidharan if (mac_addr) 193484640e27SKaricheri, Muralidharan ether_addr_copy(ndev->dev_addr, mac_addr); 193584640e27SKaricheri, Muralidharan else 193684640e27SKaricheri, Muralidharan random_ether_addr(ndev->dev_addr); 193784640e27SKaricheri, Muralidharan } 193884640e27SKaricheri, Muralidharan 193984640e27SKaricheri, Muralidharan ret = of_property_read_string(node_interface, "rx-channel", 194084640e27SKaricheri, Muralidharan &netcp->dma_chan_name); 194184640e27SKaricheri, Muralidharan if (ret < 0) { 194284640e27SKaricheri, Muralidharan dev_err(dev, "missing \"rx-channel\" parameter\n"); 194384640e27SKaricheri, Muralidharan ret = -ENODEV; 194484640e27SKaricheri, Muralidharan goto quit; 194584640e27SKaricheri, Muralidharan } 194684640e27SKaricheri, Muralidharan 194784640e27SKaricheri, Muralidharan ret = of_property_read_u32(node_interface, "rx-queue", 194884640e27SKaricheri, Muralidharan &netcp->rx_queue_id); 194984640e27SKaricheri, Muralidharan if (ret < 0) { 195084640e27SKaricheri, Muralidharan dev_warn(dev, "missing \"rx-queue\" parameter\n"); 195184640e27SKaricheri, Muralidharan netcp->rx_queue_id = KNAV_QUEUE_QPEND; 195284640e27SKaricheri, Muralidharan } 195384640e27SKaricheri, Muralidharan 195484640e27SKaricheri, Muralidharan ret = of_property_read_u32_array(node_interface, "rx-queue-depth", 195584640e27SKaricheri, Muralidharan netcp->rx_queue_depths, 195684640e27SKaricheri, Muralidharan KNAV_DMA_FDQ_PER_CHAN); 195784640e27SKaricheri, Muralidharan if (ret < 0) { 195884640e27SKaricheri, Muralidharan dev_err(dev, "missing \"rx-queue-depth\" parameter\n"); 195984640e27SKaricheri, Muralidharan netcp->rx_queue_depths[0] = 128; 196084640e27SKaricheri, Muralidharan } 196184640e27SKaricheri, Muralidharan 196284640e27SKaricheri, Muralidharan ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2); 196384640e27SKaricheri, Muralidharan if (ret < 0) { 196484640e27SKaricheri, Muralidharan dev_err(dev, "missing \"rx-pool\" parameter\n"); 196584640e27SKaricheri, Muralidharan ret = -ENODEV; 196684640e27SKaricheri, Muralidharan goto quit; 196784640e27SKaricheri, Muralidharan } 196884640e27SKaricheri, Muralidharan netcp->rx_pool_size = temp[0]; 196984640e27SKaricheri, Muralidharan netcp->rx_pool_region_id = temp[1]; 197084640e27SKaricheri, Muralidharan 197184640e27SKaricheri, Muralidharan ret = of_property_read_u32_array(node_interface, "tx-pool", temp, 2); 197284640e27SKaricheri, Muralidharan if (ret < 0) { 197384640e27SKaricheri, Muralidharan dev_err(dev, "missing \"tx-pool\" parameter\n"); 197484640e27SKaricheri, Muralidharan ret = -ENODEV; 197584640e27SKaricheri, Muralidharan goto quit; 197684640e27SKaricheri, Muralidharan } 197784640e27SKaricheri, Muralidharan netcp->tx_pool_size = temp[0]; 197884640e27SKaricheri, Muralidharan netcp->tx_pool_region_id = temp[1]; 197984640e27SKaricheri, Muralidharan 198084640e27SKaricheri, Muralidharan if (netcp->tx_pool_size < MAX_SKB_FRAGS) { 198184640e27SKaricheri, Muralidharan dev_err(dev, "tx-pool size too small, must be atleast(%ld)\n", 198284640e27SKaricheri, Muralidharan MAX_SKB_FRAGS); 198384640e27SKaricheri, Muralidharan ret = -ENODEV; 198484640e27SKaricheri, Muralidharan goto quit; 198584640e27SKaricheri, Muralidharan } 198684640e27SKaricheri, Muralidharan 198784640e27SKaricheri, Muralidharan ret = of_property_read_u32(node_interface, "tx-completion-queue", 198884640e27SKaricheri, Muralidharan &netcp->tx_compl_qid); 198984640e27SKaricheri, Muralidharan if (ret < 0) { 199084640e27SKaricheri, Muralidharan dev_warn(dev, "missing \"tx-completion-queue\" parameter\n"); 199184640e27SKaricheri, Muralidharan netcp->tx_compl_qid = KNAV_QUEUE_QPEND; 199284640e27SKaricheri, Muralidharan } 199384640e27SKaricheri, Muralidharan 199484640e27SKaricheri, Muralidharan /* NAPI register */ 199584640e27SKaricheri, Muralidharan netif_napi_add(ndev, &netcp->rx_napi, netcp_rx_poll, NETCP_NAPI_WEIGHT); 1996d64b5e85SEric Dumazet netif_tx_napi_add(ndev, &netcp->tx_napi, netcp_tx_poll, NETCP_NAPI_WEIGHT); 199784640e27SKaricheri, Muralidharan 199884640e27SKaricheri, Muralidharan /* Register the network device */ 199984640e27SKaricheri, Muralidharan ndev->dev_id = 0; 200084640e27SKaricheri, Muralidharan ndev->watchdog_timeo = NETCP_TX_TIMEOUT; 200184640e27SKaricheri, Muralidharan ndev->netdev_ops = &netcp_netdev_ops; 200284640e27SKaricheri, Muralidharan SET_NETDEV_DEV(ndev, dev); 200384640e27SKaricheri, Muralidharan 200484640e27SKaricheri, Muralidharan list_add_tail(&netcp->interface_list, &netcp_device->interface_head); 200584640e27SKaricheri, Muralidharan return 0; 200684640e27SKaricheri, Muralidharan 200784640e27SKaricheri, Muralidharan quit: 200884640e27SKaricheri, Muralidharan free_netdev(ndev); 200984640e27SKaricheri, Muralidharan return ret; 201084640e27SKaricheri, Muralidharan } 201184640e27SKaricheri, Muralidharan 201284640e27SKaricheri, Muralidharan static void netcp_delete_interface(struct netcp_device *netcp_device, 201384640e27SKaricheri, Muralidharan struct net_device *ndev) 201484640e27SKaricheri, Muralidharan { 201584640e27SKaricheri, Muralidharan struct netcp_intf_modpriv *intf_modpriv, *tmp; 201684640e27SKaricheri, Muralidharan struct netcp_intf *netcp = netdev_priv(ndev); 201784640e27SKaricheri, Muralidharan struct netcp_module *module; 201884640e27SKaricheri, Muralidharan 201984640e27SKaricheri, Muralidharan dev_dbg(netcp_device->device, "Removing interface \"%s\"\n", 202084640e27SKaricheri, Muralidharan ndev->name); 202184640e27SKaricheri, Muralidharan 202284640e27SKaricheri, Muralidharan /* Notify each of the modules that the interface is going away */ 202384640e27SKaricheri, Muralidharan list_for_each_entry_safe(intf_modpriv, tmp, &netcp->module_head, 202484640e27SKaricheri, Muralidharan intf_list) { 202584640e27SKaricheri, Muralidharan module = intf_modpriv->netcp_module; 202684640e27SKaricheri, Muralidharan dev_dbg(netcp_device->device, "Releasing module \"%s\"\n", 202784640e27SKaricheri, Muralidharan module->name); 202884640e27SKaricheri, Muralidharan if (module->release) 202984640e27SKaricheri, Muralidharan module->release(intf_modpriv->module_priv); 203084640e27SKaricheri, Muralidharan list_del(&intf_modpriv->intf_list); 203184640e27SKaricheri, Muralidharan kfree(intf_modpriv); 203284640e27SKaricheri, Muralidharan } 203384640e27SKaricheri, Muralidharan WARN(!list_empty(&netcp->module_head), "%s interface module list is not empty!\n", 203484640e27SKaricheri, Muralidharan ndev->name); 203584640e27SKaricheri, Muralidharan 203684640e27SKaricheri, Muralidharan list_del(&netcp->interface_list); 203784640e27SKaricheri, Muralidharan 203884640e27SKaricheri, Muralidharan of_node_put(netcp->node_interface); 203984640e27SKaricheri, Muralidharan unregister_netdev(ndev); 204084640e27SKaricheri, Muralidharan netif_napi_del(&netcp->rx_napi); 204184640e27SKaricheri, Muralidharan free_netdev(ndev); 204284640e27SKaricheri, Muralidharan } 204384640e27SKaricheri, Muralidharan 204484640e27SKaricheri, Muralidharan static int netcp_probe(struct platform_device *pdev) 204584640e27SKaricheri, Muralidharan { 204684640e27SKaricheri, Muralidharan struct device_node *node = pdev->dev.of_node; 204784640e27SKaricheri, Muralidharan struct netcp_intf *netcp_intf, *netcp_tmp; 204884640e27SKaricheri, Muralidharan struct device_node *child, *interfaces; 204984640e27SKaricheri, Muralidharan struct netcp_device *netcp_device; 205084640e27SKaricheri, Muralidharan struct device *dev = &pdev->dev; 205184640e27SKaricheri, Muralidharan int ret; 205284640e27SKaricheri, Muralidharan 205384640e27SKaricheri, Muralidharan if (!node) { 205484640e27SKaricheri, Muralidharan dev_err(dev, "could not find device info\n"); 205584640e27SKaricheri, Muralidharan return -ENODEV; 205684640e27SKaricheri, Muralidharan } 205784640e27SKaricheri, Muralidharan 205884640e27SKaricheri, Muralidharan /* Allocate a new NETCP device instance */ 205984640e27SKaricheri, Muralidharan netcp_device = devm_kzalloc(dev, sizeof(*netcp_device), GFP_KERNEL); 206084640e27SKaricheri, Muralidharan if (!netcp_device) 206184640e27SKaricheri, Muralidharan return -ENOMEM; 206284640e27SKaricheri, Muralidharan 206384640e27SKaricheri, Muralidharan pm_runtime_enable(&pdev->dev); 206484640e27SKaricheri, Muralidharan ret = pm_runtime_get_sync(&pdev->dev); 206584640e27SKaricheri, Muralidharan if (ret < 0) { 206684640e27SKaricheri, Muralidharan dev_err(dev, "Failed to enable NETCP power-domain\n"); 206784640e27SKaricheri, Muralidharan pm_runtime_disable(&pdev->dev); 206884640e27SKaricheri, Muralidharan return ret; 206984640e27SKaricheri, Muralidharan } 207084640e27SKaricheri, Muralidharan 207184640e27SKaricheri, Muralidharan /* Initialize the NETCP device instance */ 207284640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp_device->interface_head); 207384640e27SKaricheri, Muralidharan INIT_LIST_HEAD(&netcp_device->modpriv_head); 207484640e27SKaricheri, Muralidharan netcp_device->device = dev; 207584640e27SKaricheri, Muralidharan platform_set_drvdata(pdev, netcp_device); 207684640e27SKaricheri, Muralidharan 207784640e27SKaricheri, Muralidharan /* create interfaces */ 207884640e27SKaricheri, Muralidharan interfaces = of_get_child_by_name(node, "netcp-interfaces"); 207984640e27SKaricheri, Muralidharan if (!interfaces) { 208084640e27SKaricheri, Muralidharan dev_err(dev, "could not find netcp-interfaces node\n"); 208184640e27SKaricheri, Muralidharan ret = -ENODEV; 208284640e27SKaricheri, Muralidharan goto probe_quit; 208384640e27SKaricheri, Muralidharan } 208484640e27SKaricheri, Muralidharan 208584640e27SKaricheri, Muralidharan for_each_available_child_of_node(interfaces, child) { 208684640e27SKaricheri, Muralidharan ret = netcp_create_interface(netcp_device, child); 208784640e27SKaricheri, Muralidharan if (ret) { 208884640e27SKaricheri, Muralidharan dev_err(dev, "could not create interface(%s)\n", 208984640e27SKaricheri, Muralidharan child->name); 209084640e27SKaricheri, Muralidharan goto probe_quit_interface; 209184640e27SKaricheri, Muralidharan } 209284640e27SKaricheri, Muralidharan } 209384640e27SKaricheri, Muralidharan 209484640e27SKaricheri, Muralidharan /* Add the device instance to the list */ 209584640e27SKaricheri, Muralidharan list_add_tail(&netcp_device->device_list, &netcp_devices); 209684640e27SKaricheri, Muralidharan 209784640e27SKaricheri, Muralidharan return 0; 209884640e27SKaricheri, Muralidharan 209984640e27SKaricheri, Muralidharan probe_quit_interface: 210084640e27SKaricheri, Muralidharan list_for_each_entry_safe(netcp_intf, netcp_tmp, 210184640e27SKaricheri, Muralidharan &netcp_device->interface_head, 210284640e27SKaricheri, Muralidharan interface_list) { 210384640e27SKaricheri, Muralidharan netcp_delete_interface(netcp_device, netcp_intf->ndev); 210484640e27SKaricheri, Muralidharan } 210584640e27SKaricheri, Muralidharan 210684640e27SKaricheri, Muralidharan probe_quit: 210784640e27SKaricheri, Muralidharan pm_runtime_put_sync(&pdev->dev); 210884640e27SKaricheri, Muralidharan pm_runtime_disable(&pdev->dev); 210984640e27SKaricheri, Muralidharan platform_set_drvdata(pdev, NULL); 211084640e27SKaricheri, Muralidharan return ret; 211184640e27SKaricheri, Muralidharan } 211284640e27SKaricheri, Muralidharan 211384640e27SKaricheri, Muralidharan static int netcp_remove(struct platform_device *pdev) 211484640e27SKaricheri, Muralidharan { 211584640e27SKaricheri, Muralidharan struct netcp_device *netcp_device = platform_get_drvdata(pdev); 211601a03099SKaricheri, Muralidharan struct netcp_intf *netcp_intf, *netcp_tmp; 211784640e27SKaricheri, Muralidharan struct netcp_inst_modpriv *inst_modpriv, *tmp; 211884640e27SKaricheri, Muralidharan struct netcp_module *module; 211984640e27SKaricheri, Muralidharan 212084640e27SKaricheri, Muralidharan list_for_each_entry_safe(inst_modpriv, tmp, &netcp_device->modpriv_head, 212184640e27SKaricheri, Muralidharan inst_list) { 212284640e27SKaricheri, Muralidharan module = inst_modpriv->netcp_module; 212384640e27SKaricheri, Muralidharan dev_dbg(&pdev->dev, "Removing module \"%s\"\n", module->name); 212484640e27SKaricheri, Muralidharan module->remove(netcp_device, inst_modpriv->module_priv); 212584640e27SKaricheri, Muralidharan list_del(&inst_modpriv->inst_list); 212684640e27SKaricheri, Muralidharan kfree(inst_modpriv); 212784640e27SKaricheri, Muralidharan } 212884640e27SKaricheri, Muralidharan 212901a03099SKaricheri, Muralidharan /* now that all modules are removed, clean up the interfaces */ 213001a03099SKaricheri, Muralidharan list_for_each_entry_safe(netcp_intf, netcp_tmp, 213101a03099SKaricheri, Muralidharan &netcp_device->interface_head, 213201a03099SKaricheri, Muralidharan interface_list) { 213301a03099SKaricheri, Muralidharan netcp_delete_interface(netcp_device, netcp_intf->ndev); 213401a03099SKaricheri, Muralidharan } 213501a03099SKaricheri, Muralidharan 213601a03099SKaricheri, Muralidharan WARN(!list_empty(&netcp_device->interface_head), 213701a03099SKaricheri, Muralidharan "%s interface list not empty!\n", pdev->name); 213884640e27SKaricheri, Muralidharan 213984640e27SKaricheri, Muralidharan pm_runtime_put_sync(&pdev->dev); 214084640e27SKaricheri, Muralidharan pm_runtime_disable(&pdev->dev); 214184640e27SKaricheri, Muralidharan platform_set_drvdata(pdev, NULL); 214284640e27SKaricheri, Muralidharan return 0; 214384640e27SKaricheri, Muralidharan } 214484640e27SKaricheri, Muralidharan 21451156c965SFabian Frederick static const struct of_device_id of_match[] = { 214684640e27SKaricheri, Muralidharan { .compatible = "ti,netcp-1.0", }, 214784640e27SKaricheri, Muralidharan {}, 214884640e27SKaricheri, Muralidharan }; 214984640e27SKaricheri, Muralidharan MODULE_DEVICE_TABLE(of, of_match); 215084640e27SKaricheri, Muralidharan 215184640e27SKaricheri, Muralidharan static struct platform_driver netcp_driver = { 215284640e27SKaricheri, Muralidharan .driver = { 215384640e27SKaricheri, Muralidharan .name = "netcp-1.0", 215484640e27SKaricheri, Muralidharan .of_match_table = of_match, 215584640e27SKaricheri, Muralidharan }, 215684640e27SKaricheri, Muralidharan .probe = netcp_probe, 215784640e27SKaricheri, Muralidharan .remove = netcp_remove, 215884640e27SKaricheri, Muralidharan }; 215984640e27SKaricheri, Muralidharan module_platform_driver(netcp_driver); 216084640e27SKaricheri, Muralidharan 216184640e27SKaricheri, Muralidharan MODULE_LICENSE("GPL v2"); 216284640e27SKaricheri, Muralidharan MODULE_DESCRIPTION("TI NETCP driver for Keystone SOCs"); 216384640e27SKaricheri, Muralidharan MODULE_AUTHOR("Sandeep Nair <sandeep_n@ti.com"); 2164