diff options
-rw-r--r-- | drivers/net/ethernet/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/Kconfig | 30 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/Makefile | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_7k.c | 149 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_7k.h | 72 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_debug.c | 311 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_debug.h | 34 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_framing.c | 156 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_framing.h | 134 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_spi.c | 993 | ||||
-rw-r--r-- | drivers/net/ethernet/qualcomm/qca_spi.h | 114 |
12 files changed, 2001 insertions, 0 deletions
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index dc7406c81c45..0005e3792e6d 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig | |||
@@ -150,6 +150,7 @@ config ETHOC | |||
150 | source "drivers/net/ethernet/packetengines/Kconfig" | 150 | source "drivers/net/ethernet/packetengines/Kconfig" |
151 | source "drivers/net/ethernet/pasemi/Kconfig" | 151 | source "drivers/net/ethernet/pasemi/Kconfig" |
152 | source "drivers/net/ethernet/qlogic/Kconfig" | 152 | source "drivers/net/ethernet/qlogic/Kconfig" |
153 | source "drivers/net/ethernet/qualcomm/Kconfig" | ||
153 | source "drivers/net/ethernet/realtek/Kconfig" | 154 | source "drivers/net/ethernet/realtek/Kconfig" |
154 | source "drivers/net/ethernet/renesas/Kconfig" | 155 | source "drivers/net/ethernet/renesas/Kconfig" |
155 | source "drivers/net/ethernet/rdc/Kconfig" | 156 | source "drivers/net/ethernet/rdc/Kconfig" |
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 224a01877149..153bf2dd9fad 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile | |||
@@ -60,6 +60,7 @@ obj-$(CONFIG_ETHOC) += ethoc.o | |||
60 | obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/ | 60 | obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/ |
61 | obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/ | 61 | obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/ |
62 | obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/ | 62 | obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/ |
63 | obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/ | ||
63 | obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ | 64 | obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ |
64 | obj-$(CONFIG_SH_ETH) += renesas/ | 65 | obj-$(CONFIG_SH_ETH) += renesas/ |
65 | obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ | 66 | obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ |
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig new file mode 100644 index 000000000000..f3a47147937d --- /dev/null +++ b/drivers/net/ethernet/qualcomm/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # Qualcomm network device configuration | ||
3 | # | ||
4 | |||
5 | config NET_VENDOR_QUALCOMM | ||
6 | bool "Qualcomm devices" | ||
7 | default y | ||
8 | depends on SPI_MASTER && OF_GPIO | ||
9 | ---help--- | ||
10 | If you have a network (Ethernet) card belonging to this class, say Y | ||
11 | and read the Ethernet-HOWTO, available from | ||
12 | <http://www.tldp.org/docs.html#howto>. | ||
13 | |||
14 | Note that the answer to this question doesn't directly affect the | ||
15 | kernel: saying N will just cause the configurator to skip all | ||
16 | the questions about Qualcomm cards. If you say Y, you will be asked | ||
17 | for your specific card in the following questions. | ||
18 | |||
19 | if NET_VENDOR_QUALCOMM | ||
20 | |||
21 | config QCA7000 | ||
22 | tristate "Qualcomm Atheros QCA7000 support" | ||
23 | depends on SPI_MASTER && OF_GPIO | ||
24 | ---help--- | ||
25 | This SPI protocol driver supports the Qualcomm Atheros QCA7000. | ||
26 | |||
27 | To compile this driver as a module, choose M here. The module | ||
28 | will be called qcaspi. | ||
29 | |||
30 | endif # NET_VENDOR_QUALCOMM | ||
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile new file mode 100644 index 000000000000..9da2d75db700 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the Qualcomm network device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_QCA7000) += qcaspi.o | ||
6 | qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c new file mode 100644 index 000000000000..f0066fbb44a6 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_7k.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
4 | * Copyright (c) 2014, I2SE GmbH | ||
5 | * | ||
6 | * Permission to use, copy, modify, and/or distribute this software | ||
7 | * for any purpose with or without fee is hereby granted, provided | ||
8 | * that the above copyright notice and this permission notice appear | ||
9 | * in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
12 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
13 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
14 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
15 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
16 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
17 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
18 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* This module implements the Qualcomm Atheros SPI protocol for | ||
23 | * kernel-based SPI device. | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/version.h> | ||
31 | |||
32 | #include "qca_7k.h" | ||
33 | |||
34 | void | ||
35 | qcaspi_spi_error(struct qcaspi *qca) | ||
36 | { | ||
37 | if (qca->sync != QCASPI_SYNC_READY) | ||
38 | return; | ||
39 | |||
40 | netdev_err(qca->net_dev, "spi error\n"); | ||
41 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
42 | qca->stats.spi_err++; | ||
43 | } | ||
44 | |||
45 | int | ||
46 | qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result) | ||
47 | { | ||
48 | __be16 rx_data; | ||
49 | __be16 tx_data; | ||
50 | struct spi_transfer *transfer; | ||
51 | struct spi_message *msg; | ||
52 | int ret; | ||
53 | |||
54 | tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg); | ||
55 | |||
56 | if (qca->legacy_mode) { | ||
57 | msg = &qca->spi_msg1; | ||
58 | transfer = &qca->spi_xfer1; | ||
59 | transfer->tx_buf = &tx_data; | ||
60 | transfer->rx_buf = NULL; | ||
61 | transfer->len = QCASPI_CMD_LEN; | ||
62 | spi_sync(qca->spi_dev, msg); | ||
63 | } else { | ||
64 | msg = &qca->spi_msg2; | ||
65 | transfer = &qca->spi_xfer2[0]; | ||
66 | transfer->tx_buf = &tx_data; | ||
67 | transfer->rx_buf = NULL; | ||
68 | transfer->len = QCASPI_CMD_LEN; | ||
69 | transfer = &qca->spi_xfer2[1]; | ||
70 | } | ||
71 | transfer->tx_buf = NULL; | ||
72 | transfer->rx_buf = &rx_data; | ||
73 | transfer->len = QCASPI_CMD_LEN; | ||
74 | ret = spi_sync(qca->spi_dev, msg); | ||
75 | |||
76 | if (!ret) | ||
77 | ret = msg->status; | ||
78 | |||
79 | if (ret) | ||
80 | qcaspi_spi_error(qca); | ||
81 | else | ||
82 | *result = be16_to_cpu(rx_data); | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | int | ||
88 | qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) | ||
89 | { | ||
90 | __be16 tx_data[2]; | ||
91 | struct spi_transfer *transfer; | ||
92 | struct spi_message *msg; | ||
93 | int ret; | ||
94 | |||
95 | tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg); | ||
96 | tx_data[1] = cpu_to_be16(value); | ||
97 | |||
98 | if (qca->legacy_mode) { | ||
99 | msg = &qca->spi_msg1; | ||
100 | transfer = &qca->spi_xfer1; | ||
101 | transfer->tx_buf = &tx_data[0]; | ||
102 | transfer->rx_buf = NULL; | ||
103 | transfer->len = QCASPI_CMD_LEN; | ||
104 | spi_sync(qca->spi_dev, msg); | ||
105 | } else { | ||
106 | msg = &qca->spi_msg2; | ||
107 | transfer = &qca->spi_xfer2[0]; | ||
108 | transfer->tx_buf = &tx_data[0]; | ||
109 | transfer->rx_buf = NULL; | ||
110 | transfer->len = QCASPI_CMD_LEN; | ||
111 | transfer = &qca->spi_xfer2[1]; | ||
112 | } | ||
113 | transfer->tx_buf = &tx_data[1]; | ||
114 | transfer->rx_buf = NULL; | ||
115 | transfer->len = QCASPI_CMD_LEN; | ||
116 | ret = spi_sync(qca->spi_dev, msg); | ||
117 | |||
118 | if (!ret) | ||
119 | ret = msg->status; | ||
120 | |||
121 | if (ret) | ||
122 | qcaspi_spi_error(qca); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | int | ||
128 | qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) | ||
129 | { | ||
130 | __be16 tx_data; | ||
131 | struct spi_message *msg = &qca->spi_msg1; | ||
132 | struct spi_transfer *transfer = &qca->spi_xfer1; | ||
133 | int ret; | ||
134 | |||
135 | tx_data = cpu_to_be16(cmd); | ||
136 | transfer->len = sizeof(tx_data); | ||
137 | transfer->tx_buf = &tx_data; | ||
138 | transfer->rx_buf = NULL; | ||
139 | |||
140 | ret = spi_sync(qca->spi_dev, msg); | ||
141 | |||
142 | if (!ret) | ||
143 | ret = msg->status; | ||
144 | |||
145 | if (ret) | ||
146 | qcaspi_spi_error(qca); | ||
147 | |||
148 | return ret; | ||
149 | } | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h new file mode 100644 index 000000000000..1cad851ee507 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_7k.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* Qualcomm Atheros SPI register definition. | ||
22 | * | ||
23 | * This module is designed to define the Qualcomm Atheros SPI | ||
24 | * register placeholders. | ||
25 | */ | ||
26 | |||
27 | #ifndef _QCA_7K_H | ||
28 | #define _QCA_7K_H | ||
29 | |||
30 | #include <linux/types.h> | ||
31 | |||
32 | #include "qca_spi.h" | ||
33 | |||
34 | #define QCA7K_SPI_READ (1 << 15) | ||
35 | #define QCA7K_SPI_WRITE (0 << 15) | ||
36 | #define QCA7K_SPI_INTERNAL (1 << 14) | ||
37 | #define QCA7K_SPI_EXTERNAL (0 << 14) | ||
38 | |||
39 | #define QCASPI_CMD_LEN 2 | ||
40 | #define QCASPI_HW_PKT_LEN 4 | ||
41 | #define QCASPI_HW_BUF_LEN 0xC5B | ||
42 | |||
43 | /* SPI registers; */ | ||
44 | #define SPI_REG_BFR_SIZE 0x0100 | ||
45 | #define SPI_REG_WRBUF_SPC_AVA 0x0200 | ||
46 | #define SPI_REG_RDBUF_BYTE_AVA 0x0300 | ||
47 | #define SPI_REG_SPI_CONFIG 0x0400 | ||
48 | #define SPI_REG_SPI_STATUS 0x0500 | ||
49 | #define SPI_REG_INTR_CAUSE 0x0C00 | ||
50 | #define SPI_REG_INTR_ENABLE 0x0D00 | ||
51 | #define SPI_REG_RDBUF_WATERMARK 0x1200 | ||
52 | #define SPI_REG_WRBUF_WATERMARK 0x1300 | ||
53 | #define SPI_REG_SIGNATURE 0x1A00 | ||
54 | #define SPI_REG_ACTION_CTRL 0x1B00 | ||
55 | |||
56 | /* SPI_CONFIG register definition; */ | ||
57 | #define QCASPI_SLAVE_RESET_BIT (1 << 6) | ||
58 | |||
59 | /* INTR_CAUSE/ENABLE register definition. */ | ||
60 | #define SPI_INT_WRBUF_BELOW_WM (1 << 10) | ||
61 | #define SPI_INT_CPU_ON (1 << 6) | ||
62 | #define SPI_INT_ADDR_ERR (1 << 3) | ||
63 | #define SPI_INT_WRBUF_ERR (1 << 2) | ||
64 | #define SPI_INT_RDBUF_ERR (1 << 1) | ||
65 | #define SPI_INT_PKT_AVLBL (1 << 0) | ||
66 | |||
67 | void qcaspi_spi_error(struct qcaspi *qca); | ||
68 | int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result); | ||
69 | int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value); | ||
70 | int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd); | ||
71 | |||
72 | #endif /* _QCA_7K_H */ | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c new file mode 100644 index 000000000000..8e28234dddad --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_debug.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* This file contains debugging routines for use in the QCA7K driver. | ||
21 | */ | ||
22 | |||
23 | #include <linux/debugfs.h> | ||
24 | #include <linux/ethtool.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/types.h> | ||
27 | |||
28 | #include "qca_7k.h" | ||
29 | #include "qca_debug.h" | ||
30 | |||
31 | #define QCASPI_MAX_REGS 0x20 | ||
32 | |||
33 | static const u16 qcaspi_spi_regs[] = { | ||
34 | SPI_REG_BFR_SIZE, | ||
35 | SPI_REG_WRBUF_SPC_AVA, | ||
36 | SPI_REG_RDBUF_BYTE_AVA, | ||
37 | SPI_REG_SPI_CONFIG, | ||
38 | SPI_REG_SPI_STATUS, | ||
39 | SPI_REG_INTR_CAUSE, | ||
40 | SPI_REG_INTR_ENABLE, | ||
41 | SPI_REG_RDBUF_WATERMARK, | ||
42 | SPI_REG_WRBUF_WATERMARK, | ||
43 | SPI_REG_SIGNATURE, | ||
44 | SPI_REG_ACTION_CTRL | ||
45 | }; | ||
46 | |||
47 | /* The order of these strings must match the order of the fields in | ||
48 | * struct qcaspi_stats | ||
49 | * See qca_spi.h | ||
50 | */ | ||
51 | static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = { | ||
52 | "Triggered resets", | ||
53 | "Device resets", | ||
54 | "Reset timeouts", | ||
55 | "Read errors", | ||
56 | "Write errors", | ||
57 | "Read buffer errors", | ||
58 | "Write buffer errors", | ||
59 | "Out of memory", | ||
60 | "Write buffer misses", | ||
61 | "Transmit ring full", | ||
62 | "SPI errors", | ||
63 | }; | ||
64 | |||
65 | #ifdef CONFIG_DEBUG_FS | ||
66 | |||
67 | static int | ||
68 | qcaspi_info_show(struct seq_file *s, void *what) | ||
69 | { | ||
70 | struct qcaspi *qca = s->private; | ||
71 | |||
72 | seq_printf(s, "RX buffer size : %lu\n", | ||
73 | (unsigned long)qca->buffer_size); | ||
74 | |||
75 | seq_puts(s, "TX ring state : "); | ||
76 | |||
77 | if (qca->txr.skb[qca->txr.head] == NULL) | ||
78 | seq_puts(s, "empty"); | ||
79 | else if (qca->txr.skb[qca->txr.tail]) | ||
80 | seq_puts(s, "full"); | ||
81 | else | ||
82 | seq_puts(s, "in use"); | ||
83 | |||
84 | seq_puts(s, "\n"); | ||
85 | |||
86 | seq_printf(s, "TX ring size : %u\n", | ||
87 | qca->txr.size); | ||
88 | |||
89 | seq_printf(s, "Sync state : %u (", | ||
90 | (unsigned int)qca->sync); | ||
91 | switch (qca->sync) { | ||
92 | case QCASPI_SYNC_UNKNOWN: | ||
93 | seq_puts(s, "QCASPI_SYNC_UNKNOWN"); | ||
94 | break; | ||
95 | case QCASPI_SYNC_RESET: | ||
96 | seq_puts(s, "QCASPI_SYNC_RESET"); | ||
97 | break; | ||
98 | case QCASPI_SYNC_READY: | ||
99 | seq_puts(s, "QCASPI_SYNC_READY"); | ||
100 | break; | ||
101 | default: | ||
102 | seq_puts(s, "INVALID"); | ||
103 | break; | ||
104 | } | ||
105 | seq_puts(s, ")\n"); | ||
106 | |||
107 | seq_printf(s, "IRQ : %d\n", | ||
108 | qca->spi_dev->irq); | ||
109 | seq_printf(s, "INTR REQ : %u\n", | ||
110 | qca->intr_req); | ||
111 | seq_printf(s, "INTR SVC : %u\n", | ||
112 | qca->intr_svc); | ||
113 | |||
114 | seq_printf(s, "SPI max speed : %lu\n", | ||
115 | (unsigned long)qca->spi_dev->max_speed_hz); | ||
116 | seq_printf(s, "SPI mode : %x\n", | ||
117 | qca->spi_dev->mode); | ||
118 | seq_printf(s, "SPI chip select : %u\n", | ||
119 | (unsigned int)qca->spi_dev->chip_select); | ||
120 | seq_printf(s, "SPI legacy mode : %u\n", | ||
121 | (unsigned int)qca->legacy_mode); | ||
122 | seq_printf(s, "SPI burst length : %u\n", | ||
123 | (unsigned int)qca->burst_len); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int | ||
129 | qcaspi_info_open(struct inode *inode, struct file *file) | ||
130 | { | ||
131 | return single_open(file, qcaspi_info_show, inode->i_private); | ||
132 | } | ||
133 | |||
134 | static const struct file_operations qcaspi_info_ops = { | ||
135 | .open = qcaspi_info_open, | ||
136 | .read = seq_read, | ||
137 | .llseek = seq_lseek, | ||
138 | .release = single_release, | ||
139 | }; | ||
140 | |||
141 | void | ||
142 | qcaspi_init_device_debugfs(struct qcaspi *qca) | ||
143 | { | ||
144 | struct dentry *device_root; | ||
145 | |||
146 | device_root = debugfs_create_dir(dev_name(&qca->net_dev->dev), NULL); | ||
147 | qca->device_root = device_root; | ||
148 | |||
149 | if (IS_ERR(device_root) || !device_root) { | ||
150 | pr_warn("failed to create debugfs directory for %s\n", | ||
151 | dev_name(&qca->net_dev->dev)); | ||
152 | return; | ||
153 | } | ||
154 | debugfs_create_file("info", S_IFREG | S_IRUGO, device_root, qca, | ||
155 | &qcaspi_info_ops); | ||
156 | } | ||
157 | |||
158 | void | ||
159 | qcaspi_remove_device_debugfs(struct qcaspi *qca) | ||
160 | { | ||
161 | debugfs_remove_recursive(qca->device_root); | ||
162 | } | ||
163 | |||
164 | #else /* CONFIG_DEBUG_FS */ | ||
165 | |||
166 | void | ||
167 | qcaspi_init_device_debugfs(struct qcaspi *qca) | ||
168 | { | ||
169 | } | ||
170 | |||
171 | void | ||
172 | qcaspi_remove_device_debugfs(struct qcaspi *qca) | ||
173 | { | ||
174 | } | ||
175 | |||
176 | #endif | ||
177 | |||
178 | static void | ||
179 | qcaspi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *p) | ||
180 | { | ||
181 | struct qcaspi *qca = netdev_priv(dev); | ||
182 | |||
183 | strlcpy(p->driver, QCASPI_DRV_NAME, sizeof(p->driver)); | ||
184 | strlcpy(p->version, QCASPI_DRV_VERSION, sizeof(p->version)); | ||
185 | strlcpy(p->fw_version, "QCA7000", sizeof(p->fw_version)); | ||
186 | strlcpy(p->bus_info, dev_name(&qca->spi_dev->dev), | ||
187 | sizeof(p->bus_info)); | ||
188 | } | ||
189 | |||
190 | static int | ||
191 | qcaspi_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
192 | { | ||
193 | cmd->transceiver = XCVR_INTERNAL; | ||
194 | cmd->supported = SUPPORTED_10baseT_Half; | ||
195 | ethtool_cmd_speed_set(cmd, SPEED_10); | ||
196 | cmd->duplex = DUPLEX_HALF; | ||
197 | cmd->port = PORT_OTHER; | ||
198 | cmd->autoneg = AUTONEG_DISABLE; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static void | ||
204 | qcaspi_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *data) | ||
205 | { | ||
206 | struct qcaspi *qca = netdev_priv(dev); | ||
207 | struct qcaspi_stats *st = &qca->stats; | ||
208 | |||
209 | memcpy(data, st, ARRAY_SIZE(qcaspi_gstrings_stats) * sizeof(u64)); | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | qcaspi_get_strings(struct net_device *dev, u32 stringset, u8 *buf) | ||
214 | { | ||
215 | switch (stringset) { | ||
216 | case ETH_SS_STATS: | ||
217 | memcpy(buf, &qcaspi_gstrings_stats, | ||
218 | sizeof(qcaspi_gstrings_stats)); | ||
219 | break; | ||
220 | default: | ||
221 | WARN_ON(1); | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | qcaspi_get_sset_count(struct net_device *dev, int sset) | ||
228 | { | ||
229 | switch (sset) { | ||
230 | case ETH_SS_STATS: | ||
231 | return ARRAY_SIZE(qcaspi_gstrings_stats); | ||
232 | default: | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | static int | ||
238 | qcaspi_get_regs_len(struct net_device *dev) | ||
239 | { | ||
240 | return sizeof(u32) * QCASPI_MAX_REGS; | ||
241 | } | ||
242 | |||
243 | static void | ||
244 | qcaspi_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) | ||
245 | { | ||
246 | struct qcaspi *qca = netdev_priv(dev); | ||
247 | u32 *regs_buff = p; | ||
248 | unsigned int i; | ||
249 | |||
250 | regs->version = 1; | ||
251 | memset(regs_buff, 0, sizeof(u32) * QCASPI_MAX_REGS); | ||
252 | |||
253 | for (i = 0; i < ARRAY_SIZE(qcaspi_spi_regs); i++) { | ||
254 | u16 offset, value; | ||
255 | |||
256 | qcaspi_read_register(qca, qcaspi_spi_regs[i], &value); | ||
257 | offset = qcaspi_spi_regs[i] >> 8; | ||
258 | regs_buff[offset] = value; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | static void | ||
263 | qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) | ||
264 | { | ||
265 | struct qcaspi *qca = netdev_priv(dev); | ||
266 | |||
267 | ring->rx_max_pending = 4; | ||
268 | ring->tx_max_pending = TX_RING_MAX_LEN; | ||
269 | ring->rx_pending = 4; | ||
270 | ring->tx_pending = qca->txr.count; | ||
271 | } | ||
272 | |||
273 | static int | ||
274 | qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) | ||
275 | { | ||
276 | struct qcaspi *qca = netdev_priv(dev); | ||
277 | |||
278 | if ((ring->rx_pending) || | ||
279 | (ring->rx_mini_pending) || | ||
280 | (ring->rx_jumbo_pending)) | ||
281 | return -EINVAL; | ||
282 | |||
283 | if (netif_running(dev)) | ||
284 | qcaspi_netdev_close(dev); | ||
285 | |||
286 | qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); | ||
287 | qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); | ||
288 | |||
289 | if (netif_running(dev)) | ||
290 | qcaspi_netdev_open(dev); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static const struct ethtool_ops qcaspi_ethtool_ops = { | ||
296 | .get_drvinfo = qcaspi_get_drvinfo, | ||
297 | .get_link = ethtool_op_get_link, | ||
298 | .get_settings = qcaspi_get_settings, | ||
299 | .get_ethtool_stats = qcaspi_get_ethtool_stats, | ||
300 | .get_strings = qcaspi_get_strings, | ||
301 | .get_sset_count = qcaspi_get_sset_count, | ||
302 | .get_regs_len = qcaspi_get_regs_len, | ||
303 | .get_regs = qcaspi_get_regs, | ||
304 | .get_ringparam = qcaspi_get_ringparam, | ||
305 | .set_ringparam = qcaspi_set_ringparam, | ||
306 | }; | ||
307 | |||
308 | void qcaspi_set_ethtool_ops(struct net_device *dev) | ||
309 | { | ||
310 | dev->ethtool_ops = &qcaspi_ethtool_ops; | ||
311 | } | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.h b/drivers/net/ethernet/qualcomm/qca_debug.h new file mode 100644 index 000000000000..46a785844421 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_debug.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* This file contains debugging routines for use in the QCA7K driver. | ||
21 | */ | ||
22 | |||
23 | #ifndef _QCA_DEBUG_H | ||
24 | #define _QCA_DEBUG_H | ||
25 | |||
26 | #include "qca_spi.h" | ||
27 | |||
28 | void qcaspi_init_device_debugfs(struct qcaspi *qca); | ||
29 | |||
30 | void qcaspi_remove_device_debugfs(struct qcaspi *qca); | ||
31 | |||
32 | void qcaspi_set_ethtool_ops(struct net_device *dev); | ||
33 | |||
34 | #endif /* _QCA_DEBUG_H */ | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_framing.c new file mode 100644 index 000000000000..faa924c85e29 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_framing.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* Atheros ethernet framing. Every Ethernet frame is surrounded | ||
21 | * by an atheros frame while transmitted over a serial channel; | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | |||
26 | #include "qca_framing.h" | ||
27 | |||
28 | u16 | ||
29 | qcafrm_create_header(u8 *buf, u16 length) | ||
30 | { | ||
31 | __le16 len; | ||
32 | |||
33 | if (!buf) | ||
34 | return 0; | ||
35 | |||
36 | len = cpu_to_le16(length); | ||
37 | |||
38 | buf[0] = 0xAA; | ||
39 | buf[1] = 0xAA; | ||
40 | buf[2] = 0xAA; | ||
41 | buf[3] = 0xAA; | ||
42 | buf[4] = len & 0xff; | ||
43 | buf[5] = (len >> 8) & 0xff; | ||
44 | buf[6] = 0; | ||
45 | buf[7] = 0; | ||
46 | |||
47 | return QCAFRM_HEADER_LEN; | ||
48 | } | ||
49 | |||
50 | u16 | ||
51 | qcafrm_create_footer(u8 *buf) | ||
52 | { | ||
53 | if (!buf) | ||
54 | return 0; | ||
55 | |||
56 | buf[0] = 0x55; | ||
57 | buf[1] = 0x55; | ||
58 | return QCAFRM_FOOTER_LEN; | ||
59 | } | ||
60 | |||
61 | /* Gather received bytes and try to extract a full ethernet frame by | ||
62 | * following a simple state machine. | ||
63 | * | ||
64 | * Return: QCAFRM_GATHER No ethernet frame fully received yet. | ||
65 | * QCAFRM_NOHEAD Header expected but not found. | ||
66 | * QCAFRM_INVLEN Atheros frame length is invalid | ||
67 | * QCAFRM_NOTAIL Footer expected but not found. | ||
68 | * > 0 Number of byte in the fully received | ||
69 | * Ethernet frame | ||
70 | */ | ||
71 | |||
72 | s32 | ||
73 | qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte) | ||
74 | { | ||
75 | s32 ret = QCAFRM_GATHER; | ||
76 | u16 len; | ||
77 | |||
78 | switch (handle->state) { | ||
79 | case QCAFRM_HW_LEN0: | ||
80 | case QCAFRM_HW_LEN1: | ||
81 | /* by default, just go to next state */ | ||
82 | handle->state--; | ||
83 | |||
84 | if (recv_byte != 0x00) { | ||
85 | /* first two bytes of length must be 0 */ | ||
86 | handle->state = QCAFRM_HW_LEN0; | ||
87 | } | ||
88 | break; | ||
89 | case QCAFRM_HW_LEN2: | ||
90 | case QCAFRM_HW_LEN3: | ||
91 | handle->state--; | ||
92 | break; | ||
93 | /* 4 bytes header pattern */ | ||
94 | case QCAFRM_WAIT_AA1: | ||
95 | case QCAFRM_WAIT_AA2: | ||
96 | case QCAFRM_WAIT_AA3: | ||
97 | case QCAFRM_WAIT_AA4: | ||
98 | if (recv_byte != 0xAA) { | ||
99 | ret = QCAFRM_NOHEAD; | ||
100 | handle->state = QCAFRM_HW_LEN0; | ||
101 | } else { | ||
102 | handle->state--; | ||
103 | } | ||
104 | break; | ||
105 | /* 2 bytes length. */ | ||
106 | /* Borrow offset field to hold length for now. */ | ||
107 | case QCAFRM_WAIT_LEN_BYTE0: | ||
108 | handle->offset = recv_byte; | ||
109 | handle->state = QCAFRM_WAIT_LEN_BYTE1; | ||
110 | break; | ||
111 | case QCAFRM_WAIT_LEN_BYTE1: | ||
112 | handle->offset = handle->offset | (recv_byte << 8); | ||
113 | handle->state = QCAFRM_WAIT_RSVD_BYTE1; | ||
114 | break; | ||
115 | case QCAFRM_WAIT_RSVD_BYTE1: | ||
116 | handle->state = QCAFRM_WAIT_RSVD_BYTE2; | ||
117 | break; | ||
118 | case QCAFRM_WAIT_RSVD_BYTE2: | ||
119 | len = handle->offset; | ||
120 | if (len > buf_len || len < QCAFRM_ETHMINLEN) { | ||
121 | ret = QCAFRM_INVLEN; | ||
122 | handle->state = QCAFRM_HW_LEN0; | ||
123 | } else { | ||
124 | handle->state = (enum qcafrm_state)(len + 1); | ||
125 | /* Remaining number of bytes. */ | ||
126 | handle->offset = 0; | ||
127 | } | ||
128 | break; | ||
129 | default: | ||
130 | /* Receiving Ethernet frame itself. */ | ||
131 | buf[handle->offset] = recv_byte; | ||
132 | handle->offset++; | ||
133 | handle->state--; | ||
134 | break; | ||
135 | case QCAFRM_WAIT_551: | ||
136 | if (recv_byte != 0x55) { | ||
137 | ret = QCAFRM_NOTAIL; | ||
138 | handle->state = QCAFRM_HW_LEN0; | ||
139 | } else { | ||
140 | handle->state = QCAFRM_WAIT_552; | ||
141 | } | ||
142 | break; | ||
143 | case QCAFRM_WAIT_552: | ||
144 | if (recv_byte != 0x55) { | ||
145 | ret = QCAFRM_NOTAIL; | ||
146 | handle->state = QCAFRM_HW_LEN0; | ||
147 | } else { | ||
148 | ret = handle->offset; | ||
149 | /* Frame is fully received. */ | ||
150 | handle->state = QCAFRM_HW_LEN0; | ||
151 | } | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | return ret; | ||
156 | } | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h new file mode 100644 index 000000000000..5d965959c978 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_framing.h | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* Atheros Ethernet framing. Every Ethernet frame is surrounded by an atheros | ||
21 | * frame while transmitted over a serial channel. | ||
22 | */ | ||
23 | |||
24 | #ifndef _QCA_FRAMING_H | ||
25 | #define _QCA_FRAMING_H | ||
26 | |||
27 | #include <linux/if_ether.h> | ||
28 | #include <linux/if_vlan.h> | ||
29 | #include <linux/types.h> | ||
30 | |||
31 | /* Frame is currently being received */ | ||
32 | #define QCAFRM_GATHER 0 | ||
33 | |||
34 | /* No header byte while expecting it */ | ||
35 | #define QCAFRM_NOHEAD (QCAFRM_ERR_BASE - 1) | ||
36 | |||
37 | /* No tailer byte while expecting it */ | ||
38 | #define QCAFRM_NOTAIL (QCAFRM_ERR_BASE - 2) | ||
39 | |||
40 | /* Frame length is invalid */ | ||
41 | #define QCAFRM_INVLEN (QCAFRM_ERR_BASE - 3) | ||
42 | |||
43 | /* Frame length is invalid */ | ||
44 | #define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4) | ||
45 | |||
46 | /* Min/Max Ethernet MTU */ | ||
47 | #define QCAFRM_ETHMINMTU 46 | ||
48 | #define QCAFRM_ETHMAXMTU 1500 | ||
49 | |||
50 | /* Min/Max frame lengths */ | ||
51 | #define QCAFRM_ETHMINLEN (QCAFRM_ETHMINMTU + ETH_HLEN) | ||
52 | #define QCAFRM_ETHMAXLEN (QCAFRM_ETHMAXMTU + VLAN_ETH_HLEN) | ||
53 | |||
54 | /* QCA7K header len */ | ||
55 | #define QCAFRM_HEADER_LEN 8 | ||
56 | |||
57 | /* QCA7K footer len */ | ||
58 | #define QCAFRM_FOOTER_LEN 2 | ||
59 | |||
60 | /* QCA7K Framing. */ | ||
61 | #define QCAFRM_ERR_BASE -1000 | ||
62 | |||
63 | enum qcafrm_state { | ||
64 | QCAFRM_HW_LEN0 = 0x8000, | ||
65 | QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1, | ||
66 | QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1, | ||
67 | QCAFRM_HW_LEN3 = QCAFRM_HW_LEN2 - 1, | ||
68 | |||
69 | /* Waiting first 0xAA of header */ | ||
70 | QCAFRM_WAIT_AA1 = QCAFRM_HW_LEN3 - 1, | ||
71 | |||
72 | /* Waiting second 0xAA of header */ | ||
73 | QCAFRM_WAIT_AA2 = QCAFRM_WAIT_AA1 - 1, | ||
74 | |||
75 | /* Waiting third 0xAA of header */ | ||
76 | QCAFRM_WAIT_AA3 = QCAFRM_WAIT_AA2 - 1, | ||
77 | |||
78 | /* Waiting fourth 0xAA of header */ | ||
79 | QCAFRM_WAIT_AA4 = QCAFRM_WAIT_AA3 - 1, | ||
80 | |||
81 | /* Waiting Byte 0-1 of length (litte endian) */ | ||
82 | QCAFRM_WAIT_LEN_BYTE0 = QCAFRM_WAIT_AA4 - 1, | ||
83 | QCAFRM_WAIT_LEN_BYTE1 = QCAFRM_WAIT_AA4 - 2, | ||
84 | |||
85 | /* Reserved bytes */ | ||
86 | QCAFRM_WAIT_RSVD_BYTE1 = QCAFRM_WAIT_AA4 - 3, | ||
87 | QCAFRM_WAIT_RSVD_BYTE2 = QCAFRM_WAIT_AA4 - 4, | ||
88 | |||
89 | /* The frame length is used as the state until | ||
90 | * the end of the Ethernet frame | ||
91 | * Waiting for first 0x55 of footer | ||
92 | */ | ||
93 | QCAFRM_WAIT_551 = 1, | ||
94 | |||
95 | /* Waiting for second 0x55 of footer */ | ||
96 | QCAFRM_WAIT_552 = QCAFRM_WAIT_551 - 1 | ||
97 | }; | ||
98 | |||
99 | /* Structure to maintain the frame decoding during reception. */ | ||
100 | |||
101 | struct qcafrm_handle { | ||
102 | /* Current decoding state */ | ||
103 | enum qcafrm_state state; | ||
104 | |||
105 | /* Offset in buffer (borrowed for length too) */ | ||
106 | s16 offset; | ||
107 | |||
108 | /* Frame length as kept by this module */ | ||
109 | u16 len; | ||
110 | }; | ||
111 | |||
112 | u16 qcafrm_create_header(u8 *buf, u16 len); | ||
113 | |||
114 | u16 qcafrm_create_footer(u8 *buf); | ||
115 | |||
116 | static inline void qcafrm_fsm_init(struct qcafrm_handle *handle) | ||
117 | { | ||
118 | handle->state = QCAFRM_HW_LEN0; | ||
119 | } | ||
120 | |||
121 | /* Gather received bytes and try to extract a full Ethernet frame | ||
122 | * by following a simple state machine. | ||
123 | * | ||
124 | * Return: QCAFRM_GATHER No Ethernet frame fully received yet. | ||
125 | * QCAFRM_NOHEAD Header expected but not found. | ||
126 | * QCAFRM_INVLEN QCA7K frame length is invalid | ||
127 | * QCAFRM_NOTAIL Footer expected but not found. | ||
128 | * > 0 Number of byte in the fully received | ||
129 | * Ethernet frame | ||
130 | */ | ||
131 | |||
132 | s32 qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte); | ||
133 | |||
134 | #endif /* _QCA_FRAMING_H */ | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c new file mode 100644 index 000000000000..74eb520e2649 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_spi.c | |||
@@ -0,0 +1,993 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* This module implements the Qualcomm Atheros SPI protocol for | ||
21 | * kernel-based SPI device; it is essentially an Ethernet-to-SPI | ||
22 | * serial converter; | ||
23 | */ | ||
24 | |||
25 | #include <linux/errno.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/if_arp.h> | ||
28 | #include <linux/if_ether.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/jiffies.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/kthread.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/netdevice.h> | ||
37 | #include <linux/of.h> | ||
38 | #include <linux/of_device.h> | ||
39 | #include <linux/of_net.h> | ||
40 | #include <linux/sched.h> | ||
41 | #include <linux/skbuff.h> | ||
42 | #include <linux/spi/spi.h> | ||
43 | #include <linux/types.h> | ||
44 | #include <linux/version.h> | ||
45 | |||
46 | #include "qca_7k.h" | ||
47 | #include "qca_debug.h" | ||
48 | #include "qca_framing.h" | ||
49 | #include "qca_spi.h" | ||
50 | |||
51 | #define MAX_DMA_BURST_LEN 5000 | ||
52 | |||
53 | /* Modules parameters */ | ||
54 | #define QCASPI_CLK_SPEED_MIN 1000000 | ||
55 | #define QCASPI_CLK_SPEED_MAX 16000000 | ||
56 | #define QCASPI_CLK_SPEED 8000000 | ||
57 | static int qcaspi_clkspeed; | ||
58 | module_param(qcaspi_clkspeed, int, 0); | ||
59 | MODULE_PARM_DESC(qcaspi_clkspeed, "SPI bus clock speed (Hz). Use 1000000-16000000."); | ||
60 | |||
61 | #define QCASPI_BURST_LEN_MIN 1 | ||
62 | #define QCASPI_BURST_LEN_MAX MAX_DMA_BURST_LEN | ||
63 | static int qcaspi_burst_len = MAX_DMA_BURST_LEN; | ||
64 | module_param(qcaspi_burst_len, int, 0); | ||
65 | MODULE_PARM_DESC(qcaspi_burst_len, "Number of data bytes per burst. Use 1-5000."); | ||
66 | |||
67 | #define QCASPI_PLUGGABLE_MIN 0 | ||
68 | #define QCASPI_PLUGGABLE_MAX 1 | ||
69 | static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; | ||
70 | module_param(qcaspi_pluggable, int, 0); | ||
71 | MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); | ||
72 | |||
73 | #define QCASPI_MTU QCAFRM_ETHMAXMTU | ||
74 | #define QCASPI_TX_TIMEOUT (1 * HZ) | ||
75 | #define QCASPI_QCA7K_REBOOT_TIME_MS 1000 | ||
76 | |||
77 | static void | ||
78 | start_spi_intr_handling(struct qcaspi *qca, u16 *intr_cause) | ||
79 | { | ||
80 | *intr_cause = 0; | ||
81 | |||
82 | qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0); | ||
83 | qcaspi_read_register(qca, SPI_REG_INTR_CAUSE, intr_cause); | ||
84 | netdev_dbg(qca->net_dev, "interrupts: 0x%04x\n", *intr_cause); | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | end_spi_intr_handling(struct qcaspi *qca, u16 intr_cause) | ||
89 | { | ||
90 | u16 intr_enable = (SPI_INT_CPU_ON | | ||
91 | SPI_INT_PKT_AVLBL | | ||
92 | SPI_INT_RDBUF_ERR | | ||
93 | SPI_INT_WRBUF_ERR); | ||
94 | |||
95 | qcaspi_write_register(qca, SPI_REG_INTR_CAUSE, intr_cause); | ||
96 | qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, intr_enable); | ||
97 | netdev_dbg(qca->net_dev, "acking int: 0x%04x\n", intr_cause); | ||
98 | } | ||
99 | |||
100 | static u32 | ||
101 | qcaspi_write_burst(struct qcaspi *qca, u8 *src, u32 len) | ||
102 | { | ||
103 | __be16 cmd; | ||
104 | struct spi_message *msg = &qca->spi_msg2; | ||
105 | struct spi_transfer *transfer = &qca->spi_xfer2[0]; | ||
106 | int ret; | ||
107 | |||
108 | cmd = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_EXTERNAL); | ||
109 | transfer->tx_buf = &cmd; | ||
110 | transfer->rx_buf = NULL; | ||
111 | transfer->len = QCASPI_CMD_LEN; | ||
112 | transfer = &qca->spi_xfer2[1]; | ||
113 | transfer->tx_buf = src; | ||
114 | transfer->rx_buf = NULL; | ||
115 | transfer->len = len; | ||
116 | |||
117 | ret = spi_sync(qca->spi_dev, msg); | ||
118 | |||
119 | if (ret || (msg->actual_length != QCASPI_CMD_LEN + len)) { | ||
120 | qcaspi_spi_error(qca); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | return len; | ||
125 | } | ||
126 | |||
127 | static u32 | ||
128 | qcaspi_write_legacy(struct qcaspi *qca, u8 *src, u32 len) | ||
129 | { | ||
130 | struct spi_message *msg = &qca->spi_msg1; | ||
131 | struct spi_transfer *transfer = &qca->spi_xfer1; | ||
132 | int ret; | ||
133 | |||
134 | transfer->tx_buf = src; | ||
135 | transfer->rx_buf = NULL; | ||
136 | transfer->len = len; | ||
137 | |||
138 | ret = spi_sync(qca->spi_dev, msg); | ||
139 | |||
140 | if (ret || (msg->actual_length != len)) { | ||
141 | qcaspi_spi_error(qca); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | return len; | ||
146 | } | ||
147 | |||
148 | static u32 | ||
149 | qcaspi_read_burst(struct qcaspi *qca, u8 *dst, u32 len) | ||
150 | { | ||
151 | struct spi_message *msg = &qca->spi_msg2; | ||
152 | __be16 cmd; | ||
153 | struct spi_transfer *transfer = &qca->spi_xfer2[0]; | ||
154 | int ret; | ||
155 | |||
156 | cmd = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_EXTERNAL); | ||
157 | transfer->tx_buf = &cmd; | ||
158 | transfer->rx_buf = NULL; | ||
159 | transfer->len = QCASPI_CMD_LEN; | ||
160 | transfer = &qca->spi_xfer2[1]; | ||
161 | transfer->tx_buf = NULL; | ||
162 | transfer->rx_buf = dst; | ||
163 | transfer->len = len; | ||
164 | |||
165 | ret = spi_sync(qca->spi_dev, msg); | ||
166 | |||
167 | if (ret || (msg->actual_length != QCASPI_CMD_LEN + len)) { | ||
168 | qcaspi_spi_error(qca); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | return len; | ||
173 | } | ||
174 | |||
175 | static u32 | ||
176 | qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len) | ||
177 | { | ||
178 | struct spi_message *msg = &qca->spi_msg1; | ||
179 | struct spi_transfer *transfer = &qca->spi_xfer1; | ||
180 | int ret; | ||
181 | |||
182 | transfer->tx_buf = NULL; | ||
183 | transfer->rx_buf = dst; | ||
184 | transfer->len = len; | ||
185 | |||
186 | ret = spi_sync(qca->spi_dev, msg); | ||
187 | |||
188 | if (ret || (msg->actual_length != len)) { | ||
189 | qcaspi_spi_error(qca); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | return len; | ||
194 | } | ||
195 | |||
196 | static int | ||
197 | qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb) | ||
198 | { | ||
199 | u32 count; | ||
200 | u32 written; | ||
201 | u32 offset; | ||
202 | u32 len; | ||
203 | |||
204 | len = skb->len; | ||
205 | |||
206 | qcaspi_write_register(qca, SPI_REG_BFR_SIZE, len); | ||
207 | if (qca->legacy_mode) | ||
208 | qcaspi_tx_cmd(qca, QCA7K_SPI_WRITE | QCA7K_SPI_EXTERNAL); | ||
209 | |||
210 | offset = 0; | ||
211 | while (len) { | ||
212 | count = len; | ||
213 | if (count > qca->burst_len) | ||
214 | count = qca->burst_len; | ||
215 | |||
216 | if (qca->legacy_mode) { | ||
217 | written = qcaspi_write_legacy(qca, | ||
218 | skb->data + offset, | ||
219 | count); | ||
220 | } else { | ||
221 | written = qcaspi_write_burst(qca, | ||
222 | skb->data + offset, | ||
223 | count); | ||
224 | } | ||
225 | |||
226 | if (written != count) | ||
227 | return -1; | ||
228 | |||
229 | offset += count; | ||
230 | len -= count; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int | ||
237 | qcaspi_transmit(struct qcaspi *qca) | ||
238 | { | ||
239 | struct net_device_stats *n_stats = &qca->net_dev->stats; | ||
240 | u16 available = 0; | ||
241 | u32 pkt_len; | ||
242 | u16 new_head; | ||
243 | u16 packets = 0; | ||
244 | |||
245 | if (qca->txr.skb[qca->txr.head] == NULL) | ||
246 | return 0; | ||
247 | |||
248 | qcaspi_read_register(qca, SPI_REG_WRBUF_SPC_AVA, &available); | ||
249 | |||
250 | while (qca->txr.skb[qca->txr.head]) { | ||
251 | pkt_len = qca->txr.skb[qca->txr.head]->len + QCASPI_HW_PKT_LEN; | ||
252 | |||
253 | if (available < pkt_len) { | ||
254 | if (packets == 0) | ||
255 | qca->stats.write_buf_miss++; | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | if (qcaspi_tx_frame(qca, qca->txr.skb[qca->txr.head]) == -1) { | ||
260 | qca->stats.write_err++; | ||
261 | return -1; | ||
262 | } | ||
263 | |||
264 | packets++; | ||
265 | n_stats->tx_packets++; | ||
266 | n_stats->tx_bytes += qca->txr.skb[qca->txr.head]->len; | ||
267 | available -= pkt_len; | ||
268 | |||
269 | /* remove the skb from the queue */ | ||
270 | /* XXX After inconsistent lock states netif_tx_lock() | ||
271 | * has been replaced by netif_tx_lock_bh() and so on. | ||
272 | */ | ||
273 | netif_tx_lock_bh(qca->net_dev); | ||
274 | dev_kfree_skb(qca->txr.skb[qca->txr.head]); | ||
275 | qca->txr.skb[qca->txr.head] = NULL; | ||
276 | qca->txr.size -= pkt_len; | ||
277 | new_head = qca->txr.head + 1; | ||
278 | if (new_head >= qca->txr.count) | ||
279 | new_head = 0; | ||
280 | qca->txr.head = new_head; | ||
281 | if (netif_queue_stopped(qca->net_dev)) | ||
282 | netif_wake_queue(qca->net_dev); | ||
283 | netif_tx_unlock_bh(qca->net_dev); | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int | ||
290 | qcaspi_receive(struct qcaspi *qca) | ||
291 | { | ||
292 | struct net_device *net_dev = qca->net_dev; | ||
293 | struct net_device_stats *n_stats = &net_dev->stats; | ||
294 | u16 available = 0; | ||
295 | u32 bytes_read; | ||
296 | u8 *cp; | ||
297 | |||
298 | /* Allocate rx SKB if we don't have one available. */ | ||
299 | if (!qca->rx_skb) { | ||
300 | qca->rx_skb = netdev_alloc_skb(net_dev, | ||
301 | net_dev->mtu + VLAN_ETH_HLEN); | ||
302 | if (!qca->rx_skb) { | ||
303 | netdev_dbg(net_dev, "out of RX resources\n"); | ||
304 | qca->stats.out_of_mem++; | ||
305 | return -1; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /* Read the packet size. */ | ||
310 | qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available); | ||
311 | netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %08x\n", | ||
312 | available); | ||
313 | |||
314 | if (available == 0) { | ||
315 | netdev_dbg(net_dev, "qcaspi_receive called without any data being available!\n"); | ||
316 | return -1; | ||
317 | } | ||
318 | |||
319 | qcaspi_write_register(qca, SPI_REG_BFR_SIZE, available); | ||
320 | |||
321 | if (qca->legacy_mode) | ||
322 | qcaspi_tx_cmd(qca, QCA7K_SPI_READ | QCA7K_SPI_EXTERNAL); | ||
323 | |||
324 | while (available) { | ||
325 | u32 count = available; | ||
326 | |||
327 | if (count > qca->burst_len) | ||
328 | count = qca->burst_len; | ||
329 | |||
330 | if (qca->legacy_mode) { | ||
331 | bytes_read = qcaspi_read_legacy(qca, qca->rx_buffer, | ||
332 | count); | ||
333 | } else { | ||
334 | bytes_read = qcaspi_read_burst(qca, qca->rx_buffer, | ||
335 | count); | ||
336 | } | ||
337 | |||
338 | netdev_dbg(net_dev, "available: %d, byte read: %d\n", | ||
339 | available, bytes_read); | ||
340 | |||
341 | if (bytes_read) { | ||
342 | available -= bytes_read; | ||
343 | } else { | ||
344 | qca->stats.read_err++; | ||
345 | return -1; | ||
346 | } | ||
347 | |||
348 | cp = qca->rx_buffer; | ||
349 | |||
350 | while ((bytes_read--) && (qca->rx_skb)) { | ||
351 | s32 retcode; | ||
352 | |||
353 | retcode = qcafrm_fsm_decode(&qca->frm_handle, | ||
354 | qca->rx_skb->data, | ||
355 | skb_tailroom(qca->rx_skb), | ||
356 | *cp); | ||
357 | cp++; | ||
358 | switch (retcode) { | ||
359 | case QCAFRM_GATHER: | ||
360 | case QCAFRM_NOHEAD: | ||
361 | break; | ||
362 | case QCAFRM_NOTAIL: | ||
363 | netdev_dbg(net_dev, "no RX tail\n"); | ||
364 | n_stats->rx_errors++; | ||
365 | n_stats->rx_dropped++; | ||
366 | break; | ||
367 | case QCAFRM_INVLEN: | ||
368 | netdev_dbg(net_dev, "invalid RX length\n"); | ||
369 | n_stats->rx_errors++; | ||
370 | n_stats->rx_dropped++; | ||
371 | break; | ||
372 | default: | ||
373 | qca->rx_skb->dev = qca->net_dev; | ||
374 | n_stats->rx_packets++; | ||
375 | n_stats->rx_bytes += retcode; | ||
376 | skb_put(qca->rx_skb, retcode); | ||
377 | qca->rx_skb->protocol = eth_type_trans( | ||
378 | qca->rx_skb, qca->rx_skb->dev); | ||
379 | qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
380 | netif_rx_ni(qca->rx_skb); | ||
381 | qca->rx_skb = netdev_alloc_skb(net_dev, | ||
382 | net_dev->mtu + VLAN_ETH_HLEN); | ||
383 | if (!qca->rx_skb) { | ||
384 | netdev_dbg(net_dev, "out of RX resources\n"); | ||
385 | n_stats->rx_errors++; | ||
386 | qca->stats.out_of_mem++; | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /* Check that tx ring stores only so much bytes | ||
397 | * that fit into the internal QCA buffer. | ||
398 | */ | ||
399 | |||
400 | static int | ||
401 | qcaspi_tx_ring_has_space(struct tx_ring *txr) | ||
402 | { | ||
403 | if (txr->skb[txr->tail]) | ||
404 | return 0; | ||
405 | |||
406 | return (txr->size + QCAFRM_ETHMAXLEN < QCASPI_HW_BUF_LEN) ? 1 : 0; | ||
407 | } | ||
408 | |||
409 | /* Flush the tx ring. This function is only safe to | ||
410 | * call from the qcaspi_spi_thread. | ||
411 | */ | ||
412 | |||
413 | static void | ||
414 | qcaspi_flush_tx_ring(struct qcaspi *qca) | ||
415 | { | ||
416 | int i; | ||
417 | |||
418 | /* XXX After inconsistent lock states netif_tx_lock() | ||
419 | * has been replaced by netif_tx_lock_bh() and so on. | ||
420 | */ | ||
421 | netif_tx_lock_bh(qca->net_dev); | ||
422 | for (i = 0; i < TX_RING_MAX_LEN; i++) { | ||
423 | if (qca->txr.skb[i]) { | ||
424 | dev_kfree_skb(qca->txr.skb[i]); | ||
425 | qca->txr.skb[i] = NULL; | ||
426 | qca->net_dev->stats.tx_dropped++; | ||
427 | } | ||
428 | } | ||
429 | qca->txr.tail = 0; | ||
430 | qca->txr.head = 0; | ||
431 | qca->txr.size = 0; | ||
432 | netif_tx_unlock_bh(qca->net_dev); | ||
433 | } | ||
434 | |||
435 | static void | ||
436 | qcaspi_qca7k_sync(struct qcaspi *qca, int event) | ||
437 | { | ||
438 | u16 signature = 0; | ||
439 | u16 spi_config; | ||
440 | u16 wrbuf_space = 0; | ||
441 | static u16 reset_count; | ||
442 | |||
443 | if (event == QCASPI_EVENT_CPUON) { | ||
444 | /* Read signature twice, if not valid | ||
445 | * go back to unknown state. | ||
446 | */ | ||
447 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
448 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
449 | if (signature != QCASPI_GOOD_SIGNATURE) { | ||
450 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
451 | netdev_dbg(qca->net_dev, "sync: got CPU on, but signature was invalid, restart\n"); | ||
452 | } else { | ||
453 | /* ensure that the WRBUF is empty */ | ||
454 | qcaspi_read_register(qca, SPI_REG_WRBUF_SPC_AVA, | ||
455 | &wrbuf_space); | ||
456 | if (wrbuf_space != QCASPI_HW_BUF_LEN) { | ||
457 | netdev_dbg(qca->net_dev, "sync: got CPU on, but wrbuf not empty. reset!\n"); | ||
458 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
459 | } else { | ||
460 | netdev_dbg(qca->net_dev, "sync: got CPU on, now in sync\n"); | ||
461 | qca->sync = QCASPI_SYNC_READY; | ||
462 | return; | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | |||
467 | switch (qca->sync) { | ||
468 | case QCASPI_SYNC_READY: | ||
469 | /* Read signature, if not valid go to unknown state. */ | ||
470 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
471 | if (signature != QCASPI_GOOD_SIGNATURE) { | ||
472 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
473 | netdev_dbg(qca->net_dev, "sync: bad signature, restart\n"); | ||
474 | /* don't reset right away */ | ||
475 | return; | ||
476 | } | ||
477 | break; | ||
478 | case QCASPI_SYNC_UNKNOWN: | ||
479 | /* Read signature, if not valid stay in unknown state */ | ||
480 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
481 | if (signature != QCASPI_GOOD_SIGNATURE) { | ||
482 | netdev_dbg(qca->net_dev, "sync: could not read signature to reset device, retry.\n"); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | /* TODO: use GPIO to reset QCA7000 in legacy mode*/ | ||
487 | netdev_dbg(qca->net_dev, "sync: resetting device.\n"); | ||
488 | qcaspi_read_register(qca, SPI_REG_SPI_CONFIG, &spi_config); | ||
489 | spi_config |= QCASPI_SLAVE_RESET_BIT; | ||
490 | qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config); | ||
491 | |||
492 | qca->sync = QCASPI_SYNC_RESET; | ||
493 | qca->stats.trig_reset++; | ||
494 | reset_count = 0; | ||
495 | break; | ||
496 | case QCASPI_SYNC_RESET: | ||
497 | reset_count++; | ||
498 | netdev_dbg(qca->net_dev, "sync: waiting for CPU on, count %u.\n", | ||
499 | reset_count); | ||
500 | if (reset_count >= QCASPI_RESET_TIMEOUT) { | ||
501 | /* reset did not seem to take place, try again */ | ||
502 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
503 | qca->stats.reset_timeout++; | ||
504 | netdev_dbg(qca->net_dev, "sync: reset timeout, restarting process.\n"); | ||
505 | } | ||
506 | break; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | static int | ||
511 | qcaspi_spi_thread(void *data) | ||
512 | { | ||
513 | struct qcaspi *qca = data; | ||
514 | u16 intr_cause = 0; | ||
515 | |||
516 | netdev_info(qca->net_dev, "SPI thread created\n"); | ||
517 | while (!kthread_should_stop()) { | ||
518 | set_current_state(TASK_INTERRUPTIBLE); | ||
519 | if ((qca->intr_req == qca->intr_svc) && | ||
520 | (qca->txr.skb[qca->txr.head] == NULL) && | ||
521 | (qca->sync == QCASPI_SYNC_READY)) | ||
522 | schedule(); | ||
523 | |||
524 | set_current_state(TASK_RUNNING); | ||
525 | |||
526 | netdev_dbg(qca->net_dev, "have work to do. int: %d, tx_skb: %p\n", | ||
527 | qca->intr_req - qca->intr_svc, | ||
528 | qca->txr.skb[qca->txr.head]); | ||
529 | |||
530 | qcaspi_qca7k_sync(qca, QCASPI_EVENT_UPDATE); | ||
531 | |||
532 | if (qca->sync != QCASPI_SYNC_READY) { | ||
533 | netdev_dbg(qca->net_dev, "sync: not ready %u, turn off carrier and flush\n", | ||
534 | (unsigned int)qca->sync); | ||
535 | netif_stop_queue(qca->net_dev); | ||
536 | netif_carrier_off(qca->net_dev); | ||
537 | qcaspi_flush_tx_ring(qca); | ||
538 | msleep(QCASPI_QCA7K_REBOOT_TIME_MS); | ||
539 | } | ||
540 | |||
541 | if (qca->intr_svc != qca->intr_req) { | ||
542 | qca->intr_svc = qca->intr_req; | ||
543 | start_spi_intr_handling(qca, &intr_cause); | ||
544 | |||
545 | if (intr_cause & SPI_INT_CPU_ON) { | ||
546 | qcaspi_qca7k_sync(qca, QCASPI_EVENT_CPUON); | ||
547 | |||
548 | /* not synced. */ | ||
549 | if (qca->sync != QCASPI_SYNC_READY) | ||
550 | continue; | ||
551 | |||
552 | qca->stats.device_reset++; | ||
553 | netif_wake_queue(qca->net_dev); | ||
554 | netif_carrier_on(qca->net_dev); | ||
555 | } | ||
556 | |||
557 | if (intr_cause & SPI_INT_RDBUF_ERR) { | ||
558 | /* restart sync */ | ||
559 | netdev_dbg(qca->net_dev, "===> rdbuf error!\n"); | ||
560 | qca->stats.read_buf_err++; | ||
561 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
562 | continue; | ||
563 | } | ||
564 | |||
565 | if (intr_cause & SPI_INT_WRBUF_ERR) { | ||
566 | /* restart sync */ | ||
567 | netdev_dbg(qca->net_dev, "===> wrbuf error!\n"); | ||
568 | qca->stats.write_buf_err++; | ||
569 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
570 | continue; | ||
571 | } | ||
572 | |||
573 | /* can only handle other interrupts | ||
574 | * if sync has occured | ||
575 | */ | ||
576 | if (qca->sync == QCASPI_SYNC_READY) { | ||
577 | if (intr_cause & SPI_INT_PKT_AVLBL) | ||
578 | qcaspi_receive(qca); | ||
579 | } | ||
580 | |||
581 | end_spi_intr_handling(qca, intr_cause); | ||
582 | } | ||
583 | |||
584 | if (qca->sync == QCASPI_SYNC_READY) | ||
585 | qcaspi_transmit(qca); | ||
586 | } | ||
587 | set_current_state(TASK_RUNNING); | ||
588 | netdev_info(qca->net_dev, "SPI thread exit\n"); | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static irqreturn_t | ||
594 | qcaspi_intr_handler(int irq, void *data) | ||
595 | { | ||
596 | struct qcaspi *qca = data; | ||
597 | |||
598 | qca->intr_req++; | ||
599 | if (qca->spi_thread && | ||
600 | qca->spi_thread->state != TASK_RUNNING) | ||
601 | wake_up_process(qca->spi_thread); | ||
602 | |||
603 | return IRQ_HANDLED; | ||
604 | } | ||
605 | |||
606 | int | ||
607 | qcaspi_netdev_open(struct net_device *dev) | ||
608 | { | ||
609 | struct qcaspi *qca = netdev_priv(dev); | ||
610 | int ret = 0; | ||
611 | |||
612 | if (!qca) | ||
613 | return -EINVAL; | ||
614 | |||
615 | qca->intr_req = 1; | ||
616 | qca->intr_svc = 0; | ||
617 | qca->sync = QCASPI_SYNC_UNKNOWN; | ||
618 | qcafrm_fsm_init(&qca->frm_handle); | ||
619 | |||
620 | qca->spi_thread = kthread_run((void *)qcaspi_spi_thread, | ||
621 | qca, "%s", dev->name); | ||
622 | |||
623 | if (IS_ERR(qca->spi_thread)) { | ||
624 | netdev_err(dev, "%s: unable to start kernel thread.\n", | ||
625 | QCASPI_DRV_NAME); | ||
626 | return PTR_ERR(qca->spi_thread); | ||
627 | } | ||
628 | |||
629 | ret = request_irq(qca->spi_dev->irq, qcaspi_intr_handler, 0, | ||
630 | dev->name, qca); | ||
631 | if (ret) { | ||
632 | netdev_err(dev, "%s: unable to get IRQ %d (irqval=%d).\n", | ||
633 | QCASPI_DRV_NAME, qca->spi_dev->irq, ret); | ||
634 | kthread_stop(qca->spi_thread); | ||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | netif_start_queue(qca->net_dev); | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | int | ||
644 | qcaspi_netdev_close(struct net_device *dev) | ||
645 | { | ||
646 | struct qcaspi *qca = netdev_priv(dev); | ||
647 | |||
648 | netif_stop_queue(dev); | ||
649 | |||
650 | qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0); | ||
651 | free_irq(qca->spi_dev->irq, qca); | ||
652 | |||
653 | kthread_stop(qca->spi_thread); | ||
654 | qca->spi_thread = NULL; | ||
655 | qcaspi_flush_tx_ring(qca); | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static netdev_tx_t | ||
661 | qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) | ||
662 | { | ||
663 | u32 frame_len; | ||
664 | u8 *ptmp; | ||
665 | struct qcaspi *qca = netdev_priv(dev); | ||
666 | u16 new_tail; | ||
667 | struct sk_buff *tskb; | ||
668 | u8 pad_len = 0; | ||
669 | |||
670 | if (skb->len < QCAFRM_ETHMINLEN) | ||
671 | pad_len = QCAFRM_ETHMINLEN - skb->len; | ||
672 | |||
673 | if (qca->txr.skb[qca->txr.tail]) { | ||
674 | netdev_warn(qca->net_dev, "queue was unexpectedly full!\n"); | ||
675 | netif_stop_queue(qca->net_dev); | ||
676 | qca->stats.ring_full++; | ||
677 | return NETDEV_TX_BUSY; | ||
678 | } | ||
679 | |||
680 | if ((skb_headroom(skb) < QCAFRM_HEADER_LEN) || | ||
681 | (skb_tailroom(skb) < QCAFRM_FOOTER_LEN + pad_len)) { | ||
682 | tskb = skb_copy_expand(skb, QCAFRM_HEADER_LEN, | ||
683 | QCAFRM_FOOTER_LEN + pad_len, GFP_ATOMIC); | ||
684 | if (!tskb) { | ||
685 | netdev_dbg(qca->net_dev, "could not allocate tx_buff\n"); | ||
686 | qca->stats.out_of_mem++; | ||
687 | return NETDEV_TX_BUSY; | ||
688 | } | ||
689 | dev_kfree_skb(skb); | ||
690 | skb = tskb; | ||
691 | } | ||
692 | |||
693 | frame_len = skb->len + pad_len; | ||
694 | |||
695 | ptmp = skb_push(skb, QCAFRM_HEADER_LEN); | ||
696 | qcafrm_create_header(ptmp, frame_len); | ||
697 | |||
698 | if (pad_len) { | ||
699 | ptmp = skb_put(skb, pad_len); | ||
700 | memset(ptmp, 0, pad_len); | ||
701 | } | ||
702 | |||
703 | ptmp = skb_put(skb, QCAFRM_FOOTER_LEN); | ||
704 | qcafrm_create_footer(ptmp); | ||
705 | |||
706 | netdev_dbg(qca->net_dev, "Tx-ing packet: Size: 0x%08x\n", | ||
707 | skb->len); | ||
708 | |||
709 | qca->txr.size += skb->len + QCASPI_HW_PKT_LEN; | ||
710 | |||
711 | new_tail = qca->txr.tail + 1; | ||
712 | if (new_tail >= qca->txr.count) | ||
713 | new_tail = 0; | ||
714 | |||
715 | qca->txr.skb[qca->txr.tail] = skb; | ||
716 | qca->txr.tail = new_tail; | ||
717 | |||
718 | if (!qcaspi_tx_ring_has_space(&qca->txr)) { | ||
719 | netif_stop_queue(qca->net_dev); | ||
720 | qca->stats.ring_full++; | ||
721 | } | ||
722 | |||
723 | dev->trans_start = jiffies; | ||
724 | |||
725 | if (qca->spi_thread && | ||
726 | qca->spi_thread->state != TASK_RUNNING) | ||
727 | wake_up_process(qca->spi_thread); | ||
728 | |||
729 | return NETDEV_TX_OK; | ||
730 | } | ||
731 | |||
732 | static void | ||
733 | qcaspi_netdev_tx_timeout(struct net_device *dev) | ||
734 | { | ||
735 | struct qcaspi *qca = netdev_priv(dev); | ||
736 | |||
737 | netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n", | ||
738 | jiffies, jiffies - dev->trans_start); | ||
739 | qca->net_dev->stats.tx_errors++; | ||
740 | /* wake the queue if there is room */ | ||
741 | if (qcaspi_tx_ring_has_space(&qca->txr)) | ||
742 | netif_wake_queue(dev); | ||
743 | } | ||
744 | |||
745 | static int | ||
746 | qcaspi_netdev_init(struct net_device *dev) | ||
747 | { | ||
748 | struct qcaspi *qca = netdev_priv(dev); | ||
749 | |||
750 | dev->mtu = QCASPI_MTU; | ||
751 | dev->type = ARPHRD_ETHER; | ||
752 | qca->clkspeed = qcaspi_clkspeed; | ||
753 | qca->burst_len = qcaspi_burst_len; | ||
754 | qca->spi_thread = NULL; | ||
755 | qca->buffer_size = (dev->mtu + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + | ||
756 | QCAFRM_FOOTER_LEN + 4) * 4; | ||
757 | |||
758 | memset(&qca->stats, 0, sizeof(struct qcaspi_stats)); | ||
759 | |||
760 | qca->rx_buffer = kmalloc(qca->buffer_size, GFP_KERNEL); | ||
761 | if (!qca->rx_buffer) | ||
762 | return -ENOBUFS; | ||
763 | |||
764 | qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN); | ||
765 | if (!qca->rx_skb) { | ||
766 | kfree(qca->rx_buffer); | ||
767 | netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n"); | ||
768 | return -ENOBUFS; | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static void | ||
775 | qcaspi_netdev_uninit(struct net_device *dev) | ||
776 | { | ||
777 | struct qcaspi *qca = netdev_priv(dev); | ||
778 | |||
779 | kfree(qca->rx_buffer); | ||
780 | qca->buffer_size = 0; | ||
781 | if (qca->rx_skb) | ||
782 | dev_kfree_skb(qca->rx_skb); | ||
783 | } | ||
784 | |||
785 | static int | ||
786 | qcaspi_netdev_change_mtu(struct net_device *dev, int new_mtu) | ||
787 | { | ||
788 | if ((new_mtu < QCAFRM_ETHMINMTU) || (new_mtu > QCAFRM_ETHMAXMTU)) | ||
789 | return -EINVAL; | ||
790 | |||
791 | dev->mtu = new_mtu; | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static const struct net_device_ops qcaspi_netdev_ops = { | ||
797 | .ndo_init = qcaspi_netdev_init, | ||
798 | .ndo_uninit = qcaspi_netdev_uninit, | ||
799 | .ndo_open = qcaspi_netdev_open, | ||
800 | .ndo_stop = qcaspi_netdev_close, | ||
801 | .ndo_start_xmit = qcaspi_netdev_xmit, | ||
802 | .ndo_change_mtu = qcaspi_netdev_change_mtu, | ||
803 | .ndo_set_mac_address = eth_mac_addr, | ||
804 | .ndo_tx_timeout = qcaspi_netdev_tx_timeout, | ||
805 | .ndo_validate_addr = eth_validate_addr, | ||
806 | }; | ||
807 | |||
808 | static void | ||
809 | qcaspi_netdev_setup(struct net_device *dev) | ||
810 | { | ||
811 | struct qcaspi *qca = NULL; | ||
812 | |||
813 | ether_setup(dev); | ||
814 | |||
815 | dev->netdev_ops = &qcaspi_netdev_ops; | ||
816 | qcaspi_set_ethtool_ops(dev); | ||
817 | dev->watchdog_timeo = QCASPI_TX_TIMEOUT; | ||
818 | dev->flags = IFF_MULTICAST; | ||
819 | dev->tx_queue_len = 100; | ||
820 | |||
821 | qca = netdev_priv(dev); | ||
822 | memset(qca, 0, sizeof(struct qcaspi)); | ||
823 | |||
824 | memset(&qca->spi_xfer1, 0, sizeof(struct spi_transfer)); | ||
825 | memset(&qca->spi_xfer2, 0, sizeof(struct spi_transfer) * 2); | ||
826 | |||
827 | spi_message_init(&qca->spi_msg1); | ||
828 | spi_message_add_tail(&qca->spi_xfer1, &qca->spi_msg1); | ||
829 | |||
830 | spi_message_init(&qca->spi_msg2); | ||
831 | spi_message_add_tail(&qca->spi_xfer2[0], &qca->spi_msg2); | ||
832 | spi_message_add_tail(&qca->spi_xfer2[1], &qca->spi_msg2); | ||
833 | |||
834 | memset(&qca->txr, 0, sizeof(qca->txr)); | ||
835 | qca->txr.count = TX_RING_MAX_LEN; | ||
836 | } | ||
837 | |||
838 | static const struct of_device_id qca_spi_of_match[] = { | ||
839 | { .compatible = "qca,qca7000" }, | ||
840 | { /* sentinel */ } | ||
841 | }; | ||
842 | MODULE_DEVICE_TABLE(of, qca_spi_of_match); | ||
843 | |||
844 | static int | ||
845 | qca_spi_probe(struct spi_device *spi_device) | ||
846 | { | ||
847 | struct qcaspi *qca = NULL; | ||
848 | struct net_device *qcaspi_devs = NULL; | ||
849 | u8 legacy_mode = 0; | ||
850 | u16 signature; | ||
851 | const char *mac; | ||
852 | |||
853 | if (!spi_device->dev.of_node) { | ||
854 | dev_err(&spi_device->dev, "Missing device tree\n"); | ||
855 | return -EINVAL; | ||
856 | } | ||
857 | |||
858 | legacy_mode = of_property_read_bool(spi_device->dev.of_node, | ||
859 | "qca,legacy-mode"); | ||
860 | |||
861 | if (qcaspi_clkspeed == 0) { | ||
862 | if (spi_device->max_speed_hz) | ||
863 | qcaspi_clkspeed = spi_device->max_speed_hz; | ||
864 | else | ||
865 | qcaspi_clkspeed = QCASPI_CLK_SPEED; | ||
866 | } | ||
867 | |||
868 | if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) || | ||
869 | (qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) { | ||
870 | dev_info(&spi_device->dev, "Invalid clkspeed: %d\n", | ||
871 | qcaspi_clkspeed); | ||
872 | return -EINVAL; | ||
873 | } | ||
874 | |||
875 | if ((qcaspi_burst_len < QCASPI_BURST_LEN_MIN) || | ||
876 | (qcaspi_burst_len > QCASPI_BURST_LEN_MAX)) { | ||
877 | dev_info(&spi_device->dev, "Invalid burst len: %d\n", | ||
878 | qcaspi_burst_len); | ||
879 | return -EINVAL; | ||
880 | } | ||
881 | |||
882 | if ((qcaspi_pluggable < QCASPI_PLUGGABLE_MIN) || | ||
883 | (qcaspi_pluggable > QCASPI_PLUGGABLE_MAX)) { | ||
884 | dev_info(&spi_device->dev, "Invalid pluggable: %d\n", | ||
885 | qcaspi_pluggable); | ||
886 | return -EINVAL; | ||
887 | } | ||
888 | |||
889 | dev_info(&spi_device->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n", | ||
890 | QCASPI_DRV_VERSION, | ||
891 | qcaspi_clkspeed, | ||
892 | qcaspi_burst_len, | ||
893 | qcaspi_pluggable); | ||
894 | |||
895 | spi_device->mode = SPI_MODE_3; | ||
896 | spi_device->max_speed_hz = qcaspi_clkspeed; | ||
897 | if (spi_setup(spi_device) < 0) { | ||
898 | dev_err(&spi_device->dev, "Unable to setup SPI device\n"); | ||
899 | return -EFAULT; | ||
900 | } | ||
901 | |||
902 | qcaspi_devs = alloc_etherdev(sizeof(struct qcaspi)); | ||
903 | if (!qcaspi_devs) | ||
904 | return -ENOMEM; | ||
905 | |||
906 | qcaspi_netdev_setup(qcaspi_devs); | ||
907 | |||
908 | qca = netdev_priv(qcaspi_devs); | ||
909 | if (!qca) { | ||
910 | free_netdev(qcaspi_devs); | ||
911 | dev_err(&spi_device->dev, "Fail to retrieve private structure\n"); | ||
912 | return -ENOMEM; | ||
913 | } | ||
914 | qca->net_dev = qcaspi_devs; | ||
915 | qca->spi_dev = spi_device; | ||
916 | qca->legacy_mode = legacy_mode; | ||
917 | |||
918 | mac = of_get_mac_address(spi_device->dev.of_node); | ||
919 | |||
920 | if (mac) | ||
921 | ether_addr_copy(qca->net_dev->dev_addr, mac); | ||
922 | |||
923 | if (!is_valid_ether_addr(qca->net_dev->dev_addr)) { | ||
924 | eth_hw_addr_random(qca->net_dev); | ||
925 | dev_info(&spi_device->dev, "Using random MAC address: %pM\n", | ||
926 | qca->net_dev->dev_addr); | ||
927 | } | ||
928 | |||
929 | netif_carrier_off(qca->net_dev); | ||
930 | |||
931 | if (!qcaspi_pluggable) { | ||
932 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
933 | qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); | ||
934 | |||
935 | if (signature != QCASPI_GOOD_SIGNATURE) { | ||
936 | dev_err(&spi_device->dev, "Invalid signature (0x%04X)\n", | ||
937 | signature); | ||
938 | free_netdev(qcaspi_devs); | ||
939 | return -EFAULT; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | if (register_netdev(qcaspi_devs)) { | ||
944 | dev_info(&spi_device->dev, "Unable to register net device %s\n", | ||
945 | qcaspi_devs->name); | ||
946 | free_netdev(qcaspi_devs); | ||
947 | return -EFAULT; | ||
948 | } | ||
949 | |||
950 | spi_set_drvdata(spi_device, qcaspi_devs); | ||
951 | |||
952 | qcaspi_init_device_debugfs(qca); | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | static int | ||
958 | qca_spi_remove(struct spi_device *spi_device) | ||
959 | { | ||
960 | struct net_device *qcaspi_devs = spi_get_drvdata(spi_device); | ||
961 | struct qcaspi *qca = netdev_priv(qcaspi_devs); | ||
962 | |||
963 | qcaspi_remove_device_debugfs(qca); | ||
964 | |||
965 | unregister_netdev(qcaspi_devs); | ||
966 | free_netdev(qcaspi_devs); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static const struct spi_device_id qca_spi_id[] = { | ||
972 | { "qca7000", 0 }, | ||
973 | { /* sentinel */ } | ||
974 | }; | ||
975 | MODULE_DEVICE_TABLE(spi, qca_spi_id); | ||
976 | |||
977 | static struct spi_driver qca_spi_driver = { | ||
978 | .driver = { | ||
979 | .name = QCASPI_DRV_NAME, | ||
980 | .owner = THIS_MODULE, | ||
981 | .of_match_table = qca_spi_of_match, | ||
982 | }, | ||
983 | .id_table = qca_spi_id, | ||
984 | .probe = qca_spi_probe, | ||
985 | .remove = qca_spi_remove, | ||
986 | }; | ||
987 | module_spi_driver(qca_spi_driver); | ||
988 | |||
989 | MODULE_DESCRIPTION("Qualcomm Atheros SPI Driver"); | ||
990 | MODULE_AUTHOR("Qualcomm Atheros Communications"); | ||
991 | MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); | ||
992 | MODULE_LICENSE("Dual BSD/GPL"); | ||
993 | MODULE_VERSION(QCASPI_DRV_VERSION); | ||
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h new file mode 100644 index 000000000000..6e31a0e744a4 --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_spi.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. | ||
3 | * Copyright (c) 2014, I2SE GmbH | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software | ||
6 | * for any purpose with or without fee is hereby granted, provided | ||
7 | * that the above copyright notice and this permission notice appear | ||
8 | * in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
11 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | ||
13 | * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
14 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
15 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | /* Qualcomm Atheros SPI register definition. | ||
21 | * | ||
22 | * This module is designed to define the Qualcomm Atheros SPI register | ||
23 | * placeholders; | ||
24 | */ | ||
25 | |||
26 | #ifndef _QCA_SPI_H | ||
27 | #define _QCA_SPI_H | ||
28 | |||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | #include <linux/spi/spi.h> | ||
33 | #include <linux/types.h> | ||
34 | |||
35 | #include "qca_framing.h" | ||
36 | |||
37 | #define QCASPI_DRV_VERSION "0.2.7-i" | ||
38 | #define QCASPI_DRV_NAME "qcaspi" | ||
39 | |||
40 | #define QCASPI_GOOD_SIGNATURE 0xAA55 | ||
41 | |||
42 | #define TX_RING_MAX_LEN 10 | ||
43 | #define TX_RING_MIN_LEN 2 | ||
44 | |||
45 | /* sync related constants */ | ||
46 | #define QCASPI_SYNC_UNKNOWN 0 | ||
47 | #define QCASPI_SYNC_RESET 1 | ||
48 | #define QCASPI_SYNC_READY 2 | ||
49 | |||
50 | #define QCASPI_RESET_TIMEOUT 10 | ||
51 | |||
52 | /* sync events */ | ||
53 | #define QCASPI_EVENT_UPDATE 0 | ||
54 | #define QCASPI_EVENT_CPUON 1 | ||
55 | |||
56 | struct tx_ring { | ||
57 | struct sk_buff *skb[TX_RING_MAX_LEN]; | ||
58 | u16 head; | ||
59 | u16 tail; | ||
60 | u16 size; | ||
61 | u16 count; | ||
62 | }; | ||
63 | |||
64 | struct qcaspi_stats { | ||
65 | u64 trig_reset; | ||
66 | u64 device_reset; | ||
67 | u64 reset_timeout; | ||
68 | u64 read_err; | ||
69 | u64 write_err; | ||
70 | u64 read_buf_err; | ||
71 | u64 write_buf_err; | ||
72 | u64 out_of_mem; | ||
73 | u64 write_buf_miss; | ||
74 | u64 ring_full; | ||
75 | u64 spi_err; | ||
76 | }; | ||
77 | |||
78 | struct qcaspi { | ||
79 | struct net_device *net_dev; | ||
80 | struct spi_device *spi_dev; | ||
81 | struct task_struct *spi_thread; | ||
82 | |||
83 | struct tx_ring txr; | ||
84 | struct qcaspi_stats stats; | ||
85 | |||
86 | struct spi_message spi_msg1; | ||
87 | struct spi_message spi_msg2; | ||
88 | struct spi_transfer spi_xfer1; | ||
89 | struct spi_transfer spi_xfer2[2]; | ||
90 | |||
91 | u8 *rx_buffer; | ||
92 | u32 buffer_size; | ||
93 | u8 sync; | ||
94 | |||
95 | struct qcafrm_handle frm_handle; | ||
96 | struct sk_buff *rx_skb; | ||
97 | |||
98 | unsigned int intr_req; | ||
99 | unsigned int intr_svc; | ||
100 | |||
101 | #ifdef CONFIG_DEBUG_FS | ||
102 | struct dentry *device_root; | ||
103 | #endif | ||
104 | |||
105 | /* user configurable options */ | ||
106 | u32 clkspeed; | ||
107 | u8 legacy_mode; | ||
108 | u16 burst_len; | ||
109 | }; | ||
110 | |||
111 | int qcaspi_netdev_open(struct net_device *dev); | ||
112 | int qcaspi_netdev_close(struct net_device *dev); | ||
113 | |||
114 | #endif /* _QCA_SPI_H */ | ||