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

Commit c12a2242 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'for-davem' of git://gitorious.org/linux-can/linux-can-next



Marc Kleine-Budde says:

====================
this is a pull request for net-next. There are two patches from Gerhard
Sittig, which improves the clock handling on mpc5121. Oliver Hartkopp
provides a patch that adds a per rule limitation of frame hops.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e7abfe40 391ac128
Loading
Loading
Loading
Loading
+16 −7
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data {
	unsigned int type;
	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
			 int *mscan_clksrc);
	void (*put_clock)(struct platform_device *ofdev);
};

#ifdef CONFIG_PPC_MPC52xx
@@ -148,7 +149,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
		goto exit_put;
	}

	/* Determine the MSCAN device index from the physical address */
	/* Determine the MSCAN device index from the peripheral's
	 * physical address. Register address offsets against the
	 * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
	 */
	pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
	BUG_ON(!pval || plen < sizeof(*pval));
	clockidx = (*pval & 0x80) ? 1 : 0;
@@ -177,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
			clockdiv = 1;

		if (!clock_name || !strcmp(clock_name, "sys")) {
			sys_clk = clk_get(&ofdev->dev, "sys_clk");
			sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
			if (IS_ERR(sys_clk)) {
				dev_err(&ofdev->dev, "couldn't get sys_clk\n");
				goto exit_unmap;
@@ -200,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
		}

		if (clocksrc < 0) {
			ref_clk = clk_get(&ofdev->dev, "ref_clk");
			ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
			if (IS_ERR(ref_clk)) {
				dev_err(&ofdev->dev, "couldn't get ref_clk\n");
				goto exit_unmap;
@@ -277,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
	dev = alloc_mscandev();
	if (!dev)
		goto exit_dispose_irq;
	platform_set_drvdata(ofdev, dev);
	SET_NETDEV_DEV(dev, &ofdev->dev);

	priv = netdev_priv(dev);
	priv->reg_base = base;
@@ -293,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
		goto exit_free_mscan;
	}

	SET_NETDEV_DEV(dev, &ofdev->dev);

	err = register_mscandev(dev, mscan_clksrc);
	if (err) {
		dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -302,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
		goto exit_free_mscan;
	}

	platform_set_drvdata(ofdev, dev);

	dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
		 priv->reg_base, dev->irq, priv->can.clock.freq);

@@ -321,10 +323,17 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)

static int mpc5xxx_can_remove(struct platform_device *ofdev)
{
	const struct of_device_id *match;
	const struct mpc5xxx_can_data *data;
	struct net_device *dev = platform_get_drvdata(ofdev);
	struct mscan_priv *priv = netdev_priv(dev);

	match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
	data = match ? match->data : NULL;

	unregister_mscandev(dev);
	if (data && data->put_clock)
		data->put_clock(ofdev);
	iounmap(priv->reg_base);
	irq_dispose_mapping(dev->irq);
	free_candev(dev);
+24 −1
Original line number Diff line number Diff line
@@ -573,10 +573,21 @@ static int mscan_open(struct net_device *dev)
	struct mscan_priv *priv = netdev_priv(dev);
	struct mscan_regs __iomem *regs = priv->reg_base;

	if (priv->clk_ipg) {
		ret = clk_prepare_enable(priv->clk_ipg);
		if (ret)
			goto exit_retcode;
	}
	if (priv->clk_can) {
		ret = clk_prepare_enable(priv->clk_can);
		if (ret)
			goto exit_dis_ipg_clock;
	}

	/* common open */
	ret = open_candev(dev);
	if (ret)
		return ret;
		goto exit_dis_can_clock;

	napi_enable(&priv->napi);

@@ -604,6 +615,13 @@ static int mscan_open(struct net_device *dev)
exit_napi_disable:
	napi_disable(&priv->napi);
	close_candev(dev);
exit_dis_can_clock:
	if (priv->clk_can)
		clk_disable_unprepare(priv->clk_can);
exit_dis_ipg_clock:
	if (priv->clk_ipg)
		clk_disable_unprepare(priv->clk_ipg);
exit_retcode:
	return ret;
}

@@ -621,6 +639,11 @@ static int mscan_close(struct net_device *dev)
	close_candev(dev);
	free_irq(dev->irq, dev);

	if (priv->clk_can)
		clk_disable_unprepare(priv->clk_can);
	if (priv->clk_ipg)
		clk_disable_unprepare(priv->clk_ipg);

	return 0;
}

+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#ifndef __MSCAN_H__
#define __MSCAN_H__

#include <linux/clk.h>
#include <linux/types.h>

/* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,8 @@ struct mscan_priv {
	unsigned int type; 	/* MSCAN type variants */
	unsigned long flags;
	void __iomem *reg_base;	/* ioremap'ed address to registers */
	struct clk *clk_ipg;	/* clock for registers */
	struct clk *clk_can;	/* clock for bitrates */
	u8 shadow_statflg;
	u8 shadow_canrier;
	u8 cur_pri;
+8 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ enum {
	CGW_DST_IF,	/* ifindex of destination network interface */
	CGW_FILTER,	/* specify struct can_filter on source CAN device */
	CGW_DELETED,	/* number of deleted CAN frames (see max_hops param) */
	CGW_LIM_HOPS,	/* limit the number of hops of this specific rule */
	__CGW_MAX
};

@@ -116,13 +117,19 @@ enum {
 * Sets a CAN receive filter for the gateway job specified by the
 * struct can_filter described in include/linux/can.h
 *
 * CGW_MOD_XXX (length 17 bytes):
 * CGW_MOD_(AND|OR|XOR|SET) (length 17 bytes):
 * Specifies a modification that's done to a received CAN frame before it is
 * send out to the destination interface.
 *
 * <struct can_frame> data used as operator
 * <u8> affected CAN frame elements
 *
 * CGW_LIM_HOPS (length 1 byte):
 * Limit the number of hops of this specific rule. Usually the received CAN
 * frame can be processed as much as 'max_hops' times (which is given at module
 * load time of the can-gw module). This value is used to reduce the number of
 * possible hops for this gateway rule to a value smaller then max_hops.
 *
 * CGW_CS_XOR (length 4 bytes):
 * Set a simple XOR checksum starting with an initial value into
 * data[result-idx] using data[start-idx] .. data[end-idx]
+31 −4
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ struct cgw_job {
		/* tbc */
	};
	u8 gwtype;
	u8 limit_hops;
	u16 flags;
};

@@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)

	/* put the incremented hop counter in the cloned skb */
	cgw_hops(nskb) = cgw_hops(skb) + 1;

	/* first processing of this CAN frame -> adjust to private hop limit */
	if (gwj->limit_hops && cgw_hops(nskb) == 1)
		cgw_hops(nskb) = max_hops - gwj->limit_hops + 1;

	nskb->dev = gwj->dst.dev;

	/* pointer to modifiable CAN frame */
@@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,

	/* check non default settings of attributes */

	if (gwj->limit_hops) {
		if (nla_put_u8(skb, CGW_LIM_HOPS, gwj->limit_hops) < 0)
			goto cancel;
	}

	if (gwj->mod.modtype.and) {
		memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
		mb.modtype = gwj->mod.modtype.and;
@@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
	[CGW_SRC_IF]	= { .type = NLA_U32 },
	[CGW_DST_IF]	= { .type = NLA_U32 },
	[CGW_FILTER]	= { .len = sizeof(struct can_filter) },
	[CGW_LIM_HOPS]	= { .type = NLA_U8 },
};

/* check for common and gwtype specific attributes */
static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
			  u8 gwtype, void *gwtypeattr)
			  u8 gwtype, void *gwtypeattr, u8 *limhops)
{
	struct nlattr *tb[CGW_MAX+1];
	struct cgw_frame_mod mb;
@@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
	if (err < 0)
		return err;

	if (tb[CGW_LIM_HOPS]) {
		*limhops = nla_get_u8(tb[CGW_LIM_HOPS]);

		if (*limhops < 1 || *limhops > max_hops)
			return -EINVAL;
	}

	/* check for AND/OR/XOR/SET modifications */

	if (tb[CGW_MOD_AND]) {
@@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	struct rtcanmsg *r;
	struct cgw_job *gwj;
	u8 limhops = 0;
	int err = 0;

	if (!capable(CAP_NET_ADMIN))
@@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
	gwj->flags = r->flags;
	gwj->gwtype = r->gwtype;

	err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw);
	err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw,
			     &limhops);
	if (err < 0)
		goto out;

@@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
	if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops)
		goto put_src_dst_out;

	gwj->limit_hops = limhops;

	ASSERT_RTNL();

	err = cgw_register_filter(gwj);
@@ -874,6 +897,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
	struct rtcanmsg *r;
	struct cf_mod mod;
	struct can_can_gw ccgw;
	u8 limhops = 0;
	int err = 0;

	if (!capable(CAP_NET_ADMIN))
@@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
	if (r->gwtype != CGW_TYPE_CAN_CAN)
		return -EINVAL;

	err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw);
	err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
	if (err < 0)
		return err;

@@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
		if (gwj->flags != r->flags)
			continue;

		if (gwj->limit_hops != limhops)
			continue;

		if (memcmp(&gwj->mod, &mod, sizeof(mod)))
			continue;