* Re: question about map_read_chunks()
From: J. Bruce Fields @ 2013-09-27 20:15 UTC (permalink / raw)
To: Tom Tucker
Cc: Dan Carpenter, Tom Tucker, J. Bruce Fields,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-nfs-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <5245A2DE.9020307-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
On Fri, Sep 27, 2013 at 10:23:10AM -0500, Tom Tucker wrote:
> Hi Dan,
>
> On 9/27/13 7:21 AM, Dan Carpenter wrote:
> >I have looked at this again, and I still worry that it looks like a bug.
> >(remote security related blah blah blah).
> >
> >regards,
> >dan carpenter
> >
> >On Mon, Feb 20, 2012 at 12:50:19PM +0300, Dan Carpenter wrote:
> >>I had a couple questions about some map_read_chunks().
> >>
> >>net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
> >>
> >> 150 ch_bytes = ntohl(ch->rc_target.rs_length);
> >> ^^^^^^^^
> >>It look like this is 32 bits from the network?
> >>
> >> 151 head->arg.head[0] = rqstp->rq_arg.head[0];
> >> 152 head->arg.tail[0] = rqstp->rq_arg.tail[0];
> >> 153 head->arg.pages = &head->pages[head->count];
> >> 154 head->hdr_count = head->count; /* save count of hdr pages */
> >> 155 head->arg.page_base = 0;
> >> 156 head->arg.page_len = ch_bytes;
> >> 157 head->arg.len = rqstp->rq_arg.len + ch_bytes;
> >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>Can overflow.
> >> 158 head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes;
> agreed.
> >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>Same. I didn't follow it through to see if an overflow matters. Does
> >>it?
> >>
> >> 159 head->count++;
> >> 160 chl_map->ch[0].start = 0;
> >> 161 while (byte_count) {
> >> 162 rpl_map->sge[sge_no].iov_base =
> >> 163 page_address(rqstp->rq_arg.pages[page_no]) + page_off;
> >> 164 sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes);
> >> ^^^
> >>This is the wrong cast to use. A large ch_bytes would be counted as a
> >>negative value and get around the cap here.
> True, but if we validate the wire data like we should, that's
> probably not an issue.
Well, my last attempt to do rdma nfs io resulted in an instant server
reboot, so I can take a look at this but it may be the least of our
problems....
--b.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" 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
* [PATCH net 0/7] be2net: Bug fixes
From: Ajit Khaparde @ 2013-09-27 20:16 UTC (permalink / raw)
To: netdev
Series of 7 patches against net tree.
Please apply.
Thanks
-Ajit
[1/7] be2net: Fix to prevent Tx stall on SH-R when packet size < 32
[2/7] be2net: Fix the size of be_nic_res_desc structure
[3/7] be2net: Fix VLAN promiscuous mode programming
[4/7] be2net: Fix number of VLANs supported in UMC mode for BE3-R.
[5/7] be2net: Fix to allow VLAN configuration on VF interfaces.
[6/7] be2net: Fix to configure VLAN priority for a VF interface.
[7/7] be2net: Fix to display the VLAN priority for a VF
^ permalink raw reply
* [PATCH net 1/7] be2net: Fix to prevent Tx stall on SH-R when packet size < 32
From: Ajit Khaparde @ 2013-09-27 20:17 UTC (permalink / raw)
To: netdev
Tx on SH-R can lockup if the packet size is less than 32 bytes.
Pad such packets to a safer 36-byte size.
Patch uses the Lancer-R workaround - which checks for packet <= 32-bytes
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 100b528..31fa13b 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -855,11 +855,11 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
unsigned int eth_hdr_len;
struct iphdr *ip;
- /* Lancer ASIC has a bug wherein packets that are 32 bytes or less
+ /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
* may cause a transmit stall on that port. So the work-around is to
- * pad such packets to a 36-byte length.
+ * pad short packets (<= 32 bytes) to a 36-byte length.
*/
- if (unlikely(lancer_chip(adapter) && skb->len <= 32)) {
+ if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
if (skb_padto(skb, 36))
goto tx_drop;
skb->len = 36;
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 2/7] be2net: Fix the size of be_nic_res_desc structure
From: Ajit Khaparde @ 2013-09-27 20:17 UTC (permalink / raw)
To: netdev
Size of be_nic_res_desc structure is incorrect. Fix it.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_cmds.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index d026226..51a93bd 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1791,7 +1791,7 @@ struct be_nic_res_desc {
u8 acpi_params;
u8 wol_param;
u16 rsvd7;
- u32 rsvd8[3];
+ u32 rsvd8[7];
} __packed;
struct be_cmd_req_get_func_config {
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 3/7] be2net: Fix VLAN promiscuous mode programming
From: Ajit Khaparde @ 2013-09-27 20:17 UTC (permalink / raw)
To: netdev
When the interface runs out of the allocated entries in VLAN table,
we program the interface in VLAN promiscuous mode.
Use OPCODE_COMMON_NTWK_RX_FILTER to set VLAN Promiscuous mode
instead of OPCODE_COMMON_NTWK_VLAN_CONFIG.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be.h | 1 +
drivers/net/ethernet/emulex/benet/be_cmds.c | 9 ++++++++
drivers/net/ethernet/emulex/benet/be_cmds.h | 2 ++
drivers/net/ethernet/emulex/benet/be_main.c | 34 ++++++++++++++++++++++++-----
4 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index ace5050..95d303d 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -333,6 +333,7 @@ enum vf_state {
#define BE_FLAGS_LINK_STATUS_INIT 1
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
+#define BE_FLAGS_VLAN_PROMISC (1 << 4)
#define BE_FLAGS_NAPI_ENABLED (1 << 9)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 1ab5dab..bd0e0c0 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -180,6 +180,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
dev_err(&adapter->pdev->dev,
"opcode %d-%d failed:status %d-%d\n",
opcode, subsystem, compl_status, extd_status);
+
+ if (extd_status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+ return extd_status;
}
}
done:
@@ -1812,6 +1815,12 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
} else if (flags & IFF_ALLMULTI) {
req->if_flags_mask = req->if_flags =
cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
+ } else if (flags & BE_FLAGS_VLAN_PROMISC) {
+ req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
+
+ if (value == ON)
+ req->if_flags =
+ cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
} else {
struct netdev_hw_addr *ha;
int i = 0;
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 51a93bd..108ca8a 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -60,6 +60,8 @@ enum {
MCC_STATUS_NOT_SUPPORTED = 66
};
+#define MCC_ADDL_STS_INSUFFICIENT_RESOURCES 0x16
+
#define CQE_STATUS_COMPL_MASK 0xFFFF
#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
#define CQE_STATUS_EXTD_MASK 0xFFFF
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 31fa13b..036f583 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1013,18 +1013,40 @@ static int be_vid_config(struct be_adapter *adapter)
status = be_cmd_vlan_config(adapter, adapter->if_handle,
vids, num, 1, 0);
- /* Set to VLAN promisc mode as setting VLAN filter failed */
if (status) {
- dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
- dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n");
- goto set_vlan_promisc;
+ /* Set to VLAN promisc mode as setting VLAN filter failed */
+ if (status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
+ goto set_vlan_promisc;
+ dev_err(&adapter->pdev->dev,
+ "Setting HW VLAN filtering failed.\n");
+ } else {
+ if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
+ /* hw VLAN filtering re-enabled. */
+ status = be_cmd_rx_filter(adapter,
+ BE_FLAGS_VLAN_PROMISC, OFF);
+ if (!status) {
+ dev_info(&adapter->pdev->dev,
+ "Disabling VLAN Promiscuous mode.\n");
+ adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+ dev_info(&adapter->pdev->dev,
+ "Re-Enabling HW VLAN filtering\n");
+ }
+ }
}
return status;
set_vlan_promisc:
- status = be_cmd_vlan_config(adapter, adapter->if_handle,
- NULL, 0, 1, 1);
+ dev_warn(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
+
+ status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
+ if (!status) {
+ dev_info(&adapter->pdev->dev, "Enable VLAN Promiscuous mode\n");
+ dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering\n");
+ adapter->flags |= BE_FLAGS_VLAN_PROMISC;
+ } else
+ dev_err(&adapter->pdev->dev,
+ "Failed to enable VLAN Promiscuous mode.\n");
return status;
}
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 4/7] be2net: Fix number of VLANs supported in UMC mode for BE3-R.
From: Ajit Khaparde @ 2013-09-27 20:18 UTC (permalink / raw)
To: netdev
In BE3-R, when UMC is enabled, the number of VLANs that can be added
to the interface is reduced to 15.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be.h | 1 +
drivers/net/ethernet/emulex/benet/be_main.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 95d303d..db02023 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -88,6 +88,7 @@ static inline char *nic_name(struct pci_dev *pdev)
#define BE_MIN_MTU 256
#define BE_NUM_VLANS_SUPPORTED 64
+#define BE_UMC_NUM_VLANS_SUPPORTED 15
#define BE_MAX_EQD 96u
#define BE_MAX_TX_FRAG_COUNT 30
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 036f583..2962d2f 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2985,6 +2985,8 @@ static void BEx_get_resources(struct be_adapter *adapter,
if (adapter->function_mode & FLEX10_MODE)
res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+ else if (adapter->function_mode & UMC_ENABLED)
+ res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
else
res->max_vlans = BE_NUM_VLANS_SUPPORTED;
res->max_mcast_mac = BE_MAX_MC;
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 5/7] be2net: Fix to allow VLAN configuration on VF interfaces.
From: Ajit Khaparde @ 2013-09-27 20:18 UTC (permalink / raw)
To: netdev
Now the VF interfaces have privilege to add VLANs.
Allow VLANs to be configured on these interfaces.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 2962d2f..9c25607 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1055,10 +1055,6 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
- if (!lancer_chip(adapter) && !be_physfn(adapter)) {
- status = -EINVAL;
- goto ret;
- }
/* Packets with VID 0 are always received by Lancer by default */
if (lancer_chip(adapter) && vid == 0)
@@ -1081,11 +1077,6 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
- if (!lancer_chip(adapter) && !be_physfn(adapter)) {
- status = -EINVAL;
- goto ret;
- }
-
/* Packets with VID 0 are always received by Lancer by default */
if (lancer_chip(adapter) && vid == 0)
goto ret;
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 6/7] be2net: Fix to configure VLAN priority for a VF interface.
From: Ajit Khaparde @ 2013-09-27 20:18 UTC (permalink / raw)
To: netdev
Thix fix allows the VLAN priority to be configured for a VF interface
via the "ip link set DEVICE vf NUM" path.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 9c25607..ad593ca 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1212,28 +1212,29 @@ static int be_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
int status = 0;
if (!sriov_enabled(adapter))
return -EPERM;
- if (vf >= adapter->num_vfs || vlan > 4095)
+ if (vf >= adapter->num_vfs || vlan > 4095 || qos > 7)
return -EINVAL;
- if (vlan) {
- if (adapter->vf_cfg[vf].vlan_tag != vlan) {
+ if (vlan || qos) {
+ vlan |= qos << VLAN_PRIO_SHIFT;
+ if (vf_cfg->vlan_tag != vlan) {
/* If this is new value, program it. Else skip. */
- adapter->vf_cfg[vf].vlan_tag = vlan;
-
- status = be_cmd_set_hsw_config(adapter, vlan,
- vf + 1, adapter->vf_cfg[vf].if_handle, 0);
+ vf_cfg->vlan_tag = vlan;
+ status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
+ vf_cfg->if_handle, 0);
}
} else {
/* Reset Transparent Vlan Tagging. */
- adapter->vf_cfg[vf].vlan_tag = 0;
- vlan = adapter->vf_cfg[vf].def_vid;
+ vf_cfg->vlan_tag = 0;
+ vlan = vf_cfg->def_vid;
status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
- adapter->vf_cfg[vf].if_handle, 0);
+ vf_cfg->if_handle, 0);
}
--
1.8.1.2
^ permalink raw reply related
* [PATCH net 7/7] be2net: Fix to display the VLAN priority for a VF
From: Ajit Khaparde @ 2013-09-27 20:18 UTC (permalink / raw)
To: netdev
VLAN priority is not being displayed for a VF currently when user executes
"ip link show" command. This patch fixes it.
Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index ad593ca..2c38cc4 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1201,8 +1201,8 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
vi->vf = vf;
vi->tx_rate = vf_cfg->tx_rate;
- vi->vlan = vf_cfg->vlan_tag;
- vi->qos = 0;
+ vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
+ vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
return 0;
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH] ipv6: Fix preferred_lft not updating in some cases
From: Paul Marks @ 2013-09-27 20:28 UTC (permalink / raw)
To: Paul Marks, netdev, davem, yoshfuji, Lorenzo Colitti
In-Reply-To: <20130927081604.GB28287@order.stressinduktion.org>
On Fri, Sep 27, 2013 at 1:16 AM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> On Wed, Sep 25, 2013 at 03:12:55PM -0700, Paul Marks wrote:
>> - if (prefered_lft != ifp->prefered_lft) {
>
> Wouldn't the easiest solution be to just drop this if and execute the two
> lines below unconditionally?
Yes, that's also correct. But is it not better to have simpler code
than shorter diffs? Should we transliterate English to C, or think
about what the algorithm is actually doing? The fact that this bug
has gone unnoticed provides some evidence that the code may have been
too complicated.
>> + const u32 minimum_lft = min(
>> + stored_lft, (u32)MIN_VALID_LIFETIME);
>> + valid_lft = max(valid_lft, minimum_lft);
>
> Quick question: Don't we need a prefered_lft = min(preferred_lft, valid_lft)
> here?
The invariant is (preferred_lft <= valid_lft), and valid_lft can only
get bigger, so I don't think there's a problem.
^ permalink raw reply
* Re: [PATCH v3 net-next 0/2] qlge: feature update
From: David Miller @ 2013-09-27 21:03 UTC (permalink / raw)
To: jitendra.kalsaria; +Cc: netdev, ron.mercer, Dept-HSGLinuxNICDev
In-Reply-To: <1380302267-27843-1-git-send-email-jitendra.kalsaria@qlogic.com>
From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Date: Fri, 27 Sep 2013 13:17:45 -0400
> From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
>
> This patch series enhance the handling of nested vlan tags in Rx path.
>
> V2 changes:
> * removed module parameter.
>
> V3 changes:
> * Users can enable or disable hardware VLAN acceleration using ethtool
>
> Please apply it to net-next.
Series applied, thanks.
^ permalink raw reply
* Re: pull request: wireless 2013-09-27
From: David Miller @ 2013-09-27 21:03 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20130927180549.GB10994@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Fri, 27 Sep 2013 14:05:49 -0400
> Please pull this batch of fixes intended for the 3.12 stream!
Pulled, thanks a lot John.
^ permalink raw reply
* Re: [PATCH v2.40 6/7] datapath: Break out deacceleration portion of vlan_push
From: Jesse Gross @ 2013-09-27 21:05 UTC (permalink / raw)
To: Ben Pfaff
Cc: Simon Horman, dev@openvswitch.org, netdev, Pravin B Shelar,
Ravi K, Isaku Yamahata, Joe Stringer
In-Reply-To: <20130927194857.GE17506@nicira.com>
On Fri, Sep 27, 2013 at 12:48 PM, Ben Pfaff <blp@nicira.com> wrote:
> On Fri, Sep 27, 2013 at 09:18:35AM +0900, Simon Horman wrote:
>> Break out deacceleration portion of vlan_push into vlan_put
>> so that it may be re-used by mpls_push.
>>
>> For both vlan_push and mpls_push if there is an accelerated VLAN tag
>> present then it should be deaccelerated, adding it to the data of
>> the skb, before the new tag is added.
>>
>> Signed-off-by: Simon Horman <horms@verge.net.au>
>
> I think Jesse already reviewed and approved patches 6 and 7, but I don't
> see any Acked-by attached to them.
There were a few small issues remaining last time, so I'll look
through them again.
^ permalink raw reply
* Re: [PATCH net 0/7] be2net: Bug fixes
From: David Miller @ 2013-09-27 21:12 UTC (permalink / raw)
To: ajit.khaparde; +Cc: netdev
In-Reply-To: <20130927201654.GA4494@emulex.com>
From: Ajit Khaparde <ajit.khaparde@emulex.com>
Date: Fri, 27 Sep 2013 15:16:54 -0500
> Series of 7 patches against net tree.
> Please apply.
...
> [1/7] be2net: Fix to prevent Tx stall on SH-R when packet size < 32
> [2/7] be2net: Fix the size of be_nic_res_desc structure
> [3/7] be2net: Fix VLAN promiscuous mode programming
> [4/7] be2net: Fix number of VLANs supported in UMC mode for BE3-R.
> [5/7] be2net: Fix to allow VLAN configuration on VF interfaces.
> [6/7] be2net: Fix to configure VLAN priority for a VF interface.
> [7/7] be2net: Fix to display the VLAN priority for a VF
Series applied, thanks.
^ permalink raw reply
* [PATCH] pkt_sched: fq: qdisc dismantle fixes
From: Eric Dumazet @ 2013-09-27 21:20 UTC (permalink / raw)
To: David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
fq_reset() should drops all packets in queue, including
throttled flows.
This patch moves code from fq_destroy() to fq_reset()
to do the cleaning.
fq_change() must stop calling fq_dequeue() if all remaining
packets are from throttled flows.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/sched/sch_fq.c | 57 +++++++++++++++++++++++++++----------------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 32ad015..fc6de56 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -285,7 +285,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
/* remove one skb from head of flow queue */
-static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
+static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow)
{
struct sk_buff *skb = flow->head;
@@ -293,6 +293,8 @@ static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
flow->head = skb->next;
skb->next = NULL;
flow->qlen--;
+ sch->qstats.backlog -= qdisc_pkt_len(skb);
+ sch->q.qlen--;
}
return skb;
}
@@ -419,7 +421,7 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
struct sk_buff *skb;
struct fq_flow *f;
- skb = fq_dequeue_head(&q->internal);
+ skb = fq_dequeue_head(sch, &q->internal);
if (skb)
goto out;
fq_check_throttled(q, now);
@@ -449,7 +451,7 @@ begin:
goto begin;
}
- skb = fq_dequeue_head(f);
+ skb = fq_dequeue_head(sch, f);
if (!skb) {
head->first = f->next;
/* force a pass through old_flows to prevent starvation */
@@ -490,19 +492,44 @@ begin:
}
}
out:
- sch->qstats.backlog -= qdisc_pkt_len(skb);
qdisc_bstats_update(sch, skb);
- sch->q.qlen--;
qdisc_unthrottled(sch);
return skb;
}
static void fq_reset(struct Qdisc *sch)
{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ struct rb_root *root;
struct sk_buff *skb;
+ struct rb_node *p;
+ struct fq_flow *f;
+ unsigned int idx;
- while ((skb = fq_dequeue(sch)) != NULL)
+ while ((skb = fq_dequeue_head(sch, &q->internal)) != NULL)
kfree_skb(skb);
+
+ if (!q->fq_root)
+ return;
+
+ for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
+ root = &q->fq_root[idx];
+ while ((p = rb_first(root)) != NULL) {
+ f = container_of(p, struct fq_flow, fq_node);
+ rb_erase(p, root);
+
+ while ((skb = fq_dequeue_head(sch, f)) != NULL)
+ kfree_skb(skb);
+
+ kmem_cache_free(fq_flow_cachep, f);
+ }
+ }
+ q->new_flows.first = NULL;
+ q->old_flows.first = NULL;
+ q->delayed = RB_ROOT;
+ q->flows = 0;
+ q->inactive_flows = 0;
+ q->throttled_flows = 0;
}
static void fq_rehash(struct fq_sched_data *q,
@@ -645,6 +672,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = fq_dequeue(sch);
+ if (!skb)
+ break;
kfree_skb(skb);
drop_count++;
}
@@ -657,21 +686,9 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
static void fq_destroy(struct Qdisc *sch)
{
struct fq_sched_data *q = qdisc_priv(sch);
- struct rb_root *root;
- struct rb_node *p;
- unsigned int idx;
- if (q->fq_root) {
- for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
- root = &q->fq_root[idx];
- while ((p = rb_first(root)) != NULL) {
- rb_erase(p, root);
- kmem_cache_free(fq_flow_cachep,
- container_of(p, struct fq_flow, fq_node));
- }
- }
- kfree(q->fq_root);
- }
+ fq_reset(sch);
+ kfree(q->fq_root);
qdisc_watchdog_cancel(&q->watchdog);
}
^ permalink raw reply related
* Re: [PATCH net 1/1] qlcnic: Fix register device in FAILED state for 82xx.
From: David Miller @ 2013-09-27 21:26 UTC (permalink / raw)
To: sucheta.chakraborty; +Cc: netdev, Dept-HSGLinuxNICDev
In-Reply-To: <1380262356-26221-1-git-send-email-sucheta.chakraborty@qlogic.com>
From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Date: Fri, 27 Sep 2013 02:12:36 -0400
> o Commit 7e2cf4feba058476324dc545e3d1b316998c91e6
> ("qlcnic: change driver hardware interface mechanism")
> has overwritten
> commit b43e5ee76a4320c070cf0fe65cf4927198fbb4d1
> ("qlcnic: Register device in FAILED state")
>
> Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 2/2] net: phy: at803x: add suspend/resume callbacks
From: David Miller @ 2013-09-27 21:28 UTC (permalink / raw)
To: zonque; +Cc: mugunthanvnm, netdev, ujhelyi.m, sergei.shtylyov
In-Reply-To: <5245D31C.4080104@gmail.com>
From: Daniel Mack <zonque@gmail.com>
Date: Fri, 27 Sep 2013 20:49:00 +0200
> On 22.09.2013 08:00, Mugunthan V N wrote:
>> On Saturday 21 September 2013 08:23 PM, Daniel Mack wrote:
>>> When WOL is enabled, the chip can't be put into power-down (BMCR_PDOWN)
>>> mode, as that will also switch off the MAC, which consequently leads to
>>> a link loss.
>>>
>>> Use BMCR_ISOLATE in that case, which will at least save us some
>>> milliamperes in comparison to normal operation mode.
>>>
>>> Signed-off-by: Daniel Mack <zonque@gmail.com>
>> Looks good to me
>>
>> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
>
> Thanks :)
>
> David, can you take these two patches with Mugunthan's Acked-by: or do
> you want me to resend them?
Both applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH net-next 1/2] ipv6: avoid high order memory allocations for /proc/net/ipv6_route
From: David Miller @ 2013-09-27 21:33 UTC (permalink / raw)
To: hannes; +Cc: netdev, greearb, kaber, yoshfuji
In-Reply-To: <20130921145559.GA20730@order.stressinduktion.org>
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Sat, 21 Sep 2013 16:55:59 +0200
> Dumping routes on a system with lots rt6_infos in the fibs causes up to
> 11-order allocations in seq_file (which fail). While we could switch
> there to vmalloc we could just implement the streaming interface for
> /proc/net/ipv6_route. This patch switches /proc/net/ipv6_route from
> single_open_net to seq_open_net.
>
> loff_t *pos tracks dst entries.
>
> Also kill never used struct rt6_proc_arg and now unused function
> fib6_clean_all_ro.
>
> Cc: Ben Greear <greearb@candelatech.com>
> Cc: Patrick McHardy <kaber@trash.net>
> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Applied, nice work.
^ permalink raw reply
* Re: [PATCH net-next 2/2] ipv6: compare sernum when walking fib for /proc/net/ipv6_route as safety net
From: David Miller @ 2013-09-27 21:33 UTC (permalink / raw)
To: hannes; +Cc: netdev, greearb, kaber, yoshfuji
In-Reply-To: <20130921145610.GA20769@order.stressinduktion.org>
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Sat, 21 Sep 2013 16:56:10 +0200
> This patch provides an additional safety net against NULL
> pointer dereferences while walking the fib trie for the new
> /proc/net/ipv6_route walkers. I never needed it myself and am unsure
> if it is needed at all, but the same checks where introduced in
> 2bec5a369ee79576a3eea2c23863325089785a2c ("ipv6: fib: fix crash when
> changing large fib while dumping it") to fix NULL pointer bugs.
>
> This patch is separated from the first patch to make it easier to revert
> if we are sure we can drop this logic.
>
> Cc: Ben Greear <greearb@candelatech.com>
> Cc: Patrick McHardy <kaber@trash.net>
> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Applied.
^ permalink raw reply
* Re: [net-next] hp100: replace hardcoded name in /proc/interrupts with interface name
From: David Miller @ 2013-09-27 21:39 UTC (permalink / raw)
To: me; +Cc: netdev
In-Reply-To: <1379789289-10961-1-git-send-email-me@mihirsingh.com>
From: Mihir Singh <me@mihirsingh.com>
Date: Sat, 21 Sep 2013 18:48:09 +0000
> The /proc/interrupts file displays hp100, which is not the accepted style. Printing eth%d is more helpful.
>
> Signed-off-by: Mihir Singh <me@mihirsingh.com>
Applied.
^ permalink raw reply
* Re: [net-next] Fix hardcoded interrupt name lp->name to use system device value
From: David Miller @ 2013-09-27 21:40 UTC (permalink / raw)
To: tedheadster; +Cc: thenaterhood, netdev
In-Reply-To: <20130923022532.GA17124@gmail.com>
From: Matthew Whitehead <tedheadster@gmail.com>
Date: Sun, 22 Sep 2013 22:25:33 -0400
> On Sat, Sep 21, 2013 at 06:49:41PM +0000, Nate Levesque wrote:
>> The lance interrupt handler was using the hard-coded name which would make it difficult to tell where the interrupt came from. Changed to use the device name that made the interrupt.
>>
>> Signed-off-by: Nate Levesque <thenaterhood@gmail.com>
>> ---
>> drivers/net/ethernet/amd/lance.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c
>> index 5c72843..256f590 100644
>> --- a/drivers/net/ethernet/amd/lance.c
>> +++ b/drivers/net/ethernet/amd/lance.c
>> @@ -754,7 +754,7 @@ lance_open(struct net_device *dev)
>> int i;
>>
>> if (dev->irq == 0 ||
>> - request_irq(dev->irq, lance_interrupt, 0, lp->name, dev)) {
>> + request_irq(dev->irq, lance_interrupt, 0, dev->name, dev)) {
>> return -EAGAIN;
>> }
>>
>> --
>> 1.8.1.2
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> Reviewed-by: Matthew Whitehead <tedheadster@gmail.com>
Applied but please use a more appriate subsystem prefix in your Subject
lines, in this case you could say "lance: " after "[net-next] "
^ permalink raw reply
* [PATCH] can: add Renesas R-Car CAN driver
From: Sergei Shtylyov @ 2013-09-27 22:11 UTC (permalink / raw)
To: netdev, wg, mkl, linux-can; +Cc: linux-sh
Add support for the CAN controller found in Renesas R-Car SoCs.
Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
---
The patch is against the 'linux-can-next.git' repo.
drivers/net/can/Kconfig | 9
drivers/net/can/Makefile | 1
drivers/net/can/rcar_can.c | 898 ++++++++++++++++++++++++++++++++++
include/linux/can/platform/rcar_can.h | 15
4 files changed, 923 insertions(+)
Index: linux-can-next/drivers/net/can/Kconfig
===================================================================
--- linux-can-next.orig/drivers/net/can/Kconfig
+++ linux-can-next/drivers/net/can/Kconfig
@@ -125,6 +125,15 @@ config CAN_GRCAN
endian syntheses of the cores would need some modifications on
the hardware level to work.
+config CAN_RCAR
+ tristate "Renesas R-Car CAN controller"
+ ---help---
+ Say Y here if you want to use CAN controller found on Renesas R-Car
+ SoCs.
+
+ To compile this driver as a module, choose M here: the module will
+ be called rcar_can.
+
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
Index: linux-can-next/drivers/net/can/Makefile
===================================================================
--- linux-can-next.orig/drivers/net/can/Makefile
+++ linux-can-next/drivers/net/can/Makefile
@@ -25,5 +25,6 @@ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ica
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_RCAR) += rcar_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
Index: linux-can-next/drivers/net/can/rcar_can.c
===================================================================
--- /dev/null
+++ linux-can-next/drivers/net/can/rcar_can.c
@@ -0,0 +1,898 @@
+/*
+ * Renesas R-Car CAN device driver
+ *
+ * Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com>
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/can/led.h>
+#include <linux/can/dev.h>
+#include <linux/clk.h>
+#include <linux/can/platform/rcar_can.h>
+
+#define DRV_NAME "rcar_can"
+
+#define RCAR_CAN_MIER1 0x42C /* CANi Mailbox Interrupt Enable Register 1 */
+#define RCAR_CAN_MKR(n) ((n) < 2 ? 0x430 + 4 * (n) : 0x400 + 4 * ((n) - 2))
+ /* CANi Mask Register */
+#define RCAR_CAN_MKIVLR0 0x438 /* CANi Mask Invalid Register 0 */
+#define RCAR_CAN_MIER0 0x43C /* CANi Mailbox Interrupt Enable Register 0 */
+
+#define RCAR_CAN_MCTL(n) (0x800 + (n)) /* CANi Message Control Register */
+#define RCAR_CAN_CTLR 0x840 /* CANi Control Register */
+#define RCAR_CAN_STR 0x842 /* CANi Status Register */
+#define RCAR_CAN_BCR 0x844 /* CANi Bit Configuration Register */
+#define RCAR_CAN_CLKR 0x847 /* CANi Clock Select Register */
+#define RCAR_CAN_EIER 0x84C /* CANi Error Interrupt Enable Register */
+#define RCAR_CAN_EIFR 0x84D /* CANi Err Interrupt Factor Judge Register */
+#define RCAR_CAN_RECR 0x84E /* CANi Receive Error Count Register */
+#define RCAR_CAN_TECR 0x84F /* CANi Transmit Error Count Register */
+#define RCAR_CAN_ECSR 0x850 /* CANi Error Code Store Register */
+#define RCAR_CAN_MSSR 0x852 /* CANi Mailbox Search Status Register */
+#define RCAR_CAN_MSMR 0x853 /* CANi Mailbox Search Mode Register */
+#define RCAR_CAN_TCR 0x858 /* CANi Test Control Register */
+#define RCAR_CAN_IER 0x860 /* CANi Interrupt Enable Register */
+#define RCAR_CAN_ISR 0x861 /* CANi Interrupt Status Register */
+
+/* Offsets of RCAR_CAN Mailbox Registers */
+#define MBX_HDR_OFFSET 0x0
+#define MBX_DLC_OFFSET 0x5
+#define MBX_DATA_OFFSET 0x6
+
+#define RCAR_CAN_MBX_SIZE 0x10
+
+/* Control Register bits */
+#define CTLR_SLPM BIT(10)
+#define CTLR_HALT BIT(9)
+#define CTLR_RESET BIT(8)
+#define CTLR_FORCE_RESET (3 << 8)
+#define CTLR_TPM BIT(4) /* Transmission Priority Mode Select Bit */
+#define CTLR_IDFM_MIXED BIT(2) /* Mixed ID mode */
+
+/* Message Control Register bits */
+#define MCTL_TRMREQ BIT(7)
+#define MCTL_RECREQ BIT(6)
+#define MCTL_ONESHOT BIT(4)
+#define MCTL_SENTDATA BIT(0)
+#define MCTL_NEWDATA BIT(0)
+
+#define N_RX_MKREGS 2 /* Number of mask registers */
+ /* for Rx mailboxes 0-31 */
+
+/* Bit Configuration Register settings */
+#define BCR_TSEG1(x) (((x) & 0x0f) << 28)
+#define BCR_BPR(x) (((x) & 0x3ff) << 16)
+#define BCR_SJW(x) (((x) & 0x3) << 12)
+#define BCR_TSEG2(x) (((x) & 0x07) << 8)
+
+/* Mailbox and Mask Registers bits */
+#define RCAR_CAN_IDE BIT(31)
+#define RCAR_CAN_RTR BIT(30)
+#define RCAR_CAN_SID_SHIFT 18
+
+/* Interrupt Enable Register bits */
+#define IER_ERSIE BIT(5) /* Error (ERS) Interrupt Enable Bit */
+#define IER_RXM0IE BIT(2) /* Mailbox 0 Successful Reception (RXM0) */
+ /* Interrupt Enable Bit */
+#define IER_RXM1IE BIT(1) /* Mailbox 1 Successful Reception (RXM0) */
+ /* Interrupt Enable Bit */
+#define IER_TXMIE BIT(0) /* Mailbox 32 to 63 Successful Tx */
+ /* Interrupt Enable Bit */
+
+/* Interrupt Status Register bits */
+#define ISR_ERSF BIT(5) /* Error (ERS) Interrupt Status Bit */
+#define ISR_RXM0F BIT(2) /* Mailbox 0 Successful Reception (RXM0) */
+ /* Interrupt Status Bit */
+#define ISR_RXM1F BIT(1) /* Mailbox 1 to 63 Successful Reception */
+ /* (RXM1) Interrupt Status Bit */
+#define ISR_TXMF BIT(0) /* Mailbox 32 to 63 Successful Transmission */
+ /* (TXM) Interrupt Status Bit */
+
+/* Error Interrupt Enable Register bits */
+#define EIER_BLIE BIT(7) /* Bus Lock Interrupt Enable */
+#define EIER_OLIE BIT(6) /* Overload Frame Transmit Interrupt Enable */
+#define EIER_ORIE BIT(5) /* Receive Overrun Interrupt Enable */
+#define EIER_BORIE BIT(4) /* Bus-Off Recovery Interrupt Enable */
+
+#define EIER_BOEIE BIT(3) /* Bus-Off Entry Interrupt Enable */
+#define EIER_EPIE BIT(2) /* Error Passive Interrupt Enable */
+#define EIER_EWIE BIT(1) /* Error Warning Interrupt Enable */
+#define EIER_BEIE BIT(0) /* Bus Error Interrupt Enable */
+
+/* Error Interrupt Factor Judge Register bits */
+#define EIFR_BLIF BIT(7) /* Bus Lock Detect Flag */
+#define EIFR_OLIF BIT(6) /* Overload Frame Transmission Detect Flag */
+#define EIFR_ORIF BIT(5) /* Receive Overrun Detect Flag */
+#define EIFR_BORIF BIT(4) /* Bus-Off Recovery Detect Flag */
+#define EIFR_BOEIF BIT(3) /* Bus-Off Entry Detect Flag */
+#define EIFR_EPIF BIT(2) /* Error Passive Detect Flag */
+#define EIFR_EWIF BIT(1) /* Error Warning Detect Flag */
+#define EIFR_BEIF BIT(0) /* Bus Error Detect Flag */
+
+/* Error Code Store Register bits */
+#define ECSR_EDPM BIT(7) /* Error Display Mode Select Bit */
+#define ECSR_ADEF BIT(6) /* ACK Delimiter Error Flag */
+#define ECSR_BE0F BIT(5) /* Bit Error (dominant) Flag */
+#define ECSR_BE1F BIT(4) /* Bit Error (recessive) Flag */
+#define ECSR_CEF BIT(3) /* CRC Error Flag */
+#define ECSR_AEF BIT(2) /* ACK Error Flag */
+#define ECSR_FEF BIT(1) /* Form Error Flag */
+#define ECSR_SEF BIT(0) /* Stuff Error Flag */
+
+/* Mailbox Search Status Register bits */
+#define MSSR_SEST BIT(7) /* Search Result Status Bit */
+#define MSSR_MBNST 0x3f /* Search Result Mailbox Number Status mask */
+
+/* Mailbox Search Mode Register values */
+#define MSMR_TXMB 1 /* Transmit mailbox search mode */
+#define MSMR_RXMB 0 /* Receive mailbox search mode */
+
+/* Mailbox configuration:
+ * mailbox 0 - not used
+ * mailbox 1-31 - Rx
+ * mailbox 32-63 - Tx
+ * no FIFO mailboxes
+ */
+#define N_MBX 64
+#define FIRST_TX_MB 32
+#define RX_MBX_MASK 0xFFFFFFFE
+
+#define RCAR_CAN_NAPI_WEIGHT (FIRST_TX_MB - 1)
+
+struct rcar_can_priv {
+ struct can_priv can; /* Must be the first member! */
+ struct net_device *ndev;
+ struct napi_struct napi;
+ void __iomem *reg_base;
+ struct clk *clk;
+ spinlock_t mier_lock;
+ u8 clock_select;
+};
+
+static const struct can_bittiming_const rcar_can_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static inline u32 rcar_can_readl(struct rcar_can_priv *priv, int reg)
+{
+ return readl(priv->reg_base + reg);
+}
+
+static inline u16 rcar_can_readw(struct rcar_can_priv *priv, int reg)
+{
+ return readw(priv->reg_base + reg);
+}
+
+static inline u8 rcar_can_readb(struct rcar_can_priv *priv, int reg)
+{
+ return readb(priv->reg_base + reg);
+}
+
+static inline void rcar_can_writel(struct rcar_can_priv *priv, int reg, u32 val)
+{
+ writel(val, priv->reg_base + reg);
+}
+
+static inline void rcar_can_writew(struct rcar_can_priv *priv, int reg, u16 val)
+{
+ writew(val, priv->reg_base + reg);
+}
+
+static inline void rcar_can_writeb(struct rcar_can_priv *priv, int reg, u8 val)
+{
+ writeb(val, priv->reg_base + reg);
+}
+
+static inline u32 rcar_can_mbx_readl(struct rcar_can_priv *priv,
+ u32 mbxno, u8 offset)
+{
+ return rcar_can_readl(priv, RCAR_CAN_MBX_SIZE * mbxno + offset);
+}
+
+static inline u8 rcar_can_mbx_readb(struct rcar_can_priv *priv,
+ u32 mbxno, u8 offset)
+{
+ return rcar_can_readb(priv, RCAR_CAN_MBX_SIZE * mbxno + offset);
+}
+
+static inline void rcar_can_mbx_writel(struct rcar_can_priv *priv, u32 mbxno,
+ u8 offset, u32 val)
+{
+ rcar_can_writel(priv, RCAR_CAN_MBX_SIZE * mbxno + offset, val);
+}
+
+static inline void rcar_can_mbx_writeb(struct rcar_can_priv *priv, u32 mbxno,
+ u8 offset, u8 val)
+{
+ rcar_can_writeb(priv, RCAR_CAN_MBX_SIZE * mbxno + offset, val);
+}
+
+static void rcar_can_error(struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u8 eifr;
+
+ /* Propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb) {
+ if (printk_ratelimit())
+ netdev_err(priv->ndev,
+ "%s: alloc_can_err_skb() failed\n",
+ __func__);
+ return;
+ }
+
+ eifr = rcar_can_readb(priv, RCAR_CAN_EIFR);
+ if (eifr & EIFR_EWIF) {
+ netdev_dbg(priv->ndev, "Error warning interrupt\n");
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (rcar_can_readb(priv, RCAR_CAN_TECR) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ if (rcar_can_readb(priv, RCAR_CAN_RECR) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ /* Clear interrupt condition */
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_EWIF);
+ }
+ if (eifr & EIFR_EPIF) {
+ netdev_dbg(priv->ndev, "Error passive interrupt\n");
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (rcar_can_readb(priv, RCAR_CAN_TECR) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ if (rcar_can_readb(priv, RCAR_CAN_RECR) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ /* Clear interrupt condition */
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_EPIF);
+ }
+ if (eifr & EIFR_BOEIF) {
+ netdev_dbg(priv->ndev, "Bus-off entry interrupt\n");
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ /* Clear interrupt condition */
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_BOEIF);
+ /* Disable all interrupts in bus-off to avoid int hog */
+ rcar_can_writeb(priv, RCAR_CAN_EIER, 0);
+ rcar_can_writeb(priv, RCAR_CAN_IER, 0);
+ can_bus_off(ndev);
+ }
+ if (eifr & EIFR_BEIF) {
+ int rx_errors = 0, tx_errors = 0, bus_errors = 0;
+ u8 ecsr;
+
+ netdev_dbg(priv->ndev, "Bus error interrupt:\n");
+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_UNSPEC;
+
+ ecsr = rcar_can_readb(priv, RCAR_CAN_ECSR);
+ if (ecsr & ECSR_ADEF) {
+ netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
+ bus_errors++;
+ tx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_ADEF);
+ }
+ if (ecsr & ECSR_BE0F) {
+ netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ bus_errors++;
+ tx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_BE0F);
+ }
+ if (ecsr & ECSR_BE1F) {
+ netdev_dbg(priv->ndev, "Bit Error (recessive)\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ bus_errors++;
+ tx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_BE1F);
+ }
+ if (ecsr & ECSR_CEF) {
+ netdev_dbg(priv->ndev, "CRC Error\n");
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ bus_errors++;
+ rx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_CEF);
+ }
+ if (ecsr & ECSR_AEF) {
+ netdev_dbg(priv->ndev, "ACK Error\n");
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ bus_errors++;
+ tx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_AEF);
+ }
+ if (ecsr & ECSR_FEF) {
+ netdev_dbg(priv->ndev, "Form Error\n");
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ bus_errors++;
+ rx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_FEF);
+ }
+ if (ecsr & ECSR_SEF) {
+ netdev_dbg(priv->ndev, "Stuff Error\n");
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ bus_errors++;
+ rx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_SEF);
+ }
+
+ priv->can.can_stats.bus_error += bus_errors;
+ ndev->stats.rx_errors += rx_errors;
+ ndev->stats.tx_errors += tx_errors;
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_BEIF);
+ }
+ if (eifr & EIFR_ORIF) {
+ netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ ndev->stats.rx_over_errors++;
+ ndev->stats.rx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_ORIF);
+ }
+ if (eifr & EIFR_OLIF) {
+ netdev_dbg(priv->ndev,
+ "Overload Frame Transmission error interrupt\n");
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
+ ndev->stats.rx_over_errors++;
+ ndev->stats.rx_errors++;
+ rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_OLIF);
+ }
+
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static irqreturn_t rcar_can_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ u8 isr;
+
+ isr = rcar_can_readb(priv, RCAR_CAN_ISR);
+ if (isr & ISR_ERSF)
+ rcar_can_error(ndev);
+
+ if (isr & ISR_TXMF) {
+ u32 ie_mask = 0;
+
+ /* Set Transmit Mailbox Search Mode */
+ rcar_can_writeb(priv, RCAR_CAN_MSMR, MSMR_TXMB);
+ while (1) {
+ u8 mctl, mbx;
+
+ mbx = rcar_can_readb(priv, RCAR_CAN_MSSR);
+ if (mbx & MSSR_SEST)
+ break;
+ mbx &= MSSR_MBNST;
+ mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbx));
+ /* Bits SENTDATA and TRMREQ cannot be
+ * set to 0 simultaneously
+ */
+ mctl &= ~MCTL_TRMREQ;
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx), mctl);
+ mctl &= ~MCTL_SENTDATA;
+ /* Clear interrupt */
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx), mctl);
+ ie_mask |= BIT(mbx - FIRST_TX_MB);
+ stats->tx_bytes += can_get_echo_skb(ndev,
+ mbx - FIRST_TX_MB);
+ stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+ }
+ /* Set receive mailbox search mode */
+ rcar_can_writeb(priv, RCAR_CAN_MSMR, MSMR_RXMB);
+ /* Disable mailbox interrupt, mark mailbox as free */
+ if (ie_mask) {
+ u32 mier1;
+
+ spin_lock(&priv->mier_lock);
+ mier1 = rcar_can_readl(priv, RCAR_CAN_MIER1);
+ rcar_can_writel(priv, RCAR_CAN_MIER1, mier1 & ~ie_mask);
+ spin_unlock(&priv->mier_lock);
+ if (unlikely(netif_queue_stopped(ndev)))
+ netif_wake_queue(ndev);
+ }
+ }
+ if (isr & ISR_RXM1F) {
+ if (napi_schedule_prep(&priv->napi)) {
+ /* Disable Rx interrupts */
+ rcar_can_writeb(priv, RCAR_CAN_IER,
+ rcar_can_readb(priv, RCAR_CAN_IER) &
+ ~IER_RXM1IE);
+ __napi_schedule(&priv->napi);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int rcar_can_set_bittiming(struct net_device *dev)
+{
+ struct rcar_can_priv *priv = netdev_priv(dev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ u32 bcr;
+ u16 ctlr;
+ u8 clkr;
+
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ if (ctlr & CTLR_SLPM) {
+ /* Write to BCR in CAN reset mode or CAN halt mode */
+ return -EBUSY;
+ }
+ /* Don't overwrite CLKR with 32-bit BCR access */
+ /* CLKR has 8-bit access */
+ clkr = rcar_can_readb(priv, RCAR_CAN_CLKR);
+ bcr = BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
+ BCR_BPR(bt->brp - 1) | BCR_SJW(bt->sjw - 1) |
+ BCR_TSEG2(bt->phase_seg2 - 1);
+ rcar_can_writel(priv, RCAR_CAN_BCR, bcr);
+ rcar_can_writeb(priv, RCAR_CAN_CLKR, clkr);
+ return 0;
+}
+
+static void rcar_can_start(struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr, n;
+
+ /* Set controller to known mode:
+ * - normal mailbox mode (no FIFO);
+ * - accept all messages (no filter).
+ * CAN is in sleep mode after MCU hardware or software reset.
+ */
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ ctlr &= ~CTLR_SLPM;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ /* Go to reset mode */
+ ctlr |= CTLR_FORCE_RESET;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ ctlr |= CTLR_IDFM_MIXED; /* Select mixed ID mode */
+ ctlr &= ~CTLR_TPM; /* Set ID priority transmit mode */
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+
+ rcar_can_writeb(priv, RCAR_CAN_CLKR, priv->clock_select);
+
+ /* Accept all SID and EID */
+ for (n = 0; n < N_RX_MKREGS; n++)
+ rcar_can_writel(priv, RCAR_CAN_MKR(n), 0);
+ rcar_can_writel(priv, RCAR_CAN_MKIVLR0, 0);
+
+ rcar_can_set_bittiming(ndev);
+
+ /* Initial value of MIER1 undefined. Mark all Tx mailboxes as free. */
+ rcar_can_writel(priv, RCAR_CAN_MIER1, 0);
+
+ rcar_can_writeb(priv, RCAR_CAN_IER, IER_TXMIE | IER_ERSIE | IER_RXM1IE);
+
+ /* Accumulate error codes */
+ rcar_can_writeb(priv, RCAR_CAN_ECSR, ECSR_EDPM);
+ /* Enable error interrupts */
+ rcar_can_writeb(priv, RCAR_CAN_EIER,
+ EIER_EWIE | EIER_EPIE | EIER_BOEIE | EIER_BEIE |
+ EIER_ORIE | EIER_OLIE);
+ /* Enable interrupts for RX mailboxes */
+ rcar_can_writel(priv, RCAR_CAN_MIER0, RX_MBX_MASK);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* Write to the CiMCTLj register in CAN
+ * operation mode or CAN halt mode.
+ * Configure mailboxes 0-31 as Rx mailboxes.
+ * Configure mailboxes 32-63 as Tx mailboxes.
+ */
+ /* Go to halt mode */
+ ctlr |= CTLR_HALT;
+ ctlr &= ~CTLR_RESET;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ for (n = 0; n < FIRST_TX_MB; n++) {
+ /* According to documentation we should clear MCTL
+ * register before configuring mailbox.
+ */
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(n), 0);
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(n), MCTL_RECREQ);
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(FIRST_TX_MB + n), 0);
+ }
+ /* Go to operation mode */
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr & ~CTLR_FORCE_RESET);
+}
+
+static int rcar_can_open(struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ int err;
+
+ err = open_candev(ndev);
+ if (err) {
+ netdev_err(ndev, "open_candev() failed %d\n", err);
+ goto out;
+ }
+ napi_enable(&priv->napi);
+ err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
+ if (err) {
+ netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq);
+ goto out_close;
+ }
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ rcar_can_start(ndev);
+ netif_start_queue(ndev);
+ return 0;
+out_close:
+ napi_disable(&priv->napi);
+ close_candev(ndev);
+out:
+ return err;
+}
+
+static void rcar_can_stop(struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr;
+
+ /* Go to (force) reset mode */
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr | CTLR_FORCE_RESET);
+ rcar_can_writel(priv, RCAR_CAN_MIER0, 0);
+ rcar_can_writel(priv, RCAR_CAN_MIER1, 0);
+ rcar_can_writeb(priv, RCAR_CAN_IER, 0);
+ rcar_can_writeb(priv, RCAR_CAN_EIER, 0);
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int rcar_can_close(struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ rcar_can_stop(ndev);
+ free_irq(ndev->irq, ndev);
+ napi_disable(&priv->napi);
+ close_candev(ndev);
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+ return 0;
+}
+
+static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 data, mier1, mbxno, i;
+ unsigned long flags;
+ u8 mctl;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ spin_lock_irqsave(&priv->mier_lock, flags);
+ mier1 = rcar_can_readl(priv, RCAR_CAN_MIER1);
+ if (unlikely(mier1 == ~0U)) {
+ spin_unlock_irqrestore(&priv->mier_lock, flags);
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+ rcar_can_writel(priv, RCAR_CAN_MIER1, mier1 | (mier1 + 1));
+ spin_unlock_irqrestore(&priv->mier_lock, flags);
+ mbxno = ffz(mier1) + FIRST_TX_MB;
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ /* Extended frame format */
+ data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE;
+ } else {
+ /* Standard frame format */
+ data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT;
+ }
+ if (cf->can_id & CAN_RTR_FLAG) {
+ /* Remote transmission request */
+ data |= RCAR_CAN_RTR;
+ }
+ rcar_can_mbx_writel(priv, mbxno, MBX_HDR_OFFSET, data);
+
+ rcar_can_mbx_writeb(priv, mbxno, MBX_DLC_OFFSET, cf->can_dlc);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ rcar_can_mbx_writeb(priv, mbxno,
+ MBX_DATA_OFFSET + i, cf->data[i]);
+
+ can_put_echo_skb(skb, ndev, mbxno - FIRST_TX_MB);
+
+ rcar_can_writeb(priv, RCAR_CAN_IER,
+ rcar_can_readb(priv, RCAR_CAN_IER) | IER_TXMIE);
+
+ mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbxno));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ mctl |= MCTL_ONESHOT;
+ else
+ mctl &= ~MCTL_ONESHOT;
+ /* Start TX */
+ mctl |= MCTL_TRMREQ;
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(mbxno), mctl);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops rcar_can_netdev_ops = {
+ .ndo_open = rcar_can_open,
+ .ndo_stop = rcar_can_close,
+ .ndo_start_xmit = rcar_can_start_xmit,
+};
+
+static void rcar_can_rx_pkt(struct rcar_can_priv *priv, int mbx)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 data;
+ u8 dlc;
+
+ skb = alloc_can_skb(priv->ndev, &cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ if (printk_ratelimit())
+ netdev_err(priv->ndev,
+ "%s: alloc_can_skb() failed\n", __func__);
+ return;
+ }
+
+ data = rcar_can_mbx_readl(priv, mbx, MBX_HDR_OFFSET);
+ if (data & RCAR_CAN_IDE)
+ cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK;
+ if (data & RCAR_CAN_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+
+ dlc = rcar_can_mbx_readb(priv, mbx, MBX_DLC_OFFSET);
+ cf->can_dlc = get_can_dlc(dlc);
+ for (dlc = 0; dlc < cf->can_dlc; dlc++)
+ cf->data[dlc] = rcar_can_mbx_readb(priv, mbx,
+ MBX_DATA_OFFSET + dlc);
+
+ can_led_event(priv->ndev, CAN_LED_EVENT_RX);
+
+ netif_receive_skb(skb);
+ stats->rx_bytes += cf->can_dlc;
+ stats->rx_packets++;
+}
+
+static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct rcar_can_priv *priv = container_of(napi,
+ struct rcar_can_priv, napi);
+ u32 num_pkts = 0;
+
+ /* Find mailbox */
+ while (1) {
+ u8 mctl, mbx;
+
+ mbx = rcar_can_readb(priv, RCAR_CAN_MSSR);
+ if (mbx & MSSR_SEST || num_pkts >= quota)
+ break;
+ mbx &= MSSR_MBNST;
+ mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbx));
+ /* Clear interrupt */
+ rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx),
+ mctl & ~MCTL_NEWDATA);
+ rcar_can_rx_pkt(priv, mbx);
+ ++num_pkts;
+ }
+ /* All packets processed */
+ if (num_pkts < quota) {
+ u8 ier;
+
+ napi_complete(napi);
+ ier = rcar_can_readb(priv, RCAR_CAN_IER);
+ rcar_can_writeb(priv, RCAR_CAN_IER, ier | IER_RXM1IE);
+ }
+ return num_pkts;
+}
+
+static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ rcar_can_start(ndev);
+ netif_wake_queue(ndev);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int rcar_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct rcar_can_priv *priv = netdev_priv(dev);
+
+ bec->txerr = rcar_can_readb(priv, RCAR_CAN_TECR);
+ bec->rxerr = rcar_can_readb(priv, RCAR_CAN_RECR);
+ return 0;
+}
+
+static int rcar_can_probe(struct platform_device *pdev)
+{
+ struct rcar_can_platform_data *pdata;
+ struct rcar_can_priv *priv;
+ struct net_device *ndev;
+ struct resource *mem;
+ void __iomem *addr;
+ int err = -ENODEV;
+ int irq;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data provided!\n");
+ goto fail;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ goto fail;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(addr)) {
+ err = PTR_ERR(addr);
+ goto fail;
+ }
+
+ ndev = alloc_candev(sizeof(struct rcar_can_priv), N_MBX - FIRST_TX_MB);
+ if (!ndev) {
+ dev_err(&pdev->dev, "alloc_candev failed\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ priv = netdev_priv(ndev);
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ err = PTR_ERR(priv->clk);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", err);
+ goto fail_clk;
+ }
+ clk_enable(priv->clk);
+
+ ndev->netdev_ops = &rcar_can_netdev_ops;
+ ndev->irq = irq;
+ ndev->flags |= IFF_ECHO;
+ priv->ndev = ndev;
+ priv->reg_base = addr;
+ priv->clock_select = pdata->clock_select;
+ priv->can.clock.freq = clk_get_rate(priv->clk);
+ priv->can.bittiming_const = &rcar_can_bittiming_const;
+ priv->can.do_set_bittiming = rcar_can_set_bittiming;
+ priv->can.do_set_mode = rcar_can_do_set_mode;
+ priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_ONE_SHOT;
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ spin_lock_init(&priv->mier_lock);
+
+ netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll,
+ RCAR_CAN_NAPI_WEIGHT);
+ err = register_candev(ndev);
+ if (err) {
+ dev_err(&pdev->dev, "register_candev() failed\n");
+ goto fail_candev;
+ }
+
+ devm_can_led_init(ndev);
+
+ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
+ priv->reg_base, ndev->irq);
+
+ return 0;
+fail_candev:
+ netif_napi_del(&priv->napi);
+fail_clk:
+ free_candev(ndev);
+fail:
+ return err;
+}
+
+static int rcar_can_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr;
+
+ unregister_candev(ndev);
+ netif_napi_del(&priv->napi);
+ /* Go to sleep mode */
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr | CTLR_SLPM);
+ clk_disable(priv->clk);
+ free_candev(ndev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_can_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr;
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ ctlr |= CTLR_HALT;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ ctlr |= CTLR_SLPM;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ clk_disable(priv->clk);
+ return 0;
+}
+
+static int rcar_can_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr;
+
+ clk_enable(priv->clk);
+
+ ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
+ ctlr &= ~CTLR_SLPM;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ ctlr &= ~CTLR_FORCE_RESET;
+ rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
+
+static struct platform_driver rcar_can_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &rcar_can_pm_ops,
+ },
+ .probe = rcar_can_probe,
+ .remove = rcar_can_remove,
+};
+
+module_platform_driver(rcar_can_driver);
+
+MODULE_AUTHOR("Cogent Embedded, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC");
+MODULE_ALIAS("platform:" DRV_NAME);
Index: linux-can-next/include/linux/can/platform/rcar_can.h
===================================================================
--- /dev/null
+++ linux-can-next/include/linux/can/platform/rcar_can.h
@@ -0,0 +1,15 @@
+#ifndef _CAN_PLATFORM_RCAR_CAN_H_
+#define _CAN_PLATFORM_RCAR_CAN_H_
+
+#include <linux/types.h>
+
+/* Clock Select Register settings */
+#define CLKR_CLKEXT 3 /* Externally input clock */
+#define CLKR_CLKP2 1 /* Peripheral clock (clkp2) */
+#define CLKR_CLKP1 0 /* Peripheral clock (clkp1) */
+
+struct rcar_can_platform_data {
+ u8 clock_select; /* Clock source select */
+};
+
+#endif /* !_CAN_PLATFORM_RCAR_CAN_H_ */
^ permalink raw reply
* Re: [PATCH 2/2] ipv4 igmp: use del_timer_sync instead of del_timer in ip_mc_down
From: Salam Noureddine @ 2013-09-27 23:04 UTC (permalink / raw)
To: Stephen Hemminger
Cc: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev
In-Reply-To: <CAO7SqHA4LJhy_NBkPLViJB3s7hM85qd88pmjy3hq-hCCuQstaA@mail.gmail.com>
I tried using in_dev_put instead of __in_dev_put and it seems to work
fine in my testing on linux-3.4. I don't quite understand the reason
for having __in_dev_put decrement the refcnt without destroying the
in_device in case it reaches 0. If the timer handler assumes it cannot
be the last one to hold a reference then that would mean it doesn't
need the reference in the first place.
If this solution is preferable to using del_timer_sync I would go
ahead and submit a new patch.
Thanks,
Salam
On Thu, Sep 5, 2013 at 10:22 AM, Salam Noureddine
<noureddine@aristanetworks.com> wrote:
> On Thu, Sep 5, 2013 at 8:43 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
>> On Wed, 4 Sep 2013 23:43:24 -0700
>> Salam Noureddine <noureddine@aristanetworks.com> wrote:
>>
>>> Delete timers using del_timer_sync in ip_mc_down. Otherwise, it is
>>> possible for the timer to be the last to release its reference to the
>>> in_device and since __in_dev_put doesn't destroy the in_device we
>>> would end up leaking a reference to the net_device and see messages
>>> like the following,
>>>
>>> unregister_netdevice: waiting for eth0 to become free. Usage count = 1
>>>
>>> Tested on linux-3.4.43.
>>>
>>> Signed-off-by: Salam Noureddine <noureddine@aristanetworks.com>
>>
>> Why not just call in_dev_put instead which just proper cleanup.
>> It is less risky of deadlock than del_timer_sync.
>
> I was wondering if there was a reason behind using __in_dev_put since
> the multicast code
> is the only user of that function. I can test using in_dev_put
> instead. Should __in_dev_put
> be removed altogether in that case?
>
> Thanks,
>
> Salam
^ permalink raw reply
* Re: [PATCH net-next] net: introduce SO_MAX_PACING_RATE
From: Steinar H. Gunderson @ 2013-09-27 21:16 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev, Michael Kerrisk
In-Reply-To: <1379949014.3165.24.camel@edumazet-glaptop>
On Mon, Sep 23, 2013 at 08:10:14AM -0700, Eric Dumazet wrote:
> SO_MAX_PACING_RATE offers the application the ability to cap the
> rate computed by transport layer. Value is in bytes per second.
I tried this (the first version) on top of 3.12-rc2, but it doesn't actually
appear to work.
The setsockopt goes through:
[pid 30501] setsockopt(11, SOL_SOCKET, 0x2f /* SO_??? */, [1920000], 4) = 0
And the fq scheduler is active on the machine:
pannekake:~> sudo tc qdisc
qdisc fq 8001: dev eth0 root refcnt 2 limit 10000p flow_limit 100p buckets 1024 quantum 3028 initial_quantum 15140
Yet the packets come out way too close on the wire, as measured by tcpdump
(I have tso/gso off):
23:11:13.687773 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 706316:707764, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687787 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 707764:709212, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687793 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 709212:710660, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687799 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 710660:712108, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687804 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 712108:713556, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687809 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 713556:715004, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687814 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 715004:716452, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687819 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 716452:717900, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687825 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 717900:719348, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687830 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 719348:720796, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687835 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 720796:722244, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687840 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 722244:723692, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687845 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 723692:725140, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687850 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 725140:726588, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687855 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 726588:728036, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687860 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 728036:729484, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687864 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 729484:730932, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687869 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 730932:732380, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687874 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 732380:733828, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687878 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 733828:735276, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687883 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 735276:736724, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687888 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 736724:738172, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687893 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 738172:739620, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687902 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 739620:741068, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.687921 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 741068:742516, ack 1, win 114, options [nop,nop,TS val 5666415 ecr 46581981], length 1448
23:11:13.688818 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 742516:743964, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.688833 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 743964:745412, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.689780 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 745412:746860, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.689794 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 746860:748308, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.690647 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 748308:749756, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.690660 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 749756:751204, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.691493 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 751204:752652, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.691505 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 752652:754100, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
23:11:13.692299 IP 193.35.52.50.9094 > 178.83.234.79.51249: Flags [.], seq 754100:755548, ack 1, win 114, options [nop,nop,TS val 5666416 ecr 46581981], length 1448
/* Steinar */
--
Software Engineer, Google Switzerland
^ permalink raw reply
* Re: [PATCH 2/2] ipv4 igmp: use del_timer_sync instead of del_timer in ip_mc_down
From: Salam Noureddine @ 2013-09-27 23:28 UTC (permalink / raw)
To: Alexey Kuznetsov
Cc: Stephen Hemminger, David S. Miller, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev
In-Reply-To: <20130927231532.GA23750@ms2.inr.ac.ru>
Thanks for the explanation. Currenlty, __in_dev_put is both used in
timer handler function and in ip_mc_down where del_timer is invoked. I
guess we need to change the timer handler so it uses in_dev_put to do
proper cleanup in cases where it runs past the call to ip_mc_down and
has the last reference.
On Fri, Sep 27, 2013 at 4:15 PM, Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> wrote:
> On Fri, Sep 27, 2013 at 04:04:00PM -0700, Salam Noureddine wrote:
>> I don't quite understand the reason
>> for having __in_dev_put decrement the refcnt without destroying the
>> in_device in case it reaches 0. If the timer handler assumes it cannot
>> be the last one to hold a reference then that would mean it doesn't
>> need the reference in the first place.
>
> I would like to explain this, because this can result in a big mistake.
>
> Timer takes reference, when it _can_ be the last sometimes.
>
> When we do del_timer() and know for sure that someone holds refcnt, we can just
> decrese it. In this cae it is obvious: we sit in context whcih deals with in_dev,
> so that reference from timer acannot be the last: caller of the function holds refcnt.
>
> But in another places timer _expires_ and that last reference is dropped by in_dev_put().
>
> Alexey
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox