diff options
author | David S. Miller <davem@davemloft.net> | 2013-09-03 21:54:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-09-03 21:54:02 -0400 |
commit | c12a22428ae773eff27bad490d35028fe036bf35 (patch) | |
tree | 7ca4b687b6033031b243518e6252700ffcb27340 | |
parent | e7abfe40928f4f8c1aa908477c36c13843bd1a57 (diff) | |
parent | 391ac1282dd7ff1cb8245cccc5262e8e4173edc4 (diff) |
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: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/can/mscan/mpc5xxx_can.c | 23 | ||||
-rw-r--r-- | drivers/net/can/mscan/mscan.c | 25 | ||||
-rw-r--r-- | drivers/net/can/mscan/mscan.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/can/gw.h | 9 | ||||
-rw-r--r-- | net/can/gw.c | 35 |
5 files changed, 82 insertions, 13 deletions
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 5b0ee8ef5885..e59b3a392af6 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c | |||
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data { | |||
40 | unsigned int type; | 40 | unsigned int type; |
41 | u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name, | 41 | u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name, |
42 | int *mscan_clksrc); | 42 | int *mscan_clksrc); |
43 | void (*put_clock)(struct platform_device *ofdev); | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | #ifdef CONFIG_PPC_MPC52xx | 46 | #ifdef CONFIG_PPC_MPC52xx |
@@ -148,7 +149,10 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev, | |||
148 | goto exit_put; | 149 | goto exit_put; |
149 | } | 150 | } |
150 | 151 | ||
151 | /* Determine the MSCAN device index from the physical address */ | 152 | /* Determine the MSCAN device index from the peripheral's |
153 | * physical address. Register address offsets against the | ||
154 | * IMMR base are: 0x1300, 0x1380, 0x2300, 0x2380 | ||
155 | */ | ||
152 | pval = of_get_property(ofdev->dev.of_node, "reg", &plen); | 156 | pval = of_get_property(ofdev->dev.of_node, "reg", &plen); |
153 | BUG_ON(!pval || plen < sizeof(*pval)); | 157 | BUG_ON(!pval || plen < sizeof(*pval)); |
154 | clockidx = (*pval & 0x80) ? 1 : 0; | 158 | clockidx = (*pval & 0x80) ? 1 : 0; |
@@ -177,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev, | |||
177 | clockdiv = 1; | 181 | clockdiv = 1; |
178 | 182 | ||
179 | if (!clock_name || !strcmp(clock_name, "sys")) { | 183 | if (!clock_name || !strcmp(clock_name, "sys")) { |
180 | sys_clk = clk_get(&ofdev->dev, "sys_clk"); | 184 | sys_clk = devm_clk_get(&ofdev->dev, "sys_clk"); |
181 | if (IS_ERR(sys_clk)) { | 185 | if (IS_ERR(sys_clk)) { |
182 | dev_err(&ofdev->dev, "couldn't get sys_clk\n"); | 186 | dev_err(&ofdev->dev, "couldn't get sys_clk\n"); |
183 | goto exit_unmap; | 187 | goto exit_unmap; |
@@ -200,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev, | |||
200 | } | 204 | } |
201 | 205 | ||
202 | if (clocksrc < 0) { | 206 | if (clocksrc < 0) { |
203 | ref_clk = clk_get(&ofdev->dev, "ref_clk"); | 207 | ref_clk = devm_clk_get(&ofdev->dev, "ref_clk"); |
204 | if (IS_ERR(ref_clk)) { | 208 | if (IS_ERR(ref_clk)) { |
205 | dev_err(&ofdev->dev, "couldn't get ref_clk\n"); | 209 | dev_err(&ofdev->dev, "couldn't get ref_clk\n"); |
206 | goto exit_unmap; | 210 | goto exit_unmap; |
@@ -277,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev) | |||
277 | dev = alloc_mscandev(); | 281 | dev = alloc_mscandev(); |
278 | if (!dev) | 282 | if (!dev) |
279 | goto exit_dispose_irq; | 283 | goto exit_dispose_irq; |
284 | platform_set_drvdata(ofdev, dev); | ||
285 | SET_NETDEV_DEV(dev, &ofdev->dev); | ||
280 | 286 | ||
281 | priv = netdev_priv(dev); | 287 | priv = netdev_priv(dev); |
282 | priv->reg_base = base; | 288 | priv->reg_base = base; |
@@ -293,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev) | |||
293 | goto exit_free_mscan; | 299 | goto exit_free_mscan; |
294 | } | 300 | } |
295 | 301 | ||
296 | SET_NETDEV_DEV(dev, &ofdev->dev); | ||
297 | |||
298 | err = register_mscandev(dev, mscan_clksrc); | 302 | err = register_mscandev(dev, mscan_clksrc); |
299 | if (err) { | 303 | if (err) { |
300 | dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", | 304 | dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", |
@@ -302,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev) | |||
302 | goto exit_free_mscan; | 306 | goto exit_free_mscan; |
303 | } | 307 | } |
304 | 308 | ||
305 | platform_set_drvdata(ofdev, dev); | ||
306 | |||
307 | dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n", | 309 | dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n", |
308 | priv->reg_base, dev->irq, priv->can.clock.freq); | 310 | priv->reg_base, dev->irq, priv->can.clock.freq); |
309 | 311 | ||
@@ -321,10 +323,17 @@ exit_unmap_mem: | |||
321 | 323 | ||
322 | static int mpc5xxx_can_remove(struct platform_device *ofdev) | 324 | static int mpc5xxx_can_remove(struct platform_device *ofdev) |
323 | { | 325 | { |
326 | const struct of_device_id *match; | ||
327 | const struct mpc5xxx_can_data *data; | ||
324 | struct net_device *dev = platform_get_drvdata(ofdev); | 328 | struct net_device *dev = platform_get_drvdata(ofdev); |
325 | struct mscan_priv *priv = netdev_priv(dev); | 329 | struct mscan_priv *priv = netdev_priv(dev); |
326 | 330 | ||
331 | match = of_match_device(mpc5xxx_can_table, &ofdev->dev); | ||
332 | data = match ? match->data : NULL; | ||
333 | |||
327 | unregister_mscandev(dev); | 334 | unregister_mscandev(dev); |
335 | if (data && data->put_clock) | ||
336 | data->put_clock(ofdev); | ||
328 | iounmap(priv->reg_base); | 337 | iounmap(priv->reg_base); |
329 | irq_dispose_mapping(dev->irq); | 338 | irq_dispose_mapping(dev->irq); |
330 | free_candev(dev); | 339 | free_candev(dev); |
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index e6b40954e204..a955ec8c4b97 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c | |||
@@ -573,10 +573,21 @@ static int mscan_open(struct net_device *dev) | |||
573 | struct mscan_priv *priv = netdev_priv(dev); | 573 | struct mscan_priv *priv = netdev_priv(dev); |
574 | struct mscan_regs __iomem *regs = priv->reg_base; | 574 | struct mscan_regs __iomem *regs = priv->reg_base; |
575 | 575 | ||
576 | if (priv->clk_ipg) { | ||
577 | ret = clk_prepare_enable(priv->clk_ipg); | ||
578 | if (ret) | ||
579 | goto exit_retcode; | ||
580 | } | ||
581 | if (priv->clk_can) { | ||
582 | ret = clk_prepare_enable(priv->clk_can); | ||
583 | if (ret) | ||
584 | goto exit_dis_ipg_clock; | ||
585 | } | ||
586 | |||
576 | /* common open */ | 587 | /* common open */ |
577 | ret = open_candev(dev); | 588 | ret = open_candev(dev); |
578 | if (ret) | 589 | if (ret) |
579 | return ret; | 590 | goto exit_dis_can_clock; |
580 | 591 | ||
581 | napi_enable(&priv->napi); | 592 | napi_enable(&priv->napi); |
582 | 593 | ||
@@ -604,6 +615,13 @@ exit_free_irq: | |||
604 | exit_napi_disable: | 615 | exit_napi_disable: |
605 | napi_disable(&priv->napi); | 616 | napi_disable(&priv->napi); |
606 | close_candev(dev); | 617 | close_candev(dev); |
618 | exit_dis_can_clock: | ||
619 | if (priv->clk_can) | ||
620 | clk_disable_unprepare(priv->clk_can); | ||
621 | exit_dis_ipg_clock: | ||
622 | if (priv->clk_ipg) | ||
623 | clk_disable_unprepare(priv->clk_ipg); | ||
624 | exit_retcode: | ||
607 | return ret; | 625 | return ret; |
608 | } | 626 | } |
609 | 627 | ||
@@ -621,6 +639,11 @@ static int mscan_close(struct net_device *dev) | |||
621 | close_candev(dev); | 639 | close_candev(dev); |
622 | free_irq(dev->irq, dev); | 640 | free_irq(dev->irq, dev); |
623 | 641 | ||
642 | if (priv->clk_can) | ||
643 | clk_disable_unprepare(priv->clk_can); | ||
644 | if (priv->clk_ipg) | ||
645 | clk_disable_unprepare(priv->clk_ipg); | ||
646 | |||
624 | return 0; | 647 | return 0; |
625 | } | 648 | } |
626 | 649 | ||
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h index af2ed8baf0a3..9c24d60a23b1 100644 --- a/drivers/net/can/mscan/mscan.h +++ b/drivers/net/can/mscan/mscan.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #ifndef __MSCAN_H__ | 21 | #ifndef __MSCAN_H__ |
22 | #define __MSCAN_H__ | 22 | #define __MSCAN_H__ |
23 | 23 | ||
24 | #include <linux/clk.h> | ||
24 | #include <linux/types.h> | 25 | #include <linux/types.h> |
25 | 26 | ||
26 | /* MSCAN control register 0 (CANCTL0) bits */ | 27 | /* MSCAN control register 0 (CANCTL0) bits */ |
@@ -283,6 +284,8 @@ struct mscan_priv { | |||
283 | unsigned int type; /* MSCAN type variants */ | 284 | unsigned int type; /* MSCAN type variants */ |
284 | unsigned long flags; | 285 | unsigned long flags; |
285 | void __iomem *reg_base; /* ioremap'ed address to registers */ | 286 | void __iomem *reg_base; /* ioremap'ed address to registers */ |
287 | struct clk *clk_ipg; /* clock for registers */ | ||
288 | struct clk *clk_can; /* clock for bitrates */ | ||
286 | u8 shadow_statflg; | 289 | u8 shadow_statflg; |
287 | u8 shadow_canrier; | 290 | u8 shadow_canrier; |
288 | u8 cur_pri; | 291 | u8 cur_pri; |
diff --git a/include/uapi/linux/can/gw.h b/include/uapi/linux/can/gw.h index ae07bec74f4b..4e27c82b564a 100644 --- a/include/uapi/linux/can/gw.h +++ b/include/uapi/linux/can/gw.h | |||
@@ -45,6 +45,7 @@ enum { | |||
45 | CGW_DST_IF, /* ifindex of destination network interface */ | 45 | CGW_DST_IF, /* ifindex of destination network interface */ |
46 | CGW_FILTER, /* specify struct can_filter on source CAN device */ | 46 | CGW_FILTER, /* specify struct can_filter on source CAN device */ |
47 | CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */ | 47 | CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */ |
48 | CGW_LIM_HOPS, /* limit the number of hops of this specific rule */ | ||
48 | __CGW_MAX | 49 | __CGW_MAX |
49 | }; | 50 | }; |
50 | 51 | ||
@@ -116,13 +117,19 @@ enum { | |||
116 | * Sets a CAN receive filter for the gateway job specified by the | 117 | * Sets a CAN receive filter for the gateway job specified by the |
117 | * struct can_filter described in include/linux/can.h | 118 | * struct can_filter described in include/linux/can.h |
118 | * | 119 | * |
119 | * CGW_MOD_XXX (length 17 bytes): | 120 | * CGW_MOD_(AND|OR|XOR|SET) (length 17 bytes): |
120 | * Specifies a modification that's done to a received CAN frame before it is | 121 | * Specifies a modification that's done to a received CAN frame before it is |
121 | * send out to the destination interface. | 122 | * send out to the destination interface. |
122 | * | 123 | * |
123 | * <struct can_frame> data used as operator | 124 | * <struct can_frame> data used as operator |
124 | * <u8> affected CAN frame elements | 125 | * <u8> affected CAN frame elements |
125 | * | 126 | * |
127 | * CGW_LIM_HOPS (length 1 byte): | ||
128 | * Limit the number of hops of this specific rule. Usually the received CAN | ||
129 | * frame can be processed as much as 'max_hops' times (which is given at module | ||
130 | * load time of the can-gw module). This value is used to reduce the number of | ||
131 | * possible hops for this gateway rule to a value smaller then max_hops. | ||
132 | * | ||
126 | * CGW_CS_XOR (length 4 bytes): | 133 | * CGW_CS_XOR (length 4 bytes): |
127 | * Set a simple XOR checksum starting with an initial value into | 134 | * Set a simple XOR checksum starting with an initial value into |
128 | * data[result-idx] using data[start-idx] .. data[end-idx] | 135 | * data[result-idx] using data[start-idx] .. data[end-idx] |
diff --git a/net/can/gw.c b/net/can/gw.c index 2f291f961a17..3f9b0f3a2818 100644 --- a/net/can/gw.c +++ b/net/can/gw.c | |||
@@ -146,6 +146,7 @@ struct cgw_job { | |||
146 | /* tbc */ | 146 | /* tbc */ |
147 | }; | 147 | }; |
148 | u8 gwtype; | 148 | u8 gwtype; |
149 | u8 limit_hops; | ||
149 | u16 flags; | 150 | u16 flags; |
150 | }; | 151 | }; |
151 | 152 | ||
@@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
402 | 403 | ||
403 | /* put the incremented hop counter in the cloned skb */ | 404 | /* put the incremented hop counter in the cloned skb */ |
404 | cgw_hops(nskb) = cgw_hops(skb) + 1; | 405 | cgw_hops(nskb) = cgw_hops(skb) + 1; |
406 | |||
407 | /* first processing of this CAN frame -> adjust to private hop limit */ | ||
408 | if (gwj->limit_hops && cgw_hops(nskb) == 1) | ||
409 | cgw_hops(nskb) = max_hops - gwj->limit_hops + 1; | ||
410 | |||
405 | nskb->dev = gwj->dst.dev; | 411 | nskb->dev = gwj->dst.dev; |
406 | 412 | ||
407 | /* pointer to modifiable CAN frame */ | 413 | /* pointer to modifiable CAN frame */ |
@@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, | |||
509 | 515 | ||
510 | /* check non default settings of attributes */ | 516 | /* check non default settings of attributes */ |
511 | 517 | ||
518 | if (gwj->limit_hops) { | ||
519 | if (nla_put_u8(skb, CGW_LIM_HOPS, gwj->limit_hops) < 0) | ||
520 | goto cancel; | ||
521 | } | ||
522 | |||
512 | if (gwj->mod.modtype.and) { | 523 | if (gwj->mod.modtype.and) { |
513 | memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); | 524 | memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); |
514 | mb.modtype = gwj->mod.modtype.and; | 525 | mb.modtype = gwj->mod.modtype.and; |
@@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = { | |||
606 | [CGW_SRC_IF] = { .type = NLA_U32 }, | 617 | [CGW_SRC_IF] = { .type = NLA_U32 }, |
607 | [CGW_DST_IF] = { .type = NLA_U32 }, | 618 | [CGW_DST_IF] = { .type = NLA_U32 }, |
608 | [CGW_FILTER] = { .len = sizeof(struct can_filter) }, | 619 | [CGW_FILTER] = { .len = sizeof(struct can_filter) }, |
620 | [CGW_LIM_HOPS] = { .type = NLA_U8 }, | ||
609 | }; | 621 | }; |
610 | 622 | ||
611 | /* check for common and gwtype specific attributes */ | 623 | /* check for common and gwtype specific attributes */ |
612 | static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, | 624 | static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, |
613 | u8 gwtype, void *gwtypeattr) | 625 | u8 gwtype, void *gwtypeattr, u8 *limhops) |
614 | { | 626 | { |
615 | struct nlattr *tb[CGW_MAX+1]; | 627 | struct nlattr *tb[CGW_MAX+1]; |
616 | struct cgw_frame_mod mb; | 628 | struct cgw_frame_mod mb; |
@@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, | |||
625 | if (err < 0) | 637 | if (err < 0) |
626 | return err; | 638 | return err; |
627 | 639 | ||
640 | if (tb[CGW_LIM_HOPS]) { | ||
641 | *limhops = nla_get_u8(tb[CGW_LIM_HOPS]); | ||
642 | |||
643 | if (*limhops < 1 || *limhops > max_hops) | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
628 | /* check for AND/OR/XOR/SET modifications */ | 647 | /* check for AND/OR/XOR/SET modifications */ |
629 | 648 | ||
630 | if (tb[CGW_MOD_AND]) { | 649 | if (tb[CGW_MOD_AND]) { |
@@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
782 | { | 801 | { |
783 | struct rtcanmsg *r; | 802 | struct rtcanmsg *r; |
784 | struct cgw_job *gwj; | 803 | struct cgw_job *gwj; |
804 | u8 limhops = 0; | ||
785 | int err = 0; | 805 | int err = 0; |
786 | 806 | ||
787 | if (!capable(CAP_NET_ADMIN)) | 807 | if (!capable(CAP_NET_ADMIN)) |
@@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
808 | gwj->flags = r->flags; | 828 | gwj->flags = r->flags; |
809 | gwj->gwtype = r->gwtype; | 829 | gwj->gwtype = r->gwtype; |
810 | 830 | ||
811 | err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw); | 831 | err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw, |
832 | &limhops); | ||
812 | if (err < 0) | 833 | if (err < 0) |
813 | goto out; | 834 | goto out; |
814 | 835 | ||
@@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
836 | if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops) | 857 | if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops) |
837 | goto put_src_dst_out; | 858 | goto put_src_dst_out; |
838 | 859 | ||
860 | gwj->limit_hops = limhops; | ||
861 | |||
839 | ASSERT_RTNL(); | 862 | ASSERT_RTNL(); |
840 | 863 | ||
841 | err = cgw_register_filter(gwj); | 864 | err = cgw_register_filter(gwj); |
@@ -867,13 +890,14 @@ static void cgw_remove_all_jobs(void) | |||
867 | } | 890 | } |
868 | } | 891 | } |
869 | 892 | ||
870 | static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | 893 | static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) |
871 | { | 894 | { |
872 | struct cgw_job *gwj = NULL; | 895 | struct cgw_job *gwj = NULL; |
873 | struct hlist_node *nx; | 896 | struct hlist_node *nx; |
874 | struct rtcanmsg *r; | 897 | struct rtcanmsg *r; |
875 | struct cf_mod mod; | 898 | struct cf_mod mod; |
876 | struct can_can_gw ccgw; | 899 | struct can_can_gw ccgw; |
900 | u8 limhops = 0; | ||
877 | int err = 0; | 901 | int err = 0; |
878 | 902 | ||
879 | if (!capable(CAP_NET_ADMIN)) | 903 | if (!capable(CAP_NET_ADMIN)) |
@@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
890 | if (r->gwtype != CGW_TYPE_CAN_CAN) | 914 | if (r->gwtype != CGW_TYPE_CAN_CAN) |
891 | return -EINVAL; | 915 | return -EINVAL; |
892 | 916 | ||
893 | err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw); | 917 | err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); |
894 | if (err < 0) | 918 | if (err < 0) |
895 | return err; | 919 | return err; |
896 | 920 | ||
@@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
910 | if (gwj->flags != r->flags) | 934 | if (gwj->flags != r->flags) |
911 | continue; | 935 | continue; |
912 | 936 | ||
937 | if (gwj->limit_hops != limhops) | ||
938 | continue; | ||
939 | |||
913 | if (memcmp(&gwj->mod, &mod, sizeof(mod))) | 940 | if (memcmp(&gwj->mod, &mod, sizeof(mod))) |
914 | continue; | 941 | continue; |
915 | 942 | ||