Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking updates from David Miller:

Changes of note:

 1) Allow to schedule ICMP packets in IPVS, from Alex Gartrell.

 2) Provide FIB table ID in ipv4 route dumps just as ipv6 does, from
    David Ahern.

 3) Allow the user to ask for the statistics to be filtered out of
    ipv4/ipv6 address netlink dumps.  From Sowmini Varadhan.

 4) More work to pass the network namespace context around deep into
    various packet path APIs, starting with the netfilter hooks.  From
    Eric W Biederman.

 5) Add layer 2 TX/RX checksum offloading to qeth driver, from Thomas
    Richter.

 6) Use usec resolution for SYN/ACK RTTs in TCP, from Yuchung Cheng.

 7) Support Very High Throughput in wireless MESH code, from Bob
    Copeland.

 8) Allow setting the ageing_time in switchdev/rocker.  From Scott
    Feldman.

 9) Properly autoload L2TP type modules, from Stephen Hemminger.

10) Fix and enable offload features by default in 8139cp driver, from
    David Woodhouse.

11) Support both ipv4 and ipv6 sockets in a single vxlan device, from
    Jiri Benc.

12) Fix CWND limiting of thin streams in TCP, from Bendik Rønning
    Opstad.

13) Fix IPSEC flowcache overflows on large systems, from Steffen
    Klassert.

14) Convert bridging to track VLANs using rhashtable entries rather than
    a bitmap.  From Nikolay Aleksandrov.

15) Make TCP listener handling completely lockless, this is a major
    accomplishment.  Incoming request sockets now live in the
    established hash table just like any other socket too.

    From Eric Dumazet.

15) Provide more bridging attributes to netlink, from Nikolay
    Aleksandrov.

16) Use hash based algorithm for ipv4 multipath routing, this was very
    long overdue.  From Peter Nørlund.

17) Several y2038 cures, mostly avoiding timespec.  From Arnd Bergmann.

18) Allow non-root execution of EBPF programs, from Alexei Starovoitov.

19) Support SO_INCOMING_CPU as setsockopt, from Eric Dumazet.  This
    influences the port binding selection logic used by SO_REUSEPORT.

20) Add ipv6 support to VRF, from David Ahern.

21) Add support for Mellanox Spectrum switch ASIC, from Jiri Pirko.

22) Add rtl8xxxu Realtek wireless driver, from Jes Sorensen.

23) Implement RACK loss recovery in TCP, from Yuchung Cheng.

24) Support multipath routes in MPLS, from Roopa Prabhu.

25) Fix POLLOUT notification for listening sockets in AF_UNIX, from Eric
    Dumazet.

26) Add new QED Qlogic river, from Yuval Mintz, Manish Chopra, and
    Sudarsana Kalluru.

27) Don't fetch timestamps on AF_UNIX sockets, from Hannes Frederic
    Sowa.

28) Support ipv6 geneve tunnels, from John W Linville.

29) Add flood control support to switchdev layer, from Ido Schimmel.

30) Fix CHECKSUM_PARTIAL handling of potentially fragmented frames, from
    Hannes Frederic Sowa.

31) Support persistent maps and progs in bpf, from Daniel Borkmann.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1790 commits)
  sh_eth: use DMA barriers
  switchdev: respect SKIP_EOPNOTSUPP flag in case there is no recursion
  net: sched: kill dead code in sch_choke.c
  irda: Delete an unnecessary check before the function call "irlmp_unregister_service"
  net: dsa: mv88e6xxx: include DSA ports in VLANs
  net: dsa: mv88e6xxx: disable SA learning for DSA and CPU ports
  net/core: fix for_each_netdev_feature
  vlan: Invoke driver vlan hooks only if device is present
  arcnet/com20020: add LEDS_CLASS dependency
  bpf, verifier: annotate verbose printer with __printf
  dp83640: Only wait for timestamps for packets with timestamping enabled.
  ptp: Change ptp_class to a proper bitmask
  dp83640: Prune rx timestamp list before reading from it
  dp83640: Delay scheduled work.
  dp83640: Include hash in timestamp/packet matching
  ipv6: fix tunnel error handling
  net/mlx5e: Fix LSO vlan insertion
  net/mlx5e: Re-eanble client vlan TX acceleration
  net/mlx5e: Return error in case mlx5e_set_features() fails
  net/mlx5e: Don't allow more than max supported channels
  ...
This commit is contained in:
Linus Torvalds 2015-11-04 09:41:05 -08:00
commit b0f85fa11a
1595 changed files with 115088 additions and 24172 deletions

View file

@ -154,8 +154,9 @@
!Finclude/net/cfg80211.h cfg80211_scan_request
!Finclude/net/cfg80211.h cfg80211_scan_done
!Finclude/net/cfg80211.h cfg80211_bss
!Finclude/net/cfg80211.h cfg80211_inform_bss_width_frame
!Finclude/net/cfg80211.h cfg80211_inform_bss_width
!Finclude/net/cfg80211.h cfg80211_inform_bss
!Finclude/net/cfg80211.h cfg80211_inform_bss_frame_data
!Finclude/net/cfg80211.h cfg80211_inform_bss_data
!Finclude/net/cfg80211.h cfg80211_unlink_bss
!Finclude/net/cfg80211.h cfg80211_find_ie
!Finclude/net/cfg80211.h ieee80211_bss_get_ie

View file

@ -37,6 +37,14 @@ Required properties for ethernet interfaces that have external PHY:
Optional properties:
- status: Should be "ok" or "disabled" for enabled/disabled. Default is "ok".
- tx-delay: Delay value for RGMII bridge TX clock.
Valid values are between 0 to 7, that maps to
417, 717, 1020, 1321, 1611, 1913, 2215, 2514 ps
Default value is 4, which corresponds to 1611 ps
- rx-delay: Delay value for RGMII bridge RX clock.
Valid values are between 0 to 7, that maps to
273, 589, 899, 1222, 1480, 1806, 2147, 2464 ps
Default value is 2, which corresponds to 899 ps
Example:
menetclk: menetclk {
@ -72,5 +80,7 @@ Example:
/* Board-specific peripheral configurations */
&menet {
tx-delay = <4>;
rx-delay = <2>;
status = "ok";
};

View file

@ -0,0 +1,23 @@
* Broadcom iProc MDIO bus controller
Required properties:
- compatible: should be "brcm,iproc-mdio"
- reg: address and length of the register set for the MDIO interface
- #size-cells: must be 1
- #address-cells: must be 0
Child nodes of this MDIO bus controller node are standard Ethernet PHY device
nodes as described in Documentation/devicetree/bindings/net/phy.txt
Example:
mdio@18002000 {
compatible = "brcm,iproc-mdio";
reg = <0x18002000 0x8>;
#size-cells = <1>;
#address-cells = <0>;
enet-gphy@0 {
reg = <0>;
};
};

View file

@ -0,0 +1,36 @@
Allwinner A10/A20 CAN controller Device Tree Bindings
-----------------------------------------------------
Required properties:
- compatible: "allwinner,sun4i-a10-can"
- reg: physical base address and size of the Allwinner A10/A20 CAN register map.
- interrupts: interrupt specifier for the sole interrupt.
- clock: phandle and clock specifier.
Example
-------
SoC common .dtsi file:
can0_pins_a: can0@0 {
allwinner,pins = "PH20","PH21";
allwinner,function = "can";
allwinner,drive = <0>;
allwinner,pull = <0>;
};
...
can0: can@01c2bc00 {
compatible = "allwinner,sun4i-a10-can";
reg = <0x01c2bc00 0x400>;
interrupts = <0 26 4>;
clocks = <&apb1_gates 4>;
status = "disabled";
};
Board specific .dts file:
can0: can@01c2bc00 {
pinctrl-names = "default";
pinctrl-0 = <&can0_pins_a>;
status = "okay";
};

View file

@ -30,6 +30,13 @@ Optional properties:
- dual_emac : Specifies Switch to act as Dual EMAC
- syscon : Phandle to the system control device node, which is
the control module device of the am33x
- mode-gpios : Should be added if one/multiple gpio lines are
required to be driven so that cpsw data lines
can be connected to the phy via selective mux.
For example in dra72x-evm, pcf gpio has to be
driven low so that cpsw slave 0 and phy data
lines are connected via mux.
Slave Properties:
Required properties:

View file

@ -57,6 +57,10 @@ Properties:
"rgmii-id", as all other connection types are detected by hardware.
- fsl,magic-packet : If present, indicates that the hardware supports
waking up via magic packet.
- fsl,wake-on-filer : If present, indicates that the hardware supports
waking up by Filer General Purpose Interrupt (FGPI) asserted on the
Rx int line. This is an advanced power management capability allowing
certain packet types (user) defined by filer rules to wake up the system.
- bd-stash : If present, indicates that the hardware supports stashing
buffer descriptors in the L2.
- rx-stash-len : Denotes the number of bytes of a received buffer to stash

View file

@ -32,13 +32,13 @@ Required properties:
Required properties:
- compatible: should be "hisilicon,hip04-mdio".
- compatible: should be "hisilicon,mdio".
- Inherits from MDIO bus node binding [2]
[2] Documentation/devicetree/bindings/net/phy.txt
Example:
mdio {
compatible = "hisilicon,hip04-mdio";
compatible = "hisilicon,mdio";
reg = <0x28f1000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;

View file

@ -0,0 +1,49 @@
Hisilicon DSA Fabric device controller
Required properties:
- compatible: should be "hisilicon,hns-dsaf-v1" or "hisilicon,hns-dsaf-v2".
"hisilicon,hns-dsaf-v1" is for hip05.
"hisilicon,hns-dsaf-v2" is for Hi1610 and Hi1612.
- dsa-name: dsa fabric name who provide this interface.
should be "dsafX", X is the dsaf id.
- mode: dsa fabric mode string. only support one of dsaf modes like these:
"2port-64vf",
"6port-16rss",
"6port-16vf".
- interrupt-parent: the interrupt parent of this device.
- interrupts: should contain the DSA Fabric and rcb interrupt.
- reg: specifies base physical address(es) and size of the device registers.
The first region is external interface control register base and size.
The second region is SerDes base register and size.
The third region is the PPE register base and size.
The fourth region is dsa fabric base register and size.
The fifth region is cpld base register and size, it is not required if do not use cpld.
- phy-handle: phy handle of physicl port, 0 if not any phy device. see ethernet.txt [1].
- buf-size: rx buffer size, should be 16-1024.
- desc-num: number of description in TX and RX queue, should be 512, 1024, 2048 or 4096.
[1] Documentation/devicetree/bindings/net/phy.txt
Example:
dsa: dsa@c7000000 {
compatible = "hisilicon,hns-dsaf-v1";
dsa_name = "dsaf0";
mode = "6port-16rss";
interrupt-parent = <&mbigen_dsa>;
reg = <0x0 0xC0000000 0x0 0x420000
0x0 0xC2000000 0x0 0x300000
0x0 0xc5000000 0x0 0x890000
0x0 0xc7000000 0x0 0x60000>;
phy-handle = <0 0 0 0 &soc0_phy4 &soc0_phy5 0 0>;
interrupts = <131 4>,<132 4>, <133 4>,<134 4>,
<135 4>,<136 4>, <137 4>,<138 4>,
<139 4>,<140 4>, <141 4>,<142 4>,
<143 4>,<144 4>, <145 4>,<146 4>,
<147 4>,<148 4>, <384 1>,<385 1>,
<386 1>,<387 1>, <388 1>,<389 1>,
<390 1>,<391 1>,
buf-size = <4096>;
desc-num = <1024>;
dma-coherent;
};

View file

@ -0,0 +1,22 @@
Hisilicon MDIO bus controller
Properties:
- compatible: "hisilicon,mdio","hisilicon,hns-mdio".
- reg: The base address of the MDIO bus controller register bank.
- #address-cells: Must be <1>.
- #size-cells: Must be <0>. MDIO addresses have no size component.
Typically an MDIO bus might have several children.
Example:
mdio@803c0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "hisilicon,hns-mdio","hisilicon,mdio";
reg = <0x0 0x803c0000 0x0 0x10000>;
ethernet-phy@0 {
...
reg = <0>;
};
};

View file

@ -0,0 +1,47 @@
Hisilicon Network Subsystem NIC controller
Required properties:
- compatible: "hisilicon,hns-nic-v1" or "hisilicon,hns-nic-v2".
"hisilicon,hns-nic-v1" is for hip05.
"hisilicon,hns-nic-v2" is for Hi1610 and Hi1612.
- ae-name: accelerator name who provides this interface,
is simply a name referring to the name of name in the accelerator node.
- port-id: is the index of port provided by DSAF (the accelerator). DSAF can
connect to 8 PHYs. Port 0 to 1 are both used for adminstration purpose. They
are called debug ports.
The remaining 6 PHYs are taken according to the mode of DSAF.
In NIC mode of DSAF, all 6 PHYs are taken as ethernet ports to the CPU. The
port-id can be 2 to 7. Here is the diagram:
+-----+---------------+
| CPU |
+-+-+-+---+-+-+-+-+-+-+
| | | | | | | |
debug service
port port
(0,1) (2-7)
In Switch mode of DSAF, all 6 PHYs are taken as physical ports connect to a
LAN Switch while the CPU side assume itself have one single NIC connect to
this switch. In this case, the port-id will be 2 only.
+-----+---------------+
| CPU |
+-+-+-+---+-+-+-+-+-+-+
| | service| port(2)
debug +------------+
port | switch |
(0,1) +-+-+-+-+-+-++
| | | | | |
external port
- local-mac-address: mac addr of the ethernet interface
Example:
ethernet@0{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <0>;
local-mac-address = [a2 14 e4 4b 56 76];
};

View file

@ -0,0 +1,20 @@
* MRF24J40 IEEE 802.15.4 *
Required properties:
- compatible: should be "microchip,mrf24j40", "microchip,mrf24j40ma",
or "microchip,mrf24j40mc" depends on your transceiver
board
- spi-max-frequency: maximal bus speed, should be set something under or equal
10000000
- reg: the chipselect index
- interrupts: the interrupt generated by the device.
Example:
mrf24j40ma@0 {
compatible = "microchip,mrf24j40ma";
spi-max-frequency = <8500000>;
reg = <0>;
interrupts = <19 8>;
interrupt-parent = <&gpio3>;
};

View file

@ -1,7 +1,10 @@
* Marvell International Ltd. NCI NFC Controller
Required properties:
- compatible: Should be "mrvl,nfc-uart".
- compatible: Should be:
- "marvell,nfc-uart" or "mrvl,nfc-uart" for UART devices
- "marvell,nfc-i2c" for I2C devices
- "marvell,nfc-spi" for SPI devices
Optional SoC specific properties:
- pinctrl-names: Contains only one value - "default".
@ -13,13 +16,19 @@ Optional UART-based chip specific properties:
- flow-control: Specifies that the chip is using RTS/CTS.
- break-control: Specifies that the chip needs specific break management.
Optional I2C-based chip specific properties:
- i2c-int-falling: Specifies that the chip read event shall be trigged on
falling edge.
- i2c-int-rising: Specifies that the chip read event shall be trigged on
rising edge.
Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):
&uart5 {
status = "okay";
nfcmrvluart: nfcmrvluart@5 {
compatible = "mrvl,nfc-uart";
compatible = "marvell,nfc-uart";
reset-n-io = <&gpio3 16 0>;
@ -27,3 +36,51 @@ Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):
flow-control;
}
};
Example (for ARM-based BeagleBoard Black with 88W8887 on I2C1):
&i2c1 {
status = "okay";
clock-frequency = <400000>;
nfcmrvli2c0: i2c@1 {
compatible = "marvell,nfc-i2c";
reg = <0x8>;
/* I2C INT configuration */
interrupt-parent = <&gpio3>;
interrupts = <21 0>;
/* I2C INT trigger configuration */
i2c-int-rising;
/* Reset IO */
reset-n-io = <&gpio3 19 0>;
};
};
Example (for ARM-based BeagleBoard Black on SPI0):
&spi0 {
mrvlnfcspi0: spi@0 {
compatible = "marvell,nfc-spi";
reg = <0>;
/* SPI Bus configuration */
spi-max-frequency = <3000000>;
spi-cpha;
spi-cpol;
/* SPI INT configuration */
interrupt-parent = <&gpio1>;
interrupts = <17 0>;
/* Reset IO */
reset-n-io = <&gpio3 19 0>;
};
};

View file

@ -11,6 +11,10 @@ Required properties:
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
- ese-present: Specifies that an ese is physically connected to the nfc
controller.
- uicc-present: Specifies that the uicc swp signal can be physically
connected to the nfc controller.
Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
};
};

View file

@ -2,7 +2,7 @@
Required properties:
- compatible: Should be "st,st21nfcb-spi"
- spi-max-frequency: Maximum SPI frequency (<= 10000000).
- spi-max-frequency: Maximum SPI frequency (<= 4000000).
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- reset-gpios: Output GPIO pin used to reset the ST21NFCB
@ -10,6 +10,10 @@ Required properties:
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
- ese-present: Specifies that an ese is physically connected to the nfc
controller.
- uicc-present: Specifies that the uicc swp signal can be physically
connected to the nfc controller.
Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
@ -27,5 +31,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
interrupts = <2 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
};
};

View file

@ -6,8 +6,12 @@ interface contains.
Required properties:
- compatible: "renesas,etheravb-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,etheravb-r8a7794" if the device is a part of R8A7794 SoC.
"renesas,etheravb-r8a7795" if the device is a part of R8A7795 SoC.
- reg: offset and length of (1) the register block and (2) the stream buffer.
- interrupts: interrupt specifier for the sole interrupt.
- interrupts: A list of interrupt-specifiers, one for each entry in
interrupt-names.
If interrupt-names is not present, an interrupt specifier
for a single muxed interrupt.
- phy-mode: see ethernet.txt file in the same directory.
- phy-handle: see ethernet.txt file in the same directory.
- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
@ -18,6 +22,12 @@ Required properties:
Optional properties:
- interrupt-parent: the phandle for the interrupt controller that services
interrupts for this device.
- interrupt-names: A list of interrupt names.
For the R8A7795 SoC this property is mandatory;
it should include one entry per channel, named "ch%u",
where %u is the channel number ranging from 0 to 24.
For other SoCs this property is optional; if present
it should contain "mux" for a single muxed interrupt.
- pinctrl-names: pin configuration state name ("default").
- renesas,no-ether-link: boolean, specify when a board does not provide a proper
AVB_LINK signal.
@ -27,13 +37,46 @@ Optional properties:
Example:
ethernet@e6800000 {
compatible = "renesas,etheravb-r8a7790";
reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
compatible = "renesas,etheravb-r8a7795";
reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
interrupt-parent = <&gic>;
interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp8_clks R8A7790_CLK_ETHERAVB>;
phy-mode = "rmii";
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ch0", "ch1", "ch2", "ch3",
"ch4", "ch5", "ch6", "ch7",
"ch8", "ch9", "ch10", "ch11",
"ch12", "ch13", "ch14", "ch15",
"ch16", "ch17", "ch18", "ch19",
"ch20", "ch21", "ch22", "ch23",
"ch24";
clocks = <&mstp8_clks R8A7795_CLK_ETHERAVB>;
power-domains = <&cpg_clocks>;
phy-mode = "rgmii-id";
phy-handle = <&phy0>;
pinctrl-0 = <&ether_pins>;
pinctrl-names = "default";
renesas,no-ether-link;
@ -41,8 +84,20 @@ Example:
#size-cells = <0>;
phy0: ethernet-phy@0 {
rxc-skew-ps = <900>;
rxdv-skew-ps = <0>;
rxd0-skew-ps = <0>;
rxd1-skew-ps = <0>;
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txc-skew-ps = <900>;
txen-skew-ps = <0>;
txd0-skew-ps = <0>;
txd1-skew-ps = <0>;
txd2-skew-ps = <0>;
txd3-skew-ps = <0>;
reg = <0>;
interrupt-parent = <&gpio2>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
};
};

View file

@ -157,6 +157,9 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:
both: use both BOOTP and RARP but not DHCP
(old option kept for backwards compatibility)
if dhcp is used, the client identifier can be used by following
format "ip=dhcp,client-id-type,client-id-value"
Default: any
<dns0-ip> IP address of first nameserver.

View file

@ -7,11 +7,11 @@ Introduction
The IEEE 802.15.4 working group focuses on standardization of bottom
two layers: Medium Access Control (MAC) and Physical (PHY). And there
are mainly two options available for upper layers:
- ZigBee - proprietary protocol from ZigBee Alliance
- 6LowPAN - IPv6 networking over low rate personal area networks
- ZigBee - proprietary protocol from the ZigBee Alliance
- 6LoWPAN - IPv6 networking over low rate personal area networks
The Linux-ZigBee project goal is to provide complete implementation
of IEEE 802.15.4 and 6LoWPAN protocols. IEEE 802.15.4 is a stack
The linux-wpan project goal is to provide a complete implementation
of the IEEE 802.15.4 and 6LoWPAN protocols. IEEE 802.15.4 is a stack
of protocols for organizing Low-Rate Wireless Personal Area Networks.
The stack is composed of three main parts:

View file

@ -384,6 +384,14 @@ tcp_mem - vector of 3 INTEGERs: min, pressure, max
Defaults are calculated at boot time from amount of available
memory.
tcp_min_rtt_wlen - INTEGER
The window length of the windowed min filter to track the minimum RTT.
A shorter window lets a flow more quickly pick up new (higher)
minimum RTT when it is moved to a longer path (e.g., due to traffic
engineering). A longer window makes the filter more resistant to RTT
inflations such as transient congestion. The unit is seconds.
Default: 300
tcp_moderate_rcvbuf - BOOLEAN
If set, TCP performs receive buffer auto-tuning, attempting to
automatically size the buffer (no greater than tcp_rmem[2]) to
@ -425,6 +433,15 @@ tcp_orphan_retries - INTEGER
you should think about lowering this value, such sockets
may consume significant resources. Cf. tcp_max_orphans.
tcp_recovery - INTEGER
This value is a bitmap to enable various experimental loss recovery
features.
RACK: 0x1 enables the RACK loss detection for fast detection of lost
retransmissions and tail drops.
Default: 0x1
tcp_reordering - INTEGER
Initial reordering level of packets in a TCP stream.
TCP stack can then dynamically adjust flow reordering level
@ -1199,7 +1216,8 @@ tag - INTEGER
xfrm4_gc_thresh - INTEGER
The threshold at which we will start garbage collecting for IPv4
destination cache entries. At twice this value the system will
refuse new allocations.
refuse new allocations. The value must be set below the flowcache
limit (4096 * number of online cpus) to take effect.
igmp_link_local_mcast_reports - BOOLEAN
Enable IGMP reports for link local multicast groups in the
@ -1645,7 +1663,8 @@ ratelimit - INTEGER
xfrm6_gc_thresh - INTEGER
The threshold at which we will start garbage collecting for IPv6
destination cache entries. At twice this value the system will
refuse new allocations.
refuse new allocations. The value must be set below the flowcache
limit (4096 * number of online cpus) to take effect.
IPv6 Update by:

View file

@ -157,6 +157,16 @@ expire_quiescent_template - BOOLEAN
persistence template if it is to be used to schedule a new
connection and the destination server is quiescent.
ignore_tunneled - BOOLEAN
0 - disabled (default)
not 0 - enabled
If set, ipvs will set the ipvs_property on all packets which are of
unrecognized protocols. This prevents us from routing tunneled
protocols like ipip, which is useful to prevent rescheduling
packets that have been tunneled to the ipvs host (i.e. to prevent
ipvs routing loops when ipvs is also acting as a real server).
nat_icmp_send - BOOLEAN
0 - disabled (default)
not 0 - enabled

View file

@ -213,15 +213,12 @@ To create an L2TPv3 ethernet pseudowire between local host 192.168.1.1
and peer 192.168.1.2, using IP addresses 10.5.1.1 and 10.5.1.2 for the
tunnel endpoints:-
# modprobe l2tp_eth
# modprobe l2tp_netlink
# ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 udp_sport 5000 \
udp_dport 5000 encap udp local 192.168.1.1 remote 192.168.1.2
# ip l2tp add session tunnel_id 1 session_id 1 peer_session_id 1
# ifconfig -a
# ip -s -d show dev l2tpeth0
# ip addr add 10.5.1.2/32 peer 10.5.1.1/32 dev l2tpeth0
# ifconfig l2tpeth0 up
# ip li set dev l2tpeth0 up
Choose IP addresses to be the address of a local IP interface and that
of the remote system. The IP addresses of the l2tpeth0 interface can be

View file

@ -115,7 +115,7 @@ Switch ID
^^^^^^^^^
The switchdev driver must implement the switchdev op switchdev_port_attr_get
for SWITCHDEV_ATTR_PORT_PARENT_ID for each port netdev, returning the same
for SWITCHDEV_ATTR_ID_PORT_PARENT_ID for each port netdev, returning the same
physical ID for each port of a switch. The ID must be unique between switches
on the same system. The ID does not need to be unique between switches on
different systems.
@ -178,7 +178,7 @@ entries are installed, for example, using iproute2 bridge cmd:
bridge fdb add ADDR dev DEV [vlan VID] [self]
The driver should use the helper switchdev_port_fdb_xxx ops for ndo_fdb_xxx
ops, and handle add/delete/dump of SWITCHDEV_OBJ_PORT_FDB object using
ops, and handle add/delete/dump of SWITCHDEV_OBJ_ID_PORT_FDB object using
switchdev_port_obj_xxx ops.
XXX: what should be done if offloading this rule to hardware fails (for
@ -233,26 +233,27 @@ the bridge's FDB. It's possible, but not optimal, to enable learning on the
device port and on the bridge port, and disable learning_sync.
To support learning and learning_sync port attributes, the driver implements
switchdev op switchdev_port_attr_get/set for SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS.
The driver should initialize the attributes to the hardware defaults.
switchdev op switchdev_port_attr_get/set for
SWITCHDEV_ATTR_PORT_ID_BRIDGE_FLAGS. The driver should initialize the attributes
to the hardware defaults.
FDB Ageing
^^^^^^^^^^
There are two FDB ageing models supported: 1) ageing by the device, and 2)
ageing by the kernel. Ageing by the device is preferred if many FDB entries
are supported. The driver calls call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
...) to age out the FDB entry. In this model, ageing by the kernel should be
turned off. XXX: how to turn off ageing in kernel on a per-port basis or
otherwise prevent the kernel from ageing out the FDB entry?
The bridge will skip ageing FDB entries marked with NTF_EXT_LEARNED and it is
the responsibility of the port driver/device to age out these entries. If the
port device supports ageing, when the FDB entry expires, it will notify the
driver which in turn will notify the bridge with SWITCHDEV_FDB_DEL. If the
device does not support ageing, the driver can simulate ageing using a
garbage collection timer to monitor FBD entries. Expired entries will be
notified to the bridge using SWITCHDEV_FDB_DEL. See rocker driver for
example of driver running ageing timer.
In the kernel ageing model, the standard bridge ageing mechanism is used to age
out stale FDB entries. To keep an FDB entry "alive", the driver should refresh
the FDB entry by calling call_switchdev_notifiers(SWITCHDEV_FDB_ADD, ...). The
To keep an NTF_EXT_LEARNED entry "alive", the driver should refresh the FDB
entry by calling call_switchdev_notifiers(SWITCHDEV_FDB_ADD, ...). The
notification will reset the FDB entry's last-used time to now. The driver
should rate limit refresh notifications, for example, no more than once a
second. If the FDB entry expires, fdb_delete is called to remove entry from
the device.
second. (The last-used time is visible using the bridge -s fdb option).
STP State Change on Port
^^^^^^^^^^^^^^^^^^^^^^^^
@ -260,7 +261,7 @@ STP State Change on Port
Internally or with a third-party STP protocol implementation (e.g. mstpd), the
bridge driver maintains the STP state for ports, and will notify the switch
driver of STP state change on a port using the switchdev op
switchdev_attr_port_set for SWITCHDEV_ATTR_PORT_STP_UPDATE.
switchdev_attr_port_set for SWITCHDEV_ATTR_PORT_ID_STP_UPDATE.
State is one of BR_STATE_*. The switch driver can use STP state updates to
update ingress packet filter list for the port. For example, if port is
@ -277,8 +278,8 @@ Flooding L2 domain
For a given L2 VLAN domain, the switch device should flood multicast/broadcast
and unknown unicast packets to all ports in domain, if allowed by port's
current STP state. The switch driver, knowing which ports are within which
vlan L2 domain, can program the switch device for flooding. The packet should
also be sent to the port netdev for processing by the bridge driver. The
vlan L2 domain, can program the switch device for flooding. The packet may
be sent to the port netdev for processing by the bridge driver. The
bridge should not reflood the packet to the same ports the device flooded,
otherwise there will be duplicate packets on the wire.
@ -297,6 +298,9 @@ packets up to the bridge driver for flooding. This is not ideal as the number
of ports scale in the L2 domain as the device is much more efficient at
flooding packets that software.
If supported by the device, flood control can be offloaded to it, preventing
certain netdevs from flooding unicast traffic for which there is no FDB entry.
IGMP Snooping
^^^^^^^^^^^^^
@ -316,9 +320,9 @@ SWITCHDEV_OBJ_IPV[4|6]_FIB object using switchdev_port_obj_xxx ops.
switchdev_port_obj_add is used for both adding a new FIB entry to the device,
or modifying an existing entry on the device.
XXX: Currently, only SWITCHDEV_OBJ_IPV4_FIB objects are supported.
XXX: Currently, only SWITCHDEV_OBJ_ID_IPV4_FIB objects are supported.
SWITCHDEV_OBJ_IPV4_FIB object passes:
SWITCHDEV_OBJ_ID_IPV4_FIB object passes:
struct switchdev_obj_ipv4_fib { /* IPV4_FIB */
u32 dst;
@ -369,3 +373,22 @@ The driver can monitor for updates to arp_tbl using the netevent notifier
NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops
for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy
to know when arp_tbl neighbor entries are purged from the port.
Transaction item queue
^^^^^^^^^^^^^^^^^^^^^^
For switchdev ops attr_set and obj_add, there is a 2 phase transaction model
used. First phase is to "prepare" anything needed, including various checks,
memory allocation, etc. The goal is to handle the stuff that is not unlikely
to fail here. The second phase is to "commit" the actual changes.
Switchdev provides an inftrastructure for sharing items (for example memory
allocations) between the two phases.
The object created by a driver in "prepare" phase and it is queued up by:
switchdev_trans_item_enqueue()
During the "commit" phase, the driver gets the object by:
switchdev_trans_item_dequeue()
If a transaction is aborted during "prepare" phase, switchdev code will handle
cleanup of the queued-up objects.

View file

@ -90,7 +90,304 @@ or to specify the output device using cmsg and IP_PKTINFO.
Limitations
-----------
VRF device currently only works for IPv4. Support for IPv6 is under development.
Index of original ingress interface is not available via cmsg. Will address
soon.
################################################################################
Using iproute2 for VRFs
=======================
VRF devices do *not* have to start with 'vrf-'. That is a convention used here
for emphasis of the device type, similar to use of 'br' in bridge names.
1. Create a VRF
To instantiate a VRF device and associate it with a table:
$ ip link add dev NAME type vrf table ID
Remember to add the ip rules as well:
$ ip ru add oif NAME table 10
$ ip ru add iif NAME table 10
$ ip -6 ru add oif NAME table 10
$ ip -6 ru add iif NAME table 10
Without the rules route lookups are not directed to the table.
For example:
$ ip link add dev vrf-blue type vrf table 10
$ ip ru add pref 200 oif vrf-blue table 10
$ ip ru add pref 200 iif vrf-blue table 10
$ ip -6 ru add pref 200 oif vrf-blue table 10
$ ip -6 ru add pref 200 iif vrf-blue table 10
2. List VRFs
To list VRFs that have been created:
$ ip [-d] link show type vrf
NOTE: The -d option is needed to show the table id
For example:
$ ip -d link show type vrf
11: vrf-mgmt: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 72:b3:ba:91:e2:24 brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 1 addrgenmode eui64
12: vrf-red: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether b6:6f:6e:f6:da:73 brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 10 addrgenmode eui64
13: vrf-blue: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 36:62:e8:7d:bb:8c brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 66 addrgenmode eui64
14: vrf-green: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether e6:28:b8:63:70:bb brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 81 addrgenmode eui64
Or in brief output:
$ ip -br link show type vrf
vrf-mgmt UP 72:b3:ba:91:e2:24 <NOARP,MASTER,UP,LOWER_UP>
vrf-red UP b6:6f:6e:f6:da:73 <NOARP,MASTER,UP,LOWER_UP>
vrf-blue UP 36:62:e8:7d:bb:8c <NOARP,MASTER,UP,LOWER_UP>
vrf-green UP e6:28:b8:63:70:bb <NOARP,MASTER,UP,LOWER_UP>
3. Assign a Network Interface to a VRF
Network interfaces are assigned to a VRF by enslaving the netdevice to a
VRF device:
$ ip link set dev NAME master VRF-NAME
On enslavement connected and local routes are automatically moved to the
table associated with the VRF device.
For example:
$ ip link set dev eth0 master vrf-mgmt
4. Show Devices Assigned to a VRF
To show devices that have been assigned to a specific VRF add the master
option to the ip command:
$ ip link show master VRF-NAME
For example:
$ ip link show master vrf-red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
Or using the brief output:
$ ip -br link show master vrf-red
eth1 UP 02:00:00:00:02:02 <BROADCAST,MULTICAST,UP,LOWER_UP>
eth2 UP 02:00:00:00:02:03 <BROADCAST,MULTICAST,UP,LOWER_UP>
eth5 DOWN 02:00:00:00:02:06 <BROADCAST,MULTICAST>
5. Show Neighbor Entries for a VRF
To list neighbor entries associated with devices enslaved to a VRF device
add the master option to the ip command:
$ ip [-6] neigh show master VRF-NAME
For example:
$ ip neigh show master vrf-red
10.2.1.254 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
10.2.2.254 dev eth2 lladdr 5e:54:01:6a:ee:80 REACHABLE
$ ip -6 neigh show master vrf-red
2002:1::64 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
6. Show Addresses for a VRF
To show addresses for interfaces associated with a VRF add the master
option to the ip command:
$ ip addr show master VRF-NAME
For example:
$ ip addr show master vrf-red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
inet 10.2.1.2/24 brd 10.2.1.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 2002:1::2/120 scope global
valid_lft forever preferred_lft forever
inet6 fe80::ff:fe00:202/64 scope link
valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
inet 10.2.2.2/24 brd 10.2.2.255 scope global eth2
valid_lft forever preferred_lft forever
inet6 2002:2::2/120 scope global
valid_lft forever preferred_lft forever
inet6 fe80::ff:fe00:203/64 scope link
valid_lft forever preferred_lft forever
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN group default qlen 1000
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
Or in brief format:
$ ip -br addr show master vrf-red
eth1 UP 10.2.1.2/24 2002:1::2/120 fe80::ff:fe00:202/64
eth2 UP 10.2.2.2/24 2002:2::2/120 fe80::ff:fe00:203/64
eth5 DOWN
7. Show Routes for a VRF
To show routes for a VRF use the ip command to display the table associated
with the VRF device:
$ ip [-6] route show table ID
For example:
$ ip route show table vrf-red
prohibit default
broadcast 10.2.1.0 dev eth1 proto kernel scope link src 10.2.1.2
10.2.1.0/24 dev eth1 proto kernel scope link src 10.2.1.2
local 10.2.1.2 dev eth1 proto kernel scope host src 10.2.1.2
broadcast 10.2.1.255 dev eth1 proto kernel scope link src 10.2.1.2
broadcast 10.2.2.0 dev eth2 proto kernel scope link src 10.2.2.2
10.2.2.0/24 dev eth2 proto kernel scope link src 10.2.2.2
local 10.2.2.2 dev eth2 proto kernel scope host src 10.2.2.2
broadcast 10.2.2.255 dev eth2 proto kernel scope link src 10.2.2.2
$ ip -6 route show table vrf-red
local 2002:1:: dev lo proto none metric 0 pref medium
local 2002:1::2 dev lo proto none metric 0 pref medium
2002:1::/120 dev eth1 proto kernel metric 256 pref medium
local 2002:2:: dev lo proto none metric 0 pref medium
local 2002:2::2 dev lo proto none metric 0 pref medium
2002:2::/120 dev eth2 proto kernel metric 256 pref medium
local fe80:: dev lo proto none metric 0 pref medium
local fe80:: dev lo proto none metric 0 pref medium
local fe80::ff:fe00:202 dev lo proto none metric 0 pref medium
local fe80::ff:fe00:203 dev lo proto none metric 0 pref medium
fe80::/64 dev eth1 proto kernel metric 256 pref medium
fe80::/64 dev eth2 proto kernel metric 256 pref medium
ff00::/8 dev vrf-red metric 256 pref medium
ff00::/8 dev eth1 metric 256 pref medium
ff00::/8 dev eth2 metric 256 pref medium
8. Route Lookup for a VRF
A test route lookup can be done for a VRF by adding the oif option to ip:
$ ip [-6] route get oif VRF-NAME ADDRESS
For example:
$ ip route get 10.2.1.40 oif vrf-red
10.2.1.40 dev eth1 table vrf-red src 10.2.1.2
cache
$ ip -6 route get 2002:1::32 oif vrf-red
2002:1::32 from :: dev eth1 table vrf-red proto kernel src 2002:1::2 metric 256 pref medium
9. Removing Network Interface from a VRF
Network interfaces are removed from a VRF by breaking the enslavement to
the VRF device:
$ ip link set dev NAME nomaster
Connected routes are moved back to the default table and local entries are
moved to the local table.
For example:
$ ip link set dev eth0 nomaster
--------------------------------------------------------------------------------
Commands used in this example:
cat >> /etc/iproute2/rt_tables <<EOF
1 vrf-mgmt
10 vrf-red
66 vrf-blue
81 vrf-green
EOF
function vrf_create
{
VRF=$1
TBID=$2
# create VRF device
ip link add vrf-${VRF} type vrf table ${TBID}
# add rules that direct lookups to vrf table
ip ru add pref 200 oif vrf-${VRF} table ${TBID}
ip ru add pref 200 iif vrf-${VRF} table ${TBID}
ip -6 ru add pref 200 oif vrf-${VRF} table ${TBID}
ip -6 ru add pref 200 iif vrf-${VRF} table ${TBID}
if [ "${VRF}" != "mgmt" ]; then
ip route add table ${TBID} prohibit default
fi
ip link set dev vrf-${VRF} up
ip link set dev vrf-${VRF} state up
}
vrf_create mgmt 1
ip link set dev eth0 master vrf-mgmt
vrf_create red 10
ip link set dev eth1 master vrf-red
ip link set dev eth2 master vrf-red
ip link set dev eth5 master vrf-red
vrf_create blue 66
ip link set dev eth3 master vrf-blue
vrf_create green 81
ip link set dev eth4 master vrf-green
Interface addresses from /etc/network/interfaces:
auto eth0
iface eth0 inet static
address 10.0.0.2
netmask 255.255.255.0
gateway 10.0.0.254
iface eth0 inet6 static
address 2000:1::2
netmask 120
auto eth1
iface eth1 inet static
address 10.2.1.2
netmask 255.255.255.0
iface eth1 inet6 static
address 2002:1::2
netmask 120
auto eth2
iface eth2 inet static
address 10.2.2.2
netmask 255.255.255.0
iface eth2 inet6 static
address 2002:2::2
netmask 120
auto eth3
iface eth3 inet static
address 10.2.3.2
netmask 255.255.255.0
iface eth3 inet6 static
address 2002:3::2
netmask 120
auto eth4
iface eth4 inet static
address 10.2.4.2
netmask 255.255.255.0
iface eth4 inet6 static
address 2002:4::2
netmask 120

View file

@ -5574,7 +5574,7 @@ F: drivers/net/wireless/iwlegacy/
INTEL WIRELESS WIFI LINK (iwlwifi)
M: Johannes Berg <johannes.berg@intel.com>
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
M: Intel Linux Wireless <linuxwifi@intel.com>
L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
@ -6121,6 +6121,13 @@ F: Documentation/auxdisplay/ks0108
F: drivers/auxdisplay/ks0108.c
F: include/linux/ks0108.h
L3MDEV
M: David Ahern <dsa@cumulusnetworks.com>
L: netdev@vger.kernel.org
S: Maintained
F: net/l3mdev
F: include/net/l3mdev.h
LAPB module
L: linux-x25@vger.kernel.org
S: Orphan
@ -7005,6 +7012,7 @@ M: Alan Ott <alan@signal11.us>
L: linux-wpan@vger.kernel.org
S: Maintained
F: drivers/net/ieee802154/mrf24j40.c
F: Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
MSI LAPTOP SUPPORT
M: "Lee, Chun-Yi" <jlee@suse.com>
@ -7339,7 +7347,6 @@ S: Odd Fixes
F: drivers/net/
F: include/linux/if_*
F: include/linux/netdevice.h
F: include/linux/arcdevice.h
F: include/linux/etherdevice.h
F: include/linux/fcdevice.h
F: include/linux/fddidevice.h
@ -8560,6 +8567,16 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/qlogic/qlge/
QLOGIC QL4xxx ETHERNET DRIVER
M: Yuval Mintz <Yuval.Mintz@qlogic.com>
M: Ariel Elior <Ariel.Elior@qlogic.com>
M: everest-linux-l2@qlogic.com
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/qlogic/qed/
F: include/linux/qed/
F: drivers/net/ethernet/qlogic/qede/
QNX4 FILESYSTEM
M: Anders Larsen <al@alarsen.net>
W: http://www.alarsen.net/linux/qnx4fs/
@ -8911,6 +8928,13 @@ S: Maintained
F: drivers/net/wireless/rtlwifi/
F: drivers/net/wireless/rtlwifi/rtl8192ce/
RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
M: Jes Sorensen <Jes.Sorensen@redhat.com>
L: linux-wireless@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
S: Maintained
F: drivers/net/wireless/realtek/rtl8xxxu/
S3 SAVAGE FRAMEBUFFER DRIVER
M: Antonino Daplas <adaplas@gmail.com>
L: linux-fbdev@vger.kernel.org
@ -11315,7 +11339,6 @@ M: Shrijeet Mukherjee <shm@cumulusnetworks.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/vrf.c
F: include/net/vrf.h
F: Documentation/networking/vrf.txt
VT1211 HARDWARE MONITOR DRIVER

View file

@ -591,6 +591,7 @@
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
ranges;
syscon = <&scm_conf>;
davinci_mdio: mdio@4a101000 {
compatible = "ti,am4372-mdio","ti,davinci_mdio";

View file

@ -1448,6 +1448,7 @@
<GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>;
ranges;
syscon = <&scm_conf>;
status = "disabled";
davinci_mdio: mdio@48485000 {

View file

@ -18,7 +18,6 @@
#include <linux/leds.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/mdio-gpio.h>
#include <linux/io.h>
#include <asm/setup.h>

View file

@ -15,7 +15,6 @@
#include <linux/input.h>
#include <linux/skbuff.h>
#include <linux/gpio_keys.h>
#include <linux/mdio-gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>

View file

@ -15,7 +15,6 @@
#include <linux/input.h>
#include <linux/skbuff.h>
#include <linux/gpio_keys.h>
#include <linux/mdio-gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>

View file

@ -125,7 +125,7 @@ static u64 jit_get_skb_w(struct sk_buff *skb, int offset)
}
/*
* Wrapper that handles both OABI and EABI and assures Thumb2 interworking
* Wrappers which handle both OABI and EABI and assures Thumb2 interworking
* (where the assembly routines like __aeabi_uidiv could cause problems).
*/
static u32 jit_udiv(u32 dividend, u32 divisor)
@ -133,6 +133,11 @@ static u32 jit_udiv(u32 dividend, u32 divisor)
return dividend / divisor;
}
static u32 jit_mod(u32 dividend, u32 divisor)
{
return dividend % divisor;
}
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
{
inst |= (cond << 28);
@ -471,11 +476,17 @@ static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
#endif
}
static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx,
int bpf_op)
{
#if __LINUX_ARM_ARCH__ == 7
if (elf_hwcap & HWCAP_IDIVA) {
emit(ARM_UDIV(rd, rm, rn), ctx);
if (bpf_op == BPF_DIV)
emit(ARM_UDIV(rd, rm, rn), ctx);
else {
emit(ARM_UDIV(ARM_R3, rm, rn), ctx);
emit(ARM_MLS(rd, rn, ARM_R3, rm), ctx);
}
return;
}
#endif
@ -496,7 +507,8 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
emit(ARM_MOV_R(ARM_R0, rm), ctx);
ctx->seen |= SEEN_CALL;
emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
emit_mov_i(ARM_R3, bpf_op == BPF_DIV ? (u32)jit_udiv : (u32)jit_mod,
ctx);
emit_blx_r(ARM_R3, ctx);
if (rd != ARM_R0)
@ -698,13 +710,27 @@ load_ind:
if (k == 1)
break;
emit_mov_i(r_scratch, k, ctx);
emit_udiv(r_A, r_A, r_scratch, ctx);
emit_udivmod(r_A, r_A, r_scratch, ctx, BPF_DIV);
break;
case BPF_ALU | BPF_DIV | BPF_X:
update_on_xread(ctx);
emit(ARM_CMP_I(r_X, 0), ctx);
emit_err_ret(ARM_COND_EQ, ctx);
emit_udiv(r_A, r_A, r_X, ctx);
emit_udivmod(r_A, r_A, r_X, ctx, BPF_DIV);
break;
case BPF_ALU | BPF_MOD | BPF_K:
if (k == 1) {
emit_mov_i(r_A, 0, ctx);
break;
}
emit_mov_i(r_scratch, k, ctx);
emit_udivmod(r_A, r_A, r_scratch, ctx, BPF_MOD);
break;
case BPF_ALU | BPF_MOD | BPF_X:
update_on_xread(ctx);
emit(ARM_CMP_I(r_X, 0), ctx);
emit_err_ret(ARM_COND_EQ, ctx);
emit_udivmod(r_A, r_A, r_X, ctx, BPF_MOD);
break;
case BPF_ALU | BPF_OR | BPF_K:
/* A |= K */
@ -1048,7 +1074,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *)ctx.target;
fp->jited = true;
fp->jited = 1;
out:
kfree(ctx.offsets);
return;

View file

@ -115,6 +115,8 @@
#define ARM_INST_UMULL 0x00800090
#define ARM_INST_MLS 0x00600090
/*
* Use a suitable undefined instruction to use for ARM/Thumb2 faulting.
* We need to be careful not to conflict with those used by other modules
@ -210,4 +212,7 @@
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
| (rd_lo) << 12 | (rm) << 8 | rn)
#define ARM_MLS(rd, rn, rm, ra) (ARM_INST_MLS | (rd) << 16 | (rn) | (rm) << 8 \
| (ra) << 12)
#endif /* PFILTER_OPCODES_ARM_H */

View file

@ -207,6 +207,17 @@
clock-output-names = "xge0clk";
};
xge1clk: xge1clk@1f62c000 {
compatible = "apm,xgene-device-clock";
status = "disabled";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f62c000 0x0 0x1000>;
reg-names = "csr-reg";
csr-mask = <0x3>;
clock-output-names = "xge1clk";
};
sataphy1clk: sataphy1clk@1f21c000 {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
@ -826,6 +837,23 @@
phy-connection-type = "xgmii";
};
xgenet1: ethernet@1f620000 {
compatible = "apm,xgene1-xgenet";
status = "disabled";
reg = <0x0 0x1f620000 0x0 0xd100>,
<0x0 0x1f600000 0x0 0Xc300>,
<0x0 0x18000000 0x0 0X8000>;
reg-names = "enet_csr", "ring_csr", "ring_cmd";
interrupts = <0x0 0x6C 0x4>,
<0x0 0x6D 0x4>;
port-id = <1>;
dma-coherent;
clocks = <&xge1clk 0>;
/* mac address will be overwritten by the bootloader */
local-mac-address = [00 00 00 00 00 00];
phy-connection-type = "xgmii";
};
rng: rng@10520000 {
compatible = "apm,xgene-rng";
reg = <0x0 0x10520000 0x0 0x100>;

View file

@ -0,0 +1,191 @@
soc0: soc@000000000 {
#address-cells = <2>;
#size-cells = <2>;
device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0x0 0x0 0x0 0x1 0x0>;
chip-id = <0>;
soc0_mdio0: mdio@803c0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "hisilicon,hns-mdio";
reg = <0x0 0x803c0000 0x0 0x10000
0x0 0x80000000 0x0 0x10000>;
soc0_phy0: ethernet-phy@0 {
reg = <0x0>;
compatible = "ethernet-phy-ieee802.3-c22";
};
soc0_phy1: ethernet-phy@1 {
reg = <0x1>;
compatible = "ethernet-phy-ieee802.3-c22";
};
};
dsa: dsa@c7000000 {
compatible = "hisilicon,hns-dsaf-v1";
dsa_name = "dsaf0";
mode = "6port-16rss";
interrupt-parent = <&mbigen_dsa>;
reg = <0x0 0xC0000000 0x0 0x420000
0x0 0xC2000000 0x0 0x300000
0x0 0xc5000000 0x0 0x890000
0x0 0xc7000000 0x0 0x60000
>;
phy-handle = <0 0 0 0 &soc0_phy0 &soc0_phy1 0 0>;
interrupts = <
/* [14] ge fifo err 8 / xge 6**/
149 0x4 150 0x4 151 0x4 152 0x4
153 0x4 154 0x4 26 0x4 27 0x4
155 0x4 156 0x4 157 0x4 158 0x4 159 0x4 160 0x4
/* [12] rcb com 4*3**/
0x6 0x4 0x7 0x4 0x8 0x4 0x9 0x4
16 0x4 17 0x4 18 0x4 19 0x4
22 0x4 23 0x4 24 0x4 25 0x4
/* [8] ppe tnl 0-7***/
0x0 0x4 0x1 0x4 0x2 0x4 0x3 0x4
0x4 0x4 0x5 0x4 12 0x4 13 0x4
/* [21] dsaf event int 3+18**/
128 0x4 129 0x4 130 0x4
0x83 0x4 0x84 0x4 0x85 0x4 0x86 0x4 0x87 0x4 0x88 0x4
0x89 0x4 0x8a 0x4 0x8b 0x4 0x8c 0x4 0x8d 0x4 0x8e 0x4
0x8f 0x4 0x90 0x4 0x91 0x4 0x92 0x4 0x93 0x4 0x94 0x4
/* [4] debug rcb 2*2*/
0xe 0x1 0xf 0x1 0x14 0x1 0x15 0x1
/* [256] sevice rcb 2*128*/
0x180 0x1 0x181 0x1 0x182 0x1 0x183 0x1
0x184 0x1 0x185 0x1 0x186 0x1 0x187 0x1
0x188 0x1 0x189 0x1 0x18a 0x1 0x18b 0x1
0x18c 0x1 0x18d 0x1 0x18e 0x1 0x18f 0x1
0x190 0x1 0x191 0x1 0x192 0x1 0x193 0x1
0x194 0x1 0x195 0x1 0x196 0x1 0x197 0x1
0x198 0x1 0x199 0x1 0x19a 0x1 0x19b 0x1
0x19c 0x1 0x19d 0x1 0x19e 0x1 0x19f 0x1
0x1a0 0x1 0x1a1 0x1 0x1a2 0x1 0x1a3 0x1
0x1a4 0x1 0x1a5 0x1 0x1a6 0x1 0x1a7 0x1
0x1a8 0x1 0x1a9 0x1 0x1aa 0x1 0x1ab 0x1
0x1ac 0x1 0x1ad 0x1 0x1ae 0x1 0x1af 0x1
0x1b0 0x1 0x1b1 0x1 0x1b2 0x1 0x1b3 0x1
0x1b4 0x1 0x1b5 0x1 0x1b6 0x1 0x1b7 0x1
0x1b8 0x1 0x1b9 0x1 0x1ba 0x1 0x1bb 0x1
0x1bc 0x1 0x1bd 0x1 0x1be 0x1 0x1bf 0x1
0x1c0 0x1 0x1c1 0x1 0x1c2 0x1 0x1c3 0x1
0x1c4 0x1 0x1c5 0x1 0x1c6 0x1 0x1c7 0x1
0x1c8 0x1 0x1c9 0x1 0x1ca 0x1 0x1cb 0x1
0x1cc 0x1 0x1cd 0x1 0x1ce 0x1 0x1cf 0x1
0x1d0 0x1 0x1d1 0x1 0x1d2 0x1 0x1d3 0x1
0x1d4 0x1 0x1d5 0x1 0x1d6 0x1 0x1d7 0x1
0x1d8 0x1 0x1d9 0x1 0x1da 0x1 0x1db 0x1
0x1dc 0x1 0x1dd 0x1 0x1de 0x1 0x1df 0x1
0x1e0 0x1 0x1e1 0x1 0x1e2 0x1 0x1e3 0x1
0x1e4 0x1 0x1e5 0x1 0x1e6 0x1 0x1e7 0x1
0x1e8 0x1 0x1e9 0x1 0x1ea 0x1 0x1eb 0x1
0x1ec 0x1 0x1ed 0x1 0x1ee 0x1 0x1ef 0x1
0x1f0 0x1 0x1f1 0x1 0x1f2 0x1 0x1f3 0x1
0x1f4 0x1 0x1f5 0x1 0x1f6 0x1 0x1f7 0x1
0x1f8 0x1 0x1f9 0x1 0x1fa 0x1 0x1fb 0x1
0x1fc 0x1 0x1fd 0x1 0x1fe 0x1 0x1ff 0x1
0x200 0x1 0x201 0x1 0x202 0x1 0x203 0x1
0x204 0x1 0x205 0x1 0x206 0x1 0x207 0x1
0x208 0x1 0x209 0x1 0x20a 0x1 0x20b 0x1
0x20c 0x1 0x20d 0x1 0x20e 0x1 0x20f 0x1
0x210 0x1 0x211 0x1 0x212 0x1 0x213 0x1
0x214 0x1 0x215 0x1 0x216 0x1 0x217 0x1
0x218 0x1 0x219 0x1 0x21a 0x1 0x21b 0x1
0x21c 0x1 0x21d 0x1 0x21e 0x1 0x21f 0x1
0x220 0x1 0x221 0x1 0x222 0x1 0x223 0x1
0x224 0x1 0x225 0x1 0x226 0x1 0x227 0x1
0x228 0x1 0x229 0x1 0x22a 0x1 0x22b 0x1
0x22c 0x1 0x22d 0x1 0x22e 0x1 0x22f 0x1
0x230 0x1 0x231 0x1 0x232 0x1 0x233 0x1
0x234 0x1 0x235 0x1 0x236 0x1 0x237 0x1
0x238 0x1 0x239 0x1 0x23a 0x1 0x23b 0x1
0x23c 0x1 0x23d 0x1 0x23e 0x1 0x23f 0x1
0x240 0x1 0x241 0x1 0x242 0x1 0x243 0x1
0x244 0x1 0x245 0x1 0x246 0x1 0x247 0x1
0x248 0x1 0x249 0x1 0x24a 0x1 0x24b 0x1
0x24c 0x1 0x24d 0x1 0x24e 0x1 0x24f 0x1
0x250 0x1 0x251 0x1 0x252 0x1 0x253 0x1
0x254 0x1 0x255 0x1 0x256 0x1 0x257 0x1
0x258 0x1 0x259 0x1 0x25a 0x1 0x25b 0x1
0x25c 0x1 0x25d 0x1 0x25e 0x1 0x25f 0x1
0x260 0x1 0x261 0x1 0x262 0x1 0x263 0x1
0x264 0x1 0x265 0x1 0x266 0x1 0x267 0x1
0x268 0x1 0x269 0x1 0x26a 0x1 0x26b 0x1
0x26c 0x1 0x26d 0x1 0x26e 0x1 0x26f 0x1
0x270 0x1 0x271 0x1 0x272 0x1 0x273 0x1
0x274 0x1 0x275 0x1 0x276 0x1 0x277 0x1
0x278 0x1 0x279 0x1 0x27a 0x1 0x27b 0x1
0x27c 0x1 0x27d 0x1 0x27e 0x1 0x27f 0x1>;
buf-size = <4096>;
desc-num = <1024>;
dma-coherent;
};
eth0: ethernet@0{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <0>;
local-mac-address = [00 00 00 01 00 58];
status = "disabled";
dma-coherent;
};
eth1: ethernet@1{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <1>;
status = "disabled";
dma-coherent;
};
eth2: ethernet@2{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <2>;
local-mac-address = [00 00 00 01 00 5a];
status = "disabled";
dma-coherent;
};
eth3: ethernet@3{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <3>;
local-mac-address = [00 00 00 01 00 5b];
status = "disabled";
dma-coherent;
};
eth4: ethernet@4{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <4>;
local-mac-address = [00 00 00 01 00 5c];
status = "disabled";
dma-coherent;
};
eth5: ethernet@5{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <5>;
local-mac-address = [00 00 00 01 00 5d];
status = "disabled";
dma-coherent;
};
eth6: ethernet@6{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <6>;
local-mac-address = [00 00 00 01 00 5e];
status = "disabled";
dma-coherent;
};
eth7: ethernet@7{
compatible = "hisilicon,hns-nic-v1";
ae-name = "dsaf0";
port-id = <7>;
local-mac-address = [00 00 00 01 00 5f];
status = "disabled";
dma-coherent;
};
};

View file

@ -744,7 +744,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
set_memory_ro((unsigned long)header, header->pages);
prog->bpf_func = (void *)ctx.image;
prog->jited = true;
prog->jited = 1;
out:
kfree(ctx.offset);
}

View file

@ -29,6 +29,7 @@
int psc_present;
volatile __u8 *psc;
EXPORT_SYMBOL_GPL(psc);
/*
* Debugging dump, used in various places to see what's going on.

View file

@ -4,6 +4,7 @@ config BCM47XX_SSB
bool "SSB Support for Broadcom BCM47XX"
select SYS_HAS_CPU_BMIPS32_3300
select SSB
select SSB_HOST_SOC
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
select SSB_EMBEDDED

View file

@ -1251,7 +1251,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
fp->bpf_func = (void *)ctx.target;
fp->jited = true;
fp->jited = 1;
out:
kfree(ctx.offsets);

View file

@ -224,10 +224,12 @@
/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
fsl,wake-on-filer;
};
/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
fsl,wake-on-filer;
};
global-utilities@e0000 {

View file

@ -679,7 +679,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
((u64 *)image)[1] = local_paca->kernel_toc;
#endif
fp->bpf_func = (void *)image;
fp->jited = true;
fp->jited = 1;
}
out:
kfree(addrs);

View file

@ -1310,7 +1310,7 @@ void bpf_int_jit_compile(struct bpf_prog *fp)
if (jit.prg_buf) {
set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *) jit.prg_buf;
fp->jited = true;
fp->jited = 1;
}
free_addrs:
kfree(jit.addrs);

View file

@ -812,7 +812,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
if (image) {
bpf_flush_icache(image, image + proglen);
fp->bpf_func = (void *)image;
fp->jited = true;
fp->jited = 1;
}
out:
kfree(addrs);

View file

@ -1109,7 +1109,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
bpf_flush_icache(header, image + proglen);
set_memory_ro((unsigned long)header, header->pages);
prog->bpf_func = (void *)image;
prog->jited = true;
prog->jited = 1;
}
out:
kfree(addrs);

View file

@ -112,7 +112,8 @@ static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data)
static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry) return -1;
if (!entry)
return -ENOMEM;
entry->data = data;
entry->next = NULL;
if (que->next == NULL)
@ -1175,7 +1176,7 @@ static int rx_pkt(struct atm_dev *dev)
if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) {
if (vcc->vci < 32)
printk("Drop control packets\n");
goto out_free_desc;
goto out_free_desc;
}
skb_put(skb,len);
// pwang_test

View file

@ -436,13 +436,8 @@ int bcma_bus_register(struct bcma_bus *bus)
}
dev = bcma_bus_get_host_dev(bus);
/* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when
* of_default_bus_match_table is exported or in some other way
* accessible. This is just a temporary workaround.
*/
if (IS_BUILTIN(CONFIG_BCMA) && dev) {
of_platform_populate(dev->of_node, of_default_bus_match_table,
NULL, dev);
if (dev) {
of_platform_default_populate(dev->of_node, NULL, dev);
}
/* Cores providing flash access go before SPROM init */

View file

@ -4,6 +4,7 @@ menu "Bluetooth device drivers"
config BT_INTEL
tristate
select REGMAP
config BT_BCM
tristate
@ -182,7 +183,8 @@ config BT_HCIBCM203X
config BT_HCIBPA10X
tristate "HCI BPA10x USB driver"
depends on USB
depends on USB && BT_HCIUART
select BT_HCIUART_H4
help
Bluetooth HCI BPA10x USB driver.
This driver provides support for the Digianswer BPA 100/105 Bluetooth
@ -275,7 +277,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997.
Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module.
@ -289,7 +291,7 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997
chipsets are supported.
Say Y here to compile support for Marvell BT-over-SDIO driver

View file

@ -93,6 +93,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x300f) },
{ USB_DEVICE(0x04CA, 0x3010) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x021c) },
{ USB_DEVICE(0x0930, 0x0220) },
{ USB_DEVICE(0x0930, 0x0227) },
{ USB_DEVICE(0x0b05, 0x17d0) },
@ -104,6 +105,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0CF3, 0x311F) },
{ USB_DEVICE(0x0cf3, 0x3121) },
{ USB_DEVICE(0x0CF3, 0x817a) },
{ USB_DEVICE(0x0CF3, 0x817b) },
{ USB_DEVICE(0x0cf3, 0xe003) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0CF3, 0xE005) },
@ -153,6 +155,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
@ -164,6 +167,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },

View file

@ -422,17 +422,12 @@ static int bfusb_open(struct hci_dev *hdev)
BT_DBG("hdev %p bfusb %p", hdev, data);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
write_lock_irqsave(&data->lock, flags);
err = bfusb_rx_submit(data, NULL);
if (!err) {
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
bfusb_rx_submit(data, NULL);
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
}
write_unlock_irqrestore(&data->lock, flags);
@ -458,9 +453,6 @@ static int bfusb_close(struct hci_dev *hdev)
BT_DBG("hdev %p bfusb %p", hdev, data);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
write_lock_irqsave(&data->lock, flags);
write_unlock_irqrestore(&data->lock, flags);
@ -479,9 +471,6 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;

View file

@ -390,7 +390,7 @@ static void bluecard_receive(struct bluecard_info *info,
for (i = 0; i < len; i++) {
/* Allocate packet */
if (info->rx_skb == NULL) {
if (!info->rx_skb) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@ -628,9 +628,6 @@ static int bluecard_hci_open(struct hci_dev *hdev)
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {
unsigned int iobase = info->p_dev->resource[0]->start;
@ -646,9 +643,6 @@ static int bluecard_hci_close(struct hci_dev *hdev)
{
struct bluecard_info *info = hci_get_drvdata(hdev);
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
bluecard_hci_flush(hdev);
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) {

View file

@ -35,7 +35,9 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#define VERSION "0.10"
#include "hci_uart.h"
#define VERSION "0.11"
static const struct usb_device_id bpa10x_table[] = {
/* Tektronix BPA 100/105 (Digianswer) */
@ -56,112 +58,6 @@ struct bpa10x_data {
struct sk_buff *rx_skb[2];
};
#define HCI_VENDOR_HDR_SIZE 5
struct hci_vendor_hdr {
__u8 type;
__le16 snum;
__le16 dlen;
} __packed;
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
{
struct bpa10x_data *data = hci_get_drvdata(hdev);
BT_DBG("%s queue %d buffer %p count %d", hdev->name,
queue, buf, count);
if (queue < 0 || queue > 1)
return -EILSEQ;
hdev->stat.byte_rx += count;
while (count) {
struct sk_buff *skb = data->rx_skb[queue];
struct { __u8 type; int expect; } *scb;
int type, len = 0;
if (!skb) {
/* Start of the frame */
type = *((__u8 *) buf);
count--; buf++;
switch (type) {
case HCI_EVENT_PKT:
if (count >= HCI_EVENT_HDR_SIZE) {
struct hci_event_hdr *h = buf;
len = HCI_EVENT_HDR_SIZE + h->plen;
} else
return -EILSEQ;
break;
case HCI_ACLDATA_PKT:
if (count >= HCI_ACL_HDR_SIZE) {
struct hci_acl_hdr *h = buf;
len = HCI_ACL_HDR_SIZE +
__le16_to_cpu(h->dlen);
} else
return -EILSEQ;
break;
case HCI_SCODATA_PKT:
if (count >= HCI_SCO_HDR_SIZE) {
struct hci_sco_hdr *h = buf;
len = HCI_SCO_HDR_SIZE + h->dlen;
} else
return -EILSEQ;
break;
case HCI_VENDOR_PKT:
if (count >= HCI_VENDOR_HDR_SIZE) {
struct hci_vendor_hdr *h = buf;
len = HCI_VENDOR_HDR_SIZE +
__le16_to_cpu(h->dlen);
} else
return -EILSEQ;
break;
}
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) {
BT_ERR("%s no memory for packet", hdev->name);
return -ENOMEM;
}
data->rx_skb[queue] = skb;
scb = (void *) skb->cb;
scb->type = type;
scb->expect = len;
} else {
/* Continuation */
scb = (void *) skb->cb;
len = scb->expect;
}
len = min(len, count);
memcpy(skb_put(skb, len), buf, len);
scb->expect -= len;
if (scb->expect == 0) {
/* Complete frame */
data->rx_skb[queue] = NULL;
bt_cb(skb)->pkt_type = scb->type;
hci_recv_frame(hdev, skb);
}
count -= len; buf += len;
}
return 0;
}
static void bpa10x_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
@ -184,6 +80,22 @@ done:
kfree_skb(skb);
}
#define HCI_VENDOR_HDR_SIZE 5
#define HCI_RECV_VENDOR \
.type = HCI_VENDOR_PKT, \
.hlen = HCI_VENDOR_HDR_SIZE, \
.loff = 3, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE
static const struct h4_recv_pkt bpa10x_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ HCI_RECV_VENDOR, .recv = hci_recv_diag },
};
static void bpa10x_rx_complete(struct urb *urb)
{
struct hci_dev *hdev = urb->context;
@ -197,11 +109,17 @@ static void bpa10x_rx_complete(struct urb *urb)
return;
if (urb->status == 0) {
if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
bool idx = usb_pipebulk(urb->pipe);
data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx],
urb->transfer_buffer,
urb->actual_length) < 0) {
urb->actual_length,
bpa10x_recv_pkts,
ARRAY_SIZE(bpa10x_recv_pkts));
if (IS_ERR(data->rx_skb[idx])) {
BT_ERR("%s corrupted event packet", hdev->name);
hdev->stat.err_rx++;
data->rx_skb[idx] = NULL;
}
}
@ -304,9 +222,6 @@ static int bpa10x_open(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
err = bpa10x_submit_intr_urb(hdev);
if (err < 0)
goto error;
@ -320,8 +235,6 @@ static int bpa10x_open(struct hci_dev *hdev)
error:
usb_kill_anchored_urbs(&data->rx_anchor);
clear_bit(HCI_RUNNING, &hdev->flags);
return err;
}
@ -331,9 +244,6 @@ static int bpa10x_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
usb_kill_anchored_urbs(&data->rx_anchor);
return 0;
@ -350,6 +260,24 @@ static int bpa10x_flush(struct hci_dev *hdev)
return 0;
}
static int bpa10x_setup(struct hci_dev *hdev)
{
const u8 req[] = { 0x07 };
struct sk_buff *skb;
BT_DBG("%s", hdev->name);
/* Read revision string */
skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
return 0;
}
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct bpa10x_data *data = hci_get_drvdata(hdev);
@ -360,9 +288,6 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
skb->dev = (void *) hdev;
urb = usb_alloc_urb(0, GFP_ATOMIC);
@ -431,6 +356,25 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)
{
const u8 req[] = { 0x00, enable };
struct sk_buff *skb;
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -ENETDOWN;
/* Enable sniffer operation */
skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
return 0;
}
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct bpa10x_data *data;
@ -465,7 +409,9 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
hdev->open = bpa10x_open;
hdev->close = bpa10x_close;
hdev->flush = bpa10x_flush;
hdev->setup = bpa10x_setup;
hdev->send = bpa10x_send_frame;
hdev->set_diag = bpa10x_set_diag;
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);

View file

@ -233,7 +233,7 @@ static void bt3c_receive(struct bt3c_info *info)
info->hdev->stat.byte_rx++;
/* Allocate packet */
if (info->rx_skb == NULL) {
if (!info->rx_skb) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@ -270,7 +270,6 @@ static void bt3c_receive(struct bt3c_info *info)
/* Unknown packet */
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
info->hdev->stat.err_rx++;
clear_bit(HCI_RUNNING, &(info->hdev->flags));
kfree_skb(info->rx_skb);
info->rx_skb = NULL;
@ -395,17 +394,12 @@ static int bt3c_hci_flush(struct hci_dev *hdev)
static int bt3c_hci_open(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &(hdev->flags));
return 0;
}
static int bt3c_hci_close(struct hci_dev *hdev)
{
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
bt3c_hci_flush(hdev);
return 0;
@ -453,7 +447,8 @@ static int bt3c_load_firmware(struct bt3c_info *info,
{
char *ptr = (char *) firmware;
char b[9];
unsigned int iobase, size, addr, fcs, tmp;
unsigned int iobase, tmp;
unsigned long size, addr, fcs;
int i, err = 0;
iobase = info->p_dev->resource[0]->start;
@ -478,15 +473,18 @@ static int bt3c_load_firmware(struct bt3c_info *info,
memset(b, 0, sizeof(b));
memcpy(b, ptr + 2, 2);
size = simple_strtoul(b, NULL, 16);
if (kstrtoul(b, 16, &size) < 0)
return -EINVAL;
memset(b, 0, sizeof(b));
memcpy(b, ptr + 4, 8);
addr = simple_strtoul(b, NULL, 16);
if (kstrtoul(b, 16, &addr) < 0)
return -EINVAL;
memset(b, 0, sizeof(b));
memcpy(b, ptr + (size * 2) + 2, 2);
fcs = simple_strtoul(b, NULL, 16);
if (kstrtoul(b, 16, &fcs) < 0)
return -EINVAL;
memset(b, 0, sizeof(b));
for (tmp = 0, i = 0; i < size; i++) {

View file

@ -181,6 +181,27 @@ static int btbcm_reset(struct hci_dev *hdev)
return 0;
}
static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: BCM: Reading local name failed (%ld)",
hdev->name, PTR_ERR(skb));
return skb;
}
if (skb->len != sizeof(struct hci_rp_read_local_name)) {
BT_ERR("%s: BCM: Local name length mismatch", hdev->name);
kfree_skb(skb);
return ERR_PTR(-EIO);
}
return skb;
}
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
{
struct sk_buff *skb;
@ -302,7 +323,7 @@ int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
}
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
hw_name ? : "BCM", (subver & 0x7000) >> 13,
hw_name ? : "BCM", (subver & 0xe000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
return 0;
@ -332,7 +353,7 @@ int btbcm_finalize(struct hci_dev *hdev)
kfree_skb(skb);
BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
(subver & 0x7000) >> 13, (subver & 0x1f00) >> 8,
(subver & 0xe000) >> 13, (subver & 0x1f00) >> 8,
(subver & 0x00ff), rev & 0x0fff);
btbcm_check_bdaddr(hdev);
@ -393,6 +414,14 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
kfree_skb(skb);
/* Read Local Name */
skb = btbcm_read_local_name(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
switch ((rev & 0xf000) >> 12) {
case 0:
case 3:
@ -432,7 +461,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
}
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
hw_name ? : "BCM", (subver & 0x7000) >> 13,
hw_name ? : "BCM", (subver & 0xe000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
err = request_firmware(&fw, fw_name, &hdev->dev);
@ -461,9 +490,17 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
kfree_skb(skb);
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
hw_name ? : "BCM", (subver & 0x7000) >> 13,
hw_name ? : "BCM", (subver & 0xe000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
/* Read Local Name */
skb = btbcm_read_local_name(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
btbcm_check_bdaddr(hdev);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
@ -475,12 +512,34 @@ EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
int btbcm_setup_apple(struct hci_dev *hdev)
{
struct sk_buff *skb;
int err;
/* Reset */
err = btbcm_reset(hdev);
if (err)
return err;
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config(hdev);
if (!IS_ERR(skb)) {
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
get_unaligned_le16(skb->data + 5));
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name,
skb->data[1], get_unaligned_le16(skb->data + 5));
kfree_skb(skb);
}
/* Read USB Product Info */
skb = btbcm_read_usb_product(hdev);
if (!IS_ERR(skb)) {
BT_INFO("%s: BCM: product %4.4x:%4.4x", hdev->name,
get_unaligned_le16(skb->data + 1),
get_unaligned_le16(skb->data + 3));
kfree_skb(skb);
}
/* Read Local Name */
skb = btbcm_read_local_name(hdev);
if (!IS_ERR(skb)) {
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
}

View file

@ -22,6 +22,8 @@
*/
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@ -89,6 +91,75 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
int btintel_set_diag(struct hci_dev *hdev, bool enable)
{
struct sk_buff *skb;
u8 param[3];
int err;
if (enable) {
param[0] = 0x03;
param[1] = 0x03;
param[2] = 0x03;
} else {
param[0] = 0x00;
param[1] = 0x00;
param[2] = 0x00;
}
skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
if (err == -ENODATA)
goto done;
BT_ERR("%s: Changing Intel diagnostic mode failed (%d)",
hdev->name, err);
return err;
}
kfree_skb(skb);
done:
btintel_set_event_mask(hdev, enable);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_set_diag);
int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
{
struct sk_buff *skb;
u8 param[2];
int err;
param[0] = 0x01;
param[1] = 0x00;
skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
hdev->name, err);
return PTR_ERR(skb);
}
kfree_skb(skb);
err = btintel_set_diag(hdev, enable);
param[0] = 0x00;
param[1] = 0x00;
skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
hdev->name, err);
return PTR_ERR(skb);
}
kfree_skb(skb);
return err;
}
EXPORT_SYMBOL_GPL(btintel_set_diag_mfg);
void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
struct sk_buff *skb;
@ -169,6 +240,304 @@ int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
}
EXPORT_SYMBOL_GPL(btintel_secure_send);
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
{
const struct firmware *fw;
struct sk_buff *skb;
const u8 *fw_ptr;
int err;
err = request_firmware_direct(&fw, ddc_name, &hdev->dev);
if (err < 0) {
bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)",
ddc_name, err);
return err;
}
bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name);
fw_ptr = fw->data;
/* DDC file contains one or more DDC structure which has
* Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
*/
while (fw->size > fw_ptr - fw->data) {
u8 cmd_plen = fw_ptr[0] + sizeof(u8);
skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)",
PTR_ERR(skb));
release_firmware(fw);
return PTR_ERR(skb);
}
fw_ptr += cmd_plen;
kfree_skb(skb);
}
release_firmware(fw);
bt_dev_info(hdev, "Applying Intel DDC parameters completed");
return 0;
}
EXPORT_SYMBOL_GPL(btintel_load_ddc_config);
int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
{
u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct sk_buff *skb;
int err;
if (debug)
mask[1] |= 0x62;
skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Setting Intel event mask failed (%d)",
hdev->name, err);
return err;
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_set_event_mask);
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
{
struct sk_buff *skb;
u8 param[2];
int err;
param[0] = 0x01;
param[1] = 0x00;
skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
hdev->name, err);
return PTR_ERR(skb);
}
kfree_skb(skb);
err = btintel_set_event_mask(hdev, debug);
param[0] = 0x00;
param[1] = 0x00;
skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
hdev->name, err);
return PTR_ERR(skb);
}
kfree_skb(skb);
return err;
}
EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg);
/* ------- REGMAP IBT SUPPORT ------- */
#define IBT_REG_MODE_8BIT 0x00
#define IBT_REG_MODE_16BIT 0x01
#define IBT_REG_MODE_32BIT 0x02
struct regmap_ibt_context {
struct hci_dev *hdev;
__u16 op_write;
__u16 op_read;
};
struct ibt_cp_reg_access {
__le32 addr;
__u8 mode;
__u8 len;
__u8 data[0];
} __packed;
struct ibt_rp_reg_access {
__u8 status;
__le32 addr;
__u8 data[0];
} __packed;
static int regmap_ibt_read(void *context, const void *addr, size_t reg_size,
void *val, size_t val_size)
{
struct regmap_ibt_context *ctx = context;
struct ibt_cp_reg_access cp;
struct ibt_rp_reg_access *rp;
struct sk_buff *skb;
int err = 0;
if (reg_size != sizeof(__le32))
return -EINVAL;
switch (val_size) {
case 1:
cp.mode = IBT_REG_MODE_8BIT;
break;
case 2:
cp.mode = IBT_REG_MODE_16BIT;
break;
case 4:
cp.mode = IBT_REG_MODE_32BIT;
break;
default:
return -EINVAL;
}
/* regmap provides a little-endian formatted addr */
cp.addr = *(__le32 *)addr;
cp.len = val_size;
bt_dev_dbg(ctx->hdev, "Register (0x%x) read", le32_to_cpu(cp.addr));
skb = hci_cmd_sync(ctx->hdev, ctx->op_read, sizeof(cp), &cp,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error (%d)",
le32_to_cpu(cp.addr), err);
return err;
}
if (skb->len != sizeof(*rp) + val_size) {
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad len",
le32_to_cpu(cp.addr));
err = -EINVAL;
goto done;
}
rp = (struct ibt_rp_reg_access *)skb->data;
if (rp->addr != cp.addr) {
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad addr",
le32_to_cpu(rp->addr));
err = -EINVAL;
goto done;
}
memcpy(val, rp->data, val_size);
done:
kfree_skb(skb);
return err;
}
static int regmap_ibt_gather_write(void *context,
const void *addr, size_t reg_size,
const void *val, size_t val_size)
{
struct regmap_ibt_context *ctx = context;
struct ibt_cp_reg_access *cp;
struct sk_buff *skb;
int plen = sizeof(*cp) + val_size;
u8 mode;
int err = 0;
if (reg_size != sizeof(__le32))
return -EINVAL;
switch (val_size) {
case 1:
mode = IBT_REG_MODE_8BIT;
break;
case 2:
mode = IBT_REG_MODE_16BIT;
break;
case 4:
mode = IBT_REG_MODE_32BIT;
break;
default:
return -EINVAL;
}
cp = kmalloc(plen, GFP_KERNEL);
if (!cp)
return -ENOMEM;
/* regmap provides a little-endian formatted addr/value */
cp->addr = *(__le32 *)addr;
cp->mode = mode;
cp->len = val_size;
memcpy(&cp->data, val, val_size);
bt_dev_dbg(ctx->hdev, "Register (0x%x) write", le32_to_cpu(cp->addr));
skb = hci_cmd_sync(ctx->hdev, ctx->op_write, plen, cp, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(ctx->hdev, "regmap: Register (0x%x) write error (%d)",
le32_to_cpu(cp->addr), err);
goto done;
}
kfree_skb(skb);
done:
kfree(cp);
return err;
}
static int regmap_ibt_write(void *context, const void *data, size_t count)
{
/* data contains register+value, since we only support 32bit addr,
* minimum data size is 4 bytes.
*/
if (WARN_ONCE(count < 4, "Invalid register access"))
return -EINVAL;
return regmap_ibt_gather_write(context, data, 4, data + 4, count - 4);
}
static void regmap_ibt_free_context(void *context)
{
kfree(context);
}
static struct regmap_bus regmap_ibt = {
.read = regmap_ibt_read,
.write = regmap_ibt_write,
.gather_write = regmap_ibt_gather_write,
.free_context = regmap_ibt_free_context,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
/* Config is the same for all register regions */
static const struct regmap_config regmap_ibt_cfg = {
.name = "btintel_regmap",
.reg_bits = 32,
.val_bits = 32,
};
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
u16 opcode_write)
{
struct regmap_ibt_context *ctx;
bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read,
opcode_write);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->op_read = opcode_read;
ctx->op_write = opcode_write;
ctx->hdev = hdev;
return regmap_init(&hdev->dev, &regmap_ibt, ctx, &regmap_ibt_cfg);
}
EXPORT_SYMBOL_GPL(btintel_regmap_init);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);

View file

@ -73,11 +73,19 @@ struct intel_secure_send_result {
int btintel_check_bdaddr(struct hci_dev *hdev);
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int btintel_set_diag(struct hci_dev *hdev, bool enable);
int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
const void *param);
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
u16 opcode_write);
#else
@ -91,11 +99,22 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd
return -EOPNOTSUPP;
}
static inline int btintel_set_diag(struct hci_dev *hdev, bool enable)
{
return -EOPNOTSUPP;
}
static inline int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
{
return -EOPNOTSUPP;
}
static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
}
static void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
static inline void btintel_version_info(struct hci_dev *hdev,
struct intel_version *ver)
{
}
@ -105,4 +124,26 @@ static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
return -EOPNOTSUPP;
}
static inline int btintel_load_ddc_config(struct hci_dev *hdev,
const char *ddc_name)
{
return -EOPNOTSUPP;
}
static inline int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
{
return -EOPNOTSUPP;
}
static inline int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
{
return -EOPNOTSUPP;
}
static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
u16 opcode_read,
u16 opcode_write)
{
return ERR_PTR(-EINVAL);
}
#endif

View file

@ -184,7 +184,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
}
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
if (skb == NULL) {
if (!skb) {
BT_ERR("No free skb");
return -ENOMEM;
}
@ -377,20 +377,6 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)
return -EINVAL;
}
if (skb_headroom(skb) < BTM_HEADER_LEN) {
struct sk_buff *tmp = skb;
skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);
if (!skb) {
BT_ERR("Tx Error: realloc_headroom failed %d",
BTM_HEADER_LEN);
skb = tmp;
return -EINVAL;
}
kfree_skb(tmp);
}
skb_push(skb, BTM_HEADER_LEN);
/* header type: byte[3]
@ -450,13 +436,6 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
skb->data, skb->len);
return -EBUSY;
}
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
@ -491,9 +470,6 @@ static int btmrvl_close(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
skb_queue_purge(&priv->adapter->tx_queue);
return 0;
@ -501,8 +477,6 @@ static int btmrvl_close(struct hci_dev *hdev)
static int btmrvl_open(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &hdev->flags);
return 0;
}
@ -542,14 +516,17 @@ static int btmrvl_check_device_tree(struct btmrvl_private *priv)
ret = of_property_read_u8_array(dt_node, "btmrvl,cal-data",
cal_data + BT_CAL_HDR_LEN,
BT_CAL_DATA_SIZE);
if (ret)
if (ret) {
of_node_put(dt_node);
return ret;
}
BT_DBG("Use cal data from device tree");
ret = btmrvl_download_cal_data(priv, cal_data,
BT_CAL_DATA_SIZE);
if (ret) {
BT_ERR("Fail to download calibrate data");
of_node_put(dt_node);
return ret;
}
}

View file

@ -146,6 +146,29 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
.fw_dump_end = 0xea,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
.cfg = 0x00,
.host_int_mask = 0x08,
.host_intstatus = 0x0c,
.card_status = 0x5c,
.sq_read_base_addr_a0 = 0xf8,
.sq_read_base_addr_a1 = 0xf9,
.card_revision = 0xc8,
.card_fw_status0 = 0xe8,
.card_fw_status1 = 0xe9,
.card_rx_len = 0xea,
.card_rx_unit = 0xeb,
.io_port_0 = 0xe4,
.io_port_1 = 0xe5,
.io_port_2 = 0xe6,
.int_read_to_clear = true,
.host_int_rsr = 0x04,
.card_misc_cfg = 0xD8,
.fw_dump_ctrl = 0xf0,
.fw_dump_start = 0xf1,
.fw_dump_end = 0xf8,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "mrvl/sd8688_helper.bin",
.firmware = "mrvl/sd8688.bin",
@ -191,25 +214,37 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
.supports_fw_dump = true,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
.helper = NULL,
.firmware = "mrvl/sd8997_uapsta.bin",
.reg = &btmrvl_reg_8997,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = true,
};
static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
.driver_data = (unsigned long) &btmrvl_sdio_sd8688 },
.driver_data = (unsigned long)&btmrvl_sdio_sd8688 },
/* Marvell SD8787 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
.driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
/* Marvell SD8787 Bluetooth AMP device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
.driver_data = (unsigned long)&btmrvl_sdio_sd8787 },
/* Marvell SD8797 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
.driver_data = (unsigned long)&btmrvl_sdio_sd8797 },
/* Marvell SD8887 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
/* Marvell SD8897 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
.driver_data = (unsigned long)&btmrvl_sdio_sd8897 },
/* Marvell SD8997 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142),
.driver_data = (unsigned long)&btmrvl_sdio_sd8997 },
{ } /* Terminating entry */
};
@ -619,7 +654,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
/* Allocate buffer */
skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
if (skb == NULL) {
if (!skb) {
BT_ERR("No free skb");
ret = -ENOMEM;
goto exit;
@ -1278,6 +1313,12 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
if (memory_size == 0) {
BT_INFO("Firmware dump finished!");
sdio_writeb(card->func, FW_DUMP_READ_DONE,
card->reg->fw_dump_ctrl, &ret);
if (ret) {
BT_ERR("SDIO Write MEMDUMP_FINISH ERR");
goto done;
}
break;
}
@ -1616,3 +1657,4 @@ MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");

View file

@ -194,21 +194,15 @@ static int btsdio_open(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
sdio_claim_host(data->func);
err = sdio_enable_func(data->func);
if (err < 0) {
clear_bit(HCI_RUNNING, &hdev->flags);
if (err < 0)
goto release;
}
err = sdio_claim_irq(data->func, btsdio_interrupt);
if (err < 0) {
sdio_disable_func(data->func);
clear_bit(HCI_RUNNING, &hdev->flags);
goto release;
}
@ -229,9 +223,6 @@ static int btsdio_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
sdio_claim_host(data->func);
sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
@ -261,9 +252,6 @@ static int btsdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;

View file

@ -38,7 +38,7 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@ -188,7 +188,7 @@ static void btuart_receive(struct btuart_info *info)
info->hdev->stat.byte_rx++;
/* Allocate packet */
if (info->rx_skb == NULL) {
if (!info->rx_skb) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
@ -223,7 +223,6 @@ static void btuart_receive(struct btuart_info *info)
/* Unknown packet */
BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
info->hdev->stat.err_rx++;
clear_bit(HCI_RUNNING, &(info->hdev->flags));
kfree_skb(info->rx_skb);
info->rx_skb = NULL;
@ -409,17 +408,12 @@ static int btuart_hci_flush(struct hci_dev *hdev)
static int btuart_hci_open(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &(hdev->flags));
return 0;
}
static int btuart_hci_close(struct hci_dev *hdev)
{
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
btuart_hci_flush(hdev);
return 0;

View file

@ -60,6 +60,8 @@ static struct usb_driver btusb_driver;
#define BTUSB_QCA_ROME 0x8000
#define BTUSB_BCM_APPLE 0x10000
#define BTUSB_REALTEK 0x20000
#define BTUSB_BCM2045 0x40000
#define BTUSB_IFNUM_2 0x80000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@ -73,7 +75,7 @@ static const struct usb_device_id btusb_table[] = {
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_APPLE },
.driver_info = BTUSB_BCM_APPLE | BTUSB_IFNUM_2 },
/* MediaTek MT76x0E */
{ USB_DEVICE(0x0e8d, 0x763f) },
@ -124,6 +126,9 @@ static const struct usb_device_id btusb_table[] = {
/* Broadcom BCM20702B0 (Dynex/Insignia) */
{ USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM },
/* Broadcom BCM43142A0 (Foxconn/Lenovo) */
{ USB_DEVICE(0x105b, 0xe065), .driver_info = BTUSB_BCM_PATCHRAM },
/* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
@ -164,6 +169,9 @@ static const struct usb_device_id blacklist_table[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
/* Broadcom BCM2045 devices */
{ USB_DEVICE(0x0a5c, 0x2045), .driver_info = BTUSB_BCM2045 },
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
@ -195,6 +203,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
@ -206,6 +215,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817b), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
@ -341,12 +351,14 @@ static const struct usb_device_id blacklist_table[] = {
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING 9
#define BTUSB_RESET_RESUME 10
#define BTUSB_DIAG_RUNNING 11
struct btusb_data {
struct hci_dev *hdev;
struct usb_device *udev;
struct usb_interface *intf;
struct usb_interface *isoc;
struct usb_interface *diag;
unsigned long flags;
@ -361,6 +373,7 @@ struct btusb_data {
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
struct usb_anchor diag_anchor;
spinlock_t rxlock;
struct sk_buff *evt_skb;
@ -372,6 +385,8 @@ struct btusb_data {
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;
struct usb_endpoint_descriptor *diag_tx_ep;
struct usb_endpoint_descriptor *diag_rx_ep;
__u8 cmdreq_type;
__u8 cmdreq;
@ -869,6 +884,92 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
return err;
}
static void btusb_diag_complete(struct urb *urb)
{
struct hci_dev *hdev = urb->context;
struct btusb_data *data = hci_get_drvdata(hdev);
int err;
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
urb->actual_length);
if (urb->status == 0) {
struct sk_buff *skb;
skb = bt_skb_alloc(urb->actual_length, GFP_ATOMIC);
if (skb) {
memcpy(skb_put(skb, urb->actual_length),
urb->transfer_buffer, urb->actual_length);
hci_recv_diag(hdev, skb);
}
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
return;
}
if (!test_bit(BTUSB_DIAG_RUNNING, &data->flags))
return;
usb_anchor_urb(urb, &data->diag_anchor);
usb_mark_last_busy(data->udev);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
/* -EPERM: urb is being killed;
* -ENODEV: device got disconnected */
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
}
static int btusb_submit_diag_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct urb *urb;
unsigned char *buf;
unsigned int pipe;
int err, size = HCI_MAX_FRAME_SIZE;
BT_DBG("%s", hdev->name);
if (!data->diag_rx_ep)
return -ENODEV;
urb = usb_alloc_urb(0, mem_flags);
if (!urb)
return -ENOMEM;
buf = kmalloc(size, mem_flags);
if (!buf) {
usb_free_urb(urb);
return -ENOMEM;
}
pipe = usb_rcvbulkpipe(data->udev, data->diag_rx_ep->bEndpointAddress);
usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
btusb_diag_complete, hdev);
urb->transfer_flags |= URB_FREE_BUFFER;
usb_mark_last_busy(data->udev);
usb_anchor_urb(urb, &data->diag_anchor);
err = usb_submit_urb(urb, mem_flags);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
}
usb_free_urb(urb);
return err;
}
static void btusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
@ -940,9 +1041,6 @@ static int btusb_open(struct hci_dev *hdev)
data->intf->needs_remote_wakeup = 1;
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
goto done;
if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
goto done;
@ -959,13 +1057,17 @@ static int btusb_open(struct hci_dev *hdev)
set_bit(BTUSB_BULK_RUNNING, &data->flags);
btusb_submit_bulk_urb(hdev, GFP_KERNEL);
if (data->diag) {
if (!btusb_submit_diag_urb(hdev, GFP_KERNEL))
set_bit(BTUSB_DIAG_RUNNING, &data->flags);
}
done:
usb_autopm_put_interface(data->intf);
return 0;
failed:
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
clear_bit(HCI_RUNNING, &hdev->flags);
usb_autopm_put_interface(data->intf);
return err;
}
@ -975,6 +1077,7 @@ static void btusb_stop_traffic(struct btusb_data *data)
usb_kill_anchored_urbs(&data->intr_anchor);
usb_kill_anchored_urbs(&data->bulk_anchor);
usb_kill_anchored_urbs(&data->isoc_anchor);
usb_kill_anchored_urbs(&data->diag_anchor);
}
static int btusb_close(struct hci_dev *hdev)
@ -984,15 +1087,13 @@ static int btusb_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
cancel_work_sync(&data->work);
cancel_work_sync(&data->waker);
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
clear_bit(BTUSB_DIAG_RUNNING, &data->flags);
btusb_stop_traffic(data);
btusb_free_frags(data);
@ -1156,9 +1257,6 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
urb = alloc_ctrl_urb(hdev, skb);
@ -1277,6 +1375,20 @@ static void btusb_work(struct work_struct *work)
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
/* When isochronous alternate setting needs to be
* changed, because SCO connection has been added
* or removed, a packet fragment may be left in the
* reassembling state. This could lead to wrongly
* assembled fragments.
*
* Clear outstanding fragment when selecting a new
* alternate setting.
*/
spin_lock(&data->rxlock);
kfree_skb(data->sco_skb);
data->sco_skb = NULL;
spin_unlock(&data->rxlock);
if (__set_isoc_interface(hdev, new_alts) < 0)
return;
}
@ -1348,7 +1460,9 @@ static int btusb_setup_csr(struct hci_dev *hdev)
rp = (struct hci_rp_read_local_version *)skb->data;
if (le16_to_cpu(rp->manufacturer) != 10) {
/* Detect controllers which aren't real CSR ones. */
if (le16_to_cpu(rp->manufacturer) != 10 ||
le16_to_cpu(rp->lmp_subver) == 0x0c5c) {
/* Clear the reset quirk since this is not an actual
* early Bluetooth 1.1 device from CSR.
*/
@ -1587,8 +1701,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
BT_INFO("%s: Intel device is already patched. patch num: %02x",
hdev->name, ver->fw_patch_num);
kfree_skb(skb);
btintel_check_bdaddr(hdev);
return 0;
goto complete;
}
/* Opens the firmware patch file based on the firmware version read
@ -1600,8 +1713,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
fw = btusb_setup_intel_get_fw(hdev, ver);
if (!fw) {
kfree_skb(skb);
btintel_check_bdaddr(hdev);
return 0;
goto complete;
}
fw_ptr = fw->data;
@ -1674,8 +1786,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
hdev->name);
btintel_check_bdaddr(hdev);
return 0;
goto complete;
exit_mfg_disable:
/* Disable the manufacturer mode without reset */
@ -1690,8 +1801,7 @@ exit_mfg_disable:
BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);
btintel_check_bdaddr(hdev);
return 0;
goto complete;
exit_mfg_deactivate:
release_firmware(fw);
@ -1711,6 +1821,12 @@ exit_mfg_deactivate:
BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
hdev->name);
complete:
/* Set the event mask for Intel specific vendor events. This enables
* a few extra events that are useful during general operation.
*/
btintel_set_event_mask_mfg(hdev, false);
btintel_check_bdaddr(hdev);
return 0;
}
@ -1827,9 +1943,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
@ -2003,6 +2116,15 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
BT_INFO("%s: Secure boot is %s", hdev->name,
params->secure_boot ? "enabled" : "disabled");
BT_INFO("%s: OTP lock is %s", hdev->name,
params->otp_lock ? "enabled" : "disabled");
BT_INFO("%s: API lock is %s", hdev->name,
params->api_lock ? "enabled" : "disabled");
BT_INFO("%s: Debug lock is %s", hdev->name,
params->debug_lock ? "enabled" : "disabled");
BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
params->min_fw_build_nn, params->min_fw_build_cw,
2000 + params->min_fw_build_yy);
@ -2217,36 +2339,16 @@ done:
* The device can work without DDC parameters, so even if it fails
* to load the file, no need to fail the setup.
*/
err = request_firmware_direct(&fw, fwname, &hdev->dev);
if (err < 0)
return 0;
btintel_load_ddc_config(hdev, fwname);
BT_INFO("%s: Found Intel DDC parameters: %s", hdev->name, fwname);
fw_ptr = fw->data;
/* DDC file contains one or more DDC structure which has
* Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
/* Set the event mask for Intel specific vendor events. This enables
* a few extra events that are useful during general operation. It
* does not enable any debugging related events.
*
* The device will function correctly without these events enabled
* and thus no need to fail the setup.
*/
while (fw->size > fw_ptr - fw->data) {
u8 cmd_plen = fw_ptr[0] + sizeof(u8);
skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Failed to send Intel_Write_DDC (%ld)",
hdev->name, PTR_ERR(skb));
release_firmware(fw);
return PTR_ERR(skb);
}
fw_ptr += cmd_plen;
kfree_skb(skb);
}
release_firmware(fw);
BT_INFO("%s: Applying Intel DDC parameters completed", hdev->name);
btintel_set_event_mask(hdev, false);
return 0;
}
@ -2573,19 +2675,115 @@ static int btusb_setup_qca(struct hci_dev *hdev)
return 0;
}
#ifdef CONFIG_BT_HCIBTUSB_BCM
static inline int __set_diag_interface(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct usb_interface *intf = data->diag;
int i;
if (!data->diag)
return -ENODEV;
data->diag_tx_ep = NULL;
data->diag_rx_ep = NULL;
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
struct usb_endpoint_descriptor *ep_desc;
ep_desc = &intf->cur_altsetting->endpoint[i].desc;
if (!data->diag_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
data->diag_tx_ep = ep_desc;
continue;
}
if (!data->diag_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
data->diag_rx_ep = ep_desc;
continue;
}
}
if (!data->diag_tx_ep || !data->diag_rx_ep) {
BT_ERR("%s invalid diagnostic descriptors", hdev->name);
return -ENODEV;
}
return 0;
}
static struct urb *alloc_diag_urb(struct hci_dev *hdev, bool enable)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct sk_buff *skb;
struct urb *urb;
unsigned int pipe;
if (!data->diag_tx_ep)
return ERR_PTR(-ENODEV);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return ERR_PTR(-ENOMEM);
skb = bt_skb_alloc(2, GFP_KERNEL);
if (!skb) {
usb_free_urb(urb);
return ERR_PTR(-ENOMEM);
}
*skb_put(skb, 1) = 0xf0;
*skb_put(skb, 1) = enable;
pipe = usb_sndbulkpipe(data->udev, data->diag_tx_ep->bEndpointAddress);
usb_fill_bulk_urb(urb, data->udev, pipe,
skb->data, skb->len, btusb_tx_complete, skb);
skb->dev = (void *)hdev;
return urb;
}
static int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct urb *urb;
if (!data->diag)
return -ENODEV;
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -ENETDOWN;
urb = alloc_diag_urb(hdev, enable);
if (IS_ERR(urb))
return PTR_ERR(urb);
return submit_or_queue_tx_urb(hdev, urb);
}
#endif
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *ep_desc;
struct btusb_data *data;
struct hci_dev *hdev;
unsigned ifnum_base;
int i, err;
BT_DBG("intf %p id %p", intf, id);
/* interface numbers are hardcoded in the spec */
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) {
if (!(id->driver_info & BTUSB_IFNUM_2))
return -ENODEV;
if (intf->cur_altsetting->desc.bInterfaceNumber != 2)
return -ENODEV;
}
ifnum_base = intf->cur_altsetting->desc.bInterfaceNumber;
if (!id->driver_info) {
const struct usb_device_id *match;
@ -2653,6 +2851,7 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->intr_anchor);
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
init_usb_anchor(&data->diag_anchor);
spin_lock_init(&data->rxlock);
if (id->driver_info & BTUSB_INTEL_NEW) {
@ -2686,33 +2885,53 @@ static int btusb_probe(struct usb_interface *intf,
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
if (id->driver_info & BTUSB_BCM2045)
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
if (id->driver_info & BTUSB_BCM92035)
hdev->setup = btusb_setup_bcm92035;
#ifdef CONFIG_BT_HCIBTUSB_BCM
if (id->driver_info & BTUSB_BCM_PATCHRAM) {
hdev->manufacturer = 15;
hdev->setup = btbcm_setup_patchram;
hdev->set_diag = btusb_bcm_set_diag;
hdev->set_bdaddr = btbcm_set_bdaddr;
/* Broadcom LM_DIAG Interface numbers are hardcoded */
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
}
if (id->driver_info & BTUSB_BCM_APPLE)
if (id->driver_info & BTUSB_BCM_APPLE) {
hdev->manufacturer = 15;
hdev->setup = btbcm_setup_apple;
hdev->set_diag = btusb_bcm_set_diag;
/* Broadcom LM_DIAG Interface numbers are hardcoded */
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
}
#endif
if (id->driver_info & BTUSB_INTEL) {
hdev->manufacturer = 2;
hdev->setup = btusb_setup_intel;
hdev->shutdown = btusb_shutdown_intel;
hdev->set_diag = btintel_set_diag_mfg;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
if (id->driver_info & BTUSB_INTEL_NEW) {
hdev->manufacturer = 2;
hdev->send = btusb_send_frame_intel;
hdev->setup = btusb_setup_intel_new;
hdev->hw_error = btintel_hw_error;
hdev->set_diag = btintel_set_diag;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
if (id->driver_info & BTUSB_MARVELL)
@ -2723,8 +2942,10 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
}
if (id->driver_info & BTUSB_INTEL_BOOT)
if (id->driver_info & BTUSB_INTEL_BOOT) {
hdev->manufacturer = 2;
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
}
if (id->driver_info & BTUSB_ATH3012) {
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
@ -2753,8 +2974,8 @@ static int btusb_probe(struct usb_interface *intf,
/* AMP controllers do not support SCO packets */
data->isoc = NULL;
} else {
/* Interface numbers are hardcoded in the specification */
data->isoc = usb_ifnum_to_if(data->udev, 1);
/* Interface orders are hardcoded in the specification */
data->isoc = usb_ifnum_to_if(data->udev, ifnum_base + 1);
}
if (!reset)
@ -2782,7 +3003,7 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
/* Fake CSR devices with broken commands */
if (bcdDevice <= 0x100)
if (bcdDevice <= 0x100 || bcdDevice == 0x134)
hdev->setup = btusb_setup_csr;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
@ -2817,6 +3038,16 @@ static int btusb_probe(struct usb_interface *intf,
}
}
#ifdef CONFIG_BT_HCIBTUSB_BCM
if (data->diag) {
if (!usb_driver_claim_interface(&btusb_driver,
data->diag, data))
__set_diag_interface(hdev);
else
data->diag = NULL;
}
#endif
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
@ -2844,12 +3075,25 @@ static void btusb_disconnect(struct usb_interface *intf)
if (data->isoc)
usb_set_intfdata(data->isoc, NULL);
if (data->diag)
usb_set_intfdata(data->diag, NULL);
hci_unregister_dev(hdev);
if (intf == data->isoc)
if (intf == data->intf) {
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
if (data->diag)
usb_driver_release_interface(&btusb_driver, data->diag);
} else if (intf == data->isoc) {
if (data->diag)
usb_driver_release_interface(&btusb_driver, data->diag);
usb_driver_release_interface(&btusb_driver, data->intf);
else if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
} else if (intf == data->diag) {
usb_driver_release_interface(&btusb_driver, data->intf);
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
}
hci_free_dev(hdev);
}

View file

@ -155,9 +155,6 @@ static int ti_st_open(struct hci_dev *hdev)
BT_DBG("%s %p", hdev->name, hdev);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
/* provide contexts for callbacks from ST */
hst = hci_get_drvdata(hdev);
@ -181,7 +178,6 @@ static int ti_st_open(struct hci_dev *hdev)
goto done;
if (err != -EINPROGRESS) {
clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("st_register failed %d", err);
return err;
}
@ -195,7 +191,6 @@ static int ti_st_open(struct hci_dev *hdev)
(&hst->wait_reg_completion,
msecs_to_jiffies(BT_REGISTER_TIMEOUT));
if (!timeleft) {
clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("Timeout(%d sec),didn't get reg "
"completion signal from ST",
BT_REGISTER_TIMEOUT / 1000);
@ -205,7 +200,6 @@ static int ti_st_open(struct hci_dev *hdev)
/* Is ST registration callback
* called with ERROR status? */
if (hst->reg_status != 0) {
clear_bit(HCI_RUNNING, &hdev->flags);
BT_ERR("ST registration completed with invalid "
"status %d", hst->reg_status);
return -EAGAIN;
@ -215,7 +209,6 @@ done:
hst->st_write = ti_st_proto[i].write;
if (!hst->st_write) {
BT_ERR("undefined ST write function");
clear_bit(HCI_RUNNING, &hdev->flags);
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
/* Undo registration with ST */
err = st_unregister(&ti_st_proto[i]);
@ -236,9 +229,6 @@ static int ti_st_close(struct hci_dev *hdev)
int err, i;
struct ti_st *hst = hci_get_drvdata(hdev);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
err = st_unregister(&ti_st_proto[i]);
if (err)
@ -256,9 +246,6 @@ static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
struct ti_st *hst;
long len;
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
hst = hci_get_drvdata(hdev);
/* Prepend skb with frame type */

View file

@ -357,8 +357,6 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
static int dtl1_hci_open(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &(hdev->flags));
return 0;
}
@ -376,9 +374,6 @@ static int dtl1_hci_flush(struct hci_dev *hdev)
static int dtl1_hci_close(struct hci_dev *hdev)
{
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
dtl1_hci_flush(hdev);
return 0;

View file

@ -243,6 +243,7 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
static const struct hci_uart_proto athp = {
.id = HCI_UART_ATH3K,
.name = "ATH3K",
.manufacturer = 69,
.open = ath_open,
.close = ath_close,
.flush = ath_flush,

View file

@ -31,6 +31,9 @@
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/tty.h>
#include <linux/interrupt.h>
#include <linux/dmi.h>
#include <linux/pm_runtime.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@ -38,6 +41,11 @@
#include "btbcm.h"
#include "hci_uart.h"
#define BCM_LM_DIAG_PKT 0x07
#define BCM_LM_DIAG_SIZE 63
#define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */
struct bcm_device {
struct list_head list;
@ -51,8 +59,10 @@ struct bcm_device {
bool clk_enabled;
u32 init_speed;
int irq;
u8 irq_polarity;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM
struct hci_uart *hu;
bool is_suspended; /* suspend/resume flag */
#endif
@ -66,7 +76,7 @@ struct bcm_data {
};
/* List of BCM BT UART devices */
static DEFINE_SPINLOCK(bcm_device_lock);
static DEFINE_MUTEX(bcm_device_lock);
static LIST_HEAD(bcm_device_list);
static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
@ -80,7 +90,7 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
clock.type = BCM_UART_CLOCK_48MHZ;
BT_DBG("%s: Set Controller clock (%d)", hdev->name, clock.type);
bt_dev_dbg(hdev, "Set Controller clock (%d)", clock.type);
/* This Broadcom specific command changes the UART's controller
* clock for baud rate > 3000000.
@ -88,15 +98,15 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
BT_ERR("%s: BCM: failed to write clock command (%d)",
hdev->name, err);
bt_dev_err(hdev, "BCM: failed to write clock (%d)",
err);
return err;
}
kfree_skb(skb);
}
BT_DBG("%s: Set Controller UART speed to %d bit/s", hdev->name, speed);
bt_dev_dbg(hdev, "Set Controller UART speed to %d bit/s", speed);
param.zero = cpu_to_le16(0);
param.baud_rate = cpu_to_le32(speed);
@ -108,8 +118,8 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
BT_ERR("%s: BCM: failed to write update baudrate command (%d)",
hdev->name, err);
bt_dev_err(hdev, "BCM: failed to write update baudrate (%d)",
err);
return err;
}
@ -149,12 +159,125 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
return 0;
}
#ifdef CONFIG_PM
static irqreturn_t bcm_host_wake(int irq, void *data)
{
struct bcm_device *bdev = data;
bt_dev_dbg(bdev, "Host wake IRQ");
pm_runtime_get(&bdev->pdev->dev);
pm_runtime_mark_last_busy(&bdev->pdev->dev);
pm_runtime_put_autosuspend(&bdev->pdev->dev);
return IRQ_HANDLED;
}
static int bcm_request_irq(struct bcm_data *bcm)
{
struct bcm_device *bdev = bcm->dev;
int err = 0;
/* If this is not a platform device, do not enable PM functionalities */
mutex_lock(&bcm_device_lock);
if (!bcm_device_exists(bdev)) {
err = -ENODEV;
goto unlock;
}
if (bdev->irq > 0) {
err = devm_request_irq(&bdev->pdev->dev, bdev->irq,
bcm_host_wake, IRQF_TRIGGER_RISING,
"host_wake", bdev);
if (err)
goto unlock;
device_init_wakeup(&bdev->pdev->dev, true);
pm_runtime_set_autosuspend_delay(&bdev->pdev->dev,
BCM_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&bdev->pdev->dev);
pm_runtime_set_active(&bdev->pdev->dev);
pm_runtime_enable(&bdev->pdev->dev);
}
unlock:
mutex_unlock(&bcm_device_lock);
return err;
}
static const struct bcm_set_sleep_mode default_sleep_params = {
.sleep_mode = 1, /* 0=Disabled, 1=UART, 2=Reserved, 3=USB */
.idle_host = 2, /* idle threshold HOST, in 300ms */
.idle_dev = 2, /* idle threshold device, in 300ms */
.bt_wake_active = 1, /* BT_WAKE active mode: 1 = high, 0 = low */
.host_wake_active = 0, /* HOST_WAKE active mode: 1 = high, 0 = low */
.allow_host_sleep = 1, /* Allow host sleep in SCO flag */
.combine_modes = 1, /* Combine sleep and LPM flag */
.tristate_control = 0, /* Allow tri-state control of UART tx flag */
/* Irrelevant USB flags */
.usb_auto_sleep = 0,
.usb_resume_timeout = 0,
.pulsed_host_wake = 0,
.break_to_host = 0
};
static int bcm_setup_sleep(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
struct sk_buff *skb;
struct bcm_set_sleep_mode sleep_params = default_sleep_params;
sleep_params.host_wake_active = !bcm->dev->irq_polarity;
skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params),
&sleep_params, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
bt_dev_err(hu->hdev, "Sleep VSC failed (%d)", err);
return err;
}
kfree_skb(skb);
bt_dev_dbg(hu->hdev, "Set Sleep Parameters VSC succeeded");
return 0;
}
#else
static inline int bcm_request_irq(struct bcm_data *bcm) { return 0; }
static inline int bcm_setup_sleep(struct hci_uart *hu) { return 0; }
#endif
static int bcm_set_diag(struct hci_dev *hdev, bool enable)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct bcm_data *bcm = hu->priv;
struct sk_buff *skb;
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -ENETDOWN;
skb = bt_skb_alloc(3, GFP_KERNEL);
if (!skb)
return -ENOMEM;
*skb_put(skb, 1) = BCM_LM_DIAG_PKT;
*skb_put(skb, 1) = 0xf0;
*skb_put(skb, 1) = enable;
skb_queue_tail(&bcm->txq, skb);
hci_uart_tx_wakeup(hu);
return 0;
}
static int bcm_open(struct hci_uart *hu)
{
struct bcm_data *bcm;
struct list_head *p;
BT_DBG("hu %p", hu);
bt_dev_dbg(hu->hdev, "hu %p", hu);
bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
if (!bcm)
@ -164,7 +287,7 @@ static int bcm_open(struct hci_uart *hu)
hu->priv = bcm;
spin_lock(&bcm_device_lock);
mutex_lock(&bcm_device_lock);
list_for_each(p, &bcm_device_list) {
struct bcm_device *dev = list_entry(p, struct bcm_device, list);
@ -175,17 +298,15 @@ static int bcm_open(struct hci_uart *hu)
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
bcm->dev = dev;
hu->init_speed = dev->init_speed;
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM
dev->hu = hu;
#endif
bcm_gpio_set_power(bcm->dev, true);
break;
}
}
if (bcm->dev)
bcm_gpio_set_power(bcm->dev, true);
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
return 0;
}
@ -193,18 +314,27 @@ static int bcm_open(struct hci_uart *hu)
static int bcm_close(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
struct bcm_device *bdev = bcm->dev;
BT_DBG("hu %p", hu);
bt_dev_dbg(hu->hdev, "hu %p", hu);
/* Protect bcm->dev against removal of the device or driver */
spin_lock(&bcm_device_lock);
if (bcm_device_exists(bcm->dev)) {
bcm_gpio_set_power(bcm->dev, false);
#ifdef CONFIG_PM_SLEEP
bcm->dev->hu = NULL;
mutex_lock(&bcm_device_lock);
if (bcm_device_exists(bdev)) {
bcm_gpio_set_power(bdev, false);
#ifdef CONFIG_PM
pm_runtime_disable(&bdev->pdev->dev);
pm_runtime_set_suspended(&bdev->pdev->dev);
if (device_can_wakeup(&bdev->pdev->dev)) {
devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
device_init_wakeup(&bdev->pdev->dev, false);
}
bdev->hu = NULL;
#endif
}
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
skb_queue_purge(&bcm->txq);
kfree_skb(bcm->rx_skb);
@ -218,7 +348,7 @@ static int bcm_flush(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
BT_DBG("hu %p", hu);
bt_dev_dbg(hu->hdev, "hu %p", hu);
skb_queue_purge(&bcm->txq);
@ -227,13 +357,15 @@ static int bcm_flush(struct hci_uart *hu)
static int bcm_setup(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
char fw_name[64];
const struct firmware *fw;
unsigned int speed;
int err;
BT_DBG("hu %p", hu);
bt_dev_dbg(hu->hdev, "hu %p", hu);
hu->hdev->set_diag = bcm_set_diag;
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
@ -242,13 +374,13 @@ static int bcm_setup(struct hci_uart *hu)
err = request_firmware(&fw, fw_name, &hu->hdev->dev);
if (err < 0) {
BT_INFO("%s: BCM: Patch %s not found", hu->hdev->name, fw_name);
bt_dev_info(hu->hdev, "BCM: Patch %s not found", fw_name);
return 0;
}
err = btbcm_patchram(hu->hdev, fw);
if (err) {
BT_INFO("%s: BCM: Patch failed (%d)", hu->hdev->name, err);
bt_dev_info(hu->hdev, "BCM: Patch failed (%d)", err);
goto finalize;
}
@ -281,14 +413,28 @@ finalize:
release_firmware(fw);
err = btbcm_finalize(hu->hdev);
if (err)
return err;
err = bcm_request_irq(bcm);
if (!err)
err = bcm_setup_sleep(hu);
return err;
}
#define BCM_RECV_LM_DIAG \
.type = BCM_LM_DIAG_PKT, \
.hlen = BCM_LM_DIAG_SIZE, \
.loff = 0, \
.lsize = 0, \
.maxlen = BCM_LM_DIAG_SIZE
static const struct h4_recv_pkt bcm_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ BCM_RECV_LM_DIAG, .recv = hci_recv_diag },
};
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
@ -302,9 +448,18 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts));
if (IS_ERR(bcm->rx_skb)) {
int err = PTR_ERR(bcm->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
bcm->rx_skb = NULL;
return err;
} else if (!bcm->rx_skb) {
/* Delay auto-suspend when receiving completed packet */
mutex_lock(&bcm_device_lock);
if (bcm->dev && bcm_device_exists(bcm->dev)) {
pm_runtime_get(&bcm->dev->pdev->dev);
pm_runtime_mark_last_busy(&bcm->dev->pdev->dev);
pm_runtime_put_autosuspend(&bcm->dev->pdev->dev);
}
mutex_unlock(&bcm_device_lock);
}
return count;
@ -314,7 +469,7 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct bcm_data *bcm = hu->priv;
BT_DBG("hu %p skb %p", hu, skb);
bt_dev_dbg(hu->hdev, "hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
@ -326,39 +481,105 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
struct sk_buff *skb = NULL;
struct bcm_device *bdev = NULL;
return skb_dequeue(&bcm->txq);
mutex_lock(&bcm_device_lock);
if (bcm_device_exists(bcm->dev)) {
bdev = bcm->dev;
pm_runtime_get_sync(&bdev->pdev->dev);
/* Shall be resumed here */
}
skb = skb_dequeue(&bcm->txq);
if (bdev) {
pm_runtime_mark_last_busy(&bdev->pdev->dev);
pm_runtime_put_autosuspend(&bdev->pdev->dev);
}
mutex_unlock(&bcm_device_lock);
return skb;
}
#ifdef CONFIG_PM_SLEEP
/* Platform suspend callback */
static int bcm_suspend(struct device *dev)
#ifdef CONFIG_PM
static int bcm_suspend_device(struct device *dev)
{
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
BT_DBG("suspend (%p): is_suspended %d", bdev, bdev->is_suspended);
bt_dev_dbg(bdev, "");
spin_lock(&bcm_device_lock);
if (!bdev->hu)
goto unlock;
if (!bdev->is_suspended) {
if (!bdev->is_suspended && bdev->hu) {
hci_uart_set_flow_control(bdev->hu, true);
/* Once this callback returns, driver suspends BT via GPIO */
/* Once this returns, driver suspends BT via GPIO */
bdev->is_suspended = true;
}
/* Suspend the device */
if (bdev->device_wakeup) {
gpiod_set_value(bdev->device_wakeup, false);
BT_DBG("suspend, delaying 15 ms");
bt_dev_dbg(bdev, "suspend, delaying 15 ms");
mdelay(15);
}
return 0;
}
static int bcm_resume_device(struct device *dev)
{
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
bt_dev_dbg(bdev, "");
if (bdev->device_wakeup) {
gpiod_set_value(bdev->device_wakeup, true);
bt_dev_dbg(bdev, "resume, delaying 15 ms");
mdelay(15);
}
/* When this executes, the device has woken up already */
if (bdev->is_suspended && bdev->hu) {
bdev->is_suspended = false;
hci_uart_set_flow_control(bdev->hu, false);
}
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
/* Platform suspend callback */
static int bcm_suspend(struct device *dev)
{
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
int error;
bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
/* bcm_suspend can be called at any time as long as platform device is
* bound, so it should use bcm_device_lock to protect access to hci_uart
* and device_wake-up GPIO.
*/
mutex_lock(&bcm_device_lock);
if (!bdev->hu)
goto unlock;
if (pm_runtime_active(dev))
bcm_suspend_device(dev);
if (device_may_wakeup(&bdev->pdev->dev)) {
error = enable_irq_wake(bdev->irq);
if (!error)
bt_dev_dbg(bdev, "BCM irq: enabled");
}
unlock:
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
return 0;
}
@ -368,28 +589,30 @@ static int bcm_resume(struct device *dev)
{
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
BT_DBG("resume (%p): is_suspended %d", bdev, bdev->is_suspended);
bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);
spin_lock(&bcm_device_lock);
/* bcm_resume can be called at any time as long as platform device is
* bound, so it should use bcm_device_lock to protect access to hci_uart
* and device_wake-up GPIO.
*/
mutex_lock(&bcm_device_lock);
if (!bdev->hu)
goto unlock;
if (bdev->device_wakeup) {
gpiod_set_value(bdev->device_wakeup, true);
BT_DBG("resume, delaying 15 ms");
mdelay(15);
if (device_may_wakeup(&bdev->pdev->dev)) {
disable_irq_wake(bdev->irq);
bt_dev_dbg(bdev, "BCM irq: disabled");
}
/* When this callback executes, the device has woken up already */
if (bdev->is_suspended) {
bdev->is_suspended = false;
hci_uart_set_flow_control(bdev->hu, false);
}
bcm_resume_device(dev);
unlock:
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
}
@ -397,24 +620,59 @@ unlock:
static const struct acpi_gpio_params device_wakeup_gpios = { 0, 0, false };
static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
static const struct acpi_gpio_params host_wakeup_gpios = { 2, 0, false };
static const struct acpi_gpio_mapping acpi_bcm_default_gpios[] = {
{ "device-wakeup-gpios", &device_wakeup_gpios, 1 },
{ "shutdown-gpios", &shutdown_gpios, 1 },
{ "host-wakeup-gpios", &host_wakeup_gpios, 1 },
{ },
};
#ifdef CONFIG_ACPI
static u8 acpi_active_low = ACPI_ACTIVE_LOW;
/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
{
.ident = "Asus T100TA",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR,
"ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = &acpi_active_low,
},
{ }
};
static int bcm_resource(struct acpi_resource *ares, void *data)
{
struct bcm_device *dev = data;
struct acpi_resource_extended_irq *irq;
struct acpi_resource_gpio *gpio;
struct acpi_resource_uart_serialbus *sb;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_uart_serialbus *sb;
switch (ares->type) {
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
irq = &ares->data.extended_irq;
dev->irq_polarity = irq->polarity;
break;
case ACPI_RESOURCE_TYPE_GPIO:
gpio = &ares->data.gpio;
if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
dev->irq_polarity = gpio->polarity;
break;
case ACPI_RESOURCE_TYPE_SERIAL_BUS:
sb = &ares->data.uart_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_UART)
dev->init_speed = sb->default_baud_rate;
break;
default:
break;
}
/* Always tell the ACPI core to skip this resource */
@ -424,15 +682,10 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
static int bcm_acpi_probe(struct bcm_device *dev)
{
struct platform_device *pdev = dev->pdev;
const struct acpi_device_id *id;
struct acpi_device *adev;
LIST_HEAD(resources);
const struct dmi_system_id *dmi_id;
int ret;
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (!id)
return -ENODEV;
/* Retrieve GPIO data */
dev->name = dev_name(&pdev->dev);
ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
@ -453,6 +706,21 @@ static int bcm_acpi_probe(struct bcm_device *dev)
if (IS_ERR(dev->shutdown))
return PTR_ERR(dev->shutdown);
/* IRQ can be declared in ACPI table as Interrupt or GpioInt */
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq <= 0) {
struct gpio_desc *gpio;
gpio = devm_gpiod_get_optional(&pdev->dev, "host-wakeup",
GPIOD_IN);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
dev->irq = gpiod_to_irq(gpio);
}
dev_info(&pdev->dev, "BCM irq: %d\n", dev->irq);
/* Make sure at-least one of the GPIO is defined and that
* a name is specified for this instance
*/
@ -462,11 +730,18 @@ static int bcm_acpi_probe(struct bcm_device *dev)
}
/* Retrieve UART ACPI info */
adev = ACPI_COMPANION(&dev->pdev->dev);
if (!adev)
return 0;
ret = acpi_dev_get_resources(ACPI_COMPANION(&dev->pdev->dev),
&resources, bcm_resource, dev);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&resources);
acpi_dev_get_resources(adev, &resources, bcm_resource, dev);
dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table);
if (dmi_id) {
bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low",
dmi_id->ident);
dev->irq_polarity = *(u8 *)dmi_id->driver_data;
}
return 0;
}
@ -480,7 +755,6 @@ static int bcm_acpi_probe(struct bcm_device *dev)
static int bcm_probe(struct platform_device *pdev)
{
struct bcm_device *dev;
struct acpi_device_id *pdata = pdev->dev.platform_data;
int ret;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@ -489,24 +763,18 @@ static int bcm_probe(struct platform_device *pdev)
dev->pdev = pdev;
if (ACPI_HANDLE(&pdev->dev)) {
ret = bcm_acpi_probe(dev);
if (ret)
return ret;
} else if (pdata) {
dev->name = pdata->id;
} else {
return -ENODEV;
}
ret = bcm_acpi_probe(dev);
if (ret)
return ret;
platform_set_drvdata(pdev, dev);
dev_info(&pdev->dev, "%s device registered.\n", dev->name);
/* Place this instance on the device list */
spin_lock(&bcm_device_lock);
mutex_lock(&bcm_device_lock);
list_add_tail(&dev->list, &bcm_device_list);
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
bcm_gpio_set_power(dev, false);
@ -517,9 +785,9 @@ static int bcm_remove(struct platform_device *pdev)
{
struct bcm_device *dev = platform_get_drvdata(pdev);
spin_lock(&bcm_device_lock);
mutex_lock(&bcm_device_lock);
list_del(&dev->list);
spin_unlock(&bcm_device_lock);
mutex_unlock(&bcm_device_lock);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
@ -531,6 +799,7 @@ static int bcm_remove(struct platform_device *pdev)
static const struct hci_uart_proto bcm_proto = {
.id = HCI_UART_BCM,
.name = "BCM",
.manufacturer = 15,
.init_speed = 115200,
.oper_speed = 4000000,
.open = bcm_open,
@ -553,7 +822,10 @@ MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
#endif
/* Platform suspend and resume callbacks */
static SIMPLE_DEV_PM_OPS(bcm_pm_ops, bcm_suspend, bcm_resume);
static const struct dev_pm_ops bcm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume)
SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL)
};
static struct platform_driver bcm_driver = {
.probe = bcm_probe,

View file

@ -266,3 +266,4 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
return skb;
}
EXPORT_SYMBOL_GPL(h4_recv_buf);

View file

@ -128,7 +128,7 @@ static void h5_timed_event(unsigned long arg)
{
const unsigned char sync_req[] = { 0x01, 0x7e };
unsigned char conf_req[] = { 0x03, 0xfc, 0x01 };
struct hci_uart *hu = (struct hci_uart *) arg;
struct hci_uart *hu = (struct hci_uart *)arg;
struct h5 *h5 = hu->priv;
struct sk_buff *skb;
unsigned long flags;
@ -210,7 +210,7 @@ static int h5_open(struct hci_uart *hu)
init_timer(&h5->timer);
h5->timer.function = h5_timed_event;
h5->timer.data = (unsigned long) hu;
h5->timer.data = (unsigned long)hu;
h5->tx_win = H5_TX_WIN_MAX;
@ -453,7 +453,7 @@ static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c)
return -ENOMEM;
}
h5->rx_skb->dev = (void *) hu->hdev;
h5->rx_skb->dev = (void *)hu->hdev;
return 0;
}
@ -696,7 +696,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
}
skb = skb_dequeue(&h5->unrel);
if (skb != NULL) {
if (skb) {
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {
@ -714,7 +714,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
goto unlock;
skb = skb_dequeue(&h5->rel);
if (skb != NULL) {
if (skb) {
nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type,
skb->data, skb->len);
if (nskb) {

View file

@ -31,6 +31,8 @@
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@ -43,19 +45,45 @@
#define STATE_FIRMWARE_LOADED 2
#define STATE_FIRMWARE_FAILED 3
#define STATE_BOOTING 4
#define STATE_LPM_ENABLED 5
#define STATE_TX_ACTIVE 6
#define STATE_SUSPENDED 7
#define STATE_LPM_TRANSACTION 8
#define HCI_LPM_WAKE_PKT 0xf0
#define HCI_LPM_PKT 0xf1
#define HCI_LPM_MAX_SIZE 10
#define HCI_LPM_HDR_SIZE HCI_EVENT_HDR_SIZE
#define LPM_OP_TX_NOTIFY 0x00
#define LPM_OP_SUSPEND_ACK 0x02
#define LPM_OP_RESUME_ACK 0x03
#define LPM_SUSPEND_DELAY_MS 1000
struct hci_lpm_pkt {
__u8 opcode;
__u8 dlen;
__u8 data[0];
} __packed;
struct intel_device {
struct list_head list;
struct platform_device *pdev;
struct gpio_desc *reset;
struct hci_uart *hu;
struct mutex hu_lock;
int irq;
};
static LIST_HEAD(intel_device_list);
static DEFINE_SPINLOCK(intel_device_list_lock);
static DEFINE_MUTEX(intel_device_list_lock);
struct intel_data {
struct sk_buff *rx_skb;
struct sk_buff_head txq;
struct work_struct busy_work;
struct hci_uart *hu;
unsigned long flags;
};
@ -101,24 +129,185 @@ static int intel_wait_booting(struct hci_uart *hu)
msecs_to_jiffies(1000));
if (err == 1) {
BT_ERR("%s: Device boot interrupted", hu->hdev->name);
bt_dev_err(hu->hdev, "Device boot interrupted");
return -EINTR;
}
if (err) {
BT_ERR("%s: Device boot timeout", hu->hdev->name);
bt_dev_err(hu->hdev, "Device boot timeout");
return -ETIMEDOUT;
}
return err;
}
#ifdef CONFIG_PM
static int intel_wait_lpm_transaction(struct hci_uart *hu)
{
struct intel_data *intel = hu->priv;
int err;
err = wait_on_bit_timeout(&intel->flags, STATE_LPM_TRANSACTION,
TASK_INTERRUPTIBLE,
msecs_to_jiffies(1000));
if (err == 1) {
bt_dev_err(hu->hdev, "LPM transaction interrupted");
return -EINTR;
}
if (err) {
bt_dev_err(hu->hdev, "LPM transaction timeout");
return -ETIMEDOUT;
}
return err;
}
static int intel_lpm_suspend(struct hci_uart *hu)
{
static const u8 suspend[] = { 0x01, 0x01, 0x01 };
struct intel_data *intel = hu->priv;
struct sk_buff *skb;
if (!test_bit(STATE_LPM_ENABLED, &intel->flags) ||
test_bit(STATE_SUSPENDED, &intel->flags))
return 0;
if (test_bit(STATE_TX_ACTIVE, &intel->flags))
return -EAGAIN;
bt_dev_dbg(hu->hdev, "Suspending");
skb = bt_skb_alloc(sizeof(suspend), GFP_KERNEL);
if (!skb) {
bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
return -ENOMEM;
}
memcpy(skb_put(skb, sizeof(suspend)), suspend, sizeof(suspend));
bt_cb(skb)->pkt_type = HCI_LPM_PKT;
set_bit(STATE_LPM_TRANSACTION, &intel->flags);
/* LPM flow is a priority, enqueue packet at list head */
skb_queue_head(&intel->txq, skb);
hci_uart_tx_wakeup(hu);
intel_wait_lpm_transaction(hu);
/* Even in case of failure, continue and test the suspended flag */
clear_bit(STATE_LPM_TRANSACTION, &intel->flags);
if (!test_bit(STATE_SUSPENDED, &intel->flags)) {
bt_dev_err(hu->hdev, "Device suspend error");
return -EINVAL;
}
bt_dev_dbg(hu->hdev, "Suspended");
hci_uart_set_flow_control(hu, true);
return 0;
}
static int intel_lpm_resume(struct hci_uart *hu)
{
struct intel_data *intel = hu->priv;
struct sk_buff *skb;
if (!test_bit(STATE_LPM_ENABLED, &intel->flags) ||
!test_bit(STATE_SUSPENDED, &intel->flags))
return 0;
bt_dev_dbg(hu->hdev, "Resuming");
hci_uart_set_flow_control(hu, false);
skb = bt_skb_alloc(0, GFP_KERNEL);
if (!skb) {
bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
return -ENOMEM;
}
bt_cb(skb)->pkt_type = HCI_LPM_WAKE_PKT;
set_bit(STATE_LPM_TRANSACTION, &intel->flags);
/* LPM flow is a priority, enqueue packet at list head */
skb_queue_head(&intel->txq, skb);
hci_uart_tx_wakeup(hu);
intel_wait_lpm_transaction(hu);
/* Even in case of failure, continue and test the suspended flag */
clear_bit(STATE_LPM_TRANSACTION, &intel->flags);
if (test_bit(STATE_SUSPENDED, &intel->flags)) {
bt_dev_err(hu->hdev, "Device resume error");
return -EINVAL;
}
bt_dev_dbg(hu->hdev, "Resumed");
return 0;
}
#endif /* CONFIG_PM */
static int intel_lpm_host_wake(struct hci_uart *hu)
{
static const u8 lpm_resume_ack[] = { LPM_OP_RESUME_ACK, 0x00 };
struct intel_data *intel = hu->priv;
struct sk_buff *skb;
hci_uart_set_flow_control(hu, false);
clear_bit(STATE_SUSPENDED, &intel->flags);
skb = bt_skb_alloc(sizeof(lpm_resume_ack), GFP_KERNEL);
if (!skb) {
bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet");
return -ENOMEM;
}
memcpy(skb_put(skb, sizeof(lpm_resume_ack)), lpm_resume_ack,
sizeof(lpm_resume_ack));
bt_cb(skb)->pkt_type = HCI_LPM_PKT;
/* LPM flow is a priority, enqueue packet at list head */
skb_queue_head(&intel->txq, skb);
hci_uart_tx_wakeup(hu);
bt_dev_dbg(hu->hdev, "Resumed by controller");
return 0;
}
static irqreturn_t intel_irq(int irq, void *dev_id)
{
struct intel_device *idev = dev_id;
dev_info(&idev->pdev->dev, "hci_intel irq\n");
mutex_lock(&idev->hu_lock);
if (idev->hu)
intel_lpm_host_wake(idev->hu);
mutex_unlock(&idev->hu_lock);
/* Host/Controller are now LPM resumed, trigger a new delayed suspend */
pm_runtime_get(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
pm_runtime_put_autosuspend(&idev->pdev->dev);
return IRQ_HANDLED;
}
static int intel_set_power(struct hci_uart *hu, bool powered)
{
struct list_head *p;
int err = -ENODEV;
spin_lock(&intel_device_list_lock);
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
@ -139,13 +328,73 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
hu, dev_name(&idev->pdev->dev), powered);
gpiod_set_value(idev->reset, powered);
/* Provide to idev a hu reference which is used to run LPM
* transactions (lpm suspend/resume) from PM callbacks.
* hu needs to be protected against concurrent removing during
* these PM ops.
*/
mutex_lock(&idev->hu_lock);
idev->hu = powered ? hu : NULL;
mutex_unlock(&idev->hu_lock);
if (idev->irq < 0)
break;
if (powered && device_can_wakeup(&idev->pdev->dev)) {
err = devm_request_threaded_irq(&idev->pdev->dev,
idev->irq, NULL,
intel_irq,
IRQF_ONESHOT,
"bt-host-wake", idev);
if (err) {
BT_ERR("hu %p, unable to allocate irq-%d",
hu, idev->irq);
break;
}
device_wakeup_enable(&idev->pdev->dev);
pm_runtime_set_active(&idev->pdev->dev);
pm_runtime_use_autosuspend(&idev->pdev->dev);
pm_runtime_set_autosuspend_delay(&idev->pdev->dev,
LPM_SUSPEND_DELAY_MS);
pm_runtime_enable(&idev->pdev->dev);
} else if (!powered && device_may_wakeup(&idev->pdev->dev)) {
devm_free_irq(&idev->pdev->dev, idev->irq, idev);
device_wakeup_disable(&idev->pdev->dev);
pm_runtime_disable(&idev->pdev->dev);
}
}
spin_unlock(&intel_device_list_lock);
mutex_unlock(&intel_device_list_lock);
return err;
}
static void intel_busy_work(struct work_struct *work)
{
struct list_head *p;
struct intel_data *intel = container_of(work, struct intel_data,
busy_work);
/* Link is busy, delay the suspend */
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
list);
if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
pm_runtime_get(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
pm_runtime_put_autosuspend(&idev->pdev->dev);
break;
}
}
mutex_unlock(&intel_device_list_lock);
}
static int intel_open(struct hci_uart *hu)
{
struct intel_data *intel;
@ -157,6 +406,9 @@ static int intel_open(struct hci_uart *hu)
return -ENOMEM;
skb_queue_head_init(&intel->txq);
INIT_WORK(&intel->busy_work, intel_busy_work);
intel->hu = hu;
hu->priv = intel;
@ -172,6 +424,8 @@ static int intel_close(struct hci_uart *hu)
BT_DBG("hu %p", hu);
cancel_work_sync(&intel->busy_work);
intel_set_power(hu, false);
skb_queue_purge(&intel->txq);
@ -237,11 +491,11 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed)
if (err && err != ETIMEDOUT)
return err;
BT_INFO("%s: Change controller speed to %d", hdev->name, speed);
bt_dev_info(hdev, "Change controller speed to %d", speed);
speed_cmd[3] = intel_convert_speed(speed);
if (speed_cmd[3] == 0xff) {
BT_ERR("%s: Unsupported speed", hdev->name);
bt_dev_err(hdev, "Unsupported speed");
return -EINVAL;
}
@ -250,16 +504,15 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed)
*/
skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reading Intel version information failed (%ld)",
hdev->name, PTR_ERR(skb));
bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL);
if (!skb) {
BT_ERR("%s: Failed to allocate memory for baudrate packet",
hdev->name);
bt_dev_err(hdev, "Failed to alloc memory for baudrate packet");
return -ENOMEM;
}
@ -284,11 +537,14 @@ static int intel_setup(struct hci_uart *hu)
{
static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
0x00, 0x08, 0x04, 0x00 };
static const u8 lpm_param[] = { 0x03, 0x07, 0x01, 0x0b };
struct intel_data *intel = hu->priv;
struct intel_device *idev = NULL;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
struct intel_version *ver;
struct intel_boot_params *params;
struct list_head *p;
const struct firmware *fw;
const u8 *fw_ptr;
char fwname[64];
@ -299,8 +555,9 @@ static int intel_setup(struct hci_uart *hu)
int speed_change = 0;
int err;
BT_DBG("%s", hdev->name);
bt_dev_dbg(hdev, "start intel_setup");
hu->hdev->set_diag = btintel_set_diag;
hu->hdev->set_bdaddr = btintel_set_bdaddr;
calltime = ktime_get();
@ -335,21 +592,21 @@ static int intel_setup(struct hci_uart *hu)
*/
skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reading Intel version information failed (%ld)",
hdev->name, PTR_ERR(skb));
bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: Intel version event size mismatch", hdev->name);
bt_dev_err(hdev, "Intel version event size mismatch");
kfree_skb(skb);
return -EILSEQ;
}
ver = (struct intel_version *)skb->data;
if (ver->status) {
BT_ERR("%s: Intel version command failure (%02x)",
hdev->name, ver->status);
bt_dev_err(hdev, "Intel version command failure (%02x)",
ver->status);
err = -bt_to_errno(ver->status);
kfree_skb(skb);
return err;
@ -359,8 +616,8 @@ static int intel_setup(struct hci_uart *hu)
* for now only accept this single value.
*/
if (ver->hw_platform != 0x37) {
BT_ERR("%s: Unsupported Intel hardware platform (%u)",
hdev->name, ver->hw_platform);
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
ver->hw_platform);
kfree_skb(skb);
return -EINVAL;
}
@ -371,8 +628,8 @@ static int intel_setup(struct hci_uart *hu)
* when newer hardware variants come along.
*/
if (ver->hw_variant != 0x0b) {
BT_ERR("%s: Unsupported Intel hardware variant (%u)",
hdev->name, ver->hw_variant);
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
ver->hw_variant);
kfree_skb(skb);
return -EINVAL;
}
@ -403,8 +660,8 @@ static int intel_setup(struct hci_uart *hu)
* choice is to return an error and abort the device initialization.
*/
if (ver->fw_variant != 0x06) {
BT_ERR("%s: Unsupported Intel firmware variant (%u)",
hdev->name, ver->fw_variant);
bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
ver->fw_variant);
kfree_skb(skb);
return -ENODEV;
}
@ -416,33 +673,33 @@ static int intel_setup(struct hci_uart *hu)
*/
skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reading Intel boot parameters failed (%ld)",
hdev->name, PTR_ERR(skb));
bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
if (skb->len != sizeof(*params)) {
BT_ERR("%s: Intel boot parameters size mismatch", hdev->name);
bt_dev_err(hdev, "Intel boot parameters size mismatch");
kfree_skb(skb);
return -EILSEQ;
}
params = (struct intel_boot_params *)skb->data;
if (params->status) {
BT_ERR("%s: Intel boot parameters command failure (%02x)",
hdev->name, params->status);
bt_dev_err(hdev, "Intel boot parameters command failure (%02x)",
params->status);
err = -bt_to_errno(params->status);
kfree_skb(skb);
return err;
}
BT_INFO("%s: Device revision is %u", hdev->name,
le16_to_cpu(params->dev_revid));
bt_dev_info(hdev, "Device revision is %u",
le16_to_cpu(params->dev_revid));
BT_INFO("%s: Secure boot is %s", hdev->name,
params->secure_boot ? "enabled" : "disabled");
bt_dev_info(hdev, "Secure boot is %s",
params->secure_boot ? "enabled" : "disabled");
BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
params->min_fw_build_nn, params->min_fw_build_cw,
2000 + params->min_fw_build_yy);
@ -451,8 +708,8 @@ static int intel_setup(struct hci_uart *hu)
* that this bootloader does not send them, then abort the setup.
*/
if (params->limited_cce != 0x00) {
BT_ERR("%s: Unsupported Intel firmware loading method (%u)",
hdev->name, params->limited_cce);
bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
params->limited_cce);
kfree_skb(skb);
return -EINVAL;
}
@ -461,7 +718,7 @@ static int intel_setup(struct hci_uart *hu)
* also be no valid address for the operational firmware.
*/
if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
BT_INFO("%s: No device address configured", hdev->name);
bt_dev_info(hdev, "No device address configured");
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
@ -476,19 +733,23 @@ static int intel_setup(struct hci_uart *hu)
err = request_firmware(&fw, fwname, &hdev->dev);
if (err < 0) {
BT_ERR("%s: Failed to load Intel firmware file (%d)",
hdev->name, err);
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)",
err);
kfree_skb(skb);
return err;
}
BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
bt_dev_info(hdev, "Found device firmware: %s", fwname);
/* Save the DDC file name for later */
snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
le16_to_cpu(params->dev_revid));
kfree_skb(skb);
if (fw->size < 644) {
BT_ERR("%s: Invalid size of firmware file (%zu)",
hdev->name, fw->size);
bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
fw->size);
err = -EBADF;
goto done;
}
@ -500,8 +761,7 @@ static int intel_setup(struct hci_uart *hu)
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data);
if (err < 0) {
BT_ERR("%s: Failed to send firmware header (%d)",
hdev->name, err);
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
goto done;
}
@ -510,8 +770,8 @@ static int intel_setup(struct hci_uart *hu)
*/
err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
if (err < 0) {
BT_ERR("%s: Failed to send firmware public key (%d)",
hdev->name, err);
bt_dev_err(hdev, "Failed to send firmware public key (%d)",
err);
goto done;
}
@ -520,8 +780,8 @@ static int intel_setup(struct hci_uart *hu)
*/
err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
if (err < 0) {
BT_ERR("%s: Failed to send firmware signature (%d)",
hdev->name, err);
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
err);
goto done;
}
@ -533,8 +793,8 @@ static int intel_setup(struct hci_uart *hu)
frag_len += sizeof(*cmd) + cmd->plen;
BT_DBG("%s: patching %td/%zu", hdev->name,
(fw_ptr - fw->data), fw->size);
bt_dev_dbg(hdev, "Patching %td/%zu", (fw_ptr - fw->data),
fw->size);
/* The parameter length of the secure send command requires
* a 4 byte alignment. It happens so that the firmware file
@ -552,8 +812,8 @@ static int intel_setup(struct hci_uart *hu)
*/
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
if (err < 0) {
BT_ERR("%s: Failed to send firmware data (%d)",
hdev->name, err);
bt_dev_err(hdev, "Failed to send firmware data (%d)",
err);
goto done;
}
@ -563,7 +823,7 @@ static int intel_setup(struct hci_uart *hu)
set_bit(STATE_FIRMWARE_LOADED, &intel->flags);
BT_INFO("%s: Waiting for firmware download to complete", hdev->name);
bt_dev_info(hdev, "Waiting for firmware download to complete");
/* Before switching the device into operational mode and with that
* booting the loaded firmware, wait for the bootloader notification
@ -580,19 +840,19 @@ static int intel_setup(struct hci_uart *hu)
TASK_INTERRUPTIBLE,
msecs_to_jiffies(5000));
if (err == 1) {
BT_ERR("%s: Firmware loading interrupted", hdev->name);
bt_dev_err(hdev, "Firmware loading interrupted");
err = -EINTR;
goto done;
}
if (err) {
BT_ERR("%s: Firmware loading timeout", hdev->name);
bt_dev_err(hdev, "Firmware loading timeout");
err = -ETIMEDOUT;
goto done;
}
if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) {
BT_ERR("%s: Firmware loading failed", hdev->name);
bt_dev_err(hdev, "Firmware loading failed");
err = -ENOEXEC;
goto done;
}
@ -601,7 +861,7 @@ static int intel_setup(struct hci_uart *hu)
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration);
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
done:
release_firmware(fw);
@ -634,7 +894,7 @@ done:
* 1 second. However if that happens, then just fail the setup
* since something went wrong.
*/
BT_INFO("%s: Waiting for device to boot", hdev->name);
bt_dev_info(hdev, "Waiting for device to boot");
err = intel_wait_booting(hu);
if (err)
@ -646,7 +906,39 @@ done:
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration);
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
/* Enable LPM if matching pdev with wakeup enabled */
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *dev = list_entry(p, struct intel_device,
list);
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
if (device_may_wakeup(&dev->pdev->dev))
idev = dev;
break;
}
}
mutex_unlock(&intel_device_list_lock);
if (!idev)
goto no_lpm;
bt_dev_info(hdev, "Enabling LPM");
skb = __hci_cmd_sync(hdev, 0xfc8b, sizeof(lpm_param), lpm_param,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to enable LPM");
goto no_lpm;
}
kfree_skb(skb);
set_bit(STATE_LPM_ENABLED, &intel->flags);
no_lpm:
/* Ignore errors, device can work without DDC parameters */
btintel_load_ddc_config(hdev, fwname);
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb))
@ -659,7 +951,7 @@ done:
return err;
}
BT_INFO("%s: Setup complete", hdev->name);
bt_dev_info(hdev, "Setup complete");
clear_bit(STATE_BOOTLOADER, &intel->flags);
@ -708,10 +1000,71 @@ recv:
return hci_recv_frame(hdev, skb);
}
static void intel_recv_lpm_notify(struct hci_dev *hdev, int value)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct intel_data *intel = hu->priv;
bt_dev_dbg(hdev, "TX idle notification (%d)", value);
if (value) {
set_bit(STATE_TX_ACTIVE, &intel->flags);
schedule_work(&intel->busy_work);
} else {
clear_bit(STATE_TX_ACTIVE, &intel->flags);
}
}
static int intel_recv_lpm(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_lpm_pkt *lpm = (void *)skb->data;
struct hci_uart *hu = hci_get_drvdata(hdev);
struct intel_data *intel = hu->priv;
switch (lpm->opcode) {
case LPM_OP_TX_NOTIFY:
if (lpm->dlen < 1) {
bt_dev_err(hu->hdev, "Invalid LPM notification packet");
break;
}
intel_recv_lpm_notify(hdev, lpm->data[0]);
break;
case LPM_OP_SUSPEND_ACK:
set_bit(STATE_SUSPENDED, &intel->flags);
if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) {
smp_mb__after_atomic();
wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION);
}
break;
case LPM_OP_RESUME_ACK:
clear_bit(STATE_SUSPENDED, &intel->flags);
if (test_and_clear_bit(STATE_LPM_TRANSACTION, &intel->flags)) {
smp_mb__after_atomic();
wake_up_bit(&intel->flags, STATE_LPM_TRANSACTION);
}
break;
default:
bt_dev_err(hdev, "Unknown LPM opcode (%02x)", lpm->opcode);
break;
}
kfree_skb(skb);
return 0;
}
#define INTEL_RECV_LPM \
.type = HCI_LPM_PKT, \
.hlen = HCI_LPM_HDR_SIZE, \
.loff = 1, \
.lsize = 1, \
.maxlen = HCI_LPM_MAX_SIZE
static const struct h4_recv_pkt intel_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = intel_recv_event },
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = intel_recv_event },
{ INTEL_RECV_LPM, .recv = intel_recv_lpm },
};
static int intel_recv(struct hci_uart *hu, const void *data, int count)
@ -726,7 +1079,7 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count)
ARRAY_SIZE(intel_recv_pkts));
if (IS_ERR(intel->rx_skb)) {
int err = PTR_ERR(intel->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
intel->rx_skb = NULL;
return err;
}
@ -737,9 +1090,27 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count)
static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct intel_data *intel = hu->priv;
struct list_head *p;
BT_DBG("hu %p skb %p", hu, skb);
/* Be sure our controller is resumed and potential LPM transaction
* completed before enqueuing any packet.
*/
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
list);
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
pm_runtime_get_sync(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
pm_runtime_put_autosuspend(&idev->pdev->dev);
break;
}
}
mutex_unlock(&intel_device_list_lock);
skb_queue_tail(&intel->txq, skb);
return 0;
@ -777,6 +1148,7 @@ static struct sk_buff *intel_dequeue(struct hci_uart *hu)
static const struct hci_uart_proto intel_proto = {
.id = HCI_UART_INTEL,
.name = "Intel",
.manufacturer = 2,
.init_speed = 115200,
.oper_speed = 3000000,
.open = intel_open,
@ -795,24 +1167,61 @@ static const struct acpi_device_id intel_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
#endif
static int intel_acpi_probe(struct intel_device *idev)
#ifdef CONFIG_PM
static int intel_suspend_device(struct device *dev)
{
const struct acpi_device_id *id;
struct intel_device *idev = dev_get_drvdata(dev);
id = acpi_match_device(intel_acpi_match, &idev->pdev->dev);
if (!id)
return -ENODEV;
mutex_lock(&idev->hu_lock);
if (idev->hu)
intel_lpm_suspend(idev->hu);
mutex_unlock(&idev->hu_lock);
return 0;
}
#else
static int intel_acpi_probe(struct intel_device *idev)
static int intel_resume_device(struct device *dev)
{
return -ENODEV;
struct intel_device *idev = dev_get_drvdata(dev);
mutex_lock(&idev->hu_lock);
if (idev->hu)
intel_lpm_resume(idev->hu);
mutex_unlock(&idev->hu_lock);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int intel_suspend(struct device *dev)
{
struct intel_device *idev = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(idev->irq);
return intel_suspend_device(dev);
}
static int intel_resume(struct device *dev)
{
struct intel_device *idev = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(idev->irq);
return intel_resume_device(dev);
}
#endif
static const struct dev_pm_ops intel_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
SET_RUNTIME_PM_OPS(intel_suspend_device, intel_resume_device, NULL)
};
static int intel_probe(struct platform_device *pdev)
{
struct intel_device *idev;
@ -821,15 +1230,9 @@ static int intel_probe(struct platform_device *pdev)
if (!idev)
return -ENOMEM;
idev->pdev = pdev;
mutex_init(&idev->hu_lock);
if (ACPI_HANDLE(&pdev->dev)) {
int err = intel_acpi_probe(idev);
if (err)
return err;
} else {
return -ENODEV;
}
idev->pdev = pdev;
idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
GPIOD_OUT_LOW);
@ -838,14 +1241,40 @@ static int intel_probe(struct platform_device *pdev)
return PTR_ERR(idev->reset);
}
idev->irq = platform_get_irq(pdev, 0);
if (idev->irq < 0) {
struct gpio_desc *host_wake;
dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
GPIOD_IN);
if (IS_ERR(host_wake)) {
dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
goto no_irq;
}
idev->irq = gpiod_to_irq(host_wake);
if (idev->irq < 0) {
dev_err(&pdev->dev, "No corresponding irq for gpio\n");
goto no_irq;
}
}
/* Only enable wake-up/irq when controller is powered */
device_set_wakeup_capable(&pdev->dev, true);
device_wakeup_disable(&pdev->dev);
no_irq:
platform_set_drvdata(pdev, idev);
/* Place this instance on the device list */
spin_lock(&intel_device_list_lock);
mutex_lock(&intel_device_list_lock);
list_add_tail(&idev->list, &intel_device_list);
spin_unlock(&intel_device_list_lock);
mutex_unlock(&intel_device_list_lock);
dev_info(&pdev->dev, "registered.\n");
dev_info(&pdev->dev, "registered, gpio(%d)/irq(%d).\n",
desc_to_gpio(idev->reset), idev->irq);
return 0;
}
@ -854,9 +1283,11 @@ static int intel_remove(struct platform_device *pdev)
{
struct intel_device *idev = platform_get_drvdata(pdev);
spin_lock(&intel_device_list_lock);
device_wakeup_disable(&pdev->dev);
mutex_lock(&intel_device_list_lock);
list_del(&idev->list);
spin_unlock(&intel_device_list_lock);
mutex_unlock(&intel_device_list_lock);
dev_info(&pdev->dev, "unregistered.\n");
@ -869,6 +1300,7 @@ static struct platform_driver intel_driver = {
.driver = {
.name = "hci_intel",
.acpi_match_table = ACPI_PTR(intel_acpi_match),
.pm = &intel_pm_ops,
},
};

View file

@ -208,9 +208,6 @@ static int hci_uart_open(struct hci_dev *hdev)
BT_DBG("%s %p", hdev->name, hdev);
/* Nothing to do for UART driver */
set_bit(HCI_RUNNING, &hdev->flags);
return 0;
}
@ -241,9 +238,6 @@ static int hci_uart_close(struct hci_dev *hdev)
{
BT_DBG("hdev %p", hdev);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
hci_uart_flush(hdev);
hdev->flush = NULL;
return 0;
@ -254,9 +248,6 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
hu->proto->enqueue(hu, skb);
@ -470,8 +461,6 @@ static int hci_uart_tty_open(struct tty_struct *tty)
INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work);
spin_lock_init(&hu->rx_lock);
/* Flush any pending characters in the driver and line discipline. */
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
@ -569,14 +558,14 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
return;
spin_lock(&hu->rx_lock);
/* It does not need a lock here as it is already protected by a mutex in
* tty caller
*/
hu->proto->recv(hu, data, count);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
tty_unthrottle(tty);
}
@ -598,6 +587,13 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->bus = HCI_UART;
hci_set_drvdata(hdev, hu);
/* Only when vendor specific setup callback is provided, consider
* the manufacturer information valid. This avoids filling in the
* value for Ericsson when nothing is specified.
*/
if (hu->proto->setup)
hdev->manufacturer = hu->proto->manufacturer;
hdev->open = hci_uart_open;
hdev->close = hci_uart_close;
hdev->flush = hci_uart_flush;

View file

@ -41,13 +41,13 @@
#define HCI_IBS_SLEEP_IND 0xFE
#define HCI_IBS_WAKE_IND 0xFD
#define HCI_IBS_WAKE_ACK 0xFC
#define HCI_MAX_IBS_SIZE 10
#define HCI_MAX_IBS_SIZE 10
/* Controller states */
#define STATE_IN_BAND_SLEEP_ENABLED 1
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
#define IBS_TX_IDLE_TIMEOUT_MS 2000
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
#define IBS_TX_IDLE_TIMEOUT_MS 2000
#define BAUDRATE_SETTLE_TIMEOUT_MS 300
/* HCI_IBS transmit side sleep protocol states */
@ -181,8 +181,8 @@ static void serial_clock_vote(unsigned long vote, struct hci_uart *hu)
else
__serial_clock_off(hu->tty);
BT_DBG("Vote serial clock %s(%s)", new_vote? "true" : "false",
vote? "true" : "false");
BT_DBG("Vote serial clock %s(%s)", new_vote ? "true" : "false",
vote ? "true" : "false");
diff = jiffies_to_msecs(jiffies - qca->vote_last_jif);
@ -347,7 +347,7 @@ static void hci_ibs_wake_retrans_timeout(unsigned long arg)
struct hci_uart *hu = (struct hci_uart *)arg;
struct qca_data *qca = hu->priv;
unsigned long flags, retrans_delay;
unsigned long retransmit = 0;
bool retransmit = false;
BT_DBG("hu %p wake retransmit timeout in %d state",
hu, qca->tx_ibs_state);
@ -358,7 +358,7 @@ static void hci_ibs_wake_retrans_timeout(unsigned long arg)
switch (qca->tx_ibs_state) {
case HCI_IBS_TX_WAKING:
/* No WAKE_ACK, retransmit WAKE */
retransmit = 1;
retransmit = true;
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
BT_ERR("Failed to acknowledge device wake up");
break;
@ -821,7 +821,7 @@ static struct sk_buff *qca_dequeue(struct hci_uart *hu)
static uint8_t qca_get_baudrate_value(int speed)
{
switch(speed) {
switch (speed) {
case 9600:
return QCA_BAUDRATE_9600;
case 19200:
@ -947,6 +947,7 @@ static int qca_setup(struct hci_uart *hu)
static struct hci_uart_proto qca_proto = {
.id = HCI_UART_QCA,
.name = "QCA",
.manufacturer = 29,
.init_speed = 115200,
.oper_speed = 3000000,
.open = qca_open,

View file

@ -59,6 +59,7 @@ struct hci_uart;
struct hci_uart_proto {
unsigned int id;
const char *name;
unsigned int manufacturer;
unsigned int init_speed;
unsigned int oper_speed;
int (*open)(struct hci_uart *hu);
@ -85,7 +86,6 @@ struct hci_uart {
struct sk_buff *tx_skb;
unsigned long tx_state;
spinlock_t rx_lock;
unsigned int init_speed;
unsigned int oper_speed;

View file

@ -55,8 +55,6 @@ struct vhci_data {
static int vhci_open_dev(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &hdev->flags);
return 0;
}
@ -64,9 +62,6 @@ static int vhci_close_dev(struct hci_dev *hdev)
{
struct vhci_data *data = hci_get_drvdata(hdev);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
skb_queue_purge(&data->readq);
return 0;
@ -85,9 +80,6 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct vhci_data *data = hci_get_drvdata(hdev);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&data->readq, skb);

View file

@ -1325,9 +1325,6 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
"%u.%u", nesadapter->firmware_version >> 16,
nesadapter->firmware_version & 0x000000ff);
strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
drvinfo->regdump_len = 0;
}

View file

@ -56,9 +56,6 @@
#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5)
#define ARMADA_370_XP_FABRIC_IRQ (3)
#define IPI_DOORBELL_START (0)
#define IPI_DOORBELL_END (8)
#define IPI_DOORBELL_MASK 0xFF
@ -81,13 +78,10 @@ static phys_addr_t msi_doorbell_addr;
static inline bool is_percpu_irq(irq_hw_number_t irq)
{
switch (irq) {
case ARMADA_370_XP_TIMER0_PER_CPU_IRQ:
case ARMADA_370_XP_FABRIC_IRQ:
if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS)
return true;
default:
return false;
}
return false;
}
/*
@ -550,7 +544,7 @@ static void armada_370_xp_mpic_resume(void)
if (virq == 0)
continue;
if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
if (!is_percpu_irq(irq))
writel(irq, per_cpu_int_base +
ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
else

View file

@ -646,14 +646,14 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
f1 = Read_hfc8_stable(l1p->hw, A_F1);
f2 = Read_hfc8(l1p->hw, A_F2);
df = f1 - f2;
if ((f1 - f2) < 0)
df = f1 - f2 + MAX_F_CNT + 1;
if (f1 < f2)
df = MAX_F_CNT + 1 + f1 - f2;
else
df = f1 - f2;
if (!df) {
if (!df)
return; /* no complete frame in fifo */
}
z1 = Read_hfc16_stable(l1p->hw, A_Z1);
z2 = Read_hfc16(l1p->hw, A_Z2);

View file

@ -301,6 +301,8 @@ isdn_ppp_open(int min, struct file *file)
is->compflags = 0;
is->reset = isdn_ppp_ccp_reset_alloc(is);
if (!is->reset)
return -ENOMEM;
is->lp = NULL;
is->mp_seqno = 0; /* MP sequence number */
@ -320,6 +322,10 @@ isdn_ppp_open(int min, struct file *file)
* VJ header compression init
*/
is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
if (IS_ERR(is->slcomp)) {
isdn_ppp_ccp_reset_free(is);
return PTR_ERR(is->slcomp);
}
#endif
#ifdef CONFIG_IPPP_FILTER
is->pass_filter = NULL;
@ -567,10 +573,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
is->maxcid = val;
#ifdef CONFIG_ISDN_PPP_VJ
sltmp = slhc_init(16, val);
if (!sltmp) {
printk(KERN_ERR "ippp, can't realloc slhc struct\n");
return -ENOMEM;
}
if (IS_ERR(sltmp))
return PTR_ERR(sltmp);
if (is->slcomp)
slhc_free(is->slcomp);
is->slcomp = sltmp;

View file

@ -235,7 +235,7 @@ void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
{
int len, incomplete = 0, found = 0;
int incomplete = 0, found = 0;
char *dup, *tok, *name, *args;
struct dsp_element_entry *entry, *n;
struct dsp_pipeline_entry *pipeline_entry;
@ -247,17 +247,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
if (!list_empty(&pipeline->list))
_dsp_pipeline_destroy(pipeline);
if (!cfg)
return 0;
len = strlen(cfg);
if (!len)
return 0;
dup = kmalloc(len + 1, GFP_ATOMIC);
dup = kstrdup(cfg, GFP_ATOMIC);
if (!dup)
return 0;
strcpy(dup, cfg);
while ((tok = strsep(&dup, "|"))) {
if (!strlen(tok))
continue;

View file

@ -298,7 +298,10 @@ config NLMON
config NET_VRF
tristate "Virtual Routing and Forwarding (Lite)"
depends on IP_MULTIPLE_TABLES && IPV6_MULTIPLE_TABLES
depends on IP_MULTIPLE_TABLES
depends on NET_L3_MASTER_DEV
depends on IPV6 || IPV6=n
depends on IPV6_MULTIPLE_TABLES || IPV6=n
---help---
This option enables the support for mapping interfaces into VRF's. The
support enables VRF devices.

View file

@ -103,6 +103,7 @@ config ARCNET_RIM_I
config ARCNET_COM20020
tristate "ARCnet COM20020 chipset driver"
depends on LEDS_CLASS
help
This is the driver for the new COM20020 chipset. It supports such
things as promiscuous mode, so packet sniffing is possible, and

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - "raw mode" packet encapsulation (no soft headers)
*
*
* Written 1994-1999 by Avery Pennarun.
* Derived from skeleton.c by Donald Becker.
*
@ -24,6 +24,8 @@
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/init.h>
@ -31,20 +33,124 @@
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: raw mode (`r') encapsulation support loaded.\n"
#include "arcdevice.h"
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int build_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, uint8_t daddr);
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum);
static struct ArcProto rawmode_proto =
struct archdr *pkthdr, int length)
{
struct arcnet_local *lp = netdev_priv(dev);
struct sk_buff *skb;
struct archdr *pkt = pkthdr;
int ofs;
arc_printk(D_DURING, dev, "it's a raw packet (length=%d)\n", length);
if (length > MTU)
ofs = 512 - length;
else
ofs = 256 - length;
skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (!skb) {
dev->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE);
skb->dev = dev;
pkt = (struct archdr *)skb->data;
skb_reset_mac_header(skb);
skb_pull(skb, ARC_HDR_SIZE);
/* up to sizeof(pkt->soft) has already been copied from the card */
memcpy(pkt, pkthdr, sizeof(struct archdr));
if (length > sizeof(pkt->soft))
lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
pkt->soft.raw + sizeof(pkt->soft),
length - sizeof(pkt->soft));
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, skb, "rx");
skb->protocol = cpu_to_be16(ETH_P_ARCNET);
netif_rx(skb);
}
/* Create the ARCnet hard/soft headers for raw mode.
* There aren't any soft headers in raw mode - not even the protocol id.
*/
static int build_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, uint8_t daddr)
{
int hdr_size = ARC_HDR_SIZE;
struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size);
/* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. ARCnet does not allow us to change the source address
* in the actual packet sent.
*/
pkt->hard.source = *dev->dev_addr;
/* see linux/net/ethernet/eth.c to see where I got the following */
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
/* FIXME: fill in the last byte of the dest ipaddr here
* to better comply with RFC1051 in "noarp" mode.
*/
pkt->hard.dest = 0;
return hdr_size;
}
/* otherwise, just fill it in and go! */
pkt->hard.dest = daddr;
return hdr_size; /* success */
}
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum)
{
struct arcnet_local *lp = netdev_priv(dev);
struct arc_hardware *hard = &pkt->hard;
int ofs;
arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
/* hard header is not included in packet length */
length -= ARC_HDR_SIZE;
if (length > XMTU) {
/* should never happen! other people already check for this. */
arc_printk(D_NORMAL, dev, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
length = XMTU;
}
if (length >= MinTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length;
} else if (length > MTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length - 3;
} else {
hard->offset[0] = ofs = 256 - length;
}
arc_printk(D_DURING, dev, "prepare_tx: length=%d ofs=%d\n",
length, ofs);
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);
lp->lastload_dest = hard->dest;
return 1; /* done */
}
static struct ArcProto rawmode_proto = {
.suffix = 'r',
.mtu = XMTU,
.rx = rx,
@ -54,12 +160,11 @@ static struct ArcProto rawmode_proto =
.ack_tx = NULL
};
static int __init arcnet_raw_init(void)
{
int count;
printk(VERSION);
pr_info("raw mode (`r') encapsulation support loaded\n");
for (count = 0; count < 256; count++)
if (arc_proto_map[count] == arc_proto_default)
@ -82,122 +187,3 @@ module_init(arcnet_raw_init);
module_exit(arcnet_raw_exit);
MODULE_LICENSE("GPL");
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
{
struct arcnet_local *lp = netdev_priv(dev);
struct sk_buff *skb;
struct archdr *pkt = pkthdr;
int ofs;
BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length);
if (length > MTU)
ofs = 512 - length;
else
ofs = 256 - length;
skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
dev->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE);
skb->dev = dev;
pkt = (struct archdr *) skb->data;
skb_reset_mac_header(skb);
skb_pull(skb, ARC_HDR_SIZE);
/* up to sizeof(pkt->soft) has already been copied from the card */
memcpy(pkt, pkthdr, sizeof(struct archdr));
if (length > sizeof(pkt->soft))
lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
pkt->soft.raw + sizeof(pkt->soft),
length - sizeof(pkt->soft));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
skb->protocol = cpu_to_be16(ETH_P_ARCNET);
netif_rx(skb);
}
/*
* Create the ARCnet hard/soft headers for raw mode.
* There aren't any soft headers in raw mode - not even the protocol id.
*/
static int build_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, uint8_t daddr)
{
int hdr_size = ARC_HDR_SIZE;
struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
/*
* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. ARCnet does not allow us to change the source address in
* the actual packet sent)
*/
pkt->hard.source = *dev->dev_addr;
/* see linux/net/ethernet/eth.c to see where I got the following */
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
/*
* FIXME: fill in the last byte of the dest ipaddr here to better
* comply with RFC1051 in "noarp" mode.
*/
pkt->hard.dest = 0;
return hdr_size;
}
/* otherwise, just fill it in and go! */
pkt->hard.dest = daddr;
return hdr_size; /* success */
}
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum)
{
struct arcnet_local *lp = netdev_priv(dev);
struct arc_hardware *hard = &pkt->hard;
int ofs;
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
length = XMTU;
}
if (length >= MinTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length;
} else if (length > MTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length - 3;
} else
hard->offset[0] = ofs = 256 - length;
BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n",
length,ofs);
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);
lp->lastload_dest = hard->dest;
return 1; /* done */
}

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
*
*
* Written 1994-1999 by Avery Pennarun.
* Written 1999-2000 by Martin Mares <mj@ucw.cz>.
* Derived from skeleton.c by Donald Becker.
@ -24,6 +24,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@ -33,12 +36,10 @@
#include <linux/bootmem.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: RIM I (entirely mem-mapped) support\n"
#include <linux/io.h>
#include "arcdevice.h"
#include "com9026.h"
/* Internal function declarations */
@ -50,66 +51,46 @@ static void arcrimi_setmask(struct net_device *dev, int mask);
static int arcrimi_reset(struct net_device *dev, int really_reset);
static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void arcrimi_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
/* Handy defines for ARCnet specific stuff */
/* Amount of I/O memory used by the card */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE * 4)
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#define _CONFIG (ioaddr+2) /* Configuration register */
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() readb(_STATUS)
#define ACOMMAND(cmd) writeb((cmd),_COMMAND)
#define AINTMASK(msk) writeb((msk),_INTMASK)
#define SETCONF() writeb(lp->config,_CONFIG)
/*
* We cannot probe for a RIM I card; one reason is I don't know how to reset
/* We cannot probe for a RIM I card; one reason is I don't know how to reset
* them. In fact, we can't even get their node ID automatically. So, we
* need to be passed a specific shmem address, IRQ, and node ID.
*/
static int __init arcrimi_probe(struct net_device *dev)
{
BUGLVL(D_NORMAL) printk(VERSION);
BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n");
BUGLVL(D_NORMAL) printk("Given: node %02Xh, shmem %lXh, irq %d\n",
dev->dev_addr[0], dev->mem_start, dev->irq);
if (BUGLVL(D_NORMAL)) {
pr_info("%s\n", "RIM I (entirely mem-mapped) support");
pr_info("E-mail me if you actually test the RIM I driver, please!\n");
pr_info("Given: node %02Xh, shmem %lXh, irq %d\n",
dev->dev_addr[0], dev->mem_start, dev->irq);
}
if (dev->mem_start <= 0 || dev->irq <= 0) {
BUGLVL(D_NORMAL) printk("No autoprobe for RIM I; you "
"must specify the shmem and irq!\n");
if (BUGLVL(D_NORMAL))
pr_err("No autoprobe for RIM I; you must specify the shmem and irq!\n");
return -ENODEV;
}
if (dev->dev_addr[0] == 0) {
BUGLVL(D_NORMAL) printk("You need to specify your card's station "
"ID!\n");
if (BUGLVL(D_NORMAL))
pr_err("You need to specify your card's station ID!\n");
return -ENODEV;
}
/*
* Grab the memory region at mem_start for MIRROR_SIZE bytes.
/* Grab the memory region at mem_start for MIRROR_SIZE bytes.
* Later in arcrimi_found() the real size will be determined
* and this reserve will be released and the correct size
* will be taken.
*/
if (!request_mem_region(dev->mem_start, MIRROR_SIZE, "arcnet (90xx)")) {
BUGLVL(D_NORMAL) printk("Card memory already allocated\n");
if (BUGLVL(D_NORMAL))
pr_notice("Card memory already allocated\n");
return -ENODEV;
}
return arcrimi_found(dev);
@ -125,7 +106,7 @@ static int check_mirror(unsigned long addr, size_t size)
p = ioremap(addr, size);
if (p) {
if (readb(p) == TESTvalue)
if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
res = 1;
else
res = 0;
@ -136,9 +117,8 @@ static int check_mirror(unsigned long addr, size_t size)
return res;
}
/*
* Set up the struct net_device associated with this card. Called after
* probing succeeds.
/* Set up the struct net_device associated with this card.
* Called after probing succeeds.
*/
static int __init arcrimi_found(struct net_device *dev)
{
@ -151,7 +131,7 @@ static int __init arcrimi_found(struct net_device *dev)
p = ioremap(dev->mem_start, MIRROR_SIZE);
if (!p) {
release_mem_region(dev->mem_start, MIRROR_SIZE);
BUGMSG(D_NORMAL, "Can't ioremap\n");
arc_printk(D_NORMAL, dev, "Can't ioremap\n");
return -ENODEV;
}
@ -159,13 +139,14 @@ static int __init arcrimi_found(struct net_device *dev)
if (request_irq(dev->irq, arcnet_interrupt, 0, "arcnet (RIM I)", dev)) {
iounmap(p);
release_mem_region(dev->mem_start, MIRROR_SIZE);
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
shmem = dev->mem_start;
writeb(TESTvalue, p);
writeb(dev->dev_addr[0], p + 1); /* actually the node ID */
arcnet_writeb(TESTvalue, p, COM9026_REG_W_INTMASK);
arcnet_writeb(TESTvalue, p, COM9026_REG_W_COMMAND);
/* actually the station/node ID */
/* find the real shared memory start/end points, including mirrors */
@ -174,7 +155,7 @@ static int __init arcrimi_found(struct net_device *dev)
* 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size = MIRROR_SIZE;
if (readb(p) == TESTvalue &&
if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
mirror_size = 2 * MIRROR_SIZE;
@ -204,8 +185,7 @@ static int __init arcrimi_found(struct net_device *dev)
lp->hw.copy_to_card = arcrimi_copy_to_card;
lp->hw.copy_from_card = arcrimi_copy_from_card;
/*
* re-reserve the memory region - arcrimi_probe() alloced this reqion
/* re-reserve the memory region - arcrimi_probe() alloced this reqion
* but didn't know the real size. Free that region and then re-get
* with the correct size. There is a VERY slim chance this could
* fail.
@ -215,24 +195,25 @@ static int __init arcrimi_found(struct net_device *dev)
if (!request_mem_region(dev->mem_start,
dev->mem_end - dev->mem_start + 1,
"arcnet (90xx)")) {
BUGMSG(D_NORMAL, "Card memory already allocated\n");
arc_printk(D_NORMAL, dev, "Card memory already allocated\n");
goto err_free_irq;
}
lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1);
lp->mem_start = ioremap(dev->mem_start,
dev->mem_end - dev->mem_start + 1);
if (!lp->mem_start) {
BUGMSG(D_NORMAL, "Can't remap device memory!\n");
arc_printk(D_NORMAL, dev, "Can't remap device memory!\n");
goto err_release_mem;
}
/* get and check the station ID from offset 1 in shmem */
dev->dev_addr[0] = readb(lp->mem_start + 1);
dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION);
BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, "
"ShMem %lXh (%ld*%d bytes).\n",
dev->dev_addr[0],
dev->irq, dev->mem_start,
(dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size);
arc_printk(D_NORMAL, dev, "ARCnet RIM I: station %02Xh found at IRQ %d, ShMem %lXh (%ld*%d bytes)\n",
dev->dev_addr[0],
dev->irq, dev->mem_start,
(dev->mem_end - dev->mem_start + 1) / mirror_size,
mirror_size);
err = register_netdev(dev);
if (err)
@ -249,9 +230,7 @@ err_free_irq:
return -EIO;
}
/*
* Do a hardware reset on the card, and set up necessary registers.
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
@ -263,17 +242,19 @@ static int arcrimi_reset(struct net_device *dev, int really_reset)
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->mem_start + 0x800;
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
dev->name, arcnet_readb(ioaddr, COM9026_REG_R_STATUS));
if (really_reset) {
writeb(TESTvalue, ioaddr - 0x800); /* fake reset */
arcnet_writeb(TESTvalue, ioaddr, -0x800); /* fake reset */
return 0;
}
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* clear flags & end reset */
arcnet_writeb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
arcnet_writeb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
arcnet_writeb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
/* done! return success. */
return 0;
@ -284,7 +265,7 @@ static void arcrimi_setmask(struct net_device *dev, int mask)
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->mem_start + 0x800;
AINTMASK(mask);
arcnet_writeb(mask, ioaddr, COM9026_REG_W_INTMASK);
}
static int arcrimi_status(struct net_device *dev)
@ -292,7 +273,7 @@ static int arcrimi_status(struct net_device *dev)
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->mem_start + 0x800;
return ASTATUS();
return arcnet_readb(ioaddr, COM9026_REG_R_STATUS);
}
static void arcrimi_command(struct net_device *dev, int cmd)
@ -300,7 +281,7 @@ static void arcrimi_command(struct net_device *dev, int cmd)
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->mem_start + 0x800;
ACOMMAND(cmd);
arcnet_writeb(cmd, ioaddr, COM9026_REG_W_COMMAND);
}
static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
@ -308,16 +289,17 @@ static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset,
{
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
}
static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
static void arcrimi_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset;
TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
static int node;
@ -374,12 +356,13 @@ static void __exit arc_rimi_exit(void)
static int __init arcrimi_setup(char *s)
{
int ints[8];
s = get_options(s, 8, ints);
if (!ints[0])
return 1;
switch (ints[0]) {
default: /* ERROR */
printk("arcrimi: Too many arguments.\n");
pr_err("Too many arguments\n");
case 3: /* Node ID */
node = ints[3];
case 2: /* IRQ */

View file

@ -34,7 +34,6 @@
*/
#define RECON_THRESHOLD 30
/*
* Define this to the minimum "timeout" value. If a transmit takes longer
* than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large
@ -44,14 +43,12 @@
*/
#define TX_TIMEOUT (HZ * 200 / 1000)
/* Display warnings about the driver being an ALPHA version. */
#undef ALPHA_WARNING
/*
* Debugging bitflags: each option can be enabled individually.
*
*
* Note: only debug flags included in the ARCNET_DEBUG_MAX define will
* actually be available. GCC will (at least, GCC 2.7.0 will) notice
* lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
@ -77,35 +74,47 @@
#endif
#ifndef ARCNET_DEBUG
#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
#define ARCNET_DEBUG (D_NORMAL | D_EXTRA)
#endif
extern int arcnet_debug;
#define BUGLVL(x) ((x) & ARCNET_DEBUG_MAX & arcnet_debug)
/* macros to simplify debug checking */
#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
#define BUGMSG2(x,msg,args...) do { BUGLVL(x) printk(msg, ## args); } while (0)
#define BUGMSG(x,msg,args...) \
BUGMSG2(x, "%s%6s: " msg, \
x==D_NORMAL ? KERN_WARNING \
: x < D_DURING ? KERN_INFO : KERN_DEBUG, \
dev->name , ## args)
#define arc_printk(x, dev, fmt, ...) \
do { \
if (BUGLVL(x)) { \
if ((x) == D_NORMAL) \
netdev_warn(dev, fmt, ##__VA_ARGS__); \
else if ((x) < D_DURING) \
netdev_info(dev, fmt, ##__VA_ARGS__); \
else \
netdev_dbg(dev, fmt, ##__VA_ARGS__); \
} \
} while (0)
#define arc_cont(x, fmt, ...) \
do { \
if (BUGLVL(x)) \
pr_cont(fmt, ##__VA_ARGS__); \
} while (0)
/* see how long a function call takes to run, expressed in CPU cycles */
#define TIME(name, bytes, call) BUGLVL(D_TIMING) { \
unsigned long _x, _y; \
_x = get_cycles(); \
call; \
_y = get_cycles(); \
BUGMSG(D_TIMING, \
"%s: %d bytes in %lu cycles == " \
"%lu Kbytes/100Mcycle\n",\
name, bytes, _y - _x, \
100000000 / 1024 * bytes / (_y - _x + 1));\
} \
else { \
call;\
}
#define TIME(dev, name, bytes, call) \
do { \
if (BUGLVL(D_TIMING)) { \
unsigned long _x, _y; \
_x = get_cycles(); \
call; \
_y = get_cycles(); \
arc_printk(D_TIMING, dev, \
"%s: %d bytes in %lu cycles == %lu Kbytes/100Mcycle\n", \
name, bytes, _y - _x, \
100000000 / 1024 * bytes / (_y - _x + 1)); \
} else { \
call; \
} \
} while (0)
/*
* Time needed to reset the card - in ms (milliseconds). This works on my
@ -155,6 +164,7 @@ extern int arcnet_debug;
#define CONFIGcmd 0x05 /* define configuration */
#define CFLAGScmd 0x06 /* clear flags */
#define TESTcmd 0x07 /* load test flags */
#define STARTIOcmd 0x18 /* start internal operation */
/* flags for "clear flags" command */
#define RESETclear 0x08 /* power-on-reset */
@ -182,29 +192,27 @@ extern int arcnet_debug;
#define ARC_CAN_10MBIT 2 /* card uses COM20022, supporting 10MBit,
but default is 2.5MBit. */
/* information needed to define an encapsulation driver */
struct ArcProto {
char suffix; /* a for RFC1201, e for ether-encap, etc. */
int mtu; /* largest possible packet */
int is_ip; /* This is a ip plugin - not a raw thing */
void (*rx) (struct net_device * dev, int bufnum,
struct archdr * pkthdr, int length);
int (*build_header) (struct sk_buff * skb, struct net_device *dev,
unsigned short ethproto, uint8_t daddr);
void (*rx)(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
int (*build_header)(struct sk_buff *skb, struct net_device *dev,
unsigned short ethproto, uint8_t daddr);
/* these functions return '1' if the skb can now be freed */
int (*prepare_tx) (struct net_device * dev, struct archdr * pkt, int length,
int bufnum);
int (*continue_tx) (struct net_device * dev, int bufnum);
int (*ack_tx) (struct net_device * dev, int acked);
int (*prepare_tx)(struct net_device *dev, struct archdr *pkt,
int length, int bufnum);
int (*continue_tx)(struct net_device *dev, int bufnum);
int (*ack_tx)(struct net_device *dev, int acked);
};
extern struct ArcProto *arc_proto_map[256], *arc_proto_default,
*arc_bcast_proto, *arc_raw_proto;
/*
* "Incoming" is information needed for each address that could be sending
* to us. Mostly for partially-received split packets.
@ -216,7 +224,6 @@ struct Incoming {
numpackets; /* number of packets in split */
};
/* only needed for RFC1201 */
struct Outgoing {
struct ArcProto *proto; /* protocol driver that owns this:
@ -230,6 +237,7 @@ struct Outgoing {
numsegs; /* number of segments */
};
#define ARCNET_LED_NAME_SZ (IFNAMSIZ + 6)
struct arcnet_local {
uint8_t config, /* current value of CONFIG register */
@ -251,10 +259,16 @@ struct arcnet_local {
char *card_name; /* card ident string */
int card_flags; /* special card features */
/* On preemtive and SMB a lock is needed */
spinlock_t lock;
struct led_trigger *tx_led_trig;
char tx_led_trig_name[ARCNET_LED_NAME_SZ];
struct led_trigger *recon_led_trig;
char recon_led_trig_name[ARCNET_LED_NAME_SZ];
struct timer_list timer;
/*
* Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
* which can be used for either sending or receiving. The new dynamic
@ -263,13 +277,13 @@ struct arcnet_local {
* situations in which we (for example) want to pre-load a transmit
* buffer, or start receiving while we copy a received packet to
* memory.
*
*
* The rules: only the interrupt handler is allowed to _add_ buffers to
* the queue; thus, this doesn't require a lock. Both the interrupt
* handler and the transmit function will want to _remove_ buffers, so
* we need to handle the situation where they try to do it at the same
* time.
*
*
* If next_buf == first_free_buf, the queue is empty. Since there are
* only four possible buffers, the queue should never be full.
*/
@ -298,34 +312,41 @@ struct arcnet_local {
/* hardware-specific functions */
struct {
struct module *owner;
void (*command) (struct net_device * dev, int cmd);
int (*status) (struct net_device * dev);
void (*intmask) (struct net_device * dev, int mask);
int (*reset) (struct net_device * dev, int really_reset);
void (*open) (struct net_device * dev);
void (*close) (struct net_device * dev);
void (*command)(struct net_device *dev, int cmd);
int (*status)(struct net_device *dev);
void (*intmask)(struct net_device *dev, int mask);
int (*reset)(struct net_device *dev, int really_reset);
void (*open)(struct net_device *dev);
void (*close)(struct net_device *dev);
void (*datatrigger) (struct net_device * dev, int enable);
void (*recontrigger) (struct net_device * dev, int enable);
void (*copy_to_card) (struct net_device * dev, int bufnum, int offset,
void *buf, int count);
void (*copy_from_card) (struct net_device * dev, int bufnum, int offset,
void *buf, int count);
void (*copy_to_card)(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
void (*copy_from_card)(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
} hw;
void __iomem *mem_start; /* pointer to ioremap'ed MMIO */
};
enum arcnet_led_event {
ARCNET_LED_EVENT_RECON,
ARCNET_LED_EVENT_OPEN,
ARCNET_LED_EVENT_STOP,
ARCNET_LED_EVENT_TX,
};
#define ARCRESET(x) (lp->hw.reset(dev, (x)))
#define ACOMMAND(x) (lp->hw.command(dev, (x)))
#define ASTATUS() (lp->hw.status(dev))
#define AINTMASK(x) (lp->hw.intmask(dev, (x)))
void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event);
void devm_arcnet_led_init(struct net_device *netdev, int index, int subid);
#if ARCNET_DEBUG_MAX & D_SKB
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
#else
#define arcnet_dump_skb(dev,skb,desc) ;
static inline
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
{
}
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
@ -335,8 +356,34 @@ struct net_device *alloc_arcdev(const char *name);
int arcnet_open(struct net_device *dev);
int arcnet_close(struct net_device *dev);
netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
struct net_device *dev);
struct net_device *dev);
void arcnet_timeout(struct net_device *dev);
/* I/O equivalents */
#ifdef CONFIG_SA1100_CT6001
#define BUS_ALIGN 2 /* 8 bit device on a 16 bit bus - needs padding */
#else
#define BUS_ALIGN 1
#endif
/* addr and offset allow register like names to define the actual IO address.
* A configuration option multiplies the offset for alignment.
*/
#define arcnet_inb(addr, offset) \
inb((addr) + BUS_ALIGN * (offset))
#define arcnet_outb(value, addr, offset) \
outb(value, (addr) + BUS_ALIGN * (offset))
#define arcnet_insb(addr, offset, buffer, count) \
insb((addr) + BUS_ALIGN * (offset), buffer, count)
#define arcnet_outsb(addr, offset, buffer, count) \
outsb((addr) + BUS_ALIGN * (offset), buffer, count)
#define arcnet_readb(addr, offset) \
readb((addr) + (offset))
#define arcnet_writeb(value, addr, offset) \
writeb(value, (addr) + (offset))
#endif /* __KERNEL__ */
#endif /* _LINUX_ARCDEVICE_H */

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,8 @@
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/init.h>
@ -33,9 +35,8 @@
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n"
#include "arcdevice.h"
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
@ -47,7 +48,8 @@ static void rx(struct net_device *dev, int bufnum,
char *pktbuf, *pkthdrbuf;
int ofs;
BUGMSG(D_DURING, "it's a raw(cap) packet (length=%d)\n", length);
arc_printk(D_DURING, dev, "it's a raw(cap) packet (length=%d)\n",
length);
if (length >= MinTU)
ofs = 512 - length;
@ -55,8 +57,7 @@ static void rx(struct net_device *dev, int bufnum,
ofs = 256 - length;
skb = alloc_skb(length + ARC_HDR_SIZE + sizeof(int), GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
if (!skb) {
dev->stats.rx_dropped++;
return;
}
@ -66,17 +67,17 @@ static void rx(struct net_device *dev, int bufnum,
pkt = (struct archdr *)skb_mac_header(skb);
skb_pull(skb, ARC_HDR_SIZE);
/* up to sizeof(pkt->soft) has already been copied from the card */
/* squeeze in an int for the cap encapsulation */
/* use these variables to be sure we count in bytes, not in
sizeof(struct archdr) */
pktbuf=(char*)pkt;
pkthdrbuf=(char*)pkthdr;
memcpy(pktbuf, pkthdrbuf, ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto));
memcpy(pktbuf+ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto)+sizeof(int),
pkthdrbuf+ARC_HDR_SIZE+sizeof(pkt->soft.cap.proto),
sizeof(struct archdr)-ARC_HDR_SIZE-sizeof(pkt->soft.cap.proto));
/* up to sizeof(pkt->soft) has already been copied from the card
* squeeze in an int for the cap encapsulation
* use these variables to be sure we count in bytes, not in
* sizeof(struct archdr)
*/
pktbuf = (char *)pkt;
pkthdrbuf = (char *)pkthdr;
memcpy(pktbuf, pkthdrbuf, ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto));
memcpy(pktbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto) + sizeof(int),
pkthdrbuf + ARC_HDR_SIZE + sizeof(pkt->soft.cap.proto),
sizeof(struct archdr) - ARC_HDR_SIZE - sizeof(pkt->soft.cap.proto));
if (length > sizeof(pkt->soft))
lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
@ -84,15 +85,14 @@ static void rx(struct net_device *dev, int bufnum,
+ sizeof(int),
length - sizeof(pkt->soft));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, skb, "rx");
skb->protocol = cpu_to_be16(ETH_P_ARCNET);
netif_rx(skb);
}
/*
* Create the ARCnet hard/soft headers for cap mode.
/* Create the ARCnet hard/soft headers for cap mode.
* There aren't any soft headers in cap mode - not even the protocol id.
*/
static int build_header(struct sk_buff *skb,
@ -101,12 +101,12 @@ static int build_header(struct sk_buff *skb,
uint8_t daddr)
{
int hdr_size = ARC_HDR_SIZE;
struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size);
BUGMSG(D_PROTO, "Preparing header for cap packet %x.\n",
*((int*)&pkt->soft.cap.cookie[0]));
/*
* Set the source hardware address.
arc_printk(D_PROTO, dev, "Preparing header for cap packet %x.\n",
*((int *)&pkt->soft.cap.cookie[0]));
/* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. ARCnet does not allow us to change the source address in
@ -117,9 +117,8 @@ static int build_header(struct sk_buff *skb,
/* see linux/net/ethernet/eth.c to see where I got the following */
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
/*
* FIXME: fill in the last byte of the dest ipaddr here to better
* comply with RFC1051 in "noarp" mode.
/* FIXME: fill in the last byte of the dest ipaddr here to
* better comply with RFC1051 in "noarp" mode.
*/
pkt->hard.dest = 0;
return hdr_size;
@ -130,7 +129,6 @@ static int build_header(struct sk_buff *skb,
return hdr_size; /* success */
}
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum)
{
@ -138,22 +136,21 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
struct arc_hardware *hard = &pkt->hard;
int ofs;
/* hard header is not included in packet length */
length -= ARC_HDR_SIZE;
/* And neither is the cookie field */
length -= sizeof(int);
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
BUGMSG(D_PROTO, "Sending for cap packet %x.\n",
*((int*)&pkt->soft.cap.cookie[0]));
arc_printk(D_PROTO, dev, "Sending for cap packet %x.\n",
*((int *)&pkt->soft.cap.cookie[0]));
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
arc_printk(D_NORMAL, dev, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
length = XMTU;
}
if (length > MinTU) {
@ -162,11 +159,12 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
} else if (length > MTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length - 3;
} else
} else {
hard->offset[0] = ofs = 256 - length;
}
BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n",
length,ofs);
arc_printk(D_DURING, dev, "prepare_tx: length=%d ofs=%d\n",
length, ofs);
/* Copy the arcnet-header + the protocol byte down: */
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
@ -174,9 +172,10 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
sizeof(pkt->soft.cap.proto));
/* Skip the extra integer we have written into it as a cookie
but write the rest of the message: */
lp->hw.copy_to_card(dev, bufnum, ofs+1,
((unsigned char*)&pkt->soft.cap.mes),length-1);
* but write the rest of the message:
*/
lp->hw.copy_to_card(dev, bufnum, ofs + 1,
((unsigned char *)&pkt->soft.cap.mes), length - 1);
lp->lastload_dest = hard->dest;
@ -188,21 +187,20 @@ static int ack_tx(struct net_device *dev, int acked)
struct arcnet_local *lp = netdev_priv(dev);
struct sk_buff *ackskb;
struct archdr *ackpkt;
int length=sizeof(struct arc_cap);
int length = sizeof(struct arc_cap);
BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
lp->outgoing.skb->protocol, acked);
arc_printk(D_DURING, dev, "capmode: ack_tx: protocol: %x: result: %d\n",
lp->outgoing.skb->protocol, acked);
BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
/* Now alloc a skb to send back up through the layers: */
ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
if (ackskb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
ackskb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (!ackskb)
goto free_outskb;
}
skb_put(ackskb, length + ARC_HDR_SIZE );
skb_put(ackskb, length + ARC_HDR_SIZE);
ackskb->dev = dev;
skb_reset_mac_header(ackskb);
@ -212,39 +210,40 @@ static int ack_tx(struct net_device *dev, int acked)
skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
ARC_HDR_SIZE + sizeof(struct arc_cap));
ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
ackpkt->soft.cap.mes.ack=acked;
ackpkt->soft.cap.mes.ack = acked;
BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
*((int*)&ackpkt->soft.cap.cookie[0]));
arc_printk(D_PROTO, dev, "Ackknowledge for cap packet %x.\n",
*((int *)&ackpkt->soft.cap.cookie[0]));
ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
netif_rx(ackskb);
free_outskb:
dev_kfree_skb_irq(lp->outgoing.skb);
lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
lp->outgoing.proto = NULL;
/* We are always finished when in this protocol */
return 0;
}
static struct ArcProto capmode_proto =
{
'r',
XMTU,
0,
rx,
build_header,
prepare_tx,
NULL,
ack_tx
static struct ArcProto capmode_proto = {
.suffix = 'r',
.mtu = XMTU,
.rx = rx,
.build_header = build_header,
.prepare_tx = prepare_tx,
.ack_tx = ack_tx
};
static void arcnet_cap_init(void)
static int __init capmode_module_init(void)
{
int count;
pr_info("cap mode (`c') encapsulation support loaded\n");
for (count = 1; count <= 8; count++)
if (arc_proto_map[count] == arc_proto_default)
arc_proto_map[count] = &capmode_proto;
@ -255,12 +254,7 @@ static void arcnet_cap_init(void)
arc_proto_default = &capmode_proto;
arc_raw_proto = &capmode_proto;
}
static int __init capmode_module_init(void)
{
printk(VERSION);
arcnet_cap_init();
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM20020 chipset support
*
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999-2000 by Martin Mares <mj@ucw.cz>.
@ -25,6 +25,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@ -36,16 +39,12 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/bootmem.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <linux/io.h>
#include <asm/io.h>
#include "arcdevice.h"
#include "com20020.h"
#define VERSION "arcnet: COM20020 ISA support (by David Woodhouse et al.)\n"
/*
* We cannot (yet) probe for an IO mapped card, although we can check that
/* We cannot (yet) probe for an IO mapped card, although we can check that
* it's where we were told it was, and even do autoirq.
*/
static int __init com20020isa_probe(struct net_device *dev)
@ -55,21 +54,21 @@ static int __init com20020isa_probe(struct net_device *dev)
struct arcnet_local *lp = netdev_priv(dev);
int err;
BUGLVL(D_NORMAL) printk(VERSION);
if (BUGLVL(D_NORMAL))
pr_info("%s\n", "COM20020 ISA support (by David Woodhouse et al.)");
ioaddr = dev->base_addr;
if (!ioaddr) {
BUGMSG(D_NORMAL, "No autoprobe (yet) for IO mapped cards; you "
"must specify the base address!\n");
arc_printk(D_NORMAL, dev, "No autoprobe (yet) for IO mapped cards; you must specify the base address!\n");
return -ENODEV;
}
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
arc_printk(D_NORMAL, dev, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
if (ASTATUS() == 0xFF) {
BUGMSG(D_NORMAL, "IO address %x empty\n", ioaddr);
if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
arc_printk(D_NORMAL, dev, "IO address %x empty\n", ioaddr);
err = -ENODEV;
goto out;
}
@ -83,23 +82,24 @@ static int __init com20020isa_probe(struct net_device *dev)
* card has just reset and the NORXflag is on until
* we tell it to start receiving.
*/
BUGMSG(D_INIT_REASONS, "intmask was %02Xh\n", inb(_INTMASK));
outb(0, _INTMASK);
arc_printk(D_INIT_REASONS, dev, "intmask was %02Xh\n",
arcnet_inb(ioaddr, COM20020_REG_R_STATUS));
arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
arcnet_outb(NORXflag, ioaddr, COM20020_REG_W_INTMASK);
udelay(1);
outb(0, _INTMASK);
arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
dev->irq = probe_irq_off(airqmask);
if ((int)dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n");
arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed first time\n");
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
arcnet_outb(NORXflag, ioaddr, COM20020_REG_W_INTMASK);
udelay(5);
outb(0, _INTMASK);
arcnet_outb(0, ioaddr, COM20020_REG_W_INTMASK);
dev->irq = probe_irq_off(airqmask);
if ((int)dev->irq <= 0) {
BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n");
arc_printk(D_NORMAL, dev, "Autoprobe IRQ failed.\n");
err = -ENODEV;
goto out;
}
@ -107,7 +107,9 @@ static int __init com20020isa_probe(struct net_device *dev)
}
lp->card_name = "ISA COM20020";
if ((err = com20020_found(dev, 0)) != 0)
err = com20020_found(dev, 0);
if (err != 0)
goto out;
return 0;
@ -194,7 +196,7 @@ static int __init com20020isa_setup(char *s)
switch (ints[0]) {
default: /* ERROR */
printk("com90xx: Too many arguments.\n");
pr_info("Too many arguments\n");
case 6: /* Timeout */
timeout = ints[6];
case 5: /* CKP value */

View file

@ -1,7 +1,7 @@
/*
* Linux ARCnet driver - COM20020 PCI support
* Contemporary Controls PCI20 and SOHARD SH-ARC PCI
*
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
* Written 1999-2000 by Martin Mares <mj@ucw.cz>.
@ -26,6 +26,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@ -36,14 +39,12 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/leds.h>
#include <asm/io.h>
#define VERSION "arcnet: COM20020 PCI support\n"
#include "arcdevice.h"
#include "com20020.h"
/* Module parameters */
@ -62,11 +63,43 @@ module_param(clockp, int, 0);
module_param(clockm, int, 0);
MODULE_LICENSE("GPL");
static void led_tx_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct com20020_dev *card;
struct com20020_priv *priv;
struct com20020_pci_card_info *ci;
card = container_of(led_cdev, struct com20020_dev, tx_led);
priv = card->pci_priv;
ci = priv->ci;
outb(!!value, priv->misc + ci->leds[card->index].green);
}
static void led_recon_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct com20020_dev *card;
struct com20020_priv *priv;
struct com20020_pci_card_info *ci;
card = container_of(led_cdev, struct com20020_dev, recon_led);
priv = card->pci_priv;
ci = priv->ci;
outb(!!value, priv->misc + ci->leds[card->index].red);
}
static void com20020pci_remove(struct pci_dev *pdev);
static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static int com20020pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct com20020_pci_card_info *ci;
struct com20020_pci_channel_map *mm;
struct net_device *dev;
struct arcnet_local *lp;
struct com20020_priv *priv;
@ -83,9 +116,21 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
ci = (struct com20020_pci_card_info *)id->driver_data;
priv->ci = ci;
mm = &ci->misc_map;
INIT_LIST_HEAD(&priv->list_dev);
if (mm->size) {
ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
r = devm_request_region(&pdev->dev, ioaddr, mm->size,
"com20020-pci");
if (!r) {
pr_err("IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + mm->size - 1);
return -EBUSY;
}
priv->misc = ioaddr;
}
for (i = 0; i < ci->devcount; i++) {
struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
@ -96,18 +141,19 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
ret = -ENOMEM;
goto out_port;
}
dev->dev_port = i;
dev->netdev_ops = &com20020_netdev_ops;
lp = netdev_priv(dev);
BUGMSG(D_NORMAL, "%s Controls\n", ci->name);
arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
r = devm_request_region(&pdev->dev, ioaddr, cm->size,
"com20020-pci");
if (!r) {
pr_err("IO region %xh-%xh already allocated.\n",
pr_err("IO region %xh-%xh already allocated\n",
ioaddr, ioaddr + cm->size - 1);
ret = -EBUSY;
goto out_port;
@ -117,8 +163,8 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
* ARCNET controller needs
* this access to detect bustype
*/
outb(0x00, ioaddr + 1);
inb(ioaddr + 1);
arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
dev->base_addr = ioaddr;
dev->dev_addr[0] = node;
@ -131,7 +177,14 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
lp->timeout = timeout;
lp->hw.owner = THIS_MODULE;
if (ASTATUS() == 0xFF) {
/* Get the dev_id from the PLX rotary coder */
if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
dev->dev_id = 0xc;
dev->dev_id ^= inb(priv->misc + ci->rotary) >> 4;
snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
pr_err("IO address %Xh is empty!\n", ioaddr);
ret = -EIO;
goto out_port;
@ -143,21 +196,46 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
GFP_KERNEL);
if (!card) {
pr_err("%s out of memory!\n", __func__);
if (!card)
return -ENOMEM;
}
card->index = i;
card->pci_priv = priv;
card->tx_led.brightness_set = led_tx_set;
card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
GFP_KERNEL, "arc%d-%d-tx",
dev->dev_id, i);
card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"pci:green:tx:%d-%d",
dev->dev_id, i);
card->tx_led.dev = &dev->dev;
card->recon_led.brightness_set = led_recon_set;
card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
GFP_KERNEL, "arc%d-%d-recon",
dev->dev_id, i);
card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"pci:red:recon:%d-%d",
dev->dev_id, i);
card->recon_led.dev = &dev->dev;
card->dev = dev;
ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
if (ret)
goto out_port;
ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
if (ret)
goto out_port;
dev_set_drvdata(&dev->dev, card);
ret = com20020_found(dev, IRQF_SHARED);
if (ret)
goto out_port;
devm_arcnet_led_init(dev, dev->dev_id, i);
list_add(&card->list, &priv->list_dev);
}
@ -190,7 +268,11 @@ static struct com20020_pci_card_info card_info_10mbit = {
.name = "ARC-PCI",
.devcount = 1,
.chan_map_tbl = {
{ 2, 0x00, 0x08 },
{
.bar = 2,
.offset = 0x00,
.size = 0x08,
},
},
.flags = ARC_CAN_10MBIT,
};
@ -199,7 +281,11 @@ static struct com20020_pci_card_info card_info_5mbit = {
.name = "ARC-PCI",
.devcount = 1,
.chan_map_tbl = {
{ 2, 0x00, 0x08 },
{
.bar = 2,
.offset = 0x00,
.size = 0x08,
},
},
.flags = ARC_IS_5MBIT,
};
@ -209,7 +295,11 @@ static struct com20020_pci_card_info card_info_sohard = {
.devcount = 1,
/* SOHARD needs PCI base addr 4 */
.chan_map_tbl = {
{4, 0x00, 0x08},
{
.bar = 4,
.offset = 0x00,
.size = 0x08
},
},
.flags = ARC_CAN_10MBIT,
};
@ -218,8 +308,24 @@ static struct com20020_pci_card_info card_info_eae_arc1 = {
.name = "EAE PLX-PCI ARC1",
.devcount = 1,
.chan_map_tbl = {
{ 2, 0x00, 0x08 },
{
.bar = 2,
.offset = 0x00,
.size = 0x08,
},
},
.misc_map = {
.bar = 2,
.offset = 0x10,
.size = 0x04,
},
.leds = {
{
.green = 0x0,
.red = 0x1,
},
},
.rotary = 0x0,
.flags = ARC_CAN_10MBIT,
};
@ -227,9 +333,31 @@ static struct com20020_pci_card_info card_info_eae_ma1 = {
.name = "EAE PLX-PCI MA1",
.devcount = 2,
.chan_map_tbl = {
{ 2, 0x00, 0x08 },
{ 2, 0x08, 0x08 }
{
.bar = 2,
.offset = 0x00,
.size = 0x08,
}, {
.bar = 2,
.offset = 0x08,
.size = 0x08,
}
},
.misc_map = {
.bar = 2,
.offset = 0x10,
.size = 0x04,
},
.leds = {
{
.green = 0x0,
.red = 0x1,
}, {
.green = 0x2,
.red = 0x3,
},
},
.rotary = 0x0,
.flags = ARC_CAN_10MBIT,
};
@ -404,7 +532,8 @@ static struct pci_driver com20020pci_driver = {
static int __init com20020pci_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
if (BUGLVL(D_NORMAL))
pr_info("%s\n", "COM20020 PCI support");
return pci_register_driver(&com20020pci_driver);
}

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM20020 chipset support
*
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@ucw.cz>.
@ -25,6 +25,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@ -34,17 +37,16 @@
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <linux/io.h>
#include <asm/io.h>
#include "arcdevice.h"
#include "com20020.h"
#define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n"
static char *clockrates[] =
{"10 Mb/s", "Reserved", "5 Mb/s",
"2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s",
"156.25 Kb/s", "Reserved", "Reserved", "Reserved"};
static const char * const clockrates[] = {
"XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",
"1.25Mb/s", "625 Kb/s", "312.5 Kb/s", "156.25 Kb/s",
"Reserved", "Reserved", "Reserved"
};
static void com20020_command(struct net_device *dev, int command);
static int com20020_status(struct net_device *dev);
@ -63,35 +65,38 @@ static void com20020_copy_from_card(struct net_device *dev, int bufnum,
int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
/* set up the address register */
outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(ofs & 0xff, _ADDR_LO);
arcnet_outb((ofs >> 8) | RDDATAflag | AUTOINCflag,
ioaddr, COM20020_REG_W_ADDR_HI);
arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
/* copy the data */
TIME("insb", count, insb(_MEMDATA, buf, count));
TIME(dev, "insb", count,
arcnet_insb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
}
static void com20020_copy_to_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset;
/* set up the address register */
outb((ofs >> 8) | AUTOINCflag, _ADDR_HI);
outb(ofs & 0xff, _ADDR_LO);
arcnet_outb((ofs >> 8) | AUTOINCflag, ioaddr, COM20020_REG_W_ADDR_HI);
arcnet_outb(ofs & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
/* copy the data */
TIME("outsb", count, outsb(_MEMDATA, buf, count));
TIME(dev, "outsb", count,
arcnet_outsb(ioaddr, COM20020_REG_RW_MEMDATA, buf, count));
}
/* Reset the card and check some basic stuff during the detection stage. */
int com20020_check(struct net_device *dev)
{
int ioaddr = dev->base_addr, status;
struct arcnet_local *lp = netdev_priv(dev);
ARCRESET0;
arcnet_outb(XTOcfg(3) | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
udelay(5);
arcnet_outb(XTOcfg(3), ioaddr, COM20020_REG_W_CONFIG);
mdelay(RESETtime);
lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
@ -101,49 +106,46 @@ int com20020_check(struct net_device *dev)
/* Enable P1Mode for backplane mode */
lp->setup = lp->setup | P1MODE;
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
if (lp->clockm != 0) {
com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
if (lp->clockm != 0)
{
SET_SUBADR(SUB_SETUP2);
outb(lp->setup2, _XREG);
/* must now write the magic "restart operation" command */
mdelay(1);
outb(0x18, _COMMAND);
arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
}
lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2);
lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
/* set node ID to 0x42 (but transmitter is disabled, so it's okay) */
SETCONF;
outb(0x42, ioaddr + BUS_ALIGN*7);
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG);
status = ASTATUS();
status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) {
BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status);
arc_printk(D_NORMAL, dev, "status invalid (%Xh).\n", status);
return -ENODEV;
}
BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status);
arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status);
/* Enable TX */
outb(0x39, _CONFIG);
outb(inb(ioaddr + BUS_ALIGN*8), ioaddr + BUS_ALIGN*7);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ASTATUS();
BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n",
status);
arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
ioaddr, COM20020_REG_W_COMMAND);
status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS);
arc_printk(D_INIT_REASONS, dev, "status after reset acknowledged: %X\n",
status);
/* Read first location of memory */
outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(0, _ADDR_LO);
arcnet_outb(0 | RDDATAflag | AUTOINCflag,
ioaddr, COM20020_REG_W_ADDR_HI);
arcnet_outb(0, ioaddr, COM20020_REG_W_ADDR_LO);
if ((status = inb(_MEMDATA)) != TESTvalue) {
BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n",
status);
status = arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA);
if (status != TESTvalue) {
arc_printk(D_NORMAL, dev, "Signature byte not found (%02Xh != D1h).\n",
status);
return -ENODEV;
}
return 0;
@ -156,15 +158,39 @@ static int com20020_set_hwaddr(struct net_device *dev, void *addr)
struct sockaddr *hwaddr = addr;
memcpy(dev->dev_addr, hwaddr->sa_data, 1);
SET_SUBADR(SUB_NODE);
outb(dev->dev_addr[0], _XREG);
com20020_set_subaddress(lp, ioaddr, SUB_NODE);
arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
return 0;
}
static int com20020_netdev_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct arcnet_local *lp = netdev_priv(dev);
lp->config |= TXENcfg;
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
return arcnet_open(dev);
}
static int com20020_netdev_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct arcnet_local *lp = netdev_priv(dev);
arcnet_close(dev);
/* disable transmitter */
lp->config &= ~TXENcfg;
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
return 0;
}
const struct net_device_ops com20020_netdev_ops = {
.ndo_open = arcnet_open,
.ndo_stop = arcnet_close,
.ndo_open = com20020_netdev_open,
.ndo_stop = com20020_netdev_close,
.ndo_start_xmit = arcnet_send_packet,
.ndo_tx_timeout = arcnet_timeout,
.ndo_set_mac_address = com20020_set_hwaddr,
@ -192,48 +218,54 @@ int com20020_found(struct net_device *dev, int shared)
lp->hw.copy_from_card = com20020_copy_from_card;
lp->hw.close = com20020_close;
/* FIXME: do this some other way! */
if (!dev->dev_addr[0])
dev->dev_addr[0] = inb(ioaddr + BUS_ALIGN*8); /* FIXME: do this some other way! */
dev->dev_addr[0] = arcnet_inb(ioaddr, 8);
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
if (lp->card_flags & ARC_CAN_10MBIT) {
com20020_set_subaddress(lp, ioaddr, SUB_SETUP2);
arcnet_outb(lp->setup2, ioaddr, COM20020_REG_W_XREG);
if (lp->card_flags & ARC_CAN_10MBIT)
{
SET_SUBADR(SUB_SETUP2);
outb(lp->setup2, _XREG);
/* must now write the magic "restart operation" command */
mdelay(1);
outb(0x18, _COMMAND);
arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND);
}
lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1;
lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE;
/* Default 0x38 + register: Node ID */
SETCONF;
outb(dev->dev_addr[0], _XREG);
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG);
/* reserve the irq */
if (request_irq(dev->irq, arcnet_interrupt, shared,
"arcnet (COM20020)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
arc_printk(D_NORMAL, dev, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
lp->card_name, dev->dev_addr[0], dev->base_addr, dev->irq);
if (lp->backplane)
BUGMSG(D_NORMAL, "Using backplane mode.\n");
arc_printk(D_NORMAL, dev, "Using backplane mode.\n");
if (lp->timeout != 3)
BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout);
arc_printk(D_NORMAL, dev, "Using extended timeout value of %d\n",
lp->timeout);
BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
lp->setup >> 1,
clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
arc_printk(D_NORMAL, dev, "Using CKP %d - data rate %s\n",
lp->setup >> 1,
clockrates[3 -
((lp->setup2 & 0xF0) >> 4) +
((lp->setup & 0x0F) >> 1)]);
/* The clockrates array index looks very fragile.
* It seems like it could have negative indexing.
*/
if (register_netdev(dev)) {
free_irq(dev->irq, dev);
@ -242,10 +274,8 @@ int com20020_found(struct net_device *dev, int shared)
return 0;
}
/*
* Do a hardware reset on the card, and set up necessary registers.
*
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
@ -257,65 +287,71 @@ static int com20020_reset(struct net_device *dev, int really_reset)
u_int ioaddr = dev->base_addr;
u_char inbyte;
BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
__FILE__,__LINE__,__func__,dev,lp,dev->name);
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
dev->name, ASTATUS());
arc_printk(D_DEBUG, dev, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
__FILE__, __LINE__, __func__, dev, lp, dev->name);
arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS));
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
lp->config |= (lp->timeout << 3) | (lp->backplane << 2);
/* power-up defaults */
SETCONF;
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
if (really_reset) {
/* reset the card */
ARCRESET;
mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */
arcnet_outb(lp->config | RESETcfg, ioaddr, COM20020_REG_W_CONFIG);
udelay(5);
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
mdelay(RESETtime * 2);
/* COM20020 seems to be slower sometimes */
}
/* clear flags & end reset */
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
ioaddr, COM20020_REG_W_COMMAND);
/* verify that the ARCnet signature byte is present */
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
if (inbyte != TESTvalue) {
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
arc_printk(D_DEBUG, dev, "%s: %d: %s\n",
__FILE__, __LINE__, __func__);
arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM20020_REG_W_COMMAND);
arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__);
/* done! return success. */
return 0;
}
static void com20020_setmask(struct net_device *dev, int mask)
{
u_int ioaddr = dev->base_addr;
BUGMSG(D_DURING, "Setting mask to %x at %x\n",mask,ioaddr);
AINTMASK(mask);
}
arc_printk(D_DURING, dev, "Setting mask to %x at %x\n", mask, ioaddr);
arcnet_outb(mask, ioaddr, COM20020_REG_W_INTMASK);
}
static void com20020_command(struct net_device *dev, int cmd)
{
u_int ioaddr = dev->base_addr;
ACOMMAND(cmd);
}
arcnet_outb(cmd, ioaddr, COM20020_REG_W_COMMAND);
}
static int com20020_status(struct net_device *dev)
{
u_int ioaddr = dev->base_addr;
return ASTATUS() + (ADIAGSTATUS()<<8);
return arcnet_inb(ioaddr, COM20020_REG_R_STATUS) +
(arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT) << 8);
}
static void com20020_close(struct net_device *dev)
@ -325,7 +361,7 @@ static void com20020_close(struct net_device *dev)
/* disable transmitter */
lp->config &= ~TXENcfg;
SETCONF;
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
}
/* Set or clear the multicast filter for this adaptor.
@ -340,20 +376,20 @@ static void com20020_set_mc_list(struct net_device *dev)
struct arcnet_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */
if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) {
/* Enable promiscuous mode */
if (!(lp->setup & PROMISCset))
BUGMSG(D_NORMAL, "Setting promiscuous flag...\n");
SET_SUBADR(SUB_SETUP1);
arc_printk(D_NORMAL, dev, "Setting promiscuous flag...\n");
com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
lp->setup |= PROMISCset;
outb(lp->setup, _XREG);
} else
arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
} else {
/* Disable promiscuous mode, use normal mode */
{
if ((lp->setup & PROMISCset))
BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n");
SET_SUBADR(SUB_SETUP1);
arc_printk(D_NORMAL, dev, "Resetting promiscuous flag...\n");
com20020_set_subaddress(lp, ioaddr, SUB_SETUP1);
lp->setup &= ~PROMISCset;
outb(lp->setup, _XREG);
arcnet_outb(lp->setup, ioaddr, COM20020_REG_W_XREG);
}
}
@ -371,7 +407,8 @@ MODULE_LICENSE("GPL");
static int __init com20020_module_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
if (BUGLVL(D_NORMAL))
pr_info("%s\n", "COM20020 chipset support (by David Woodhouse et al.)");
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM20020 chipset support - function declarations
*
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Derived from skeleton.c by Donald Becker.
@ -26,6 +26,7 @@
*/
#ifndef __COM20020_H
#define __COM20020_H
#include <linux/leds.h>
int com20020_check(struct net_device *dev);
int com20020_found(struct net_device *dev, int shared);
@ -34,15 +35,13 @@ extern const struct net_device_ops com20020_netdev_ops;
/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 8
/* various register addresses */
#ifdef CONFIG_SA1100_CT6001
#define BUS_ALIGN 2 /* 8 bit device on a 16 bit bus - needs padding */
#else
#define BUS_ALIGN 1
#endif
#define PLX_PCI_MAX_CARDS 2
struct ledoffsets {
int green;
int red;
};
struct com20020_pci_channel_map {
u32 bar;
u32 offset;
@ -54,6 +53,10 @@ struct com20020_pci_card_info {
int devcount;
struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS];
struct com20020_pci_channel_map misc_map;
struct ledoffsets leds[PLX_PCI_MAX_CARDS];
int rotary;
unsigned int flags;
};
@ -61,27 +64,32 @@ struct com20020_pci_card_info {
struct com20020_priv {
struct com20020_pci_card_info *ci;
struct list_head list_dev;
resource_size_t misc;
};
struct com20020_dev {
struct list_head list;
struct net_device *dev;
struct led_classdev tx_led;
struct led_classdev recon_led;
struct com20020_priv *pci_priv;
int index;
};
#define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */
#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */
#define _COMMAND (ioaddr+BUS_ALIGN*1) /* standard arcnet commands */
#define _DIAGSTAT (ioaddr+BUS_ALIGN*1) /* diagnostic status register */
#define _ADDR_HI (ioaddr+BUS_ALIGN*2) /* control registers for IO-mapped memory */
#define _ADDR_LO (ioaddr+BUS_ALIGN*3)
#define _MEMDATA (ioaddr+BUS_ALIGN*4) /* data port for IO-mapped memory */
#define _SUBADR (ioaddr+BUS_ALIGN*5) /* the extended port _XREG refers to */
#define _CONFIG (ioaddr+BUS_ALIGN*6) /* configuration register */
#define _XREG (ioaddr+BUS_ALIGN*7) /* extra registers (indexed by _CONFIG
or _SUBADR) */
#define COM20020_REG_W_INTMASK 0 /* writable */
#define COM20020_REG_R_STATUS 0 /* readable */
#define COM20020_REG_W_COMMAND 1 /* standard arcnet commands */
#define COM20020_REG_R_DIAGSTAT 1 /* diagnostic status */
#define COM20020_REG_W_ADDR_HI 2 /* control for IO-mapped memory */
#define COM20020_REG_W_ADDR_LO 3
#define COM20020_REG_RW_MEMDATA 4 /* data port for IO-mapped memory */
#define COM20020_REG_W_SUBADR 5 /* the extended port _XREG refers to */
#define COM20020_REG_W_CONFIG 6 /* configuration */
#define COM20020_REG_W_XREG 7 /* extra
* (indexed by _CONFIG or _SUBADDR)
*/
/* in the ADDR_HI register */
#define RDDATAflag 0x80 /* next access is a read (not a write) */
@ -92,6 +100,7 @@ struct com20020_dev {
/* in the CONFIG register */
#define RESETcfg 0x80 /* put card in reset state */
#define TXENcfg 0x20 /* enable TX */
#define XTOcfg(x) ((x) << 3) /* extended timeout */
/* in SETUP register */
#define PROMISCset 0x10 /* enable RCV_ALL */
@ -109,37 +118,15 @@ struct com20020_dev {
#define SUB_BUSCTL 5 /* bus control options */
#define SUB_DMACOUNT 6 /* DMA count options */
#define SET_SUBADR(x) do { \
if ((x) < 4) \
{ \
lp->config = (lp->config & ~0x03) | (x); \
SETCONF; \
} \
else \
{ \
outb(x, _SUBADR); \
} \
} while (0)
#undef ARCRESET
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \
udelay(5); \
outb(lp->config , _CONFIG); \
}
#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \
udelay(5); \
outb(0x18 , _CONFIG); \
}
#define ASTATUS() inb(_STATUS)
#define ADIAGSTATUS() inb(_DIAGSTAT)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF outb(lp->config, _CONFIG)
static inline void com20020_set_subaddress(struct arcnet_local *lp,
int ioaddr, int val)
{
if (val < 4) {
lp->config = (lp->config & ~0x03) | val;
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
} else {
arcnet_outb(val, ioaddr, COM20020_REG_W_SUBADR);
}
}
#endif /* __COM20020_H */

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM20020 PCMCIA support
*
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
* Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
@ -19,18 +19,21 @@
* Director, National Security Agency. This software may only be used
* and distributed according to the terms of the GNU General Public License as
* modified by SRC, incorporated herein by reference.
*
*
* **********************
* Changes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
* - reorganize kmallocs in com20020_attach, checking all for failure
* and releasing the previous allocations if one fails
* **********************
*
*
* For more details, see drivers/net/arcnet.c
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
@ -39,52 +42,45 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/arcdevice.h>
#include <linux/com20020.h>
#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <asm/io.h>
#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
#include "arcdevice.h"
#include "com20020.h"
static void regdump(struct net_device *dev)
{
#ifdef DEBUG
int ioaddr = dev->base_addr;
int count;
netdev_dbg(dev, "register dump:\n");
for (count = ioaddr; count < ioaddr + 16; count++)
{
if (!(count % 16))
pr_cont("%04X:", count);
pr_cont(" %02X", inb(count));
}
pr_cont("\n");
netdev_dbg(dev, "buffer0 dump:\n");
int ioaddr = dev->base_addr;
int count;
netdev_dbg(dev, "register dump:\n");
for (count = 0; count < 16; count++) {
if (!(count % 16))
pr_cont("%04X:", ioaddr + count);
pr_cont(" %02X", arcnet_inb(ioaddr, count));
}
pr_cont("\n");
netdev_dbg(dev, "buffer0 dump:\n");
/* set up the address register */
count = 0;
outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
outb(count & 0xff, _ADDR_LO);
for (count = 0; count < 256+32; count++)
{
if (!(count % 16))
pr_cont("%04X:", count);
/* copy the data */
pr_cont(" %02X", inb(_MEMDATA));
}
pr_cont("\n");
count = 0;
arcnet_outb((count >> 8) | RDDATAflag | AUTOINCflag,
ioaddr, com20020_REG_W_ADDR_HI);
arcnet_outb(count & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
for (count = 0; count < 256 + 32; count++) {
if (!(count % 16))
pr_cont("%04X:", count);
/* copy the data */
pr_cont(" %02X", arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA));
}
pr_cont("\n");
#endif
}
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
@ -114,169 +110,161 @@ static void com20020_detach(struct pcmcia_device *p_dev);
static int com20020_probe(struct pcmcia_device *p_dev)
{
struct com20020_dev *info;
struct net_device *dev;
struct arcnet_local *lp;
struct com20020_dev *info;
struct net_device *dev;
struct arcnet_local *lp;
dev_dbg(&p_dev->dev, "com20020_attach()\n");
dev_dbg(&p_dev->dev, "com20020_attach()\n");
/* Create new network device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
goto fail_alloc_info;
/* Create new network device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
goto fail_alloc_info;
dev = alloc_arcdev("");
if (!dev)
goto fail_alloc_dev;
dev = alloc_arcdev("");
if (!dev)
goto fail_alloc_dev;
lp = netdev_priv(dev);
lp->timeout = timeout;
lp->backplane = backplane;
lp->clockp = clockp;
lp->clockm = clockm & 3;
lp->hw.owner = THIS_MODULE;
lp = netdev_priv(dev);
lp->timeout = timeout;
lp->backplane = backplane;
lp->clockp = clockp;
lp->clockm = clockm & 3;
lp->hw.owner = THIS_MODULE;
/* fill in our module parameters as defaults */
dev->dev_addr[0] = node;
/* fill in our module parameters as defaults */
dev->dev_addr[0] = node;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->resource[0]->end = 16;
p_dev->config_flags |= CONF_ENABLE_IRQ;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->resource[0]->end = 16;
p_dev->config_flags |= CONF_ENABLE_IRQ;
info->dev = dev;
p_dev->priv = info;
info->dev = dev;
p_dev->priv = info;
return com20020_config(p_dev);
return com20020_config(p_dev);
fail_alloc_dev:
kfree(info);
kfree(info);
fail_alloc_info:
return -ENOMEM;
return -ENOMEM;
} /* com20020_attach */
static void com20020_detach(struct pcmcia_device *link)
{
struct com20020_dev *info = link->priv;
struct net_device *dev = info->dev;
struct com20020_dev *info = link->priv;
struct net_device *dev = info->dev;
dev_dbg(&link->dev, "detach...\n");
dev_dbg(&link->dev, "detach...\n");
dev_dbg(&link->dev, "com20020_detach\n");
dev_dbg(&link->dev, "com20020_detach\n");
dev_dbg(&link->dev, "unregister...\n");
dev_dbg(&link->dev, "unregister...\n");
unregister_netdev(dev);
unregister_netdev(dev);
/*
* this is necessary because we register our IRQ separately
* from card services.
*/
if (dev->irq)
free_irq(dev->irq, dev);
/* this is necessary because we register our IRQ separately
* from card services.
*/
if (dev->irq)
free_irq(dev->irq, dev);
com20020_release(link);
com20020_release(link);
/* Unlink device structure, free bits */
dev_dbg(&link->dev, "unlinking...\n");
if (link->priv)
{
dev = info->dev;
if (dev)
{
dev_dbg(&link->dev, "kfree...\n");
free_netdev(dev);
/* Unlink device structure, free bits */
dev_dbg(&link->dev, "unlinking...\n");
if (link->priv) {
dev = info->dev;
if (dev) {
dev_dbg(&link->dev, "kfree...\n");
free_netdev(dev);
}
dev_dbg(&link->dev, "kfree2...\n");
kfree(info);
}
dev_dbg(&link->dev, "kfree2...\n");
kfree(info);
}
} /* com20020_detach */
static int com20020_config(struct pcmcia_device *link)
{
struct arcnet_local *lp;
struct com20020_dev *info;
struct net_device *dev;
int i, ret;
int ioaddr;
struct arcnet_local *lp;
struct com20020_dev *info;
struct net_device *dev;
int i, ret;
int ioaddr;
info = link->priv;
dev = info->dev;
info = link->priv;
dev = info->dev;
dev_dbg(&link->dev, "config...\n");
dev_dbg(&link->dev, "config...\n");
dev_dbg(&link->dev, "com20020_config\n");
dev_dbg(&link->dev, "com20020_config\n");
dev_dbg(&link->dev, "baseport1 is %Xh\n",
(unsigned int) link->resource[0]->start);
dev_dbg(&link->dev, "baseport1 is %Xh\n",
(unsigned int)link->resource[0]->start);
i = -ENODEV;
link->io_lines = 16;
i = -ENODEV;
link->io_lines = 16;
if (!link->resource[0]->start)
{
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
{
link->resource[0]->start = ioaddr;
i = pcmcia_request_io(link);
if (i == 0)
break;
if (!link->resource[0]->start) {
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) {
link->resource[0]->start = ioaddr;
i = pcmcia_request_io(link);
if (i == 0)
break;
}
} else {
i = pcmcia_request_io(link);
}
}
else
i = pcmcia_request_io(link);
if (i != 0)
{
dev_dbg(&link->dev, "requestIO failed totally!\n");
goto failed;
}
ioaddr = dev->base_addr = link->resource[0]->start;
dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
dev_dbg(&link->dev, "request IRQ %d\n",
link->irq);
if (!link->irq)
{
dev_dbg(&link->dev, "requestIRQ failed totally!\n");
goto failed;
}
if (i != 0) {
dev_dbg(&link->dev, "requestIO failed totally!\n");
goto failed;
}
dev->irq = link->irq;
ioaddr = dev->base_addr = link->resource[0]->start;
dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
dev_dbg(&link->dev, "request IRQ %d\n",
link->irq);
if (!link->irq) {
dev_dbg(&link->dev, "requestIRQ failed totally!\n");
goto failed;
}
if (com20020_check(dev))
{
regdump(dev);
goto failed;
}
lp = netdev_priv(dev);
lp->card_name = "PCMCIA COM20020";
lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
dev->irq = link->irq;
SET_NETDEV_DEV(dev, &link->dev);
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
i = com20020_found(dev, 0); /* calls register_netdev */
if (i != 0) {
dev_notice(&link->dev,
"com20020_found() failed\n");
goto failed;
}
if (com20020_check(dev)) {
regdump(dev);
goto failed;
}
netdev_dbg(dev, "port %#3lx, irq %d\n",
dev->base_addr, dev->irq);
return 0;
lp = netdev_priv(dev);
lp->card_name = "PCMCIA COM20020";
lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
SET_NETDEV_DEV(dev, &link->dev);
i = com20020_found(dev, 0); /* calls register_netdev */
if (i != 0) {
dev_notice(&link->dev,
"com20020_found() failed\n");
goto failed;
}
netdev_dbg(dev, "port %#3lx, irq %d\n",
dev->base_addr, dev->irq);
return 0;
failed:
dev_dbg(&link->dev, "com20020_config failed...\n");
com20020_release(link);
return -ENODEV;
dev_dbg(&link->dev, "com20020_config failed...\n");
com20020_release(link);
return -ENODEV;
} /* com20020_config */
static void com20020_release(struct pcmcia_device *link)
@ -304,7 +292,10 @@ static int com20020_resume(struct pcmcia_device *link)
if (link->open) {
int ioaddr = dev->base_addr;
struct arcnet_local *lp = netdev_priv(dev);
ARCRESET;
arcnet_outb(lp->config | 0x80, ioaddr, COM20020_REG_W_CONFIG);
udelay(5);
arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
}
return 0;
@ -312,9 +303,9 @@ static int com20020_resume(struct pcmcia_device *link)
static const struct pcmcia_device_id com20020_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
"PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
"PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
PCMCIA_DEVICE_PROD_ID12("SoHard AG",
"SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
"SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, com20020_ids);

View file

@ -0,0 +1,17 @@
#ifndef __COM9026_H
#define __COM9026_H
/* COM 9026 controller chip --> ARCnet register addresses */
#define COM9026_REG_W_INTMASK 0 /* writable */
#define COM9026_REG_R_STATUS 0 /* readable */
#define COM9026_REG_W_COMMAND 1 /* writable, returns random vals on read (?) */
#define COM9026_REG_RW_CONFIG 2 /* Configuration register */
#define COM9026_REG_R_RESET 8 /* software reset (on read) */
#define COM9026_REG_RW_MEMDATA 12 /* Data port for IO-mapped memory */
#define COM9026_REG_W_ADDR_LO 14 /* Control registers for said */
#define COM9026_REG_W_ADDR_HI 15
#define COM9026_REG_R_STATION 1 /* Station ID */
#endif

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM90xx chipset (IO-mapped buffers)
*
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
* Written 1999-2000 by Martin Mares <mj@ucw.cz>.
@ -25,6 +25,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@ -34,12 +37,10 @@
#include <linux/bootmem.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: COM90xx IO-mapped mode support (by David Woodhouse et el.)\n"
#include <linux/io.h>
#include "arcdevice.h"
#include "com9026.h"
/* Internal function declarations */
@ -50,35 +51,14 @@ static void com90io_setmask(struct net_device *dev, int mask);
static int com90io_reset(struct net_device *dev, int really_reset);
static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void com90io_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
/* Handy defines for ARCnet specific stuff */
/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 16
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#define _CONFIG (ioaddr+2) /* Configuration register */
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define SETCONF() outb((lp->config),_CONFIG)
/****************************************************************************
* *
* IO-mapped operation routines *
@ -92,58 +72,59 @@ static u_char get_buffer_byte(struct net_device *dev, unsigned offset)
{
int ioaddr = dev->base_addr;
outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI);
arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
return inb(_MEMDATA);
return arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
}
#ifdef ONE_AT_A_TIME_TX
static void put_buffer_byte(struct net_device *dev, unsigned offset, u_char datum)
static void put_buffer_byte(struct net_device *dev, unsigned offset,
u_char datum)
{
int ioaddr = dev->base_addr;
outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
arcnet_outb(offset >> 8, ioaddr, COM9026_REG_W_ADDR_HI);
arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
outb(datum, _MEMDATA);
arcnet_outb(datum, ioaddr, COM9026_REG_RW_MEMDATA);
}
#endif
static void get_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest)
static void get_whole_buffer(struct net_device *dev, unsigned offset,
unsigned length, char *dest)
{
int ioaddr = dev->base_addr;
outb((offset >> 8) | AUTOINCflag, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
arcnet_outb(offset & 0xff, ioaddr, COM9026_REG_W_ADDR_LO);
while (length--)
#ifdef ONE_AT_A_TIME_RX
*(dest++) = get_buffer_byte(dev, offset++);
#else
*(dest++) = inb(_MEMDATA);
*(dest++) = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
#endif
}
static void put_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest)
static void put_whole_buffer(struct net_device *dev, unsigned offset,
unsigned length, char *dest)
{
int ioaddr = dev->base_addr;
outb((offset >> 8) | AUTOINCflag, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
arcnet_outb((offset >> 8) | AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
arcnet_outb(offset & 0xff, ioaddr,COM9026_REG_W_ADDR_LO);
while (length--)
#ifdef ONE_AT_A_TIME_TX
put_buffer_byte(dev, offset++, *(dest++));
#else
outb(*(dest++), _MEMDATA);
arcnet_outb(*(dest++), ioaddr, COM9026_REG_RW_MEMDATA);
#endif
}
/*
* We cannot probe for an IO mapped card either, although we can check that
/* We cannot probe for an IO mapped card either, although we can check that
* it's where we were told it was, and even autoirq
*/
static int __init com90io_probe(struct net_device *dev)
@ -151,71 +132,78 @@ static int __init com90io_probe(struct net_device *dev)
int ioaddr = dev->base_addr, status;
unsigned long airqmask;
BUGLVL(D_NORMAL) printk(VERSION);
BUGLVL(D_NORMAL) printk("E-mail me if you actually test this driver, please!\n");
if (BUGLVL(D_NORMAL)) {
pr_info("%s\n", "COM90xx IO-mapped mode support (by David Woodhouse et el.)");
pr_info("E-mail me if you actually test this driver, please!\n");
}
if (!ioaddr) {
BUGMSG(D_NORMAL, "No autoprobe for IO mapped cards; you "
"must specify the base address!\n");
arc_printk(D_NORMAL, dev, "No autoprobe for IO mapped cards; you must specify the base address!\n");
return -ENODEV;
}
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
BUGMSG(D_INIT_REASONS, "IO request_region %x-%x failed.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
arc_printk(D_INIT_REASONS, dev, "IO request_region %x-%x failed\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
if (ASTATUS() == 0xFF) {
BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr);
if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) {
arc_printk(D_INIT_REASONS, dev, "IO address %x empty\n",
ioaddr);
goto err_out;
}
inb(_RESET);
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
status = ASTATUS();
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status);
arc_printk(D_INIT_REASONS, dev, "Status invalid (%Xh)\n",
status);
goto err_out;
}
BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status);
arc_printk(D_INIT_REASONS, dev, "Status after reset: %X\n", status);
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
ioaddr, COM9026_REG_W_COMMAND);
BUGMSG(D_INIT_REASONS, "Status after reset acknowledged: %X\n", status);
arc_printk(D_INIT_REASONS, dev, "Status after reset acknowledged: %X\n",
status);
status = ASTATUS();
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
if (status & RESETflag) {
BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status);
arc_printk(D_INIT_REASONS, dev, "Eternal reset (status=%Xh)\n",
status);
goto err_out;
}
outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG);
arcnet_outb((0x16 | IOMAPflag) & ~ENABLE16flag,
ioaddr, COM9026_REG_RW_CONFIG);
/* Read first loc'n of memory */
outb(AUTOINCflag, _ADDR_HI);
outb(0, _ADDR_LO);
arcnet_outb(AUTOINCflag, ioaddr, COM9026_REG_W_ADDR_HI);
arcnet_outb(0, ioaddr, COM9026_REG_W_ADDR_LO);
if ((status = inb(_MEMDATA)) != 0xd1) {
BUGMSG(D_INIT_REASONS, "Signature byte not found"
" (%Xh instead).\n", status);
status = arcnet_inb(ioaddr, COM9026_REG_RW_MEMDATA);
if (status != 0xd1) {
arc_printk(D_INIT_REASONS, dev, "Signature byte not found (%Xh instead).\n",
status);
goto err_out;
}
if (!dev->irq) {
/*
* if we do this, we're sure to get an IRQ since the
/* if we do this, we're sure to get an IRQ since the
* card has just reset and the NORXflag is on until
* we tell it to start receiving.
*/
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
udelay(1);
outb(0, _INTMASK);
arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
dev->irq = probe_irq_off(airqmask);
if ((int)dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n");
arc_printk(D_INIT_REASONS, dev, "Autoprobe IRQ failed\n");
goto err_out;
}
}
@ -227,7 +215,6 @@ err_out:
return -ENODEV;
}
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
@ -238,12 +225,14 @@ static int __init com90io_found(struct net_device *dev)
int err;
/* Reserve the irq */
if (request_irq(dev->irq, arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
if (request_irq(dev->irq, arcnet_interrupt, 0,
"arcnet (COM90xx-IO)", dev)) {
arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
/* Reserve the I/O region */
if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) {
if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE,
"arcnet (COM90xx-IO)")) {
free_irq(dev->irq, dev);
return -EBUSY;
}
@ -259,7 +248,7 @@ static int __init com90io_found(struct net_device *dev)
lp->hw.copy_from_card = com90io_copy_from_card;
lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag;
SETCONF();
arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG);
/* get and check the station ID from offset 1 in shmem */
@ -267,21 +256,20 @@ static int __init com90io_found(struct net_device *dev)
err = register_netdev(dev);
if (err) {
outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag,
ioaddr, COM9026_REG_RW_CONFIG);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
return err;
}
BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n",
dev->dev_addr[0], dev->base_addr, dev->irq);
arc_printk(D_NORMAL, dev, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n",
dev->dev_addr[0], dev->base_addr, dev->irq);
return 0;
}
/*
* Do a hardware reset on the card, and set up necessary registers.
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
@ -293,67 +281,66 @@ static int com90io_reset(struct net_device *dev, int really_reset)
struct arcnet_local *lp = netdev_priv(dev);
short ioaddr = dev->base_addr;
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS());
arc_printk(D_INIT, dev, "Resetting %s (status=%02Xh)\n",
dev->name, arcnet_inb(ioaddr, COM9026_REG_R_STATUS));
if (really_reset) {
/* reset the card */
inb(_RESET);
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
}
/* Set the thing to IO-mapped, 8-bit mode */
lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag;
SETCONF();
arcnet_outb(lp->config, ioaddr, COM9026_REG_RW_CONFIG);
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
/* clear flags & end reset */
arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
/* verify that the ARCnet signature byte is present */
if (get_buffer_byte(dev, 0) != TESTvalue) {
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
/* done! return success. */
return 0;
}
static void com90io_command(struct net_device *dev, int cmd)
{
short ioaddr = dev->base_addr;
ACOMMAND(cmd);
arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND);
}
static int com90io_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ASTATUS();
return arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
}
static void com90io_setmask(struct net_device *dev, int mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK);
}
static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
static void com90io_copy_to_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
TIME("put_whole_buffer", count, put_whole_buffer(dev, bufnum * 512 + offset, count, buf));
TIME(dev, "put_whole_buffer", count,
put_whole_buffer(dev, bufnum * 512 + offset, count, buf));
}
static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
static void com90io_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf));
TIME(dev, "get_whole_buffer", count,
get_whole_buffer(dev, bufnum * 512 + offset, count, buf));
}
static int io; /* use the insmod io= irq= shmem= options */
@ -369,12 +356,13 @@ MODULE_LICENSE("GPL");
static int __init com90io_setup(char *s)
{
int ints[4];
s = get_options(s, 4, ints);
if (!ints[0])
return 0;
switch (ints[0]) {
default: /* ERROR */
printk("com90io: Too many arguments.\n");
pr_err("Too many arguments\n");
case 2: /* IRQ */
irq = ints[2];
case 1: /* IO address */
@ -421,8 +409,11 @@ static void __exit com90io_exit(void)
unregister_netdev(dev);
/* Set the thing back to MMAP mode, in case the old driver is loaded later */
outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
/* In case the old driver is loaded later,
* set the thing back to MMAP mode
*/
arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) & ~IOMAPflag,
ioaddr, COM9026_REG_RW_CONFIG);
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - COM90xx chipset (memory-mapped buffers)
*
*
* Written 1994-1999 by Avery Pennarun.
* Written 1999 by Martin Mares <mj@ucw.cz>.
* Derived from skeleton.c by Donald Becker.
@ -24,6 +24,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@ -32,12 +35,10 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: COM90xx chipset support\n"
#include <linux/io.h>
#include "arcdevice.h"
#include "com9026.h"
/* Define this to speed up the autoprobe by assuming if only one io port and
* shmem are left in the list at Stage 5, they must correspond to each
@ -53,7 +54,6 @@
*/
#undef FAST_PROBE
/* Internal function declarations */
static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *);
static void com90xx_command(struct net_device *dev, int command);
@ -62,8 +62,8 @@ static void com90xx_setmask(struct net_device *dev, int mask);
static int com90xx_reset(struct net_device *dev, int really_reset);
static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count);
static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
/* Known ARCnet cards */
@ -77,26 +77,7 @@ static int numcards;
/* Amount of I/O memory used by the card */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define _CONFIG (ioaddr+2) /* Configuration register */
#define _RESET (ioaddr+8) /* software reset (on read) */
#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */
#define _ADDR_HI (ioaddr+15) /* Control registers for said */
#define _ADDR_LO (ioaddr+14)
#undef ASTATUS
#undef ACOMMAND
#undef AINTMASK
#define ASTATUS() inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
#define MIRROR_SIZE (BUFFER_SIZE * 4)
static int com90xx_skip_probe __initdata = 0;
@ -116,8 +97,7 @@ static void __init com90xx_probe(void)
{
int count, status, ioaddr, numprint, airq, openparen = 0;
unsigned long airqmask;
int ports[(0x3f0 - 0x200) / 16 + 1] =
{0};
int ports[(0x3f0 - 0x200) / 16 + 1] = { 0 };
unsigned long *shmems;
void __iomem **iomem;
int numports, numshmems, *port;
@ -127,18 +107,19 @@ static void __init com90xx_probe(void)
if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
return;
shmems = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(unsigned long),
shmems = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(unsigned long),
GFP_KERNEL);
if (!shmems)
return;
iomem = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(void __iomem *),
GFP_KERNEL);
iomem = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(void __iomem *),
GFP_KERNEL);
if (!iomem) {
kfree(shmems);
return;
}
BUGLVL(D_NORMAL) printk(VERSION);
if (BUGLVL(D_NORMAL))
pr_info("%s\n", "COM90xx chipset support");
/* set up the arrays where we'll store the possible probe addresses */
numports = numshmems = 0;
@ -161,38 +142,43 @@ static void __init com90xx_probe(void)
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S1: ");
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S1: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
arc_cont(D_INIT, "%Xh ", *port);
ioaddr = *port;
if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) {
BUGMSG2(D_INIT_REASONS, "(request_region)\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
if (!request_region(*port, ARCNET_TOTAL_SIZE,
"arcnet (90xx)")) {
arc_cont(D_INIT_REASONS, "(request_region)\n");
arc_cont(D_INIT_REASONS, "S1: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
*port-- = ports[--numports];
continue;
}
if (ASTATUS() == 0xFF) {
BUGMSG2(D_INIT_REASONS, "(empty)\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) {
arc_cont(D_INIT_REASONS, "(empty)\n");
arc_cont(D_INIT_REASONS, "S1: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
}
inb(_RESET); /* begin resetting card */
/* begin resetting card */
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG2(D_INIT_REASONS, "S1: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "\n");
arc_cont(D_INIT_REASONS, "S1: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
}
BUGMSG2(D_INIT, "\n");
arc_cont(D_INIT, "\n");
if (!numports) {
BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n");
arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n");
kfree(shmems);
kfree(iomem);
return;
@ -206,12 +192,12 @@ static void __init com90xx_probe(void)
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S2: ");
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S2: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
arc_cont(D_INIT, "%Xh ", *port);
}
BUGMSG2(D_INIT, "\n");
arc_cont(D_INIT, "\n");
mdelay(RESETtime);
/* Stage 3: abandon any shmem addresses that don't have the signature
@ -224,29 +210,33 @@ static void __init com90xx_probe(void)
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S3: ");
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S3: ");
}
BUGMSG2(D_INIT, "%lXh ", *p);
arc_cont(D_INIT, "%lXh ", *p);
if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) {
BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n");
BUGMSG2(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "(request_mem_region)\n");
arc_cont(D_INIT_REASONS, "Stage 3: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
goto out;
}
base = ioremap(*p, MIRROR_SIZE);
if (!base) {
BUGMSG2(D_INIT_REASONS, "(ioremap)\n");
BUGMSG2(D_INIT_REASONS, "Stage 3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "(ioremap)\n");
arc_cont(D_INIT_REASONS, "Stage 3: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
goto out1;
}
if (readb(base) != TESTvalue) {
BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
readb(base), TESTvalue);
BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) {
arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
arcnet_readb(base, COM9026_REG_R_STATUS),
TESTvalue);
arc_cont(D_INIT_REASONS, "S3: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
goto out2;
}
/* By writing 0x42 to the TESTvalue location, we also make
@ -254,15 +244,16 @@ static void __init com90xx_probe(void)
* in another pass through this loop, they will be discarded
* because *cptr != TESTvalue.
*/
writeb(0x42, base);
if (readb(base) != 0x42) {
BUGMSG2(D_INIT_REASONS, "(read only)\n");
BUGMSG2(D_INIT_REASONS, "S3: ");
arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK);
if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) {
arc_cont(D_INIT_REASONS, "(read only)\n");
arc_cont(D_INIT_REASONS, "S3: ");
goto out2;
}
BUGMSG2(D_INIT_REASONS, "\n");
BUGMSG2(D_INIT_REASONS, "S3: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "\n");
arc_cont(D_INIT_REASONS, "S3: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
iomem[index] = base;
continue;
out2:
@ -273,10 +264,10 @@ static void __init com90xx_probe(void)
*p-- = shmems[--numshmems];
index--;
}
BUGMSG2(D_INIT, "\n");
arc_cont(D_INIT, "\n");
if (!numshmems) {
BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n");
arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n");
for (port = &ports[0]; port < ports + numports; port++)
release_region(*port, ARCNET_TOTAL_SIZE);
kfree(shmems);
@ -291,12 +282,12 @@ static void __init com90xx_probe(void)
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S4: ");
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S4: ");
}
BUGMSG2(D_INIT, "%lXh ", *p);
arc_cont(D_INIT, "%lXh ", *p);
}
BUGMSG2(D_INIT, "\n");
arc_cont(D_INIT, "\n");
/* Stage 5: for any ports that have the correct status, can disable
* the RESET flag, and (if no irq is given) generate an autoirq,
@ -308,33 +299,37 @@ static void __init com90xx_probe(void)
numprint = -1;
for (port = &ports[0]; port < ports + numports; port++) {
int found = 0;
numprint++;
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
BUGMSG2(D_INIT, "S5: ");
arc_cont(D_INIT, "\n");
arc_cont(D_INIT, "S5: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
arc_cont(D_INIT, "%Xh ", *port);
ioaddr = *port;
status = ASTATUS();
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
if ((status & 0x9D)
!= (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status);
arc_cont(D_INIT_REASONS, "S5: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
}
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
status = ASTATUS();
arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear,
ioaddr, COM9026_REG_W_COMMAND);
status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
if (status & RESETflag) {
BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
status);
arc_cont(D_INIT_REASONS, "S5: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
@ -348,15 +343,16 @@ static void __init com90xx_probe(void)
* we tell it to start receiving.
*/
airqmask = probe_irq_on();
AINTMASK(NORXflag);
arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK);
udelay(1);
AINTMASK(0);
arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK);
airq = probe_irq_off(airqmask);
if (airq <= 0) {
BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
BUGMSG2(D_INIT_REASONS, "S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
arc_cont(D_INIT_REASONS, "(airq=%d)\n", airq);
arc_cont(D_INIT_REASONS, "S5: ");
if (BUGLVL(D_INIT_REASONS))
numprint = 0;
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
continue;
@ -365,7 +361,7 @@ static void __init com90xx_probe(void)
airq = irq;
}
BUGMSG2(D_INIT, "(%d,", airq);
arc_cont(D_INIT, "(%d,", airq);
openparen = 1;
/* Everything seems okay. But which shmem, if any, puts
@ -376,14 +372,15 @@ static void __init com90xx_probe(void)
*/
#ifdef FAST_PROBE
if (numports > 1 || numshmems > 1) {
inb(_RESET);
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
} else {
/* just one shmem and port, assume they match */
writeb(TESTvalue, iomem[0]);
arcnet_writeb(TESTvalue, iomem[0],
COM9026_REG_W_INTMASK);
}
#else
inb(_RESET);
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
#endif
@ -391,8 +388,8 @@ static void __init com90xx_probe(void)
u_long ptr = shmems[index];
void __iomem *base = iomem[index];
if (readb(base) == TESTvalue) { /* found one */
BUGMSG2(D_INIT, "%lXh)\n", *p);
if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) { /* found one */
arc_cont(D_INIT, "%lXh)\n", *p);
openparen = 0;
/* register the card */
@ -405,25 +402,30 @@ static void __init com90xx_probe(void)
iomem[index] = iomem[numshmems];
break; /* go to the next I/O port */
} else {
BUGMSG2(D_INIT_REASONS, "%Xh-", readb(base));
arc_cont(D_INIT_REASONS, "%Xh-",
arcnet_readb(base, COM9026_REG_R_STATUS));
}
}
if (openparen) {
BUGLVL(D_INIT) printk("no matching shmem)\n");
BUGLVL(D_INIT_REASONS) printk("S5: ");
BUGLVL(D_INIT_REASONS) numprint = 0;
if (BUGLVL(D_INIT))
pr_cont("no matching shmem)\n");
if (BUGLVL(D_INIT_REASONS)) {
pr_cont("S5: ");
numprint = 0;
}
}
if (!found)
release_region(*port, ARCNET_TOTAL_SIZE);
*port-- = ports[--numports];
}
BUGLVL(D_INIT_REASONS) printk("\n");
if (BUGLVL(D_INIT_REASONS))
pr_cont("\n");
/* Now put back TESTvalue on all leftover shmems. */
for (index = 0; index < numshmems; index++) {
writeb(TESTvalue, iomem[index]);
arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK);
iounmap(iomem[index]);
release_mem_region(shmems[index], MIRROR_SIZE);
}
@ -441,7 +443,7 @@ static int check_mirror(unsigned long addr, size_t size)
p = ioremap(addr, size);
if (p) {
if (readb(p) == TESTvalue)
if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue)
res = 1;
else
res = 0;
@ -455,7 +457,8 @@ static int check_mirror(unsigned long addr, size_t size)
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p)
static int __init com90xx_found(int ioaddr, int airq, u_long shmem,
void __iomem *p)
{
struct net_device *dev = NULL;
struct arcnet_local *lp;
@ -465,7 +468,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem
/* allocate struct net_device */
dev = alloc_arcdev(device);
if (!dev) {
BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");
arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n");
iounmap(p);
release_mem_region(shmem, MIRROR_SIZE);
return -ENOMEM;
@ -478,7 +481,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem
* 2k (or there are no mirrors at all) but on some, it's 4k.
*/
mirror_size = MIRROR_SIZE;
if (readb(p) == TESTvalue &&
if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue &&
check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&
check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)
mirror_size = 2 * MIRROR_SIZE;
@ -499,12 +502,14 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem
iounmap(p);
release_mem_region(shmem, MIRROR_SIZE);
if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"))
if (!request_mem_region(dev->mem_start,
dev->mem_end - dev->mem_start + 1,
"arcnet (90xx)"))
goto err_free_dev;
/* reserve the irq */
if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq);
arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", airq);
goto err_release_mem;
}
dev->irq = airq;
@ -518,22 +523,23 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem
lp->hw.owner = THIS_MODULE;
lp->hw.copy_to_card = com90xx_copy_to_card;
lp->hw.copy_from_card = com90xx_copy_from_card;
lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1);
lp->mem_start = ioremap(dev->mem_start,
dev->mem_end - dev->mem_start + 1);
if (!lp->mem_start) {
BUGMSG(D_NORMAL, "Can't remap device memory!\n");
arc_printk(D_NORMAL, dev, "Can't remap device memory!\n");
goto err_free_irq;
}
/* get and check the station ID from offset 1 in shmem */
dev->dev_addr[0] = readb(lp->mem_start + 1);
dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION);
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, "
"ShMem %lXh (%ld*%xh).\n",
dev->dev_addr[0],
dev->base_addr, dev->irq, dev->mem_start,
(dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size);
arc_printk(D_NORMAL, dev, "COM90xx station %02Xh found at %03lXh, IRQ %d, ShMem %lXh (%ld*%xh).\n",
dev->dev_addr[0],
dev->base_addr, dev->irq, dev->mem_start,
(dev->mem_end - dev->mem_start + 1) / mirror_size,
mirror_size);
if (register_netdev(dev))
goto err_unmap;
@ -552,34 +558,29 @@ err_free_dev:
return -EIO;
}
static void com90xx_command(struct net_device *dev, int cmd)
{
short ioaddr = dev->base_addr;
ACOMMAND(cmd);
arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND);
}
static int com90xx_status(struct net_device *dev)
{
short ioaddr = dev->base_addr;
return ASTATUS();
return arcnet_inb(ioaddr, COM9026_REG_R_STATUS);
}
static void com90xx_setmask(struct net_device *dev, int mask)
{
short ioaddr = dev->base_addr;
AINTMASK(mask);
arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK);
}
/*
* Do a hardware reset on the card, and set up necessary registers.
*
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
* token on the network (causes a RECON) and requires a significant delay.
*
@ -590,53 +591,58 @@ static int com90xx_reset(struct net_device *dev, int really_reset)
struct arcnet_local *lp = netdev_priv(dev);
short ioaddr = dev->base_addr;
BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
arc_printk(D_INIT, dev, "Resetting (status=%02Xh)\n",
arcnet_inb(ioaddr, COM9026_REG_R_STATUS));
if (really_reset) {
/* reset the card */
inb(_RESET);
arcnet_inb(ioaddr, COM9026_REG_R_RESET);
mdelay(RESETtime);
}
ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd | CONFIGclear);
/* clear flags & end reset */
arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND);
arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND);
#if 0
/* don't do this until we verify that it doesn't hurt older cards! */
/* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */
arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag,
ioaddr, COM9026_REG_RW_CONFIG);
#endif
/* verify that the ARCnet signature byte is present */
if (readb(lp->mem_start) != TESTvalue) {
if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) {
if (really_reset)
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd | EXTconf);
arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND);
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(lp->mem_start, 0x42, 2048);
if (BUGLVL(D_DURING))
memset_io(lp->mem_start, 0x42, 2048);
/* done! return success. */
return 0;
}
static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
static void com90xx_copy_to_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));
TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count));
}
static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset,
void *buf, int count)
static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
{
struct arcnet_local *lp = netdev_priv(dev);
void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;
TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
MODULE_LICENSE("GPL");
@ -664,7 +670,8 @@ static void __exit com90xx_exit(void)
free_irq(dev->irq, dev);
iounmap(lp->mem_start);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
release_mem_region(dev->mem_start,
dev->mem_end - dev->mem_start + 1);
free_netdev(dev);
}
}
@ -679,13 +686,13 @@ static int __init com90xx_setup(char *s)
s = get_options(s, 8, ints);
if (!ints[0] && !*s) {
printk("com90xx: Disabled.\n");
pr_notice("Disabled\n");
return 1;
}
switch (ints[0]) {
default: /* ERROR */
printk("com90xx: Too many arguments.\n");
pr_err("Too many arguments\n");
case 3: /* Mem address */
shmem = ints[3];
case 2: /* IRQ */

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation
*
*
* Written 1994-1999 by Avery Pennarun.
* Derived from skeleton.c by Donald Becker.
*
@ -23,6 +23,9 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/init.h>
@ -30,10 +33,8 @@
#include <net/arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n"
#include "arcdevice.h"
static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
@ -43,9 +44,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum);
static struct ArcProto rfc1051_proto =
{
static struct ArcProto rfc1051_proto = {
.suffix = 's',
.mtu = XMTU - RFC1051_HDR_SIZE,
.is_ip = 1,
@ -56,10 +55,9 @@ static struct ArcProto rfc1051_proto =
.ack_tx = NULL
};
static int __init arcnet_rfc1051_init(void)
{
printk(VERSION);
pr_info("%s\n", "RFC1051 \"simple standard\" (`s') encapsulation support loaded");
arc_proto_map[ARC_P_IP_RFC1051]
= arc_proto_map[ARC_P_ARP_RFC1051]
@ -82,14 +80,13 @@ module_exit(arcnet_rfc1051_exit);
MODULE_LICENSE("GPL");
/*
* Determine a packet's protocol ID.
*
/* Determine a packet's protocol ID.
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct archdr *pkt = (struct archdr *) skb->data;
struct archdr *pkt = (struct archdr *)skb->data;
struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
@ -97,9 +94,9 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
skb_reset_mac_header(skb);
skb_pull(skb, hdr_size);
if (pkt->hard.dest == 0)
if (pkt->hard.dest == 0) {
skb->pkt_type = PACKET_BROADCAST;
else if (dev->flags & IFF_PROMISC) {
} else if (dev->flags & IFF_PROMISC) {
/* if we're not sending to ourselves :) */
if (pkt->hard.dest != dev->dev_addr[0])
skb->pkt_type = PACKET_OTHERHOST;
@ -120,7 +117,6 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_IP);
}
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
@ -130,7 +126,7 @@ static void rx(struct net_device *dev, int bufnum,
struct archdr *pkt = pkthdr;
int ofs;
BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length);
arc_printk(D_DURING, dev, "it's a raw packet (length=%d)\n", length);
if (length >= MinTU)
ofs = 512 - length;
@ -138,15 +134,14 @@ static void rx(struct net_device *dev, int bufnum,
ofs = 256 - length;
skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
if (!skb) {
dev->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE);
skb->dev = dev;
pkt = (struct archdr *) skb->data;
pkt = (struct archdr *)skb->data;
/* up to sizeof(pkt->soft) has already been copied from the card */
memcpy(pkt, pkthdr, sizeof(struct archdr));
@ -155,21 +150,19 @@ static void rx(struct net_device *dev, int bufnum,
pkt->soft.raw + sizeof(pkt->soft),
length - sizeof(pkt->soft));
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
}
/*
* Create the ARCnet hard/soft headers for RFC1051.
*/
/* Create the ARCnet hard/soft headers for RFC1051 */
static int build_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, uint8_t daddr)
{
int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size);
struct arc_rfc1051 *soft = &pkt->soft.rfc1051;
/* set the protocol ID according to RFC1051 */
@ -181,29 +174,26 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
soft->proto = ARC_P_ARP_RFC1051;
break;
default:
BUGMSG(D_NORMAL, "RFC1051: I don't understand protocol %d (%Xh)\n",
type, type);
arc_printk(D_NORMAL, dev, "RFC1051: I don't understand protocol %d (%Xh)\n",
type, type);
dev->stats.tx_errors++;
dev->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
/* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. ARCnet does not allow us to change the source address in
* the actual packet sent)
* debugging. ARCnet does not allow us to change the source address
* in the actual packet sent.
*/
pkt->hard.source = *dev->dev_addr;
/* see linux/net/ethernet/eth.c to see where I got the following */
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
/*
* FIXME: fill in the last byte of the dest ipaddr here to better
* comply with RFC1051 in "noarp" mode.
/* FIXME: fill in the last byte of the dest ipaddr here to
* better comply with RFC1051 in "noarp" mode.
*/
pkt->hard.dest = 0;
return hdr_size;
@ -214,7 +204,6 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
return hdr_size; /* success */
}
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum)
{
@ -222,15 +211,16 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
struct arc_hardware *hard = &pkt->hard;
int ofs;
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
/* hard header is not included in packet length */
length -= ARC_HDR_SIZE;
if (length > XMTU) {
/* should never happen! other people already check for this. */
BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
arc_printk(D_NORMAL, dev, "Bug! prepare_tx with size %d (> %d)\n",
length, XMTU);
length = XMTU;
}
if (length > MinTU) {
@ -239,8 +229,9 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
} else if (length > MTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length - 3;
} else
} else {
hard->offset[0] = ofs = 256 - length;
}
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length);

View file

@ -1,6 +1,6 @@
/*
* Linux ARCnet driver - RFC1201 (standard) packet encapsulation
*
*
* Written 1994-1999 by Avery Pennarun.
* Derived from skeleton.c by Donald Becker.
*
@ -23,17 +23,19 @@
*
* **********************
*/
#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/arcdevice.h>
#include "arcdevice.h"
MODULE_LICENSE("GPL");
#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n"
static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
@ -44,8 +46,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum);
static int continue_tx(struct net_device *dev, int bufnum);
static struct ArcProto rfc1201_proto =
{
static struct ArcProto rfc1201_proto = {
.suffix = 'a',
.mtu = 1500, /* could be more, but some receivers can't handle it... */
.is_ip = 1, /* This is for sending IP and ARP packages */
@ -56,10 +57,9 @@ static struct ArcProto rfc1201_proto =
.ack_tx = NULL
};
static int __init arcnet_rfc1201_init(void)
{
printk(VERSION);
pr_info("%s\n", "RFC1201 \"standard\" (`a') encapsulation support loaded");
arc_proto_map[ARC_P_IP]
= arc_proto_map[ARC_P_IPV6]
@ -84,14 +84,13 @@ static void __exit arcnet_rfc1201_exit(void)
module_init(arcnet_rfc1201_init);
module_exit(arcnet_rfc1201_exit);
/*
* Determine a packet's protocol ID.
*
/* Determine a packet's protocol ID.
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct archdr *pkt = (struct archdr *) skb->data;
struct archdr *pkt = (struct archdr *)skb->data;
struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
@ -99,9 +98,9 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
skb_reset_mac_header(skb);
skb_pull(skb, hdr_size);
if (pkt->hard.dest == 0)
if (pkt->hard.dest == 0) {
skb->pkt_type = PACKET_BROADCAST;
else if (dev->flags & IFF_PROMISC) {
} else if (dev->flags & IFF_PROMISC) {
/* if we're not sending to ourselves :) */
if (pkt->hard.dest != dev->dev_addr[0])
skb->pkt_type = PACKET_OTHERHOST;
@ -129,7 +128,6 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_IP);
}
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
@ -141,7 +139,8 @@ static void rx(struct net_device *dev, int bufnum,
int saddr = pkt->hard.source, ofs;
struct Incoming *in = &lp->rfc1201.incoming[saddr];
BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", length);
arc_printk(D_DURING, dev, "it's an RFC1201 packet (length=%d)\n",
length);
if (length >= MinTU)
ofs = 512 - length;
@ -149,11 +148,11 @@ static void rx(struct net_device *dev, int bufnum,
ofs = 256 - length;
if (soft->split_flag == 0xFF) { /* Exception Packet */
if (length >= 4 + RFC1201_HDR_SIZE)
BUGMSG(D_DURING, "compensating for exception packet\n");
else {
BUGMSG(D_EXTRA, "short RFC1201 exception packet from %02Xh",
saddr);
if (length >= 4 + RFC1201_HDR_SIZE) {
arc_printk(D_DURING, dev, "compensating for exception packet\n");
} else {
arc_printk(D_EXTRA, dev, "short RFC1201 exception packet from %02Xh",
saddr);
return;
}
@ -164,12 +163,13 @@ static void rx(struct net_device *dev, int bufnum,
soft, sizeof(pkt->soft));
}
if (!soft->split_flag) { /* not split */
BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n",
soft->split_flag);
arc_printk(D_RX, dev, "incoming is not split (splitflag=%d)\n",
soft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
arc_printk(D_EXTRA, dev, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag,
soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
dev_kfree_skb_irq(in->skb);
dev->stats.rx_errors++;
@ -179,82 +179,86 @@ static void rx(struct net_device *dev, int bufnum,
in->sequence = soft->sequence;
skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n");
if (!skb) {
dev->stats.rx_dropped++;
return;
}
skb_put(skb, length + ARC_HDR_SIZE);
skb->dev = dev;
pkt = (struct archdr *) skb->data;
pkt = (struct archdr *)skb->data;
soft = &pkt->soft.rfc1201;
/* up to sizeof(pkt->soft) has already been copied from the card */
/* up to sizeof(pkt->soft) has already
* been copied from the card
*/
memcpy(pkt, pkthdr, sizeof(struct archdr));
if (length > sizeof(pkt->soft))
lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft),
pkt->soft.raw + sizeof(pkt->soft),
lp->hw.copy_from_card(dev, bufnum,
ofs + sizeof(pkt->soft),
pkt->soft.raw + sizeof(pkt->soft),
length - sizeof(pkt->soft));
/*
* ARP packets have problems when sent from some DOS systems: the
* source address is always 0! So we take the hardware source addr
* (which is impossible to fumble) and insert it ourselves.
/* ARP packets have problems when sent from some DOS systems:
* the source address is always 0!
* So we take the hardware source addr (which is impossible
* to fumble) and insert it ourselves.
*/
if (soft->proto == ARC_P_ARP) {
struct arphdr *arp = (struct arphdr *) soft->payload;
struct arphdr *arp = (struct arphdr *)soft->payload;
/* make sure addresses are the right length */
if (arp->ar_hln == 1 && arp->ar_pln == 4) {
uint8_t *cptr = (uint8_t *) arp + sizeof(struct arphdr);
uint8_t *cptr = (uint8_t *)arp + sizeof(struct arphdr);
if (!*cptr) { /* is saddr = 00? */
BUGMSG(D_EXTRA,
"ARP source address was 00h, set to %02Xh.\n",
saddr);
arc_printk(D_EXTRA, dev,
"ARP source address was 00h, set to %02Xh\n",
saddr);
dev->stats.rx_crc_errors++;
*cptr = saddr;
} else {
BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n",
*cptr);
arc_printk(D_DURING, dev, "ARP source address (%Xh) is fine.\n",
*cptr);
}
} else {
BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln, arp->ar_pln);
arc_printk(D_NORMAL, dev, "funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln, arp->ar_pln);
dev->stats.rx_errors++;
dev->stats.rx_crc_errors++;
}
}
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
} else { /* split packet */
/*
* NOTE: MSDOS ARP packet correction should only need to apply to
* unsplit packets, since ARP packets are so short.
/* NOTE: MSDOS ARP packet correction should only need to
* apply to unsplit packets, since ARP packets are so short.
*
* My interpretation of the RFC1201 document is that if a packet is
* received out of order, the entire assembly process should be
* aborted.
* My interpretation of the RFC1201 document is that if a
* packet is received out of order, the entire assembly
* process should be aborted.
*
* The RFC also mentions "it is possible for successfully received
* packets to be retransmitted." As of 0.40 all previously received
* packets are allowed, not just the most recent one.
* The RFC also mentions "it is possible for successfully
* received packets to be retransmitted." As of 0.40 all
* previously received packets are allowed, not just the
* most recent one.
*
* We allow multiple assembly processes, one for each ARCnet card
* possible on the network. Seems rather like a waste of memory,
* but there's no other way to be reliable.
* We allow multiple assembly processes, one for each
* ARCnet card possible on the network.
* Seems rather like a waste of memory, but there's no
* other way to be reliable.
*/
BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n",
soft->split_flag, in->sequence);
arc_printk(D_RX, dev, "packet is split (splitflag=%d, seq=%d)\n",
soft->split_flag, in->sequence);
if (in->skb && in->sequence != soft->sequence) {
BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
saddr, in->sequence, soft->sequence,
soft->split_flag);
arc_printk(D_EXTRA, dev, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
saddr, in->sequence, soft->sequence,
soft->split_flag);
dev_kfree_skb_irq(in->skb);
in->skb = NULL;
dev->stats.rx_errors++;
@ -262,24 +266,23 @@ static void rx(struct net_device *dev, int bufnum,
in->lastpacket = in->numpackets = 0;
}
if (soft->split_flag & 1) { /* first packet in split */
BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n",
soft->split_flag);
arc_printk(D_RX, dev, "brand new splitpacket (splitflag=%d)\n",
soft->split_flag);
if (in->skb) { /* already assembling one! */
BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly "
"(splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag,
soft->sequence);
arc_printk(D_EXTRA, dev, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag,
soft->sequence);
dev->stats.rx_errors++;
dev->stats.rx_missed_errors++;
dev_kfree_skb_irq(in->skb);
}
in->sequence = soft->sequence;
in->numpackets = ((unsigned) soft->split_flag >> 1) + 2;
in->numpackets = ((unsigned)soft->split_flag >> 1) + 2;
in->lastpacket = 1;
if (in->numpackets > 16) {
BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
soft->split_flag);
arc_printk(D_EXTRA, dev, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
soft->split_flag);
lp->rfc1201.aborted_seq = soft->sequence;
dev->stats.rx_errors++;
dev->stats.rx_length_errors++;
@ -287,14 +290,14 @@ static void rx(struct net_device *dev, int bufnum,
}
in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE,
GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n");
if (!skb) {
arc_printk(D_NORMAL, dev, "(split) memory squeeze, dropping packet.\n");
lp->rfc1201.aborted_seq = soft->sequence;
dev->stats.rx_dropped++;
return;
}
skb->dev = dev;
pkt = (struct archdr *) skb->data;
pkt = (struct archdr *)skb->data;
soft = &pkt->soft.rfc1201;
memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE);
@ -302,37 +305,37 @@ static void rx(struct net_device *dev, int bufnum,
soft->split_flag = 0; /* end result won't be split */
} else { /* not first packet */
int packetnum = ((unsigned) soft->split_flag >> 1) + 1;
int packetnum = ((unsigned)soft->split_flag >> 1) + 1;
/*
* if we're not assembling, there's no point trying to
/* if we're not assembling, there's no point trying to
* continue.
*/
if (!in->skb) {
if (lp->rfc1201.aborted_seq != soft->sequence) {
BUGMSG(D_EXTRA, "can't continue split without starting "
"first! (splitflag=%d, seq=%d, aborted=%d)\n",
soft->split_flag, soft->sequence,
lp->rfc1201.aborted_seq);
arc_printk(D_EXTRA, dev, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n",
soft->split_flag,
soft->sequence,
lp->rfc1201.aborted_seq);
dev->stats.rx_errors++;
dev->stats.rx_missed_errors++;
}
return;
}
in->lastpacket++;
if (packetnum != in->lastpacket) { /* not the right flag! */
/* if not the right flag */
if (packetnum != in->lastpacket) {
/* harmless duplicate? ignore. */
if (packetnum <= in->lastpacket - 1) {
BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n",
soft->split_flag);
arc_printk(D_EXTRA, dev, "duplicate splitpacket ignored! (splitflag=%d)\n",
soft->split_flag);
dev->stats.rx_errors++;
dev->stats.rx_frame_errors++;
return;
}
/* "bad" duplicate, kill reassembly */
BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly "
"(seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag, soft->sequence);
arc_printk(D_EXTRA, dev, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence, soft->split_flag,
soft->sequence);
lp->rfc1201.aborted_seq = soft->sequence;
dev_kfree_skb_irq(in->skb);
in->skb = NULL;
@ -341,7 +344,7 @@ static void rx(struct net_device *dev, int bufnum,
in->lastpacket = in->numpackets = 0;
return;
}
pkt = (struct archdr *) in->skb->data;
pkt = (struct archdr *)in->skb->data;
soft = &pkt->soft.rfc1201;
}
@ -357,11 +360,12 @@ static void rx(struct net_device *dev, int bufnum,
in->skb = NULL;
in->lastpacket = in->numpackets = 0;
BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (unsplit)\n",
skb->len, pkt->hard.source);
BUGMSG(D_SKB_SIZE, "skb: received %d bytes from %02X (split)\n",
skb->len, pkt->hard.source);
BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx");
arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (unsplit)\n",
skb->len, pkt->hard.source);
arc_printk(D_SKB_SIZE, dev, "skb: received %d bytes from %02X (split)\n",
skb->len, pkt->hard.source);
if (BUGLVL(D_SKB))
arcnet_dump_skb(dev, skb, "rx");
skb->protocol = type_trans(skb, dev);
netif_rx(skb);
@ -369,14 +373,13 @@ static void rx(struct net_device *dev, int bufnum,
}
}
/* Create the ARCnet hard/soft headers for RFC1201. */
static int build_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, uint8_t daddr)
{
struct arcnet_local *lp = netdev_priv(dev);
int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size);
struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size);
struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
/* set the protocol ID according to RFC1201 */
@ -402,19 +405,18 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
soft->proto = ARC_P_ATALK;
break;
default:
BUGMSG(D_NORMAL, "RFC1201: I don't understand protocol %d (%Xh)\n",
type, type);
arc_printk(D_NORMAL, dev, "RFC1201: I don't understand protocol %d (%Xh)\n",
type, type);
dev->stats.tx_errors++;
dev->stats.tx_aborted_errors++;
return 0;
}
/*
* Set the source hardware address.
/* Set the source hardware address.
*
* This is pretty pointless for most purposes, but it can help in
* debugging. ARCnet does not allow us to change the source address in
* the actual packet sent)
* debugging. ARCnet does not allow us to change the source address
* in the actual packet sent.
*/
pkt->hard.source = *dev->dev_addr;
@ -424,10 +426,10 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
/* see linux/net/ethernet/eth.c to see where I got the following */
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
/*
* FIXME: fill in the last byte of the dest ipaddr here to better
* comply with RFC1051 in "noarp" mode. For now, always broadcasting
* will probably at least get packets sent out :)
/* FIXME: fill in the last byte of the dest ipaddr here
* to better comply with RFC1051 in "noarp" mode.
* For now, always broadcasting will probably at least get
* packets sent out :)
*/
pkt->hard.dest = 0;
return hdr_size;
@ -437,7 +439,6 @@ static int build_header(struct sk_buff *skb, struct net_device *dev,
return hdr_size;
}
static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
struct arc_rfc1201 *soft, int softlen, int bufnum)
{
@ -461,8 +462,9 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
hard->offset[1] = ofs - RFC1201_HDR_SIZE;
lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE,
&excsoft, RFC1201_HDR_SIZE);
} else
} else {
hard->offset[0] = ofs = 256 - softlen;
}
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen);
@ -470,7 +472,6 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
lp->lastload_dest = hard->dest;
}
static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
int bufnum)
{
@ -478,11 +479,11 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
const int maxsegsize = XMTU - RFC1201_HDR_SIZE;
struct Outgoing *out;
arc_printk(D_DURING, dev, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n",
lp->next_tx, lp->cur_tx, bufnum);
length -= ARC_HDR_SIZE; /* hard header is not included in packet length */
/* hard header is not included in packet length */
length -= ARC_HDR_SIZE;
pkt->soft.rfc1201.split_flag = 0;
/* need to do a split packet? */
@ -494,9 +495,9 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize;
out->segnum = 0;
BUGMSG(D_DURING, "rfc1201 prep_tx: ready for %d-segment split "
"(%d bytes, seq=%d)\n", out->numsegs, out->length,
pkt->soft.rfc1201.sequence);
arc_printk(D_DURING, dev, "rfc1201 prep_tx: ready for %d-segment split (%d bytes, seq=%d)\n",
out->numsegs, out->length,
pkt->soft.rfc1201.sequence);
return 0; /* not done */
}
@ -506,7 +507,6 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
return 1; /* done */
}
static int continue_tx(struct net_device *dev, int bufnum)
{
struct arcnet_local *lp = netdev_priv(dev);
@ -516,9 +516,9 @@ static int continue_tx(struct net_device *dev, int bufnum)
int maxsegsize = XMTU - RFC1201_HDR_SIZE;
int seglen;
BUGMSG(D_DURING,
"rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n",
out->segnum, out->numsegs, soft->sequence);
arc_printk(D_DURING, dev,
"rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n",
out->segnum, out->numsegs, soft->sequence);
/* the "new" soft header comes right before the data chunk */
newsoft = (struct arc_rfc1201 *)

View file

@ -127,6 +127,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
struct port *port);
static void ad_marker_response_received(struct bond_marker *marker,
struct port *port);
static void ad_update_actor_keys(struct port *port, bool reset);
/* ================= api to bonding and kernel code ================== */
@ -327,14 +328,12 @@ static u16 __get_link_speed(struct port *port)
static u8 __get_duplex(struct port *port)
{
struct slave *slave = port->slave;
u8 retval;
u8 retval = 0x0;
/* handling a special case: when the configuration starts with
* link down, it sets the duplex to 0.
*/
if (slave->link != BOND_LINK_UP) {
retval = 0x0;
} else {
if (slave->link == BOND_LINK_UP) {
switch (slave->duplex) {
case DUPLEX_FULL:
retval = 0x1;
@ -1953,14 +1952,7 @@ void bond_3ad_bind_slave(struct slave *slave)
* user key
*/
port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
port->actor_admin_port_key |= __get_duplex(port);
port->actor_admin_port_key |= (__get_link_speed(port) << 1);
port->actor_oper_port_key = port->actor_admin_port_key;
/* if the port is not full duplex, then the port should be not
* lacp Enabled
*/
if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS))
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
ad_update_actor_keys(port, false);
/* actor system is the bond's system */
port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
port->actor_system_priority =
@ -2310,45 +2302,60 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
}
/**
* bond_3ad_adapter_speed_changed - handle a slave's speed change indication
* @slave: slave struct to work on
* ad_update_actor_keys - Update the oper / admin keys for a port based on
* its current speed and duplex settings.
*
* Handle reselection of aggregator (if needed) for this port.
* @port: the port we'are looking at
* @reset: Boolean to just reset the speed and the duplex part of the key
*
* The logic to change the oper / admin keys is:
* (a) A full duplex port can participate in LACP with partner.
* (b) When the speed is changed, LACP need to be reinitiated.
*/
void bond_3ad_adapter_speed_changed(struct slave *slave)
static void ad_update_actor_keys(struct port *port, bool reset)
{
struct port *port;
u8 duplex = 0;
u16 ospeed = 0, speed = 0;
u16 old_oper_key = port->actor_oper_port_key;
port = &(SLAVE_AD_INFO(slave)->port);
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
netdev_warn(slave->bond->dev, "speed changed for uninitialized port on %s\n",
slave->dev->name);
return;
port->actor_admin_port_key &= ~(AD_SPEED_KEY_MASKS|AD_DUPLEX_KEY_MASKS);
if (!reset) {
speed = __get_link_speed(port);
ospeed = (old_oper_key & AD_SPEED_KEY_MASKS) >> 1;
duplex = __get_duplex(port);
port->actor_admin_port_key |= (speed << 1) | duplex;
}
spin_lock_bh(&slave->bond->mode_lock);
port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS;
port->actor_admin_port_key |= __get_link_speed(port) << 1;
port->actor_oper_port_key = port->actor_admin_port_key;
netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number);
/* there is no need to reselect a new aggregator, just signal the
* state machines to reinitialize
*/
port->sm_vars |= AD_PORT_BEGIN;
spin_unlock_bh(&slave->bond->mode_lock);
if (old_oper_key != port->actor_oper_port_key) {
/* Only 'duplex' port participates in LACP */
if (duplex)
port->sm_vars |= AD_PORT_LACP_ENABLED;
else
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
if (!reset) {
if (!speed) {
netdev_err(port->slave->dev,
"speed changed to 0 for port %s",
port->slave->dev->name);
} else if (duplex && ospeed != speed) {
/* Speed change restarts LACP state-machine */
port->sm_vars |= AD_PORT_BEGIN;
}
}
}
}
/**
* bond_3ad_adapter_duplex_changed - handle a slave's duplex change indication
* bond_3ad_adapter_speed_duplex_changed - handle a slave's speed / duplex
* change indication
*
* @slave: slave struct to work on
*
* Handle reselection of aggregator (if needed) for this port.
*/
void bond_3ad_adapter_duplex_changed(struct slave *slave)
void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
{
struct port *port;
@ -2356,25 +2363,16 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
/* if slave is null, the whole port is not initialized */
if (!port->slave) {
netdev_warn(slave->bond->dev, "duplex changed for uninitialized port on %s\n",
netdev_warn(slave->bond->dev,
"speed/duplex changed for uninitialized port %s\n",
slave->dev->name);
return;
}
spin_lock_bh(&slave->bond->mode_lock);
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS;
port->actor_admin_port_key |= __get_duplex(port);
port->actor_oper_port_key = port->actor_admin_port_key;
netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n",
ad_update_actor_keys(port, false);
netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
port->actor_port_number, slave->dev->name);
if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
port->sm_vars |= AD_PORT_LACP_ENABLED;
/* there is no need to reselect a new aggregator, just signal the
* state machines to reinitialize
*/
port->sm_vars |= AD_PORT_BEGIN;
spin_unlock_bh(&slave->bond->mode_lock);
}
@ -2406,26 +2404,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
* on link up we are forcing recheck on the duplex and speed since
* some of he adaptors(ce1000.lan) report.
*/
port->actor_admin_port_key &= ~(AD_DUPLEX_KEY_MASKS|AD_SPEED_KEY_MASKS);
if (link == BOND_LINK_UP) {
port->is_enabled = true;
port->actor_admin_port_key |=
(__get_link_speed(port) << 1) | __get_duplex(port);
if (port->actor_admin_port_key & AD_DUPLEX_KEY_MASKS)
port->sm_vars |= AD_PORT_LACP_ENABLED;
ad_update_actor_keys(port, false);
} else {
/* link has failed */
port->is_enabled = false;
port->sm_vars &= ~AD_PORT_LACP_ENABLED;
ad_update_actor_keys(port, true);
}
port->actor_oper_port_key = port->actor_admin_port_key;
netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
port->actor_port_number,
link == BOND_LINK_UP ? "UP" : "DOWN");
/* there is no need to reselect a new aggregator, just signal the
* state machines to reinitialize
*/
port->sm_vars |= AD_PORT_BEGIN;
spin_unlock_bh(&slave->bond->mode_lock);

View file

@ -1071,7 +1071,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
NETIF_F_HIGHDMA | NETIF_F_LRO)
#define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\
NETIF_F_TSO)
NETIF_F_ALL_TSO)
static void bond_compute_features(struct bonding *bond)
{
@ -2943,8 +2943,6 @@ static int bond_slave_netdev_event(unsigned long event,
struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary;
struct bonding *bond;
struct net_device *bond_dev;
u32 old_speed;
u8 old_duplex;
/* A netdev event can be generated while enslaving a device
* before netdev_rx_handler_register is called in which case
@ -2965,17 +2963,9 @@ static int bond_slave_netdev_event(unsigned long event,
break;
case NETDEV_UP:
case NETDEV_CHANGE:
old_speed = slave->speed;
old_duplex = slave->duplex;
bond_update_speed_duplex(slave);
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
if (old_speed != slave->speed)
bond_3ad_adapter_speed_changed(slave);
if (old_duplex != slave->duplex)
bond_3ad_adapter_duplex_changed(slave);
}
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_adapter_speed_duplex_changed(slave);
/* Fallthrough */
case NETDEV_DOWN:
/* Refresh slave-array if applicable!
@ -3136,6 +3126,10 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
struct flow_keys flow;
u32 hash;
if (bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP34 &&
skb->l4_hash)
return skb->hash;
if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
!bond_flow_dissect(bond, skb, &flow))
return bond_eth_hash(skb);

View file

@ -129,6 +129,16 @@ config CAN_RCAR
To compile this driver as a module, choose M here: the module will
be called rcar_can.
config CAN_SUN4I
tristate "Allwinner A10 CAN controller"
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
---help---
Say Y here if you want to use CAN controller found on Allwinner
A10/A20 SoCs.
To compile this driver as a module, choose M here: the module will
be called sun4i_can.
config CAN_XILINXCAN
tristate "Xilinx CAN"
depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST

View file

@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o
obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
subdir-ccflags-y += -D__CHECK_ENDIAN__

View file

@ -8,15 +8,6 @@
* Public License ("GPL") version 2 as distributed in the 'COPYING'
* file from the main directory of the linux kernel source.
*
*
* Your platform definition file should specify something like:
*
* static struct at91_can_data ek_can_data = {
* transceiver_switch = sam9263ek_transceiver_switch,
* };
*
* at91_add_device_can(&ek_can_data);
*
*/
#include <linux/clk.h>
@ -33,7 +24,6 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/platform_data/atmel.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
@ -324,15 +314,6 @@ static inline u32 at91_can_id_to_reg_mid(canid_t can_id)
return reg_mid;
}
/*
* Swtich transceiver on or off
*/
static void at91_transceiver_switch(const struct at91_priv *priv, int on)
{
if (priv->pdata && priv->pdata->transceiver_switch)
priv->pdata->transceiver_switch(on);
}
static void at91_setup_mailboxes(struct net_device *dev)
{
struct at91_priv *priv = netdev_priv(dev);
@ -416,7 +397,6 @@ static void at91_chip_start(struct net_device *dev)
at91_set_bittiming(dev);
at91_setup_mailboxes(dev);
at91_transceiver_switch(priv, 1);
/* enable chip */
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
@ -444,7 +424,6 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
reg_mr = at91_read(priv, AT91_MR);
at91_write(priv, AT91_MR, reg_mr & ~AT91_MR_CANEN);
at91_transceiver_switch(priv, 0);
priv->can.state = state;
}

View file

@ -915,7 +915,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put(skb, IFLA_CAN_BITTIMING_CONST,
sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
nla_put_u32(skb, IFLA_CAN_STATE, state) ||
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||

View file

@ -26,12 +26,8 @@
#include <linux/can/led.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@ -63,10 +59,10 @@
#define FLEXCAN_MCR_LPRIO_EN BIT(13)
#define FLEXCAN_MCR_AEN BIT(12)
#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f)
#define FLEXCAN_MCR_IDAM_A (0 << 8)
#define FLEXCAN_MCR_IDAM_B (1 << 8)
#define FLEXCAN_MCR_IDAM_C (2 << 8)
#define FLEXCAN_MCR_IDAM_D (3 << 8)
#define FLEXCAN_MCR_IDAM_A (0x0 << 8)
#define FLEXCAN_MCR_IDAM_B (0x1 << 8)
#define FLEXCAN_MCR_IDAM_C (0x2 << 8)
#define FLEXCAN_MCR_IDAM_D (0x3 << 8)
/* FLEXCAN control register (CANCTRL) bits */
#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24)
@ -161,7 +157,7 @@
#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24)
#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24)
#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24)
#define FLEXCAN_MB_CODE_RX_OVERRRUN (0x6 << 24)
#define FLEXCAN_MB_CODE_RX_OVERRUN (0x6 << 24)
#define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24)
#define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24)
@ -175,12 +171,9 @@
#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16)
#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff)
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
#define FLEXCAN_TIMEOUT_US (50)
#define FLEXCAN_TIMEOUT_US (50)
/*
* FLEXCAN hardware feature flags
/* FLEXCAN hardware feature flags
*
* Below is some version info we got:
* SOC Version IP-Version Glitch- [TR]WRN_INT Memory err RTR re-
@ -194,9 +187,9 @@
*
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
*/
#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
#define FLEXCAN_HAS_MECR_FEATURES BIT(3) /* Memory error detection */
#define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */
#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
#define FLEXCAN_QUIRK_DISABLE_MECR BIT(3) /* Disble Memory error detection */
/* Structure of the message buffer */
struct flexcan_mb {
@ -228,7 +221,7 @@ struct flexcan_regs {
u32 rxfgmask; /* 0x48 */
u32 rxfir; /* 0x4c */
u32 _reserved3[12]; /* 0x50 */
struct flexcan_mb cantxfg[64]; /* 0x80 */
struct flexcan_mb mb[64]; /* 0x80 */
/* FIFO-mode:
* MB
* 0x080...0x08f 0 RX message buffer
@ -236,7 +229,7 @@ struct flexcan_regs {
* 0x0e0...0x0ff 6-7 8 entry ID table
* (mx25, mx28, mx35, mx53)
* 0x0e0...0x2df 6-7..37 8..128 entry ID table
* size conf'ed via ctrl2::RFFN
* size conf'ed via ctrl2::RFFN
* (mx6, vf610)
*/
u32 _reserved4[408];
@ -251,14 +244,14 @@ struct flexcan_regs {
};
struct flexcan_devtype_data {
u32 features; /* hardware controller features */
u32 quirks; /* quirks needed for different IP cores */
};
struct flexcan_priv {
struct can_priv can;
struct napi_struct napi;
void __iomem *base;
struct flexcan_regs __iomem *regs;
u32 reg_esr;
u32 reg_ctrl_default;
@ -270,14 +263,17 @@ struct flexcan_priv {
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
.features = FLEXCAN_HAS_BROKEN_ERR_STATE,
.quirks = FLEXCAN_QUIRK_BROKEN_ERR_STATE,
};
static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
.features = FLEXCAN_HAS_V10_FEATURES,
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG,
};
static struct flexcan_devtype_data fsl_vf610_devtype_data = {
.features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_MECR_FEATURES,
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
@ -292,11 +288,10 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
.brp_inc = 1,
};
/*
* Abstract off the read/write for arm versus ppc. This
/* Abstract off the read/write for arm versus ppc. This
* assumes that PPC uses big-endian registers and everything
* else uses little-endian registers, independent of CPU
* endianess.
* endianness.
*/
#if defined(CONFIG_PPC)
static inline u32 flexcan_read(void __iomem *addr)
@ -345,7 +340,7 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
static int flexcan_chip_enable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
@ -364,7 +359,7 @@ static int flexcan_chip_enable(struct flexcan_priv *priv)
static int flexcan_chip_disable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
@ -383,7 +378,7 @@ static int flexcan_chip_disable(struct flexcan_priv *priv)
static int flexcan_chip_freeze(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
u32 reg;
@ -402,7 +397,7 @@ static int flexcan_chip_freeze(struct flexcan_priv *priv)
static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
@ -421,7 +416,7 @@ static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
static int flexcan_chip_softreset(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
@ -434,12 +429,11 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv)
return 0;
}
static int __flexcan_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg = flexcan_read(&regs->ecr);
bec->txerr = (reg >> 0) & 0xff;
@ -474,9 +468,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
struct can_frame *cf = (struct can_frame *)skb->data;
u32 can_id;
u32 data;
u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
if (can_dropped_invalid_skb(dev, skb))
@ -495,26 +490,26 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
ctrl |= FLEXCAN_MB_CNT_RTR;
if (cf->can_dlc > 0) {
u32 data = be32_to_cpup((__be32 *)&cf->data[0]);
flexcan_write(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
data = be32_to_cpup((__be32 *)&cf->data[0]);
flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[0]);
}
if (cf->can_dlc > 3) {
u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
flexcan_write(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
data = be32_to_cpup((__be32 *)&cf->data[4]);
flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[1]);
}
can_put_echo_skb(skb, dev, 0);
flexcan_write(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
flexcan_write(ctrl, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
flexcan_write(can_id, &regs->mb[FLEXCAN_TX_BUF_ID].can_id);
flexcan_write(ctrl, &regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
/* Errata ERR005829 step8:
* Write twice INACTIVE(0x8) code to first MB.
*/
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
&regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
&regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
return NETDEV_TX_OK;
}
@ -597,14 +592,14 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
new_state = max(tx_state, rx_state);
} else {
__flexcan_get_berr_counter(dev, &bec);
new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ?
CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
}
@ -633,8 +628,8 @@ static void flexcan_read_fifo(const struct net_device *dev,
struct can_frame *cf)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
struct flexcan_regs __iomem *regs = priv->regs;
struct flexcan_mb __iomem *mb = &regs->mb[0];
u32 reg_ctrl, reg_id;
reg_ctrl = flexcan_read(&mb->can_ctrl);
@ -683,12 +678,11 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
{
struct net_device *dev = napi->dev;
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
int work_done = 0;
/*
* The error bits are cleared on read,
/* The error bits are cleared on read,
* use saved value from irq handler.
*/
reg_esr = flexcan_read(&regs->esr) | priv->reg_esr;
@ -723,17 +717,17 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
reg_iflag1 = flexcan_read(&regs->iflag1);
reg_esr = flexcan_read(&regs->esr);
/* ACK all bus error and state change IRQ sources */
if (reg_esr & FLEXCAN_ESR_ALL_INT)
flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, &regs->esr);
/*
* schedule NAPI in case of:
/* schedule NAPI in case of:
* - rx IRQ
* - state change IRQ
* - bus error IRQ and bus error reporting is activated
@ -741,15 +735,14 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
(reg_esr & FLEXCAN_ESR_ERR_STATE) ||
flexcan_has_and_handle_berr(priv, reg_esr)) {
/*
* The error bits are cleared on read,
/* The error bits are cleared on read,
* save them for later use.
*/
priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
flexcan_write(FLEXCAN_IFLAG_DEFAULT &
~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
&regs->ctrl);
&regs->ctrl);
napi_schedule(&priv->napi);
}
@ -765,9 +758,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++;
can_led_event(dev, CAN_LED_EVENT_TX);
/* after sending a RTR frame mailbox is in RX mode */
/* after sending a RTR frame MB is in RX mode */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
&regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev);
}
@ -779,7 +773,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg;
reg = flexcan_read(&regs->ctrl);
@ -813,8 +807,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
flexcan_read(&regs->mcr), flexcan_read(&regs->ctrl));
}
/*
* flexcan_chip_start
/* flexcan_chip_start
*
* this functions is entered with clocks enabled
*
@ -822,7 +815,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
int err, i;
@ -838,29 +831,26 @@ static int flexcan_chip_start(struct net_device *dev)
flexcan_set_bittiming(dev);
/*
* MCR
/* MCR
*
* enable freeze
* enable fifo
* halt now
* only supervisor access
* enable warning int
* choose format C
* disable local echo
*
* choose format C
* set max mailbox number
*/
reg_mcr = flexcan_read(&regs->mcr);
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS |
FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
flexcan_write(reg_mcr, &regs->mcr);
/*
* CTRL
/* CTRL
*
* disable timer sync feature
*
@ -875,12 +865,12 @@ static int flexcan_chip_start(struct net_device *dev)
reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
FLEXCAN_CTRL_ERR_STATE;
/*
* enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK),
/* enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK),
* on most Flexcan cores, too. Otherwise we don't get
* any error warning or passive interrupts.
*/
if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_ERR_STATE ||
priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
else
@ -888,41 +878,41 @@ static int flexcan_chip_start(struct net_device *dev)
/* save for later use */
priv->reg_ctrl_default = reg_ctrl;
/* leave interrupts disabled for now */
reg_ctrl &= ~FLEXCAN_CTRL_ERR_ALL;
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
flexcan_write(reg_ctrl, &regs->ctrl);
/* clear and invalidate all mailboxes first */
for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->cantxfg); i++) {
for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->mb); i++) {
flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE,
&regs->cantxfg[i].can_ctrl);
&regs->mb[i].can_ctrl);
}
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
&regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
/* mark TX mailbox as INACTIVE */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
&regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
/* acceptance mask/acceptance code (accept everything) */
flexcan_write(0x0, &regs->rxgmask);
flexcan_write(0x0, &regs->rx14mask);
flexcan_write(0x0, &regs->rx15mask);
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
flexcan_write(0x0, &regs->rxfgmask);
/*
* On Vybrid, disable memory error detection interrupts
/* On Vybrid, disable memory error detection interrupts
* and freeze mode.
* This also works around errata e5295 which generates
* false positive memory errors and put the device in
* freeze mode.
*/
if (priv->devtype_data->features & FLEXCAN_HAS_MECR_FEATURES) {
/*
* Follow the protocol as described in "Detection
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) {
/* Follow the protocol as described in "Detection
* and Correction of Memory Errors" to write to
* MECR register
*/
@ -934,7 +924,7 @@ static int flexcan_chip_start(struct net_device *dev)
reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
flexcan_write(reg_mecr, &regs->mecr);
reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
FLEXCAN_MECR_FANCEI_MSK);
FLEXCAN_MECR_FANCEI_MSK);
flexcan_write(reg_mecr, &regs->mecr);
}
@ -949,8 +939,11 @@ static int flexcan_chip_start(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable FIFO interrupts */
/* enable interrupts atomically */
disable_irq(dev->irq);
flexcan_write(priv->reg_ctrl_default, &regs->ctrl);
flexcan_write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
enable_irq(dev->irq);
/* print chip status */
netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
@ -965,16 +958,14 @@ static int flexcan_chip_start(struct net_device *dev)
return err;
}
/*
* flexcan_chip_stop
/* flexcan_chip_stop
*
* this functions is entered with clocks enabled
*
*/
static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
/* freeze + disable module */
flexcan_chip_freeze(priv);
@ -987,8 +978,6 @@ static void flexcan_chip_stop(struct net_device *dev)
flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
return;
}
static int flexcan_open(struct net_device *dev)
@ -1085,7 +1074,7 @@ static const struct net_device_ops flexcan_netdev_ops = {
static int register_flexcandev(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg, err;
err = clk_prepare_enable(priv->clk_ipg);
@ -1114,8 +1103,7 @@ static int register_flexcandev(struct net_device *dev)
FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
flexcan_write(reg, &regs->mcr);
/*
* Currently we only support newer versions of this core
/* Currently we only support newer versions of this core
* featuring a RX FIFO. Older cores found on some Coldfire
* derivates are not yet supported.
*/
@ -1168,7 +1156,7 @@ static int flexcan_probe(struct platform_device *pdev)
struct regulator *reg_xceiver;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
void __iomem *base;
struct flexcan_regs __iomem *regs;
int err, irq;
u32 clock_freq = 0;
@ -1180,7 +1168,7 @@ static int flexcan_probe(struct platform_device *pdev)
if (pdev->dev.of_node)
of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &clock_freq);
"clock-frequency", &clock_freq);
if (!clock_freq) {
clk_ipg = devm_clk_get(&pdev->dev, "ipg");
@ -1202,9 +1190,9 @@ static int flexcan_probe(struct platform_device *pdev)
if (irq <= 0)
return -ENODEV;
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(regs))
return PTR_ERR(regs);
of_id = of_match_device(flexcan_of_match, &pdev->dev);
if (of_id) {
@ -1232,12 +1220,11 @@ static int flexcan_probe(struct platform_device *pdev)
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
priv->base = base;
priv->regs = regs;
priv->clk_ipg = clk_ipg;
priv->clk_per = clk_per;
priv->pdata = dev_get_platdata(&pdev->dev);
priv->devtype_data = devtype_data;
priv->reg_xceiver = reg_xceiver;
netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
@ -1254,7 +1241,7 @@ static int flexcan_probe(struct platform_device *pdev)
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq);
priv->regs, dev->irq);
return 0;

857
drivers/net/can/sun4i_can.c Normal file
View file

@ -0,0 +1,857 @@
/*
* sun4i_can.c - CAN bus controller driver for Allwinner SUN4I&SUN7I based SoCs
*
* Copyright (C) 2013 Peter Chen
* Copyright (C) 2015 Gerhard Bertelsmann
* All rights reserved.
*
* Parts of this software are based on (derived from) the SJA1000 code by:
* Copyright (C) 2014 Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
* Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2002-2007 Volkswagen Group Electronic Research
* Copyright (C) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
* 38106 Braunschweig, GERMANY
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Volkswagen nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Alternatively, provided that this notice is retained in full, this
* software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2, in which case the provisions of the
* GPL apply INSTEAD OF those given above.
*
* The provided data structures and external interfaces from this code
* are not restricted to be used by modules with a GPL compatible license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define DRV_NAME "sun4i_can"
/* Registers address (physical base address 0x01C2BC00) */
#define SUN4I_REG_MSEL_ADDR 0x0000 /* CAN Mode Select */
#define SUN4I_REG_CMD_ADDR 0x0004 /* CAN Command */
#define SUN4I_REG_STA_ADDR 0x0008 /* CAN Status */
#define SUN4I_REG_INT_ADDR 0x000c /* CAN Interrupt Flag */
#define SUN4I_REG_INTEN_ADDR 0x0010 /* CAN Interrupt Enable */
#define SUN4I_REG_BTIME_ADDR 0x0014 /* CAN Bus Timing 0 */
#define SUN4I_REG_TEWL_ADDR 0x0018 /* CAN Tx Error Warning Limit */
#define SUN4I_REG_ERRC_ADDR 0x001c /* CAN Error Counter */
#define SUN4I_REG_RMCNT_ADDR 0x0020 /* CAN Receive Message Counter */
#define SUN4I_REG_RBUFSA_ADDR 0x0024 /* CAN Receive Buffer Start Address */
#define SUN4I_REG_BUF0_ADDR 0x0040 /* CAN Tx/Rx Buffer 0 */
#define SUN4I_REG_BUF1_ADDR 0x0044 /* CAN Tx/Rx Buffer 1 */
#define SUN4I_REG_BUF2_ADDR 0x0048 /* CAN Tx/Rx Buffer 2 */
#define SUN4I_REG_BUF3_ADDR 0x004c /* CAN Tx/Rx Buffer 3 */
#define SUN4I_REG_BUF4_ADDR 0x0050 /* CAN Tx/Rx Buffer 4 */
#define SUN4I_REG_BUF5_ADDR 0x0054 /* CAN Tx/Rx Buffer 5 */
#define SUN4I_REG_BUF6_ADDR 0x0058 /* CAN Tx/Rx Buffer 6 */
#define SUN4I_REG_BUF7_ADDR 0x005c /* CAN Tx/Rx Buffer 7 */
#define SUN4I_REG_BUF8_ADDR 0x0060 /* CAN Tx/Rx Buffer 8 */
#define SUN4I_REG_BUF9_ADDR 0x0064 /* CAN Tx/Rx Buffer 9 */
#define SUN4I_REG_BUF10_ADDR 0x0068 /* CAN Tx/Rx Buffer 10 */
#define SUN4I_REG_BUF11_ADDR 0x006c /* CAN Tx/Rx Buffer 11 */
#define SUN4I_REG_BUF12_ADDR 0x0070 /* CAN Tx/Rx Buffer 12 */
#define SUN4I_REG_ACPC_ADDR 0x0040 /* CAN Acceptance Code 0 */
#define SUN4I_REG_ACPM_ADDR 0x0044 /* CAN Acceptance Mask 0 */
#define SUN4I_REG_RBUF_RBACK_START_ADDR 0x0180 /* CAN transmit buffer start */
#define SUN4I_REG_RBUF_RBACK_END_ADDR 0x01b0 /* CAN transmit buffer end */
/* Controller Register Description */
/* mode select register (r/w)
* offset:0x0000 default:0x0000_0001
*/
#define SUN4I_MSEL_SLEEP_MODE (0x01 << 4) /* write in reset mode */
#define SUN4I_MSEL_WAKE_UP (0x00 << 4)
#define SUN4I_MSEL_SINGLE_FILTER (0x01 << 3) /* write in reset mode */
#define SUN4I_MSEL_DUAL_FILTERS (0x00 << 3)
#define SUN4I_MSEL_LOOPBACK_MODE BIT(2)
#define SUN4I_MSEL_LISTEN_ONLY_MODE BIT(1)
#define SUN4I_MSEL_RESET_MODE BIT(0)
/* command register (w)
* offset:0x0004 default:0x0000_0000
*/
#define SUN4I_CMD_BUS_OFF_REQ BIT(5)
#define SUN4I_CMD_SELF_RCV_REQ BIT(4)
#define SUN4I_CMD_CLEAR_OR_FLAG BIT(3)
#define SUN4I_CMD_RELEASE_RBUF BIT(2)
#define SUN4I_CMD_ABORT_REQ BIT(1)
#define SUN4I_CMD_TRANS_REQ BIT(0)
/* status register (r)
* offset:0x0008 default:0x0000_003c
*/
#define SUN4I_STA_BIT_ERR (0x00 << 22)
#define SUN4I_STA_FORM_ERR (0x01 << 22)
#define SUN4I_STA_STUFF_ERR (0x02 << 22)
#define SUN4I_STA_OTHER_ERR (0x03 << 22)
#define SUN4I_STA_MASK_ERR (0x03 << 22)
#define SUN4I_STA_ERR_DIR BIT(21)
#define SUN4I_STA_ERR_SEG_CODE (0x1f << 16)
#define SUN4I_STA_START (0x03 << 16)
#define SUN4I_STA_ID28_21 (0x02 << 16)
#define SUN4I_STA_ID20_18 (0x06 << 16)
#define SUN4I_STA_SRTR (0x04 << 16)
#define SUN4I_STA_IDE (0x05 << 16)
#define SUN4I_STA_ID17_13 (0x07 << 16)
#define SUN4I_STA_ID12_5 (0x0f << 16)
#define SUN4I_STA_ID4_0 (0x0e << 16)
#define SUN4I_STA_RTR (0x0c << 16)
#define SUN4I_STA_RB1 (0x0d << 16)
#define SUN4I_STA_RB0 (0x09 << 16)
#define SUN4I_STA_DLEN (0x0b << 16)
#define SUN4I_STA_DATA_FIELD (0x0a << 16)
#define SUN4I_STA_CRC_SEQUENCE (0x08 << 16)
#define SUN4I_STA_CRC_DELIMITER (0x18 << 16)
#define SUN4I_STA_ACK (0x19 << 16)
#define SUN4I_STA_ACK_DELIMITER (0x1b << 16)
#define SUN4I_STA_END (0x1a << 16)
#define SUN4I_STA_INTERMISSION (0x12 << 16)
#define SUN4I_STA_ACTIVE_ERROR (0x11 << 16)
#define SUN4I_STA_PASSIVE_ERROR (0x16 << 16)
#define SUN4I_STA_TOLERATE_DOMINANT_BITS (0x13 << 16)
#define SUN4I_STA_ERROR_DELIMITER (0x17 << 16)
#define SUN4I_STA_OVERLOAD (0x1c << 16)
#define SUN4I_STA_BUS_OFF BIT(7)
#define SUN4I_STA_ERR_STA BIT(6)
#define SUN4I_STA_TRANS_BUSY BIT(5)
#define SUN4I_STA_RCV_BUSY BIT(4)
#define SUN4I_STA_TRANS_OVER BIT(3)
#define SUN4I_STA_TBUF_RDY BIT(2)
#define SUN4I_STA_DATA_ORUN BIT(1)
#define SUN4I_STA_RBUF_RDY BIT(0)
/* interrupt register (r)
* offset:0x000c default:0x0000_0000
*/
#define SUN4I_INT_BUS_ERR BIT(7)
#define SUN4I_INT_ARB_LOST BIT(6)
#define SUN4I_INT_ERR_PASSIVE BIT(5)
#define SUN4I_INT_WAKEUP BIT(4)
#define SUN4I_INT_DATA_OR BIT(3)
#define SUN4I_INT_ERR_WRN BIT(2)
#define SUN4I_INT_TBUF_VLD BIT(1)
#define SUN4I_INT_RBUF_VLD BIT(0)
/* interrupt enable register (r/w)
* offset:0x0010 default:0x0000_0000
*/
#define SUN4I_INTEN_BERR BIT(7)
#define SUN4I_INTEN_ARB_LOST BIT(6)
#define SUN4I_INTEN_ERR_PASSIVE BIT(5)
#define SUN4I_INTEN_WAKEUP BIT(4)
#define SUN4I_INTEN_OR BIT(3)
#define SUN4I_INTEN_ERR_WRN BIT(2)
#define SUN4I_INTEN_TX BIT(1)
#define SUN4I_INTEN_RX BIT(0)
/* error code */
#define SUN4I_ERR_INRCV (0x1 << 5)
#define SUN4I_ERR_INTRANS (0x0 << 5)
/* filter mode */
#define SUN4I_FILTER_CLOSE 0
#define SUN4I_SINGLE_FLTER_MODE 1
#define SUN4I_DUAL_FILTER_MODE 2
/* message buffer flags */
#define SUN4I_MSG_EFF_FLAG BIT(7)
#define SUN4I_MSG_RTR_FLAG BIT(6)
/* max. number of interrupts handled in ISR */
#define SUN4I_CAN_MAX_IRQ 20
#define SUN4I_MODE_MAX_RETRIES 100
struct sun4ican_priv {
struct can_priv can;
void __iomem *base;
struct clk *clk;
spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
};
static const struct can_bittiming_const sun4ican_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
};
static void sun4i_can_write_cmdreg(struct sun4ican_priv *priv, u8 val)
{
unsigned long flags;
spin_lock_irqsave(&priv->cmdreg_lock, flags);
writel(val, priv->base + SUN4I_REG_CMD_ADDR);
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
}
static int set_normal_mode(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
int retry = SUN4I_MODE_MAX_RETRIES;
u32 mod_reg_val = 0;
do {
mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR);
mod_reg_val &= ~SUN4I_MSEL_RESET_MODE;
writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR);
} while (retry-- && (mod_reg_val & SUN4I_MSEL_RESET_MODE));
if (readl(priv->base + SUN4I_REG_MSEL_ADDR) & SUN4I_MSEL_RESET_MODE) {
netdev_err(dev,
"setting controller into normal mode failed!\n");
return -ETIMEDOUT;
}
return 0;
}
static int set_reset_mode(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
int retry = SUN4I_MODE_MAX_RETRIES;
u32 mod_reg_val = 0;
do {
mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR);
mod_reg_val |= SUN4I_MSEL_RESET_MODE;
writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR);
} while (retry-- && !(mod_reg_val & SUN4I_MSEL_RESET_MODE));
if (!(readl(priv->base + SUN4I_REG_MSEL_ADDR) &
SUN4I_MSEL_RESET_MODE)) {
netdev_err(dev, "setting controller into reset mode failed!\n");
return -ETIMEDOUT;
}
return 0;
}
/* bittiming is called in reset_mode only */
static int sun4ican_set_bittiming(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
struct can_bittiming *bt = &priv->can.bittiming;
u32 cfg;
cfg = ((bt->brp - 1) & 0x3FF) |
(((bt->sjw - 1) & 0x3) << 14) |
(((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) << 16) |
(((bt->phase_seg2 - 1) & 0x7) << 20);
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
cfg |= 0x800000;
netdev_dbg(dev, "setting BITTIMING=0x%08x\n", cfg);
writel(cfg, priv->base + SUN4I_REG_BTIME_ADDR);
return 0;
}
static int sun4ican_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct sun4ican_priv *priv = netdev_priv(dev);
u32 errors;
int err;
err = clk_prepare_enable(priv->clk);
if (err) {
netdev_err(dev, "could not enable clock\n");
return err;
}
errors = readl(priv->base + SUN4I_REG_ERRC_ADDR);
bec->txerr = errors & 0xFF;
bec->rxerr = (errors >> 16) & 0xFF;
clk_disable_unprepare(priv->clk);
return 0;
}
static int sun4i_can_start(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
int err;
u32 mod_reg_val;
/* we need to enter the reset mode */
err = set_reset_mode(dev);
if (err) {
netdev_err(dev, "could not enter reset mode\n");
return err;
}
/* set filters - we accept all */
writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR);
writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR);
/* clear error counters and error code capture */
writel(0, priv->base + SUN4I_REG_ERRC_ADDR);
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
writel(0xFF, priv->base + SUN4I_REG_INTEN_ADDR);
else
writel(0xFF & ~SUN4I_INTEN_BERR,
priv->base + SUN4I_REG_INTEN_ADDR);
/* enter the selected mode */
mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR);
if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
mod_reg_val |= SUN4I_MSEL_LOOPBACK_MODE;
else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
mod_reg_val |= SUN4I_MSEL_LISTEN_ONLY_MODE;
writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR);
err = sun4ican_set_bittiming(dev);
if (err)
return err;
/* we are ready to enter the normal mode */
err = set_normal_mode(dev);
if (err) {
netdev_err(dev, "could not enter normal mode\n");
return err;
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
}
static int sun4i_can_stop(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
int err;
priv->can.state = CAN_STATE_STOPPED;
/* we need to enter reset mode */
err = set_reset_mode(dev);
if (err) {
netdev_err(dev, "could not enter reset mode\n");
return err;
}
/* disable all interrupts */
writel(0, priv->base + SUN4I_REG_INTEN_ADDR);
return 0;
}
static int sun4ican_set_mode(struct net_device *dev, enum can_mode mode)
{
int err;
switch (mode) {
case CAN_MODE_START:
err = sun4i_can_start(dev);
if (err) {
netdev_err(dev, "starting CAN controller failed!\n");
return err;
}
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
/* transmit a CAN message
* message layout in the sk_buff should be like this:
* xx xx xx xx ff ll 00 11 22 33 44 55 66 77
* [ can_id ] [flags] [len] [can data (up to 8 bytes]
*/
static int sun4ican_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc;
u32 dreg, msg_flag_n;
canid_t id;
int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
id = cf->can_id;
dlc = cf->can_dlc;
msg_flag_n = dlc;
if (id & CAN_RTR_FLAG)
msg_flag_n |= SUN4I_MSG_RTR_FLAG;
if (id & CAN_EFF_FLAG) {
msg_flag_n |= SUN4I_MSG_EFF_FLAG;
dreg = SUN4I_REG_BUF5_ADDR;
writel((id >> 21) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR);
writel((id >> 13) & 0xFF, priv->base + SUN4I_REG_BUF2_ADDR);
writel((id >> 5) & 0xFF, priv->base + SUN4I_REG_BUF3_ADDR);
writel((id << 3) & 0xF8, priv->base + SUN4I_REG_BUF4_ADDR);
} else {
dreg = SUN4I_REG_BUF3_ADDR;
writel((id >> 3) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR);
writel((id << 5) & 0xE0, priv->base + SUN4I_REG_BUF2_ADDR);
}
for (i = 0; i < dlc; i++)
writel(cf->data[i], priv->base + (dreg + i * 4));
writel(msg_flag_n, priv->base + SUN4I_REG_BUF0_ADDR);
can_put_echo_skb(skb, dev, 0);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
sun4i_can_write_cmdreg(priv, SUN4I_CMD_SELF_RCV_REQ);
else
sun4i_can_write_cmdreg(priv, SUN4I_CMD_TRANS_REQ);
return NETDEV_TX_OK;
}
static void sun4i_can_rx(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u8 fi;
u32 dreg;
canid_t id;
int i;
/* create zero'ed CAN frame buffer */
skb = alloc_can_skb(dev, &cf);
if (!skb)
return;
fi = readl(priv->base + SUN4I_REG_BUF0_ADDR);
cf->can_dlc = get_can_dlc(fi & 0x0F);
if (fi & SUN4I_MSG_EFF_FLAG) {
dreg = SUN4I_REG_BUF5_ADDR;
id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 21) |
(readl(priv->base + SUN4I_REG_BUF2_ADDR) << 13) |
(readl(priv->base + SUN4I_REG_BUF3_ADDR) << 5) |
((readl(priv->base + SUN4I_REG_BUF4_ADDR) >> 3) & 0x1f);
id |= CAN_EFF_FLAG;
} else {
dreg = SUN4I_REG_BUF3_ADDR;
id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 3) |
((readl(priv->base + SUN4I_REG_BUF2_ADDR) >> 5) & 0x7);
}
/* remote frame ? */
if (fi & SUN4I_MSG_RTR_FLAG)
id |= CAN_RTR_FLAG;
else
for (i = 0; i < cf->can_dlc; i++)
cf->data[i] = readl(priv->base + dreg + i * 4);
cf->can_id = id;
sun4i_can_write_cmdreg(priv, SUN4I_CMD_RELEASE_RBUF);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
can_led_event(dev, CAN_LED_EVENT_RX);
}
static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
{
struct sun4ican_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
enum can_state state = priv->can.state;
enum can_state rx_state, tx_state;
unsigned int rxerr, txerr, errc;
u32 ecc, alc;
/* we don't skip if alloc fails because we want the stats anyhow */
skb = alloc_can_err_skb(dev, &cf);
errc = readl(priv->base + SUN4I_REG_ERRC_ADDR);
rxerr = (errc >> 16) & 0xFF;
txerr = errc & 0xFF;
if (skb) {
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
if (isrc & SUN4I_INT_DATA_OR) {
/* data overrun interrupt */
netdev_dbg(dev, "data overrun interrupt\n");
if (likely(skb)) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
}
stats->rx_over_errors++;
stats->rx_errors++;
/* clear bit */
sun4i_can_write_cmdreg(priv, SUN4I_CMD_CLEAR_OR_FLAG);
}
if (isrc & SUN4I_INT_ERR_WRN) {
/* error warning interrupt */
netdev_dbg(dev, "error warning interrupt\n");
if (status & SUN4I_STA_BUS_OFF)
state = CAN_STATE_BUS_OFF;
else if (status & SUN4I_STA_ERR_STA)
state = CAN_STATE_ERROR_WARNING;
else
state = CAN_STATE_ERROR_ACTIVE;
}
if (isrc & SUN4I_INT_BUS_ERR) {
/* bus error interrupt */
netdev_dbg(dev, "bus error interrupt\n");
priv->can.can_stats.bus_error++;
stats->rx_errors++;
if (likely(skb)) {
ecc = readl(priv->base + SUN4I_REG_STA_ADDR);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
switch (ecc & SUN4I_STA_MASK_ERR) {
case SUN4I_STA_BIT_ERR:
cf->data[2] |= CAN_ERR_PROT_BIT;
break;
case SUN4I_STA_FORM_ERR:
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case SUN4I_STA_STUFF_ERR:
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE)
>> 16;
break;
}
/* error occurred during transmission? */
if ((ecc & SUN4I_STA_ERR_DIR) == 0)
cf->data[2] |= CAN_ERR_PROT_TX;
}
}
if (isrc & SUN4I_INT_ERR_PASSIVE) {
/* error passive interrupt */
netdev_dbg(dev, "error passive interrupt\n");
if (state == CAN_STATE_ERROR_PASSIVE)
state = CAN_STATE_ERROR_WARNING;
else
state = CAN_STATE_ERROR_PASSIVE;
}
if (isrc & SUN4I_INT_ARB_LOST) {
/* arbitration lost interrupt */
netdev_dbg(dev, "arbitration lost interrupt\n");
alc = readl(priv->base + SUN4I_REG_STA_ADDR);
priv->can.can_stats.arbitration_lost++;
stats->tx_errors++;
if (likely(skb)) {
cf->can_id |= CAN_ERR_LOSTARB;
cf->data[0] = (alc >> 8) & 0x1f;
}
}
if (state != priv->can.state) {
tx_state = txerr >= rxerr ? state : 0;
rx_state = txerr <= rxerr ? state : 0;
if (likely(skb))
can_change_state(dev, cf, tx_state, rx_state);
else
priv->can.state = state;
if (state == CAN_STATE_BUS_OFF)
can_bus_off(dev);
}
if (likely(skb)) {
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
} else {
return -ENOMEM;
}
return 0;
}
static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct sun4ican_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
u8 isrc, status;
int n = 0;
while ((isrc = readl(priv->base + SUN4I_REG_INT_ADDR)) &&
(n < SUN4I_CAN_MAX_IRQ)) {
n++;
status = readl(priv->base + SUN4I_REG_STA_ADDR);
if (isrc & SUN4I_INT_WAKEUP)
netdev_warn(dev, "wakeup interrupt\n");
if (isrc & SUN4I_INT_TBUF_VLD) {
/* transmission complete interrupt */
stats->tx_bytes +=
readl(priv->base +
SUN4I_REG_RBUF_RBACK_START_ADDR) & 0xf;
stats->tx_packets++;
can_get_echo_skb(dev, 0);
netif_wake_queue(dev);
can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & SUN4I_INT_RBUF_VLD) {
/* receive interrupt */
while (status & SUN4I_STA_RBUF_RDY) {
/* RX buffer is not empty */
sun4i_can_rx(dev);
status = readl(priv->base + SUN4I_REG_STA_ADDR);
}
}
if (isrc &
(SUN4I_INT_DATA_OR | SUN4I_INT_ERR_WRN | SUN4I_INT_BUS_ERR |
SUN4I_INT_ERR_PASSIVE | SUN4I_INT_ARB_LOST)) {
/* error interrupt */
if (sun4i_can_err(dev, isrc, status))
netdev_err(dev, "can't allocate buffer - clearing pending interrupts\n");
}
/* clear interrupts */
writel(isrc, priv->base + SUN4I_REG_INT_ADDR);
readl(priv->base + SUN4I_REG_INT_ADDR);
}
if (n >= SUN4I_CAN_MAX_IRQ)
netdev_dbg(dev, "%d messages handled in ISR", n);
return (n) ? IRQ_HANDLED : IRQ_NONE;
}
static int sun4ican_open(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
int err;
/* common open */
err = open_candev(dev);
if (err)
return err;
/* register interrupt handler */
err = request_irq(dev->irq, sun4i_can_interrupt, 0, dev->name, dev);
if (err) {
netdev_err(dev, "request_irq err: %d\n", err);
goto exit_irq;
}
/* turn on clocking for CAN peripheral block */
err = clk_prepare_enable(priv->clk);
if (err) {
netdev_err(dev, "could not enable CAN peripheral clock\n");
goto exit_clock;
}
err = sun4i_can_start(dev);
if (err) {
netdev_err(dev, "could not start CAN peripheral\n");
goto exit_can_start;
}
can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev);
return 0;
exit_can_start:
clk_disable_unprepare(priv->clk);
exit_clock:
free_irq(dev->irq, dev);
exit_irq:
close_candev(dev);
return err;
}
static int sun4ican_close(struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
sun4i_can_stop(dev);
clk_disable_unprepare(priv->clk);
free_irq(dev->irq, dev);
close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
static const struct net_device_ops sun4ican_netdev_ops = {
.ndo_open = sun4ican_open,
.ndo_stop = sun4ican_close,
.ndo_start_xmit = sun4ican_start_xmit,
};
static const struct of_device_id sun4ican_of_match[] = {
{.compatible = "allwinner,sun4i-a10-can"},
{},
};
MODULE_DEVICE_TABLE(of, sun4ican_of_match);
static int sun4ican_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_netdev(dev);
free_candev(dev);
return 0;
}
static int sun4ican_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct resource *mem;
struct clk *clk;
void __iomem *addr;
int err, irq;
struct net_device *dev;
struct sun4ican_priv *priv;
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "unable to request clock\n");
err = -ENODEV;
goto exit;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "could not get a valid irq\n");
err = -ENODEV;
goto exit;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) {
err = -EBUSY;
goto exit;
}
dev = alloc_candev(sizeof(struct sun4ican_priv), 1);
if (!dev) {
dev_err(&pdev->dev,
"could not allocate memory for CAN device\n");
err = -ENOMEM;
goto exit;
}
dev->netdev_ops = &sun4ican_netdev_ops;
dev->irq = irq;
dev->flags |= IFF_ECHO;
priv = netdev_priv(dev);
priv->can.clock.freq = clk_get_rate(clk);
priv->can.bittiming_const = &sun4ican_bittiming_const;
priv->can.do_set_mode = sun4ican_set_mode;
priv->can.do_get_berr_counter = sun4ican_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_PRESUME_ACK |
CAN_CTRLMODE_3_SAMPLES;
priv->base = addr;
priv->clk = clk;
spin_lock_init(&priv->cmdreg_lock);
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_candev(dev);
if (err) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_free;
}
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (base=%p, irq=%d)\n",
priv->base, dev->irq);
return 0;
exit_free:
free_candev(dev);
exit:
return err;
}
static struct platform_driver sun4i_can_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = sun4ican_of_match,
},
.probe = sun4ican_probe,
.remove = sun4ican_remove,
};
module_platform_driver(sun4i_can_driver);
MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>");
MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20)");

View file

@ -21,10 +21,13 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <net/dsa.h>
#include <linux/ethtool.h>
#include <linux/if_bridge.h>
#include <linux/brcmphy.h>
#include <linux/etherdevice.h>
#include <net/switchdev.h>
#include "bcm_sf2.h"
#include "bcm_sf2_regs.h"
@ -264,6 +267,50 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
}
}
static inline void bcm_sf2_port_intr_enable(struct bcm_sf2_priv *priv,
int port)
{
unsigned int off;
switch (port) {
case 7:
off = P7_IRQ_OFF;
break;
case 0:
/* Port 0 interrupts are located on the first bank */
intrl2_0_mask_clear(priv, P_IRQ_MASK(P0_IRQ_OFF));
return;
default:
off = P_IRQ_OFF(port);
break;
}
intrl2_1_mask_clear(priv, P_IRQ_MASK(off));
}
static inline void bcm_sf2_port_intr_disable(struct bcm_sf2_priv *priv,
int port)
{
unsigned int off;
switch (port) {
case 7:
off = P7_IRQ_OFF;
break;
case 0:
/* Port 0 interrupts are located on the first bank */
intrl2_0_mask_set(priv, P_IRQ_MASK(P0_IRQ_OFF));
intrl2_0_writel(priv, P_IRQ_MASK(P0_IRQ_OFF), INTRL2_CPU_CLEAR);
return;
default:
off = P_IRQ_OFF(port);
break;
}
intrl2_1_mask_set(priv, P_IRQ_MASK(off));
intrl2_1_writel(priv, P_IRQ_MASK(off), INTRL2_CPU_CLEAR);
}
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
@ -280,7 +327,7 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
core_writel(priv, 0, CORE_G_PCTL_PORT(port));
/* Re-enable the GPHY and re-apply workarounds */
if (port == 0 && priv->hw_params.num_gphy == 1) {
if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1) {
bcm_sf2_gphy_enable_set(ds, true);
if (phy) {
/* if phy_stop() has been called before, phy
@ -297,9 +344,9 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
}
}
/* Enable port 7 interrupts to get notified */
if (port == 7)
intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
/* Enable MoCA port interrupts to get notified */
if (port == priv->moca_port)
bcm_sf2_port_intr_enable(priv, port);
/* Set this port, and only this one to be in the default VLAN,
* if member of a bridge, restore its membership prior to
@ -329,12 +376,10 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
if (priv->wol_ports_mask & (1 << port))
return;
if (port == 7) {
intrl2_1_mask_set(priv, P_IRQ_MASK(P7_IRQ_OFF));
intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
}
if (port == priv->moca_port)
bcm_sf2_port_intr_disable(priv, port);
if (port == 0 && priv->hw_params.num_gphy == 1)
if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, false);
if (dsa_is_cpu_port(ds, port))
@ -555,6 +600,236 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
return 0;
}
/* Address Resolution Logic routines */
static int bcm_sf2_arl_op_wait(struct bcm_sf2_priv *priv)
{
unsigned int timeout = 10;
u32 reg;
do {
reg = core_readl(priv, CORE_ARLA_RWCTL);
if (!(reg & ARL_STRTDN))
return 0;
usleep_range(1000, 2000);
} while (timeout--);
return -ETIMEDOUT;
}
static int bcm_sf2_arl_rw_op(struct bcm_sf2_priv *priv, unsigned int op)
{
u32 cmd;
if (op > ARL_RW)
return -EINVAL;
cmd = core_readl(priv, CORE_ARLA_RWCTL);
cmd &= ~IVL_SVL_SELECT;
cmd |= ARL_STRTDN;
if (op)
cmd |= ARL_RW;
else
cmd &= ~ARL_RW;
core_writel(priv, cmd, CORE_ARLA_RWCTL);
return bcm_sf2_arl_op_wait(priv);
}
static int bcm_sf2_arl_read(struct bcm_sf2_priv *priv, u64 mac,
u16 vid, struct bcm_sf2_arl_entry *ent, u8 *idx,
bool is_valid)
{
unsigned int i;
int ret;
ret = bcm_sf2_arl_op_wait(priv);
if (ret)
return ret;
/* Read the 4 bins */
for (i = 0; i < 4; i++) {
u64 mac_vid;
u32 fwd_entry;
mac_vid = core_readq(priv, CORE_ARLA_MACVID_ENTRY(i));
fwd_entry = core_readl(priv, CORE_ARLA_FWD_ENTRY(i));
bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
if (ent->is_valid && is_valid) {
*idx = i;
return 0;
}
/* This is the MAC we just deleted */
if (!is_valid && (mac_vid & mac))
return 0;
}
return -ENOENT;
}
static int bcm_sf2_arl_op(struct bcm_sf2_priv *priv, int op, int port,
const unsigned char *addr, u16 vid, bool is_valid)
{
struct bcm_sf2_arl_entry ent;
u32 fwd_entry;
u64 mac, mac_vid = 0;
u8 idx = 0;
int ret;
/* Convert the array into a 64-bit MAC */
mac = bcm_sf2_mac_to_u64(addr);
/* Perform a read for the given MAC and VID */
core_writeq(priv, mac, CORE_ARLA_MAC);
core_writel(priv, vid, CORE_ARLA_VID);
/* Issue a read operation for this MAC */
ret = bcm_sf2_arl_rw_op(priv, 1);
if (ret)
return ret;
ret = bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
/* If this is a read, just finish now */
if (op)
return ret;
/* We could not find a matching MAC, so reset to a new entry */
if (ret) {
fwd_entry = 0;
idx = 0;
}
memset(&ent, 0, sizeof(ent));
ent.port = port;
ent.is_valid = is_valid;
ent.vid = vid;
ent.is_static = true;
memcpy(ent.mac, addr, ETH_ALEN);
bcm_sf2_arl_from_entry(&mac_vid, &fwd_entry, &ent);
core_writeq(priv, mac_vid, CORE_ARLA_MACVID_ENTRY(idx));
core_writel(priv, fwd_entry, CORE_ARLA_FWD_ENTRY(idx));
ret = bcm_sf2_arl_rw_op(priv, 0);
if (ret)
return ret;
/* Re-read the entry to check */
return bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
}
static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans)
{
/* We do not need to do anything specific here yet */
return 0;
}
static int bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb,
struct switchdev_trans *trans)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true);
}
static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
}
static int bcm_sf2_arl_search_wait(struct bcm_sf2_priv *priv)
{
unsigned timeout = 1000;
u32 reg;
do {
reg = core_readl(priv, CORE_ARLA_SRCH_CTL);
if (!(reg & ARLA_SRCH_STDN))
return 0;
if (reg & ARLA_SRCH_VLID)
return 0;
usleep_range(1000, 2000);
} while (timeout--);
return -ETIMEDOUT;
}
static void bcm_sf2_arl_search_rd(struct bcm_sf2_priv *priv, u8 idx,
struct bcm_sf2_arl_entry *ent)
{
u64 mac_vid;
u32 fwd_entry;
mac_vid = core_readq(priv, CORE_ARLA_SRCH_RSLT_MACVID(idx));
fwd_entry = core_readl(priv, CORE_ARLA_SRCH_RSLT(idx));
bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
}
static int bcm_sf2_sw_fdb_copy(struct net_device *dev, int port,
const struct bcm_sf2_arl_entry *ent,
struct switchdev_obj_port_fdb *fdb,
int (*cb)(struct switchdev_obj *obj))
{
if (!ent->is_valid)
return 0;
if (port != ent->port)
return 0;
ether_addr_copy(fdb->addr, ent->mac);
fdb->vid = ent->vid;
fdb->ndm_state = ent->is_static ? NUD_NOARP : NUD_REACHABLE;
return cb(&fdb->obj);
}
static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_fdb *fdb,
int (*cb)(struct switchdev_obj *obj))
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct net_device *dev = ds->ports[port];
struct bcm_sf2_arl_entry results[2];
unsigned int count = 0;
int ret;
/* Start search operation */
core_writel(priv, ARLA_SRCH_STDN, CORE_ARLA_SRCH_CTL);
do {
ret = bcm_sf2_arl_search_wait(priv);
if (ret)
return ret;
/* Read both entries, then return their values back */
bcm_sf2_arl_search_rd(priv, 0, &results[0]);
ret = bcm_sf2_sw_fdb_copy(dev, port, &results[0], fdb, cb);
if (ret)
return ret;
bcm_sf2_arl_search_rd(priv, 1, &results[1]);
ret = bcm_sf2_sw_fdb_copy(dev, port, &results[1], fdb, cb);
if (ret)
return ret;
if (!results[0].is_valid && !results[1].is_valid)
break;
} while (count++ < CORE_ARLA_NUM_ENTRIES);
return 0;
}
static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
{
struct bcm_sf2_priv *priv = dev_id;
@ -615,6 +890,42 @@ static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)
intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
}
static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
struct device_node *dn)
{
struct device_node *port;
const char *phy_mode_str;
int mode;
unsigned int port_num;
int ret;
priv->moca_port = -1;
for_each_available_child_of_node(dn, port) {
if (of_property_read_u32(port, "reg", &port_num))
continue;
/* Internal PHYs get assigned a specific 'phy-mode' property
* value: "internal" to help flag them before MDIO probing
* has completed, since they might be turned off at that
* time
*/
mode = of_get_phy_mode(port);
if (mode < 0) {
ret = of_property_read_string(port, "phy-mode",
&phy_mode_str);
if (ret < 0)
continue;
if (!strcasecmp(phy_mode_str, "internal"))
priv->int_phy_mask |= 1 << port_num;
}
if (mode == PHY_INTERFACE_MODE_MOCA)
priv->moca_port = port_num;
}
}
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@ -633,6 +944,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
* level
*/
dn = ds->pd->of_node->parent;
bcm_sf2_identify_ports(priv, ds->pd->of_node);
priv->irq0 = irq_of_parse_and_map(dn, 0);
priv->irq1 = irq_of_parse_and_map(dn, 1);
@ -913,7 +1225,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
status->link = 0;
/* Port 7 is special as we do not get link status from CORE_LNKSTS,
/* MoCA port is special as we do not get link status from CORE_LNKSTS,
* which means that we need to force the link at the port override
* level to get the data to flow. We do use what the interrupt handler
* did determine before.
@ -921,7 +1233,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
* For the other ports, we just force the link status, since this is
* a fixed PHY device.
*/
if (port == 7) {
if (port == priv->moca_port) {
status->link = priv->port_sts[port].link;
/* For MoCA interfaces, also force a link down notification
* since some version of the user-space daemon (mocad) use
@ -1076,6 +1388,10 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.port_join_bridge = bcm_sf2_sw_br_join,
.port_leave_bridge = bcm_sf2_sw_br_leave,
.port_stp_update = bcm_sf2_sw_br_set_stp_state,
.port_fdb_prepare = bcm_sf2_sw_fdb_prepare,
.port_fdb_add = bcm_sf2_sw_fdb_add,
.port_fdb_del = bcm_sf2_sw_fdb_del,
.port_fdb_dump = bcm_sf2_sw_fdb_dump,
};
static int __init bcm_sf2_init(void)

View file

@ -19,6 +19,8 @@
#include <linux/mutex.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <net/dsa.h>
@ -50,6 +52,60 @@ struct bcm_sf2_port_status {
u32 vlan_ctl_mask;
};
struct bcm_sf2_arl_entry {
u8 port;
u8 mac[ETH_ALEN];
u16 vid;
u8 is_valid:1;
u8 is_age:1;
u8 is_static:1;
};
static inline void bcm_sf2_mac_from_u64(u64 src, u8 *dst)
{
unsigned int i;
for (i = 0; i < ETH_ALEN; i++)
dst[ETH_ALEN - 1 - i] = (src >> (8 * i)) & 0xff;
}
static inline u64 bcm_sf2_mac_to_u64(const u8 *src)
{
unsigned int i;
u64 dst = 0;
for (i = 0; i < ETH_ALEN; i++)
dst |= (u64)src[ETH_ALEN - 1 - i] << (8 * i);
return dst;
}
static inline void bcm_sf2_arl_to_entry(struct bcm_sf2_arl_entry *ent,
u64 mac_vid, u32 fwd_entry)
{
memset(ent, 0, sizeof(*ent));
ent->port = fwd_entry & PORTID_MASK;
ent->is_valid = !!(fwd_entry & ARL_VALID);
ent->is_age = !!(fwd_entry & ARL_AGE);
ent->is_static = !!(fwd_entry & ARL_STATIC);
bcm_sf2_mac_from_u64(mac_vid, ent->mac);
ent->vid = mac_vid >> VID_SHIFT;
}
static inline void bcm_sf2_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
const struct bcm_sf2_arl_entry *ent)
{
*mac_vid = bcm_sf2_mac_to_u64(ent->mac);
*mac_vid |= (u64)(ent->vid & VID_MASK) << VID_SHIFT;
*fwd_entry = ent->port & PORTID_MASK;
if (ent->is_valid)
*fwd_entry |= ARL_VALID;
if (ent->is_static)
*fwd_entry |= ARL_STATIC;
if (ent->is_age)
*fwd_entry |= ARL_AGE;
}
struct bcm_sf2_priv {
/* Base registers, keep those in order with BCM_SF2_REGS_NAME */
void __iomem *core;
@ -78,6 +134,12 @@ struct bcm_sf2_priv {
/* Mask of ports enabled for Wake-on-LAN */
u32 wol_ports_mask;
/* MoCA port location */
int moca_port;
/* Bitmask of ports having an integrated PHY */
unsigned int int_phy_mask;
};
struct bcm_sf2_hw_stats {

Some files were not shown because too many files have changed in this diff Show more