aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-06-19 17:47:13 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-19 17:47:13 -0400
commit3879d4e3977329607a2a8042483140af3581b5c3 (patch)
treec9e8cd2b3a99ddc917bced812fa2265150d45c44 /drivers/net
parenta77f4b4acf5b77f038bc11d3ca9b3af6f0124015 (diff)
parentea53fe0c667ad3cae61d4d71d2be41908ac5c0a4 (diff)
Merge branch 'master' of git://gitorious.org/linux-can/linux-can-next
Marc Kleine-Budde says: ==================== here is our second pull request for net-next. In this series Federico Vaga adds a pci driver for c_can/d_can hardware using the existing generic c_can driver. The remaining 6 patches are by Oliver Hartkopp. He adds CANFD support to the CAN stack while keeping binary compatibility for existing applications. CANFD is an extension to the existing CAN standard, it allows longer CAN frames and/or higher data rates. There's no real hardware available yet, but this series adds CANFD support to the vcan driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/can/c_can/Kconfig7
-rw-r--r--drivers/net/can/c_can/Makefile1
-rw-r--r--drivers/net/can/c_can/c_can_pci.c236
-rw-r--r--drivers/net/can/dev.c35
-rw-r--r--drivers/net/can/vcan.c27
5 files changed, 298 insertions, 8 deletions
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 25d371cf98dd..3b83bafcd947 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -13,4 +13,11 @@ config CAN_C_CAN_PLATFORM
13 boards from ST Microelectronics (http://www.st.com) like the 13 boards from ST Microelectronics (http://www.st.com) like the
14 SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com) 14 SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
15 boards like am335x, dm814x, dm813x and dm811x. 15 boards like am335x, dm814x, dm813x and dm811x.
16
17config CAN_C_CAN_PCI
18 tristate "Generic PCI Bus based C_CAN/D_CAN driver"
19 depends on PCI
20 ---help---
21 This driver adds support for the C_CAN/D_CAN chips connected
22 to the PCI bus.
16endif 23endif
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
index 9273f6d5c4b7..ad1cc842170a 100644
--- a/drivers/net/can/c_can/Makefile
+++ b/drivers/net/can/c_can/Makefile
@@ -4,5 +4,6 @@
4 4
5obj-$(CONFIG_CAN_C_CAN) += c_can.o 5obj-$(CONFIG_CAN_C_CAN) += c_can.o
6obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o 6obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
7obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
7 8
8ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG 9ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c
new file mode 100644
index 000000000000..914aecfa09a9
--- /dev/null
+++ b/drivers/net/can/c_can/c_can_pci.c
@@ -0,0 +1,236 @@
1/*
2 * PCI bus driver for Bosch C_CAN/D_CAN controller
3 *
4 * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
5 *
6 * Borrowed from c_can_platform.c
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/netdevice.h>
16#include <linux/clk.h>
17#include <linux/pci.h>
18
19#include <linux/can/dev.h>
20
21#include "c_can.h"
22
23enum c_can_pci_reg_align {
24 C_CAN_REG_ALIGN_16,
25 C_CAN_REG_ALIGN_32,
26};
27
28struct c_can_pci_data {
29 /* Specify if is C_CAN or D_CAN */
30 enum c_can_dev_id type;
31 /* Set the register alignment in the memory */
32 enum c_can_pci_reg_align reg_align;
33 /* Set the frequency if clk is not usable */
34 unsigned int freq;
35};
36
37/*
38 * 16-bit c_can registers can be arranged differently in the memory
39 * architecture of different implementations. For example: 16-bit
40 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
41 * Handle the same by providing a common read/write interface.
42 */
43static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
44 enum reg index)
45{
46 return readw(priv->base + priv->regs[index]);
47}
48
49static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
50 enum reg index, u16 val)
51{
52 writew(val, priv->base + priv->regs[index]);
53}
54
55static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
56 enum reg index)
57{
58 return readw(priv->base + 2 * priv->regs[index]);
59}
60
61static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
62 enum reg index, u16 val)
63{
64 writew(val, priv->base + 2 * priv->regs[index]);
65}
66
67static int __devinit c_can_pci_probe(struct pci_dev *pdev,
68 const struct pci_device_id *ent)
69{
70 struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
71 struct c_can_priv *priv;
72 struct net_device *dev;
73 void __iomem *addr;
74 struct clk *clk;
75 int ret;
76
77 ret = pci_enable_device(pdev);
78 if (ret) {
79 dev_err(&pdev->dev, "pci_enable_device FAILED\n");
80 goto out;
81 }
82
83 ret = pci_request_regions(pdev, KBUILD_MODNAME);
84 if (ret) {
85 dev_err(&pdev->dev, "pci_request_regions FAILED\n");
86 goto out_disable_device;
87 }
88
89 pci_set_master(pdev);
90 pci_enable_msi(pdev);
91
92 addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
93 if (!addr) {
94 dev_err(&pdev->dev,
95 "device has no PCI memory resources, "
96 "failing adapter\n");
97 ret = -ENOMEM;
98 goto out_release_regions;
99 }
100
101 /* allocate the c_can device */
102 dev = alloc_c_can_dev();
103 if (!dev) {
104 ret = -ENOMEM;
105 goto out_iounmap;
106 }
107
108 priv = netdev_priv(dev);
109 pci_set_drvdata(pdev, dev);
110 SET_NETDEV_DEV(dev, &pdev->dev);
111
112 dev->irq = pdev->irq;
113 priv->base = addr;
114
115 if (!c_can_pci_data->freq) {
116 /* get the appropriate clk */
117 clk = clk_get(&pdev->dev, NULL);
118 if (IS_ERR(clk)) {
119 dev_err(&pdev->dev, "no clock defined\n");
120 ret = -ENODEV;
121 goto out_free_c_can;
122 }
123 priv->can.clock.freq = clk_get_rate(clk);
124 priv->priv = clk;
125 } else {
126 priv->can.clock.freq = c_can_pci_data->freq;
127 priv->priv = NULL;
128 }
129
130 /* Configure CAN type */
131 switch (c_can_pci_data->type) {
132 case C_CAN_DEVTYPE:
133 priv->regs = reg_map_c_can;
134 break;
135 case D_CAN_DEVTYPE:
136 priv->regs = reg_map_d_can;
137 priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
138 break;
139 default:
140 ret = -EINVAL;
141 goto out_free_clock;
142 }
143
144 /* Configure access to registers */
145 switch (c_can_pci_data->reg_align) {
146 case C_CAN_REG_ALIGN_32:
147 priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
148 priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
149 break;
150 case C_CAN_REG_ALIGN_16:
151 priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
152 priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
153 break;
154 default:
155 ret = -EINVAL;
156 goto out_free_clock;
157 }
158
159 ret = register_c_can_dev(dev);
160 if (ret) {
161 dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
162 KBUILD_MODNAME, ret);
163 goto out_free_clock;
164 }
165
166 dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
167 KBUILD_MODNAME, priv->regs, dev->irq);
168
169 return 0;
170
171out_free_clock:
172 if (priv->priv)
173 clk_put(priv->priv);
174out_free_c_can:
175 pci_set_drvdata(pdev, NULL);
176 free_c_can_dev(dev);
177out_iounmap:
178 pci_iounmap(pdev, addr);
179out_release_regions:
180 pci_disable_msi(pdev);
181 pci_clear_master(pdev);
182 pci_release_regions(pdev);
183out_disable_device:
184 pci_disable_device(pdev);
185out:
186 return ret;
187}
188
189static void __devexit c_can_pci_remove(struct pci_dev *pdev)
190{
191 struct net_device *dev = pci_get_drvdata(pdev);
192 struct c_can_priv *priv = netdev_priv(dev);
193
194 unregister_c_can_dev(dev);
195
196 if (priv->priv)
197 clk_put(priv->priv);
198
199 pci_set_drvdata(pdev, NULL);
200 free_c_can_dev(dev);
201
202 pci_iounmap(pdev, priv->base);
203 pci_disable_msi(pdev);
204 pci_clear_master(pdev);
205 pci_release_regions(pdev);
206 pci_disable_device(pdev);
207}
208
209static struct c_can_pci_data c_can_sta2x11= {
210 .type = C_CAN_DEVTYPE,
211 .reg_align = C_CAN_REG_ALIGN_32,
212 .freq = 52000000, /* 52 Mhz */
213};
214
215#define C_CAN_ID(_vend, _dev, _driverdata) { \
216 PCI_DEVICE(_vend, _dev), \
217 .driver_data = (unsigned long)&_driverdata, \
218}
219static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
220 C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
221 c_can_sta2x11),
222 {},
223};
224static struct pci_driver c_can_pci_driver = {
225 .name = KBUILD_MODNAME,
226 .id_table = c_can_pci_tbl,
227 .probe = c_can_pci_probe,
228 .remove = __devexit_p(c_can_pci_remove),
229};
230
231module_pci_driver(c_can_pci_driver);
232
233MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
234MODULE_LICENSE("GPL v2");
235MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
236MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index f03d7a481a80..239e4dd92ca1 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC);
33MODULE_LICENSE("GPL v2"); 33MODULE_LICENSE("GPL v2");
34MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); 34MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
35 35
36/* CAN DLC to real data length conversion helpers */
37
38static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
39 8, 12, 16, 20, 24, 32, 48, 64};
40
41/* get data length from can_dlc with sanitized can_dlc */
42u8 can_dlc2len(u8 can_dlc)
43{
44 return dlc2len[can_dlc & 0x0F];
45}
46EXPORT_SYMBOL_GPL(can_dlc2len);
47
48static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
49 9, 9, 9, 9, /* 9 - 12 */
50 10, 10, 10, 10, /* 13 - 16 */
51 11, 11, 11, 11, /* 17 - 20 */
52 12, 12, 12, 12, /* 21 - 24 */
53 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
54 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
55 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
56 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
57 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
58
59/* map the sanitized data length to an appropriate data length code */
60u8 can_len2dlc(u8 len)
61{
62 if (unlikely(len > 64))
63 return 0xF;
64
65 return len2dlc[len];
66}
67EXPORT_SYMBOL_GPL(can_len2dlc);
68
36#ifdef CONFIG_CAN_CALC_BITTIMING 69#ifdef CONFIG_CAN_CALC_BITTIMING
37#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ 70#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
38 71
@@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
454static void can_setup(struct net_device *dev) 487static void can_setup(struct net_device *dev)
455{ 488{
456 dev->type = ARPHRD_CAN; 489 dev->type = ARPHRD_CAN;
457 dev->mtu = sizeof(struct can_frame); 490 dev->mtu = CAN_MTU;
458 dev->hard_header_len = 0; 491 dev->hard_header_len = 0;
459 dev->addr_len = 0; 492 dev->addr_len = 0;
460 dev->tx_queue_len = 10; 493 dev->tx_queue_len = 10;
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index ea2d94285936..4f93c0be0053 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -70,13 +70,12 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
70 70
71static void vcan_rx(struct sk_buff *skb, struct net_device *dev) 71static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
72{ 72{
73 struct can_frame *cf = (struct can_frame *)skb->data; 73 struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
74 struct net_device_stats *stats = &dev->stats; 74 struct net_device_stats *stats = &dev->stats;
75 75
76 stats->rx_packets++; 76 stats->rx_packets++;
77 stats->rx_bytes += cf->can_dlc; 77 stats->rx_bytes += cfd->len;
78 78
79 skb->protocol = htons(ETH_P_CAN);
80 skb->pkt_type = PACKET_BROADCAST; 79 skb->pkt_type = PACKET_BROADCAST;
81 skb->dev = dev; 80 skb->dev = dev;
82 skb->ip_summed = CHECKSUM_UNNECESSARY; 81 skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -86,7 +85,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
86 85
87static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) 86static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
88{ 87{
89 struct can_frame *cf = (struct can_frame *)skb->data; 88 struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
90 struct net_device_stats *stats = &dev->stats; 89 struct net_device_stats *stats = &dev->stats;
91 int loop; 90 int loop;
92 91
@@ -94,7 +93,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
94 return NETDEV_TX_OK; 93 return NETDEV_TX_OK;
95 94
96 stats->tx_packets++; 95 stats->tx_packets++;
97 stats->tx_bytes += cf->can_dlc; 96 stats->tx_bytes += cfd->len;
98 97
99 /* set flag whether this packet has to be looped back */ 98 /* set flag whether this packet has to be looped back */
100 loop = skb->pkt_type == PACKET_LOOPBACK; 99 loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -108,7 +107,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
108 * CAN core already did the echo for us 107 * CAN core already did the echo for us
109 */ 108 */
110 stats->rx_packets++; 109 stats->rx_packets++;
111 stats->rx_bytes += cf->can_dlc; 110 stats->rx_bytes += cfd->len;
112 } 111 }
113 kfree_skb(skb); 112 kfree_skb(skb);
114 return NETDEV_TX_OK; 113 return NETDEV_TX_OK;
@@ -133,14 +132,28 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
133 return NETDEV_TX_OK; 132 return NETDEV_TX_OK;
134} 133}
135 134
135static int vcan_change_mtu(struct net_device *dev, int new_mtu)
136{
137 /* Do not allow changing the MTU while running */
138 if (dev->flags & IFF_UP)
139 return -EBUSY;
140
141 if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
142 return -EINVAL;
143
144 dev->mtu = new_mtu;
145 return 0;
146}
147
136static const struct net_device_ops vcan_netdev_ops = { 148static const struct net_device_ops vcan_netdev_ops = {
137 .ndo_start_xmit = vcan_tx, 149 .ndo_start_xmit = vcan_tx,
150 .ndo_change_mtu = vcan_change_mtu,
138}; 151};
139 152
140static void vcan_setup(struct net_device *dev) 153static void vcan_setup(struct net_device *dev)
141{ 154{
142 dev->type = ARPHRD_CAN; 155 dev->type = ARPHRD_CAN;
143 dev->mtu = sizeof(struct can_frame); 156 dev->mtu = CAN_MTU;
144 dev->hard_header_len = 0; 157 dev->hard_header_len = 0;
145 dev->addr_len = 0; 158 dev->addr_len = 0;
146 dev->tx_queue_len = 0; 159 dev->tx_queue_len = 0;