* [PATCH] bluetooth: bnep: fix buffer overflow
From: Vasiliy Kulikov @ 2011-02-14 10:54 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: security-DgEjT+Ai2ygdnm+yROfE0A, Marcel Holtmann,
Gustavo F. Padovan, David S. Miller, Tejun Heo,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
Struct ca is copied from userspace. It is not checked whether the "device"
field is NULL terminated. This potentially leads to BUG() inside of
alloc_netdev_mqs() and/or information leak by creating a device with a name
made of contents of kernel stack.
Signed-off-by: Vasiliy Kulikov <segoon-cxoSlKxDwOJWk0Htik3J/w@public.gmane.org>
---
Compile tested.
net/bluetooth/bnep/sock.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 2862f53..30faaf1 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -88,6 +88,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
sockfd_put(nsock);
return -EBADFD;
}
+ ca.device[sizeof(ca.device)-1] = 0;
err = bnep_add_connection(&ca, nsock);
if (!err) {
--
1.7.0.4
^ permalink raw reply related
* [PATCH] bluethooth: sco: fix information leak to userspace
From: Vasiliy Kulikov @ 2011-02-14 10:54 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: security-DgEjT+Ai2ygdnm+yROfE0A, Marcel Holtmann,
Gustavo F. Padovan, David S. Miller,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
struct sco_conninfo has one padding byte in the end. Local variable
cinfo of type sco_conninfo is copied to userspace with this uninizialized
one byte, leading to old stack contents leak.
Signed-off-by: Vasiliy Kulikov <segoon-cxoSlKxDwOJWk0Htik3J/w@public.gmane.org>
---
Compile tested.
net/bluetooth/sco.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 960c6d1..926ed39 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -703,6 +703,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
break;
}
+ memset(&cinfo, 0, sizeof(cinfo));
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH v2 09/13] can: pruss CAN driver.
From: Marc Kleine-Budde @ 2011-02-14 9:35 UTC (permalink / raw)
To: Subhasish Ghosh
Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
CAN NETWORK DRIVERS, Wolfgang Grandegger, m-watkins-l0cyMroinI0,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1F33D30F9B2D47ECA80CEC807A6C0727@subhasishg>
[-- Attachment #1.1: Type: text/plain, Size: 613 bytes --]
Hello,
On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
> That is correct, we receive only pre-programmed CAN ids and "all" or
> "range" implementation is not there in the PRU firmware.
I'd really like to see that you add a "all" implementation to the
firmware. Or even better use the standard id/mask approach.
cheers, Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
[-- Attachment #2: Type: text/plain, Size: 188 bytes --]
_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core
^ permalink raw reply
* Re: [PATCH v2 09/13] can: pruss CAN driver.
From: Wolfgang Grandegger @ 2011-02-14 9:28 UTC (permalink / raw)
To: Subhasish Ghosh
Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1F33D30F9B2D47ECA80CEC807A6C0727@subhasishg>
Hi Subhasish,
On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
> That is correct, we receive only pre-programmed CAN ids and "all" or
> "range" implementation is not there in the PRU firmware.
I'm curious about that CAN hardware and firmware. I found a nice block
diagram in [PATCH 0/13]:
http://marc.info/?l=linux-arm-kernel&m=129743511311286&w=4
So, one PRU is used for TX and the second for RX. Who is providing the
firmware you are using? Wouldn't it be possible to provide a firmware
for RX using just one message object (mailbox) with some buffering or
fifo? That would fit much better the SocketCAN approach favoring Basic
CAN controllers (in contrast to Full CAN [1]). And such an
implementation seems even simpler too me requiring less PRU resources.
And how about RTR and Extended CAN IDs? Is that supported?
Thanks,
Wolfgang.
[1] http://www.kvaser.com/en/about-can/the-can-protocol/18.html
^ permalink raw reply
* Re: [patch net-next-2.6] net: make dev->master general
From: Jiri Pirko @ 2011-02-14 9:01 UTC (permalink / raw)
To: Nicolas de Pesloüan
Cc: netdev, davem, shemminger, kaber, fubar, eric.dumazet
In-Reply-To: <4D58EC6C.7030005@gmail.com>
Mon, Feb 14, 2011 at 09:48:44AM CET, nicolas.2p.debian@gmail.com wrote:
>Le 12/02/2011 17:48, Jiri Pirko a écrit :
>>dev->master is now tightly connected to bonding driver. This patch makes
>>this pointer more general and ready to be used by others.
>>
>> - netdev_set_master() - bond specifics moved to new function
>> netdev_set_bond_master()
>> - introduced netif_is_bond_slave() to check if device is a bonding slave
>>
>>Signed-off-by: Jiri Pirko<jpirko@redhat.com>
>
>Hi Jiri,
>
>Even if DaveM already applied your patch, I'm not comfortable with it.
>
>What is the rational behind it? Do you have anything in mind to use
>the now "more general" master field of net_device?
>
>Of course, I won't advocate for every fields having only a single
>possible usage, but, using master for several different things might
>jeopardize our ability to share an interface between several logical
>interface systems:
>
>Due to the current usage of the rx_handler field in net_device, the
>code suggest that an interface cannot be part of a bridge and of a
>macvlan at the same time. Even if bridge provide an hook for ebtables
>to ignore an skb and allow other to get it, macvlan cannot be
>registered on the same lower interface as a bridge, because
>rx_handler can only hold a single value.
>
>By giving master a more general meaning, I think we might face a
>similar problem. It might disallow an interface to be enslaved to
>bonding and part of another logical interface at the same time, if
>such logical interface also use the master field.
That is true. I think that it makes no sense to have iface enslaved in
bond and bridge at the same time. Do you have a scenario where it makes
sense?
>
>It doesn't mean I don't support the general idea, but I would like to
>clearly understand the possible unexpected impact: do we want to stop
>interfaces to be "enslaved" to several logical interface at the same
>time?
>
>>---
>> drivers/infiniband/hw/nes/nes.c | 3 +-
>> drivers/infiniband/hw/nes/nes_cm.c | 2 +-
>> drivers/net/bonding/bond_main.c | 10 +++---
>> drivers/net/cxgb3/cxgb3_offload.c | 3 +-
>> include/linux/netdevice.h | 7 +++++
>> net/core/dev.c | 49 +++++++++++++++++++++++++++---------
>> 6 files changed, 54 insertions(+), 20 deletions(-)
>>
>>diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
>>index 3b4ec32..3d7f366 100644
>>--- a/drivers/infiniband/hw/nes/nes.c
>>+++ b/drivers/infiniband/hw/nes/nes.c
>>@@ -153,7 +153,8 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
>> nesdev, nesdev->netdev[0]->name);
>> netdev = nesdev->netdev[0];
>> nesvnic = netdev_priv(netdev);
>>- is_bonded = (netdev->master == event_netdev);
>>+ is_bonded = netif_is_bond_slave(netdev)&&
>>+ (netdev->master == event_netdev);
>> if ((netdev == event_netdev) || is_bonded) {
>> if (nesvnic->rdma_enabled == 0) {
>> nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
>>diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
>>index 009ec81..ec3aa11 100644
>>--- a/drivers/infiniband/hw/nes/nes_cm.c
>>+++ b/drivers/infiniband/hw/nes/nes_cm.c
>>@@ -1118,7 +1118,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
>> return rc;
>> }
>>
>>- if (nesvnic->netdev->master)
>>+ if (netif_is_bond_slave(netdev))
>> netdev = nesvnic->netdev->master;
>> else
>> netdev = nesvnic->netdev;
>>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>>index 1df9f0e..9f87787 100644
>>--- a/drivers/net/bonding/bond_main.c
>>+++ b/drivers/net/bonding/bond_main.c
>>@@ -1594,9 +1594,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
>> }
>> }
>>
>>- res = netdev_set_master(slave_dev, bond_dev);
>>+ res = netdev_set_bond_master(slave_dev, bond_dev);
>> if (res) {
>>- pr_debug("Error %d calling netdev_set_master\n", res);
>>+ pr_debug("Error %d calling netdev_set_bond_master\n", res);
>> goto err_restore_mac;
>> }
>> /* open the slave since the application closed it */
>>@@ -1812,7 +1812,7 @@ err_close:
>> dev_close(slave_dev);
>>
>> err_unset_master:
>>- netdev_set_master(slave_dev, NULL);
>>+ netdev_set_bond_master(slave_dev, NULL);
>>
>> err_restore_mac:
>> if (!bond->params.fail_over_mac) {
>>@@ -1992,7 +1992,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
>> netif_addr_unlock_bh(bond_dev);
>> }
>>
>>- netdev_set_master(slave_dev, NULL);
>>+ netdev_set_bond_master(slave_dev, NULL);
>>
>> #ifdef CONFIG_NET_POLL_CONTROLLER
>> read_lock_bh(&bond->lock);
>>@@ -2114,7 +2114,7 @@ static int bond_release_all(struct net_device *bond_dev)
>> netif_addr_unlock_bh(bond_dev);
>> }
>>
>>- netdev_set_master(slave_dev, NULL);
>>+ netdev_set_bond_master(slave_dev, NULL);
>>
>> /* close slave before restoring its mac address */
>> dev_close(slave_dev);
>>diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
>>index 7ea94b5..862804f 100644
>>--- a/drivers/net/cxgb3/cxgb3_offload.c
>>+++ b/drivers/net/cxgb3/cxgb3_offload.c
>>@@ -186,9 +186,10 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
>> dev = NULL;
>> if (grp)
>> dev = vlan_group_get_device(grp, vlan);
>>- } else
>>+ } else if (netif_is_bond_slave(dev)) {
>> while (dev->master)
>> dev = dev->master;
>
>The while() here suggests that nesting bonding is possible. This is
>not true (even if not enforced yet). And even if it was true, then
>you needed to use netif_is_bond_slave(dev) inside the while() loop,
>to be consistent.
>
>>+ }
>> return dev;
>> }
>> }
>>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>index 5a5baea..5a42b10 100644
>>--- a/include/linux/netdevice.h
>>+++ b/include/linux/netdevice.h
>>@@ -2377,6 +2377,8 @@ extern int netdev_max_backlog;
>> extern int netdev_tstamp_prequeue;
>> extern int weight_p;
>> extern int netdev_set_master(struct net_device *dev, struct net_device *master);
>>+extern int netdev_set_bond_master(struct net_device *dev,
>>+ struct net_device *master);
>> extern int skb_checksum_help(struct sk_buff *skb);
>> extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features);
>> #ifdef CONFIG_BUG
>>@@ -2437,6 +2439,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
>> dev->gso_max_size = size;
>> }
>>
>>+static inline int netif_is_bond_slave(struct net_device *dev)
>>+{
>>+ return dev->flags& IFF_SLAVE&& dev->priv_flags& IFF_BONDING;
>>+}
>>+
>
>Does this means you also consider IFF_SLAVE as a "more general" flag
>now? Wasn't IFF_SLAVE a sufficient evidence of the interface being
>enslaved to a bonding interface, before?
>
>> extern struct pernet_operations __net_initdata loopback_net_ops;
>>
>> static inline int dev_ethtool_get_settings(struct net_device *dev,
>>diff --git a/net/core/dev.c b/net/core/dev.c
>>index d874fd1..a413276 100644
>>--- a/net/core/dev.c
>>+++ b/net/core/dev.c
>>@@ -3146,7 +3146,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
>> struct packet_type *ptype, *pt_prev;
>> rx_handler_func_t *rx_handler;
>> struct net_device *orig_dev;
>>- struct net_device *master;
>> struct net_device *null_or_orig;
>> struct net_device *orig_or_bond;
>> int ret = NET_RX_DROP;
>>@@ -3173,15 +3172,19 @@ static int __netif_receive_skb(struct sk_buff *skb)
>> */
>> null_or_orig = NULL;
>> orig_dev = skb->dev;
>>- master = ACCESS_ONCE(orig_dev->master);
>> if (skb->deliver_no_wcard)
>> null_or_orig = orig_dev;
>>- else if (master) {
>>- if (__skb_bond_should_drop(skb, master)) {
>>- skb->deliver_no_wcard = 1;
>>- null_or_orig = orig_dev; /* deliver only exact match */
>>- } else
>>- skb->dev = master;
>>+ else if (netif_is_bond_slave(orig_dev)) {
>>+ struct net_device *bond_master = ACCESS_ONCE(orig_dev->master);
>>+
>>+ if (likely(bond_master)) {
>>+ if (__skb_bond_should_drop(skb, bond_master)) {
>>+ skb->deliver_no_wcard = 1;
>>+ /* deliver only exact match */
>>+ null_or_orig = orig_dev;
>>+ } else
>>+ skb->dev = bond_master;
>>+ }
>
>I think we need an "else" here. If orig_dev->master is NULL, while
>netif_is_bond_slave(orig_dev) is TRUE, we apparently face an
>unexpected situation and we should at least issue a warning.
>
>> }
>>
>> __this_cpu_inc(softnet_data.processed);
>>@@ -4346,15 +4349,14 @@ static int __init dev_proc_init(void)
>>
>>
>> /**
>>- * netdev_set_master - set up master/slave pair
>>+ * netdev_set_master - set up master pointer
>> * @slave: slave device
>> * @master: new master device
>> *
>> * Changes the master device of the slave. Pass %NULL to break the
>> * bonding. The caller must hold the RTNL semaphore. On a failure
>> * a negative errno code is returned. On success the reference counts
>>- * are adjusted, %RTM_NEWLINK is sent to the routing socket and the
>>- * function returns zero.
>>+ * are adjusted and the function returns zero.
>> */
>> int netdev_set_master(struct net_device *slave, struct net_device *master)
>> {
>>@@ -4374,6 +4376,29 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
>> synchronize_net();
>> dev_put(old);
>> }
>>+ return 0;
>>+}
>>+EXPORT_SYMBOL(netdev_set_master);
>>+
>>+/**
>>+ * netdev_set_bond_master - set up bonding master/slave pair
>>+ * @slave: slave device
>>+ * @master: new master device
>>+ *
>>+ * Changes the master device of the slave. Pass %NULL to break the
>>+ * bonding. The caller must hold the RTNL semaphore. On a failure
>>+ * a negative errno code is returned. On success %RTM_NEWLINK is sent
>>+ * to the routing socket and the function returns zero.
>>+ */
>>+int netdev_set_bond_master(struct net_device *slave, struct net_device *master)
>>+{
>>+ int err;
>>+
>>+ ASSERT_RTNL();
>>+
>>+ err = netdev_set_master(slave, master);
>>+ if (err)
>>+ return err;
>> if (master)
>> slave->flags |= IFF_SLAVE;
>> else
>>@@ -4382,7 +4407,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
>> rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE);
>> return 0;
>> }
>>-EXPORT_SYMBOL(netdev_set_master);
>>+EXPORT_SYMBOL(netdev_set_bond_master);
>>
>> static void dev_change_rx_flags(struct net_device *dev, int flags)
>> {
>
^ permalink raw reply
* [PATCH] pch_gbe: Fix the MAC Address load issue.
From: Toshiharu Okada @ 2011-02-14 8:51 UTC (permalink / raw)
To: ML netdev, David S. Miller
Cc: Tomoya Morinaga, LKML, Wang, Qi, Wang, Yong Y, Andrew, Intel OTC,
Ewe, Kok Howg
With the specification of hardware,
the processing at the time of driver starting was modified.
This device write automatically the MAC address read from serial ROM
into a MAC Adress1A/1B register at the time of power on reset.
However, when stable clock is not supplied,
the writing of MAC Adress1A/1B register may not be completed.
In this case, it is necessary to load MAC address to MAC Address1A/1B register
by the MAC Address1 load register.
This patch always does the above processing,
in order not to be dependent on system environment.
Signed-off-by: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com>
---
drivers/net/pch_gbe/pch_gbe.h | 2 +-
drivers/net/pch_gbe/pch_gbe_main.c | 7 +++++++
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h
index a0c26a9..e1e33c8 100644
--- a/drivers/net/pch_gbe/pch_gbe.h
+++ b/drivers/net/pch_gbe/pch_gbe.h
@@ -73,7 +73,7 @@ struct pch_gbe_regs {
struct pch_gbe_regs_mac_adr mac_adr[16];
u32 ADDR_MASK;
u32 MIIM;
- u32 reserve2;
+ u32 MAC_ADDR_LOAD;
u32 RGMII_ST;
u32 RGMII_CTRL;
u32 reserve3[3];
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index 8ec48ad..8bba091 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -89,6 +89,12 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
int data);
+
+inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw)
+{
+ iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD);
+}
+
/**
* pch_gbe_mac_read_mac_addr - Read MAC address
* @hw: Pointer to the HW structure
@@ -2333,6 +2339,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
netdev->features = NETIF_F_HW_CSUM | NETIF_F_GRO;
pch_gbe_set_ethtool_ops(netdev);
+ pch_gbe_mac_load_mac_addr(&adapter->hw);
pch_gbe_mac_reset_hw(&adapter->hw);
/* setup the private structure */
--
1.6.2.5
^ permalink raw reply related
* Re: [patch net-next-2.6] net: make dev->master general
From: Nicolas de Pesloüan @ 2011-02-14 8:48 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, shemminger, kaber, fubar, eric.dumazet
In-Reply-To: <20110212164836.GB12156@psychotron.redhat.com>
Le 12/02/2011 17:48, Jiri Pirko a écrit :
> dev->master is now tightly connected to bonding driver. This patch makes
> this pointer more general and ready to be used by others.
>
> - netdev_set_master() - bond specifics moved to new function
> netdev_set_bond_master()
> - introduced netif_is_bond_slave() to check if device is a bonding slave
>
> Signed-off-by: Jiri Pirko<jpirko@redhat.com>
Hi Jiri,
Even if DaveM already applied your patch, I'm not comfortable with it.
What is the rational behind it? Do you have anything in mind to use the now "more general" master
field of net_device?
Of course, I won't advocate for every fields having only a single possible usage, but, using master
for several different things might jeopardize our ability to share an interface between several
logical interface systems:
Due to the current usage of the rx_handler field in net_device, the code suggest that an interface
cannot be part of a bridge and of a macvlan at the same time. Even if bridge provide an hook for
ebtables to ignore an skb and allow other to get it, macvlan cannot be registered on the same lower
interface as a bridge, because rx_handler can only hold a single value.
By giving master a more general meaning, I think we might face a similar problem. It might disallow
an interface to be enslaved to bonding and part of another logical interface at the same time, if
such logical interface also use the master field.
It doesn't mean I don't support the general idea, but I would like to clearly understand the
possible unexpected impact: do we want to stop interfaces to be "enslaved" to several logical
interface at the same time?
> ---
> drivers/infiniband/hw/nes/nes.c | 3 +-
> drivers/infiniband/hw/nes/nes_cm.c | 2 +-
> drivers/net/bonding/bond_main.c | 10 +++---
> drivers/net/cxgb3/cxgb3_offload.c | 3 +-
> include/linux/netdevice.h | 7 +++++
> net/core/dev.c | 49 +++++++++++++++++++++++++++---------
> 6 files changed, 54 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
> index 3b4ec32..3d7f366 100644
> --- a/drivers/infiniband/hw/nes/nes.c
> +++ b/drivers/infiniband/hw/nes/nes.c
> @@ -153,7 +153,8 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
> nesdev, nesdev->netdev[0]->name);
> netdev = nesdev->netdev[0];
> nesvnic = netdev_priv(netdev);
> - is_bonded = (netdev->master == event_netdev);
> + is_bonded = netif_is_bond_slave(netdev)&&
> + (netdev->master == event_netdev);
> if ((netdev == event_netdev) || is_bonded) {
> if (nesvnic->rdma_enabled == 0) {
> nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
> diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
> index 009ec81..ec3aa11 100644
> --- a/drivers/infiniband/hw/nes/nes_cm.c
> +++ b/drivers/infiniband/hw/nes/nes_cm.c
> @@ -1118,7 +1118,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
> return rc;
> }
>
> - if (nesvnic->netdev->master)
> + if (netif_is_bond_slave(netdev))
> netdev = nesvnic->netdev->master;
> else
> netdev = nesvnic->netdev;
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 1df9f0e..9f87787 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1594,9 +1594,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
> }
> }
>
> - res = netdev_set_master(slave_dev, bond_dev);
> + res = netdev_set_bond_master(slave_dev, bond_dev);
> if (res) {
> - pr_debug("Error %d calling netdev_set_master\n", res);
> + pr_debug("Error %d calling netdev_set_bond_master\n", res);
> goto err_restore_mac;
> }
> /* open the slave since the application closed it */
> @@ -1812,7 +1812,7 @@ err_close:
> dev_close(slave_dev);
>
> err_unset_master:
> - netdev_set_master(slave_dev, NULL);
> + netdev_set_bond_master(slave_dev, NULL);
>
> err_restore_mac:
> if (!bond->params.fail_over_mac) {
> @@ -1992,7 +1992,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
> netif_addr_unlock_bh(bond_dev);
> }
>
> - netdev_set_master(slave_dev, NULL);
> + netdev_set_bond_master(slave_dev, NULL);
>
> #ifdef CONFIG_NET_POLL_CONTROLLER
> read_lock_bh(&bond->lock);
> @@ -2114,7 +2114,7 @@ static int bond_release_all(struct net_device *bond_dev)
> netif_addr_unlock_bh(bond_dev);
> }
>
> - netdev_set_master(slave_dev, NULL);
> + netdev_set_bond_master(slave_dev, NULL);
>
> /* close slave before restoring its mac address */
> dev_close(slave_dev);
> diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
> index 7ea94b5..862804f 100644
> --- a/drivers/net/cxgb3/cxgb3_offload.c
> +++ b/drivers/net/cxgb3/cxgb3_offload.c
> @@ -186,9 +186,10 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
> dev = NULL;
> if (grp)
> dev = vlan_group_get_device(grp, vlan);
> - } else
> + } else if (netif_is_bond_slave(dev)) {
> while (dev->master)
> dev = dev->master;
The while() here suggests that nesting bonding is possible. This is not true (even if not enforced
yet). And even if it was true, then you needed to use netif_is_bond_slave(dev) inside the while()
loop, to be consistent.
> + }
> return dev;
> }
> }
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 5a5baea..5a42b10 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -2377,6 +2377,8 @@ extern int netdev_max_backlog;
> extern int netdev_tstamp_prequeue;
> extern int weight_p;
> extern int netdev_set_master(struct net_device *dev, struct net_device *master);
> +extern int netdev_set_bond_master(struct net_device *dev,
> + struct net_device *master);
> extern int skb_checksum_help(struct sk_buff *skb);
> extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features);
> #ifdef CONFIG_BUG
> @@ -2437,6 +2439,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
> dev->gso_max_size = size;
> }
>
> +static inline int netif_is_bond_slave(struct net_device *dev)
> +{
> + return dev->flags& IFF_SLAVE&& dev->priv_flags& IFF_BONDING;
> +}
> +
Does this means you also consider IFF_SLAVE as a "more general" flag now? Wasn't IFF_SLAVE a
sufficient evidence of the interface being enslaved to a bonding interface, before?
> extern struct pernet_operations __net_initdata loopback_net_ops;
>
> static inline int dev_ethtool_get_settings(struct net_device *dev,
> diff --git a/net/core/dev.c b/net/core/dev.c
> index d874fd1..a413276 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -3146,7 +3146,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
> struct packet_type *ptype, *pt_prev;
> rx_handler_func_t *rx_handler;
> struct net_device *orig_dev;
> - struct net_device *master;
> struct net_device *null_or_orig;
> struct net_device *orig_or_bond;
> int ret = NET_RX_DROP;
> @@ -3173,15 +3172,19 @@ static int __netif_receive_skb(struct sk_buff *skb)
> */
> null_or_orig = NULL;
> orig_dev = skb->dev;
> - master = ACCESS_ONCE(orig_dev->master);
> if (skb->deliver_no_wcard)
> null_or_orig = orig_dev;
> - else if (master) {
> - if (__skb_bond_should_drop(skb, master)) {
> - skb->deliver_no_wcard = 1;
> - null_or_orig = orig_dev; /* deliver only exact match */
> - } else
> - skb->dev = master;
> + else if (netif_is_bond_slave(orig_dev)) {
> + struct net_device *bond_master = ACCESS_ONCE(orig_dev->master);
> +
> + if (likely(bond_master)) {
> + if (__skb_bond_should_drop(skb, bond_master)) {
> + skb->deliver_no_wcard = 1;
> + /* deliver only exact match */
> + null_or_orig = orig_dev;
> + } else
> + skb->dev = bond_master;
> + }
I think we need an "else" here. If orig_dev->master is NULL, while netif_is_bond_slave(orig_dev) is
TRUE, we apparently face an unexpected situation and we should at least issue a warning.
> }
>
> __this_cpu_inc(softnet_data.processed);
> @@ -4346,15 +4349,14 @@ static int __init dev_proc_init(void)
>
>
> /**
> - * netdev_set_master - set up master/slave pair
> + * netdev_set_master - set up master pointer
> * @slave: slave device
> * @master: new master device
> *
> * Changes the master device of the slave. Pass %NULL to break the
> * bonding. The caller must hold the RTNL semaphore. On a failure
> * a negative errno code is returned. On success the reference counts
> - * are adjusted, %RTM_NEWLINK is sent to the routing socket and the
> - * function returns zero.
> + * are adjusted and the function returns zero.
> */
> int netdev_set_master(struct net_device *slave, struct net_device *master)
> {
> @@ -4374,6 +4376,29 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
> synchronize_net();
> dev_put(old);
> }
> + return 0;
> +}
> +EXPORT_SYMBOL(netdev_set_master);
> +
> +/**
> + * netdev_set_bond_master - set up bonding master/slave pair
> + * @slave: slave device
> + * @master: new master device
> + *
> + * Changes the master device of the slave. Pass %NULL to break the
> + * bonding. The caller must hold the RTNL semaphore. On a failure
> + * a negative errno code is returned. On success %RTM_NEWLINK is sent
> + * to the routing socket and the function returns zero.
> + */
> +int netdev_set_bond_master(struct net_device *slave, struct net_device *master)
> +{
> + int err;
> +
> + ASSERT_RTNL();
> +
> + err = netdev_set_master(slave, master);
> + if (err)
> + return err;
> if (master)
> slave->flags |= IFF_SLAVE;
> else
> @@ -4382,7 +4407,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
> rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE);
> return 0;
> }
> -EXPORT_SYMBOL(netdev_set_master);
> +EXPORT_SYMBOL(netdev_set_bond_master);
>
> static void dev_change_rx_flags(struct net_device *dev, int flags)
> {
^ permalink raw reply
* Re: [PATCH v2 09/13] can: pruss CAN driver.
From: Subhasish Ghosh @ 2011-02-14 8:45 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: Kurt Van Dijck, davinci-linux-open-source, linux-arm-kernel,
m-watkins, nsekhar, sachi, open list:CAN NETWORK DRIVERS,
open list:CAN NETWORK DRIVERS, open list
In-Reply-To: <4D58D854.5090503@grandegger.com>
That is correct, we receive only pre-programmed CAN ids and "all" or "range"
implementation is not there in the PRU firmware.
Will check the sysfs option and update.
--------------------------------------------------
From: "Wolfgang Grandegger" <wg@grandegger.com>
Sent: Monday, February 14, 2011 12:53 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Kurt Van Dijck" <kurt.van.dijck@eia.be>;
<davinci-linux-open-source@linux.davincidsp.com>;
<linux-arm-kernel@lists.infradead.org>; <m-watkins@ti.com>;
<nsekhar@ti.com>; <sachi@mistralsolutions.com>; "open list:CAN NETWORK
DRIVERS" <socketcan-core@lists.berlios.de>; "open list:CAN NETWORK DRIVERS"
<netdev@vger.kernel.org>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
> On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
>> Hello,
>>
>> I had a discussion regarding this with Wolfgang:
>>
>> http://www.mail-archive.com/socketcan-users@lists.berlios.de/msg00324.html
>>
>> The problem here is that we must configure the mailbox ID's and this
>> support is not available in the socketCan sub-system.
>
> To understand you correctly. A mailbox (or message object) can *only*
> receive messages with the pre-programmed CAN id? Isn't there a chance to
> receive all or a range of CAN ids? That's a very unusual piece of
> hardware. Anyway, using kernel configuration parameters to define the
> CAN id's would be the less flexible method. The user will not have a
> chance to change them at run-time. Using SysFS files would already be
> much better.
>
> Wolfgang.
^ permalink raw reply
* Re: [PATCH 02/14] net/fec: release mem_region requested in probe in error path and remove
From: Uwe Kleine-König @ 2011-02-14 8:25 UTC (permalink / raw)
To: David Miller; +Cc: netdev, shawn.guo, kernel
In-Reply-To: <20110213.131531.57465973.davem@davemloft.net>
Hi David,
On Sun, Feb 13, 2011 at 01:15:31PM -0800, David Miller wrote:
> From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Date: Sun, 13 Feb 2011 22:07:09 +0100
> > On Fri, Feb 11, 2011 at 09:25:32PM -0800, David Miller wrote:
> >> I can't pull from that tree because it is _NOT_ based upon net-next-2.6
> >> and therefore brings in all kinds of commits not related to your work.
> > Sorry, I'm not used to the customs on netdev. I can rebase, but still I
> > wonder about the reason you cannot pull for. The only reason I can
> > imagine is that you fear unrelated breakage when taking these patches
> > that are already in Linus' tree. But if it's that, wouldn't it be great
> > the realize this breakage already now and not only during the next merge
> > window?
>
> My trees only merge in Linus's tree when absolutely necessary,
> to resolve conflicts or similar.
You don't merge Linus' tree, you merge mine that just happen to be based
on a newer version of Linus' tree. I'm sure Linus won't yell on you for
that. He only objects to merge directly from his tree, because the
result for him is an "empty" merge.
> We don't bring in unrelated changes into my tree, just for the
> sake of doing so.
>
> Otherwise Linus gets all of these ugly merge commits when he
> pulls from me, which are entirely unnecessary.
The result Linus gets if you pull my tree based on
v2.6.38-rc4-106-gd247852 (as it is now) is the same as if it were based
on v2.6.38-rc2-210-gc69b909 (which is the most recent commit net-next
currently bases on): my 14 patches and your merge commit. The reason for
that is that Linus already has the commits between
v2.6.38-rc2-210-gc69b909 and v2.6.38-rc4-106-gd247852. So this is really
only about when these commits enter *your* tree.
There are currently the following commits in Linus' tree that are used
by commits in net-next as parents:
c56eb8fb6dccb83d9fe62fd4dc00c834de9bc470
ff76015f3bdfbc482c723cb4f2559cef84d178ca (*)
c753796769e4fb0cd813b6e5801b3c01f4681d4f
0c21e3aaf6ae85bee804a325aa29c325209180fd (*)
e92427b289d252cfbd4cb5282d92f4ce1a5bb1fb (*)
1bae4ce27c9c90344f23c65ea6966c50ffeae2f5
7cc2edb83447775a34ed3bf9d29d8295a434b523 (*)
8f2771f2b85aea4d0f9a0137ad3b63d1173c0962 (*)
c4c93106741bbf61ecd05a2a835af8e3bf31c1bd (*)
c7c1806098752c1f46943d8db2c69aff07f5d4bc (*)
479600777bb588724d044815415f7d708d06644b (*)
1e6d93e45b231b3ae87c01902ede2315aacfe976 (*)
9b00b4157f7b3265de291ac8979a5f1611ce64ab
c69b90920a36b88ab0d649963d81355d865eeb05 (*)
and you don't want to take d247852 to this list because it's newer than
all these? How did you decide to take the newest in the list above and
why was that OK?
And as a last point let me note, that from Linus' POV the commits marked
with an asterisk above go into net-next by an empty merge.
Can you please reping me if you still consider that I should rebase my
tree for you to be able to merge it?
Best regards and thanks
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH 1/5] omap: panda: wlan board muxing
From: panduranga @ 2011-02-14 8:01 UTC (permalink / raw)
To: Ohad Ben-Cohen, Mallireddy, Panduranga
Cc: Coelho, Luciano, netdev, linux-omap, linux-mmc, Gabay, Benzy,
Gurumath, Pradeep, Mahaveer, Vishal, Boudet, Xavier, Jain, Naveen,
Savoy, Pavan, Halli, Manjunatha, tony, cjb
In-Reply-To: <AANLkTik4+CRp8B8Ajnpy-_k1m+=MZNe62c2WG8cjaz-D@mail.gmail.com>
Hi Ohad,
I will modify the patch accordingly.
Regards,
Pandu.
----- Original Message -----
From: "Ohad Ben-Cohen" <ohad@wizery.com>
To: "Mallireddy, Panduranga" <panduranga_mallireddy@ti.com>
Cc: "Coelho, Luciano" <coelho@ti.com>; <netdev@vger.kernel.org>;
<linux-omap@vger.kernel.org>; <linux-mmc@vger.kernel.org>; "Gabay, Benzy"
<benzyg@ti.com>; "Gurumath, Pradeep" <pradeepgurumath@ti.com>; "Mahaveer,
Vishal" <vishalm@ti.com>; "Boudet, Xavier" <x-boudet@ti.com>; "Jain, Naveen"
<naveen_jain@ti.com>; "Savoy, Pavan" <pavan_savoy@ti.com>; "Halli,
Manjunatha" <manjunatha_halli@ti.com>; <tony@atomide.com>; <cjb@laptop.org>
Sent: Monday, February 14, 2011 12:54 PM
Subject: Re: [PATCH 1/5] omap: panda: wlan board muxing
Hi Pandu,
On Mon, Feb 14, 2011 at 9:19 AM, <panduranga_mallireddy@ti.com> wrote:
> + /* WLAN IRQ - GPIO 53 */
> + OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP),
Actually we don't need to pull up the IRQ line - it is always held by
the 1271 device, and there's no need for the host to pull it up
(wasting some power while doing it).
We have that on the ZOOM, but that's not necessary, and will be fixed
there, too.
Thanks,
Ohad.
^ permalink raw reply
* [PATCH] net/can/softing: make CAN_SOFTING_CS depend on CAN_SOFTING
From: Kurt Van Dijck @ 2011-02-14 7:55 UTC (permalink / raw)
To: Randy Dunlap; +Cc: akpm, netdev, linux-kernel, davem
In-Reply-To: <4D56AF22.4070803@oracle.com>
The statement 'select CAN_SOFTING' may ignore the dependancies
for CAN_SOFTING while selecting CAN_SOFTING_CS, as is therefore a bad choice.
Signed-off-by: Kurt Van Dijck <kurt.van.dijck@eia.be>
Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
---
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
index 92bd6bd..55dd3e4 100644
--- a/drivers/net/can/softing/Kconfig
+++ b/drivers/net/can/softing/Kconfig
@@ -18,7 +18,7 @@ config CAN_SOFTING
config CAN_SOFTING_CS
tristate "Softing Gmbh CAN pcmcia cards"
depends on PCMCIA
- select CAN_SOFTING
+ depends on CAN_SOFTING
---help---
Support for PCMCIA cards from Softing Gmbh & some cards
from Vector Gmbh.
^ permalink raw reply related
* Re: [PATCH v2 09/13] can: pruss CAN driver.
From: Kurt Van Dijck @ 2011-02-14 7:42 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
Subhasish Ghosh, nsekhar-l0cyMroinI0, open list,
CAN NETWORK DRIVERS, CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <4D58D854.5090503-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
On Mon, Feb 14, 2011 at 08:23:00AM +0100, Wolfgang Grandegger wrote:
> On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
> > Hello,
> >
> > I had a discussion regarding this with Wolfgang:
> >
> > http://www.mail-archive.com/socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org/msg00324.html
> >
> > The problem here is that we must configure the mailbox ID's and this
> > support is not available in the socketCan sub-system.
>
> Using SysFS files would already be much better.
Ack.
Kurt
^ permalink raw reply
* Re: linux-next: Tree for February 10 (netfilter)
From: Patrick McHardy @ 2011-02-14 7:34 UTC (permalink / raw)
To: Randy Dunlap
Cc: Stephen Rothwell, netdev, linux-next, LKML, netfilter-devel,
Thomas Graf
In-Reply-To: <20110210095210.6fcf3011.randy.dunlap@oracle.com>
On 10.02.2011 18:52, Randy Dunlap wrote:
> On Thu, 10 Feb 2011 18:05:25 +1100 Stephen Rothwell wrote:
>
>> Hi all,
>>
>> [The kernel.org mirroring is being slow ...]
>>
>> Changes since 20110209:
>
>
> xt_AUDIT.c:(.text+0x39ca9): undefined reference to `ipv6_skip_exthdr'
>
> IPV6 is not enabled.
>
> Full config file is attached.
Thomas, please have a look at this.
^ permalink raw reply
* Re: [PATCH net-next-2.6 v8 1/1] can: c_can: Added support for Bosch C_CAN controller
From: David Miller @ 2011-02-14 7:26 UTC (permalink / raw)
To: bhupesh.sharma-qxv4g6HH51o
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA, mkl-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <1297666006-8627-1-git-send-email-bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
From: Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
Date: Mon, 14 Feb 2011 12:16:46 +0530
> Bosch C_CAN controller is a full-CAN implementation which is compliant
> to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can be
> obtained from:
> http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
> c_can/users_manual_c_can.pdf
>
> This patch adds the support for this controller.
> The following are the design choices made while writing the controller
> driver:
> 1. Interface Register set IF1 has be used only in the current design.
> 2. Out of the 32 Message objects available, 16 are kept aside for RX
> purposes and the rest for TX purposes.
> 3. NAPI implementation is such that both the TX and RX paths function
> in polling mode.
>
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 1/5] omap: panda: wlan board muxing
From: Ohad Ben-Cohen @ 2011-02-14 7:24 UTC (permalink / raw)
To: panduranga_mallireddy
Cc: coelho, netdev, linux-omap, linux-mmc, benzyg, pradeepgurumath,
vishalm, x-boudet, naveen_jain, pavan_savoy, manjunatha_halli,
tony, cjb
In-Reply-To: <1297667958-22377-2-git-send-email-panduranga_mallireddy@ti.com>
Hi Pandu,
On Mon, Feb 14, 2011 at 9:19 AM, <panduranga_mallireddy@ti.com> wrote:
> + /* WLAN IRQ - GPIO 53 */
> + OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP),
Actually we don't need to pull up the IRQ line - it is always held by
the 1271 device, and there's no need for the host to pull it up
(wasting some power while doing it).
We have that on the ZOOM, but that's not necessary, and will be fixed
there, too.
Thanks,
Ohad.
^ permalink raw reply
* Re: [PATCH v2 09/13] can: pruss CAN driver.
From: Wolfgang Grandegger @ 2011-02-14 7:23 UTC (permalink / raw)
To: Subhasish Ghosh
Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <C1C4300CE90A406FBDA2388D5491FAD5@subhasishg>
On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
> Hello,
>
> I had a discussion regarding this with Wolfgang:
>
> http://www.mail-archive.com/socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org/msg00324.html
>
> The problem here is that we must configure the mailbox ID's and this
> support is not available in the socketCan sub-system.
To understand you correctly. A mailbox (or message object) can *only*
receive messages with the pre-programmed CAN id? Isn't there a chance to
receive all or a range of CAN ids? That's a very unusual piece of
hardware. Anyway, using kernel configuration parameters to define the
CAN id's would be the less flexible method. The user will not have a
chance to change them at run-time. Using SysFS files would already be
much better.
Wolfgang.
^ permalink raw reply
* [PATCH 5/5] OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Kishore Kadiyala,
Panduranga Mallireddy
In-Reply-To: <1297667958-22377-5-git-send-email-panduranga_mallireddy@ti.com>
From: Kishore Kadiyala <kishore.kadiyala@ti.com>
OMAP4 supports up to 5 MMC controllers, but only 3 of these were
initialized. MMC5 is used by wl12xx chip. So initialize MMC4 and MMC5.
Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
arch/arm/mach-omap2/hsmmc.c | 5 +++++
drivers/mmc/host/omap_hsmmc.c | 24 ++++++++++++++++++++----
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 8f1a484..3c0809f 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -348,6 +348,11 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
mmc->slots[0].after_set_reg = NULL;
}
break;
+ case 4:
+ case 5:
+ mmc->slots[0].before_set_reg = NULL;
+ mmc->slots[0].after_set_reg = NULL;
+ break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);
kfree(mmc);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f59f8da..2525071 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -260,7 +260,7 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
return ret;
}
-static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
struct omap_hsmmc_host *host =
@@ -316,6 +316,12 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
return ret;
}
+static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ return 0;
+}
+
static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
int vdd, int cardsleep)
{
@@ -326,7 +332,7 @@ static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
return regulator_set_mode(host->vcc, mode);
}
-static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
+static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
int vdd, int cardsleep)
{
struct omap_hsmmc_host *host =
@@ -365,6 +371,12 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
return regulator_enable(host->vcc_aux);
}
+static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
+ int vdd, int cardsleep)
+{
+ return 0;
+}
+
static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{
struct regulator *reg;
@@ -379,10 +391,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
break;
case OMAP_MMC2_DEVID:
case OMAP_MMC3_DEVID:
+ case OMAP_MMC5_DEVID:
/* Off-chip level shifting, or none */
- mmc_slot(host).set_power = omap_hsmmc_23_set_power;
- mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep;
+ mmc_slot(host).set_power = omap_hsmmc_235_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
break;
+ case OMAP_MMC4_DEVID:
+ mmc_slot(host).set_power = omap_hsmmc_4_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
default:
pr_err("MMC%d configuration not supported!\n", host->id);
return -EINVAL;
--
1.5.6.3
^ permalink raw reply related
* [PATCH 4/5] omap: panda: add mmc5/wl1271 device support
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297667958-22377-4-git-send-email-panduranga_mallireddy@ti.com>
From: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
Add MMC5 support on PANDA, which has the wl1271 device hardwired to.
The wl1271 is a 4-wire, 1.8V, embedded SDIO WLAN device with an
external IRQ line, and power-controlled by a GPIO-based fixed regulator.
Based on the patch for mmc3/wl1271 device support for zoom by Ohad
Ben-Cohen <ohad@wizery.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
arch/arm/mach-omap2/board-omap4panda.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index cd25255..ef43010 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -27,6 +27,7 @@
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -47,6 +48,7 @@
#define GPIO_HUB_POWER 1
#define GPIO_HUB_NRESET 62
#define GPIO_WIFI_PMENA 43
+#define GPIO_WIFI_IRQ 53
static struct gpio_led gpio_leds[] = {
{
@@ -164,6 +166,15 @@ static struct omap2_hsmmc_info mmc[] = {
.gpio_wp = -EINVAL,
.gpio_cd = -EINVAL,
},
+ {
+ .name = "wl1271",
+ .mmc = 5,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .ocr_mask = MMC_VDD_165_195,
+ .nonremovable = true,
+ },
{} /* Terminator */
};
@@ -205,6 +216,12 @@ static struct platform_device omap_vwlan_device = {
},
};
+struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
+ /* PANDA ref clock is 38.4 MHz */
+ .board_ref_clock = 2,
+};
+
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
int ret = 0;
@@ -461,6 +478,9 @@ static void __init omap4_panda_init(void)
package = OMAP_PACKAGE_CBL;
omap4_mux_init(board_mux, package);
+ if (wl12xx_set_platform_data(&omap_panda_wlan_data))
+ pr_err("error setting wl12xx data\n");
+
omap4_panda_i2c_init();
platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
platform_device_register(&omap_vwlan_device);
--
1.5.6.3
^ permalink raw reply related
* [PATCH 3/5] omap: panda: add fixed regulator device for wlan
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297667958-22377-3-git-send-email-panduranga_mallireddy@ti.com>
From: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
Add a fixed regulator vmmc device to enable power control
of the wl1271 wlan device.
Based on the patch for zoom by Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
arch/arm/mach-omap2/board-omap4panda.c | 34 ++++++++++++++++++++++++++++++++
1 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index cc9df6c..cd25255 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -26,6 +26,7 @@
#include <linux/usb/otg.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -45,6 +46,7 @@
#define GPIO_HUB_POWER 1
#define GPIO_HUB_NRESET 62
+#define GPIO_WIFI_PMENA 43
static struct gpio_led gpio_leds[] = {
{
@@ -172,6 +174,37 @@ static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
},
};
+static struct regulator_consumer_supply omap4_panda_vmmc5_supply = {
+ .supply = "vmmc",
+ .dev_name = "mmci-omap-hs.4",
+};
+
+static struct regulator_init_data panda_vmmc5 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap4_panda_vmmc5_supply,
+};
+
+static struct fixed_voltage_config panda_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = GPIO_WIFI_PMENA,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &panda_vmmc5,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &panda_vwlan,
+ },
+};
+
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
int ret = 0;
@@ -430,6 +463,7 @@ static void __init omap4_panda_init(void)
omap4_panda_i2c_init();
platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
+ platform_device_register(&omap_vwlan_device);
omap_serial_init();
omap4_twl6030_hsmmc_init(mmc);
/* OMAP4 Panda uses internal transceiver so register nop transceiver */
--
1.5.6.3
^ permalink raw reply related
* [PATCH 2/5] omap: select REGULATOR_FIXED_VOLTAGE by default for panda and sdp4430
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297667958-22377-2-git-send-email-panduranga_mallireddy@ti.com>
From: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
Power to the wl12xx wlan device is controlled by a fixed regulator.
Boards that have the wl12xx should select REGULATOR_FIXED_VOLTAGE.
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
arch/arm/mach-omap2/Kconfig | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 1a2cf62..eeaeb3b 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -300,6 +300,7 @@ config MACH_OMAP_4430SDP
depends on ARCH_OMAP4
select OMAP_PACKAGE_CBL
select OMAP_PACKAGE_CBS
+ select REGULATOR_FIXED_VOLTAGE
config MACH_OMAP4_PANDA
bool "OMAP4 Panda Board"
@@ -307,6 +308,7 @@ config MACH_OMAP4_PANDA
depends on ARCH_OMAP4
select OMAP_PACKAGE_CBL
select OMAP_PACKAGE_CBS
+ select REGULATOR_FIXED_VOLTAGE
config OMAP3_EMU
bool "OMAP3 debugging peripherals"
--
1.5.6.3
^ permalink raw reply related
* [PATCH 1/5] omap: panda: wlan board muxing
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
In-Reply-To: <1297667958-22377-1-git-send-email-panduranga_mallireddy@ti.com>
From: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
Add board muxing to support the wlan wl1271 chip that is
hardwired to mmc5 (fifth mmc controller) on the PANDA.
Based on the wlan board muxing for zoom3 by Ohad Ben-Cohen
<ohadb@ti.com>
Signed-off-by: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
---
arch/arm/mach-omap2/board-omap4panda.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 9218862..cc9df6c 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -401,6 +401,19 @@ static int __init omap4_panda_i2c_init(void)
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ /* WLAN IRQ - GPIO 53 */
+ OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN POWER ENABLE - GPIO 43 */
+ OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* WLAN SDIO: MMC5 CMD */
+ OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 CLK */
+ OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 DAT[0-3] */
+ OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#else
--
1.5.6.3
^ permalink raw reply related
* [PATCH 0/5] Panda: Support for WLAN on WL127x
From: panduranga_mallireddy @ 2011-02-14 7:19 UTC (permalink / raw)
To: coelho, netdev, linux-omap, linux-mmc
Cc: ohad, benzyg, pradeepgurumath, vishalm, x-boudet, naveen_jain,
pavan_savoy, manjunatha_halli, tony, cjb, Panduranga Mallireddy
From: Panduranga Mallireddy <panduranga_mallireddy@ti.com>
Adding support for WLAN on Panda board using wl12xx and mac80211 drivers
Patches were tested on Panda board.
These patches add software control for emulating card detect events,
add board configurations to support the wl127x device.
These patches are dependent on the patches that enable clock for WLAN on panda.
Please refer the following links for these patches:
https://patchwork.kernel.org/patch/546381/
https://patchwork.kernel.org/patch/546401/
[PATCH 5/5] OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms
is dependent on hwmod adpotation for HSMMC patches series.
For original patches of adpotation for HSMMC refer:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg43464.html
Patches are based on mainline 2.6.38-rc3
Kishore Kadiyala (1):
OMAP: hsmmc: Enable MMC4 and MMC5 on OMAP4 platforms
Panduranga Mallireddy (4):
omap: panda: wlan board muxing
omap: select REGULATOR_FIXED_VOLTAGE by default for panda and sdp4430
omap: panda: add fixed regulator device for wlan
omap: panda: add mmc5/wl1271 device support
arch/arm/mach-omap2/Kconfig | 2 +
arch/arm/mach-omap2/board-omap4panda.c | 67 ++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/hsmmc.c | 5 ++
drivers/mmc/host/omap_hsmmc.c | 24 +++++++++--
4 files changed, 94 insertions(+), 4 deletions(-)
^ permalink raw reply
* [PATCH net-next-2.6 v8 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Bhupesh Sharma @ 2011-02-14 6:46 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w, mkl-bIcnvbaLZ9MEGnE8C9+IrQ
Bosch C_CAN controller is a full-CAN implementation which is compliant
to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can be
obtained from:
http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
c_can/users_manual_c_can.pdf
This patch adds the support for this controller.
The following are the design choices made while writing the controller
driver:
1. Interface Register set IF1 has be used only in the current design.
2. Out of the 32 Message objects available, 16 are kept aside for RX
purposes and the rest for TX purposes.
3. NAPI implementation is such that both the TX and RX paths function
in polling mode.
Signed-off-by: Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
---
Changes since V7:
1. Added protection against CONFIG_HAVE_CLK macro for clk_* routines to allow
compilation on x86 platforms as well.
drivers/net/can/Kconfig | 2 +
drivers/net/can/Makefile | 1 +
drivers/net/can/c_can/Kconfig | 15 +
drivers/net/can/c_can/Makefile | 8 +
drivers/net/can/c_can/c_can.c | 1158 ++++++++++++++++++++++++++++++++
drivers/net/can/c_can/c_can.h | 86 +++
drivers/net/can/c_can/c_can_platform.c | 215 ++++++
7 files changed, 1485 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/c_can/Kconfig
create mode 100644 drivers/net/can/c_can/Makefile
create mode 100644 drivers/net/can/c_can/c_can.c
create mode 100644 drivers/net/can/c_can/c_can.h
create mode 100644 drivers/net/can/c_can/c_can_platform.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 5dec456..1d699e3 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -115,6 +115,8 @@ source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
+source "drivers/net/can/c_can/Kconfig"
+
source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 53c82a7..24ebfe8 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -13,6 +13,7 @@ obj-y += softing/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_MSCAN) += mscan/
+obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
new file mode 100644
index 0000000..ffb9773
--- /dev/null
+++ b/drivers/net/can/c_can/Kconfig
@@ -0,0 +1,15 @@
+menuconfig CAN_C_CAN
+ tristate "Bosch C_CAN devices"
+ depends on CAN_DEV && HAS_IOMEM
+
+if CAN_C_CAN
+
+config CAN_C_CAN_PLATFORM
+ tristate "Generic Platform Bus based C_CAN driver"
+ ---help---
+ This driver adds support for the C_CAN chips connected to
+ the "platform bus" (Linux abstraction for directly to the
+ processor attached devices) which can be found on various
+ boards from ST Microelectronics (http://www.st.com)
+ like the SPEAr1310 and SPEAr320 evaluation boards.
+endif
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
new file mode 100644
index 0000000..9273f6d
--- /dev/null
+++ b/drivers/net/can/c_can/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Bosch C_CAN controller drivers.
+#
+
+obj-$(CONFIG_CAN_C_CAN) += c_can.o
+obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
new file mode 100644
index 0000000..1405078
--- /dev/null
+++ b/drivers/net/can/c_can/c_can.c
@@ -0,0 +1,1158 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
+ *
+ * TX and RX NAPI implementation has been borrowed from at91 CAN driver
+ * written by:
+ * Copyright
+ * (C) 2007 by Hans J. Koch <hjk-vqZO0P4V72/QD6PfKP4TzA@public.gmane.org>
+ * (C) 2008, 2009 by Marc Kleine-Budde <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "c_can.h"
+
+/* control register */
+#define CONTROL_TEST BIT(7)
+#define CONTROL_CCE BIT(6)
+#define CONTROL_DISABLE_AR BIT(5)
+#define CONTROL_ENABLE_AR (0 << 5)
+#define CONTROL_EIE BIT(3)
+#define CONTROL_SIE BIT(2)
+#define CONTROL_IE BIT(1)
+#define CONTROL_INIT BIT(0)
+
+/* test register */
+#define TEST_RX BIT(7)
+#define TEST_TX1 BIT(6)
+#define TEST_TX2 BIT(5)
+#define TEST_LBACK BIT(4)
+#define TEST_SILENT BIT(3)
+#define TEST_BASIC BIT(2)
+
+/* status register */
+#define STATUS_BOFF BIT(7)
+#define STATUS_EWARN BIT(6)
+#define STATUS_EPASS BIT(5)
+#define STATUS_RXOK BIT(4)
+#define STATUS_TXOK BIT(3)
+
+/* error counter register */
+#define ERR_CNT_TEC_MASK 0xff
+#define ERR_CNT_TEC_SHIFT 0
+#define ERR_CNT_REC_SHIFT 8
+#define ERR_CNT_REC_MASK (0x7f << ERR_CNT_REC_SHIFT)
+#define ERR_CNT_RP_SHIFT 15
+#define ERR_CNT_RP_MASK (0x1 << ERR_CNT_RP_SHIFT)
+
+/* bit-timing register */
+#define BTR_BRP_MASK 0x3f
+#define BTR_BRP_SHIFT 0
+#define BTR_SJW_SHIFT 6
+#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT)
+#define BTR_TSEG1_SHIFT 8
+#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT 12
+#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
+
+/* brp extension register */
+#define BRP_EXT_BRPE_MASK 0x0f
+#define BRP_EXT_BRPE_SHIFT 0
+
+/* IFx command request */
+#define IF_COMR_BUSY BIT(15)
+
+/* IFx command mask */
+#define IF_COMM_WR BIT(7)
+#define IF_COMM_MASK BIT(6)
+#define IF_COMM_ARB BIT(5)
+#define IF_COMM_CONTROL BIT(4)
+#define IF_COMM_CLR_INT_PND BIT(3)
+#define IF_COMM_TXRQST BIT(2)
+#define IF_COMM_DATAA BIT(1)
+#define IF_COMM_DATAB BIT(0)
+#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
+ IF_COMM_CONTROL | IF_COMM_TXRQST | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* IFx arbitration */
+#define IF_ARB_MSGVAL BIT(15)
+#define IF_ARB_MSGXTD BIT(14)
+#define IF_ARB_TRANSMIT BIT(13)
+
+/* IFx message control */
+#define IF_MCONT_NEWDAT BIT(15)
+#define IF_MCONT_MSGLST BIT(14)
+#define IF_MCONT_CLR_MSGLST (0 << 14)
+#define IF_MCONT_INTPND BIT(13)
+#define IF_MCONT_UMASK BIT(12)
+#define IF_MCONT_TXIE BIT(11)
+#define IF_MCONT_RXIE BIT(10)
+#define IF_MCONT_RMTEN BIT(9)
+#define IF_MCONT_TXRQST BIT(8)
+#define IF_MCONT_EOB BIT(7)
+#define IF_MCONT_DLC_MASK 0xf
+
+/*
+ * IFx register masks:
+ * allow easy operation on 16-bit registers when the
+ * argument is 32-bit instead
+ */
+#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
+#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
+
+/* message object split */
+#define C_CAN_NO_OF_OBJECTS 32
+#define C_CAN_MSG_OBJ_RX_NUM 16
+#define C_CAN_MSG_OBJ_TX_NUM 16
+
+#define C_CAN_MSG_OBJ_RX_FIRST 1
+#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
+ C_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
+#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
+ C_CAN_MSG_OBJ_TX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_RX_SPLIT 9
+#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
+#define RECEIVE_OBJECT_BITS 0x0000ffff
+
+/* status interrupt */
+#define STATUS_INTERRUPT 0x8000
+
+/* global interrupt masks */
+#define ENABLE_ALL_INTERRUPTS 1
+#define DISABLE_ALL_INTERRUPTS 0
+
+/* minimum timeout for checking BUSY status */
+#define MIN_TIMEOUT_VALUE 6
+
+/* napi related */
+#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
+
+/* c_can lec values */
+enum c_can_lec_type {
+ LEC_NO_ERROR = 0,
+ LEC_STUFF_ERROR,
+ LEC_FORM_ERROR,
+ LEC_ACK_ERROR,
+ LEC_BIT1_ERROR,
+ LEC_BIT0_ERROR,
+ LEC_CRC_ERROR,
+ LEC_UNUSED,
+};
+
+/*
+ * c_can error types:
+ * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
+ */
+enum c_can_bus_error_types {
+ C_CAN_NO_ERROR = 0,
+ C_CAN_BUS_OFF,
+ C_CAN_ERROR_WARNING,
+ C_CAN_ERROR_PASSIVE,
+};
+
+static struct can_bittiming_const c_can_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/
+ .brp_inc = 1,
+};
+
+static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static u32 c_can_read_reg32(struct c_can_priv *priv, void *reg)
+{
+ u32 val = priv->read_reg(priv, reg);
+ val |= ((u32) priv->read_reg(priv, reg + 2)) << 16;
+ return val;
+}
+
+static void c_can_enable_all_interrupts(struct c_can_priv *priv,
+ int enable)
+{
+ unsigned int cntrl_save = priv->read_reg(priv,
+ &priv->regs->control);
+
+ if (enable)
+ cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
+ else
+ cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+
+ priv->write_reg(priv, &priv->regs->control, cntrl_save);
+}
+
+static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
+{
+ int count = MIN_TIMEOUT_VALUE;
+
+ while (count && priv->read_reg(priv,
+ &priv->regs->ifregs[iface].com_req) &
+ IF_COMR_BUSY) {
+ count--;
+ udelay(1);
+ }
+
+ if (!count)
+ return 1;
+
+ return 0;
+}
+
+static inline void c_can_object_get(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask,
+ IFX_WRITE_LOW_16BIT(mask));
+ priv->write_reg(priv, &priv->regs->ifregs[iface].com_req,
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object get\n");
+}
+
+static inline void c_can_object_put(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask,
+ (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
+ priv->write_reg(priv, &priv->regs->ifregs[iface].com_req,
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object put\n");
+}
+
+static void c_can_write_msg_object(struct net_device *dev,
+ int iface, struct can_frame *frame, int objno)
+{
+ int i;
+ u16 flags = 0;
+ unsigned int id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(frame->can_id & CAN_RTR_FLAG))
+ flags |= IF_ARB_TRANSMIT;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ id = frame->can_id & CAN_EFF_MASK;
+ flags |= IF_ARB_MSGXTD;
+ } else
+ id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+ flags |= IF_ARB_MSGVAL;
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb1,
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, flags |
+ IFX_WRITE_HIGH_16BIT(id));
+
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ priv->write_reg(priv, &priv->regs->ifregs[iface].data[i / 2],
+ frame->data[i] | (frame->data[i + 1] << 8));
+ }
+
+ /* enable interrupt for this message object */
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+ IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
+ frame->can_dlc);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL);
+}
+
+static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+ ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+
+}
+
+static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
+ int iface,
+ int ctrl_mask)
+{
+ int i;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
+ }
+}
+
+static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+}
+
+static void c_can_handle_lost_msg_obj(struct net_device *dev,
+ int iface, int objno)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ netdev_err(dev, "msg lost in buffer %d\n", objno);
+
+ c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl,
+ IF_MCONT_CLR_MSGLST);
+
+ c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
+
+ /* create an error msg */
+ skb = alloc_can_err_skb(dev, &frame);
+ if (unlikely(!skb))
+ return;
+
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_errors++;
+ stats->rx_over_errors++;
+
+ netif_receive_skb(skb);
+}
+
+static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
+{
+ u16 flags, data;
+ int i;
+ unsigned int val;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_skb(dev, &frame);
+ if (!skb) {
+ stats->rx_dropped++;
+ return -ENOMEM;
+ }
+
+ frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+
+ flags = priv->read_reg(priv, &priv->regs->ifregs[iface].arb2);
+ val = priv->read_reg(priv, &priv->regs->ifregs[iface].arb1) |
+ (flags << 16);
+
+ if (flags & IF_ARB_MSGXTD)
+ frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ frame->can_id = (val >> 18) & CAN_SFF_MASK;
+
+ if (flags & IF_ARB_TRANSMIT)
+ frame->can_id |= CAN_RTR_FLAG;
+ else {
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ data = priv->read_reg(priv,
+ &priv->regs->ifregs[iface].data[i / 2]);
+ frame->data[i] = data;
+ frame->data[i + 1] = data >> 8;
+ }
+ }
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += frame->can_dlc;
+
+ return 0;
+}
+
+static void c_can_setup_receive_object(struct net_device *dev, int iface,
+ int objno, unsigned int mask,
+ unsigned int id, unsigned int mcont)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].mask1,
+ IFX_WRITE_LOW_16BIT(mask));
+ priv->write_reg(priv, &priv->regs->ifregs[iface].mask2,
+ IFX_WRITE_HIGH_16BIT(mask));
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb1,
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb2,
+ (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, mcont);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, &priv->regs->msgval1));
+}
+
+static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0);
+ priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0);
+ priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0);
+
+ c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, &priv->regs->msgval1));
+}
+
+static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno)
+{
+ int val = c_can_read_reg32(priv, &priv->regs->txrqst1);
+
+ /*
+ * as transmission request register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (objno - 1)))
+ return 1;
+
+ return 0;
+}
+
+static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ u32 msg_obj_no;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct can_frame *frame = (struct can_frame *)skb->data;
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ msg_obj_no = get_tx_next_msg_obj(priv);
+
+ /* prepare message object for transmission */
+ c_can_write_msg_object(dev, 0, frame, msg_obj_no);
+ can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+
+ /*
+ * we have to stop the queue in case of a wrap around or
+ * if the next TX message object is still in use
+ */
+ priv->tx_next++;
+ if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
+ (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+ netif_stop_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static int c_can_set_bittiming(struct net_device *dev)
+{
+ unsigned int reg_btr, reg_brpe, ctrl_save;
+ u8 brp, brpe, sjw, tseg1, tseg2;
+ u32 ten_bit_brp;
+ struct c_can_priv *priv = netdev_priv(dev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+
+ /* c_can provides a 6-bit brp and 4-bit brpe fields */
+ ten_bit_brp = bt->brp - 1;
+ brp = ten_bit_brp & BTR_BRP_MASK;
+ brpe = ten_bit_brp >> 6;
+
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
+ (tseg2 << BTR_TSEG2_SHIFT);
+ reg_brpe = brpe & BRP_EXT_BRPE_MASK;
+
+ netdev_info(dev,
+ "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
+
+ ctrl_save = priv->read_reg(priv, &priv->regs->control);
+ priv->write_reg(priv, &priv->regs->control,
+ ctrl_save | CONTROL_CCE | CONTROL_INIT);
+ priv->write_reg(priv, &priv->regs->btr, reg_btr);
+ priv->write_reg(priv, &priv->regs->brp_ext, reg_brpe);
+ priv->write_reg(priv, &priv->regs->control, ctrl_save);
+
+ return 0;
+}
+
+/*
+ * Configure C_CAN message objects for Tx and Rx purposes:
+ * C_CAN provides a total of 32 message objects that can be configured
+ * either for Tx or Rx purposes. Here the first 16 message objects are used as
+ * a reception FIFO. The end of reception FIFO is signified by the EoB bit
+ * being SET. The remaining 16 message objects are kept aside for Tx purposes.
+ * See user guide document for further details on configuring message
+ * objects.
+ */
+static void c_can_configure_msg_objects(struct net_device *dev)
+{
+ int i;
+
+ /* first invalidate all message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
+ c_can_inval_msg_object(dev, 0, i);
+
+ /* setup receive message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
+ c_can_setup_receive_object(dev, 0, i, 0, 0,
+ (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+
+ c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+}
+
+/*
+ * Configure C_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static void c_can_chip_config(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ /* disable automatic retransmission */
+ priv->write_reg(priv, &priv->regs->control,
+ CONTROL_DISABLE_AR);
+ else
+ /* enable automatic retransmission */
+ priv->write_reg(priv, &priv->regs->control,
+ CONTROL_ENABLE_AR);
+
+ if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY &
+ CAN_CTRLMODE_LOOPBACK)) {
+ /* loopback + silent mode : useful for hot self-test */
+ priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, &priv->regs->test,
+ TEST_LBACK | TEST_SILENT);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ /* loopback mode : useful for self-test function */
+ priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, &priv->regs->test, TEST_LBACK);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ /* silent mode : bus-monitoring mode */
+ priv->write_reg(priv, &priv->regs->control, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, &priv->regs->test, TEST_SILENT);
+ } else
+ /* normal mode*/
+ priv->write_reg(priv, &priv->regs->control,
+ CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
+
+ /* configure message objects */
+ c_can_configure_msg_objects(dev);
+
+ /* set a `lec` value so that we can check for updates later */
+ priv->write_reg(priv, &priv->regs->status, LEC_UNUSED);
+
+ /* set bittiming params */
+ c_can_set_bittiming(dev);
+}
+
+static void c_can_start(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* enable status change, error and module interrupts */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+
+ /* basic c_can configuration */
+ c_can_chip_config(dev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* reset tx helper pointers */
+ priv->tx_next = priv->tx_echo = 0;
+}
+
+static void c_can_stop(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ /* set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ c_can_start(dev);
+ netif_wake_queue(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int c_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ unsigned int reg_err_counter;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
+ bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
+ ERR_CNT_REC_SHIFT;
+ bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
+
+ return 0;
+}
+
+/*
+ * theory of operation:
+ *
+ * priv->tx_echo holds the number of the oldest can_frame put for
+ * transmission into the hardware, but not yet ACKed by the CAN tx
+ * complete IRQ.
+ *
+ * We iterate from priv->tx_echo to priv->tx_next and check if the
+ * packet has been transmitted, echo it back to the CAN framework.
+ * If we discover a not yet transmitted package, stop looking for more.
+ */
+static void c_can_do_tx(struct net_device *dev)
+{
+ u32 val;
+ u32 msg_obj_no;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+
+ for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+ msg_obj_no = get_tx_echo_msg_obj(priv);
+ c_can_inval_msg_object(dev, 0, msg_obj_no);
+ val = c_can_read_reg32(priv, &priv->regs->txrqst1);
+ if (!(val & (1 << msg_obj_no))) {
+ can_get_echo_skb(dev,
+ msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+ stats->tx_bytes += priv->read_reg(priv,
+ &priv->regs->ifregs[0].msg_cntrl)
+ & IF_MCONT_DLC_MASK;
+ stats->tx_packets++;
+ }
+ }
+
+ /* restart queue if wrap-up or if queue stalled on last pkt */
+ if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
+ ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
+ netif_wake_queue(dev);
+}
+
+/*
+ * theory of operation:
+ *
+ * c_can core saves a received CAN message into the first free message
+ * object it finds free (starting with the lowest). Bits NEWDAT and
+ * INTPND are set for this message object indicating that a new message
+ * has arrived. To work-around this issue, we keep two groups of message
+ * objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
+ *
+ * To ensure in-order frame reception we use the following
+ * approach while re-activating a message object to receive further
+ * frames:
+ * - if the current message object number is lower than
+ * C_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
+ * the INTPND bit.
+ * - if the current message object number is equal to
+ * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
+ * receive message objects.
+ * - if the current message object number is greater than
+ * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
+ * only this message object.
+ */
+static int c_can_do_rx_poll(struct net_device *dev, int quota)
+{
+ u32 num_rx_pkts = 0;
+ unsigned int msg_obj, msg_ctrl_save;
+ struct c_can_priv *priv = netdev_priv(dev);
+ u32 val = c_can_read_reg32(priv, &priv->regs->intpnd1);
+
+ for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
+ msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
+ val = c_can_read_reg32(priv, &priv->regs->intpnd1),
+ msg_obj++) {
+ /*
+ * as interrupt pending register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (msg_obj - 1))) {
+ c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
+ ~IF_COMM_TXRQST);
+ msg_ctrl_save = priv->read_reg(priv,
+ &priv->regs->ifregs[0].msg_cntrl);
+
+ if (msg_ctrl_save & IF_MCONT_EOB)
+ return num_rx_pkts;
+
+ if (msg_ctrl_save & IF_MCONT_MSGLST) {
+ c_can_handle_lost_msg_obj(dev, 0, msg_obj);
+ num_rx_pkts++;
+ quota--;
+ continue;
+ }
+
+ if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ c_can_read_msg_object(dev, 0, msg_ctrl_save);
+
+ if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
+ c_can_mark_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
+ /* activate this msg obj */
+ c_can_activate_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
+ /* activate all lower message objects */
+ c_can_activate_all_lower_rx_msg_obj(dev,
+ 0, msg_ctrl_save);
+
+ num_rx_pkts++;
+ quota--;
+ }
+ }
+
+ return num_rx_pkts;
+}
+
+static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
+{
+ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+ (priv->current_status & LEC_UNUSED);
+}
+
+static int c_can_handle_state_change(struct net_device *dev,
+ enum c_can_bus_error_types error_type)
+{
+ unsigned int reg_err_counter;
+ unsigned int rx_err_passive;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct can_berr_counter bec;
+
+ /* propogate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ c_can_get_berr_counter(dev, &bec);
+ reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
+ rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
+ ERR_CNT_RP_SHIFT;
+
+ switch (error_type) {
+ case C_CAN_ERROR_WARNING:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+
+ break;
+ case C_CAN_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (rx_err_passive)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case C_CAN_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ /*
+ * disable all interrupts in bus-off mode to ensure that
+ * the CPU is not hogged down
+ */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_handle_bus_err(struct net_device *dev,
+ enum c_can_lec_type lec_type)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /*
+ * early exit if no lec update or no error.
+ * no lec update means that no CAN bus event has been detected
+ * since CPU wrote 0x7 value to status reg.
+ */
+ if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
+ return 0;
+
+ /* propogate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ /*
+ * check for 'last error code' which tells us the
+ * type of the last error to occur on the CAN bus
+ */
+
+ /* common for all type of bus errors */
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+ switch (lec_type) {
+ case LEC_STUFF_ERROR:
+ netdev_dbg(dev, "stuff error\n");
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case LEC_FORM_ERROR:
+ netdev_dbg(dev, "form error\n");
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case LEC_ACK_ERROR:
+ netdev_dbg(dev, "ack error\n");
+ cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
+ CAN_ERR_PROT_LOC_ACK_DEL);
+ break;
+ case LEC_BIT1_ERROR:
+ netdev_dbg(dev, "bit1 error\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ break;
+ case LEC_BIT0_ERROR:
+ netdev_dbg(dev, "bit0 error\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ break;
+ case LEC_CRC_ERROR:
+ netdev_dbg(dev, "CRC error\n");
+ cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL);
+ break;
+ default:
+ break;
+ }
+
+ /* set a `lec` value so that we can check for updates later */
+ priv->write_reg(priv, &priv->regs->status, LEC_UNUSED);
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_poll(struct napi_struct *napi, int quota)
+{
+ u16 irqstatus;
+ int lec_type = 0;
+ int work_done = 0;
+ struct net_device *dev = napi->dev;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
+ if (!irqstatus)
+ goto end;
+
+ /* status events have the highest priority */
+ if (irqstatus == STATUS_INTERRUPT) {
+ priv->current_status = priv->read_reg(priv,
+ &priv->regs->status);
+
+ /* handle Tx/Rx events */
+ if (priv->current_status & STATUS_TXOK)
+ priv->write_reg(priv, &priv->regs->status,
+ priv->current_status & ~STATUS_TXOK);
+
+ if (priv->current_status & STATUS_RXOK)
+ priv->write_reg(priv, &priv->regs->status,
+ priv->current_status & ~STATUS_RXOK);
+
+ /* handle state changes */
+ if ((priv->current_status & STATUS_EWARN) &&
+ (!(priv->last_status & STATUS_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_WARNING);
+ }
+ if ((priv->current_status & STATUS_EPASS) &&
+ (!(priv->last_status & STATUS_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_PASSIVE);
+ }
+ if ((priv->current_status & STATUS_BOFF) &&
+ (!(priv->last_status & STATUS_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_BUS_OFF);
+ }
+
+ /* handle bus recovery events */
+ if ((!(priv->current_status & STATUS_BOFF)) &&
+ (priv->last_status & STATUS_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(priv->current_status & STATUS_EPASS)) &&
+ (priv->last_status & STATUS_EPASS)) {
+ netdev_dbg(dev, "left error passive state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ priv->last_status = priv->current_status;
+
+ /* handle lec errors on the bus */
+ lec_type = c_can_has_and_handle_berr(priv);
+ if (lec_type)
+ work_done += c_can_handle_bus_err(dev, lec_type);
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
+ /* handle events corresponding to receive message objects */
+ work_done += c_can_do_rx_poll(dev, (quota - work_done));
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
+ /* handle events corresponding to transmit message objects */
+ c_can_do_tx(dev);
+ }
+
+end:
+ if (work_done < quota) {
+ napi_complete(napi);
+ /* enable all IRQs */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t c_can_isr(int irq, void *dev_id)
+{
+ u16 irqstatus;
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
+ if (!irqstatus)
+ return IRQ_NONE;
+
+ /* disable all interrupts and schedule the NAPI */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int c_can_open(struct net_device *dev)
+{
+ int err;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* open the can device */
+ err = open_candev(dev);
+ if (err) {
+ netdev_err(dev, "failed to open can device\n");
+ return err;
+ }
+
+ /* register interrupt handler */
+ err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
+ dev);
+ if (err < 0) {
+ netdev_err(dev, "failed to request interrupt\n");
+ goto exit_irq_fail;
+ }
+
+ /* start the c_can controller */
+ c_can_start(dev);
+
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+
+ return 0;
+
+exit_irq_fail:
+ close_candev(dev);
+ return err;
+}
+
+static int c_can_close(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ c_can_stop(dev);
+ free_irq(dev->irq, dev);
+ close_candev(dev);
+
+ return 0;
+}
+
+struct net_device *alloc_c_can_dev(void)
+{
+ struct net_device *dev;
+ struct c_can_priv *priv;
+
+ dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
+ if (!dev)
+ return NULL;
+
+ priv = netdev_priv(dev);
+ netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
+
+ priv->dev = dev;
+ priv->can.bittiming_const = &c_can_bittiming_const;
+ priv->can.do_set_mode = c_can_set_mode;
+ priv->can.do_get_berr_counter = c_can_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT |
+ CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_BERR_REPORTING;
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_c_can_dev);
+
+void free_c_can_dev(struct net_device *dev)
+{
+ free_candev(dev);
+}
+EXPORT_SYMBOL_GPL(free_c_can_dev);
+
+static const struct net_device_ops c_can_netdev_ops = {
+ .ndo_open = c_can_open,
+ .ndo_stop = c_can_close,
+ .ndo_start_xmit = c_can_start_xmit,
+};
+
+int register_c_can_dev(struct net_device *dev)
+{
+ dev->flags |= IFF_ECHO; /* we support local echo */
+ dev->netdev_ops = &c_can_netdev_ops;
+
+ return register_candev(dev);
+}
+EXPORT_SYMBOL_GPL(register_c_can_dev);
+
+void unregister_c_can_dev(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ unregister_candev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_c_can_dev);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
new file mode 100644
index 0000000..9b7fbef
--- /dev/null
+++ b/drivers/net/can/c_can/c_can.h
@@ -0,0 +1,86 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef C_CAN_H
+#define C_CAN_H
+
+/* c_can IF registers */
+struct c_can_if_regs {
+ u16 com_req;
+ u16 com_mask;
+ u16 mask1;
+ u16 mask2;
+ u16 arb1;
+ u16 arb2;
+ u16 msg_cntrl;
+ u16 data[4];
+ u16 _reserved[13];
+};
+
+/* c_can hardware registers */
+struct c_can_regs {
+ u16 control;
+ u16 status;
+ u16 err_cnt;
+ u16 btr;
+ u16 interrupt;
+ u16 test;
+ u16 brp_ext;
+ u16 _reserved1;
+ struct c_can_if_regs ifregs[2]; /* [0] = IF1 and [1] = IF2 */
+ u16 _reserved2[8];
+ u16 txrqst1;
+ u16 txrqst2;
+ u16 _reserved3[6];
+ u16 newdat1;
+ u16 newdat2;
+ u16 _reserved4[6];
+ u16 intpnd1;
+ u16 intpnd2;
+ u16 _reserved5[6];
+ u16 msgval1;
+ u16 msgval2;
+ u16 _reserved6[6];
+};
+
+/* c_can private data structure */
+struct c_can_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *dev;
+ int tx_object;
+ int current_status;
+ int last_status;
+ u16 (*read_reg) (struct c_can_priv *priv, void *reg);
+ void (*write_reg) (struct c_can_priv *priv, void *reg, u16 val);
+ struct c_can_regs __iomem *regs;
+ unsigned long irq_flags; /* for request_irq() */
+ unsigned int tx_next;
+ unsigned int tx_echo;
+ void *priv; /* for board-specific data */
+};
+
+struct net_device *alloc_c_can_dev(void);
+void free_c_can_dev(struct net_device *dev);
+int register_c_can_dev(struct net_device *dev);
+void unregister_c_can_dev(struct net_device *dev);
+
+#endif /* C_CAN_H */
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
new file mode 100644
index 0000000..e629b96
--- /dev/null
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -0,0 +1,215 @@
+/*
+ * Platform CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+ void *reg)
+{
+ return readw(reg);
+}
+
+static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+ void *reg, u16 val)
+{
+ writew(val, reg);
+}
+
+static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+ void *reg)
+{
+ return readw(reg + (long)reg - (long)priv->regs);
+}
+
+static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+ void *reg, u16 val)
+{
+ writew(val, reg + (long)reg - (long)priv->regs);
+}
+
+static int __devinit c_can_plat_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *addr;
+ struct net_device *dev;
+ struct c_can_priv *priv;
+ struct resource *mem, *irq;
+#ifdef CONFIG_HAVE_CLK
+ struct clk *clk;
+
+ /* get the appropriate clk */
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ ret = -ENODEV;
+ goto exit;
+ }
+#endif
+
+ /* get the platform data */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mem || (irq <= 0)) {
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ if (!request_mem_region(mem->start, resource_size(mem),
+ KBUILD_MODNAME)) {
+ dev_err(&pdev->dev, "resource unavailable\n");
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ addr = ioremap(mem->start, resource_size(mem));
+ if (!addr) {
+ dev_err(&pdev->dev, "failed to map can port\n");
+ ret = -ENOMEM;
+ goto exit_release_mem;
+ }
+
+ /* allocate the c_can device */
+ dev = alloc_c_can_dev();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto exit_iounmap;
+ }
+
+ priv = netdev_priv(dev);
+
+ dev->irq = irq->start;
+ priv->regs = addr;
+#ifdef CONFIG_HAVE_CLK
+ priv->can.clock.freq = clk_get_rate(clk);
+ priv->priv = clk;
+#endif
+
+ switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ case IORESOURCE_MEM_32BIT:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+ break;
+ case IORESOURCE_MEM_16BIT:
+ default:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+ break;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ ret = register_c_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto exit_free_device;
+ }
+
+ dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+ KBUILD_MODNAME, priv->regs, dev->irq);
+ return 0;
+
+exit_free_device:
+ platform_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+exit_iounmap:
+ iounmap(addr);
+exit_release_mem:
+ release_mem_region(mem->start, resource_size(mem));
+exit_free_clk:
+#ifdef CONFIG_HAVE_CLK
+ clk_put(clk);
+exit:
+#endif
+ dev_err(&pdev->dev, "probe failed\n");
+
+ return ret;
+}
+
+static int __devexit c_can_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ unregister_c_can_dev(dev);
+ platform_set_drvdata(pdev, NULL);
+
+ free_c_can_dev(dev);
+ iounmap(priv->regs);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+#ifdef CONFIG_HAVE_CLK
+ clk_put(priv->priv);
+#endif
+
+ return 0;
+}
+
+static struct platform_driver c_can_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = c_can_plat_probe,
+ .remove = __devexit_p(c_can_plat_remove),
+};
+
+static int __init c_can_plat_init(void)
+{
+ return platform_driver_register(&c_can_plat_driver);
+}
+module_init(c_can_plat_init);
+
+static void __exit c_can_plat_exit(void)
+{
+ platform_driver_unregister(&c_can_plat_driver);
+}
+module_exit(c_can_plat_exit);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
--
1.6.0.2
^ permalink raw reply related
* THANKS AND TREAT AS URGENT PLEASE
From: Mr Dubeam Solion @ 2011-02-14 5:59 UTC (permalink / raw)
Dear Friend,
Good day to you, I know that my message will come to you as a surprise, but never mind, I am Mr.Solion DUBEAM, the credit officer in BOA Bank of Africa here in my country Burkina-Faso west Africa, In my department here in the bank I discover an abandon sum of $12.5Million United State Dollars, that belong to one of our biggest customer here in this bank, who died years ago in a plane crash with his family, I contacted you so that you will help me see that the total sum of $12.5Million will be transfer into your account in your country.
And after the successful transfer i will come over to your country to meet you, and we shall share 50% for you while 50% will be for me, if you agree to help me, I will like you to get back to me immediately
You should call me as soon as you reply my mail so that I can check my mailing box and give you the details about this deal +226 78708420
Thanks and have a nice day.
Mr.Solion DUBEAM
tele: +226 78708420
^ permalink raw reply
* Re: [PATCH v3] pch_gbe: Fix the issue that the receiving data is not normal.
From: David Miller @ 2011-02-14 5:51 UTC (permalink / raw)
To: toshiharu-linux
Cc: netdev, tomoya-linux, linux-kernel, qi.wang, yong.y.wang,
andrew.chih.howe.khor, joel.clark, kok.howg.ewe
In-Reply-To: <4D524D3F.70906@dsn.okisemi.com>
From: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com>
Date: Wed, 09 Feb 2011 17:15:59 +0900
> This PCH_GBE driver had an issue that the receiving data is not normal.
> This driver had not removed correctly the padding data
> which the DMA include in receiving data.
>
> This patch fixed this issue.
>
> Signed-off-by: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com>
Applied, thank you.
^ permalink raw reply
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