On Thu, Jul 14, 2016 at 7:28 AM, Amir Levy <amir.jer.l...@intel.com> wrote:
> Negotiation states that a peer goes through in order to establish
> the communication with the second peer.
> This includes communication with upper layer and additional
> infrastructure support to communicate with the second peer through ICM.
>
> Signed-off-by: Amir Levy <amir.jer.l...@intel.com>
> ---
>  drivers/thunderbolt/icm/Makefile  |   2 +-
>  drivers/thunderbolt/icm/icm_nhi.c | 304 ++++++++++++++-
>  drivers/thunderbolt/icm/net.c     | 802 
> ++++++++++++++++++++++++++++++++++++++
>  drivers/thunderbolt/icm/net.h     |  74 ++++
>  4 files changed, 1171 insertions(+), 11 deletions(-)
>  create mode 100644 drivers/thunderbolt/icm/net.c
>
> diff --git a/drivers/thunderbolt/icm/Makefile 
> b/drivers/thunderbolt/icm/Makefile
> index 3adfc35..624ee31 100644
> --- a/drivers/thunderbolt/icm/Makefile
> +++ b/drivers/thunderbolt/icm/Makefile
> @@ -25,4 +25,4 @@
>  
> ################################################################################
>
>  obj-${CONFIG_THUNDERBOLT_ICM} += thunderbolt-icm.o
> -thunderbolt-icm-objs := icm_nhi.o
> +thunderbolt-icm-objs := icm_nhi.o net.o
> diff --git a/drivers/thunderbolt/icm/icm_nhi.c 
> b/drivers/thunderbolt/icm/icm_nhi.c
> index 9d178a5..060bb38 100644
> --- a/drivers/thunderbolt/icm/icm_nhi.c
> +++ b/drivers/thunderbolt/icm/icm_nhi.c
> @@ -101,6 +101,12 @@ static const struct nla_policy 
> nhi_genl_policy[NHI_ATTR_MAX + 1] = {
>                                         .len = TBT_ICM_RING_MAX_FRAME_SIZE },
>         [NHI_ATTR_MSG_FROM_ICM]         = { .type = NLA_BINARY,
>                                         .len = TBT_ICM_RING_MAX_FRAME_SIZE },
> +       [NHI_ATTR_LOCAL_ROUTE_STRING]   = {.len = sizeof(struct 
> route_string)},
> +       [NHI_ATTR_LOCAL_UNIQUE_ID]      = { .len = sizeof(unique_id) },
> +       [NHI_ATTR_REMOTE_UNIQUE_ID]     = { .len = sizeof(unique_id) },
> +       [NHI_ATTR_LOCAL_DEPTH]          = { .type = NLA_U8, },
> +       [NHI_ATTR_ENABLE_FULL_E2E]      = { .type = NLA_FLAG, },
> +       [NHI_ATTR_MATCH_FRAME_ID]       = { .type = NLA_FLAG, },
>  };
>
>  /* NHI genetlink family */
> @@ -531,6 +537,29 @@ int nhi_mailbox(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd, 
> u32 data, bool deinit)
>         return 0;
>  }
>
> +static inline bool nhi_is_path_disconnected(u32 cmd, u8 num_ports)
> +{
> +       return (cmd >= DISCONNECT_PORT_A_INTER_DOMAIN_PATH &&
> +               cmd < (DISCONNECT_PORT_A_INTER_DOMAIN_PATH + num_ports));
> +}
> +
> +static int nhi_mailbox_disconn_path(struct tbt_nhi_ctxt *nhi_ctxt, u32 cmd)
> +       __releases(&controllers_list_rwsem)
> +{
> +       struct port_net_dev *port;
> +       u32 port_num = cmd - DISCONNECT_PORT_A_INTER_DOMAIN_PATH;
> +
> +       port = &(nhi_ctxt->net_devices[port_num]);
> +       mutex_lock(&port->state_mutex);
> +
> +       up_read(&controllers_list_rwsem);
> +       port->medium_sts = MEDIUM_READY_FOR_APPROVAL;
> +       if (port->net_dev)
> +               negotiation_events(port->net_dev, MEDIUM_DISCONNECTED);
> +       mutex_unlock(&port->state_mutex);
> +       return  0;
> +}
> +
>  static int nhi_mailbox_generic(struct tbt_nhi_ctxt *nhi_ctxt, u32 mb_cmd)
>         __releases(&controllers_list_rwsem)
>  {
> @@ -579,13 +608,93 @@ static int nhi_genl_mailbox(__always_unused struct 
> sk_buff *u_skb,
>         down_read(&controllers_list_rwsem);
>
>         nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
> -       if (nhi_ctxt && !nhi_ctxt->d0_exit)
> -               return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
> +       if (nhi_ctxt && !nhi_ctxt->d0_exit) {
> +
> +               /* rwsem is released later by the below functions */
> +               if (nhi_is_path_disconnected(cmd, nhi_ctxt->num_ports))
> +                       return nhi_mailbox_disconn_path(nhi_ctxt, cmd);
> +               else
> +                       return nhi_mailbox_generic(nhi_ctxt, mb_cmd);
> +
> +       }
>
>         up_read(&controllers_list_rwsem);
>         return -ENODEV;
>  }
>
> +static int nhi_genl_approve_networking(__always_unused struct sk_buff *u_skb,
> +                                      struct genl_info *info)
> +{
> +       struct tbt_nhi_ctxt *nhi_ctxt;
> +       struct route_string *route_str;
> +       int res = -ENODEV;
> +       u8 port_num;
> +
> +       if (!info || !info->userhdr || !info->attrs ||
> +           !info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING] ||
> +           !info->attrs[NHI_ATTR_LOCAL_UNIQUE_ID] ||
> +           !info->attrs[NHI_ATTR_REMOTE_UNIQUE_ID] ||
> +           !info->attrs[NHI_ATTR_LOCAL_DEPTH])
> +               return -EINVAL;
> +
> +       /*
> +        * route_str is an unique topological address
> +        * used for approving remote controller
> +        */
> +       route_str = nla_data(info->attrs[NHI_ATTR_LOCAL_ROUTE_STRING]);
> +       /* extracts the port we're connected to */
> +       port_num = PORT_NUM_FROM_LINK(L0_PORT_NUM(route_str->lo));
> +
> +       down_read(&controllers_list_rwsem);
> +
> +       nhi_ctxt = nhi_search_ctxt(*(u32 *)info->userhdr);
> +       if (nhi_ctxt && !nhi_ctxt->d0_exit) {
> +               struct port_net_dev *port;
> +
> +               if (port_num >= nhi_ctxt->num_ports) {
> +                       res = -EINVAL;
> +                       goto free_ctl_list;
> +               }
> +
> +               port = &(nhi_ctxt->net_devices[port_num]);
> +
> +               mutex_lock(&port->state_mutex);
> +               up_read(&controllers_list_rwsem);
> +
> +               if (port->medium_sts != MEDIUM_READY_FOR_APPROVAL) {
> +                       dev_info(&nhi_ctxt->pdev->dev,
> +                               "%s: controller id %#x in state %u <> 
> MEDIUM_READY_FOR_APPROVAL\n",
> +                               __func__, nhi_ctxt->id, port->medium_sts);
> +                       goto unlock;
> +               }
> +
> +               port->medium_sts = MEDIUM_READY_FOR_CONNECTION;
> +
> +               if (!port->net_dev) {
> +                       port->net_dev = nhi_alloc_etherdev(nhi_ctxt, port_num,
> +                                                          info);
> +                       if (!port->net_dev) {
> +                               mutex_unlock(&port->state_mutex);
> +                               return -ENOMEM;
> +                       }
> +               } else {
> +                       nhi_update_etherdev(nhi_ctxt, port->net_dev, info);
> +
> +                       negotiation_events(port->net_dev,
> +                                          MEDIUM_READY_FOR_CONNECTION);
> +               }
> +
> +unlock:
> +               mutex_unlock(&port->state_mutex);
> +
> +               return 0;
> +       }
> +
> +free_ctl_list:
> +       up_read(&controllers_list_rwsem);
> +
> +       return res;
> +}
>
>  static int nhi_genl_send_msg(struct tbt_nhi_ctxt *nhi_ctxt, enum pdf_value 
> pdf,
>                              const u8 *msg, u32 msg_len)
> @@ -635,17 +744,169 @@ genl_put_reply_failure:
>         return res;
>  }
>
> +static bool nhi_handle_inter_domain_msg(struct tbt_nhi_ctxt *nhi_ctxt,
> +                                       struct thunderbolt_ip_header *hdr)
> +{
> +       struct port_net_dev *port;
> +       u8 port_num;
> +
> +       const unique_id_be proto_uuid = APPLE_THUNDERBOLT_IP_PROTOCOL_UUID;
> +
> +       if (memcmp(proto_uuid, hdr->apple_tbt_ip_proto_uuid,
> +                  sizeof(proto_uuid)) != 0) {
> +               dev_dbg(&nhi_ctxt->pdev->dev,
> +                       "controller id %#x XDomain discovery message\n",
> +                       nhi_ctxt->id);
> +               return true;
> +       }
> +
> +       dev_dbg(&nhi_ctxt->pdev->dev,
> +               "controller id %#x ThunderboltIP %u\n",
> +               nhi_ctxt->id, be32_to_cpu(hdr->packet_type));
> +
> +       port_num = PORT_NUM_FROM_LINK(
> +                               L0_PORT_NUM(be32_to_cpu(hdr->route_str.lo)));
> +
> +       if (unlikely(port_num >= nhi_ctxt->num_ports)) {
> +               dev_err(&nhi_ctxt->pdev->dev,
> +                       "controller id %#x invalid port %u in ThunderboltIP 
> message\n",
> +                       nhi_ctxt->id, port_num);
> +               return false;
> +       }
> +
> +       port = &(nhi_ctxt->net_devices[port_num]);
> +       mutex_lock(&port->state_mutex);
> +       if (likely(port->net_dev != NULL))
> +               negotiation_messages(port->net_dev, hdr);
> +       else
> +               dev_notice(&nhi_ctxt->pdev->dev,
> +                          "controller id %#x port %u in ThunderboltIP 
> message was not initialized\n",
> +                          nhi_ctxt->id, port_num);
> +       mutex_unlock(&port->state_mutex);
> +
> +       return false;
> +}
> +
> +static void nhi_handle_notification_msg(struct tbt_nhi_ctxt *nhi_ctxt,
> +                                       const u8 *msg)
> +{
> +       struct port_net_dev *port;
> +       u8 port_num;
> +
> +#define INTER_DOMAIN_LINK_SHIFT 0
> +#define INTER_DOMAIN_LINK_MASK GENMASK(2, INTER_DOMAIN_LINK_SHIFT)
> +       switch (msg[3]) {
> +
> +       case NC_INTER_DOMAIN_CONNECTED:
> +               port_num = PORT_NUM_FROM_MSG(msg[5]);
> +#define INTER_DOMAIN_APPROVED BIT(3)
> +               if (likely(port_num < nhi_ctxt->num_ports)) {
> +                       if (!(msg[5] & INTER_DOMAIN_APPROVED))
> +                               nhi_ctxt->net_devices[
> +                                       port_num].medium_sts =
> +                                    MEDIUM_READY_FOR_APPROVAL;
> +               } else {
> +                       dev_err(&nhi_ctxt->pdev->dev,
> +                               "controller id %#x invalid port %u in inter 
> domain connected message\n",
> +                               nhi_ctxt->id, port_num);
> +               }
> +               break;
> +
> +       case NC_INTER_DOMAIN_DISCONNECTED:
> +               port_num = PORT_NUM_FROM_MSG(msg[5]);
> +
> +               if (unlikely(port_num >= nhi_ctxt->num_ports)) {
> +                       dev_err(&nhi_ctxt->pdev->dev,
> +                               "controller id %#x invalid port %u in inter 
> domain disconnected message\n",
> +                               nhi_ctxt->id, port_num);
> +                       break;
> +               }
> +
> +               port = &(nhi_ctxt->net_devices[port_num]);
> +               mutex_lock(&port->state_mutex);
> +               port->medium_sts = MEDIUM_DISCONNECTED;
> +
> +               if (likely(port->net_dev != NULL))
> +                       negotiation_events(port->net_dev,
> +                                          MEDIUM_DISCONNECTED);
> +               else
> +                       dev_notice(&nhi_ctxt->pdev->dev,
> +                                  "controller id %#x port %u in inter domain 
> disconnected message was not initialized\n",
> +                                  nhi_ctxt->id, port_num);
> +               mutex_unlock(&port->state_mutex);
> +               break;
> +       }
> +}
> +
> +static bool nhi_handle_icm_response_msg(struct tbt_nhi_ctxt *nhi_ctxt,
> +                                       const u8 *msg)
> +{
> +       struct port_net_dev *port;
> +       bool send_event = true;
> +       u8 port_num;
> +
> +       if (nhi_ctxt->ignore_icm_resp &&
> +           msg[3] == RC_INTER_DOMAIN_PKT_SENT) {
> +               nhi_ctxt->ignore_icm_resp = false;
> +               send_event = false;
> +       }
> +       if (nhi_ctxt->wait_for_icm_resp) {
> +               nhi_ctxt->wait_for_icm_resp = false;
> +               up(&nhi_ctxt->send_sem);
> +       }
> +
> +       if (msg[3] == RC_APPROVE_INTER_DOMAIN_CONNEXION) {
> +#define APPROVE_INTER_DOMAIN_ERROR BIT(0)
> +               if (unlikely(msg[2] & APPROVE_INTER_DOMAIN_ERROR)) {
> +                       dev_err(&nhi_ctxt->pdev->dev,
> +                               "controller id %#x inter domain approve 
> error\n",
> +                               nhi_ctxt->id);
> +                       return send_event;
> +               }
> +               port_num = 
> PORT_NUM_FROM_LINK((msg[5]&INTER_DOMAIN_LINK_MASK)>>
> +                                              INTER_DOMAIN_LINK_SHIFT);
> +
> +               if (unlikely(port_num >= nhi_ctxt->num_ports)) {
> +                       dev_err(&nhi_ctxt->pdev->dev,
> +                               "controller id %#x invalid port %u in inter 
> domain approve message\n",
> +                               nhi_ctxt->id, port_num);
> +                       return send_event;
> +               }
> +
> +               port = &(nhi_ctxt->net_devices[port_num]);
> +               mutex_lock(&port->state_mutex);
> +               port->medium_sts = MEDIUM_CONNECTED;
> +
> +               if (likely(port->net_dev != NULL))
> +                       negotiation_events(port->net_dev, MEDIUM_CONNECTED);
> +               else
> +                       dev_err(&nhi_ctxt->pdev->dev,
> +                               "controller id %#x port %u in inter domain 
> approve message was not initialized\n",
> +                               nhi_ctxt->id, port_num);
> +               mutex_unlock(&port->state_mutex);
> +       }
> +
> +       return send_event;
> +}
> +
>  static bool nhi_msg_from_icm_analysis(struct tbt_nhi_ctxt *nhi_ctxt,
>                                         enum pdf_value pdf,
>                                         const u8 *msg, u32 msg_len)
>  {
> -       /*
> -        * preparation for messages that won't be sent,
> -        * currently unused in this patch.
> -        */
>         bool send_event = true;
>
>         switch (pdf) {
> +       case PDF_INTER_DOMAIN_REQUEST:
> +       case PDF_INTER_DOMAIN_RESPONSE:
> +               send_event = nhi_handle_inter_domain_msg(
> +                                       nhi_ctxt,
> +                                       (struct thunderbolt_ip_header *)msg);
> +               break;
> +
> +       case PDF_FW_TO_SW_NOTIFICATION:
> +               nhi_handle_notification_msg(nhi_ctxt, msg);
> +               break;
> +
>         case PDF_ERROR_NOTIFICATION:
>                 dev_err(&nhi_ctxt->pdev->dev,
>                         "controller id %#x PDF_ERROR_NOTIFICATION %hhu msg 
> len %u\n",
> @@ -661,10 +922,7 @@ static bool nhi_msg_from_icm_analysis(struct 
> tbt_nhi_ctxt *nhi_ctxt,
>                 break;
>
>         case PDF_FW_TO_SW_RESPONSE:
> -               if (nhi_ctxt->wait_for_icm_resp) {
> -                       nhi_ctxt->wait_for_icm_resp = false;
> -                       up(&nhi_ctxt->send_sem);
> -               }
> +               send_event = nhi_handle_icm_response_msg(nhi_ctxt, msg);
>                 break;
>
>         default:
> @@ -869,6 +1127,12 @@ static const struct genl_ops nhi_ops[] = {
>                 .doit = nhi_genl_mailbox,
>                 .flags = GENL_ADMIN_PERM,
>         },
> +       {
> +               .cmd = NHI_CMD_APPROVE_TBT_NETWORKING,
> +               .policy = nhi_genl_policy,
> +               .doit = nhi_genl_approve_networking,
> +               .flags = GENL_ADMIN_PERM,
> +       },
>  };
>
>  static int nhi_suspend(struct device *dev) __releases(&nhi_ctxt->send_sem)
> @@ -876,6 +1140,17 @@ static int nhi_suspend(struct device *dev) 
> __releases(&nhi_ctxt->send_sem)
>         struct tbt_nhi_ctxt *nhi_ctxt = pci_get_drvdata(to_pci_dev(dev));
>         void __iomem *rx_reg, *tx_reg;
>         u32 rx_reg_val, tx_reg_val;
> +       int i;
> +
> +       for (i = 0; i < nhi_ctxt->num_ports; i++) {
> +               struct port_net_dev *port = &nhi_ctxt->net_devices[i];
> +
> +               mutex_lock(&port->state_mutex);
> +               port->medium_sts = MEDIUM_DISCONNECTED;
> +               if (port->net_dev)
> +                       negotiation_events(port->net_dev, 
> MEDIUM_DISCONNECTED);
> +               mutex_unlock(&port->state_mutex);
> +       }
>
>         /* must be after negotiation_events, since messages might be sent */
>         nhi_ctxt->d0_exit = true;
> @@ -1035,6 +1310,15 @@ static void icm_nhi_remove(struct pci_dev *pdev)
>
>         nhi_suspend(&pdev->dev);
>
> +       for (i = 0; i < nhi_ctxt->num_ports; i++) {
> +               mutex_lock(&nhi_ctxt->net_devices[i].state_mutex);
> +               if (nhi_ctxt->net_devices[i].net_dev) {
> +                       
> nhi_dealloc_etherdev(nhi_ctxt->net_devices[i].net_dev);
> +                       nhi_ctxt->net_devices[i].net_dev = NULL;
> +               }
> +               mutex_unlock(&nhi_ctxt->net_devices[i].state_mutex);
> +       }
> +
>         if (nhi_ctxt->net_workqueue)
>                 destroy_workqueue(nhi_ctxt->net_workqueue);
>
> diff --git a/drivers/thunderbolt/icm/net.c b/drivers/thunderbolt/icm/net.c
> new file mode 100644
> index 0000000..e983dfb
> --- /dev/null
> +++ b/drivers/thunderbolt/icm/net.c
> @@ -0,0 +1,802 @@
> +/*******************************************************************************
> + *
> + * Intel Thunderbolt(TM) driver
> + * Copyright(c) 2014 - 2016 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + *
> + * Contact Information:
> + * Intel Thunderbolt Mailing List <thunderbolt-softw...@lists.01.org>
> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
> + *
> + 
> ******************************************************************************/
> +
> +#include <linux/module.h>

I did not see anything like module_init in this driver;  I think it
seems like you
want linux/moduleparam.h here.

Thanks,
Paul.

--

> +#include <linux/etherdevice.h>
> +#include <linux/crc32.h>
> +#include <linux/prefetch.h>
> +#include <linux/highmem.h>
> +#include <linux/if_vlan.h>
> +#include <linux/jhash.h>
> +#include <linux/vmalloc.h>
> +#include <net/ip6_checksum.h>
> +#include "icm_nhi.h"
> +#include "net.h"
>

Reply via email to