aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-09-03 21:54:02 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-03 21:54:02 -0400
commitc12a22428ae773eff27bad490d35028fe036bf35 (patch)
tree7ca4b687b6033031b243518e6252700ffcb27340
parente7abfe40928f4f8c1aa908477c36c13843bd1a57 (diff)
parent391ac1282dd7ff1cb8245cccc5262e8e4173edc4 (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.c23
-rw-r--r--drivers/net/can/mscan/mscan.c25
-rw-r--r--drivers/net/can/mscan/mscan.h3
-rw-r--r--include/uapi/linux/can/gw.h9
-rw-r--r--net/can/gw.c35
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
322static int mpc5xxx_can_remove(struct platform_device *ofdev) 324static 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:
604exit_napi_disable: 615exit_napi_disable:
605 napi_disable(&priv->napi); 616 napi_disable(&priv->napi);
606 close_candev(dev); 617 close_candev(dev);
618exit_dis_can_clock:
619 if (priv->clk_can)
620 clk_disable_unprepare(priv->clk_can);
621exit_dis_ipg_clock:
622 if (priv->clk_ipg)
623 clk_disable_unprepare(priv->clk_ipg);
624exit_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 */
612static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, 624static 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
870static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) 893static 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