Skip to content

Commit

Permalink
caif: Restructure how link caif link layer enroll
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
sjur.brandeland@stericsson.com authored and davem330 committed Dec 1, 2011
1 parent 200c5a3 commit 7c18d22
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 90 deletions.
21 changes: 21 additions & 0 deletions include/net/caif/caif_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <net/caif/caif_layer.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/caif_device.h>
#include <linux/caif/caif_socket.h>
#include <linux/if.h>
#include <linux/net.h>
Expand Down Expand Up @@ -104,4 +105,24 @@ void caif_client_register_refcnt(struct cflayer *adapt_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_ */
9 changes: 5 additions & 4 deletions include/net/caif/cfcnfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,16 @@ void cfcnfg_remove(struct cfcnfg *cfg);
* @phy_layer: Specify the physical layer. The transmit function
* MUST be set in the structure.
* @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.
* @stx: Specify if Start Of Frame eXtention is used.
* @head_room: Head space needed by link specific protocol.
*/

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,
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.
Expand Down
145 changes: 90 additions & 55 deletions net/caif/caif_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfserl.h>

MODULE_LICENSE("GPL");

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

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

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

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

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

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

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

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

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

static struct packet_type caif_packet_type __read_mostly = {
Expand Down Expand Up @@ -203,69 +214,96 @@ static void dev_flowctrl(struct net_device *dev, int on)
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 */
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;
enum cfcnfg_phy_preference pref;
enum cfcnfg_phy_type phy_type;
struct cfcnfg *cfg;
struct cflayer *layer, *link_support;
int head_room = 0;
struct caif_device_entry_list *caifdevs;

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

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

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

switch (what) {
case NETDEV_REGISTER:
caifd = caif_device_alloc(dev);
if (!caifd)
return 0;
if (caifd != NULL)
break;

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) {
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;
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;
}
}
strncpy(caifd->layer.name, dev->name,
sizeof(caifd->layer.name) - 1);
caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;

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);
caif_enroll_dev(dev, caifdev, link_support, head_room,
&layer, NULL);
caifdev->flowctrl = dev_flowctrl;
break;

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

if (!cfg || !caifdevs)
return;

rtnl_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) {
int i = 0;
list_del_rcu(&caifd->list);
Expand Down
Loading

0 comments on commit 7c18d22

Please sign in to comment.