From: Johannes Berg <johannes.berg@xxxxxxxxx> Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> --- drivers/net/wwan/iosm/iosm_ipc_imem_ops.h | 1 - drivers/net/wwan/iosm/iosm_ipc_pcie.c | 7 - drivers/net/wwan/iosm/iosm_ipc_pcie.h | 2 - drivers/net/wwan/iosm/iosm_ipc_wwan.c | 310 +++++++--------------- include/uapi/linux/if_link.h | 10 - tools/include/uapi/linux/if_link.h | 10 - 6 files changed, 103 insertions(+), 237 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h index 6677a82be77b..84087cf33329 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h @@ -29,7 +29,6 @@ /* IP MUX channel range */ #define IP_MUX_SESSION_START 1 #define IP_MUX_SESSION_END 8 -#define MAX_IP_MUX_SESSION IP_MUX_SESSION_END /** * ipc_imem_sys_port_open - Open a port link to CP. diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c index 0c26047ebc1c..ac6baddfde61 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.c +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c @@ -567,18 +567,11 @@ static int __init iosm_ipc_driver_init(void) return -1; } - if (rtnl_link_register(&iosm_netlink)) { - pr_err("IOSM RTNL register failed"); - pci_unregister_driver(&iosm_ipc_driver); - return -1; - } - return 0; } static void __exit iosm_ipc_driver_exit(void) { - rtnl_link_unregister(&iosm_netlink); pci_unregister_driver(&iosm_ipc_driver); } diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.h b/drivers/net/wwan/iosm/iosm_ipc_pcie.h index 839809fee3dd..7d1f0cd7364c 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.h +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.h @@ -12,8 +12,6 @@ #include "iosm_ipc_irq.h" -extern struct rtnl_link_ops iosm_netlink; - /* Device ID */ #define INTEL_CP_DEVICE_7560_ID 0x7560 diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c index 719c88d9b2e9..daf3d36edc4e 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c +++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c @@ -6,8 +6,7 @@ #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <linux/if_link.h> -#include <net/rtnetlink.h> - +#include <linux/wwan.h> #include "iosm_ipc_chnl_cfg.h" #include "iosm_ipc_imem_ops.h" #include "iosm_ipc_wwan.h" @@ -18,65 +17,52 @@ #define IOSM_IF_ID_PAYLOAD 2 -static struct device_type wwan_type = { .name = "wwan" }; - -static const struct nla_policy ipc_wwan_policy[IFLA_IOSM_MAX + 1] = { - [IFLA_IOSM_IF_ID] = { .type = NLA_U16 }, -}; - /** - * struct iosm_net_link - This structure includes information about interface - * dev. + * struct iosm_netdev_priv - netdev private data * @if_id: Interface id for device. * @ch_id: IPC channel number for which interface device is created. - * @netdev: Pointer to network interface device structure * @ipc_wwan: Pointer to iosm_wwan struct */ - -struct iosm_net_link { +struct iosm_netdev_priv { + struct iosm_wwan *ipc_wwan; + struct net_device *netdev; int if_id; int ch_id; - struct net_device *netdev; - struct iosm_wwan *ipc_wwan; }; /** * struct iosm_wwan - This structure contains information about WWAN root device - * and interface to the IPC layer. - * @netdev: Pointer to network interface device structure. - * @sub_netlist: List of netlink interfaces + * and interface to the IPC layer. * @ipc_imem: Pointer to imem data-struct + * @sub_netlist: List of active netdevs * @dev: Pointer device structure * @if_mutex: Mutex used for add and remove interface id - * @is_registered: Registration status with netdev */ struct iosm_wwan { - struct net_device *netdev; - struct iosm_net_link __rcu *sub_netlist[MAX_IP_MUX_SESSION]; struct iosm_imem *ipc_imem; + struct iosm_netdev_priv __rcu *sub_netlist[IP_MUX_SESSION_END + 1]; struct device *dev; struct mutex if_mutex; /* Mutex used for add and remove interface id */ - u8 is_registered:1; }; /* Bring-up the wwan net link */ static int ipc_wwan_link_open(struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); - struct iosm_wwan *ipc_wwan = netlink->ipc_wwan; - int if_id = netlink->if_id; - int ret = -EINVAL; + struct iosm_netdev_priv *priv = netdev_priv(netdev); + struct iosm_wwan *ipc_wwan = priv->ipc_wwan; + int if_id = priv->if_id; + int ret; - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) - return ret; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; mutex_lock(&ipc_wwan->if_mutex); /* get channel id */ - netlink->ch_id = - ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id); + priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id); - if (netlink->ch_id < 0) { + if (priv->ch_id < 0) { dev_err(ipc_wwan->dev, "cannot connect wwan0 & id %d to the IPC mem layer", if_id); @@ -88,7 +74,7 @@ static int ipc_wwan_link_open(struct net_device *netdev) netif_start_queue(netdev); dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d", - netlink->ch_id, netlink->if_id); + priv->ch_id, priv->if_id); ret = 0; out: @@ -99,14 +85,15 @@ static int ipc_wwan_link_open(struct net_device *netdev) /* Bring-down the wwan net link */ static int ipc_wwan_link_stop(struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); + struct iosm_netdev_priv *priv = netdev_priv(netdev); netif_stop_queue(netdev); - mutex_lock(&netlink->ipc_wwan->if_mutex); - ipc_imem_sys_wwan_close(netlink->ipc_wwan->ipc_imem, netlink->if_id, - netlink->ch_id); - mutex_unlock(&netlink->ipc_wwan->if_mutex); + mutex_lock(&priv->ipc_wwan->if_mutex); + ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id, + priv->ch_id); + priv->ch_id = -1; + mutex_unlock(&priv->ipc_wwan->if_mutex); return 0; } @@ -115,20 +102,21 @@ static int ipc_wwan_link_stop(struct net_device *netdev) static int ipc_wwan_link_transmit(struct sk_buff *skb, struct net_device *netdev) { - struct iosm_net_link *netlink = netdev_priv(netdev); - struct iosm_wwan *ipc_wwan = netlink->ipc_wwan; - int if_id = netlink->if_id; - int ret = -EINVAL; + struct iosm_netdev_priv *priv = netdev_priv(netdev); + struct iosm_wwan *ipc_wwan = priv->ipc_wwan; + int if_id = priv->if_id; + int ret; /* Interface IDs from 1 to 8 are for IP data * & from 257 to 261 are for non-IP data */ - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) - goto exit; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; /* Send the SKB to device for transmission */ ret = ipc_imem_sys_wwan_transmit(ipc_wwan->ipc_imem, - if_id, netlink->ch_id, skb); + if_id, priv->ch_id, skb); /* Return code of zero is success */ if (ret == 0) { @@ -175,137 +163,72 @@ static void ipc_wwan_setup(struct net_device *iosm_dev) iosm_dev->netdev_ops = &ipc_inm_ops; } -static struct device_type inm_type = { .name = "iosmdev" }; - /* Create new wwan net link */ -static int ipc_wwan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) +static int ipc_wwan_newlink(void *ctxt, struct net_device *dev, + u32 if_id, struct netlink_ext_ack *extack) { - struct iosm_net_link *netlink = netdev_priv(dev); - struct iosm_wwan *ipc_wwan; - struct net_device *netdev; - int err = -EINVAL; - int index; - - if (!data[IFLA_IOSM_IF_ID]) { - pr_err("Interface ID not specified"); - goto out; - } - - if (!tb[IFLA_LINK]) { - pr_err("Link not specified"); - goto out; - } - - netlink->netdev = dev; - - netdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); - - netlink->ipc_wwan = netdev_priv(netdev); - - ipc_wwan = netlink->ipc_wwan; + struct iosm_wwan *ipc_wwan = ctxt; + struct iosm_netdev_priv *priv; + int err; - if (ipc_wwan->netdev != netdev) - goto out; - - netlink->if_id = nla_get_u16(data[IFLA_IOSM_IF_ID]); - index = netlink->if_id; - - /* Complete all memory stores before this point */ - smp_mb(); - if (index < IP_MUX_SESSION_START || index > IP_MUX_SESSION_END) - goto out; + if (if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) + return -EINVAL; - rcu_read_lock(); + priv = netdev_priv(dev); + priv->if_id = if_id; - if (rcu_access_pointer(ipc_wwan->sub_netlist[index - 1])) { - pr_err("IOSM interface ID already in use"); - goto out_free_lock; + mutex_lock(&ipc_wwan->if_mutex); + if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id])) { + err = -EBUSY; + goto out_unlock; } - SET_NETDEV_DEVTYPE(dev, &inm_type); - - eth_hw_addr_random(dev); err = register_netdevice(dev); - if (err) { - dev_err(ipc_wwan->dev, "register netlink failed.\n"); - goto out_free_lock; - } - - err = netdev_upper_dev_link(ipc_wwan->netdev, dev, extack); + if (err) + goto out_unlock; - if (err) { - dev_err(ipc_wwan->dev, "netdev linking with parent failed.\n"); - goto netlink_err; - } + rcu_assign_pointer(ipc_wwan->sub_netlist[if_id], priv); + mutex_unlock(&ipc_wwan->if_mutex); - rcu_assign_pointer(ipc_wwan->sub_netlist[index - 1], netlink); netif_device_attach(dev); - rcu_read_unlock(); return 0; -netlink_err: - unregister_netdevice(dev); -out_free_lock: - rcu_read_unlock(); -out: +out_unlock: + mutex_unlock(&ipc_wwan->if_mutex); return err; } -/* Delete new wwan net link */ -static void ipc_wwan_dellink(struct net_device *dev, struct list_head *head) +static void ipc_wwan_dellink(void *ctxt, struct net_device *dev, + struct list_head *head) { - struct iosm_net_link *netlink = netdev_priv(dev); - u16 index = netlink->if_id; - - netdev_upper_dev_unlink(netlink->ipc_wwan->netdev, dev); - unregister_netdevice(dev); + struct iosm_wwan *ipc_wwan = ctxt; + struct iosm_netdev_priv *priv = netdev_priv(dev); + int if_id = priv->if_id; - mutex_lock(&netlink->ipc_wwan->if_mutex); - rcu_assign_pointer(netlink->ipc_wwan->sub_netlist[index - 1], NULL); - mutex_unlock(&netlink->ipc_wwan->if_mutex); -} + if (WARN_ON(if_id < IP_MUX_SESSION_START || + if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))) + return; -/* Get size for iosm net link payload*/ -static size_t ipc_wwan_get_size(const struct net_device *dev) -{ - return nla_total_size(IOSM_IF_ID_PAYLOAD); -} - -/* Validate the input parameters for wwan net link */ -static int ipc_wwan_validate(struct nlattr *tb[], struct nlattr *data[], - struct netlink_ext_ack *extack) -{ - u16 if_id; - - if (!data || !data[IFLA_IOSM_IF_ID]) { - NL_SET_ERR_MSG_MOD(extack, "IF ID not specified"); - return -EINVAL; - } + mutex_lock(&ipc_wwan->if_mutex); - if_id = nla_get_u16(data[IFLA_IOSM_IF_ID]); + if (WARN_ON(rcu_access_pointer(ipc_wwan->sub_netlist[if_id]) != priv)) + goto unlock; - if (if_id < IP_MUX_SESSION_START || if_id > IP_MUX_SESSION_END) { - NL_SET_ERR_MSG_MOD(extack, "Invalid Interface"); - return -ERANGE; - } + RCU_INIT_POINTER(ipc_wwan->sub_netlist[if_id], NULL); + /* unregistering includes synchronize_net() */ + unregister_netdevice(dev); - return 0; +unlock: + mutex_unlock(&ipc_wwan->if_mutex); } -/* RT Net link ops structure for new wwan net link */ -struct rtnl_link_ops iosm_netlink __read_mostly = { - .kind = "iosm", - .maxtype = __IFLA_IOSM_MAX, - .priv_size = sizeof(struct iosm_net_link), - .setup = ipc_wwan_setup, - .validate = ipc_wwan_validate, - .newlink = ipc_wwan_newlink, - .dellink = ipc_wwan_dellink, - .get_size = ipc_wwan_get_size, - .policy = ipc_wwan_policy, +static const struct wwan_ops iosm_wwan_ops = { + .priv_size = sizeof(struct iosm_netdev_priv), + .setup = ipc_wwan_setup, + .newlink = ipc_wwan_newlink, + .dellink = ipc_wwan_dellink, }; int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, @@ -313,7 +236,7 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, { struct sk_buff *skb = skb_arg; struct net_device_stats *stats; - struct iosm_net_link *priv; + struct iosm_netdev_priv *priv; int ret; if ((skb->data[0] & IOSM_IP_TYPE_MASK) == IOSM_IP_TYPE_IPV4) @@ -353,10 +276,17 @@ int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg, void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int if_id, bool on) { struct net_device *netdev; + struct iosm_netdev_priv *priv; bool is_tx_blk; rcu_read_lock(); - netdev = rcu_dereference(ipc_wwan->sub_netlist[if_id])->netdev; + priv = rcu_dereference(ipc_wwan->sub_netlist[if_id]); + if (!priv) { + rcu_read_unlock(); + return; + } + + netdev = priv->netdev; is_tx_blk = netif_queue_stopped(netdev); @@ -371,78 +301,44 @@ void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int if_id, bool on) rcu_read_unlock(); } -static void ipc_netdev_setup(struct net_device *dev) {} - struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev) { - static const struct net_device_ops iosm_wwandev_ops = {}; struct iosm_wwan *ipc_wwan; - struct net_device *netdev; - netdev = alloc_netdev(sizeof(*ipc_wwan), "wwan%d", NET_NAME_ENUM, - ipc_netdev_setup); - - if (!netdev) + ipc_wwan = kzalloc(sizeof(*ipc_wwan), GFP_KERNEL); + if (!ipc_wwan) return NULL; - ipc_wwan = netdev_priv(netdev); - ipc_wwan->dev = dev; - ipc_wwan->netdev = netdev; - ipc_wwan->is_registered = false; - ipc_wwan->ipc_imem = ipc_imem; - mutex_init(&ipc_wwan->if_mutex); - - /* allocate random ethernet address */ - eth_random_addr(netdev->dev_addr); - netdev->addr_assign_type = NET_ADDR_RANDOM; - - netdev->netdev_ops = &iosm_wwandev_ops; - netdev->flags |= IFF_NOARP; - - SET_NETDEV_DEVTYPE(netdev, &wwan_type); - - if (register_netdev(netdev)) { - dev_err(ipc_wwan->dev, "register_netdev failed"); - goto reg_fail; + if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan)) { + kfree(ipc_wwan); + return NULL; } - ipc_wwan->is_registered = true; - - netif_device_attach(netdev); + mutex_init(&ipc_wwan->if_mutex); return ipc_wwan; - -reg_fail: - free_netdev(netdev); - return NULL; } void ipc_wwan_deinit(struct iosm_wwan *ipc_wwan) { - struct iosm_net_link *netlink; - int i; - - if (ipc_wwan->is_registered) { - rcu_read_lock(); - for (i = IP_MUX_SESSION_START; i <= IP_MUX_SESSION_END; i++) { - if (rcu_access_pointer(ipc_wwan->sub_netlist[i - 1])) { - netlink = - rcu_dereference(ipc_wwan->sub_netlist[i - 1]); - rtnl_lock(); - netdev_upper_dev_unlink(ipc_wwan->netdev, - netlink->netdev); - unregister_netdevice(netlink->netdev); - rtnl_unlock(); - rcu_assign_pointer(ipc_wwan->sub_netlist[i - 1], - NULL); - } - } - rcu_read_unlock(); + int if_id; - unregister_netdev(ipc_wwan->netdev); - free_netdev(ipc_wwan->netdev); + wwan_unregister_ops(ipc_wwan->dev); + + for (if_id = 0; if_id < ARRAY_SIZE(ipc_wwan->sub_netlist); if_id++) { + struct iosm_netdev_priv *priv; + + priv = rcu_access_pointer(ipc_wwan->sub_netlist[if_id]); + if (!priv) + continue; + + ipc_wwan_dellink(ipc_wwan, priv->netdev, NULL); } + + mutex_destroy(&ipc_wwan->if_mutex); + + kfree(ipc_wwan); } diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 3455780193a4..0ac1f6ab5673 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1257,14 +1257,4 @@ struct ifla_rmnet_flags { __u32 mask; }; -/* IOSM Section */ - -enum { - IFLA_IOSM_UNSPEC, - IFLA_IOSM_IF_ID, - __IFLA_IOSM_MAX, -}; - -#define IFLA_IOSM_MAX (__IFLA_IOSM_MAX - 1) - #endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index cb496d0de39e..d208b2af697f 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -1046,14 +1046,4 @@ struct ifla_rmnet_flags { __u32 mask; }; -/* IOSM Section */ - -enum { - IFLA_IOSM_UNSPEC, - IFLA_IOSM_IF_ID, - __IFLA_IOSM_MAX, -}; - -#define IFLA_IOSM_MAX (__IFLA_IOSM_MAX - 1) - #endif /* _UAPI_LINUX_IF_LINK_H */ -- 2.31.1