* Re: [PATCHv2] braille-console: Fix value returned by _braille_console_setup
From: Sergey Senozhatsky @ 2017-03-27 15:43 UTC (permalink / raw)
To: Samuel Thibault, Petr Mladek
Cc: Steven Rostedt, Ming Lei, Aleksey Makarov, linux-serial,
Joe Perches, linux-kernel, Sergey Senozhatsky
In-Reply-To: <20170326204736.65jjbfrfvammgxqy@var.youpi.perso.aquilenet.fr>
On (03/26/17 22:47), Samuel Thibault wrote:
> commit bbeddf52adc1 ("printk: move braille console support into
> separate braille.[ch] files") introduced _braille_console_setup()
> to outline the braille initialization code. There was however some
> confusion over the value it was supposed to return. commit 2cfe6c4ac7ee
> ("printk: Fix return of braille_register_console()") tried to fix it
> but failed to.
>
> This fixes and documents the returned value according to the use
> in printk.c: non-zero return means a parsing error, and thus this
> console configuration should be ignored.
I just found this patch in my gmail "spam" folder.
sorry.
the patch looks OK to me.
btw, is there any reason why _braille_console_setup() and
_braille_register_console()/_braille_unregister_console()
names start with a dash? do we also want to "clean this up"?
well since we are at it.
-ss
^ permalink raw reply
* Re: [PATCH v8 3/3] printk: fix double printing with earlycon
From: Petr Mladek @ 2017-03-27 14:14 UTC (permalink / raw)
To: Aleksey Makarov
Cc: linux-serial, linux-kernel, Sudeep Holla, Greg Kroah-Hartman,
Peter Hurley, Jiri Slaby, Robin Murphy, Steven Rostedt,
Nair, Jayachandran, Sergey Senozhatsky
In-Reply-To: <20170320100302.8656-1-aleksey.makarov@linaro.org>
On Mon 2017-03-20 13:03:00, Aleksey Makarov wrote:
> If a console was specified by ACPI SPCR table _and_ command line
> parameters like "console=ttyAMA0" _and_ "earlycon" were specified,
> then log messages appear twice.
>
> The root cause is that the code traverses the list of specified
> consoles (the `console_cmdline` array) and stops at the first match.
> But it may happen that the same console is referred by the elements
> of this array twice:
>
> pl011,mmio,0x87e024000000,115200 -- from SPCR
> ttyAMA0 -- from command line
>
> but in this case `preferred_console` points to the second entry and
> the flag CON_CONSDEV is not set, so bootconsole is not deregistered.
>
> To fix that, introduce an invariant "The last non-braille console
> is always the preferred one" on the entries of the console_cmdline
> array. Then traverse it in reverse order to be sure that if
> the console is preferred then it will be the first matching entry.
Sigh, I am afraid that we need to go this way. I hate the side
effects of the match() functions. It would be great to get
rid of them. But it is non-trivial and out of scope for this fix.
> Reported-by: Sudeep Holla <sudeep.holla@arm.com>
> Signed-off-by: Aleksey Makarov <aleksey.makarov@linaro.org>
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index fd752f0c8ef1..462036e7a767 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -1909,8 +1909,28 @@ static int __add_preferred_console(char *name, int idx, char *options,
> i < MAX_CMDLINECONSOLES && c->name[0];
> i++, c++) {
> if (strcmp(c->name, name) == 0 && c->index == idx) {
> - if (!brl_options)
> - preferred_console = i;
> + int last;
> +
> + if (brl_options)
> + return 0;
> +
> + /*
> + * Maintain an invariant that will help to find if
> + * the matching console is preferred, see
> + * register_console():
> + *
> + * The last non-braille console is always
> + * the preferred one.
> + */
> + for (last = MAX_CMDLINECONSOLES - 1;
> + last >= 0 && !console_cmdline[last].name[0];
> + last--)
> + ;
This is a rather non-trivial code to find the last element.
I might make sense to count it in a global variable.
Then we might remove the check for console_cmdline[i].name[0]
also in the other for cycles and make them better readable.
> +
> + if (i != last)
> + swap(console_cmdline[i], console_cmdline[last]);
I was not aware of the swap() function. It is great to know ;-)
Otherwise, I am find with this approach.
Best Regards,
Petr
^ permalink raw reply
* [PATCH RFC v4 10/10] tty: serdev: add functions to retrieve common UART settings
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
Currently serdev core doesn't provide functions to retrieve common
UART settings like data bits, stop bits or parity. This patch adds
the interface to the core and the necessary implementation for
serdev-ttyport.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/tty/serdev/core.c | 33 ++++++++++++++++++++++++++
drivers/tty/serdev/serdev-ttyport.c | 47 +++++++++++++++++++++++++++++++++++++
include/linux/serdev.h | 22 +++++++++++++++++
3 files changed, 102 insertions(+)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index 531aa89..7b1e5bf 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -173,6 +173,39 @@ void serdev_device_set_flow_control(struct serdev_device *serdev, bool enable)
}
EXPORT_SYMBOL_GPL(serdev_device_set_flow_control);
+int serdev_device_get_data_bits(struct serdev_device *serdev)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->get_data_bits)
+ return -EINVAL;
+
+ return ctrl->ops->get_data_bits(ctrl);
+}
+EXPORT_SYMBOL_GPL(serdev_device_get_data_bits);
+
+int serdev_device_get_parity(struct serdev_device *serdev)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->get_parity)
+ return -EINVAL;
+
+ return ctrl->ops->get_parity(ctrl);
+}
+EXPORT_SYMBOL_GPL(serdev_device_get_parity);
+
+int serdev_device_get_stop_bits(struct serdev_device *serdev)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->get_stop_bits)
+ return -EINVAL;
+
+ return ctrl->ops->get_stop_bits(ctrl);
+}
+EXPORT_SYMBOL_GPL(serdev_device_get_stop_bits);
+
static int serdev_drv_probe(struct device *dev)
{
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index 8a30abe..5698682 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -167,6 +167,50 @@ static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable
tty_set_termios(tty, &ktermios);
}
+static int ttyport_get_data_bits(struct serdev_controller *ctrl)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+ struct ktermios ktermios = tty->termios;
+
+ switch (ktermios.c_cflag & CSIZE) {
+ case CS5:
+ return 5;
+ case CS6:
+ return 6;
+ case CS7:
+ return 7;
+ case CS8:
+ return 8;
+ }
+
+ return 0;
+}
+
+static int ttyport_get_parity(struct serdev_controller *ctrl)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+ struct ktermios ktermios = tty->termios;
+
+ if (!(ktermios.c_cflag & PARENB))
+ return SERDEV_PARITY_NONE;
+
+ if (ktermios.c_cflag & PARODD)
+ return SERDEV_PARITY_ODD;
+
+ return SERDEV_PARITY_EVEN;
+}
+
+static int ttyport_get_stop_bits(struct serdev_controller *ctrl)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+ struct ktermios ktermios = tty->termios;
+
+ return (ktermios.c_cflag & CSTOPB) ? 2 : 1;
+}
+
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
@@ -175,6 +219,9 @@ static const struct serdev_controller_ops ctrl_ops = {
.close = ttyport_close,
.set_flow_control = ttyport_set_flow_control,
.set_baudrate = ttyport_set_baudrate,
+ .get_data_bits = ttyport_get_data_bits,
+ .get_parity = ttyport_get_parity,
+ .get_stop_bits = ttyport_get_stop_bits,
};
struct device *serdev_tty_port_register(struct tty_port *port,
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 5176cdc..6180aa2 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -16,6 +16,10 @@
#include <linux/types.h>
#include <linux/device.h>
+#define SERDEV_PARITY_NONE 0
+#define SERDEV_PARITY_ODD 1
+#define SERDEV_PARITY_EVEN 2
+
struct serdev_controller;
struct serdev_device;
@@ -81,6 +85,9 @@ struct serdev_controller_ops {
void (*close)(struct serdev_controller *);
void (*set_flow_control)(struct serdev_controller *, bool);
unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int);
+ int (*get_data_bits)(struct serdev_controller *);
+ int (*get_parity)(struct serdev_controller *);
+ int (*get_stop_bits)(struct serdev_controller *);
};
/**
@@ -189,6 +196,9 @@ void serdev_device_set_flow_control(struct serdev_device *, bool);
int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
void serdev_device_write_flush(struct serdev_device *);
int serdev_device_write_room(struct serdev_device *);
+int serdev_device_get_data_bits(struct serdev_device *);
+int serdev_device_get_parity(struct serdev_device *);
+int serdev_device_get_stop_bits(struct serdev_device *);
/*
* serdev device driver functions
@@ -232,6 +242,18 @@ static inline int serdev_device_write_room(struct serdev_device *sdev)
{
return 0;
}
+static inline int serdev_device_get_data_bits(struct serdev_device *sdev)
+{
+ return -ENODEV;
+}
+static inline int serdev_device_get_parity(struct serdev_device *sdev)
+{
+ return -ENODEV;
+}
+static inline int serdev_device_get_stop_bits(struct serdev_device *sdev)
+{
+ return -ENODEV;
+}
#define serdev_device_driver_register(x)
#define serdev_device_driver_unregister(x)
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 09/10] tty: serdev-ttyport: return actual baudrate from ttyport_set_baudrate
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
Instead of returning the requested baudrate, we better return the
actual one because it isn't always the same.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/tty/serdev/serdev-ttyport.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index d053935..8a30abe 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -150,7 +150,7 @@ static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigne
/* tty_set_termios() return not checked as it is always 0 */
tty_set_termios(tty, &ktermios);
- return speed;
+ return ktermios.c_ospeed;
}
static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 08/10] net: qualcomm: add QCA7000 UART driver
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
This patch adds the Ethernet over UART driver for the
Qualcomm QCA7000 HomePlug GreenPHY.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/net/ethernet/qualcomm/Kconfig | 10 +
drivers/net/ethernet/qualcomm/Makefile | 2 +
drivers/net/ethernet/qualcomm/qca_common.h | 6 +
drivers/net/ethernet/qualcomm/qca_uart.c | 419 +++++++++++++++++++++++++++++
4 files changed, 437 insertions(+)
create mode 100644 drivers/net/ethernet/qualcomm/qca_uart.c
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index b4c369d..ad6b5a4 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -30,6 +30,16 @@ config QCA7000_SPI
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.
+
+ 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
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index 00d8729..8847db7 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -5,5 +5,7 @@
obj-$(CONFIG_QCA7000) += qca_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/
diff --git a/drivers/net/ethernet/qualcomm/qca_common.h b/drivers/net/ethernet/qualcomm/qca_common.h
index 431f99d..539399e 100644
--- a/drivers/net/ethernet/qualcomm/qca_common.h
+++ b/drivers/net/ethernet/qualcomm/qca_common.h
@@ -122,6 +122,12 @@ static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle)
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
* by following a simple state machine.
*
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
new file mode 100644
index 0000000..81a0353
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc.
+ * Copyright (c) 2017, I2SE GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* This module implements the Qualcomm Atheros UART protocol for
+ * kernel-based UART device; it is essentially an Ethernet-to-UART
+ * serial converter;
+ */
+
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/sched.h>
+#include <linux/serdev.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+
+#include "qca_common.h"
+
+#define QCAUART_DRV_VERSION "0.1.0"
+#define QCAUART_DRV_NAME "qcauart"
+#define QCAUART_TX_TIMEOUT (1 * HZ)
+
+struct qcauart {
+ struct net_device *net_dev;
+ spinlock_t lock; /* transmit lock */
+ struct work_struct tx_work; /* Flushes transmit buffer */
+
+ struct serdev_device *serdev;
+
+ unsigned char xbuff[QCAFRM_ETHMAXMTU]; /* transmitter buffer */
+ unsigned char *xhead; /* pointer to next XMIT byte */
+ int xleft; /* bytes left in XMIT queue */
+
+ struct qcafrm_handle frm_handle;
+
+ struct sk_buff *rx_skb;
+};
+
+static int
+qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
+ size_t count)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+ struct net_device_stats *n_stats = &qca->net_dev->stats;
+ size_t i;
+
+ if (!qca->rx_skb) {
+ qca->rx_skb = netdev_alloc_skb(qca->net_dev, qca->net_dev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ s32 retcode;
+
+ retcode = qcafrm_fsm_decode(&qca->frm_handle,
+ qca->rx_skb->data,
+ skb_tailroom(qca->rx_skb),
+ data[i]);
+
+ switch (retcode) {
+ case QCAFRM_GATHER:
+ case QCAFRM_NOHEAD:
+ break;
+ case QCAFRM_NOTAIL:
+ netdev_dbg(qca->net_dev, "recv: no RX tail\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ case QCAFRM_INVLEN:
+ netdev_dbg(qca->net_dev, "recv: invalid RX length\n");
+ n_stats->rx_errors++;
+ n_stats->rx_dropped++;
+ break;
+ default:
+ qca->rx_skb->dev = qca->net_dev;
+ n_stats->rx_packets++;
+ n_stats->rx_bytes += retcode;
+ skb_put(qca->rx_skb, retcode);
+ qca->rx_skb->protocol = eth_type_trans(
+ qca->rx_skb, qca->rx_skb->dev);
+ qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_rx_ni(qca->rx_skb);
+ qca->rx_skb = netdev_alloc_skb(qca->net_dev,
+ qca->net_dev->mtu +
+ VLAN_ETH_HLEN);
+ if (!qca->rx_skb) {
+ netdev_dbg(qca->net_dev, "recv: out of RX resources\n");
+ n_stats->rx_errors++;
+ break;
+ }
+ }
+ }
+
+ return i;
+}
+
+/* Write out any remaining transmit buffer. Scheduled when tty is writable */
+static void qcauart_transmit(struct work_struct *work)
+{
+ struct qcauart *qca = container_of(work, struct qcauart, tx_work);
+ struct net_device_stats *n_stats = &qca->net_dev->stats;
+ int written;
+
+ spin_lock_bh(&qca->lock);
+
+ /* First make sure we're connected. */
+ if (!netif_running(qca->net_dev)) {
+ spin_unlock_bh(&qca->lock);
+ return;
+ }
+
+ if (qca->xleft <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet
+ */
+ n_stats->tx_packets++;
+ spin_unlock_bh(&qca->lock);
+ netif_wake_queue(qca->net_dev);
+ return;
+ }
+
+ written = serdev_device_write_buf(qca->serdev, qca->xhead, qca->xleft);
+ if (written > 0) {
+ qca->xleft -= written;
+ qca->xhead += written;
+ }
+ spin_unlock_bh(&qca->lock);
+}
+
+/* Called by the driver when there's room for more data.
+ * Schedule the transmit.
+ */
+static void qca_tty_wakeup(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ schedule_work(&qca->tx_work);
+}
+
+static struct serdev_device_ops qca_serdev_ops = {
+ .receive_buf = qca_tty_receive,
+ .write_wakeup = qca_tty_wakeup,
+};
+
+int
+qcauart_netdev_open(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ qcafrm_fsm_init_uart(&qca->frm_handle);
+ netif_start_queue(qca->net_dev);
+
+ return 0;
+}
+
+int
+qcauart_netdev_close(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ spin_lock_bh(&qca->lock);
+ netif_stop_queue(dev);
+ qca->xleft = 0;
+ spin_unlock_bh(&qca->lock);
+
+ return 0;
+}
+
+netdev_tx_t
+qcauart_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *n_stats = &dev->stats;
+ struct qcauart *qca = netdev_priv(dev);
+ u8 pad_len = 0;
+ int written;
+ u8 *pos;
+
+ spin_lock(&qca->lock);
+
+ if (!netif_running(dev)) {
+ spin_unlock(&qca->lock);
+ netdev_warn(qca->net_dev, "xmit: iface is down\n");
+ goto out;
+ }
+
+ pos = qca->xbuff;
+
+ if (skb->len < QCAFRM_ETHMINLEN)
+ pad_len = QCAFRM_ETHMINLEN - skb->len;
+
+ pos += qcafrm_create_header(pos, skb->len + pad_len);
+
+ memcpy(pos, skb->data, skb->len);
+ pos += skb->len;
+
+ if (pad_len) {
+ memset(pos, 0, pad_len);
+ pos += pad_len;
+ }
+
+ pos += qcafrm_create_footer(pos);
+
+ netif_stop_queue(qca->net_dev);
+
+ written = serdev_device_write_buf(qca->serdev, qca->xbuff,
+ pos - qca->xbuff);
+ if (written > 0) {
+ qca->xleft = (pos - qca->xbuff) - written;
+ qca->xhead = qca->xbuff + written;
+ n_stats->tx_bytes += written;
+ }
+ spin_unlock(&qca->lock);
+
+ netif_trans_update(dev);
+out:
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+void
+qcauart_netdev_tx_timeout(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n",
+ jiffies, dev_trans_start(dev));
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+}
+
+static int
+qcauart_netdev_init(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ /* Finish setting up the device info. */
+ dev->mtu = QCAFRM_ETHMAXMTU;
+ dev->type = ARPHRD_ETHER;
+
+ qca->rx_skb = netdev_alloc_skb(qca->net_dev,
+ qca->net_dev->mtu + VLAN_ETH_HLEN);
+ if (!qca->rx_skb)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void
+qcauart_netdev_uninit(struct net_device *dev)
+{
+ struct qcauart *qca = netdev_priv(dev);
+
+ if (qca->rx_skb)
+ dev_kfree_skb(qca->rx_skb);
+}
+
+static const struct net_device_ops qcauart_netdev_ops = {
+ .ndo_init = qcauart_netdev_init,
+ .ndo_uninit = qcauart_netdev_uninit,
+ .ndo_open = qcauart_netdev_open,
+ .ndo_stop = qcauart_netdev_close,
+ .ndo_start_xmit = qcauart_netdev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_tx_timeout = qcauart_netdev_tx_timeout,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static void
+qcauart_netdev_setup(struct net_device *dev)
+{
+ struct qcauart *qca;
+
+ dev->netdev_ops = &qcauart_netdev_ops;
+ dev->watchdog_timeo = QCAUART_TX_TIMEOUT;
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ dev->tx_queue_len = 100;
+
+ /* MTU range: 46 - 1500 */
+ dev->min_mtu = QCAFRM_ETHMINMTU;
+ dev->max_mtu = QCAFRM_ETHMAXMTU;
+
+ qca = netdev_priv(dev);
+ memset(qca, 0, sizeof(struct qcauart));
+}
+
+static const struct of_device_id qca_uart_of_match[] = {
+ {
+ .compatible = "qca,qca7000-uart",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qca_uart_of_match);
+
+static int qca_uart_probe(struct serdev_device *serdev)
+{
+ struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart));
+ struct qcauart *qca;
+ const char *mac;
+ u32 speed = 115200;
+ int ret;
+
+ if (!qcauart_dev)
+ return -ENOMEM;
+
+ qcauart_netdev_setup(qcauart_dev);
+
+ qca = netdev_priv(qcauart_dev);
+ if (!qca) {
+ pr_err("qca_uart: Fail to retrieve private structure\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+ qca->net_dev = qcauart_dev;
+ qca->serdev = serdev;
+
+ spin_lock_init(&qca->lock);
+ INIT_WORK(&qca->tx_work, qcauart_transmit);
+
+ of_property_read_u32(serdev->dev.of_node, "current-speed", &speed);
+
+ mac = of_get_mac_address(serdev->dev.of_node);
+
+ if (mac)
+ ether_addr_copy(qca->net_dev->dev_addr, mac);
+
+ if (!is_valid_ether_addr(qca->net_dev->dev_addr)) {
+ eth_hw_addr_random(qca->net_dev);
+ dev_info(&serdev->dev, "Using random MAC address: %pM\n",
+ qca->net_dev->dev_addr);
+ }
+
+ netif_carrier_on(qca->net_dev);
+ serdev_device_set_drvdata(serdev, qca);
+ serdev_device_set_client_ops(serdev, &qca_serdev_ops);
+
+ ret = serdev_device_open(serdev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to open device %s\n",
+ qcauart_dev->name);
+ goto free;
+ }
+
+ speed = serdev_device_set_baudrate(serdev, speed);
+ dev_info(&serdev->dev, "Using baudrate: %u\n", speed);
+
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = register_netdev(qcauart_dev);
+ if (ret) {
+ dev_err(&serdev->dev, "Unable to register net device %s\n",
+ qcauart_dev->name);
+ goto free;
+ }
+
+ return 0;
+
+free:
+ free_netdev(qcauart_dev);
+ return ret;
+}
+
+static void qca_uart_remove(struct serdev_device *serdev)
+{
+ struct qcauart *qca = serdev_device_get_drvdata(serdev);
+
+ /* Flush any pending characters in the driver. */
+ serdev_device_close(serdev);
+
+ netif_carrier_off(qca->net_dev);
+ unregister_netdev(qca->net_dev);
+ free_netdev(qca->net_dev);
+}
+
+static struct serdev_device_driver qca_uart_driver = {
+ .probe = qca_uart_probe,
+ .remove = qca_uart_remove,
+ .driver = {
+ .name = QCAUART_DRV_NAME,
+ .of_match_table = of_match_ptr(qca_uart_of_match),
+ },
+};
+
+module_serdev_device_driver(qca_uart_driver);
+
+MODULE_DESCRIPTION("Qualcomm Atheros UART Driver");
+MODULE_AUTHOR("Qualcomm Atheros Communications");
+MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(QCAUART_DRV_VERSION);
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 07/10] dt-bindings: net: add binding for QCA7000 UART
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
This is the serdev binding for the QCA7000 UART driver (Ethernet over UART).
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
According to this binding are still some questions:
Where should be the optional hardware flow control defined (at master or slave side)?
Is it okay to have two bindings (qca-qca7000-spi and qca-qca7000-uart) or should they be merged?
.../devicetree/bindings/net/qca-qca7000-uart.txt | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/qca-qca7000-uart.txt
diff --git a/Documentation/devicetree/bindings/net/qca-qca7000-uart.txt b/Documentation/devicetree/bindings/net/qca-qca7000-uart.txt
new file mode 100644
index 0000000..f2e0450
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/qca-qca7000-uart.txt
@@ -0,0 +1,31 @@
+* Qualcomm QCA7000 (Ethernet over UART protocol)
+
+Note: This binding applies in case the QCA7000 is configured as a
+UART slave device. It is possible to preconfigure the UART settings
+of the QCA7000 firmware, which can't be changed during runtime.
+
+Required properties:
+- compatible : Should be "qca,qca7000-uart"
+
+Optional properties:
+- local-mac-address : 6 bytes, Specifies MAC address
+- current-speed : Specifies the serial device speed in
+ bits per second (default = 115200), which is
+ predefined by the QCA7000 firmware configuration
+
+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-uart";
+ local-mac-address = [ A0 B0 C0 D0 E0 F0 ];
+ current-speed = <38400>;
+ };
+};
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 06/10] net: qualcomm: make qca_common a separate kernel module
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren-eS4NqCHxEME@public.gmane.org>
In order to share common functions between QCA7000 SPI and UART protocol
driver the qca_common needs to be a separate kernel module.
Signed-off-by: Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>
---
drivers/net/ethernet/qualcomm/Kconfig | 8 +++++++-
drivers/net/ethernet/qualcomm/Makefile | 5 +++--
drivers/net/ethernet/qualcomm/qca_common.c | 10 ++++++++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index d7720bf..b4c369d 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -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.
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index 8080570..00d8729 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -2,7 +2,8 @@
# Makefile for the Qualcomm network device drivers.
#
-obj-$(CONFIG_QCA7000) += qcaspi.o
-qcaspi-objs := qca_spi.o qca_common.o qca_7k.o qca_debug.o
+obj-$(CONFIG_QCA7000) += qca_common.o
+obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
+qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_common.c b/drivers/net/ethernet/qualcomm/qca_common.c
index d930524..f2c9e76 100644
--- a/drivers/net/ethernet/qualcomm/qca_common.c
+++ b/drivers/net/ethernet/qualcomm/qca_common.c
@@ -21,7 +21,9 @@
* by an atheros frame while transmitted over a serial channel;
*/
+#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include "qca_common.h"
@@ -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.
@@ -154,3 +158,9 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
return ret;
}
+EXPORT_SYMBOL_GPL(qcafrm_fsm_decode);
+
+MODULE_DESCRIPTION("Qualcomm Atheros Common");
+MODULE_AUTHOR("Qualcomm Atheros Communications");
+MODULE_AUTHOR("Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>");
+MODULE_LICENSE("Dual BSD/GPL");
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v4 05/10] net: qualcomm: prepare frame decoding for UART driver
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren-eS4NqCHxEME@public.gmane.org>
Unfortunately the frame format is not exactly identical between SPI
and UART. In case of SPI there is an additional HW length at the
beginning. So store the initial state to make the decoding state machine
more flexible and easy to extend for UART support.
Signed-off-by: Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>
---
drivers/net/ethernet/qualcomm/qca_common.c | 12 ++++++------
drivers/net/ethernet/qualcomm/qca_common.h | 8 ++++++--
drivers/net/ethernet/qualcomm/qca_spi.c | 2 +-
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/qca_common.c b/drivers/net/ethernet/qualcomm/qca_common.c
index 26453a9..d930524 100644
--- a/drivers/net/ethernet/qualcomm/qca_common.c
+++ b/drivers/net/ethernet/qualcomm/qca_common.c
@@ -83,7 +83,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 +97,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--;
}
@@ -119,7 +119,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
len = handle->offset;
if (len > buf_len || len < QCAFRM_ETHMINLEN) {
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 +135,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,11 +143,11 @@ 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;
}
diff --git a/drivers/net/ethernet/qualcomm/qca_common.h b/drivers/net/ethernet/qualcomm/qca_common.h
index d5e795d..431f99d 100644
--- a/drivers/net/ethernet/qualcomm/qca_common.h
+++ b/drivers/net/ethernet/qualcomm/qca_common.h
@@ -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,6 +102,8 @@ 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;
@@ -113,9 +116,10 @@ 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;
}
/* Gather received bytes and try to extract a full Ethernet frame
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 65adc10..3617bde 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -638,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);
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v4 04/10] net: qualcomm: rename qca_framing.c to qca_common.c
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
As preparation for the upcoming UART driver we need a module
which contains common functions for both interfaces. The module
qca_framing is a good candidate but renaming to qca_common would
make it clear.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/net/ethernet/qualcomm/Makefile | 2 +-
drivers/net/ethernet/qualcomm/{qca_framing.c => qca_common.c} | 2 +-
drivers/net/ethernet/qualcomm/{qca_framing.h => qca_common.h} | 0
drivers/net/ethernet/qualcomm/qca_spi.c | 2 +-
drivers/net/ethernet/qualcomm/qca_spi.h | 2 +-
5 files changed, 4 insertions(+), 4 deletions(-)
rename drivers/net/ethernet/qualcomm/{qca_framing.c => qca_common.c} (99%)
rename drivers/net/ethernet/qualcomm/{qca_framing.h => qca_common.h} (100%)
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index aacb0a5..8080570 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -3,6 +3,6 @@
#
obj-$(CONFIG_QCA7000) += qcaspi.o
-qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o
+qcaspi-objs := qca_spi.o qca_common.o qca_7k.o qca_debug.o
obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_common.c
similarity index 99%
rename from drivers/net/ethernet/qualcomm/qca_framing.c
rename to drivers/net/ethernet/qualcomm/qca_common.c
index faa924c..26453a9 100644
--- a/drivers/net/ethernet/qualcomm/qca_framing.c
+++ b/drivers/net/ethernet/qualcomm/qca_common.c
@@ -23,7 +23,7 @@
#include <linux/kernel.h>
-#include "qca_framing.h"
+#include "qca_common.h"
u16
qcafrm_create_header(u8 *buf, u16 length)
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_common.h
similarity index 100%
rename from drivers/net/ethernet/qualcomm/qca_framing.h
rename to drivers/net/ethernet/qualcomm/qca_common.h
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 4f431bc..65adc10 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -43,8 +43,8 @@
#include <linux/types.h>
#include "qca_7k.h"
+#include "qca_common.h"
#include "qca_debug.h"
-#include "qca_framing.h"
#include "qca_spi.h"
#define MAX_DMA_BURST_LEN 5000
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index 064853d..cce4802 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -32,7 +32,7 @@
#include <linux/spi/spi.h>
#include <linux/types.h>
-#include "qca_framing.h"
+#include "qca_common.h"
#define QCASPI_DRV_VERSION "0.2.7-i"
#define QCASPI_DRV_NAME "qcaspi"
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 03/10] net: qualcomm: move qcaspi_tx_cmd to qca_spi.c
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
The function qcaspi_tx_cmd() is only called from qca_spi.c. So we better
move it there.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/net/ethernet/qualcomm/qca_7k.c | 24 ------------------------
drivers/net/ethernet/qualcomm/qca_7k.h | 1 -
drivers/net/ethernet/qualcomm/qca_spi.c | 24 ++++++++++++++++++++++++
3 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c
index 557d53c..aa90a1d 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k.c
@@ -119,27 +119,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;
-}
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h
index 1cad851..b390b1f 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k.h
@@ -67,6 +67,5 @@
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 */
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 513e6c7..4f431bc 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -193,6 +193,30 @@ qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 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)
{
u32 count;
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 02/10] net: qca_debug: use net_device_ops instead of direct call
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren@i2se.com>
There is no need to export qcaspi_netdev_open and qcaspi_netdev_close
because they are also accessible via the net_device_ops.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/net/ethernet/qualcomm/qca_debug.c | 5 +++--
drivers/net/ethernet/qualcomm/qca_spi.h | 3 ---
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index d145df9..92b6be9 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -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;
}
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index 6e31a0e..064853d 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -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 */
--
2.1.4
^ permalink raw reply related
* [PATCH RFC v4 01/10] net: qualcomm: remove unnecessary includes
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stefan Wahren
In-Reply-To: <1490621848-24828-1-git-send-email-stefan.wahren-eS4NqCHxEME@public.gmane.org>
Most of the includes in qca_7k.c are unnecessary so we better remove them.
Signed-off-by: Stefan Wahren <stefan.wahren-eS4NqCHxEME@public.gmane.org>
---
drivers/net/ethernet/qualcomm/qca_7k.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c
index f0066fb..557d53c 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k.c
@@ -23,11 +23,7 @@
* kernel-based SPI device.
*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/spi/spi.h>
-#include <linux/version.h>
#include "qca_7k.h"
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH RFC v4 00/10] net: qualcomm: add QCA7000 UART driver
From: Stefan Wahren @ 2017-03-27 13:37 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, David S. Miller
Cc: Greg Kroah-Hartman, Jiri Slaby, Marcel Holtmann,
Sebastian Reichel, netdev, devicetree, linux-serial, linux-kernel,
Stefan Wahren
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. Patches 4 - 7 prepare the existing QCA7000
code for UART support. Patch 8 contains the new driver. The last
two patches are suggested improvements for serial device bus.
The code itself has been tested on a Freescale i.MX28 board and
a Raspberry Pi Zero.
Changes in v4:
* rebase to current linux-next
* use parameter -M for git format-patch
* change order of local variables where possible
* implement basic serdev support (without hardware flow control)
Changes in v3:
* rebase to current net-next
Changes in v2:
* fix build issue by using netif_trans_update() and dev_trans_start()
[1] - https://github.com/IoE/qca7000
Stefan Wahren (10):
net: qualcomm: remove unnecessary includes
net: qca_debug: use net_device_ops instead of direct call
net: qualcomm: move qcaspi_tx_cmd to qca_spi.c
net: qualcomm: rename qca_framing.c to qca_common.c
net: qualcomm: prepare frame decoding for UART driver
net: qualcomm: make qca_common a separate kernel module
dt-bindings: net: add binding for QCA7000 UART
net: qualcomm: add QCA7000 UART driver
tty: serdev-ttyport: return actual baudrate from ttyport_set_baudrate
tty: serdev: add functions to retrieve common UART settings
.../devicetree/bindings/net/qca-qca7000-uart.txt | 31 ++
drivers/net/ethernet/qualcomm/Kconfig | 18 +-
drivers/net/ethernet/qualcomm/Makefile | 7 +-
drivers/net/ethernet/qualcomm/qca_7k.c | 28 --
drivers/net/ethernet/qualcomm/qca_7k.h | 1 -
.../qualcomm/{qca_framing.c => qca_common.c} | 24 +-
.../qualcomm/{qca_framing.h => qca_common.h} | 14 +-
drivers/net/ethernet/qualcomm/qca_debug.c | 5 +-
drivers/net/ethernet/qualcomm/qca_spi.c | 28 +-
drivers/net/ethernet/qualcomm/qca_spi.h | 5 +-
drivers/net/ethernet/qualcomm/qca_uart.c | 419 +++++++++++++++++++++
drivers/tty/serdev/core.c | 33 ++
drivers/tty/serdev/serdev-ttyport.c | 49 ++-
include/linux/serdev.h | 22 ++
14 files changed, 634 insertions(+), 50 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/qca-qca7000-uart.txt
rename drivers/net/ethernet/qualcomm/{qca_framing.c => qca_common.c} (86%)
rename drivers/net/ethernet/qualcomm/{qca_framing.h => qca_common.h} (90%)
create mode 100644 drivers/net/ethernet/qualcomm/qca_uart.c
--
2.1.4
^ permalink raw reply
* [PATCHv2] braille-console: Fix value returned by _braille_console_setup
From: Samuel Thibault @ 2017-03-26 20:47 UTC (permalink / raw)
To: Petr Mladek, Sergey Senozhatsky, Steven Rostedt
Cc: Ming Lei, Aleksey Makarov, linux-serial, Joe Perches,
linux-kernel
commit bbeddf52adc1 ("printk: move braille console support into
separate braille.[ch] files") introduced _braille_console_setup()
to outline the braille initialization code. There was however some
confusion over the value it was supposed to return. commit 2cfe6c4ac7ee
("printk: Fix return of braille_register_console()") tried to fix it
but failed to.
This fixes and documents the returned value according to the use
in printk.c: non-zero return means a parsing error, and thus this
console configuration should be ignored.
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Cc: Aleksey Makarov <aleksey.makarov@linaro.org>
Cc: Joe Perches <joe@perches.com>
Cc: Ming Lei <ming.lei@canonical.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Acked-by: Petr Mladek <pmladek@suse.com>
---
new in v2:
- drop now-useless else
Index: linux-4.10/kernel/printk/braille.c
===================================================================
--- linux-4.10.orig/kernel/printk/braille.c
+++ linux-4.10/kernel/printk/braille.c
@@ -2,12 +2,13 @@
#include <linux/kernel.h>
#include <linux/console.h>
+#include <linux/errno.h>
#include <linux/string.h>
#include "console_cmdline.h"
#include "braille.h"
-char *_braille_console_setup(char **str, char **brl_options)
+int _braille_console_setup(char **str, char **brl_options)
{
if (!strncmp(*str, "brl,", 4)) {
*brl_options = "";
@@ -15,14 +16,14 @@ char *_braille_console_setup(char **str,
} else if (!strncmp(*str, "brl=", 4)) {
*brl_options = *str + 4;
*str = strchr(*brl_options, ',');
- if (!*str)
+ if (!*str) {
pr_err("need port name after brl=\n");
- else
- *((*str)++) = 0;
- } else
- return NULL;
+ return -EINVAL;
+ }
+ *((*str)++) = 0;
+ }
- return *str;
+ return 0;
}
int
Index: linux-4.10/kernel/printk/braille.h
===================================================================
--- linux-4.10.orig/kernel/printk/braille.h
+++ linux-4.10/kernel/printk/braille.h
@@ -9,7 +9,14 @@ braille_set_options(struct console_cmdli
c->brl_options = brl_options;
}
-char *
+/*
+ * Setup console according to braille options.
+ * Return -EINVAL on syntax error, 0 on success (or no braille option was
+ * actually given).
+ * Modifies str to point to the serial options
+ * Sets brl_options to the parsed braille options.
+ */
+int
_braille_console_setup(char **str, char **brl_options);
int
@@ -25,10 +32,10 @@ braille_set_options(struct console_cmdli
{
}
-static inline char *
+static inline int
_braille_console_setup(char **str, char **brl_options)
{
- return NULL;
+ return 0;
}
static inline int
^ permalink raw reply
* [GIT PULL] TTY/Serial driver fixes for 4.11-rc4
From: Greg KH @ 2017-03-26 11:04 UTC (permalink / raw)
To: Linus Torvalds, Jiri Slaby; +Cc: Andrew Morton, linux-kernel, linux-serial
The following changes since commit 4495c08e84729385774601b5146d51d9e5849f81:
Linux 4.11-rc2 (2017-03-12 14:47:08 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git/ tags/tty-4.11-rc4
for you to fetch changes up to a4a3e061149f09c075f108b6f1cf04d9739a6bc2:
tty: fix data race in tty_ldisc_ref_wait() (2017-03-17 14:07:10 +0900)
----------------------------------------------------------------
TTY/Serial driver fixes for 4.11-rc4
Here are some tty and serial driver fixes for 4.11-rc4. One of these
fix a long-standing issue in the ldisc code that was found by Dmitry
Vyukov with his great fuzzing work. The other fixes resolve other
reported issues, and there is one revert of a patch in 4.11-rc1 that
wasn't correct.
All of these have been in linux-next for a while with no reported
issues.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----------------------------------------------------------------
Aleksey Makarov (1):
Revert "tty: serial: pl011: add ttyAMA for matching pl011 console"
Dmitry Vyukov (2):
tty: don't panic on OOM in tty_set_ldisc()
tty: fix data race in tty_ldisc_ref_wait()
Heiko Stuebner (1):
serial: 8250_dw: Honor clk_round_rate errors in dw8250_set_termios
James Hogan (1):
serial: 8250_dw: Fix breakage when HAVE_CLK=n
Timur Tabi (1):
tty: acpi/spcr: QDF2400 E44 checks for wrong OEM revision
drivers/acpi/spcr.c | 2 +-
drivers/tty/serial/8250/8250_dw.c | 9 +++-
drivers/tty/serial/amba-pl011.c | 2 +-
drivers/tty/tty_ldisc.c | 92 +++++++++------------------------------
4 files changed, 30 insertions(+), 75 deletions(-)
^ permalink raw reply
* Re: [PATCH 0/2] Move uart_register_driver call to device probe for pl010 and sh-sci
From: Russell King - ARM Linux @ 2017-03-26 10:01 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Sjoerd Simons, linux-serial@vger.kernel.org, Linux-Renesas,
Greg Kroah-Hartman, linux-kernel@vger.kernel.org, Jiri Slaby
In-Reply-To: <CAMuHMdUkfzJw6W0jQZPChN+Uqb0Ewkn86o0Pzd+9+Wi1-XZRAw@mail.gmail.com>
On Sun, Mar 26, 2017 at 11:22:57AM +0200, Geert Uytterhoeven wrote:
> Time for the serial subsystem to switch to dynamic minors, and get rid of the
> what-is-your-serial-port-called-again-on-this-platform
> multi-million-euro question?
Dynamic device numbers are fine for those who use devtmpfs / udev, but I
would imagine that there are systems out there which don't, and if they
change, systems become inaccessible (the port becomes dead, even to
sysrq.)
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* Re: [PATCH 0/2] Move uart_register_driver call to device probe for pl010 and sh-sci
From: Geert Uytterhoeven @ 2017-03-26 9:22 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Sjoerd Simons, linux-serial@vger.kernel.org, Linux-Renesas,
Greg Kroah-Hartman, linux-kernel@vger.kernel.org, Jiri Slaby
In-Reply-To: <20170324164202.GI7909@n2100.armlinux.org.uk>
Hi Russell, Sjoerd,
On Fri, Mar 24, 2017 at 5:42 PM, Russell King - ARM Linux
<linux@armlinux.org.uk> wrote:
> On Fri, Mar 24, 2017 at 05:26:32PM +0100, Sjoerd Simons wrote:
>> When testing on a Renesas board with the PL010 serial driver enabled
>> serial output broke. Turns out the minor device numbers for both
>> drivers happen to overlap, causing whichever driver happened to be the
>> second one to register to fail.
>
> How the **** has the SH serial driver ended up with overlapping device
> numbers?
Interesting...
> What happened to our maintained list of allocated major/minor device
> numbers, which is supposed to stop crap like this happening?
AMBA PL010 has been assigned major 204, minors 16..31,
SCI has been assigned major 204, minors 8..11.
Over the years, Renesas SoCs have been gaining more and more serial
ports, leading to
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
with CONFIG_SERIAL_SH_SCI_NR_UARTS=20 in shmobile_defconfig and
multi_v7_defconfig (although the maximum value on any supported SoC is 18).
But once the value becomes 5 or more, it starts overflowing into the ttyFWx
and ttyAMx space.
How to solve this?
Time for the serial subsystem to switch to dynamic minors, and get rid of the
what-is-your-serial-port-called-again-on-this-platform
multi-million-euro question?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v2 1/2] tty: serial_core: Add name field to uart_port struct
From: Vignesh R @ 2017-03-25 10:33 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Jisheng Zhang, Greg Kroah-Hartman, linux-kernel@vger.kernel.org,
linux-serial@vger.kernel.org, Jiri Slaby, linux-arm Mailing List
In-Reply-To: <CAHp75VeRBq=VVgh7FaiuFF6GjTx98A2oEYyWaQVEPAmwPExMdg@mail.gmail.com>
On 3/24/2017 5:16 PM, Andy Shevchenko wrote:
> On Fri, Mar 24, 2017 at 7:27 AM, Vignesh R <vigneshr@ti.com> wrote:
>> Introduce a field to store name of uart_port that can be used to easily
>> identify UART port instances on a system that has more than one UART
>> instance. The name is of the form ttyXN(eg. ttyS0, ttyAMA0,..) where N
>> is number that particular UART instance.
>> This field will be useful when printing debug info for a particular port
>> or in register IRQs with unique IRQ name. Port name is populated during
>> uart_add_one_port().
>>
>
> Looks good to me:
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
>
> Just in case, have you checked if there any possible scenarios where
> memory will be leaked?
I ran kmemleak scan after opening and closing a serial port and did not
see any memleak report. Also uport->tty_groups is allocated and
deallocated in the same functions uport->name.
>
>> Signed-off-by: Vignesh R <vigneshr@ti.com>
>> ---
>>
>> v2:
>> use kasprintf() instead of snprintf()
>> Fix up commit message.
>>
>> drivers/tty/serial/serial_core.c | 7 +++++++
>> include/linux/serial_core.h | 1 +
>> 2 files changed, 8 insertions(+)
>>
>> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
>> index 0fb3f7cce62a..f5572e28d16a 100644
>> --- a/drivers/tty/serial/serial_core.c
>> +++ b/drivers/tty/serial/serial_core.c
>> @@ -2744,6 +2744,12 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
>> state->pm_state = UART_PM_STATE_UNDEFINED;
>> uport->cons = drv->cons;
>> uport->minor = drv->tty_driver->minor_start + uport->line;
>> + uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
>> + drv->tty_driver->name_base + uport->line);
>> + if (!uport->name) {
>> + ret = -ENOMEM;
>> + goto out;
>> + }
>>
>> /*
>> * If this port is a console, then the spinlock is already
>> @@ -2861,6 +2867,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
>> if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
>> uport->ops->release_port(uport);
>> kfree(uport->tty_groups);
>> + kfree(uport->name);
>>
>> /*
>> * Indicate that there isn't a port here anymore.
>> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
>> index 58484fb35cc8..60530678c633 100644
>> --- a/include/linux/serial_core.h
>> +++ b/include/linux/serial_core.h
>> @@ -247,6 +247,7 @@ struct uart_port {
>> unsigned char suspended;
>> unsigned char irq_wake;
>> unsigned char unused[2];
>> + char *name; /* port name */
>> struct attribute_group *attr_group; /* port specific attributes */
>> const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
>> struct serial_rs485 rs485;
>> --
>> 2.11.0
>>
>
>
>
^ permalink raw reply
* [PATCH] tty: serial: fsl_lpuart: lock port on console write
From: Stefan Agner @ 2017-03-24 18:33 UTC (permalink / raw)
To: gregkh; +Cc: jslaby, bhuvanchandra.dv, linux-serial, linux-kernel,
Stefan Agner
The console write code is not entirely race free (e.g. the operations
to disabling the UART interrupts are not atomic) hence locking is
required. This has been become apparent with the PREEMPT RT patchset
applied: With the fully preemptible kernel configuration the system
often ended up in a freeze already at startup.
Disable interrupts and lock using read_lock_irqsave. Try to lock in
the sysrq/oops case, but don't bother if locking fails.
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
drivers/tty/serial/fsl_lpuart.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index f02934ffb329..15df1ba78095 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1705,6 +1705,13 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned char old_cr2, cr2;
+ unsigned long flags;
+ int locked = 1;
+
+ if (sport->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&sport->port.lock, flags);
+ else
+ spin_lock_irqsave(&sport->port.lock, flags);
/* first save CR2 and then disable interrupts */
cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
@@ -1719,6 +1726,9 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
barrier();
writeb(old_cr2, sport->port.membase + UARTCR2);
+
+ if (locked)
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void
@@ -1726,6 +1736,13 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned long old_cr, cr;
+ unsigned long flags;
+ int locked = 1;
+
+ if (sport->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&sport->port.lock, flags);
+ else
+ spin_lock_irqsave(&sport->port.lock, flags);
/* first save CR2 and then disable interrupts */
cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
@@ -1740,6 +1757,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
barrier();
lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
--
2.12.0
^ permalink raw reply related
* Re: [PATCH] serdev: Replace serdev_device_write_buf with serdev_device_write
From: Rob Herring @ 2017-03-24 18:31 UTC (permalink / raw)
To: Andrey Smirnov
Cc: Chris Healy, Guenter Roeck, Andy Shevchenko,
linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20170320165628.26738-1-andrew.smirnov@gmail.com>
On Mon, Mar 20, 2017 at 11:56 AM, Andrey Smirnov
<andrew.smirnov@gmail.com> wrote:
> Convert serdev_device_write_buf's code to be able to transfer amount of
> data potentially exceeding "write room" at the moment of invocation.
>
> To support that, also add serdev_device_write_wakeup.
>
> Drivers wanting to use full extent of serdev_device_write functionality
> asre expected to provide serdev_device_write_wakeup as a sole handler of
> .write_wakeup event or call it as a part of driver's custom
> .write_wakeup code.
>
> Drivers wanting to retain old serdev_device_write_buf behaviour can
> replace those call to calls to serdev_device_write with timeout of
> 0. Providing .write_wakeup handler in such case is optional.
Looks good, just a couple of things.
>
> Cc: cphealy@gmail.com
> Cc: Guenter Roeck <linux@roeck-us.net>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: linux-serial@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
> drivers/tty/serdev/core.c | 36 +++++++++++++++++++++++++++++++-----
> include/linux/serdev.h | 11 +++++++++--
> 2 files changed, 40 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> index f4c6c90..9962d84 100644
> --- a/drivers/tty/serdev/core.c
> +++ b/drivers/tty/serdev/core.c
> @@ -116,17 +116,41 @@ void serdev_device_close(struct serdev_device *serdev)
> }
> EXPORT_SYMBOL_GPL(serdev_device_close);
>
> -int serdev_device_write_buf(struct serdev_device *serdev,
> - const unsigned char *buf, size_t count)
> +void serdev_device_write_wakeup(struct serdev_device *serdev)
> +{
> + complete(&serdev->write_comp);
> +}
> +EXPORT_SYMBOL_GPL(serdev_device_write_wakeup);
> +
> +int serdev_device_write(struct serdev_device *serdev,
> + const unsigned char *buf, size_t count,
> + unsigned long timeout)
> {
> struct serdev_controller *ctrl = serdev->ctrl;
> + int ret;
>
> - if (!ctrl || !ctrl->ops->write_buf)
> + if (!ctrl || !ctrl->ops->write_buf ||
> + (timeout && !serdev->ops->write_wakeup))
> return -EINVAL;
>
> - return ctrl->ops->write_buf(ctrl, buf, count);
> + mutex_lock(&serdev->write_lock);
> + do {
> + reinit_completion(&serdev->write_comp);
> +
> + ret = ctrl->ops->write_buf(ctrl, buf, count);
> + if (ret < 0)
> + break;
> +
> + buf += ret;
> + count -= ret;
> +
> + } while (count &&
> + wait_for_completion_timeout(&serdev->write_comp,
> + timeout));
This is going to wait for timeout time on each loop. We want the
timeout passed in to be the total time.
> + mutex_unlock(&serdev->write_lock);
> + return ret < 0 ? ret : (count ? -ETIMEDOUT : 0);
> }
> -EXPORT_SYMBOL_GPL(serdev_device_write_buf);
> +EXPORT_SYMBOL_GPL(serdev_device_write);
>
> void serdev_device_write_flush(struct serdev_device *serdev)
> {
> @@ -232,6 +256,8 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl)
> serdev->dev.parent = &ctrl->dev;
> serdev->dev.bus = &serdev_bus_type;
> serdev->dev.type = &serdev_device_type;
> + init_completion(&serdev->write_comp);
> + mutex_init(&serdev->write_lock);
> return serdev;
> }
> EXPORT_SYMBOL_GPL(serdev_device_alloc);
> diff --git a/include/linux/serdev.h b/include/linux/serdev.h
> index 5176cdc..18cbbed 100644
> --- a/include/linux/serdev.h
> +++ b/include/linux/serdev.h
> @@ -39,12 +39,17 @@ struct serdev_device_ops {
> * @nr: Device number on serdev bus.
> * @ctrl: serdev controller managing this device.
> * @ops: Device operations.
> + * @write_comp Completion used by serdev_device_write internally
> + * @write_lock Mutext used to esure exclusive access to the bus when
> + * writing data with serdev_device_write()
> */
> struct serdev_device {
> struct device dev;
> int nr;
> struct serdev_controller *ctrl;
> const struct serdev_device_ops *ops;
> + struct completion write_comp;
> + struct mutex write_lock;
> };
>
> static inline struct serdev_device *to_serdev_device(struct device *d)
> @@ -186,10 +191,12 @@ int serdev_device_open(struct serdev_device *);
> void serdev_device_close(struct serdev_device *);
> unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
> void serdev_device_set_flow_control(struct serdev_device *, bool);
> -int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
> +void serdev_device_write_wakeup(struct serdev_device *);
> +int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, unsigned long);
> void serdev_device_write_flush(struct serdev_device *);
> int serdev_device_write_room(struct serdev_device *);
>
> +
> /*
> * serdev device driver functions
> */
> @@ -223,7 +230,7 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev
> return 0;
> }
> static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {}
> -static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsigned char *buf, size_t count)
We probably should keep a wrapper for serdev_device_write_buf to avoid
cross tree dependencies. However, the Nokia BT support is going to
have them anyway.
> +static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf, size_t count)
> {
> return -ENODEV;
> }
> --
> 2.9.3
>
^ permalink raw reply
* Re: [PATCH 1/2] serial: pl010: Move uart_register_driver call to device probe
From: Russell King - ARM Linux @ 2017-03-24 16:47 UTC (permalink / raw)
To: Sjoerd Simons
Cc: linux-serial, linux-renesas-soc, Greg Kroah-Hartman, linux-kernel,
Jiri Slaby
In-Reply-To: <20170324162634.8880-2-sjoerd.simons@collabora.co.uk>
On Fri, Mar 24, 2017 at 05:26:33PM +0100, Sjoerd Simons wrote:
> uart_register_driver call binds the driver to a specific device
> node through tty_register_driver call. This should typically
> happen during device probe call.
>
> In a multiplatform scenario, it is possible that multiple serial
> drivers are part of the kernel. Currently the driver registration fails
> if multiple serial drivers with overlapping major/minor numbers are
> included.
This is racy. The driver model locking is on a _per_ device basis,
it is not on a per driver basis.
It is entirely possible for a driver to be probed by two devices at
once, possibly on two different CPUs. Checking the state of the
UART driver structure and then registering it means there is a window
where we could end up with two CPUs registering the same UART driver
at the same time, which would cause things to go wrong.
Therefore, this needs some form of locking.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* Re: [PATCH 0/2] Move uart_register_driver call to device probe for pl010 and sh-sci
From: Russell King - ARM Linux @ 2017-03-24 16:42 UTC (permalink / raw)
To: Sjoerd Simons
Cc: linux-serial, linux-renesas-soc, Greg Kroah-Hartman, linux-kernel,
Jiri Slaby
In-Reply-To: <20170324162634.8880-1-sjoerd.simons@collabora.co.uk>
On Fri, Mar 24, 2017 at 05:26:32PM +0100, Sjoerd Simons wrote:
> When testing on a Renesas board with the PL010 serial driver enabled
> serial output broke. Turns out the minor device numbers for both
> drivers happen to overlap, causing whichever driver happened to be the
> second one to register to fail.
How the **** has the SH serial driver ended up with overlapping device
numbers?
What happened to our maintained list of allocated major/minor device
numbers, which is supposed to stop crap like this happening?
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* Re: [PATCH] braille-console: Fix value returned by _braille_console_setup
From: Petr Mladek @ 2017-03-24 16:41 UTC (permalink / raw)
To: Samuel Thibault, Steven Rostedt, Ming Lei, Aleksey Makarov,
linux-serial, Joe Perches, linux-kernel
In-Reply-To: <20170319143726.p6motwasbc2lfdao@var.youpi.perso.aquilenet.fr>
On Sun 2017-03-19 15:37:26, Samuel Thibault wrote:
> commit bbeddf52adc1 ("printk: move braille console support into
> separate braille.[ch] files") introduced _braille_console_setup()
> to outline the braille initialization code. There was however some
> confusion over the value it was supposed to return. commit 2cfe6c4ac7ee
> ("printk: Fix return of braille_register_console()") tried to fix it
> but failed to.
>
> This fixes and documents the returned value according to the use
> in printk.c: non-zero return means a parsing error, and thus this
> console configuration should be ignored.
>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> Cc: Aleksey Makarov <aleksey.makarov@linaro.org>
> Cc: Joe Perches <joe@perches.com>
> Cc: Ming Lei <ming.lei@canonical.com>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Petr Mladek <pmladek@suse.com>
>
> Index: linux-4.10/kernel/printk/braille.c
> ===================================================================
> --- linux-4.10.orig/kernel/printk/braille.c
> +++ linux-4.10/kernel/printk/braille.c
> @@ -2,12 +2,13 @@
>
> #include <linux/kernel.h>
> #include <linux/console.h>
> +#include <linux/errno.h>
> #include <linux/string.h>
>
> #include "console_cmdline.h"
> #include "braille.h"
>
> -char *_braille_console_setup(char **str, char **brl_options)
> +int _braille_console_setup(char **str, char **brl_options)
> {
> if (!strncmp(*str, "brl,", 4)) {
> *brl_options = "";
> @@ -15,14 +16,15 @@ char *_braille_console_setup(char **str,
> } else if (!strncmp(*str, "brl=", 4)) {
> *brl_options = *str + 4;
> *str = strchr(*brl_options, ',');
> - if (!*str)
> + if (!*str) {
> pr_err("need port name after brl=\n");
> + return -EINVAL;
> + }
> else
This "else" has become superfluous because there is return now.
> *((*str)++) = 0;
> - } else
> - return NULL;
> + }
>
> - return *str;
> + return 0;
> }
Otherwise, the patch looks fine to me. With it, the logic is
exactly the same as before the commit bbeddf52adc1b4207674ab
("printk: move braille console support into separate braille.[ch]
files") that broke it.
With the superfluous "else" removed:
Acked-by: Petr Mladek <pmladek@suse.com>
Best Regards,
Petr
^ permalink raw reply
* [PATCH 2/2] serial: sh-sci: Move uart_register_driver call to device probe
From: Sjoerd Simons @ 2017-03-24 16:26 UTC (permalink / raw)
To: linux-serial
Cc: linux-renesas-soc, Greg Kroah-Hartman, linux-kernel, Jiri Slaby
In-Reply-To: <20170324162634.8880-1-sjoerd.simons@collabora.co.uk>
uart_register_driver call binds the driver to a specific device
node through tty_register_driver call. This should typically
happen during device probe call.
In a multiplatform scenario, it is possible that multiple serial
drivers are part of the kernel. Currently the driver registration fails
if multiple serial drivers with overlapping major/minor numbers are
included.
Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
drivers/tty/serial/sh-sci.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 9a47cc4f16a2..7c1c0c08459e 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -3063,6 +3063,12 @@ static int sci_probe_single(struct platform_device *dev,
return -EINVAL;
}
+ if (!sci_uart_driver.state) {
+ ret = uart_register_driver(&sci_uart_driver);
+ if (ret)
+ return ret;
+ }
+
ret = sci_init_single(dev, sciport, index, p, false);
if (ret)
return ret;
@@ -3186,24 +3192,17 @@ static struct platform_driver sci_driver = {
static int __init sci_init(void)
{
- int ret;
-
pr_info("%s\n", banner);
- ret = uart_register_driver(&sci_uart_driver);
- if (likely(ret == 0)) {
- ret = platform_driver_register(&sci_driver);
- if (unlikely(ret))
- uart_unregister_driver(&sci_uart_driver);
- }
-
- return ret;
+ return platform_driver_register(&sci_driver);
}
static void __exit sci_exit(void)
{
platform_driver_unregister(&sci_driver);
- uart_unregister_driver(&sci_uart_driver);
+
+ if (sci_uart_driver.state)
+ uart_unregister_driver(&sci_uart_driver);
}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
--
2.11.0
^ permalink raw reply related
* [PATCH 1/2] serial: pl010: Move uart_register_driver call to device probe
From: Sjoerd Simons @ 2017-03-24 16:26 UTC (permalink / raw)
To: linux-serial
Cc: linux-renesas-soc, Greg Kroah-Hartman, linux-kernel, Russell King,
Jiri Slaby
In-Reply-To: <20170324162634.8880-1-sjoerd.simons@collabora.co.uk>
uart_register_driver call binds the driver to a specific device
node through tty_register_driver call. This should typically
happen during device probe call.
In a multiplatform scenario, it is possible that multiple serial
drivers are part of the kernel. Currently the driver registration fails
if multiple serial drivers with overlapping major/minor numbers are
included.
Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
---
drivers/tty/serial/amba-pl010.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index f2f251075109..74a1d3b2e45d 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -749,6 +749,16 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
amba_ports[i] = uap;
amba_set_drvdata(dev, uap);
+
+ if (!amba_reg.state) {
+ ret = uart_register_driver(&amba_reg);
+ if (ret < 0) {
+ dev_err(uap->port.dev,
+ "Failed to register AMBA-PL010 driver\n");
+ return ret;
+ }
+ }
+
ret = uart_add_one_port(&amba_reg, &uap->port);
if (ret)
amba_ports[i] = NULL;
@@ -760,12 +770,18 @@ static int pl010_remove(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
int i;
+ bool busy = false;
uart_remove_one_port(&amba_reg, &uap->port);
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == uap)
amba_ports[i] = NULL;
+ else if (amba_ports[i])
+ busy = true;
+
+ if (!busy)
+ uart_unregister_driver(&amba_reg);
return 0;
}
@@ -816,23 +832,14 @@ static struct amba_driver pl010_driver = {
static int __init pl010_init(void)
{
- int ret;
-
printk(KERN_INFO "Serial: AMBA driver\n");
- ret = uart_register_driver(&amba_reg);
- if (ret == 0) {
- ret = amba_driver_register(&pl010_driver);
- if (ret)
- uart_unregister_driver(&amba_reg);
- }
- return ret;
+ return amba_driver_register(&pl010_driver);
}
static void __exit pl010_exit(void)
{
amba_driver_unregister(&pl010_driver);
- uart_unregister_driver(&amba_reg);
}
module_init(pl010_init);
--
2.11.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox