* [PATCH 0/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2010-08-11 4:18 UTC (permalink / raw)
To: netdev; +Cc: adapter_linux_open_src_team
From: Rasesh Mody <rmody@brocade.com>
This is patch 0/6 which contains the summary of changes we've
done in this particular submission for Brocade's BR1010/BR1020
10Gb CEE capable ethernet adapter. Source is based against
net-next-2.6.
The changes are as follows:
- Minimized the scope of some APIs as per the comments
- Converted spin_lock _irq()/spin_unlock_irq() to safer spin_lock_irqsave()/spin_lock_irqrestore() respectively
We wish these patches to be considered for inclusion in net-next-2.6.
Signed-off-by: Rasesh Mody <rmody@brocade.com>
---
0 files changed
^ permalink raw reply
* Performance problem OpenWRT Routing
From: Sol Kavy @ 2010-08-11 1:59 UTC (permalink / raw)
To: netdev
To Netdev Developers:
Linux: 2.6.28 (untested but appears the similiar in 2.6.35).
Arch: Ubicom32 <not yet pushed>
Distro: OpenWRT
While working on a response time problem in OpenWRT when the router is fully flooded with packets, I found that do_softirq() was spending up to 56 milliseconds in execution. This function is called from both irq_exit() and from ksoftirqd().
do_softirq() is designed to drain the softirq_pending work. It executes in a loop up to
MAX_SOFTIRQ_RESTART (10) times. As long as one of the softirqs has pending work, all of the softirqs will have a chance to run 10 times.
Inside of net/core/dev.c, net_rx_action() attempts to "limit" the amount of data that it processes in one "call". It tries to limit things to 1 or 2 jiffies worth of work with a budget of 300 packets. Reading the code one is left with the feeling that the author believed that returning (would enable the rest of the system to continue). However, this is not true if do_softirq() is going to call net_rx_action() 10 times before giving up.
The result of do_softirq() re-invoking net_rx_action() is that both packet budget and jiffies budget are reset. The current values result in a maximum of 10 x 300 or 3,000 packets processed in one do_softirq() sequence.
By setting the value to 30, the processing is reduced to the 10 millisecond range and most of the packet processing is moved to ksoftirqd. The value of this is that one can then prioritize ksoftirqd with other threads. Irq_exit() cannot be prioritized since it is executing on the back side of the interrupt.
Questions:
1) Is my analysis correct?
2) Are there any negative side effects of this change besides slowing the work a bit since it is now moved to ksoftirqd?
3) Is there a better knob to tweak?
4) Should net_rx_action() use in_irq() and have different budget's based on the calling context?
Thanks in advance for any feedback,
Sol Kavy
diff --git a/net/core/dev.c b/net/core/dev.c
index 144184c..9e4fb4f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1905,7 +1905,7 @@ out:
=======================================================================*/
int netdev_max_backlog __read_mostly = 1000;
-int netdev_budget __read_mostly = 300;
+int netdev_budget __read_mostly = 30;
int weight_p __read_mostly = 64; /* old backlog weight */
DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
^ permalink raw reply related
* Re: [RFC PATCH v8 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11 3:28 UTC (permalink / raw)
To: Avi Kivity
Cc: xiaohui.xin, netdev, kvm, linux-kernel, mst, mingo, davem,
herbert, jdike
In-Reply-To: <4C56F318.7030409@redhat.com>
Hello Avi,
On Mon, 2010-08-02 at 19:32 +0300, Avi Kivity wrote:
> When are you seeing gup_fast() fall back to gup()? It should be at
> most
> once per page (when a guest starts up none of its pages are mapped,
> it
> faults them in on demand).
netperf/netserver latency results are pretty good for message size
between 1 bytes and 512 bytes when I have 64 bytes small copy.
However if I don't have any small copy , the ping RTT time is
unreasonable huge. Since we think it's better to have small message with
copy, so there will be no issue.
Thanks
Shirley
^ permalink raw reply
* Re: [RFC PATCH v9 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11 1:43 UTC (permalink / raw)
To: xiaohui.xin; +Cc: netdev, kvm, linux-kernel, mst, mingo, davem, herbert, jdike
In-Reply-To: <1281489804.3391.23.camel@localhost.localdomain>
On Tue, 2010-08-10 at 18:23 -0700, Shirley Ma wrote:
> Also I found some vhost performance regression on the new
> kernel with tuning. I used to get 9.4Gb/s, now I couldn't get it.
I forgot to mention the kernel I used 2.6.36 one. And I found the native
host BW is limited to 8.0Gb/s, so the regression might come from the
device driver not vhost.
Shirley
^ permalink raw reply
* Re: [RFC PATCH v9 00/16] Provide a zero-copy method on KVM virtio-net.
From: Shirley Ma @ 2010-08-11 1:23 UTC (permalink / raw)
To: xiaohui.xin; +Cc: netdev, kvm, linux-kernel, mst, mingo, davem, herbert, jdike
In-Reply-To: <1281086624-5765-1-git-send-email-xiaohui.xin@intel.com>
Hello Xiaohui,
On Fri, 2010-08-06 at 17:23 +0800, xiaohui.xin@intel.com wrote:
> Our goal is to improve the bandwidth and reduce the CPU usage.
> Exact performance data will be provided later.
Have you had any performance data to share here? I tested my
experimental macvtap zero copy for TX only. The performance I have seen
as below without any tuning, (default setting):
Before: netperf 16K message size results with 60 secs run is 7.5Gb/s
over ixgbe 10GbE card. perf top shows:
2103.00 12.9% copy_user_generic_string
1541.00 9.4% handle_tx
1490.00 9.1% _raw_spin_unlock_irqrestore
1361.00 8.3% _raw_spin_lock_irqsave
1288.00 7.9% _raw_spin_lock
924.00 5.7% vhost_worker
After: netperf results with 60 secs run is 8.1Gb/s, perf output:
1093.00 9.9% _raw_spin_unlock_irqrestore
1048.00 9.5% handle_tx
934.00 8.5% _raw_spin_lock_irqsave
864.00 7.9% _raw_spin_lock
644.00 5.9% vhost_worker
387.00 3.5% use_mm
I am still working on collecting more data (latency, cpu
utilization...). I will let you know once I get all data for macvtap TX
zero copy. Also I found some vhost performance regression on the new
kernel with tuning. I used to get 9.4Gb/s, now I couldn't get it.
Shirley
^ permalink raw reply
* Re: [PATCH] 3c59x: fix deadlock when using netconsole with 3c59x
From: Neil Horman @ 2010-08-11 1:16 UTC (permalink / raw)
To: David Miller; +Cc: netdev, klassert
In-Reply-To: <20100810.164803.13754555.davem@davemloft.net>
On Tue, Aug 10, 2010 at 04:48:03PM -0700, David Miller wrote:
> From: Neil Horman <nhorman@tuxdriver.com>
> Date: Mon, 9 Aug 2010 12:32:10 -0400
>
> > When using netpoll, its possible to deadlock the 3c59x driver. Since it takes
> > an internal spinlock (vp->lock) that serializes boomerang_interrupt and parts
> > of boomerang_start_xmit, if we call pr_debug in the former, we can go through
> > the tx path on the same cpu, and recurse into the same driver again, deadlocking
> > in the transmit routine.
> >
> > This patch fixes that problem by stopping the queues during interrupt
> > processing, so that subsequent transmits will get queued until a later point.
> > Its not a great solution, but we need to find some way to serialize access to
> > the register file on the card without enforcing a deadlock. I think the queue
> > stop is the best way to do that. And since we only print things in
> > boomerang_interrupt when we have debug enabled, we can mitigate the impact of
> > this change to only stop the queues when debug is on.
> >
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
>
> Nothing serialized changes to "vortex_debug" with the tests you're
> making here. Simply turning it off when a packet arrives can deadlock
> the send queue of the device.
>
> Even if proper serializatio did exist, I still see this as an awful
> solution.
>
> And the default value of this thing is "1" so it's always going to be
> doing this send queue state flipping for effectively everyone.
>
> Please find another way to solve this problem.
>
Crap-spackle, you're right. I was thinking the module_param defaulted it to
zero, but it doesn't. Regardless, sysfs would let us change this value and
deadlock it all to heck.
Recinded. I'll find a better way to fix this. Sorry for the noise
Neil
^ permalink raw reply
* Re: [RFC PATCH 1/2] pci: add function reset call that can be used inside of probe
From: Kenji Kaneshige @ 2010-08-11 0:44 UTC (permalink / raw)
To: Alexander Duyck
Cc: Kirsher, Jeffrey T, davem@davemloft.net, jbarnes@virtuousgeek.org,
netdev@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <4C61DD57.5030208@intel.com>
(2010/08/11 8:14), Alexander Duyck wrote:
> Kenji Kaneshige wrote:
>> (2010/07/31 9:58), Jeff Kirsher wrote:
>>> From: Alexander Duyck<alexander.h.duyck@intel.com>
>>> + /*
>>> + * both INTx and MSI are disabled after the Interrupt Disable bit
>>> + * is set and the Bus Master bit is cleared.
>>> + */
>>> + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
>>> +
>>> + rc = __pci_dev_reset(dev, 0);
>>
>> Could you tell me why you need to program command register before reset?
>>
>> "MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore,
>> resetting the device clears the "Interrupt Disable bit", even though it
>> was set just before the rest. So I'm a little confused.
>>
>> Thanks,
>> Kenji Kaneshige
>>
>
> The point is to prevent any pending transactions from being on the bus
> while we are doing the reset. By writing only the INTX disable bit we
> are disabling all interrupts from being generated, and also disabling
> all DMA and MSI interrupts since the bus master enable bit is not set.
>
> Without this change the device might be in the middle of a transaction
> or sending an interrupt while we are doing the reset which may lead to
> other issues after the reset.
>
Thank you for clarification. I understood.
Thanks,
Kenji Kaneshige
^ permalink raw reply
* [MeeGo-Dev][PATCH] Topcliff: Update PCH_CAN driver to 2.6.35
From: Masayuki Ohtak @ 2010-08-11 0:25 UTC (permalink / raw)
To: meego-dev-WXzIur8shnEAvxtiuMwx3w, Wolfgang Grandegger,
socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA
Cc: andrew.chih.howe.khor-ral2JQCrhuEAvxtiuMwx3w
[-- Attachment #1.1: Type: text/plain, Size: 124239 bytes --]
CAN driver of Topcliff PCH
Topcliff PCH is the platform controller hub that is going to be used in
Intel's upcoming general embedded platform. All IO peripherals in
Topcliff PCH are actually devices sitting on AMBA bus.
Topcliff PCH has CAN I/F. This driver enables CAN function.
Signed-off-by: Masayuki Ohtake <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>
---
drivers/net/can/Kconfig | 8 +
drivers/net/can/Makefile | 1 +
drivers/net/can/pch_can.c | 4076 +++++++++++++++++++++++++++++++++++++++++++++
drivers/net/can/pch_can.h | 435 +++++
4 files changed, 4520 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/pch_can.c
create mode 100644 drivers/net/can/pch_can.h
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 2c5227c..5c98a20 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -73,6 +73,14 @@ config CAN_JANZ_ICAN3
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
+config PCH_CAN
+ tristate "PCH CAN"
+ depends on CAN_DEV
+ ---help---
+ This driver is for PCH CAN of Topcliff which is an IOH for x86
+ embedded processor.
+ This driver can access CAN bus.
+
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 9047cd0..3ddc6a7 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
+obj-$(CONFIG_PCH_CAN) += pch_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
new file mode 100644
index 0000000..3f4fb5e
--- /dev/null
+++ b/drivers/net/can/pch_can.c
@@ -0,0 +1,4076 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pch_can.h"
+
+static unsigned int pch_can_clock = 50000;
+static unsigned int pch_can_rx_buf_size = 16; /* The number of message objects
+ that has to be configured as
+ receive objects.
+ */
+
+static unsigned int pch_can_tx_buf_size = 16; /* The number of message objects
+ that has to be configured as
+ transmit objects.
+ */
+
+static struct pch_can_os can_os[MAX_CAN_DEVICES];
+
+static enum pch_can_auto_restart restat_mode = CAN_MANUAL; /* The variable used
+ to store the
+ restart mode. */
+
+static struct can_bittiming_const pch_can_bittiming_const = {
+ .name = MODULE_NAME,
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024, /* 6bit + extended 4bit */
+ .brp_inc = 1,
+};
+
+static const struct pci_device_id pch_can_pcidev_id[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_CAN)},
+ {}
+};
+
+/*
+This variable is used to store the configuration (receive /transmit) of the
+available message objects.
+This variable is used for storing the message object configuration related
+information. It includes the information about which message object is used as
+Receiver and Transmitter.
+*/
+static unsigned int pch_msg_obj_conf[MAX_MSG_OBJ] = {
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3
+};
+
+/* Array to store the timing settings. */
+static struct pch_can_timing can_rec_timing[] = {
+ /* <Baud rate> <BRP> <TS1> <TS2> <SJW> */
+ /* settings for 62.5MHz */
+ {0xa, 0x250, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 10 kbits/s */
+ {0x14, 0x8D, 0xB, 0x5, 0x0, 0x0, 0x0}, /* < 20 kbits/s */
+ {0x32, 0x5C, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 50 kbits/s */
+ {0x7d, 0x18, 0xC, 0x5, 0x0, 0x0, 0x0}, /* < 125 kbits/s */
+ {0xfa, 0x18, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 250 kbits/s */
+ {0x1f4, 0x8, 0x9, 0x2, 0x0, 0x0, 0x0}, /* < 500 kbits/s */
+ {0x320, 0x5, 0x8, 0x2, 0x0, 0x0, 0x0}, /* < 800 kbits/s */
+ {0x3e8, 0x2, 0xC, 0x6, 0x0, 0x0, 0x0}, /* < 1000 kbits/s */
+
+ /* settings for 24MHz */
+ {0xa, 0xCF, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 10 kbits/s */
+ {0x14, 0x57, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 20 kbits/s */
+ {0x32, 0xF, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 50 kbits/s */
+ {0x7d, 0xF, 0x8, 0x1, 0x0, 0x0, 0x0}, /* < 125 kbits/s */
+ {0xfa, 0x7, 0x8, 0x1, 0x0, 0x0, 0x0}, /* < 250 kbits/s */
+ {0x1f4, 0x3, 0x8, 0x1, 0x0, 0x0, 0x0}, /* < 500 kbits/s */
+ {0x320, 0x2, 0x7, 0x0, 0x0, 0x0, 0x0}, /* < 800 kbits/s */
+ {0x3e8, 0x1, 0x8, 0x1, 0x0, 0x0, 0x0}, /* < 1000 kbits/s */
+
+ /* settings for 50MHz */
+ {0xa, 0xFA, 0xC, 0x5, 0x1, 0x0, 0x0}, /* < 10 kbits/s */
+ {0x14, 0x7D, 0xC, 0x5, 0x1, 0x0, 0x0}, /* < 20 kbits/s */
+ {0x32, 0x32, 0xF, 0x2, 0x0, 0x0, 0x0}, /* < 50 kbits/s */
+ {0x7d, 0x19, 0xC, 0x1, 0x0, 0x0, 0x0}, /* < 125 kbits/s */
+ {0xfa, 0xA, 0xF, 0x2, 0x0, 0x0, 0x0}, /* < 250 kbits/s */
+ {0x1f4, 0x5, 0xF, 0x2, 0x0, 0x0, 0x0}, /* < 500 kbits/s */
+ {0x320, 0x5, 0x8, 0x2, 0x1, 0x0, 0x0}, /* < 800 kbits/s */
+ {0x3e8, 0x2, 0xF, 0x7, 0x0, 0x0, 0x0} /* < 1000 kbits/s */
+ /* Add the new clock settings here. */
+};
+
+static DEFINE_MUTEX(pch_can_mutex);
+
+#ifdef PCH_CAN_FIFO_MODE
+static int check_can_fifo_status(int handle)
+{
+ int ret_val;
+ struct can_fifo *f = (struct can_fifo *) handle;
+
+ if (f->head == f->tail)
+ ret_val = PCH_CAN_FIFO_EMPTY;
+ else if (f->head->next == f->tail)
+ ret_val = PCH_CAN_FIFO_FULL;
+ else
+ ret_val = PCH_CAN_FIFO_NOT_EMPTY;
+
+ return ret_val;
+}
+
+static int
+read_can_fifo(int handle, struct pch_can_msg *msg, struct net_device *ndev)
+{
+ int i;
+ int retval = 0;
+ struct can_fifo *f = (struct can_fifo *) handle;
+ struct pch_can_msg msg_tmp;
+
+ if ((handle == 0) || (msg == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid parameter.\n", __func__);
+ retval = -EPERM;
+ } else if (f->head == f->tail) { /* Buffer Empty */
+ dev_dbg(&ndev->dev, "%s -> FIFO empty.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Accessing the msg object in the FIFO. */
+ msg_tmp = f->tail->msg;
+
+ /* Filling in the msg object. */
+ msg->ide = msg_tmp.ide;
+ msg->id = msg_tmp.id;
+ msg->dlc = msg_tmp.dlc;
+ msg->rtr = msg_tmp.rtr;
+
+ for (i = 0; i < PCH_CAN_MSG_DATA_LEN; i++)
+ msg->data[i] = msg_tmp.data[i];
+
+ /* Proceeding the FIFO read pointer. */
+ f->tail = f->tail->next;
+ dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+ return retval;
+}
+
+static int
+write_can_fifo(int handle, struct pch_can_msg *msg, struct net_device *ndev)
+{
+ int i;
+ int retval = 0;
+ struct can_fifo *f = (struct can_fifo *) handle;
+ struct pch_can_msg *msg_tmp;
+
+ if ((handle == 0) || (msg == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid parameters.\n", __func__);
+ retval = -EPERM;
+ } else if (f->head->next == f->tail) {
+ dev_dbg(&ndev->dev, "%s -> FIFO Full.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Accessing the write node in the FIFO */
+ msg_tmp = &(f->head->msg);
+
+ /* Filling in the FIFO node. */
+ msg_tmp->ide = msg->ide;
+ msg_tmp->rtr = msg->rtr;
+ msg_tmp->id = msg->id;
+ msg_tmp->dlc = msg->dlc;
+
+ for (i = 0; i < PCH_CAN_MSG_DATA_LEN; i++)
+ msg_tmp->data[i] = msg->data[i];
+
+ /* Proceeding the write node. */
+ f->head = f->head->next;
+ dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_error_stats(int handle, struct pch_can_error *error)
+{
+ u32 reg_val;
+ int retval = 0;
+
+ if ((handle == 0) || (error == NULL)) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Reading the error count register. */
+ reg_val = ioread32(can->io_base + CAN_ERRC_OFFSET);
+
+ error->rxgte96 = 0;
+ error->txgte96 = 0;
+
+ error->rx_err_cnt =
+ (reg_val & MSK_ES_RXERRCNT) >> BIT_ES_RXERRCNT;
+ error->tx_err_cnt =
+ (reg_val & MSK_ES_TXERRCNT) >> BIT_ES_TXERRCNT;
+
+ /* receive error count > 96 */
+ if (error->rx_err_cnt >= ERROR_COUNT)
+ error->rxgte96 = 1;
+ /* transmit error count > 96. */
+ if (error->tx_err_cnt >= ERROR_COUNT)
+ error->txgte96 = 1;
+
+ /* Reading the Can status register. */
+ reg_val = ioread32(can->io_base + CAN_STAT_OFFSET);
+
+ /* EPass */
+ if ((reg_val & (1 << BIT_SHIFT_FIVE)) != 0)
+ error->error_stat = 1;
+ /* Buss Off */
+ else if ((reg_val & (1 << BIT_SHIFT_SEVEN)) != 0)
+ error->error_stat = 3;
+ else
+ error->error_stat = 0;
+ }
+
+ return retval;
+}
+#endif
+
+static void delete_can_fifo(int handle, struct net_device *ndev)
+{
+ unsigned int i;
+ struct can_fifo_item *curr = NULL;
+ struct can_fifo_item *next = NULL;
+ struct can_fifo *f = (struct can_fifo *) handle;
+
+ if (handle != 0) {
+ curr = f->head;
+ if (f->head != NULL) {
+ next = curr->next;
+
+ /* Freeing individual node. */
+ for (i = 0; i < f->size; i++) {
+ kfree(curr);
+ curr = next;
+ next = (struct can_fifo_item *) curr->next;
+ }
+ }
+
+ /* Free the START node. */
+ kfree(f);
+ } else {
+ dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+ }
+
+ dev_dbg(&ndev->dev, "%s successful.\n", __func__);
+}
+
+static int create_can_fifo(unsigned int fifo_entries, struct net_device *ndev)
+{
+ unsigned int i;
+ struct can_fifo_item *curr;
+ struct can_fifo *f;
+ int retval;
+
+ /* Allocating the Main start node. */
+ f = kmalloc(sizeof(struct can_fifo), GFP_KERNEL);
+
+ if (f == NULL) {
+ dev_err(&ndev->dev,
+ "%s -> msg queue allocation failed.\n", __func__);
+ retval = (int) PCH_CAN_NULL;
+ } else {
+ /* Allocating the first node. */
+ f->head = kmalloc(sizeof(struct can_fifo_item), GFP_KERNEL);
+ if ((f->head == NULL)) {
+ kfree(f);
+ retval = (int) PCH_CAN_NULL;
+ } else {
+ /* Initially empty. */
+ f->tail = f->head;
+ curr = f->head;
+
+ /* Rest of the nod ecreation Node creation. */
+ for (i = 1; i <= fifo_entries; i++) {
+ curr->next =
+ kmalloc(sizeof(struct can_fifo_item),
+ GFP_KERNEL);
+ /* If allocation failed. */
+ if ((curr->next == NULL)) {
+ dev_err(&ndev->dev,
+ "%s -> Allocation failed.\n",
+ __func__);
+ i = (i - 1);
+ /* Freeing the already allocated
+ nodes. */
+ while (i > 0) {
+ curr = f->head;
+ f->head = curr->next;
+ kfree(curr);
+
+ i--;
+ }
+
+ /* Freeing the main start node. */
+ kfree(f);
+ f = NULL;
+ retval =
+ (int) PCH_CAN_NULL;
+ break;
+ }
+
+ curr = curr->next;
+ }
+
+ if (f != NULL) {
+ /* Making it circular. */
+ curr->next = f->head;
+ f->size = fifo_entries;
+
+ retval = (int) f;
+ dev_dbg(&ndev->dev,
+ "%s sucessful.\n", __func__);
+ }
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %u.\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_create(u8 *io_base, struct net_device *ndev)
+{
+ struct can_hw *can = NULL;
+ int retval = (int) PCH_CAN_NULL;
+
+ if (io_base == NULL) {
+ dev_err(&ndev->dev, "%s -> Invalid IO Base\n", __func__);
+ }
+
+ else {
+ /* Allocates memory for the handle. */
+ can = kmalloc(sizeof(struct can_hw), GFP_KERNEL);
+ if (can == NULL) { /* Allocation failed */
+ dev_err(&ndev->dev,
+ "%s -> CAN Memory allocation failed\n", __func__);
+ } else { /* Allocation successful */
+
+ can->io_base = io_base;
+ retval = (int) can;
+ dev_dbg(&ndev->dev,
+ "%s -> Handle Creation successful.\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %x\n", __func__, retval);
+ return retval;
+}
+
+static void pch_can_destroy(int handle, struct net_device *ndev)
+{
+ struct can_hw *can = (struct can_hw *) handle;
+
+ if (handle != 0) {
+ /* Free the memory for the handle. */
+ kfree(can);
+ dev_dbg(&ndev->dev, "%s -> Free successful.\n", __func__);
+ } else {
+ dev_err(&ndev->dev, "%s-> Invalid handle.\n", __func__);
+ }
+}
+
+static int pch_can_set_run_mode(int handle, enum pch_can_run_mode mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+ struct can_hw *can;
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Retrieving base address for access. */
+ can = (struct can_hw *) handle;
+
+ switch (mode) {
+ case PCH_CAN_RUN:
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_INIT);
+ dev_dbg(&ndev->dev,
+ "%s -> Can set to RUN Mode.\n", __func__);
+ break;
+
+ case PCH_CAN_STOP:
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_INIT);
+ dev_dbg(&ndev->dev,
+ "%s -> Can set to STOP Mode.\n", __func__);
+ break;
+
+ default:
+ dev_err(&ndev->dev,
+ "%s -> Invalid run mode.\n", __func__);
+ retval = -EPERM;
+ break;
+ }
+ }
+
+ dev_dbg(&ndev->dev,
+ "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_run_mode(int handle, enum pch_can_run_mode *mode,
+ struct net_device *ndev)
+{
+ u32 reg_val;
+ struct can_hw *can;
+ int retval = 0;
+
+ if ((handle == 0) || (mode == NULL)) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid parameter.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ can = (struct can_hw *) handle;
+
+ reg_val = ioread32(can->io_base + CAN_CONT_OFFSET);
+
+ /* Checking the Init bit of Can Control Register.
+ Init Bit 1 -> Stop
+ Init Bit 0 -> Run
+ */
+ if ((reg_val & CAN_CTRL_INIT) != 0) {
+ *mode = PCH_CAN_STOP;
+ dev_dbg(&ndev->dev,
+ "%s -> Mode is PCH_CAN_STOP\n", __func__);
+ } else {
+ *mode = PCH_CAN_RUN;
+ dev_dbg(&ndev->dev,
+ "%s -> Mode is PCH_CAN_RUN\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_arbiter_mode(int handle, enum pch_can_arbiter mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid Handle\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* PCH CAN Controller supports only PCH_CAN_FIXED_PRIORITY
+ arbiter mode.
+ */
+ switch (mode) {
+ case PCH_CAN_FIXED_PRIORITY:
+ dev_dbg(&ndev->dev,
+ "%s -> FIXED PRIORITY is set for Arbiter mode\n",
+ __func__);
+ break;
+
+ case PCH_CAN_ROUND_ROBIN:
+ default:
+ dev_dbg(&ndev->dev,
+ "%s -> Invalid arbiter mode\n", __func__);
+ retval = -EPERM;
+ break;
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_arbiter_mode(int handle, enum pch_can_arbiter *mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if ((handle == 0) || (mode == NULL)) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid parameter\n", __func__);
+ retval = -EPERM;
+ }
+
+ else {
+ /* PCH CAN Controller supports only PCH_CAN_FIXED_PRIORITY
+ arbiter mode.
+ */
+ *mode = PCH_CAN_FIXED_PRIORITY;
+ dev_dbg(&ndev->dev,
+ "%s -> Arbiter Mode is PCH_CAN_FIXED_PRIORITY\n", __func__);
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_restart_mode(int handle, enum pch_can_auto_restart mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+ retval = -EPERM;
+ } else {
+ switch (mode) {
+ case CAN_MANUAL:
+ restat_mode = CAN_MANUAL;
+ dev_dbg(&ndev->dev, "%s -> Value of variable "
+ " restat_mode = 0. CAN_MANUAL mode set.\n",
+ __func__);
+ break;
+
+ case CAN_AUTO:
+ restat_mode = CAN_AUTO;
+ dev_dbg(&ndev->dev, "%s -> Value of variable "
+ " restat_mode = 1. CAN_AUTO mode set.\n",
+ __func__);
+ break;
+
+ default:
+ dev_dbg(&ndev->dev,
+ "%s -> Invalid restart mode\n", __func__);
+ retval = -EPERM;
+ break;
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d\n", __func__,
+ retval);
+ return retval;
+}
+
+static int pch_can_get_restart_mode(int handle, enum pch_can_auto_restart *mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if ((handle == 0) || (mode == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid parameter.\n", __func__);
+ retval = -EPERM;
+ } else {
+ if (CAN_AUTO == restat_mode) {
+ *mode = CAN_AUTO;
+ dev_dbg(&ndev->dev,
+ "%s -> Mode CAN_AUTO.\n", __func__);
+ } else {
+ *mode = CAN_MANUAL;
+ dev_dbg(&ndev->dev,
+ "%s -> Mode CAN_MANUAL.\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s returns: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_listen_mode(int handle, enum pch_can_listen_mode mode,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Setting for Bit3 of Can Extended function register for
+ appropriate mode.
+ Silent bit = 0 (Active mode)
+ Silent bit = 1 (Silent mode)
+ */
+ switch (mode) {
+ case PCH_CAN_LISTEN:
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_OPT);
+ PCH_CAN_BIT_SET((can->io_base + CAN_OPT_OFFSET),
+ CAN_OPT_SILENT);
+ dev_dbg(&ndev->dev,
+ "%s -> PCH_CAN_LISTEN mode set.\n", __func__);
+ break;
+
+ case PCH_CAN_ACTIVE:
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_OPT);
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_OPT_OFFSET),
+ CAN_OPT_SILENT);
+ dev_dbg(&ndev->dev,
+ "%s ->PCH_CAN_ACTIVE mode set.\n", __func__);
+ break;
+
+ default:
+ dev_dbg(&ndev->dev,
+ "%s ->Invalid listen mode\n", __func__);
+ retval = -EPERM;
+ break;
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_listen_mode(int handle, enum pch_can_listen_mode *mode,
+ struct net_device *ndev)
+{
+ u32 reg_val;
+ int retval = 0;
+
+ if ((handle == 0) || (mode == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid Parameter\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Attaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ reg_val = ioread32(can->io_base + CAN_OPT_OFFSET);
+
+ /* Checking for Bit3 of Can Extended function register
+ for silent mode
+ Silent bit = 0 (Active mode)
+ Silent bit = 1 (Silent mode)
+ */
+
+ if ((reg_val & CAN_OPT_SILENT) != 0) {
+ *mode = PCH_CAN_LISTEN;
+ dev_dbg(&ndev->dev,
+ "%s -> Mode is listen\n", __func__);
+ } else {
+ *mode = PCH_CAN_ACTIVE;
+ dev_dbg(&ndev->dev, "%s -> Mode is active\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_int_custom(int handle, u32 interrupts)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Clearing the IE, SIE and EIE bits of Can control register. */
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_IE_SIE_EIE);
+
+ /* Appropriately setting them. */
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ ((interrupts & MSK_CTRL_IE_SIE_EIE) <<
+ BIT_SHIFT_ONE));
+ }
+
+ return retval;
+}
+
+/* This function retrieves interrupt enabled for the CAN device. */
+static int pch_can_get_int_enables(int handle, u32 *enables)
+{
+ u32 reg_ctrl_val;
+ int retval = 0;
+
+ if ((handle == 0) || (enables == NULL)) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Reading the Can control register. */
+ reg_ctrl_val = ioread32(can->io_base + CAN_CONT_OFFSET);
+
+ /* Obtaining the status of IE, SIE and EIE interrupt bits. */
+ *enables =
+ (((reg_ctrl_val & CAN_CTRL_IE_SIE_EIE) >> BIT_SHIFT_ONE));
+ }
+
+ return retval;
+}
+
+static int pch_can_set_int_enables(int handle,
+ enum pch_can_interrupt interrupt_no,
+ struct net_device *ndev)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+
+ /* Obatining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /*
+ Appropriately setting the IE, SIE and EIE bits of Can control
+ register.
+ */
+ switch (interrupt_no) {
+ case CAN_ENABLE:
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_IE);
+ dev_dbg(&ndev->dev,
+ "%s -> CAN_ENABLE (IE) interrupt set.\n", __func__);
+ break;
+
+ case CAN_DISABLE:
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_IE);
+ dev_dbg(&ndev->dev,
+ "%s -> CAN_DIABLE (IE) interrupt reset.\n", __func__);
+ break;
+
+ case CAN_ALL:
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_IE_SIE_EIE);
+ dev_dbg(&ndev->dev,
+ "%s -> CAN_ALL (IE,SIE,EIE) interrupt set.\n",
+ __func__);
+ break;
+
+ case CAN_NONE:
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_IE_SIE_EIE);
+ dev_dbg(&ndev->dev,
+ "%s -> CAN_NONE (IE,SIE,EIE) interrupt reset.\n",
+ __func__);
+ break;
+
+ default:
+ dev_dbg(&ndev->dev,
+ "%s -> Invalid parameter interrupt.\n", __func__);
+ retval = -EPERM;
+ break;
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_rx_enable(int handle, u32 buff_num, u32 set,
+ struct net_device *ndev)
+{
+ u32 counter;
+ int retval = 0;
+ u32 if1_creq;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+ (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+ /* if invalid buffer number. */
+ dev_err(&ndev->dev,
+ "%s -> Message object %u not configured for receive.\n",
+ __func__, buff_num);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /*Reading the receive buffer data from RAM to Interface1
+ registers */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ dev_err(&ndev->dev,
+ "%s -> Cannot read the message buffer object %u.\n",
+ __func__, buff_num);
+ retval = -EPERM;
+ } else { /* Reading successful */
+
+ /* Setting the IF1MASK1 register to access MsgVal and
+ RxIE bits */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+ CAN_CMASK_CTRL),
+ (can->io_base +
+ CAN_IF1_CMASK_OFFSET));
+
+ if (set == ENABLE) {
+ /* Setting the MsgVal and RxIE bits */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ CAN_IF_MCONT_RXIE);
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ CAN_ID_MSGVAL);
+
+ dev_dbg(&ndev->dev,
+ "%s -> Enabled receive message buffer %u.\n",
+ __func__, buff_num);
+ } else if (set == DISABLE) {
+ /* Resetting the MsgVal and RxIE bits */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ CAN_IF_MCONT_RXIE);
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ CAN_ID_MSGVAL);
+
+ dev_dbg(&ndev->dev,
+ "%s -> Disabled receive message buffer %u",
+ __func__, buff_num);
+ }
+
+ /* Updating the changes to the message object. */
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ /* Confirming the write by checking the busy bit. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ dev_err(&ndev->dev,
+ "%s -> Write failed.\n", __func__);
+ retval = -EPERM;
+ }
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_rx_enable_all(int handle, struct net_device *ndev)
+{
+ u32 counter = 0;
+ int retval = 0;
+ u32 i;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Traversing to obtain the object configured as receivers. */
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+ /* Here i is the index, however (i+1) is object
+ number. */
+ retval =
+ pch_can_set_rx_enable(handle, (i + 1),
+ ENABLE, ndev);
+
+ if (retval == -EPERM) {
+ dev_dbg(&ndev->dev,
+ "%s -> Cannot Enable receive "
+ "object%u\n", __func__, i + 1);
+ counter++;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Enabled receive object %u\n",
+ __func__, i + 1);
+ }
+ }
+ }
+
+ /* If enabling of all the receive object failed. */
+ if (counter == pch_can_rx_buf_size) {
+ retval = -EPERM;
+ dev_err(&ndev->dev, "%s failed.\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_rx_disable_all(int handle, struct net_device *ndev)
+{
+ u32 counter = 0;
+ int retval = 0;
+ u32 i;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Traversing to obtain the object configured as receivers. */
+ for (i = 0; i < (pch_can_rx_buf_size + pch_can_tx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+ /* Here i is the index, however (i+1) is the
+ object number. */
+ retval =
+ pch_can_set_rx_enable(handle, (i + 1),
+ DISABLE, ndev);
+
+ if (retval == -EPERM) {
+ dev_dbg(&ndev->dev,
+ "%s -> Disabling of Rx buffer %u "
+ "failed.\n", __func__, (i + 1));
+ counter++;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Disabled receive object %u\n",
+ __func__, i + 1);
+ }
+ }
+ }
+
+ /* If disabling of all the receive object failed. */
+ if (counter == pch_can_rx_buf_size) {
+ retval = -EPERM;
+ dev_err(&ndev->dev, "%s failed.\n", __func__);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_tx_enable(int handle, u32 buff_num, u32 set,
+ struct net_device *ndev)
+{
+ int retval = 0;
+ u32 counter;
+ u32 if1_creq;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle", __func__);
+ retval = -EPERM;
+ } else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_TX) ||
+ (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+ /* invalid buffer number. */
+ dev_err(&ndev->dev,
+ "%s -> Message object %u not configured for transmit.\n",
+ __func__, buff_num);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /*Reading the Message buffer from Message RAM to Interface2
+ registers. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ dev_err(&ndev->dev,
+ "%s -> Reading transmit buffer failed.\n", __func__);
+ retval = -EPERM;
+ } else { /* Reading successful. */
+
+ /* Setting the IF2CMASK register for accessing the
+ MsgVal and TxIE bits */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+ CAN_CMASK_CTRL),
+ (can->io_base +
+ CAN_IF1_CMASK_OFFSET));
+
+ if (set == ENABLE) {
+ /* Setting the MsgVal and TxIE bits */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ CAN_IF_MCONT_TXIE);
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ CAN_ID_MSGVAL);
+
+ dev_dbg(&ndev->dev,
+ "%s -> Enabled transmit message buffer %u\n",
+ __func__, buff_num);
+ } else if (set == DISABLE) {
+ /* Resetting the MsgVal and TxIE bits. */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ CAN_IF_MCONT_TXIE);
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ CAN_ID_MSGVAL);
+
+ dev_dbg(&ndev->dev,
+ "%s -> Disabled transmit message buffer %u\n",
+ __func__, buff_num);
+ }
+
+ /* Updating the changes to the message buffer. */
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ /* Confirming the updation. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) { /* Updation failed. */
+ dev_err(&ndev->dev,
+ "%s -> Write failed.\n", __func__);
+ retval = -EPERM;
+ }
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_tx_enable_all(int handle, struct net_device *ndev)
+{
+ u32 counter = 0;
+ int retval = 0;
+ u32 i;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Traversing to obtain the object configured as transmit
+ object. */
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+ /* Here i denotes the index, however (i+1) is
+ the object number. */
+ retval =
+ pch_can_set_tx_enable(handle, (i + 1),
+ ENABLE, ndev);
+
+ if (retval == -EPERM) {
+ counter++;
+ dev_dbg(&ndev->dev, "%s -> "
+ "Cannot Enable transmit object %u\n",
+ __func__, (i + 1));
+ } else {
+ dev_dbg(&ndev->dev, "%s -> "
+ "Enabled transmit object %u\n",
+ __func__, (i + 1));
+ }
+ }
+ }
+
+ /* If enabling of all transmit object failed. */
+ if (counter == pch_can_tx_buf_size) {
+ dev_err(&ndev->dev, "%s failed.\n", __func__);
+ retval = -EPERM;
+ }
+
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_tx_disable_all(int handle, struct net_device *ndev)
+{
+ u32 counter = 0;
+ int retval = 0;
+ u32 i;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid Handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Traversing to obtain the object configured as transmit
+ object. */
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_tx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+ /* Here i denotes the index, however (i+1) is
+ the object number. */
+
+ /* Disabling. */
+ retval =
+ pch_can_set_tx_enable(handle, (i + 1),
+ DISABLE, ndev);
+
+ if (retval == -EPERM) {
+ dev_dbg(&ndev->dev, "%s -> Disabling"
+ " Tx buffer %u failed.\n",
+ __func__, (i + 1));
+ counter++;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Disabled transmit object %u\n",
+ __func__, (i + 1));
+ }
+ }
+ }
+
+ /* If disabling of all the transmit object failed. */
+ if (counter == pch_can_tx_buf_size) {
+ dev_err(&ndev->dev, "%s -> failed.\n", __func__);
+ retval = -EPERM;
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_set_rx_filter(int handle, struct pch_can_rx_filter *filter)
+{
+ u32 reg1;
+ u32 reg2;
+ u32 counter;
+ int retval = 0;
+ u32 if1_creq;
+
+ if ((handle == 0) || (filter == NULL)) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ can->io_base + CAN_IF1_CMASK_OFFSET);
+ /* Setting the CMASK for reading */
+ iowrite32(filter->num,
+ can->io_base + CAN_IF1_CREQ_OFFSET);
+ /* Setting CREQ to specified Msg Obj. */
+
+ /* Confirming the read completion. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) { /* Read Unsuccessful. */
+ retval = -EPERM;
+ } else { /* read successful. */
+
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID2_OFFSET), MSK_ALL_THIRTEEN);
+ /* Clearing the bit 0- 12 of ID2 */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID2_OFFSET), CAN_ID2_XTD);
+ /* Clearing XTD bit */
+
+ if ((filter->aidr.id_ext == 1)) { /* Extended ID */
+ reg1 = filter->aidr.id & MSK_ALL_SIXTEEN;
+ /* ID1 value. */
+ /* ID2 value with XTD bit set. */
+ reg2 =
+ (((filter->aidr.
+ id & (MSK_ALL_THIRTEEN <<
+ BIT_SHIFT_SIXTEEN))
+ >> BIT_SHIFT_SIXTEEN) | CAN_ID2_XTD);
+ } else { /* Standard ID */
+
+ reg1 = 0;
+ reg2 = ((filter->aidr.id & MSK_ALL_ELEVEN) <<
+ BIT_SHIFT_TWO);
+ }
+
+ iowrite32(reg1, (can->io_base + CAN_IF1_ID1_OFFSET));
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_ID2_OFFSET), reg2);
+
+ if (filter->umask == 1) {
+ /* If mask has to be set. */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MASK2_OFFSET),
+ MSK_ALL_THIRTEEN);
+ /* Clearing bit 0-12 */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MASK2_OFFSET),
+ CAN_MASK2_MDIR_MXTD);
+ /* Clearing Mdir & MXtd */
+
+ if (filter->amr.id_ext == 1) {
+ /* Extended Mask */
+ reg1 = filter->amr.id & MSK_ALL_SIXTEEN;
+ /* Mask1 value */
+ /* Mask2 value with MXtd set */
+ reg2 = (((filter->amr.
+ id & (MSK_ALL_THIRTEEN <<
+ BIT_SHIFT_SIXTEEN))
+ >> BIT_SHIFT_SIXTEEN) |
+ CAN_IF_MASK2_MXTD);
+ } else {
+ reg1 = 0;
+ reg2 = ((filter->amr.id &
+ MSK_ALL_ELEVEN) <<
+ BIT_SHIFT_TWO);
+ /* Mask2 Value */
+ }
+
+ iowrite32(reg1,
+ (can->io_base + CAN_IF1_MASK1_OFFSET));
+ /* Writing MASK1 */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MASK2_OFFSET), reg2);
+ /* Writing MASK2 */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_UMASK);
+ /* Setting Umask bit */
+ } else {
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_UMASK);
+ /* Resetting Umask bit. */
+ }
+
+ /* Setting CMASK for writing */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_MASK |
+ CAN_CMASK_ARB | CAN_CMASK_CTRL),
+ (can->io_base +
+ CAN_IF1_CMASK_OFFSET));
+ iowrite32(filter->num, (can->io_base +
+ CAN_IF1_CREQ_OFFSET));
+ /* Setting CREQ for specified sg Obj. */
+
+ /* Confirming the write completion. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter == 0) /* Write failed */
+ retval = -EPERM;
+ }
+ }
+
+ return retval;
+}
+
+static int
+pch_can_rx_init_filter(int handle, u32 buff_num, struct net_device *ndev)
+{
+ int retval = 0;
+ struct pch_can_rx_filter filter;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+ (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+ /* if invalid buffer number. */
+ dev_err(&ndev->dev,
+ "%s -> Invalid buffer no:%d\n", __func__, buff_num);
+ retval = -EPERM;
+ } else {
+ /* Set all Rx filters to allow all msgs. */
+ filter.amr.id = (u32) 0;
+ filter.amr.id_ext = (u32) 0;
+
+ filter.aidr.id = (u32) 0;
+ filter.aidr.id_ext = (u32) 0;
+
+ filter.num = buff_num;
+ filter.umask = 1;
+
+ retval = pch_can_set_rx_filter(handle, &filter);
+ }
+
+ return retval;
+}
+
+static int pch_can_get_rx_enable(int handle, u32 buff_num, u32 *enable,
+ struct net_device *ndev)
+{
+ int retval = 0;
+ u32 counter;
+ u32 if1_creq;
+
+ if ((handle == 0) || (enable == NULL)) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid Parameter.\n", __func__);
+ retval = -EPERM;
+ }
+ /* Invalid buffer number. */
+ else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+ (buff_num > (pch_can_tx_buf_size + pch_can_rx_buf_size))) {
+ dev_err(&ndev->dev,
+ "%s -> Message object %u not configured for receive.\n",
+ __func__, buff_num);
+ retval = -EPERM;
+ }
+
+ else {
+ /* Obtaining the remap address fro access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32((can->io_base +
+ CAN_IF1_CREQ_OFFSET))) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter == 0) {
+ dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+ retval = -EPERM;
+ } else {
+ if (((ioread32(can->io_base +
+ CAN_IF1_ID2_OFFSET)) &
+ CAN_ID_MSGVAL) &&
+ ((ioread32(can->io_base +
+ CAN_IF1_MCONT_OFFSET)) &
+ CAN_IF_MCONT_RXIE)) {
+ *enable = ENABLE;
+
+ dev_dbg(&ndev->dev, "%s -> Receive message "
+ "buffer %u is enabled.\n",
+ __func__, buff_num);
+ } else {
+ *enable = DISABLE;
+ dev_dbg(&ndev->dev, "%s -> Receive Message "
+ "buffer %u is disabled.\n",
+ __func__, buff_num);
+ }
+ }
+
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_tx_enable(int handle, u32 buff_num, u32 *enable,
+ struct net_device *ndev)
+{
+ int retval = 0;
+ u32 counter;
+ u32 if1_creq;
+
+ if ((handle == 0) || (enable == NULL)) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid Parameter.\n", __func__);
+ retval = -EPERM;
+ }
+ /* invalid buffer number. */
+ else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_TX) ||
+ (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+ dev_err(&ndev->dev, "%s ->"
+ " Invalid Message "
+ "object %u.\n", __func__, buff_num);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the buffer number for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter == 0) {
+ dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+ retval = -EPERM;
+ } else {
+ if (((ioread32(can->io_base +
+ CAN_IF1_ID2_OFFSET)) & CAN_ID_MSGVAL) &&
+ ((ioread32(can->io_base +
+ CAN_IF1_MCONT_OFFSET)) &
+ CAN_IF_MCONT_TXIE)) {
+ *enable = ENABLE;
+
+ dev_dbg(&ndev->dev,
+ "%s -> Transmit message buffer %u is "
+ "enabled.\n", __func__, buff_num);
+ } else {
+ *enable = DISABLE;
+
+ dev_dbg(&ndev->dev,
+ "%s -> Transmit message buffer %u is "
+ "disabled.\n", __func__, buff_num);
+ }
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+ return retval;
+}
+
+/* This function returns whether or not interrupts are pending for the CAN
+ * device.
+*/
+static int pch_can_int_pending(int handle)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else {
+ /* Obatining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+ retval = (ioread32(can->io_base + CAN_INT_OFFSET) &
+ MSK_ALL_SIXTEEN);
+ }
+
+ return retval;
+}
+
+static int pch_can_set_baud_simple(int handle, enum pch_can_baud baud)
+{
+ u32 reg_val;
+ int retval = 0;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+ u32 offset;
+
+ /* Setting the CCE bit of Can control register for accessing the
+ Timing Register. */
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_CCE);
+
+ /* Calculating the offset of the settings array for the current
+ clock. */
+ switch (pch_can_clock) {
+ case 62500:
+ offset = PCH_CAN_CLOCK_62_5_OFFSET;
+ break;
+
+ case 24000:
+ offset = PCH_CAN_CLOCK_24_OFFSET;
+ break;
+
+ case 50000:
+ offset = PCH_CAN_CLOCK_50_OFFSET;
+ break;
+
+ /* The default section will not be invoked since
+ the clock frequency has been validated at the module
+ init procedure. */
+ default:
+ offset = PCH_CAN_CLOCK_DEFAULT_OFFSET;
+ break;
+ }
+
+ /* Getting the appropriate register value. */
+ reg_val = (((can_rec_timing[baud + offset].
+ cfg_bitrate & MSK_BITT_BRP) << BIT_BITT_BRP) |
+ (can_rec_timing[baud + offset].
+ cfg_tseg1 << BIT_BITT_TSEG1) |
+ (can_rec_timing[baud + offset].cfg_tseg2 <<
+ BIT_BITT_TSEG2) |
+ (can_rec_timing[baud + offset].cfg_sjw <<
+ BIT_BITT_SJW));
+
+ /* Writing to Can Timing register. */
+ iowrite32(reg_val, (can->io_base + CAN_BITT_OFFSET));
+ /* Writing to the CAN BRP register. */
+ iowrite32(((can_rec_timing[baud + offset].
+ cfg_bitrate & MSK_BRPE_BRPE) >> BIT_BRPE_BRPE),
+ (can->io_base + CAN_BRPE_OFFSET));
+
+ /* Resetting the CCE bit of the Can control register. */
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_CCE);
+ }
+
+ return retval;
+}
+
+static int pch_can_set_baud_custom(int handle, struct pch_can_timing *timing)
+{
+ u32 reg_val;
+ int retval = 0;
+
+ if ((handle == 0) || (timing == NULL))
+ retval = -EPERM;
+
+ /* max is MAX_BITRATE */
+ else if (timing->bitrate > MAX_BITRATE) {
+ retval = -EPERM;
+ }
+
+ else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Setting the CCE bit of Can control register for accessing the
+ Can Timing register. */
+ PCH_CAN_BIT_SET((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_CCE);
+
+ /* Obtaining the appropriate register value. */
+ reg_val =
+ (((timing->cfg_bitrate & MSK_BITT_BRP) << BIT_BITT_BRP) |
+ (timing->cfg_tseg1 << BIT_BITT_TSEG1) |
+ (timing->cfg_tseg2 << BIT_BITT_TSEG2) |
+ (timing->cfg_sjw << BIT_BITT_SJW));
+
+ /* Writing to the timing register. */
+ iowrite32(reg_val, (can->io_base + CAN_BITT_OFFSET));
+ /* Writing to the BRP register. */
+ iowrite32(((timing->cfg_bitrate & MSK_BRPE_BRPE) >>
+ BIT_BRPE_BRPE),
+ (can->io_base + CAN_BRPE_OFFSET));
+
+ /* Resetting the CCE bit. */
+ PCH_CAN_BIT_CLEAR((can->io_base + CAN_CONT_OFFSET),
+ CAN_CTRL_CCE);
+
+ }
+
+ return retval;
+}
+
+static int pch_can_get_baud(int handle, struct pch_can_timing *timing)
+{
+ u32 timing_bitt_reg;
+ u32 timing_brpe_reg;
+ int retval = 0;
+
+ if ((handle == 0) || (timing == NULL)) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ timing_bitt_reg = ioread32(can->io_base + CAN_BITT_OFFSET);
+ timing_brpe_reg = ioread32(can->io_base + CAN_BRPE_OFFSET);
+
+ /* Separating the individual part from the values read. */
+ timing->cfg_bitrate = ((timing_bitt_reg & MSK_BITT_BRP) |
+ ((timing_brpe_reg & MSK_BRPE_GET) << BIT_BRPE_BRPE));
+ timing->cfg_tseg1 =
+ (timing_bitt_reg & MSK_BITT_TSEG1) >> BIT_BITT_TSEG1;
+ timing->cfg_tseg2 =
+ (timing_bitt_reg & MSK_BITT_TSEG2) >> BIT_BITT_TSEG2;
+ timing->cfg_sjw =
+ (timing_bitt_reg & MSK_BITT_SJW) >> BIT_BITT_SJW;
+ }
+
+ return retval;
+}
+
+static int pch_can_set_rx_buffer_link(int handle, u32 buffer_num, u32 set,
+ struct net_device *ndev)
+{
+ u32 counter;
+ int retval = 0;
+ u32 if1_creq;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+ retval = -EPERM;
+ } else if ((pch_msg_obj_conf[buffer_num - 1] != MSG_OBJ_RX) ||
+ (buffer_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+ /* invalid buffer nummber. */
+ dev_err(&ndev->dev, "%s -> Invalid buffer number %u.\n"
+ , __func__, buffer_num);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Reading the corresponding object. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buffer_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = ioread32((can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ /* Confirming read. */
+ if ((counter == 0)) {
+ dev_err(&ndev->dev, "%s -> Read failed\n", __func__);
+ retval = -EPERM;
+ } else {
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL),
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+
+ /*
+ Setting/Resetting the EOD bit for Buffer link operation.
+ EOB bit = 1 -> Buffer link disabled.
+ EOB bit = 0 -> Biffer link enabled.
+ */
+ if (set == ENABLE) {
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET), CAN_IF_MCONT_EOB);
+ dev_dbg(&ndev->dev,
+ "%s -> Buffer Link enabled.\n",
+ __func__);
+ } else {
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ CAN_IF_MCONT_EOB);
+ dev_dbg(&ndev->dev,
+ "%s -> Buffer Link disabled.\n", __func__);
+ }
+
+ iowrite32(buffer_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter == 0) {
+ dev_err(&ndev->dev, "%s -> Write failed.\n",
+ __func__);
+ retval = -EPERM;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Write successful.\n", __func__);
+ retval = 0;
+ }
+
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_rx_buffer_link(int handle, u32 buffer_num,
+ u32 *link, struct net_device *ndev)
+{
+ u32 reg_val;
+ u32 counter;
+ int retval = 0;
+ u32 if1_creq;
+
+ if ((handle == 0) || (link == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+ retval = -EPERM;
+ } else if ((pch_msg_obj_conf[buffer_num - 1] != MSG_OBJ_RX) ||
+ (buffer_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+ dev_err(&ndev->dev,
+ "%s -> Invalid buffer number %u.\n", __func__, buffer_num);
+ retval = -EPERM;
+ } else {
+ /* Obatining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Reading the corresponding message object. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(buffer_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32((can->io_base +
+ CAN_IF1_CREQ_OFFSET)) & CAN_IF_CREQ_BUSY);
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ /* Confirming read. */
+ if ((counter == 0)) {
+ dev_err(&ndev->dev, "%s -> Read Failed.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Checking for the EOB bit.
+ EOB bit = 1 -> Buffer link disabled.
+ EOB bit = 0 -> Biffer link enabled.
+ */
+ reg_val = ioread32(can->io_base +
+ CAN_IF1_MCONT_OFFSET);
+ if (reg_val & CAN_IF_MCONT_EOB)
+ *link = DISABLE;
+ else
+ *link = ENABLE;
+ dev_dbg(&ndev->dev, "%s -> EOB bit = %d\n", __func__,
+ (reg_val & CAN_IF_MCONT_EOB) >> BIT_SHIFT_SEVEN);
+ dev_dbg(&ndev->dev,
+ "%s -> Buffer Link = %u (1 - Set ,0 -> not set)\n",
+ __func__, *link);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_get_rx_filter(int handle, struct pch_can_rx_filter *filter,
+ struct net_device *ndev)
+{
+ u32 reg_val1;
+ u32 reg_val2;
+ u32 counter;
+ int retval = 0;
+ u32 if1_creq;
+
+ if ((handle == 0) || (filter == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Preparing to read the specified Msg Obj. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(filter->num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+
+ /* Confirming the read completion. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) & CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) { /* Read unsuccessful. */
+ dev_err(&ndev->dev,
+ "%s -> Reading of receive buffer %u failed.\n",
+ __func__, filter->num);
+ retval = -EPERM;
+ } else { /* read successful. */
+
+ /* Checking for Umask */
+ reg_val1 = ioread32((can->io_base +
+ CAN_IF1_MCONT_OFFSET));
+ filter->umask = ((CAN_IF_MCONT_UMASK & reg_val1) >>
+ BIT_SHIFT_TWELVE);
+
+ if (filter->umask == 1) { /* If Umask is set */
+ /* Getting the Mask data. */
+
+ /* Reading MASK2 register. */
+ reg_val1 = ioread32((can->io_base +
+ CAN_IF1_MASK2_OFFSET));
+
+ if ((CAN_IF_MASK2_MXTD & reg_val1) != 0) {
+ /* Extended Mask set.
+ Mask ID is 29 bits */
+ reg_val2 = ioread32((can->io_base +
+ CAN_IF1_MASK1_OFFSET));
+
+ /* Extracting the 16 MSB bits of the
+ 29bit ID. */
+ reg_val2 = reg_val2 & MSK_ALL_SIXTEEN;
+ /* Extracting the remaing 13 bits */
+ reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+ /* Combing them to a single 29bit ID. */
+ reg_val1 =
+ reg_val1 << BIT_SHIFT_SIXTEEN;
+ reg_val1 = reg_val1 | reg_val2;
+
+ filter->amr.id = reg_val1;
+ filter->amr.id_ext = 1;
+ } else { /* Standard Mask 11bit Mask ID */
+
+ /* Extracting the 13 bits of MASK2
+ register. */
+ reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+ /* Modifying it to represent 11bit Mask
+ ID */
+ reg_val1 = reg_val1 >> BIT_SHIFT_TWO;
+
+ filter->amr.id = reg_val1;
+ filter->amr.id_ext = 0;
+ }
+ }
+
+ reg_val1 = ioread32((can->io_base +
+ CAN_IF1_ID2_OFFSET));
+
+ if ((CAN_ID2_XTD & reg_val1) != 0) { /* Extended ID
+ 29bits */
+ reg_val2 = ioread32((can->io_base +
+ CAN_IF1_ID1_OFFSET));
+
+ /* Extracting the 16 MSB bits of the 29bit
+ ID. */
+ reg_val2 = reg_val2 & MSK_ALL_SIXTEEN;
+ /* Extracting the remaining 13 bit. */
+ reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+
+ /* Combining them to represent 29bit ID. */
+ reg_val1 = reg_val1 << BIT_SHIFT_SIXTEEN;
+ reg_val1 = reg_val1 | reg_val2;
+
+ filter->aidr.id = reg_val1;
+ filter->aidr.id_ext = 1;
+ } else { /* Standard Id 11bits. */
+
+ /* Extracting the 13 bits of ID2 register */
+ reg_val1 = reg_val1 & MSK_ALL_THIRTEEN;
+ /* Modifying it to represent the 11 bit ID */
+ reg_val1 = reg_val1 >> BIT_SHIFT_TWO;
+
+ filter->aidr.id = reg_val1;
+ filter->aidr.id_ext = 0;
+ }
+
+ dev_dbg(&ndev->dev,
+ "%s -> Successfully read the filter of Msg Obj %u.\n",
+ __func__, filter->num);
+ }
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_clear_buffers(int handle)
+{
+ u32 i;
+ u32 rx_buff_num;
+ u32 tx_buff_num;
+ int retval = 0;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else {
+ /* Obatining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ iowrite32(CAN_CMASK_RX_TX_SET,
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32(CAN_CMASK_RX_TX_SET,
+ (can->io_base + CAN_IF2_CMASK_OFFSET));
+
+ iowrite32(MSK_ALL_SIXTEEN,
+ (can->io_base + CAN_IF1_MASK1_OFFSET));
+ iowrite32(MSK_ALL_SIXTEEN,
+ (can->io_base + CAN_IF1_MASK2_OFFSET));
+ iowrite32(MSK_ALL_SIXTEEN,
+ (can->io_base + CAN_IF2_MASK1_OFFSET));
+ iowrite32(MSK_ALL_SIXTEEN,
+ (can->io_base + CAN_IF2_MASK2_OFFSET));
+
+ iowrite32(0x0, (can->io_base + CAN_IF1_ID1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF1_ID2_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_ID1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_ID2_OFFSET));
+
+ iowrite32(0x0, (can->io_base + CAN_IF1_MCONT_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_MCONT_OFFSET));
+
+ iowrite32(0x0, (can->io_base + CAN_IF1_DATAA1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF1_DATAA2_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF1_DATAB1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF1_DATAB2_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_DATAA1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_DATAA2_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_DATAB1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF2_DATAB2_OFFSET));
+
+ for (i = 1; i <= (MAX_MSG_OBJ / 2); i++) {
+ rx_buff_num = 2 * i;
+ tx_buff_num = (2 * i) - 1;
+
+ iowrite32(rx_buff_num,
+ (can->io_base + CAN_IF1_CREQ_OFFSET));
+ iowrite32(tx_buff_num,
+ (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+ mdelay(10);
+ }
+ }
+
+ return retval;
+}
+
+static void pch_can_config_rx_tx_buffers(int handle, struct net_device *ndev)
+{
+ u32 i;
+ u32 counter;
+ u32 if1_creq;
+ u32 if2_creq;
+
+ if (handle != 0) { /* if handle valid. */
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /*For accssing MsgVal, ID and EOB bit */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+ CAN_CMASK_CTRL),
+ (can->io_base + CAN_IF1_CMASK_OFFSET));
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_ARB |
+ CAN_CMASK_CTRL),
+ (can->io_base + CAN_IF2_CMASK_OFFSET));
+
+ iowrite32(0x0, (can->io_base + CAN_IF1_ID1_OFFSET));
+ iowrite32(0x0, (can->io_base + CAN_IF1_ID2_OFFSET));
+ /* Resetting DIR bit for reception */
+ iowrite32(0x0, (can->io_base + CAN_IF2_ID1_OFFSET));
+ iowrite32((CAN_ID2_DIR | (MSK_ALL_ELEVEN << 2)),
+ (can->io_base + CAN_IF2_ID2_OFFSET));
+ /* Setting DIR bit for transmission */
+
+ iowrite32(CAN_IF_MCONT_EOB,
+ (can->io_base + CAN_IF1_MCONT_OFFSET));
+ /* Setting EOB bit for receiver */
+ iowrite32(CAN_IF_MCONT_EOB,
+ (can->io_base + CAN_IF2_MCONT_OFFSET));
+ /* Setting EOB bit for transmitter */
+
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ counter = COUNTER_LIMIT;
+ /* Configure the receive message objects */
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+
+ iowrite32((i + 1), (can->io_base +
+ CAN_IF1_CREQ_OFFSET));
+
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ dev_dbg(&ndev->dev, "%s ->Config failed"
+ " for receive message object %u\n",
+ __func__, (i + 1));
+ }
+ }
+ /* Configure the transmit message objects */
+ else if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+ iowrite32((i + 1), (can->io_base +
+ CAN_IF2_CREQ_OFFSET));
+
+ while (counter) {
+ if2_creq = (ioread32(can->io_base +
+ CAN_IF2_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if2_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ dev_dbg(&ndev->dev, "%s ->Config failed"
+ " for transmit message object %u\n",
+ __func__, (i + 1));
+ }
+ }
+
+ }
+ }
+}
+
+static int pch_can_open(int handle, enum pch_can_listen_mode listen,
+ enum pch_can_arbiter arbiter, struct net_device *ndev)
+{
+ int retval;
+ s32 i;
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ do {
+ /* Stopping the Can device. */
+ retval = pch_can_set_run_mode(handle, PCH_CAN_STOP,
+ ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_run_mode "
+ "failed(returned %d).\n", __func__, retval);
+
+ break;
+ }
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_set_run_mode invoked successfully.\n",
+ __func__);
+
+ /* Clearing all the message object buffers. */
+ retval = pch_can_clear_buffers(handle);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev, "%s ->pch_can_clear_buffers"
+ " failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s ->pch_can_clear_buffers invoked"
+ " successfully(returned %d).\n", __func__, retval);
+
+ /* Configuring the respective message object as either
+ receive/transmit object. */
+ pch_can_config_rx_tx_buffers(handle, ndev);
+ dev_dbg(&ndev->dev, "%s -> pch_can_config_rx_tx_buffers"
+ " invoked successfully.\n", __func__);
+
+ /* Initializing filters for receive object. */
+ for (i = 0;
+ i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+ /* Here i denotes the index, however
+ the object number is (i+1) */
+ retval =
+ pch_can_rx_init_filter(handle,
+ (i + 1), ndev);
+
+ if (retval != 0) {
+ dev_err(&ndev->dev,
+ "pch_can_rx_init_filter "
+ "failed for msg obj:%d\n",
+ (i + 1));
+ break;
+ }
+ }
+ }
+ if (retval != 0)
+ break;
+ dev_dbg(&ndev->dev, "%s -> pch_can_rx_init_filter "
+ "invoked successfully.\n", __func__);
+
+ /* Enabling all receive objects. */
+ retval = pch_can_rx_enable_all(handle, ndev);
+
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_rx_enable_all "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_rx_enable_all "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Enabling all transmit objects. */
+ retval = pch_can_tx_enable_all(handle, ndev);
+
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_tx_enable_all failed"
+ "(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_tx_enable_all "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Setting the arbiter mode. */
+ retval = pch_can_set_arbiter_mode(handle, arbiter,
+ ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_arbiter_mode "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_arbiter_mode "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Setting the listen mode. */
+ retval = pch_can_set_listen_mode(handle, listen, ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_listen_mode "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_listen_mode "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Enabling the interrupts. */
+ retval = pch_can_set_int_enables(handle, CAN_ALL, ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_int_enables "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_int_enables "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Setting the restart mode. */
+ retval = pch_can_set_restart_mode(handle, CAN_AUTO,
+ ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_restart_mode failed"
+ "(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_restart_mode "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Setting the CAN to run mode. */
+ retval = pch_can_set_run_mode(handle, PCH_CAN_RUN,
+ ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_run_mode "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_set_run_mode "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ } while (false);
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_release(int handle, struct net_device *ndev)
+{
+ int retval = 0;
+
+ if (handle == 0) {
+ dev_err(&ndev->dev, "%s -> Invalid handle.\n", __func__);
+ retval = -EPERM;
+ } else {
+ do {
+ /* Stooping the CAN device. */
+ retval = pch_can_set_run_mode(handle, PCH_CAN_STOP,
+ ndev);
+
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_run_mode failed"
+ "(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_run_mode invoked"
+ " successfully(returned %d).\n", __func__, retval);
+
+ /* Disabling the interrupts. */
+ retval = pch_can_set_int_enables(handle, CAN_NONE,
+ ndev);
+
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_set_int_enables failed"
+ "(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev, "%s -> pch_can_set_int_enables "
+ "invoked successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Disabling all the receive object. */
+ retval = pch_can_rx_disable_all(handle, ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_rx_disable_all "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_rx_disable_all invoked "
+ "successfully(returned %d).\n", __func__, retval);
+
+ /* Disabling all the transmit object. */
+ retval = pch_can_tx_disable_all(handle, ndev);
+ if (retval == -EPERM) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_tx_disable_all "
+ "failed(returned %d).\n", __func__, retval);
+ break;
+ }
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_tx_disable_all invoked "
+ "successfully(returned %d).\n", __func__, retval);
+
+ } while (false);
+ }
+
+ dev_dbg(&ndev->dev, "%s returns %d.\n", __func__, retval);
+ return retval;
+}
+
+/* This function clears interrupt(s) from the CAN device. */
+static void pch_can_int_clr(int handle, u32 mask, struct net_device *ndev)
+{
+ u32 counter;
+ u32 rtr;
+ u32 if2_creq;
+
+ if ((handle != 0) && (mask != 0)) { /* if valid
+ parameters. */
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Clearing status interrupt. */
+ if (mask == CAN_STATUS_INT) {
+ ioread32((can->io_base + CAN_STAT_OFFSET));
+ dev_dbg(&ndev->dev,
+ "%s -> Status Interrupt cleared.\n", __func__);
+ } else if ((mask > 0) && (mask <= MAX_MSG_OBJ)) {
+ /* Clear interrupt for transmit object */
+ if (pch_msg_obj_conf[mask - 1] == MSG_OBJ_TX) {
+ /* Checking if the transmission is for remote
+ frame. */
+ rtr = ((ioread32((can->io_base +
+ CAN_IF2_ID2_OFFSET)) &
+ CAN_ID2_DIR) == 0);
+
+ if (rtr == 1) {
+
+ dev_dbg(&ndev->dev,
+ "%s -> Remote frame transmission "
+ "interrupt cleared for message"
+ "object %d.\n", __func__, mask);
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Data frame transmission "
+ "interrupt cleared for message "
+ "object %d.\n", __func__, mask);
+ }
+
+ /* Setting CMASK for clearing interrupts for
+ frame transmission. */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL |
+ CAN_CMASK_ARB),
+ (can->io_base +
+ CAN_IF2_CMASK_OFFSET));
+
+ /* Resetting the ID registers. */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF2_ID2_OFFSET),
+ (CAN_ID2_DIR |
+ (MSK_ALL_ELEVEN << 2)));
+ iowrite32(0x0,
+ (can->io_base + CAN_IF2_ID1_OFFSET));
+
+ /* Claring NewDat, TxRqst & IntPnd */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF2_MCONT_OFFSET),
+ (CAN_IF_MCONT_NEWDAT |
+ CAN_IF_MCONT_INTPND |
+ CAN_IF_MCONT_TXRQXT));
+
+ iowrite32(mask,
+ (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if2_creq = (ioread32(can->io_base +
+ CAN_IF2_CREQ_OFFSET) &
+ CAN_IF_CREQ_BUSY);
+ if (if2_creq == 0)
+ break;
+
+ counter--;
+ }
+ }
+ /* Clear interrupt for receive object */
+ else if (pch_msg_obj_conf[mask - 1] == MSG_OBJ_RX) {
+ /* Checking if the reception is for remote
+ frame. */
+ rtr = ((ioread32((can->io_base +
+ CAN_IF2_ID2_OFFSET)) &
+ CAN_ID2_DIR) != 0);
+
+ if (rtr == 1) { /* if remote frame. */
+ dev_dbg(&ndev->dev,
+ "%s -> Remote frame reception "
+ "interrupt cleared for message "
+ "object %d.\n", __func__, mask);
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Data frame reception "
+ "interrupt cleared for message object"
+ "%d.\n", __func__, mask);
+ }
+
+ /* Setting CMASK for clearing the reception
+ interrupts. */
+ iowrite32((CAN_CMASK_RDWR | CAN_CMASK_CTRL |
+ CAN_CMASK_ARB),
+ (can->io_base +
+ CAN_IF2_CMASK_OFFSET));
+
+ /* Clearing the Dir bit. */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF2_ID2_OFFSET),
+ CAN_ID2_DIR);
+
+ /* Clearing NewDat & IntPnd */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF2_MCONT_OFFSET),
+ (CAN_IF_MCONT_NEWDAT |
+ CAN_IF_MCONT_INTPND));
+
+ iowrite32(mask,
+ (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if2_creq = ioread32(can->io_base +
+ CAN_IF2_CREQ_OFFSET) &
+ CAN_IF_CREQ_BUSY;
+ if (if2_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ }
+ }
+ }
+}
+
+static int pch_can_get_buffer_status(int handle)
+{
+ u32 reg_treq1;
+ u32 reg_treq2;
+ int retval = 0;
+
+ if (handle == 0) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Reading the transmission request registers. */
+ reg_treq1 = (ioread32(can->io_base + CAN_TREQ1_OFFSET) &
+ MSK_ALL_SIXTEEN);
+ reg_treq2 = ((ioread32(can->io_base + CAN_TREQ2_OFFSET) &
+ MSK_ALL_SIXTEEN) << BIT_SHIFT_SIXTEEN);
+
+ retval = (reg_treq1 | reg_treq2);
+ }
+
+ return retval;
+}
+
+static int pch_can_msg_tx(int handle, struct pch_can_msg *msg,
+ struct net_device *ndev)
+{
+ u32 id1 = 0;
+ u32 id2 = 0;
+ u32 data_a1 = 0;
+ u32 data_a2 = 0;
+ u32 data_b1 = 0;
+ u32 data_b2 = 0;
+ u32 tx_disable_counter = 0;
+ u32 buffer_status = 0;
+ u32 tx_buffer_avail = 0;
+ u32 status;
+ u32 i;
+ u32 counter;
+ enum pch_can_run_mode run_mode;
+ int retval = 0;
+ u32 if1_creq;
+
+ if ((handle == 0) || (msg == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+ retval = -EPERM;
+ }
+
+ else {
+ /* Obatining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ /* Getting the current CAN mode. */
+ pch_can_get_run_mode(handle, &run_mode, ndev);
+
+ /* If CAN is in STOP mode. */
+ if (run_mode != PCH_CAN_RUN) {
+ dev_err(&ndev->dev,
+ "%s -> CAN stopped on transmit attempt.\n", __func__);
+ retval = -EPERM;
+ } else {
+ unsigned long flags;
+ /* Attaining the lock. */
+ spin_lock_irqsave(&can_os->tx_spinlock, flags);
+
+ /* Getting the message object status. */
+ buffer_status = (u32) pch_can_get_buffer_status(handle);
+
+ /* Getting the free transmit message object. */
+ for (i = 0;
+ i < (pch_can_rx_buf_size + pch_can_tx_buf_size);
+ i++) {
+ if ((pch_msg_obj_conf[i] == MSG_OBJ_TX)) {
+ /* Checking whether the object is
+ enabled. */
+ pch_can_get_tx_enable(handle,
+ (i + 1),
+ &status, ndev);
+
+ if ((ENABLE == status)) {
+ if ((((buffer_status >> i) & 1)
+ == 0)) {
+ tx_buffer_avail =
+ (i + 1);
+ break;
+ }
+ } else {
+ tx_disable_counter++;
+ }
+ }
+ }
+
+ /* If no transmit object available. */
+ if (tx_buffer_avail == 0) {
+ dev_dbg(&ndev->dev, "%s -> tx_disable_counter "
+ "= %d.\n", __func__, tx_disable_counter);
+ /* If no object is enabled. */
+ if ((tx_disable_counter ==
+ pch_can_tx_buf_size)){
+ retval = -EPERM;
+ dev_err(&ndev->dev,
+ "%s -> All transmit buffers "
+ "are disabled.\n", __func__);
+ } else {
+ dev_err(&ndev->dev,
+ "%s -> No transmit buffer free.\n",
+ __func__);
+ retval = PCH_CAN_NO_TX_BUFF;
+ }
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s ->Transmit buffer obtained.\n", __func__);
+
+ /* Reading the message object from the Message
+ RAM to the Interface register. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base +
+ CAN_IF1_CMASK_OFFSET));
+ iowrite32(tx_buffer_avail,
+ (can->io_base +
+ CAN_IF1_CREQ_OFFSET));
+
+ /* Confirming the read. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+ /* If Read not successful. */
+ if (counter == 0) {
+ pch_can_set_tx_enable(handle,
+ tx_buffer_avail,
+ ENABLE, ndev);
+ retval = -EPERM;
+ } else {
+ /* Setting the CMASK register. */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_CMASK_OFFSET),
+ CAN_CMASK_ALL);
+
+ /* If ID extended is set. */
+ if (msg->ide == 1) {
+ /* Setting 29 bit ID with XTD
+ bit set. */
+ id1 =
+ (msg->id & MSK_ALL_SIXTEEN);
+ id2 =
+ ((msg->
+ id & (MSK_ALL_THIRTEEN <<
+ BIT_SHIFT_SIXTEEN))
+ >> BIT_SHIFT_SIXTEEN);
+
+ id2 |= CAN_ID2_XTD;
+ } else {
+ /* Setting 11bit ID with XTD bit
+ reset. */
+ id1 = 0;
+ id2 =
+ ((msg->
+ id & MSK_ALL_ELEVEN) <<
+ BIT_SHIFT_TWO);
+ }
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID1_OFFSET),
+ MSK_ALL_SIXTEEN);
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ (MSK_ALL_THIRTEEN |
+ CAN_ID2_XTD));
+
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_ID1_OFFSET),
+ id1);
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ id2);
+
+ /* If remote frame has to be
+ transmitted.. */
+ if (msg->rtr == 1) {
+ PCH_CAN_BIT_CLEAR((
+ can->io_base +
+ CAN_IF1_ID2_OFFSET),
+ CAN_ID2_DIR);
+ msg->dlc = 0;
+
+ dev_dbg(&ndev->dev,
+ "%s -> Transmitting a remote"
+ " frame.\n", __func__);
+ } else { /* Data frame
+ transmission. */
+
+ msg->dlc &= MSK_ALL_FOUR;
+
+ dev_dbg(&ndev->dev,
+ "%s -> Transmitting a data "
+ "frame.\n", __func__);
+ }
+
+ /* Writing the data and the DLC */
+ switch (msg->dlc) {
+ case 0:
+ break;
+
+ case 1:
+ data_a1 = msg->data[0];
+ break;
+ case 2:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ break;
+ case 3:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ break;
+ case 4:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ data_a2 |=
+ (((u32) msg->
+ data[3]) <<
+ BIT_SHIFT_EIGHT);
+ break;
+ case 5:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ data_a2 |=
+ (((u32) msg->
+ data[3]) <<
+ BIT_SHIFT_EIGHT);
+ data_b1 = msg->data[4];
+ break;
+ case 6:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ data_a2 |=
+ (((u32) msg->
+ data[3]) <<
+ BIT_SHIFT_EIGHT);
+ data_b1 = msg->data[4];
+ data_b1 |=
+ (((u32) msg->
+ data[5]) <<
+ BIT_SHIFT_EIGHT);
+ break;
+ case 7:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ data_a2 |=
+ (((u32) msg->
+ data[3]) <<
+ BIT_SHIFT_EIGHT);
+ data_b1 = msg->data[4];
+ data_b1 |=
+ (((u32) msg->
+ data[5]) <<
+ BIT_SHIFT_EIGHT);
+ data_b2 = msg->data[6];
+ break;
+ case 8:
+ default:
+ data_a1 = msg->data[0];
+ data_a1 |=
+ (((u32) msg->
+ data[1]) <<
+ BIT_SHIFT_EIGHT);
+ data_a2 = msg->data[2];
+ data_a2 |=
+ (((u32) msg->
+ data[3]) <<
+ BIT_SHIFT_EIGHT);
+ data_b1 = msg->data[4];
+ data_b1 |=
+ (((u32) msg->
+ data[5]) <<
+ BIT_SHIFT_EIGHT);
+ data_b2 = msg->data[6];
+ data_b2 |=
+ (((u32) msg->
+ data[7]) <<
+ BIT_SHIFT_EIGHT);
+ break;
+
+ }
+
+ /* Writing the DATA registers. */
+ iowrite32(data_a1,
+ (can->io_base +
+ CAN_IF1_DATAA1_OFFSET));
+ iowrite32(data_a2,
+ (can->io_base +
+ CAN_IF1_DATAA2_OFFSET));
+ iowrite32(data_b1,
+ (can->io_base +
+ CAN_IF1_DATAB1_OFFSET));
+ iowrite32(data_b2,
+ (can->io_base +
+ CAN_IF1_DATAB2_OFFSET));
+
+ /* Updating the size of the data. */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ MSK_ALL_FOUR);
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ msg->dlc);
+
+ /* Clearing IntPend, NewDat & TxRqst */
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ (CAN_IF_MCONT_NEWDAT |
+ CAN_IF_MCONT_INTPND |
+ CAN_IF_MCONT_TXRQXT));
+
+ /* Setting NewDat, TxRqst bits */
+ PCH_CAN_BIT_SET((can->io_base +
+ CAN_IF1_MCONT_OFFSET),
+ (CAN_IF_MCONT_NEWDAT |
+ CAN_IF_MCONT_TXRQXT));
+
+ /* Writing the updation to the Message
+ object. */
+ iowrite32(tx_buffer_avail,
+ (can->io_base +
+ CAN_IF1_CREQ_OFFSET));
+
+ /* Confirming the updation. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if1_creq = (ioread32(
+ can->io_base +
+ CAN_IF1_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+ if (if1_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if ((counter == 0)) {
+ retval = -EPERM;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> Updation of transmit "
+ "buffer successful.\n"
+ "Message object enabled "
+ "for transmission.\n",
+ __func__);
+ }
+
+ } /* if message read object successful */
+ } /* if transmit buffer available */
+
+ /* Releasing the lock. */
+ spin_unlock_irqrestore(&can_os->tx_spinlock, flags);
+ } /* if device in run mode */
+ } /* if parameters valid */
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d.\n", __func__, retval);
+ return retval;
+}
+
+/* This function gets a pending message from the CAN device. */
+static int pch_can_rx_dequeue(int handle, struct pch_can_msg *msg,
+ u32 buff_num, struct net_device *ndev)
+{
+ s32 i;
+ u32 reg;
+ int retval = -EPERM;
+
+ if ((handle == 0) || (msg == NULL)) {
+ dev_err(&ndev->dev, "%s -> Invalid Parameter.\n", __func__);
+ } else if ((pch_msg_obj_conf[buff_num - 1] != MSG_OBJ_RX) ||
+ (buff_num > (pch_can_rx_buf_size + pch_can_tx_buf_size))) {
+ /* invalid buffer number. */
+ dev_err(&ndev->dev, "%s -> Invalid Buffer number.\n", __func__);
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) handle;
+
+ msg->ide = 0;
+ msg->id = 0;
+ msg->dlc = 0;
+ for (i = 0; i < PCH_CAN_MSG_DATA_LEN;)
+ msg->data[i++] = 0;
+
+ /* Read the ID type. */
+ msg->ide = ((ioread32(can->io_base + CAN_IF2_ID2_OFFSET)) &
+ CAN_ID2_XTD) >> BIT_SHIFT_FOURTEEN;
+
+ /* Extracting the ID. */
+ if (msg->ide == 1) { /* Extended 29bit ID. */
+ msg->id = (ioread32(can->io_base +
+ CAN_IF2_ID1_OFFSET) & MSK_ALL_SIXTEEN);
+ msg->id |= (((ioread32(can->io_base +
+ CAN_IF2_ID2_OFFSET)) &
+ MSK_ALL_THIRTEEN) << BIT_SHIFT_SIXTEEN);
+ } else { /* Standard 11bit ID. */
+
+ msg->id = (((ioread32(can->io_base +
+ CAN_IF2_ID2_OFFSET)) &
+ (MSK_ALL_ELEVEN <<
+ BIT_SHIFT_TWO)) >>
+ BIT_SHIFT_TWO);
+ }
+
+ /* Getting the size of the data and the Remote frame bit. */
+ if (msg->rtr == 1) {
+ msg->dlc = 0;
+
+ dev_dbg(&ndev->dev,
+ "%s -> Remote frame read with message id: %x.\n",
+ __func__, msg->id);
+ } else {
+ msg->dlc = ((ioread32(can->io_base +
+ CAN_IF2_MCONT_OFFSET)) &
+ MSK_ALL_FOUR);
+
+ dev_dbg(&ndev->dev,
+ "%s -> Data frame read with message id: %x.\n",
+ __func__, msg->id);
+ }
+
+ /* Reading back the data. */
+ switch (msg->dlc) {
+ case 0:
+ break;
+
+ case 1:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ break;
+
+ case 2:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+ break;
+
+ case 3:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ break;
+
+ case 4:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ msg->data[3] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+ break;
+
+ case 5:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ msg->data[3] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+ msg->data[4] = reg & MSK_ALL_EIGHT;
+ break;
+
+ case 6:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ msg->data[3] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+ msg->data[4] = reg & MSK_ALL_EIGHT;
+ msg->data[5] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+ break;
+
+ case 7:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ msg->data[3] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+ msg->data[4] = reg & MSK_ALL_EIGHT;
+ msg->data[5] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB2_OFFSET);
+ msg->data[6] = reg & MSK_ALL_EIGHT;
+ break;
+
+ case 8:
+ default:
+ reg = ioread32(can->io_base + CAN_IF2_DATAA1_OFFSET);
+ msg->data[0] = reg & MSK_ALL_EIGHT;
+ msg->data[1] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAA2_OFFSET);
+ msg->data[2] = reg & MSK_ALL_EIGHT;
+ msg->data[3] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB1_OFFSET);
+ msg->data[4] = reg & MSK_ALL_EIGHT;
+ msg->data[5] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ reg = ioread32(can->io_base + CAN_IF2_DATAB2_OFFSET);
+ msg->data[6] = reg & MSK_ALL_EIGHT;
+ msg->data[7] =
+ ((reg & (MSK_ALL_EIGHT << BIT_SHIFT_EIGHT))
+ >> BIT_SHIFT_EIGHT);
+
+ break;
+ }
+ retval = 0;
+ }
+
+ dev_dbg(&ndev->dev, "%s -> Return value: %d\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_reset(struct pch_can_os *can_os)
+{
+ int retval = 0;
+
+ if ((can_os == NULL)) {
+ retval = -EPERM;
+ } else {
+ /* Obtaining the remap address for access. */
+ struct can_hw *can = (struct can_hw *) can_os->can;
+
+ /* write to sw reset register */
+ iowrite32(1, (can->io_base + CAN_SRST_OFFSET));
+ iowrite32(0, (can->io_base + CAN_SRST_OFFSET));
+
+ }
+ return retval;
+}
+
+static irqreturn_t pch_can_handler(int irq, void *dev_id)
+{
+ irqreturn_t retval = IRQ_NONE;
+ u32 int_stat;
+ struct pch_can_os *can_os = (struct pch_can_os *) dev_id;
+ dev_dbg(&can_os->ndev->dev, "%s -> Invoked.\n", __func__);
+
+ int_stat = pch_can_int_pending(can_os->can);
+
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> pch_can_int_pending returned value: %x\n", __func__, int_stat);
+
+ if ((can_os != NULL) && (int_stat > 0)) {
+ can_os->int_stat = int_stat;
+ (*can_os->can_callback) (can_os);
+
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> Callback function invoked successfully.\n", __func__);
+
+ retval = IRQ_HANDLED;
+ }
+ return retval;
+}
+
+static void pch_can_log_message(u32 status, struct net_device *ndev)
+{
+ static int cnt;
+
+ switch ((status & MSK_ALL_THREE)) {
+
+ case 0:
+ dev_dbg(&ndev->dev, "%s -> No Error\n", __func__);
+ break;
+ case 1:
+ dev_err(&ndev->dev, "%s -> Stuff Error\n", __func__);
+ break;
+ case 2:
+ dev_err(&ndev->dev, "%s -> Form Error.\n", __func__);
+ break;
+ case 3:
+ if (cnt % 200 == 0)
+ dev_err(&ndev->dev, "%s -> Ack Error\n", __func__);
+ cnt++;
+ break;
+ case 4:
+ dev_err(&ndev->dev, "%s -> Bit 1 Error\n", __func__);
+ break;
+ case 5:
+ dev_err(&ndev->dev, "%s -> Bit 0 Error.\n", __func__);
+ break;
+ case 6:
+ dev_err(&ndev->dev, "%s -> Crc Error\n", __func__);
+ break;
+ case 7:
+ dev_err(&ndev->dev, "%s -> Undefined Error\n", __func__);
+ break;
+ default:
+ break;
+ }
+}
+
+static void pch_can_entcb(void (*pch_can_cb) (struct pch_can_os *),
+ struct pch_can_os *p_can_os, struct net_device *ndev)
+{
+ if ((pch_can_cb != NULL) && (p_can_os != NULL)) {
+ p_can_os->can_callback = pch_can_cb;
+ dev_dbg(&ndev->dev,
+ "%s -> Callback function set successful.\n", __func__);
+ } else {
+ dev_err(&ndev->dev,
+ "%s -> Callback function set unsuccessful.\n", __func__);
+ }
+}
+
+static void pch_can_callback(struct pch_can_os *can_os)
+{
+ u32 int_stat;
+ u32 reg;
+ u32 reg_stat;
+ u32 counter;
+ struct pch_can_msg receive_msg;
+ struct can_hw *can = (struct can_hw *) (can_os->can);
+ int retval = 0;
+ u32 if2_creq;
+ enum pch_can_auto_restart restart_mode = 0;
+
+
+ /* Get the interrupt status */
+ int_stat = can_os->int_stat;
+ can_os->int_stat = 0;
+
+ /* Checking for status interrupt */
+ if (int_stat == CAN_STATUS_INT) {
+ /* Reading of the CANSTAT register. */
+ reg_stat = ioread32((can->io_base + CAN_STAT_OFFSET));
+ reg_stat = reg_stat & MSK_ALL_EIGHT;
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> Status Register: %x.\n", __func__, reg_stat);
+
+ /* If recovered from Bus-Off interrupt. */
+ if ((reg_stat == 0) && (can_os->bus_off_interrupt == 1)) {
+ can_os->bus_off_interrupt = 0;
+ pch_can_tx_enable_all(can_os->can, can_os->ndev);
+ pch_can_rx_enable_all(can_os->can, can_os->ndev);
+
+ dev_err(&can_os->ndev->dev,
+ "%s -> Bus off stage recovered.\n", __func__);
+ } else {
+ /* Bus off interrupt. */
+ if (reg_stat & ((u32) 1 << BIT_SHIFT_SEVEN)) {
+ if (can_os->bus_off_interrupt == 0) {
+
+ dev_err(&can_os->ndev->dev,
+ "%s -> Bus off "
+ "interrupt.\n", __func__);
+
+ pch_can_tx_disable_all(can_os->can,
+ can_os->ndev);
+ pch_can_rx_disable_all(can_os->can,
+ can_os->ndev);
+
+ pch_can_get_restart_mode(can_os->can,
+ &restart_mode, can_os->ndev);
+
+ if (restart_mode == CAN_AUTO) {
+ can_os->bus_off_interrupt = 1;
+ pch_can_set_run_mode(
+ can_os->can,
+ PCH_CAN_RUN,
+ can_os->ndev);
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> Device restarted.\n",
+ __func__);
+ }
+ }
+ }
+ /* EWarn interrupt. */
+ if ((reg_stat & ((u32) 1 << BIT_SHIFT_SIX)) != 0) {
+ dev_info(&can_os->ndev->dev,
+ "%s -> EWarn interrupt.\n", __func__);
+ }
+ /* EPass interrupt. */
+ if ((reg_stat & ((u32) 1 << BIT_SHIFT_FIVE)) != 0) {
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> EPass interrupt.\n", __func__);
+ }
+ /* RxOK interrupt. */
+ if ((reg_stat & ((u32) 1 << BIT_SHIFT_FOUR)) != 0) {
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> RxOK interrupt.\n", __func__);
+ reg_stat =
+ reg_stat & ~((u32) 1 << BIT_SHIFT_FOUR);
+ }
+ /* TxOK interrupt */
+ if ((reg_stat & ((u32) 1 << BIT_SHIFT_THREE)) != 0) {
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> TxOK interrupt.\n", __func__);
+ reg_stat =
+ reg_stat & ~((u32) 1 << BIT_SHIFT_THREE);
+ }
+ /* Error status */
+ pch_can_log_message((reg_stat & MSK_ALL_THREE),
+ can_os->ndev);
+ reg_stat = reg_stat & ~(MSK_ALL_THREE);
+
+ /* Clearing status register interrupt bits. */
+ iowrite32(reg_stat,
+ (can->io_base + CAN_STAT_OFFSET));
+
+ int_stat = pch_can_int_pending(can_os->can);
+ }
+ }
+
+ /* Message object interrupt. */
+ if ((int_stat > 0) && (int_stat <= MAX_MSG_OBJ)) {
+ /* Reading the messsage object from the Message RAM to the
+ interface registers. */
+ iowrite32(CAN_CMASK_RX_TX_GET,
+ (can->io_base + CAN_IF2_CMASK_OFFSET));
+ iowrite32((int_stat),
+ (can->io_base + CAN_IF2_CREQ_OFFSET));
+
+ /* Confirming the read. */
+ counter = COUNTER_LIMIT;
+ while (counter) {
+ if2_creq = (ioread32(can->io_base +
+ CAN_IF2_CREQ_OFFSET)) &
+ CAN_IF_CREQ_BUSY;
+
+ if (if2_creq == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter > 0) { /* If read successful. */
+ /* Reading the MCONT register. */
+ reg = ioread32((can->io_base +
+ CAN_IF2_MCONT_OFFSET));
+ reg &= MSK_ALL_SIXTEEN;
+
+ /* If MsgLost bit set. */
+ if ((reg & CAN_IF_MCONT_MSGLOST) != 0) {
+ PCH_CAN_BIT_CLEAR((can->io_base +
+ CAN_IF2_MCONT_OFFSET),
+ CAN_IF_MCONT_MSGLOST);
+
+ dev_err(&can_os->ndev->dev,
+ "%s -> Message object %d has "
+ "been overwritten.\n", __func__, int_stat);
+ }
+
+ /* Read the direction bit for determination of remote
+ frame during reception. */
+ receive_msg.rtr = ((ioread32((can->io_base +
+ CAN_IF2_ID2_OFFSET)) &
+ CAN_ID2_DIR) != 0);
+
+ /* Clearing interrupts. */
+ pch_can_int_clr(can_os->can, int_stat, can_os->ndev);
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> pch_can_int_clr invoked successfully.\n",
+ __func__);
+
+ /* Hanlde reception interrupt */
+ if (pch_msg_obj_conf[int_stat - 1] == MSG_OBJ_RX) {
+ /* If new data arrived */
+ if ((reg & CAN_IF_MCONT_NEWDAT) != 0) {
+ /* Reading the message object content.*/
+ retval =
+ pch_can_rx_dequeue(can_os->can,
+ &receive_msg,
+ int_stat, can_os->ndev);
+
+ if (retval == 0) {
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ struct net_device_stats *stats;
+ stats = &(can_os->ndev->stats);
+ /* create zero'ed CAN frame
+ buffer */
+ skb = alloc_can_skb
+ (can_os->ndev, &cf);
+ if (skb == NULL)
+ return;
+
+ if (receive_msg.ide) {
+ cf->can_id =
+ ((receive_msg.id) &
+ 0x1fffffff) |
+ 0x80000000;
+ } else { /* Standard*/
+ cf->can_id =
+ ((receive_msg.id) &
+ 0x00000fff);
+ }
+ if (receive_msg.rtr)
+ cf->can_id |=
+ 0x40000000;
+ cf->can_dlc = receive_msg.dlc;
+ memcpy(cf->data,
+ receive_msg.data, 8);
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ }
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> Reception interrupt handled "
+ "for receive message object %u.\n",
+ __func__, int_stat);
+ }
+
+ }
+ /* Hanlde transmission interrupt */
+ else if (pch_msg_obj_conf[int_stat - 1] == MSG_OBJ_TX) {
+ can_get_echo_skb(can_os->ndev, 0);
+ netif_wake_queue(can_os->ndev);
+
+ dev_dbg(&can_os->ndev->dev,
+ "%s -> Transmission interrupt handled for "
+ "transmit message object %u.\n",
+ __func__, int_stat);
+ }
+ }
+ }
+}
+
+static void pch_can_start(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ pch_can_reset(priv->pch_can_os_p);
+
+ return;
+}
+
+static int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ pch_can_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int pch_can_get_state(const struct net_device *ndev,
+ enum can_state *state)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+
+ *state = priv->can.state;
+ return 0;
+}
+
+static int get_baud_id(int baud_bps)
+{
+ int id;
+ switch (baud_bps) {
+ case 10000:/* 10kbps*/
+ id = PCH_CAN_BAUD_10;
+ break;
+ case 20000:
+ id = PCH_CAN_BAUD_20;
+ break;
+ case 50000:
+ id = PCH_CAN_BAUD_50;
+ break;
+ case 125000:
+ id = PCH_CAN_BAUD_125;
+ break;
+ case 250000:
+ id = PCH_CAN_BAUD_250;
+ break;
+ case 500000:
+ id = PCH_CAN_BAUD_500;
+ break;
+ case 800000:
+ id = PCH_CAN_BAUD_800;
+ break;
+ case 1000000:
+ id = PCH_CAN_BAUD_1000;
+ break;
+ default:
+ id = -1;
+ }
+ return id;
+}
+
+static int pch_set_bittiming(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct pch_can_os *dev_can_os = priv->pch_can_os_p;
+ const struct can_bittiming *bt = &priv->can.bittiming;
+ struct pch_can_timing pch_can_timing_data;
+ int baurate_id;
+ enum pch_can_run_mode curr_mode;
+ int retval;
+
+ memset(&pch_can_timing_data, 0, sizeof(pch_can_timing_data));
+ pch_can_timing_data.bitrate = bt->bitrate/1000; /* bps to Kbps */
+ pch_can_timing_data.cfg_bitrate = (bt->tq) / (1000000/pch_can_clock);
+ /* Tq to BRP */
+ pch_can_timing_data.cfg_tseg1 = bt->phase_seg1;
+ pch_can_timing_data.cfg_tseg2 = bt->phase_seg2;
+ pch_can_timing_data.cfg_sjw = bt->sjw;
+ pch_can_timing_data.smpl_mode = bt->sample_point;
+ pch_can_timing_data.edge_mode = 0;
+
+ pch_can_get_run_mode(dev_can_os->can,
+ &curr_mode, ndev);
+ if (curr_mode == PCH_CAN_RUN)
+ pch_can_set_run_mode(dev_can_os->can,
+ PCH_CAN_STOP, ndev);
+
+ baurate_id = get_baud_id(bt->bitrate);
+ if (baurate_id == -1)
+ retval = pch_can_set_baud_custom(dev_can_os->can,
+ &pch_can_timing_data);
+ else
+ retval = pch_can_set_baud_simple(dev_can_os->can, baurate_id);
+ if (curr_mode == PCH_CAN_RUN)
+ pch_can_set_run_mode(dev_can_os->can,
+ PCH_CAN_RUN, ndev);
+
+ return 0;
+}
+
+static int pch_open(struct net_device *ndev)
+{
+ int err;
+ int retval;
+ int ret;
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct pch_can_os *dev_can_os = priv->pch_can_os_p;
+
+ ret = mutex_lock_interruptible(&pch_can_mutex);
+ if (ret)
+ return -ERESTARTSYS;
+
+ retval = pch_can_open(dev_can_os->can,
+ PCH_CAN_ACTIVE, PCH_CAN_FIXED_PRIORITY, ndev);
+ if (retval != 0) {
+ dev_err(&ndev->dev,
+ "%s -> pch_can_open failed (returned %d).\n",
+ __func__, retval);
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_open invoked successfully (returned %d).\n",
+ __func__, retval);
+
+ dev_can_os->rx_fifo = create_can_fifo(NUM_NODES, ndev);
+
+ if (!(dev_can_os->rx_fifo)) {
+ dev_err(&ndev->dev, "%s -> create_can_fifo failed.\n",
+ __func__);
+
+ pch_can_release(dev_can_os->can, ndev);
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_release invoked successfully.\n",
+ __func__);
+
+ retval = -EPERM;
+ } else {
+ dev_dbg(&ndev->dev,
+ "%s -> create_can_fifo invoked successfully.\n",
+ __func__);
+
+ /* Registering the callback function for
+ interrupt handling. */
+ pch_can_entcb(pch_can_callback, dev_can_os, ndev);
+ dev_dbg(&ndev->dev,
+ "%s -> pch_can_entcb invoked successfully.\n",
+ __func__);
+
+ err = pci_enable_msi(dev_can_os->dev);
+ if (err != 0) {
+ priv->have_msi = 0;
+ dev_err(&ndev->dev, "Unable to allocate MSI "
+ "interrupt Error: %d\n", err);
+
+ } else {
+ priv->have_msi = 1;
+ }
+
+ /* Update IRQ value */
+ dev_can_os->irq = dev_can_os->dev->irq;
+ ndev->irq = dev_can_os->dev->irq;
+
+ /* Regsitering the interrupt. */
+ retval =
+ request_irq(dev_can_os->dev->irq,
+ pch_can_handler, IRQF_SHARED,
+ ndev->name, dev_can_os
+ );
+
+ if (retval != 0) {
+ pch_can_release(dev_can_os->can, ndev);
+ delete_can_fifo(dev_can_os->rx_fifo, ndev);
+ dev_can_os->rx_fifo = 0;
+ dev_can_os->can_callback = NULL;
+
+ dev_err(&ndev->dev,
+ "%s -> request_irq failed on irq %d"
+ "(returned %d).\n",
+ __func__, dev_can_os->irq, retval);
+ } else {
+ dev_dbg(&ndev->dev, "%s -> request_irq invoked "
+ "successfully(returned %d).\n",
+ __func__, retval);
+
+ /* Assuming that no bus off
+ interrupt. */
+ dev_can_os->bus_off_interrupt = 0;
+ dev_can_os->write_wait_flag = 0;
+
+ /* Setting the block mode. */
+ dev_can_os->block_mode = 1;
+
+ dev_can_os->opened = 1;
+
+ /* Storing the can structure for further
+ use. */
+ retval = 0;
+ }
+ }
+ }
+
+ /* Open common can device */
+ err = open_candev(ndev);
+ if (err) {
+ mutex_unlock(&pch_can_mutex);
+ dev_err(ndev->dev.parent, "open_candev() failed %d\n", err);
+ free_irq(ndev->irq, dev_can_os);
+ return err;
+ }
+
+ netif_start_queue(ndev);
+
+ mutex_unlock(&pch_can_mutex);
+ return 0;
+}
+
+static int pch_close(struct net_device *ndev)
+{
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct pch_can_os *can_os = priv->pch_can_os_p;
+
+ netif_stop_queue(ndev);
+ close_candev(ndev);
+ free_irq(ndev->irq, can_os);
+ if (priv->have_msi != 0)
+ pci_disable_msi(can_os->dev);
+
+ delete_can_fifo(can_os->rx_fifo, ndev);
+ pch_can_release(can_os->can, ndev);
+ can_os->opened = 0;
+ can_os->rx_fifo = 0;
+ can_os->can_callback = NULL;
+
+ return 0;
+}
+
+static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int err; /* error variable. */
+ int ret;
+ struct pch_can_msg msg; /* The message object for writing. */
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct pch_can_os *can_os = priv->pch_can_os_p;
+ struct can_frame *canframe_dat = (struct can_frame *)skb->data;
+ struct net_device_stats *stats = &ndev->stats;
+
+ ret = mutex_lock_interruptible(&pch_can_mutex);
+ if (ret)
+ return -ERESTARTSYS;
+
+ /* Translate CAN core format to CAN PCH's HW format */
+ memset(&msg, 0, sizeof(msg));
+ msg.ide = canframe_dat->can_id & 0x80000000;
+ if (canframe_dat->can_id & 0x80000000) {
+ msg.ide = 1;
+ msg.id = canframe_dat->can_id & 0x1fffffff;/* Extended
+ Message */
+ } else {
+ msg.ide = 0;
+ msg.id = canframe_dat->can_id & 0x00000fff;/* Standard
+ Message */
+
+ }
+
+ msg.dlc = canframe_dat->can_dlc;
+ memcpy(&msg.data, canframe_dat->data, 8);
+
+ if (canframe_dat->can_id & 0x40000000)
+ msg.rtr = 1;
+ else
+ msg.rtr = 0;
+
+ /* If device suspended. */
+ if ((can_os->is_suspending) == 1) {
+ dev_err(&ndev->dev,
+ "%s -> Device is in suspend mode.\n", __func__);
+ dev_dbg(&ndev->dev, "%s returns %d\n", __func__, -EAGAIN);
+ err = -EAGAIN;
+ goto err_out;
+ }
+
+ can_put_echo_skb(skb, ndev, 0);
+ err = pch_can_msg_tx(can_os->can, &msg, ndev);
+
+ if ((err != 0)) {
+ /* Transmission failed due to unavailability of transmit object
+ and it is block mode. */
+ if ((err == PCH_CAN_NO_TX_BUFF) && (can_os->block_mode == 1)) {
+ dev_dbg(&ndev->dev, "%s -> Waiting for "
+ "transmit message object.\n", __func__);
+
+ /* Transmitting again. */
+ err = pch_can_msg_tx(can_os->can, &msg, ndev);
+
+ /* If again error. */
+ if (err != 0) {
+ dev_err(&ndev->dev,
+ "%s -> Transmit failed after 2 attempts.\n",
+ __func__);
+ dev_dbg(&ndev->dev, "%s returns %d\n",
+ __func__, -EPERM);
+ err = -EPERM;
+ goto err_out;
+ }
+ } else { /* If failed due to some other reasons. */
+ dev_err(&ndev->dev,
+ "%s -> Write from CAN device failed %d.\n",
+ __func__, -EIO);
+ dev_dbg(&ndev->dev, "%s returns %d\n", __func__, -EIO);
+ err = -EIO;
+ goto err_out;
+ }
+ }
+ dev_dbg(&ndev->dev,
+ "%s -> Message send for transmission successfully.\n"
+ "The transmitted Message is :\n"
+ "Msg ID : 0x%x\n"
+ "EXT ID : %hu\n"
+ "Msg Size : %hu\n"
+ "Rment : %hu\n"
+ "Dat Byt1 : 0x%x\n"
+ "Dat Byt2 : 0x%x\n"
+ "Dat Byt3 : 0x%x\n"
+ "Dat Byt4 : 0x%x\n"
+ "Dat Byt5 : 0x%x\n"
+ "Dat Byt6 : 0x%x\n"
+ "Dat Byt7 : 0x%x\n"
+ "Dat Byt8 : 0x%x\n"
+ "Write from CAN device successful ( returns %d).",
+ __func__, msg.id, msg.ide, msg.dlc, msg.rtr, msg.data[0],
+ msg.data[1], msg.data[2], msg.data[3], msg.data[4], msg.data[5],
+ msg.data[6], msg.data[7], sizeof(struct pch_can_msg));
+
+ stats->tx_bytes += canframe_dat->can_dlc;
+ stats->tx_packets++;
+
+ mutex_unlock(&pch_can_mutex);
+ return NETDEV_TX_OK;
+
+err_out:
+ mutex_unlock(&pch_can_mutex);
+ return err;
+}
+
+static const struct net_device_ops pch_can_netdev_ops = {
+ .ndo_open = pch_open,
+ .ndo_stop = pch_close,
+ .ndo_start_xmit = pch_xmit,
+};
+
+static void __devexit pch_can_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct pch_can_priv *priv = netdev_priv(ndev);
+ struct pch_can_os *can_os = priv->pch_can_os_p;
+
+ unregister_candev(ndev);
+ pch_can_destroy(can_os->can, ndev);
+ pci_iounmap(pdev, (void *)priv->base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ free_candev(priv->ndev);
+ can_free_echo_skb(ndev, 0);
+ platform_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int pch_can_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ int i; /* Counter variable. */
+ int retval; /* Return value. */
+/* struct pch_can_os *can_os = pdev->dev.driver_data; */
+ struct pch_can_os *can_os =
+ (struct pch_can_os *) dev_get_drvdata(&pdev->dev);
+
+ /* If the device is opened get the current run mode. */
+ if (can_os->opened == 1) {
+ /* Save the Run Mode. */
+ pch_can_get_run_mode(can_os->can, &(can_os->run_mode),
+ can_os->ndev);
+ }
+
+ /* Stop the CAN controller */
+ pch_can_set_run_mode(can_os->can, PCH_CAN_STOP, can_os->ndev);
+
+ /* Indicate that we are aboutto/in suspend */
+ can_os->is_suspending = 1;
+
+ if (can_os->opened == 1) {
+ u32 buf_stat; /* Variable for reading the transmit buffer
+ status. */
+ u32 counter = 0xFFFFFF;
+
+ /*
+ Waiting for all transmission to complete.
+ This is done by checking the TXQST pending
+ register. The loop teriminates when no
+ transmission is pending.
+ */
+ while (counter) {
+ buf_stat = pch_can_get_buffer_status(can_os->can);
+ if (buf_stat == 0)
+ break;
+
+ counter--;
+ }
+
+ if (counter > 0) {
+ dev_dbg(&pdev->dev,
+ "%s -> No transmission is pending.\n", __func__);
+ } else {
+ dev_err(&pdev->dev,
+ "%s -> Transmission time out.\n", __func__);
+ }
+
+ /* Save interrupt configuration and then disable them */
+ pch_can_get_int_enables(can_os->can,
+ &(can_os->int_enables));
+ pch_can_set_int_enables(can_os->can, CAN_DISABLE, can_os->ndev);
+
+ /* Save Tx buffer enable state */
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+ /* Here i is the index, however (i+1) is object
+ number. */
+ pch_can_get_tx_enable(can_os->can,
+ (i + 1),
+ &(can_os->tx_enable[i]),
+ can_os->ndev);
+ }
+ }
+
+ /* Disable all Transmit buffers */
+ pch_can_tx_disable_all(can_os->can, can_os->ndev);
+
+ /* Save Rx buffer enable state */
+ for (i = 0; i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+ /* Here i is the index, however (i+1) is object
+ number. */
+
+ pch_can_get_rx_enable(can_os->can,
+ (i + 1),
+ &(can_os->rx_enable[i]),
+ can_os->ndev);
+ pch_can_get_rx_buffer_link(can_os->can,
+ (i + 1),
+ &(can_os->rx_link[i]),
+ can_os->ndev);
+
+ /* Save Rx Filters */
+ can_os->rx_filter[i].num = (i + 1);
+ pch_can_get_rx_filter(can_os->can,
+ &(can_os->rx_filter[i]),
+ can_os->ndev);
+ }
+ }
+
+ /* Disable all Receive buffers */
+ pch_can_rx_disable_all(can_os->can, can_os->ndev);
+
+ /* Save Context */
+ pch_can_get_baud(can_os->can, &(can_os->timing));
+ /* Timing. */
+ pch_can_get_listen_mode(can_os->can,
+ &(can_os->listen_mode), can_os->ndev);
+ /* Listen mode */
+ pch_can_get_arbiter_mode(can_os->can,
+ &(can_os->arbiter_mode), can_os->ndev);
+ /* Arbiter mode */
+
+ }
+
+ retval = pci_save_state(pdev);
+
+ if (retval != 0) {
+ /* Indicate that we have not suspended */
+ can_os->is_suspending = 0;
+
+ dev_err(&pdev->dev,
+ "%s -> pci_save_state failed(returned %d).\n",
+ __func__, retval);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s -> pci_save_state successful(returned %d).\n",
+ __func__, retval);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ dev_dbg(&pdev->dev,
+ "%s -> pci_enable_wake invoked successfully.\n", __func__);
+
+ pci_disable_device(pdev);
+ dev_dbg(&pdev->dev,
+ "%s -> pci_disable_device invoked successfully.\n", __func__);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ dev_dbg(&pdev->dev,
+ "%s -> pci_set_power_state invoked successfully.\n", __func__);
+ }
+
+ dev_dbg(&pdev->dev, "%s returns %d.\n", __func__, retval);
+ return retval;
+}
+
+static int pch_can_resume(struct pci_dev *pdev)
+{
+ int i; /* Counter variable. */
+ int retval; /* Return variable. */
+ struct pch_can_os *can_os =
+ (struct pch_can_os *) dev_get_drvdata(&pdev->dev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ dev_dbg(&pdev->dev,
+ "pch_can_resume -> pci_set_power_state invoked successfully.\n");
+
+ pci_restore_state(pdev);
+ dev_dbg(&pdev->dev,
+ "pch_can_resume -> pci_restore_state invoked successfully.\n");
+
+ retval = pci_enable_device(pdev);
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "pch_can_resume -> pci_enable_device failed(returned %d).\n",
+ retval);
+ }
+
+ else {
+ dev_dbg(&pdev->dev, "pch_can_resume -> pci_enable_device"
+ " invoked successfully(returned %d)\n", retval);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ /* Disabling all interrupts. */
+ pch_can_set_int_enables(can_os->can, CAN_DISABLE, can_os->ndev);
+
+ /* Setting the CAN device in Stop Mode. */
+ pch_can_set_run_mode(can_os->can, PCH_CAN_STOP, can_os->ndev);
+
+ /* Configuring the transmit and receive buffers. */
+ pch_can_config_rx_tx_buffers(can_os->can, can_os->ndev);
+ dev_dbg(&pdev->dev, "pch_can_resume -> "
+ "pch_can_config_rx_tx_buffers invoked successfully.\n");
+
+ if (can_os->opened == 1) {
+ /* Restore the CAN state */
+ pch_can_set_baud_custom(can_os->can, &(can_os->timing));
+ /* Timing */
+ pch_can_set_listen_mode(
+ can_os->can, can_os->listen_mode, can_os->ndev);
+ /* Listen/Active */
+ pch_can_set_arbiter_mode(can_os->can,
+ can_os->arbiter_mode, can_os->ndev);
+ /* Arbiter mode */
+
+ /* Enabling the transmit buffer. */
+ for (i = 0;
+ i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_TX) {
+ /* Here i is the index, however (i+1) is
+ object number. */
+ pch_can_set_tx_enable(can_os->can,
+ (i + 1),
+ can_os->tx_enable[i],
+ can_os->ndev);
+ }
+ }
+
+ /* Configuring the receive buffer and enabling them. */
+ for (i = 0;
+ i < (pch_can_tx_buf_size + pch_can_rx_buf_size);
+ i++) {
+ if (pch_msg_obj_conf[i] == MSG_OBJ_RX) {
+ /* Here i is the index, however (i+1) is
+ object number. */
+
+ /* Restore buffer link */
+ pch_can_set_rx_buffer_link(can_os->can,
+ (i + 1),
+ can_os->rx_link[i],
+ can_os->ndev);
+
+ /* Restore Rx Filters */
+ can_os->rx_filter[i].num = (i + 1);
+ pch_can_set_rx_filter(can_os->can,
+ &(can_os->rx_filter[i]));
+
+ /* Restore buffer enables */
+ pch_can_set_rx_enable(can_os->can,
+ (i + 1),
+ can_os->rx_enable[i],
+ can_os->ndev);
+ }
+ }
+
+ /* Enable CAN Interrupts */
+ pch_can_set_int_custom(can_os->can,
+ can_os->int_enables);
+
+ /* Restore Run Mode */
+ pch_can_set_run_mode(can_os->can,
+ can_os->run_mode, can_os->ndev);
+ }
+ /* if opened */
+ can_os->is_suspending = 0;
+ } /* else */
+
+ dev_dbg(&pdev->dev, "pch_can_resume returns %d\n", retval);
+ return retval;
+}
+#else
+#define pch_can_suspend NULL
+#define pch_can_resume NULL
+#endif
+
+static int __devinit pch_can_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *ndev;
+ struct pch_can_priv *priv;
+ unsigned int can_num = 0; /* Variable to denote the CAN */
+ int rc;
+ int index;
+
+ ndev = alloc_candev(sizeof(struct pch_can_priv), 1);
+ if (!ndev)
+ return -ENOMEM;
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ priv = netdev_priv(ndev);
+
+ priv->ndev = ndev;
+
+ priv->can.bittiming_const = &pch_can_bittiming_const;
+ priv->can.do_set_bittiming = &pch_set_bittiming;
+ priv->can.do_set_mode = pch_can_do_set_mode;
+ priv->can.do_get_state = pch_can_get_state;
+ priv->can.clock.freq = pch_can_clock * 1000;
+ /* Unit is Hz(pch_can_clock is KHz) */
+ priv->pch_can_os_p = &can_os[can_num];
+ ndev->flags |= (IFF_NOARP | IFF_ECHO);
+ platform_set_drvdata(pdev, ndev);
+ ndev->netdev_ops = &pch_can_netdev_ops;
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err_out_free;
+
+ rc = pci_request_regions(pdev, DRIVER_NAME);
+ if (rc)
+ goto err_out_disable;
+
+ can_os[can_num].pci_remap = pci_iomap(pdev, 1, 0);
+ if (can_os[can_num].pci_remap == 0) {
+ rc = -EIO;
+ goto err_out_res;
+ }
+
+ /* Creating the device handle denoting the remap base address. */
+ can_os[can_num].can = pch_can_create((void *)can_os[can_num].pci_remap,
+ ndev);
+
+ /* If handle creation fails. */
+ if (can_os[can_num].can == 0) {
+ dev_err(&pdev->dev,
+ "%s -> pch_can_create failed.\n", __func__);
+ rc = -EPERM;
+ goto err_out_iomap;
+ }
+
+ /* Can number (index to the structure) */
+ can_os[can_num].can_num = can_num;
+ can_os[can_num].irq = pdev->irq;/* IRQ allocated to this device. */
+ ndev->irq = pdev->irq;
+ can_os[can_num].dev = pdev;/* Reference to pci_device structure. */
+ can_os[can_num].opened = 0;/* Open flag denoting the device usage. */
+ can_os[can_num].is_suspending = 0;/* Flag denoting the suspend stage. */
+ can_os[can_num].ndev = ndev;
+
+ priv->base = (void *)can_os[can_num].pci_remap;
+
+ for (index = 0; index < pch_can_rx_buf_size;)
+ pch_msg_obj_conf[index++] = MSG_OBJ_RX;
+
+ for (index = index;
+ index < (pch_can_rx_buf_size + pch_can_tx_buf_size);)
+ pch_msg_obj_conf[index++] = MSG_OBJ_TX;
+
+ rc = register_candev(ndev);
+ if (rc)
+ goto err_out_reg_candev;
+
+ return 0;
+
+err_out_reg_candev:
+ pch_can_destroy(can_os->can, ndev);
+err_out_iomap:
+ pci_iounmap(pdev, (void *)can_os[can_num].pci_remap);
+err_out_res:
+ pci_release_regions(pdev);
+err_out_disable:
+ pci_disable_device(pdev);
+err_out_free:
+ free_candev(ndev);
+
+ return rc;
+}
+
+static struct pci_driver pch_can_pcidev = {
+ .name = MODULE_NAME,
+ .id_table = pch_can_pcidev_id,
+ .probe = pch_can_probe,
+ .remove = __devexit_p(pch_can_remove),
+ .suspend = pch_can_suspend,
+ .resume = pch_can_resume,
+};
+
+static int __init pch_can_pci_init(void)
+{
+ return pci_register_driver(&pch_can_pcidev);
+}
+
+static void __exit pch_can_pci_exit(void)
+{
+ /* Unregistering the registered PCI Driver. */
+ pci_unregister_driver(&pch_can_pcidev);
+}
+
+MODULE_DESCRIPTION("Controller Area Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.94");
+
+module_param_named(pch_can_rx_buf_size, pch_can_rx_buf_size, int, 444);
+module_param_named(pch_can_tx_buf_size, pch_can_tx_buf_size, int, 444);
+module_param_named(pch_can_clock, pch_can_clock, int, 444);
+MODULE_DEVICE_TABLE(pci, pch_can_pcidev_id);
+
+module_init(pch_can_pci_init);
+module_exit(pch_can_pci_exit);
diff --git a/drivers/net/can/pch_can.h b/drivers/net/can/pch_can.h
new file mode 100644
index 0000000..88a9559
--- /dev/null
+++ b/drivers/net/can/pch_can.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PCH_CAN_H__
+#define __PCH_CAN_H__
+
+#define MAX_CAN_DEVICES 1
+#define MAX_BITRATE 0x3e8
+#define NUM_NODES 2000 /* Maximum number of
+ Software FIFO nodes. */
+#define MAX_MSG_OBJ 32
+#define MSG_OBJ_RX 0 /* The receive message object flag. */
+#define MSG_OBJ_TX 1 /* The transmit message object flag. */
+
+#define ENABLE 1 /* The enable flag */
+#define DISABLE 0 /* The disable flag */
+#define CAN_CTRL_INIT 0x0001 /* The INIT bit of CANCONT register. */
+#define CAN_CTRL_IE 0x0002 /* The IE bit of CAN control register */
+#define CAN_CTRL_SIE 0x0004
+#define CAN_CTRL_EIE 0x0008
+#define CAN_CTRL_DAR 0x0020
+#define CAN_CTRL_IE_SIE_EIE 0x000e
+#define CAN_CTRL_CCE 0x0040
+#define CAN_CTRL_OPT 0x0080 /* The OPT bit of CANCONT register. */
+#define CAN_OPT_SILENT 0x0008 /* The Silent bit of CANOPT register. */
+#define CAN_CMASK_RX_TX_SET 0x00f3
+#define CAN_CMASK_RX_TX_GET 0x0073
+#define CAN_CMASK_ALL 0xff
+#define CAN_CMASK_RDWR 0x80
+#define CAN_CMASK_ARB 0x20
+#define CAN_CMASK_CTRL 0x10
+#define CAN_CMASK_MASK 0x40
+#define CAN_CMASK_CLPNT 0x08
+
+#define CAN_CMASK_NEWINT 0x04 /* The TxRqst/NewDat bit for the CMASK
+ register. */
+
+#define CAN_IF_MCONT_NEWDAT 0x8000 /* The NewDat bit of the MCONT
+ register. */
+
+#define CAN_IF_MCONT_INTPND 0x2000 /* The IntPnd bit of the MCONT
+ register. */
+
+#define CAN_IF_MCONT_UMASK 0x1000
+#define CAN_IF_MCONT_TXIE 0x0800
+#define CAN_IF_MCONT_RXIE 0x0400
+#define CAN_IF_MCONT_RMTEN 0x0200
+#define CAN_IF_MCONT_TXRQXT 0x0100
+#define CAN_IF_MCONT_EOB 0x0080
+#define CAN_IF_MCONT_MSGLOST 0x4000
+#define CAN_MASK2_MDIR_MXTD 0xc000
+#define CAN_ID2_MSGVAL_XTD_DIR 0xe000
+#define CAN_ID2_MSGVAL_DIR 0xa000
+#define CAN_ID2_DIR 0x2000
+#define CAN_ID_MSGVAL 0x8000
+#define CAN_IF_MASK2_MDIR ((u32)1 << 14)
+#define CAN_IF_MASK2_MXTD ((u32)1 << 15)
+
+#define CAN_STATUS_INT 0x8000 /* The status interrupt value of
+ the CAN device. */
+
+#define CAN_IF_CREQ_BUSY 0x8000 /* The Busy flag bit of the CREQ
+ register. */
+
+#define CAN_ID2_XTD 0x4000 /* The Xtd bit of ID2
+ register. */
+
+#define CAN_SRST_BIT 0x0001
+#define CAN_CONT_OFFSET 0x00 /*Can Control register */
+#define CAN_STAT_OFFSET 0x04
+#define CAN_ERRC_OFFSET 0x08
+#define CAN_BITT_OFFSET 0x0c
+#define CAN_INT_OFFSET 0x010
+#define CAN_OPT_OFFSET 0x14 /*Extended function register */
+#define CAN_BRPE_OFFSET 0x18
+
+/* Message interface one (IF1) registers */
+#define CAN_IF1_CREQ_OFFSET 0x020
+#define CAN_IF1_CMASK_OFFSET 0x024
+#define CAN_IF1_ID1_OFFSET 0x030
+#define CAN_IF1_ID2_OFFSET 0x034
+#define CAN_IF1_MCONT_OFFSET 0x038
+#define CAN_IF1_DATAA1_OFFSET 0x03C
+#define CAN_IF1_DATAA2_OFFSET 0x040
+#define CAN_IF1_DATAB1_OFFSET 0x044
+#define CAN_IF1_DATAB2_OFFSET 0x048
+#define CAN_IF1_MASK1_OFFSET 0x028
+#define CAN_IF1_MASK2_OFFSET 0x02c
+#define CAN_IF2_CREQ_OFFSET 0x080
+#define CAN_IF2_CMASK_OFFSET 0x084
+#define CAN_IF2_ID1_OFFSET 0x090
+#define CAN_IF2_ID2_OFFSET 0x094
+#define CAN_IF2_MCONT_OFFSET 0x098
+#define CAN_IF2_DATAA1_OFFSET 0x09c
+#define CAN_IF2_DATAA2_OFFSET 0x0a0
+#define CAN_IF2_DATAB1_OFFSET 0x0a4
+#define CAN_IF2_DATAB2_OFFSET 0x0a8
+#define CAN_IF2_MASK1_OFFSET 0x088
+#define CAN_IF2_MASK2_OFFSET 0x08c
+#define CAN_TREQ1_OFFSET 0x100
+#define CAN_TREQ2_OFFSET 0x104
+#define CAN_SRST_OFFSET 0x1FC
+#define BIT_SHIFT_ONE 1
+#define BIT_SHIFT_TWO 2
+#define BIT_SHIFT_THREE 3
+#define BIT_SHIFT_FOUR 4
+#define BIT_SHIFT_FIVE 5
+#define BIT_SHIFT_SIX 6
+#define BIT_SHIFT_SEVEN 7
+#define BIT_SHIFT_EIGHT 8
+#define BIT_SHIFT_TWELVE 12
+#define BIT_SHIFT_THIRTEEN 13
+#define BIT_SHIFT_FOURTEEN 14
+#define BIT_SHIFT_FIFTEEN 15
+#define BIT_SHIFT_SIXTEEN 16
+
+/* bit position of certain controller bits. */
+#define BIT_BITT_BRP 0
+#define BIT_BITT_SJW 6
+#define BIT_BITT_TSEG1 8
+#define BIT_BITT_TSEG2 12
+#define BIT_IF1_MCONT_RXIE 10
+#define BIT_IF2_MCONT_TXIE 11
+#define BIT_BRPE_BRPE 6
+#define BIT_ES_TXERRCNT 0
+#define BIT_ES_RXERRCNT 8
+#define MSK_BITT_BRP 0x3f
+#define MSK_BITT_SJW 0xc0
+#define MSK_BITT_TSEG1 0xf00
+#define MSK_BITT_TSEG2 0x7000
+#define MSK_BRPE_BRPE 0x3c0
+#define MSK_BRPE_GET 0x0f
+#define MSK_CTRL_IE_SIE_EIE 0x07
+#define MSK_MCONT_TXIE 0x08
+#define MSK_MCONT_RXIE 0x10
+#define MSK_ALL_THREE 0x07
+#define MSK_ALL_FOUR 0x0f
+#define MSK_ALL_EIGHT 0xff
+#define MSK_ALL_ELEVEN 0x7ff
+#define MSK_ALL_THIRTEEN 0x1fff
+#define MSK_ALL_SIXTEEN 0xffff
+
+/* Error */
+#define MSK_ES_TXERRCNT ((u32)0xff << BIT_ES_TXERRCNT) /* Tx err count */
+#define MSK_ES_RXERRCNT ((u32)0x7f << BIT_ES_RXERRCNT) /* Rx err count */
+
+#define PCH_CAN_BIT_SET(reg, bitmask) \
+ (iowrite32((ioread32((reg)) | ((u32)(bitmask))), (reg)))
+#define PCH_CAN_BIT_CLEAR(reg, bitmask) \
+ (iowrite32((ioread32((reg)) & ~((u32)(bitmask))), (reg)))
+
+#define PCH_CAN_NO_TX_BUFF 1 /* The flag value for denoting the
+ unavailability of the transmit
+ message object. */
+
+#define ERROR_COUNT 96
+#define PCH_CAN_MSG_DATA_LEN 8 /* CAN Msg data length */
+
+#define PCH_CAN_FIFO_NOT_EMPTY 0
+#define PCH_CAN_FIFO_EMPTY 1
+#define PCH_CAN_FIFO_FULL 2
+#define PCH_CAN_NULL NULL
+
+#define PCI_DEVICE_ID_INTEL_PCH1_CAN 0x8818
+#define DRIVER_NAME "can"
+
+#define PCH_CAN_CLOCK_DEFAULT_OFFSET 0
+#define PCH_CAN_CLOCK_62_5_OFFSET 0
+#define PCH_CAN_CLOCK_24_OFFSET 8
+#define PCH_CAN_CLOCK_50_OFFSET 16
+
+#define COUNTER_LIMIT 0xFFFF
+
+#define MODULE_NAME "pch_can"
+
+enum pch_can_listen_mode {
+ PCH_CAN_ACTIVE = 0,
+ PCH_CAN_LISTEN
+};
+
+enum pch_can_run_mode {
+ PCH_CAN_STOP = 0,
+ PCH_CAN_RUN
+};
+
+enum pch_can_arbiter {
+ PCH_CAN_ROUND_ROBIN = 0,
+ PCH_CAN_FIXED_PRIORITY
+};
+
+enum pch_can_auto_restart {
+ CAN_MANUAL = 0,
+ CAN_AUTO
+};
+
+enum pch_can_baud {
+ PCH_CAN_BAUD_10 = 0,
+ PCH_CAN_BAUD_20,
+ PCH_CAN_BAUD_50,
+ PCH_CAN_BAUD_125,
+ PCH_CAN_BAUD_250,
+ PCH_CAN_BAUD_500,
+ PCH_CAN_BAUD_800,
+ PCH_CAN_BAUD_1000
+};
+
+enum pch_can_interrupt {
+ CAN_ENABLE,
+ CAN_DISABLE,
+ CAN_ALL,
+ CAN_NONE
+};
+
+/**
+ * struct pch_can_msg - CAN message structure
+ * @ide: Standard/extended msg
+ * @id: 11 or 29 bit msg id
+ * @dlc: Size of data
+ * @data: Message pay load
+ * @rtr: RTR message
+ */
+struct pch_can_msg {
+ unsigned short ide;
+ unsigned int id;
+ unsigned short dlc;
+ unsigned char data[PCH_CAN_MSG_DATA_LEN];
+ unsigned short rtr;
+};
+
+/**
+ * pch_can_timing - CAN bittiming structure
+ * @bitrate: Bitrate (kbps)
+ * @cfg_bitrate: Bitrate
+ * @cfg_tseg1: Tseg1
+ * @cfg_tseg2: Tseg2
+ * @cfg_sjw: Sync jump width
+ * @smpl_mode: Sampling mode
+ * @edge_mode: Edge R / D
+ */
+struct pch_can_timing {
+ unsigned int bitrate;
+ unsigned int cfg_bitrate;
+ unsigned int cfg_tseg1;
+ unsigned int cfg_tseg2;
+ unsigned int cfg_sjw;
+ unsigned int smpl_mode;
+ unsigned int edge_mode;
+};
+
+/**
+ * struct pch_can_error - CAN error structure
+ * @rxgte96: Rx err cnt >=96
+ * @txgte96: Tx err cnt >=96
+ * @error_stat: Error state of CAN node,
+ * 00=error active (normal)
+ * 01=error passive
+ * 1x=bus off
+ * @rx_err_cnt: Rx error count
+ * @tx_err_cnt: Tx error count
+ */
+struct pch_can_error {
+ unsigned int rxgte96;
+ unsigned int txgte96;
+ unsigned int error_stat;
+ unsigned int rx_err_cnt;
+ unsigned int tx_err_cnt;
+};
+
+/**
+ * struct pch_can_acc_filter - CAN Filter structure
+ * @id: The id/mask data
+ * @id_ext: Standard/extended ID
+ * @rtr: RTR message
+ */
+struct pch_can_acc_filter {
+ unsigned int id;
+ unsigned int id_ext;
+ unsigned int rtr;
+};
+
+/**
+ * struct pch_can_rx_filter - CAN RX filter
+ * @num: Filter number
+ * @umask: UMask value
+ * @amr: Acceptance Mask Reg
+ * @aidr: Acceptance Control Reg
+ */
+struct pch_can_rx_filter {
+ unsigned int num;
+ unsigned int umask;
+ struct pch_can_acc_filter amr;
+ struct pch_can_acc_filter aidr;
+};
+
+/**
+ * struct pch_can_os - structure to store the CAN device information.
+ * @can: CAN: device handle
+ * @opened: Linux opened device
+ * @can_num: Linux: CAN Number
+ * @pci_remap: Linux: MMap regs
+ * @dev: Linux: PCI Device
+ * @irq: Linux: IRQ
+ * @block_mode: Blocking / non-blocking
+ * @rx_fifo: Rx FIFO
+ * @read_wait_queue: Linux: Read wait queue
+ * @write_wait_queue: Linux: Write wait queue
+ * @write_wait_flag: Linux: Write wait flag
+ * @read_wait_flag: Linux: Read wait flag
+ * @open_spinlock: Linux: Open lock variable
+ * @is_suspending: Linux: Is suspending state
+ * @inode: Linux: inode
+ * @timing: CAN: timing
+ * @run_mode: CAN: run mode
+ * @listen_mode: CAN: listen mode
+ * @arbiter_mode: CAN: arbiter mode
+ * @tx_enable: CAN: Tx buffer state
+ * @rx_enable: CAN: Rx buffer state
+ * @rx_link: CAN: Rx link set
+ * @int_enables: CAN: ints enabled
+ * @int_stat: CAN: int status
+ * @bus_off_interrupt: CAN: Buss off int flag
+ * @rx_filter: CAN: Rx filters
+ * @can_callback: CAN: callback function pointer
+ * @ndev: net_device pointer
+ * @tx_spinlock: CAN: transmission lock variable
+ */
+struct pch_can_os {
+ int can;
+ unsigned int opened;
+ unsigned int can_num;
+ void __iomem *pci_remap;
+ struct pci_dev *dev;
+ unsigned int irq;
+ int block_mode;
+ int rx_fifo;
+ wait_queue_head_t read_wait_queue;
+ wait_queue_head_t write_wait_queue;
+ unsigned int write_wait_flag;
+ unsigned int read_wait_flag;
+ spinlock_t open_spinlock;
+ unsigned int is_suspending;
+ struct inode *inode;
+ struct pch_can_timing timing;
+ enum pch_can_run_mode run_mode;
+ enum pch_can_listen_mode listen_mode;
+ enum pch_can_arbiter arbiter_mode;
+ unsigned int tx_enable[MAX_MSG_OBJ];
+ unsigned int rx_enable[MAX_MSG_OBJ];
+ unsigned int rx_link[MAX_MSG_OBJ];
+ unsigned int int_enables;
+ unsigned int int_stat;
+ unsigned int bus_off_interrupt;
+ struct pch_can_rx_filter rx_filter[MAX_MSG_OBJ];
+ void (*can_callback) (struct pch_can_os *);
+ struct net_device *ndev;
+ spinlock_t tx_spinlock;
+};
+
+/**
+ * struct pch_can_priv - CAN driver private data structure
+ * @can: MUST be first member/field
+ * @ndev: Pointer to net_device structure
+ * @clk: unused
+ * @base: Base address
+ * @scc_ram_offset: unused
+ * @hecc_ram_offset: unused
+ * @mbx_offset: unused
+ * @int_line: unused
+ * @mbx_lock: unused
+ * @tx_head: unused
+ * @tx_tail: unused
+ * @rx_next: unused
+ * @pch_can_os_p: Pointer to CAN device information
+ * @have_msi: PCI MSI mode flag
+ *
+ * Longer description of this structure.
+ */
+struct pch_can_priv {
+ struct can_priv can;
+ struct net_device *ndev;
+ struct clk *clk;
+ void __iomem *base;
+ u32 scc_ram_offset;
+ u32 hecc_ram_offset;
+ u32 mbx_offset;
+ u32 int_line;
+ spinlock_t mbx_lock;
+ u32 tx_head;
+ u32 tx_tail;
+ u32 rx_next;
+ struct pch_can_os *pch_can_os_p;
+ unsigned int have_msi;
+};
+
+/**
+ * struct can_fifo_item - FIFO Item structure
+ * @msg: The msg object
+ * @next: The next pointer
+ */
+struct can_fifo_item {
+ struct pch_can_msg msg;
+ struct can_fifo_item *next;
+};
+
+/**
+ * struct can_fifo - CAN FIFO structure
+ * @head: The node where insertion can be done
+ * @tail: The node where reading can be done
+ * @size: The number of FIFO nodes
+ */
+struct can_fifo {
+ struct can_fifo_item *head;
+ struct can_fifo_item *tail;
+ unsigned int size;
+};
+
+/* This structure defines format for the storage of base address */
+struct can_hw {
+ void __iomem *io_base;
+};
+#endif /* __PCH_CAN_H__ */
-- 1.6.0.6
[-- Attachment #1.2: Type: text/html, Size: 130674 bytes --]
[-- Attachment #2: Type: text/plain, Size: 163 bytes --]
_______________________________________________
MeeGo-dev mailing list
MeeGo-dev-WXzIur8shnEAvxtiuMwx3w@public.gmane.org
http://lists.meego.com/listinfo/meego-dev
^ permalink raw reply related
* Re: [RFC PATCH] platform: Faciliatate the creation of pseduo-platform busses
From: Greg KH @ 2010-08-10 23:53 UTC (permalink / raw)
To: Grant Likely
Cc: Patrick Pannuto, Patrick Pannuto, linux-kernel@vger.kernel.org,
linux-arm-msm@vger.kernel.org, linux-omap@vger.kernel.org,
damm@opensource.se, lethal@linux-sh.org, rjw@sisk.pl,
dtor@mail.ru, eric.y.miao@gmail.com, netdev@vger.kernel.org,
Kevin Hilman
In-Reply-To: <AANLkTimjXd=SL61KvjDfvJ-JtXsSVW9pwOYBFUHX0mVp@mail.gmail.com>
On Sat, Aug 07, 2010 at 11:28:13AM -0600, Grant Likely wrote:
> On Sat, Aug 7, 2010 at 12:35 AM, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On Fri, Aug 6, 2010 at 5:46 PM, Greg KH <gregkh@suse.de> wrote:
> >> That would be nice, but take your "standard" PC today:
> >> > ls /sys/devices/platform/
> >> Fixed MDIO bus.0 i8042 pcspkr power serial8250 uevent vesafb.0
> >>
> >> There are tty devices below the serial port, which is nice to see, but
> >> the others? I don't know what type of bus they would be on, do you?
> [...]
> > I wouldn't have any problem modifying those specific drivers to
> > register under something like /sys/devices/legacy, but I don't really
> > think it is in any way necessary.
>
> Or for that matter, make those drivers explicitly use
> /sys/devices/platform so that I don't cause churn on PCs. :-) I'd
> like to be rid of it as default behaviour for embedded though.
Yes, that would be the easier (and better) solution.
thanks,
greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 2/2] platform: Facilitate the creation of pseudo-platform buses
From: Patrick Pannuto @ 2010-08-10 23:49 UTC (permalink / raw)
To: linux-kernel
Cc: ppannuto, linux-arm-msm, magnus.damm, grant.likely, gregkh,
Kevin Hilman, Paul Mundt, Magnus Damm, Rafael J. Wysocki,
Eric Miao, Dmitry Torokhov, netdev
In-Reply-To: <1281484174-32174-1-git-send-email-ppannuto@codeaurora.org>
(lkml.org seems to have lost August 3rd...)
RFC: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01342.html
v1: http://lkml.indiana.edu/hypermail//linux/kernel/1008.0/01942.html
Based on the idea and code originally proposed by Kevin Hilman:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg31161.html
Changes from v1:
* "Pseduo" buses are no longer init'd, they are [un]registered by:
- pseudo_platform_bus_register(struct bus_type *)
- pseudo_platform_bus_unregister(struct bus_type *)
* These registrations [de]allocate a dev_pm_ops structure for the
pseudo bus_type
* Do not overwrite the parent if .bus is already set (that is, allow
pseudo bus devices to be root devices)
* Split into 2 patches:
- 1/2: Already sent separately, but included here for clarity
- 2/2: The real meat of the patch (this patch)
INTRO
As SOCs become more popular, the desire to quickly define a simple,
but functional, bus type with only a few unique properties becomes
desirable. As they become more complicated, the ability to nest these
simple busses and otherwise orchestrate them to match the actual
topology also becomes desirable.
EXAMPLE USAGE
/arch/ARCH/MY_ARCH/my_bus.c:
#include <linux/device.h>
#include <linux/platform_device.h>
struct bus_type SOC_bus_type = {
.name = "SOC-bus-type",
};
EXPORT_SYMBOL_GPL(SOC_bus_type);
struct platform_device SOC_bus1 = {
.name = "SOC-bus1",
.id = -1,
.dev.bus = &SOC_bus_type;
};
EXPORT_SYMBOL_GPL(SOC_bus1);
struct platform_device SOC_bus2 = {
.name = "SOC-bus2",
.id = -2,
.dev.bus = &SOC_bus_type;
};
EXPORT_SYMBOL_GPL(SOC_bus2);
static int __init SOC_bus_init(void)
{
int error;
error = pseudo_platform_bus_register(&SOC_bus_type);
if (error)
return error;
error = platform_device_register(&SOC_bus1);
if (error)
goto fail_bus1;
error = platform_device_register(&SOC_bus2);
if (error)
goto fail_bus2;
return error;
/* platform_device_unregister(&SOC_bus2); */
fail_bus2:
platform_device_unregister(&SOC_bus1);
fail_bus1:
pseudo_platform_bus_unregister(&SOC_bus_type);
return error;
}
/drivers/my_driver.c:
static struct platform_driver my_driver = {
.driver = {
.name = "my-driver",
.owner = THIS_MODULE,
.bus = &SOC_bus_type,
},
};
/somewhere/my_device.c:
static struct platform_device my_device = {
.name = "my-device",
.id = -1,
.dev.bus = &my_bus_type,
.dev.parent = &SOC_bus1.dev,
};
This will build a device tree that mirrors the actual system:
/sys/bus
|-- SOC-bus-type
| |-- devices
| | |-- SOC_bus1 -> ../../../devices/SOC_bus1
| | |-- SOC_bus2 -> ../../../devices/SOC_bus2
| | |-- my-device -> ../../../devices/SOC_bus1/my-device
| |-- drivers
| | |-- my-driver
/sys/devices
|-- SOC_bus1
| |-- my-device
|-- SOC_bus2
Driver can drive any device on the SOC, which is logical, without
actually being registered on multiple /bus_types/, even though the
devices may be on different /physical buses/ (which are actually
just devices).
THOUGHTS:
1.
Notice that for a device / driver, only 3 lines were added to
switch from the platform bus to the new SOC_bus. This is
especially valuable if we consider supporting a legacy SOCs
and new SOCs where the same driver is used, but may need to
be on either the platform bus or the new SOC_bus. The above
code then becomes:
(possibly in a header)
#ifdef CONFIG_MY_BUS
#define MY_BUS_TYPE &SOC_bus_type
#else
#define MY_BUS_TYPE NULL
#endif
/drivers/my_driver.c
static struct platform_driver my_driver = {
.driver = {
.name = "my-driver",
.owner = THIS_MODULE,
.bus = MY_BUS_TYPE,
},
};
Which will allow the same driver to easily to used on either
the platform bus or the newly defined bus type.
2.
Implementations wishing to make dynamic / run-time decisions on where
devices are placed could easily create wrapper functions, that is
int SOC_device_register(struct platform_device *pdev)
{
if (pdev->archdata->flag)
pdev->dev.parent = &SOC_bus1.dev;
else
pdev->dev.parent = &SOC_bus2.dev;
return platform_device_register(pdev);
}
A similar solution also would allow for run-time determination of dev.bus,
if that were necessary for your platform.
3.
I'm not convinced that dynamically allocating a new copy of dev_pm_ops is
the best solution. I *AM*, however, convinced that removing const from
struct bus_type {
...
const struct dev_pm_ops *pm;
...
};
would be a mistake; it is far too easy to overwrite one of the function
pointers on accident, and the const serves a very useful purpose here.
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Patrick Pannuto <ppannuto@codeaurora.org>
---
drivers/base/platform.c | 92 +++++++++++++++++++++++++++++++++++++-
include/linux/platform_device.h | 3 +
2 files changed, 92 insertions(+), 3 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b69ccb4..933e0c1 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -238,8 +238,12 @@ int platform_device_add(struct platform_device *pdev)
if (!pdev)
return -EINVAL;
- if (!pdev->dev.parent)
- pdev->dev.parent = &platform_bus;
+ if (!pdev->dev.bus) {
+ pdev->dev.bus = &platform_bus_type;
+
+ if (!pdev->dev.parent)
+ pdev->dev.parent = &platform_bus;
+ }
pdev->dev.bus = &platform_bus_type;
@@ -482,7 +486,8 @@ static void platform_drv_shutdown(struct device *_dev)
*/
int platform_driver_register(struct platform_driver *drv)
{
- drv->driver.bus = &platform_bus_type;
+ if (!drv->driver.bus)
+ drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
@@ -1017,6 +1022,87 @@ struct bus_type platform_bus_type = {
};
EXPORT_SYMBOL_GPL(platform_bus_type);
+/** pseudo_platform_bus_register - register an "almost platform bus"
+ * @bus: partially complete bus type to register
+ *
+ * This init will fill in any ommitted fields in @bus, however, it
+ * also allocates memory and replaces the pm field in @bus, since
+ * pm is const, but some of its pointers may need this one-time
+ * initialziation overwrite.
+ *
+ * @bus's registered this way should be released with
+ * pseudo_platform_bus_unregister
+ */
+int pseudo_platform_bus_register(struct bus_type *bus)
+{
+ int error;
+ struct dev_pm_ops* heap_pm;
+ heap_pm = kmalloc(sizeof (*heap_pm), GFP_KERNEL);
+
+ if (!heap_pm)
+ return -ENOMEM;
+
+ if (!bus->dev_attrs)
+ bus->dev_attrs = platform_bus_type.dev_attrs;
+ if (!bus->match)
+ bus->match = platform_bus_type.match;
+ if (!bus->uevent)
+ bus->uevent = platform_bus_type.uevent;
+ if (!bus->pm)
+ memcpy(heap_pm, &platform_bus_type.pm, sizeof(*heap_pm));
+ else {
+ heap_pm->prepare = (bus->pm->prepare) ?
+ bus->pm->prepare : platform_pm_prepare;
+ heap_pm->complete = (bus->pm->complete) ?
+ bus->pm->complete : platform_pm_complete;
+ heap_pm->suspend = (bus->pm->suspend) ?
+ bus->pm->suspend : platform_pm_suspend;
+ heap_pm->resume = (bus->pm->resume) ?
+ bus->pm->resume : platform_pm_resume;
+ heap_pm->freeze = (bus->pm->freeze) ?
+ bus->pm->freeze : platform_pm_freeze;
+ heap_pm->thaw = (bus->pm->thaw) ?
+ bus->pm->thaw : platform_pm_thaw;
+ heap_pm->poweroff = (bus->pm->poweroff) ?
+ bus->pm->poweroff : platform_pm_poweroff;
+ heap_pm->restore = (bus->pm->restore) ?
+ bus->pm->restore : platform_pm_restore;
+ heap_pm->suspend_noirq = (bus->pm->suspend_noirq) ?
+ bus->pm->suspend_noirq : platform_pm_suspend_noirq;
+ heap_pm->resume_noirq = (bus->pm->resume_noirq) ?
+ bus->pm->resume_noirq : platform_pm_resume_noirq;
+ heap_pm->freeze_noirq = (bus->pm->freeze_noirq) ?
+ bus->pm->freeze_noirq : platform_pm_freeze_noirq;
+ heap_pm->thaw_noirq = (bus->pm->thaw_noirq) ?
+ bus->pm->thaw_noirq : platform_pm_thaw_noirq;
+ heap_pm->poweroff_noirq = (bus->pm->poweroff_noirq) ?
+ bus->pm->poweroff_noirq : platform_pm_poweroff_noirq;
+ heap_pm->restore_noirq = (bus->pm->restore_noirq) ?
+ bus->pm->restore_noirq : platform_pm_restore_noirq;
+ heap_pm->runtime_suspend = (bus->pm->runtime_suspend) ?
+ bus->pm->runtime_suspend : platform_pm_runtime_suspend;
+ heap_pm->runtime_resume = (bus->pm->runtime_resume) ?
+ bus->pm->runtime_resume : platform_pm_runtime_resume;
+ heap_pm->runtime_idle = (bus->pm->runtime_idle) ?
+ bus->pm->runtime_idle : platform_pm_runtime_idle;
+ }
+ bus->pm = heap_pm;
+
+ error = bus_register(bus);
+ if (error)
+ kfree(bus->pm);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(pseudo_platform_bus_register);
+
+void pseudo_platform_bus_unregister(struct bus_type *bus)
+{
+ bus_unregister(bus);
+ kfree(bus->pm);
+}
+EXPORT_SYMBOL_GPL(pseudo_platform_bus_unregister);
+
int __init platform_bus_init(void)
{
int error;
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 5417944..5ec827c 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -79,6 +79,9 @@ extern int platform_driver_probe(struct platform_driver *driver,
#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)->dev)
#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))
+extern int pseudo_platform_bus_register(struct bus_type *);
+extern void pseudo_platform_bus_unregister(struct bus_type *);
+
extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
int (*probe)(struct platform_device *),
struct resource *res, unsigned int n_res,
--
1.7.2
^ permalink raw reply related
* Re: [PATCH] 3c59x: fix deadlock when using netconsole with 3c59x
From: David Miller @ 2010-08-10 23:48 UTC (permalink / raw)
To: nhorman; +Cc: netdev, klassert
In-Reply-To: <20100809163210.GA1781@hmsreliant.think-freely.org>
From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon, 9 Aug 2010 12:32:10 -0400
> When using netpoll, its possible to deadlock the 3c59x driver. Since it takes
> an internal spinlock (vp->lock) that serializes boomerang_interrupt and parts
> of boomerang_start_xmit, if we call pr_debug in the former, we can go through
> the tx path on the same cpu, and recurse into the same driver again, deadlocking
> in the transmit routine.
>
> This patch fixes that problem by stopping the queues during interrupt
> processing, so that subsequent transmits will get queued until a later point.
> Its not a great solution, but we need to find some way to serialize access to
> the register file on the card without enforcing a deadlock. I think the queue
> stop is the best way to do that. And since we only print things in
> boomerang_interrupt when we have debug enabled, we can mitigate the impact of
> this change to only stop the queues when debug is on.
>
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Nothing serialized changes to "vortex_debug" with the tests you're
making here. Simply turning it off when a packet arrives can deadlock
the send queue of the device.
Even if proper serializatio did exist, I still see this as an awful
solution.
And the default value of this thing is "1" so it's always going to be
doing this send queue state flipping for effectively everyone.
Please find another way to solve this problem.
^ permalink raw reply
* Re: [PATCH v2] net: add Fast Ethernet driver for PXA168.
From: David Miller @ 2010-08-10 23:42 UTC (permalink / raw)
To: prakity; +Cc: buytenh, ssanap, netdev, akarkare, sarnaik, eric.y.miao, markb
In-Reply-To: <847F8195-87A2-4318-9E07-FF8A7E9FA1E6@marvell.com>
From: Philip Rakity <prakity@marvell.com>
Date: Tue, 10 Aug 2010 11:12:45 -0700
> Maybe the solution is to add a new option in Kconfig to define the
> extra headers size the driver will need. That option will increase
> the headers. I do not like that very much since it requires someone
> know how big the value should be. Could default it to 48 or 64
> bytes and allow it to be edited. It is not great solution since it
> fixes the pxa168 driver but does not handle other drivers.
Take a look at how we define LL_MAX_HEADER in include/linux/netdevice.h
^ permalink raw reply
* Re: [PATCH 2/2] caif-spi: Bugfix SPI_DATA_POS settings were inverted.
From: David Miller @ 2010-08-10 23:39 UTC (permalink / raw)
To: sjur.brandeland; +Cc: sjurbren, netdev
In-Reply-To: <1281461807-17408-2-git-send-email-sjur.brandeland@stericsson.com>
From: sjur.brandeland@stericsson.com
Date: Tue, 10 Aug 2010 19:36:47 +0200
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
>
> The setting of SPI_DATA_POS depending on CONFIG_CAIF_SPI_SYNC
> where inverted.
>
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
Applied.
^ permalink raw reply
* Re: [PATCH 1/2] caif: Bugfix - Increase default headroom size for control channel.
From: David Miller @ 2010-08-10 23:39 UTC (permalink / raw)
To: sjur.brandeland; +Cc: sjurbren, netdev
In-Reply-To: <1281461807-17408-1-git-send-email-sjur.brandeland@stericsson.com>
From: sjur.brandeland@stericsson.com
Date: Tue, 10 Aug 2010 19:36:46 +0200
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
>
> Headroom size for control channel must be at least 48 bytes in some scenarios.
>
> Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
Applied.
^ permalink raw reply
* Re: [PATCH] netpoll: use non-BH variant of RCU
From: David Miller @ 2010-08-10 23:31 UTC (permalink / raw)
To: paulmck; +Cc: herbert, linville, netdev
In-Reply-To: <20100810211932.GG2379@linux.vnet.ibm.com>
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Date: Tue, 10 Aug 2010 14:19:32 -0700
> Your suggestion of providing another API rcu_read_lock_irqsoff()
> and rcu_read_unlock_irqsoff() is the best I can think of right offhand.
>
> What tree/commit do you need the patch against?
Linus's tree is fine for this.
But we need this fix for 2.6.35-stable too. Herbert would
you object to putting John's more simple fix there?
John, when referencing other commits in commit messages,
please provide the SHA1 ID as well as the commit message
header line.
Thanks.
^ permalink raw reply
* Re: [PATCH] net: make netpoll_rx return bool for !CONFIG_NETPOLL
From: David Miller @ 2010-08-10 23:24 UTC (permalink / raw)
To: linville; +Cc: netdev
In-Reply-To: <1281469487-8946-1-git-send-email-linville@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 10 Aug 2010 15:44:47 -0400
> "netpoll: Use 'bool' for netpoll_rx() return type." missed the case when
> CONFIG_NETPOLL is disabled.
>
> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Applied, thanks John.
^ permalink raw reply
* Re: [RFC PATCH 1/2] pci: add function reset call that can be used inside of probe
From: Alexander Duyck @ 2010-08-10 23:14 UTC (permalink / raw)
To: Kenji Kaneshige
Cc: Kirsher, Jeffrey T, davem@davemloft.net, jbarnes@virtuousgeek.org,
netdev@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <4C612C5E.8020909@jp.fujitsu.com>
Kenji Kaneshige wrote:
> (2010/07/31 9:58), Jeff Kirsher wrote:
>> From: Alexander Duyck<alexander.h.duyck@intel.com>
>> + /*
>> + * both INTx and MSI are disabled after the Interrupt Disable bit
>> + * is set and the Bus Master bit is cleared.
>> + */
>> + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
>> +
>> + rc = __pci_dev_reset(dev, 0);
>
> Could you tell me why you need to program command register before reset?
>
> "MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore,
> resetting the device clears the "Interrupt Disable bit", even though it
> was set just before the rest. So I'm a little confused.
>
> Thanks,
> Kenji Kaneshige
>
The point is to prevent any pending transactions from being on the bus
while we are doing the reset. By writing only the INTX disable bit we
are disabling all interrupts from being generated, and also disabling
all DMA and MSI interrupts since the bus master enable bit is not set.
Without this change the device might be in the middle of a transaction
or sending an interrupt while we are doing the reset which may lead to
other issues after the reset.
Thanks,
Alex
^ permalink raw reply
* Re: pull request: wireless-2.6 2010-08-10
From: David Miller @ 2010-08-10 23:00 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20100810204251.GB2728@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 10 Aug 2010 16:42:51 -0400
> Here are a few more fixes intended for 2.6.36. Included are a locking
> fix for cfg80211, a fix for iwlagn to prevent it from using RTS/CTS
> or CTS-to-self protection on every frame (even inappropriately),
> a reversion of a mistakenly added PCI ID from p54, and a simple fix
> for some build breakage some have been experiencing in libertas.
> Also included are a handful of Bluetooth fixes by way of Marcel.
Pulled, thanks a lot John.
^ permalink raw reply
* Re: [PATCH] netpoll: use non-BH variant of RCU
From: Paul E. McKenney @ 2010-08-10 21:19 UTC (permalink / raw)
To: Herbert Xu; +Cc: John W. Linville, netdev, David S. Miller
In-Reply-To: <20100810204358.GA1076@gondor.apana.org.au>
On Tue, Aug 10, 2010 at 04:43:58PM -0400, Herbert Xu wrote:
> On Tue, Aug 10, 2010 at 04:25:24PM -0400, John W. Linville wrote:
> > "netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
> > of RCU. Unfortunately, calling netpoll_rx from netif_rx resulted in
> > the following backtrace:
>
> Thanks for catching this John!
>
> > diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
> > index 413742c..0bdd527 100644
> > --- a/include/linux/netpoll.h
> > +++ b/include/linux/netpoll.h
> > @@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
> > unsigned long flags;
> > bool ret = false;
> >
> > - rcu_read_lock_bh();
> > - npinfo = rcu_dereference_bh(skb->dev->npinfo);
> > + rcu_read_lock();
> > + npinfo = rcu_dereference(skb->dev->npinfo);
>
> I really wanted to avoid mixing the two different RCU primitives
> because they require different synchronisations.
>
> In this case, the problem is that we're being called in IRQ
> context, where BH is diabled anyway, so we don't actually need
> to do anything (assuming IRQ is off).
>
> Paul, what could we do to resolve this (other than by switching
> to the non-BH variant of RCU)? Perhaps an additional variant
> of rcu_read_lock_bh that checks whether IRQ is off?
Hello, Herbert,
Your suggestion of providing another API rcu_read_lock_irqsoff()
and rcu_read_unlock_irqsoff() is the best I can think of right offhand.
What tree/commit do you need the patch against?
Thanx, Paul
^ permalink raw reply
* Re: [PATCH] netpoll: use non-BH variant of RCU
From: Herbert Xu @ 2010-08-10 20:43 UTC (permalink / raw)
To: John W. Linville; +Cc: netdev, David S. Miller, Paul E. McKenney
In-Reply-To: <1281471924-2237-1-git-send-email-linville@tuxdriver.com>
On Tue, Aug 10, 2010 at 04:25:24PM -0400, John W. Linville wrote:
> "netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
> of RCU. Unfortunately, calling netpoll_rx from netif_rx resulted in
> the following backtrace:
Thanks for catching this John!
> diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
> index 413742c..0bdd527 100644
> --- a/include/linux/netpoll.h
> +++ b/include/linux/netpoll.h
> @@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
> unsigned long flags;
> bool ret = false;
>
> - rcu_read_lock_bh();
> - npinfo = rcu_dereference_bh(skb->dev->npinfo);
> + rcu_read_lock();
> + npinfo = rcu_dereference(skb->dev->npinfo);
I really wanted to avoid mixing the two different RCU primitives
because they require different synchronisations.
In this case, the problem is that we're being called in IRQ
context, where BH is diabled anyway, so we don't actually need
to do anything (assuming IRQ is off).
Paul, what could we do to resolve this (other than by switching
to the non-BH variant of RCU)? Perhaps an additional variant
of rcu_read_lock_bh that checks whether IRQ is off?
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* pull request: wireless-2.6 2010-08-10
From: John W. Linville @ 2010-08-10 20:42 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
Dave,
Here are a few more fixes intended for 2.6.36. Included are a locking
fix for cfg80211, a fix for iwlagn to prevent it from using RTS/CTS
or CTS-to-self protection on every frame (even inappropriately),
a reversion of a mistakenly added PCI ID from p54, and a simple fix
for some build breakage some have been experiencing in libertas.
Also included are a handful of Bluetooth fixes by way of Marcel.
Please let me know if there are problems!
Thanks,
John
---
The following changes since commit 9871e50edd25e2adf69b369817100821cb1e6de8:
net: Use NET_XMIT_SUCCESS where possible. (2010-08-10 02:51:11 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master
Johannes Berg (2):
cfg80211: fix locking in action frame TX
iwlagn: fix rts cts protection
John W. Linville (3):
Revert "p54pci: Add PCI ID for SMC2802W"
libertas: fix build break by including linux/sched.h
Merge branch 'master' of git://git.kernel.org/.../holtmann/bluetooth-2.6
Mat Martineau (4):
Bluetooth: Fix endianness issue with L2CAP MPS configuration
Bluetooth: Change default L2CAP ERTM retransmit timeout
Bluetooth: Fix incorrect setting of remote_tx_win for L2CAP ERTM
Bluetooth: Use 3-DH5 payload size for default ERTM max PDU size
drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-3945.c | 18 +-----
drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-5000.c | 10 ++--
drivers/net/wireless/iwlwifi/iwl-6000.c | 16 +++---
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | 19 +++++-
drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 20 +------
drivers/net/wireless/iwlwifi/iwl-agn.c | 85 +++++++--------------------
drivers/net/wireless/iwlwifi/iwl-core.c | 29 ++++++++-
drivers/net/wireless/iwlwifi/iwl-core.h | 14 +++--
drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +-
drivers/net/wireless/libertas/cfg.c | 1 +
drivers/net/wireless/p54/p54pci.c | 2 -
include/net/bluetooth/l2cap.h | 4 +-
net/bluetooth/l2cap.c | 11 ++--
net/wireless/mlme.c | 8 ++-
16 files changed, 102 insertions(+), 144 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 8848333..fec0262 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -260,7 +260,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.shadow_ram_support = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index a07310f..6950a78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -769,22 +769,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
rts_retry_limit = data_retry_limit;
tx_cmd->rts_retry_limit = rts_retry_limit;
- if (ieee80211_is_mgmt(fc)) {
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
- if (tx_flags & TX_CMD_FLG_RTS_MSK) {
- tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
- break;
- default:
- break;
- }
- }
-
tx_cmd->rate = rate;
tx_cmd->tx_flags = tx_flags;
@@ -2717,7 +2701,7 @@ static struct iwl_lib_ops iwl3945_lib = {
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
- .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+ .tx_cmd_protection = iwlcore_tx_cmd_protection,
.request_scan = iwl3945_request_scan,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d6531ad..d6da356 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2223,7 +2223,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
- .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+ .tx_cmd_protection = iwlcore_tx_cmd_protection,
.calc_rssi = iwl4965_calc_rssi,
.request_scan = iwlagn_request_scan,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 8093ce2..aacf377 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -506,7 +506,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -537,7 +537,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -597,7 +597,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -628,7 +628,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -659,7 +659,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
.use_bsm = false,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 5827052..af4fd50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -381,7 +381,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -489,7 +489,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -563,7 +563,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -637,7 +637,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -714,7 +714,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -821,7 +821,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -859,7 +859,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
@@ -933,7 +933,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
- .use_rts_for_ht = true, /* use rts/cts protection */
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index a7216dd..75b901b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -211,10 +211,21 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
}
}
-static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
- __le32 *tx_flags)
+static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags)
{
- *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+ info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+ return;
+ }
+
+ if (priv->cfg->use_rts_for_aggregation &&
+ info->flags & IEEE80211_TX_CTL_AMPDU) {
+ *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+ return;
+ }
}
/* Calc max signal level (dBm) among 3 possible receivers */
@@ -268,7 +279,7 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
.gain_computation = iwlagn_gain_computation,
.chain_noise_reset = iwlagn_chain_noise_reset,
- .rts_tx_cmd_flag = iwlagn_rts_tx_cmd_flag,
+ .tx_cmd_protection = iwlagn_tx_cmd_protection,
.calc_rssi = iwlagn_calc_rssi,
.request_scan = iwlagn_request_scan,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index d04502d..69155aa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -379,10 +379,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
- if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
- tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+ priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
if (ieee80211_is_mgmt(fc)) {
@@ -456,21 +453,6 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
rate_flags |= RATE_MCS_CCK_MSK;
- /* Set up RTS and CTS flags for certain packets */
- switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
- case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
- case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
- if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
- tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
- break;
- default:
- break;
- }
-
/* Set up antennas */
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
priv->hw_params.valid_tx_ant);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 35337b1..c1882fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -202,13 +202,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
priv->start_calib = 0;
if (new_assoc) {
- /*
- * allow CTS-to-self if possible for new association.
- * this is relevant only for 5000 series and up,
- * but will not damage 4965
- */
- priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
-
/* Apply the new configuration
* RXON assoc doesn't clear the station table in uCode,
*/
@@ -1618,45 +1611,9 @@ static ssize_t store_tx_power(struct device *d,
static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
-static ssize_t show_rts_ht_protection(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "%s\n",
- priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
-}
-
-static ssize_t store_rts_ht_protection(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "Input is not in decimal form.\n");
- else {
- if (!iwl_is_associated(priv))
- priv->cfg->use_rts_for_ht = val ? true : false;
- else
- IWL_ERR(priv, "Sta associated with AP - "
- "Change protection mechanism is not allowed\n");
- ret = count;
- }
- return ret;
-}
-
-static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
- show_rts_ht_protection, store_rts_ht_protection);
-
-
static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_temperature.attr,
&dev_attr_tx_power.attr,
- &dev_attr_rts_ht_protection.attr,
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
@@ -3464,25 +3421,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-/*
- * switch to RTS/CTS for TX
- */
-static void iwl_enable_rts_cts(struct iwl_priv *priv)
-{
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
- if (!test_bit(STATUS_SCANNING, &priv->status)) {
- IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");
- iwlcore_commit_rxon(priv);
- } else {
- /* scanning, defer the request until scan completed */
- IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");
- }
-}
-
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -3529,14 +3467,33 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
ret = 0;
+ if (priv->cfg->use_rts_for_aggregation) {
+ struct iwl_station_priv *sta_priv =
+ (void *) sta->drv_priv;
+ /*
+ * switch off RTS/CTS if it was previously enabled
+ */
+
+ sta_priv->lq_sta.lq.general_params.flags &=
+ ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+ iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+ CMD_ASYNC, false);
+ }
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- if (priv->cfg->use_rts_for_ht) {
+ if (priv->cfg->use_rts_for_aggregation) {
+ struct iwl_station_priv *sta_priv =
+ (void *) sta->drv_priv;
+
/*
* switch to RTS/CTS if it is the prefer protection
* method for HT traffic
*/
- iwl_enable_rts_cts(priv);
+
+ sta_priv->lq_sta.lq.general_params.flags |=
+ LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+ iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+ CMD_ASYNC, false);
}
ret = 0;
break;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8ccb6d2..2c03c6e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -401,21 +401,38 @@ void iwlcore_free_geos(struct iwl_priv *priv)
EXPORT_SYMBOL(iwlcore_free_geos);
/*
- * iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
+ * iwlcore_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
* function.
*/
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
- __le32 *tx_flags)
+void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags)
{
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
*tx_flags |= TX_CMD_FLG_RTS_MSK;
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ if (!ieee80211_is_mgmt(fc))
+ return;
+
+ switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ break;
+ }
} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
*tx_flags |= TX_CMD_FLG_CTS_MSK;
+ *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
}
}
-EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
+EXPORT_SYMBOL(iwlcore_tx_cmd_protection);
+
static bool is_single_rx_stream(struct iwl_priv *priv)
{
@@ -1869,6 +1886,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+ if (bss_conf->use_cts_prot)
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
}
if (changes & BSS_CHANGED_BASIC_RATES) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index e9d23f2..4a71dfb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -104,8 +104,9 @@ struct iwl_hcmd_utils_ops {
u32 min_average_noise,
u8 default_chain);
void (*chain_noise_reset)(struct iwl_priv *priv);
- void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
- __le32 *tx_flags);
+ void (*tx_cmd_protection)(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags);
int (*calc_rssi)(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
@@ -249,7 +250,7 @@ struct iwl_mod_params {
* @led_compensation: compensate on the led on/off time per HW according
* to the deviation to achieve the desired led frequency.
* The detail algorithm is described in iwl-led.c
- * @use_rts_for_ht: use rts/cts protection for HT traffic
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @chain_noise_num_beacons: number of beacons used to compute chain noise
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
@@ -318,7 +319,7 @@ struct iwl_cfg {
const bool ht_greenfield_support;
u16 led_compensation;
const bool broken_powersave;
- bool use_rts_for_ht;
+ bool use_rts_for_aggregation;
int chain_noise_num_beacons;
const bool supports_idle;
bool adv_thermal_throttle;
@@ -390,8 +391,9 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
int iwl_alloc_txq_mem(struct iwl_priv *priv);
void iwl_free_txq_mem(struct iwl_priv *priv);
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
- __le32 *tx_flags);
+void iwlcore_tx_cmd_protection(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ __le16 fc, __le32 *tx_flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index d24eb47..70c4b8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -435,10 +435,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
- if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
- tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+ priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
if (ieee80211_is_mgmt(fc)) {
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 8e9fbfd..51a96f5 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -7,6 +7,7 @@
*/
#include <linux/slab.h>
+#include <linux/sched.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 71a101f..822f8dc 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -43,8 +43,6 @@ static DEFINE_PCI_DEVICE_TABLE(p54p_table) = {
{ PCI_DEVICE(0x1260, 0x3886) },
/* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */
{ PCI_DEVICE(0x1260, 0xffff) },
- /* Standard Microsystems Corp SMC2802W Wireless PCI */
- { PCI_DEVICE(0x10b8, 0x2802) },
{ },
};
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 636724b..6c24144 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -33,9 +33,9 @@
#define L2CAP_DEFAULT_FLUSH_TO 0xffff
#define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_MAX_TX 3
-#define L2CAP_DEFAULT_RETRANS_TO 1000 /* 1 second */
+#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
-#define L2CAP_DEFAULT_MAX_PDU_SIZE 672
+#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 3e3cd9d..fadf26b 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2705,8 +2705,9 @@ done:
case L2CAP_MODE_ERTM:
pi->remote_tx_win = rfc.txwin_size;
pi->remote_max_tx = rfc.max_transmit;
- if (rfc.max_pdu_size > pi->conn->mtu - 10)
- rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
+
+ if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
+ rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
@@ -2723,8 +2724,8 @@ done:
break;
case L2CAP_MODE_STREAMING:
- if (rfc.max_pdu_size > pi->conn->mtu - 10)
- rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
+ if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10)
+ rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
@@ -2806,7 +2807,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
if (*result == L2CAP_CONF_SUCCESS) {
switch (rfc.mode) {
case L2CAP_MODE_ERTM:
- pi->remote_tx_win = rfc.txwin_size;
pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
pi->mps = le16_to_cpu(rfc.max_pdu_size);
@@ -2862,7 +2862,6 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
done:
switch (rfc.mode) {
case L2CAP_MODE_ERTM:
- pi->remote_tx_win = rfc.txwin_size;
pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
pi->mps = le16_to_cpu(rfc.max_pdu_size);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index e74a1a2..d1a3fb9 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -843,13 +843,19 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
return -EINVAL;
if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
/* Verify that we are associated with the destination AP */
+ wdev_lock(wdev);
+
if (!wdev->current_bss ||
memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
ETH_ALEN) != 0 ||
(wdev->iftype == NL80211_IFTYPE_STATION &&
memcmp(wdev->current_bss->pub.bssid, mgmt->da,
- ETH_ALEN) != 0))
+ ETH_ALEN) != 0)) {
+ wdev_unlock(wdev);
return -ENOTCONN;
+ }
+
+ wdev_unlock(wdev);
}
if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
--
John W. Linville Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org might be all we have. Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH] netpoll: use non-BH variant of RCU
From: John W. Linville @ 2010-08-10 20:25 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Herbert Xu, Paul E. McKenney, John W. Linville
"netpoll: Fix RCU usage" switched netpoll_rx to use the BH variant
of RCU. Unfortunately, calling netpoll_rx from netif_rx resulted in
the following backtrace:
WARNING: at kernel/softirq.c:143 _local_bh_enable_ip+0x3e/0xab()
Hardware name: 2373HU6
Modules linked in: arc4 ecb lib80211_crypt_wep fuse nfsd lockd nfs_acl auth_rpcgss exportfs sunrpc cpufreq_ondemand acpi_cpufreq mperf ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 dm_multipath uinput snd_intel8x0m snd_intel8x0 snd_ac97_codec ac97_bus ppdev snd_seq ipw2200 nsc_ircc snd_seq_device video irda e1000 parport_pc snd_pcm libipw parport output crc_ccitt thinkpad_acpi cfg80211 i2c_i801 joydev pcspkr iTCO_wdt rfkill iTCO_vendor_support lib80211 snd_timer snd soundcore snd_page_alloc yenta_socket radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded: microcode]
Pid: 0, comm: swapper Not tainted 2.6.35-wl+ #5
Call Trace:
[<c043aa42>] warn_slowpath_common+0x6a/0x7f
[<c0440541>] ? _local_bh_enable_ip+0x3e/0xab
[<c072e8dc>] ? rcu_read_unlock_bh+0x21/0x23
[<c043aa6b>] warn_slowpath_null+0x14/0x18
[<c0440541>] _local_bh_enable_ip+0x3e/0xab
[<c04405cd>] local_bh_enable+0x10/0x12
[<c072e8dc>] rcu_read_unlock_bh+0x21/0x23
[<c072e978>] netpoll_rx+0x9a/0xa2
[<c0730ab9>] netif_rx+0x13/0x85
[<f7cc02db>] libipw_rx+0x78c/0x7b6 [libipw]
[<c07c6902>] ? _raw_spin_lock_irqsave+0x60/0x6a
[<f81aedc9>] ipw_irq_tasklet+0xec3/0x1285 [ipw2200]
[<c07c6f01>] ? _raw_spin_unlock_irq+0x26/0x30
[<c046189a>] ? print_lock_contention_bug+0x11/0xb2
[<c046189a>] ? print_lock_contention_bug+0x11/0xb2
[<c043fd87>] tasklet_action+0x78/0xcb
[<c0440293>] __do_softirq+0xc4/0x183
[<c044038d>] do_softirq+0x3b/0x5f
[<c04404d0>] irq_exit+0x3a/0x6d
[<c0404423>] do_IRQ+0x8b/0x9f
[<c04038b5>] common_interrupt+0x35/0x3c
[<c062ecfa>] ? acpi_idle_enter_simple+0xfe/0x13c
[<c045007b>] ? exit_itimers+0x2d/0x73
[<c062ecfc>] ? acpi_idle_enter_simple+0x100/0x13c
[<c070bf10>] cpuidle_idle_call+0x78/0xdc
[<c040251c>] cpu_idle+0x9b/0xb7
[<c07b1dd2>] rest_init+0xa6/0xab
[<c0a4b96d>] start_kernel+0x389/0x38e
[<c0a4b0c9>] i386_start_kernel+0xc9/0xd0
Switching back to the non-BH variant of RCU resolves the issue.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
include/linux/netpoll.h | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 413742c..0bdd527 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -63,8 +63,8 @@ static inline bool netpoll_rx(struct sk_buff *skb)
unsigned long flags;
bool ret = false;
- rcu_read_lock_bh();
- npinfo = rcu_dereference_bh(skb->dev->npinfo);
+ rcu_read_lock();
+ npinfo = rcu_dereference(skb->dev->npinfo);
if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
goto out;
@@ -76,13 +76,13 @@ static inline bool netpoll_rx(struct sk_buff *skb)
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
out:
- rcu_read_unlock_bh();
+ rcu_read_unlock();
return ret;
}
static inline int netpoll_rx_on(struct sk_buff *skb)
{
- struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
+ struct netpoll_info *npinfo = rcu_dereference(skb->dev->npinfo);
return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
}
--
1.7.2.1
^ permalink raw reply related
* [PATCH] net: make netpoll_rx return bool for !CONFIG_NETPOLL
From: John W. Linville @ 2010-08-10 19:44 UTC (permalink / raw)
To: netdev; +Cc: davem, John W. Linville
"netpoll: Use 'bool' for netpoll_rx() return type." missed the case when
CONFIG_NETPOLL is disabled.
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
include/linux/netpoll.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 413742c..791d510 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -122,7 +122,7 @@ static inline int netpoll_tx_running(struct net_device *dev)
}
#else
-static inline int netpoll_rx(struct sk_buff *skb)
+static inline bool netpoll_rx(struct sk_buff *skb)
{
return 0;
}
--
1.7.2.1
^ permalink raw reply related
* ethtool v2.6.35 released
From: Jeff Garzik @ 2010-08-10 18:49 UTC (permalink / raw)
To: NetDev
ethtool version 2.6.35, code named bhutchings, has been released.
Home page: https://sourceforge.net/projects/gkernel/
Download link:
https://sourceforge.net/projects/gkernel/files/ethtool/2.6.35/ethtool-2.6.35.tar.gz/download
Release overview:
* Feature: sfc register dump support
* Feature: improve cmd line parsing of ints, IPv4 addresses
* Feature: support ethtool named flags, messaging types
* Feature: minor man page fixes
* Feature: control RX flow hash indirection
^ permalink raw reply
* [PATCH 2/2] caif-spi: Bugfix SPI_DATA_POS settings were inverted.
From: sjur.brandeland @ 2010-08-10 17:36 UTC (permalink / raw)
To: davem; +Cc: sjurbren, netdev, Sjur Braendeland
In-Reply-To: <1281461807-17408-1-git-send-email-sjur.brandeland@stericsson.com>
From: Sjur Braendeland <sjur.brandeland@stericsson.com>
The setting of SPI_DATA_POS depending on CONFIG_CAIF_SPI_SYNC
where inverted.
Change-Id: I4886d1d69cc50557f516e05c40f649fed55384a2
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
drivers/net/caif/caif_spi_slave.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
index 077ccf8..2111dbf 100644
--- a/drivers/net/caif/caif_spi_slave.c
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -22,13 +22,13 @@
#include <net/caif/caif_spi.h>
#ifndef CONFIG_CAIF_SPI_SYNC
-#define SPI_DATA_POS SPI_CMD_SZ
+#define SPI_DATA_POS 0
static inline int forward_to_spi_cmd(struct cfspi *cfspi)
{
return cfspi->rx_cpck_len;
}
#else
-#define SPI_DATA_POS 0
+#define SPI_DATA_POS SPI_CMD_SZ
static inline int forward_to_spi_cmd(struct cfspi *cfspi)
{
return 0;
--
1.6.3.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox