diff options
Diffstat (limited to 'drivers/staging/fsl_dpa_offload/wrp_dpa_classifier.c')
-rw-r--r-- | drivers/staging/fsl_dpa_offload/wrp_dpa_classifier.c | 3123 |
1 files changed, 3123 insertions, 0 deletions
diff --git a/drivers/staging/fsl_dpa_offload/wrp_dpa_classifier.c b/drivers/staging/fsl_dpa_offload/wrp_dpa_classifier.c new file mode 100644 index 0000000..aa2017a --- /dev/null +++ b/drivers/staging/fsl_dpa_offload/wrp_dpa_classifier.c @@ -0,0 +1,3123 @@ + +/* Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DPA Classifier Wrapper implementation. + */ + +/* DPA offloading layer includes */ +#include <linux/fsl_dpa_classifier.h> +#include "wrp_dpa_classifier.h" +#include "dpa_classifier_ioctl.h" + +/* Other includes */ +#include <linux/uaccess.h> +#include <linux/fdtable.h> +#include <linux/export.h> +#include "lnxwrp_fm.h" +#include "fm_pcd_ioctls.h" +#include "fm_port_ioctls.h" +#ifdef CONFIG_COMPAT +#include "lnxwrp_ioctls_fm_compat.h" +#endif /* CONFIG_COMPAT */ + + +#define COPY_KEY_PARAMS \ +do { \ + if ((kparam.key.size <= 0) || \ + (kparam.key.size > DPA_OFFLD_MAXENTRYKEYSIZE)) { \ + pr_err("ERROR: %s, %s (%d): Invalid lookup key size " \ + "(%d bytes).\n", __FILE__, __func__, __LINE__, \ + kparam.key.size); \ + return -EINVAL; \ + } \ + \ + if (copy_from_user(key_buf, kparam.key.byte, \ + kparam.key.size)) { \ + pr_err("ERROR: %s, %s (%d): Read failed: lookup " \ + "key.\n", __FILE__, __func__, __LINE__); \ + return -EBUSY; \ + } \ + kparam.key.byte = key_buf; \ + \ + if (kparam.key.mask) { \ + if (copy_from_user(mask_buf, kparam.key.mask, \ + kparam.key.size)) { \ + pr_err("ERROR: %s, %s (%d): Read failed: " \ + "key mask.\n", __FILE__, __func__, \ + __LINE__); \ + return -EBUSY; \ + } \ + \ + kparam.key.mask = mask_buf; \ + } \ +} while (0) + +#define COPY_NEW_KEY_PARAMS \ +do { \ + if (kparam.mod_params.key) { \ + if (copy_from_user(&new_key, \ + kparam.mod_params.key, \ + sizeof(struct dpa_offload_lookup_key))) { \ + pr_err("ERROR: %s, %s (%d): Read failed: " \ + "new lookup key.\n", __FILE__, \ + __func__, __LINE__); \ + return -EBUSY; \ + } \ + kparam.mod_params.key = &new_key; \ + \ + if ((kparam.mod_params.key->size <= 0) || \ + (kparam.mod_params.key->size > \ + DPA_OFFLD_MAXENTRYKEYSIZE)) { \ + pr_err("ERROR: %s, %s (%d): Invalid new lookup " \ + "key size (%d bytes).\n", __FILE__, \ + __func__, __LINE__, \ + kparam.mod_params.key->size); \ + return -EINVAL; \ + } \ + \ + if (kparam.mod_params.key->byte) { \ + if (copy_from_user(new_key_buf, \ + kparam.mod_params.key->byte, \ + kparam.mod_params.key->size)) { \ + pr_err("ERROR: %s, %s (%d): Read " \ + "failed: new lookup key data.\n", \ + __FILE__, __func__, __LINE__); \ + return -EBUSY; \ + } \ + kparam.mod_params.key->byte = new_key_buf; \ + } \ + if (kparam.mod_params.key->mask) { \ + if (copy_from_user(new_mask_buf, \ + kparam.mod_params.key->mask, \ + kparam.mod_params.key->size)) { \ + pr_err("ERROR: %s, %s (%d): Read " \ + "failed: new key mask.\n", \ + __FILE__, __func__, __LINE__); \ + return -EBUSY; \ + } \ + kparam.mod_params.key->mask = new_mask_buf; \ + } \ + } \ +} while (0) + +#ifdef DPA_CLASSIFIER_WRP_DEBUG +#define dpa_cls_wrp_dbg(message) printk message +#else +#define dpa_cls_wrp_dbg(message) +#endif /* DPA_CLASSIFIER_DEBUG */ + + +static long do_ioctl_table_create(unsigned long args, bool compat_mode); + +static long do_ioctl_table_modify_miss_action(unsigned long args, + bool compat_mode); + +static long do_ioctl_table_insert_entry(unsigned long args, bool compat_mode); + +static long do_ioctl_table_modify_entry_by_key(unsigned long args, + bool compat_mode); + +static long do_ioctl_table_modify_entry_by_ref(unsigned long args, + bool compat_mode); + +static long do_ioctl_table_lookup_by_key(unsigned long args, bool compat_mode); + +static long do_ioctl_table_lookup_by_ref(unsigned long args, bool compat_mode); + +static long do_ioctl_table_delete_entry_by_key(unsigned long args, + bool compat_mode); + +static long do_ioctl_table_get_stats_by_key(unsigned long args, + bool compat_mode); + +static long do_ioctl_set_remove_hm(unsigned long args, + bool compat_mode); + +static long do_ioctl_modify_remove_hm(unsigned long args, + bool compat_mode); + +static long do_ioctl_set_insert_hm(unsigned long args, + bool compat_mode); + +static long do_ioctl_modify_insert_hm(unsigned long args, + bool compat_mode); + +static long do_ioctl_set_vlan_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_modify_vlan_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_set_nat_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_modify_nat_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_set_update_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_modify_update_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_set_fwd_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_modify_fwd_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_set_mpls_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_modify_mpls_hm(unsigned long args, bool compat_mode); + +static long do_ioctl_mcast_create_group(unsigned long args, bool compat_mode); + +static long do_ioctl_mcast_add_member(unsigned long args, bool compat_mode); + +void *translate_fm_pcd_handle(void *fm_pcd); + +static const struct file_operations dpa_classif_fops = { + .owner = THIS_MODULE, + .open = wrp_dpa_classif_open, + .read = wrp_dpa_classif_read, + .write = wrp_dpa_classif_write, + .unlocked_ioctl = wrp_dpa_classif_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = wrp_dpa_classif_compat_ioctl, +#endif /* CONFIG_COMPAT */ + .release = wrp_dpa_classif_release +}; + +static int dpa_cls_cdev_major = -1; + + +int wrp_dpa_classif_init(void) +{ + /* Cannot initialize the wrapper twice */ + if (dpa_cls_cdev_major >= 0) + return 0; + + dpa_cls_cdev_major = register_chrdev( + 0, + WRP_DPA_CLS_CDEVNAME, + &dpa_classif_fops); + if (dpa_cls_cdev_major < 0) { + pr_err("ERROR: %s, %s (%d): Could not register DPA Classifier " + "Control Device.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + return 0; +} + + +int wrp_dpa_classif_exit(void) +{ + if (dpa_cls_cdev_major < 0) + return 0; + + unregister_chrdev(dpa_cls_cdev_major, WRP_DPA_CLS_CDEVNAME); + + dpa_cls_cdev_major = -1; + + return 0; +} + + +int wrp_dpa_classif_open(struct inode *inode, struct file *filp) +{ + return 0; +} + + +int wrp_dpa_classif_release(struct inode *inode, struct file *filp) +{ + return 0; +} + + +ssize_t wrp_dpa_classif_read( + struct file *filp, + char __user *buf, + size_t len, + loff_t *offp) +{ + return 0; +} + + +ssize_t wrp_dpa_classif_write( + struct file *filp, + const char __user *buf, + size_t len, + loff_t *offp) +{ + return 0; +} + + +#ifdef CONFIG_COMPAT +long wrp_dpa_classif_compat_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long args) +{ + return wrp_dpa_classif_do_ioctl(filp, cmd, args, true); +} +#endif /* CONFIG_COMPAT */ + + +long wrp_dpa_classif_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long args) +{ + return wrp_dpa_classif_do_ioctl(filp, cmd, args, false); +} + + +long wrp_dpa_classif_do_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long args, + bool compat_mode) +{ + long ret = 0; + + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) --> Processing ioctl " + "cmd=0x%x\n", __func__, __LINE__, cmd)); + + switch (cmd) { +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_CREATE: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_CREATE: + ret = do_ioctl_table_create(args, compat_mode); + break; + + case DPA_CLS_IOC_TBL_FREE: + ret = dpa_classif_table_free((int)args); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_MODIFY_MISS_ACTION: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_MODIFY_MISS_ACTION: + ret = do_ioctl_table_modify_miss_action(args, compat_mode); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_INSERT_ENTRY: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_INSERT_ENTRY: + ret = do_ioctl_table_insert_entry(args, compat_mode); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_MODIFY_ENTRY_BY_KEY: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_MODIFY_ENTRY_BY_KEY: + ret = do_ioctl_table_modify_entry_by_key(args, compat_mode); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_MODIFY_ENTRY_BY_REF: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_MODIFY_ENTRY_BY_REF: + ret = do_ioctl_table_modify_entry_by_ref(args, compat_mode); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_DELETE_ENTRY_BY_KEY: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_DELETE_ENTRY_BY_KEY: + ret = do_ioctl_table_delete_entry_by_key(args, compat_mode); + break; + + case DPA_CLS_IOC_TBL_DELETE_ENTRY_BY_REF: + { + struct ioc_dpa_cls_tbl_entry_by_ref param; + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d): " + "delete_entry_by_ref\n", __func__, __LINE__)); + + /* Prepare arguments */ + if (copy_from_user(¶m, (void *) args, sizeof(param))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "dpa_classif_table_delete_entry_by_ref user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Call function */ + ret = dpa_classif_table_delete_entry_by_ref(param.td, + param.entry_id); + + break; + } + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_LOOKUP_BY_KEY: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_LOOKUP_BY_KEY: + ret = do_ioctl_table_lookup_by_key(args, compat_mode); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_LOOKUP_BY_REF: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_LOOKUP_BY_REF: + ret = do_ioctl_table_lookup_by_ref(args, compat_mode); + break; + + case DPA_CLS_IOC_TBL_FLUSH: + ret = dpa_classif_table_flush((int)args); + break; + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_GET_STATS_BY_KEY: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_GET_STATS_BY_KEY: + ret = do_ioctl_table_get_stats_by_key(args, compat_mode); + break; + + case DPA_CLS_IOC_TBL_GET_STATS_BY_REF: + { + struct ioc_dpa_cls_tbl_entry_stats_by_ref param; + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d): " + "get_stats_by_ref\n", __func__, __LINE__)); + + /* Prepare arguments */ + if (copy_from_user(¶m, (void *) args, sizeof(param))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "dpa_classif_table_get_entry_stats_by_ref user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Call function */ + ret = dpa_classif_table_get_entry_stats_by_ref(param.td, + param.entry_id, + ¶m.stats); + if (ret < 0) + return ret; + + /* Return results to user space */ + if (copy_to_user((void *) args, ¶m, sizeof(param))) { + pr_err("ERROR: %s, %s (%d): Write failed: " + "dpa_classif_table_get_entry_stats_by_ref " + "result.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + break; + } + +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_TBL_GET_PARAMS: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_TBL_GET_PARAMS: + { + struct ioc_dpa_cls_tbl_params kparam; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_params uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, + sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "dpa_classif_table_lookup_by_key user " + "space args.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + kparam.td = uparam.td; + } else +#endif /* CONFIG_COMPAT */ + /* Prepare arguments */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "dpa_classif_table_lookup_by_key user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d): " + "table_get_params\n", __func__, __LINE__)); + + /* Call function */ + ret = dpa_classif_table_get_params(kparam.td, + &kparam.table_params); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + ret = dpa_cls_tbl_params_rcompatcpy(&uparam, &kparam); + if (ret < 0) + return ret; + + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: " + "dpa_classif_table_get_params result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + /* Return results to user space */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: " + "dpa_classif_table_get_params result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + break; + } +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_REMOVE_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_REMOVE_HM: + ret = do_ioctl_set_remove_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_REMOVE_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_REMOVE_HM: + ret = do_ioctl_modify_remove_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_INSERT_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_INSERT_HM: + ret = do_ioctl_set_insert_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_INSERT_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_INSERT_HM: + ret = do_ioctl_modify_insert_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_VLAN_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_VLAN_HM: + ret = do_ioctl_set_vlan_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_VLAN_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_VLAN_HM: + ret = do_ioctl_modify_vlan_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_NAT_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_NAT_HM: + ret = do_ioctl_set_nat_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_NAT_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_NAT_HM: + ret = do_ioctl_modify_nat_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_UPDATE_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_UPDATE_HM: + ret = do_ioctl_set_update_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_UPDATE_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_UPDATE_HM: + ret = do_ioctl_modify_update_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_FWD_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_FWD_HM: + ret = do_ioctl_set_fwd_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_FWD_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_FWD_HM: + ret = do_ioctl_modify_fwd_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_SET_MPLS_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_SET_MPLS_HM: + ret = do_ioctl_set_mpls_hm(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MODIFY_MPLS_HM: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MODIFY_MPLS_HM: + ret = do_ioctl_modify_mpls_hm(args, compat_mode); + break; + case DPA_CLS_IOC_FREE_HM: + ret = dpa_classif_free_hm((int)args); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MCAST_CREATE_GROUP: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MCAST_CREATE_GROUP: + ret = do_ioctl_mcast_create_group(args, compat_mode); + break; +#ifdef CONFIG_COMPAT + case DPA_CLS_IOC_COMPAT_MCAST_ADD_MEMBER: +#endif /* CONFIG_COMPAT */ + case DPA_CLS_IOC_MCAST_ADD_MEMBER: + ret = do_ioctl_mcast_add_member(args, compat_mode); + break; + case DPA_CLS_IOC_MCAST_REMOVE_MEMBER: { + struct ioc_dpa_cls_mcast_remove_params params; + int sz; + sz = sizeof(struct ioc_dpa_cls_mcast_remove_params); + if (copy_from_user(¶ms, + (struct ioc_dpa_cls_mcast_remove_params *)args, + sz)) { + pr_err("ERROR: %s, %s (%d):Could not copy parameters\n", + __FILE__, __func__, __LINE__); + return -EINVAL; + } +#if (DPAA_VERSION >= 11) + ret = dpa_classif_mcast_remove_member(params.grpd, + params.md); +#else + pr_err("ERROR: %s, %s (%d): Multicast not supported on this" + "platform.\n", __FILE__, __func__, __LINE__); + ret = -EINVAL; + return ret; +#endif + break; + } + case DPA_CLS_IOC_MCAST_FREE_GROUP: { + int grpd; + if (copy_from_user(&grpd, (int *)args, sizeof(int))) { + pr_err("ERROR: %s, %s (%d):Could not copy parameters\n", + __FILE__, __func__, __LINE__); + return -EINVAL; + } +#if (DPAA_VERSION >= 11) + ret = dpa_classif_mcast_free_group(grpd); + if (ret < 0) + return ret; +#else + pr_err("ERROR: %s, %s (%d): Multicast not supported on this" + "platform.\n", __FILE__, __func__, __LINE__); + ret = -EINVAL; + return ret; +#endif + break; + } + default: + pr_err("ERROR: %s, %s (%d): DPA Classifier ioctl command " + "(0x%x) not suppoted", __FILE__, __func__, __LINE__, + cmd); + return -EINVAL; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d): Done <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_table_create(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_tbl_params kparam; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_params uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + memset(&kparam, 0, sizeof(struct ioc_dpa_cls_tbl_params)); + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + /* Call function */ + ret = dpa_classif_table_create(&kparam.table_params, + &kparam.td); + if (ret < 0) + return ret; + + /* Return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.td = kparam.td; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_set_remove_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_remove_params kparam; + struct dpa_cls_hm_remove_resources *p_res = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_remove_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_remove_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.remove_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.rm_params.fm_pcd = + translate_fm_pcd_handle(kparam.rm_params.fm_pcd); + if (!kparam.rm_params.fm_pcd) + return -EINVAL; + } + + ret = dpa_classif_set_remove_hm(&kparam.rm_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + if (ret < 0) + return ret; + + /* Return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_remove_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_remove_params kparam; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_hm_remove_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_remove_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + return dpa_classif_modify_remove_hm(kparam.hmd, &kparam.rm_params, + kparam.modify_flags); +} + +static long do_ioctl_set_insert_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_insert_params kparam; + struct dpa_cls_hm_insert_resources *p_res = NULL; + uint8_t *data = NULL; + uint8_t sz; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_insert_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_insert_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: space args.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.insert_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.ins_params.fm_pcd = + translate_fm_pcd_handle(kparam.ins_params.fm_pcd); + if (!kparam.ins_params.fm_pcd) + return -EINVAL; + } + + if (kparam.ins_params.type == DPA_CLS_HM_INSERT_CUSTOM) { + sz = kparam.ins_params.custom.size; + data = kzalloc(sz * sizeof(*data), GFP_KERNEL); + if (!data) { + pr_err("ERROR: %s, %s (%d): Failed to allocate memory " + "for data param for DPA_CLS_HM_INSERT_CUSTOM" + " parameter type.\n", + __FILE__, __func__, __LINE__); + return -ENOMEM; + } + + copy_from_user(data, kparam.ins_params.custom.data, sz); + kparam.ins_params.custom.data = data; + } + + ret = dpa_classif_set_insert_hm(&kparam.ins_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + kfree(data); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_insert_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_insert_params kparam; + uint8_t *data = NULL; + uint8_t sz; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_insert_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_insert_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.ins_params.type == DPA_CLS_HM_INSERT_CUSTOM) { + sz = kparam.ins_params.custom.size; + data = kzalloc(sz * sizeof(*data), GFP_KERNEL); + if (!data) { + pr_err("ERROR: %s, %s (%d): Failed to allocate memory " + "for data param for DPA_CLS_HM_INSERT_CUSTOM " + "parameter type.\n", + __FILE__, __func__, __LINE__); + return -ENOMEM; + } + + copy_from_user(data, kparam.ins_params.custom.data, sz); + kparam.ins_params.custom.data = data; + } + + ret = dpa_classif_modify_insert_hm(kparam.hmd, &kparam.ins_params, + kparam.modify_flags); + kfree(data); + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_set_vlan_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_vlan_params kparam; + struct dpa_cls_hm_vlan_resources *p_res = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_vlan_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_vlan_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.vlan_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.vlan_params.fm_pcd = + translate_fm_pcd_handle(kparam.vlan_params.fm_pcd); + if (!kparam.vlan_params.fm_pcd) + return -EINVAL; + } + + ret = dpa_classif_set_vlan_hm(&kparam.vlan_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; + +} + +static long do_ioctl_modify_vlan_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_vlan_params kparam; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_hm_vlan_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_vlan_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space args.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + return dpa_classif_modify_vlan_hm(kparam.hmd, &kparam.vlan_params, + kparam.modify_flags); +} + +static long do_ioctl_set_nat_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_nat_params kparam; + struct dpa_cls_hm_nat_resources *p_res = NULL; + int type; + unsigned int sz; + uint8_t *options = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_nat_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_nat_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.l3_update_node || kparam.res.l4_update_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.nat_params.fm_pcd = + translate_fm_pcd_handle(kparam.nat_params.fm_pcd); + if (!kparam.nat_params.fm_pcd) + return -EINVAL; + } + + if (kparam.nat_params.type == DPA_CLS_HM_NAT_TYPE_NAT_PT) { + type = kparam.nat_params.nat_pt.type; + if (type == DPA_CLS_HM_NAT_PT_IPv6_TO_IPv4) { + sz = kparam.nat_params.nat_pt.new_header.ipv4. + options_size; + options = kzalloc(sz * sizeof(*options), GFP_KERNEL); + if (!options) { + pr_err("ERROR: %s, %s (%d): Failed to allocate" + " memory for options param for" + " DPA_CLS_HM_NAT_TYPE_NAT_PT parameter" + " type.\n", __FILE__, __func__, + __LINE__); + return -ENOMEM; + } + copy_from_user(options, + kparam.nat_params.nat_pt.new_header. + ipv4.options, sz); + kparam.nat_params.nat_pt.new_header.ipv4.options = + options; + } + } + + ret = dpa_classif_set_nat_hm(&kparam.nat_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + kfree(options); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_nat_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_nat_params kparam; + uint8_t *options = NULL; + long ret = 0; + int type; + unsigned int sz; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_nat_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_nat_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + if (kparam.nat_params.type == DPA_CLS_HM_NAT_TYPE_NAT_PT) { + type = kparam.nat_params.nat_pt.type; + if (type == DPA_CLS_HM_NAT_PT_IPv6_TO_IPv4) { + sz = kparam.nat_params.nat_pt.new_header.ipv4. + options_size; + options = kzalloc(sz * sizeof(*options), GFP_KERNEL); + if (!options) { + pr_err("ERROR: %s, %s (%d): Failed to allocate" + " memory for options param for" + " DPA_CLS_HM_NAT_TYPE_NAT_PT parameter" + " type.\n", __FILE__, __func__, + __LINE__); + return -ENOMEM; + } + copy_from_user(options, + kparam.nat_params.nat_pt.new_header. + ipv4.options, sz); + kparam.nat_params.nat_pt.new_header.ipv4.options = + options; + } + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + ret = dpa_classif_modify_nat_hm(kparam.hmd, &kparam.nat_params, + kparam.modify_flags); + kfree(options); + + return ret; +} + +static long do_ioctl_set_update_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_update_params kparam; + struct dpa_cls_hm_update_resources *p_res = NULL; + unsigned int sz; + uint8_t *options = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_update_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_update_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.ip_frag_node || kparam.res.update_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.update_params.fm_pcd = + translate_fm_pcd_handle(kparam.update_params.fm_pcd); + if (!kparam.update_params.fm_pcd) + return -EINVAL; + } + + if (kparam.update_params.op_flags == DPA_CLS_HM_REPLACE_IPv6_BY_IPv4) { + sz = kparam.update_params.replace.new_ipv4_hdr.options_size; + options = kzalloc(sz * sizeof(*options), GFP_KERNEL); + if (!options) { + pr_err("ERROR: %s, %s (%d): Failed to allocate memory " + "for options param for" + " DPA_CLS_HM_REPLACE_IPv6_BY_IPv4" + " parameter type.\n", __FILE__, __func__, + __LINE__); + return -ENOMEM; + } + + copy_from_user(options, + kparam.update_params.replace.new_ipv4_hdr. + options, sz); + kparam.update_params.replace.new_ipv4_hdr.options = options; + } + + ret = dpa_classif_set_update_hm(&kparam.update_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + kfree(options); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_update_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_update_params kparam; + uint8_t *options = NULL; + long ret = 0; + unsigned int sz; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_update_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_update_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + if (kparam.update_params.op_flags == DPA_CLS_HM_REPLACE_IPv6_BY_IPv4) { + sz = kparam.update_params.replace.new_ipv4_hdr.options_size; + options = kzalloc(sz * sizeof(*options), GFP_KERNEL); + if (!options) { + pr_err("ERROR: %s, %s (%d): Failed to allocate memory " + "for options param for" + " DPA_CLS_HM_REPLACE_IPv6_BY_IPv4" + " parameter type.\n", __FILE__, __func__, + __LINE__); + return -ENOMEM; + } + + copy_from_user(options, + kparam.update_params.replace.new_ipv4_hdr. + options, sz); + kparam.update_params.replace.new_ipv4_hdr.options = options; + } + + ret = dpa_classif_modify_update_hm(kparam.hmd, &kparam.update_params, + kparam.modify_flags); + + kfree(options); + + return ret; +} + +static long do_ioctl_set_fwd_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_fwd_params kparam; + struct dpa_cls_hm_fwd_resources *p_res = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_fwd_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_fwd_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.ip_frag_node || kparam.res.fwd_node || + kparam.res.pppoe_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.fwd_params.fm_pcd = + translate_fm_pcd_handle(kparam.fwd_params.fm_pcd); + if (!kparam.fwd_params.fm_pcd) + return -EINVAL; + } + + ret = dpa_classif_set_fwd_hm(&kparam.fwd_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_fwd_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_fwd_params kparam; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_hm_fwd_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_fwd_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + return dpa_classif_modify_fwd_hm(kparam.hmd, &kparam.fwd_params, + kparam.modify_flags); +} + +static long do_ioctl_set_mpls_hm(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_hm_mpls_params kparam; + struct dpa_cls_hm_mpls_resources *p_res = NULL; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_hm_mpls_params uparam; + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_mpls_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + if (kparam.res.ins_rm_node) + p_res = &kparam.res; + + /* Translate FM_PCD file descriptor */ + if (!p_res) { + kparam.mpls_params.fm_pcd = + translate_fm_pcd_handle(kparam.mpls_params.fm_pcd); + if (!kparam.mpls_params.fm_pcd) + return -EINVAL; + } + + ret = dpa_classif_set_mpls_hm(&kparam.mpls_params, kparam.next_hmd, + &kparam.hmd, kparam.chain_head, + p_res); + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.hmd = kparam.hmd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_modify_mpls_hm(unsigned long args, bool compat_mode) +{ + struct ioc_dpa_cls_hm_mpls_params kparam; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_hm_mpls_params uparam; + + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_hm_mpls_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + return dpa_classif_modify_mpls_hm(kparam.hmd, &kparam.mpls_params, + kparam.modify_flags); +} + +static long do_ioctl_mcast_create_group(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_mcast_group_params kparam; + struct dpa_cls_tbl_policer_params policer_params; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_mcast_group_params uparam; + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.mcast_grp_params.first_member_params.policer_params = + &policer_params; + /* + * Transfer the data into the kernel space params: + */ + ret = dpa_cls_mcast_group_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + if (kparam.mcast_grp_params.first_member_params. + policer_params) { + if (copy_from_user(&policer_params, + kparam.mcast_grp_params. + first_member_params.policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + kparam.mcast_grp_params.first_member_params. + policer_params = + &policer_params; + } + } + /* + * Translate FM_PCD file descriptor + */ + if (!kparam.mcast_grp_params.group) { + kparam.mcast_grp_params.fm_pcd = + translate_fm_pcd_handle(kparam. + mcast_grp_params.fm_pcd); + if (!kparam.mcast_grp_params.fm_pcd) + return -EINVAL; + } + +#if (DPAA_VERSION >= 11) + ret = dpa_classif_mcast_create_group(&kparam.mcast_grp_params, + &kparam.grpd); +#else + pr_err("ERROR: %s, %s (%d): Multicast not supported on this" + "platform.\n", __FILE__, __func__, __LINE__); + return -EINVAL; +#endif + + if (ret < 0) + return ret; + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.grpd = kparam.grpd; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_mcast_add_member(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_mcast_member_params kparam; + struct dpa_cls_tbl_policer_params policer_params; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_mcast_member_params uparam; + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.member_params.policer_params = &policer_params; + /* + * Transfer the data into the kernel space params: + */ + ret = dpa_cls_mcast_member_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + if (kparam.member_params.policer_params) { + if (copy_from_user(&policer_params, + kparam.member_params.policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + + kparam.member_params.policer_params = &policer_params; + } + } +#if (DPAA_VERSION >= 11) + ret = dpa_classif_mcast_add_member(kparam.grpd, &kparam.member_params, + &kparam.md); + if (ret < 0) + return ret; +#else + pr_err("ERROR: %s, %s (%d): Multicast not supported on this" + "platform.\n", __FILE__, __func__, __LINE__); + return -EINVAL; +#endif + +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.md = kparam.md; + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + + +static long do_ioctl_table_modify_miss_action(unsigned long args, + bool compat_mode) +{ + struct ioc_dpa_cls_tbl_miss_action kparam; + struct dpa_cls_tbl_policer_params policer_params; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_tbl_miss_action uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.miss_action.enq_params.policer_params = &policer_params; + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_miss_action_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + if (kparam.miss_action.enq_params.policer_params) { + if (copy_from_user(&policer_params, + kparam.miss_action.enq_params.policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + + kparam.miss_action.enq_params.policer_params = + &policer_params; + } + } + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + /* Call function */ + return dpa_classif_table_modify_miss_action(kparam.td, + &kparam.miss_action); +} + +static long do_ioctl_table_insert_entry(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_tbl_entry_params kparam; + struct dpa_cls_tbl_policer_params policer_params; + uint8_t key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_entry_params uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.key.byte = key_buf; + kparam.key.mask = mask_buf; + kparam.key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + kparam.action.enq_params.policer_params = &policer_params; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_entry_params_compatcpy(&kparam, &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + COPY_KEY_PARAMS; + + /* Check if we need to copy also the policer params */ + if ((kparam.action.type == DPA_CLS_TBL_ACTION_ENQ) && + (kparam.action.enq_params.policer_params)) { + if (copy_from_user(&policer_params, + kparam.action.enq_params.policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + kparam.action.enq_params.policer_params = &policer_params; + } + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + /* Call function */ + ret = dpa_classif_table_insert_entry(kparam.td, + &kparam.key, + &kparam.action, + kparam.priority, + &kparam.entry_id); + if (ret < 0) + return ret; + + /* In case of success return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + uparam.entry_id = kparam.entry_id; + + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_table_modify_entry_by_key(unsigned long args, + bool compat_mode) +{ + struct ioc_dpa_cls_tbl_entry_mod_by_key kparam; + struct dpa_offload_lookup_key new_key; + struct dpa_cls_tbl_action action; + struct dpa_cls_tbl_policer_params policer_params; + uint8_t key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t new_key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t new_mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_tbl_entry_mod_by_key uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.key.byte = key_buf; + kparam.key.mask = mask_buf; + kparam.key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + new_key.byte = new_key_buf; + new_key.mask = new_mask_buf; + new_key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + kparam.mod_params.key = &new_key; + kparam.mod_params.action = &action; + kparam.mod_params.action->enq_params.policer_params = + &policer_params; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_entry_mod_by_key_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + COPY_KEY_PARAMS; + + /* Check if we need to copy the new key */ + COPY_NEW_KEY_PARAMS; + + if (kparam.mod_params.action) { + if (copy_from_user(&action, + kparam.mod_params.action, + sizeof(struct dpa_cls_tbl_action))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "new action params.\n", __FILE__, + __func__, __LINE__); + return -EBUSY; + } + kparam.mod_params.action = &action; + + /* Check if we need to copy policer params */ + if ((kparam.mod_params.action->type == + DPA_CLS_TBL_ACTION_ENQ) && + (kparam.mod_params.action->enq_params. + policer_params)) { + if (copy_from_user(&policer_params, + kparam.mod_params. + action->enq_params. + policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read " + "failed: new policer params.\n", __FILE__, + __func__, __LINE__); + return -EBUSY; + } + kparam.mod_params.action->enq_params. + policer_params = + &policer_params; + } + } + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + /* Call function */ + return dpa_classif_table_modify_entry_by_key(kparam.td, + &kparam.key, + &kparam.mod_params); + +} + +static long do_ioctl_table_modify_entry_by_ref(unsigned long args, + bool compat_mode) +{ + struct ioc_dpa_cls_tbl_entry_mod_by_ref kparam; + struct dpa_offload_lookup_key new_key; + struct dpa_cls_tbl_action action; + struct dpa_cls_tbl_policer_params policer_params; + uint8_t new_key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t new_mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_tbl_entry_mod_by_ref uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + new_key.byte = new_key_buf; + new_key.mask = new_mask_buf; + new_key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + memset(&kparam, 0, + sizeof(struct ioc_dpa_cls_tbl_entry_mod_by_ref)); + kparam.mod_params.key = &new_key; + kparam.mod_params.action = &action; + kparam.mod_params.action->enq_params.policer_params = + &policer_params; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_entry_mod_by_ref_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Check if we need to copy the new key */ + COPY_NEW_KEY_PARAMS; + + if (kparam.mod_params.action) { + if (copy_from_user(&action, + kparam.mod_params.action, + sizeof(struct dpa_cls_tbl_action))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "new action params.\n", __FILE__, + __func__, __LINE__); + return -EBUSY; + } + kparam.mod_params.action = &action; + + /* Check if we need to copy policer params */ + if ((kparam.mod_params.action->type == + DPA_CLS_TBL_ACTION_ENQ) && + (kparam.mod_params.action->enq_params. + policer_params)) { + if (copy_from_user(&policer_params, + kparam.mod_params. + action->enq_params. + policer_params, + sizeof(policer_params))) { + pr_err("ERROR: %s, %s (%d): Read " + "failed: new policer params.\n", __FILE__, + __func__, __LINE__); + return -EBUSY; + } + kparam.mod_params.action->enq_params. + policer_params = + &policer_params; + } + } + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + /* Call function */ + return dpa_classif_table_modify_entry_by_ref(kparam.td, + kparam.entry_id, + &kparam.mod_params); +} + +static long do_ioctl_table_lookup_by_key(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_tbl_lookup_by_key kparam; + uint8_t key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_lookup_by_key uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.key.byte = key_buf; + kparam.key.mask = mask_buf; + kparam.key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_lookup_by_key_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + COPY_KEY_PARAMS; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + /* Call function */ + ret = dpa_classif_table_lookup_by_key(kparam.td, + &kparam.key, + &kparam.action); + if (ret < 0) + return ret; + + /* Return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + ret = dpa_cls_tbl_action_params_rcompatcpy(&uparam.action, + &kparam.action); + if (ret < 0) + return ret; + + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_table_lookup_by_ref(unsigned long args, bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_tbl_lookup_by_ref kparam; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_lookup_by_ref uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_lookup_by_ref_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + /* Prepare arguments */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + /* Call function */ + ret = dpa_classif_table_lookup_by_ref(kparam.td, + kparam.entry_id, + &kparam.action); + if (ret < 0) + return ret; + + /* Return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + ret = dpa_cls_tbl_action_params_rcompatcpy(&uparam.action, + &kparam.action); + if (ret < 0) + return ret; + + if (copy_to_user((void *)args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +static long do_ioctl_table_delete_entry_by_key(unsigned long args, + bool compat_mode) +{ + struct ioc_dpa_cls_tbl_entry_by_key kparam; + uint8_t key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + long ret = 0; + struct compat_ioc_dpa_cls_tbl_entry_by_key uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.key.byte = key_buf; + kparam.key.mask = mask_buf; + kparam.key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_entry_by_key_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + /* Prepare arguments */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + COPY_KEY_PARAMS; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d)\n", __func__, + __LINE__)); + + /* Call function */ + return dpa_classif_table_delete_entry_by_key(kparam.td, + &kparam.key); +} + +static long do_ioctl_table_get_stats_by_key(unsigned long args, + bool compat_mode) +{ + long ret = 0; + struct ioc_dpa_cls_tbl_entry_stats_by_key kparam; + uint8_t key_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; + uint8_t mask_buf[DPA_OFFLD_MAXENTRYKEYSIZE]; +#ifdef CONFIG_COMPAT + struct compat_ioc_dpa_cls_tbl_entry_stats_by_key uparam; + + /* Prepare arguments */ + if (compat_mode) { + if (copy_from_user(&uparam, (void *) args, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user " + "space args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + kparam.key.byte = key_buf; + kparam.key.mask = mask_buf; + kparam.key.size = DPA_OFFLD_MAXENTRYKEYSIZE; + + /* Transfer the data into the kernel space params: */ + ret = dpa_cls_tbl_entry_stats_by_key_params_compatcpy(&kparam, + &uparam); + if (ret < 0) + return ret; + } else +#endif /* CONFIG_COMPAT */ + { + /* Prepare arguments */ + if (copy_from_user(&kparam, (void *) args, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Read failed: user space " + "args.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + COPY_KEY_PARAMS; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) -->\n", __func__, + __LINE__)); + + /* Call function */ + ret = dpa_classif_table_get_entry_stats_by_key(kparam.td, + &kparam.key, + &kparam.stats); + if (ret < 0) + return ret; + + /* Return results to user space */ +#ifdef CONFIG_COMPAT + if (compat_mode) { + memcpy(&uparam.stats, &kparam.stats, + sizeof(struct dpa_cls_tbl_entry_stats)); + + if (copy_to_user((void *) args, &uparam, sizeof(uparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else +#endif /* CONFIG_COMPAT */ + if (copy_to_user((void *) args, &kparam, sizeof(kparam))) { + pr_err("ERROR: %s, %s (%d): Write failed: result.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + dpa_cls_wrp_dbg(("DEBUG: classifier_wrp %s (%d) <--\n", __func__, + __LINE__)); + + return ret; +} + +void *translate_fm_pcd_handle(void *fm_pcd) +{ + struct file *fm_pcd_file; + t_LnxWrpFmDev *fm_wrapper_dev; + + fm_pcd_file = fcheck((unsigned long)fm_pcd); + if (!fm_pcd_file) { + pr_err("ERROR: %s, %s (%d): Could not translate PCD handle " + "fm_pcd=0x%p.\n", __FILE__, __func__, __LINE__, fm_pcd); + return NULL; + } + fm_wrapper_dev = (t_LnxWrpFmDev *)fm_pcd_file->private_data; + BUG_ON(!fm_wrapper_dev); + BUG_ON(!fm_wrapper_dev->h_PcdDev); + + return (void *)fm_wrapper_dev->h_PcdDev; +} + +#ifdef CONFIG_COMPAT + +int dpa_cls_tbl_entry_by_key_params_compatcpy( + struct ioc_dpa_cls_tbl_entry_by_key *kparam, + const struct compat_ioc_dpa_cls_tbl_entry_by_key *uparam) +{ + kparam->td = uparam->td; + return dpa_lookup_key_params_compatcpy(&kparam->key, &uparam->key); +} + +int dpa_cls_tbl_entry_stats_by_key_params_compatcpy( + struct ioc_dpa_cls_tbl_entry_stats_by_key *kparam, + const struct compat_ioc_dpa_cls_tbl_entry_stats_by_key *uparam) +{ + int err = 0; + + kparam->td = uparam->td; + + err = dpa_lookup_key_params_compatcpy(&kparam->key, &uparam->key); + if (err < 0) + return err; + + memcpy(&kparam->stats, + &uparam->stats, + sizeof(struct dpa_cls_tbl_entry_stats)); + + return 0; +} + +int dpa_lookup_key_params_compatcpy( + struct dpa_offload_lookup_key *kparam, + const struct compat_ioc_dpa_offld_lookup_key *uparam) +{ + BUG_ON(!uparam->byte); + BUG_ON(!kparam->byte); + BUG_ON(kparam->size < uparam->size); + BUG_ON(uparam->size <= 0); + + kparam->size = uparam->size; + if (copy_from_user(kparam->byte, compat_ptr(uparam->byte), + uparam->size)) { + pr_err("ERROR: %s, %s (%d): Read failed: lookup key.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + + if (compat_ptr(uparam->mask)) { + BUG_ON(!kparam->mask); + if (copy_from_user(kparam->mask, compat_ptr(uparam->mask), + uparam->size)) { + pr_err("ERROR: %s, %s (%d): Read failed: key mask.\n", + __FILE__, __func__, __LINE__); + return -EBUSY; + } + } else + kparam->mask = NULL; + + return 0; +} + +int dpa_cls_tbl_entry_params_compatcpy( + struct ioc_dpa_cls_tbl_entry_params *kparam, + const struct compat_ioc_dpa_cls_tbl_entry_params *uparam) +{ + int err; + + kparam->td = uparam->td; + kparam->priority = uparam->priority; + kparam->entry_id = uparam->entry_id; + + err = dpa_lookup_key_params_compatcpy(&kparam->key, &uparam->key); + if (err < 0) + return err; + + return dpa_cls_tbl_action_params_compatcpy(&kparam->action, + &uparam->action); +} + +int dpa_cls_tbl_action_params_compatcpy( + struct dpa_cls_tbl_action *kparam, + const struct dpa_cls_compat_tbl_action *uparam) +{ + kparam->type = uparam->type; + kparam->enable_statistics = uparam->enable_statistics; + + switch (uparam->type) { + case DPA_CLS_TBL_ACTION_ENQ: + kparam->enq_params.override_fqid = + uparam->enq_params.override_fqid; + kparam->enq_params.new_fqid = + uparam->enq_params.new_fqid; + kparam->enq_params.hmd = uparam->enq_params.hmd; + kparam->enq_params.new_rel_vsp_id = + uparam->enq_params.new_rel_vsp_id; + if (compat_ptr(uparam->enq_params.policer_params)) { + BUG_ON(!kparam->enq_params.policer_params); + if (copy_from_user(kparam->enq_params.policer_params, + compat_ptr(uparam->enq_params.policer_params), + sizeof(struct dpa_cls_tbl_policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + } else + kparam->enq_params.policer_params = NULL; + break; + case DPA_CLS_TBL_ACTION_NEXT_TABLE: + kparam->next_table_params.next_td = + uparam->next_table_params.next_td; + break; + case DPA_CLS_TBL_ACTION_MCAST: + kparam->mcast_params.grpd = uparam->mcast_params.grpd; + kparam->mcast_params.hmd = uparam->mcast_params.hmd; + break; + default: + break; + } + + return 0; +} + +int dpa_cls_tbl_action_params_rcompatcpy( + struct dpa_cls_compat_tbl_action *uparam, + const struct dpa_cls_tbl_action *kparam) +{ + uparam->type = kparam->type; + uparam->enable_statistics = kparam->enable_statistics; + + switch (kparam->type) { + case DPA_CLS_TBL_ACTION_ENQ: + uparam->enq_params.override_fqid = + kparam->enq_params.override_fqid; + uparam->enq_params.new_fqid = + kparam->enq_params.new_fqid; + uparam->enq_params.hmd = kparam->enq_params.hmd; + + /* + * Policer params structure address has no meaning in user + * space + */ + uparam->enq_params.policer_params = 0; + + break; + case DPA_CLS_TBL_ACTION_NEXT_TABLE: + uparam->next_table_params.next_td = + kparam->next_table_params.next_td; + break; + default: + break; + } + + return 0; +} + +int dpa_cls_tbl_params_compatcpy( + struct ioc_dpa_cls_tbl_params *kparam, + const struct compat_ioc_dpa_cls_tbl_params *uparam) +{ + kparam->table_params.cc_node = compat_get_id2ptr( + uparam->table_params.cc_node, + FM_MAP_TYPE_PCD_NODE); + if (compat_ptr(uparam->table_params.distribution)) + kparam->table_params.distribution = compat_get_id2ptr( + uparam->table_params.distribution, + FM_MAP_TYPE_PCD_NODE); + if (compat_ptr(uparam->table_params.classification)) + kparam->table_params.classification = compat_get_id2ptr( + uparam->table_params.classification, + FM_MAP_TYPE_PCD_NODE); + + kparam->table_params.type = uparam->table_params.type; + kparam->table_params.entry_mgmt = uparam->table_params.entry_mgmt; + kparam->table_params.prefilled_entries = + uparam->table_params.prefilled_entries; + + switch (uparam->table_params.type) { + case DPA_CLS_TBL_INDEXED: + memcpy(&kparam->table_params.indexed_params, + &uparam->table_params.indexed_params, + sizeof(struct dpa_cls_tbl_indexed_params)); + break; + case DPA_CLS_TBL_HASH: + memcpy(&kparam->table_params.hash_params, + &uparam->table_params.hash_params, + sizeof(struct dpa_cls_tbl_hash_params)); + + break; + case DPA_CLS_TBL_EXACT_MATCH: + memcpy(&kparam->table_params.exact_match_params, + &uparam->table_params.exact_match_params, + sizeof(struct dpa_cls_tbl_exact_match_params)); + + break; + } + + return 0; +} + +int dpa_cls_tbl_params_rcompatcpy( + struct compat_ioc_dpa_cls_tbl_params *uparam, + const struct ioc_dpa_cls_tbl_params *kparam) +{ + uparam->table_params.cc_node = compat_get_ptr2id( + kparam->table_params.cc_node, + FM_MAP_TYPE_PCD_NODE); + if (kparam->table_params.distribution) + uparam->table_params.distribution = compat_get_ptr2id( + kparam->table_params.distribution, + FM_MAP_TYPE_PCD_NODE); + if (kparam->table_params.classification) + uparam->table_params.classification = compat_get_ptr2id( + kparam->table_params.classification, + FM_MAP_TYPE_PCD_NODE); + + uparam->table_params.type = kparam->table_params.type; + uparam->table_params.entry_mgmt = kparam->table_params.entry_mgmt; + uparam->table_params.prefilled_entries = + kparam->table_params.prefilled_entries; + + switch (kparam->table_params.type) { + case DPA_CLS_TBL_INDEXED: + memcpy(&uparam->table_params.indexed_params, + &kparam->table_params.indexed_params, + sizeof(struct dpa_cls_tbl_indexed_params)); + break; + case DPA_CLS_TBL_HASH: + memcpy(&uparam->table_params.hash_params, + &kparam->table_params.hash_params, + sizeof(struct dpa_cls_tbl_hash_params)); + + break; + case DPA_CLS_TBL_EXACT_MATCH: + memcpy(&uparam->table_params.exact_match_params, + &kparam->table_params.exact_match_params, + sizeof(struct dpa_cls_tbl_exact_match_params)); + + break; + } + + return 0; +} + +int dpa_cls_tbl_miss_action_params_compatcpy( + struct ioc_dpa_cls_tbl_miss_action *kparam, + const struct compat_ioc_dpa_cls_tbl_miss_action *uparam) +{ + kparam->td = uparam->td; + + return dpa_cls_tbl_action_params_compatcpy(&kparam->miss_action, + &uparam->miss_action); +} + +int dpa_cls_tbl_entry_mod_by_key_params_compatcpy( + struct ioc_dpa_cls_tbl_entry_mod_by_key *kparam, + const struct compat_ioc_dpa_cls_tbl_entry_mod_by_key *uparam) +{ + int err; + + kparam->td = uparam->td; + + err = dpa_lookup_key_params_compatcpy(&kparam->key, &uparam->key); + if (err < 0) + return err; + + return dpa_cls_tbl_entry_mod_params_compatcpy(&kparam->mod_params, + &uparam->mod_params); +} + +int dpa_cls_tbl_entry_mod_params_compatcpy( + struct dpa_cls_tbl_entry_mod_params *kparam, + const struct dpa_cls_compat_tbl_entry_mod_params *uparam) +{ + int err = 0; + + kparam->type = uparam->type; + + if (compat_ptr(uparam->key)) { + struct compat_ioc_dpa_offld_lookup_key key; + + BUG_ON(!kparam->key); + if (copy_from_user(&key, compat_ptr(uparam->key), + sizeof(struct compat_ioc_dpa_offld_lookup_key))) { + pr_err("ERROR: %s, %s (%d): Read failed: New key " + "parameters.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + err = dpa_lookup_key_params_compatcpy(kparam->key, &key); + } else + kparam->key = NULL; + + if (err < 0) + return err; + + if (compat_ptr(uparam->action)) { + struct dpa_cls_compat_tbl_action action; + + BUG_ON(!kparam->action); + + if (copy_from_user(&action, compat_ptr(uparam->action), + sizeof(struct dpa_cls_compat_tbl_action))) { + pr_err("ERROR: %s, %s (%d): Read failed: New action " + "parameters.\n", __FILE__, __func__, __LINE__); + return -EBUSY; + } + + err = dpa_cls_tbl_action_params_compatcpy(kparam->action, + &action); + } else + kparam->action = NULL; + + return err; +} + +int dpa_cls_tbl_entry_mod_by_ref_params_compatcpy( + struct ioc_dpa_cls_tbl_entry_mod_by_ref *kparam, + const struct compat_ioc_dpa_cls_tbl_entry_mod_by_ref *uparam) +{ + kparam->td = uparam->td; + kparam->entry_id = uparam->entry_id; + + return dpa_cls_tbl_entry_mod_params_compatcpy(&kparam->mod_params, + &uparam->mod_params); +} + +int dpa_cls_tbl_lookup_by_key_params_compatcpy( + struct ioc_dpa_cls_tbl_lookup_by_key *kparam, + const struct compat_ioc_dpa_cls_tbl_lookup_by_key *uparam) +{ + kparam->td = uparam->td; + + return dpa_lookup_key_params_compatcpy(&kparam->key, &uparam->key); +} + +int dpa_cls_tbl_lookup_by_ref_params_compatcpy( + struct ioc_dpa_cls_tbl_lookup_by_ref *kparam, + const struct compat_ioc_dpa_cls_tbl_lookup_by_ref *uparam) +{ + kparam->td = uparam->td; + kparam->entry_id = uparam->entry_id; + + return 0; +} + +int dpa_cls_hm_remove_params_compatcpy( + struct ioc_dpa_cls_hm_remove_params *kparam, + const struct compat_ioc_dpa_cls_hm_remove_params *uparam) +{ + kparam->rm_params.type = uparam->rm_params.type; + memcpy(&kparam->rm_params.custom, &uparam->rm_params.custom, + sizeof(struct dpa_cls_hm_custom_rm_params)); + + kparam->rm_params.fm_pcd = compat_ptr(uparam->rm_params.fm_pcd); + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.remove_node) + kparam->res.remove_node = compat_get_id2ptr( + uparam->res.remove_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.remove_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_insert_params_compatcpy( + struct ioc_dpa_cls_hm_insert_params *kparam, + const struct compat_ioc_dpa_cls_hm_insert_params *uparam) +{ + int type; + + kparam->ins_params.type = uparam->ins_params.type; + + type = kparam->ins_params.type; + switch (type) { + case DPA_CLS_HM_INSERT_CUSTOM: + kparam->ins_params.custom.offset = uparam->ins_params. + custom.offset; + kparam->ins_params.custom.size = uparam->ins_params. + custom.size; + kparam->ins_params.custom.data = compat_ptr(uparam->ins_params. + custom.data); + break; + case DPA_CLS_HM_INSERT_ETHERNET: + memcpy(&kparam->ins_params.eth, &uparam->ins_params.eth, + sizeof(struct dpa_cls_hm_eth_ins_params)); + break; + case DPA_CLS_HM_INSERT_PPPoE: + memcpy(&kparam->ins_params.pppoe, &uparam->ins_params.pppoe, + sizeof(struct dpa_cls_hm_pppoe_ins_params)); + break; + case DPA_CLS_HM_INSERT_PPP: + kparam->ins_params.ppp_pid = uparam->ins_params.ppp_pid; + break; + default: + break; + } + + kparam->ins_params.fm_pcd = compat_ptr(uparam->ins_params.fm_pcd); + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + if (uparam->res.insert_node) + kparam->res.insert_node = compat_get_id2ptr( + uparam->res.insert_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.insert_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_vlan_params_compatcpy( + struct ioc_dpa_cls_hm_vlan_params *kparam, + const struct compat_ioc_dpa_cls_hm_vlan_params *uparam) +{ + int type; + + kparam->vlan_params.type = uparam->vlan_params.type; + type = kparam->vlan_params.type; + switch (type) { + case DPA_CLS_HM_VLAN_INGRESS: + memcpy(&kparam->vlan_params.ingress, + &uparam->vlan_params.ingress, + sizeof(struct dpa_cls_hm_ingress_vlan_params)); + break; + case DPA_CLS_HM_VLAN_EGRESS: + memcpy(&kparam->vlan_params.egress, + &uparam->vlan_params.egress, + sizeof(struct dpa_cls_hm_egress_vlan_params)); + break; + default: + break; + } + + kparam->vlan_params.fm_pcd = compat_ptr(uparam->vlan_params.fm_pcd); + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.vlan_node) + kparam->res.vlan_node = compat_get_id2ptr( + uparam->res.vlan_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.vlan_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_nat_params_compatcpy( + struct ioc_dpa_cls_hm_nat_params *kparam, + const struct compat_ioc_dpa_cls_hm_nat_params *uparam) +{ + int type; + kparam->nat_params.flags = uparam->nat_params.flags; + kparam->nat_params.proto = uparam->nat_params.proto; + kparam->nat_params.type = uparam->nat_params.type; + + if (kparam->nat_params.type == DPA_CLS_HM_NAT_TYPE_NAT_PT) { + kparam->nat_params.nat_pt.type = uparam->nat_params.nat_pt.type; + type = kparam->nat_params.nat_pt.type; + switch (type) { + case DPA_CLS_HM_NAT_PT_IPv6_TO_IPv4: + kparam->nat_params.nat_pt.new_header.ipv4.options_size = + uparam->nat_params.nat_pt.new_header.ipv4.options_size; + kparam->nat_params.nat_pt.new_header.ipv4.options = + compat_ptr(uparam->nat_params.nat_pt.new_header.ipv4. + options); + memcpy(&kparam->nat_params.nat_pt.new_header.ipv4. + header, &uparam->nat_params.nat_pt.new_header. + ipv4.header, sizeof(struct iphdr)); + break; + case DPA_CLS_HM_NAT_PT_IPv4_TO_IPv6: + memcpy(&kparam->nat_params.nat_pt.new_header.ipv6, + &uparam->nat_params.nat_pt.new_header.ipv6, + sizeof(struct ipv6_header)); + break; + default: + break; + } + } else if (kparam->nat_params.type == DPA_CLS_HM_NAT_TYPE_TRADITIONAL) + memcpy(&kparam->nat_params.nat, &uparam->nat_params.nat, + sizeof(struct dpa_cls_hm_traditional_nat_params)); + + kparam->nat_params.fm_pcd = compat_ptr(uparam->nat_params.fm_pcd); + kparam->nat_params.sport = uparam->nat_params.sport; + kparam->nat_params.dport = uparam->nat_params.dport; + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.l3_update_node) + kparam->res.l3_update_node = compat_get_id2ptr( + uparam->res.l3_update_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.l3_update_node = NULL; + + if (uparam->res.l4_update_node) + kparam->res.l4_update_node = compat_get_id2ptr( + uparam->res.l4_update_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.l4_update_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_update_params_compatcpy( + struct ioc_dpa_cls_hm_update_params *kparam, + const struct compat_ioc_dpa_cls_hm_update_params *uparam) +{ + int op_flags; + + kparam->update_params.op_flags = uparam->update_params.op_flags; + op_flags = kparam->update_params.op_flags; + memcpy(&kparam->update_params.update, &uparam->update_params.update, + sizeof(kparam->update_params.update)); + memcpy(&kparam->update_params.ip_frag_params, + &uparam->update_params.ip_frag_params, + sizeof(kparam->update_params.ip_frag_params)); + + switch (op_flags) { + case DPA_CLS_HM_REPLACE_IPv4_BY_IPv6: + memcpy(&kparam->update_params.replace.new_ipv6_hdr, + &uparam->update_params.replace.new_ipv6_hdr, + sizeof(struct ipv6_header)); + break; + case DPA_CLS_HM_REPLACE_IPv6_BY_IPv4: + kparam->update_params.replace.new_ipv4_hdr.options_size = + uparam->update_params.replace.new_ipv4_hdr.options_size; + kparam->update_params.replace.new_ipv4_hdr.options = + compat_ptr(uparam->update_params.replace.new_ipv4_hdr. + options); + memcpy(&kparam->update_params.replace.new_ipv4_hdr.header, + &uparam->update_params.replace.new_ipv4_hdr.header, + sizeof(struct iphdr)); + break; + default: + break; + } + + + kparam->update_params.fm_pcd = compat_ptr(uparam->update_params.fm_pcd); + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.update_node) + kparam->res.update_node = compat_get_id2ptr( + uparam->res.update_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.update_node = NULL; + + if (uparam->res.ip_frag_node) + kparam->res.ip_frag_node = compat_get_id2ptr( + uparam->res.ip_frag_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.ip_frag_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_fwd_params_compatcpy( + struct ioc_dpa_cls_hm_fwd_params *kparam, + const struct compat_ioc_dpa_cls_hm_fwd_params *uparam) +{ + int type; + + kparam->fwd_params.out_if_type = uparam->fwd_params.out_if_type; + kparam->fwd_params.fm_pcd = compat_ptr(uparam->fwd_params.fm_pcd); + + type = kparam->fwd_params.out_if_type; + switch (type) { + case DPA_CLS_HM_IF_TYPE_ETHERNET: + memcpy(&kparam->fwd_params.eth, &uparam->fwd_params.eth, + sizeof(struct dpa_cls_hm_fwd_l2_param)); + break; + case DPA_CLS_HM_IF_TYPE_PPPoE: + memcpy(&kparam->fwd_params.pppoe, &uparam->fwd_params.pppoe, + sizeof(struct dpa_cls_hm_fwd_pppoe_param)); + break; + case DPA_CLS_HM_IF_TYPE_PPP: + memcpy(&kparam->fwd_params.ppp, &uparam->fwd_params.ppp, + sizeof(struct dpa_cls_hm_fwd_ppp_param)); + break; + default: + break; + } + + memcpy(&kparam->fwd_params.ip_frag_params, + &uparam->fwd_params.ip_frag_params, + sizeof(struct dpa_cls_hm_ip_frag_params)); + + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.fwd_node) + kparam->res.fwd_node = compat_get_id2ptr(uparam->res.fwd_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.fwd_node = NULL; + + if (uparam->res.pppoe_node) + kparam->res.pppoe_node = compat_get_id2ptr( + uparam->res.pppoe_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.pppoe_node = NULL; + + if (uparam->res.ip_frag_node) + kparam->res.ip_frag_node = compat_get_id2ptr( + uparam->res.ip_frag_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.ip_frag_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_hm_mpls_params_compatcpy( + struct ioc_dpa_cls_hm_mpls_params *kparam, + const struct compat_ioc_dpa_cls_hm_mpls_params *uparam) +{ + kparam->mpls_params.type = uparam->mpls_params.type; + memcpy(kparam->mpls_params.mpls_hdr, uparam->mpls_params.mpls_hdr, + sizeof(struct mpls_header) * DPA_CLS_HM_MAX_MPLS_LABELS); + kparam->mpls_params.num_labels = uparam->mpls_params.num_labels; + kparam->mpls_params.fm_pcd = compat_ptr(uparam->mpls_params.fm_pcd); + kparam->next_hmd = uparam->next_hmd; + kparam->hmd = uparam->hmd; + + if (uparam->res.ins_rm_node) + kparam->res.ins_rm_node = compat_get_id2ptr( + uparam->res.ins_rm_node, + FM_MAP_TYPE_PCD_NODE); + else + kparam->res.ins_rm_node = NULL; + + kparam->chain_head = uparam->chain_head; + kparam->modify_flags = uparam->modify_flags; + + return 0; +} + +int dpa_cls_mcast_group_params_compatcpy( + struct ioc_dpa_cls_mcast_group_params *kparam, + const struct compat_ioc_dpa_cls_mcast_group_params *uparam) +{ + kparam->mcast_grp_params.max_members = + uparam->mcast_grp_params.max_members; + kparam->mcast_grp_params.fm_pcd = compat_ptr(uparam->mcast_grp_params. + fm_pcd); + kparam->mcast_grp_params.first_member_params.override_fqid = + uparam->mcast_grp_params.first_member_params.override_fqid; + kparam->mcast_grp_params.first_member_params.new_fqid = + uparam->mcast_grp_params.first_member_params.new_fqid; + kparam->mcast_grp_params.first_member_params.new_rel_vsp_id = + uparam->mcast_grp_params.first_member_params.new_rel_vsp_id; + if (compat_ptr(uparam->mcast_grp_params.first_member_params. + policer_params)) { + if (copy_from_user(kparam->mcast_grp_params.first_member_params. + policer_params, + compat_ptr(uparam->mcast_grp_params.first_member_params. + policer_params), + sizeof(struct dpa_cls_tbl_policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + } else + kparam->mcast_grp_params.first_member_params.policer_params = + NULL; + + kparam->mcast_grp_params.first_member_params.hmd = + uparam->mcast_grp_params.first_member_params.hmd; + kparam->mcast_grp_params.prefilled_members = + uparam->mcast_grp_params.prefilled_members; + + if (uparam->mcast_grp_params.group) + kparam->mcast_grp_params.group = compat_get_id2ptr( + uparam->mcast_grp_params.group, + FM_MAP_TYPE_PCD_NODE); + else + kparam->mcast_grp_params.group = NULL; + + if (compat_ptr(uparam->mcast_grp_params.distribution)) + kparam->mcast_grp_params.distribution = compat_get_id2ptr( + uparam->mcast_grp_params.distribution, + FM_MAP_TYPE_PCD_NODE); + else + kparam->mcast_grp_params.distribution = NULL; + + if (compat_ptr(uparam->mcast_grp_params.classification)) + kparam->mcast_grp_params.classification = compat_get_id2ptr( + uparam->mcast_grp_params.classification, + FM_MAP_TYPE_PCD_NODE); + else + kparam->mcast_grp_params.classification = NULL; + + return 0; +} + +int dpa_cls_mcast_member_params_compatcpy( + struct ioc_dpa_cls_mcast_member_params *kparam, + const struct compat_ioc_dpa_cls_mcast_member_params *uparam) +{ + kparam->grpd = uparam->grpd; + kparam->member_params.hmd = uparam->member_params.hmd; + kparam->member_params.new_fqid = uparam->member_params.new_fqid; + kparam->member_params.override_fqid = + uparam->member_params.override_fqid; + kparam->member_params.new_rel_vsp_id = + uparam->member_params.new_rel_vsp_id; + if (compat_ptr(uparam->member_params.policer_params)) { + if (copy_from_user(kparam->member_params.policer_params, + compat_ptr(uparam->member_params.policer_params), + sizeof(struct dpa_cls_tbl_policer_params))) { + pr_err("ERROR: %s, %s (%d): Read failed: " + "policer params.\n", __FILE__, __func__, + __LINE__); + return -EBUSY; + } + } else + kparam->member_params.policer_params = NULL; + + return 0; +} + +#endif /* CONFIG_COMPAT */ |