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