Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c18d220 authored by sjur.brandeland@stericsson.com's avatar sjur.brandeland@stericsson.com Committed by David S. Miller
Browse files

caif: Restructure how link caif link layer enroll



Enrolling CAIF link layers are refactored.

Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 200c5a3b
Loading
Loading
Loading
Loading
+21 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@


#include <net/caif/caif_layer.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/caif_device.h>
#include <linux/caif/caif_socket.h>
#include <linux/caif/caif_socket.h>
#include <linux/if.h>
#include <linux/if.h>
#include <linux/net.h>
#include <linux/net.h>
@@ -104,4 +105,24 @@ void caif_client_register_refcnt(struct cflayer *adapt_layer,
 */
 */
void caif_free_client(struct cflayer *adap_layer);
void caif_free_client(struct cflayer *adap_layer);


/**
 * struct caif_enroll_dev - Enroll a net-device as a CAIF Link layer
 * @dev:		Network device to enroll.
 * @caifdev:		Configuration information from CAIF Link Layer
 * @link_support:	Link layer support layer
 * @head_room:		Head room needed by link support layer
 * @layer:		Lowest layer in CAIF stack
 * @rcv_fun:		Receive function for CAIF stack.
 *
 * This function enroll a CAIF link layer into CAIF Stack and
 * expects the interface to be able to handle CAIF payload.
 * The link_support layer is used to add any Link Layer specific
 * framing.
 */
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
			struct cflayer *link_support, int head_room,
			struct cflayer **layer, int (**rcv_func)(
				struct sk_buff *, struct net_device *,
				struct packet_type *, struct net_device *));

#endif /* CAIF_DEV_H_ */
#endif /* CAIF_DEV_H_ */
+5 −4
Original line number Original line Diff line number Diff line
@@ -72,15 +72,16 @@ void cfcnfg_remove(struct cfcnfg *cfg);
 * @phy_layer:	Specify the physical layer. The transmit function
 * @phy_layer:	Specify the physical layer. The transmit function
 *		MUST be set in the structure.
 *		MUST be set in the structure.
 * @pref:	The phy (link layer) preference.
 * @pref:	The phy (link layer) preference.
 * @link_support: Protocol implementation for link layer specific protocol.
 * @fcs:	Specify if checksum is used in CAIF Framing Layer.
 * @fcs:	Specify if checksum is used in CAIF Framing Layer.
 * @stx:	Specify if Start Of Frame eXtention is used.
 * @head_room:	Head space needed by link specific protocol.
 */
 */

void
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
		     struct net_device *dev, struct cflayer *phy_layer,
		     struct net_device *dev, struct cflayer *phy_layer,
		     enum cfcnfg_phy_preference pref,
		     enum cfcnfg_phy_preference pref,
		     bool fcs, bool stx);
		     struct cflayer *link_support,
		     bool fcs, int head_room);


/**
/**
 * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack.
 * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack.
+90 −55
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@
#include <net/caif/caif_layer.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfserl.h>


MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");


@@ -53,7 +54,8 @@ struct cfcnfg *get_cfcnfg(struct net *net)
	struct caif_net *caifn;
	struct caif_net *caifn;
	BUG_ON(!net);
	BUG_ON(!net);
	caifn = net_generic(net, caif_net_id);
	caifn = net_generic(net, caif_net_id);
	BUG_ON(!caifn);
	if (!caifn)
		return NULL;
	return caifn->cfg;
	return caifn->cfg;
}
}
EXPORT_SYMBOL(get_cfcnfg);
EXPORT_SYMBOL(get_cfcnfg);
@@ -63,7 +65,8 @@ static struct caif_device_entry_list *caif_device_list(struct net *net)
	struct caif_net *caifn;
	struct caif_net *caifn;
	BUG_ON(!net);
	BUG_ON(!net);
	caifn = net_generic(net, caif_net_id);
	caifn = net_generic(net, caif_net_id);
	BUG_ON(!caifn);
	if (!caifn)
		return NULL;
	return &caifn->caifdevs;
	return &caifn->caifdevs;
}
}


@@ -92,7 +95,8 @@ static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
	struct caif_device_entry *caifd;
	struct caif_device_entry *caifd;


	caifdevs = caif_device_list(dev_net(dev));
	caifdevs = caif_device_list(dev_net(dev));
	BUG_ON(!caifdevs);
	if (!caifdevs)
		return NULL;


	caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
	caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
	if (!caifd)
	if (!caifd)
@@ -112,7 +116,9 @@ static struct caif_device_entry *caif_get(struct net_device *dev)
	struct caif_device_entry_list *caifdevs =
	struct caif_device_entry_list *caifdevs =
	    caif_device_list(dev_net(dev));
	    caif_device_list(dev_net(dev));
	struct caif_device_entry *caifd;
	struct caif_device_entry *caifd;
	BUG_ON(!caifdevs);
	if (!caifdevs)
		return NULL;

	list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
	list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
		if (caifd->netdev == dev)
		if (caifd->netdev == dev)
			return caifd;
			return caifd;
@@ -129,6 +135,8 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt)


	skb = cfpkt_tonative(pkt);
	skb = cfpkt_tonative(pkt);
	skb->dev = caifd->netdev;
	skb->dev = caifd->netdev;
	skb_reset_network_header(skb);
	skb->protocol = htons(ETH_P_CAIF);


	err = dev_queue_xmit(skb);
	err = dev_queue_xmit(skb);
	if (err > 0)
	if (err > 0)
@@ -172,7 +180,10 @@ static int receive(struct sk_buff *skb, struct net_device *dev,


	/* Release reference to stack upwards */
	/* Release reference to stack upwards */
	caifd_put(caifd);
	caifd_put(caifd);
	return 0;

	if (err != 0)
		err = NET_RX_DROP;
	return err;
}
}


static struct packet_type caif_packet_type __read_mostly = {
static struct packet_type caif_packet_type __read_mostly = {
@@ -203,42 +214,24 @@ static void dev_flowctrl(struct net_device *dev, int on)
	caifd_put(caifd);
	caifd_put(caifd);
}
}


/* notify Caif of device events */
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
static int caif_device_notify(struct notifier_block *me, unsigned long what,
			struct cflayer *link_support, int head_room,
			      void *arg)
			struct cflayer **layer, int (**rcv_func)(
				struct sk_buff *, struct net_device *,
				struct packet_type *, struct net_device *))
{
{
	struct net_device *dev = arg;
	struct caif_device_entry *caifd;
	struct caif_device_entry *caifd = NULL;
	struct caif_dev_common *caifdev;
	enum cfcnfg_phy_preference pref;
	enum cfcnfg_phy_preference pref;
	enum cfcnfg_phy_type phy_type;
	struct cfcnfg *cfg = get_cfcnfg(dev_net(dev));
	struct cfcnfg *cfg;
	struct caif_device_entry_list *caifdevs;
	struct caif_device_entry_list *caifdevs;


	if (dev->type != ARPHRD_CAIF)
		return 0;

	cfg = get_cfcnfg(dev_net(dev));
	if (cfg == NULL)
		return 0;

	caifdevs = caif_device_list(dev_net(dev));
	caifdevs = caif_device_list(dev_net(dev));

	if (!cfg || !caifdevs)
	switch (what) {
		return;
	case NETDEV_REGISTER:
	caifd = caif_device_alloc(dev);
	caifd = caif_device_alloc(dev);
	if (!caifd)
	if (!caifd)
			return 0;
		return;

	*layer = &caifd->layer;
		caifdev = netdev_priv(dev);
		caifdev->flowctrl = dev_flowctrl;

		caifd->layer.transmit = transmit;

		if (caifdev->use_frag)
			phy_type = CFPHYTYPE_FRAG;
		else
			phy_type = CFPHYTYPE_CAIF;


	switch (caifdev->link_select) {
	switch (caifdev->link_select) {
	case CAIF_LINK_HIGH_BANDW:
	case CAIF_LINK_HIGH_BANDW:
@@ -251,21 +244,66 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
		pref = CFPHYPREF_HIGH_BW;
		pref = CFPHYPREF_HIGH_BW;
		break;
		break;
	}
	}
		strncpy(caifd->layer.name, dev->name,
			sizeof(caifd->layer.name) - 1);
		caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;

	mutex_lock(&caifdevs->lock);
	mutex_lock(&caifdevs->lock);
	list_add_rcu(&caifd->list, &caifdevs->list);
	list_add_rcu(&caifd->list, &caifdevs->list);


	strncpy(caifd->layer.name, dev->name,
		sizeof(caifd->layer.name) - 1);
	caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
	caifd->layer.transmit = transmit;
	cfcnfg_add_phy_layer(cfg,
	cfcnfg_add_phy_layer(cfg,
				     phy_type,
				dev,
				dev,
				&caifd->layer,
				&caifd->layer,
				pref,
				pref,
				link_support,
				caifdev->use_fcs,
				caifdev->use_fcs,
				     caifdev->use_stx);
				head_room);
	mutex_unlock(&caifdevs->lock);
	mutex_unlock(&caifdevs->lock);
	if (rcv_func)
		*rcv_func = receive;
}

/* notify Caif of device events */
static int caif_device_notify(struct notifier_block *me, unsigned long what,
			      void *arg)
{
	struct net_device *dev = arg;
	struct caif_device_entry *caifd = NULL;
	struct caif_dev_common *caifdev;
	struct cfcnfg *cfg;
	struct cflayer *layer, *link_support;
	int head_room = 0;
	struct caif_device_entry_list *caifdevs;

	cfg = get_cfcnfg(dev_net(dev));
	caifdevs = caif_device_list(dev_net(dev));
	if (!cfg || !caifdevs)
		return 0;

	caifd = caif_get(dev);
	if (caifd == NULL && dev->type != ARPHRD_CAIF)
		return 0;

	switch (what) {
	case NETDEV_REGISTER:
		if (caifd != NULL)
			break;

		caifdev = netdev_priv(dev);

		link_support = NULL;
		if (caifdev->use_frag) {
			head_room = 1;
			link_support = cfserl_create(dev->ifindex,
					CFPHYTYPE_FRAG, caifdev->use_stx);
			if (!link_support) {
				pr_warn("Out of memory\n");
				break;
			}
		}
		caif_enroll_dev(dev, caifdev, link_support, head_room,
				&layer, NULL);
		caifdev->flowctrl = dev_flowctrl;
		break;
		break;


	case NETDEV_UP:
	case NETDEV_UP:
@@ -371,17 +409,14 @@ static void caif_exit_net(struct net *net)
	struct caif_device_entry *caifd, *tmp;
	struct caif_device_entry *caifd, *tmp;
	struct caif_device_entry_list *caifdevs =
	struct caif_device_entry_list *caifdevs =
	    caif_device_list(net);
	    caif_device_list(net);
	struct cfcnfg *cfg;
	struct cfcnfg *cfg =  get_cfcnfg(net);

	if (!cfg || !caifdevs)
		return;


	rtnl_lock();
	rtnl_lock();
	mutex_lock(&caifdevs->lock);
	mutex_lock(&caifdevs->lock);


	cfg = get_cfcnfg(net);
	if (cfg == NULL) {
		mutex_unlock(&caifdevs->lock);
		return;
	}

	list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
	list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
		int i = 0;
		int i = 0;
		list_del_rcu(&caifd->list);
		list_del_rcu(&caifd->list);
+16 −31
Original line number Original line Diff line number Diff line
@@ -45,8 +45,8 @@ struct cfcnfg_phyinfo {
	/* Interface index */
	/* Interface index */
	int ifindex;
	int ifindex;


	/* Use Start of frame extension */
	/* Protocol head room added for CAIF link layer */
	bool use_stx;
	int head_room;


	/* Use Start of frame checksum */
	/* Use Start of frame checksum */
	bool use_fcs;
	bool use_fcs;
@@ -187,11 +187,11 @@ int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
	if (channel_id != 0) {
	if (channel_id != 0) {
		struct cflayer *servl;
		struct cflayer *servl;
		servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
		servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
		cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
		if (servl != NULL)
		if (servl != NULL)
			layer_set_up(servl, NULL);
			layer_set_up(servl, NULL);
	} else
	} else
		pr_debug("nothing to disconnect\n");
		pr_debug("nothing to disconnect\n");
	cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);


	/* Do RCU sync before initiating cleanup */
	/* Do RCU sync before initiating cleanup */
	synchronize_rcu();
	synchronize_rcu();
@@ -350,9 +350,7 @@ int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,


	*ifindex = phy->ifindex;
	*ifindex = phy->ifindex;
	*proto_tail = 2;
	*proto_tail = 2;
	*proto_head =
	*proto_head = protohead[param.linktype] + phy->head_room;

	protohead[param.linktype] + (phy->use_stx ? 1 : 0);


	rcu_read_unlock();
	rcu_read_unlock();


@@ -460,13 +458,13 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
}
}


void
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
		     struct net_device *dev, struct cflayer *phy_layer,
		     struct net_device *dev, struct cflayer *phy_layer,
		     enum cfcnfg_phy_preference pref,
		     enum cfcnfg_phy_preference pref,
		     bool fcs, bool stx)
		     struct cflayer *link_support,
		     bool fcs, int head_room)
{
{
	struct cflayer *frml;
	struct cflayer *frml;
	struct cflayer *phy_driver = NULL;
	struct cfcnfg_phyinfo *phyinfo = NULL;
	struct cfcnfg_phyinfo *phyinfo = NULL;
	int i;
	int i;
	u8 phyid;
	u8 phyid;
@@ -482,26 +480,13 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
			goto got_phyid;
			goto got_phyid;
	}
	}
	pr_warn("Too many CAIF Link Layers (max 6)\n");
	pr_warn("Too many CAIF Link Layers (max 6)\n");
	goto out_err;
	goto out;


got_phyid:
got_phyid:
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
	if (!phyinfo)
	if (!phyinfo)
		goto out_err;
		goto out_err;


	switch (phy_type) {
	case CFPHYTYPE_FRAG:
		phy_driver =
		    cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
		if (!phy_driver)
			goto out_err;
		break;
	case CFPHYTYPE_CAIF:
		phy_driver = NULL;
		break;
	default:
		goto out_err;
	}
	phy_layer->id = phyid;
	phy_layer->id = phyid;
	phyinfo->pref = pref;
	phyinfo->pref = pref;
	phyinfo->id = phyid;
	phyinfo->id = phyid;
@@ -509,7 +494,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
	phyinfo->dev_info.dev = dev;
	phyinfo->dev_info.dev = dev;
	phyinfo->phy_layer = phy_layer;
	phyinfo->phy_layer = phy_layer;
	phyinfo->ifindex = dev->ifindex;
	phyinfo->ifindex = dev->ifindex;
	phyinfo->use_stx = stx;
	phyinfo->head_room = head_room;
	phyinfo->use_fcs = fcs;
	phyinfo->use_fcs = fcs;


	frml = cffrml_create(phyid, fcs);
	frml = cffrml_create(phyid, fcs);
@@ -519,23 +504,23 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
	phyinfo->frm_layer = frml;
	phyinfo->frm_layer = frml;
	layer_set_up(frml, cnfg->mux);
	layer_set_up(frml, cnfg->mux);


	if (phy_driver != NULL) {
	if (link_support != NULL) {
		phy_driver->id = phyid;
		link_support->id = phyid;
		layer_set_dn(frml, phy_driver);
		layer_set_dn(frml, link_support);
		layer_set_up(phy_driver, frml);
		layer_set_up(link_support, frml);
		layer_set_dn(phy_driver, phy_layer);
		layer_set_dn(link_support, phy_layer);
		layer_set_up(phy_layer, phy_driver);
		layer_set_up(phy_layer, link_support);
	} else {
	} else {
		layer_set_dn(frml, phy_layer);
		layer_set_dn(frml, phy_layer);
		layer_set_up(phy_layer, frml);
		layer_set_up(phy_layer, frml);
	}
	}


	list_add_rcu(&phyinfo->node, &cnfg->phys);
	list_add_rcu(&phyinfo->node, &cnfg->phys);
out:
	mutex_unlock(&cnfg->lock);
	mutex_unlock(&cnfg->lock);
	return;
	return;


out_err:
out_err:
	kfree(phy_driver);
	kfree(phyinfo);
	kfree(phyinfo);
	mutex_unlock(&cnfg->lock);
	mutex_unlock(&cnfg->lock);
}
}