mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
linux-can-next-for-4.16-20180116
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEE4bay/IylYqM/npjQHv7KIOw4HPYFAlpeCCQTHG1rbEBwZW5n dXRyb25peC5kZQAKCRAe/sog7Dgc9ti9B/4jAoCYTuYXnkRvS34jdgQQV99QyC8M EpcAgzHo2kYNPDf5q8TEVheXxvA9XeGiA+TtjL9cNowxwMMtJev3/dmBtOmU6jek RgOsYlR8guxBHOx8pj1IMl1xPoWTLfg4Kv1qnpXx3zvhOP610G/edBBSZt659MGF SW6pBoNivbl+EYSM5x81QIfqJ4NlD5AKY4PeeSnGrnSthd8EFNp2zKkcY8nMOJ0D Gm2YyxGJXh+lHse965DQRNg+owZxIWyheQplulVrw9v34LOjbFko3Cd+D9KLW5MG LVVRJ3E0jm7W75AvxNcv2WP+lZVcDxXqsxFH0dP8WOJNZiKZeJ5aZfji =ROXk -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-4.16-20180116' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2018-01-16 this is a pull request for net-next/master consisting of 9 patches. This is a series of patches, some of them initially by Franklin S Cooper Jr, which was picked up by Faiz Abbas. Faiz Abbas added some patches while working on this series, I contributed one as well. The first two patches add support to CAN device infrastructure to limit the bitrate of a CAN adapter if the used CAN-transceiver has a certain maximum bitrate. The remaining patches improve the m_can driver. They add support for bitrate limiting to the driver, clean up the driver and add support for runtime PM. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4f7d58517f
@ -0,0 +1,24 @@
|
||||
Generic CAN transceiver Device Tree binding
|
||||
------------------------------
|
||||
|
||||
CAN transceiver typically limits the max speed in standard CAN and CAN FD
|
||||
modes. Typically these limitations are static and the transceivers themselves
|
||||
provide no way to detect this limitation at runtime. For this situation,
|
||||
the "can-transceiver" node can be used.
|
||||
|
||||
Required Properties:
|
||||
max-bitrate: a positive non 0 value that determines the max
|
||||
speed that CAN/CAN-FD can run. Any other value
|
||||
will be ignored.
|
||||
|
||||
Examples:
|
||||
|
||||
Based on Texas Instrument's TCAN1042HGV CAN Transceiver
|
||||
|
||||
m_can0 {
|
||||
....
|
||||
can-transceiver {
|
||||
max-bitrate = <5000000>;
|
||||
};
|
||||
...
|
||||
};
|
@ -43,6 +43,11 @@ Required properties:
|
||||
Please refer to 2.4.1 Message RAM Configuration in
|
||||
Bosch M_CAN user manual for details.
|
||||
|
||||
Optional Subnode:
|
||||
- can-transceiver : Can-transceiver subnode describing maximum speed
|
||||
that can be used for CAN/CAN-FD modes. See
|
||||
Documentation/devicetree/bindings/net/can/can-transceiver.txt
|
||||
for details.
|
||||
Example:
|
||||
SoC dtsi:
|
||||
m_can1: can@20e8000 {
|
||||
@ -63,4 +68,8 @@ Board dts:
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_m_can1>;
|
||||
status = "enabled";
|
||||
|
||||
can-transceiver {
|
||||
max-bitrate = <5000000>;
|
||||
};
|
||||
};
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/of.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
@ -814,6 +815,29 @@ int open_candev(struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(open_candev);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* Common function that can be used to understand the limitation of
|
||||
* a transceiver when it provides no means to determine these limitations
|
||||
* at runtime.
|
||||
*/
|
||||
void of_can_transceiver(struct net_device *dev)
|
||||
{
|
||||
struct device_node *dn;
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
struct device_node *np = dev->dev.parent->of_node;
|
||||
int ret;
|
||||
|
||||
dn = of_get_child_by_name(np, "can-transceiver");
|
||||
if (!dn)
|
||||
return;
|
||||
|
||||
ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
|
||||
if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
|
||||
netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_can_transceiver);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Common close function for cleanup before the device gets closed.
|
||||
*
|
||||
@ -913,6 +937,13 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
priv->bitrate_const_cnt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&priv->bittiming, &bt, sizeof(bt));
|
||||
|
||||
if (priv->do_set_bittiming) {
|
||||
@ -997,6 +1028,13 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
priv->data_bitrate_const_cnt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
|
||||
|
||||
if (priv->do_set_data_bittiming) {
|
||||
@ -1064,6 +1102,7 @@ static size_t can_get_size(const struct net_device *dev)
|
||||
if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
|
||||
size += nla_total_size(sizeof(*priv->data_bitrate_const) *
|
||||
priv->data_bitrate_const_cnt);
|
||||
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -1121,7 +1160,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
|
||||
sizeof(*priv->data_bitrate_const) *
|
||||
priv->data_bitrate_const_cnt,
|
||||
priv->data_bitrate_const))
|
||||
priv->data_bitrate_const)) ||
|
||||
|
||||
(nla_put(skb, IFLA_CAN_BITRATE_MAX,
|
||||
sizeof(priv->bitrate_max),
|
||||
&priv->bitrate_max))
|
||||
)
|
||||
|
||||
return -EMSGSIZE;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
@ -126,6 +127,12 @@ enum m_can_mram_cfg {
|
||||
#define DBTP_DSJW_SHIFT 0
|
||||
#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT)
|
||||
|
||||
/* Transmitter Delay Compensation Register (TDCR) */
|
||||
#define TDCR_TDCO_SHIFT 8
|
||||
#define TDCR_TDCO_MASK (0x7F << TDCR_TDCO_SHIFT)
|
||||
#define TDCR_TDCF_SHIFT 0
|
||||
#define TDCR_TDCF_MASK (0x7F << TDCR_TDCF_SHIFT)
|
||||
|
||||
/* Test Register (TEST) */
|
||||
#define TEST_LBCK BIT(4)
|
||||
|
||||
@ -625,21 +632,16 @@ static int m_can_clk_start(struct m_can_priv *priv)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(priv->hclk);
|
||||
err = pm_runtime_get_sync(priv->device);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = clk_prepare_enable(priv->cclk);
|
||||
if (err)
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
pm_runtime_put_noidle(priv->device);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void m_can_clk_stop(struct m_can_priv *priv)
|
||||
{
|
||||
clk_disable_unprepare(priv->cclk);
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
pm_runtime_put_sync(priv->device);
|
||||
}
|
||||
|
||||
static int m_can_get_berr_counter(const struct net_device *dev,
|
||||
@ -987,13 +989,47 @@ static int m_can_set_bittiming(struct net_device *dev)
|
||||
m_can_write(priv, M_CAN_NBTP, reg_btp);
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
|
||||
reg_btp = 0;
|
||||
brp = dbt->brp - 1;
|
||||
sjw = dbt->sjw - 1;
|
||||
tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
|
||||
tseg2 = dbt->phase_seg2 - 1;
|
||||
reg_btp = (brp << DBTP_DBRP_SHIFT) | (sjw << DBTP_DSJW_SHIFT) |
|
||||
(tseg1 << DBTP_DTSEG1_SHIFT) |
|
||||
(tseg2 << DBTP_DTSEG2_SHIFT);
|
||||
|
||||
/* TDC is only needed for bitrates beyond 2.5 MBit/s.
|
||||
* This is mentioned in the "Bit Time Requirements for CAN FD"
|
||||
* paper presented at the International CAN Conference 2013
|
||||
*/
|
||||
if (dbt->bitrate > 2500000) {
|
||||
u32 tdco, ssp;
|
||||
|
||||
/* Use the same value of secondary sampling point
|
||||
* as the data sampling point
|
||||
*/
|
||||
ssp = dbt->sample_point;
|
||||
|
||||
/* Equation based on Bosch's M_CAN User Manual's
|
||||
* Transmitter Delay Compensation Section
|
||||
*/
|
||||
tdco = (priv->can.clock.freq / 1000) *
|
||||
ssp / dbt->bitrate;
|
||||
|
||||
/* Max valid TDCO value is 127 */
|
||||
if (tdco > 127) {
|
||||
netdev_warn(dev, "TDCO value of %u is beyond maximum. Using maximum possible value\n",
|
||||
tdco);
|
||||
tdco = 127;
|
||||
}
|
||||
|
||||
reg_btp |= DBTP_TDC;
|
||||
m_can_write(priv, M_CAN_TDCR,
|
||||
tdco << TDCR_TDCO_SHIFT);
|
||||
}
|
||||
|
||||
reg_btp |= (brp << DBTP_DBRP_SHIFT) |
|
||||
(sjw << DBTP_DSJW_SHIFT) |
|
||||
(tseg1 << DBTP_DTSEG1_SHIFT) |
|
||||
(tseg2 << DBTP_DTSEG2_SHIFT);
|
||||
|
||||
m_can_write(priv, M_CAN_DBTP, reg_btp);
|
||||
}
|
||||
|
||||
@ -1143,11 +1179,6 @@ static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_m_can_dev(struct net_device *dev)
|
||||
{
|
||||
free_candev(dev);
|
||||
}
|
||||
|
||||
/* Checks core release number of M_CAN
|
||||
* returns 0 if an unsupported device is detected
|
||||
* else it returns the release and step coded as:
|
||||
@ -1207,31 +1238,20 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)
|
||||
return !niso_timeout;
|
||||
}
|
||||
|
||||
static struct net_device *alloc_m_can_dev(struct platform_device *pdev,
|
||||
void __iomem *addr, u32 tx_fifo_size)
|
||||
static int m_can_dev_setup(struct platform_device *pdev, struct net_device *dev,
|
||||
void __iomem *addr)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct m_can_priv *priv;
|
||||
int m_can_version;
|
||||
unsigned int echo_buffer_count;
|
||||
|
||||
m_can_version = m_can_check_core_release(addr);
|
||||
/* return if unsupported version */
|
||||
if (!m_can_version) {
|
||||
dev = NULL;
|
||||
goto return_dev;
|
||||
dev_err(&pdev->dev, "Unsupported version number: %2d",
|
||||
m_can_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If version < 3.1.x, then only one echo buffer is used */
|
||||
echo_buffer_count = ((m_can_version == 30)
|
||||
? 1U
|
||||
: (unsigned int)tx_fifo_size);
|
||||
|
||||
dev = alloc_candev(sizeof(*priv), echo_buffer_count);
|
||||
if (!dev) {
|
||||
dev = NULL;
|
||||
goto return_dev;
|
||||
}
|
||||
priv = netdev_priv(dev);
|
||||
netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT);
|
||||
|
||||
@ -1273,16 +1293,12 @@ static struct net_device *alloc_m_can_dev(struct platform_device *pdev,
|
||||
: 0);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported device: free candev */
|
||||
free_m_can_dev(dev);
|
||||
dev_err(&pdev->dev, "Unsupported version number: %2d",
|
||||
priv->version);
|
||||
dev = NULL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return_dev:
|
||||
return dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m_can_open(struct net_device *dev)
|
||||
@ -1574,37 +1590,26 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
/* Enable clocks. Necessary to read Core Release in order to determine
|
||||
* M_CAN version
|
||||
*/
|
||||
ret = clk_prepare_enable(hclk);
|
||||
if (ret)
|
||||
goto disable_hclk_ret;
|
||||
|
||||
ret = clk_prepare_enable(cclk);
|
||||
if (ret)
|
||||
goto disable_cclk_ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
irq = platform_get_irq_byname(pdev, "int0");
|
||||
|
||||
if (IS_ERR(addr) || irq < 0) {
|
||||
ret = -EINVAL;
|
||||
goto disable_cclk_ret;
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
/* message ram could be shared */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
goto disable_cclk_ret;
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!mram_addr) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_cclk_ret;
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
/* get message ram configuration */
|
||||
@ -1613,7 +1618,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
sizeof(mram_config_vals) / 4);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not get Message RAM configuration.");
|
||||
goto disable_cclk_ret;
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
/* Get TX FIFO size
|
||||
@ -1622,11 +1627,12 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
tx_fifo_size = mram_config_vals[7];
|
||||
|
||||
/* allocate the m_can device */
|
||||
dev = alloc_m_can_dev(pdev, addr, tx_fifo_size);
|
||||
dev = alloc_candev(sizeof(*priv), tx_fifo_size);
|
||||
if (!dev) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_cclk_ret;
|
||||
goto failed_ret;
|
||||
}
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
dev->irq = irq;
|
||||
priv->device = &pdev->dev;
|
||||
@ -1640,30 +1646,42 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
|
||||
/* Enable clocks. Necessary to read Core Release in order to determine
|
||||
* M_CAN version
|
||||
*/
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
ret = m_can_clk_start(priv);
|
||||
if (ret)
|
||||
goto pm_runtime_fail;
|
||||
|
||||
ret = m_can_dev_setup(pdev, dev, addr);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
ret = register_m_can_dev(dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
goto failed_free_dev;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
devm_can_led_init(dev);
|
||||
|
||||
of_can_transceiver(dev);
|
||||
|
||||
dev_info(&pdev->dev, "%s device registered (irq=%d, version=%d)\n",
|
||||
KBUILD_MODNAME, dev->irq, priv->version);
|
||||
|
||||
/* Probe finished
|
||||
* Stop clocks. They will be reactivated once the M_CAN device is opened
|
||||
*/
|
||||
|
||||
goto disable_cclk_ret;
|
||||
|
||||
failed_free_dev:
|
||||
free_m_can_dev(dev);
|
||||
disable_cclk_ret:
|
||||
clk_disable_unprepare(cclk);
|
||||
disable_hclk_ret:
|
||||
clk_disable_unprepare(hclk);
|
||||
clk_disable:
|
||||
m_can_clk_stop(priv);
|
||||
pm_runtime_fail:
|
||||
if (ret) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_candev(dev);
|
||||
}
|
||||
failed_ret:
|
||||
return ret;
|
||||
}
|
||||
@ -1721,14 +1739,47 @@ static int m_can_plat_remove(struct platform_device *pdev)
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
unregister_m_can_dev(dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
free_m_can_dev(dev);
|
||||
free_candev(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m_can_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_priv *priv = netdev_priv(ndev);
|
||||
|
||||
clk_disable_unprepare(priv->cclk);
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m_can_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_priv *priv = netdev_priv(ndev);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(priv->hclk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = clk_prepare_enable(priv->cclk);
|
||||
if (err)
|
||||
clk_disable_unprepare(priv->hclk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops m_can_pmops = {
|
||||
SET_RUNTIME_PM_OPS(m_can_runtime_suspend,
|
||||
m_can_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
|
||||
};
|
||||
|
||||
|
@ -46,6 +46,7 @@ struct can_priv {
|
||||
unsigned int bitrate_const_cnt;
|
||||
const u32 *data_bitrate_const;
|
||||
unsigned int data_bitrate_const_cnt;
|
||||
u32 bitrate_max;
|
||||
struct can_clock clock;
|
||||
|
||||
enum can_state state;
|
||||
@ -166,6 +167,12 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
|
||||
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
void of_can_transceiver(struct net_device *dev);
|
||||
#else
|
||||
static inline void of_can_transceiver(struct net_device *dev) { }
|
||||
#endif
|
||||
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
|
||||
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd);
|
||||
|
@ -132,6 +132,7 @@ enum {
|
||||
IFLA_CAN_TERMINATION_CONST,
|
||||
IFLA_CAN_BITRATE_CONST,
|
||||
IFLA_CAN_DATA_BITRATE_CONST,
|
||||
IFLA_CAN_BITRATE_MAX,
|
||||
__IFLA_CAN_MAX
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user