diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-at91 | 25 | ||||
-rw-r--r-- | drivers/net/can/at91_can.c | 90 |
2 files changed, 108 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-at91 b/Documentation/ABI/testing/sysfs-platform-at91 new file mode 100644 index 00000000000..4cc6a865ae6 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-at91 | |||
@@ -0,0 +1,25 @@ | |||
1 | What: /sys/devices/platform/at91_can/net/<iface>/mb0_id | ||
2 | Date: January 2011 | ||
3 | KernelVersion: 2.6.38 | ||
4 | Contact: Marc Kleine-Budde <kernel@pengutronix.de> | ||
5 | Description: | ||
6 | Value representing the can_id of mailbox 0. | ||
7 | |||
8 | Default: 0x7ff (standard frame) | ||
9 | |||
10 | Due to a chip bug (errata 50.2.6.3 & 50.3.5.3 in | ||
11 | "AT91SAM9263 Preliminary 6249H-ATARM-27-Jul-09") the | ||
12 | contents of mailbox 0 may be send under certain | ||
13 | conditions (even if disabled or in rx mode). | ||
14 | |||
15 | The workaround in the errata suggests not to use the | ||
16 | mailbox and load it with an unused identifier. | ||
17 | |||
18 | In order to use an extended can_id add the | ||
19 | CAN_EFF_FLAG (0x80000000U) to the can_id. Example: | ||
20 | |||
21 | - standard id 0x7ff: | ||
22 | echo 0x7ff > /sys/class/net/can0/mb0_id | ||
23 | |||
24 | - extended id 0x1fffffff: | ||
25 | echo 0x9fffffff > /sys/class/net/can0/mb0_id | ||
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 16e45a51cbb..2532b963153 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/rtnetlink.h> | ||
33 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
34 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
35 | #include <linux/string.h> | 36 | #include <linux/string.h> |
@@ -169,6 +170,8 @@ struct at91_priv { | |||
169 | 170 | ||
170 | struct clk *clk; | 171 | struct clk *clk; |
171 | struct at91_can_data *pdata; | 172 | struct at91_can_data *pdata; |
173 | |||
174 | canid_t mb0_id; | ||
172 | }; | 175 | }; |
173 | 176 | ||
174 | static struct can_bittiming_const at91_bittiming_const = { | 177 | static struct can_bittiming_const at91_bittiming_const = { |
@@ -221,6 +224,18 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb, | |||
221 | set_mb_mode_prio(priv, mb, mode, 0); | 224 | set_mb_mode_prio(priv, mb, mode, 0); |
222 | } | 225 | } |
223 | 226 | ||
227 | static inline u32 at91_can_id_to_reg_mid(canid_t can_id) | ||
228 | { | ||
229 | u32 reg_mid; | ||
230 | |||
231 | if (can_id & CAN_EFF_FLAG) | ||
232 | reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE; | ||
233 | else | ||
234 | reg_mid = (can_id & CAN_SFF_MASK) << 18; | ||
235 | |||
236 | return reg_mid; | ||
237 | } | ||
238 | |||
224 | /* | 239 | /* |
225 | * Swtich transceiver on or off | 240 | * Swtich transceiver on or off |
226 | */ | 241 | */ |
@@ -234,6 +249,7 @@ static void at91_setup_mailboxes(struct net_device *dev) | |||
234 | { | 249 | { |
235 | struct at91_priv *priv = netdev_priv(dev); | 250 | struct at91_priv *priv = netdev_priv(dev); |
236 | unsigned int i; | 251 | unsigned int i; |
252 | u32 reg_mid; | ||
237 | 253 | ||
238 | /* | 254 | /* |
239 | * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first | 255 | * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first |
@@ -242,8 +258,13 @@ static void at91_setup_mailboxes(struct net_device *dev) | |||
242 | * overwrite option. The overwrite flag indicates a FIFO | 258 | * overwrite option. The overwrite flag indicates a FIFO |
243 | * overflow. | 259 | * overflow. |
244 | */ | 260 | */ |
245 | for (i = 0; i < AT91_MB_RX_FIRST; i++) | 261 | reg_mid = at91_can_id_to_reg_mid(priv->mb0_id); |
262 | for (i = 0; i < AT91_MB_RX_FIRST; i++) { | ||
246 | set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); | 263 | set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); |
264 | at91_write(priv, AT91_MID(i), reg_mid); | ||
265 | at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */ | ||
266 | } | ||
267 | |||
247 | for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) | 268 | for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) |
248 | set_mb_mode(priv, i, AT91_MB_MODE_RX); | 269 | set_mb_mode(priv, i, AT91_MB_MODE_RX); |
249 | set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); | 270 | set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); |
@@ -378,12 +399,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
378 | netdev_err(dev, "BUG! TX buffer full when queue awake!\n"); | 399 | netdev_err(dev, "BUG! TX buffer full when queue awake!\n"); |
379 | return NETDEV_TX_BUSY; | 400 | return NETDEV_TX_BUSY; |
380 | } | 401 | } |
381 | 402 | reg_mid = at91_can_id_to_reg_mid(cf->can_id); | |
382 | if (cf->can_id & CAN_EFF_FLAG) | ||
383 | reg_mid = (cf->can_id & CAN_EFF_MASK) | AT91_MID_MIDE; | ||
384 | else | ||
385 | reg_mid = (cf->can_id & CAN_SFF_MASK) << 18; | ||
386 | |||
387 | reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) | | 403 | reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) | |
388 | (cf->can_dlc << 16) | AT91_MCR_MTCR; | 404 | (cf->can_dlc << 16) | AT91_MCR_MTCR; |
389 | 405 | ||
@@ -1047,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = { | |||
1047 | .ndo_start_xmit = at91_start_xmit, | 1063 | .ndo_start_xmit = at91_start_xmit, |
1048 | }; | 1064 | }; |
1049 | 1065 | ||
1066 | static ssize_t at91_sysfs_show_mb0_id(struct device *dev, | ||
1067 | struct device_attribute *attr, char *buf) | ||
1068 | { | ||
1069 | struct at91_priv *priv = netdev_priv(to_net_dev(dev)); | ||
1070 | |||
1071 | if (priv->mb0_id & CAN_EFF_FLAG) | ||
1072 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id); | ||
1073 | else | ||
1074 | return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id); | ||
1075 | } | ||
1076 | |||
1077 | static ssize_t at91_sysfs_set_mb0_id(struct device *dev, | ||
1078 | struct device_attribute *attr, const char *buf, size_t count) | ||
1079 | { | ||
1080 | struct net_device *ndev = to_net_dev(dev); | ||
1081 | struct at91_priv *priv = netdev_priv(ndev); | ||
1082 | unsigned long can_id; | ||
1083 | ssize_t ret; | ||
1084 | int err; | ||
1085 | |||
1086 | rtnl_lock(); | ||
1087 | |||
1088 | if (ndev->flags & IFF_UP) { | ||
1089 | ret = -EBUSY; | ||
1090 | goto out; | ||
1091 | } | ||
1092 | |||
1093 | err = strict_strtoul(buf, 0, &can_id); | ||
1094 | if (err) { | ||
1095 | ret = err; | ||
1096 | goto out; | ||
1097 | } | ||
1098 | |||
1099 | if (can_id & CAN_EFF_FLAG) | ||
1100 | can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; | ||
1101 | else | ||
1102 | can_id &= CAN_SFF_MASK; | ||
1103 | |||
1104 | priv->mb0_id = can_id; | ||
1105 | ret = count; | ||
1106 | |||
1107 | out: | ||
1108 | rtnl_unlock(); | ||
1109 | return ret; | ||
1110 | } | ||
1111 | |||
1112 | static DEVICE_ATTR(mb0_id, S_IWUGO | S_IRUGO, | ||
1113 | at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id); | ||
1114 | |||
1115 | static struct attribute *at91_sysfs_attrs[] = { | ||
1116 | &dev_attr_mb0_id.attr, | ||
1117 | NULL, | ||
1118 | }; | ||
1119 | |||
1120 | static struct attribute_group at91_sysfs_attr_group = { | ||
1121 | .attrs = at91_sysfs_attrs, | ||
1122 | }; | ||
1123 | |||
1050 | static int __devinit at91_can_probe(struct platform_device *pdev) | 1124 | static int __devinit at91_can_probe(struct platform_device *pdev) |
1051 | { | 1125 | { |
1052 | struct net_device *dev; | 1126 | struct net_device *dev; |
@@ -1092,6 +1166,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) | |||
1092 | dev->netdev_ops = &at91_netdev_ops; | 1166 | dev->netdev_ops = &at91_netdev_ops; |
1093 | dev->irq = irq; | 1167 | dev->irq = irq; |
1094 | dev->flags |= IFF_ECHO; | 1168 | dev->flags |= IFF_ECHO; |
1169 | dev->sysfs_groups[0] = &at91_sysfs_attr_group; | ||
1095 | 1170 | ||
1096 | priv = netdev_priv(dev); | 1171 | priv = netdev_priv(dev); |
1097 | priv->can.clock.freq = clk_get_rate(clk); | 1172 | priv->can.clock.freq = clk_get_rate(clk); |
@@ -1103,6 +1178,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) | |||
1103 | priv->dev = dev; | 1178 | priv->dev = dev; |
1104 | priv->clk = clk; | 1179 | priv->clk = clk; |
1105 | priv->pdata = pdev->dev.platform_data; | 1180 | priv->pdata = pdev->dev.platform_data; |
1181 | priv->mb0_id = 0x7ff; | ||
1106 | 1182 | ||
1107 | netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); | 1183 | netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); |
1108 | 1184 | ||