caif: Restructure how link caif link layer enroll

Enrolling CAIF link layers are refactored.

Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
sjur.brandeland@stericsson.com 2011-11-30 09:22:47 +00:00 committed by David S. Miller
parent 200c5a3b38
commit 7c18d2205e
4 changed files with 132 additions and 90 deletions

View File

@ -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_ */

View File

@ -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.

View File

@ -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,6 +214,55 @@ static void dev_flowctrl(struct net_device *dev, int on)
caifd_put(caifd); caifd_put(caifd);
} }
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 *))
{
struct caif_device_entry *caifd;
enum cfcnfg_phy_preference pref;
struct cfcnfg *cfg = get_cfcnfg(dev_net(dev));
struct caif_device_entry_list *caifdevs;
caifdevs = caif_device_list(dev_net(dev));
if (!cfg || !caifdevs)
return;
caifd = caif_device_alloc(dev);
if (!caifd)
return;
*layer = &caifd->layer;
switch (caifdev->link_select) {
case CAIF_LINK_HIGH_BANDW:
pref = CFPHYPREF_HIGH_BW;
break;
case CAIF_LINK_LOW_LATENCY:
pref = CFPHYPREF_LOW_LAT;
break;
default:
pref = CFPHYPREF_HIGH_BW;
break;
}
mutex_lock(&caifdevs->lock);
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,
dev,
&caifd->layer,
pref,
link_support,
caifdev->use_fcs,
head_room);
mutex_unlock(&caifdevs->lock);
if (rcv_func)
*rcv_func = receive;
}
/* notify Caif of device events */ /* notify Caif of device events */
static int caif_device_notify(struct notifier_block *me, unsigned long what, static int caif_device_notify(struct notifier_block *me, unsigned long what,
void *arg) void *arg)
@ -210,62 +270,40 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
struct net_device *dev = arg; struct net_device *dev = arg;
struct caif_device_entry *caifd = NULL; struct caif_device_entry *caifd = NULL;
struct caif_dev_common *caifdev; struct caif_dev_common *caifdev;
enum cfcnfg_phy_preference pref;
enum cfcnfg_phy_type phy_type;
struct cfcnfg *cfg; struct cfcnfg *cfg;
struct cflayer *layer, *link_support;
int head_room = 0;
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)); cfg = get_cfcnfg(dev_net(dev));
if (cfg == NULL) caifdevs = caif_device_list(dev_net(dev));
if (!cfg || !caifdevs)
return 0; return 0;
caifdevs = caif_device_list(dev_net(dev)); caifd = caif_get(dev);
if (caifd == NULL && dev->type != ARPHRD_CAIF)
return 0;
switch (what) { switch (what) {
case NETDEV_REGISTER: case NETDEV_REGISTER:
caifd = caif_device_alloc(dev); if (caifd != NULL)
if (!caifd) break;
return 0;
caifdev = netdev_priv(dev); caifdev = netdev_priv(dev);
caifdev->flowctrl = dev_flowctrl;
caifd->layer.transmit = transmit; link_support = NULL;
if (caifdev->use_frag) {
if (caifdev->use_frag) head_room = 1;
phy_type = CFPHYTYPE_FRAG; link_support = cfserl_create(dev->ifindex,
else CFPHYTYPE_FRAG, caifdev->use_stx);
phy_type = CFPHYTYPE_CAIF; if (!link_support) {
pr_warn("Out of memory\n");
switch (caifdev->link_select) { break;
case CAIF_LINK_HIGH_BANDW: }
pref = CFPHYPREF_HIGH_BW;
break;
case CAIF_LINK_LOW_LATENCY:
pref = CFPHYPREF_LOW_LAT;
break;
default:
pref = CFPHYPREF_HIGH_BW;
break;
} }
strncpy(caifd->layer.name, dev->name, caif_enroll_dev(dev, caifdev, link_support, head_room,
sizeof(caifd->layer.name) - 1); &layer, NULL);
caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; caifdev->flowctrl = dev_flowctrl;
mutex_lock(&caifdevs->lock);
list_add_rcu(&caifd->list, &caifdevs->list);
cfcnfg_add_phy_layer(cfg,
phy_type,
dev,
&caifd->layer,
pref,
caifdev->use_fcs,
caifdev->use_stx);
mutex_unlock(&caifdevs->lock);
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);

View File

@ -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 @@ unlock:
} }
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 @@ got_phyid:
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 @@ got_phyid:
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);
} }