* Re: [PATCH v3] ip6_output: ensure flow saddr actually belongs to device
From: David Ahern @ 2016-11-14 16:55 UTC (permalink / raw)
To: Hannes Frederic Sowa, Jason A. Donenfeld, Netdev,
WireGuard mailing list, LKML, YOSHIFUJI Hideaki
In-Reply-To: <1479141867.3723362.787321689.4A3DCFD6@webmail.messagingengine.com>
On 11/14/16 9:44 AM, Hannes Frederic Sowa wrote:
> On Mon, Nov 14, 2016, at 00:28, Jason A. Donenfeld wrote:
>> This puts the IPv6 routing functions in parity with the IPv4 routing
>> functions. Namely, we now check in v6 that if a flowi6 requests an
>> saddr, the returned dst actually corresponds to a net device that has
>> that saddr. This mirrors the v4 logic with __ip_dev_find in
>> __ip_route_output_key_hash. In the event that the returned dst is not
>> for a dst with a dev that has the saddr, we return -EINVAL, just like
>> v4; this makes it easy to use the same error handlers for both cases.
>>
>> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>> Cc: David Ahern <dsa@cumulusnetworks.com>
>> ---
>> Changes from v2:
>> It turns out ipv6_chk_addr already has the device enumeration
>> logic that we need by simply passing NULL.
>>
>> net/ipv6/ip6_output.c | 4 ++++
>> 1 file changed, 4 insertions(+)
>>
>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>> index 6001e78..b3b5cb6 100644
>> --- a/net/ipv6/ip6_output.c
>> +++ b/net/ipv6/ip6_output.c
>> @@ -926,6 +926,10 @@ static int ip6_dst_lookup_tail(struct net *net,
>> const struct sock *sk,
>> int err;
>> int flags = 0;
>>
>> + if (!ipv6_addr_any(&fl6->saddr) &&
>> + !ipv6_chk_addr(net, &fl6->saddr, NULL, 1))
>> + return -EINVAL;
>
> Hmm, this check is too permissive, no?
>
> E.g. what happens if you move a link local address from one interface to
> another? In this case this code would still allow the saddr to be used.
This check -- like the ipv4 variant -- only verifies the saddr is locally assigned. If the address moves interfaces it should be fine.
>
> I just also quickly read up on the history (sorry was travelling last
> week) and wonder if you ever saw a user space facing bug or if this is
> basically some difference you saw while writing out of tree code?
I checked the userspace API this morning. bind and cmsg for example check that the address is valid with calls to ipv6_chk_addr.
^ permalink raw reply
* Re: [PATCH v3] ip6_output: ensure flow saddr actually belongs to device
From: Hannes Frederic Sowa @ 2016-11-14 17:04 UTC (permalink / raw)
To: David Ahern, Jason A. Donenfeld, Netdev, WireGuard mailing list,
LKML, YOSHIFUJI Hideaki
In-Reply-To: <fd1c804d-3e44-0321-8a3e-67d6ff7357fa@cumulusnetworks.com>
On 14.11.2016 17:55, David Ahern wrote:
> On 11/14/16 9:44 AM, Hannes Frederic Sowa wrote:
>> On Mon, Nov 14, 2016, at 00:28, Jason A. Donenfeld wrote:
>>> This puts the IPv6 routing functions in parity with the IPv4 routing
>>> functions. Namely, we now check in v6 that if a flowi6 requests an
>>> saddr, the returned dst actually corresponds to a net device that has
>>> that saddr. This mirrors the v4 logic with __ip_dev_find in
>>> __ip_route_output_key_hash. In the event that the returned dst is not
>>> for a dst with a dev that has the saddr, we return -EINVAL, just like
>>> v4; this makes it easy to use the same error handlers for both cases.
>>>
>>> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>>> Cc: David Ahern <dsa@cumulusnetworks.com>
>>> ---
>>> Changes from v2:
>>> It turns out ipv6_chk_addr already has the device enumeration
>>> logic that we need by simply passing NULL.
>>>
>>> net/ipv6/ip6_output.c | 4 ++++
>>> 1 file changed, 4 insertions(+)
>>>
>>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>>> index 6001e78..b3b5cb6 100644
>>> --- a/net/ipv6/ip6_output.c
>>> +++ b/net/ipv6/ip6_output.c
>>> @@ -926,6 +926,10 @@ static int ip6_dst_lookup_tail(struct net *net,
>>> const struct sock *sk,
>>> int err;
>>> int flags = 0;
>>>
>>> + if (!ipv6_addr_any(&fl6->saddr) &&
>>> + !ipv6_chk_addr(net, &fl6->saddr, NULL, 1))
>>> + return -EINVAL;
>>
>> Hmm, this check is too permissive, no?
>>
>> E.g. what happens if you move a link local address from one interface to
>> another? In this case this code would still allow the saddr to be used.
>
> This check -- like the ipv4 variant -- only verifies the saddr is locally assigned. If the address moves interfaces it should be fine.
But in this case we should actually bail out, no?
Let's say, user assumes we are on ifindex eth0 with LL address from
eth0. Suddenly the LL address from eth0 is moved to eth1, we can't
accept this source address anymore and need to return -EINVAL, too.
>> I just also quickly read up on the history (sorry was travelling last
>> week) and wonder if you ever saw a user space facing bug or if this is
>> basically some difference you saw while writing out of tree code?
>
> I checked the userspace API this morning. bind and cmsg for example check that the address is valid with calls to ipv6_chk_addr.
Hmm, so it fixes no real bug.
Because of translations of flowi6_oif we actually can't do a correct
check of source address for cases like the one I outlined above? Hmm,
maybe we should simply depend on user space checks.
Bye,
Hannes
^ permalink raw reply
* Assalamu`Alaikum.
From: mohammad ouattara @ 2016-11-14 17:00 UTC (permalink / raw)
In-Reply-To: <1854474938.4647011.1479142846322.ref@mail.yahoo.com>
Dear Sir/Madam.
Assalamu`Alaikum.
I am Dr mohammad ouattara, I have ($10.6 Million us dollars) to transfer into your account,
I will send you more details about this deal and the procedures to follow when I receive a positive response from you,
Have a great day,
Dr mohammad ouattara.
^ permalink raw reply
* Re: [PATCH v3] ip6_output: ensure flow saddr actually belongs to device
From: David Ahern @ 2016-11-14 17:17 UTC (permalink / raw)
To: Hannes Frederic Sowa, Jason A. Donenfeld, Netdev,
WireGuard mailing list, LKML, YOSHIFUJI Hideaki
In-Reply-To: <7d8c0210-9132-c755-9053-6ec19409e343@stressinduktion.org>
On 11/14/16 10:04 AM, Hannes Frederic Sowa wrote:
> On 14.11.2016 17:55, David Ahern wrote:
>> On 11/14/16 9:44 AM, Hannes Frederic Sowa wrote:
>>> On Mon, Nov 14, 2016, at 00:28, Jason A. Donenfeld wrote:
>>>> This puts the IPv6 routing functions in parity with the IPv4 routing
>>>> functions. Namely, we now check in v6 that if a flowi6 requests an
>>>> saddr, the returned dst actually corresponds to a net device that has
>>>> that saddr. This mirrors the v4 logic with __ip_dev_find in
>>>> __ip_route_output_key_hash. In the event that the returned dst is not
>>>> for a dst with a dev that has the saddr, we return -EINVAL, just like
>>>> v4; this makes it easy to use the same error handlers for both cases.
>>>>
>>>> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>>>> Cc: David Ahern <dsa@cumulusnetworks.com>
>>>> ---
>>>> Changes from v2:
>>>> It turns out ipv6_chk_addr already has the device enumeration
>>>> logic that we need by simply passing NULL.
>>>>
>>>> net/ipv6/ip6_output.c | 4 ++++
>>>> 1 file changed, 4 insertions(+)
>>>>
>>>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>>>> index 6001e78..b3b5cb6 100644
>>>> --- a/net/ipv6/ip6_output.c
>>>> +++ b/net/ipv6/ip6_output.c
>>>> @@ -926,6 +926,10 @@ static int ip6_dst_lookup_tail(struct net *net,
>>>> const struct sock *sk,
>>>> int err;
>>>> int flags = 0;
>>>>
>>>> + if (!ipv6_addr_any(&fl6->saddr) &&
>>>> + !ipv6_chk_addr(net, &fl6->saddr, NULL, 1))
>>>> + return -EINVAL;
>>>
>>> Hmm, this check is too permissive, no?
>>>
>>> E.g. what happens if you move a link local address from one interface to
>>> another? In this case this code would still allow the saddr to be used.
>>
>> This check -- like the ipv4 variant -- only verifies the saddr is locally assigned. If the address moves interfaces it should be fine.
>
> But in this case we should actually bail out, no?
>
> Let's say, user assumes we are on ifindex eth0 with LL address from
> eth0. Suddenly the LL address from eth0 is moved to eth1, we can't
> accept this source address anymore and need to return -EINVAL, too.
so you mean if rt6_need_strict(&fl6->saddr) then the dev needs to be considered.
>
>>> I just also quickly read up on the history (sorry was travelling last
>>> week) and wonder if you ever saw a user space facing bug or if this is
>>> basically some difference you saw while writing out of tree code?
>>
>> I checked the userspace API this morning. bind and cmsg for example check that the address is valid with calls to ipv6_chk_addr.
>
> Hmm, so it fixes no real bug.
>
> Because of translations of flowi6_oif we actually can't do a correct
> check of source address for cases like the one I outlined above? Hmm,
> maybe we should simply depend on user space checks.
I believe Jason's case is forwarding path and the ipv6_stub->ipv6_dst_lookup API.
^ permalink raw reply
* Re: Kernel 4.8.7 crashing
From: Cong Wang @ 2016-11-14 17:18 UTC (permalink / raw)
To: Ashton Holmes; +Cc: LKML, Linux Kernel Network Developers
In-Reply-To: <CAM_iQpUiBE93MsYsMWKcSRBTCNMPvWRqiqAkH3DDqFP1cCSdtw@mail.gmail.com>
(Really Cc'ing netdev.. ;-p )
On Mon, Nov 14, 2016 at 9:18 AM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> Cc'ing netdev.
>
> On Sat, Nov 12, 2016 at 2:17 PM, Ashton Holmes <scoopta@gmail.com> wrote:
>> I upgraded to 4.8.7 and the system boots and my root partition gets
>> decrypted but right after that both of my monitors turn off and
>> looking at syslog from 4.8.6 shows the following:
>>
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853197] ------------[ cut
>> here ]------------
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853206] WARNING: CPU: 2
>> PID: 177 at fs/proc/proc_sysctl.c:1607 ops_exit_list.isra.4+0x33/0x60
>
> Probably this warning in source code:
>
> void retire_sysctl_set(struct ctl_table_set *set)
> {
> WARN_ON(!RB_EMPTY_ROOT(&set->dir.root));
> }
>
>
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853210] Modules linked in:
>> amdgpu eeepc_wmi i2c_algo_bit asus_wmi drm_kms_helper video rfkill
>> snd_hda_codec_realtek ttm snd_hda_codec_generic snd_hda_codec_hdmi drm
>> snd_hda_intel snd_usb_audio sparse_keymap snd_hda_codec mxm_wmi
>> snd_usbmidi_lib snd_hda_core efi_pstore snd_hwdep snd_rawmidi evdev
>> snd_seq_device joydev snd_pcm serio_raw pcspkr efivars fam15h_power
>> k10temp snd_timer snd sp5100_tco i2c_piix4 sg soundcore i2c_core
>> shpchp tpm_infineon tpm_tis tpm_tis_core tpm wmi button it87 hwmon_vid
>> autofs4 ext4 crc16 jbd2 mbcache algif_skcipher af_alg dm_crypt dm_mod
>> hid_generic usbhid hid sr_mod cdrom sd_mod ohci_pci crct10dif_pclmul
>> crc32_pclmul crc32c_intel aesni_intel aes_x86_64 glue_helper lrw
>> gf128mul ablk_helper cryptd psmouse ohci_hcd ahci libahci ehci_pci
>> ehci_hcd libata xhci_pci xhci_hcd e1000e usbcore scsi_mod ptp
>> usb_common pps_core
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853264] CPU: 2 PID: 177
>> Comm: kworker/u16:2 Not tainted 4.8.7 #1
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853267] Hardware name: To
>> be filled by O.E.M. To be filled by O.E.M./CROSSHAIR V FORMULA-Z, BIOS
>> 2201 03/23/2015
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853273] Workqueue: netns cleanup_net
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853276] 0000000000000286
>> 00000000b98071d2 ffffffff81302a8f 0000000000000000
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853281] 0000000000000000
>> ffffffff81076f54 ffff880814f88040 ffff8808140efdf0
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853285] ffffffff818f11d8
>> ffffffff818f11e0 ffff8808140efde0 0000000000000200
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853290] Call Trace:
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853295]
>> [<ffffffff81302a8f>] ? dump_stack+0x5c/0x7d
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853299]
>> [<ffffffff81076f54>] ? __warn+0xc4/0xe0
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853302]
>> [<ffffffff8149e243>] ? ops_exit_list.isra.4+0x33/0x60
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853305]
>> [<ffffffff8149f230>] ? cleanup_net+0x1b0/0x290
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853309]
>> [<ffffffff8108fefd>] ? process_one_work+0x14d/0x410
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853312]
>> [<ffffffff81090cc2>] ? worker_thread+0x62/0x490
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853315]
>> [<ffffffff81090c60>] ? rescuer_thread+0x340/0x340
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853318]
>> [<ffffffff81095f3f>] ? kthread+0xdf/0x100
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853322]
>> [<ffffffff8102b78b>] ? __switch_to+0x2bb/0x710
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853325]
>> [<ffffffff815a371f>] ? ret_from_fork+0x1f/0x40
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853328]
>> [<ffffffff81095e60>] ? kthread_park+0x50/0x50
>> Nov 12 11:54:24 user-desktop kernel: [ 19.853331] ---[ end trace
>> c4840b46b58dbe12 ]---
>
> Looks like net->sysctls is not empty when unregistering,
> perhaps unregister_net_sysctl_table() is missing somewhere.
^ permalink raw reply
* Re: [PATCH 1/6] dt-bindings: mdio-mux: Add documentation for mdio mux for NSP SoC
From: Rob Herring @ 2016-11-14 17:22 UTC (permalink / raw)
To: Yendapally Reddy Dhananjaya Reddy
Cc: Mark Rutland, Russell King, Ray Jui, Scott Branden, Jon Mason,
Florian Fainelli, Kishon Vijay Abraham I,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1478683994-12008-2-git-send-email-yendapally.reddy-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
On Wed, Nov 09, 2016 at 04:33:09AM -0500, Yendapally Reddy Dhananjaya Reddy wrote:
> Add documentation for mdio mux available in Broadcom NSP SoC
>
> Signed-off-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> ---
> .../devicetree/bindings/net/brcm,mdio-mux-nsp.txt | 57 ++++++++++++++++++++++
> 1 file changed, 57 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/brcm,mdio-mux-nsp.txt
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/6] dt-bindings: phy: Add documentation for NSP USB3 PHY
From: Rob Herring @ 2016-11-14 17:23 UTC (permalink / raw)
To: Yendapally Reddy Dhananjaya Reddy
Cc: Mark Rutland, Russell King, Ray Jui, Scott Branden, Jon Mason,
Florian Fainelli, Kishon Vijay Abraham I,
bcm-kernel-feedback-list, netdev, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <1478683994-12008-3-git-send-email-yendapally.reddy@broadcom.com>
On Wed, Nov 09, 2016 at 04:33:10AM -0500, Yendapally Reddy Dhananjaya Reddy wrote:
> Add documentation for USB3 PHY available in Northstar plus SoC
>
> Signed-off-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>
> ---
> .../devicetree/bindings/phy/brcm,nsp-usb3-phy.txt | 39 ++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt b/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt
> new file mode 100644
> index 0000000..30cf4b9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt
> @@ -0,0 +1,39 @@
> +Broadcom USB3 phy binding northstar plus SoC
> +This is a child bus node of "brcm,mdio-mux-nsp" node.
> +
> +Required mdio bus properties:
> +- reg: MDIO Bus number for the MDIO interface
> +- #address-cells: must be 1
> +- #size-cells: must be 0
> +
> +Required PHY properties:
> +- compatible: should be "brcm,nsp-usb3-phy"
> +- reg: Phy address in the MDIO interface
> +- usb3-ctrl-syscon: handler of syscon node defining physical address
> + of usb3 control register.
> +- #phy-cells: must be 0
> +
> +Required usb3 control properties:
> +- compatible: should be "brcm,nsp-usb3-ctrl"
> +- reg: offset and length of the control registers
> +
> +Example:
> +
> + mdio@0 {
> + reg = <0x0>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + usb3_phy: usb3-phy@10 {
Just 'usb-phy@10'. With that,
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/5] net: thunderx: Fix configuration of L3/L4 length checking
From: Sunil Kovvuri @ 2016-11-14 17:26 UTC (permalink / raw)
To: Corentin Labbe; +Cc: Linux Netdev List, Sunil Goutham, LKML, LAKML
In-Reply-To: <20161114123350.GA2449@Red>
>>You could use the BIT() macro here
Thanks, will change and resubmit.
Sunil.
^ permalink raw reply
* Re: [PATCH 0/5] net: thunderx: Miscellaneous fixes
From: Sunil Kovvuri @ 2016-11-14 17:27 UTC (permalink / raw)
To: Matthias Brugger
Cc: Robert Richter, Linux Netdev List, Sunil Goutham, LKML, LAKML
In-Reply-To: <2948c47d-0f15-8153-440b-7a2c753b7251@suse.com>
>>If so, please add "Cc: stable@vger.kernel.org" to the Sigend-off list.
Yes they are, thanks, will do that along with resubmission.
Sunil.
^ permalink raw reply
* Re: [PATCH net 2/2] r8152: rx descriptor check
From: David Miller @ 2016-11-14 17:27 UTC (permalink / raw)
To: hayeswang; +Cc: mlord, netdev, nic_swsd, linux-kernel, linux-usb
In-Reply-To: <0835B3720019904CB8F7AA43166CEEB20104EBCC@RTITMBSV03.realtek.com.tw>
From: Hayes Wang <hayeswang@realtek.com>
Date: Mon, 14 Nov 2016 07:23:51 +0000
> Mark Lord [mailto:mlord@pobox.com]
>> Sent: Monday, November 14, 2016 4:34 AM
> [...]
>> Perhaps the driver
>> is somehow accessing the buffer space again after doing usb_submit_urb()?
>> That would certainly produce this kind of behaviour.
>
> I don't think so. First, the driver only read the received buffer.
> That is, the driver would not change (or write) the data. Second,
> The driver would lose the point address of the received buffer
> after submitting the urb to the USB host controller, until the
> transfer is completed by the USB host controller. That is, the
> driver doesn't how to access the buffer after calling usb_submit_urb().
This is why it's most likely some DMA implementation issue or similar.
^ permalink raw reply
* Re: [PATCH v2 0/2] bnx2: Wait for in-flight DMA to complete at probe stage
From: David Miller @ 2016-11-14 17:28 UTC (permalink / raw)
To: pmenzel
Cc: bhe, netdev, michael.chan, linux-kernel, Dept-GELinuxNICDev,
rasesh.mody, harish.patil, frank, jsr, jroedel, dyoung
In-Reply-To: <8010f40d-e7ca-8fd1-7317-f576289c112f@molgen.mpg.de>
From: Paul Menzel <pmenzel@molgen.mpg.de>
Date: Mon, 14 Nov 2016 09:25:47 +0100
> Dear Baoquan,
>
> On 11/13/16 06:01, Baoquan He wrote:
>> This is v2 post.
>>
>> In commit 3e1be7a ("bnx2: Reset device during driver initialization"),
>> firmware requesting code was moved from open stage to probe stage.
>> The reason is in kdump kernel hardware iommu need device be reset in
>> driver probe stage, otherwise those in-flight DMA from 1st kernel
>> will continue going and look up into the newly created io-page tables.
>> However bnx2 chip resetting involves firmware requesting issue, that
>> need be done in open stage.
>>
>> Michale Chan suggested we can just wait for the old in-flight DMA to
>> complete at probe stage, then though without device resetting, we
>> don't need to worry the old in-flight DMA could continue looking up
>> the newly created io-page tables.
>>
>> v1->v2:
>> Michael suggested to wait for the in-flight DMA to complete at probe
>> stage. So give up the old method of trying to reset chip at probe
>> stage, take the new way accordingly.
>
> thank you for posting the updated series. Could you please resend a v3
> with stable@vger.kernel.org added [1]?
This is not the proper procedure for networking patches.
^ permalink raw reply
* Re: Long delays creating a netns after deleting one (possibly RCU related)
From: Hannes Frederic Sowa @ 2016-11-14 17:29 UTC (permalink / raw)
To: Cong Wang, Paul E. McKenney
Cc: Rolf Neugebauer, LKML, Linux Kernel Network Developers,
Justin Cormack, Ian Campbell
In-Reply-To: <CAM_iQpUDnPfVayQv7Q+ZtC_2_ZbX9MRX=514gFpF3E6XY+GtSA@mail.gmail.com>
Hi Cong,
On Sat, Nov 12, 2016, at 01:55, Cong Wang wrote:
> On Fri, Nov 11, 2016 at 4:23 PM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >
> > Ah! This net_mutex is different than RTNL. Should synchronize_net() be
> > modified to check for net_mutex being held in addition to the current
> > checks for RTNL being held?
> >
>
> Good point!
>
> Like commit be3fc413da9eb17cce0991f214ab0, checking
> for net_mutex for this case seems to be an optimization, I assume
> synchronize_rcu_expedited() and synchronize_rcu() have the same
> behavior...
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index eaad4c2..3415b6b 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -7762,7 +7762,7 @@ EXPORT_SYMBOL(free_netdev);
> void synchronize_net(void)
> {
> might_sleep();
> - if (rtnl_is_locked())
> + if (rtnl_is_locked() || lockdep_is_held(&net_mutex))
> synchronize_rcu_expedited();
I don't think we should depend on lockdep for this check but rather use
mutex_is_locked here (I think it would fail to build like this without
CONFIG_LOCKDEP).
Bye,
Hannes
^ permalink raw reply
* Re: [PATCH net-next v5] cadence: Add LSO support.
From: David Miller @ 2016-11-14 17:30 UTC (permalink / raw)
To: rafalo; +Cc: nicolas.ferre, netdev, linux-kernel
In-Reply-To: <BN3PR07MB2516C30913D2FB8D4788071AC9BC0@BN3PR07MB2516.namprd07.prod.outlook.com>
From: Rafal Ozieblo <rafalo@cadence.com>
Date: Mon, 14 Nov 2016 09:32:34 +0000
>> If UFO is in use it should not silently disable UDP checksums.
>>
>> If you cannot support UFO with proper checksumming, then you cannot enable support for that feature.
>
> According Cadence Gigabit Ethernet MAC documentation:
>
> "Hardware will not calculate the UDP checksum or modify the UDP checksum field. Therefore software
> must set a value of zero in the checksum field in the UDP header (in the first payload buffer)
> to indicate to the receiver that the UDP datagram does not include a checksum."
>
> It is hardware requirement.
I do not doubt that it is a hardware restriction.
But I am saying that you cannot enable this feature under Linux if
this is how it operates on your hardware.
^ permalink raw reply
* Re: [PATCH net-next v7 03/10] dpaa_eth: add option to use one buffer pool set
From: David Miller @ 2016-11-14 17:31 UTC (permalink / raw)
To: madalin.bucur
Cc: netdev, linuxppc-dev, linux-kernel, oss, ppc, joe, pebolle,
joakim.tjernlund
In-Reply-To: <AM4PR04MB16040D32960405FD16007950ECBC0@AM4PR04MB1604.eurprd04.prod.outlook.com>
From: Madalin-Cristian Bucur <madalin.bucur@nxp.com>
Date: Mon, 14 Nov 2016 10:25:13 +0000
> I've introduced this Kconfig option as a backwards compatible option, to
> be able to run comparative tests between the independent buffer pool setup
> and the previous common buffer pool setup. There are not so many reasons
> to use the same buffer pool besides "having the old setup", the memory
> saving is marginal, in all other aspects the separate buffer pools setup
> fares better.
>
> I'll remove this patch from the next submission. Should anyone care for
> this I can add an entry to the feature backlog to add runtime support but
> it will be quite low in priority.
If it's a debugging feature then that's certainly how this should be
handled.
^ permalink raw reply
* Re: Debugging Ethernet issues
From: Florian Fainelli @ 2016-11-14 17:32 UTC (permalink / raw)
To: Mason, Andrew Lunn
Cc: netdev, Mans Rullgard, Sergei Shtylyov, Tom Lendacky, Zach Brown,
Shaohui Xie, Tim Beale, Brian Hill, Vince Bridgers,
Balakumaran Kannan, David S. Miller, Sebastian Frias,
Kirill Kapranov
In-Reply-To: <5829D95C.6060509@free.fr>
On 11/14/2016 07:33 AM, Mason wrote:
> On 14/11/2016 15:58, Mason wrote:
>
>> nb8800 26000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
>> vs
>> nb8800 26000.ethernet eth0: Link is Up - 100Mbps/Full - flow control off
>>
>> I'm not sure whether "flow control" is relevant...
>
> Based on phy_print_status()
> phydev->pause ? "rx/tx" : "off"
> I added the following patch.
>
> diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
> index defc22a15f67..4e758c1cfa4e 100644
> --- a/drivers/net/ethernet/aurora/nb8800.c
> +++ b/drivers/net/ethernet/aurora/nb8800.c
> @@ -667,6 +667,8 @@ static void nb8800_link_reconfigure(struct net_device *dev)
> struct phy_device *phydev = priv->phydev;
> int change = 0;
>
> + printk("%s from %pf\n", __func__, __builtin_return_address(0));
> +
> if (phydev->link) {
> if (phydev->speed != priv->speed) {
> priv->speed = phydev->speed;
> @@ -1274,9 +1276,9 @@ static int nb8800_hw_init(struct net_device *dev)
> nb8800_writeb(priv, NB8800_PQ2, val & 0xff);
>
> /* Auto-negotiate by default */
> - priv->pause_aneg = true;
> - priv->pause_rx = true;
> - priv->pause_tx = true;
> + priv->pause_aneg = false;
> + priv->pause_rx = false;
> + priv->pause_tx = false;
>
> nb8800_mc_init(dev, 0);
>
>
> Connected to 1000 Mbps switch:
>
> # time udhcpc | while read LINE; do date; echo $LINE; done
> Thu Jan 1 00:00:22 UTC 1970
> udhcpc (v1.22.1) started
> Thu Jan 1 00:00:22 UTC 1970
> Sending discover...
> [ 24.565346] nb8800_link_reconfigure from phy_state_machine
> Thu Jan 1 00:00:25 UTC 1970
> Sending discover...
> [ 26.575402] nb8800_link_reconfigure from phy_state_machine
> [ 26.580972] nb8800 26000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx
> Thu Jan 1 00:00:28 UTC 1970
> Sending discover...
> Thu Jan 1 00:00:29 UTC 1970
> Sending select for 172.27.64.58...
> Thu Jan 1 00:00:29 UTC 1970
> Lease of 172.27.64.58 obtained, lease time 604800
> Thu Jan 1 00:00:29 UTC 1970
> deleting routers
> Thu Jan 1 00:00:29 UTC 1970
> adding dns 172.27.0.17
>
> real 0m7.388s
> user 0m0.040s
> sys 0m0.090s
>
>
>
> Connected to 100 Mbps switch:
>
> # time udhcpc | while read LINE; do date; echo $LINE; done
> Thu Jan 1 00:00:14 UTC 1970
> udhcpc (v1.22.1) started
> Thu Jan 1 00:00:15 UTC 1970
> Sending discover...
> [ 16.968621] nb8800_link_reconfigure from phy_state_machine
> [ 17.975359] nb8800_link_reconfigure from phy_state_machine
> [ 17.980923] nb8800 26000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
> Thu Jan 1 00:00:18 UTC 1970
> Sending discover...
> Thu Jan 1 00:00:19 UTC 1970
> Sending select for 172.27.64.58...
> Thu Jan 1 00:00:19 UTC 1970
> Lease of 172.27.64.58 obtained, lease time 604800
> Thu Jan 1 00:00:19 UTC 1970
> deleting routers
> Thu Jan 1 00:00:19 UTC 1970
> adding dns 172.27.0.17
>
> real 0m4.355s
> user 0m0.043s
> sys 0m0.083s
>
And the time difference is clearly accounted for auto-negotiation time
here, as you can see it takes about 3 seconds for Gigabit Ethernet to
auto-negotiate and that seems completely acceptable and normal to me
since it is a more involved process than lower speeds.
>
>
> OK, so now it works (by accident?) even on 100 Mbps switch, but it still
> prints "flow control rx/tx"...
Because your link partner advertises flow control, and that's what
phydev->pause and phydev->asym_pause report (I know it's confusing, but
that's what it is at the moment).
>
> # ethtool -a eth0
> Pause parameters for eth0:
> Autonegotiate: off
> RX: off
> TX: off
>
> These values make sense considering my changes in the driver.
>
> Are 100 Mbps switches supposed to support these pause features,
> and are they supposed to be able to auto-negotiate them?
Yes, switches can support flow control aka pause frames, and unless they
are configurable, they typically advertise what their EEPROM has defined
for them, so most likely the full auto-negotiated spectrum:
10/100/1000Mbps and support for flow control, but your mileage may vary
of course.
--
Florian
^ permalink raw reply
* Re: [PATCH 0/5] net: thunderx: Miscellaneous fixes
From: David Miller @ 2016-11-14 17:32 UTC (permalink / raw)
To: mbrugger; +Cc: sunil.kovvuri, netdev, sgoutham, linux-kernel, linux-arm-kernel
In-Reply-To: <2948c47d-0f15-8153-440b-7a2c753b7251@suse.com>
From: Matthias Brugger <mbrugger@suse.com>
Date: Mon, 14 Nov 2016 13:01:25 +0100
>
>
> On 14/11/16 11:54, sunil.kovvuri@gmail.com wrote:
>> From: Sunil Goutham <sgoutham@cavium.com>
>>
>> This patchset includes fixes for incorrect LMAC credits,
>> unreliable driver statistics, memory leak upon interface
>> down e.t.c
>>
>
> Are these fixes relevant to for older kernels as well?
> If so, please add "Cc: stable@vger.kernel.org" to the Sigend-off list.
This is not appropriate for networking patches.
People instead explicitly request -stable inclusion when the
submit networking changes to me, and I queue them up for
later submission.
^ permalink raw reply
* Re: [PATCH v3] ip6_output: ensure flow saddr actually belongs to device
From: Hannes Frederic Sowa @ 2016-11-14 17:33 UTC (permalink / raw)
To: David Ahern, Jason A. Donenfeld, Netdev, WireGuard mailing list,
LKML, YOSHIFUJI Hideaki
In-Reply-To: <c75290bd-7ea2-0bf8-7ac0-fc5a3c81e312@cumulusnetworks.com>
On 14.11.2016 18:17, David Ahern wrote:
> On 11/14/16 10:04 AM, Hannes Frederic Sowa wrote:
>> On 14.11.2016 17:55, David Ahern wrote:
>>> On 11/14/16 9:44 AM, Hannes Frederic Sowa wrote:
>>>> On Mon, Nov 14, 2016, at 00:28, Jason A. Donenfeld wrote:
>>>>> This puts the IPv6 routing functions in parity with the IPv4 routing
>>>>> functions. Namely, we now check in v6 that if a flowi6 requests an
>>>>> saddr, the returned dst actually corresponds to a net device that has
>>>>> that saddr. This mirrors the v4 logic with __ip_dev_find in
>>>>> __ip_route_output_key_hash. In the event that the returned dst is not
>>>>> for a dst with a dev that has the saddr, we return -EINVAL, just like
>>>>> v4; this makes it easy to use the same error handlers for both cases.
>>>>>
>>>>> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>>>>> Cc: David Ahern <dsa@cumulusnetworks.com>
>>>>> ---
>>>>> Changes from v2:
>>>>> It turns out ipv6_chk_addr already has the device enumeration
>>>>> logic that we need by simply passing NULL.
>>>>>
>>>>> net/ipv6/ip6_output.c | 4 ++++
>>>>> 1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>>>>> index 6001e78..b3b5cb6 100644
>>>>> --- a/net/ipv6/ip6_output.c
>>>>> +++ b/net/ipv6/ip6_output.c
>>>>> @@ -926,6 +926,10 @@ static int ip6_dst_lookup_tail(struct net *net,
>>>>> const struct sock *sk,
>>>>> int err;
>>>>> int flags = 0;
>>>>>
>>>>> + if (!ipv6_addr_any(&fl6->saddr) &&
>>>>> + !ipv6_chk_addr(net, &fl6->saddr, NULL, 1))
>>>>> + return -EINVAL;
>>>>
>>>> Hmm, this check is too permissive, no?
>>>>
>>>> E.g. what happens if you move a link local address from one interface to
>>>> another? In this case this code would still allow the saddr to be used.
>>>
>>> This check -- like the ipv4 variant -- only verifies the saddr is locally assigned. If the address moves interfaces it should be fine.
>>
>> But in this case we should actually bail out, no?
>>
>> Let's say, user assumes we are on ifindex eth0 with LL address from
>> eth0. Suddenly the LL address from eth0 is moved to eth1, we can't
>> accept this source address anymore and need to return -EINVAL, too.
>
> so you mean if rt6_need_strict(&fl6->saddr) then the dev needs to be considered.
Exactly, like we do in the user space facing APIs.
>>>> I just also quickly read up on the history (sorry was travelling last
>>>> week) and wonder if you ever saw a user space facing bug or if this is
>>>> basically some difference you saw while writing out of tree code?
>>>
>>> I checked the userspace API this morning. bind and cmsg for example check that the address is valid with calls to ipv6_chk_addr.
>>
>> Hmm, so it fixes no real bug.
>>
>> Because of translations of flowi6_oif we actually can't do a correct
>> check of source address for cases like the one I outlined above? Hmm,
>> maybe we should simply depend on user space checks.
>
> I believe Jason's case is forwarding path and the ipv6_stub->ipv6_dst_lookup API.
It is not a kernel API, because we don't support something like that for
external kernel modules. We basically exported ipv6_dst_lookup to allow
some IPv4 code to do ipv6 stunts when the IPv6 module is loaded. ;)
Bye,
Hannes
^ permalink raw reply
* Re: [PATCH v2 0/2] bnx2: Wait for in-flight DMA to complete at probe stage
From: Paul Menzel @ 2016-11-14 17:35 UTC (permalink / raw)
To: David Miller
Cc: bhe, netdev, michael.chan, linux-kernel, Dept-GELinuxNICDev,
rasesh.mody, harish.patil, frank, jsr, jroedel, dyoung
In-Reply-To: <20161114.122838.1039215178593568702.davem@davemloft.net>
On 11/14/16 18:28, David Miller wrote:
> From: Paul Menzel <pmenzel@molgen.mpg.de>
> Date: Mon, 14 Nov 2016 09:25:47 +0100
>> On 11/13/16 06:01, Baoquan He wrote:
>>> This is v2 post.
>>>
>>> In commit 3e1be7a ("bnx2: Reset device during driver initialization"),
>>> firmware requesting code was moved from open stage to probe stage.
>>> The reason is in kdump kernel hardware iommu need device be reset in
>>> driver probe stage, otherwise those in-flight DMA from 1st kernel
>>> will continue going and look up into the newly created io-page tables.
>>> However bnx2 chip resetting involves firmware requesting issue, that
>>> need be done in open stage.
>>>
>>> Michale Chan suggested we can just wait for the old in-flight DMA to
>>> complete at probe stage, then though without device resetting, we
>>> don't need to worry the old in-flight DMA could continue looking up
>>> the newly created io-page tables.
>>>
>>> v1->v2:
>>> Michael suggested to wait for the in-flight DMA to complete at probe
>>> stage. So give up the old method of trying to reset chip at probe
>>> stage, take the new way accordingly.
>>
>> thank you for posting the updated series. Could you please resend a v3
>> with stable@vger.kernel.org added [1]?
>
> This is not the proper procedure for networking patches.
Oh, I didn’t know that. Sorry for spreading false information.
Kind regards,
Paul
^ permalink raw reply
* Re: [PATCH net 2/3] bpf, mlx5: fix various refcount/prog issues in mlx5e_xdp_set
From: Alexei Starovoitov @ 2016-11-14 17:35 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: davem, bblanco, tariqt, zhiyisun, ranas, netdev
In-Reply-To: <58297AAD.8060003@iogearbox.net>
On Mon, Nov 14, 2016 at 09:49:49AM +0100, Daniel Borkmann wrote:
> On 11/14/2016 03:49 AM, Alexei Starovoitov wrote:
> >On Mon, Nov 14, 2016 at 01:43:41AM +0100, Daniel Borkmann wrote:
> [...]
> >>diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> >>index 751e806..a0fca9f 100644
> >>--- a/kernel/bpf/syscall.c
> >>+++ b/kernel/bpf/syscall.c
> >>@@ -682,6 +682,17 @@ struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i)
> >> }
> >> EXPORT_SYMBOL_GPL(bpf_prog_add);
> >>
> >>+void bpf_prog_sub(struct bpf_prog *prog, int i)
> >>+{
> >>+ /* Only to be used for undoing previous bpf_prog_add() in some
> >>+ * error path. We still know that another entity in our call
> >>+ * path holds a reference to the program, thus atomic_sub() can
> >>+ * be safely used in such cases!
> >>+ */
> >>+ WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0);
> >>+}
> >>+EXPORT_SYMBOL_GPL(bpf_prog_sub);
> >
> >the patches look good. I'm only worried about net/net-next merge
> >conflict here. (I would have to deal with it as well).
> >So instead of copying the above helper can we apply net-next's
> >'bpf, mlx4: fix prog refcount in mlx4_en_try_alloc_resources error path'
> >patch to net without mlx4_xdp_set hunk and then apply
> >the rest of this patch?
> >Even better is to send this patch 2/3 to net-next?
> >yes, it's an issue, but very small one. There is no security
> >concern here, so I would prefer to avoid merge conflict.
> >Did you do a test merge of net/net-next by any chance?
>
> Yes, I did a test merge and git resolved the above just fine w/o
> any conflicts. I have no strong opinion whether net or net-next.
> If preferred, I can just resend this series in the evening against
> net-next instead, perhaps that's a bit better.
I have slight preference to go via net-next, but since it merges fine,
I don't mind net route too.
^ permalink raw reply
* Re: [PATCH 0/5] net: thunderx: Miscellaneous fixes
From: Matthias Brugger @ 2016-11-14 17:35 UTC (permalink / raw)
To: David Miller
Cc: sunil.kovvuri, netdev, sgoutham, linux-kernel, linux-arm-kernel
In-Reply-To: <20161114.123253.476733911183519472.davem@davemloft.net>
On 11/14/2016 06:32 PM, David Miller wrote:
> From: Matthias Brugger <mbrugger@suse.com>
> Date: Mon, 14 Nov 2016 13:01:25 +0100
>
>>
>>
>> On 14/11/16 11:54, sunil.kovvuri@gmail.com wrote:
>>> From: Sunil Goutham <sgoutham@cavium.com>
>>>
>>> This patchset includes fixes for incorrect LMAC credits,
>>> unreliable driver statistics, memory leak upon interface
>>> down e.t.c
>>>
>>
>> Are these fixes relevant to for older kernels as well?
>> If so, please add "Cc: stable@vger.kernel.org" to the Sigend-off list.
>
> This is not appropriate for networking patches.
>
> People instead explicitly request -stable inclusion when the
> submit networking changes to me, and I queue them up for
> later submission.
>
Ok, thanks for clarification.
^ permalink raw reply
* Re: Long delays creating a netns after deleting one (possibly RCU related)
From: Cong Wang @ 2016-11-14 17:44 UTC (permalink / raw)
To: Paul E. McKenney
Cc: Rolf Neugebauer, LKML, Linux Kernel Network Developers,
Justin Cormack, Ian Campbell
In-Reply-To: <20161114162417.GJ4127@linux.vnet.ibm.com>
On Mon, Nov 14, 2016 at 8:24 AM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
> On Sun, Nov 13, 2016 at 10:47:01PM -0800, Cong Wang wrote:
>> On Fri, Nov 11, 2016 at 4:55 PM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>> > On Fri, Nov 11, 2016 at 4:23 PM, Paul E. McKenney
>> > <paulmck@linux.vnet.ibm.com> wrote:
>> >>
>> >> Ah! This net_mutex is different than RTNL. Should synchronize_net() be
>> >> modified to check for net_mutex being held in addition to the current
>> >> checks for RTNL being held?
>> >>
>> >
>> > Good point!
>> >
>> > Like commit be3fc413da9eb17cce0991f214ab0, checking
>> > for net_mutex for this case seems to be an optimization, I assume
>> > synchronize_rcu_expedited() and synchronize_rcu() have the same
>> > behavior...
>>
>> Thinking a bit more, I think commit be3fc413da9eb17cce0991f
>> gets wrong on rtnl_is_locked(), the lock could be locked by other
>> process not by the current one, therefore it should be
>> lockdep_rtnl_is_held() which, however, is defined only when LOCKDEP
>> is enabled... Sigh.
>>
>> I don't see any better way than letting callers decide if they want the
>> expedited version or not, but this requires changes of all callers of
>> synchronize_net(). Hm.
>
> I must confess that I don't understand how it would help to use an
> expedited grace period when some other process is holding RTNL.
> In contrast, I do well understand how it helps when the current process
> is holding RTNL.
Yeah, this is exactly my point. And same for ASSERT_RTNL() which checks
rtnl_is_locked(), clearly we need to assert "it is held by the current process"
rather than "it is locked by whatever process".
But given *_is_held() is always defined by LOCKDEP, so we probably need
mutex to provide such a helper directly, mutex->owner is not always defined
either. :-/
^ permalink raw reply
* Re: [PATCH v3] ip6_output: ensure flow saddr actually belongs to device
From: David Ahern @ 2016-11-14 17:48 UTC (permalink / raw)
To: Hannes Frederic Sowa, Jason A. Donenfeld, Netdev,
WireGuard mailing list, LKML, YOSHIFUJI Hideaki
In-Reply-To: <7779da88-08dc-0adb-42dd-8e00502693df@stressinduktion.org>
On 11/14/16 10:33 AM, Hannes Frederic Sowa wrote:
>>>>> I just also quickly read up on the history (sorry was travelling last
>>>>> week) and wonder if you ever saw a user space facing bug or if this is
>>>>> basically some difference you saw while writing out of tree code?
>>>>
>>>> I checked the userspace API this morning. bind and cmsg for example check that the address is valid with calls to ipv6_chk_addr.
>>>
>>> Hmm, so it fixes no real bug.
>>>
>>> Because of translations of flowi6_oif we actually can't do a correct
>>> check of source address for cases like the one I outlined above? Hmm,
>>> maybe we should simply depend on user space checks.
>>
>> I believe Jason's case is forwarding path and the ipv6_stub->ipv6_dst_lookup API.
>
> It is not a kernel API, because we don't support something like that for
> external kernel modules. We basically exported ipv6_dst_lookup to allow
> some IPv4 code to do ipv6 stunts when the IPv6 module is loaded. ;)
???
ipv6_stub is exported for modules (EXPORT_SYMBOL_GPL(ipv6_stub)).
ipv6_stub->ipv6_dst_lookup is used by several modules -- geneve, tipc, vxlan, mpls -- for IPv6 lookups, not IPv4 code do IPv6 stunts.
So how do you say that is not an exported kernel API?
^ permalink raw reply
* Re: [net] 2ab9fb18c4: kernel BUG at include/linux/skbuff.h:1935!
From: Duyck, Alexander H @ 2016-11-14 17:54 UTC (permalink / raw)
To: eric.dumazet@gmail.com, Ye, Xiaolong
Cc: tom@herbertland.com, ast@kernel.org, willemb@google.com,
netdev@vger.kernel.org, jojvargh@cisco.com, davem@davemloft.net,
lkp@01.org, yibyang@cisco.com
In-Reply-To: <5828fc09.rTUEnj6qw0eDHzYL%xiaolong.ye@intel.com>
On Mon, 2016-11-14 at 07:49 +0800, kernel test robot wrote:
> FYI, we noticed the following commit:
>
> https://github.com/0day-ci/linux Eric-Dumazet/net-__skb_flow_dissect-must-cap-its-return-value/20161110-080839
> commit 2ab9fb18c46b91b16a0f0f329336d3be9fc32deb ("net: __skb_flow_dissect() must cap its return value")
>
> in testcase: kbuild
> with following parameters:
>
> runtime: 300s
> nr_task: 50%
> cpufreq_governor: performance
>
>
>
>
> on test machine: 8 threads Intel(R) Atom(TM) CPU C2750 @ 2.40GHz with 16G memory
>
> caused below changes:
>
>
> +-------------------------------------------------------+------------+------------+
> >
> > | cdb26d3387 | 2ab9fb18c4 |
> +-------------------------------------------------------+------------+------------+
> >
> > boot_successes | 10 | 3 |
> > boot_failures | 0 | 9 |
> > kernel_BUG_at_include/linux/skbuff.h | 0 | 8 |
> > invalid_opcode:#[##]SMP | 0 | 8 |
> > RIP:eth_type_trans | 0 | 8 |
> > Kernel_panic-not_syncing:Fatal_exception_in_interrupt | 0 | 5 |
> > WARNING:at_fs/sysfs/dir.c:#sysfs_warn_dup | 0 | 1 |
> > calltrace:parport_pc_init | 0 | 1 |
> > calltrace:SyS_finit_module | 0 | 1 |
> > WARNING:at_lib/kobject.c:#kobject_add_internal | 0 | 1 |
> +-------------------------------------------------------+------------+------------+
>
>
>
> [ 20.491020] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
> [ 20.502988] Sending DHCP requests .
> [ 20.506729] ------------[ cut here ]------------
> [ 20.511369] kernel BUG at include/linux/skbuff.h:1935!
> [ 20.517893] invalid opcode: 0000 [#1] SMP
> [ 20.521902] Modules linked in:
> [ 20.524979] CPU: 4 PID: 0 Comm: swapper/4 Not tainted 4.9.0-rc3-00286-g2ab9fb1 #1
> [ 20.532463] Hardware name: Supermicro SYS-5018A-TN4/A1SAi, BIOS 1.1a 08/27/2015
> [ 20.539768] task: ffff8804456c2480 task.stack: ffffc90001920000
> [ 20.545684] RIP: 0010:[<ffffffff81837b48>] [<ffffffff81837b48>] eth_type_trans+0xe8/0x140
> [ 20.553972] RSP: 0018:ffff88047fd03db8 EFLAGS: 00010297
> [ 20.559283] RAX: 0000000000000158 RBX: ffff88047d8ae600 RCX: 0000000000001073
> [ 20.566415] RDX: ffff88047bf07dc0 RSI: ffff88047d8a4000 RDI: ffff88047dac0f00
> [ 20.573546] RBP: ffff88047fd03e20 R08: ffff88047d8a4000 R09: 0000000000000800
> [ 20.580678] R10: ffff88047bf07ec0 R11: ffffea0011f6e400 R12: ffff88047dac0f00
> [ 20.587810] R13: ffff880457413000 R14: ffffc90002129000 R15: 000000000000015e
> [ 20.594946] FS: 0000000000000000(0000) GS:ffff88047fd00000(0000) knlGS:0000000000000000
> [ 20.603032] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 20.608775] CR2: 00007fffadfb4ef0 CR3: 000000047ee07000 CR4: 00000000001006e0
> [ 20.615906] Stack:
> [ 20.617927] ffffffff816905a7 ffffea0011f6e400 ffffea0000000008 ffff88047d8ae450
> [ 20.625403] ffff88047d8ae400 0000004000000166 ffffea0011f6e400 0000ffff00000000
> [ 20.632873] 0000000000000040 0000000000000000 ffff88047d8ae450 ffff88047d8b1140
> [ 20.640352] Call Trace:
> [ 20.642805] <IRQ>
> [ 20.644740] [<ffffffff816905a7>] ? igb_clean_rx_irq+0x6a7/0x7d0
> [ 20.650760] [<ffffffff81690a52>] igb_poll+0x382/0x700
> [ 20.655904] [<ffffffff8146edd9>] ? timerqueue_add+0x59/0xb0
> [ 20.661564] [<ffffffff8180f2d7>] net_rx_action+0x217/0x360
> [ 20.667137] [<ffffffff81957ef4>] __do_softirq+0x104/0x2ab
> [ 20.672624] [<ffffffff81086961>] irq_exit+0xf1/0x100
> [ 20.677673] [<ffffffff81957c34>] do_IRQ+0x54/0xd0
> [ 20.682466] [<ffffffff81955acc>] common_interrupt+0x8c/0x8c
> [ 20.688123] <EOI>
> [ 20.690054] [<ffffffff817c1d12>] ? cpuidle_enter_state+0x122/0x2e0
> [ 20.696333] [<ffffffff817c1f07>] cpuidle_enter+0x17/0x20
> [ 20.701733] [<ffffffff810c64c3>] call_cpuidle+0x23/0x40
> [ 20.707045] [<ffffffff810c66f4>] cpu_startup_entry+0x114/0x200
> [ 20.712964] [<ffffffff81051c87>] start_secondary+0x107/0x130
> [ 20.718708] Code: 00 04 00 00 c9 c3 48 33 86 70 03 00 00 48 c1 e0 10 48 85 c0 0f b6 87 90 00 00 00 75 28 83 e0 f8 83 c8 01 88 87 90 00 00 00 eb 82 <0f> 0b 0f b6 87 90 00 00 00 83 e0 f8 83 c8 03 88 87 90 00 00 00
> [ 20.738722] RIP [<ffffffff81837b48>] eth_type_trans+0xe8/0x140
> [ 20.744662] RSP <ffff88047fd03db8>
> [ 20.748160] ---[ end trace 153440bf1ca2e6fc ]---
> [ 20.748165] ------------[ cut here ]------------
>
>
> To reproduce:
>
> git clone git://git.kernel.org/pub/scm/linux/kernel/git/wfg/lkp-tests.git
> cd lkp-tests
> bin/lkp install job.yaml # job file is attached in this email
> bin/lkp run job.yaml
>
>
>
> Thanks,
> Kernel Test Robot
So I am trying to reproduce this but need some additional data as just
copying the config apparently isn't enough.
I just wanted to confirm. It looks like you are running serial over
lan over one of the igb ports. Do I have that right? I ask because
the igb driver loading in the dmesg log seems to cause a 2.1 second
skip and doesn't display the driver version or any information on the
igb devices.
Another question I had is what versions of gcc are you testing with? I
see the dmesg for the failing case is using gcc version 6.2. Are there
any other versions of gcc that are being tested, and if so are they
showing similar failures?
Thanks.
- Alex
^ permalink raw reply
* [PATCH 1/2] can: holt_hi311x: document device tree bindings
From: Akshay Bhat @ 2016-11-14 17:55 UTC (permalink / raw)
To: wg, mkl, robh+dt
Cc: mark.rutland, linux-can, netdev, devicetree, linux-kernel,
Akshay Bhat, Akshay Bhat
Document the HOLT HI-311x CAN device tree bindings.
Signed-off-by: Akshay Bhat <nodeax@gmail.com>
---
.../devicetree/bindings/net/can/holt_hi311x.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/can/holt_hi311x.txt
diff --git a/Documentation/devicetree/bindings/net/can/holt_hi311x.txt b/Documentation/devicetree/bindings/net/can/holt_hi311x.txt
new file mode 100644
index 0000000..23aa94e
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/holt_hi311x.txt
@@ -0,0 +1,24 @@
+* Holt HI-311X stand-alone CAN controller device tree bindings
+
+Required properties:
+ - compatible: Should be one of the following:
+ - "holt,hi3110" for HI-3110
+ - reg: SPI chip select.
+ - clocks: The clock feeding the CAN controller.
+ - interrupt-parent: The parent interrupt controller.
+ - interrupts: Should contain IRQ line for the CAN controller.
+
+Optional properties:
+ - vdd-supply: Regulator that powers the CAN controller.
+ - xceiver-supply: Regulator that powers the CAN transceiver.
+
+Example:
+ can0: can@1 {
+ compatible = "holt,hi3110";
+ reg = <1>;
+ clocks = <&clk32m>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <13 IRQ_TYPE_EDGE_RISING>;
+ vdd-supply = <®5v0>;
+ xceiver-supply = <®5v0>;
+ };
--
2.8.1
^ permalink raw reply related
* [PATCH 2/2] can: spi: hi311x: Add Holt HI-311x CAN driver
From: Akshay Bhat @ 2016-11-14 17:55 UTC (permalink / raw)
To: wg, mkl, robh+dt
Cc: mark.rutland, linux-can, netdev, devicetree, linux-kernel,
Akshay Bhat, Akshay Bhat
In-Reply-To: <1479146144-29143-1-git-send-email-akshay.bhat@timesys.com>
This patch adds support for the Holt HI-311x CAN controller. The HI311x
CAN controller is capable of transmitting and receiving standard data
frames, extended data frames and remote frames. The HI311x interfaces
with the host over SPI.
Datasheet: www.holtic.com/documents/371-hi-3110_v-rev-jpdf.do
Signed-off-by: Akshay Bhat <nodeax@gmail.com>
---
drivers/net/can/spi/Kconfig | 6 +
drivers/net/can/spi/Makefile | 1 +
drivers/net/can/spi/hi311x.c | 1071 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1078 insertions(+)
create mode 100644 drivers/net/can/spi/hi311x.c
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 148cae5..9eb1bb1 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -7,4 +7,10 @@ config CAN_MCP251X
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
+config CAN_HI311X
+ tristate "Holt HI311x SPI CAN controllers"
+ depends on CAN_DEV && SPI && HAS_DMA
+ ---help---
+ Driver for the Holt HI311x SPI CAN controllers.
+
endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index 0e86040..eac7c3a 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
+obj-$(CONFIG_CAN_HI311X) += hi311x.o
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
new file mode 100644
index 0000000..1020166
--- /dev/null
+++ b/drivers/net/can/spi/hi311x.c
@@ -0,0 +1,1071 @@
+/* CAN bus driver for Holt HI3110 CAN Controller with SPI Interface
+ *
+ * Based on Microchip 251x CAN Controller (mcp251x) Linux kernel driver
+ *
+ * Copyright(C) Timesys Corporation 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/can/core.h>
+#include <linux/can/dev.h>
+#include <linux/can/led.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/uaccess.h>
+
+#define HI3110_MASTER_RESET 0x56
+#define HI3110_READ_CTRL0 0xD2
+#define HI3110_READ_CTRL1 0xD4
+#define HI3110_READ_STATF 0xE2
+#define HI3110_WRITE_CTRL0 0x14
+#define HI3110_WRITE_CTRL1 0x16
+#define HI3110_WRITE_INTE 0x1C
+#define HI3110_WRITE_BTR0 0x18
+#define HI3110_WRITE_BTR1 0x1A
+#define HI3110_READ_BTR0 0xD6
+#define HI3110_READ_BTR1 0xD8
+#define HI3110_READ_INTF 0xDE
+#define HI3110_READ_ERR 0xDC
+#define HI3110_READ_FIFO_WOTIME 0x48
+#define HI3110_WRITE_FIFO 0x12
+#define HI3110_READ_MESSTAT 0xDA
+#define HI3110_READ_TEC 0xEC
+
+#define HI3110_CTRL0_MODE_MASK (7 << 5)
+#define HI3110_CTRL0_NORMAL_MODE (0 << 5)
+#define HI3110_CTRL0_LOOPBACK_MODE (1 << 5)
+#define HI3110_CTRL0_MONITOR_MODE (2 << 5)
+#define HI3110_CTRL0_SLEEP_MODE (3 << 5)
+#define HI3110_CTRL0_INIT_MODE (4 << 5)
+
+#define HI3110_CTRL1_TXEN BIT(7)
+
+#define HI3110_INT_RXTMP BIT(7)
+#define HI3110_INT_RXFIFO BIT(6)
+#define HI3110_INT_TXCPLT BIT(5)
+#define HI3110_INT_BUSERR BIT(4)
+#define HI3110_INT_MCHG BIT(3)
+#define HI3110_INT_WAKEUP BIT(2)
+#define HI3110_INT_F1MESS BIT(1)
+#define HI3110_INT_F0MESS BIT(0)
+
+#define HI3110_ERR_BUSOFF BIT(7)
+#define HI3110_ERR_TXERRP BIT(6)
+#define HI3110_ERR_RXERRP BIT(5)
+#define HI3110_ERR_BITERR BIT(4)
+#define HI3110_ERR_FRMERR BIT(3)
+#define HI3110_ERR_CRCERR BIT(2)
+#define HI3110_ERR_ACKERR BIT(1)
+#define HI3110_ERR_STUFERR BIT(0)
+#define HI3110_ERR_PROTOCOL_MASK (0x1F)
+
+#define HI3110_STAT_RXFMTY BIT(1)
+
+#define HI3110_BTR0_SJW_SHIFT 6
+#define HI3110_BTR0_BRP_SHIFT 0
+
+#define HI3110_BTR1_SAMP_3PERBIT (1 << 7)
+#define HI3110_BTR1_SAMP_1PERBIT (0 << 7)
+#define HI3110_BTR1_TSEG2_SHIFT 4
+#define HI3110_BTR1_TSEG1_SHIFT 0
+
+#define HI3110_FIFO_WOTIME_TAG_OFF 0
+#define HI3110_FIFO_WOTIME_ID_OFF 1
+#define HI3110_FIFO_WOTIME_DLC_OFF 5
+#define HI3110_FIFO_WOTIME_DAT_OFF 6
+
+#define HI3110_FIFO_WOTIME_TAG_IDE BIT(7)
+#define HI3110_FIFO_WOTIME_ID_RTR BIT(0)
+
+#define HI3110_FIFO_TAG_OFF 0
+#define HI3110_FIFO_ID_OFF 1
+#define HI3110_FIFO_STD_DLC_OFF 3
+#define HI3110_FIFO_STD_DATA_OFF 4
+#define HI3110_FIFO_EXT_DLC_OFF 5
+#define HI3110_FIFO_EXT_DATA_OFF 6
+
+#define CAN_FRAME_MAX_DATA_LEN 8
+#define RX_BUF_LEN 15
+#define TX_STD_BUF_LEN 12
+#define TX_EXT_BUF_LEN 14
+#define CAN_FRAME_MAX_BITS 128
+
+#define TX_ECHO_SKB_MAX 1
+
+#define HI3110_OST_DELAY_MS (10)
+
+#define DEVICE_NAME "hi3110"
+
+static int hi3110_enable_dma = 1; /* Enable SPI DMA. Default: 1 (On) */
+module_param(hi3110_enable_dma, int, 0444);
+MODULE_PARM_DESC(hi3110_enable_dma, "Enable SPI DMA. Default: 1 (On)");
+
+static const struct can_bittiming_const hi3110_bittiming_const = {
+ .name = DEVICE_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+};
+
+enum hi3110_model {
+ CAN_HI3110_HI3110 = 0x3110,
+};
+
+struct hi3110_priv {
+ struct can_priv can;
+ struct net_device *net;
+ struct spi_device *spi;
+ enum hi3110_model model;
+
+ struct mutex hi3110_lock; /* SPI device lock */
+
+ u8 *spi_tx_buf;
+ u8 *spi_rx_buf;
+ dma_addr_t spi_tx_dma;
+ dma_addr_t spi_rx_dma;
+
+ struct sk_buff *tx_skb;
+ int tx_len;
+
+ struct workqueue_struct *wq;
+ struct work_struct tx_work;
+ struct work_struct restart_work;
+
+ int force_quit;
+ int after_suspend;
+#define AFTER_SUSPEND_UP 1
+#define AFTER_SUSPEND_DOWN 2
+#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
+ int restart_tx;
+ struct regulator *power;
+ struct regulator *transceiver;
+ struct clk *clk;
+};
+
+static void hi3110_clean(struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+
+ if (priv->tx_skb || priv->tx_len)
+ net->stats.tx_errors++;
+ if (priv->tx_skb)
+ dev_kfree_skb(priv->tx_skb);
+ if (priv->tx_len)
+ can_free_echo_skb(priv->net, 0);
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+}
+
+/* Note about handling of error return of hi3110_spi_trans: accessing
+ * registers via SPI is not really different conceptually than using
+ * normal I/O assembler instructions, although it's much more
+ * complicated from a practical POV. So it's not advisable to always
+ * check the return value of this function. Imagine that every
+ * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+ * error();", it would be a great mess (well there are some situation
+ * when exception handling C++ like could be useful after all). So we
+ * just check that transfers are OK at the beginning of our
+ * conversation with the chip and to avoid doing really nasty things
+ * (like injecting bogus packets in the network stack).
+ */
+static int hi3110_spi_trans(struct spi_device *spi, int len)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ struct spi_transfer t = {
+ .tx_buf = priv->spi_tx_buf,
+ .rx_buf = priv->spi_rx_buf,
+ .len = len,
+ .cs_change = 0,
+ };
+ struct spi_message m;
+ int ret;
+
+ spi_message_init(&m);
+
+ if (hi3110_enable_dma) {
+ t.tx_dma = priv->spi_tx_dma;
+ t.rx_dma = priv->spi_rx_dma;
+ m.is_dma_mapped = 1;
+ }
+
+ spi_message_add_tail(&t, &m);
+
+ ret = spi_sync(spi, &m);
+
+ if (ret)
+ dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
+ return ret;
+}
+
+static u8 hi3110_cmd(struct spi_device *spi, uint8_t command)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+
+ priv->spi_tx_buf[0] = command;
+ dev_dbg(&spi->dev, "hi3110_cmd: %02X\n", command);
+
+ return hi3110_spi_trans(spi, 1);
+}
+
+static u8 hi3110_read(struct spi_device *spi, uint8_t command)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ u8 val = 0;
+
+ priv->spi_tx_buf[0] = command;
+ hi3110_spi_trans(spi, 2);
+ val = priv->spi_rx_buf[1];
+ dev_dbg(&spi->dev, "hi3110_read: %02X, %02X\n", command, val);
+
+ return val;
+}
+
+static void hi3110_write(struct spi_device *spi, u8 reg, uint8_t val)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+
+ priv->spi_tx_buf[0] = reg;
+ priv->spi_tx_buf[1] = val;
+ dev_dbg(&spi->dev, "hi3110_write: %02X, %02X\n", reg, val);
+
+ hi3110_spi_trans(spi, 2);
+}
+
+static void hi3110_hw_tx_frame(struct spi_device *spi, u8 *buf, int len)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+
+ priv->spi_tx_buf[0] = HI3110_WRITE_FIFO;
+ memcpy(priv->spi_tx_buf + 1, buf, len);
+ hi3110_spi_trans(spi, len + 1);
+}
+
+static void hi3110_hw_tx(struct spi_device *spi, struct can_frame *frame)
+{
+ u8 buf[TX_EXT_BUF_LEN];
+
+ buf[HI3110_FIFO_TAG_OFF] = 0;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ /* Extended frame */
+ buf[HI3110_FIFO_ID_OFF] = (frame->can_id & CAN_EFF_MASK) >> 21;
+ buf[HI3110_FIFO_ID_OFF + 1] =
+ ((((frame->can_id & CAN_EFF_MASK) >> 18) & 0x07) << 5) |
+ 0x18 | /* Recessive SRR and IDE */
+ (((frame->can_id & CAN_EFF_MASK) >> 15) & 0x07);
+ buf[HI3110_FIFO_ID_OFF + 2] =
+ (frame->can_id & CAN_EFF_MASK) >> 7;
+ buf[HI3110_FIFO_ID_OFF + 3] =
+ ((frame->can_id & CAN_EFF_MASK) << 1) |
+ ((frame->can_id & CAN_RTR_FLAG) ? 1 : 0);
+
+ buf[HI3110_FIFO_EXT_DLC_OFF] = frame->can_dlc;
+
+ memcpy(buf + HI3110_FIFO_EXT_DATA_OFF,
+ frame->data, frame->can_dlc);
+
+ hi3110_hw_tx_frame(spi, buf, TX_EXT_BUF_LEN -
+ (CAN_FRAME_MAX_DATA_LEN - frame->can_dlc));
+ } else {
+ /* Standard frame */
+ buf[HI3110_FIFO_ID_OFF] = (frame->can_id & CAN_SFF_MASK) >> 3;
+ buf[HI3110_FIFO_ID_OFF + 1] =
+ ((frame->can_id & CAN_SFF_MASK) << 5) |
+ ((frame->can_id & CAN_RTR_FLAG) ? (1 << 4) : 0);
+
+ buf[HI3110_FIFO_STD_DLC_OFF] = frame->can_dlc;
+
+ memcpy(buf + HI3110_FIFO_STD_DATA_OFF,
+ frame->data, frame->can_dlc);
+
+ hi3110_hw_tx_frame(spi, buf, TX_STD_BUF_LEN -
+ (CAN_FRAME_MAX_DATA_LEN - frame->can_dlc));
+ }
+}
+
+static void hi3110_hw_rx_frame(struct spi_device *spi, u8 *buf)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+
+ priv->spi_tx_buf[0] = HI3110_READ_FIFO_WOTIME;
+ hi3110_spi_trans(spi, RX_BUF_LEN);
+ memcpy(buf, priv->spi_rx_buf + 1, RX_BUF_LEN - 1);
+}
+
+static void hi3110_hw_rx(struct spi_device *spi)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ struct sk_buff *skb;
+ struct can_frame *frame;
+ u8 buf[RX_BUF_LEN - 1];
+
+ skb = alloc_can_skb(priv->net, &frame);
+ if (!skb) {
+ dev_err(&spi->dev, "cannot allocate RX skb\n");
+ priv->net->stats.rx_dropped++;
+ return;
+ }
+
+ hi3110_hw_rx_frame(spi, buf);
+ if (buf[HI3110_FIFO_WOTIME_TAG_OFF] & HI3110_FIFO_WOTIME_TAG_IDE) {
+ /* IDE is recessive (1), indicating extended 29-bit frame */
+ frame->can_id = CAN_EFF_FLAG;
+ frame->can_id |=
+ (buf[HI3110_FIFO_WOTIME_ID_OFF] << 21) |
+ (((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0xE0) >> 5) << 18) |
+ ((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0x07) << 15) |
+ (buf[HI3110_FIFO_WOTIME_ID_OFF + 2] << 7) |
+ (buf[HI3110_FIFO_WOTIME_ID_OFF + 3] >> 1);
+ } else {
+ /* IDE is dominant (0), frame indicating standard 11-bit */
+ frame->can_id =
+ (buf[HI3110_FIFO_WOTIME_ID_OFF] << 3) |
+ ((buf[HI3110_FIFO_WOTIME_ID_OFF + 1] & 0xE0) >> 5);
+ }
+
+ if (buf[HI3110_FIFO_WOTIME_ID_OFF + 3] & HI3110_FIFO_WOTIME_ID_RTR) {
+ /* RTR is recessive (1), indicating remote request frame */
+ frame->can_id |= CAN_RTR_FLAG;
+ }
+
+ /* Data length */
+ frame->can_dlc = get_can_dlc(buf[HI3110_FIFO_WOTIME_DLC_OFF] & 0x0F);
+ memcpy(frame->data, buf + HI3110_FIFO_WOTIME_DAT_OFF, frame->can_dlc);
+
+ priv->net->stats.rx_packets++;
+ priv->net->stats.rx_bytes += frame->can_dlc;
+
+ can_led_event(priv->net, CAN_LED_EVENT_RX);
+
+ netif_rx_ni(skb);
+}
+
+static void hi3110_hw_sleep(struct spi_device *spi)
+{
+ hi3110_write(spi, HI3110_WRITE_CTRL0, HI3110_CTRL0_SLEEP_MODE);
+}
+
+static netdev_tx_t hi3110_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+
+ if (priv->tx_skb || priv->tx_len) {
+ dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ if (can_dropped_invalid_skb(net, skb))
+ return NETDEV_TX_OK;
+
+ netif_stop_queue(net);
+ priv->tx_skb = skb;
+ queue_work(priv->wq, &priv->tx_work);
+
+ return NETDEV_TX_OK;
+}
+
+static int hi3110_do_set_mode(struct net_device *net, enum can_mode mode)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+
+ switch (mode) {
+ case CAN_MODE_START:
+ hi3110_clean(net);
+ /* We have to delay work since SPI I/O may sleep */
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ priv->restart_tx = 1;
+ if (priv->can.restart_ms == 0)
+ priv->after_suspend = AFTER_SUSPEND_RESTART;
+ queue_work(priv->wq, &priv->restart_work);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int hi3110_set_normal_mode(struct spi_device *spi)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ u8 reg;
+
+ hi3110_write(spi, HI3110_WRITE_INTE, HI3110_INT_BUSERR |
+ HI3110_INT_RXFIFO | HI3110_INT_TXCPLT);
+
+ /* Enable TX */
+ hi3110_write(spi, HI3110_WRITE_CTRL1, HI3110_CTRL1_TXEN);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ /* Put device into loopback mode */
+ hi3110_write(spi, HI3110_WRITE_CTRL0,
+ HI3110_CTRL0_LOOPBACK_MODE);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ /* Put device into listen-only mode */
+ hi3110_write(spi, HI3110_WRITE_CTRL0,
+ HI3110_CTRL0_MONITOR_MODE);
+ } else {
+ /* Put device into normal mode */
+ hi3110_write(spi, HI3110_WRITE_CTRL0,
+ HI3110_CTRL0_NORMAL_MODE);
+
+ /* Wait for the device to enter normal mode */
+ mdelay(HI3110_OST_DELAY_MS);
+ reg = hi3110_read(spi, HI3110_READ_CTRL0);
+ if ((reg & HI3110_CTRL0_MODE_MASK) != HI3110_CTRL0_NORMAL_MODE)
+ return -EBUSY;
+ }
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+}
+
+static int hi3110_do_set_bittiming(struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct spi_device *spi = priv->spi;
+
+ hi3110_write(spi, HI3110_WRITE_BTR0,
+ ((bt->sjw - 1) << HI3110_BTR0_SJW_SHIFT) |
+ ((bt->brp - 1) << HI3110_BTR0_BRP_SHIFT));
+
+ hi3110_write(spi, HI3110_WRITE_BTR1,
+ (priv->can.ctrlmode &
+ CAN_CTRLMODE_3_SAMPLES ?
+ HI3110_BTR1_SAMP_3PERBIT : HI3110_BTR1_SAMP_1PERBIT) |
+ ((bt->phase_seg1 + bt->prop_seg - 1)
+ << HI3110_BTR1_TSEG1_SHIFT) |
+ ((bt->phase_seg2 - 1) << HI3110_BTR1_TSEG2_SHIFT));
+
+ dev_dbg(&spi->dev, "BT: 0x%02x 0x%02x\n",
+ hi3110_read(spi, HI3110_READ_BTR0),
+ hi3110_read(spi, HI3110_READ_BTR1));
+
+ return 0;
+}
+
+static int hi3110_setup(struct net_device *net, struct hi3110_priv *priv,
+ struct spi_device *spi)
+{
+ hi3110_do_set_bittiming(net);
+ return 0;
+}
+
+static int hi3110_hw_reset(struct spi_device *spi)
+{
+ u8 reg;
+ int ret;
+
+ /* Wait for oscillator startup timer after power up */
+ mdelay(HI3110_OST_DELAY_MS);
+
+ ret = hi3110_cmd(spi, HI3110_MASTER_RESET);
+ if (ret)
+ return ret;
+
+ /* Wait for oscillator startup timer after reset */
+ mdelay(HI3110_OST_DELAY_MS);
+
+ reg = hi3110_read(spi, HI3110_READ_CTRL0);
+ if ((reg & HI3110_CTRL0_MODE_MASK) != HI3110_CTRL0_INIT_MODE)
+ return -ENODEV;
+
+ /* As per the datasheet it appears the error flags are
+ * not cleared on reset. Explicitly clear them by performing a read
+ */
+ hi3110_read(spi, HI3110_READ_ERR);
+
+ return 0;
+}
+
+static int hi3110_hw_probe(struct spi_device *spi)
+{
+ u8 statf;
+
+ hi3110_hw_reset(spi);
+
+ /* Confirm correct operation by checking against reset values
+ * in datasheet
+ */
+ statf = hi3110_read(spi, HI3110_READ_STATF);
+
+ dev_dbg(&spi->dev, "statf: %02X\n", statf);
+
+ if (statf != 0x82)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int hi3110_power_enable(struct regulator *reg, int enable)
+{
+ if (IS_ERR_OR_NULL(reg))
+ return 0;
+
+ if (enable)
+ return regulator_enable(reg);
+ else
+ return regulator_disable(reg);
+}
+
+static void hi3110_open_clean(struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+
+ free_irq(spi->irq, priv);
+ hi3110_hw_sleep(spi);
+ hi3110_power_enable(priv->transceiver, 0);
+ close_candev(net);
+}
+
+static int hi3110_stop(struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+
+ close_candev(net);
+
+ priv->force_quit = 1;
+ free_irq(spi->irq, priv);
+ destroy_workqueue(priv->wq);
+ priv->wq = NULL;
+
+ mutex_lock(&priv->hi3110_lock);
+
+ /* Disable transmit, interrupts and clear flags */
+ hi3110_write(spi, HI3110_WRITE_CTRL1, 0x0);
+ hi3110_write(spi, HI3110_WRITE_INTE, 0x0);
+ hi3110_read(spi, HI3110_READ_INTF);
+
+ hi3110_clean(net);
+
+ hi3110_hw_sleep(spi);
+
+ hi3110_power_enable(priv->transceiver, 0);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ mutex_unlock(&priv->hi3110_lock);
+
+ can_led_event(net, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+static void hi3110_error_skb(struct net_device *net, int can_id,
+ int data1, int data2)
+{
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_err_skb(net, &frame);
+ if (skb) {
+ frame->can_id |= can_id;
+ frame->data[1] = data1;
+ frame->data[2] = data2;
+ netif_rx_ni(skb);
+ } else {
+ netdev_err(net, "cannot allocate error skb\n");
+ }
+}
+
+static void hi3110_tx_work_handler(struct work_struct *ws)
+{
+ struct hi3110_priv *priv = container_of(ws, struct hi3110_priv,
+ tx_work);
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
+ struct can_frame *frame;
+
+ mutex_lock(&priv->hi3110_lock);
+ if (priv->tx_skb) {
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ hi3110_clean(net);
+ } else {
+ frame = (struct can_frame *)priv->tx_skb->data;
+
+ if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
+ frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
+ hi3110_hw_tx(spi, frame);
+ priv->tx_len = 1 + frame->can_dlc;
+ can_put_echo_skb(priv->tx_skb, net, 0);
+ priv->tx_skb = NULL;
+ }
+ }
+ mutex_unlock(&priv->hi3110_lock);
+}
+
+static void hi3110_restart_work_handler(struct work_struct *ws)
+{
+ struct hi3110_priv *priv = container_of(ws, struct hi3110_priv,
+ restart_work);
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
+
+ mutex_lock(&priv->hi3110_lock);
+ if (priv->after_suspend) {
+ hi3110_hw_reset(spi);
+ hi3110_setup(net, priv, spi);
+ if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
+ hi3110_set_normal_mode(spi);
+ } else if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ netif_device_attach(net);
+ hi3110_clean(net);
+ hi3110_set_normal_mode(spi);
+ netif_wake_queue(net);
+ } else {
+ hi3110_hw_sleep(spi);
+ }
+ priv->after_suspend = 0;
+ priv->force_quit = 0;
+ }
+
+ if (priv->restart_tx) {
+ priv->restart_tx = 0;
+ hi3110_clean(net);
+ netif_wake_queue(net);
+ hi3110_error_skb(net, CAN_ERR_RESTARTED, 0, 0);
+ }
+ mutex_unlock(&priv->hi3110_lock);
+}
+
+static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
+{
+ struct hi3110_priv *priv = dev_id;
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
+
+ mutex_lock(&priv->hi3110_lock);
+
+ while (!priv->force_quit) {
+ enum can_state new_state;
+ u8 intf;
+ u8 eflag;
+ int can_id = 0, data1 = 0, data2 = 0;
+
+ while (!(HI3110_STAT_RXFMTY &
+ hi3110_read(spi, HI3110_READ_STATF))) {
+ hi3110_hw_rx(spi);
+ };
+
+ intf = hi3110_read(spi, HI3110_READ_INTF);
+ eflag = hi3110_read(spi, HI3110_READ_ERR);
+ /* Update can state */
+ if (eflag & HI3110_ERR_BUSOFF) {
+ new_state = CAN_STATE_BUS_OFF;
+ can_id |= CAN_ERR_BUSOFF;
+ } else if (eflag & HI3110_ERR_TXERRP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_TX_PASSIVE;
+ } else if (eflag & HI3110_ERR_RXERRP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_PASSIVE;
+ } else {
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ /* Check for protocol errors */
+ if (eflag & HI3110_ERR_PROTOCOL_MASK) {
+ can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ priv->can.can_stats.bus_error++;
+ priv->net->stats.rx_errors++;
+ if (eflag & HI3110_ERR_BITERR)
+ data2 |= CAN_ERR_PROT_BIT;
+ else if (eflag & HI3110_ERR_FRMERR)
+ data2 |= CAN_ERR_PROT_FORM;
+ else if (eflag & HI3110_ERR_STUFERR)
+ data2 |= CAN_ERR_PROT_STUFF;
+ else
+ data2 |= CAN_ERR_PROT_UNSPEC;
+ }
+
+ /* Update can state statistics */
+ switch (priv->can.state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ if (new_state >= CAN_STATE_ERROR_WARNING &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_warning++;
+ /* fallthrough */
+ case CAN_STATE_ERROR_WARNING:
+ if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ break;
+ }
+ priv->can.state = new_state;
+
+ if (intf & HI3110_INT_BUSERR) {
+ /* Note: HI3110 Does report overflow errors */
+ hi3110_error_skb(net, can_id, data1, data2);
+ }
+
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ if (priv->can.restart_ms == 0) {
+ priv->force_quit = 1;
+ priv->can.can_stats.bus_off++;
+ can_bus_off(net);
+ hi3110_hw_sleep(spi);
+ break;
+ }
+ }
+
+ if (intf == 0)
+ break;
+
+ if (intf & HI3110_INT_TXCPLT) {
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += priv->tx_len - 1;
+ can_led_event(net, CAN_LED_EVENT_TX);
+ if (priv->tx_len) {
+ can_get_echo_skb(net, 0);
+ priv->tx_len = 0;
+ }
+ netif_wake_queue(net);
+ }
+ }
+ mutex_unlock(&priv->hi3110_lock);
+ return IRQ_HANDLED;
+}
+
+static int hi3110_open(struct net_device *net)
+{
+ struct hi3110_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+ unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_RISING;
+ int ret;
+
+ ret = open_candev(net);
+ if (ret) {
+ dev_err(&spi->dev, "unable to set initial baudrate!\n");
+ return ret;
+ }
+
+ mutex_lock(&priv->hi3110_lock);
+ hi3110_power_enable(priv->transceiver, 1);
+
+ priv->force_quit = 0;
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+
+ ret = request_threaded_irq(spi->irq, NULL, hi3110_can_ist,
+ flags, DEVICE_NAME, priv);
+ if (ret) {
+ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+ hi3110_power_enable(priv->transceiver, 0);
+ close_candev(net);
+ goto open_unlock;
+ }
+
+ priv->wq = alloc_workqueue("hi3110_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
+ 0);
+ INIT_WORK(&priv->tx_work, hi3110_tx_work_handler);
+ INIT_WORK(&priv->restart_work, hi3110_restart_work_handler);
+
+ ret = hi3110_hw_reset(spi);
+ if (ret) {
+ hi3110_open_clean(net);
+ goto open_unlock;
+ }
+ ret = hi3110_setup(net, priv, spi);
+ if (ret) {
+ hi3110_open_clean(net);
+ goto open_unlock;
+ }
+ ret = hi3110_set_normal_mode(spi);
+ if (ret) {
+ hi3110_open_clean(net);
+ goto open_unlock;
+ }
+ can_led_event(net, CAN_LED_EVENT_OPEN);
+ netif_wake_queue(net);
+
+open_unlock:
+ mutex_unlock(&priv->hi3110_lock);
+ return ret;
+}
+
+static const struct net_device_ops hi3110_netdev_ops = {
+ .ndo_open = hi3110_open,
+ .ndo_stop = hi3110_stop,
+ .ndo_start_xmit = hi3110_hard_start_xmit,
+};
+
+static const struct of_device_id hi3110_of_match[] = {
+ {
+ .compatible = "holt,hi3110",
+ .data = (void *)CAN_HI3110_HI3110,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hi3110_of_match);
+
+static const struct spi_device_id hi3110_id_table[] = {
+ {
+ .name = "hi3110",
+ .driver_data = (kernel_ulong_t)CAN_HI3110_HI3110,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, hi3110_id_table);
+
+static int hi3110_can_probe(struct spi_device *spi)
+{
+ const struct of_device_id *of_id = of_match_device(hi3110_of_match,
+ &spi->dev);
+ struct net_device *net;
+ struct hi3110_priv *priv;
+ struct clk *clk;
+ int freq, ret;
+
+ clk = devm_clk_get(&spi->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&spi->dev, "no CAN clock source defined\n");
+ return PTR_ERR(clk);
+ }
+ freq = clk_get_rate(clk);
+
+ /* Sanity check */
+ if (freq > 40000000)
+ return -ERANGE;
+
+ /* Allocate can/net device */
+ net = alloc_candev(sizeof(struct hi3110_priv), TX_ECHO_SKB_MAX);
+ if (!net)
+ return -ENOMEM;
+
+ if (!IS_ERR(clk)) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto out_free;
+ }
+
+ net->netdev_ops = &hi3110_netdev_ops;
+ net->flags |= IFF_ECHO;
+
+ priv = netdev_priv(net);
+ priv->can.bittiming_const = &hi3110_bittiming_const;
+ priv->can.do_set_mode = hi3110_do_set_mode;
+ priv->can.clock.freq = freq / 2;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
+ if (of_id)
+ priv->model = (enum hi3110_model)of_id->data;
+ else
+ priv->model = spi_get_device_id(spi)->driver_data;
+ priv->net = net;
+ priv->clk = clk;
+
+ spi_set_drvdata(spi, priv);
+
+ /* Configure the SPI bus */
+ spi->bits_per_word = 8;
+ ret = spi_setup(spi);
+ if (ret)
+ goto out_clk;
+
+ priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
+ priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
+ if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
+ (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
+ ret = -EPROBE_DEFER;
+ goto out_clk;
+ }
+
+ ret = hi3110_power_enable(priv->power, 1);
+ if (ret)
+ goto out_clk;
+
+ priv->spi = spi;
+ mutex_init(&priv->hi3110_lock);
+
+ /* If requested, allocate DMA buffers */
+ if (hi3110_enable_dma) {
+ spi->dev.coherent_dma_mask = ~0;
+
+ /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+ * that much and share it between Tx and Rx DMA buffers.
+ */
+ priv->spi_tx_buf = dmam_alloc_coherent(&spi->dev,
+ PAGE_SIZE,
+ &priv->spi_tx_dma,
+ GFP_DMA);
+
+ if (priv->spi_tx_buf) {
+ priv->spi_rx_buf = (priv->spi_tx_buf + (PAGE_SIZE / 2));
+ priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
+ (PAGE_SIZE / 2));
+ } else {
+ /* Fall back to non-DMA */
+ hi3110_enable_dma = 0;
+ }
+ }
+
+ /* Allocate non-DMA buffers */
+ if (!hi3110_enable_dma) {
+ priv->spi_tx_buf = devm_kzalloc(&spi->dev, RX_BUF_LEN,
+ GFP_KERNEL);
+ if (!priv->spi_tx_buf) {
+ ret = -ENOMEM;
+ goto error_probe;
+ }
+ priv->spi_rx_buf = devm_kzalloc(&spi->dev, RX_BUF_LEN,
+ GFP_KERNEL);
+
+ if (!priv->spi_rx_buf) {
+ ret = -ENOMEM;
+ goto error_probe;
+ }
+ }
+
+ SET_NETDEV_DEV(net, &spi->dev);
+
+ ret = hi3110_hw_probe(spi);
+ if (ret) {
+ if (ret == -ENODEV)
+ dev_err(&spi->dev, "Cannot initialize %x. Wrong wiring?\n",
+ priv->model);
+ goto error_probe;
+ }
+ hi3110_hw_sleep(spi);
+
+ ret = register_candev(net);
+ if (ret)
+ goto error_probe;
+
+ devm_can_led_init(net);
+ netdev_info(net, "%x successfully initialized.\n", priv->model);
+
+ return 0;
+
+error_probe:
+ hi3110_power_enable(priv->power, 0);
+
+out_clk:
+ if (!IS_ERR(clk))
+ clk_disable_unprepare(clk);
+
+out_free:
+ free_candev(net);
+
+ dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
+ return ret;
+}
+
+static int hi3110_can_remove(struct spi_device *spi)
+{
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ struct net_device *net = priv->net;
+
+ unregister_candev(net);
+
+ hi3110_power_enable(priv->power, 0);
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
+ free_candev(net);
+
+ return 0;
+}
+
+static int __maybe_unused hi3110_can_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+ struct net_device *net = priv->net;
+
+ priv->force_quit = 1;
+ disable_irq(spi->irq);
+
+ /* Note: at this point neither IST nor workqueues are running.
+ * open/stop cannot be called anyway so locking is not needed
+ */
+ if (netif_running(net)) {
+ netif_device_detach(net);
+
+ hi3110_hw_sleep(spi);
+ hi3110_power_enable(priv->transceiver, 0);
+ priv->after_suspend = AFTER_SUSPEND_UP;
+ } else {
+ priv->after_suspend = AFTER_SUSPEND_DOWN;
+ }
+
+ if (!IS_ERR_OR_NULL(priv->power)) {
+ regulator_disable(priv->power);
+ priv->after_suspend |= AFTER_SUSPEND_POWER;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused hi3110_can_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct hi3110_priv *priv = spi_get_drvdata(spi);
+
+ if (priv->after_suspend & AFTER_SUSPEND_POWER)
+ hi3110_power_enable(priv->power, 1);
+
+ if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ hi3110_power_enable(priv->transceiver, 1);
+ queue_work(priv->wq, &priv->restart_work);
+ } else {
+ priv->after_suspend = 0;
+ }
+
+ priv->force_quit = 0;
+ enable_irq(spi->irq);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(hi3110_can_pm_ops, hi3110_can_suspend,
+ hi3110_can_resume);
+
+static struct spi_driver hi3110_can_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = hi3110_of_match,
+ .pm = &hi3110_can_pm_ops,
+ },
+ .id_table = hi3110_id_table,
+ .probe = hi3110_can_probe,
+ .remove = hi3110_can_remove,
+};
+
+module_spi_driver(hi3110_can_driver);
+
+MODULE_AUTHOR("Akshay Bhat <akshay.bhat@timesys.com>");
+MODULE_AUTHOR("Casey Fitzpatrick <casey.fitzpatrick@timesys.com>");
+MODULE_DESCRIPTION("Holt HI-3110 CAN driver");
+MODULE_LICENSE("GPL v2");
--
2.8.1
^ 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