Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
This merge resolves conflicts with 75aec9df3a
("bridge: Remove
br_nf_push_frag_xmit_sk") as part of Eric Biederman's effort to improve
netns support in the network stack that reached upstream via David's
net-next tree.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Conflicts:
net/bridge/br_netfilter_hooks.c
This commit is contained in:
commit
f0a0a978b6
|
@ -0,0 +1,23 @@
|
||||||
|
* Broadcom iProc MDIO bus controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "brcm,iproc-mdio"
|
||||||
|
- reg: address and length of the register set for the MDIO interface
|
||||||
|
- #size-cells: must be 1
|
||||||
|
- #address-cells: must be 0
|
||||||
|
|
||||||
|
Child nodes of this MDIO bus controller node are standard Ethernet PHY device
|
||||||
|
nodes as described in Documentation/devicetree/bindings/net/phy.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
mdio@18002000 {
|
||||||
|
compatible = "brcm,iproc-mdio";
|
||||||
|
reg = <0x18002000 0x8>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
#address-cells = <0>;
|
||||||
|
|
||||||
|
enet-gphy@0 {
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -57,6 +57,10 @@ Properties:
|
||||||
"rgmii-id", as all other connection types are detected by hardware.
|
"rgmii-id", as all other connection types are detected by hardware.
|
||||||
- fsl,magic-packet : If present, indicates that the hardware supports
|
- fsl,magic-packet : If present, indicates that the hardware supports
|
||||||
waking up via magic packet.
|
waking up via magic packet.
|
||||||
|
- fsl,wake-on-filer : If present, indicates that the hardware supports
|
||||||
|
waking up by Filer General Purpose Interrupt (FGPI) asserted on the
|
||||||
|
Rx int line. This is an advanced power management capability allowing
|
||||||
|
certain packet types (user) defined by filer rules to wake up the system.
|
||||||
- bd-stash : If present, indicates that the hardware supports stashing
|
- bd-stash : If present, indicates that the hardware supports stashing
|
||||||
buffer descriptors in the L2.
|
buffer descriptors in the L2.
|
||||||
- rx-stash-len : Denotes the number of bytes of a received buffer to stash
|
- rx-stash-len : Denotes the number of bytes of a received buffer to stash
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
* MRF24J40 IEEE 802.15.4 *
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "microchip,mrf24j40", "microchip,mrf24j40ma",
|
||||||
|
or "microchip,mrf24j40mc" depends on your transceiver
|
||||||
|
board
|
||||||
|
- spi-max-frequency: maximal bus speed, should be set something under or equal
|
||||||
|
10000000
|
||||||
|
- reg: the chipselect index
|
||||||
|
- interrupts: the interrupt generated by the device.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
mrf24j40ma@0 {
|
||||||
|
compatible = "microchip,mrf24j40ma";
|
||||||
|
spi-max-frequency = <8500000>;
|
||||||
|
reg = <0>;
|
||||||
|
interrupts = <19 8>;
|
||||||
|
interrupt-parent = <&gpio3>;
|
||||||
|
};
|
|
@ -90,7 +90,304 @@ or to specify the output device using cmsg and IP_PKTINFO.
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
VRF device currently only works for IPv4. Support for IPv6 is under development.
|
|
||||||
|
|
||||||
Index of original ingress interface is not available via cmsg. Will address
|
Index of original ingress interface is not available via cmsg. Will address
|
||||||
soon.
|
soon.
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
Using iproute2 for VRFs
|
||||||
|
=======================
|
||||||
|
VRF devices do *not* have to start with 'vrf-'. That is a convention used here
|
||||||
|
for emphasis of the device type, similar to use of 'br' in bridge names.
|
||||||
|
|
||||||
|
1. Create a VRF
|
||||||
|
|
||||||
|
To instantiate a VRF device and associate it with a table:
|
||||||
|
$ ip link add dev NAME type vrf table ID
|
||||||
|
|
||||||
|
Remember to add the ip rules as well:
|
||||||
|
$ ip ru add oif NAME table 10
|
||||||
|
$ ip ru add iif NAME table 10
|
||||||
|
$ ip -6 ru add oif NAME table 10
|
||||||
|
$ ip -6 ru add iif NAME table 10
|
||||||
|
|
||||||
|
Without the rules route lookups are not directed to the table.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip link add dev vrf-blue type vrf table 10
|
||||||
|
$ ip ru add pref 200 oif vrf-blue table 10
|
||||||
|
$ ip ru add pref 200 iif vrf-blue table 10
|
||||||
|
$ ip -6 ru add pref 200 oif vrf-blue table 10
|
||||||
|
$ ip -6 ru add pref 200 iif vrf-blue table 10
|
||||||
|
|
||||||
|
|
||||||
|
2. List VRFs
|
||||||
|
|
||||||
|
To list VRFs that have been created:
|
||||||
|
$ ip [-d] link show type vrf
|
||||||
|
NOTE: The -d option is needed to show the table id
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip -d link show type vrf
|
||||||
|
11: vrf-mgmt: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 72:b3:ba:91:e2:24 brd ff:ff:ff:ff:ff:ff promiscuity 0
|
||||||
|
vrf table 1 addrgenmode eui64
|
||||||
|
12: vrf-red: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether b6:6f:6e:f6:da:73 brd ff:ff:ff:ff:ff:ff promiscuity 0
|
||||||
|
vrf table 10 addrgenmode eui64
|
||||||
|
13: vrf-blue: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 36:62:e8:7d:bb:8c brd ff:ff:ff:ff:ff:ff promiscuity 0
|
||||||
|
vrf table 66 addrgenmode eui64
|
||||||
|
14: vrf-green: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether e6:28:b8:63:70:bb brd ff:ff:ff:ff:ff:ff promiscuity 0
|
||||||
|
vrf table 81 addrgenmode eui64
|
||||||
|
|
||||||
|
|
||||||
|
Or in brief output:
|
||||||
|
|
||||||
|
$ ip -br link show type vrf
|
||||||
|
vrf-mgmt UP 72:b3:ba:91:e2:24 <NOARP,MASTER,UP,LOWER_UP>
|
||||||
|
vrf-red UP b6:6f:6e:f6:da:73 <NOARP,MASTER,UP,LOWER_UP>
|
||||||
|
vrf-blue UP 36:62:e8:7d:bb:8c <NOARP,MASTER,UP,LOWER_UP>
|
||||||
|
vrf-green UP e6:28:b8:63:70:bb <NOARP,MASTER,UP,LOWER_UP>
|
||||||
|
|
||||||
|
|
||||||
|
3. Assign a Network Interface to a VRF
|
||||||
|
|
||||||
|
Network interfaces are assigned to a VRF by enslaving the netdevice to a
|
||||||
|
VRF device:
|
||||||
|
$ ip link set dev NAME master VRF-NAME
|
||||||
|
|
||||||
|
On enslavement connected and local routes are automatically moved to the
|
||||||
|
table associated with the VRF device.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip link set dev eth0 master vrf-mgmt
|
||||||
|
|
||||||
|
|
||||||
|
4. Show Devices Assigned to a VRF
|
||||||
|
|
||||||
|
To show devices that have been assigned to a specific VRF add the master
|
||||||
|
option to the ip command:
|
||||||
|
$ ip link show master VRF-NAME
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip link show master vrf-red
|
||||||
|
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
|
||||||
|
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
|
||||||
|
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
|
||||||
|
|
||||||
|
|
||||||
|
Or using the brief output:
|
||||||
|
$ ip -br link show master vrf-red
|
||||||
|
eth1 UP 02:00:00:00:02:02 <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||||
|
eth2 UP 02:00:00:00:02:03 <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||||
|
eth5 DOWN 02:00:00:00:02:06 <BROADCAST,MULTICAST>
|
||||||
|
|
||||||
|
|
||||||
|
5. Show Neighbor Entries for a VRF
|
||||||
|
|
||||||
|
To list neighbor entries associated with devices enslaved to a VRF device
|
||||||
|
add the master option to the ip command:
|
||||||
|
$ ip [-6] neigh show master VRF-NAME
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip neigh show master vrf-red
|
||||||
|
10.2.1.254 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
|
||||||
|
10.2.2.254 dev eth2 lladdr 5e:54:01:6a:ee:80 REACHABLE
|
||||||
|
|
||||||
|
$ ip -6 neigh show master vrf-red
|
||||||
|
2002:1::64 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
|
||||||
|
|
||||||
|
|
||||||
|
6. Show Addresses for a VRF
|
||||||
|
|
||||||
|
To show addresses for interfaces associated with a VRF add the master
|
||||||
|
option to the ip command:
|
||||||
|
$ ip addr show master VRF-NAME
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip addr show master vrf-red
|
||||||
|
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
|
||||||
|
inet 10.2.1.2/24 brd 10.2.1.255 scope global eth1
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 2002:1::2/120 scope global
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 fe80::ff:fe00:202/64 scope link
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
|
||||||
|
inet 10.2.2.2/24 brd 10.2.2.255 scope global eth2
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 2002:2::2/120 scope global
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
inet6 fe80::ff:fe00:203/64 scope link
|
||||||
|
valid_lft forever preferred_lft forever
|
||||||
|
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN group default qlen 1000
|
||||||
|
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
|
||||||
|
|
||||||
|
Or in brief format:
|
||||||
|
$ ip -br addr show master vrf-red
|
||||||
|
eth1 UP 10.2.1.2/24 2002:1::2/120 fe80::ff:fe00:202/64
|
||||||
|
eth2 UP 10.2.2.2/24 2002:2::2/120 fe80::ff:fe00:203/64
|
||||||
|
eth5 DOWN
|
||||||
|
|
||||||
|
|
||||||
|
7. Show Routes for a VRF
|
||||||
|
|
||||||
|
To show routes for a VRF use the ip command to display the table associated
|
||||||
|
with the VRF device:
|
||||||
|
$ ip [-6] route show table ID
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip route show table vrf-red
|
||||||
|
prohibit default
|
||||||
|
broadcast 10.2.1.0 dev eth1 proto kernel scope link src 10.2.1.2
|
||||||
|
10.2.1.0/24 dev eth1 proto kernel scope link src 10.2.1.2
|
||||||
|
local 10.2.1.2 dev eth1 proto kernel scope host src 10.2.1.2
|
||||||
|
broadcast 10.2.1.255 dev eth1 proto kernel scope link src 10.2.1.2
|
||||||
|
broadcast 10.2.2.0 dev eth2 proto kernel scope link src 10.2.2.2
|
||||||
|
10.2.2.0/24 dev eth2 proto kernel scope link src 10.2.2.2
|
||||||
|
local 10.2.2.2 dev eth2 proto kernel scope host src 10.2.2.2
|
||||||
|
broadcast 10.2.2.255 dev eth2 proto kernel scope link src 10.2.2.2
|
||||||
|
|
||||||
|
$ ip -6 route show table vrf-red
|
||||||
|
local 2002:1:: dev lo proto none metric 0 pref medium
|
||||||
|
local 2002:1::2 dev lo proto none metric 0 pref medium
|
||||||
|
2002:1::/120 dev eth1 proto kernel metric 256 pref medium
|
||||||
|
local 2002:2:: dev lo proto none metric 0 pref medium
|
||||||
|
local 2002:2::2 dev lo proto none metric 0 pref medium
|
||||||
|
2002:2::/120 dev eth2 proto kernel metric 256 pref medium
|
||||||
|
local fe80:: dev lo proto none metric 0 pref medium
|
||||||
|
local fe80:: dev lo proto none metric 0 pref medium
|
||||||
|
local fe80::ff:fe00:202 dev lo proto none metric 0 pref medium
|
||||||
|
local fe80::ff:fe00:203 dev lo proto none metric 0 pref medium
|
||||||
|
fe80::/64 dev eth1 proto kernel metric 256 pref medium
|
||||||
|
fe80::/64 dev eth2 proto kernel metric 256 pref medium
|
||||||
|
ff00::/8 dev vrf-red metric 256 pref medium
|
||||||
|
ff00::/8 dev eth1 metric 256 pref medium
|
||||||
|
ff00::/8 dev eth2 metric 256 pref medium
|
||||||
|
|
||||||
|
|
||||||
|
8. Route Lookup for a VRF
|
||||||
|
|
||||||
|
A test route lookup can be done for a VRF by adding the oif option to ip:
|
||||||
|
$ ip [-6] route get oif VRF-NAME ADDRESS
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip route get 10.2.1.40 oif vrf-red
|
||||||
|
10.2.1.40 dev eth1 table vrf-red src 10.2.1.2
|
||||||
|
cache
|
||||||
|
|
||||||
|
$ ip -6 route get 2002:1::32 oif vrf-red
|
||||||
|
2002:1::32 from :: dev eth1 table vrf-red proto kernel src 2002:1::2 metric 256 pref medium
|
||||||
|
|
||||||
|
|
||||||
|
9. Removing Network Interface from a VRF
|
||||||
|
|
||||||
|
Network interfaces are removed from a VRF by breaking the enslavement to
|
||||||
|
the VRF device:
|
||||||
|
$ ip link set dev NAME nomaster
|
||||||
|
|
||||||
|
Connected routes are moved back to the default table and local entries are
|
||||||
|
moved to the local table.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
$ ip link set dev eth0 nomaster
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Commands used in this example:
|
||||||
|
|
||||||
|
cat >> /etc/iproute2/rt_tables <<EOF
|
||||||
|
1 vrf-mgmt
|
||||||
|
10 vrf-red
|
||||||
|
66 vrf-blue
|
||||||
|
81 vrf-green
|
||||||
|
EOF
|
||||||
|
|
||||||
|
function vrf_create
|
||||||
|
{
|
||||||
|
VRF=$1
|
||||||
|
TBID=$2
|
||||||
|
# create VRF device
|
||||||
|
ip link add vrf-${VRF} type vrf table ${TBID}
|
||||||
|
|
||||||
|
# add rules that direct lookups to vrf table
|
||||||
|
ip ru add pref 200 oif vrf-${VRF} table ${TBID}
|
||||||
|
ip ru add pref 200 iif vrf-${VRF} table ${TBID}
|
||||||
|
ip -6 ru add pref 200 oif vrf-${VRF} table ${TBID}
|
||||||
|
ip -6 ru add pref 200 iif vrf-${VRF} table ${TBID}
|
||||||
|
|
||||||
|
if [ "${VRF}" != "mgmt" ]; then
|
||||||
|
ip route add table ${TBID} prohibit default
|
||||||
|
fi
|
||||||
|
ip link set dev vrf-${VRF} up
|
||||||
|
ip link set dev vrf-${VRF} state up
|
||||||
|
}
|
||||||
|
|
||||||
|
vrf_create mgmt 1
|
||||||
|
ip link set dev eth0 master vrf-mgmt
|
||||||
|
|
||||||
|
vrf_create red 10
|
||||||
|
ip link set dev eth1 master vrf-red
|
||||||
|
ip link set dev eth2 master vrf-red
|
||||||
|
ip link set dev eth5 master vrf-red
|
||||||
|
|
||||||
|
vrf_create blue 66
|
||||||
|
ip link set dev eth3 master vrf-blue
|
||||||
|
|
||||||
|
vrf_create green 81
|
||||||
|
ip link set dev eth4 master vrf-green
|
||||||
|
|
||||||
|
|
||||||
|
Interface addresses from /etc/network/interfaces:
|
||||||
|
auto eth0
|
||||||
|
iface eth0 inet static
|
||||||
|
address 10.0.0.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
gateway 10.0.0.254
|
||||||
|
|
||||||
|
iface eth0 inet6 static
|
||||||
|
address 2000:1::2
|
||||||
|
netmask 120
|
||||||
|
|
||||||
|
auto eth1
|
||||||
|
iface eth1 inet static
|
||||||
|
address 10.2.1.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
|
||||||
|
iface eth1 inet6 static
|
||||||
|
address 2002:1::2
|
||||||
|
netmask 120
|
||||||
|
|
||||||
|
auto eth2
|
||||||
|
iface eth2 inet static
|
||||||
|
address 10.2.2.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
|
||||||
|
iface eth2 inet6 static
|
||||||
|
address 2002:2::2
|
||||||
|
netmask 120
|
||||||
|
|
||||||
|
auto eth3
|
||||||
|
iface eth3 inet static
|
||||||
|
address 10.2.3.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
|
||||||
|
iface eth3 inet6 static
|
||||||
|
address 2002:3::2
|
||||||
|
netmask 120
|
||||||
|
|
||||||
|
auto eth4
|
||||||
|
iface eth4 inet static
|
||||||
|
address 10.2.4.2
|
||||||
|
netmask 255.255.255.0
|
||||||
|
|
||||||
|
iface eth4 inet6 static
|
||||||
|
address 2002:4::2
|
||||||
|
netmask 120
|
||||||
|
|
|
@ -5546,7 +5546,7 @@ F: drivers/net/wireless/iwlegacy/
|
||||||
INTEL WIRELESS WIFI LINK (iwlwifi)
|
INTEL WIRELESS WIFI LINK (iwlwifi)
|
||||||
M: Johannes Berg <johannes.berg@intel.com>
|
M: Johannes Berg <johannes.berg@intel.com>
|
||||||
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||||||
M: Intel Linux Wireless <ilw@linux.intel.com>
|
M: Intel Linux Wireless <linuxwifi@intel.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
W: http://intellinuxwireless.org
|
W: http://intellinuxwireless.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
|
||||||
|
@ -6978,6 +6978,7 @@ M: Alan Ott <alan@signal11.us>
|
||||||
L: linux-wpan@vger.kernel.org
|
L: linux-wpan@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/ieee802154/mrf24j40.c
|
F: drivers/net/ieee802154/mrf24j40.c
|
||||||
|
F: Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
|
||||||
|
|
||||||
MSI LAPTOP SUPPORT
|
MSI LAPTOP SUPPORT
|
||||||
M: "Lee, Chun-Yi" <jlee@suse.com>
|
M: "Lee, Chun-Yi" <jlee@suse.com>
|
||||||
|
|
|
@ -125,7 +125,7 @@ static u64 jit_get_skb_w(struct sk_buff *skb, int offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper that handles both OABI and EABI and assures Thumb2 interworking
|
* Wrappers which handle both OABI and EABI and assures Thumb2 interworking
|
||||||
* (where the assembly routines like __aeabi_uidiv could cause problems).
|
* (where the assembly routines like __aeabi_uidiv could cause problems).
|
||||||
*/
|
*/
|
||||||
static u32 jit_udiv(u32 dividend, u32 divisor)
|
static u32 jit_udiv(u32 dividend, u32 divisor)
|
||||||
|
@ -133,6 +133,11 @@ static u32 jit_udiv(u32 dividend, u32 divisor)
|
||||||
return dividend / divisor;
|
return dividend / divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 jit_mod(u32 dividend, u32 divisor)
|
||||||
|
{
|
||||||
|
return dividend % divisor;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
|
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
|
||||||
{
|
{
|
||||||
inst |= (cond << 28);
|
inst |= (cond << 28);
|
||||||
|
@ -471,11 +476,17 @@ static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
|
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx,
|
||||||
|
int bpf_op)
|
||||||
{
|
{
|
||||||
#if __LINUX_ARM_ARCH__ == 7
|
#if __LINUX_ARM_ARCH__ == 7
|
||||||
if (elf_hwcap & HWCAP_IDIVA) {
|
if (elf_hwcap & HWCAP_IDIVA) {
|
||||||
emit(ARM_UDIV(rd, rm, rn), ctx);
|
if (bpf_op == BPF_DIV)
|
||||||
|
emit(ARM_UDIV(rd, rm, rn), ctx);
|
||||||
|
else {
|
||||||
|
emit(ARM_UDIV(ARM_R3, rm, rn), ctx);
|
||||||
|
emit(ARM_MLS(rd, rn, ARM_R3, rm), ctx);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -496,7 +507,8 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
|
||||||
emit(ARM_MOV_R(ARM_R0, rm), ctx);
|
emit(ARM_MOV_R(ARM_R0, rm), ctx);
|
||||||
|
|
||||||
ctx->seen |= SEEN_CALL;
|
ctx->seen |= SEEN_CALL;
|
||||||
emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
|
emit_mov_i(ARM_R3, bpf_op == BPF_DIV ? (u32)jit_udiv : (u32)jit_mod,
|
||||||
|
ctx);
|
||||||
emit_blx_r(ARM_R3, ctx);
|
emit_blx_r(ARM_R3, ctx);
|
||||||
|
|
||||||
if (rd != ARM_R0)
|
if (rd != ARM_R0)
|
||||||
|
@ -697,13 +709,27 @@ load_ind:
|
||||||
if (k == 1)
|
if (k == 1)
|
||||||
break;
|
break;
|
||||||
emit_mov_i(r_scratch, k, ctx);
|
emit_mov_i(r_scratch, k, ctx);
|
||||||
emit_udiv(r_A, r_A, r_scratch, ctx);
|
emit_udivmod(r_A, r_A, r_scratch, ctx, BPF_DIV);
|
||||||
break;
|
break;
|
||||||
case BPF_ALU | BPF_DIV | BPF_X:
|
case BPF_ALU | BPF_DIV | BPF_X:
|
||||||
update_on_xread(ctx);
|
update_on_xread(ctx);
|
||||||
emit(ARM_CMP_I(r_X, 0), ctx);
|
emit(ARM_CMP_I(r_X, 0), ctx);
|
||||||
emit_err_ret(ARM_COND_EQ, ctx);
|
emit_err_ret(ARM_COND_EQ, ctx);
|
||||||
emit_udiv(r_A, r_A, r_X, ctx);
|
emit_udivmod(r_A, r_A, r_X, ctx, BPF_DIV);
|
||||||
|
break;
|
||||||
|
case BPF_ALU | BPF_MOD | BPF_K:
|
||||||
|
if (k == 1) {
|
||||||
|
emit_mov_i(r_A, 0, ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emit_mov_i(r_scratch, k, ctx);
|
||||||
|
emit_udivmod(r_A, r_A, r_scratch, ctx, BPF_MOD);
|
||||||
|
break;
|
||||||
|
case BPF_ALU | BPF_MOD | BPF_X:
|
||||||
|
update_on_xread(ctx);
|
||||||
|
emit(ARM_CMP_I(r_X, 0), ctx);
|
||||||
|
emit_err_ret(ARM_COND_EQ, ctx);
|
||||||
|
emit_udivmod(r_A, r_A, r_X, ctx, BPF_MOD);
|
||||||
break;
|
break;
|
||||||
case BPF_ALU | BPF_OR | BPF_K:
|
case BPF_ALU | BPF_OR | BPF_K:
|
||||||
/* A |= K */
|
/* A |= K */
|
||||||
|
|
|
@ -115,6 +115,8 @@
|
||||||
|
|
||||||
#define ARM_INST_UMULL 0x00800090
|
#define ARM_INST_UMULL 0x00800090
|
||||||
|
|
||||||
|
#define ARM_INST_MLS 0x00600090
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use a suitable undefined instruction to use for ARM/Thumb2 faulting.
|
* Use a suitable undefined instruction to use for ARM/Thumb2 faulting.
|
||||||
* We need to be careful not to conflict with those used by other modules
|
* We need to be careful not to conflict with those used by other modules
|
||||||
|
@ -210,4 +212,7 @@
|
||||||
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
|
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
|
||||||
| (rd_lo) << 12 | (rm) << 8 | rn)
|
| (rd_lo) << 12 | (rm) << 8 | rn)
|
||||||
|
|
||||||
|
#define ARM_MLS(rd, rn, rm, ra) (ARM_INST_MLS | (rd) << 16 | (rn) | (rm) << 8 \
|
||||||
|
| (ra) << 12)
|
||||||
|
|
||||||
#endif /* PFILTER_OPCODES_ARM_H */
|
#endif /* PFILTER_OPCODES_ARM_H */
|
||||||
|
|
|
@ -224,10 +224,12 @@
|
||||||
|
|
||||||
/include/ "pq3-etsec2-0.dtsi"
|
/include/ "pq3-etsec2-0.dtsi"
|
||||||
enet0: enet0_grp2: ethernet@b0000 {
|
enet0: enet0_grp2: ethernet@b0000 {
|
||||||
|
fsl,wake-on-filer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/include/ "pq3-etsec2-1.dtsi"
|
/include/ "pq3-etsec2-1.dtsi"
|
||||||
enet1: enet1_grp2: ethernet@b1000 {
|
enet1: enet1_grp2: ethernet@b1000 {
|
||||||
|
fsl,wake-on-filer;
|
||||||
};
|
};
|
||||||
|
|
||||||
global-utilities@e0000 {
|
global-utilities@e0000 {
|
||||||
|
|
|
@ -112,7 +112,8 @@ static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data)
|
||||||
|
|
||||||
static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
|
static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
|
||||||
IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
if (!entry) return -1;
|
if (!entry)
|
||||||
|
return -ENOMEM;
|
||||||
entry->data = data;
|
entry->data = data;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
if (que->next == NULL)
|
if (que->next == NULL)
|
||||||
|
@ -1175,7 +1176,7 @@ static int rx_pkt(struct atm_dev *dev)
|
||||||
if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) {
|
if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) {
|
||||||
if (vcc->vci < 32)
|
if (vcc->vci < 32)
|
||||||
printk("Drop control packets\n");
|
printk("Drop control packets\n");
|
||||||
goto out_free_desc;
|
goto out_free_desc;
|
||||||
}
|
}
|
||||||
skb_put(skb,len);
|
skb_put(skb,len);
|
||||||
// pwang_test
|
// pwang_test
|
||||||
|
|
|
@ -98,6 +98,8 @@ struct regmap {
|
||||||
|
|
||||||
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
|
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
|
||||||
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
|
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
|
||||||
|
int (*reg_update_bits)(void *context, unsigned int reg,
|
||||||
|
unsigned int mask, unsigned int val);
|
||||||
|
|
||||||
bool defer_caching;
|
bool defer_caching;
|
||||||
|
|
||||||
|
|
|
@ -619,6 +619,7 @@ struct regmap *__regmap_init(struct device *dev,
|
||||||
goto skip_format_initialization;
|
goto skip_format_initialization;
|
||||||
} else {
|
} else {
|
||||||
map->reg_read = _regmap_bus_read;
|
map->reg_read = _regmap_bus_read;
|
||||||
|
map->reg_update_bits = bus->reg_update_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_endian = regmap_get_reg_endian(bus, config);
|
reg_endian = regmap_get_reg_endian(bus, config);
|
||||||
|
@ -2509,20 +2510,26 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int tmp, orig;
|
unsigned int tmp, orig;
|
||||||
|
|
||||||
ret = _regmap_read(map, reg, &orig);
|
if (change)
|
||||||
if (ret != 0)
|
*change = false;
|
||||||
return ret;
|
|
||||||
|
|
||||||
tmp = orig & ~mask;
|
if (regmap_volatile(map, reg) && map->reg_update_bits) {
|
||||||
tmp |= val & mask;
|
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
|
||||||
|
if (ret == 0 && change)
|
||||||
if (force_write || (tmp != orig)) {
|
|
||||||
ret = _regmap_write(map, reg, tmp);
|
|
||||||
if (change)
|
|
||||||
*change = true;
|
*change = true;
|
||||||
} else {
|
} else {
|
||||||
if (change)
|
ret = _regmap_read(map, reg, &orig);
|
||||||
*change = false;
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tmp = orig & ~mask;
|
||||||
|
tmp |= val & mask;
|
||||||
|
|
||||||
|
if (force_write || (tmp != orig)) {
|
||||||
|
ret = _regmap_write(map, reg, tmp);
|
||||||
|
if (ret == 0 && change)
|
||||||
|
*change = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -436,13 +436,8 @@ int bcma_bus_register(struct bcma_bus *bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = bcma_bus_get_host_dev(bus);
|
dev = bcma_bus_get_host_dev(bus);
|
||||||
/* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when
|
if (dev) {
|
||||||
* of_default_bus_match_table is exported or in some other way
|
of_platform_default_populate(dev->of_node, NULL, dev);
|
||||||
* accessible. This is just a temporary workaround.
|
|
||||||
*/
|
|
||||||
if (IS_BUILTIN(CONFIG_BCMA) && dev) {
|
|
||||||
of_platform_populate(dev->of_node, of_default_bus_match_table,
|
|
||||||
NULL, dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cores providing flash access go before SPROM init */
|
/* Cores providing flash access go before SPROM init */
|
||||||
|
|
|
@ -4,6 +4,7 @@ menu "Bluetooth device drivers"
|
||||||
|
|
||||||
config BT_INTEL
|
config BT_INTEL
|
||||||
tristate
|
tristate
|
||||||
|
select REGMAP
|
||||||
|
|
||||||
config BT_BCM
|
config BT_BCM
|
||||||
tristate
|
tristate
|
||||||
|
@ -183,6 +184,7 @@ config BT_HCIBCM203X
|
||||||
config BT_HCIBPA10X
|
config BT_HCIBPA10X
|
||||||
tristate "HCI BPA10x USB driver"
|
tristate "HCI BPA10x USB driver"
|
||||||
depends on USB
|
depends on USB
|
||||||
|
select BT_HCIUART_H4
|
||||||
help
|
help
|
||||||
Bluetooth HCI BPA10x USB driver.
|
Bluetooth HCI BPA10x USB driver.
|
||||||
This driver provides support for the Digianswer BPA 100/105 Bluetooth
|
This driver provides support for the Digianswer BPA 100/105 Bluetooth
|
||||||
|
@ -275,7 +277,7 @@ config BT_MRVL
|
||||||
The core driver to support Marvell Bluetooth devices.
|
The core driver to support Marvell Bluetooth devices.
|
||||||
|
|
||||||
This driver is required if you want to support
|
This driver is required if you want to support
|
||||||
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
|
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997.
|
||||||
|
|
||||||
Say Y here to compile Marvell Bluetooth driver
|
Say Y here to compile Marvell Bluetooth driver
|
||||||
into the kernel or say M to compile it as module.
|
into the kernel or say M to compile it as module.
|
||||||
|
@ -289,7 +291,7 @@ config BT_MRVL_SDIO
|
||||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||||
|
|
||||||
This driver is required if you want to use Marvell Bluetooth
|
This driver is required if you want to use Marvell Bluetooth
|
||||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
|
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997
|
||||||
chipsets are supported.
|
chipsets are supported.
|
||||||
|
|
||||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||||
|
|
|
@ -422,17 +422,12 @@ static int bfusb_open(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("hdev %p bfusb %p", hdev, data);
|
BT_DBG("hdev %p bfusb %p", hdev, data);
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
write_lock_irqsave(&data->lock, flags);
|
write_lock_irqsave(&data->lock, flags);
|
||||||
|
|
||||||
err = bfusb_rx_submit(data, NULL);
|
err = bfusb_rx_submit(data, NULL);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
|
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
|
||||||
bfusb_rx_submit(data, NULL);
|
bfusb_rx_submit(data, NULL);
|
||||||
} else {
|
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write_unlock_irqrestore(&data->lock, flags);
|
write_unlock_irqrestore(&data->lock, flags);
|
||||||
|
@ -458,9 +453,6 @@ static int bfusb_close(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("hdev %p bfusb %p", hdev, data);
|
BT_DBG("hdev %p bfusb %p", hdev, data);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
write_lock_irqsave(&data->lock, flags);
|
write_lock_irqsave(&data->lock, flags);
|
||||||
write_unlock_irqrestore(&data->lock, flags);
|
write_unlock_irqrestore(&data->lock, flags);
|
||||||
|
|
||||||
|
@ -479,9 +471,6 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
|
BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
switch (bt_cb(skb)->pkt_type) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
hdev->stat.cmd_tx++;
|
hdev->stat.cmd_tx++;
|
||||||
|
|
|
@ -390,7 +390,7 @@ static void bluecard_receive(struct bluecard_info *info,
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
|
||||||
/* Allocate packet */
|
/* Allocate packet */
|
||||||
if (info->rx_skb == NULL) {
|
if (!info->rx_skb) {
|
||||||
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
||||||
info->rx_count = 0;
|
info->rx_count = 0;
|
||||||
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
||||||
|
@ -628,9 +628,6 @@ static int bluecard_hci_open(struct hci_dev *hdev)
|
||||||
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
|
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
|
||||||
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
|
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
|
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
|
||||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||||
|
|
||||||
|
@ -646,9 +643,6 @@ static int bluecard_hci_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
bluecard_hci_flush(hdev);
|
bluecard_hci_flush(hdev);
|
||||||
|
|
||||||
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
|
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
|
||||||
|
|
|
@ -35,7 +35,9 @@
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
|
|
||||||
#define VERSION "0.10"
|
#include "hci_uart.h"
|
||||||
|
|
||||||
|
#define VERSION "0.11"
|
||||||
|
|
||||||
static const struct usb_device_id bpa10x_table[] = {
|
static const struct usb_device_id bpa10x_table[] = {
|
||||||
/* Tektronix BPA 100/105 (Digianswer) */
|
/* Tektronix BPA 100/105 (Digianswer) */
|
||||||
|
@ -56,112 +58,6 @@ struct bpa10x_data {
|
||||||
struct sk_buff *rx_skb[2];
|
struct sk_buff *rx_skb[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HCI_VENDOR_HDR_SIZE 5
|
|
||||||
|
|
||||||
struct hci_vendor_hdr {
|
|
||||||
__u8 type;
|
|
||||||
__le16 snum;
|
|
||||||
__le16 dlen;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
|
|
||||||
{
|
|
||||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
|
||||||
|
|
||||||
BT_DBG("%s queue %d buffer %p count %d", hdev->name,
|
|
||||||
queue, buf, count);
|
|
||||||
|
|
||||||
if (queue < 0 || queue > 1)
|
|
||||||
return -EILSEQ;
|
|
||||||
|
|
||||||
hdev->stat.byte_rx += count;
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
struct sk_buff *skb = data->rx_skb[queue];
|
|
||||||
struct { __u8 type; int expect; } *scb;
|
|
||||||
int type, len = 0;
|
|
||||||
|
|
||||||
if (!skb) {
|
|
||||||
/* Start of the frame */
|
|
||||||
|
|
||||||
type = *((__u8 *) buf);
|
|
||||||
count--; buf++;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case HCI_EVENT_PKT:
|
|
||||||
if (count >= HCI_EVENT_HDR_SIZE) {
|
|
||||||
struct hci_event_hdr *h = buf;
|
|
||||||
len = HCI_EVENT_HDR_SIZE + h->plen;
|
|
||||||
} else
|
|
||||||
return -EILSEQ;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_ACLDATA_PKT:
|
|
||||||
if (count >= HCI_ACL_HDR_SIZE) {
|
|
||||||
struct hci_acl_hdr *h = buf;
|
|
||||||
len = HCI_ACL_HDR_SIZE +
|
|
||||||
__le16_to_cpu(h->dlen);
|
|
||||||
} else
|
|
||||||
return -EILSEQ;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_SCODATA_PKT:
|
|
||||||
if (count >= HCI_SCO_HDR_SIZE) {
|
|
||||||
struct hci_sco_hdr *h = buf;
|
|
||||||
len = HCI_SCO_HDR_SIZE + h->dlen;
|
|
||||||
} else
|
|
||||||
return -EILSEQ;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_VENDOR_PKT:
|
|
||||||
if (count >= HCI_VENDOR_HDR_SIZE) {
|
|
||||||
struct hci_vendor_hdr *h = buf;
|
|
||||||
len = HCI_VENDOR_HDR_SIZE +
|
|
||||||
__le16_to_cpu(h->dlen);
|
|
||||||
} else
|
|
||||||
return -EILSEQ;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
|
||||||
if (!skb) {
|
|
||||||
BT_ERR("%s no memory for packet", hdev->name);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->rx_skb[queue] = skb;
|
|
||||||
|
|
||||||
scb = (void *) skb->cb;
|
|
||||||
scb->type = type;
|
|
||||||
scb->expect = len;
|
|
||||||
} else {
|
|
||||||
/* Continuation */
|
|
||||||
|
|
||||||
scb = (void *) skb->cb;
|
|
||||||
len = scb->expect;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = min(len, count);
|
|
||||||
|
|
||||||
memcpy(skb_put(skb, len), buf, len);
|
|
||||||
|
|
||||||
scb->expect -= len;
|
|
||||||
|
|
||||||
if (scb->expect == 0) {
|
|
||||||
/* Complete frame */
|
|
||||||
|
|
||||||
data->rx_skb[queue] = NULL;
|
|
||||||
|
|
||||||
bt_cb(skb)->pkt_type = scb->type;
|
|
||||||
hci_recv_frame(hdev, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
count -= len; buf += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bpa10x_tx_complete(struct urb *urb)
|
static void bpa10x_tx_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = urb->context;
|
struct sk_buff *skb = urb->context;
|
||||||
|
@ -184,6 +80,22 @@ done:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HCI_VENDOR_HDR_SIZE 5
|
||||||
|
|
||||||
|
#define HCI_RECV_VENDOR \
|
||||||
|
.type = HCI_VENDOR_PKT, \
|
||||||
|
.hlen = HCI_VENDOR_HDR_SIZE, \
|
||||||
|
.loff = 3, \
|
||||||
|
.lsize = 2, \
|
||||||
|
.maxlen = HCI_MAX_FRAME_SIZE
|
||||||
|
|
||||||
|
static const struct h4_recv_pkt bpa10x_recv_pkts[] = {
|
||||||
|
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
||||||
|
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||||
|
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
||||||
|
{ HCI_RECV_VENDOR, .recv = hci_recv_diag },
|
||||||
|
};
|
||||||
|
|
||||||
static void bpa10x_rx_complete(struct urb *urb)
|
static void bpa10x_rx_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = urb->context;
|
struct hci_dev *hdev = urb->context;
|
||||||
|
@ -197,11 +109,17 @@ static void bpa10x_rx_complete(struct urb *urb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (urb->status == 0) {
|
if (urb->status == 0) {
|
||||||
if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
|
bool idx = usb_pipebulk(urb->pipe);
|
||||||
|
|
||||||
|
data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx],
|
||||||
urb->transfer_buffer,
|
urb->transfer_buffer,
|
||||||
urb->actual_length) < 0) {
|
urb->actual_length,
|
||||||
|
bpa10x_recv_pkts,
|
||||||
|
ARRAY_SIZE(bpa10x_recv_pkts));
|
||||||
|
if (IS_ERR(data->rx_skb[idx])) {
|
||||||
BT_ERR("%s corrupted event packet", hdev->name);
|
BT_ERR("%s corrupted event packet", hdev->name);
|
||||||
hdev->stat.err_rx++;
|
hdev->stat.err_rx++;
|
||||||
|
data->rx_skb[idx] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,9 +222,6 @@ static int bpa10x_open(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err = bpa10x_submit_intr_urb(hdev);
|
err = bpa10x_submit_intr_urb(hdev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -320,8 +235,6 @@ static int bpa10x_open(struct hci_dev *hdev)
|
||||||
error:
|
error:
|
||||||
usb_kill_anchored_urbs(&data->rx_anchor);
|
usb_kill_anchored_urbs(&data->rx_anchor);
|
||||||
|
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,9 +244,6 @@ static int bpa10x_close(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
usb_kill_anchored_urbs(&data->rx_anchor);
|
usb_kill_anchored_urbs(&data->rx_anchor);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -350,6 +260,24 @@ static int bpa10x_flush(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpa10x_setup(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
const u8 req[] = { 0x07 };
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
/* Read revision string */
|
||||||
|
skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
|
||||||
|
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||||
|
@ -360,9 +288,6 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
skb->dev = (void *) hdev;
|
skb->dev = (void *) hdev;
|
||||||
|
|
||||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||||
|
@ -431,6 +356,25 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
|
||||||
|
{
|
||||||
|
const u8 req[] = { 0x00, enable };
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
|
return -ENETDOWN;
|
||||||
|
|
||||||
|
/* Enable sniffer operation */
|
||||||
|
skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
struct bpa10x_data *data;
|
struct bpa10x_data *data;
|
||||||
|
@ -465,7 +409,9 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||||
hdev->open = bpa10x_open;
|
hdev->open = bpa10x_open;
|
||||||
hdev->close = bpa10x_close;
|
hdev->close = bpa10x_close;
|
||||||
hdev->flush = bpa10x_flush;
|
hdev->flush = bpa10x_flush;
|
||||||
|
hdev->setup = bpa10x_setup;
|
||||||
hdev->send = bpa10x_send_frame;
|
hdev->send = bpa10x_send_frame;
|
||||||
|
hdev->set_diag = bpa10x_set_diag;
|
||||||
|
|
||||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ static void bt3c_receive(struct bt3c_info *info)
|
||||||
info->hdev->stat.byte_rx++;
|
info->hdev->stat.byte_rx++;
|
||||||
|
|
||||||
/* Allocate packet */
|
/* Allocate packet */
|
||||||
if (info->rx_skb == NULL) {
|
if (!info->rx_skb) {
|
||||||
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
||||||
info->rx_count = 0;
|
info->rx_count = 0;
|
||||||
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
||||||
|
@ -270,7 +270,6 @@ static void bt3c_receive(struct bt3c_info *info)
|
||||||
/* Unknown packet */
|
/* Unknown packet */
|
||||||
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
|
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
|
||||||
info->hdev->stat.err_rx++;
|
info->hdev->stat.err_rx++;
|
||||||
clear_bit(HCI_RUNNING, &(info->hdev->flags));
|
|
||||||
|
|
||||||
kfree_skb(info->rx_skb);
|
kfree_skb(info->rx_skb);
|
||||||
info->rx_skb = NULL;
|
info->rx_skb = NULL;
|
||||||
|
@ -395,17 +394,12 @@ static int bt3c_hci_flush(struct hci_dev *hdev)
|
||||||
|
|
||||||
static int bt3c_hci_open(struct hci_dev *hdev)
|
static int bt3c_hci_open(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
set_bit(HCI_RUNNING, &(hdev->flags));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int bt3c_hci_close(struct hci_dev *hdev)
|
static int bt3c_hci_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
bt3c_hci_flush(hdev);
|
bt3c_hci_flush(hdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -181,6 +181,27 @@ static int btbcm_reset(struct hci_dev *hdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
|
||||||
|
HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
BT_ERR("%s: BCM: Reading local name failed (%ld)",
|
||||||
|
hdev->name, PTR_ERR(skb));
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skb->len != sizeof(struct hci_rp_read_local_name)) {
|
||||||
|
BT_ERR("%s: BCM: Local name length mismatch", hdev->name);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return ERR_PTR(-EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
|
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
@ -393,6 +414,14 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
|
||||||
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
|
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
/* Read Local Name */
|
||||||
|
skb = btbcm_read_local_name(hdev);
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
|
||||||
|
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
switch ((rev & 0xf000) >> 12) {
|
switch ((rev & 0xf000) >> 12) {
|
||||||
case 0:
|
case 0:
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -464,6 +493,14 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
|
||||||
hw_name ? : "BCM", (subver & 0x7000) >> 13,
|
hw_name ? : "BCM", (subver & 0x7000) >> 13,
|
||||||
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
|
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
|
||||||
|
|
||||||
|
/* Read Local Name */
|
||||||
|
skb = btbcm_read_local_name(hdev);
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
|
||||||
|
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
btbcm_check_bdaddr(hdev);
|
btbcm_check_bdaddr(hdev);
|
||||||
|
|
||||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||||
|
@ -475,12 +512,25 @@ EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
|
||||||
int btbcm_setup_apple(struct hci_dev *hdev)
|
int btbcm_setup_apple(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
|
err = btbcm_reset(hdev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
/* Read Verbose Config Version Info */
|
/* Read Verbose Config Version Info */
|
||||||
skb = btbcm_read_verbose_config(hdev);
|
skb = btbcm_read_verbose_config(hdev);
|
||||||
if (!IS_ERR(skb)) {
|
if (!IS_ERR(skb)) {
|
||||||
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
|
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name,
|
||||||
get_unaligned_le16(skb->data + 5));
|
skb->data[1], get_unaligned_le16(skb->data + 5));
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read Local Name */
|
||||||
|
skb = btbcm_read_local_name(hdev);
|
||||||
|
if (!IS_ERR(skb)) {
|
||||||
|
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
|
@ -215,6 +216,201 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(btintel_load_ddc_config);
|
EXPORT_SYMBOL_GPL(btintel_load_ddc_config);
|
||||||
|
|
||||||
|
/* ------- REGMAP IBT SUPPORT ------- */
|
||||||
|
|
||||||
|
#define IBT_REG_MODE_8BIT 0x00
|
||||||
|
#define IBT_REG_MODE_16BIT 0x01
|
||||||
|
#define IBT_REG_MODE_32BIT 0x02
|
||||||
|
|
||||||
|
struct regmap_ibt_context {
|
||||||
|
struct hci_dev *hdev;
|
||||||
|
__u16 op_write;
|
||||||
|
__u16 op_read;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ibt_cp_reg_access {
|
||||||
|
__le32 addr;
|
||||||
|
__u8 mode;
|
||||||
|
__u8 len;
|
||||||
|
__u8 data[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ibt_rp_reg_access {
|
||||||
|
__u8 status;
|
||||||
|
__le32 addr;
|
||||||
|
__u8 data[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static int regmap_ibt_read(void *context, const void *addr, size_t reg_size,
|
||||||
|
void *val, size_t val_size)
|
||||||
|
{
|
||||||
|
struct regmap_ibt_context *ctx = context;
|
||||||
|
struct ibt_cp_reg_access cp;
|
||||||
|
struct ibt_rp_reg_access *rp;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (reg_size != sizeof(__le32))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (val_size) {
|
||||||
|
case 1:
|
||||||
|
cp.mode = IBT_REG_MODE_8BIT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cp.mode = IBT_REG_MODE_16BIT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cp.mode = IBT_REG_MODE_32BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* regmap provides a little-endian formatted addr */
|
||||||
|
cp.addr = *(__le32 *)addr;
|
||||||
|
cp.len = val_size;
|
||||||
|
|
||||||
|
bt_dev_dbg(ctx->hdev, "Register (0x%x) read", le32_to_cpu(cp.addr));
|
||||||
|
|
||||||
|
skb = hci_cmd_sync(ctx->hdev, ctx->op_read, sizeof(cp), &cp,
|
||||||
|
HCI_CMD_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
err = PTR_ERR(skb);
|
||||||
|
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error (%d)",
|
||||||
|
le32_to_cpu(cp.addr), err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skb->len != sizeof(*rp) + val_size) {
|
||||||
|
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad len",
|
||||||
|
le32_to_cpu(cp.addr));
|
||||||
|
err = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rp = (struct ibt_rp_reg_access *)skb->data;
|
||||||
|
|
||||||
|
if (rp->addr != cp.addr) {
|
||||||
|
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad addr",
|
||||||
|
le32_to_cpu(rp->addr));
|
||||||
|
err = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(val, rp->data, val_size);
|
||||||
|
|
||||||
|
done:
|
||||||
|
kfree_skb(skb);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int regmap_ibt_gather_write(void *context,
|
||||||
|
const void *addr, size_t reg_size,
|
||||||
|
const void *val, size_t val_size)
|
||||||
|
{
|
||||||
|
struct regmap_ibt_context *ctx = context;
|
||||||
|
struct ibt_cp_reg_access *cp;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int plen = sizeof(*cp) + val_size;
|
||||||
|
u8 mode;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (reg_size != sizeof(__le32))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (val_size) {
|
||||||
|
case 1:
|
||||||
|
mode = IBT_REG_MODE_8BIT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mode = IBT_REG_MODE_16BIT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mode = IBT_REG_MODE_32BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = kmalloc(plen, GFP_KERNEL);
|
||||||
|
if (!cp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* regmap provides a little-endian formatted addr/value */
|
||||||
|
cp->addr = *(__le32 *)addr;
|
||||||
|
cp->mode = mode;
|
||||||
|
cp->len = val_size;
|
||||||
|
memcpy(&cp->data, val, val_size);
|
||||||
|
|
||||||
|
bt_dev_dbg(ctx->hdev, "Register (0x%x) write", le32_to_cpu(cp->addr));
|
||||||
|
|
||||||
|
skb = hci_cmd_sync(ctx->hdev, ctx->op_write, plen, cp, HCI_CMD_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
err = PTR_ERR(skb);
|
||||||
|
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) write error (%d)",
|
||||||
|
le32_to_cpu(cp->addr), err);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
done:
|
||||||
|
kfree(cp);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int regmap_ibt_write(void *context, const void *data, size_t count)
|
||||||
|
{
|
||||||
|
/* data contains register+value, since we only support 32bit addr,
|
||||||
|
* minimum data size is 4 bytes.
|
||||||
|
*/
|
||||||
|
if (WARN_ONCE(count < 4, "Invalid register access"))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return regmap_ibt_gather_write(context, data, 4, data + 4, count - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void regmap_ibt_free_context(void *context)
|
||||||
|
{
|
||||||
|
kfree(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct regmap_bus regmap_ibt = {
|
||||||
|
.read = regmap_ibt_read,
|
||||||
|
.write = regmap_ibt_write,
|
||||||
|
.gather_write = regmap_ibt_gather_write,
|
||||||
|
.free_context = regmap_ibt_free_context,
|
||||||
|
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
|
||||||
|
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Config is the same for all register regions */
|
||||||
|
static const struct regmap_config regmap_ibt_cfg = {
|
||||||
|
.name = "btintel_regmap",
|
||||||
|
.reg_bits = 32,
|
||||||
|
.val_bits = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
||||||
|
u16 opcode_write)
|
||||||
|
{
|
||||||
|
struct regmap_ibt_context *ctx;
|
||||||
|
|
||||||
|
bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read,
|
||||||
|
opcode_write);
|
||||||
|
|
||||||
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||||
|
if (!ctx)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
ctx->op_read = opcode_read;
|
||||||
|
ctx->op_write = opcode_write;
|
||||||
|
ctx->hdev = hdev;
|
||||||
|
|
||||||
|
return regmap_init(&hdev->dev, ®map_ibt, ctx, ®map_ibt_cfg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(btintel_regmap_init);
|
||||||
|
|
||||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||||
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
|
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
|
||||||
MODULE_VERSION(VERSION);
|
MODULE_VERSION(VERSION);
|
||||||
|
|
|
@ -80,6 +80,9 @@ int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
|
||||||
const void *param);
|
const void *param);
|
||||||
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
|
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
|
||||||
|
|
||||||
|
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
||||||
|
u16 opcode_write);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
|
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||||
|
@ -113,4 +116,10 @@ static inline int btintel_load_ddc_config(struct hci_dev *hdev,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
|
||||||
|
u16 opcode_read,
|
||||||
|
u16 opcode_write)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -184,7 +184,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
|
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
|
||||||
if (skb == NULL) {
|
if (!skb) {
|
||||||
BT_ERR("No free skb");
|
BT_ERR("No free skb");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -436,13 +436,6 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
|
BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
|
||||||
BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
|
|
||||||
print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
|
|
||||||
skb->data, skb->len);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
switch (bt_cb(skb)->pkt_type) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
hdev->stat.cmd_tx++;
|
hdev->stat.cmd_tx++;
|
||||||
|
@ -477,9 +470,6 @@ static int btmrvl_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
skb_queue_purge(&priv->adapter->tx_queue);
|
skb_queue_purge(&priv->adapter->tx_queue);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -487,8 +477,6 @@ static int btmrvl_close(struct hci_dev *hdev)
|
||||||
|
|
||||||
static int btmrvl_open(struct hci_dev *hdev)
|
static int btmrvl_open(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
set_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,29 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
|
||||||
.fw_dump_end = 0xea,
|
.fw_dump_end = 0xea,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
|
||||||
|
.cfg = 0x00,
|
||||||
|
.host_int_mask = 0x08,
|
||||||
|
.host_intstatus = 0x0c,
|
||||||
|
.card_status = 0x5c,
|
||||||
|
.sq_read_base_addr_a0 = 0xf8,
|
||||||
|
.sq_read_base_addr_a1 = 0xf9,
|
||||||
|
.card_revision = 0xc8,
|
||||||
|
.card_fw_status0 = 0xe8,
|
||||||
|
.card_fw_status1 = 0xe9,
|
||||||
|
.card_rx_len = 0xea,
|
||||||
|
.card_rx_unit = 0xeb,
|
||||||
|
.io_port_0 = 0xe4,
|
||||||
|
.io_port_1 = 0xe5,
|
||||||
|
.io_port_2 = 0xe6,
|
||||||
|
.int_read_to_clear = true,
|
||||||
|
.host_int_rsr = 0x04,
|
||||||
|
.card_misc_cfg = 0xD8,
|
||||||
|
.fw_dump_ctrl = 0xf0,
|
||||||
|
.fw_dump_start = 0xf1,
|
||||||
|
.fw_dump_end = 0xf8,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||||
.helper = "mrvl/sd8688_helper.bin",
|
.helper = "mrvl/sd8688_helper.bin",
|
||||||
.firmware = "mrvl/sd8688.bin",
|
.firmware = "mrvl/sd8688.bin",
|
||||||
|
@ -191,25 +214,37 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
||||||
.supports_fw_dump = true,
|
.supports_fw_dump = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
|
||||||
|
.helper = NULL,
|
||||||
|
.firmware = "mrvl/sd8997_uapsta.bin",
|
||||||
|
.reg = &btmrvl_reg_8997,
|
||||||
|
.support_pscan_win_report = true,
|
||||||
|
.sd_blksz_fw_dl = 256,
|
||||||
|
.supports_fw_dump = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||||
/* Marvell SD8688 Bluetooth device */
|
/* Marvell SD8688 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8688 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8688 },
|
||||||
/* Marvell SD8787 Bluetooth device */
|
/* Marvell SD8787 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
|
||||||
/* Marvell SD8787 Bluetooth AMP device */
|
/* Marvell SD8787 Bluetooth AMP device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
|
||||||
/* Marvell SD8797 Bluetooth device */
|
/* Marvell SD8797 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8797 },
|
||||||
/* Marvell SD8887 Bluetooth device */
|
/* Marvell SD8887 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
|
||||||
.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
|
||||||
/* Marvell SD8897 Bluetooth device */
|
/* Marvell SD8897 Bluetooth device */
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
|
||||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
|
||||||
|
/* Marvell SD8997 Bluetooth device */
|
||||||
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142),
|
||||||
|
.driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
|
||||||
|
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
@ -619,7 +654,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
|
||||||
|
|
||||||
/* Allocate buffer */
|
/* Allocate buffer */
|
||||||
skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
|
skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
|
||||||
if (skb == NULL) {
|
if (!skb) {
|
||||||
BT_ERR("No free skb");
|
BT_ERR("No free skb");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -1278,6 +1313,12 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
|
||||||
|
|
||||||
if (memory_size == 0) {
|
if (memory_size == 0) {
|
||||||
BT_INFO("Firmware dump finished!");
|
BT_INFO("Firmware dump finished!");
|
||||||
|
sdio_writeb(card->func, FW_DUMP_READ_DONE,
|
||||||
|
card->reg->fw_dump_ctrl, &ret);
|
||||||
|
if (ret) {
|
||||||
|
BT_ERR("SDIO Write MEMDUMP_FINISH ERR");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1616,3 +1657,4 @@ MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
|
||||||
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
|
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
|
||||||
|
MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");
|
||||||
|
|
|
@ -194,21 +194,15 @@ static int btsdio_open(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sdio_claim_host(data->func);
|
sdio_claim_host(data->func);
|
||||||
|
|
||||||
err = sdio_enable_func(data->func);
|
err = sdio_enable_func(data->func);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
goto release;
|
goto release;
|
||||||
}
|
|
||||||
|
|
||||||
err = sdio_claim_irq(data->func, btsdio_interrupt);
|
err = sdio_claim_irq(data->func, btsdio_interrupt);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
sdio_disable_func(data->func);
|
sdio_disable_func(data->func);
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,9 +223,6 @@ static int btsdio_close(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sdio_claim_host(data->func);
|
sdio_claim_host(data->func);
|
||||||
|
|
||||||
sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
|
sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
|
||||||
|
@ -261,9 +252,6 @@ static int btsdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
switch (bt_cb(skb)->pkt_type) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
hdev->stat.cmd_tx++;
|
hdev->stat.cmd_tx++;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/serial_reg.h>
|
#include <linux/serial_reg.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <asm/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
#include <pcmcia/cistpl.h>
|
#include <pcmcia/cistpl.h>
|
||||||
#include <pcmcia/ciscode.h>
|
#include <pcmcia/ciscode.h>
|
||||||
|
@ -188,7 +188,7 @@ static void btuart_receive(struct btuart_info *info)
|
||||||
info->hdev->stat.byte_rx++;
|
info->hdev->stat.byte_rx++;
|
||||||
|
|
||||||
/* Allocate packet */
|
/* Allocate packet */
|
||||||
if (info->rx_skb == NULL) {
|
if (!info->rx_skb) {
|
||||||
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
info->rx_state = RECV_WAIT_PACKET_TYPE;
|
||||||
info->rx_count = 0;
|
info->rx_count = 0;
|
||||||
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
||||||
|
@ -223,7 +223,6 @@ static void btuart_receive(struct btuart_info *info)
|
||||||
/* Unknown packet */
|
/* Unknown packet */
|
||||||
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
|
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
|
||||||
info->hdev->stat.err_rx++;
|
info->hdev->stat.err_rx++;
|
||||||
clear_bit(HCI_RUNNING, &(info->hdev->flags));
|
|
||||||
|
|
||||||
kfree_skb(info->rx_skb);
|
kfree_skb(info->rx_skb);
|
||||||
info->rx_skb = NULL;
|
info->rx_skb = NULL;
|
||||||
|
@ -409,17 +408,12 @@ static int btuart_hci_flush(struct hci_dev *hdev)
|
||||||
|
|
||||||
static int btuart_hci_open(struct hci_dev *hdev)
|
static int btuart_hci_open(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
set_bit(HCI_RUNNING, &(hdev->flags));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int btuart_hci_close(struct hci_dev *hdev)
|
static int btuart_hci_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
btuart_hci_flush(hdev);
|
btuart_hci_flush(hdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -940,9 +940,6 @@ static int btusb_open(struct hci_dev *hdev)
|
||||||
|
|
||||||
data->intf->needs_remote_wakeup = 1;
|
data->intf->needs_remote_wakeup = 1;
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
|
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -965,7 +962,6 @@ done:
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
usb_autopm_put_interface(data->intf);
|
usb_autopm_put_interface(data->intf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -984,9 +980,6 @@ static int btusb_close(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cancel_work_sync(&data->work);
|
cancel_work_sync(&data->work);
|
||||||
cancel_work_sync(&data->waker);
|
cancel_work_sync(&data->waker);
|
||||||
|
|
||||||
|
@ -1156,9 +1149,6 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
switch (bt_cb(skb)->pkt_type) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
urb = alloc_ctrl_urb(hdev, skb);
|
urb = alloc_ctrl_urb(hdev, skb);
|
||||||
|
@ -1843,9 +1833,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
switch (bt_cb(skb)->pkt_type) {
|
switch (bt_cb(skb)->pkt_type) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
|
if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
|
||||||
|
|
|
@ -155,9 +155,6 @@ static int ti_st_open(struct hci_dev *hdev)
|
||||||
|
|
||||||
BT_DBG("%s %p", hdev->name, hdev);
|
BT_DBG("%s %p", hdev->name, hdev);
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/* provide contexts for callbacks from ST */
|
/* provide contexts for callbacks from ST */
|
||||||
hst = hci_get_drvdata(hdev);
|
hst = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
|
@ -181,7 +178,6 @@ static int ti_st_open(struct hci_dev *hdev)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (err != -EINPROGRESS) {
|
if (err != -EINPROGRESS) {
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
BT_ERR("st_register failed %d", err);
|
BT_ERR("st_register failed %d", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +191,6 @@ static int ti_st_open(struct hci_dev *hdev)
|
||||||
(&hst->wait_reg_completion,
|
(&hst->wait_reg_completion,
|
||||||
msecs_to_jiffies(BT_REGISTER_TIMEOUT));
|
msecs_to_jiffies(BT_REGISTER_TIMEOUT));
|
||||||
if (!timeleft) {
|
if (!timeleft) {
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
BT_ERR("Timeout(%d sec),didn't get reg "
|
BT_ERR("Timeout(%d sec),didn't get reg "
|
||||||
"completion signal from ST",
|
"completion signal from ST",
|
||||||
BT_REGISTER_TIMEOUT / 1000);
|
BT_REGISTER_TIMEOUT / 1000);
|
||||||
|
@ -205,7 +200,6 @@ static int ti_st_open(struct hci_dev *hdev)
|
||||||
/* Is ST registration callback
|
/* Is ST registration callback
|
||||||
* called with ERROR status? */
|
* called with ERROR status? */
|
||||||
if (hst->reg_status != 0) {
|
if (hst->reg_status != 0) {
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
BT_ERR("ST registration completed with invalid "
|
BT_ERR("ST registration completed with invalid "
|
||||||
"status %d", hst->reg_status);
|
"status %d", hst->reg_status);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
@ -215,7 +209,6 @@ done:
|
||||||
hst->st_write = ti_st_proto[i].write;
|
hst->st_write = ti_st_proto[i].write;
|
||||||
if (!hst->st_write) {
|
if (!hst->st_write) {
|
||||||
BT_ERR("undefined ST write function");
|
BT_ERR("undefined ST write function");
|
||||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
|
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
|
||||||
/* Undo registration with ST */
|
/* Undo registration with ST */
|
||||||
err = st_unregister(&ti_st_proto[i]);
|
err = st_unregister(&ti_st_proto[i]);
|
||||||
|
@ -236,9 +229,6 @@ static int ti_st_close(struct hci_dev *hdev)
|
||||||
int err, i;
|
int err, i;
|
||||||
struct ti_st *hst = hci_get_drvdata(hdev);
|
struct ti_st *hst = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
|
for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
|
||||||
err = st_unregister(&ti_st_proto[i]);
|
err = st_unregister(&ti_st_proto[i]);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -256,9 +246,6 @@ static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
struct ti_st *hst;
|
struct ti_st *hst;
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
hst = hci_get_drvdata(hdev);
|
hst = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
/* Prepend skb with frame type */
|
/* Prepend skb with frame type */
|
||||||
|
|
|
@ -357,8 +357,6 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
|
||||||
|
|
||||||
static int dtl1_hci_open(struct hci_dev *hdev)
|
static int dtl1_hci_open(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
set_bit(HCI_RUNNING, &(hdev->flags));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,9 +374,6 @@ static int dtl1_hci_flush(struct hci_dev *hdev)
|
||||||
|
|
||||||
static int dtl1_hci_close(struct hci_dev *hdev)
|
static int dtl1_hci_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dtl1_hci_flush(hdev);
|
dtl1_hci_flush(hdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
|
@ -39,6 +41,11 @@
|
||||||
#include "btbcm.h"
|
#include "btbcm.h"
|
||||||
#include "hci_uart.h"
|
#include "hci_uart.h"
|
||||||
|
|
||||||
|
#define BCM_LM_DIAG_PKT 0x07
|
||||||
|
#define BCM_LM_DIAG_SIZE 63
|
||||||
|
|
||||||
|
#define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */
|
||||||
|
|
||||||
struct bcm_device {
|
struct bcm_device {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
|
@ -55,7 +62,7 @@ struct bcm_device {
|
||||||
int irq;
|
int irq;
|
||||||
u8 irq_polarity;
|
u8 irq_polarity;
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
struct hci_uart *hu;
|
struct hci_uart *hu;
|
||||||
bool is_suspended; /* suspend/resume flag */
|
bool is_suspended; /* suspend/resume flag */
|
||||||
#endif
|
#endif
|
||||||
|
@ -152,13 +159,17 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
static irqreturn_t bcm_host_wake(int irq, void *data)
|
static irqreturn_t bcm_host_wake(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct bcm_device *bdev = data;
|
struct bcm_device *bdev = data;
|
||||||
|
|
||||||
bt_dev_dbg(bdev, "Host wake IRQ");
|
bt_dev_dbg(bdev, "Host wake IRQ");
|
||||||
|
|
||||||
|
pm_runtime_get(&bdev->pdev->dev);
|
||||||
|
pm_runtime_mark_last_busy(&bdev->pdev->dev);
|
||||||
|
pm_runtime_put_autosuspend(&bdev->pdev->dev);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +193,12 @@ static int bcm_request_irq(struct bcm_data *bcm)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
device_init_wakeup(&bdev->pdev->dev, true);
|
device_init_wakeup(&bdev->pdev->dev, true);
|
||||||
|
|
||||||
|
pm_runtime_set_autosuspend_delay(&bdev->pdev->dev,
|
||||||
|
BCM_AUTOSUSPEND_DELAY);
|
||||||
|
pm_runtime_use_autosuspend(&bdev->pdev->dev);
|
||||||
|
pm_runtime_set_active(&bdev->pdev->dev);
|
||||||
|
pm_runtime_enable(&bdev->pdev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -197,7 +214,7 @@ static const struct bcm_set_sleep_mode default_sleep_params = {
|
||||||
.bt_wake_active = 1, /* BT_WAKE active mode: 1 = high, 0 = low */
|
.bt_wake_active = 1, /* BT_WAKE active mode: 1 = high, 0 = low */
|
||||||
.host_wake_active = 0, /* HOST_WAKE active mode: 1 = high, 0 = low */
|
.host_wake_active = 0, /* HOST_WAKE active mode: 1 = high, 0 = low */
|
||||||
.allow_host_sleep = 1, /* Allow host sleep in SCO flag */
|
.allow_host_sleep = 1, /* Allow host sleep in SCO flag */
|
||||||
.combine_modes = 0, /* Combine sleep and LPM flag */
|
.combine_modes = 1, /* Combine sleep and LPM flag */
|
||||||
.tristate_control = 0, /* Allow tri-state control of UART tx flag */
|
.tristate_control = 0, /* Allow tri-state control of UART tx flag */
|
||||||
/* Irrelevant USB flags */
|
/* Irrelevant USB flags */
|
||||||
.usb_auto_sleep = 0,
|
.usb_auto_sleep = 0,
|
||||||
|
@ -232,6 +249,29 @@ static inline int bcm_request_irq(struct bcm_data *bcm) { return 0; }
|
||||||
static inline int bcm_setup_sleep(struct hci_uart *hu) { return 0; }
|
static inline int bcm_setup_sleep(struct hci_uart *hu) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int bcm_set_diag(struct hci_dev *hdev, bool enable)
|
||||||
|
{
|
||||||
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
|
struct bcm_data *bcm = hu->priv;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||||
|
return -ENETDOWN;
|
||||||
|
|
||||||
|
skb = bt_skb_alloc(3, GFP_KERNEL);
|
||||||
|
if (IS_ERR(skb))
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
|
||||||
|
*skb_put(skb, 1) = BCM_LM_DIAG_PKT;
|
||||||
|
*skb_put(skb, 1) = 0xf0;
|
||||||
|
*skb_put(skb, 1) = enable;
|
||||||
|
|
||||||
|
skb_queue_tail(&bcm->txq, skb);
|
||||||
|
hci_uart_tx_wakeup(hu);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bcm_open(struct hci_uart *hu)
|
static int bcm_open(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct bcm_data *bcm;
|
struct bcm_data *bcm;
|
||||||
|
@ -258,7 +298,7 @@ static int bcm_open(struct hci_uart *hu)
|
||||||
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
|
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
|
||||||
bcm->dev = dev;
|
bcm->dev = dev;
|
||||||
hu->init_speed = dev->init_speed;
|
hu->init_speed = dev->init_speed;
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
dev->hu = hu;
|
dev->hu = hu;
|
||||||
#endif
|
#endif
|
||||||
bcm_gpio_set_power(bcm->dev, true);
|
bcm_gpio_set_power(bcm->dev, true);
|
||||||
|
@ -282,7 +322,10 @@ static int bcm_close(struct hci_uart *hu)
|
||||||
mutex_lock(&bcm_device_lock);
|
mutex_lock(&bcm_device_lock);
|
||||||
if (bcm_device_exists(bdev)) {
|
if (bcm_device_exists(bdev)) {
|
||||||
bcm_gpio_set_power(bdev, false);
|
bcm_gpio_set_power(bdev, false);
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
|
pm_runtime_disable(&bdev->pdev->dev);
|
||||||
|
pm_runtime_set_suspended(&bdev->pdev->dev);
|
||||||
|
|
||||||
if (device_can_wakeup(&bdev->pdev->dev)) {
|
if (device_can_wakeup(&bdev->pdev->dev)) {
|
||||||
devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
|
devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
|
||||||
device_init_wakeup(&bdev->pdev->dev, false);
|
device_init_wakeup(&bdev->pdev->dev, false);
|
||||||
|
@ -322,6 +365,7 @@ static int bcm_setup(struct hci_uart *hu)
|
||||||
|
|
||||||
bt_dev_dbg(hu->hdev, "hu %p", hu);
|
bt_dev_dbg(hu->hdev, "hu %p", hu);
|
||||||
|
|
||||||
|
hu->hdev->set_diag = bcm_set_diag;
|
||||||
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
|
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
|
||||||
|
|
||||||
err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
|
err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
|
||||||
|
@ -379,10 +423,18 @@ finalize:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BCM_RECV_LM_DIAG \
|
||||||
|
.type = BCM_LM_DIAG_PKT, \
|
||||||
|
.hlen = BCM_LM_DIAG_SIZE, \
|
||||||
|
.loff = 0, \
|
||||||
|
.lsize = 0, \
|
||||||
|
.maxlen = BCM_LM_DIAG_SIZE
|
||||||
|
|
||||||
static const struct h4_recv_pkt bcm_recv_pkts[] = {
|
static const struct h4_recv_pkt bcm_recv_pkts[] = {
|
||||||
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
||||||
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||||
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
||||||
|
{ BCM_RECV_LM_DIAG, .recv = hci_recv_diag },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
|
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
|
||||||
|
@ -399,6 +451,15 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
|
||||||
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
|
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
|
||||||
bcm->rx_skb = NULL;
|
bcm->rx_skb = NULL;
|
||||||
return err;
|
return err;
|
||||||
|
} else if (!bcm->rx_skb) {
|
||||||
|
/* Delay auto-suspend when receiving completed packet */
|
||||||
|
mutex_lock(&bcm_device_lock);
|
||||||
|
if (bcm->dev && bcm_device_exists(bcm->dev)) {
|
||||||
|
pm_runtime_get(&bcm->dev->pdev->dev);
|
||||||
|
pm_runtime_mark_last_busy(&bcm->dev->pdev->dev);
|
||||||
|
pm_runtime_put_autosuspend(&bcm->dev->pdev->dev);
|
||||||
|
}
|
||||||
|
mutex_unlock(&bcm_device_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -420,10 +481,76 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||||
static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
|
static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
|
||||||
{
|
{
|
||||||
struct bcm_data *bcm = hu->priv;
|
struct bcm_data *bcm = hu->priv;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
struct bcm_device *bdev = NULL;
|
||||||
|
|
||||||
return skb_dequeue(&bcm->txq);
|
mutex_lock(&bcm_device_lock);
|
||||||
|
|
||||||
|
if (bcm_device_exists(bcm->dev)) {
|
||||||
|
bdev = bcm->dev;
|
||||||
|
pm_runtime_get_sync(&bdev->pdev->dev);
|
||||||
|
/* Shall be resumed here */
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = skb_dequeue(&bcm->txq);
|
||||||
|
|
||||||
|
if (bdev) {
|
||||||
|
pm_runtime_mark_last_busy(&bdev->pdev->dev);
|
||||||
|
pm_runtime_put_autosuspend(&bdev->pdev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&bcm_device_lock);
|
||||||
|
|
||||||
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int bcm_suspend_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
|
||||||
|
|
||||||
|
bt_dev_dbg(bdev, "");
|
||||||
|
|
||||||
|
if (!bdev->is_suspended && bdev->hu) {
|
||||||
|
hci_uart_set_flow_control(bdev->hu, true);
|
||||||
|
|
||||||
|
/* Once this returns, driver suspends BT via GPIO */
|
||||||
|
bdev->is_suspended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suspend the device */
|
||||||
|
if (bdev->device_wakeup) {
|
||||||
|
gpiod_set_value(bdev->device_wakeup, false);
|
||||||
|
bt_dev_dbg(bdev, "suspend, delaying 15 ms");
|
||||||
|
mdelay(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bcm_resume_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
|
||||||
|
|
||||||
|
bt_dev_dbg(bdev, "");
|
||||||
|
|
||||||
|
if (bdev->device_wakeup) {
|
||||||
|
gpiod_set_value(bdev->device_wakeup, true);
|
||||||
|
bt_dev_dbg(bdev, "resume, delaying 15 ms");
|
||||||
|
mdelay(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When this executes, the device has woken up already */
|
||||||
|
if (bdev->is_suspended && bdev->hu) {
|
||||||
|
bdev->is_suspended = false;
|
||||||
|
|
||||||
|
hci_uart_set_flow_control(bdev->hu, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
/* Platform suspend callback */
|
/* Platform suspend callback */
|
||||||
static int bcm_suspend(struct device *dev)
|
static int bcm_suspend(struct device *dev)
|
||||||
|
@ -433,24 +560,17 @@ static int bcm_suspend(struct device *dev)
|
||||||
|
|
||||||
bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
|
bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
|
||||||
|
|
||||||
|
/* bcm_suspend can be called at any time as long as platform device is
|
||||||
|
* bound, so it should use bcm_device_lock to protect access to hci_uart
|
||||||
|
* and device_wake-up GPIO.
|
||||||
|
*/
|
||||||
mutex_lock(&bcm_device_lock);
|
mutex_lock(&bcm_device_lock);
|
||||||
|
|
||||||
if (!bdev->hu)
|
if (!bdev->hu)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (!bdev->is_suspended) {
|
if (pm_runtime_active(dev))
|
||||||
hci_uart_set_flow_control(bdev->hu, true);
|
bcm_suspend_device(dev);
|
||||||
|
|
||||||
/* Once this callback returns, driver suspends BT via GPIO */
|
|
||||||
bdev->is_suspended = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Suspend the device */
|
|
||||||
if (bdev->device_wakeup) {
|
|
||||||
gpiod_set_value(bdev->device_wakeup, false);
|
|
||||||
bt_dev_dbg(bdev, "suspend, delaying 15 ms");
|
|
||||||
mdelay(15);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device_may_wakeup(&bdev->pdev->dev)) {
|
if (device_may_wakeup(&bdev->pdev->dev)) {
|
||||||
error = enable_irq_wake(bdev->irq);
|
error = enable_irq_wake(bdev->irq);
|
||||||
|
@ -471,6 +591,10 @@ static int bcm_resume(struct device *dev)
|
||||||
|
|
||||||
bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
|
bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
|
||||||
|
|
||||||
|
/* bcm_resume can be called at any time as long as platform device is
|
||||||
|
* bound, so it should use bcm_device_lock to protect access to hci_uart
|
||||||
|
* and device_wake-up GPIO.
|
||||||
|
*/
|
||||||
mutex_lock(&bcm_device_lock);
|
mutex_lock(&bcm_device_lock);
|
||||||
|
|
||||||
if (!bdev->hu)
|
if (!bdev->hu)
|
||||||
|
@ -481,22 +605,15 @@ static int bcm_resume(struct device *dev)
|
||||||
bt_dev_dbg(bdev, "BCM irq: disabled");
|
bt_dev_dbg(bdev, "BCM irq: disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdev->device_wakeup) {
|
bcm_resume_device(dev);
|
||||||
gpiod_set_value(bdev->device_wakeup, true);
|
|
||||||
bt_dev_dbg(bdev, "resume, delaying 15 ms");
|
|
||||||
mdelay(15);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When this callback executes, the device has woken up already */
|
|
||||||
if (bdev->is_suspended) {
|
|
||||||
bdev->is_suspended = false;
|
|
||||||
|
|
||||||
hci_uart_set_flow_control(bdev->hu, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&bcm_device_lock);
|
mutex_unlock(&bcm_device_lock);
|
||||||
|
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
pm_runtime_set_active(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -513,6 +630,22 @@ static const struct acpi_gpio_mapping acpi_bcm_default_gpios[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
static u8 acpi_active_low = ACPI_ACTIVE_LOW;
|
||||||
|
|
||||||
|
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
|
||||||
|
static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
|
||||||
|
{
|
||||||
|
.ident = "Asus T100TA",
|
||||||
|
.matches = {
|
||||||
|
DMI_EXACT_MATCH(DMI_SYS_VENDOR,
|
||||||
|
"ASUSTeK COMPUTER INC."),
|
||||||
|
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
|
||||||
|
},
|
||||||
|
.driver_data = &acpi_active_low,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
static int bcm_resource(struct acpi_resource *ares, void *data)
|
static int bcm_resource(struct acpi_resource *ares, void *data)
|
||||||
{
|
{
|
||||||
struct bcm_device *dev = data;
|
struct bcm_device *dev = data;
|
||||||
|
@ -549,15 +682,10 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
|
||||||
static int bcm_acpi_probe(struct bcm_device *dev)
|
static int bcm_acpi_probe(struct bcm_device *dev)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = dev->pdev;
|
struct platform_device *pdev = dev->pdev;
|
||||||
const struct acpi_device_id *id;
|
|
||||||
struct acpi_device *adev;
|
|
||||||
LIST_HEAD(resources);
|
LIST_HEAD(resources);
|
||||||
|
const struct dmi_system_id *dmi_id;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
|
|
||||||
if (!id)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* Retrieve GPIO data */
|
/* Retrieve GPIO data */
|
||||||
dev->name = dev_name(&pdev->dev);
|
dev->name = dev_name(&pdev->dev);
|
||||||
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||||
|
@ -602,11 +730,18 @@ static int bcm_acpi_probe(struct bcm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve UART ACPI info */
|
/* Retrieve UART ACPI info */
|
||||||
adev = ACPI_COMPANION(&dev->pdev->dev);
|
ret = acpi_dev_get_resources(ACPI_COMPANION(&dev->pdev->dev),
|
||||||
if (!adev)
|
&resources, bcm_resource, dev);
|
||||||
return 0;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
acpi_dev_free_resource_list(&resources);
|
||||||
|
|
||||||
acpi_dev_get_resources(adev, &resources, bcm_resource, dev);
|
dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table);
|
||||||
|
if (dmi_id) {
|
||||||
|
bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low",
|
||||||
|
dmi_id->ident);
|
||||||
|
dev->irq_polarity = *(u8 *)dmi_id->driver_data;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -620,7 +755,6 @@ static int bcm_acpi_probe(struct bcm_device *dev)
|
||||||
static int bcm_probe(struct platform_device *pdev)
|
static int bcm_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct bcm_device *dev;
|
struct bcm_device *dev;
|
||||||
struct acpi_device_id *pdata = pdev->dev.platform_data;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||||
|
@ -629,15 +763,9 @@ static int bcm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
dev->pdev = pdev;
|
dev->pdev = pdev;
|
||||||
|
|
||||||
if (ACPI_HANDLE(&pdev->dev)) {
|
ret = bcm_acpi_probe(dev);
|
||||||
ret = bcm_acpi_probe(dev);
|
if (ret)
|
||||||
if (ret)
|
return ret;
|
||||||
return ret;
|
|
||||||
} else if (pdata) {
|
|
||||||
dev->name = pdata->id;
|
|
||||||
} else {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, dev);
|
platform_set_drvdata(pdev, dev);
|
||||||
|
|
||||||
|
@ -693,7 +821,10 @@ MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Platform suspend and resume callbacks */
|
/* Platform suspend and resume callbacks */
|
||||||
static SIMPLE_DEV_PM_OPS(bcm_pm_ops, bcm_suspend, bcm_resume);
|
static const struct dev_pm_ops bcm_pm_ops = {
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume)
|
||||||
|
SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_driver bcm_driver = {
|
static struct platform_driver bcm_driver = {
|
||||||
.probe = bcm_probe,
|
.probe = bcm_probe,
|
||||||
|
|
|
@ -266,3 +266,4 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(h4_recv_buf);
|
||||||
|
|
|
@ -128,7 +128,7 @@ static void h5_timed_event(unsigned long arg)
|
||||||
{
|
{
|
||||||
const unsigned char sync_req[] = { 0x01, 0x7e };
|
const unsigned char sync_req[] = { 0x01, 0x7e };
|
||||||
unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
|
unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
|
||||||
struct hci_uart *hu = (struct hci_uart *) arg;
|
struct hci_uart *hu = (struct hci_uart *)arg;
|
||||||
struct h5 *h5 = hu->priv;
|
struct h5 *h5 = hu->priv;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -210,7 +210,7 @@ static int h5_open(struct hci_uart *hu)
|
||||||
|
|
||||||
init_timer(&h5->timer);
|
init_timer(&h5->timer);
|
||||||
h5->timer.function = h5_timed_event;
|
h5->timer.function = h5_timed_event;
|
||||||
h5->timer.data = (unsigned long) hu;
|
h5->timer.data = (unsigned long)hu;
|
||||||
|
|
||||||
h5->tx_win = H5_TX_WIN_MAX;
|
h5->tx_win = H5_TX_WIN_MAX;
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5->rx_skb->dev = (void *) hu->hdev;
|
h5->rx_skb->dev = (void *)hu->hdev;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -696,7 +696,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = skb_dequeue(&h5->unrel);
|
skb = skb_dequeue(&h5->unrel);
|
||||||
if (skb != NULL) {
|
if (skb) {
|
||||||
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
|
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
|
||||||
skb->data, skb->len);
|
skb->data, skb->len);
|
||||||
if (nskb) {
|
if (nskb) {
|
||||||
|
@ -714,7 +714,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
skb = skb_dequeue(&h5->rel);
|
skb = skb_dequeue(&h5->rel);
|
||||||
if (skb != NULL) {
|
if (skb) {
|
||||||
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
|
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
|
||||||
skb->data, skb->len);
|
skb->data, skb->len);
|
||||||
if (nskb) {
|
if (nskb) {
|
||||||
|
|
|
@ -1165,22 +1165,6 @@ static const struct acpi_device_id intel_acpi_match[] = {
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
|
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
|
||||||
|
|
||||||
static int intel_acpi_probe(struct intel_device *idev)
|
|
||||||
{
|
|
||||||
const struct acpi_device_id *id;
|
|
||||||
|
|
||||||
id = acpi_match_device(intel_acpi_match, &idev->pdev->dev);
|
|
||||||
if (!id)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int intel_acpi_probe(struct intel_device *idev)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@ -1248,14 +1232,6 @@ static int intel_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
idev->pdev = pdev;
|
idev->pdev = pdev;
|
||||||
|
|
||||||
if (ACPI_HANDLE(&pdev->dev)) {
|
|
||||||
int err = intel_acpi_probe(idev);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
} else {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
|
idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
|
||||||
GPIOD_OUT_LOW);
|
GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(idev->reset)) {
|
if (IS_ERR(idev->reset)) {
|
||||||
|
|
|
@ -208,9 +208,6 @@ static int hci_uart_open(struct hci_dev *hdev)
|
||||||
BT_DBG("%s %p", hdev->name, hdev);
|
BT_DBG("%s %p", hdev->name, hdev);
|
||||||
|
|
||||||
/* Nothing to do for UART driver */
|
/* Nothing to do for UART driver */
|
||||||
|
|
||||||
set_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,9 +238,6 @@ static int hci_uart_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
BT_DBG("hdev %p", hdev);
|
BT_DBG("hdev %p", hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hci_uart_flush(hdev);
|
hci_uart_flush(hdev);
|
||||||
hdev->flush = NULL;
|
hdev->flush = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -254,9 +248,6 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
|
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
|
||||||
|
|
||||||
hu->proto->enqueue(hu, skb);
|
hu->proto->enqueue(hu, skb);
|
||||||
|
@ -470,8 +461,6 @@ static int hci_uart_tty_open(struct tty_struct *tty)
|
||||||
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||||
|
|
||||||
spin_lock_init(&hu->rx_lock);
|
|
||||||
|
|
||||||
/* Flush any pending characters in the driver and line discipline. */
|
/* Flush any pending characters in the driver and line discipline. */
|
||||||
|
|
||||||
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
|
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
|
||||||
|
@ -569,14 +558,14 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
|
||||||
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock(&hu->rx_lock);
|
/* It does not need a lock here as it is already protected by a mutex in
|
||||||
|
* tty caller
|
||||||
|
*/
|
||||||
hu->proto->recv(hu, data, count);
|
hu->proto->recv(hu, data, count);
|
||||||
|
|
||||||
if (hu->hdev)
|
if (hu->hdev)
|
||||||
hu->hdev->stat.byte_rx += count;
|
hu->hdev->stat.byte_rx += count;
|
||||||
|
|
||||||
spin_unlock(&hu->rx_lock);
|
|
||||||
|
|
||||||
tty_unthrottle(tty);
|
tty_unthrottle(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,7 @@ static void hci_ibs_wake_retrans_timeout(unsigned long arg)
|
||||||
struct hci_uart *hu = (struct hci_uart *)arg;
|
struct hci_uart *hu = (struct hci_uart *)arg;
|
||||||
struct qca_data *qca = hu->priv;
|
struct qca_data *qca = hu->priv;
|
||||||
unsigned long flags, retrans_delay;
|
unsigned long flags, retrans_delay;
|
||||||
unsigned long retransmit = 0;
|
bool retransmit = false;
|
||||||
|
|
||||||
BT_DBG("hu %p wake retransmit timeout in %d state",
|
BT_DBG("hu %p wake retransmit timeout in %d state",
|
||||||
hu, qca->tx_ibs_state);
|
hu, qca->tx_ibs_state);
|
||||||
|
@ -358,7 +358,7 @@ static void hci_ibs_wake_retrans_timeout(unsigned long arg)
|
||||||
switch (qca->tx_ibs_state) {
|
switch (qca->tx_ibs_state) {
|
||||||
case HCI_IBS_TX_WAKING:
|
case HCI_IBS_TX_WAKING:
|
||||||
/* No WAKE_ACK, retransmit WAKE */
|
/* No WAKE_ACK, retransmit WAKE */
|
||||||
retransmit = 1;
|
retransmit = true;
|
||||||
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
|
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
|
||||||
BT_ERR("Failed to acknowledge device wake up");
|
BT_ERR("Failed to acknowledge device wake up");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -85,7 +85,6 @@ struct hci_uart {
|
||||||
|
|
||||||
struct sk_buff *tx_skb;
|
struct sk_buff *tx_skb;
|
||||||
unsigned long tx_state;
|
unsigned long tx_state;
|
||||||
spinlock_t rx_lock;
|
|
||||||
|
|
||||||
unsigned int init_speed;
|
unsigned int init_speed;
|
||||||
unsigned int oper_speed;
|
unsigned int oper_speed;
|
||||||
|
|
|
@ -55,8 +55,6 @@ struct vhci_data {
|
||||||
|
|
||||||
static int vhci_open_dev(struct hci_dev *hdev)
|
static int vhci_open_dev(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
set_bit(HCI_RUNNING, &hdev->flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +62,6 @@ static int vhci_close_dev(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct vhci_data *data = hci_get_drvdata(hdev);
|
struct vhci_data *data = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
skb_queue_purge(&data->readq);
|
skb_queue_purge(&data->readq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -85,9 +80,6 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct vhci_data *data = hci_get_drvdata(hdev);
|
struct vhci_data *data = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||||
skb_queue_tail(&data->readq, skb);
|
skb_queue_tail(&data->readq, skb);
|
||||||
|
|
||||||
|
|
|
@ -1325,9 +1325,6 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
|
||||||
"%u.%u", nesadapter->firmware_version >> 16,
|
"%u.%u", nesadapter->firmware_version >> 16,
|
||||||
nesadapter->firmware_version & 0x000000ff);
|
nesadapter->firmware_version & 0x000000ff);
|
||||||
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
|
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
|
||||||
drvinfo->testinfo_len = 0;
|
|
||||||
drvinfo->eedump_len = 0;
|
|
||||||
drvinfo->regdump_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -235,7 +235,7 @@ void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
|
||||||
|
|
||||||
int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
|
int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
|
||||||
{
|
{
|
||||||
int len, incomplete = 0, found = 0;
|
int incomplete = 0, found = 0;
|
||||||
char *dup, *tok, *name, *args;
|
char *dup, *tok, *name, *args;
|
||||||
struct dsp_element_entry *entry, *n;
|
struct dsp_element_entry *entry, *n;
|
||||||
struct dsp_pipeline_entry *pipeline_entry;
|
struct dsp_pipeline_entry *pipeline_entry;
|
||||||
|
@ -247,17 +247,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
|
||||||
if (!list_empty(&pipeline->list))
|
if (!list_empty(&pipeline->list))
|
||||||
_dsp_pipeline_destroy(pipeline);
|
_dsp_pipeline_destroy(pipeline);
|
||||||
|
|
||||||
if (!cfg)
|
dup = kstrdup(cfg, GFP_ATOMIC);
|
||||||
return 0;
|
|
||||||
|
|
||||||
len = strlen(cfg);
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dup = kmalloc(len + 1, GFP_ATOMIC);
|
|
||||||
if (!dup)
|
if (!dup)
|
||||||
return 0;
|
return 0;
|
||||||
strcpy(dup, cfg);
|
|
||||||
while ((tok = strsep(&dup, "|"))) {
|
while ((tok = strsep(&dup, "|"))) {
|
||||||
if (!strlen(tok))
|
if (!strlen(tok))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -298,8 +298,10 @@ config NLMON
|
||||||
|
|
||||||
config NET_VRF
|
config NET_VRF
|
||||||
tristate "Virtual Routing and Forwarding (Lite)"
|
tristate "Virtual Routing and Forwarding (Lite)"
|
||||||
depends on IP_MULTIPLE_TABLES && IPV6_MULTIPLE_TABLES
|
depends on IP_MULTIPLE_TABLES
|
||||||
depends on NET_L3_MASTER_DEV
|
depends on NET_L3_MASTER_DEV
|
||||||
|
depends on IPV6 || IPV6=n
|
||||||
|
depends on IPV6_MULTIPLE_TABLES || IPV6=n
|
||||||
---help---
|
---help---
|
||||||
This option enables the support for mapping interfaces into VRF's. The
|
This option enables the support for mapping interfaces into VRF's. The
|
||||||
support enables VRF devices.
|
support enables VRF devices.
|
||||||
|
|
|
@ -1071,7 +1071,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
|
||||||
NETIF_F_HIGHDMA | NETIF_F_LRO)
|
NETIF_F_HIGHDMA | NETIF_F_LRO)
|
||||||
|
|
||||||
#define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\
|
#define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\
|
||||||
NETIF_F_TSO)
|
NETIF_F_ALL_TSO)
|
||||||
|
|
||||||
static void bond_compute_features(struct bonding *bond)
|
static void bond_compute_features(struct bonding *bond)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,15 +8,6 @@
|
||||||
* Public License ("GPL") version 2 as distributed in the 'COPYING'
|
* Public License ("GPL") version 2 as distributed in the 'COPYING'
|
||||||
* file from the main directory of the linux kernel source.
|
* file from the main directory of the linux kernel source.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* Your platform definition file should specify something like:
|
|
||||||
*
|
|
||||||
* static struct at91_can_data ek_can_data = {
|
|
||||||
* transceiver_switch = sam9263ek_transceiver_switch,
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* at91_add_device_can(&ek_can_data);
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
@ -33,7 +24,6 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/platform_data/atmel.h>
|
|
||||||
|
|
||||||
#include <linux/can/dev.h>
|
#include <linux/can/dev.h>
|
||||||
#include <linux/can/error.h>
|
#include <linux/can/error.h>
|
||||||
|
@ -324,15 +314,6 @@ static inline u32 at91_can_id_to_reg_mid(canid_t can_id)
|
||||||
return reg_mid;
|
return reg_mid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Swtich transceiver on or off
|
|
||||||
*/
|
|
||||||
static void at91_transceiver_switch(const struct at91_priv *priv, int on)
|
|
||||||
{
|
|
||||||
if (priv->pdata && priv->pdata->transceiver_switch)
|
|
||||||
priv->pdata->transceiver_switch(on);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void at91_setup_mailboxes(struct net_device *dev)
|
static void at91_setup_mailboxes(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct at91_priv *priv = netdev_priv(dev);
|
struct at91_priv *priv = netdev_priv(dev);
|
||||||
|
@ -416,7 +397,6 @@ static void at91_chip_start(struct net_device *dev)
|
||||||
|
|
||||||
at91_set_bittiming(dev);
|
at91_set_bittiming(dev);
|
||||||
at91_setup_mailboxes(dev);
|
at91_setup_mailboxes(dev);
|
||||||
at91_transceiver_switch(priv, 1);
|
|
||||||
|
|
||||||
/* enable chip */
|
/* enable chip */
|
||||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
||||||
|
@ -444,7 +424,6 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
|
||||||
reg_mr = at91_read(priv, AT91_MR);
|
reg_mr = at91_read(priv, AT91_MR);
|
||||||
at91_write(priv, AT91_MR, reg_mr & ~AT91_MR_CANEN);
|
at91_write(priv, AT91_MR, reg_mr & ~AT91_MR_CANEN);
|
||||||
|
|
||||||
at91_transceiver_switch(priv, 0);
|
|
||||||
priv->can.state = state;
|
priv->can.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -601,7 +601,7 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
|
||||||
stats->tx_errors++;
|
stats->tx_errors++;
|
||||||
if (likely(skb)) {
|
if (likely(skb)) {
|
||||||
cf->can_id |= CAN_ERR_LOSTARB;
|
cf->can_id |= CAN_ERR_LOSTARB;
|
||||||
cf->data[0] = (alc & 0x1f) >> 8;
|
cf->data[0] = (alc >> 8) & 0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,4 +854,4 @@ module_platform_driver(sun4i_can_driver);
|
||||||
MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>");
|
MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>");
|
||||||
MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>");
|
MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>");
|
||||||
MODULE_LICENSE("Dual BSD/GPL");
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
MODULE_DESCRIPTION(DRV_NAME "CAN driver for Allwinner SoCs (A10/A20)");
|
MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20)");
|
||||||
|
|
|
@ -125,7 +125,6 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
|
||||||
.set_addr = mv88e6xxx_set_addr_indirect,
|
.set_addr = mv88e6xxx_set_addr_indirect,
|
||||||
.phy_read = mv88e6xxx_phy_read,
|
.phy_read = mv88e6xxx_phy_read,
|
||||||
.phy_write = mv88e6xxx_phy_write,
|
.phy_write = mv88e6xxx_phy_write,
|
||||||
.poll_link = mv88e6xxx_poll_link,
|
|
||||||
.get_strings = mv88e6xxx_get_strings,
|
.get_strings = mv88e6xxx_get_strings,
|
||||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||||
|
|
|
@ -178,7 +178,6 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
|
||||||
.set_addr = mv88e6xxx_set_addr_direct,
|
.set_addr = mv88e6xxx_set_addr_direct,
|
||||||
.phy_read = mv88e6131_phy_read,
|
.phy_read = mv88e6131_phy_read,
|
||||||
.phy_write = mv88e6131_phy_write,
|
.phy_write = mv88e6131_phy_write,
|
||||||
.poll_link = mv88e6xxx_poll_link,
|
|
||||||
.get_strings = mv88e6xxx_get_strings,
|
.get_strings = mv88e6xxx_get_strings,
|
||||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||||
|
|
|
@ -104,7 +104,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
|
||||||
.set_addr = mv88e6xxx_set_addr_indirect,
|
.set_addr = mv88e6xxx_set_addr_indirect,
|
||||||
.phy_read = mv88e6xxx_phy_read_indirect,
|
.phy_read = mv88e6xxx_phy_read_indirect,
|
||||||
.phy_write = mv88e6xxx_phy_write_indirect,
|
.phy_write = mv88e6xxx_phy_write_indirect,
|
||||||
.poll_link = mv88e6xxx_poll_link,
|
|
||||||
.get_strings = mv88e6xxx_get_strings,
|
.get_strings = mv88e6xxx_get_strings,
|
||||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||||
|
@ -114,14 +113,13 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
|
||||||
#endif
|
#endif
|
||||||
.get_regs_len = mv88e6xxx_get_regs_len,
|
.get_regs_len = mv88e6xxx_get_regs_len,
|
||||||
.get_regs = mv88e6xxx_get_regs,
|
.get_regs = mv88e6xxx_get_regs,
|
||||||
.port_join_bridge = mv88e6xxx_join_bridge,
|
|
||||||
.port_leave_bridge = mv88e6xxx_leave_bridge,
|
|
||||||
.port_stp_update = mv88e6xxx_port_stp_update,
|
.port_stp_update = mv88e6xxx_port_stp_update,
|
||||||
.port_pvid_get = mv88e6xxx_port_pvid_get,
|
.port_pvid_get = mv88e6xxx_port_pvid_get,
|
||||||
.port_pvid_set = mv88e6xxx_port_pvid_set,
|
.port_pvid_set = mv88e6xxx_port_pvid_set,
|
||||||
.port_vlan_add = mv88e6xxx_port_vlan_add,
|
.port_vlan_add = mv88e6xxx_port_vlan_add,
|
||||||
.port_vlan_del = mv88e6xxx_port_vlan_del,
|
.port_vlan_del = mv88e6xxx_port_vlan_del,
|
||||||
.vlan_getnext = mv88e6xxx_vlan_getnext,
|
.vlan_getnext = mv88e6xxx_vlan_getnext,
|
||||||
|
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
|
||||||
.port_fdb_add = mv88e6xxx_port_fdb_add,
|
.port_fdb_add = mv88e6xxx_port_fdb_add,
|
||||||
.port_fdb_del = mv88e6xxx_port_fdb_del,
|
.port_fdb_del = mv88e6xxx_port_fdb_del,
|
||||||
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
|
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
|
||||||
|
|
|
@ -324,7 +324,6 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
|
||||||
.set_addr = mv88e6xxx_set_addr_indirect,
|
.set_addr = mv88e6xxx_set_addr_indirect,
|
||||||
.phy_read = mv88e6xxx_phy_read_indirect,
|
.phy_read = mv88e6xxx_phy_read_indirect,
|
||||||
.phy_write = mv88e6xxx_phy_write_indirect,
|
.phy_write = mv88e6xxx_phy_write_indirect,
|
||||||
.poll_link = mv88e6xxx_poll_link,
|
|
||||||
.get_strings = mv88e6xxx_get_strings,
|
.get_strings = mv88e6xxx_get_strings,
|
||||||
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
|
||||||
.get_sset_count = mv88e6xxx_get_sset_count,
|
.get_sset_count = mv88e6xxx_get_sset_count,
|
||||||
|
@ -341,14 +340,13 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
|
||||||
.set_eeprom = mv88e6352_set_eeprom,
|
.set_eeprom = mv88e6352_set_eeprom,
|
||||||
.get_regs_len = mv88e6xxx_get_regs_len,
|
.get_regs_len = mv88e6xxx_get_regs_len,
|
||||||
.get_regs = mv88e6xxx_get_regs,
|
.get_regs = mv88e6xxx_get_regs,
|
||||||
.port_join_bridge = mv88e6xxx_join_bridge,
|
|
||||||
.port_leave_bridge = mv88e6xxx_leave_bridge,
|
|
||||||
.port_stp_update = mv88e6xxx_port_stp_update,
|
.port_stp_update = mv88e6xxx_port_stp_update,
|
||||||
.port_pvid_get = mv88e6xxx_port_pvid_get,
|
.port_pvid_get = mv88e6xxx_port_pvid_get,
|
||||||
.port_pvid_set = mv88e6xxx_port_pvid_set,
|
.port_pvid_set = mv88e6xxx_port_pvid_set,
|
||||||
.port_vlan_add = mv88e6xxx_port_vlan_add,
|
.port_vlan_add = mv88e6xxx_port_vlan_add,
|
||||||
.port_vlan_del = mv88e6xxx_port_vlan_del,
|
.port_vlan_del = mv88e6xxx_port_vlan_del,
|
||||||
.vlan_getnext = mv88e6xxx_vlan_getnext,
|
.vlan_getnext = mv88e6xxx_vlan_getnext,
|
||||||
|
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
|
||||||
.port_fdb_add = mv88e6xxx_port_fdb_add,
|
.port_fdb_add = mv88e6xxx_port_fdb_add,
|
||||||
.port_fdb_del = mv88e6xxx_port_fdb_del,
|
.port_fdb_del = mv88e6xxx_port_fdb_del,
|
||||||
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
|
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <net/dsa.h>
|
#include <net/dsa.h>
|
||||||
|
#include <net/switchdev.h>
|
||||||
#include "mv88e6xxx.h"
|
#include "mv88e6xxx.h"
|
||||||
|
|
||||||
/* MDIO bus access can be nested in the case of PHYs connected to the
|
/* MDIO bus access can be nested in the case of PHYs connected to the
|
||||||
|
@ -388,73 +389,6 @@ int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void mv88e6xxx_poll_link(struct dsa_switch *ds)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < DSA_MAX_PORTS; i++) {
|
|
||||||
struct net_device *dev;
|
|
||||||
int uninitialized_var(port_status);
|
|
||||||
int pcs_ctrl;
|
|
||||||
int link;
|
|
||||||
int speed;
|
|
||||||
int duplex;
|
|
||||||
int fc;
|
|
||||||
|
|
||||||
dev = ds->ports[i];
|
|
||||||
if (dev == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pcs_ctrl = mv88e6xxx_reg_read(ds, REG_PORT(i), PORT_PCS_CTRL);
|
|
||||||
if (pcs_ctrl < 0 || pcs_ctrl & PORT_PCS_CTRL_FORCE_LINK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
link = 0;
|
|
||||||
if (dev->flags & IFF_UP) {
|
|
||||||
port_status = mv88e6xxx_reg_read(ds, REG_PORT(i),
|
|
||||||
PORT_STATUS);
|
|
||||||
if (port_status < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
link = !!(port_status & PORT_STATUS_LINK);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link) {
|
|
||||||
if (netif_carrier_ok(dev)) {
|
|
||||||
netdev_info(dev, "link down\n");
|
|
||||||
netif_carrier_off(dev);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (port_status & PORT_STATUS_SPEED_MASK) {
|
|
||||||
case PORT_STATUS_SPEED_10:
|
|
||||||
speed = 10;
|
|
||||||
break;
|
|
||||||
case PORT_STATUS_SPEED_100:
|
|
||||||
speed = 100;
|
|
||||||
break;
|
|
||||||
case PORT_STATUS_SPEED_1000:
|
|
||||||
speed = 1000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
speed = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0;
|
|
||||||
fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0;
|
|
||||||
|
|
||||||
if (!netif_carrier_ok(dev)) {
|
|
||||||
netdev_info(dev,
|
|
||||||
"link up, %d Mb/s, %s duplex, flow control %sabled\n",
|
|
||||||
speed,
|
|
||||||
duplex ? "full" : "half",
|
|
||||||
fc ? "en" : "dis");
|
|
||||||
netif_carrier_on(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
|
static bool mv88e6xxx_6065_family(struct dsa_switch *ds)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
|
@ -1112,11 +1046,6 @@ static int _mv88e6xxx_atu_flush(struct dsa_switch *ds, u16 fid, bool static_too)
|
||||||
return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
|
return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid)
|
|
||||||
{
|
|
||||||
return _mv88e6xxx_atu_flush(ds, fid, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _mv88e6xxx_atu_move(struct dsa_switch *ds, u16 fid, int from_port,
|
static int _mv88e6xxx_atu_move(struct dsa_switch *ds, u16 fid, int from_port,
|
||||||
int to_port, bool static_too)
|
int to_port, bool static_too)
|
||||||
{
|
{
|
||||||
|
@ -1178,132 +1107,23 @@ abort:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with smi lock held */
|
static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
|
||||||
static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port)
|
u16 output_ports)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
u8 fid = ps->fid[port];
|
const u16 mask = (1 << ps->num_ports) - 1;
|
||||||
u16 reg = fid << 12;
|
int reg;
|
||||||
|
|
||||||
if (dsa_is_cpu_port(ds, port))
|
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
|
||||||
reg |= ds->phys_port_mask;
|
if (reg < 0)
|
||||||
else
|
return reg;
|
||||||
reg |= (ps->bridge_mask[fid] |
|
|
||||||
(1 << dsa_upstream_port(ds))) & ~(1 << port);
|
reg &= ~mask;
|
||||||
|
reg |= output_ports & mask;
|
||||||
|
|
||||||
return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
|
return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with smi lock held */
|
|
||||||
static int _mv88e6xxx_update_bridge_config(struct dsa_switch *ds, int fid)
|
|
||||||
{
|
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
||||||
int port;
|
|
||||||
u32 mask;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mask = ds->phys_port_mask;
|
|
||||||
while (mask) {
|
|
||||||
port = __ffs(mask);
|
|
||||||
mask &= ~(1 << port);
|
|
||||||
if (ps->fid[port] != fid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = _mv88e6xxx_update_port_config(ds, port);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _mv88e6xxx_flush_fid(ds, fid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bridge handling functions */
|
|
||||||
|
|
||||||
int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
|
|
||||||
{
|
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
||||||
int ret = 0;
|
|
||||||
u32 nmask;
|
|
||||||
int fid;
|
|
||||||
|
|
||||||
/* If the bridge group is not empty, join that group.
|
|
||||||
* Otherwise create a new group.
|
|
||||||
*/
|
|
||||||
fid = ps->fid[port];
|
|
||||||
nmask = br_port_mask & ~(1 << port);
|
|
||||||
if (nmask)
|
|
||||||
fid = ps->fid[__ffs(nmask)];
|
|
||||||
|
|
||||||
nmask = ps->bridge_mask[fid] | (1 << port);
|
|
||||||
if (nmask != br_port_mask) {
|
|
||||||
netdev_err(ds->ports[port],
|
|
||||||
"join: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
|
|
||||||
fid, br_port_mask, nmask);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
|
||||||
|
|
||||||
ps->bridge_mask[fid] = br_port_mask;
|
|
||||||
|
|
||||||
if (fid != ps->fid[port]) {
|
|
||||||
clear_bit(ps->fid[port], ps->fid_bitmap);
|
|
||||||
ps->fid[port] = fid;
|
|
||||||
ret = _mv88e6xxx_update_bridge_config(ds, fid);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&ps->smi_mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
|
|
||||||
{
|
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
||||||
u8 fid, newfid;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
fid = ps->fid[port];
|
|
||||||
|
|
||||||
if (ps->bridge_mask[fid] != br_port_mask) {
|
|
||||||
netdev_err(ds->ports[port],
|
|
||||||
"leave: Bridge port mask mismatch fid=%d mask=0x%x expected 0x%x\n",
|
|
||||||
fid, br_port_mask, ps->bridge_mask[fid]);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the port was the last port of a bridge, we are done.
|
|
||||||
* Otherwise assign a new fid to the port, and fix up
|
|
||||||
* the bridge configuration.
|
|
||||||
*/
|
|
||||||
if (br_port_mask == (1 << port))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
|
||||||
|
|
||||||
newfid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID, 1);
|
|
||||||
if (unlikely(newfid > ps->num_ports)) {
|
|
||||||
netdev_err(ds->ports[port], "all first %d FIDs are used\n",
|
|
||||||
ps->num_ports);
|
|
||||||
ret = -ENOSPC;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ps->fid[port] = newfid;
|
|
||||||
set_bit(newfid, ps->fid_bitmap);
|
|
||||||
ps->bridge_mask[fid] &= ~(1 << port);
|
|
||||||
ps->bridge_mask[newfid] = 1 << port;
|
|
||||||
|
|
||||||
ret = _mv88e6xxx_update_bridge_config(ds, fid);
|
|
||||||
if (!ret)
|
|
||||||
ret = _mv88e6xxx_update_bridge_config(ds, newfid);
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&ps->smi_mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
|
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
|
@ -1613,6 +1433,7 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
|
||||||
struct mv88e6xxx_vtu_stu_entry vlan = {
|
struct mv88e6xxx_vtu_stu_entry vlan = {
|
||||||
.valid = true,
|
.valid = true,
|
||||||
.vid = vid,
|
.vid = vid,
|
||||||
|
.fid = vid, /* We use one FID per VLAN */
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1646,22 +1467,10 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Non-bridged ports and bridge groups use FIDs from 1 to
|
|
||||||
* num_ports; VLANs use FIDs from num_ports+1 to 4095.
|
|
||||||
*/
|
|
||||||
vlan.fid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID,
|
|
||||||
ps->num_ports + 1);
|
|
||||||
if (unlikely(vlan.fid == VLAN_N_VID)) {
|
|
||||||
pr_err("no more FID available for VLAN %d\n", vid);
|
|
||||||
return -ENOSPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear all MAC addresses from the new database */
|
/* Clear all MAC addresses from the new database */
|
||||||
err = _mv88e6xxx_atu_flush(ds, vlan.fid, true);
|
err = _mv88e6xxx_atu_flush(ds, vlan.fid, true);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
set_bit(vlan.fid, ps->fid_bitmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*entry = vlan;
|
*entry = vlan;
|
||||||
|
@ -1701,7 +1510,6 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
struct mv88e6xxx_vtu_stu_entry vlan;
|
struct mv88e6xxx_vtu_stu_entry vlan;
|
||||||
bool keep = false;
|
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
|
@ -1719,28 +1527,22 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
|
||||||
vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
|
vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
|
||||||
|
|
||||||
/* keep the VLAN unless all ports are excluded */
|
/* keep the VLAN unless all ports are excluded */
|
||||||
|
vlan.valid = false;
|
||||||
for (i = 0; i < ps->num_ports; ++i) {
|
for (i = 0; i < ps->num_ports; ++i) {
|
||||||
if (dsa_is_cpu_port(ds, i))
|
if (dsa_is_cpu_port(ds, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
|
if (vlan.data[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
|
||||||
keep = true;
|
vlan.valid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vlan.valid = keep;
|
|
||||||
err = _mv88e6xxx_vtu_loadpurge(ds, &vlan);
|
err = _mv88e6xxx_vtu_loadpurge(ds, &vlan);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
err = _mv88e6xxx_atu_remove(ds, vlan.fid, port, false);
|
err = _mv88e6xxx_atu_remove(ds, vlan.fid, port, false);
|
||||||
if (err)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
if (!keep)
|
|
||||||
clear_bit(vlan.fid, ps->fid_bitmap);
|
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&ps->smi_mutex);
|
mutex_unlock(&ps->smi_mutex);
|
||||||
|
|
||||||
|
@ -1867,37 +1669,13 @@ static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
|
||||||
return _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_LOAD_DB);
|
return _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_LOAD_DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid)
|
|
||||||
{
|
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
|
||||||
struct mv88e6xxx_vtu_stu_entry vlan;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (vid == 0)
|
|
||||||
return ps->fid[port];
|
|
||||||
|
|
||||||
err = _mv88e6xxx_port_vtu_getnext(ds, port, vid - 1, &vlan);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (vlan.vid == vid)
|
|
||||||
return vlan.fid;
|
|
||||||
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
|
static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
|
||||||
const unsigned char *addr, u16 vid,
|
const unsigned char *addr, u16 vid,
|
||||||
u8 state)
|
u8 state)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_atu_entry entry = { 0 };
|
struct mv88e6xxx_atu_entry entry = { 0 };
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid);
|
entry.fid = vid; /* We use one FID per VLAN */
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
entry.fid = ret;
|
|
||||||
entry.state = state;
|
entry.state = state;
|
||||||
ether_addr_copy(entry.mac, addr);
|
ether_addr_copy(entry.mac, addr);
|
||||||
if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
|
||||||
|
@ -1908,30 +1686,45 @@ static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
|
||||||
return _mv88e6xxx_atu_load(ds, &entry);
|
return _mv88e6xxx_atu_load(ds, &entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
|
||||||
const unsigned char *addr, u16 vid)
|
const struct switchdev_obj_port_fdb *fdb,
|
||||||
|
struct switchdev_trans *trans)
|
||||||
{
|
{
|
||||||
int state = is_multicast_ether_addr(addr) ?
|
/* We don't use per-port FDB */
|
||||||
|
if (fdb->vid == 0)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/* We don't need any dynamic resource from the kernel (yet),
|
||||||
|
* so skip the prepare phase.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
||||||
|
const struct switchdev_obj_port_fdb *fdb,
|
||||||
|
struct switchdev_trans *trans)
|
||||||
|
{
|
||||||
|
int state = is_multicast_ether_addr(fdb->addr) ?
|
||||||
GLOBAL_ATU_DATA_STATE_MC_STATIC :
|
GLOBAL_ATU_DATA_STATE_MC_STATIC :
|
||||||
GLOBAL_ATU_DATA_STATE_UC_STATIC;
|
GLOBAL_ATU_DATA_STATE_UC_STATIC;
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid, state);
|
ret = _mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid, state);
|
||||||
mutex_unlock(&ps->smi_mutex);
|
mutex_unlock(&ps->smi_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
||||||
const unsigned char *addr, u16 vid)
|
const struct switchdev_obj_port_fdb *fdb)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid,
|
ret = _mv88e6xxx_port_fdb_load(ds, port, fdb->addr, fdb->vid,
|
||||||
GLOBAL_ATU_DATA_STATE_UNUSED);
|
GLOBAL_ATU_DATA_STATE_UNUSED);
|
||||||
mutex_unlock(&ps->smi_mutex);
|
mutex_unlock(&ps->smi_mutex);
|
||||||
|
|
||||||
|
@ -1998,16 +1791,11 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
struct mv88e6xxx_atu_entry next;
|
struct mv88e6xxx_atu_entry next;
|
||||||
u16 fid;
|
u16 fid = *vid; /* We use one FID per VLAN */
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
|
|
||||||
ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid);
|
|
||||||
if (ret < 0)
|
|
||||||
goto unlock;
|
|
||||||
fid = ret;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (is_broadcast_ether_addr(addr)) {
|
if (is_broadcast_ether_addr(addr)) {
|
||||||
struct mv88e6xxx_vtu_stu_entry vtu;
|
struct mv88e6xxx_vtu_stu_entry vtu;
|
||||||
|
@ -2058,7 +1846,7 @@ static void mv88e6xxx_bridge_work(struct work_struct *work)
|
||||||
static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
int ret, fid;
|
int ret;
|
||||||
u16 reg;
|
u16 reg;
|
||||||
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
|
@ -2184,7 +1972,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
||||||
reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
|
reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg |= PORT_CONTROL_2_8021Q_FALLBACK;
|
reg |= PORT_CONTROL_2_8021Q_SECURE;
|
||||||
|
|
||||||
if (reg) {
|
if (reg) {
|
||||||
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
|
||||||
|
@ -2277,19 +2065,11 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto abort;
|
goto abort;
|
||||||
|
|
||||||
/* Port based VLAN map: give each port its own address
|
/* Port based VLAN map: do not give each port its own address
|
||||||
* database, allow the CPU port to talk to each of the 'real'
|
* database, and allow every port to egress frames on all other ports.
|
||||||
* ports, and allow each of the 'real' ports to only talk to
|
|
||||||
* the upstream port.
|
|
||||||
*/
|
*/
|
||||||
fid = port + 1;
|
reg = BIT(ps->num_ports) - 1; /* all ports */
|
||||||
ps->fid[port] = fid;
|
ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg & ~port);
|
||||||
set_bit(fid, ps->fid_bitmap);
|
|
||||||
|
|
||||||
if (!dsa_is_cpu_port(ds, port))
|
|
||||||
ps->bridge_mask[fid] = 1 << port;
|
|
||||||
|
|
||||||
ret = _mv88e6xxx_update_port_config(ds, port);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto abort;
|
goto abort;
|
||||||
|
|
||||||
|
|
|
@ -402,12 +402,6 @@ struct mv88e6xxx_priv_state {
|
||||||
int id; /* switch product id */
|
int id; /* switch product id */
|
||||||
int num_ports; /* number of switch ports */
|
int num_ports; /* number of switch ports */
|
||||||
|
|
||||||
/* hw bridging */
|
|
||||||
|
|
||||||
DECLARE_BITMAP(fid_bitmap, VLAN_N_VID); /* FIDs 1 to 4095 available */
|
|
||||||
u16 fid[DSA_MAX_PORTS]; /* per (non-bridged) port FID */
|
|
||||||
u16 bridge_mask[DSA_MAX_PORTS]; /* br groups (indexed by FID) */
|
|
||||||
|
|
||||||
unsigned long port_state_update_mask;
|
unsigned long port_state_update_mask;
|
||||||
u8 port_state[DSA_MAX_PORTS];
|
u8 port_state[DSA_MAX_PORTS];
|
||||||
|
|
||||||
|
@ -442,7 +436,6 @@ void mv88e6xxx_ppu_state_init(struct dsa_switch *ds);
|
||||||
int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum);
|
int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum);
|
||||||
int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
|
int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
|
||||||
int regnum, u16 val);
|
int regnum, u16 val);
|
||||||
void mv88e6xxx_poll_link(struct dsa_switch *ds);
|
|
||||||
void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data);
|
void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data);
|
||||||
void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
|
void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||||
uint64_t *data);
|
uint64_t *data);
|
||||||
|
@ -465,8 +458,6 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
|
||||||
int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
|
int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
|
||||||
int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
|
int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
|
||||||
struct phy_device *phydev, struct ethtool_eee *e);
|
struct phy_device *phydev, struct ethtool_eee *e);
|
||||||
int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask);
|
|
||||||
int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask);
|
|
||||||
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state);
|
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state);
|
||||||
int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *vid);
|
int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *vid);
|
||||||
int mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 vid);
|
int mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 vid);
|
||||||
|
@ -475,10 +466,14 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
|
||||||
int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid);
|
int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid);
|
||||||
int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
|
int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
|
||||||
unsigned long *ports, unsigned long *untagged);
|
unsigned long *ports, unsigned long *untagged);
|
||||||
|
int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
|
||||||
|
const struct switchdev_obj_port_fdb *fdb,
|
||||||
|
struct switchdev_trans *trans);
|
||||||
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
|
||||||
const unsigned char *addr, u16 vid);
|
const struct switchdev_obj_port_fdb *fdb,
|
||||||
|
struct switchdev_trans *trans);
|
||||||
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
||||||
const unsigned char *addr, u16 vid);
|
const struct switchdev_obj_port_fdb *fdb);
|
||||||
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
|
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
|
||||||
unsigned char *addr, u16 *vid, bool *is_static);
|
unsigned char *addr, u16 *vid, bool *is_static);
|
||||||
int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
|
int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
|
||||||
|
|
|
@ -1141,8 +1141,6 @@ static void greth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
|
||||||
strlcpy(info->version, "revision: 1.0", sizeof(info->version));
|
strlcpy(info->version, "revision: 1.0", sizeof(info->version));
|
||||||
strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info));
|
strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info));
|
||||||
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
|
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
|
||||||
info->eedump_len = 0;
|
|
||||||
info->regdump_len = sizeof(struct greth_regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
|
static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
|
||||||
|
|
|
@ -714,7 +714,6 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
||||||
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
||||||
snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
|
snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
|
||||||
aup->mac_id);
|
aup->mac_id);
|
||||||
info->regdump_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void au1000_set_msglevel(struct net_device *dev, u32 value)
|
static void au1000_set_msglevel(struct net_device *dev, u32 value)
|
||||||
|
|
|
@ -1940,84 +1940,31 @@ static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata)
|
||||||
static unsigned int xgbe_calculate_per_queue_fifo(unsigned int fifo_size,
|
static unsigned int xgbe_calculate_per_queue_fifo(unsigned int fifo_size,
|
||||||
unsigned int queue_count)
|
unsigned int queue_count)
|
||||||
{
|
{
|
||||||
unsigned int q_fifo_size = 0;
|
unsigned int q_fifo_size;
|
||||||
enum xgbe_mtl_fifo_size p_fifo = XGMAC_MTL_FIFO_SIZE_256;
|
unsigned int p_fifo;
|
||||||
|
|
||||||
/* Calculate Tx/Rx fifo share per queue */
|
/* Calculate the configured fifo size */
|
||||||
switch (fifo_size) {
|
q_fifo_size = 1 << (fifo_size + 7);
|
||||||
case 0:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_B(128);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_B(256);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_B(512);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(1);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(2);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(4);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(8);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(16);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(32);
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(64);
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(128);
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
q_fifo_size = XGBE_FIFO_SIZE_KB(256);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The configured value is not the actual amount of fifo RAM */
|
/* The configured value may not be the actual amount of fifo RAM */
|
||||||
q_fifo_size = min_t(unsigned int, XGBE_FIFO_MAX, q_fifo_size);
|
q_fifo_size = min_t(unsigned int, XGBE_FIFO_MAX, q_fifo_size);
|
||||||
|
|
||||||
q_fifo_size = q_fifo_size / queue_count;
|
q_fifo_size = q_fifo_size / queue_count;
|
||||||
|
|
||||||
/* Set the queue fifo size programmable value */
|
/* Each increment in the queue fifo size represents 256 bytes of
|
||||||
if (q_fifo_size >= XGBE_FIFO_SIZE_KB(256))
|
* fifo, with 0 representing 256 bytes. Distribute the fifo equally
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_256K;
|
* between the queues.
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(128))
|
*/
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_128K;
|
p_fifo = q_fifo_size / 256;
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(64))
|
if (p_fifo)
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_64K;
|
p_fifo--;
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(32))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_32K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(16))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_16K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(8))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_8K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(4))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_4K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(2))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_2K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(1))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_1K;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_B(512))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_512;
|
|
||||||
else if (q_fifo_size >= XGBE_FIFO_SIZE_B(256))
|
|
||||||
p_fifo = XGMAC_MTL_FIFO_SIZE_256;
|
|
||||||
|
|
||||||
return p_fifo;
|
return p_fifo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
|
static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
|
||||||
{
|
{
|
||||||
enum xgbe_mtl_fifo_size fifo_size;
|
unsigned int fifo_size;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size,
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size,
|
||||||
|
@ -2033,7 +1980,7 @@ static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata)
|
||||||
|
|
||||||
static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
|
static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata)
|
||||||
{
|
{
|
||||||
enum xgbe_mtl_fifo_size fifo_size;
|
unsigned int fifo_size;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size,
|
fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size,
|
||||||
|
@ -2224,7 +2171,7 @@ static u64 xgbe_mmc_read(struct xgbe_prv_data *pdata, unsigned int reg_lo)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
read_hi = false;
|
read_hi = false;
|
||||||
};
|
}
|
||||||
|
|
||||||
val = XGMAC_IOREAD(pdata, reg_lo);
|
val = XGMAC_IOREAD(pdata, reg_lo);
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,9 @@ static irqreturn_t xgbe_isr(int irq, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RBU))
|
||||||
|
pdata->ext_stats.rx_buffer_unavailable++;
|
||||||
|
|
||||||
/* Restart the device on a Fatal Bus Error */
|
/* Restart the device on a Fatal Bus Error */
|
||||||
if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE))
|
if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE))
|
||||||
schedule_work(&pdata->restart_work);
|
schedule_work(&pdata->restart_work);
|
||||||
|
@ -384,7 +387,8 @@ static irqreturn_t xgbe_isr(int irq, void *data)
|
||||||
/* Read Tx Timestamp to clear interrupt */
|
/* Read Tx Timestamp to clear interrupt */
|
||||||
pdata->tx_tstamp =
|
pdata->tx_tstamp =
|
||||||
hw_if->get_tx_tstamp(pdata);
|
hw_if->get_tx_tstamp(pdata);
|
||||||
schedule_work(&pdata->tx_tstamp_work);
|
queue_work(pdata->dev_workqueue,
|
||||||
|
&pdata->tx_tstamp_work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,7 +454,7 @@ static void xgbe_service_timer(unsigned long data)
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
|
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
|
||||||
|
|
||||||
schedule_work(&pdata->service_work);
|
queue_work(pdata->dev_workqueue, &pdata->service_work);
|
||||||
|
|
||||||
mod_timer(&pdata->service_timer, jiffies + HZ);
|
mod_timer(&pdata->service_timer, jiffies + HZ);
|
||||||
}
|
}
|
||||||
|
@ -891,7 +895,7 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
|
||||||
netif_tx_start_all_queues(netdev);
|
netif_tx_start_all_queues(netdev);
|
||||||
|
|
||||||
xgbe_start_timers(pdata);
|
xgbe_start_timers(pdata);
|
||||||
schedule_work(&pdata->service_work);
|
queue_work(pdata->dev_workqueue, &pdata->service_work);
|
||||||
|
|
||||||
DBGPR("<--xgbe_start\n");
|
DBGPR("<--xgbe_start\n");
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
|
||||||
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
|
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
|
||||||
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
|
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
|
||||||
XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
|
XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
|
||||||
|
XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats)
|
#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats)
|
||||||
|
@ -187,8 +188,6 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DBGPR("-->%s\n", __func__);
|
|
||||||
|
|
||||||
switch (stringset) {
|
switch (stringset) {
|
||||||
case ETH_SS_STATS:
|
case ETH_SS_STATS:
|
||||||
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
||||||
|
@ -198,8 +197,6 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBGPR("<--%s\n", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xgbe_get_ethtool_stats(struct net_device *netdev,
|
static void xgbe_get_ethtool_stats(struct net_device *netdev,
|
||||||
|
@ -209,23 +206,17 @@ static void xgbe_get_ethtool_stats(struct net_device *netdev,
|
||||||
u8 *stat;
|
u8 *stat;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DBGPR("-->%s\n", __func__);
|
|
||||||
|
|
||||||
pdata->hw_if.read_mmc_stats(pdata);
|
pdata->hw_if.read_mmc_stats(pdata);
|
||||||
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
for (i = 0; i < XGBE_STATS_COUNT; i++) {
|
||||||
stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset;
|
stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset;
|
||||||
*data++ = *(u64 *)stat;
|
*data++ = *(u64 *)stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBGPR("<--%s\n", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
|
static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DBGPR("-->%s\n", __func__);
|
|
||||||
|
|
||||||
switch (stringset) {
|
switch (stringset) {
|
||||||
case ETH_SS_STATS:
|
case ETH_SS_STATS:
|
||||||
ret = XGBE_STATS_COUNT;
|
ret = XGBE_STATS_COUNT;
|
||||||
|
@ -235,8 +226,6 @@ static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBGPR("<--%s\n", __func__);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,13 +234,9 @@ static void xgbe_get_pauseparam(struct net_device *netdev,
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
|
|
||||||
DBGPR("-->xgbe_get_pauseparam\n");
|
|
||||||
|
|
||||||
pause->autoneg = pdata->phy.pause_autoneg;
|
pause->autoneg = pdata->phy.pause_autoneg;
|
||||||
pause->tx_pause = pdata->phy.tx_pause;
|
pause->tx_pause = pdata->phy.tx_pause;
|
||||||
pause->rx_pause = pdata->phy.rx_pause;
|
pause->rx_pause = pdata->phy.rx_pause;
|
||||||
|
|
||||||
DBGPR("<--xgbe_get_pauseparam\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgbe_set_pauseparam(struct net_device *netdev,
|
static int xgbe_set_pauseparam(struct net_device *netdev,
|
||||||
|
@ -260,13 +245,11 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
DBGPR("-->xgbe_set_pauseparam\n");
|
if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
|
||||||
|
netdev_err(netdev,
|
||||||
DBGPR(" autoneg = %d, tx_pause = %d, rx_pause = %d\n",
|
"autoneg disabled, pause autoneg not avialable\n");
|
||||||
pause->autoneg, pause->tx_pause, pause->rx_pause);
|
|
||||||
|
|
||||||
if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
pdata->phy.pause_autoneg = pause->autoneg;
|
pdata->phy.pause_autoneg = pause->autoneg;
|
||||||
pdata->phy.tx_pause = pause->tx_pause;
|
pdata->phy.tx_pause = pause->tx_pause;
|
||||||
|
@ -286,8 +269,6 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
|
||||||
if (netif_running(netdev))
|
if (netif_running(netdev))
|
||||||
ret = pdata->phy_if.phy_config_aneg(pdata);
|
ret = pdata->phy_if.phy_config_aneg(pdata);
|
||||||
|
|
||||||
DBGPR("<--xgbe_set_pauseparam\n");
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,8 +277,6 @@ static int xgbe_get_settings(struct net_device *netdev,
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
|
|
||||||
DBGPR("-->xgbe_get_settings\n");
|
|
||||||
|
|
||||||
cmd->phy_address = pdata->phy.address;
|
cmd->phy_address = pdata->phy.address;
|
||||||
|
|
||||||
cmd->supported = pdata->phy.supported;
|
cmd->supported = pdata->phy.supported;
|
||||||
|
@ -311,8 +290,6 @@ static int xgbe_get_settings(struct net_device *netdev,
|
||||||
cmd->port = PORT_NONE;
|
cmd->port = PORT_NONE;
|
||||||
cmd->transceiver = XCVR_INTERNAL;
|
cmd->transceiver = XCVR_INTERNAL;
|
||||||
|
|
||||||
DBGPR("<--xgbe_get_settings\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,16 +300,20 @@ static int xgbe_set_settings(struct net_device *netdev,
|
||||||
u32 speed;
|
u32 speed;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DBGPR("-->xgbe_set_settings\n");
|
|
||||||
|
|
||||||
speed = ethtool_cmd_speed(cmd);
|
speed = ethtool_cmd_speed(cmd);
|
||||||
|
|
||||||
if (cmd->phy_address != pdata->phy.address)
|
if (cmd->phy_address != pdata->phy.address) {
|
||||||
|
netdev_err(netdev, "invalid phy address %hhu\n",
|
||||||
|
cmd->phy_address);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cmd->autoneg != AUTONEG_ENABLE) &&
|
if ((cmd->autoneg != AUTONEG_ENABLE) &&
|
||||||
(cmd->autoneg != AUTONEG_DISABLE))
|
(cmd->autoneg != AUTONEG_DISABLE)) {
|
||||||
|
netdev_err(netdev, "unsupported autoneg %hhu\n",
|
||||||
|
cmd->autoneg);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (cmd->autoneg == AUTONEG_DISABLE) {
|
if (cmd->autoneg == AUTONEG_DISABLE) {
|
||||||
switch (speed) {
|
switch (speed) {
|
||||||
|
@ -341,16 +322,27 @@ static int xgbe_set_settings(struct net_device *netdev,
|
||||||
case SPEED_1000:
|
case SPEED_1000:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
netdev_err(netdev, "unsupported speed %u\n", speed);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd->duplex != DUPLEX_FULL)
|
if (cmd->duplex != DUPLEX_FULL) {
|
||||||
|
netdev_err(netdev, "unsupported duplex %hhu\n",
|
||||||
|
cmd->duplex);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netif_dbg(pdata, link, netdev,
|
||||||
|
"requested advertisement %#x, phy supported %#x\n",
|
||||||
|
cmd->advertising, pdata->phy.supported);
|
||||||
|
|
||||||
cmd->advertising &= pdata->phy.supported;
|
cmd->advertising &= pdata->phy.supported;
|
||||||
if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising)
|
if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) {
|
||||||
|
netdev_err(netdev,
|
||||||
|
"unsupported requested advertisement\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
pdata->phy.autoneg = cmd->autoneg;
|
pdata->phy.autoneg = cmd->autoneg;
|
||||||
|
@ -366,8 +358,6 @@ static int xgbe_set_settings(struct net_device *netdev,
|
||||||
if (netif_running(netdev))
|
if (netif_running(netdev))
|
||||||
ret = pdata->phy_if.phy_config_aneg(pdata);
|
ret = pdata->phy_if.phy_config_aneg(pdata);
|
||||||
|
|
||||||
DBGPR("<--xgbe_set_settings\n");
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +375,20 @@ static void xgbe_get_drvinfo(struct net_device *netdev,
|
||||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
|
||||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
|
||||||
XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
|
XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
|
||||||
drvinfo->n_stats = XGBE_STATS_COUNT;
|
}
|
||||||
|
|
||||||
|
static u32 xgbe_get_msglevel(struct net_device *netdev)
|
||||||
|
{
|
||||||
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
|
|
||||||
|
return pdata->msg_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_set_msglevel(struct net_device *netdev, u32 msglevel)
|
||||||
|
{
|
||||||
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
|
|
||||||
|
pdata->msg_enable = msglevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgbe_get_coalesce(struct net_device *netdev,
|
static int xgbe_get_coalesce(struct net_device *netdev,
|
||||||
|
@ -393,8 +396,6 @@ static int xgbe_get_coalesce(struct net_device *netdev,
|
||||||
{
|
{
|
||||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||||
|
|
||||||
DBGPR("-->xgbe_get_coalesce\n");
|
|
||||||
|
|
||||||
memset(ec, 0, sizeof(struct ethtool_coalesce));
|
memset(ec, 0, sizeof(struct ethtool_coalesce));
|
||||||
|
|
||||||
ec->rx_coalesce_usecs = pdata->rx_usecs;
|
ec->rx_coalesce_usecs = pdata->rx_usecs;
|
||||||
|
@ -402,8 +403,6 @@ static int xgbe_get_coalesce(struct net_device *netdev,
|
||||||
|
|
||||||
ec->tx_max_coalesced_frames = pdata->tx_frames;
|
ec->tx_max_coalesced_frames = pdata->tx_frames;
|
||||||
|
|
||||||
DBGPR("<--xgbe_get_coalesce\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,8 +414,6 @@ static int xgbe_set_coalesce(struct net_device *netdev,
|
||||||
unsigned int rx_frames, rx_riwt, rx_usecs;
|
unsigned int rx_frames, rx_riwt, rx_usecs;
|
||||||
unsigned int tx_frames;
|
unsigned int tx_frames;
|
||||||
|
|
||||||
DBGPR("-->xgbe_set_coalesce\n");
|
|
||||||
|
|
||||||
/* Check for not supported parameters */
|
/* Check for not supported parameters */
|
||||||
if ((ec->rx_coalesce_usecs_irq) ||
|
if ((ec->rx_coalesce_usecs_irq) ||
|
||||||
(ec->rx_max_coalesced_frames_irq) ||
|
(ec->rx_max_coalesced_frames_irq) ||
|
||||||
|
@ -436,8 +433,10 @@ static int xgbe_set_coalesce(struct net_device *netdev,
|
||||||
(ec->rx_max_coalesced_frames_high) ||
|
(ec->rx_max_coalesced_frames_high) ||
|
||||||
(ec->tx_coalesce_usecs_high) ||
|
(ec->tx_coalesce_usecs_high) ||
|
||||||
(ec->tx_max_coalesced_frames_high) ||
|
(ec->tx_max_coalesced_frames_high) ||
|
||||||
(ec->rate_sample_interval))
|
(ec->rate_sample_interval)) {
|
||||||
|
netdev_err(netdev, "unsupported coalescing parameter\n");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs);
|
rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs);
|
||||||
rx_usecs = ec->rx_coalesce_usecs;
|
rx_usecs = ec->rx_coalesce_usecs;
|
||||||
|
@ -449,13 +448,13 @@ static int xgbe_set_coalesce(struct net_device *netdev,
|
||||||
|
|
||||||
/* Check the bounds of values for Rx */
|
/* Check the bounds of values for Rx */
|
||||||
if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
|
if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
|
||||||
netdev_alert(netdev, "rx-usec is limited to %d usecs\n",
|
netdev_err(netdev, "rx-usec is limited to %d usecs\n",
|
||||||
hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT));
|
hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (rx_frames > pdata->rx_desc_count) {
|
if (rx_frames > pdata->rx_desc_count) {
|
||||||
netdev_alert(netdev, "rx-frames is limited to %d frames\n",
|
netdev_err(netdev, "rx-frames is limited to %d frames\n",
|
||||||
pdata->rx_desc_count);
|
pdata->rx_desc_count);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,8 +462,8 @@ static int xgbe_set_coalesce(struct net_device *netdev,
|
||||||
|
|
||||||
/* Check the bounds of values for Tx */
|
/* Check the bounds of values for Tx */
|
||||||
if (tx_frames > pdata->tx_desc_count) {
|
if (tx_frames > pdata->tx_desc_count) {
|
||||||
netdev_alert(netdev, "tx-frames is limited to %d frames\n",
|
netdev_err(netdev, "tx-frames is limited to %d frames\n",
|
||||||
pdata->tx_desc_count);
|
pdata->tx_desc_count);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,8 +475,6 @@ static int xgbe_set_coalesce(struct net_device *netdev,
|
||||||
pdata->tx_frames = tx_frames;
|
pdata->tx_frames = tx_frames;
|
||||||
hw_if->config_tx_coalesce(pdata);
|
hw_if->config_tx_coalesce(pdata);
|
||||||
|
|
||||||
DBGPR("<--xgbe_set_coalesce\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,8 +536,10 @@ static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
|
|
||||||
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
|
||||||
|
netdev_err(netdev, "unsupported hash function\n");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
if (indir) {
|
if (indir) {
|
||||||
ret = hw_if->set_rss_lookup_table(pdata, indir);
|
ret = hw_if->set_rss_lookup_table(pdata, indir);
|
||||||
|
@ -594,6 +593,8 @@ static const struct ethtool_ops xgbe_ethtool_ops = {
|
||||||
.get_settings = xgbe_get_settings,
|
.get_settings = xgbe_get_settings,
|
||||||
.set_settings = xgbe_set_settings,
|
.set_settings = xgbe_set_settings,
|
||||||
.get_drvinfo = xgbe_get_drvinfo,
|
.get_drvinfo = xgbe_get_drvinfo,
|
||||||
|
.get_msglevel = xgbe_get_msglevel,
|
||||||
|
.set_msglevel = xgbe_set_msglevel,
|
||||||
.get_link = ethtool_op_get_link,
|
.get_link = ethtool_op_get_link,
|
||||||
.get_coalesce = xgbe_get_coalesce,
|
.get_coalesce = xgbe_get_coalesce,
|
||||||
.set_coalesce = xgbe_set_coalesce,
|
.set_coalesce = xgbe_set_coalesce,
|
||||||
|
|
|
@ -371,7 +371,7 @@ static int xgbe_probe(struct platform_device *pdev)
|
||||||
set_bit(XGBE_DOWN, &pdata->dev_state);
|
set_bit(XGBE_DOWN, &pdata->dev_state);
|
||||||
|
|
||||||
/* Check if we should use ACPI or DT */
|
/* Check if we should use ACPI or DT */
|
||||||
pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
|
pdata->use_acpi = dev->of_node ? 0 : 1;
|
||||||
|
|
||||||
phy_pdev = xgbe_get_phy_pdev(pdata);
|
phy_pdev = xgbe_get_phy_pdev(pdata);
|
||||||
if (!phy_pdev) {
|
if (!phy_pdev) {
|
||||||
|
|
|
@ -1115,8 +1115,7 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
|
||||||
unsigned int reg, link_aneg;
|
unsigned int reg, link_aneg;
|
||||||
|
|
||||||
if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
|
if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
|
||||||
if (test_and_clear_bit(XGBE_LINK, &pdata->dev_state))
|
netif_carrier_off(pdata->netdev);
|
||||||
netif_carrier_off(pdata->netdev);
|
|
||||||
|
|
||||||
pdata->phy.link = 0;
|
pdata->phy.link = 0;
|
||||||
goto adjust_link;
|
goto adjust_link;
|
||||||
|
@ -1142,10 +1141,7 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
|
||||||
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
|
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
|
||||||
clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
|
clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
|
||||||
|
|
||||||
if (!test_bit(XGBE_LINK, &pdata->dev_state)) {
|
netif_carrier_on(pdata->netdev);
|
||||||
set_bit(XGBE_LINK, &pdata->dev_state);
|
|
||||||
netif_carrier_on(pdata->netdev);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
|
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
|
||||||
xgbe_check_link_timeout(pdata);
|
xgbe_check_link_timeout(pdata);
|
||||||
|
@ -1156,10 +1152,7 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
|
||||||
|
|
||||||
xgbe_phy_status_aneg(pdata);
|
xgbe_phy_status_aneg(pdata);
|
||||||
|
|
||||||
if (test_bit(XGBE_LINK, &pdata->dev_state)) {
|
netif_carrier_off(pdata->netdev);
|
||||||
clear_bit(XGBE_LINK, &pdata->dev_state);
|
|
||||||
netif_carrier_off(pdata->netdev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adjust_link:
|
adjust_link:
|
||||||
|
@ -1179,8 +1172,7 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
|
||||||
devm_free_irq(pdata->dev, pdata->an_irq, pdata);
|
devm_free_irq(pdata->dev, pdata->an_irq, pdata);
|
||||||
|
|
||||||
pdata->phy.link = 0;
|
pdata->phy.link = 0;
|
||||||
if (test_and_clear_bit(XGBE_LINK, &pdata->dev_state))
|
netif_carrier_off(pdata->netdev);
|
||||||
netif_carrier_off(pdata->netdev);
|
|
||||||
|
|
||||||
xgbe_phy_adjust_link(pdata);
|
xgbe_phy_adjust_link(pdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,8 +209,6 @@
|
||||||
#define XGMAC_IOCTL_CONTEXT 2
|
#define XGMAC_IOCTL_CONTEXT 2
|
||||||
|
|
||||||
#define XGBE_FIFO_MAX 81920
|
#define XGBE_FIFO_MAX 81920
|
||||||
#define XGBE_FIFO_SIZE_B(x) (x)
|
|
||||||
#define XGBE_FIFO_SIZE_KB(x) (x * 1024)
|
|
||||||
|
|
||||||
#define XGBE_TC_MIN_QUANTUM 10
|
#define XGBE_TC_MIN_QUANTUM 10
|
||||||
|
|
||||||
|
@ -461,7 +459,6 @@ struct xgbe_channel {
|
||||||
|
|
||||||
enum xgbe_state {
|
enum xgbe_state {
|
||||||
XGBE_DOWN,
|
XGBE_DOWN,
|
||||||
XGBE_LINK,
|
|
||||||
XGBE_LINK_INIT,
|
XGBE_LINK_INIT,
|
||||||
XGBE_LINK_ERR,
|
XGBE_LINK_ERR,
|
||||||
};
|
};
|
||||||
|
@ -483,20 +480,6 @@ enum xgbe_int_state {
|
||||||
XGMAC_INT_STATE_RESTORE,
|
XGMAC_INT_STATE_RESTORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xgbe_mtl_fifo_size {
|
|
||||||
XGMAC_MTL_FIFO_SIZE_256 = 0x00,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_512 = 0x01,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_1K = 0x03,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_2K = 0x07,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_4K = 0x0f,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_8K = 0x1f,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_16K = 0x3f,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_32K = 0x7f,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_64K = 0xff,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_128K = 0x1ff,
|
|
||||||
XGMAC_MTL_FIFO_SIZE_256K = 0x3ff,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum xgbe_speed {
|
enum xgbe_speed {
|
||||||
XGBE_SPEED_1000 = 0,
|
XGBE_SPEED_1000 = 0,
|
||||||
XGBE_SPEED_2500,
|
XGBE_SPEED_2500,
|
||||||
|
@ -598,6 +581,7 @@ struct xgbe_mmc_stats {
|
||||||
struct xgbe_ext_stats {
|
struct xgbe_ext_stats {
|
||||||
u64 tx_tso_packets;
|
u64 tx_tso_packets;
|
||||||
u64 rx_split_header_packets;
|
u64 rx_split_header_packets;
|
||||||
|
u64 rx_buffer_unavailable;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xgbe_hw_if {
|
struct xgbe_hw_if {
|
||||||
|
|
|
@ -233,10 +233,6 @@ static void atl1c_get_drvinfo(struct net_device *netdev,
|
||||||
sizeof(drvinfo->version));
|
sizeof(drvinfo->version));
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->n_stats = 0;
|
|
||||||
drvinfo->testinfo_len = 0;
|
|
||||||
drvinfo->regdump_len = atl1c_get_regs_len(netdev);
|
|
||||||
drvinfo->eedump_len = atl1c_get_eeprom_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atl1c_get_wol(struct net_device *netdev,
|
static void atl1c_get_wol(struct net_device *netdev,
|
||||||
|
|
|
@ -316,10 +316,6 @@ static void atl1e_get_drvinfo(struct net_device *netdev,
|
||||||
strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
|
strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->n_stats = 0;
|
|
||||||
drvinfo->testinfo_len = 0;
|
|
||||||
drvinfo->regdump_len = atl1e_get_regs_len(netdev);
|
|
||||||
drvinfo->eedump_len = atl1e_get_eeprom_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atl1e_get_wol(struct net_device *netdev,
|
static void atl1e_get_wol(struct net_device *netdev,
|
||||||
|
|
|
@ -3388,7 +3388,6 @@ static void atl1_get_drvinfo(struct net_device *netdev,
|
||||||
sizeof(drvinfo->version));
|
sizeof(drvinfo->version));
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->eedump_len = ATL1_EEDUMP_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atl1_get_wol(struct net_device *netdev,
|
static void atl1_get_wol(struct net_device *netdev,
|
||||||
|
|
|
@ -2030,10 +2030,6 @@ static void atl2_get_drvinfo(struct net_device *netdev,
|
||||||
strlcpy(drvinfo->fw_version, "L2", sizeof(drvinfo->fw_version));
|
strlcpy(drvinfo->fw_version, "L2", sizeof(drvinfo->fw_version));
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->n_stats = 0;
|
|
||||||
drvinfo->testinfo_len = 0;
|
|
||||||
drvinfo->regdump_len = atl2_get_regs_len(netdev);
|
|
||||||
drvinfo->eedump_len = atl2_get_eeprom_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atl2_get_wol(struct net_device *netdev,
|
static void atl2_get_wol(struct net_device *netdev,
|
||||||
|
|
|
@ -1333,7 +1333,6 @@ static void bcm_enet_get_drvinfo(struct net_device *netdev,
|
||||||
sizeof(drvinfo->version));
|
sizeof(drvinfo->version));
|
||||||
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
||||||
strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info));
|
strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info));
|
||||||
drvinfo->n_stats = BCM_ENET_STATS_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm_enet_get_sset_count(struct net_device *netdev,
|
static int bcm_enet_get_sset_count(struct net_device *netdev,
|
||||||
|
@ -2597,7 +2596,6 @@ static void bcm_enetsw_get_drvinfo(struct net_device *netdev,
|
||||||
strncpy(drvinfo->version, bcm_enet_driver_version, 32);
|
strncpy(drvinfo->version, bcm_enet_driver_version, 32);
|
||||||
strncpy(drvinfo->fw_version, "N/A", 32);
|
strncpy(drvinfo->fw_version, "N/A", 32);
|
||||||
strncpy(drvinfo->bus_info, "bcm63xx", 32);
|
strncpy(drvinfo->bus_info, "bcm63xx", 32);
|
||||||
drvinfo->n_stats = BCM_ENETSW_STATS_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm_enetsw_get_ethtool_stats(struct net_device *netdev,
|
static void bcm_enetsw_get_ethtool_stats(struct net_device *netdev,
|
||||||
|
|
|
@ -287,7 +287,6 @@ static void bcm_sysport_get_drvinfo(struct net_device *dev,
|
||||||
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
|
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
|
||||||
strlcpy(info->version, "0.1", sizeof(info->version));
|
strlcpy(info->version, "0.1", sizeof(info->version));
|
||||||
strlcpy(info->bus_info, "platform", sizeof(info->bus_info));
|
strlcpy(info->bus_info, "platform", sizeof(info->bus_info));
|
||||||
info->n_stats = BCM_SYSPORT_STATS_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 bcm_sysport_get_msglvl(struct net_device *dev)
|
static u32 bcm_sysport_get_msglvl(struct net_device *dev)
|
||||||
|
|
|
@ -812,6 +812,46 @@ bnx2_alloc_rx_mem(struct bnx2 *bp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bnx2_free_stats_blk(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct bnx2 *bp = netdev_priv(dev);
|
||||||
|
|
||||||
|
if (bp->status_blk) {
|
||||||
|
dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
|
||||||
|
bp->status_blk,
|
||||||
|
bp->status_blk_mapping);
|
||||||
|
bp->status_blk = NULL;
|
||||||
|
bp->stats_blk = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bnx2_alloc_stats_blk(struct net_device *dev)
|
||||||
|
{
|
||||||
|
int status_blk_size;
|
||||||
|
void *status_blk;
|
||||||
|
struct bnx2 *bp = netdev_priv(dev);
|
||||||
|
|
||||||
|
/* Combine status and statistics blocks into one allocation. */
|
||||||
|
status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
|
||||||
|
if (bp->flags & BNX2_FLAG_MSIX_CAP)
|
||||||
|
status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
|
||||||
|
BNX2_SBLK_MSIX_ALIGN_SIZE);
|
||||||
|
bp->status_stats_size = status_blk_size +
|
||||||
|
sizeof(struct statistics_block);
|
||||||
|
status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
|
||||||
|
&bp->status_blk_mapping, GFP_KERNEL);
|
||||||
|
if (status_blk == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bp->status_blk = status_blk;
|
||||||
|
bp->stats_blk = status_blk + status_blk_size;
|
||||||
|
bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bnx2_free_mem(struct bnx2 *bp)
|
bnx2_free_mem(struct bnx2 *bp)
|
||||||
{
|
{
|
||||||
|
@ -829,37 +869,19 @@ bnx2_free_mem(struct bnx2 *bp)
|
||||||
bp->ctx_blk[i] = NULL;
|
bp->ctx_blk[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bnapi->status_blk.msi) {
|
|
||||||
dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
|
if (bnapi->status_blk.msi)
|
||||||
bnapi->status_blk.msi,
|
|
||||||
bp->status_blk_mapping);
|
|
||||||
bnapi->status_blk.msi = NULL;
|
bnapi->status_blk.msi = NULL;
|
||||||
bp->stats_blk = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bnx2_alloc_mem(struct bnx2 *bp)
|
bnx2_alloc_mem(struct bnx2 *bp)
|
||||||
{
|
{
|
||||||
int i, status_blk_size, err;
|
int i, err;
|
||||||
struct bnx2_napi *bnapi;
|
struct bnx2_napi *bnapi;
|
||||||
void *status_blk;
|
|
||||||
|
|
||||||
/* Combine status and statistics blocks into one allocation. */
|
|
||||||
status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
|
|
||||||
if (bp->flags & BNX2_FLAG_MSIX_CAP)
|
|
||||||
status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
|
|
||||||
BNX2_SBLK_MSIX_ALIGN_SIZE);
|
|
||||||
bp->status_stats_size = status_blk_size +
|
|
||||||
sizeof(struct statistics_block);
|
|
||||||
|
|
||||||
status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
|
|
||||||
&bp->status_blk_mapping, GFP_KERNEL);
|
|
||||||
if (status_blk == NULL)
|
|
||||||
goto alloc_mem_err;
|
|
||||||
|
|
||||||
bnapi = &bp->bnx2_napi[0];
|
bnapi = &bp->bnx2_napi[0];
|
||||||
bnapi->status_blk.msi = status_blk;
|
bnapi->status_blk.msi = bp->status_blk;
|
||||||
bnapi->hw_tx_cons_ptr =
|
bnapi->hw_tx_cons_ptr =
|
||||||
&bnapi->status_blk.msi->status_tx_quick_consumer_index0;
|
&bnapi->status_blk.msi->status_tx_quick_consumer_index0;
|
||||||
bnapi->hw_rx_cons_ptr =
|
bnapi->hw_rx_cons_ptr =
|
||||||
|
@ -870,7 +892,7 @@ bnx2_alloc_mem(struct bnx2 *bp)
|
||||||
|
|
||||||
bnapi = &bp->bnx2_napi[i];
|
bnapi = &bp->bnx2_napi[i];
|
||||||
|
|
||||||
sblk = (status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
|
sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
|
||||||
bnapi->status_blk.msix = sblk;
|
bnapi->status_blk.msix = sblk;
|
||||||
bnapi->hw_tx_cons_ptr =
|
bnapi->hw_tx_cons_ptr =
|
||||||
&sblk->status_tx_quick_consumer_index;
|
&sblk->status_tx_quick_consumer_index;
|
||||||
|
@ -880,10 +902,6 @@ bnx2_alloc_mem(struct bnx2 *bp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bp->stats_blk = status_blk + status_blk_size;
|
|
||||||
|
|
||||||
bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
|
|
||||||
|
|
||||||
if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
|
if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
|
||||||
bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
|
bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
|
||||||
if (bp->ctx_pages == 0)
|
if (bp->ctx_pages == 0)
|
||||||
|
@ -8330,6 +8348,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||||
|
|
||||||
bp->phy_addr = 1;
|
bp->phy_addr = 1;
|
||||||
|
|
||||||
|
/* allocate stats_blk */
|
||||||
|
rc = bnx2_alloc_stats_blk(dev);
|
||||||
|
if (rc)
|
||||||
|
goto err_out_unmap;
|
||||||
|
|
||||||
/* Disable WOL support if we are running on a SERDES chip. */
|
/* Disable WOL support if we are running on a SERDES chip. */
|
||||||
if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
|
if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
|
||||||
bnx2_get_5709_media(bp);
|
bnx2_get_5709_media(bp);
|
||||||
|
@ -8453,6 +8476,8 @@ err_out_disable:
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
|
kfree(bp->temp_stats_blk);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8586,6 +8611,7 @@ error:
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
err_free:
|
err_free:
|
||||||
|
bnx2_free_stats_blk(dev);
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -8603,6 +8629,7 @@ bnx2_remove_one(struct pci_dev *pdev)
|
||||||
|
|
||||||
pci_iounmap(bp->pdev, bp->regview);
|
pci_iounmap(bp->pdev, bp->regview);
|
||||||
|
|
||||||
|
bnx2_free_stats_blk(dev);
|
||||||
kfree(bp->temp_stats_blk);
|
kfree(bp->temp_stats_blk);
|
||||||
|
|
||||||
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
|
if (bp->flags & BNX2_FLAG_AER_ENABLED) {
|
||||||
|
|
|
@ -6928,6 +6928,7 @@ struct bnx2 {
|
||||||
|
|
||||||
dma_addr_t status_blk_mapping;
|
dma_addr_t status_blk_mapping;
|
||||||
|
|
||||||
|
void *status_blk;
|
||||||
struct statistics_block *stats_blk;
|
struct statistics_block *stats_blk;
|
||||||
struct statistics_block *temp_stats_blk;
|
struct statistics_block *temp_stats_blk;
|
||||||
dma_addr_t stats_blk_mapping;
|
dma_addr_t stats_blk_mapping;
|
||||||
|
|
|
@ -1090,10 +1090,6 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
|
||||||
bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));
|
bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));
|
||||||
|
|
||||||
strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
|
strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
|
||||||
info->n_stats = BNX2X_NUM_STATS;
|
|
||||||
info->testinfo_len = BNX2X_NUM_TESTS(bp);
|
|
||||||
info->eedump_len = bp->common.flash_size;
|
|
||||||
info->regdump_len = bnx2x_get_regs_len(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||||
|
|
|
@ -793,7 +793,6 @@ static void bcmgenet_get_drvinfo(struct net_device *dev,
|
||||||
{
|
{
|
||||||
strlcpy(info->driver, "bcmgenet", sizeof(info->driver));
|
strlcpy(info->driver, "bcmgenet", sizeof(info->driver));
|
||||||
strlcpy(info->version, "v2.0", sizeof(info->version));
|
strlcpy(info->version, "v2.0", sizeof(info->version));
|
||||||
info->n_stats = BCMGENET_STATS_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
|
static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
|
||||||
|
|
|
@ -153,7 +153,6 @@ lio_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
|
||||||
strncpy(drvinfo->fw_version, oct->fw_info.liquidio_firmware_version,
|
strncpy(drvinfo->fw_version, oct->fw_info.liquidio_firmware_version,
|
||||||
ETHTOOL_FWVERS_LEN);
|
ETHTOOL_FWVERS_LEN);
|
||||||
strncpy(drvinfo->bus_info, pci_name(oct->pci_dev), 32);
|
strncpy(drvinfo->bus_info, pci_name(oct->pci_dev), 32);
|
||||||
drvinfo->regdump_len = OCT_ETHTOOL_REGDUMP_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -940,6 +940,7 @@ static const char * const devlog_level_strings[] = {
|
||||||
|
|
||||||
static const char * const devlog_facility_strings[] = {
|
static const char * const devlog_facility_strings[] = {
|
||||||
[FW_DEVLOG_FACILITY_CORE] = "CORE",
|
[FW_DEVLOG_FACILITY_CORE] = "CORE",
|
||||||
|
[FW_DEVLOG_FACILITY_CF] = "CF",
|
||||||
[FW_DEVLOG_FACILITY_SCHED] = "SCHED",
|
[FW_DEVLOG_FACILITY_SCHED] = "SCHED",
|
||||||
[FW_DEVLOG_FACILITY_TIMER] = "TIMER",
|
[FW_DEVLOG_FACILITY_TIMER] = "TIMER",
|
||||||
[FW_DEVLOG_FACILITY_RES] = "RES",
|
[FW_DEVLOG_FACILITY_RES] = "RES",
|
||||||
|
@ -1128,18 +1129,26 @@ static const struct file_operations devlog_fops = {
|
||||||
static int mbox_show(struct seq_file *seq, void *v)
|
static int mbox_show(struct seq_file *seq, void *v)
|
||||||
{
|
{
|
||||||
static const char * const owner[] = { "none", "FW", "driver",
|
static const char * const owner[] = { "none", "FW", "driver",
|
||||||
"unknown" };
|
"unknown", "<unread>" };
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
unsigned int mbox = (uintptr_t)seq->private & 7;
|
unsigned int mbox = (uintptr_t)seq->private & 7;
|
||||||
struct adapter *adap = seq->private - mbox;
|
struct adapter *adap = seq->private - mbox;
|
||||||
void __iomem *addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A);
|
void __iomem *addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A);
|
||||||
unsigned int ctrl_reg = (is_t4(adap->params.chip)
|
|
||||||
? CIM_PF_MAILBOX_CTRL_A
|
|
||||||
: CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A);
|
|
||||||
void __iomem *ctrl = adap->regs + PF_REG(mbox, ctrl_reg);
|
|
||||||
|
|
||||||
i = MBOWNER_G(readl(ctrl));
|
/* For T4 we don't have a shadow copy of the Mailbox Control register.
|
||||||
|
* And since reading that real register causes a side effect of
|
||||||
|
* granting ownership, we're best of simply not reading it at all.
|
||||||
|
*/
|
||||||
|
if (is_t4(adap->params.chip)) {
|
||||||
|
i = 4; /* index of "<unread>" */
|
||||||
|
} else {
|
||||||
|
unsigned int ctrl_reg = CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A;
|
||||||
|
void __iomem *ctrl = adap->regs + PF_REG(mbox, ctrl_reg);
|
||||||
|
|
||||||
|
i = MBOWNER_G(readl(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
seq_printf(seq, "mailbox owned by %s\n\n", owner[i]);
|
seq_printf(seq, "mailbox owned by %s\n\n", owner[i]);
|
||||||
|
|
||||||
for (i = 0; i < MBOX_LEN; i += 8)
|
for (i = 0; i < MBOX_LEN; i += 8)
|
||||||
|
|
|
@ -275,7 +275,7 @@ static void link_report(struct net_device *dev)
|
||||||
else {
|
else {
|
||||||
static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" };
|
static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" };
|
||||||
|
|
||||||
const char *s = "10Mbps";
|
const char *s;
|
||||||
const struct port_info *p = netdev_priv(dev);
|
const struct port_info *p = netdev_priv(dev);
|
||||||
|
|
||||||
switch (p->link_cfg.speed) {
|
switch (p->link_cfg.speed) {
|
||||||
|
@ -291,6 +291,10 @@ static void link_report(struct net_device *dev)
|
||||||
case 40000:
|
case 40000:
|
||||||
s = "40Gbps";
|
s = "40Gbps";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
pr_info("%s: unsupported speed: %d\n",
|
||||||
|
dev->name, p->link_cfg.speed);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
|
netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
|
||||||
|
@ -3694,7 +3698,7 @@ static int adap_init0(struct adapter *adap)
|
||||||
t4_get_tp_version(adap, &adap->params.tp_vers);
|
t4_get_tp_version(adap, &adap->params.tp_vers);
|
||||||
ret = t4_check_fw_version(adap);
|
ret = t4_check_fw_version(adap);
|
||||||
/* If firmware is too old (not supported by driver) force an update. */
|
/* If firmware is too old (not supported by driver) force an update. */
|
||||||
if (ret == -EFAULT)
|
if (ret)
|
||||||
state = DEV_STATE_UNINIT;
|
state = DEV_STATE_UNINIT;
|
||||||
if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
|
if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
|
||||||
struct fw_info *fw_info;
|
struct fw_info *fw_info;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -143,6 +143,7 @@ struct enic {
|
||||||
struct vnic_dev *vdev;
|
struct vnic_dev *vdev;
|
||||||
struct timer_list notify_timer;
|
struct timer_list notify_timer;
|
||||||
struct work_struct reset;
|
struct work_struct reset;
|
||||||
|
struct work_struct tx_hang_reset;
|
||||||
struct work_struct change_mtu_work;
|
struct work_struct change_mtu_work;
|
||||||
struct msix_entry msix_entry[ENIC_INTR_MAX];
|
struct msix_entry msix_entry[ENIC_INTR_MAX];
|
||||||
struct enic_msix_entry msix[ENIC_INTR_MAX];
|
struct enic_msix_entry msix[ENIC_INTR_MAX];
|
||||||
|
|
|
@ -178,13 +178,15 @@ static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enic_log_q_error(struct enic *enic)
|
static bool enic_log_q_error(struct enic *enic)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
u32 error_status;
|
u32 error_status;
|
||||||
|
bool err = false;
|
||||||
|
|
||||||
for (i = 0; i < enic->wq_count; i++) {
|
for (i = 0; i < enic->wq_count; i++) {
|
||||||
error_status = vnic_wq_error_status(&enic->wq[i]);
|
error_status = vnic_wq_error_status(&enic->wq[i]);
|
||||||
|
err |= error_status;
|
||||||
if (error_status)
|
if (error_status)
|
||||||
netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
|
netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
|
||||||
i, error_status);
|
i, error_status);
|
||||||
|
@ -192,10 +194,13 @@ static void enic_log_q_error(struct enic *enic)
|
||||||
|
|
||||||
for (i = 0; i < enic->rq_count; i++) {
|
for (i = 0; i < enic->rq_count; i++) {
|
||||||
error_status = vnic_rq_error_status(&enic->rq[i]);
|
error_status = vnic_rq_error_status(&enic->rq[i]);
|
||||||
|
err |= error_status;
|
||||||
if (error_status)
|
if (error_status)
|
||||||
netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
|
netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
|
||||||
i, error_status);
|
i, error_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enic_msglvl_check(struct enic *enic)
|
static void enic_msglvl_check(struct enic *enic)
|
||||||
|
@ -333,10 +338,9 @@ static irqreturn_t enic_isr_msix_err(int irq, void *data)
|
||||||
|
|
||||||
vnic_intr_return_all_credits(&enic->intr[intr]);
|
vnic_intr_return_all_credits(&enic->intr[intr]);
|
||||||
|
|
||||||
enic_log_q_error(enic);
|
if (enic_log_q_error(enic))
|
||||||
|
/* schedule recovery from WQ/RQ error */
|
||||||
/* schedule recovery from WQ/RQ error */
|
schedule_work(&enic->reset);
|
||||||
schedule_work(&enic->reset);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -804,7 +808,7 @@ static void enic_set_rx_mode(struct net_device *netdev)
|
||||||
static void enic_tx_timeout(struct net_device *netdev)
|
static void enic_tx_timeout(struct net_device *netdev)
|
||||||
{
|
{
|
||||||
struct enic *enic = netdev_priv(netdev);
|
struct enic *enic = netdev_priv(netdev);
|
||||||
schedule_work(&enic->reset);
|
schedule_work(&enic->tx_hang_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
|
static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
|
||||||
|
@ -1924,6 +1928,19 @@ static int enic_dev_open(struct enic *enic)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int enic_dev_soft_reset(struct enic *enic)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
|
||||||
|
vnic_dev_soft_reset_done, 0);
|
||||||
|
if (err)
|
||||||
|
netdev_err(enic->netdev, "vNIC soft reset failed, err %d\n",
|
||||||
|
err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int enic_dev_hang_reset(struct enic *enic)
|
static int enic_dev_hang_reset(struct enic *enic)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -2059,6 +2076,26 @@ static void enic_reset(struct work_struct *work)
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
||||||
|
spin_lock(&enic->enic_api_lock);
|
||||||
|
enic_stop(enic->netdev);
|
||||||
|
enic_dev_soft_reset(enic);
|
||||||
|
enic_reset_addr_lists(enic);
|
||||||
|
enic_init_vnic_resources(enic);
|
||||||
|
enic_set_rss_nic_cfg(enic);
|
||||||
|
enic_dev_set_ig_vlan_rewrite_mode(enic);
|
||||||
|
enic_open(enic->netdev);
|
||||||
|
spin_unlock(&enic->enic_api_lock);
|
||||||
|
call_netdevice_notifiers(NETDEV_REBOOT, enic->netdev);
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enic_tx_hang_reset(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct enic *enic = container_of(work, struct enic, tx_hang_reset);
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
|
||||||
spin_lock(&enic->enic_api_lock);
|
spin_lock(&enic->enic_api_lock);
|
||||||
enic_dev_hang_notify(enic);
|
enic_dev_hang_notify(enic);
|
||||||
enic_stop(enic->netdev);
|
enic_stop(enic->netdev);
|
||||||
|
@ -2583,6 +2620,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
|
|
||||||
enic_set_rx_coal_setting(enic);
|
enic_set_rx_coal_setting(enic);
|
||||||
INIT_WORK(&enic->reset, enic_reset);
|
INIT_WORK(&enic->reset, enic_reset);
|
||||||
|
INIT_WORK(&enic->tx_hang_reset, enic_tx_hang_reset);
|
||||||
INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
|
INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
|
||||||
|
|
||||||
for (i = 0; i < enic->wq_count; i++)
|
for (i = 0; i < enic->wq_count; i++)
|
||||||
|
|
|
@ -659,14 +659,14 @@ int vnic_dev_open_done(struct vnic_dev *vdev, int *done)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
|
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
|
||||||
{
|
{
|
||||||
u64 a0 = (u32)arg, a1 = 0;
|
u64 a0 = (u32)arg, a1 = 0;
|
||||||
int wait = 1000;
|
int wait = 1000;
|
||||||
return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait);
|
return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
|
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
|
||||||
{
|
{
|
||||||
u64 a0 = 0, a1 = 0;
|
u64 a0 = 0, a1 = 0;
|
||||||
int wait = 1000;
|
int wait = 1000;
|
||||||
|
|
|
@ -155,7 +155,9 @@ int vnic_dev_deinit(struct vnic_dev *vdev);
|
||||||
void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev);
|
void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev);
|
||||||
int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev);
|
int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev);
|
||||||
int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
|
int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
|
||||||
|
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
|
||||||
int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
|
int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
|
||||||
|
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
|
||||||
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
|
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
|
||||||
enum vnic_dev_intr_mode intr_mode);
|
enum vnic_dev_intr_mode intr_mode);
|
||||||
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
|
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
|
||||||
|
|
|
@ -1597,7 +1597,6 @@ static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
|
||||||
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
|
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
|
||||||
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
||||||
strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
|
strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
|
||||||
info->eedump_len = DE_EEPROM_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int de_get_regs_len(struct net_device *dev)
|
static int de_get_regs_len(struct net_device *dev)
|
||||||
|
|
|
@ -234,9 +234,6 @@ static void be_get_drvinfo(struct net_device *netdev,
|
||||||
|
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->testinfo_len = 0;
|
|
||||||
drvinfo->regdump_len = 0;
|
|
||||||
drvinfo->eedump_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
|
static u32 lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
|
||||||
|
|
|
@ -112,9 +112,8 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 val, tempval;
|
u32 val, tempval;
|
||||||
int inc;
|
int inc;
|
||||||
struct timespec ts;
|
struct timespec64 ts;
|
||||||
u64 ns;
|
u64 ns;
|
||||||
u32 remainder;
|
|
||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (!(fep->hwts_tx_en || fep->hwts_rx_en)) {
|
if (!(fep->hwts_tx_en || fep->hwts_rx_en)) {
|
||||||
|
@ -163,8 +162,7 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
|
||||||
tempval = readl(fep->hwp + FEC_ATIME);
|
tempval = readl(fep->hwp + FEC_ATIME);
|
||||||
/* Convert the ptp local counter to 1588 timestamp */
|
/* Convert the ptp local counter to 1588 timestamp */
|
||||||
ns = timecounter_cyc2time(&fep->tc, tempval);
|
ns = timecounter_cyc2time(&fep->tc, tempval);
|
||||||
ts.tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
|
ts = ns_to_timespec64(ns);
|
||||||
ts.tv_nsec = remainder;
|
|
||||||
|
|
||||||
/* The tempval is less than 3 seconds, and so val is less than
|
/* The tempval is less than 3 seconds, and so val is less than
|
||||||
* 4 seconds. No overflow for 32bit calculation.
|
* 4 seconds. No overflow for 32bit calculation.
|
||||||
|
|
|
@ -907,6 +907,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
|
||||||
if (of_find_property(np, "fsl,magic-packet", NULL))
|
if (of_find_property(np, "fsl,magic-packet", NULL))
|
||||||
priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
|
priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
|
||||||
|
|
||||||
|
if (of_get_property(np, "fsl,wake-on-filer", NULL))
|
||||||
|
priv->device_flags |= FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER;
|
||||||
|
|
||||||
priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
||||||
|
|
||||||
/* In the case of a fixed PHY, the DT node associated
|
/* In the case of a fixed PHY, the DT node associated
|
||||||
|
@ -1415,8 +1418,14 @@ static int gfar_probe(struct platform_device *ofdev)
|
||||||
goto register_fail;
|
goto register_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_set_wakeup_capable(&dev->dev, priv->device_flags &
|
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET)
|
||||||
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
|
priv->wol_supported |= GFAR_WOL_MAGIC;
|
||||||
|
|
||||||
|
if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER) &&
|
||||||
|
priv->rx_filer_enable)
|
||||||
|
priv->wol_supported |= GFAR_WOL_FILER_UCAST;
|
||||||
|
|
||||||
|
device_set_wakeup_capable(&ofdev->dev, priv->wol_supported);
|
||||||
|
|
||||||
/* fill out IRQ number and name fields */
|
/* fill out IRQ number and name fields */
|
||||||
for (i = 0; i < priv->num_grps; i++) {
|
for (i = 0; i < priv->num_grps; i++) {
|
||||||
|
@ -1479,15 +1488,122 @@ static int gfar_remove(struct platform_device *ofdev)
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
|
static void __gfar_filer_disable(struct gfar_private *priv)
|
||||||
|
{
|
||||||
|
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
temp = gfar_read(®s->rctrl);
|
||||||
|
temp &= ~(RCTRL_FILREN | RCTRL_PRSDEP_INIT);
|
||||||
|
gfar_write(®s->rctrl, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __gfar_filer_enable(struct gfar_private *priv)
|
||||||
|
{
|
||||||
|
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
temp = gfar_read(®s->rctrl);
|
||||||
|
temp |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
|
||||||
|
gfar_write(®s->rctrl, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filer rules implementing wol capabilities */
|
||||||
|
static void gfar_filer_config_wol(struct gfar_private *priv)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
u32 rqfcr;
|
||||||
|
|
||||||
|
__gfar_filer_disable(priv);
|
||||||
|
|
||||||
|
/* clear the filer table, reject any packet by default */
|
||||||
|
rqfcr = RQFCR_RJE | RQFCR_CMP_MATCH;
|
||||||
|
for (i = 0; i <= MAX_FILER_IDX; i++)
|
||||||
|
gfar_write_filer(priv, i, rqfcr, 0);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (priv->wol_opts & GFAR_WOL_FILER_UCAST) {
|
||||||
|
/* unicast packet, accept it */
|
||||||
|
struct net_device *ndev = priv->ndev;
|
||||||
|
/* get the default rx queue index */
|
||||||
|
u8 qindex = (u8)priv->gfargrp[0].rx_queue->qindex;
|
||||||
|
u32 dest_mac_addr = (ndev->dev_addr[0] << 16) |
|
||||||
|
(ndev->dev_addr[1] << 8) |
|
||||||
|
ndev->dev_addr[2];
|
||||||
|
|
||||||
|
rqfcr = (qindex << 10) | RQFCR_AND |
|
||||||
|
RQFCR_CMP_EXACT | RQFCR_PID_DAH;
|
||||||
|
|
||||||
|
gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
|
||||||
|
|
||||||
|
dest_mac_addr = (ndev->dev_addr[3] << 16) |
|
||||||
|
(ndev->dev_addr[4] << 8) |
|
||||||
|
ndev->dev_addr[5];
|
||||||
|
rqfcr = (qindex << 10) | RQFCR_GPI |
|
||||||
|
RQFCR_CMP_EXACT | RQFCR_PID_DAL;
|
||||||
|
gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
__gfar_filer_enable(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfar_filer_restore_table(struct gfar_private *priv)
|
||||||
|
{
|
||||||
|
u32 rqfcr, rqfpr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
__gfar_filer_disable(priv);
|
||||||
|
|
||||||
|
for (i = 0; i <= MAX_FILER_IDX; i++) {
|
||||||
|
rqfcr = priv->ftp_rqfcr[i];
|
||||||
|
rqfpr = priv->ftp_rqfpr[i];
|
||||||
|
gfar_write_filer(priv, i, rqfcr, rqfpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
__gfar_filer_enable(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gfar_start() for Rx only and with the FGPI filer interrupt enabled */
|
||||||
|
static void gfar_start_wol_filer(struct gfar_private *priv)
|
||||||
|
{
|
||||||
|
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
||||||
|
u32 tempval;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* Enable Rx hw queues */
|
||||||
|
gfar_write(®s->rqueue, priv->rqueue);
|
||||||
|
|
||||||
|
/* Initialize DMACTRL to have WWR and WOP */
|
||||||
|
tempval = gfar_read(®s->dmactrl);
|
||||||
|
tempval |= DMACTRL_INIT_SETTINGS;
|
||||||
|
gfar_write(®s->dmactrl, tempval);
|
||||||
|
|
||||||
|
/* Make sure we aren't stopped */
|
||||||
|
tempval = gfar_read(®s->dmactrl);
|
||||||
|
tempval &= ~DMACTRL_GRS;
|
||||||
|
gfar_write(®s->dmactrl, tempval);
|
||||||
|
|
||||||
|
for (i = 0; i < priv->num_grps; i++) {
|
||||||
|
regs = priv->gfargrp[i].regs;
|
||||||
|
/* Clear RHLT, so that the DMA starts polling now */
|
||||||
|
gfar_write(®s->rstat, priv->gfargrp[i].rstat);
|
||||||
|
/* enable the Filer General Purpose Interrupt */
|
||||||
|
gfar_write(®s->imask, IMASK_FGPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable Rx DMA */
|
||||||
|
tempval = gfar_read(®s->maccfg1);
|
||||||
|
tempval |= MACCFG1_RX_EN;
|
||||||
|
gfar_write(®s->maccfg1, tempval);
|
||||||
|
}
|
||||||
|
|
||||||
static int gfar_suspend(struct device *dev)
|
static int gfar_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = dev_get_drvdata(dev);
|
struct gfar_private *priv = dev_get_drvdata(dev);
|
||||||
struct net_device *ndev = priv->ndev;
|
struct net_device *ndev = priv->ndev;
|
||||||
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
||||||
u32 tempval;
|
u32 tempval;
|
||||||
int magic_packet = priv->wol_en &&
|
u16 wol = priv->wol_opts;
|
||||||
(priv->device_flags &
|
|
||||||
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
|
|
||||||
|
|
||||||
if (!netif_running(ndev))
|
if (!netif_running(ndev))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1499,7 +1615,7 @@ static int gfar_suspend(struct device *dev)
|
||||||
|
|
||||||
gfar_halt(priv);
|
gfar_halt(priv);
|
||||||
|
|
||||||
if (magic_packet) {
|
if (wol & GFAR_WOL_MAGIC) {
|
||||||
/* Enable interrupt on Magic Packet */
|
/* Enable interrupt on Magic Packet */
|
||||||
gfar_write(®s->imask, IMASK_MAG);
|
gfar_write(®s->imask, IMASK_MAG);
|
||||||
|
|
||||||
|
@ -1513,6 +1629,10 @@ static int gfar_suspend(struct device *dev)
|
||||||
tempval |= MACCFG1_RX_EN;
|
tempval |= MACCFG1_RX_EN;
|
||||||
gfar_write(®s->maccfg1, tempval);
|
gfar_write(®s->maccfg1, tempval);
|
||||||
|
|
||||||
|
} else if (wol & GFAR_WOL_FILER_UCAST) {
|
||||||
|
gfar_filer_config_wol(priv);
|
||||||
|
gfar_start_wol_filer(priv);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
phy_stop(priv->phydev);
|
phy_stop(priv->phydev);
|
||||||
}
|
}
|
||||||
|
@ -1526,18 +1646,22 @@ static int gfar_resume(struct device *dev)
|
||||||
struct net_device *ndev = priv->ndev;
|
struct net_device *ndev = priv->ndev;
|
||||||
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
struct gfar __iomem *regs = priv->gfargrp[0].regs;
|
||||||
u32 tempval;
|
u32 tempval;
|
||||||
int magic_packet = priv->wol_en &&
|
u16 wol = priv->wol_opts;
|
||||||
(priv->device_flags &
|
|
||||||
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
|
|
||||||
|
|
||||||
if (!netif_running(ndev))
|
if (!netif_running(ndev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (magic_packet) {
|
if (wol & GFAR_WOL_MAGIC) {
|
||||||
/* Disable Magic Packet mode */
|
/* Disable Magic Packet mode */
|
||||||
tempval = gfar_read(®s->maccfg2);
|
tempval = gfar_read(®s->maccfg2);
|
||||||
tempval &= ~MACCFG2_MPEN;
|
tempval &= ~MACCFG2_MPEN;
|
||||||
gfar_write(®s->maccfg2, tempval);
|
gfar_write(®s->maccfg2, tempval);
|
||||||
|
|
||||||
|
} else if (wol & GFAR_WOL_FILER_UCAST) {
|
||||||
|
/* need to stop rx only, tx is already down */
|
||||||
|
gfar_halt(priv);
|
||||||
|
gfar_filer_restore_table(priv);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
phy_start(priv->phydev);
|
phy_start(priv->phydev);
|
||||||
}
|
}
|
||||||
|
@ -1998,6 +2122,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
|
||||||
gfar_irq(grp, RX)->irq);
|
gfar_irq(grp, RX)->irq);
|
||||||
goto rx_irq_fail;
|
goto rx_irq_fail;
|
||||||
}
|
}
|
||||||
|
enable_irq_wake(gfar_irq(grp, RX)->irq);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
|
err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
|
||||||
gfar_irq(grp, TX)->name, grp);
|
gfar_irq(grp, TX)->name, grp);
|
||||||
|
@ -2743,7 +2869,14 @@ irqreturn_t gfar_receive(int irq, void *grp_id)
|
||||||
{
|
{
|
||||||
struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
|
struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 imask;
|
u32 imask, ievent;
|
||||||
|
|
||||||
|
ievent = gfar_read(&grp->regs->ievent);
|
||||||
|
|
||||||
|
if (unlikely(ievent & IEVENT_FGPI)) {
|
||||||
|
gfar_write(&grp->regs->ievent, IEVENT_FGPI);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
if (likely(napi_schedule_prep(&grp->napi_rx))) {
|
if (likely(napi_schedule_prep(&grp->napi_rx))) {
|
||||||
spin_lock_irqsave(&grp->grplock, flags);
|
spin_lock_irqsave(&grp->grplock, flags);
|
||||||
|
|
|
@ -340,6 +340,7 @@ extern const char gfar_driver_version[];
|
||||||
#define IEVENT_MAG 0x00000800
|
#define IEVENT_MAG 0x00000800
|
||||||
#define IEVENT_GRSC 0x00000100
|
#define IEVENT_GRSC 0x00000100
|
||||||
#define IEVENT_RXF0 0x00000080
|
#define IEVENT_RXF0 0x00000080
|
||||||
|
#define IEVENT_FGPI 0x00000010
|
||||||
#define IEVENT_FIR 0x00000008
|
#define IEVENT_FIR 0x00000008
|
||||||
#define IEVENT_FIQ 0x00000004
|
#define IEVENT_FIQ 0x00000004
|
||||||
#define IEVENT_DPE 0x00000002
|
#define IEVENT_DPE 0x00000002
|
||||||
|
@ -372,6 +373,7 @@ extern const char gfar_driver_version[];
|
||||||
#define IMASK_MAG 0x00000800
|
#define IMASK_MAG 0x00000800
|
||||||
#define IMASK_GRSC 0x00000100
|
#define IMASK_GRSC 0x00000100
|
||||||
#define IMASK_RXFEN0 0x00000080
|
#define IMASK_RXFEN0 0x00000080
|
||||||
|
#define IMASK_FGPI 0x00000010
|
||||||
#define IMASK_FIR 0x00000008
|
#define IMASK_FIR 0x00000008
|
||||||
#define IMASK_FIQ 0x00000004
|
#define IMASK_FIQ 0x00000004
|
||||||
#define IMASK_DPE 0x00000002
|
#define IMASK_DPE 0x00000002
|
||||||
|
@ -540,6 +542,9 @@ extern const char gfar_driver_version[];
|
||||||
|
|
||||||
#define GFAR_INT_NAME_MAX (IFNAMSIZ + 6) /* '_g#_xx' */
|
#define GFAR_INT_NAME_MAX (IFNAMSIZ + 6) /* '_g#_xx' */
|
||||||
|
|
||||||
|
#define GFAR_WOL_MAGIC 0x00000001
|
||||||
|
#define GFAR_WOL_FILER_UCAST 0x00000002
|
||||||
|
|
||||||
struct txbd8
|
struct txbd8
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
|
@ -917,6 +922,7 @@ struct gfar {
|
||||||
#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200
|
#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200
|
||||||
#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400
|
#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400
|
||||||
#define FSL_GIANFAR_DEV_HAS_TIMER 0x00000800
|
#define FSL_GIANFAR_DEV_HAS_TIMER 0x00000800
|
||||||
|
#define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER 0x00001000
|
||||||
|
|
||||||
#if (MAXGROUPS == 2)
|
#if (MAXGROUPS == 2)
|
||||||
#define DEFAULT_MAPPING 0xAA
|
#define DEFAULT_MAPPING 0xAA
|
||||||
|
@ -1161,8 +1167,6 @@ struct gfar_private {
|
||||||
extended_hash:1,
|
extended_hash:1,
|
||||||
bd_stash_en:1,
|
bd_stash_en:1,
|
||||||
rx_filer_enable:1,
|
rx_filer_enable:1,
|
||||||
/* Wake-on-LAN enabled */
|
|
||||||
wol_en:1,
|
|
||||||
/* Enable priorty based Tx scheduling in Hw */
|
/* Enable priorty based Tx scheduling in Hw */
|
||||||
prio_sched_en:1,
|
prio_sched_en:1,
|
||||||
/* Flow control flags */
|
/* Flow control flags */
|
||||||
|
@ -1191,6 +1195,10 @@ struct gfar_private {
|
||||||
u32 __iomem *hash_regs[16];
|
u32 __iomem *hash_regs[16];
|
||||||
int hash_width;
|
int hash_width;
|
||||||
|
|
||||||
|
/* wake-on-lan settings */
|
||||||
|
u16 wol_opts;
|
||||||
|
u16 wol_supported;
|
||||||
|
|
||||||
/*Filer table*/
|
/*Filer table*/
|
||||||
unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
|
unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
|
||||||
unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
|
unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
|
||||||
|
|
|
@ -182,8 +182,6 @@ static void gfar_gdrvinfo(struct net_device *dev,
|
||||||
sizeof(drvinfo->version));
|
sizeof(drvinfo->version));
|
||||||
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
||||||
strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
|
strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
|
||||||
drvinfo->regdump_len = 0;
|
|
||||||
drvinfo->eedump_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -644,28 +642,49 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
|
|
||||||
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
|
wol->supported = 0;
|
||||||
wol->supported = WAKE_MAGIC;
|
wol->wolopts = 0;
|
||||||
wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0;
|
|
||||||
} else {
|
if (priv->wol_supported & GFAR_WOL_MAGIC)
|
||||||
wol->supported = wol->wolopts = 0;
|
wol->supported |= WAKE_MAGIC;
|
||||||
}
|
|
||||||
|
if (priv->wol_supported & GFAR_WOL_FILER_UCAST)
|
||||||
|
wol->supported |= WAKE_UCAST;
|
||||||
|
|
||||||
|
if (priv->wol_opts & GFAR_WOL_MAGIC)
|
||||||
|
wol->wolopts |= WAKE_MAGIC;
|
||||||
|
|
||||||
|
if (priv->wol_opts & GFAR_WOL_FILER_UCAST)
|
||||||
|
wol->wolopts |= WAKE_UCAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
|
u16 wol_opts = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
|
if (!priv->wol_supported && wol->wolopts)
|
||||||
wol->wolopts != 0)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (wol->wolopts & ~WAKE_MAGIC)
|
if (wol->wolopts & ~(WAKE_MAGIC | WAKE_UCAST))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
|
if (wol->wolopts & WAKE_MAGIC) {
|
||||||
|
wol_opts |= GFAR_WOL_MAGIC;
|
||||||
|
} else {
|
||||||
|
if (wol->wolopts & WAKE_UCAST)
|
||||||
|
wol_opts |= GFAR_WOL_FILER_UCAST;
|
||||||
|
}
|
||||||
|
|
||||||
priv->wol_en = !!device_may_wakeup(&dev->dev);
|
wol_opts &= priv->wol_supported;
|
||||||
|
priv->wol_opts = 0;
|
||||||
|
|
||||||
|
err = device_set_wakeup_enable(priv->dev, wol_opts);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
priv->wol_opts = wol_opts;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,8 +351,6 @@ uec_get_drvinfo(struct net_device *netdev,
|
||||||
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
|
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
|
||||||
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
||||||
strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
|
strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
|
||||||
drvinfo->eedump_len = 0;
|
|
||||||
drvinfo->regdump_len = uec_get_regs_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
|
@ -24,7 +24,6 @@ config HIX5HD2_GMAC
|
||||||
|
|
||||||
config HIP04_ETH
|
config HIP04_ETH
|
||||||
tristate "HISILICON P04 Ethernet support"
|
tristate "HISILICON P04 Ethernet support"
|
||||||
select PHYLIB
|
|
||||||
select MARVELL_PHY
|
select MARVELL_PHY
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
select HNS_MDIO
|
select HNS_MDIO
|
||||||
|
@ -33,8 +32,8 @@ config HIP04_ETH
|
||||||
want to use the internal ethernet then you should answer Y to this.
|
want to use the internal ethernet then you should answer Y to this.
|
||||||
|
|
||||||
config HNS_MDIO
|
config HNS_MDIO
|
||||||
tristate "Hisilicon HNS MDIO device Support"
|
tristate
|
||||||
select MDIO
|
select PHYLIB
|
||||||
---help---
|
---help---
|
||||||
This selects the HNS MDIO support. It is needed by HNS_DSAF to access
|
This selects the HNS MDIO support. It is needed by HNS_DSAF to access
|
||||||
the PHY
|
the PHY
|
||||||
|
|
|
@ -448,12 +448,12 @@ static ssize_t handles_show(struct device *dev,
|
||||||
s += sprintf(buf + s, "handle %d (eport_id=%u from %s):\n",
|
s += sprintf(buf + s, "handle %d (eport_id=%u from %s):\n",
|
||||||
i++, h->eport_id, h->dev->name);
|
i++, h->eport_id, h->dev->name);
|
||||||
for (j = 0; j < h->q_num; j++) {
|
for (j = 0; j < h->q_num; j++) {
|
||||||
s += sprintf(buf + s, "\tqueue[%d] on 0x%llx\n",
|
s += sprintf(buf + s, "\tqueue[%d] on %p\n",
|
||||||
j, (u64)h->qs[i]->io_base);
|
j, h->qs[i]->io_base);
|
||||||
#define HANDEL_TX_MSG "\t\ttx_ring on 0x%llx:%u,%u,%u,%u,%u,%llu,%llu\n"
|
#define HANDEL_TX_MSG "\t\ttx_ring on %p:%u,%u,%u,%u,%u,%llu,%llu\n"
|
||||||
s += sprintf(buf + s,
|
s += sprintf(buf + s,
|
||||||
HANDEL_TX_MSG,
|
HANDEL_TX_MSG,
|
||||||
(u64)h->qs[i]->tx_ring.io_base,
|
h->qs[i]->tx_ring.io_base,
|
||||||
h->qs[i]->tx_ring.buf_size,
|
h->qs[i]->tx_ring.buf_size,
|
||||||
h->qs[i]->tx_ring.desc_num,
|
h->qs[i]->tx_ring.desc_num,
|
||||||
h->qs[i]->tx_ring.max_desc_num_per_pkt,
|
h->qs[i]->tx_ring.max_desc_num_per_pkt,
|
||||||
|
@ -462,8 +462,8 @@ static ssize_t handles_show(struct device *dev,
|
||||||
h->qs[i]->tx_ring.stats.sw_err_cnt,
|
h->qs[i]->tx_ring.stats.sw_err_cnt,
|
||||||
h->qs[i]->tx_ring.stats.io_err_cnt);
|
h->qs[i]->tx_ring.stats.io_err_cnt);
|
||||||
s += sprintf(buf + s,
|
s += sprintf(buf + s,
|
||||||
"\t\trx_ring on 0x%llx:%u,%u,%llu,%llu,%llu\n",
|
"\t\trx_ring on %p:%u,%u,%llu,%llu,%llu\n",
|
||||||
(u64)h->qs[i]->rx_ring.io_base,
|
h->qs[i]->rx_ring.io_base,
|
||||||
h->qs[i]->rx_ring.buf_size,
|
h->qs[i]->rx_ring.buf_size,
|
||||||
h->qs[i]->rx_ring.desc_num,
|
h->qs[i]->rx_ring.desc_num,
|
||||||
h->qs[i]->rx_ring.stats.sw_err_cnt,
|
h->qs[i]->rx_ring.stats.sw_err_cnt,
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#define HNAE_DRIVER_VERSION "1.3.0"
|
#define HNAE_DRIVER_VERSION "1.3.0"
|
||||||
|
@ -429,6 +430,7 @@ struct hnae_ae_ops {
|
||||||
void (*set_coalesce_usecs)(struct hnae_handle *handle, u32 timeout);
|
void (*set_coalesce_usecs)(struct hnae_handle *handle, u32 timeout);
|
||||||
int (*set_coalesce_frames)(struct hnae_handle *handle,
|
int (*set_coalesce_frames)(struct hnae_handle *handle,
|
||||||
u32 coalesce_frames);
|
u32 coalesce_frames);
|
||||||
|
void (*set_promisc_mode)(struct hnae_handle *handle, u32 en);
|
||||||
int (*get_mac_addr)(struct hnae_handle *handle, void **p);
|
int (*get_mac_addr)(struct hnae_handle *handle, void **p);
|
||||||
int (*set_mac_addr)(struct hnae_handle *handle, void *p);
|
int (*set_mac_addr)(struct hnae_handle *handle, void *p);
|
||||||
int (*set_mc_addr)(struct hnae_handle *handle, void *addr);
|
int (*set_mc_addr)(struct hnae_handle *handle, void *addr);
|
||||||
|
|
|
@ -392,6 +392,11 @@ static int hns_ae_set_autoneg(struct hnae_handle *handle, u8 enable)
|
||||||
return hns_mac_set_autoneg(hns_get_mac_cb(handle), enable);
|
return hns_mac_set_autoneg(hns_get_mac_cb(handle), enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hns_ae_set_promisc_mode(struct hnae_handle *handle, u32 en)
|
||||||
|
{
|
||||||
|
hns_dsaf_set_promisc_mode(hns_ae_get_dsaf_dev(handle->dev), en);
|
||||||
|
}
|
||||||
|
|
||||||
static int hns_ae_get_autoneg(struct hnae_handle *handle)
|
static int hns_ae_get_autoneg(struct hnae_handle *handle)
|
||||||
{
|
{
|
||||||
u32 auto_neg;
|
u32 auto_neg;
|
||||||
|
@ -748,6 +753,7 @@ static struct hnae_ae_ops hns_dsaf_ops = {
|
||||||
.get_rx_max_coalesced_frames = hns_ae_get_rx_max_coalesced_frames,
|
.get_rx_max_coalesced_frames = hns_ae_get_rx_max_coalesced_frames,
|
||||||
.set_coalesce_usecs = hns_ae_set_coalesce_usecs,
|
.set_coalesce_usecs = hns_ae_set_coalesce_usecs,
|
||||||
.set_coalesce_frames = hns_ae_set_coalesce_frames,
|
.set_coalesce_frames = hns_ae_set_coalesce_frames,
|
||||||
|
.set_promisc_mode = hns_ae_set_promisc_mode,
|
||||||
.set_mac_addr = hns_ae_set_mac_address,
|
.set_mac_addr = hns_ae_set_mac_address,
|
||||||
.set_mc_addr = hns_ae_set_multicast_one,
|
.set_mc_addr = hns_ae_set_multicast_one,
|
||||||
.set_mtu = hns_ae_set_mtu,
|
.set_mtu = hns_ae_set_mtu,
|
||||||
|
|
|
@ -744,9 +744,11 @@ int hns_mac_get_cfg(struct dsaf_device *dsaf_dev, int mac_idx)
|
||||||
mac_cb->serdes_vaddr = dsaf_dev->sds_base;
|
mac_cb->serdes_vaddr = dsaf_dev->sds_base;
|
||||||
|
|
||||||
if (dsaf_dev->cpld_base &&
|
if (dsaf_dev->cpld_base &&
|
||||||
mac_idx < DSAF_SERVICE_PORT_NUM_PER_DSAF)
|
mac_idx < DSAF_SERVICE_PORT_NUM_PER_DSAF) {
|
||||||
mac_cb->cpld_vaddr = dsaf_dev->cpld_base +
|
mac_cb->cpld_vaddr = dsaf_dev->cpld_base +
|
||||||
mac_cb->mac_id * CPLD_ADDR_PORT_OFFSET;
|
mac_cb->mac_id * CPLD_ADDR_PORT_OFFSET;
|
||||||
|
cpld_led_reset(mac_cb);
|
||||||
|
}
|
||||||
mac_cb->sfp_prsnt = 0;
|
mac_cb->sfp_prsnt = 0;
|
||||||
mac_cb->txpkt_for_led = 0;
|
mac_cb->txpkt_for_led = 0;
|
||||||
mac_cb->rxpkt_for_led = 0;
|
mac_cb->rxpkt_for_led = 0;
|
||||||
|
|
|
@ -217,6 +217,25 @@ hns_dsaf_ppe_qid_cfg(struct dsaf_device *dsaf_dev, u32 qid_cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hns_dsaf_mix_def_qid_cfg(struct dsaf_device *dsaf_dev)
|
||||||
|
{
|
||||||
|
u16 max_q_per_vf, max_vfn;
|
||||||
|
u32 q_id, q_num_per_port;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
hns_rcb_get_queue_mode(dsaf_dev->dsaf_mode,
|
||||||
|
HNS_DSAF_COMM_SERVICE_NW_IDX,
|
||||||
|
&max_vfn, &max_q_per_vf);
|
||||||
|
q_num_per_port = max_vfn * max_q_per_vf;
|
||||||
|
|
||||||
|
for (i = 0, q_id = 0; i < DSAF_SERVICE_NW_NUM; i++) {
|
||||||
|
dsaf_set_dev_field(dsaf_dev,
|
||||||
|
DSAF_MIX_DEF_QID_0_REG + 0x0004 * i,
|
||||||
|
0xff, 0, q_id);
|
||||||
|
q_id += q_num_per_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hns_dsaf_sw_port_type_cfg - cfg sw type
|
* hns_dsaf_sw_port_type_cfg - cfg sw type
|
||||||
* @dsaf_id: dsa fabric id
|
* @dsaf_id: dsa fabric id
|
||||||
|
@ -592,6 +611,11 @@ static void hns_dsaf_tbl_tcam_data_ucast_pul(
|
||||||
dsaf_write_dev(dsaf_dev, DSAF_TBL_PUL_0_REG, o_tbl_pul);
|
dsaf_write_dev(dsaf_dev, DSAF_TBL_PUL_0_REG, o_tbl_pul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en)
|
||||||
|
{
|
||||||
|
dsaf_set_dev_bit(dsaf_dev, DSAF_CFG_0_REG, DSAF_CFG_MIX_MODE_S, !!en);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hns_dsaf_tbl_stat_en - tbl
|
* hns_dsaf_tbl_stat_en - tbl
|
||||||
* @dsaf_id: dsa fabric id
|
* @dsaf_id: dsa fabric id
|
||||||
|
@ -920,6 +944,9 @@ static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)
|
||||||
/* set 22 queue per tx ppe engine, only used in switch mode */
|
/* set 22 queue per tx ppe engine, only used in switch mode */
|
||||||
hns_dsaf_ppe_qid_cfg(dsaf_dev, DSAF_DEFAUTL_QUEUE_NUM_PER_PPE);
|
hns_dsaf_ppe_qid_cfg(dsaf_dev, DSAF_DEFAUTL_QUEUE_NUM_PER_PPE);
|
||||||
|
|
||||||
|
/* set promisc def queue id */
|
||||||
|
hns_dsaf_mix_def_qid_cfg(dsaf_dev);
|
||||||
|
|
||||||
/* in non switch mode, set all port to access mode */
|
/* in non switch mode, set all port to access mode */
|
||||||
hns_dsaf_sw_port_type_cfg(dsaf_dev, DSAF_SW_PORT_TYPE_NON_VLAN);
|
hns_dsaf_sw_port_type_cfg(dsaf_dev, DSAF_SW_PORT_TYPE_NON_VLAN);
|
||||||
|
|
||||||
|
|
|
@ -423,5 +423,6 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port);
|
||||||
|
|
||||||
void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);
|
void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);
|
||||||
int hns_dsaf_get_regs_count(void);
|
int hns_dsaf_get_regs_count(void);
|
||||||
|
void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en);
|
||||||
|
|
||||||
#endif /* __HNS_DSAF_MAIN_H__ */
|
#endif /* __HNS_DSAF_MAIN_H__ */
|
||||||
|
|
|
@ -575,8 +575,8 @@ int hns_rcb_set_coalesced_frames(struct dsaf_device *dsaf_dev,
|
||||||
*@max_vfn : max vfn number
|
*@max_vfn : max vfn number
|
||||||
*@max_q_per_vf:max ring number per vm
|
*@max_q_per_vf:max ring number per vm
|
||||||
*/
|
*/
|
||||||
static void hns_rcb_get_queue_mode(enum dsaf_mode dsaf_mode, int comm_index,
|
void hns_rcb_get_queue_mode(enum dsaf_mode dsaf_mode, int comm_index,
|
||||||
u16 *max_vfn, u16 *max_q_per_vf)
|
u16 *max_vfn, u16 *max_q_per_vf)
|
||||||
{
|
{
|
||||||
if (comm_index == HNS_DSAF_COMM_SERVICE_NW_IDX) {
|
if (comm_index == HNS_DSAF_COMM_SERVICE_NW_IDX) {
|
||||||
switch (dsaf_mode) {
|
switch (dsaf_mode) {
|
||||||
|
|
|
@ -107,6 +107,8 @@ int hns_rcb_common_init_hw(struct rcb_common_cb *rcb_common);
|
||||||
void hns_rcb_start(struct hnae_queue *q, u32 val);
|
void hns_rcb_start(struct hnae_queue *q, u32 val);
|
||||||
void hns_rcb_get_cfg(struct rcb_common_cb *rcb_common);
|
void hns_rcb_get_cfg(struct rcb_common_cb *rcb_common);
|
||||||
void hns_rcb_common_init_commit_hw(struct rcb_common_cb *rcb_common);
|
void hns_rcb_common_init_commit_hw(struct rcb_common_cb *rcb_common);
|
||||||
|
void hns_rcb_get_queue_mode(enum dsaf_mode dsaf_mode, int comm_index,
|
||||||
|
u16 *max_vfn, u16 *max_q_per_vf);
|
||||||
|
|
||||||
void hns_rcb_ring_enable_hw(struct hnae_queue *q, u32 val);
|
void hns_rcb_ring_enable_hw(struct hnae_queue *q, u32 val);
|
||||||
void hns_rcb_int_clr_hw(struct hnae_queue *q, u32 flag);
|
void hns_rcb_int_clr_hw(struct hnae_queue *q, u32 flag);
|
||||||
|
|
|
@ -51,9 +51,9 @@ static const struct mac_stats_string g_xgmac_stats_string[] = {
|
||||||
{"xgmac_rx_bad_pkt_from_dsaf", MAC_STATS_FIELD_OFF(rx_bad_from_sw)},
|
{"xgmac_rx_bad_pkt_from_dsaf", MAC_STATS_FIELD_OFF(rx_bad_from_sw)},
|
||||||
{"xgmac_tx_bad_pkt_64tomax", MAC_STATS_FIELD_OFF(tx_bad_pkts)},
|
{"xgmac_tx_bad_pkt_64tomax", MAC_STATS_FIELD_OFF(tx_bad_pkts)},
|
||||||
|
|
||||||
{"xgmac_rx_not_well_pkt", MAC_STATS_FIELD_OFF(rx_fragment_err)},
|
{"xgmac_rx_bad_pkts_minto64", MAC_STATS_FIELD_OFF(rx_fragment_err)},
|
||||||
{"xgmac_rx_good_well_pkt", MAC_STATS_FIELD_OFF(rx_undersize)},
|
{"xgmac_rx_good_pkts_minto64", MAC_STATS_FIELD_OFF(rx_undersize)},
|
||||||
{"xgmac_rx_total_pkt", MAC_STATS_FIELD_OFF(rx_under_min)},
|
{"xgmac_rx_total_pkts_minto64", MAC_STATS_FIELD_OFF(rx_under_min)},
|
||||||
{"xgmac_rx_pkt_64", MAC_STATS_FIELD_OFF(rx_64bytes)},
|
{"xgmac_rx_pkt_64", MAC_STATS_FIELD_OFF(rx_64bytes)},
|
||||||
{"xgmac_rx_pkt_65to127", MAC_STATS_FIELD_OFF(rx_65to127)},
|
{"xgmac_rx_pkt_65to127", MAC_STATS_FIELD_OFF(rx_65to127)},
|
||||||
{"xgmac_rx_pkt_128to255", MAC_STATS_FIELD_OFF(rx_128to255)},
|
{"xgmac_rx_pkt_128to255", MAC_STATS_FIELD_OFF(rx_128to255)},
|
||||||
|
|
|
@ -1161,6 +1161,21 @@ void hns_set_multicast_list(struct net_device *ndev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hns_nic_set_rx_mode(struct net_device *ndev)
|
||||||
|
{
|
||||||
|
struct hns_nic_priv *priv = netdev_priv(ndev);
|
||||||
|
struct hnae_handle *h = priv->ae_handle;
|
||||||
|
|
||||||
|
if (h->dev->ops->set_promisc_mode) {
|
||||||
|
if (ndev->flags & IFF_PROMISC)
|
||||||
|
h->dev->ops->set_promisc_mode(h, 1);
|
||||||
|
else
|
||||||
|
h->dev->ops->set_promisc_mode(h, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
hns_set_multicast_list(ndev);
|
||||||
|
}
|
||||||
|
|
||||||
struct rtnl_link_stats64 *hns_nic_get_stats64(struct net_device *ndev,
|
struct rtnl_link_stats64 *hns_nic_get_stats64(struct net_device *ndev,
|
||||||
struct rtnl_link_stats64 *stats)
|
struct rtnl_link_stats64 *stats)
|
||||||
{
|
{
|
||||||
|
@ -1220,7 +1235,7 @@ static const struct net_device_ops hns_nic_netdev_ops = {
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = hns_nic_poll_controller,
|
.ndo_poll_controller = hns_nic_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
.ndo_set_rx_mode = hns_set_multicast_list,
|
.ndo_set_rx_mode = hns_nic_set_rx_mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hns_nic_update_link_status(struct net_device *netdev)
|
static void hns_nic_update_link_status(struct net_device *netdev)
|
||||||
|
|
|
@ -682,7 +682,6 @@ static void hns_nic_get_drvinfo(struct net_device *net_dev,
|
||||||
drvinfo->bus_info[ETHTOOL_BUSINFO_LEN - 1] = '\0';
|
drvinfo->bus_info[ETHTOOL_BUSINFO_LEN - 1] = '\0';
|
||||||
|
|
||||||
strncpy(drvinfo->fw_version, "N/A", ETHTOOL_FWVERS_LEN);
|
strncpy(drvinfo->fw_version, "N/A", ETHTOOL_FWVERS_LEN);
|
||||||
drvinfo->eedump_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2204,7 +2204,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
|
||||||
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
|
||||||
snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
|
snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
|
||||||
dev->cell_index, dev->ofdev->dev.of_node->full_name);
|
dev->cell_index, dev->ofdev->dev.of_node->full_name);
|
||||||
info->regdump_len = emac_ethtool_get_regs_len(ndev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ethtool_ops emac_ethtool_ops = {
|
static const struct ethtool_ops emac_ethtool_ops = {
|
||||||
|
|
|
@ -559,8 +559,6 @@ static void e1000_get_drvinfo(struct net_device *netdev,
|
||||||
|
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->regdump_len = e1000_get_regs_len(netdev);
|
|
||||||
drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void e1000_get_ringparam(struct net_device *netdev,
|
static void e1000_get_ringparam(struct net_device *netdev,
|
||||||
|
|
|
@ -3820,7 +3820,7 @@ static int e1000_clean(struct napi_struct *napi, int budget)
|
||||||
if (work_done < budget) {
|
if (work_done < budget) {
|
||||||
if (likely(adapter->itr_setting & 3))
|
if (likely(adapter->itr_setting & 3))
|
||||||
e1000_set_itr(adapter);
|
e1000_set_itr(adapter);
|
||||||
napi_complete(napi);
|
napi_complete_done(napi, work_done);
|
||||||
if (!test_bit(__E1000_DOWN, &adapter->flags))
|
if (!test_bit(__E1000_DOWN, &adapter->flags))
|
||||||
e1000_irq_enable(adapter);
|
e1000_irq_enable(adapter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -648,8 +648,6 @@ static void e1000_get_drvinfo(struct net_device *netdev,
|
||||||
|
|
||||||
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||||
sizeof(drvinfo->bus_info));
|
sizeof(drvinfo->bus_info));
|
||||||
drvinfo->regdump_len = e1000_get_regs_len(netdev);
|
|
||||||
drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void e1000_get_ringparam(struct net_device *netdev,
|
static void e1000_get_ringparam(struct net_device *netdev,
|
||||||
|
|
|
@ -2693,7 +2693,7 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
|
||||||
if (work_done < weight) {
|
if (work_done < weight) {
|
||||||
if (adapter->itr_setting & 3)
|
if (adapter->itr_setting & 3)
|
||||||
e1000_set_itr(adapter);
|
e1000_set_itr(adapter);
|
||||||
napi_complete(napi);
|
napi_complete_done(napi, work_done);
|
||||||
if (!test_bit(__E1000_DOWN, &adapter->state)) {
|
if (!test_bit(__E1000_DOWN, &adapter->state)) {
|
||||||
if (adapter->msix_entries)
|
if (adapter->msix_entries)
|
||||||
ew32(IMS, adapter->rx_ring->ims_val);
|
ew32(IMS, adapter->rx_ring->ims_val);
|
||||||
|
|
|
@ -176,7 +176,7 @@ void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Generate a folder for each q_vector */
|
/* Generate a folder for each q_vector */
|
||||||
sprintf(name, "q_vector.%03d", q_vector->v_idx);
|
snprintf(name, sizeof(name), "q_vector.%03d", q_vector->v_idx);
|
||||||
|
|
||||||
q_vector->dbg_q_vector = debugfs_create_dir(name, interface->dbg_intfc);
|
q_vector->dbg_q_vector = debugfs_create_dir(name, interface->dbg_intfc);
|
||||||
if (!q_vector->dbg_q_vector)
|
if (!q_vector->dbg_q_vector)
|
||||||
|
@ -186,7 +186,7 @@ void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector)
|
||||||
for (i = 0; i < q_vector->tx.count; i++) {
|
for (i = 0; i < q_vector->tx.count; i++) {
|
||||||
struct fm10k_ring *ring = &q_vector->tx.ring[i];
|
struct fm10k_ring *ring = &q_vector->tx.ring[i];
|
||||||
|
|
||||||
sprintf(name, "tx_ring.%03d", ring->queue_index);
|
snprintf(name, sizeof(name), "tx_ring.%03d", ring->queue_index);
|
||||||
|
|
||||||
debugfs_create_file(name, 0600,
|
debugfs_create_file(name, 0600,
|
||||||
q_vector->dbg_q_vector, ring,
|
q_vector->dbg_q_vector, ring,
|
||||||
|
@ -197,7 +197,7 @@ void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector)
|
||||||
for (i = 0; i < q_vector->rx.count; i++) {
|
for (i = 0; i < q_vector->rx.count; i++) {
|
||||||
struct fm10k_ring *ring = &q_vector->rx.ring[i];
|
struct fm10k_ring *ring = &q_vector->rx.ring[i];
|
||||||
|
|
||||||
sprintf(name, "rx_ring.%03d", ring->queue_index);
|
snprintf(name, sizeof(name), "rx_ring.%03d", ring->queue_index);
|
||||||
|
|
||||||
debugfs_create_file(name, 0600,
|
debugfs_create_file(name, 0600,
|
||||||
q_vector->dbg_q_vector, ring,
|
q_vector->dbg_q_vector, ring,
|
||||||
|
|
|
@ -206,13 +206,13 @@ static void fm10k_get_stat_strings(struct net_device *dev, u8 *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < interface->hw.mac.max_queues; i++) {
|
for (i = 0; i < interface->hw.mac.max_queues; i++) {
|
||||||
sprintf(p, "tx_queue_%u_packets", i);
|
snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_packets", i);
|
||||||
p += ETH_GSTRING_LEN;
|
p += ETH_GSTRING_LEN;
|
||||||
sprintf(p, "tx_queue_%u_bytes", i);
|
snprintf(p, ETH_GSTRING_LEN, "tx_queue_%u_bytes", i);
|
||||||
p += ETH_GSTRING_LEN;
|
p += ETH_GSTRING_LEN;
|
||||||
sprintf(p, "rx_queue_%u_packets", i);
|
snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_packets", i);
|
||||||
p += ETH_GSTRING_LEN;
|
p += ETH_GSTRING_LEN;
|
||||||
sprintf(p, "rx_queue_%u_bytes", i);
|
snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_bytes", i);
|
||||||
p += ETH_GSTRING_LEN;
|
p += ETH_GSTRING_LEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,10 +515,6 @@ static void fm10k_get_drvinfo(struct net_device *dev,
|
||||||
sizeof(info->version) - 1);
|
sizeof(info->version) - 1);
|
||||||
strncpy(info->bus_info, pci_name(interface->pdev),
|
strncpy(info->bus_info, pci_name(interface->pdev),
|
||||||
sizeof(info->bus_info) - 1);
|
sizeof(info->bus_info) - 1);
|
||||||
|
|
||||||
info->n_stats = fm10k_get_sset_count(dev, ETH_SS_STATS);
|
|
||||||
|
|
||||||
info->regdump_len = fm10k_get_regs_len(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fm10k_get_pauseparam(struct net_device *dev,
|
static void fm10k_get_pauseparam(struct net_device *dev,
|
||||||
|
|
|
@ -593,9 +593,9 @@ static void fm10k_receive_skb(struct fm10k_q_vector *q_vector,
|
||||||
napi_gro_receive(&q_vector->napi, skb);
|
napi_gro_receive(&q_vector->napi, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector,
|
static int fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector,
|
||||||
struct fm10k_ring *rx_ring,
|
struct fm10k_ring *rx_ring,
|
||||||
int budget)
|
int budget)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = rx_ring->skb;
|
struct sk_buff *skb = rx_ring->skb;
|
||||||
unsigned int total_bytes = 0, total_packets = 0;
|
unsigned int total_bytes = 0, total_packets = 0;
|
||||||
|
@ -662,7 +662,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector,
|
||||||
q_vector->rx.total_packets += total_packets;
|
q_vector->rx.total_packets += total_packets;
|
||||||
q_vector->rx.total_bytes += total_bytes;
|
q_vector->rx.total_bytes += total_bytes;
|
||||||
|
|
||||||
return total_packets < budget;
|
return total_packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VXLAN_HLEN (sizeof(struct udphdr) + 8)
|
#define VXLAN_HLEN (sizeof(struct udphdr) + 8)
|
||||||
|
@ -1422,7 +1422,7 @@ static int fm10k_poll(struct napi_struct *napi, int budget)
|
||||||
struct fm10k_q_vector *q_vector =
|
struct fm10k_q_vector *q_vector =
|
||||||
container_of(napi, struct fm10k_q_vector, napi);
|
container_of(napi, struct fm10k_q_vector, napi);
|
||||||
struct fm10k_ring *ring;
|
struct fm10k_ring *ring;
|
||||||
int per_ring_budget;
|
int per_ring_budget, work_done = 0;
|
||||||
bool clean_complete = true;
|
bool clean_complete = true;
|
||||||
|
|
||||||
fm10k_for_each_ring(ring, q_vector->tx)
|
fm10k_for_each_ring(ring, q_vector->tx)
|
||||||
|
@ -1436,16 +1436,19 @@ static int fm10k_poll(struct napi_struct *napi, int budget)
|
||||||
else
|
else
|
||||||
per_ring_budget = budget;
|
per_ring_budget = budget;
|
||||||
|
|
||||||
fm10k_for_each_ring(ring, q_vector->rx)
|
fm10k_for_each_ring(ring, q_vector->rx) {
|
||||||
clean_complete &= fm10k_clean_rx_irq(q_vector, ring,
|
int work = fm10k_clean_rx_irq(q_vector, ring, per_ring_budget);
|
||||||
per_ring_budget);
|
|
||||||
|
work_done += work;
|
||||||
|
clean_complete &= !!(work < per_ring_budget);
|
||||||
|
}
|
||||||
|
|
||||||
/* If all work not completed, return budget and keep polling */
|
/* If all work not completed, return budget and keep polling */
|
||||||
if (!clean_complete)
|
if (!clean_complete)
|
||||||
return budget;
|
return budget;
|
||||||
|
|
||||||
/* all work done, exit the polling mode */
|
/* all work done, exit the polling mode */
|
||||||
napi_complete(napi);
|
napi_complete_done(napi, work_done);
|
||||||
|
|
||||||
/* re-enable the q_vector */
|
/* re-enable the q_vector */
|
||||||
fm10k_qv_enable(q_vector);
|
fm10k_qv_enable(q_vector);
|
||||||
|
@ -1905,7 +1908,7 @@ static void fm10k_init_reta(struct fm10k_intfc *interface)
|
||||||
u32 reta, base;
|
u32 reta, base;
|
||||||
|
|
||||||
/* If the netdev is initialized we have to maintain table if possible */
|
/* If the netdev is initialized we have to maintain table if possible */
|
||||||
if (interface->netdev->reg_state) {
|
if (interface->netdev->reg_state != NETREG_UNINITIALIZED) {
|
||||||
for (i = FM10K_RETA_SIZE; i--;) {
|
for (i = FM10K_RETA_SIZE; i--;) {
|
||||||
reta = interface->reta[i];
|
reta = interface->reta[i];
|
||||||
if ((((reta << 24) >> 24) < rss_i) &&
|
if ((((reta << 24) >> 24) < rss_i) &&
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue