Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1287 commits) icmp: Fix regression in nexthop resolution during replies. net: Fix ppc64 BPF JIT dependencies. acenic: include NET_SKB_PAD headroom to incoming skbs ixgbe: convert to ndo_fix_features ixgbe: only enable WoL for magic packet by default ixgbe: remove ifdef check for non-existent define ixgbe: Pass staterr instead of re-reading status and error bits from descriptor ixgbe: Move interrupt related values out of ring and into q_vector ixgbe: add structure for containing RX/TX rings to q_vector ixgbe: inline the ixgbe_maybe_stop_tx function ixgbe: Update ATR to use recorded TX queues instead of CPU for routing igb: Fix for DH89xxCC near end loopback test e1000: always call e1000_check_for_link() on e1000_ce4100 MACs. netxen: add fw version compatibility check be2net: request native mode each time the card is reset ipv4: Constrain UFO fragment sizes to multiples of 8 bytes virtio_net: Fix panic in virtnet_remove ipv6: make fragment identifications less predictable ipv6: unshare inetpeers can: make function can_get_bittiming static ...
This commit is contained in:
commit
951cc93a74
|
@ -402,8 +402,9 @@
|
|||
!Finclude/net/mac80211.h set_key_cmd
|
||||
!Finclude/net/mac80211.h ieee80211_key_conf
|
||||
!Finclude/net/mac80211.h ieee80211_key_flags
|
||||
!Finclude/net/mac80211.h ieee80211_tkip_key_type
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_key
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p2k
|
||||
!Finclude/net/mac80211.h ieee80211_key_removed
|
||||
</chapter>
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ int main(int argc, char *argv[])
|
|||
case 'V': opt_V++; exclusive++; break;
|
||||
|
||||
case '?':
|
||||
fprintf(stderr, usage_msg);
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
|
@ -268,13 +268,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
/* options check */
|
||||
if (exclusive > 1) {
|
||||
fprintf(stderr, usage_msg);
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_v || opt_V) {
|
||||
printf(version);
|
||||
printf("%s", version);
|
||||
if (opt_V) {
|
||||
res = 0;
|
||||
goto out;
|
||||
|
@ -282,14 +282,14 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if (opt_u) {
|
||||
printf(usage_msg);
|
||||
printf("%s", usage_msg);
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_h) {
|
||||
printf(usage_msg);
|
||||
printf(help_msg);
|
||||
printf("%s", usage_msg);
|
||||
printf("%s", help_msg);
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ int main(int argc, char *argv[])
|
|||
goto out;
|
||||
} else {
|
||||
/* Just show usage */
|
||||
fprintf(stderr, usage_msg);
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ int main(int argc, char *argv[])
|
|||
master_ifname = *spp++;
|
||||
|
||||
if (master_ifname == NULL) {
|
||||
fprintf(stderr, usage_msg);
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (slave_ifname == NULL) {
|
||||
if (opt_d || opt_c) {
|
||||
fprintf(stderr, usage_msg);
|
||||
fprintf(stderr, "%s", usage_msg);
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -106,16 +106,6 @@ inet_peer_maxttl - INTEGER
|
|||
when the number of entries in the pool is very small).
|
||||
Measured in seconds.
|
||||
|
||||
inet_peer_gc_mintime - INTEGER
|
||||
Minimum interval between garbage collection passes. This interval is
|
||||
in effect under high memory pressure on the pool.
|
||||
Measured in seconds.
|
||||
|
||||
inet_peer_gc_maxtime - INTEGER
|
||||
Minimum interval between garbage collection passes. This interval is
|
||||
in effect under low (or absent) memory pressure on the pool.
|
||||
Measured in seconds.
|
||||
|
||||
TCP variables:
|
||||
|
||||
somaxconn - INTEGER
|
||||
|
@ -394,7 +384,7 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
|
|||
min: Minimal size of receive buffer used by TCP sockets.
|
||||
It is guaranteed to each TCP socket, even under moderate memory
|
||||
pressure.
|
||||
Default: 8K
|
||||
Default: 1 page
|
||||
|
||||
default: initial size of receive buffer used by TCP sockets.
|
||||
This value overrides net.core.rmem_default used by other protocols.
|
||||
|
@ -483,7 +473,7 @@ tcp_window_scaling - BOOLEAN
|
|||
tcp_wmem - vector of 3 INTEGERs: min, default, max
|
||||
min: Amount of memory reserved for send buffers for TCP sockets.
|
||||
Each TCP socket has rights to use it due to fact of its birth.
|
||||
Default: 4K
|
||||
Default: 1 page
|
||||
|
||||
default: initial size of send buffer used by TCP sockets. This
|
||||
value overrides net.core.wmem_default used by other protocols.
|
||||
|
@ -553,13 +543,13 @@ udp_rmem_min - INTEGER
|
|||
Minimal size of receive buffer used by UDP sockets in moderation.
|
||||
Each UDP socket is able to use the size for receiving data, even if
|
||||
total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
|
||||
Default: 4096
|
||||
Default: 1 page
|
||||
|
||||
udp_wmem_min - INTEGER
|
||||
Minimal size of send buffer used by UDP sockets in moderation.
|
||||
Each UDP socket is able to use the size for sending data, even if
|
||||
total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
|
||||
Default: 4096
|
||||
Default: 1 page
|
||||
|
||||
CIPSOv4 Variables:
|
||||
|
||||
|
@ -1465,10 +1455,17 @@ sctp_mem - vector of 3 INTEGERs: min, pressure, max
|
|||
Default is calculated at boot time from amount of available memory.
|
||||
|
||||
sctp_rmem - vector of 3 INTEGERs: min, default, max
|
||||
See tcp_rmem for a description.
|
||||
Only the first value ("min") is used, "default" and "max" are
|
||||
ignored.
|
||||
|
||||
min: Minimal size of receive buffer used by SCTP socket.
|
||||
It is guaranteed to each SCTP socket (but not association) even
|
||||
under moderate memory pressure.
|
||||
|
||||
Default: 1 page
|
||||
|
||||
sctp_wmem - vector of 3 INTEGERs: min, default, max
|
||||
See tcp_wmem for a description.
|
||||
Currently this tunable has no effect.
|
||||
|
||||
addr_scope_policy - INTEGER
|
||||
Control IPv4 address scoping - draft-stewart-tsvwg-sctp-ipv4-00
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
Netdev features mess and how to get out from it alive
|
||||
=====================================================
|
||||
|
||||
Author:
|
||||
Michał Mirosław <mirq-linux@rere.qmqm.pl>
|
||||
|
||||
|
||||
|
||||
Part I: Feature sets
|
||||
======================
|
||||
|
||||
Long gone are the days when a network card would just take and give packets
|
||||
verbatim. Today's devices add multiple features and bugs (read: offloads)
|
||||
that relieve an OS of various tasks like generating and checking checksums,
|
||||
splitting packets, classifying them. Those capabilities and their state
|
||||
are commonly referred to as netdev features in Linux kernel world.
|
||||
|
||||
There are currently three sets of features relevant to the driver, and
|
||||
one used internally by network core:
|
||||
|
||||
1. netdev->hw_features set contains features whose state may possibly
|
||||
be changed (enabled or disabled) for a particular device by user's
|
||||
request. This set should be initialized in ndo_init callback and not
|
||||
changed later.
|
||||
|
||||
2. netdev->features set contains features which are currently enabled
|
||||
for a device. This should be changed only by network core or in
|
||||
error paths of ndo_set_features callback.
|
||||
|
||||
3. netdev->vlan_features set contains features whose state is inherited
|
||||
by child VLAN devices (limits netdev->features set). This is currently
|
||||
used for all VLAN devices whether tags are stripped or inserted in
|
||||
hardware or software.
|
||||
|
||||
4. netdev->wanted_features set contains feature set requested by user.
|
||||
This set is filtered by ndo_fix_features callback whenever it or
|
||||
some device-specific conditions change. This set is internal to
|
||||
networking core and should not be referenced in drivers.
|
||||
|
||||
|
||||
|
||||
Part II: Controlling enabled features
|
||||
=======================================
|
||||
|
||||
When current feature set (netdev->features) is to be changed, new set
|
||||
is calculated and filtered by calling ndo_fix_features callback
|
||||
and netdev_fix_features(). If the resulting set differs from current
|
||||
set, it is passed to ndo_set_features callback and (if the callback
|
||||
returns success) replaces value stored in netdev->features.
|
||||
NETDEV_FEAT_CHANGE notification is issued after that whenever current
|
||||
set might have changed.
|
||||
|
||||
The following events trigger recalculation:
|
||||
1. device's registration, after ndo_init returned success
|
||||
2. user requested changes in features state
|
||||
3. netdev_update_features() is called
|
||||
|
||||
ndo_*_features callbacks are called with rtnl_lock held. Missing callbacks
|
||||
are treated as always returning success.
|
||||
|
||||
A driver that wants to trigger recalculation must do so by calling
|
||||
netdev_update_features() while holding rtnl_lock. This should not be done
|
||||
from ndo_*_features callbacks. netdev->features should not be modified by
|
||||
driver except by means of ndo_fix_features callback.
|
||||
|
||||
|
||||
|
||||
Part III: Implementation hints
|
||||
================================
|
||||
|
||||
* ndo_fix_features:
|
||||
|
||||
All dependencies between features should be resolved here. The resulting
|
||||
set can be reduced further by networking core imposed limitations (as coded
|
||||
in netdev_fix_features()). For this reason it is safer to disable a feature
|
||||
when its dependencies are not met instead of forcing the dependency on.
|
||||
|
||||
This callback should not modify hardware nor driver state (should be
|
||||
stateless). It can be called multiple times between successive
|
||||
ndo_set_features calls.
|
||||
|
||||
Callback must not alter features contained in NETIF_F_SOFT_FEATURES or
|
||||
NETIF_F_NEVER_CHANGE sets. The exception is NETIF_F_VLAN_CHALLENGED but
|
||||
care must be taken as the change won't affect already configured VLANs.
|
||||
|
||||
* ndo_set_features:
|
||||
|
||||
Hardware should be reconfigured to match passed feature set. The set
|
||||
should not be altered unless some error condition happens that can't
|
||||
be reliably detected in ndo_fix_features. In this case, the callback
|
||||
should update netdev->features to match resulting hardware state.
|
||||
Errors returned are not (and cannot be) propagated anywhere except dmesg.
|
||||
(Note: successful return is zero, >0 means silent error.)
|
||||
|
||||
|
||||
|
||||
Part IV: Features
|
||||
===================
|
||||
|
||||
For current list of features, see include/linux/netdev_features.h.
|
||||
This section describes semantics of some of them.
|
||||
|
||||
* Transmit checksumming
|
||||
|
||||
For complete description, see comments near the top of include/linux/skbuff.h.
|
||||
|
||||
Note: NETIF_F_HW_CSUM is a superset of NETIF_F_IP_CSUM + NETIF_F_IPV6_CSUM.
|
||||
It means that device can fill TCP/UDP-like checksum anywhere in the packets
|
||||
whatever headers there might be.
|
||||
|
||||
* Transmit TCP segmentation offload
|
||||
|
||||
NETIF_F_TSO_ECN means that hardware can properly split packets with CWR bit
|
||||
set, be it TCPv4 (when NETIF_F_TSO is enabled) or TCPv6 (NETIF_F_TSO6).
|
||||
|
||||
* Transmit DMA from high memory
|
||||
|
||||
On platforms where this is relevant, NETIF_F_HIGHDMA signals that
|
||||
ndo_start_xmit can handle skbs with frags in high memory.
|
||||
|
||||
* Transmit scatter-gather
|
||||
|
||||
Those features say that ndo_start_xmit can handle fragmented skbs:
|
||||
NETIF_F_SG --- paged skbs (skb_shinfo()->frags), NETIF_F_FRAGLIST ---
|
||||
chained skbs (skb->next/prev list).
|
||||
|
||||
* Software features
|
||||
|
||||
Features contained in NETIF_F_SOFT_FEATURES are features of networking
|
||||
stack. Driver should not change behaviour based on them.
|
||||
|
||||
* LLTX driver (deprecated for hardware drivers)
|
||||
|
||||
NETIF_F_LLTX should be set in drivers that implement their own locking in
|
||||
transmit path or don't need locking at all (e.g. software tunnels).
|
||||
In ndo_start_xmit, it is recommended to use a try_lock and return
|
||||
NETDEV_TX_LOCKED when the spin lock fails. The locking should also properly
|
||||
protect against other callbacks (the rules you need to find out).
|
||||
|
||||
Don't use it for new drivers.
|
||||
|
||||
* netns-local device
|
||||
|
||||
NETIF_F_NETNS_LOCAL is set for devices that are not allowed to move between
|
||||
network namespaces (e.g. loopback).
|
||||
|
||||
Don't use it in drivers.
|
||||
|
||||
* VLAN challenged
|
||||
|
||||
NETIF_F_VLAN_CHALLENGED should be set for devices which can't cope with VLAN
|
||||
headers. Some drivers set this because the cards can't handle the bigger MTU.
|
||||
[FIXME: Those cases could be fixed in VLAN code by allowing only reduced-MTU
|
||||
VLANs. This may be not useful, though.]
|
|
@ -0,0 +1,128 @@
|
|||
Linux NFC subsystem
|
||||
===================
|
||||
|
||||
The Near Field Communication (NFC) subsystem is required to standardize the
|
||||
NFC device drivers development and to create an unified userspace interface.
|
||||
|
||||
This document covers the architecture overview, the device driver interface
|
||||
description and the userspace interface description.
|
||||
|
||||
Architecture overview
|
||||
---------------------
|
||||
|
||||
The NFC subsystem is responsible for:
|
||||
- NFC adapters management;
|
||||
- Polling for targets;
|
||||
- Low-level data exchange;
|
||||
|
||||
The subsystem is divided in some parts. The 'core' is responsible for
|
||||
providing the device driver interface. On the other side, it is also
|
||||
responsible for providing an interface to control operations and low-level
|
||||
data exchange.
|
||||
|
||||
The control operations are available to userspace via generic netlink.
|
||||
|
||||
The low-level data exchange interface is provided by the new socket family
|
||||
PF_NFC. The NFC_SOCKPROTO_RAW performs raw communication with NFC targets.
|
||||
|
||||
|
||||
+--------------------------------------+
|
||||
| USER SPACE |
|
||||
+--------------------------------------+
|
||||
^ ^
|
||||
| low-level | control
|
||||
| data exchange | operations
|
||||
| |
|
||||
| v
|
||||
| +-----------+
|
||||
| AF_NFC | netlink |
|
||||
| socket +-----------+
|
||||
| raw ^
|
||||
| |
|
||||
v v
|
||||
+---------+ +-----------+
|
||||
| rawsock | <--------> | core |
|
||||
+---------+ +-----------+
|
||||
^
|
||||
|
|
||||
v
|
||||
+-----------+
|
||||
| driver |
|
||||
+-----------+
|
||||
|
||||
Device Driver Interface
|
||||
-----------------------
|
||||
|
||||
When registering on the NFC subsystem, the device driver must inform the core
|
||||
of the set of supported NFC protocols and the set of ops callbacks. The ops
|
||||
callbacks that must be implemented are the following:
|
||||
|
||||
* start_poll - setup the device to poll for targets
|
||||
* stop_poll - stop on progress polling operation
|
||||
* activate_target - select and initialize one of the targets found
|
||||
* deactivate_target - deselect and deinitialize the selected target
|
||||
* data_exchange - send data and receive the response (transceive operation)
|
||||
|
||||
Userspace interface
|
||||
--------------------
|
||||
|
||||
The userspace interface is divided in control operations and low-level data
|
||||
exchange operation.
|
||||
|
||||
CONTROL OPERATIONS:
|
||||
|
||||
Generic netlink is used to implement the interface to the control operations.
|
||||
The operations are composed by commands and events, all listed below:
|
||||
|
||||
* NFC_CMD_GET_DEVICE - get specific device info or dump the device list
|
||||
* NFC_CMD_START_POLL - setup a specific device to polling for targets
|
||||
* NFC_CMD_STOP_POLL - stop the polling operation in a specific device
|
||||
* NFC_CMD_GET_TARGET - dump the list of targets found by a specific device
|
||||
|
||||
* NFC_EVENT_DEVICE_ADDED - reports an NFC device addition
|
||||
* NFC_EVENT_DEVICE_REMOVED - reports an NFC device removal
|
||||
* NFC_EVENT_TARGETS_FOUND - reports START_POLL results when 1 or more targets
|
||||
are found
|
||||
|
||||
The user must call START_POLL to poll for NFC targets, passing the desired NFC
|
||||
protocols through NFC_ATTR_PROTOCOLS attribute. The device remains in polling
|
||||
state until it finds any target. However, the user can stop the polling
|
||||
operation by calling STOP_POLL command. In this case, it will be checked if
|
||||
the requester of STOP_POLL is the same of START_POLL.
|
||||
|
||||
If the polling operation finds one or more targets, the event TARGETS_FOUND is
|
||||
sent (including the device id). The user must call GET_TARGET to get the list of
|
||||
all targets found by such device. Each reply message has target attributes with
|
||||
relevant information such as the supported NFC protocols.
|
||||
|
||||
All polling operations requested through one netlink socket are stopped when
|
||||
it's closed.
|
||||
|
||||
LOW-LEVEL DATA EXCHANGE:
|
||||
|
||||
The userspace must use PF_NFC sockets to perform any data communication with
|
||||
targets. All NFC sockets use AF_NFC:
|
||||
|
||||
struct sockaddr_nfc {
|
||||
sa_family_t sa_family;
|
||||
__u32 dev_idx;
|
||||
__u32 target_idx;
|
||||
__u32 nfc_protocol;
|
||||
};
|
||||
|
||||
To establish a connection with one target, the user must create an
|
||||
NFC_SOCKPROTO_RAW socket and call the 'connect' syscall with the sockaddr_nfc
|
||||
struct correctly filled. All information comes from NFC_EVENT_TARGETS_FOUND
|
||||
netlink event. As a target can support more than one NFC protocol, the user
|
||||
must inform which protocol it wants to use.
|
||||
|
||||
Internally, 'connect' will result in an activate_target call to the driver.
|
||||
When the socket is closed, the target is deactivated.
|
||||
|
||||
The data format exchanged through the sockets is NFC protocol dependent. For
|
||||
instance, when communicating with MIFARE tags, the data exchanged are MIFARE
|
||||
commands and their responses.
|
||||
|
||||
The first received package is the response to the first sent package and so
|
||||
on. In order to allow valid "empty" responses, every data received has a NULL
|
||||
header of 1 byte.
|
|
@ -7,7 +7,7 @@ This is the driver for the MAC 10/100/1000 on-chip Ethernet controllers
|
|||
(Synopsys IP blocks); it has been fully tested on STLinux platforms.
|
||||
|
||||
Currently this network device driver is for all STM embedded MAC/GMAC
|
||||
(7xxx SoCs). Other platforms start using it i.e. ARM SPEAr.
|
||||
(i.e. 7xxx/5xxx SoCs) and it's known working on other platforms i.e. ARM SPEAr.
|
||||
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a and DWC Ether MAC 10/100
|
||||
Universal version 4.0 have been used for developing the first code
|
||||
|
@ -71,7 +71,7 @@ Several performance tests on STM platforms showed this optimisation allows to sp
|
|||
the CPU while having the maximum throughput.
|
||||
|
||||
4.4) WOL
|
||||
Wake up on Lan feature through Magic Frame is only supported for the GMAC
|
||||
Wake up on Lan feature through Magic and Unicast frames are supported for the GMAC
|
||||
core.
|
||||
|
||||
4.5) DMA descriptors
|
||||
|
@ -91,11 +91,15 @@ LRO is not supported.
|
|||
The driver is compatible with PAL to work with PHY and GPHY devices.
|
||||
|
||||
4.9) Platform information
|
||||
Several information came from the platform; please refer to the
|
||||
driver's Header file in include/linux directory.
|
||||
Several driver's information can be passed through the platform
|
||||
These are included in the include/linux/stmmac.h header file
|
||||
and detailed below as well:
|
||||
|
||||
struct plat_stmmacenet_data {
|
||||
struct plat_stmmacenet_data {
|
||||
int bus_id;
|
||||
int phy_addr;
|
||||
int interface;
|
||||
struct stmmac_mdio_bus_data *mdio_bus_data;
|
||||
int pbl;
|
||||
int clk_csr;
|
||||
int has_gmac;
|
||||
|
@ -103,67 +107,135 @@ struct plat_stmmacenet_data {
|
|||
int tx_coe;
|
||||
int bugged_jumbo;
|
||||
int pmt;
|
||||
void (*fix_mac_speed)(void *priv, unsigned int speed);
|
||||
void (*bus_setup)(unsigned long ioaddr);
|
||||
#ifdef CONFIG_STM_DRIVERS
|
||||
struct stm_pad_config *pad_config;
|
||||
#endif
|
||||
void *bsp_priv;
|
||||
};
|
||||
int force_sf_dma_mode;
|
||||
void (*fix_mac_speed)(void *priv, unsigned int speed);
|
||||
void (*bus_setup)(void __iomem *ioaddr);
|
||||
int (*init)(struct platform_device *pdev);
|
||||
void (*exit)(struct platform_device *pdev);
|
||||
void *bsp_priv;
|
||||
};
|
||||
|
||||
Where:
|
||||
- pbl (Programmable Burst Length) is maximum number of
|
||||
beats to be transferred in one DMA transaction.
|
||||
GMAC also enables the 4xPBL by default.
|
||||
- fix_mac_speed and bus_setup are used to configure internal target
|
||||
registers (on STM platforms);
|
||||
- has_gmac: GMAC core is on board (get it at run-time in the next step);
|
||||
- bus_id: bus identifier.
|
||||
- tx_coe: core is able to perform the tx csum in HW.
|
||||
- enh_desc: if sets the MAC will use the enhanced descriptor structure.
|
||||
- clk_csr: CSR Clock range selection.
|
||||
- bugged_jumbo: some HWs are not able to perform the csum in HW for
|
||||
over-sized frames due to limited buffer sizes. Setting this
|
||||
flag the csum will be done in SW on JUMBO frames.
|
||||
o bus_id: bus identifier.
|
||||
o phy_addr: the physical address can be passed from the platform.
|
||||
If it is set to -1 the driver will automatically
|
||||
detect it at run-time by probing all the 32 addresses.
|
||||
o interface: PHY device's interface.
|
||||
o mdio_bus_data: specific platform fields for the MDIO bus.
|
||||
o pbl: the Programmable Burst Length is maximum number of beats to
|
||||
be transferred in one DMA transaction.
|
||||
GMAC also enables the 4xPBL by default.
|
||||
o clk_csr: CSR Clock range selection.
|
||||
o has_gmac: uses the GMAC core.
|
||||
o enh_desc: if sets the MAC will use the enhanced descriptor structure.
|
||||
o tx_coe: core is able to perform the tx csum in HW.
|
||||
o bugged_jumbo: some HWs are not able to perform the csum in HW for
|
||||
over-sized frames due to limited buffer sizes.
|
||||
Setting this flag the csum will be done in SW on
|
||||
JUMBO frames.
|
||||
o pmt: core has the embedded power module (optional).
|
||||
o force_sf_dma_mode: force DMA to use the Store and Forward mode
|
||||
instead of the Threshold.
|
||||
o fix_mac_speed: this callback is used for modifying some syscfg registers
|
||||
(on ST SoCs) according to the link speed negotiated by the
|
||||
physical layer .
|
||||
o bus_setup: perform HW setup of the bus. For example, on some ST platforms
|
||||
this field is used to configure the AMBA bridge to generate more
|
||||
efficient STBus traffic.
|
||||
o init/exit: callbacks used for calling a custom initialisation;
|
||||
this is sometime necessary on some platforms (e.g. ST boxes)
|
||||
where the HW needs to have set some PIO lines or system cfg
|
||||
registers.
|
||||
o custom_cfg: this is a custom configuration that can be passed while
|
||||
initialising the resources.
|
||||
|
||||
struct plat_stmmacphy_data {
|
||||
int bus_id;
|
||||
int phy_addr;
|
||||
unsigned int phy_mask;
|
||||
int interface;
|
||||
int (*phy_reset)(void *priv);
|
||||
void *priv;
|
||||
};
|
||||
The we have:
|
||||
|
||||
struct stmmac_mdio_bus_data {
|
||||
int bus_id;
|
||||
int (*phy_reset)(void *priv);
|
||||
unsigned int phy_mask;
|
||||
int *irqs;
|
||||
int probed_phy_irq;
|
||||
};
|
||||
|
||||
Where:
|
||||
- bus_id: bus identifier;
|
||||
- phy_addr: physical address used for the attached phy device;
|
||||
set it to -1 to get it at run-time;
|
||||
- interface: physical MII interface mode;
|
||||
- phy_reset: hook to reset HW function.
|
||||
o bus_id: bus identifier;
|
||||
o phy_reset: hook to reset the phy device attached to the bus.
|
||||
o phy_mask: phy mask passed when register the MDIO bus within the driver.
|
||||
o irqs: list of IRQs, one per PHY.
|
||||
o probed_phy_irq: if irqs is NULL, use this for probed PHY.
|
||||
|
||||
SOURCES:
|
||||
- Kconfig
|
||||
- Makefile
|
||||
- stmmac_main.c: main network device driver;
|
||||
- stmmac_mdio.c: mdio functions;
|
||||
- stmmac_ethtool.c: ethtool support;
|
||||
- stmmac_timer.[ch]: timer code used for mitigating the driver dma interrupts
|
||||
Only tested on ST40 platforms based.
|
||||
- stmmac.h: private driver structure;
|
||||
- common.h: common definitions and VFTs;
|
||||
- descs.h: descriptor structure definitions;
|
||||
- dwmac1000_core.c: GMAC core functions;
|
||||
- dwmac1000_dma.c: dma functions for the GMAC chip;
|
||||
- dwmac1000.h: specific header file for the GMAC;
|
||||
- dwmac100_core: MAC 100 core and dma code;
|
||||
- dwmac100_dma.c: dma funtions for the MAC chip;
|
||||
- dwmac1000.h: specific header file for the MAC;
|
||||
- dwmac_lib.c: generic DMA functions shared among chips
|
||||
- enh_desc.c: functions for handling enhanced descriptors
|
||||
- norm_desc.c: functions for handling normal descriptors
|
||||
Below an example how the structures above are using on ST platforms.
|
||||
|
||||
TODO:
|
||||
- XGMAC controller is not supported.
|
||||
- Review the timer optimisation code to use an embedded device that seems to be
|
||||
static struct plat_stmmacenet_data stxYYY_ethernet_platform_data = {
|
||||
.pbl = 32,
|
||||
.has_gmac = 0,
|
||||
.enh_desc = 0,
|
||||
.fix_mac_speed = stxYYY_ethernet_fix_mac_speed,
|
||||
|
|
||||
|-> to write an internal syscfg
|
||||
| on this platform when the
|
||||
| link speed changes from 10 to
|
||||
| 100 and viceversa
|
||||
.init = &stmmac_claim_resource,
|
||||
|
|
||||
|-> On ST SoC this calls own "PAD"
|
||||
| manager framework to claim
|
||||
| all the resources necessary
|
||||
| (GPIO ...). The .custom_cfg field
|
||||
| is used to pass a custom config.
|
||||
};
|
||||
|
||||
Below the usage of the stmmac_mdio_bus_data: on this SoC, in fact,
|
||||
there are two MAC cores: one MAC is for MDIO Bus/PHY emulation
|
||||
with fixed_link support.
|
||||
|
||||
static struct stmmac_mdio_bus_data stmmac1_mdio_bus = {
|
||||
.bus_id = 1,
|
||||
|
|
||||
|-> phy device on the bus_id 1
|
||||
.phy_reset = phy_reset;
|
||||
|
|
||||
|-> function to provide the phy_reset on this board
|
||||
.phy_mask = 0,
|
||||
};
|
||||
|
||||
static struct fixed_phy_status stmmac0_fixed_phy_status = {
|
||||
.link = 1,
|
||||
.speed = 100,
|
||||
.duplex = 1,
|
||||
};
|
||||
|
||||
During the board's device_init we can configure the first
|
||||
MAC for fixed_link by calling:
|
||||
fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status));)
|
||||
and the second one, with a real PHY device attached to the bus,
|
||||
by using the stmmac_mdio_bus_data structure (to provide the id, the
|
||||
reset procedure etc).
|
||||
|
||||
4.10) List of source files:
|
||||
o Kconfig
|
||||
o Makefile
|
||||
o stmmac_main.c: main network device driver;
|
||||
o stmmac_mdio.c: mdio functions;
|
||||
o stmmac_ethtool.c: ethtool support;
|
||||
o stmmac_timer.[ch]: timer code used for mitigating the driver dma interrupts
|
||||
Only tested on ST40 platforms based.
|
||||
o stmmac.h: private driver structure;
|
||||
o common.h: common definitions and VFTs;
|
||||
o descs.h: descriptor structure definitions;
|
||||
o dwmac1000_core.c: GMAC core functions;
|
||||
o dwmac1000_dma.c: dma functions for the GMAC chip;
|
||||
o dwmac1000.h: specific header file for the GMAC;
|
||||
o dwmac100_core: MAC 100 core and dma code;
|
||||
o dwmac100_dma.c: dma funtions for the MAC chip;
|
||||
o dwmac1000.h: specific header file for the MAC;
|
||||
o dwmac_lib.c: generic DMA functions shared among chips
|
||||
o enh_desc.c: functions for handling enhanced descriptors
|
||||
o norm_desc.c: functions for handling normal descriptors
|
||||
|
||||
5) TODO:
|
||||
o XGMAC is not supported.
|
||||
o Review the timer optimisation code to use an embedded device that will be
|
||||
available in new chip generations.
|
||||
|
|
|
@ -4290,8 +4290,8 @@ S: Maintained
|
|||
F: drivers/usb/musb/
|
||||
|
||||
MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
|
||||
M: Jon Mason <mason@myri.com>
|
||||
M: Andrew Gallatin <gallatin@myri.com>
|
||||
M: Brice Goglin <brice@myri.com>
|
||||
L: netdev@vger.kernel.org
|
||||
W: http://www.myri.com/scs/download-Myri10GE.html
|
||||
S: Supported
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <mach/common.h>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <mach/da8xx.h>
|
||||
#include <mach/sram.h>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/io.h>
|
||||
#ifdef CONFIG_MTD_PHYSMAP
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <mach/mx23.h>
|
||||
#include <mach/mx28.h>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <mach/mx28.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/sizes.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/devices-common.h>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define STE_DMA40_H
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/natfeat.h>
|
||||
#include <asm/virtconvert.h>
|
||||
|
@ -204,7 +205,6 @@ static struct net_device * __init nfeth_probe(int unit)
|
|||
dev->irq = nfEtherIRQ;
|
||||
dev->netdev_ops = &nfeth_netdev_ops;
|
||||
|
||||
dev->flags |= NETIF_F_NO_CSUM;
|
||||
memcpy(dev->dev_addr, mac, ETH_ALEN);
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
|
|
|
@ -134,6 +134,7 @@ config PPC
|
|||
select GENERIC_IRQ_SHOW_LEVEL
|
||||
select HAVE_RCU_TABLE_FREE if SMP
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_BPF_JIT if (PPC64 && NET)
|
||||
|
||||
config EARLY_PRINTK
|
||||
bool
|
||||
|
|
|
@ -154,7 +154,8 @@ core-y += arch/powerpc/kernel/ \
|
|||
arch/powerpc/lib/ \
|
||||
arch/powerpc/sysdev/ \
|
||||
arch/powerpc/platforms/ \
|
||||
arch/powerpc/math-emu/
|
||||
arch/powerpc/math-emu/ \
|
||||
arch/powerpc/net/
|
||||
core-$(CONFIG_XMON) += arch/powerpc/xmon/
|
||||
core-$(CONFIG_KVM) += arch/powerpc/kvm/
|
||||
|
||||
|
|
|
@ -71,6 +71,42 @@
|
|||
#define PPC_INST_ERATSX 0x7c000126
|
||||
#define PPC_INST_ERATSX_DOT 0x7c000127
|
||||
|
||||
/* Misc instructions for BPF compiler */
|
||||
#define PPC_INST_LD 0xe8000000
|
||||
#define PPC_INST_LHZ 0xa0000000
|
||||
#define PPC_INST_LWZ 0x80000000
|
||||
#define PPC_INST_STD 0xf8000000
|
||||
#define PPC_INST_STDU 0xf8000001
|
||||
#define PPC_INST_MFLR 0x7c0802a6
|
||||
#define PPC_INST_MTLR 0x7c0803a6
|
||||
#define PPC_INST_CMPWI 0x2c000000
|
||||
#define PPC_INST_CMPDI 0x2c200000
|
||||
#define PPC_INST_CMPLW 0x7c000040
|
||||
#define PPC_INST_CMPLWI 0x28000000
|
||||
#define PPC_INST_ADDI 0x38000000
|
||||
#define PPC_INST_ADDIS 0x3c000000
|
||||
#define PPC_INST_ADD 0x7c000214
|
||||
#define PPC_INST_SUB 0x7c000050
|
||||
#define PPC_INST_BLR 0x4e800020
|
||||
#define PPC_INST_BLRL 0x4e800021
|
||||
#define PPC_INST_MULLW 0x7c0001d6
|
||||
#define PPC_INST_MULHWU 0x7c000016
|
||||
#define PPC_INST_MULLI 0x1c000000
|
||||
#define PPC_INST_DIVWU 0x7c0003d6
|
||||
#define PPC_INST_RLWINM 0x54000000
|
||||
#define PPC_INST_RLDICR 0x78000004
|
||||
#define PPC_INST_SLW 0x7c000030
|
||||
#define PPC_INST_SRW 0x7c000430
|
||||
#define PPC_INST_AND 0x7c000038
|
||||
#define PPC_INST_ANDDOT 0x7c000039
|
||||
#define PPC_INST_OR 0x7c000378
|
||||
#define PPC_INST_ANDI 0x70000000
|
||||
#define PPC_INST_ORI 0x60000000
|
||||
#define PPC_INST_ORIS 0x64000000
|
||||
#define PPC_INST_NEG 0x7c0000d0
|
||||
#define PPC_INST_BRANCH 0x48000000
|
||||
#define PPC_INST_BRANCH_COND 0x40800000
|
||||
|
||||
/* macros to insert fields into opcodes */
|
||||
#define __PPC_RA(a) (((a) & 0x1f) << 16)
|
||||
#define __PPC_RB(b) (((b) & 0x1f) << 11)
|
||||
|
@ -83,6 +119,10 @@
|
|||
#define __PPC_T_TLB(t) (((t) & 0x3) << 21)
|
||||
#define __PPC_WC(w) (((w) & 0x3) << 21)
|
||||
#define __PPC_WS(w) (((w) & 0x1f) << 11)
|
||||
#define __PPC_SH(s) __PPC_WS(s)
|
||||
#define __PPC_MB(s) (((s) & 0x1f) << 6)
|
||||
#define __PPC_ME(s) (((s) & 0x1f) << 1)
|
||||
#define __PPC_BI(s) (((s) & 0x1f) << 16)
|
||||
|
||||
/*
|
||||
* Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# Arch-specific network modules
|
||||
#
|
||||
obj-$(CONFIG_BPF_JIT) += bpf_jit_64.o bpf_jit_comp.o
|
|
@ -0,0 +1,227 @@
|
|||
/* bpf_jit.h: BPF JIT compiler for PPC64
|
||||
*
|
||||
* Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*/
|
||||
#ifndef _BPF_JIT_H
|
||||
#define _BPF_JIT_H
|
||||
|
||||
#define BPF_PPC_STACK_LOCALS 32
|
||||
#define BPF_PPC_STACK_BASIC (48+64)
|
||||
#define BPF_PPC_STACK_SAVE (18*8)
|
||||
#define BPF_PPC_STACKFRAME (BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
|
||||
BPF_PPC_STACK_SAVE)
|
||||
#define BPF_PPC_SLOWPATH_FRAME (48+64)
|
||||
|
||||
/*
|
||||
* Generated code register usage:
|
||||
*
|
||||
* As normal PPC C ABI (e.g. r1=sp, r2=TOC), with:
|
||||
*
|
||||
* skb r3 (Entry parameter)
|
||||
* A register r4
|
||||
* X register r5
|
||||
* addr param r6
|
||||
* r7-r10 scratch
|
||||
* skb->data r14
|
||||
* skb headlen r15 (skb->len - skb->data_len)
|
||||
* m[0] r16
|
||||
* m[...] ...
|
||||
* m[15] r31
|
||||
*/
|
||||
#define r_skb 3
|
||||
#define r_ret 3
|
||||
#define r_A 4
|
||||
#define r_X 5
|
||||
#define r_addr 6
|
||||
#define r_scratch1 7
|
||||
#define r_D 14
|
||||
#define r_HL 15
|
||||
#define r_M 16
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/*
|
||||
* Assembly helpers from arch/powerpc/net/bpf_jit.S:
|
||||
*/
|
||||
extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
|
||||
|
||||
#define FUNCTION_DESCR_SIZE 24
|
||||
|
||||
/*
|
||||
* 16-bit immediate helper macros: HA() is for use with sign-extending instrs
|
||||
* (e.g. LD, ADDI). If the bottom 16 bits is "-ve", add another bit into the
|
||||
* top half to negate the effect (i.e. 0xffff + 1 = 0x(1)0000).
|
||||
*/
|
||||
#define IMM_H(i) ((uintptr_t)(i)>>16)
|
||||
#define IMM_HA(i) (((uintptr_t)(i)>>16) + \
|
||||
(((uintptr_t)(i) & 0x8000) >> 15))
|
||||
#define IMM_L(i) ((uintptr_t)(i) & 0xffff)
|
||||
|
||||
#define PLANT_INSTR(d, idx, instr) \
|
||||
do { if (d) { (d)[idx] = instr; } idx++; } while (0)
|
||||
#define EMIT(instr) PLANT_INSTR(image, ctx->idx, instr)
|
||||
|
||||
#define PPC_NOP() EMIT(PPC_INST_NOP)
|
||||
#define PPC_BLR() EMIT(PPC_INST_BLR)
|
||||
#define PPC_BLRL() EMIT(PPC_INST_BLRL)
|
||||
#define PPC_MTLR(r) EMIT(PPC_INST_MTLR | __PPC_RT(r))
|
||||
#define PPC_ADDI(d, a, i) EMIT(PPC_INST_ADDI | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_MR(d, a) PPC_OR(d, a, a)
|
||||
#define PPC_LI(r, i) PPC_ADDI(r, 0, i)
|
||||
#define PPC_ADDIS(d, a, i) EMIT(PPC_INST_ADDIS | \
|
||||
__PPC_RS(d) | __PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_LIS(r, i) PPC_ADDIS(r, 0, i)
|
||||
#define PPC_STD(r, base, i) EMIT(PPC_INST_STD | __PPC_RS(r) | \
|
||||
__PPC_RA(base) | ((i) & 0xfffc))
|
||||
|
||||
#define PPC_LD(r, base, i) EMIT(PPC_INST_LD | __PPC_RT(r) | \
|
||||
__PPC_RA(base) | IMM_L(i))
|
||||
#define PPC_LWZ(r, base, i) EMIT(PPC_INST_LWZ | __PPC_RT(r) | \
|
||||
__PPC_RA(base) | IMM_L(i))
|
||||
#define PPC_LHZ(r, base, i) EMIT(PPC_INST_LHZ | __PPC_RT(r) | \
|
||||
__PPC_RA(base) | IMM_L(i))
|
||||
/* Convenience helpers for the above with 'far' offsets: */
|
||||
#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \
|
||||
else { PPC_ADDIS(r, base, IMM_HA(i)); \
|
||||
PPC_LD(r, r, IMM_L(i)); } } while(0)
|
||||
|
||||
#define PPC_LWZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LWZ(r, base, i); \
|
||||
else { PPC_ADDIS(r, base, IMM_HA(i)); \
|
||||
PPC_LWZ(r, r, IMM_L(i)); } } while(0)
|
||||
|
||||
#define PPC_LHZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LHZ(r, base, i); \
|
||||
else { PPC_ADDIS(r, base, IMM_HA(i)); \
|
||||
PPC_LHZ(r, r, IMM_L(i)); } } while(0)
|
||||
|
||||
#define PPC_CMPWI(a, i) EMIT(PPC_INST_CMPWI | __PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_CMPDI(a, i) EMIT(PPC_INST_CMPDI | __PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_CMPLWI(a, i) EMIT(PPC_INST_CMPLWI | __PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_CMPLW(a, b) EMIT(PPC_INST_CMPLW | __PPC_RA(a) | __PPC_RB(b))
|
||||
|
||||
#define PPC_SUB(d, a, b) EMIT(PPC_INST_SUB | __PPC_RT(d) | \
|
||||
__PPC_RB(a) | __PPC_RA(b))
|
||||
#define PPC_ADD(d, a, b) EMIT(PPC_INST_ADD | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | __PPC_RB(b))
|
||||
#define PPC_MUL(d, a, b) EMIT(PPC_INST_MULLW | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | __PPC_RB(b))
|
||||
#define PPC_MULHWU(d, a, b) EMIT(PPC_INST_MULHWU | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | __PPC_RB(b))
|
||||
#define PPC_MULI(d, a, i) EMIT(PPC_INST_MULLI | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | IMM_L(i))
|
||||
#define PPC_DIVWU(d, a, b) EMIT(PPC_INST_DIVWU | __PPC_RT(d) | \
|
||||
__PPC_RA(a) | __PPC_RB(b))
|
||||
#define PPC_AND(d, a, b) EMIT(PPC_INST_AND | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_RB(b))
|
||||
#define PPC_ANDI(d, a, i) EMIT(PPC_INST_ANDI | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | IMM_L(i))
|
||||
#define PPC_AND_DOT(d, a, b) EMIT(PPC_INST_ANDDOT | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_RB(b))
|
||||
#define PPC_OR(d, a, b) EMIT(PPC_INST_OR | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_RB(b))
|
||||
#define PPC_ORI(d, a, i) EMIT(PPC_INST_ORI | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | IMM_L(i))
|
||||
#define PPC_ORIS(d, a, i) EMIT(PPC_INST_ORIS | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | IMM_L(i))
|
||||
#define PPC_SLW(d, a, s) EMIT(PPC_INST_SLW | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_RB(s))
|
||||
#define PPC_SRW(d, a, s) EMIT(PPC_INST_SRW | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_RB(s))
|
||||
/* slwi = rlwinm Rx, Ry, n, 0, 31-n */
|
||||
#define PPC_SLWI(d, a, i) EMIT(PPC_INST_RLWINM | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_SH(i) | \
|
||||
__PPC_MB(0) | __PPC_ME(31-(i)))
|
||||
/* srwi = rlwinm Rx, Ry, 32-n, n, 31 */
|
||||
#define PPC_SRWI(d, a, i) EMIT(PPC_INST_RLWINM | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_SH(32-(i)) | \
|
||||
__PPC_MB(i) | __PPC_ME(31))
|
||||
/* sldi = rldicr Rx, Ry, n, 63-n */
|
||||
#define PPC_SLDI(d, a, i) EMIT(PPC_INST_RLDICR | __PPC_RA(d) | \
|
||||
__PPC_RS(a) | __PPC_SH(i) | \
|
||||
__PPC_MB(63-(i)) | (((i) & 0x20) >> 4))
|
||||
#define PPC_NEG(d, a) EMIT(PPC_INST_NEG | __PPC_RT(d) | __PPC_RA(a))
|
||||
|
||||
/* Long jump; (unconditional 'branch') */
|
||||
#define PPC_JMP(dest) EMIT(PPC_INST_BRANCH | \
|
||||
(((dest) - (ctx->idx * 4)) & 0x03fffffc))
|
||||
/* "cond" here covers BO:BI fields. */
|
||||
#define PPC_BCC_SHORT(cond, dest) EMIT(PPC_INST_BRANCH_COND | \
|
||||
(((cond) & 0x3ff) << 16) | \
|
||||
(((dest) - (ctx->idx * 4)) & \
|
||||
0xfffc))
|
||||
#define PPC_LI32(d, i) do { PPC_LI(d, IMM_L(i)); \
|
||||
if ((u32)(uintptr_t)(i) >= 32768) { \
|
||||
PPC_ADDIS(d, d, IMM_HA(i)); \
|
||||
} } while(0)
|
||||
#define PPC_LI64(d, i) do { \
|
||||
if (!((uintptr_t)(i) & 0xffffffff00000000ULL)) \
|
||||
PPC_LI32(d, i); \
|
||||
else { \
|
||||
PPC_LIS(d, ((uintptr_t)(i) >> 48)); \
|
||||
if ((uintptr_t)(i) & 0x0000ffff00000000ULL) \
|
||||
PPC_ORI(d, d, \
|
||||
((uintptr_t)(i) >> 32) & 0xffff); \
|
||||
PPC_SLDI(d, d, 32); \
|
||||
if ((uintptr_t)(i) & 0x00000000ffff0000ULL) \
|
||||
PPC_ORIS(d, d, \
|
||||
((uintptr_t)(i) >> 16) & 0xffff); \
|
||||
if ((uintptr_t)(i) & 0x000000000000ffffULL) \
|
||||
PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \
|
||||
} } while (0);
|
||||
|
||||
static inline bool is_nearbranch(int offset)
|
||||
{
|
||||
return (offset < 32768) && (offset >= -32768);
|
||||
}
|
||||
|
||||
/*
|
||||
* The fly in the ointment of code size changing from pass to pass is
|
||||
* avoided by padding the short branch case with a NOP. If code size differs
|
||||
* with different branch reaches we will have the issue of code moving from
|
||||
* one pass to the next and will need a few passes to converge on a stable
|
||||
* state.
|
||||
*/
|
||||
#define PPC_BCC(cond, dest) do { \
|
||||
if (is_nearbranch((dest) - (ctx->idx * 4))) { \
|
||||
PPC_BCC_SHORT(cond, dest); \
|
||||
PPC_NOP(); \
|
||||
} else { \
|
||||
/* Flip the 'T or F' bit to invert comparison */ \
|
||||
PPC_BCC_SHORT(cond ^ COND_CMP_TRUE, (ctx->idx+2)*4); \
|
||||
PPC_JMP(dest); \
|
||||
} } while(0)
|
||||
|
||||
/* To create a branch condition, select a bit of cr0... */
|
||||
#define CR0_LT 0
|
||||
#define CR0_GT 1
|
||||
#define CR0_EQ 2
|
||||
/* ...and modify BO[3] */
|
||||
#define COND_CMP_TRUE 0x100
|
||||
#define COND_CMP_FALSE 0x000
|
||||
/* Together, they make all required comparisons: */
|
||||
#define COND_GT (CR0_GT | COND_CMP_TRUE)
|
||||
#define COND_GE (CR0_LT | COND_CMP_FALSE)
|
||||
#define COND_EQ (CR0_EQ | COND_CMP_TRUE)
|
||||
#define COND_NE (CR0_EQ | COND_CMP_FALSE)
|
||||
#define COND_LT (CR0_LT | COND_CMP_TRUE)
|
||||
|
||||
#define SEEN_DATAREF 0x10000 /* might call external helpers */
|
||||
#define SEEN_XREG 0x20000 /* X reg is used */
|
||||
#define SEEN_MEM 0x40000 /* SEEN_MEM+(1<<n) = use mem[n] for temporary
|
||||
* storage */
|
||||
#define SEEN_MEM_MSK 0x0ffff
|
||||
|
||||
struct codegen_context {
|
||||
unsigned int seen;
|
||||
unsigned int idx;
|
||||
int pc_ret0; /* bpf index of first RET #0 instruction (if any) */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,138 @@
|
|||
/* bpf_jit.S: Packet/header access helper functions
|
||||
* for PPC64 BPF compiler.
|
||||
*
|
||||
* Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*/
|
||||
|
||||
#include <asm/ppc_asm.h>
|
||||
#include "bpf_jit.h"
|
||||
|
||||
/*
|
||||
* All of these routines are called directly from generated code,
|
||||
* whose register usage is:
|
||||
*
|
||||
* r3 skb
|
||||
* r4,r5 A,X
|
||||
* r6 *** address parameter to helper ***
|
||||
* r7-r10 scratch
|
||||
* r14 skb->data
|
||||
* r15 skb headlen
|
||||
* r16-31 M[]
|
||||
*/
|
||||
|
||||
/*
|
||||
* To consider: These helpers are so small it could be better to just
|
||||
* generate them inline. Inline code can do the simple headlen check
|
||||
* then branch directly to slow_path_XXX if required. (In fact, could
|
||||
* load a spare GPR with the address of slow_path_generic and pass size
|
||||
* as an argument, making the call site a mtlr, li and bllr.)
|
||||
*
|
||||
* Technically, the "is addr < 0" check is unnecessary & slowing down
|
||||
* the ABS path, as it's statically checked on generation.
|
||||
*/
|
||||
.globl sk_load_word
|
||||
sk_load_word:
|
||||
cmpdi r_addr, 0
|
||||
blt bpf_error
|
||||
/* Are we accessing past headlen? */
|
||||
subi r_scratch1, r_HL, 4
|
||||
cmpd r_scratch1, r_addr
|
||||
blt bpf_slow_path_word
|
||||
/* Nope, just hitting the header. cr0 here is eq or gt! */
|
||||
lwzx r_A, r_D, r_addr
|
||||
/* When big endian we don't need to byteswap. */
|
||||
blr /* Return success, cr0 != LT */
|
||||
|
||||
.globl sk_load_half
|
||||
sk_load_half:
|
||||
cmpdi r_addr, 0
|
||||
blt bpf_error
|
||||
subi r_scratch1, r_HL, 2
|
||||
cmpd r_scratch1, r_addr
|
||||
blt bpf_slow_path_half
|
||||
lhzx r_A, r_D, r_addr
|
||||
blr
|
||||
|
||||
.globl sk_load_byte
|
||||
sk_load_byte:
|
||||
cmpdi r_addr, 0
|
||||
blt bpf_error
|
||||
cmpd r_HL, r_addr
|
||||
ble bpf_slow_path_byte
|
||||
lbzx r_A, r_D, r_addr
|
||||
blr
|
||||
|
||||
/*
|
||||
* BPF_S_LDX_B_MSH: ldxb 4*([offset]&0xf)
|
||||
* r_addr is the offset value, already known positive
|
||||
*/
|
||||
.globl sk_load_byte_msh
|
||||
sk_load_byte_msh:
|
||||
cmpd r_HL, r_addr
|
||||
ble bpf_slow_path_byte_msh
|
||||
lbzx r_X, r_D, r_addr
|
||||
rlwinm r_X, r_X, 2, 32-4-2, 31-2
|
||||
blr
|
||||
|
||||
bpf_error:
|
||||
/* Entered with cr0 = lt */
|
||||
li r3, 0
|
||||
/* Generated code will 'blt epilogue', returning 0. */
|
||||
blr
|
||||
|
||||
/* Call out to skb_copy_bits:
|
||||
* We'll need to back up our volatile regs first; we have
|
||||
* local variable space at r1+(BPF_PPC_STACK_BASIC).
|
||||
* Allocate a new stack frame here to remain ABI-compliant in
|
||||
* stashing LR.
|
||||
*/
|
||||
#define bpf_slow_path_common(SIZE) \
|
||||
mflr r0; \
|
||||
std r0, 16(r1); \
|
||||
/* R3 goes in parameter space of caller's frame */ \
|
||||
std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
|
||||
std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
|
||||
std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
|
||||
addi r5, r1, BPF_PPC_STACK_BASIC+(2*8); \
|
||||
stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
|
||||
/* R3 = r_skb, as passed */ \
|
||||
mr r4, r_addr; \
|
||||
li r6, SIZE; \
|
||||
bl skb_copy_bits; \
|
||||
/* R3 = 0 on success */ \
|
||||
addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
|
||||
ld r0, 16(r1); \
|
||||
ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
|
||||
ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
|
||||
mtlr r0; \
|
||||
cmpdi r3, 0; \
|
||||
blt bpf_error; /* cr0 = LT */ \
|
||||
ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
|
||||
/* Great success! */
|
||||
|
||||
bpf_slow_path_word:
|
||||
bpf_slow_path_common(4)
|
||||
/* Data value is on stack, and cr0 != LT */
|
||||
lwz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
|
||||
blr
|
||||
|
||||
bpf_slow_path_half:
|
||||
bpf_slow_path_common(2)
|
||||
lhz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
|
||||
blr
|
||||
|
||||
bpf_slow_path_byte:
|
||||
bpf_slow_path_common(1)
|
||||
lbz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
|
||||
blr
|
||||
|
||||
bpf_slow_path_byte_msh:
|
||||
bpf_slow_path_common(1)
|
||||
lbz r_X, BPF_PPC_STACK_BASIC+(2*8)(r1)
|
||||
rlwinm r_X, r_X, 2, 32-4-2, 31-2
|
||||
blr
|
|
@ -0,0 +1,694 @@
|
|||
/* bpf_jit_comp.c: BPF JIT compiler for PPC64
|
||||
*
|
||||
* Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
|
||||
*
|
||||
* Based on the x86 BPF compiler, by Eric Dumazet (eric.dumazet@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*/
|
||||
#include <linux/moduleloader.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/filter.h>
|
||||
#include "bpf_jit.h"
|
||||
|
||||
#ifndef __BIG_ENDIAN
|
||||
/* There are endianness assumptions herein. */
|
||||
#error "Little-endian PPC not supported in BPF compiler"
|
||||
#endif
|
||||
|
||||
int bpf_jit_enable __read_mostly;
|
||||
|
||||
|
||||
static inline void bpf_flush_icache(void *start, void *end)
|
||||
{
|
||||
smp_wmb();
|
||||
flush_icache_range((unsigned long)start, (unsigned long)end);
|
||||
}
|
||||
|
||||
static void bpf_jit_build_prologue(struct sk_filter *fp, u32 *image,
|
||||
struct codegen_context *ctx)
|
||||
{
|
||||
int i;
|
||||
const struct sock_filter *filter = fp->insns;
|
||||
|
||||
if (ctx->seen & (SEEN_MEM | SEEN_DATAREF)) {
|
||||
/* Make stackframe */
|
||||
if (ctx->seen & SEEN_DATAREF) {
|
||||
/* If we call any helpers (for loads), save LR */
|
||||
EMIT(PPC_INST_MFLR | __PPC_RT(0));
|
||||
PPC_STD(0, 1, 16);
|
||||
|
||||
/* Back up non-volatile regs. */
|
||||
PPC_STD(r_D, 1, -(8*(32-r_D)));
|
||||
PPC_STD(r_HL, 1, -(8*(32-r_HL)));
|
||||
}
|
||||
if (ctx->seen & SEEN_MEM) {
|
||||
/*
|
||||
* Conditionally save regs r15-r31 as some will be used
|
||||
* for M[] data.
|
||||
*/
|
||||
for (i = r_M; i < (r_M+16); i++) {
|
||||
if (ctx->seen & (1 << (i-r_M)))
|
||||
PPC_STD(i, 1, -(8*(32-i)));
|
||||
}
|
||||
}
|
||||
EMIT(PPC_INST_STDU | __PPC_RS(1) | __PPC_RA(1) |
|
||||
(-BPF_PPC_STACKFRAME & 0xfffc));
|
||||
}
|
||||
|
||||
if (ctx->seen & SEEN_DATAREF) {
|
||||
/*
|
||||
* If this filter needs to access skb data,
|
||||
* prepare r_D and r_HL:
|
||||
* r_HL = skb->len - skb->data_len
|
||||
* r_D = skb->data
|
||||
*/
|
||||
PPC_LWZ_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
|
||||
data_len));
|
||||
PPC_LWZ_OFFS(r_HL, r_skb, offsetof(struct sk_buff, len));
|
||||
PPC_SUB(r_HL, r_HL, r_scratch1);
|
||||
PPC_LD_OFFS(r_D, r_skb, offsetof(struct sk_buff, data));
|
||||
}
|
||||
|
||||
if (ctx->seen & SEEN_XREG) {
|
||||
/*
|
||||
* TODO: Could also detect whether first instr. sets X and
|
||||
* avoid this (as below, with A).
|
||||
*/
|
||||
PPC_LI(r_X, 0);
|
||||
}
|
||||
|
||||
switch (filter[0].code) {
|
||||
case BPF_S_RET_K:
|
||||
case BPF_S_LD_W_LEN:
|
||||
case BPF_S_ANC_PROTOCOL:
|
||||
case BPF_S_ANC_IFINDEX:
|
||||
case BPF_S_ANC_MARK:
|
||||
case BPF_S_ANC_RXHASH:
|
||||
case BPF_S_ANC_CPU:
|
||||
case BPF_S_ANC_QUEUE:
|
||||
case BPF_S_LD_W_ABS:
|
||||
case BPF_S_LD_H_ABS:
|
||||
case BPF_S_LD_B_ABS:
|
||||
/* first instruction sets A register (or is RET 'constant') */
|
||||
break;
|
||||
default:
|
||||
/* make sure we dont leak kernel information to user */
|
||||
PPC_LI(r_A, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ctx->seen & (SEEN_MEM | SEEN_DATAREF)) {
|
||||
PPC_ADDI(1, 1, BPF_PPC_STACKFRAME);
|
||||
if (ctx->seen & SEEN_DATAREF) {
|
||||
PPC_LD(0, 1, 16);
|
||||
PPC_MTLR(0);
|
||||
PPC_LD(r_D, 1, -(8*(32-r_D)));
|
||||
PPC_LD(r_HL, 1, -(8*(32-r_HL)));
|
||||
}
|
||||
if (ctx->seen & SEEN_MEM) {
|
||||
/* Restore any saved non-vol registers */
|
||||
for (i = r_M; i < (r_M+16); i++) {
|
||||
if (ctx->seen & (1 << (i-r_M)))
|
||||
PPC_LD(i, 1, -(8*(32-i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The RETs have left a return value in R3. */
|
||||
|
||||
PPC_BLR();
|
||||
}
|
||||
|
||||
/* Assemble the body code between the prologue & epilogue. */
|
||||
static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
|
||||
struct codegen_context *ctx,
|
||||
unsigned int *addrs)
|
||||
{
|
||||
const struct sock_filter *filter = fp->insns;
|
||||
int flen = fp->len;
|
||||
u8 *func;
|
||||
unsigned int true_cond;
|
||||
int i;
|
||||
|
||||
/* Start of epilogue code */
|
||||
unsigned int exit_addr = addrs[flen];
|
||||
|
||||
for (i = 0; i < flen; i++) {
|
||||
unsigned int K = filter[i].k;
|
||||
|
||||
/*
|
||||
* addrs[] maps a BPF bytecode address into a real offset from
|
||||
* the start of the body code.
|
||||
*/
|
||||
addrs[i] = ctx->idx * 4;
|
||||
|
||||
switch (filter[i].code) {
|
||||
/*** ALU ops ***/
|
||||
case BPF_S_ALU_ADD_X: /* A += X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_ADD(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_ADD_K: /* A += K; */
|
||||
if (!K)
|
||||
break;
|
||||
PPC_ADDI(r_A, r_A, IMM_L(K));
|
||||
if (K >= 32768)
|
||||
PPC_ADDIS(r_A, r_A, IMM_HA(K));
|
||||
break;
|
||||
case BPF_S_ALU_SUB_X: /* A -= X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_SUB(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_SUB_K: /* A -= K */
|
||||
if (!K)
|
||||
break;
|
||||
PPC_ADDI(r_A, r_A, IMM_L(-K));
|
||||
if (K >= 32768)
|
||||
PPC_ADDIS(r_A, r_A, IMM_HA(-K));
|
||||
break;
|
||||
case BPF_S_ALU_MUL_X: /* A *= X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_MUL(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_MUL_K: /* A *= K */
|
||||
if (K < 32768)
|
||||
PPC_MULI(r_A, r_A, K);
|
||||
else {
|
||||
PPC_LI32(r_scratch1, K);
|
||||
PPC_MUL(r_A, r_A, r_scratch1);
|
||||
}
|
||||
break;
|
||||
case BPF_S_ALU_DIV_X: /* A /= X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_CMPWI(r_X, 0);
|
||||
if (ctx->pc_ret0 != -1) {
|
||||
PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
|
||||
} else {
|
||||
/*
|
||||
* Exit, returning 0; first pass hits here
|
||||
* (longer worst-case code size).
|
||||
*/
|
||||
PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
|
||||
PPC_LI(r_ret, 0);
|
||||
PPC_JMP(exit_addr);
|
||||
}
|
||||
PPC_DIVWU(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */
|
||||
PPC_LI32(r_scratch1, K);
|
||||
/* Top 32 bits of 64bit result -> A */
|
||||
PPC_MULHWU(r_A, r_A, r_scratch1);
|
||||
break;
|
||||
case BPF_S_ALU_AND_X:
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_AND(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_AND_K:
|
||||
if (!IMM_H(K))
|
||||
PPC_ANDI(r_A, r_A, K);
|
||||
else {
|
||||
PPC_LI32(r_scratch1, K);
|
||||
PPC_AND(r_A, r_A, r_scratch1);
|
||||
}
|
||||
break;
|
||||
case BPF_S_ALU_OR_X:
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_OR(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_OR_K:
|
||||
if (IMM_L(K))
|
||||
PPC_ORI(r_A, r_A, IMM_L(K));
|
||||
if (K >= 65536)
|
||||
PPC_ORIS(r_A, r_A, IMM_H(K));
|
||||
break;
|
||||
case BPF_S_ALU_LSH_X: /* A <<= X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_SLW(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_LSH_K:
|
||||
if (K == 0)
|
||||
break;
|
||||
else
|
||||
PPC_SLWI(r_A, r_A, K);
|
||||
break;
|
||||
case BPF_S_ALU_RSH_X: /* A >>= X; */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_SRW(r_A, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_ALU_RSH_K: /* A >>= K; */
|
||||
if (K == 0)
|
||||
break;
|
||||
else
|
||||
PPC_SRWI(r_A, r_A, K);
|
||||
break;
|
||||
case BPF_S_ALU_NEG:
|
||||
PPC_NEG(r_A, r_A);
|
||||
break;
|
||||
case BPF_S_RET_K:
|
||||
PPC_LI32(r_ret, K);
|
||||
if (!K) {
|
||||
if (ctx->pc_ret0 == -1)
|
||||
ctx->pc_ret0 = i;
|
||||
}
|
||||
/*
|
||||
* If this isn't the very last instruction, branch to
|
||||
* the epilogue if we've stuff to clean up. Otherwise,
|
||||
* if there's nothing to tidy, just return. If we /are/
|
||||
* the last instruction, we're about to fall through to
|
||||
* the epilogue to return.
|
||||
*/
|
||||
if (i != flen - 1) {
|
||||
/*
|
||||
* Note: 'seen' is properly valid only on pass
|
||||
* #2. Both parts of this conditional are the
|
||||
* same instruction size though, meaning the
|
||||
* first pass will still correctly determine the
|
||||
* code size/addresses.
|
||||
*/
|
||||
if (ctx->seen)
|
||||
PPC_JMP(exit_addr);
|
||||
else
|
||||
PPC_BLR();
|
||||
}
|
||||
break;
|
||||
case BPF_S_RET_A:
|
||||
PPC_MR(r_ret, r_A);
|
||||
if (i != flen - 1) {
|
||||
if (ctx->seen)
|
||||
PPC_JMP(exit_addr);
|
||||
else
|
||||
PPC_BLR();
|
||||
}
|
||||
break;
|
||||
case BPF_S_MISC_TAX: /* X = A */
|
||||
PPC_MR(r_X, r_A);
|
||||
break;
|
||||
case BPF_S_MISC_TXA: /* A = X */
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_MR(r_A, r_X);
|
||||
break;
|
||||
|
||||
/*** Constant loads/M[] access ***/
|
||||
case BPF_S_LD_IMM: /* A = K */
|
||||
PPC_LI32(r_A, K);
|
||||
break;
|
||||
case BPF_S_LDX_IMM: /* X = K */
|
||||
PPC_LI32(r_X, K);
|
||||
break;
|
||||
case BPF_S_LD_MEM: /* A = mem[K] */
|
||||
PPC_MR(r_A, r_M + (K & 0xf));
|
||||
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
|
||||
break;
|
||||
case BPF_S_LDX_MEM: /* X = mem[K] */
|
||||
PPC_MR(r_X, r_M + (K & 0xf));
|
||||
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
|
||||
break;
|
||||
case BPF_S_ST: /* mem[K] = A */
|
||||
PPC_MR(r_M + (K & 0xf), r_A);
|
||||
ctx->seen |= SEEN_MEM | (1<<(K & 0xf));
|
||||
break;
|
||||
case BPF_S_STX: /* mem[K] = X */
|
||||
PPC_MR(r_M + (K & 0xf), r_X);
|
||||
ctx->seen |= SEEN_XREG | SEEN_MEM | (1<<(K & 0xf));
|
||||
break;
|
||||
case BPF_S_LD_W_LEN: /* A = skb->len; */
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
|
||||
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len));
|
||||
break;
|
||||
case BPF_S_LDX_W_LEN: /* X = skb->len; */
|
||||
PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len));
|
||||
break;
|
||||
|
||||
/*** Ancillary info loads ***/
|
||||
|
||||
/* None of the BPF_S_ANC* codes appear to be passed by
|
||||
* sk_chk_filter(). The interpreter and the x86 BPF
|
||||
* compiler implement them so we do too -- they may be
|
||||
* planted in future.
|
||||
*/
|
||||
case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
|
||||
protocol) != 2);
|
||||
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
|
||||
protocol));
|
||||
/* ntohs is a NOP with BE loads. */
|
||||
break;
|
||||
case BPF_S_ANC_IFINDEX:
|
||||
PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
|
||||
dev));
|
||||
PPC_CMPDI(r_scratch1, 0);
|
||||
if (ctx->pc_ret0 != -1) {
|
||||
PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
|
||||
} else {
|
||||
/* Exit, returning 0; first pass hits here. */
|
||||
PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
|
||||
PPC_LI(r_ret, 0);
|
||||
PPC_JMP(exit_addr);
|
||||
}
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
|
||||
ifindex) != 4);
|
||||
PPC_LWZ_OFFS(r_A, r_scratch1,
|
||||
offsetof(struct net_device, ifindex));
|
||||
break;
|
||||
case BPF_S_ANC_MARK:
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
|
||||
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
|
||||
mark));
|
||||
break;
|
||||
case BPF_S_ANC_RXHASH:
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
|
||||
PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
|
||||
rxhash));
|
||||
break;
|
||||
case BPF_S_ANC_QUEUE:
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
|
||||
queue_mapping) != 2);
|
||||
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
|
||||
queue_mapping));
|
||||
break;
|
||||
case BPF_S_ANC_CPU:
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* PACA ptr is r13:
|
||||
* raw_smp_processor_id() = local_paca->paca_index
|
||||
*/
|
||||
BUILD_BUG_ON(FIELD_SIZEOF(struct paca_struct,
|
||||
paca_index) != 2);
|
||||
PPC_LHZ_OFFS(r_A, 13,
|
||||
offsetof(struct paca_struct, paca_index));
|
||||
#else
|
||||
PPC_LI(r_A, 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
/*** Absolute loads from packet header/data ***/
|
||||
case BPF_S_LD_W_ABS:
|
||||
func = sk_load_word;
|
||||
goto common_load;
|
||||
case BPF_S_LD_H_ABS:
|
||||
func = sk_load_half;
|
||||
goto common_load;
|
||||
case BPF_S_LD_B_ABS:
|
||||
func = sk_load_byte;
|
||||
common_load:
|
||||
/*
|
||||
* Load from [K]. Reference with the (negative)
|
||||
* SKF_NET_OFF/SKF_LL_OFF offsets is unsupported.
|
||||
*/
|
||||
ctx->seen |= SEEN_DATAREF;
|
||||
if ((int)K < 0)
|
||||
return -ENOTSUPP;
|
||||
PPC_LI64(r_scratch1, func);
|
||||
PPC_MTLR(r_scratch1);
|
||||
PPC_LI32(r_addr, K);
|
||||
PPC_BLRL();
|
||||
/*
|
||||
* Helper returns 'lt' condition on error, and an
|
||||
* appropriate return value in r3
|
||||
*/
|
||||
PPC_BCC(COND_LT, exit_addr);
|
||||
break;
|
||||
|
||||
/*** Indirect loads from packet header/data ***/
|
||||
case BPF_S_LD_W_IND:
|
||||
func = sk_load_word;
|
||||
goto common_load_ind;
|
||||
case BPF_S_LD_H_IND:
|
||||
func = sk_load_half;
|
||||
goto common_load_ind;
|
||||
case BPF_S_LD_B_IND:
|
||||
func = sk_load_byte;
|
||||
common_load_ind:
|
||||
/*
|
||||
* Load from [X + K]. Negative offsets are tested for
|
||||
* in the helper functions, and result in a 'ret 0'.
|
||||
*/
|
||||
ctx->seen |= SEEN_DATAREF | SEEN_XREG;
|
||||
PPC_LI64(r_scratch1, func);
|
||||
PPC_MTLR(r_scratch1);
|
||||
PPC_ADDI(r_addr, r_X, IMM_L(K));
|
||||
if (K >= 32768)
|
||||
PPC_ADDIS(r_addr, r_addr, IMM_HA(K));
|
||||
PPC_BLRL();
|
||||
/* If error, cr0.LT set */
|
||||
PPC_BCC(COND_LT, exit_addr);
|
||||
break;
|
||||
|
||||
case BPF_S_LDX_B_MSH:
|
||||
/*
|
||||
* x86 version drops packet (RET 0) when K<0, whereas
|
||||
* interpreter does allow K<0 (__load_pointer, special
|
||||
* ancillary data). common_load returns ENOTSUPP if K<0,
|
||||
* so we fall back to interpreter & filter works.
|
||||
*/
|
||||
func = sk_load_byte_msh;
|
||||
goto common_load;
|
||||
break;
|
||||
|
||||
/*** Jump and branches ***/
|
||||
case BPF_S_JMP_JA:
|
||||
if (K != 0)
|
||||
PPC_JMP(addrs[i + 1 + K]);
|
||||
break;
|
||||
|
||||
case BPF_S_JMP_JGT_K:
|
||||
case BPF_S_JMP_JGT_X:
|
||||
true_cond = COND_GT;
|
||||
goto cond_branch;
|
||||
case BPF_S_JMP_JGE_K:
|
||||
case BPF_S_JMP_JGE_X:
|
||||
true_cond = COND_GE;
|
||||
goto cond_branch;
|
||||
case BPF_S_JMP_JEQ_K:
|
||||
case BPF_S_JMP_JEQ_X:
|
||||
true_cond = COND_EQ;
|
||||
goto cond_branch;
|
||||
case BPF_S_JMP_JSET_K:
|
||||
case BPF_S_JMP_JSET_X:
|
||||
true_cond = COND_NE;
|
||||
/* Fall through */
|
||||
cond_branch:
|
||||
/* same targets, can avoid doing the test :) */
|
||||
if (filter[i].jt == filter[i].jf) {
|
||||
if (filter[i].jt > 0)
|
||||
PPC_JMP(addrs[i + 1 + filter[i].jt]);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (filter[i].code) {
|
||||
case BPF_S_JMP_JGT_X:
|
||||
case BPF_S_JMP_JGE_X:
|
||||
case BPF_S_JMP_JEQ_X:
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_CMPLW(r_A, r_X);
|
||||
break;
|
||||
case BPF_S_JMP_JSET_X:
|
||||
ctx->seen |= SEEN_XREG;
|
||||
PPC_AND_DOT(r_scratch1, r_A, r_X);
|
||||
break;
|
||||
case BPF_S_JMP_JEQ_K:
|
||||
case BPF_S_JMP_JGT_K:
|
||||
case BPF_S_JMP_JGE_K:
|
||||
if (K < 32768)
|
||||
PPC_CMPLWI(r_A, K);
|
||||
else {
|
||||
PPC_LI32(r_scratch1, K);
|
||||
PPC_CMPLW(r_A, r_scratch1);
|
||||
}
|
||||
break;
|
||||
case BPF_S_JMP_JSET_K:
|
||||
if (K < 32768)
|
||||
/* PPC_ANDI is /only/ dot-form */
|
||||
PPC_ANDI(r_scratch1, r_A, K);
|
||||
else {
|
||||
PPC_LI32(r_scratch1, K);
|
||||
PPC_AND_DOT(r_scratch1, r_A,
|
||||
r_scratch1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Sometimes branches are constructed "backward", with
|
||||
* the false path being the branch and true path being
|
||||
* a fallthrough to the next instruction.
|
||||
*/
|
||||
if (filter[i].jt == 0)
|
||||
/* Swap the sense of the branch */
|
||||
PPC_BCC(true_cond ^ COND_CMP_TRUE,
|
||||
addrs[i + 1 + filter[i].jf]);
|
||||
else {
|
||||
PPC_BCC(true_cond, addrs[i + 1 + filter[i].jt]);
|
||||
if (filter[i].jf != 0)
|
||||
PPC_JMP(addrs[i + 1 + filter[i].jf]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* The filter contains something cruel & unusual.
|
||||
* We don't handle it, but also there shouldn't be
|
||||
* anything missing from our list.
|
||||
*/
|
||||
if (printk_ratelimit())
|
||||
pr_err("BPF filter opcode %04x (@%d) unsupported\n",
|
||||
filter[i].code, i);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
}
|
||||
/* Set end-of-body-code address for exit. */
|
||||
addrs[i] = ctx->idx * 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_jit_compile(struct sk_filter *fp)
|
||||
{
|
||||
unsigned int proglen;
|
||||
unsigned int alloclen;
|
||||
u32 *image = NULL;
|
||||
u32 *code_base;
|
||||
unsigned int *addrs;
|
||||
struct codegen_context cgctx;
|
||||
int pass;
|
||||
int flen = fp->len;
|
||||
|
||||
if (!bpf_jit_enable)
|
||||
return;
|
||||
|
||||
addrs = kzalloc((flen+1) * sizeof(*addrs), GFP_KERNEL);
|
||||
if (addrs == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* There are multiple assembly passes as the generated code will change
|
||||
* size as it settles down, figuring out the max branch offsets/exit
|
||||
* paths required.
|
||||
*
|
||||
* The range of standard conditional branches is +/- 32Kbytes. Since
|
||||
* BPF_MAXINSNS = 4096, we can only jump from (worst case) start to
|
||||
* finish with 8 bytes/instruction. Not feasible, so long jumps are
|
||||
* used, distinct from short branches.
|
||||
*
|
||||
* Current:
|
||||
*
|
||||
* For now, both branch types assemble to 2 words (short branches padded
|
||||
* with a NOP); this is less efficient, but assembly will always complete
|
||||
* after exactly 3 passes:
|
||||
*
|
||||
* First pass: No code buffer; Program is "faux-generated" -- no code
|
||||
* emitted but maximum size of output determined (and addrs[] filled
|
||||
* in). Also, we note whether we use M[], whether we use skb data, etc.
|
||||
* All generation choices assumed to be 'worst-case', e.g. branches all
|
||||
* far (2 instructions), return path code reduction not available, etc.
|
||||
*
|
||||
* Second pass: Code buffer allocated with size determined previously.
|
||||
* Prologue generated to support features we have seen used. Exit paths
|
||||
* determined and addrs[] is filled in again, as code may be slightly
|
||||
* smaller as a result.
|
||||
*
|
||||
* Third pass: Code generated 'for real', and branch destinations
|
||||
* determined from now-accurate addrs[] map.
|
||||
*
|
||||
* Ideal:
|
||||
*
|
||||
* If we optimise this, near branches will be shorter. On the
|
||||
* first assembly pass, we should err on the side of caution and
|
||||
* generate the biggest code. On subsequent passes, branches will be
|
||||
* generated short or long and code size will reduce. With smaller
|
||||
* code, more branches may fall into the short category, and code will
|
||||
* reduce more.
|
||||
*
|
||||
* Finally, if we see one pass generate code the same size as the
|
||||
* previous pass we have converged and should now generate code for
|
||||
* real. Allocating at the end will also save the memory that would
|
||||
* otherwise be wasted by the (small) current code shrinkage.
|
||||
* Preferably, we should do a small number of passes (e.g. 5) and if we
|
||||
* haven't converged by then, get impatient and force code to generate
|
||||
* as-is, even if the odd branch would be left long. The chances of a
|
||||
* long jump are tiny with all but the most enormous of BPF filter
|
||||
* inputs, so we should usually converge on the third pass.
|
||||
*/
|
||||
|
||||
cgctx.idx = 0;
|
||||
cgctx.seen = 0;
|
||||
cgctx.pc_ret0 = -1;
|
||||
/* Scouting faux-generate pass 0 */
|
||||
if (bpf_jit_build_body(fp, 0, &cgctx, addrs))
|
||||
/* We hit something illegal or unsupported. */
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Pretend to build prologue, given the features we've seen. This will
|
||||
* update ctgtx.idx as it pretends to output instructions, then we can
|
||||
* calculate total size from idx.
|
||||
*/
|
||||
bpf_jit_build_prologue(fp, 0, &cgctx);
|
||||
bpf_jit_build_epilogue(0, &cgctx);
|
||||
|
||||
proglen = cgctx.idx * 4;
|
||||
alloclen = proglen + FUNCTION_DESCR_SIZE;
|
||||
image = module_alloc(max_t(unsigned int, alloclen,
|
||||
sizeof(struct work_struct)));
|
||||
if (!image)
|
||||
goto out;
|
||||
|
||||
code_base = image + (FUNCTION_DESCR_SIZE/4);
|
||||
|
||||
/* Code generation passes 1-2 */
|
||||
for (pass = 1; pass < 3; pass++) {
|
||||
/* Now build the prologue, body code & epilogue for real. */
|
||||
cgctx.idx = 0;
|
||||
bpf_jit_build_prologue(fp, code_base, &cgctx);
|
||||
bpf_jit_build_body(fp, code_base, &cgctx, addrs);
|
||||
bpf_jit_build_epilogue(code_base, &cgctx);
|
||||
|
||||
if (bpf_jit_enable > 1)
|
||||
pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass,
|
||||
proglen - (cgctx.idx * 4), cgctx.seen);
|
||||
}
|
||||
|
||||
if (bpf_jit_enable > 1)
|
||||
pr_info("flen=%d proglen=%u pass=%d image=%p\n",
|
||||
flen, proglen, pass, image);
|
||||
|
||||
if (image) {
|
||||
if (bpf_jit_enable > 1)
|
||||
print_hex_dump(KERN_ERR, "JIT code: ",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1, code_base,
|
||||
proglen, false);
|
||||
|
||||
bpf_flush_icache(code_base, code_base + (proglen/4));
|
||||
/* Function descriptor nastiness: Address + TOC */
|
||||
((u64 *)image)[0] = (u64)code_base;
|
||||
((u64 *)image)[1] = local_paca->kernel_toc;
|
||||
fp->bpf_func = (void *)image;
|
||||
}
|
||||
out:
|
||||
kfree(addrs);
|
||||
return;
|
||||
}
|
||||
|
||||
static void jit_free_defer(struct work_struct *arg)
|
||||
{
|
||||
module_free(NULL, arg);
|
||||
}
|
||||
|
||||
/* run from softirq, we must use a work_struct to call
|
||||
* module_free() from process context
|
||||
*/
|
||||
void bpf_jit_free(struct sk_filter *fp)
|
||||
{
|
||||
if (fp->bpf_func != sk_run_filter) {
|
||||
struct work_struct *work = (struct work_struct *)fp->bpf_func;
|
||||
|
||||
INIT_WORK(work, jit_free_defer);
|
||||
schedule_work(work);
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@
|
|||
#include <asm/bootparam.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/swiotlb.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/setup.h>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
#include <linux/async_tx.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#undef pr
|
||||
|
|
|
@ -94,8 +94,6 @@ source "drivers/memstick/Kconfig"
|
|||
|
||||
source "drivers/leds/Kconfig"
|
||||
|
||||
source "drivers/nfc/Kconfig"
|
||||
|
||||
source "drivers/accessibility/Kconfig"
|
||||
|
||||
source "drivers/infiniband/Kconfig"
|
||||
|
|
|
@ -122,3 +122,4 @@ obj-y += ieee802154/
|
|||
obj-y += clk/
|
||||
|
||||
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
|
||||
obj-$(CONFIG_NFC) += nfc/
|
||||
|
|
|
@ -813,7 +813,7 @@ static void fill_rx_pool (amb_dev * dev, unsigned char pool,
|
|||
return;
|
||||
}
|
||||
|
||||
// top up all RX pools (can also be called as a bottom half)
|
||||
// top up all RX pools
|
||||
static void fill_rx_pools (amb_dev * dev) {
|
||||
unsigned char pool;
|
||||
|
||||
|
@ -872,11 +872,7 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id) {
|
|||
++irq_work;
|
||||
|
||||
if (irq_work) {
|
||||
#ifdef FILL_RX_POOLS_IN_BH
|
||||
schedule_work (&dev->bh);
|
||||
#else
|
||||
fill_rx_pools (dev);
|
||||
#endif
|
||||
|
||||
PRINTD (DBG_IRQ, "work done: %u", irq_work);
|
||||
} else {
|
||||
|
@ -2154,11 +2150,6 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
|
|||
dev->tx_avail = ATM_OC3_PCR;
|
||||
dev->rx_avail = ATM_OC3_PCR;
|
||||
|
||||
#ifdef FILL_RX_POOLS_IN_BH
|
||||
// initialise bottom half
|
||||
INIT_WORK(&dev->bh, (void (*)(void *)) fill_rx_pools, dev);
|
||||
#endif
|
||||
|
||||
// semaphore for txer/rxer modifications - we cannot use a
|
||||
// spinlock as the critical region needs to switch processes
|
||||
mutex_init(&dev->vcc_sf);
|
||||
|
|
|
@ -630,10 +630,6 @@ struct amb_dev {
|
|||
u32 iobase;
|
||||
u32 * membase;
|
||||
|
||||
#ifdef FILL_RX_POOLS_IN_BH
|
||||
struct work_struct bh;
|
||||
#endif
|
||||
|
||||
amb_cq cq;
|
||||
amb_txq txq;
|
||||
amb_rxq rxq[NUM_RX_POOLS];
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/atm.h>
|
||||
#include <linux/atmdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sonet.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/time.h>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <linux/ioport.h> /* for request_region */
|
||||
#include <linux/uio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/atm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/system.h>
|
||||
|
|
|
@ -1947,7 +1947,6 @@ static int __devinit lanai_pci_start(struct lanai_dev *lanai)
|
|||
{
|
||||
struct pci_dev *pci = lanai->pci;
|
||||
int result;
|
||||
u16 w;
|
||||
|
||||
if (pci_enable_device(pci) != 0) {
|
||||
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable "
|
||||
|
@ -1965,13 +1964,7 @@ static int __devinit lanai_pci_start(struct lanai_dev *lanai)
|
|||
"(itf %d): No suitable DMA available.\n", lanai->number);
|
||||
return -EBUSY;
|
||||
}
|
||||
result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w);
|
||||
if (result != PCIBIOS_SUCCESSFUL) {
|
||||
printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
|
||||
"PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
|
||||
return -EINVAL;
|
||||
}
|
||||
result = check_board_id_and_rev("PCI", w, NULL);
|
||||
result = check_board_id_and_rev("PCI", pci->subsystem_device, NULL);
|
||||
if (result != 0)
|
||||
return result;
|
||||
/* Set latency timer to zero as per lanai docs */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/atm_zatm.h>
|
||||
#include <linux/capability.h>
|
||||
|
|
|
@ -13,6 +13,11 @@ config BCMA
|
|||
Bus driver for Broadcom specific Advanced Microcontroller Bus
|
||||
Architecture.
|
||||
|
||||
# Support for Block-I/O. SELECT this from the driver that needs it.
|
||||
config BCMA_BLOCKIO
|
||||
bool
|
||||
depends on BCMA
|
||||
|
||||
config BCMA_HOST_PCI_POSSIBLE
|
||||
bool
|
||||
depends on BCMA && PCI = y
|
||||
|
@ -22,6 +27,12 @@ config BCMA_HOST_PCI
|
|||
bool "Support for BCMA on PCI-host bus"
|
||||
depends on BCMA_HOST_PCI_POSSIBLE
|
||||
|
||||
config BCMA_DRIVER_PCI_HOSTMODE
|
||||
bool "Driver for PCI core working in hostmode"
|
||||
depends on BCMA && MIPS
|
||||
help
|
||||
PCI core hostmode operation (external PCI bus).
|
||||
|
||||
config BCMA_DEBUG
|
||||
bool "BCMA debugging"
|
||||
depends on BCMA
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
bcma-y += main.o scan.o core.o
|
||||
bcma-y += main.o scan.o core.o sprom.o
|
||||
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
|
||||
bcma-y += driver_pci.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
|
||||
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
|
||||
obj-$(CONFIG_BCMA) += bcma.o
|
||||
|
||||
|
|
|
@ -13,16 +13,23 @@
|
|||
struct bcma_bus;
|
||||
|
||||
/* main.c */
|
||||
extern int bcma_bus_register(struct bcma_bus *bus);
|
||||
extern void bcma_bus_unregister(struct bcma_bus *bus);
|
||||
int bcma_bus_register(struct bcma_bus *bus);
|
||||
void bcma_bus_unregister(struct bcma_bus *bus);
|
||||
|
||||
/* scan.c */
|
||||
int bcma_bus_scan(struct bcma_bus *bus);
|
||||
|
||||
/* sprom.c */
|
||||
int bcma_sprom_get(struct bcma_bus *bus);
|
||||
|
||||
#ifdef CONFIG_BCMA_HOST_PCI
|
||||
/* host_pci.c */
|
||||
extern int __init bcma_host_pci_init(void);
|
||||
extern void __exit bcma_host_pci_exit(void);
|
||||
#endif /* CONFIG_BCMA_HOST_PCI */
|
||||
|
||||
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
||||
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
|
||||
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,7 +19,7 @@ bool bcma_core_is_enabled(struct bcma_device *core)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_is_enabled);
|
||||
|
||||
static void bcma_core_disable(struct bcma_device *core, u32 flags)
|
||||
void bcma_core_disable(struct bcma_device *core, u32 flags)
|
||||
{
|
||||
if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
|
||||
return;
|
||||
|
@ -31,6 +31,7 @@ static void bcma_core_disable(struct bcma_device *core, u32 flags)
|
|||
bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
|
||||
udelay(1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_disable);
|
||||
|
||||
int bcma_core_enable(struct bcma_device *core, u32 flags)
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
|
|||
max_msk = 0xFFFF;
|
||||
break;
|
||||
case 43224:
|
||||
case 43225:
|
||||
break;
|
||||
default:
|
||||
pr_err("PMU resource config unknown for device 0x%04X\n",
|
||||
|
@ -74,6 +75,7 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
|
|||
case 0x4313:
|
||||
case 0x4331:
|
||||
case 43224:
|
||||
case 43225:
|
||||
break;
|
||||
default:
|
||||
pr_err("PMU switch/regulators init unknown for device "
|
||||
|
@ -96,11 +98,13 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
|
|||
if (bus->chipinfo.rev == 0) {
|
||||
pr_err("Workarounds for 43224 rev 0 not fully "
|
||||
"implemented\n");
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
|
||||
} else {
|
||||
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
|
||||
}
|
||||
break;
|
||||
case 43225:
|
||||
break;
|
||||
default:
|
||||
pr_err("Workarounds unknown for device 0x%04X\n",
|
||||
bus->chipinfo.id);
|
||||
|
|
|
@ -157,7 +157,67 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
|
|||
* Init.
|
||||
**************************************************/
|
||||
|
||||
void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
|
||||
{
|
||||
bcma_pcicore_serdes_workaround(pc);
|
||||
}
|
||||
|
||||
static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
|
||||
{
|
||||
struct bcma_bus *bus = pc->core->bus;
|
||||
u16 chipid_top;
|
||||
|
||||
chipid_top = (bus->chipinfo.id & 0xFF00);
|
||||
if (chipid_top != 0x4700 &&
|
||||
chipid_top != 0x5300)
|
||||
return false;
|
||||
|
||||
if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
/* TODO: on BCMA we use address from EROM instead of magic formula */
|
||||
u32 tmp;
|
||||
return !mips_busprobe32(tmp, (bus->mmio +
|
||||
(pc->core->core_index * BCMA_CORE_SIZE)));
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
{
|
||||
if (bcma_core_pci_is_in_hostmode(pc)) {
|
||||
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
||||
bcma_core_pci_hostmode_init(pc);
|
||||
#else
|
||||
pr_err("Driver compiled without support for hostmode PCI\n");
|
||||
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
||||
} else {
|
||||
bcma_core_pci_clientmode_init(pc);
|
||||
}
|
||||
}
|
||||
|
||||
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
||||
bool enable)
|
||||
{
|
||||
struct pci_dev *pdev = pc->core->bus->host_pci;
|
||||
u32 coremask, tmp;
|
||||
int err;
|
||||
|
||||
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
coremask = BIT(core->core_index) << 8;
|
||||
if (enable)
|
||||
tmp |= coremask;
|
||||
else
|
||||
tmp &= ~coremask;
|
||||
|
||||
err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Broadcom specific AMBA
|
||||
* PCI Core in hostmode
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
||||
{
|
||||
pr_err("No support for PCI core in hostmode yet\n");
|
||||
}
|
|
@ -65,6 +65,54 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
|
|||
iowrite32(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCMA_BLOCKIO
|
||||
void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
|
||||
size_t count, u16 offset, u8 reg_width)
|
||||
{
|
||||
void __iomem *addr = core->bus->mmio + offset;
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
switch (reg_width) {
|
||||
case sizeof(u8):
|
||||
ioread8_rep(addr, buffer, count);
|
||||
break;
|
||||
case sizeof(u16):
|
||||
WARN_ON(count & 1);
|
||||
ioread16_rep(addr, buffer, count >> 1);
|
||||
break;
|
||||
case sizeof(u32):
|
||||
WARN_ON(count & 3);
|
||||
ioread32_rep(addr, buffer, count >> 2);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
|
||||
size_t count, u16 offset, u8 reg_width)
|
||||
{
|
||||
void __iomem *addr = core->bus->mmio + offset;
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
switch (reg_width) {
|
||||
case sizeof(u8):
|
||||
iowrite8_rep(addr, buffer, count);
|
||||
break;
|
||||
case sizeof(u16):
|
||||
WARN_ON(count & 1);
|
||||
iowrite16_rep(addr, buffer, count >> 1);
|
||||
break;
|
||||
case sizeof(u32):
|
||||
WARN_ON(count & 3);
|
||||
iowrite32_rep(addr, buffer, count >> 2);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
|
@ -87,6 +135,10 @@ const struct bcma_host_ops bcma_host_pci_ops = {
|
|||
.write8 = bcma_host_pci_write8,
|
||||
.write16 = bcma_host_pci_write16,
|
||||
.write32 = bcma_host_pci_write32,
|
||||
#ifdef CONFIG_BCMA_BLOCKIO
|
||||
.block_read = bcma_host_pci_block_read,
|
||||
.block_write = bcma_host_pci_block_write,
|
||||
#endif
|
||||
.aread32 = bcma_host_pci_aread32,
|
||||
.awrite32 = bcma_host_pci_awrite32,
|
||||
};
|
||||
|
@ -175,6 +227,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
|
||||
{ 0, },
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -89,6 +90,8 @@ static int bcma_register_cores(struct bcma_bus *bus)
|
|||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
core->dev.parent = &bus->host_pci->dev;
|
||||
core->dma_dev = &bus->host_pci->dev;
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_NONE:
|
||||
case BCMA_HOSTTYPE_SDIO:
|
||||
|
@ -144,6 +147,15 @@ int bcma_bus_register(struct bcma_bus *bus)
|
|||
bcma_core_pci_init(&bus->drv_pci);
|
||||
}
|
||||
|
||||
/* Try to get SPROM */
|
||||
err = bcma_sprom_get(bus);
|
||||
if (err == -ENOENT) {
|
||||
pr_err("No SPROM available\n");
|
||||
} else if (err) {
|
||||
pr_err("Failed to get SPROM: %d\n", err);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Register found cores */
|
||||
bcma_register_cores(bus);
|
||||
|
||||
|
@ -151,13 +163,11 @@ int bcma_bus_register(struct bcma_bus *bus)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_bus_register);
|
||||
|
||||
void bcma_bus_unregister(struct bcma_bus *bus)
|
||||
{
|
||||
bcma_unregister_cores(bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcma_bus_unregister);
|
||||
|
||||
int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Broadcom specific AMBA
|
||||
* SPROM reading
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/bcma/bcma_regs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define SPOFF(offset) ((offset) / sizeof(u16))
|
||||
|
||||
/**************************************************
|
||||
* R/W ops.
|
||||
**************************************************/
|
||||
|
||||
static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
|
||||
sprom[i] = bcma_read16(bus->drv_cc.core,
|
||||
BCMA_CC_SPROM + (i * 2));
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Validation.
|
||||
**************************************************/
|
||||
|
||||
static inline u8 bcma_crc8(u8 crc, u8 data)
|
||||
{
|
||||
/* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
|
||||
static const u8 t[] = {
|
||||
0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
|
||||
0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
|
||||
0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
|
||||
0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
|
||||
0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
|
||||
0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
|
||||
0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
|
||||
0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
|
||||
0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
|
||||
0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
|
||||
0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
|
||||
0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
|
||||
0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
|
||||
0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
|
||||
0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
|
||||
0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
|
||||
0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
|
||||
0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
|
||||
0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
|
||||
0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
|
||||
0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
|
||||
0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
|
||||
0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
|
||||
0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
|
||||
0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
|
||||
0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
|
||||
0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
|
||||
0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
|
||||
0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
|
||||
0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
|
||||
0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
|
||||
0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
|
||||
};
|
||||
return t[crc ^ data];
|
||||
}
|
||||
|
||||
static u8 bcma_sprom_crc(const u16 *sprom)
|
||||
{
|
||||
int word;
|
||||
u8 crc = 0xFF;
|
||||
|
||||
for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
|
||||
crc = bcma_crc8(crc, sprom[word] & 0x00FF);
|
||||
crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
|
||||
}
|
||||
crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
|
||||
crc ^= 0xFF;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static int bcma_sprom_check_crc(const u16 *sprom)
|
||||
{
|
||||
u8 crc;
|
||||
u8 expected_crc;
|
||||
u16 tmp;
|
||||
|
||||
crc = bcma_sprom_crc(sprom);
|
||||
tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
|
||||
expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
|
||||
if (crc != expected_crc)
|
||||
return -EPROTO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcma_sprom_valid(const u16 *sprom)
|
||||
{
|
||||
u16 revision;
|
||||
int err;
|
||||
|
||||
err = bcma_sprom_check_crc(sprom);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
|
||||
if (revision != 8) {
|
||||
pr_err("Unsupported SPROM revision: %d\n", revision);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* SPROM extraction.
|
||||
**************************************************/
|
||||
|
||||
static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
|
||||
{
|
||||
u16 v;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
|
||||
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
|
||||
}
|
||||
}
|
||||
|
||||
int bcma_sprom_get(struct bcma_bus *bus)
|
||||
{
|
||||
u16 *sprom;
|
||||
int err = 0;
|
||||
|
||||
if (!bus->drv_cc.core)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
|
||||
return -ENOENT;
|
||||
|
||||
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
|
||||
GFP_KERNEL);
|
||||
if (!sprom)
|
||||
return -ENOMEM;
|
||||
|
||||
bcma_sprom_read(bus, sprom);
|
||||
|
||||
err = bcma_sprom_valid(sprom);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
bcma_sprom_extract_r8(bus, sprom);
|
||||
|
||||
out:
|
||||
kfree(sprom);
|
||||
return err;
|
||||
}
|
|
@ -375,6 +375,11 @@ static int ath3k_probe(struct usb_interface *intf,
|
|||
|
||||
/* load patch and sysconfig files for AR3012 */
|
||||
if (id->driver_info & BTUSB_ATH3012) {
|
||||
|
||||
/* New firmware with patch and sysconfig files already loaded */
|
||||
if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
|
||||
return -ENODEV;
|
||||
|
||||
ret = ath3k_load_patch(udev);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Loading patch file failed");
|
||||
|
|
|
@ -54,6 +54,7 @@ static struct usb_driver btusb_driver;
|
|||
#define BTUSB_BCM92035 0x10
|
||||
#define BTUSB_BROKEN_ISOC 0x20
|
||||
#define BTUSB_WRONG_SCO_MTU 0x40
|
||||
#define BTUSB_ATH3012 0x80
|
||||
|
||||
static struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
|
@ -110,7 +111,7 @@ static struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros 3012 with sflash firmware */
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||||
|
@ -914,6 +915,15 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
|
||||
return -ENODEV;
|
||||
|
||||
if (id->driver_info & BTUSB_ATH3012) {
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
/* Old firmware would otherwise let ath3k driver load
|
||||
* patch and sysconfig files */
|
||||
if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -1523,6 +1523,21 @@ __u32 secure_ip_id(__be32 daddr)
|
|||
return half_md4_transform(hash, keyptr->secret);
|
||||
}
|
||||
|
||||
__u32 secure_ipv6_id(const __be32 daddr[4])
|
||||
{
|
||||
const struct keydata *keyptr;
|
||||
__u32 hash[4];
|
||||
|
||||
keyptr = get_keyptr();
|
||||
|
||||
hash[0] = (__force __u32)daddr[0];
|
||||
hash[1] = (__force __u32)daddr[1];
|
||||
hash[2] = (__force __u32)daddr[2];
|
||||
hash[3] = (__force __u32)daddr[3];
|
||||
|
||||
return half_md4_transform(hash, keyptr->secret);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
|
||||
__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/fs.h> /* everything... */
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
* See Documentation/dmaengine.txt for more details
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kthread.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
|
|
@ -261,16 +261,16 @@ static int fwnet_header_rebuild(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int fwnet_header_cache(const struct neighbour *neigh,
|
||||
struct hh_cache *hh)
|
||||
struct hh_cache *hh, __be16 type)
|
||||
{
|
||||
struct net_device *net;
|
||||
struct fwnet_header *h;
|
||||
|
||||
if (hh->hh_type == cpu_to_be16(ETH_P_802_3))
|
||||
if (type == cpu_to_be16(ETH_P_802_3))
|
||||
return -1;
|
||||
net = neigh->dev;
|
||||
h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
|
||||
h->h_proto = hh->hh_type;
|
||||
h->h_proto = type;
|
||||
memcpy(h->h_dest, neigh->ha, net->addr_len);
|
||||
hh->hh_len = FWNET_HLEN;
|
||||
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
|
||||
|
||||
ccflags-y := -DDEBUG -DCONFIG_FFD
|
||||
|
|
|
@ -370,8 +370,6 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy->dev.platform_data = dev;
|
||||
|
||||
memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
|
||||
dev->addr_len);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
|
|
@ -215,7 +215,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,
|
|||
|
||||
neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
|
||||
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
|
||||
neigh_event_send(rt->dst.neighbour, NULL);
|
||||
neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
|
||||
ret = -ENODATA;
|
||||
if (neigh)
|
||||
goto release;
|
||||
|
@ -273,9 +273,10 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
|
|||
goto put;
|
||||
}
|
||||
|
||||
neigh = dst->neighbour;
|
||||
neigh = dst_get_neighbour(dst);
|
||||
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
|
||||
neigh_event_send(dst->neighbour, NULL);
|
||||
if (neigh)
|
||||
neigh_event_send(neigh, NULL);
|
||||
ret = -ENODATA;
|
||||
goto put;
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
return -EINVAL;
|
||||
return netlink_dump_start(nls, skb, nlh,
|
||||
client->cb_table[op].dump,
|
||||
NULL);
|
||||
NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/mii.h>
|
||||
|
|
|
@ -1328,6 +1328,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
|
|||
struct iwch_ep *child_ep, *parent_ep = ctx;
|
||||
struct cpl_pass_accept_req *req = cplhdr(skb);
|
||||
unsigned int hwtid = GET_TID(req);
|
||||
struct neighbour *neigh;
|
||||
struct dst_entry *dst;
|
||||
struct l2t_entry *l2t;
|
||||
struct rtable *rt;
|
||||
|
@ -1364,7 +1365,8 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
|
|||
goto reject;
|
||||
}
|
||||
dst = &rt->dst;
|
||||
l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
|
||||
neigh = dst_get_neighbour(dst);
|
||||
l2t = t3_l2t_get(tdev, neigh, neigh->dev);
|
||||
if (!l2t) {
|
||||
printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
|
||||
__func__);
|
||||
|
@ -1874,10 +1876,11 @@ static int is_loopback_dst(struct iw_cm_id *cm_id)
|
|||
|
||||
int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
||||
{
|
||||
int err = 0;
|
||||
struct iwch_dev *h = to_iwch_dev(cm_id->device);
|
||||
struct neighbour *neigh;
|
||||
struct iwch_ep *ep;
|
||||
struct rtable *rt;
|
||||
int err = 0;
|
||||
|
||||
if (is_loopback_dst(cm_id)) {
|
||||
err = -ENOSYS;
|
||||
|
@ -1933,9 +1936,10 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|||
}
|
||||
ep->dst = &rt->dst;
|
||||
|
||||
neigh = dst_get_neighbour(ep->dst);
|
||||
|
||||
/* get a l2t entry */
|
||||
ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
|
||||
ep->dst->neighbour->dev);
|
||||
ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev);
|
||||
if (!ep->l2t) {
|
||||
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
|
||||
err = -ENOMEM;
|
||||
|
|
|
@ -1325,6 +1325,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
|
|||
unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid));
|
||||
struct tid_info *t = dev->rdev.lldi.tids;
|
||||
unsigned int hwtid = GET_TID(req);
|
||||
struct neighbour *neigh;
|
||||
struct dst_entry *dst;
|
||||
struct l2t_entry *l2t;
|
||||
struct rtable *rt;
|
||||
|
@ -1357,11 +1358,11 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
|
|||
goto reject;
|
||||
}
|
||||
dst = &rt->dst;
|
||||
if (dst->neighbour->dev->flags & IFF_LOOPBACK) {
|
||||
neigh = dst_get_neighbour(dst);
|
||||
if (neigh->dev->flags & IFF_LOOPBACK) {
|
||||
pdev = ip_dev_find(&init_net, peer_ip);
|
||||
BUG_ON(!pdev);
|
||||
l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
|
||||
pdev, 0);
|
||||
l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, pdev, 0);
|
||||
mtu = pdev->mtu;
|
||||
tx_chan = cxgb4_port_chan(pdev);
|
||||
smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
|
||||
|
@ -1372,17 +1373,16 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
|
|||
rss_qid = dev->rdev.lldi.rxq_ids[cxgb4_port_idx(pdev) * step];
|
||||
dev_put(pdev);
|
||||
} else {
|
||||
l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
|
||||
dst->neighbour->dev, 0);
|
||||
l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, neigh->dev, 0);
|
||||
mtu = dst_mtu(dst);
|
||||
tx_chan = cxgb4_port_chan(dst->neighbour->dev);
|
||||
smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1;
|
||||
tx_chan = cxgb4_port_chan(neigh->dev);
|
||||
smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
|
||||
step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan;
|
||||
txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step;
|
||||
ctrlq_idx = cxgb4_port_idx(dst->neighbour->dev);
|
||||
txq_idx = cxgb4_port_idx(neigh->dev) * step;
|
||||
ctrlq_idx = cxgb4_port_idx(neigh->dev);
|
||||
step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
|
||||
rss_qid = dev->rdev.lldi.rxq_ids[
|
||||
cxgb4_port_idx(dst->neighbour->dev) * step];
|
||||
cxgb4_port_idx(neigh->dev) * step];
|
||||
}
|
||||
if (!l2t) {
|
||||
printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
|
||||
|
@ -1847,6 +1847,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|||
struct c4iw_ep *ep;
|
||||
struct rtable *rt;
|
||||
struct net_device *pdev;
|
||||
struct neighbour *neigh;
|
||||
int step;
|
||||
|
||||
if ((conn_param->ord > c4iw_max_read_depth) ||
|
||||
|
@ -1908,14 +1909,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|||
}
|
||||
ep->dst = &rt->dst;
|
||||
|
||||
neigh = dst_get_neighbour(ep->dst);
|
||||
|
||||
/* get a l2t entry */
|
||||
if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) {
|
||||
if (neigh->dev->flags & IFF_LOOPBACK) {
|
||||
PDBG("%s LOOPBACK\n", __func__);
|
||||
pdev = ip_dev_find(&init_net,
|
||||
cm_id->remote_addr.sin_addr.s_addr);
|
||||
ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
|
||||
ep->dst->neighbour,
|
||||
pdev, 0);
|
||||
neigh, pdev, 0);
|
||||
ep->mtu = pdev->mtu;
|
||||
ep->tx_chan = cxgb4_port_chan(pdev);
|
||||
ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
|
||||
|
@ -1930,20 +1932,18 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
|
|||
dev_put(pdev);
|
||||
} else {
|
||||
ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
|
||||
ep->dst->neighbour,
|
||||
ep->dst->neighbour->dev, 0);
|
||||
neigh, neigh->dev, 0);
|
||||
ep->mtu = dst_mtu(ep->dst);
|
||||
ep->tx_chan = cxgb4_port_chan(ep->dst->neighbour->dev);
|
||||
ep->smac_idx = (cxgb4_port_viid(ep->dst->neighbour->dev) &
|
||||
0x7F) << 1;
|
||||
ep->tx_chan = cxgb4_port_chan(neigh->dev);
|
||||
ep->smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
|
||||
step = ep->com.dev->rdev.lldi.ntxq /
|
||||
ep->com.dev->rdev.lldi.nchan;
|
||||
ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step;
|
||||
ep->ctrlq_idx = cxgb4_port_idx(ep->dst->neighbour->dev);
|
||||
ep->txq_idx = cxgb4_port_idx(neigh->dev) * step;
|
||||
ep->ctrlq_idx = cxgb4_port_idx(neigh->dev);
|
||||
step = ep->com.dev->rdev.lldi.nrxq /
|
||||
ep->com.dev->rdev.lldi.nchan;
|
||||
ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
|
||||
cxgb4_port_idx(ep->dst->neighbour->dev) * step];
|
||||
cxgb4_port_idx(neigh->dev) * step];
|
||||
}
|
||||
if (!ep->l2t) {
|
||||
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
|
||||
|
|
|
@ -1151,7 +1151,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
|
|||
}
|
||||
|
||||
if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
|
||||
neigh_event_send(rt->dst.neighbour, NULL);
|
||||
neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
|
||||
|
||||
ip_rt_put(rt);
|
||||
return rc;
|
||||
|
|
|
@ -2917,24 +2917,19 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
|
|||
goto skip_rx_indicate0;
|
||||
|
||||
|
||||
if ((cqe_misc & NES_NIC_CQE_TAG_VALID) &&
|
||||
(nesvnic->vlan_grp != NULL)) {
|
||||
if (cqe_misc & NES_NIC_CQE_TAG_VALID) {
|
||||
vlan_tag = (u16)(le32_to_cpu(
|
||||
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
|
||||
>> 16);
|
||||
nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
|
||||
nesvnic->netdev->name, vlan_tag);
|
||||
if (nes_use_lro)
|
||||
lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
|
||||
nesvnic->vlan_grp, vlan_tag, NULL);
|
||||
else
|
||||
nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
|
||||
} else {
|
||||
if (nes_use_lro)
|
||||
lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
|
||||
else
|
||||
nes_netif_rx(rx_skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(rx_skb, vlan_tag);
|
||||
}
|
||||
if (nes_use_lro)
|
||||
lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
|
||||
else
|
||||
netif_receive_skb(rx_skb);
|
||||
|
||||
skip_rx_indicate0:
|
||||
;
|
||||
|
|
|
@ -1211,7 +1211,6 @@ struct nes_vnic {
|
|||
/* void *mem; */
|
||||
struct nes_device *nesdev;
|
||||
struct net_device *netdev;
|
||||
struct vlan_group *vlan_grp;
|
||||
atomic_t rx_skbs_needed;
|
||||
atomic_t rx_skb_timer_running;
|
||||
int budget;
|
||||
|
@ -1357,7 +1356,4 @@ struct nes_terminate_hdr {
|
|||
#define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50)
|
||||
#define NES_LINK_RECHECK_MAX 60
|
||||
|
||||
#define nes_vlan_rx vlan_hwaccel_receive_skb
|
||||
#define nes_netif_rx netif_receive_skb
|
||||
|
||||
#endif /* __NES_HW_H */
|
||||
|
|
|
@ -1584,23 +1584,19 @@ static const struct ethtool_ops nes_ethtool_ops = {
|
|||
.set_pauseparam = nes_netdev_set_pauseparam,
|
||||
};
|
||||
|
||||
|
||||
static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
|
||||
static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, u32 features)
|
||||
{
|
||||
struct nes_vnic *nesvnic = netdev_priv(netdev);
|
||||
struct nes_device *nesdev = nesvnic->nesdev;
|
||||
struct nes_adapter *nesadapter = nesdev->nesadapter;
|
||||
u32 u32temp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&nesadapter->phy_lock, flags);
|
||||
nesvnic->vlan_grp = grp;
|
||||
|
||||
nes_debug(NES_DBG_NETDEV, "%s: %s\n", __func__, netdev->name);
|
||||
|
||||
/* Enable/Disable VLAN Stripping */
|
||||
u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
|
||||
if (grp)
|
||||
if (features & NETIF_F_HW_VLAN_RX)
|
||||
u32temp &= 0xfdffffff;
|
||||
else
|
||||
u32temp |= 0x02000000;
|
||||
|
@ -1609,17 +1605,44 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g
|
|||
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
|
||||
}
|
||||
|
||||
static u32 nes_fix_features(struct net_device *netdev, u32 features)
|
||||
{
|
||||
/*
|
||||
* Since there is no support for separate rx/tx vlan accel
|
||||
* enable/disable make sure tx flag is always in same state as rx.
|
||||
*/
|
||||
if (features & NETIF_F_HW_VLAN_RX)
|
||||
features |= NETIF_F_HW_VLAN_TX;
|
||||
else
|
||||
features &= ~NETIF_F_HW_VLAN_TX;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static int nes_set_features(struct net_device *netdev, u32 features)
|
||||
{
|
||||
struct nes_vnic *nesvnic = netdev_priv(netdev);
|
||||
struct nes_device *nesdev = nesvnic->nesdev;
|
||||
u32 changed = netdev->features ^ features;
|
||||
|
||||
if (changed & NETIF_F_HW_VLAN_RX)
|
||||
nes_vlan_mode(netdev, nesdev, features);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct net_device_ops nes_netdev_ops = {
|
||||
.ndo_open = nes_netdev_open,
|
||||
.ndo_open = nes_netdev_open,
|
||||
.ndo_stop = nes_netdev_stop,
|
||||
.ndo_start_xmit = nes_netdev_start_xmit,
|
||||
.ndo_start_xmit = nes_netdev_start_xmit,
|
||||
.ndo_get_stats = nes_netdev_get_stats,
|
||||
.ndo_tx_timeout = nes_netdev_tx_timeout,
|
||||
.ndo_tx_timeout = nes_netdev_tx_timeout,
|
||||
.ndo_set_mac_address = nes_netdev_set_mac_address,
|
||||
.ndo_set_multicast_list = nes_netdev_set_multicast_list,
|
||||
.ndo_change_mtu = nes_netdev_change_mtu,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_vlan_rx_register = nes_netdev_vlan_rx_register,
|
||||
.ndo_fix_features = nes_fix_features,
|
||||
.ndo_set_features = nes_set_features,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1656,7 +1679,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
|
|||
netdev->ethtool_ops = &nes_ethtool_ops;
|
||||
netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
|
||||
nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
|
||||
netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
netdev->features |= NETIF_F_HW_VLAN_TX;
|
||||
|
||||
/* Fill in the port structure */
|
||||
nesvnic->netdev = netdev;
|
||||
|
@ -1683,7 +1706,8 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
|
|||
netdev->dev_addr[5] = (u8)u64temp;
|
||||
memcpy(netdev->perm_addr, netdev->dev_addr, 6);
|
||||
|
||||
netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM;
|
||||
netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM |
|
||||
NETIF_F_HW_VLAN_RX;
|
||||
if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
|
||||
netdev->hw_features |= NETIF_F_TSO;
|
||||
netdev->features |= netdev->hw_features;
|
||||
|
@ -1815,6 +1839,8 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
|
|||
nes_init_phy(nesdev);
|
||||
}
|
||||
|
||||
nes_vlan_mode(netdev, nesdev, netdev->features);
|
||||
|
||||
return netdev;
|
||||
}
|
||||
|
||||
|
|
|
@ -560,9 +560,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
|
|||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
struct ipoib_path *path;
|
||||
struct ipoib_neigh *neigh;
|
||||
struct neighbour *n;
|
||||
unsigned long flags;
|
||||
|
||||
neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev);
|
||||
n = dst_get_neighbour(skb_dst(skb));
|
||||
neigh = ipoib_neigh_alloc(n, skb->dev);
|
||||
if (!neigh) {
|
||||
++dev->stats.tx_dropped;
|
||||
dev_kfree_skb_any(skb);
|
||||
|
@ -571,9 +573,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4);
|
||||
path = __path_find(dev, n->ha + 4);
|
||||
if (!path) {
|
||||
path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4);
|
||||
path = path_rec_create(dev, n->ha + 4);
|
||||
if (!path)
|
||||
goto err_path;
|
||||
|
||||
|
@ -607,7 +609,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
} else {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
|
||||
ipoib_send(dev, skb, path->ah, IPOIB_QPN(n->ha));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -637,17 +639,20 @@ err_drop:
|
|||
static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct neighbour *n;
|
||||
|
||||
/* Look up path record for unicasts */
|
||||
if (skb_dst(skb)->neighbour->ha[4] != 0xff) {
|
||||
n = dst_get_neighbour(dst);
|
||||
if (n->ha[4] != 0xff) {
|
||||
neigh_add_path(skb, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add in the P_Key for multicasts */
|
||||
skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
|
||||
skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff;
|
||||
ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb);
|
||||
n->ha[8] = (priv->pkey >> 8) & 0xff;
|
||||
n->ha[9] = priv->pkey & 0xff;
|
||||
ipoib_mcast_send(dev, n->ha + 4, skb);
|
||||
}
|
||||
|
||||
static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
|
||||
|
@ -712,18 +717,20 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
struct ipoib_neigh *neigh;
|
||||
struct neighbour *n;
|
||||
unsigned long flags;
|
||||
|
||||
if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) {
|
||||
if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) {
|
||||
n = dst_get_neighbour(skb_dst(skb));
|
||||
if (likely(skb_dst(skb) && n)) {
|
||||
if (unlikely(!*to_ipoib_neigh(n))) {
|
||||
ipoib_path_lookup(skb, dev);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour);
|
||||
neigh = *to_ipoib_neigh(n);
|
||||
|
||||
if (unlikely((memcmp(&neigh->dgid.raw,
|
||||
skb_dst(skb)->neighbour->ha + 4,
|
||||
n->ha + 4,
|
||||
sizeof(union ib_gid))) ||
|
||||
(neigh->dev != dev))) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
@ -749,7 +756,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
} else if (neigh->ah) {
|
||||
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
|
||||
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
@ -812,6 +819,8 @@ static int ipoib_hard_header(struct sk_buff *skb,
|
|||
const void *daddr, const void *saddr, unsigned len)
|
||||
{
|
||||
struct ipoib_header *header;
|
||||
struct dst_entry *dst;
|
||||
struct neighbour *n;
|
||||
|
||||
header = (struct ipoib_header *) skb_push(skb, sizeof *header);
|
||||
|
||||
|
@ -823,7 +832,11 @@ static int ipoib_hard_header(struct sk_buff *skb,
|
|||
* destination address onto the front of the skb so we can
|
||||
* figure out where to send the packet later.
|
||||
*/
|
||||
if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) {
|
||||
dst = skb_dst(skb);
|
||||
n = NULL;
|
||||
if (dst)
|
||||
n = dst_get_neighbour(dst);
|
||||
if ((!dst || !n) && daddr) {
|
||||
struct ipoib_pseudoheader *phdr =
|
||||
(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
|
||||
memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
|
||||
|
|
|
@ -258,11 +258,15 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
|
|||
netif_tx_lock_bh(dev);
|
||||
while (!skb_queue_empty(&mcast->pkt_queue)) {
|
||||
struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct neighbour *n = NULL;
|
||||
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
skb->dev = dev;
|
||||
|
||||
if (!skb_dst(skb) || !skb_dst(skb)->neighbour) {
|
||||
if (dst)
|
||||
n = dst_get_neighbour(dst);
|
||||
if (!dst || !n) {
|
||||
/* put pseudoheader back on for next time */
|
||||
skb_push(skb, sizeof (struct ipoib_pseudoheader));
|
||||
}
|
||||
|
@ -715,11 +719,13 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
|
|||
|
||||
out:
|
||||
if (mcast && mcast->ah) {
|
||||
if (skb_dst(skb) &&
|
||||
skb_dst(skb)->neighbour &&
|
||||
!*to_ipoib_neigh(skb_dst(skb)->neighbour)) {
|
||||
struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour,
|
||||
skb->dev);
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct neighbour *n = NULL;
|
||||
if (dst)
|
||||
n = dst_get_neighbour(dst);
|
||||
if (n && !*to_ipoib_neigh(n)) {
|
||||
struct ipoib_neigh *neigh = ipoib_neigh_alloc(n,
|
||||
skb->dev);
|
||||
|
||||
if (neigh) {
|
||||
kref_get(&mcast->ah->ref);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <scsi/libiscsi.h>
|
||||
#include <scsi/scsi_transport_iscsi.h>
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/list.h>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
|
||||
#define HFC_MULTI_VERSION "2.03"
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNhw.h>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/isapnp.h>
|
||||
#include <linux/kmod.h>
|
||||
|
|
|
@ -1983,13 +1983,14 @@ isdn_net_rebuild_header(struct sk_buff *skb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
|
||||
static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
|
||||
__be16 type)
|
||||
{
|
||||
const struct net_device *dev = neigh->dev;
|
||||
isdn_net_local *lp = netdev_priv(dev);
|
||||
|
||||
if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
|
||||
return eth_header_cache(neigh, hh);
|
||||
return eth_header_cache(neigh, hh, type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef __FLEXCOP_COMMON_H__
|
||||
#define __FLEXCOP_COMMON_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef __MANTIS_COMMON_H
|
||||
#define __MANTIS_COMMON_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/sched.h>
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue