Commit 9711164d authored by David S. Miller's avatar David S. Miller

Merge branch 'net-qualcomm-add-QCA7000-UART-driver'

Stefan Wahren says:

====================
net: qualcomm: add QCA7000 UART driver

The Qualcomm QCA7000 HomePlug GreenPHY supports two interfaces:
UART and SPI. This patch series adds the missing support for UART.

This driver based on the Qualcomm code [1], but contains some changes:
* use random MAC address per default
* use net_device_stats from device
* share frame decoding between SPI and UART driver
* improve error handling
* reimplement tty_wakeup with work queue (based on slcan)
* use new serial device bus instead of ldisc

The patches 1 - 3 are just for clean up and are not related to
the UART support. Patch 4 adds SET_NETDEV_DEV() to qca_spi.
Patches 5 - 16 prepare the existing QCA7000 code for UART support.
The last patch contains the new driver.

The code itself has been tested on a Freescale i.MX28 board and
a Raspberry Pi Zero.

Changes in v8:
  * add necessary header includes to qca_7k.c in order to reflect
    dependencies

Changes in v7:
  * fix race between tx workqueue and device deregistration (reported by Lino)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ae803902 dfc768fb
* Qualcomm QCA7000
The QCA7000 is a serial-to-powerline bridge with a host interface which could
be configured either as SPI or UART slave. This configuration is done by
the QCA7000 firmware.
(a) Ethernet over SPI
In order to use the QCA7000 as SPI device it must be defined as a child of a
SPI master in the device tree.
Required properties:
- compatible : Should be "qca,qca7000"
- reg : Should specify the SPI chip select
- interrupts : The first cell should specify the index of the source
interrupt and the second cell should specify the trigger
type as rising edge
- spi-cpha : Must be set
- spi-cpol : Must be set
Optional properties:
- interrupt-parent : Specify the pHandle of the source interrupt
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at.
Numbers smaller than 1000000 or greater than 16000000
are invalid. Missing the property will set the SPI
frequency to 8000000 Hertz.
- local-mac-address : see ./ethernet.txt
- qca,legacy-mode : Set the SPI data transfer of the QCA7000 to legacy mode.
In this mode the SPI master must toggle the chip select
between each data word. In burst mode these gaps aren't
necessary, which is faster. This setting depends on how
the QCA7000 is setup via GPIO pin strapping. If the
property is missing the driver defaults to burst mode.
SPI Example:
/* Freescale i.MX28 SPI master*/
ssp2: spi@80014000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx28-spi";
pinctrl-names = "default";
pinctrl-0 = <&spi2_pins_a>;
status = "okay";
qca7000: ethernet@0 {
compatible = "qca,qca7000";
reg = <0x0>;
interrupt-parent = <&gpio3>; /* GPIO Bank 3 */
interrupts = <25 0x1>; /* Index: 25, rising edge */
spi-cpha; /* SPI mode: CPHA=1 */
spi-cpol; /* SPI mode: CPOL=1 */
spi-max-frequency = <8000000>; /* freq: 8 MHz */
local-mac-address = [ A0 B0 C0 D0 E0 F0 ];
};
};
(b) Ethernet over UART
In order to use the QCA7000 as UART slave it must be defined as a child of a
UART master in the device tree. It is possible to preconfigure the UART
settings of the QCA7000 firmware, but it's not possible to change them during
runtime.
Required properties:
- compatible : Should be "qca,qca7000"
Optional properties:
- local-mac-address : see ./ethernet.txt
- current-speed : current baud rate of QCA7000 which defaults to 115200
if absent, see also ../serial/slave-device.txt
UART Example:
/* Freescale i.MX28 UART */
auart0: serial@8006a000 {
compatible = "fsl,imx28-auart", "fsl,imx23-auart";
reg = <0x8006a000 0x2000>;
pinctrl-names = "default";
pinctrl-0 = <&auart0_2pins_a>;
status = "okay";
qca7000: ethernet {
compatible = "qca,qca7000";
local-mac-address = [ A0 B0 C0 D0 E0 F0 ];
current-speed = <38400>;
};
};
* Qualcomm QCA7000 (Ethernet over SPI protocol)
Note: The QCA7000 is useable as a SPI device. In this case it must be defined
as a child of a SPI master in the device tree.
Required properties:
- compatible : Should be "qca,qca7000"
- reg : Should specify the SPI chip select
- interrupts : The first cell should specify the index of the source interrupt
and the second cell should specify the trigger type as rising edge
- spi-cpha : Must be set
- spi-cpol: Must be set
Optional properties:
- interrupt-parent : Specify the pHandle of the source interrupt
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at.
Numbers smaller than 1000000 or greater than 16000000 are invalid. Missing
the property will set the SPI frequency to 8000000 Hertz.
- local-mac-address: 6 bytes, MAC address
- qca,legacy-mode : Set the SPI data transfer of the QCA7000 to legacy mode.
In this mode the SPI master must toggle the chip select between each data
word. In burst mode these gaps aren't necessary, which is faster.
This setting depends on how the QCA7000 is setup via GPIO pin strapping.
If the property is missing the driver defaults to burst mode.
Example:
/* Freescale i.MX28 SPI master*/
ssp2: spi@80014000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx28-spi";
pinctrl-names = "default";
pinctrl-0 = <&spi2_pins_a>;
status = "okay";
qca7000: ethernet@0 {
compatible = "qca,qca7000";
reg = <0x0>;
interrupt-parent = <&gpio3>; /* GPIO Bank 3 */
interrupts = <25 0x1>; /* Index: 25, rising edge */
spi-cpha; /* SPI mode: CPHA=1 */
spi-cpol; /* SPI mode: CPOL=1 */
spi-max-frequency = <8000000>; /* freq: 8 MHz */
local-mac-address = [ A0 B0 C0 D0 E0 F0 ];
};
};
......@@ -21,6 +21,15 @@ Optional Properties:
can support. For example, a particular board has some signal
quality issue or the host processor can't support higher
baud rates.
- current-speed : The current baud rate the device operates at. This should
only be present in case a driver has no chance to know
the baud rate of the slave device.
Examples:
* device supports auto-baud
* the rate is setup by a bootloader and there is no
way to reset the device
* device baud rate is configured by its firmware but
there is no way to request the actual settings
Example:
......
......@@ -16,7 +16,13 @@ config NET_VENDOR_QUALCOMM
if NET_VENDOR_QUALCOMM
config QCA7000
tristate "Qualcomm Atheros QCA7000 support"
tristate
help
This enables support for the Qualcomm Atheros QCA7000.
config QCA7000_SPI
tristate "Qualcomm Atheros QCA7000 SPI support"
select QCA7000
depends on SPI_MASTER && OF
---help---
This SPI protocol driver supports the Qualcomm Atheros QCA7000.
......@@ -24,6 +30,22 @@ config QCA7000
To compile this driver as a module, choose M here. The module
will be called qcaspi.
config QCA7000_UART
tristate "Qualcomm Atheros QCA7000 UART support"
select QCA7000
depends on SERIAL_DEV_BUS && OF
---help---
This UART protocol driver supports the Qualcomm Atheros QCA7000.
Currently the driver assumes these device UART settings:
Data bits: 8
Parity: None
Stop bits: 1
Flow control: None
To compile this driver as a module, choose M here. The module
will be called qcauart.
config QCOM_EMAC
tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support"
depends on HAS_DMA && HAS_IOMEM
......
......@@ -2,7 +2,10 @@
# Makefile for the Qualcomm network device drivers.
#
obj-$(CONFIG_QCA7000) += qcaspi.o
qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o
obj-$(CONFIG_QCA7000) += qca_7k_common.o
obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
obj-$(CONFIG_QCA7000_UART) += qcauart.o
qcauart-objs := qca_uart.o
obj-y += emac/
......@@ -23,11 +23,9 @@
* kernel-based SPI device.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/spi/spi.h>
#include <linux/version.h>
#include "qca_7k.h"
......@@ -123,27 +121,3 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
return ret;
}
int
qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd)
{
__be16 tx_data;
struct spi_message *msg = &qca->spi_msg1;
struct spi_transfer *transfer = &qca->spi_xfer1;
int ret;
tx_data = cpu_to_be16(cmd);
transfer->len = sizeof(tx_data);
transfer->tx_buf = &tx_data;
transfer->rx_buf = NULL;
ret = spi_sync(qca->spi_dev, msg);
if (!ret)
ret = msg->status;
if (ret)
qcaspi_spi_error(qca);
return ret;
}
......@@ -54,19 +54,18 @@
#define SPI_REG_ACTION_CTRL 0x1B00
/* SPI_CONFIG register definition; */
#define QCASPI_SLAVE_RESET_BIT (1 << 6)
#define QCASPI_SLAVE_RESET_BIT BIT(6)
/* INTR_CAUSE/ENABLE register definition. */
#define SPI_INT_WRBUF_BELOW_WM (1 << 10)
#define SPI_INT_CPU_ON (1 << 6)
#define SPI_INT_ADDR_ERR (1 << 3)
#define SPI_INT_WRBUF_ERR (1 << 2)
#define SPI_INT_RDBUF_ERR (1 << 1)
#define SPI_INT_PKT_AVLBL (1 << 0)
#define SPI_INT_WRBUF_BELOW_WM BIT(10)
#define SPI_INT_CPU_ON BIT(6)
#define SPI_INT_ADDR_ERR BIT(3)
#define SPI_INT_WRBUF_ERR BIT(2)
#define SPI_INT_RDBUF_ERR BIT(1)
#define SPI_INT_PKT_AVLBL BIT(0)
void qcaspi_spi_error(struct qcaspi *qca);
int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result);
int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value);
int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd);
#endif /* _QCA_7K_H */
......@@ -21,9 +21,11 @@
* by an atheros frame while transmitted over a serial channel;
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "qca_framing.h"
#include "qca_7k_common.h"
u16
qcafrm_create_header(u8 *buf, u16 length)
......@@ -46,6 +48,7 @@ qcafrm_create_header(u8 *buf, u16 length)
return QCAFRM_HEADER_LEN;
}
EXPORT_SYMBOL_GPL(qcafrm_create_header);
u16
qcafrm_create_footer(u8 *buf)
......@@ -57,6 +60,7 @@ qcafrm_create_footer(u8 *buf)
buf[1] = 0x55;
return QCAFRM_FOOTER_LEN;
}
EXPORT_SYMBOL_GPL(qcafrm_create_footer);
/* Gather received bytes and try to extract a full ethernet frame by
* following a simple state machine.
......@@ -83,7 +87,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
if (recv_byte != 0x00) {
/* first two bytes of length must be 0 */
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
}
break;
case QCAFRM_HW_LEN2:
......@@ -97,7 +101,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
case QCAFRM_WAIT_AA4:
if (recv_byte != 0xAA) {
ret = QCAFRM_NOHEAD;
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
} else {
handle->state--;
}
......@@ -117,9 +121,9 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
break;
case QCAFRM_WAIT_RSVD_BYTE2:
len = handle->offset;
if (len > buf_len || len < QCAFRM_ETHMINLEN) {
if (len > buf_len || len < QCAFRM_MIN_LEN) {
ret = QCAFRM_INVLEN;
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
} else {
handle->state = (enum qcafrm_state)(len + 1);
/* Remaining number of bytes. */
......@@ -135,7 +139,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
case QCAFRM_WAIT_551:
if (recv_byte != 0x55) {
ret = QCAFRM_NOTAIL;
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
} else {
handle->state = QCAFRM_WAIT_552;
}
......@@ -143,14 +147,20 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
case QCAFRM_WAIT_552:
if (recv_byte != 0x55) {
ret = QCAFRM_NOTAIL;
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
} else {
ret = handle->offset;
/* Frame is fully received. */
handle->state = QCAFRM_HW_LEN0;
handle->state = handle->init;
}
break;
}
return ret;
}
EXPORT_SYMBOL_GPL(qcafrm_fsm_decode);
MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common");
MODULE_AUTHOR("Qualcomm Atheros Communications");
MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
MODULE_LICENSE("Dual BSD/GPL");
......@@ -44,12 +44,12 @@
#define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4)
/* Min/Max Ethernet MTU: 46/1500 */
#define QCAFRM_ETHMINMTU (ETH_ZLEN - ETH_HLEN)
#define QCAFRM_ETHMAXMTU ETH_DATA_LEN
#define QCAFRM_MIN_MTU (ETH_ZLEN - ETH_HLEN)
#define QCAFRM_MAX_MTU ETH_DATA_LEN
/* Min/Max frame lengths */
#define QCAFRM_ETHMINLEN (QCAFRM_ETHMINMTU + ETH_HLEN)
#define QCAFRM_ETHMAXLEN (QCAFRM_ETHMAXMTU + VLAN_ETH_HLEN)
#define QCAFRM_MIN_LEN (QCAFRM_MIN_MTU + ETH_HLEN)
#define QCAFRM_MAX_LEN (QCAFRM_MAX_MTU + VLAN_ETH_HLEN)
/* QCA7K header len */
#define QCAFRM_HEADER_LEN 8
......@@ -61,6 +61,7 @@
#define QCAFRM_ERR_BASE -1000
enum qcafrm_state {
/* HW length is only available on SPI */
QCAFRM_HW_LEN0 = 0x8000,
QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1,
QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1,
......@@ -101,9 +102,11 @@ enum qcafrm_state {
struct qcafrm_handle {
/* Current decoding state */
enum qcafrm_state state;
/* Initial state depends on connection type */
enum qcafrm_state init;
/* Offset in buffer (borrowed for length too) */
s16 offset;
u16 offset;
/* Frame length as kept by this module */
u16 len;
......@@ -113,9 +116,16 @@ u16 qcafrm_create_header(u8 *buf, u16 len);
u16 qcafrm_create_footer(u8 *buf);
static inline void qcafrm_fsm_init(struct qcafrm_handle *handle)
static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle)
{
handle->state = QCAFRM_HW_LEN0;
handle->init = QCAFRM_HW_LEN0;
handle->state = handle->init;
}
static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle)
{
handle->init = QCAFRM_WAIT_AA1;
handle->state = handle->init;
}
/* Gather received bytes and try to extract a full Ethernet frame
......
......@@ -275,6 +275,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
static int
qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
const struct net_device_ops *ops = dev->netdev_ops;
struct qcaspi *qca = netdev_priv(dev);
if ((ring->rx_pending) ||
......@@ -283,13 +284,13 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
return -EINVAL;
if (netif_running(dev))
qcaspi_netdev_close(dev);
ops->ndo_stop(dev);
qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN);
qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN);
if (netif_running(dev))
qcaspi_netdev_open(dev);
ops->ndo_open(dev);
return 0;
}
......
......@@ -43,8 +43,8 @@
#include <linux/types.h>
#include "qca_7k.h"
#include "qca_7k_common.h"
#include "qca_debug.h"
#include "qca_framing.h"
#include "qca_spi.h"
#define MAX_DMA_BURST_LEN 5000
......@@ -69,7 +69,6 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN;
module_param(qcaspi_pluggable, int, 0);
MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no).");
#define QCASPI_MTU QCAFRM_ETHMAXMTU
#define QCASPI_TX_TIMEOUT (1 * HZ)
#define QCASPI_QCA7K_REBOOT_TIME_MS 1000
......@@ -192,6 +191,30 @@ qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len)
return len;
}
static int
qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd)
{
__be16 tx_data;
struct spi_message *msg = &qca->spi_msg1;
struct spi_transfer *transfer = &qca->spi_xfer1;
int ret;
tx_data = cpu_to_be16(cmd);
transfer->len = sizeof(tx_data);
transfer->tx_buf = &tx_data;
transfer->rx_buf = NULL;
ret = spi_sync(qca->spi_dev, msg);
if (!ret)
ret = msg->status;
if (ret)
qcaspi_spi_error(qca);
return ret;
}
static int
qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb)
{
......@@ -403,7 +426,7 @@ qcaspi_tx_ring_has_space(struct tx_ring *txr)
if (txr->skb[txr->tail])
return 0;
return (txr->size + QCAFRM_ETHMAXLEN < QCASPI_HW_BUF_LEN) ? 1 : 0;
return (txr->size + QCAFRM_MAX_LEN < QCASPI_HW_BUF_LEN) ? 1 : 0;
}
/* Flush the tx ring. This function is only safe to
......@@ -603,7 +626,7 @@ qcaspi_intr_handler(int irq, void *data)
return IRQ_HANDLED;
}
int
static int
qcaspi_netdev_open(struct net_device *dev)
{
struct qcaspi *qca = netdev_priv(dev);
......@@ -615,7 +638,7 @@ qcaspi_netdev_open(struct net_device *dev)
qca->intr_req = 1;
qca->intr_svc = 0;
qca->sync = QCASPI_SYNC_UNKNOWN;
qcafrm_fsm_init(&qca->frm_handle);
qcafrm_fsm_init_spi(&qca->frm_handle);
qca->spi_thread = kthread_run((void *)qcaspi_spi_thread,
qca, "%s", dev->name);
......@@ -640,7 +663,7 @@ qcaspi_netdev_open(struct net_device *dev)
return 0;
}
int
static int
qcaspi_netdev_close(struct net_device *dev)
{
struct qcaspi *qca = netdev_priv(dev);
......@@ -667,8 +690,8 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *tskb;
u8 pad_len = 0;
if (skb->len < QCAFRM_ETHMINLEN)
pad_len = QCAFRM_ETHMINLEN - skb->len;
if (skb->len < QCAFRM_MIN_LEN)
pad_len = QCAFRM_MIN_LEN - skb->len;
if (qca->txr.skb[qca->txr.tail]) {
netdev_warn(qca->net_dev, "queue was unexpectedly full!\n");
......@@ -746,7 +769,7 @@ qcaspi_netdev_init(struct net_device *dev)
{
struct qcaspi *qca = netdev_priv(dev);
dev->mtu = QCASPI_MTU;
dev->mtu = QCAFRM_MAX_MTU;
dev->type = ARPHRD_ETHER;
qca->clkspeed = qcaspi_clkspeed;
qca->burst_len = qcaspi_burst_len;
......@@ -805,8 +828,8 @@ qcaspi_netdev_setup(struct net_device *dev)
dev->tx_queue_len = 100;
/* MTU range: 46 - 1500 */
dev->min_mtu = QCAFRM_ETHMINMTU;
dev->max_mtu = QCAFRM_ETHMAXMTU;
dev->min_mtu = QCAFRM_MIN_MTU;
dev->max_mtu = QCAFRM_MAX_MTU;
qca = netdev_priv(dev);
memset(qca, 0, sizeof(struct qcaspi));
......@@ -894,6 +917,7 @@ qca_spi_probe(struct spi_device *spi)
return -ENOMEM;
qcaspi_netdev_setup(qcaspi_devs);
SET_NETDEV_DEV(qcaspi_devs, &spi->dev);
qca = netdev_priv(qcaspi_devs);
if (!qca) {
......@@ -975,7 +999,7 @@ static struct spi_driver qca_spi_driver = {
};
module_spi_driver(qca_spi_driver);
MODULE_DESCRIPTION("Qualcomm Atheros SPI Driver");
MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver");
MODULE_AUTHOR("Qualcomm Atheros Communications");
MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
MODULE_LICENSE("Dual BSD/GPL");
......
......@@ -32,7 +32,7 @@
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "qca_framing.h"
#include "qca_7k_common.h"
#define QCASPI_DRV_VERSION "0.2.7-i"
#define QCASPI_DRV_NAME "qcaspi"
......@@ -108,7 +108,4 @@ struct qcaspi {
u16 burst_len;
};
int qcaspi_netdev_open(struct net_device *dev);
int qcaspi_netdev_close(struct net_device *dev);
#endif /* _QCA_SPI_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment