- PCS registers
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
-- interrupts: Should contain the amd-xgbe interrupt
+- interrupts: Should contain the amd-xgbe interrupt(s). The first interrupt
+ listed is required and is the general device interrupt. If the optional
+ amd,per-channel-interrupt property is specified, then one additional
+ interrupt for each DMA channel supported by the device should be specified
- clocks:
- DMA clock for the amd-xgbe device (used for calculating the
correct Rx interrupt watchdog timer value on a DMA channel
- mac-address: mac address to be assigned to the device. Can be overridden
by UEFI.
- dma-coherent: Present if dma operations are coherent
+- amd,per-channel-interrupt: Indicates that Rx and Tx complete will generate
+ a unique interrupt for each DMA channel - this requires an additional
+ interrupt be configured for each DMA channel
Example:
xgbe@e0700000 {
reg = <0 0xe0700000 0 0x80000>,
<0 0xe0780000 0 0x80000>;
interrupt-parent = <&gic>;
- interrupts = <0 325 4>;
+ interrupts = <0 325 4>,
+ <0 326 1>, <0 327 1>, <0 328 1>, <0 329 1>;
+ amd,per-channel-interrupt;
clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>;
clock-names = "dma_clk", "ptp_clk";
phy-handle = <&phy>;
- dsa,ethernet : Should be a phandle to a valid Ethernet device node
- dsa,mii-bus : Should be a phandle to a valid MDIO bus device node
-Optionnal properties:
+Optional properties:
- interrupts : property with a value describing the switch
interrupt number (not supported by the driver)
- #address-cells : Must be 1
- #size-cells : Must be 0
+A switch child node has the following optional property:
+
+- eeprom-length : Set to the length of an EEPROM connected to the
+ switch. Must be set if the switch can not detect
+ the presence and/or size of a connected EEPROM,
+ otherwise optional.
+
A switch may have multiple "port" children nodes
Each port children node must have the following mandatory properties:
KSZ8021: register 0x1f, bits 5..4
KSZ8031: register 0x1f, bits 5..4
KSZ8051: register 0x1f, bits 5..4
+ KSZ8081: register 0x1f, bits 5..4
+ KSZ8091: register 0x1f, bits 5..4
See the respective PHY datasheet for the mode values.
specifications. If neither of these are specified, the default is to
assume clause 22. The compatible list may also contain other
elements.
-- max-speed: Maximum PHY supported speed (10, 100, 1000...)
If the phy's identifier is known then the list may contain an entry
of the form: "ethernet-phy-idAAAA.BBBB" where
4 hex digits. This is the chip vendor OUI bits 19:24,
followed by 10 bits of a vendor specific ID.
+- max-speed: Maximum PHY supported speed (10, 100, 1000...)
+
Example:
ethernet-phy@0 {
"renesas,ether-r8a7779" if the device is a part of R8A7779 SoC.
"renesas,ether-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,ether-r8a7791" if the device is a part of R8A7791 SoC.
+ "renesas,ether-r8a7793" if the device is a part of R8A7793 SoC.
"renesas,ether-r8a7794" if the device is a part of R8A7794 SoC.
"renesas,ether-r7s72100" if the device is a part of R7S72100 SoC.
- reg: offset and length of (1) the E-DMAC/feLic register block (required),
It is possible to adjust TCP/IP's congestion limits by
altering the net.ipv4.tcp_reordering sysctl parameter. The
- usual default value is 3, and the maximum useful value is 127.
- For a four interface balance-rr bond, expect that a single
- TCP/IP stream will utilize no more than approximately 2.3
- interface's worth of throughput, even after adjusting
- tcp_reordering.
+ usual default value is 3. But keep in mind TCP stack is able
+ to automatically increase this when it detects reorders.
Note that the fraction of packets that will be delivered out of
order is highly variable, and is unlikely to be zero. The level
may consume significant resources. Cf. tcp_max_orphans.
tcp_reordering - INTEGER
- Maximal reordering of packets in a TCP stream.
+ Initial reordering level of packets in a TCP stream.
+ TCP stack can then dynamically adjust flow reordering level
+ between this initial value and tcp_max_reordering
Default: 3
+tcp_max_reordering - INTEGER
+ Maximal reordering level of packets in a TCP stream.
+ 300 is a fairly conservative value, but you might increase it
+ if paths are using per packet load balancing (like bonding rr mode)
+ Default: 300
+
tcp_retrans_collapse - BOOLEAN
Bug-to-bug compatibility with some broken printers.
On retransmit try to send bigger packets to work around bugs in
1 - (default) discard fragmented neighbor discovery packets
0 - allow fragmented neighbor discovery packets
+optimistic_dad - BOOLEAN
+ Whether to perform Optimistic Duplicate Address Detection (RFC 4429).
+ 0: disabled (default)
+ 1: enabled
+
+use_optimistic - BOOLEAN
+ If enabled, do not classify optimistic addresses as deprecated during
+ source address selection. Preferred addresses will still be chosen
+ before optimistic addresses, subject to other ranking in the source
+ address selection algorithm.
+ 0: disabled (default)
+ 1: enabled
+
icmp/*:
ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets.
warnings
--------
-This controls console messages from the networking stack that can occur because
-of problems on the network like duplicate address or bad checksums. Normally,
-this should be enabled, but if the problem persists the messages can be
-disabled.
+This sysctl is now unused.
+
+This was used to control console messages from the networking stack that
+occur because of problems on the network like duplicate address or bad
+checksums.
+
+These messages are now emitted at KERN_DEBUG and can generally be enabled
+and controlled by the dynamic_debug facility.
netdev_budget
-------------
F: security/commoncap.c
F: kernel/capability.c
+CC2520 IEEE-802.15.4 RADIO DRIVER
+M: Varka Bhadram <varkabhadram@gmail.com>
+L: linux-wpan@vger.kernel.org
+S: Maintained
+F: drivers/net/ieee802154/cc2520.c
+F: include/linux/spi/cc2520.h
+F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
+
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@lists.ozlabs.org
F: net/ieee802154/
F: net/mac802154/
F: drivers/net/ieee802154/
+F: include/linux/nl802154.h
+F: include/linux/ieee802154.h
+F: include/net/nl802154.h
+F: include/net/mac802154.h
+F: include/net/af_ieee802154.h
+F: include/net/cfg802154.h
+F: include/net/ieee802154_netdev.h
F: Documentation/networking/ieee802154.txt
IGUANAWORKS USB IR TRANSCEIVER
S: Maintained
F: drivers/gpu/drm/armada/
+MARVELL 88E6352 DSA support
+M: Guenter Roeck <linux@roeck-us.net>
+S: Maintained
+F: drivers/net/dsa/mv88e6352.c
+
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
M: Mirko Lindner <mlindner@marvell.com>
M: Stephen Hemminger <stephen@networkplumber.org>
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _UAPI_ASM_SOCKET_H */
.port_number = 0,
.phy_addr = 0,
.speed = 0, /* Autonagotiation */
+ .intf = PHY_INTERFACE_MODE_RMII,
.init = gplugd_eth_init,
};
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _UAPI__ASM_AVR32_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_IA64_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_M32R_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _UAPI_ASM_SOCKET_H */
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_SOCKET_H */
#define SO_BPF_EXTENSIONS 0x4029
+#define SO_INCOMING_CPU 0x402A
+
#endif /* _UAPI_ASM_SOCKET_H */
#define PPC_INST_ERATSX_DOT 0x7c000127
/* Misc instructions for BPF compiler */
+#define PPC_INST_LBZ 0x88000000
#define PPC_INST_LD 0xe8000000
#define PPC_INST_LHZ 0xa0000000
#define PPC_INST_LHBRX 0x7c00062c
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_POWERPC_SOCKET_H */
#define PPC_STD(r, base, i) EMIT(PPC_INST_STD | ___PPC_RS(r) | \
___PPC_RA(base) | ((i) & 0xfffc))
+
+#define PPC_LBZ(r, base, i) EMIT(PPC_INST_LBZ | ___PPC_RT(r) | \
+ ___PPC_RA(base) | IMM_L(i))
#define PPC_LD(r, base, i) EMIT(PPC_INST_LD | ___PPC_RT(r) | \
___PPC_RA(base) | IMM_L(i))
#define PPC_LWZ(r, base, i) EMIT(PPC_INST_LWZ | ___PPC_RT(r) | \
#define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \
___PPC_RA(base) | ___PPC_RB(b))
/* Convenience helpers for the above with 'far' offsets: */
+#define PPC_LBZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LBZ(r, base, i); \
+ else { PPC_ADDIS(r, base, IMM_HA(i)); \
+ PPC_LBZ(r, r, IMM_L(i)); } } while(0)
+
#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \
else { PPC_ADDIS(r, base, IMM_HA(i)); \
PPC_LD(r, r, IMM_L(i)); } } while(0)
protocol));
break;
case BPF_ANC | SKF_AD_IFINDEX:
+ case BPF_ANC | SKF_AD_HATYPE:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+ ifindex) != 4);
+ BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+ type) != 2);
PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
dev));
PPC_CMPDI(r_scratch1, 0);
PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
} else {
/* Exit, returning 0; first pass hits here. */
- PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
+ PPC_BCC_SHORT(COND_NE, ctx->idx * 4 + 12);
PPC_LI(r_ret, 0);
PPC_JMP(exit_addr);
}
- BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
- ifindex) != 4);
- PPC_LWZ_OFFS(r_A, r_scratch1,
+ if (code == (BPF_ANC | SKF_AD_IFINDEX)) {
+ PPC_LWZ_OFFS(r_A, r_scratch1,
offsetof(struct net_device, ifindex));
+ } else {
+ PPC_LHZ_OFFS(r_A, r_scratch1,
+ offsetof(struct net_device, type));
+ }
+
break;
case BPF_ANC | SKF_AD_MARK:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
queue_mapping));
break;
+ case BPF_ANC | SKF_AD_PKTTYPE:
+ PPC_LBZ_OFFS(r_A, r_skb, PKT_TYPE_OFFSET());
+ PPC_ANDI(r_A, r_A, PKT_TYPE_MAX);
+ PPC_SRWI(r_A, r_A, 5);
+ break;
case BPF_ANC | SKF_AD_CPU:
#ifdef CONFIG_SMP
/*
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _ASM_SOCKET_H */
#define SO_BPF_EXTENSIONS 0x0032
+#define SO_INCOMING_CPU 0x0033
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
-#ifndef _ASM_X86_HASH_H
-#define _ASM_X86_HASH_H
+#ifndef __ASM_X86_HASH_H
+#define __ASM_X86_HASH_H
-struct fast_hash_ops;
-extern void setup_arch_fast_hash(struct fast_hash_ops *ops);
+#include <linux/cpufeature.h>
+#include <asm/alternative.h>
-#endif /* _ASM_X86_HASH_H */
+u32 __intel_crc4_2_hash(const void *data, u32 len, u32 seed);
+u32 __intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed);
+
+/*
+ * non-inline versions of jhash so gcc does not need to generate
+ * duplicate code in every object file
+ */
+u32 __jhash(const void *data, u32 len, u32 seed);
+u32 __jhash2(const u32 *data, u32 len, u32 seed);
+
+/*
+ * for documentation of these functions please look into
+ * <include/asm-generic/hash.h>
+ */
+
+static inline u32 arch_fast_hash(const void *data, u32 len, u32 seed)
+{
+ u32 hash;
+
+ alternative_call(__jhash, __intel_crc4_2_hash, X86_FEATURE_XMM4_2,
+#ifdef CONFIG_X86_64
+ "=a" (hash), "D" (data), "S" (len), "d" (seed));
+#else
+ "=a" (hash), "a" (data), "d" (len), "c" (seed));
+#endif
+ return hash;
+}
+
+static inline u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
+{
+ u32 hash;
+
+ alternative_call(__jhash2, __intel_crc4_2_hash2, X86_FEATURE_XMM4_2,
+#ifdef CONFIG_X86_64
+ "=a" (hash), "D" (data), "S" (len), "d" (seed));
+#else
+ "=a" (hash), "a" (data), "d" (len), "c" (seed));
+#endif
+ return hash;
+}
+
+#endif /* __ASM_X86_HASH_H */
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <linux/hash.h>
-#include <linux/init.h>
-
#include <asm/processor.h>
#include <asm/cpufeature.h>
#include <asm/hash.h>
+#include <linux/hash.h>
+#include <linux/jhash.h>
+
static inline u32 crc32_u32(u32 crc, u32 val)
{
#ifdef CONFIG_AS_CRC32
return crc;
}
-static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed)
+u32 __intel_crc4_2_hash(const void *data, u32 len, u32 seed)
{
const u32 *p32 = (const u32 *) data;
u32 i, tmp = 0;
return seed;
}
+EXPORT_SYMBOL(__intel_crc4_2_hash);
-static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
+u32 __intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
{
- const u32 *p32 = (const u32 *) data;
u32 i;
for (i = 0; i < len; i++)
- seed = crc32_u32(seed, *p32++);
+ seed = crc32_u32(seed, *data++);
return seed;
}
+EXPORT_SYMBOL(__intel_crc4_2_hash2);
-void __init setup_arch_fast_hash(struct fast_hash_ops *ops)
+u32 __jhash(const void *data, u32 len, u32 seed)
{
- if (cpu_has_xmm4_2) {
- ops->hash = intel_crc4_2_hash;
- ops->hash2 = intel_crc4_2_hash2;
- }
+ return jhash(data, len, seed);
+}
+EXPORT_SYMBOL(__jhash);
+
+u32 __jhash2(const u32 *data, u32 len, u32 seed)
+{
+ return jhash2(data, len, seed);
}
+EXPORT_SYMBOL(__jhash2);
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* _XTENSA_SOCKET_H */
/* main.c */
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
int timeout);
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
int __init bcma_bus_early_register(struct bcma_bus *bus,
}
#endif /* CONFIG_OF */
-static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
{
- int err;
-
core->dev.release = bcma_release_core_dev;
core->dev.bus = &bcma_bus_type;
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
case BCMA_HOSTTYPE_SDIO:
break;
}
+}
+
+static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+{
+ int err;
err = device_register(&core->dev);
if (err) {
bus->nr_cores++;
other_core = bcma_find_core_reverse(bus, core->id.id);
core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
+ bcma_prepare_core(bus, core);
bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe05f) },
+ { USB_DEVICE(0x0489, 0xe078) },
{ USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
{ USB_DEVICE(0x04CA, 0x3005) },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
hci_uart_tx_wakeup(hu);
}
+static void h5_peer_reset(struct hci_uart *hu)
+{
+ struct h5 *h5 = hu->priv;
+ struct sk_buff *skb;
+ const unsigned char hard_err[] = { 0x10, 0x01, 0x00 };
+
+ BT_ERR("Peer device has reset");
+
+ h5->state = H5_UNINITIALIZED;
+
+ del_timer(&h5->timer);
+
+ skb_queue_purge(&h5->rel);
+ skb_queue_purge(&h5->unrel);
+ skb_queue_purge(&h5->unack);
+
+ h5->tx_seq = 0;
+ h5->tx_ack = 0;
+
+ skb = bt_skb_alloc(3, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+ memcpy(skb_put(skb, 3), hard_err, 3);
+
+ /* Send Hardware Error to upper stack */
+ hci_recv_frame(hu->hdev, skb);
+}
+
static int h5_open(struct hci_uart *hu)
{
struct h5 *h5;
conf_req[2] = h5_cfg_field(h5);
if (memcmp(data, sync_req, 2) == 0) {
+ if (h5->state == H5_ACTIVE)
+ h5_peer_reset(hu);
h5_link_control(hu, sync_rsp, 2);
} else if (memcmp(data, sync_rsp, 2) == 0) {
+ if (h5->state == H5_ACTIVE)
+ h5_peer_reset(hu);
h5->state = H5_INITIALIZED;
h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_req, 2) == 0) {
skb = get_skb(skb, flowclen, GFP_KERNEL);
flowc = (struct fw_flowc_wr *)__skb_put(skb, flowclen);
- flowc->op_to_nparams = cpu_to_be32(FW_WR_OP(FW_FLOWC_WR) |
- FW_FLOWC_WR_NPARAMS(8));
- flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(flowclen,
- 16)) | FW_WR_FLOWID(ep->hwtid));
+ flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
+ FW_FLOWC_WR_NPARAMS_V(8));
+ flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(flowclen,
+ 16)) | FW_WR_FLOWID_V(ep->hwtid));
flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
- if (win > RCV_BUFSIZ_MASK)
- win = RCV_BUFSIZ_MASK;
+ if (win > RCV_BUFSIZ_M)
+ win = RCV_BUFSIZ_M;
opt0 = (nocong ? NO_CONG(1) : 0) |
- KEEP_ALIVE(1) |
+ KEEP_ALIVE_F |
DELACK(1) |
- WND_SCALE(wscale) |
- MSS_IDX(mtu_idx) |
- L2T_IDX(ep->l2t->idx) |
- TX_CHAN(ep->tx_chan) |
- SMAC_SEL(ep->smac_idx) |
+ WND_SCALE_V(wscale) |
+ MSS_IDX_V(mtu_idx) |
+ L2T_IDX_V(ep->l2t->idx) |
+ TX_CHAN_V(ep->tx_chan) |
+ SMAC_SEL_V(ep->smac_idx) |
DSCP(ep->tos) |
- ULP_MODE(ULP_MODE_TCPDDP) |
- RCV_BUFSIZ(win);
- opt2 = RX_CHANNEL(0) |
+ ULP_MODE_V(ULP_MODE_TCPDDP) |
+ RCV_BUFSIZ_V(win);
+ opt2 = RX_CHANNEL_V(0) |
CCTRL_ECN(enable_ecn) |
- RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
+ RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
if (enable_tcp_timestamps)
opt2 |= TSTAMPS_EN(1);
if (enable_tcp_sack)
opt2 |= SACK_EN(1);
if (wscale && enable_tcp_window_scaling)
- opt2 |= WND_SCALE_EN(1);
+ opt2 |= WND_SCALE_EN_F;
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
- opt2 |= T5_OPT_2_VALID;
+ opt2 |= T5_OPT_2_VALID_F;
opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
}
t5_req->local_ip = la->sin_addr.s_addr;
t5_req->peer_ip = ra->sin_addr.s_addr;
t5_req->opt0 = cpu_to_be64(opt0);
- t5_req->params = cpu_to_be64(V_FILTER_TUPLE(
+ t5_req->params = cpu_to_be64(FILTER_TUPLE_V(
cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
ep->l2t)));
t5_req6->peer_ip_lo = *((__be64 *)
(ra6->sin6_addr.s6_addr + 8));
t5_req6->opt0 = cpu_to_be64(opt0);
- t5_req6->params = cpu_to_be64(V_FILTER_TUPLE(
+ t5_req6->params = cpu_to_be64(FILTER_TUPLE_V(
cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
ep->l2t)));
req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen);
memset(req, 0, wrlen);
req->op_to_immdlen = cpu_to_be32(
- FW_WR_OP(FW_OFLD_TX_DATA_WR) |
- FW_WR_COMPL(1) |
- FW_WR_IMMDLEN(mpalen));
+ FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+ FW_WR_COMPL_F |
+ FW_WR_IMMDLEN_V(mpalen));
req->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(ep->hwtid) |
- FW_WR_LEN16(wrlen >> 4));
+ FW_WR_FLOWID_V(ep->hwtid) |
+ FW_WR_LEN16_V(wrlen >> 4));
req->plen = cpu_to_be32(mpalen);
req->tunnel_to_proxy = cpu_to_be32(
- FW_OFLD_TX_DATA_WR_FLUSH(1) |
- FW_OFLD_TX_DATA_WR_SHOVE(1));
+ FW_OFLD_TX_DATA_WR_FLUSH_F |
+ FW_OFLD_TX_DATA_WR_SHOVE_F);
mpa = (struct mpa_message *)(req + 1);
memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen);
memset(req, 0, wrlen);
req->op_to_immdlen = cpu_to_be32(
- FW_WR_OP(FW_OFLD_TX_DATA_WR) |
- FW_WR_COMPL(1) |
- FW_WR_IMMDLEN(mpalen));
+ FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+ FW_WR_COMPL_F |
+ FW_WR_IMMDLEN_V(mpalen));
req->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(ep->hwtid) |
- FW_WR_LEN16(wrlen >> 4));
+ FW_WR_FLOWID_V(ep->hwtid) |
+ FW_WR_LEN16_V(wrlen >> 4));
req->plen = cpu_to_be32(mpalen);
req->tunnel_to_proxy = cpu_to_be32(
- FW_OFLD_TX_DATA_WR_FLUSH(1) |
- FW_OFLD_TX_DATA_WR_SHOVE(1));
+ FW_OFLD_TX_DATA_WR_FLUSH_F |
+ FW_OFLD_TX_DATA_WR_SHOVE_F);
mpa = (struct mpa_message *)(req + 1);
memset(mpa, 0, sizeof(*mpa));
req = (struct fw_ofld_tx_data_wr *) skb_put(skb, wrlen);
memset(req, 0, wrlen);
req->op_to_immdlen = cpu_to_be32(
- FW_WR_OP(FW_OFLD_TX_DATA_WR) |
- FW_WR_COMPL(1) |
- FW_WR_IMMDLEN(mpalen));
+ FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+ FW_WR_COMPL_F |
+ FW_WR_IMMDLEN_V(mpalen));
req->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(ep->hwtid) |
- FW_WR_LEN16(wrlen >> 4));
+ FW_WR_FLOWID_V(ep->hwtid) |
+ FW_WR_LEN16_V(wrlen >> 4));
req->plen = cpu_to_be32(mpalen);
req->tunnel_to_proxy = cpu_to_be32(
- FW_OFLD_TX_DATA_WR_FLUSH(1) |
- FW_OFLD_TX_DATA_WR_SHOVE(1));
+ FW_OFLD_TX_DATA_WR_FLUSH_F |
+ FW_OFLD_TX_DATA_WR_SHOVE_F);
mpa = (struct mpa_message *)(req + 1);
memset(mpa, 0, sizeof(*mpa));
* due to the limit in the number of bits in the RCV_BUFSIZ field,
* then add the overage in to the credits returned.
*/
- if (ep->rcv_win > RCV_BUFSIZ_MASK * 1024)
- credits += ep->rcv_win - RCV_BUFSIZ_MASK * 1024;
+ if (ep->rcv_win > RCV_BUFSIZ_M * 1024)
+ credits += ep->rcv_win - RCV_BUFSIZ_M * 1024;
req = (struct cpl_rx_data_ack *) skb_put(skb, wrlen);
memset(req, 0, wrlen);
INIT_TP_WR(req, ep->hwtid);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK,
ep->hwtid));
- req->credit_dack = cpu_to_be32(credits | RX_FORCE_ACK(1) |
+ req->credit_dack = cpu_to_be32(credits | RX_FORCE_ACK_F |
F_RX_DACK_CHANGE |
V_RX_DACK_MODE(dack_mode));
set_wr_txq(skb, CPL_PRIORITY_ACK, ep->ctrlq_idx);
req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR));
- req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+ req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
req->le.filter = cpu_to_be32(cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
ep->l2t));
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
- if (win > RCV_BUFSIZ_MASK)
- win = RCV_BUFSIZ_MASK;
+ if (win > RCV_BUFSIZ_M)
+ win = RCV_BUFSIZ_M;
req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |
(nocong ? NO_CONG(1) : 0) |
- KEEP_ALIVE(1) |
+ KEEP_ALIVE_F |
DELACK(1) |
- WND_SCALE(wscale) |
- MSS_IDX(mtu_idx) |
- L2T_IDX(ep->l2t->idx) |
- TX_CHAN(ep->tx_chan) |
- SMAC_SEL(ep->smac_idx) |
+ WND_SCALE_V(wscale) |
+ MSS_IDX_V(mtu_idx) |
+ L2T_IDX_V(ep->l2t->idx) |
+ TX_CHAN_V(ep->tx_chan) |
+ SMAC_SEL_V(ep->smac_idx) |
DSCP(ep->tos) |
- ULP_MODE(ULP_MODE_TCPDDP) |
- RCV_BUFSIZ(win));
+ ULP_MODE_V(ULP_MODE_TCPDDP) |
+ RCV_BUFSIZ_V(win));
req->tcb.opt2 = (__force __be32) (PACE(1) |
TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
- RX_CHANNEL(0) |
+ RX_CHANNEL_V(0) |
CCTRL_ECN(enable_ecn) |
- RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid));
+ RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid));
if (enable_tcp_timestamps)
- req->tcb.opt2 |= (__force __be32) TSTAMPS_EN(1);
+ req->tcb.opt2 |= (__force __be32)TSTAMPS_EN(1);
if (enable_tcp_sack)
- req->tcb.opt2 |= (__force __be32) SACK_EN(1);
+ req->tcb.opt2 |= (__force __be32)SACK_EN(1);
if (wscale && enable_tcp_window_scaling)
- req->tcb.opt2 |= (__force __be32) WND_SCALE_EN(1);
- req->tcb.opt0 = cpu_to_be64((__force u64) req->tcb.opt0);
- req->tcb.opt2 = cpu_to_be32((__force u32) req->tcb.opt2);
+ req->tcb.opt2 |= (__force __be32)WND_SCALE_EN_F;
+ req->tcb.opt0 = cpu_to_be64((__force u64)req->tcb.opt0);
+ req->tcb.opt2 = cpu_to_be32((__force u32)req->tcb.opt2);
set_wr_txq(skb, CPL_PRIORITY_CONTROL, ep->ctrlq_idx);
set_bit(ACT_OFLD_CONN, &ep->com.history);
c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
* remainder will be specified in the rx_data_ack.
*/
win = ep->rcv_win >> 10;
- if (win > RCV_BUFSIZ_MASK)
- win = RCV_BUFSIZ_MASK;
+ if (win > RCV_BUFSIZ_M)
+ win = RCV_BUFSIZ_M;
opt0 = (nocong ? NO_CONG(1) : 0) |
- KEEP_ALIVE(1) |
+ KEEP_ALIVE_F |
DELACK(1) |
- WND_SCALE(wscale) |
- MSS_IDX(mtu_idx) |
- L2T_IDX(ep->l2t->idx) |
- TX_CHAN(ep->tx_chan) |
- SMAC_SEL(ep->smac_idx) |
+ WND_SCALE_V(wscale) |
+ MSS_IDX_V(mtu_idx) |
+ L2T_IDX_V(ep->l2t->idx) |
+ TX_CHAN_V(ep->tx_chan) |
+ SMAC_SEL_V(ep->smac_idx) |
DSCP(ep->tos >> 2) |
- ULP_MODE(ULP_MODE_TCPDDP) |
- RCV_BUFSIZ(win);
- opt2 = RX_CHANNEL(0) |
- RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
+ ULP_MODE_V(ULP_MODE_TCPDDP) |
+ RCV_BUFSIZ_V(win);
+ opt2 = RX_CHANNEL_V(0) |
+ RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
if (enable_tcp_timestamps && req->tcpopt.tstamp)
opt2 |= TSTAMPS_EN(1);
if (enable_tcp_sack && req->tcpopt.sack)
opt2 |= SACK_EN(1);
if (wscale && enable_tcp_window_scaling)
- opt2 |= WND_SCALE_EN(1);
+ opt2 |= WND_SCALE_EN_F;
if (enable_ecn) {
const struct tcphdr *tcph;
u32 hlen = ntohl(req->hdr_len);
}
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
u32 isn = (prandom_u32() & ~7UL) - 1;
- opt2 |= T5_OPT_2_VALID;
+ opt2 |= T5_OPT_2_VALID_F;
opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
rpl5 = (void *)rpl;
req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
memset(req, 0, sizeof(*req));
- req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL(1));
- req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+ req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F);
+ req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
req->le.version_cpl = htonl(F_FW_OFLD_CONNECTION_WR_CPL);
req->le.filter = (__force __be32) filter;
req->le.lport = lport;
* We store the qid in opt2 which will be used by the firmware
* to send us the wr response.
*/
- req->tcb.opt2 = htonl(V_RSS_QUEUE(rss_qid));
+ req->tcb.opt2 = htonl(RSS_QUEUE_V(rss_qid));
/*
* We initialize the MSS index in TCB to 0xF.
* TCB picks up the correct value. If this was 0
* TP will ignore any value > 0 for MSS index.
*/
- req->tcb.opt0 = cpu_to_be64(V_MSS_IDX(0xF));
+ req->tcb.opt0 = cpu_to_be64(MSS_IDX_V(0xF));
req->cookie = (unsigned long)skb;
set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
- FW_WR_OP(FW_RI_RES_WR) |
+ FW_WR_OP_V(FW_RI_RES_WR) |
V_FW_RI_RES_WR_NRES(1) |
- FW_WR_COMPL(1));
+ FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
- FW_WR_OP(FW_RI_RES_WR) |
+ FW_WR_OP_V(FW_RI_RES_WR) |
V_FW_RI_RES_WR_NRES(1) |
- FW_WR_COMPL(1));
+ FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
memset(req, 0, wr_len);
INIT_ULPTX_WR(req, wr_len, 0, 0);
- req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
- (wait ? FW_WR_COMPL(1) : 0));
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+ (wait ? FW_WR_COMPL_F : 0));
req->wr.wr_lo = wait ? (__force __be64)(unsigned long) &wr_wait : 0L;
- req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
- req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
+ req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
+ req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1));
- req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(len>>5));
+ req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(len>>5));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
- req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR(addr));
+ req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr));
sgl = (struct ulptx_sgl *)(req + 1);
- sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD(ULP_TX_SC_DSGL) |
+ sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
ULPTX_NSGE(1));
sgl->len0 = cpu_to_be32(len);
sgl->addr0 = cpu_to_be64(data);
u8 wr_len, *to_dp, *from_dp;
int copy_len, num_wqe, i, ret = 0;
struct c4iw_wr_wait wr_wait;
- __be32 cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
+ __be32 cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
if (is_t4(rdev->lldi.adapter_type))
- cmd |= cpu_to_be32(ULP_MEMIO_ORDER(1));
+ cmd |= cpu_to_be32(ULP_MEMIO_ORDER_F);
else
- cmd |= cpu_to_be32(V_T5_ULP_MEMIO_IMM(1));
+ cmd |= cpu_to_be32(T5_ULP_MEMIO_IMM_F);
addr &= 0x7FFFFFF;
PDBG("%s addr 0x%x len %u\n", __func__, addr, len);
INIT_ULPTX_WR(req, wr_len, 0, 0);
if (i == (num_wqe-1)) {
- req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
- FW_WR_COMPL(1));
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+ FW_WR_COMPL_F);
req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
} else
- req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR));
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
req->wr.wr_mid = cpu_to_be32(
- FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
+ FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
req->cmd = cmd;
- req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(
+ req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(
DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr),
16));
- req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR(addr + i * 3));
+ req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr + i * 3));
sc = (struct ulptx_idata *)(req + 1);
- sc->cmd_more = cpu_to_be32(ULPTX_CMD(ULP_TX_SC_IMM));
+ sc->cmd_more = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_IMM));
sc->len = cpu_to_be32(roundup(copy_len, T4_ULPTX_MIN_IO));
to_dp = (u8 *)(sc + 1);
res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
- FW_WR_OP(FW_RI_RES_WR) |
+ FW_WR_OP_V(FW_RI_RES_WR) |
V_FW_RI_RES_WR_NRES(2) |
- FW_WR_COMPL(1));
+ FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
res = res_wr->res;
wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof *wqe);
- wqe->op_compl = cpu_to_be32(FW_WR_OP(FW_RI_INIT_WR));
+ wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR));
wqe->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(qhp->ep->hwtid) |
- FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+ FW_WR_FLOWID_V(qhp->ep->hwtid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
wqe->u.terminate.type = FW_RI_TYPE_TERMINATE;
wqe->u.terminate.immdlen = cpu_to_be32(sizeof *term);
wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof *wqe);
wqe->op_compl = cpu_to_be32(
- FW_WR_OP(FW_RI_INIT_WR) |
- FW_WR_COMPL(1));
+ FW_WR_OP_V(FW_RI_INIT_WR) |
+ FW_WR_COMPL_F);
wqe->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(ep->hwtid) |
- FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+ FW_WR_FLOWID_V(ep->hwtid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
wqe->cookie = (unsigned long) &ep->com.wr_wait;
wqe->u.fini.type = FW_RI_TYPE_FINI;
wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof *wqe);
wqe->op_compl = cpu_to_be32(
- FW_WR_OP(FW_RI_INIT_WR) |
- FW_WR_COMPL(1));
+ FW_WR_OP_V(FW_RI_INIT_WR) |
+ FW_WR_COMPL_F);
wqe->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(qhp->ep->hwtid) |
- FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+ FW_WR_FLOWID_V(qhp->ep->hwtid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
dev->caps.num_ports > dev->caps.comp_pool)
return;
- eq_per_port = rounddown_pow_of_two(dev->caps.comp_pool/
- dev->caps.num_ports);
+ eq_per_port = dev->caps.comp_pool / dev->caps.num_ports;
/* Init eq table */
added_eqs = 0;
memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb),
MISDN_HEADER_LEN);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
mISDN_sock_cmsg(sk, msg, skb);
#include <linux/if_bonding.h>
#include <linux/pkt_sched.h>
#include <net/net_namespace.h>
-#include "bonding.h"
-#include "bond_3ad.h"
+#include <net/bonding.h>
+#include <net/bond_3ad.h>
/* General definitions */
#define AD_SHORT_TIMEOUT 1
+++ /dev/null
-/*
- * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- */
-
-#ifndef __BOND_3AD_H__
-#define __BOND_3AD_H__
-
-#include <asm/byteorder.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-
-/* General definitions */
-#define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW)
-#define AD_TIMER_INTERVAL 100 /*msec*/
-
-#define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02}
-
-#define AD_LACP_SLOW 0
-#define AD_LACP_FAST 1
-
-typedef struct mac_addr {
- u8 mac_addr_value[ETH_ALEN];
-} __packed mac_addr_t;
-
-enum {
- BOND_AD_STABLE = 0,
- BOND_AD_BANDWIDTH = 1,
- BOND_AD_COUNT = 2,
-};
-
-/* rx machine states(43.4.11 in the 802.3ad standard) */
-typedef enum {
- AD_RX_DUMMY,
- AD_RX_INITIALIZE, /* rx Machine */
- AD_RX_PORT_DISABLED, /* rx Machine */
- AD_RX_LACP_DISABLED, /* rx Machine */
- AD_RX_EXPIRED, /* rx Machine */
- AD_RX_DEFAULTED, /* rx Machine */
- AD_RX_CURRENT /* rx Machine */
-} rx_states_t;
-
-/* periodic machine states(43.4.12 in the 802.3ad standard) */
-typedef enum {
- AD_PERIODIC_DUMMY,
- AD_NO_PERIODIC, /* periodic machine */
- AD_FAST_PERIODIC, /* periodic machine */
- AD_SLOW_PERIODIC, /* periodic machine */
- AD_PERIODIC_TX /* periodic machine */
-} periodic_states_t;
-
-/* mux machine states(43.4.13 in the 802.3ad standard) */
-typedef enum {
- AD_MUX_DUMMY,
- AD_MUX_DETACHED, /* mux machine */
- AD_MUX_WAITING, /* mux machine */
- AD_MUX_ATTACHED, /* mux machine */
- AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */
-} mux_states_t;
-
-/* tx machine states(43.4.15 in the 802.3ad standard) */
-typedef enum {
- AD_TX_DUMMY,
- AD_TRANSMIT /* tx Machine */
-} tx_states_t;
-
-/* rx indication types */
-typedef enum {
- AD_TYPE_LACPDU = 1, /* type lacpdu */
- AD_TYPE_MARKER /* type marker */
-} pdu_type_t;
-
-/* rx marker indication types */
-typedef enum {
- AD_MARKER_INFORMATION_SUBTYPE = 1, /* marker imformation subtype */
- AD_MARKER_RESPONSE_SUBTYPE /* marker response subtype */
-} bond_marker_subtype_t;
-
-/* timers types(43.4.9 in the 802.3ad standard) */
-typedef enum {
- AD_CURRENT_WHILE_TIMER,
- AD_ACTOR_CHURN_TIMER,
- AD_PERIODIC_TIMER,
- AD_PARTNER_CHURN_TIMER,
- AD_WAIT_WHILE_TIMER
-} ad_timers_t;
-
-#pragma pack(1)
-
-/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
-typedef struct lacpdu {
- u8 subtype; /* = LACP(= 0x01) */
- u8 version_number;
- u8 tlv_type_actor_info; /* = actor information(type/length/value) */
- u8 actor_information_length; /* = 20 */
- __be16 actor_system_priority;
- struct mac_addr actor_system;
- __be16 actor_key;
- __be16 actor_port_priority;
- __be16 actor_port;
- u8 actor_state;
- u8 reserved_3_1[3]; /* = 0 */
- u8 tlv_type_partner_info; /* = partner information */
- u8 partner_information_length; /* = 20 */
- __be16 partner_system_priority;
- struct mac_addr partner_system;
- __be16 partner_key;
- __be16 partner_port_priority;
- __be16 partner_port;
- u8 partner_state;
- u8 reserved_3_2[3]; /* = 0 */
- u8 tlv_type_collector_info; /* = collector information */
- u8 collector_information_length;/* = 16 */
- __be16 collector_max_delay;
- u8 reserved_12[12];
- u8 tlv_type_terminator; /* = terminator */
- u8 terminator_length; /* = 0 */
- u8 reserved_50[50]; /* = 0 */
-} __packed lacpdu_t;
-
-typedef struct lacpdu_header {
- struct ethhdr hdr;
- struct lacpdu lacpdu;
-} __packed lacpdu_header_t;
-
-/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
-typedef struct bond_marker {
- u8 subtype; /* = 0x02 (marker PDU) */
- u8 version_number; /* = 0x01 */
- u8 tlv_type; /* = 0x01 (marker information) */
- /* = 0x02 (marker response information) */
- u8 marker_length; /* = 0x16 */
- u16 requester_port; /* The number assigned to the port by the requester */
- struct mac_addr requester_system; /* The requester's system id */
- u32 requester_transaction_id; /* The transaction id allocated by the requester, */
- u16 pad; /* = 0 */
- u8 tlv_type_terminator; /* = 0x00 */
- u8 terminator_length; /* = 0x00 */
- u8 reserved_90[90]; /* = 0 */
-} __packed bond_marker_t;
-
-typedef struct bond_marker_header {
- struct ethhdr hdr;
- struct bond_marker marker;
-} __packed bond_marker_header_t;
-
-#pragma pack()
-
-struct slave;
-struct bonding;
-struct ad_info;
-struct port;
-
-#ifdef __ia64__
-#pragma pack(8)
-#endif
-
-/* aggregator structure(43.4.5 in the 802.3ad standard) */
-typedef struct aggregator {
- struct mac_addr aggregator_mac_address;
- u16 aggregator_identifier;
- bool is_individual;
- u16 actor_admin_aggregator_key;
- u16 actor_oper_aggregator_key;
- struct mac_addr partner_system;
- u16 partner_system_priority;
- u16 partner_oper_aggregator_key;
- u16 receive_state; /* BOOLEAN */
- u16 transmit_state; /* BOOLEAN */
- struct port *lag_ports;
- /* ****** PRIVATE PARAMETERS ****** */
- struct slave *slave; /* pointer to the bond slave that this aggregator belongs to */
- u16 is_active; /* BOOLEAN. Indicates if this aggregator is active */
- u16 num_of_ports;
-} aggregator_t;
-
-struct port_params {
- struct mac_addr system;
- u16 system_priority;
- u16 key;
- u16 port_number;
- u16 port_priority;
- u16 port_state;
-};
-
-/* port structure(43.4.6 in the 802.3ad standard) */
-typedef struct port {
- u16 actor_port_number;
- u16 actor_port_priority;
- struct mac_addr actor_system; /* This parameter is added here although it is not specified in the standard, just for simplification */
- u16 actor_system_priority; /* This parameter is added here although it is not specified in the standard, just for simplification */
- u16 actor_port_aggregator_identifier;
- bool ntt;
- u16 actor_admin_port_key;
- u16 actor_oper_port_key;
- u8 actor_admin_port_state;
- u8 actor_oper_port_state;
-
- struct port_params partner_admin;
- struct port_params partner_oper;
-
- bool is_enabled;
-
- /* ****** PRIVATE PARAMETERS ****** */
- u16 sm_vars; /* all state machines variables for this port */
- rx_states_t sm_rx_state; /* state machine rx state */
- u16 sm_rx_timer_counter; /* state machine rx timer counter */
- periodic_states_t sm_periodic_state; /* state machine periodic state */
- u16 sm_periodic_timer_counter; /* state machine periodic timer counter */
- mux_states_t sm_mux_state; /* state machine mux state */
- u16 sm_mux_timer_counter; /* state machine mux timer counter */
- tx_states_t sm_tx_state; /* state machine tx state */
- u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
- struct slave *slave; /* pointer to the bond slave that this port belongs to */
- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
- struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
- u32 transaction_id; /* continuous number for identification of Marker PDU's; */
- struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */
-} port_t;
-
-/* system structure */
-struct ad_system {
- u16 sys_priority;
- struct mac_addr sys_mac_addr;
-};
-
-#ifdef __ia64__
-#pragma pack()
-#endif
-
-/* ========== AD Exported structures to the main bonding code ========== */
-#define BOND_AD_INFO(bond) ((bond)->ad_info)
-#define SLAVE_AD_INFO(slave) ((slave)->ad_info)
-
-struct ad_bond_info {
- struct ad_system system; /* 802.3ad system structure */
- u32 agg_select_timer; /* Timer to select aggregator after all adapter's hand shakes */
- u16 aggregator_identifier;
-};
-
-struct ad_slave_info {
- struct aggregator aggregator; /* 802.3ad aggregator structure */
- struct port port; /* 802.3ad port structure */
- u16 id;
-};
-
-/* ========== AD Exported functions to the main bonding code ========== */
-void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
-void bond_3ad_bind_slave(struct slave *slave);
-void bond_3ad_unbind_slave(struct slave *slave);
-void bond_3ad_state_machine_handler(struct work_struct *);
-void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
-void bond_3ad_adapter_speed_changed(struct slave *slave);
-void bond_3ad_adapter_duplex_changed(struct slave *slave);
-void bond_3ad_handle_link_change(struct slave *slave, char link);
-int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
-int __bond_3ad_get_active_agg_info(struct bonding *bond,
- struct ad_info *ad_info);
-int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
- struct slave *slave);
-int bond_3ad_set_carrier(struct bonding *bond);
-void bond_3ad_update_lacp_rate(struct bonding *bond);
-#endif /* __BOND_3AD_H__ */
-
#include <net/arp.h>
#include <net/ipv6.h>
#include <asm/byteorder.h>
-#include "bonding.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_alb.h>
}
/* no suitable interface, frame not sent */
- dev_kfree_skb_any(skb);
+ bond_tx_drop(bond->dev, skb);
out:
return NETDEV_TX_OK;
}
+++ /dev/null
-/*
- * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- */
-
-#ifndef __BOND_ALB_H__
-#define __BOND_ALB_H__
-
-#include <linux/if_ether.h>
-
-struct bonding;
-struct slave;
-
-#define BOND_ALB_INFO(bond) ((bond)->alb_info)
-#define SLAVE_TLB_INFO(slave) ((slave)->tlb_info)
-
-#define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */
-#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing.
- * Used for division - never set
- * to zero !!!
- */
-#define BOND_ALB_DEFAULT_LP_INTERVAL 1
-#define BOND_ALB_LP_INTERVAL(bond) (bond->params.lp_interval) /* In seconds, periodic send of
- * learning packets to the switch
- */
-
-#define BOND_TLB_REBALANCE_TICKS (BOND_TLB_REBALANCE_INTERVAL \
- * ALB_TIMER_TICKS_PER_SEC)
-
-#define BOND_ALB_LP_TICKS(bond) (BOND_ALB_LP_INTERVAL(bond) \
- * ALB_TIMER_TICKS_PER_SEC)
-
-#define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table.
- * Note that this value MUST NOT be smaller
- * because the key hash table is BYTE wide !
- */
-
-
-#define TLB_NULL_INDEX 0xffffffff
-
-/* rlb defs */
-#define RLB_HASH_TABLE_SIZE 256
-#define RLB_NULL_INDEX 0xffffffff
-#define RLB_UPDATE_DELAY (2*ALB_TIMER_TICKS_PER_SEC) /* 2 seconds */
-#define RLB_ARP_BURST_SIZE 2
-#define RLB_UPDATE_RETRY 3 /* 3-ticks - must be smaller than the rlb
- * rebalance interval (5 min).
- */
-/* RLB_PROMISC_TIMEOUT = 10 sec equals the time that the current slave is
- * promiscuous after failover
- */
-#define RLB_PROMISC_TIMEOUT (10*ALB_TIMER_TICKS_PER_SEC)
-
-
-struct tlb_client_info {
- struct slave *tx_slave; /* A pointer to slave used for transmiting
- * packets to a Client that the Hash function
- * gave this entry index.
- */
- u32 tx_bytes; /* Each Client accumulates the BytesTx that
- * were transmitted to it, and after each
- * CallBack the LoadHistory is divided
- * by the balance interval
- */
- u32 load_history; /* This field contains the amount of Bytes
- * that were transmitted to this client by
- * the server on the previous balance
- * interval in Bps.
- */
- u32 next; /* The next Hash table entry index, assigned
- * to use the same adapter for transmit.
- */
- u32 prev; /* The previous Hash table entry index,
- * assigned to use the same
- */
-};
-
-/* -------------------------------------------------------------------------
- * struct rlb_client_info contains all info related to a specific rx client
- * connection. This is the Clients Hash Table entry struct.
- * Note that this is not a proper hash table; if a new client's IP address
- * hash collides with an existing client entry, the old entry is replaced.
- *
- * There is a linked list (linked by the used_next and used_prev members)
- * linking all the used entries of the hash table. This allows updating
- * all the clients without walking over all the unused elements of the table.
- *
- * There are also linked lists of entries with identical hash(ip_src). These
- * allow cleaning up the table from ip_src<->mac_src associations that have
- * become outdated and would cause sending out invalid ARP updates to the
- * network. These are linked by the (src_next and src_prev members).
- * -------------------------------------------------------------------------
- */
-struct rlb_client_info {
- __be32 ip_src; /* the server IP address */
- __be32 ip_dst; /* the client IP address */
- u8 mac_src[ETH_ALEN]; /* the server MAC address */
- u8 mac_dst[ETH_ALEN]; /* the client MAC address */
-
- /* list of used hash table entries, starting at rx_hashtbl_used_head */
- u32 used_next;
- u32 used_prev;
-
- /* ip_src based hashing */
- u32 src_next; /* next entry with same hash(ip_src) */
- u32 src_prev; /* prev entry with same hash(ip_src) */
- u32 src_first; /* first entry with hash(ip_src) == this entry's index */
-
- u8 assigned; /* checking whether this entry is assigned */
- u8 ntt; /* flag - need to transmit client info */
- struct slave *slave; /* the slave assigned to this client */
- unsigned short vlan_id; /* VLAN tag associated with IP address */
-};
-
-struct tlb_slave_info {
- u32 head; /* Index to the head of the bi-directional clients
- * hash table entries list. The entries in the list
- * are the entries that were assigned to use this
- * slave for transmit.
- */
- u32 load; /* Each slave sums the loadHistory of all clients
- * assigned to it
- */
-};
-
-struct alb_bond_info {
- struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */
- u32 unbalanced_load;
- int tx_rebalance_counter;
- int lp_counter;
- /* -------- rlb parameters -------- */
- int rlb_enabled;
- struct rlb_client_info *rx_hashtbl; /* Receive hash table */
- u32 rx_hashtbl_used_head;
- u8 rx_ntt; /* flag - need to transmit
- * to all rx clients
- */
- struct slave *rx_slave;/* last slave to xmit from */
- u8 primary_is_promisc; /* boolean */
- u32 rlb_promisc_timeout_counter;/* counts primary
- * promiscuity time
- */
- u32 rlb_update_delay_counter;
- u32 rlb_update_retry_counter;/* counter of retries
- * of client update
- */
- u8 rlb_rebalance; /* flag - indicates that the
- * rx traffic should be
- * rebalanced
- */
-};
-
-int bond_alb_initialize(struct bonding *bond, int rlb_enabled);
-void bond_alb_deinitialize(struct bonding *bond);
-int bond_alb_init_slave(struct bonding *bond, struct slave *slave);
-void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
-void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
-void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
-int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
-int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
-void bond_alb_monitor(struct work_struct *);
-int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
-void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
-#endif /* __BOND_ALB_H__ */
-
#include <linux/device.h>
#include <linux/netdevice.h>
-#include "bonding.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_alb.h>
#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS)
#include <net/pkt_sched.h>
#include <linux/rculist.h>
#include <net/flow_keys.h>
-#include "bonding.h"
-#include "bond_3ad.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_3ad.h>
+#include <net/bond_alb.h>
/*---------------------------- Module parameters ----------------------------*/
}
#endif
+ if (!(bond_dev->features & NETIF_F_LRO))
+ dev_disable_lro(slave_dev);
+
res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
new_slave);
if (res) {
}
}
/* no slave that can tx has been found */
- dev_kfree_skb_any(skb);
+ bond_tx_drop(bond->dev, skb);
}
/**
slave_id = bond_rr_gen_slave_id(bond);
bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
} else {
- dev_kfree_skb_any(skb);
+ bond_tx_drop(bond_dev, skb);
}
}
if (slave)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
- dev_kfree_skb_any(skb);
+ bond_tx_drop(bond_dev, skb);
return NETDEV_TX_OK;
}
slave = slaves->arr[bond_xmit_hash(bond, skb) % count];
bond_dev_queue_xmit(bond, skb, slave->dev);
} else {
- dev_kfree_skb_any(skb);
- atomic_long_inc(&dev->tx_dropped);
+ bond_tx_drop(dev, skb);
}
return NETDEV_TX_OK;
if (slave && bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
- dev_kfree_skb_any(skb);
+ bond_tx_drop(bond_dev, skb);
return NETDEV_TX_OK;
}
/* Should never happen, mode already checked */
netdev_err(dev, "Unknown bonding mode %d\n", BOND_MODE(bond));
WARN_ON_ONCE(1);
- dev_kfree_skb_any(skb);
+ bond_tx_drop(dev, skb);
return NETDEV_TX_OK;
}
}
if (bond_has_slaves(bond))
ret = __bond_start_xmit(skb, dev);
else
- dev_kfree_skb_any(skb);
+ bond_tx_drop(dev, skb);
rcu_read_unlock();
return ret;
#include <linux/if_ether.h>
#include <net/netlink.h>
#include <net/rtnetlink.h>
-#include "bonding.h"
+#include <net/bonding.h>
static size_t bond_get_slave_size(const struct net_device *bond_dev,
const struct net_device *slave_dev)
#include <linux/rcupdate.h>
#include <linux/ctype.h>
#include <linux/inet.h>
-#include "bonding.h"
+#include <net/bonding.h>
static int bond_option_active_slave_set(struct bonding *bond,
const struct bond_opt_value *newval);
+++ /dev/null
-/*
- * drivers/net/bond/bond_options.h - bonding options
- * Copyright (c) 2013 Nikolay Aleksandrov <nikolay@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _BOND_OPTIONS_H
-#define _BOND_OPTIONS_H
-
-#define BOND_OPT_MAX_NAMELEN 32
-#define BOND_OPT_VALID(opt) ((opt) < BOND_OPT_LAST)
-#define BOND_MODE_ALL_EX(x) (~(x))
-
-/* Option flags:
- * BOND_OPTFLAG_NOSLAVES - check if the bond device is empty before setting
- * BOND_OPTFLAG_IFDOWN - check if the bond device is down before setting
- * BOND_OPTFLAG_RAWVAL - the option parses the value itself
- */
-enum {
- BOND_OPTFLAG_NOSLAVES = BIT(0),
- BOND_OPTFLAG_IFDOWN = BIT(1),
- BOND_OPTFLAG_RAWVAL = BIT(2)
-};
-
-/* Value type flags:
- * BOND_VALFLAG_DEFAULT - mark the value as default
- * BOND_VALFLAG_(MIN|MAX) - mark the value as min/max
- */
-enum {
- BOND_VALFLAG_DEFAULT = BIT(0),
- BOND_VALFLAG_MIN = BIT(1),
- BOND_VALFLAG_MAX = BIT(2)
-};
-
-/* Option IDs, their bit positions correspond to their IDs */
-enum {
- BOND_OPT_MODE,
- BOND_OPT_PACKETS_PER_SLAVE,
- BOND_OPT_XMIT_HASH,
- BOND_OPT_ARP_VALIDATE,
- BOND_OPT_ARP_ALL_TARGETS,
- BOND_OPT_FAIL_OVER_MAC,
- BOND_OPT_ARP_INTERVAL,
- BOND_OPT_ARP_TARGETS,
- BOND_OPT_DOWNDELAY,
- BOND_OPT_UPDELAY,
- BOND_OPT_LACP_RATE,
- BOND_OPT_MINLINKS,
- BOND_OPT_AD_SELECT,
- BOND_OPT_NUM_PEER_NOTIF,
- BOND_OPT_MIIMON,
- BOND_OPT_PRIMARY,
- BOND_OPT_PRIMARY_RESELECT,
- BOND_OPT_USE_CARRIER,
- BOND_OPT_ACTIVE_SLAVE,
- BOND_OPT_QUEUE_ID,
- BOND_OPT_ALL_SLAVES_ACTIVE,
- BOND_OPT_RESEND_IGMP,
- BOND_OPT_LP_INTERVAL,
- BOND_OPT_SLAVES,
- BOND_OPT_TLB_DYNAMIC_LB,
- BOND_OPT_LAST
-};
-
-/* This structure is used for storing option values and for passing option
- * values when changing an option. The logic when used as an arg is as follows:
- * - if string != NULL -> parse it, if the opt is RAW type then return it, else
- * return the parse result
- * - if string == NULL -> parse value
- */
-struct bond_opt_value {
- char *string;
- u64 value;
- u32 flags;
-};
-
-struct bonding;
-
-struct bond_option {
- int id;
- const char *name;
- const char *desc;
- u32 flags;
-
- /* unsuppmodes is used to denote modes in which the option isn't
- * supported.
- */
- unsigned long unsuppmodes;
- /* supported values which this option can have, can be a subset of
- * BOND_OPTVAL_RANGE's value range
- */
- const struct bond_opt_value *values;
-
- int (*set)(struct bonding *bond, const struct bond_opt_value *val);
-};
-
-int __bond_opt_set(struct bonding *bond, unsigned int option,
- struct bond_opt_value *val);
-int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
-
-const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
- struct bond_opt_value *val);
-const struct bond_option *bond_opt_get(unsigned int option);
-const struct bond_option *bond_opt_get_by_name(const char *name);
-const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
-
-/* This helper is used to initialize a bond_opt_value structure for parameter
- * passing. There should be either a valid string or value, but not both.
- * When value is ULLONG_MAX then string will be used.
- */
-static inline void __bond_opt_init(struct bond_opt_value *optval,
- char *string, u64 value)
-{
- memset(optval, 0, sizeof(*optval));
- optval->value = ULLONG_MAX;
- if (value == ULLONG_MAX)
- optval->string = string;
- else
- optval->value = value;
-}
-#define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
-#define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
-
-void bond_option_arp_ip_targets_clear(struct bonding *bond);
-
-#endif /* _BOND_OPTIONS_H */
#include <linux/export.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
-#include "bonding.h"
+#include <net/bonding.h>
static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
#include <net/netns/generic.h>
#include <linux/nsproxy.h>
-#include "bonding.h"
+#include <net/bonding.h>
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd))))
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include "bonding.h"
+#include <net/bonding.h>
struct slave_attribute {
struct attribute attr;
+++ /dev/null
-/*
- * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'.
- *
- * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
- * NCM: Network and Communications Management, Inc.
- *
- * BUT, I'm the one who modified it for ethernet, so:
- * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
- *
- * This software may be used and distributed according to the terms
- * of the GNU Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _LINUX_BONDING_H
-#define _LINUX_BONDING_H
-
-#include <linux/timer.h>
-#include <linux/proc_fs.h>
-#include <linux/if_bonding.h>
-#include <linux/cpumask.h>
-#include <linux/in6.h>
-#include <linux/netpoll.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/reciprocal_div.h>
-#include <linux/if_link.h>
-
-#include "bond_3ad.h"
-#include "bond_alb.h"
-#include "bond_options.h"
-
-#define DRV_VERSION "3.7.1"
-#define DRV_RELDATE "April 27, 2011"
-#define DRV_NAME "bonding"
-#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
-
-#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"
-
-#define BOND_MAX_ARP_TARGETS 16
-
-#define BOND_DEFAULT_MIIMON 100
-
-/*
- * Less bad way to call ioctl from within the kernel; this needs to be
- * done some other way to get the call out of interrupt context.
- * Needs "ioctl" variable to be supplied by calling context.
- */
-#define IOCTL(dev, arg, cmd) ({ \
- int res = 0; \
- mm_segment_t fs = get_fs(); \
- set_fs(get_ds()); \
- res = ioctl(dev, arg, cmd); \
- set_fs(fs); \
- res; })
-
-#define BOND_MODE(bond) ((bond)->params.mode)
-
-/* slave list primitives */
-#define bond_slave_list(bond) (&(bond)->dev->adj_list.lower)
-
-#define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
-
-/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
-#define bond_first_slave(bond) \
- (bond_has_slaves(bond) ? \
- netdev_adjacent_get_private(bond_slave_list(bond)->next) : \
- NULL)
-#define bond_last_slave(bond) \
- (bond_has_slaves(bond) ? \
- netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \
- NULL)
-
-/* Caller must have rcu_read_lock */
-#define bond_first_slave_rcu(bond) \
- netdev_lower_get_first_private_rcu(bond->dev)
-
-#define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond))
-#define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond))
-
-/**
- * bond_for_each_slave - iterate over all slaves
- * @bond: the bond holding this list
- * @pos: current slave
- * @iter: list_head * iterator
- *
- * Caller must hold RTNL
- */
-#define bond_for_each_slave(bond, pos, iter) \
- netdev_for_each_lower_private((bond)->dev, pos, iter)
-
-/* Caller must have rcu_read_lock */
-#define bond_for_each_slave_rcu(bond, pos, iter) \
- netdev_for_each_lower_private_rcu((bond)->dev, pos, iter)
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-extern atomic_t netpoll_block_tx;
-
-static inline void block_netpoll_tx(void)
-{
- atomic_inc(&netpoll_block_tx);
-}
-
-static inline void unblock_netpoll_tx(void)
-{
- atomic_dec(&netpoll_block_tx);
-}
-
-static inline int is_netpoll_tx_blocked(struct net_device *dev)
-{
- if (unlikely(netpoll_tx_running(dev)))
- return atomic_read(&netpoll_block_tx);
- return 0;
-}
-#else
-#define block_netpoll_tx()
-#define unblock_netpoll_tx()
-#define is_netpoll_tx_blocked(dev) (0)
-#endif
-
-struct bond_params {
- int mode;
- int xmit_policy;
- int miimon;
- u8 num_peer_notif;
- int arp_interval;
- int arp_validate;
- int arp_all_targets;
- int use_carrier;
- int fail_over_mac;
- int updelay;
- int downdelay;
- int lacp_fast;
- unsigned int min_links;
- int ad_select;
- char primary[IFNAMSIZ];
- int primary_reselect;
- __be32 arp_targets[BOND_MAX_ARP_TARGETS];
- int tx_queues;
- int all_slaves_active;
- int resend_igmp;
- int lp_interval;
- int packets_per_slave;
- int tlb_dynamic_lb;
- struct reciprocal_value reciprocal_packets_per_slave;
-};
-
-struct bond_parm_tbl {
- char *modename;
- int mode;
-};
-
-struct slave {
- struct net_device *dev; /* first - useful for panic debug */
- struct bonding *bond; /* our master */
- int delay;
- /* all three in jiffies */
- unsigned long last_link_up;
- unsigned long last_rx;
- unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
- s8 link; /* one of BOND_LINK_XXXX */
- s8 new_link;
- u8 backup:1, /* indicates backup slave. Value corresponds with
- BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
- inactive:1, /* indicates inactive slave */
- should_notify:1; /* indicateds whether the state changed */
- u8 duplex;
- u32 original_mtu;
- u32 link_failure_count;
- u32 speed;
- u16 queue_id;
- u8 perm_hwaddr[ETH_ALEN];
- struct ad_slave_info *ad_info;
- struct tlb_slave_info tlb_info;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- struct netpoll *np;
-#endif
- struct kobject kobj;
- struct rtnl_link_stats64 slave_stats;
-};
-
-struct bond_up_slave {
- unsigned int count;
- struct rcu_head rcu;
- struct slave *arr[0];
-};
-
-/*
- * Link pseudo-state only used internally by monitors
- */
-#define BOND_LINK_NOCHANGE -1
-
-/*
- * Here are the locking policies for the two bonding locks:
- * Get rcu_read_lock when reading or RTNL when writing slave list.
- */
-struct bonding {
- struct net_device *dev; /* first - useful for panic debug */
- struct slave __rcu *curr_active_slave;
- struct slave __rcu *current_arp_slave;
- struct slave __rcu *primary_slave;
- struct bond_up_slave __rcu *slave_arr; /* Array of usable slaves */
- bool force_primary;
- s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
- int (*recv_probe)(const struct sk_buff *, struct bonding *,
- struct slave *);
- /* mode_lock is used for mode-specific locking needs, currently used by:
- * 3ad mode (4) - protect against running bond_3ad_unbind_slave() and
- * bond_3ad_state_machine_handler() concurrently and also
- * the access to the state machine shared variables.
- * TLB mode (5) - to sync the use and modifications of its hash table
- * ALB mode (6) - to sync the use and modifications of its hash table
- */
- spinlock_t mode_lock;
- u8 send_peer_notif;
- u8 igmp_retrans;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc_entry;
- char proc_file_name[IFNAMSIZ];
-#endif /* CONFIG_PROC_FS */
- struct list_head bond_list;
- u32 rr_tx_counter;
- struct ad_bond_info ad_info;
- struct alb_bond_info alb_info;
- struct bond_params params;
- struct workqueue_struct *wq;
- struct delayed_work mii_work;
- struct delayed_work arp_work;
- struct delayed_work alb_work;
- struct delayed_work ad_work;
- struct delayed_work mcast_work;
- struct delayed_work slave_arr_work;
-#ifdef CONFIG_DEBUG_FS
- /* debugging support via debugfs */
- struct dentry *debug_dir;
-#endif /* CONFIG_DEBUG_FS */
- struct rtnl_link_stats64 bond_stats;
-};
-
-#define bond_slave_get_rcu(dev) \
- ((struct slave *) rcu_dereference(dev->rx_handler_data))
-
-#define bond_slave_get_rtnl(dev) \
- ((struct slave *) rtnl_dereference(dev->rx_handler_data))
-
-struct bond_vlan_tag {
- __be16 vlan_proto;
- unsigned short vlan_id;
-};
-
-/**
- * Returns NULL if the net_device does not belong to any of the bond's slaves
- *
- * Caller must hold bond lock for read
- */
-static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
- struct net_device *slave_dev)
-{
- return netdev_lower_dev_get_private(bond->dev, slave_dev);
-}
-
-static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
-{
- return slave->bond;
-}
-
-static inline bool bond_should_override_tx_queue(struct bonding *bond)
-{
- return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
- BOND_MODE(bond) == BOND_MODE_ROUNDROBIN;
-}
-
-static inline bool bond_is_lb(const struct bonding *bond)
-{
- return BOND_MODE(bond) == BOND_MODE_TLB ||
- BOND_MODE(bond) == BOND_MODE_ALB;
-}
-
-static inline bool bond_is_nondyn_tlb(const struct bonding *bond)
-{
- return (BOND_MODE(bond) == BOND_MODE_TLB) &&
- (bond->params.tlb_dynamic_lb == 0);
-}
-
-static inline bool bond_mode_uses_xmit_hash(const struct bonding *bond)
-{
- return (BOND_MODE(bond) == BOND_MODE_8023AD ||
- BOND_MODE(bond) == BOND_MODE_XOR ||
- bond_is_nondyn_tlb(bond));
-}
-
-static inline bool bond_mode_uses_arp(int mode)
-{
- return mode != BOND_MODE_8023AD && mode != BOND_MODE_TLB &&
- mode != BOND_MODE_ALB;
-}
-
-static inline bool bond_mode_uses_primary(int mode)
-{
- return mode == BOND_MODE_ACTIVEBACKUP || mode == BOND_MODE_TLB ||
- mode == BOND_MODE_ALB;
-}
-
-static inline bool bond_uses_primary(struct bonding *bond)
-{
- return bond_mode_uses_primary(BOND_MODE(bond));
-}
-
-static inline bool bond_slave_is_up(struct slave *slave)
-{
- return netif_running(slave->dev) && netif_carrier_ok(slave->dev);
-}
-
-static inline void bond_set_active_slave(struct slave *slave)
-{
- if (slave->backup) {
- slave->backup = 0;
- rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
- }
-}
-
-static inline void bond_set_backup_slave(struct slave *slave)
-{
- if (!slave->backup) {
- slave->backup = 1;
- rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
- }
-}
-
-static inline void bond_set_slave_state(struct slave *slave,
- int slave_state, bool notify)
-{
- if (slave->backup == slave_state)
- return;
-
- slave->backup = slave_state;
- if (notify) {
- rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
- slave->should_notify = 0;
- } else {
- if (slave->should_notify)
- slave->should_notify = 0;
- else
- slave->should_notify = 1;
- }
-}
-
-static inline void bond_slave_state_change(struct bonding *bond)
-{
- struct list_head *iter;
- struct slave *tmp;
-
- bond_for_each_slave(bond, tmp, iter) {
- if (tmp->link == BOND_LINK_UP)
- bond_set_active_slave(tmp);
- else if (tmp->link == BOND_LINK_DOWN)
- bond_set_backup_slave(tmp);
- }
-}
-
-static inline void bond_slave_state_notify(struct bonding *bond)
-{
- struct list_head *iter;
- struct slave *tmp;
-
- bond_for_each_slave(bond, tmp, iter) {
- if (tmp->should_notify) {
- rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC);
- tmp->should_notify = 0;
- }
- }
-}
-
-static inline int bond_slave_state(struct slave *slave)
-{
- return slave->backup;
-}
-
-static inline bool bond_is_active_slave(struct slave *slave)
-{
- return !bond_slave_state(slave);
-}
-
-static inline bool bond_slave_can_tx(struct slave *slave)
-{
- return bond_slave_is_up(slave) && slave->link == BOND_LINK_UP &&
- bond_is_active_slave(slave);
-}
-
-#define BOND_PRI_RESELECT_ALWAYS 0
-#define BOND_PRI_RESELECT_BETTER 1
-#define BOND_PRI_RESELECT_FAILURE 2
-
-#define BOND_FOM_NONE 0
-#define BOND_FOM_ACTIVE 1
-#define BOND_FOM_FOLLOW 2
-
-#define BOND_ARP_TARGETS_ANY 0
-#define BOND_ARP_TARGETS_ALL 1
-
-#define BOND_ARP_VALIDATE_NONE 0
-#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
-#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
-#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
- BOND_ARP_VALIDATE_BACKUP)
-#define BOND_ARP_FILTER (BOND_ARP_VALIDATE_ALL + 1)
-#define BOND_ARP_FILTER_ACTIVE (BOND_ARP_VALIDATE_ACTIVE | \
- BOND_ARP_FILTER)
-#define BOND_ARP_FILTER_BACKUP (BOND_ARP_VALIDATE_BACKUP | \
- BOND_ARP_FILTER)
-
-#define BOND_SLAVE_NOTIFY_NOW true
-#define BOND_SLAVE_NOTIFY_LATER false
-
-static inline int slave_do_arp_validate(struct bonding *bond,
- struct slave *slave)
-{
- return bond->params.arp_validate & (1 << bond_slave_state(slave));
-}
-
-static inline int slave_do_arp_validate_only(struct bonding *bond)
-{
- return bond->params.arp_validate & BOND_ARP_FILTER;
-}
-
-static inline int bond_is_ip_target_ok(__be32 addr)
-{
- return !ipv4_is_lbcast(addr) && !ipv4_is_zeronet(addr);
-}
-
-/* Get the oldest arp which we've received on this slave for bond's
- * arp_targets.
- */
-static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond,
- struct slave *slave)
-{
- int i = 1;
- unsigned long ret = slave->target_last_arp_rx[0];
-
- for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++)
- if (time_before(slave->target_last_arp_rx[i], ret))
- ret = slave->target_last_arp_rx[i];
-
- return ret;
-}
-
-static inline unsigned long slave_last_rx(struct bonding *bond,
- struct slave *slave)
-{
- if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
- return slave_oldest_target_arp_rx(bond, slave);
-
- return slave->last_rx;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static inline void bond_netpoll_send_skb(const struct slave *slave,
- struct sk_buff *skb)
-{
- struct netpoll *np = slave->np;
-
- if (np)
- netpoll_send_skb(np, skb);
-}
-#else
-static inline void bond_netpoll_send_skb(const struct slave *slave,
- struct sk_buff *skb)
-{
-}
-#endif
-
-static inline void bond_set_slave_inactive_flags(struct slave *slave,
- bool notify)
-{
- if (!bond_is_lb(slave->bond))
- bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
- if (!slave->bond->params.all_slaves_active)
- slave->inactive = 1;
-}
-
-static inline void bond_set_slave_active_flags(struct slave *slave,
- bool notify)
-{
- bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
- slave->inactive = 0;
-}
-
-static inline bool bond_is_slave_inactive(struct slave *slave)
-{
- return slave->inactive;
-}
-
-static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local)
-{
- struct in_device *in_dev;
- __be32 addr = 0;
-
- rcu_read_lock();
- in_dev = __in_dev_get_rcu(dev);
-
- if (in_dev)
- addr = inet_confirm_addr(dev_net(dev), in_dev, dst, local,
- RT_SCOPE_HOST);
- rcu_read_unlock();
- return addr;
-}
-
-struct bond_net {
- struct net *net; /* Associated network namespace */
- struct list_head dev_list;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc_dir;
-#endif
- struct class_attribute class_attr_bonding_masters;
-};
-
-int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
-void bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
-int bond_create(struct net *net, const char *name);
-int bond_create_sysfs(struct bond_net *net);
-void bond_destroy_sysfs(struct bond_net *net);
-void bond_prepare_sysfs_group(struct bonding *bond);
-int bond_sysfs_slave_add(struct slave *slave);
-void bond_sysfs_slave_del(struct slave *slave);
-int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
-int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
-u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
-void bond_select_active_slave(struct bonding *bond);
-void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
-void bond_create_debugfs(void);
-void bond_destroy_debugfs(void);
-void bond_debug_register(struct bonding *bond);
-void bond_debug_unregister(struct bonding *bond);
-void bond_debug_reregister(struct bonding *bond);
-const char *bond_mode_name(int mode);
-void bond_setup(struct net_device *bond_dev);
-unsigned int bond_get_num_tx_queues(void);
-int bond_netlink_init(void);
-void bond_netlink_fini(void);
-struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
-const char *bond_slave_link_status(s8 link);
-struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
- struct net_device *end_dev,
- int level);
-int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave);
-void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay);
-
-#ifdef CONFIG_PROC_FS
-void bond_create_proc_entry(struct bonding *bond);
-void bond_remove_proc_entry(struct bonding *bond);
-void bond_create_proc_dir(struct bond_net *bn);
-void bond_destroy_proc_dir(struct bond_net *bn);
-#else
-static inline void bond_create_proc_entry(struct bonding *bond)
-{
-}
-
-static inline void bond_remove_proc_entry(struct bonding *bond)
-{
-}
-
-static inline void bond_create_proc_dir(struct bond_net *bn)
-{
-}
-
-static inline void bond_destroy_proc_dir(struct bond_net *bn)
-{
-}
-#endif
-
-static inline struct slave *bond_slave_has_mac(struct bonding *bond,
- const u8 *mac)
-{
- struct list_head *iter;
- struct slave *tmp;
-
- bond_for_each_slave(bond, tmp, iter)
- if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
- return tmp;
-
- return NULL;
-}
-
-/* Caller must hold rcu_read_lock() for read */
-static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond,
- const u8 *mac)
-{
- struct list_head *iter;
- struct slave *tmp;
-
- bond_for_each_slave_rcu(bond, tmp, iter)
- if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
- return tmp;
-
- return NULL;
-}
-
-/* Caller must hold rcu_read_lock() for read */
-static inline bool bond_slave_has_mac_rx(struct bonding *bond, const u8 *mac)
-{
- struct list_head *iter;
- struct slave *tmp;
- struct netdev_hw_addr *ha;
-
- bond_for_each_slave_rcu(bond, tmp, iter)
- if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
- return true;
-
- if (netdev_uc_empty(bond->dev))
- return false;
-
- netdev_for_each_uc_addr(ha, bond->dev)
- if (ether_addr_equal_64bits(mac, ha->addr))
- return true;
-
- return false;
-}
-
-/* Check if the ip is present in arp ip list, or first free slot if ip == 0
- * Returns -1 if not found, index if found
- */
-static inline int bond_get_targets_ip(__be32 *targets, __be32 ip)
-{
- int i;
-
- for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
- if (targets[i] == ip)
- return i;
- else if (targets[i] == 0)
- break;
-
- return -1;
-}
-
-/* exported from bond_main.c */
-extern int bond_net_id;
-extern const struct bond_parm_tbl bond_lacp_tbl[];
-extern const struct bond_parm_tbl xmit_hashtype_tbl[];
-extern const struct bond_parm_tbl arp_validate_tbl[];
-extern const struct bond_parm_tbl arp_all_targets_tbl[];
-extern const struct bond_parm_tbl fail_over_mac_tbl[];
-extern const struct bond_parm_tbl pri_reselect_tbl[];
-extern struct bond_parm_tbl ad_select_tbl[];
-
-/* exported from bond_netlink.c */
-extern struct rtnl_link_ops bond_link_ops;
-
-#endif /* _LINUX_BONDING_H */
ethernet switch chips.
config NET_DSA_MV88E6171
- tristate "Marvell 88E6171 ethernet switch chip support"
+ tristate "Marvell 88E6171/6172 ethernet switch chip support"
select NET_DSA
select NET_DSA_MV88E6XXX
select NET_DSA_TAG_EDSA
---help---
- This enables support for the Marvell 88E6171 ethernet switch
- chip.
+ This enables support for the Marvell 88E6171/6172 ethernet switch
+ chips.
+
+config NET_DSA_MV88E6352
+ tristate "Marvell 88E6176/88E6352 ethernet switch chip support"
+ select NET_DSA
+ select NET_DSA_MV88E6XXX
+ select NET_DSA_TAG_EDSA
+ ---help---
+ This enables support for the Marvell 88E6176 and 88E6352 ethernet
+ switch chips.
config NET_DSA_BCM_SF2
tristate "Broadcom Starfighter 2 Ethernet switch support"
ifdef CONFIG_NET_DSA_MV88E6131
mv88e6xxx_drv-y += mv88e6131.o
endif
+ifdef CONFIG_NET_DSA_MV88E6352
+mv88e6xxx_drv-y += mv88e6352.o
+endif
ifdef CONFIG_NET_DSA_MV88E6171
mv88e6xxx_drv-y += mv88e6171.o
endif
ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03);
if (ret >= 0) {
- ret &= 0xfff0;
if (ret == 0x0600)
+ return "Marvell 88E6060 (A0)";
+ if (ret == 0x0601 || ret == 0x0602)
+ return "Marvell 88E6060 (B0)";
+ if ((ret & 0xfff0) == 0x0600)
return "Marvell 88E6060";
}
return 0;
}
+#ifdef CONFIG_NET_DSA_HWMON
+
+static int mv88e6123_61_65_get_temp(struct dsa_switch *ds, int *temp)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+ int val;
+
+ *temp = 0;
+
+ mutex_lock(&ps->phy_mutex);
+
+ ret = mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
+ if (ret < 0)
+ goto error;
+
+ /* Enable temperature sensor */
+ ret = mv88e6xxx_phy_read(ds, 0x0, 0x1a);
+ if (ret < 0)
+ goto error;
+
+ ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5));
+ if (ret < 0)
+ goto error;
+
+ /* Wait for temperature to stabilize */
+ usleep_range(10000, 12000);
+
+ val = mv88e6xxx_phy_read(ds, 0x0, 0x1a);
+ if (val < 0) {
+ ret = val;
+ goto error;
+ }
+
+ /* Disable temperature sensor */
+ ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5));
+ if (ret < 0)
+ goto error;
+
+ *temp = ((val & 0x1f) - 5) * 5;
+
+error:
+ mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
+ mutex_unlock(&ps->phy_mutex);
+ return ret;
+}
+#endif /* CONFIG_NET_DSA_HWMON */
+
static int mv88e6123_61_65_setup(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
mutex_init(&ps->smi_mutex);
mutex_init(&ps->stats_mutex);
+ mutex_init(&ps->phy_mutex);
ret = mv88e6123_61_65_switch_reset(ds);
if (ret < 0)
static int
mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum)
{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6123_61_65_port_to_phy_addr(port);
- return mv88e6xxx_phy_read(ds, addr, regnum);
+ int ret;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = mv88e6xxx_phy_read(ds, addr, regnum);
+ mutex_unlock(&ps->phy_mutex);
+ return ret;
}
static int
mv88e6123_61_65_phy_write(struct dsa_switch *ds,
int port, int regnum, u16 val)
{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int addr = mv88e6123_61_65_port_to_phy_addr(port);
- return mv88e6xxx_phy_write(ds, addr, regnum, val);
+ int ret;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = mv88e6xxx_phy_write(ds, addr, regnum, val);
+ mutex_unlock(&ps->phy_mutex);
+ return ret;
}
static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = {
{ "hist_256_511bytes", 4, 0x0b, },
{ "hist_512_1023bytes", 4, 0x0c, },
{ "hist_1024_max_bytes", 4, 0x0d, },
+ { "sw_in_discards", 4, 0x110, },
+ { "sw_in_filtered", 2, 0x112, },
+ { "sw_out_filtered", 2, 0x113, },
};
static void
.get_strings = mv88e6123_61_65_get_strings,
.get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats,
.get_sset_count = mv88e6123_61_65_get_sset_count,
+#ifdef CONFIG_NET_DSA_HWMON
+ .get_temp = mv88e6123_61_65_get_temp,
+#endif
+ .get_regs_len = mv88e6xxx_get_regs_len,
+ .get_regs = mv88e6xxx_get_regs,
};
MODULE_ALIAS("platform:mv88e6123");
#define ID_6085 0x04a0
#define ID_6095 0x0950
#define ID_6131 0x1060
+#define ID_6131_B2 0x1066
static char *mv88e6131_probe(struct device *host_dev, int sw_addr)
{
ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
if (ret >= 0) {
- ret &= 0xfff0;
- if (ret == ID_6085)
+ int ret_masked = ret & 0xfff0;
+
+ if (ret_masked == ID_6085)
return "Marvell 88E6085";
- if (ret == ID_6095)
+ if (ret_masked == ID_6095)
return "Marvell 88E6095/88E6095F";
- if (ret == ID_6131)
+ if (ret == ID_6131_B2)
+ return "Marvell 88E6131 (B2)";
+ if (ret_masked == ID_6131)
return "Marvell 88E6131";
}
-/* net/dsa/mv88e6171.c - Marvell 88e6171 switch chip support
+/* net/dsa/mv88e6171.c - Marvell 88e6171/8826172 switch chip support
* Copyright (c) 2008-2009 Marvell Semiconductor
* Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
*
if (ret >= 0) {
if ((ret & 0xfff0) == 0x1710)
return "Marvell 88E6171";
+ if ((ret & 0xfff0) == 0x1720)
+ return "Marvell 88E6172";
}
return NULL;
};
MODULE_ALIAS("platform:mv88e6171");
+MODULE_ALIAS("platform:mv88e6172");
--- /dev/null
+/*
+ * net/dsa/mv88e6352.c - Marvell 88e6352 switch chip support
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * Derived from mv88e6123_61_65.c
+ * Copyright (c) 2008-2009 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <net/dsa.h>
+#include "mv88e6xxx.h"
+
+static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask)
+{
+ unsigned long timeout = jiffies + HZ / 10;
+
+ while (time_before(jiffies, timeout)) {
+ int ret;
+
+ ret = REG_READ(REG_GLOBAL2, reg);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & mask))
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+ return -ETIMEDOUT;
+}
+
+static inline int mv88e6352_phy_wait(struct dsa_switch *ds)
+{
+ return mv88e6352_wait(ds, 0x18, 0x8000);
+}
+
+static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds)
+{
+ return mv88e6352_wait(ds, 0x14, 0x0800);
+}
+
+static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds)
+{
+ return mv88e6352_wait(ds, 0x14, 0x8000);
+}
+
+static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+ int ret;
+
+ REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum);
+
+ ret = mv88e6352_phy_wait(ds);
+ if (ret < 0)
+ return ret;
+
+ return REG_READ(REG_GLOBAL2, 0x19);
+}
+
+static int __mv88e6352_phy_write(struct dsa_switch *ds, int addr, int regnum,
+ u16 val)
+{
+ REG_WRITE(REG_GLOBAL2, 0x19, val);
+ REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum);
+
+ return mv88e6352_phy_wait(ds);
+}
+
+static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
+{
+ struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
+ int ret;
+
+ if (bus == NULL)
+ return NULL;
+
+ ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
+ if (ret >= 0) {
+ if ((ret & 0xfff0) == 0x1760)
+ return "Marvell 88E6176";
+ if (ret == 0x3521)
+ return "Marvell 88E6352 (A0)";
+ if (ret == 0x3522)
+ return "Marvell 88E6352 (A1)";
+ if ((ret & 0xfff0) == 0x3520)
+ return "Marvell 88E6352";
+ }
+
+ return NULL;
+}
+
+static int mv88e6352_switch_reset(struct dsa_switch *ds)
+{
+ unsigned long timeout;
+ int ret;
+ int i;
+
+ /* Set all ports to the disabled state. */
+ for (i = 0; i < 7; i++) {
+ ret = REG_READ(REG_PORT(i), 0x04);
+ REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+ }
+
+ /* Wait for transmit queues to drain. */
+ usleep_range(2000, 4000);
+
+ /* Reset the switch. Keep PPU active (bit 14, undocumented).
+ * The PPU needs to be active to support indirect phy register
+ * accesses through global registers 0x18 and 0x19.
+ */
+ REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
+
+ /* Wait up to one second for reset to complete. */
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
+ ret = REG_READ(REG_GLOBAL, 0x00);
+ if ((ret & 0x8800) == 0x8800)
+ break;
+ usleep_range(1000, 2000);
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mv88e6352_setup_global(struct dsa_switch *ds)
+{
+ int ret;
+ int i;
+
+ /* Discard packets with excessive collisions,
+ * mask all interrupt sources, enable PPU (bit 14, undocumented).
+ */
+ REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
+
+ /* Set the default address aging time to 5 minutes, and
+ * enable address learn messages to be sent to all message
+ * ports.
+ */
+ REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
+
+ /* Configure the priority mapping registers. */
+ ret = mv88e6xxx_config_prio(ds);
+ if (ret < 0)
+ return ret;
+
+ /* Configure the upstream port, and configure the upstream
+ * port as the port to which ingress and egress monitor frames
+ * are to be sent.
+ */
+ REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
+
+ /* Disable remote management for now, and set the switch's
+ * DSA device number.
+ */
+ REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
+
+ /* Send all frames with destination addresses matching
+ * 01:80:c2:00:00:2x to the CPU port.
+ */
+ REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
+
+ /* Send all frames with destination addresses matching
+ * 01:80:c2:00:00:0x to the CPU port.
+ */
+ REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
+
+ /* Disable the loopback filter, disable flow control
+ * messages, disable flood broadcast override, disable
+ * removing of provider tags, disable ATU age violation
+ * interrupts, disable tag flow control, force flow
+ * control priority to the highest, and send all special
+ * multicast frames to the CPU at the highest priority.
+ */
+ REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
+
+ /* Program the DSA routing table. */
+ for (i = 0; i < 32; i++) {
+ int nexthop = 0x1f;
+
+ if (i != ds->index && i < ds->dst->pd->nr_chips)
+ nexthop = ds->pd->rtable[i] & 0x1f;
+
+ REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
+ }
+
+ /* Clear all trunk masks. */
+ for (i = 0; i < 8; i++)
+ REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7f);
+
+ /* Clear all trunk mappings. */
+ for (i = 0; i < 16; i++)
+ REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
+
+ /* Disable ingress rate limiting by resetting all ingress
+ * rate limit registers to their initial state.
+ */
+ for (i = 0; i < 7; i++)
+ REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
+
+ /* Initialise cross-chip port VLAN table to reset defaults. */
+ REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
+
+ /* Clear the priority override table. */
+ for (i = 0; i < 16; i++)
+ REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
+
+ /* @@@ initialise AVB (22/23) watchdog (27) sdet (29) registers */
+
+ return 0;
+}
+
+static int mv88e6352_setup_port(struct dsa_switch *ds, int p)
+{
+ int addr = REG_PORT(p);
+ u16 val;
+
+ /* MAC Forcing register: don't force link, speed, duplex
+ * or flow control state to any particular values on physical
+ * ports, but force the CPU port and all DSA ports to 1000 Mb/s
+ * full duplex.
+ */
+ if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
+ REG_WRITE(addr, 0x01, 0x003e);
+ else
+ REG_WRITE(addr, 0x01, 0x0003);
+
+ /* Do not limit the period of time that this port can be
+ * paused for by the remote end or the period of time that
+ * this port can pause the remote end.
+ */
+ REG_WRITE(addr, 0x02, 0x0000);
+
+ /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+ * disable Header mode, enable IGMP/MLD snooping, disable VLAN
+ * tunneling, determine priority by looking at 802.1p and IP
+ * priority fields (IP prio has precedence), and set STP state
+ * to Forwarding.
+ *
+ * If this is the CPU link, use DSA or EDSA tagging depending
+ * on which tagging mode was configured.
+ *
+ * If this is a link to another switch, use DSA tagging mode.
+ *
+ * If this is the upstream port for this switch, enable
+ * forwarding of unknown unicasts and multicasts.
+ */
+ val = 0x0433;
+ if (dsa_is_cpu_port(ds, p)) {
+ if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA)
+ val |= 0x3300;
+ else
+ val |= 0x0100;
+ }
+ if (ds->dsa_port_mask & (1 << p))
+ val |= 0x0100;
+ if (p == dsa_upstream_port(ds))
+ val |= 0x000c;
+ REG_WRITE(addr, 0x04, val);
+
+ /* Port Control 1: disable trunking. Also, if this is the
+ * CPU port, enable learn messages to be sent to this port.
+ */
+ REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
+
+ /* Port based VLAN map: give each port its own address
+ * database, allow the CPU port to talk to each of the 'real'
+ * ports, and allow each of the 'real' ports to only talk to
+ * the upstream port.
+ */
+ val = (p & 0xf) << 12;
+ if (dsa_is_cpu_port(ds, p))
+ val |= ds->phys_port_mask;
+ else
+ val |= 1 << dsa_upstream_port(ds);
+ REG_WRITE(addr, 0x06, val);
+
+ /* Default VLAN ID and priority: don't set a default VLAN
+ * ID, and set the default packet priority to zero.
+ */
+ REG_WRITE(addr, 0x07, 0x0000);
+
+ /* Port Control 2: don't force a good FCS, set the maximum
+ * frame size to 10240 bytes, don't let the switch add or
+ * strip 802.1q tags, don't discard tagged or untagged frames
+ * on this port, do a destination address lookup on all
+ * received packets as usual, disable ARP mirroring and don't
+ * send a copy of all transmitted/received frames on this port
+ * to the CPU.
+ */
+ REG_WRITE(addr, 0x08, 0x2080);
+
+ /* Egress rate control: disable egress rate control. */
+ REG_WRITE(addr, 0x09, 0x0001);
+
+ /* Egress rate control 2: disable egress rate control. */
+ REG_WRITE(addr, 0x0a, 0x0000);
+
+ /* Port Association Vector: when learning source addresses
+ * of packets, add the address to the address database using
+ * a port bitmap that has only the bit for this port set and
+ * the other bits clear.
+ */
+ REG_WRITE(addr, 0x0b, 1 << p);
+
+ /* Port ATU control: disable limiting the number of address
+ * database entries that this port is allowed to use.
+ */
+ REG_WRITE(addr, 0x0c, 0x0000);
+
+ /* Priority Override: disable DA, SA and VTU priority override. */
+ REG_WRITE(addr, 0x0d, 0x0000);
+
+ /* Port Ethertype: use the Ethertype DSA Ethertype value. */
+ REG_WRITE(addr, 0x0f, ETH_P_EDSA);
+
+ /* Tag Remap: use an identity 802.1p prio -> switch prio
+ * mapping.
+ */
+ REG_WRITE(addr, 0x18, 0x3210);
+
+ /* Tag Remap 2: use an identity 802.1p prio -> switch prio
+ * mapping.
+ */
+ REG_WRITE(addr, 0x19, 0x7654);
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_DSA_HWMON
+
+static int mv88e6352_phy_page_read(struct dsa_switch *ds,
+ int port, int page, int reg)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = __mv88e6352_phy_write(ds, port, 0x16, page);
+ if (ret < 0)
+ goto error;
+ ret = __mv88e6352_phy_read(ds, port, reg);
+error:
+ __mv88e6352_phy_write(ds, port, 0x16, 0x0);
+ mutex_unlock(&ps->phy_mutex);
+ return ret;
+}
+
+static int mv88e6352_phy_page_write(struct dsa_switch *ds,
+ int port, int page, int reg, int val)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = __mv88e6352_phy_write(ds, port, 0x16, page);
+ if (ret < 0)
+ goto error;
+
+ ret = __mv88e6352_phy_write(ds, port, reg, val);
+error:
+ __mv88e6352_phy_write(ds, port, 0x16, 0x0);
+ mutex_unlock(&ps->phy_mutex);
+ return ret;
+}
+
+static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp)
+{
+ int ret;
+
+ *temp = 0;
+
+ ret = mv88e6352_phy_page_read(ds, 0, 6, 27);
+ if (ret < 0)
+ return ret;
+
+ *temp = (ret & 0xff) - 25;
+
+ return 0;
+}
+
+static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp)
+{
+ int ret;
+
+ *temp = 0;
+
+ ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ if (ret < 0)
+ return ret;
+
+ *temp = (((ret >> 8) & 0x1f) * 5) - 25;
+
+ return 0;
+}
+
+static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp)
+{
+ int ret;
+
+ ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ if (ret < 0)
+ return ret;
+ temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
+ return mv88e6352_phy_page_write(ds, 0, 6, 26,
+ (ret & 0xe0ff) | (temp << 8));
+}
+
+static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm)
+{
+ int ret;
+
+ *alarm = false;
+
+ ret = mv88e6352_phy_page_read(ds, 0, 6, 26);
+ if (ret < 0)
+ return ret;
+
+ *alarm = !!(ret & 0x40);
+
+ return 0;
+}
+#endif /* CONFIG_NET_DSA_HWMON */
+
+static int mv88e6352_setup(struct dsa_switch *ds)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+ int i;
+
+ mutex_init(&ps->smi_mutex);
+ mutex_init(&ps->stats_mutex);
+ mutex_init(&ps->phy_mutex);
+ mutex_init(&ps->eeprom_mutex);
+
+ ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0;
+
+ ret = mv88e6352_switch_reset(ds);
+ if (ret < 0)
+ return ret;
+
+ /* @@@ initialise vtu and atu */
+
+ ret = mv88e6352_setup_global(ds);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < 7; i++) {
+ ret = mv88e6352_setup_port(ds, i);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mv88e6352_port_to_phy_addr(int port)
+{
+ if (port >= 0 && port <= 4)
+ return port;
+ return -EINVAL;
+}
+
+static int
+mv88e6352_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int addr = mv88e6352_port_to_phy_addr(port);
+ int ret;
+
+ if (addr < 0)
+ return addr;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = __mv88e6352_phy_read(ds, addr, regnum);
+ mutex_unlock(&ps->phy_mutex);
+
+ return ret;
+}
+
+static int
+mv88e6352_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int addr = mv88e6352_port_to_phy_addr(port);
+ int ret;
+
+ if (addr < 0)
+ return addr;
+
+ mutex_lock(&ps->phy_mutex);
+ ret = __mv88e6352_phy_write(ds, addr, regnum, val);
+ mutex_unlock(&ps->phy_mutex);
+
+ return ret;
+}
+
+static struct mv88e6xxx_hw_stat mv88e6352_hw_stats[] = {
+ { "in_good_octets", 8, 0x00, },
+ { "in_bad_octets", 4, 0x02, },
+ { "in_unicast", 4, 0x04, },
+ { "in_broadcasts", 4, 0x06, },
+ { "in_multicasts", 4, 0x07, },
+ { "in_pause", 4, 0x16, },
+ { "in_undersize", 4, 0x18, },
+ { "in_fragments", 4, 0x19, },
+ { "in_oversize", 4, 0x1a, },
+ { "in_jabber", 4, 0x1b, },
+ { "in_rx_error", 4, 0x1c, },
+ { "in_fcs_error", 4, 0x1d, },
+ { "out_octets", 8, 0x0e, },
+ { "out_unicast", 4, 0x10, },
+ { "out_broadcasts", 4, 0x13, },
+ { "out_multicasts", 4, 0x12, },
+ { "out_pause", 4, 0x15, },
+ { "excessive", 4, 0x11, },
+ { "collisions", 4, 0x1e, },
+ { "deferred", 4, 0x05, },
+ { "single", 4, 0x14, },
+ { "multiple", 4, 0x17, },
+ { "out_fcs_error", 4, 0x03, },
+ { "late", 4, 0x1f, },
+ { "hist_64bytes", 4, 0x08, },
+ { "hist_65_127bytes", 4, 0x09, },
+ { "hist_128_255bytes", 4, 0x0a, },
+ { "hist_256_511bytes", 4, 0x0b, },
+ { "hist_512_1023bytes", 4, 0x0c, },
+ { "hist_1024_max_bytes", 4, 0x0d, },
+ { "sw_in_discards", 4, 0x110, },
+ { "sw_in_filtered", 2, 0x112, },
+ { "sw_out_filtered", 2, 0x113, },
+};
+
+static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+
+ mutex_lock(&ps->eeprom_mutex);
+
+ ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x14,
+ 0xc000 | (addr & 0xff));
+ if (ret < 0)
+ goto error;
+
+ ret = mv88e6352_eeprom_busy_wait(ds);
+ if (ret < 0)
+ goto error;
+
+ ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, 0x15);
+error:
+ mutex_unlock(&ps->eeprom_mutex);
+ return ret;
+}
+
+static int mv88e6352_get_eeprom(struct dsa_switch *ds,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ int offset;
+ int len;
+ int ret;
+
+ offset = eeprom->offset;
+ len = eeprom->len;
+ eeprom->len = 0;
+
+ eeprom->magic = 0xc3ec4951;
+
+ ret = mv88e6352_eeprom_load_wait(ds);
+ if (ret < 0)
+ return ret;
+
+ if (offset & 1) {
+ int word;
+
+ word = mv88e6352_read_eeprom_word(ds, offset >> 1);
+ if (word < 0)
+ return word;
+
+ *data++ = (word >> 8) & 0xff;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ while (len >= 2) {
+ int word;
+
+ word = mv88e6352_read_eeprom_word(ds, offset >> 1);
+ if (word < 0)
+ return word;
+
+ *data++ = word & 0xff;
+ *data++ = (word >> 8) & 0xff;
+
+ offset += 2;
+ len -= 2;
+ eeprom->len += 2;
+ }
+
+ if (len) {
+ int word;
+
+ word = mv88e6352_read_eeprom_word(ds, offset >> 1);
+ if (word < 0)
+ return word;
+
+ *data++ = word & 0xff;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ return 0;
+}
+
+static int mv88e6352_eeprom_is_readonly(struct dsa_switch *ds)
+{
+ int ret;
+
+ ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, 0x14);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & 0x0400))
+ return -EROFS;
+
+ return 0;
+}
+
+static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr,
+ u16 data)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ int ret;
+
+ mutex_lock(&ps->eeprom_mutex);
+
+ ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x15, data);
+ if (ret < 0)
+ goto error;
+
+ ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x14,
+ 0xb000 | (addr & 0xff));
+ if (ret < 0)
+ goto error;
+
+ ret = mv88e6352_eeprom_busy_wait(ds);
+error:
+ mutex_unlock(&ps->eeprom_mutex);
+ return ret;
+}
+
+static int mv88e6352_set_eeprom(struct dsa_switch *ds,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ int offset;
+ int ret;
+ int len;
+
+ if (eeprom->magic != 0xc3ec4951)
+ return -EINVAL;
+
+ ret = mv88e6352_eeprom_is_readonly(ds);
+ if (ret)
+ return ret;
+
+ offset = eeprom->offset;
+ len = eeprom->len;
+ eeprom->len = 0;
+
+ ret = mv88e6352_eeprom_load_wait(ds);
+ if (ret < 0)
+ return ret;
+
+ if (offset & 1) {
+ int word;
+
+ word = mv88e6352_read_eeprom_word(ds, offset >> 1);
+ if (word < 0)
+ return word;
+
+ word = (*data++ << 8) | (word & 0xff);
+
+ ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
+ if (ret < 0)
+ return ret;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ while (len >= 2) {
+ int word;
+
+ word = *data++;
+ word |= *data++ << 8;
+
+ ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
+ if (ret < 0)
+ return ret;
+
+ offset += 2;
+ len -= 2;
+ eeprom->len += 2;
+ }
+
+ if (len) {
+ int word;
+
+ word = mv88e6352_read_eeprom_word(ds, offset >> 1);
+ if (word < 0)
+ return word;
+
+ word = (word & 0xff00) | *data++;
+
+ ret = mv88e6352_write_eeprom_word(ds, offset >> 1, word);
+ if (ret < 0)
+ return ret;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ return 0;
+}
+
+static void
+mv88e6352_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
+{
+ mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6352_hw_stats),
+ mv88e6352_hw_stats, port, data);
+}
+
+static void
+mv88e6352_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
+{
+ mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6352_hw_stats),
+ mv88e6352_hw_stats, port, data);
+}
+
+static int mv88e6352_get_sset_count(struct dsa_switch *ds)
+{
+ return ARRAY_SIZE(mv88e6352_hw_stats);
+}
+
+struct dsa_switch_driver mv88e6352_switch_driver = {
+ .tag_protocol = DSA_TAG_PROTO_EDSA,
+ .priv_size = sizeof(struct mv88e6xxx_priv_state),
+ .probe = mv88e6352_probe,
+ .setup = mv88e6352_setup,
+ .set_addr = mv88e6xxx_set_addr_indirect,
+ .phy_read = mv88e6352_phy_read,
+ .phy_write = mv88e6352_phy_write,
+ .poll_link = mv88e6xxx_poll_link,
+ .get_strings = mv88e6352_get_strings,
+ .get_ethtool_stats = mv88e6352_get_ethtool_stats,
+ .get_sset_count = mv88e6352_get_sset_count,
+#ifdef CONFIG_NET_DSA_HWMON
+ .get_temp = mv88e6352_get_temp,
+ .get_temp_limit = mv88e6352_get_temp_limit,
+ .set_temp_limit = mv88e6352_set_temp_limit,
+ .get_temp_alarm = mv88e6352_get_temp_alarm,
+#endif
+ .get_eeprom = mv88e6352_get_eeprom,
+ .set_eeprom = mv88e6352_set_eeprom,
+ .get_regs_len = mv88e6xxx_get_regs_len,
+ .get_regs = mv88e6xxx_get_regs,
+};
+
+MODULE_ALIAS("platform:mv88e6352");
for (i = 0; i < nr_stats; i++) {
struct mv88e6xxx_hw_stat *s = stats + i;
u32 low;
- u32 high;
-
+ u32 high = 0;
+
+ if (s->reg >= 0x100) {
+ int ret;
+
+ ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
+ s->reg - 0x100);
+ if (ret < 0)
+ goto error;
+ low = ret;
+ if (s->sizeof_stat == 4) {
+ ret = mv88e6xxx_reg_read(ds, REG_PORT(port),
+ s->reg - 0x100 + 1);
+ if (ret < 0)
+ goto error;
+ high = ret;
+ }
+ data[i] = (((u64)high) << 16) | low;
+ continue;
+ }
mv88e6xxx_stats_read(ds, s->reg, &low);
if (s->sizeof_stat == 8)
mv88e6xxx_stats_read(ds, s->reg + 1, &high);
- else
- high = 0;
data[i] = (((u64)high) << 32) | low;
}
-
+error:
mutex_unlock(&ps->stats_mutex);
}
+int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
+{
+ return 32 * sizeof(u16);
+}
+
+void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
+ struct ethtool_regs *regs, void *_p)
+{
+ u16 *p = _p;
+ int i;
+
+ regs->version = 0;
+
+ memset(p, 0xff, 32 * sizeof(u16));
+
+ for (i = 0; i < 32; i++) {
+ int ret;
+
+ ret = mv88e6xxx_reg_read(ds, REG_PORT(port), i);
+ if (ret >= 0)
+ p[i] = ret;
+ }
+}
+
static int __init mv88e6xxx_init(void)
{
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65)
register_switch_driver(&mv88e6123_61_65_switch_driver);
#endif
+#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352)
+ register_switch_driver(&mv88e6352_switch_driver);
+#endif
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6171)
register_switch_driver(&mv88e6171_switch_driver);
#endif
*/
struct mutex stats_mutex;
+ /* This mutex serializes phy access for chips with
+ * indirect phy addressing. It is unused for chips
+ * with direct phy access.
+ */
+ struct mutex phy_mutex;
+
+ /* This mutex serializes eeprom access for chips with
+ * eeprom support.
+ */
+ struct mutex eeprom_mutex;
+
int id; /* switch product id */
};
void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
int nr_stats, struct mv88e6xxx_hw_stat *stats,
int port, uint64_t *data);
+int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
+void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
+ struct ethtool_regs *regs, void *_p);
extern struct dsa_switch_driver mv88e6131_switch_driver;
extern struct dsa_switch_driver mv88e6123_61_65_switch_driver;
+extern struct dsa_switch_driver mv88e6352_switch_driver;
extern struct dsa_switch_driver mv88e6171_switch_driver;
#define REG_READ(addr, reg) \
return err;
}
- image_data = (u8 *) typhoon_fw->data;
+ image_data = typhoon_fw->data;
remaining = typhoon_fw->size;
if (remaining < sizeof(struct typhoon_file_header))
goto invalid_fw;
int i;
int err;
- image_data = (u8 *) typhoon_fw->data;
+ image_data = typhoon_fw->data;
fHdr = (struct typhoon_file_header *) image_data;
/* Cannot just map the firmware image using pci_map_single() as
config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
- depends on OF_NET
+ depends on OF_NET && HAS_IOMEM
select PHYLIB
select AMD_XGBE_PHY
select BITREVERSE
/* DMA channel register entry bit positions and sizes */
#define DMA_CH_CR_PBLX8_INDEX 16
#define DMA_CH_CR_PBLX8_WIDTH 1
+#define DMA_CH_CR_SPH_INDEX 24
+#define DMA_CH_CR_SPH_WIDTH 1
#define DMA_CH_IER_AIE_INDEX 15
#define DMA_CH_IER_AIE_WIDTH 1
#define DMA_CH_IER_FBEE_INDEX 12
#define MAC_MACA0LR 0x0304
#define MAC_MACA1HR 0x0308
#define MAC_MACA1LR 0x030c
+#define MAC_RSSCR 0x0c80
+#define MAC_RSSAR 0x0c88
+#define MAC_RSSDR 0x0c8c
#define MAC_TSCR 0x0d00
#define MAC_SSIR 0x0d04
#define MAC_STSR 0x0d08
#define MAC_RCR_CST_WIDTH 1
#define MAC_RCR_DCRCC_INDEX 3
#define MAC_RCR_DCRCC_WIDTH 1
+#define MAC_RCR_HDSMS_INDEX 12
+#define MAC_RCR_HDSMS_WIDTH 3
#define MAC_RCR_IPC_INDEX 9
#define MAC_RCR_IPC_WIDTH 1
#define MAC_RCR_JE_INDEX 8
#define MAC_RFCR_UP_WIDTH 1
#define MAC_RQC0R_RXQ0EN_INDEX 0
#define MAC_RQC0R_RXQ0EN_WIDTH 2
+#define MAC_RSSAR_ADDRT_INDEX 2
+#define MAC_RSSAR_ADDRT_WIDTH 1
+#define MAC_RSSAR_CT_INDEX 1
+#define MAC_RSSAR_CT_WIDTH 1
+#define MAC_RSSAR_OB_INDEX 0
+#define MAC_RSSAR_OB_WIDTH 1
+#define MAC_RSSAR_RSSIA_INDEX 8
+#define MAC_RSSAR_RSSIA_WIDTH 8
+#define MAC_RSSCR_IP2TE_INDEX 1
+#define MAC_RSSCR_IP2TE_WIDTH 1
+#define MAC_RSSCR_RSSE_INDEX 0
+#define MAC_RSSCR_RSSE_WIDTH 1
+#define MAC_RSSCR_TCP4TE_INDEX 2
+#define MAC_RSSCR_TCP4TE_WIDTH 1
+#define MAC_RSSCR_UDP4TE_INDEX 3
+#define MAC_RSSCR_UDP4TE_WIDTH 1
+#define MAC_RSSDR_DMCH_INDEX 0
+#define MAC_RSSDR_DMCH_WIDTH 4
#define MAC_SSIR_SNSINC_INDEX 8
#define MAC_SSIR_SNSINC_WIDTH 8
#define MAC_SSIR_SSINC_INDEX 16
#define RX_PACKET_ATTRIBUTES_CONTEXT_WIDTH 1
#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_INDEX 5
#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH 1
+#define RX_PACKET_ATTRIBUTES_RSS_HASH_INDEX 6
+#define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH 1
#define RX_NORMAL_DESC0_OVT_INDEX 0
#define RX_NORMAL_DESC0_OVT_WIDTH 16
+#define RX_NORMAL_DESC2_HL_INDEX 0
+#define RX_NORMAL_DESC2_HL_WIDTH 10
#define RX_NORMAL_DESC3_CDA_INDEX 27
#define RX_NORMAL_DESC3_CDA_WIDTH 1
#define RX_NORMAL_DESC3_CTXT_INDEX 30
#define RX_NORMAL_DESC3_ES_WIDTH 1
#define RX_NORMAL_DESC3_ETLT_INDEX 16
#define RX_NORMAL_DESC3_ETLT_WIDTH 4
+#define RX_NORMAL_DESC3_FD_INDEX 29
+#define RX_NORMAL_DESC3_FD_WIDTH 1
#define RX_NORMAL_DESC3_INTE_INDEX 30
#define RX_NORMAL_DESC3_INTE_WIDTH 1
+#define RX_NORMAL_DESC3_L34T_INDEX 20
+#define RX_NORMAL_DESC3_L34T_WIDTH 4
#define RX_NORMAL_DESC3_LD_INDEX 28
#define RX_NORMAL_DESC3_LD_WIDTH 1
#define RX_NORMAL_DESC3_OWN_INDEX 31
#define RX_NORMAL_DESC3_OWN_WIDTH 1
#define RX_NORMAL_DESC3_PL_INDEX 0
#define RX_NORMAL_DESC3_PL_WIDTH 14
+#define RX_NORMAL_DESC3_RSV_INDEX 26
+#define RX_NORMAL_DESC3_RSV_WIDTH 1
+
+#define RX_DESC3_L34T_IPV4_TCP 1
+#define RX_DESC3_L34T_IPV4_UDP 2
+#define RX_DESC3_L34T_IPV4_ICMP 3
+#define RX_DESC3_L34T_IPV6_TCP 9
+#define RX_DESC3_L34T_IPV6_UDP 10
+#define RX_DESC3_L34T_IPV6_ICMP 11
#define RX_CONTEXT_DESC3_TSA_INDEX 4
#define RX_CONTEXT_DESC3_TSA_WIDTH 1
#include "xgbe.h"
#include "xgbe-common.h"
-static void xgbe_unmap_skb(struct xgbe_prv_data *, struct xgbe_ring_data *);
+static void xgbe_unmap_rdata(struct xgbe_prv_data *, struct xgbe_ring_data *);
static void xgbe_free_ring(struct xgbe_prv_data *pdata,
struct xgbe_ring *ring)
if (ring->rdata) {
for (i = 0; i < ring->rdesc_count; i++) {
rdata = XGBE_GET_DESC_DATA(ring, i);
- xgbe_unmap_skb(pdata, rdata);
+ xgbe_unmap_rdata(pdata, rdata);
}
kfree(ring->rdata);
ring->rdata = NULL;
}
+ if (ring->rx_hdr_pa.pages) {
+ dma_unmap_page(pdata->dev, ring->rx_hdr_pa.pages_dma,
+ ring->rx_hdr_pa.pages_len, DMA_FROM_DEVICE);
+ put_page(ring->rx_hdr_pa.pages);
+
+ ring->rx_hdr_pa.pages = NULL;
+ ring->rx_hdr_pa.pages_len = 0;
+ ring->rx_hdr_pa.pages_offset = 0;
+ ring->rx_hdr_pa.pages_dma = 0;
+ }
+
+ if (ring->rx_buf_pa.pages) {
+ dma_unmap_page(pdata->dev, ring->rx_buf_pa.pages_dma,
+ ring->rx_buf_pa.pages_len, DMA_FROM_DEVICE);
+ put_page(ring->rx_buf_pa.pages);
+
+ ring->rx_buf_pa.pages = NULL;
+ ring->rx_buf_pa.pages_len = 0;
+ ring->rx_buf_pa.pages_offset = 0;
+ ring->rx_buf_pa.pages_dma = 0;
+ }
+
if (ring->rdesc) {
dma_free_coherent(pdata->dev,
(sizeof(struct xgbe_ring_desc) *
return ret;
}
+static int xgbe_alloc_pages(struct xgbe_prv_data *pdata,
+ struct xgbe_page_alloc *pa, gfp_t gfp, int order)
+{
+ struct page *pages = NULL;
+ dma_addr_t pages_dma;
+ int ret;
+
+ /* Try to obtain pages, decreasing order if necessary */
+ gfp |= __GFP_COLD | __GFP_COMP;
+ while (order >= 0) {
+ pages = alloc_pages(gfp, order);
+ if (pages)
+ break;
+
+ order--;
+ }
+ if (!pages)
+ return -ENOMEM;
+
+ /* Map the pages */
+ pages_dma = dma_map_page(pdata->dev, pages, 0,
+ PAGE_SIZE << order, DMA_FROM_DEVICE);
+ ret = dma_mapping_error(pdata->dev, pages_dma);
+ if (ret) {
+ put_page(pages);
+ return ret;
+ }
+
+ pa->pages = pages;
+ pa->pages_len = PAGE_SIZE << order;
+ pa->pages_offset = 0;
+ pa->pages_dma = pages_dma;
+
+ return 0;
+}
+
+static void xgbe_set_buffer_data(struct xgbe_buffer_data *bd,
+ struct xgbe_page_alloc *pa,
+ unsigned int len)
+{
+ get_page(pa->pages);
+ bd->pa = *pa;
+
+ bd->dma = pa->pages_dma + pa->pages_offset;
+ bd->dma_len = len;
+
+ pa->pages_offset += len;
+ if ((pa->pages_offset + len) > pa->pages_len) {
+ /* This data descriptor is responsible for unmapping page(s) */
+ bd->pa_unmap = *pa;
+
+ /* Get a new allocation next time */
+ pa->pages = NULL;
+ pa->pages_len = 0;
+ pa->pages_offset = 0;
+ pa->pages_dma = 0;
+ }
+}
+
+static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata,
+ struct xgbe_ring *ring,
+ struct xgbe_ring_data *rdata)
+{
+ int order, ret;
+
+ if (!ring->rx_hdr_pa.pages) {
+ ret = xgbe_alloc_pages(pdata, &ring->rx_hdr_pa, GFP_ATOMIC, 0);
+ if (ret)
+ return ret;
+ }
+
+ if (!ring->rx_buf_pa.pages) {
+ order = max_t(int, PAGE_ALLOC_COSTLY_ORDER - 1, 0);
+ ret = xgbe_alloc_pages(pdata, &ring->rx_buf_pa, GFP_ATOMIC,
+ order);
+ if (ret)
+ return ret;
+ }
+
+ /* Set up the header page info */
+ xgbe_set_buffer_data(&rdata->rx_hdr, &ring->rx_hdr_pa,
+ XGBE_SKB_ALLOC_SIZE);
+
+ /* Set up the buffer page info */
+ xgbe_set_buffer_data(&rdata->rx_buf, &ring->rx_buf_pa,
+ pdata->rx_buf_size);
+
+ return 0;
+}
+
static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_ring *ring;
struct xgbe_ring_desc *rdesc;
struct xgbe_ring_data *rdata;
- dma_addr_t rdesc_dma, skb_dma;
- struct sk_buff *skb = NULL;
+ dma_addr_t rdesc_dma;
unsigned int i, j;
DBGPR("-->xgbe_wrapper_rx_descriptor_init\n");
rdata->rdesc = rdesc;
rdata->rdesc_dma = rdesc_dma;
- /* Allocate skb & assign to each rdesc */
- skb = dev_alloc_skb(pdata->rx_buf_size);
- if (skb == NULL)
- break;
- skb_dma = dma_map_single(pdata->dev, skb->data,
- pdata->rx_buf_size,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(pdata->dev, skb_dma)) {
- netdev_alert(pdata->netdev,
- "failed to do the dma map\n");
- dev_kfree_skb_any(skb);
+ if (xgbe_map_rx_buffer(pdata, ring, rdata))
break;
- }
- rdata->skb = skb;
- rdata->skb_dma = skb_dma;
- rdata->skb_dma_len = pdata->rx_buf_size;
rdesc++;
rdesc_dma += sizeof(struct xgbe_ring_desc);
DBGPR("<--xgbe_wrapper_rx_descriptor_init\n");
}
-static void xgbe_unmap_skb(struct xgbe_prv_data *pdata,
- struct xgbe_ring_data *rdata)
+static void xgbe_unmap_rdata(struct xgbe_prv_data *pdata,
+ struct xgbe_ring_data *rdata)
{
if (rdata->skb_dma) {
if (rdata->mapped_as_page) {
rdata->skb = NULL;
}
+ if (rdata->rx_hdr.pa.pages)
+ put_page(rdata->rx_hdr.pa.pages);
+
+ if (rdata->rx_hdr.pa_unmap.pages) {
+ dma_unmap_page(pdata->dev, rdata->rx_hdr.pa_unmap.pages_dma,
+ rdata->rx_hdr.pa_unmap.pages_len,
+ DMA_FROM_DEVICE);
+ put_page(rdata->rx_hdr.pa_unmap.pages);
+ }
+
+ if (rdata->rx_buf.pa.pages)
+ put_page(rdata->rx_buf.pa.pages);
+
+ if (rdata->rx_buf.pa_unmap.pages) {
+ dma_unmap_page(pdata->dev, rdata->rx_buf.pa_unmap.pages_dma,
+ rdata->rx_buf.pa_unmap.pages_len,
+ DMA_FROM_DEVICE);
+ put_page(rdata->rx_buf.pa_unmap.pages);
+ }
+
+ memset(&rdata->rx_hdr, 0, sizeof(rdata->rx_hdr));
+ memset(&rdata->rx_buf, 0, sizeof(rdata->rx_buf));
+
rdata->tso_header = 0;
rdata->len = 0;
rdata->interrupt = 0;
err_out:
while (start_index < cur_index) {
rdata = XGBE_GET_DESC_DATA(ring, start_index++);
- xgbe_unmap_skb(pdata, rdata);
+ xgbe_unmap_rdata(pdata, rdata);
}
DBGPR("<--xgbe_map_tx_skb: count=0\n");
return 0;
}
-static void xgbe_realloc_skb(struct xgbe_channel *channel)
+static void xgbe_realloc_rx_buffer(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_ring *ring = channel->rx_ring;
struct xgbe_ring_data *rdata;
- struct sk_buff *skb = NULL;
- dma_addr_t skb_dma;
int i;
- DBGPR("-->xgbe_realloc_skb: rx_ring->rx.realloc_index = %u\n",
+ DBGPR("-->xgbe_realloc_rx_buffer: rx_ring->rx.realloc_index = %u\n",
ring->rx.realloc_index);
for (i = 0; i < ring->dirty; i++) {
rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index);
/* Reset rdata values */
- xgbe_unmap_skb(pdata, rdata);
+ xgbe_unmap_rdata(pdata, rdata);
- /* Allocate skb & assign to each rdesc */
- skb = dev_alloc_skb(pdata->rx_buf_size);
- if (skb == NULL)
+ if (xgbe_map_rx_buffer(pdata, ring, rdata))
break;
- skb_dma = dma_map_single(pdata->dev, skb->data,
- pdata->rx_buf_size, DMA_FROM_DEVICE);
- if (dma_mapping_error(pdata->dev, skb_dma)) {
- netdev_alert(pdata->netdev,
- "failed to do the dma map\n");
- dev_kfree_skb_any(skb);
- break;
- }
- rdata->skb = skb;
- rdata->skb_dma = skb_dma;
- rdata->skb_dma_len = pdata->rx_buf_size;
hw_if->rx_desc_reset(rdata);
}
ring->dirty = 0;
- DBGPR("<--xgbe_realloc_skb\n");
+ DBGPR("<--xgbe_realloc_rx_buffer\n");
}
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if)
desc_if->alloc_ring_resources = xgbe_alloc_ring_resources;
desc_if->free_ring_resources = xgbe_free_ring_resources;
desc_if->map_tx_skb = xgbe_map_tx_skb;
- desc_if->realloc_skb = xgbe_realloc_skb;
- desc_if->unmap_skb = xgbe_unmap_skb;
+ desc_if->realloc_rx_buffer = xgbe_realloc_rx_buffer;
+ desc_if->unmap_rdata = xgbe_unmap_rdata;
desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init;
desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init;
}
}
+static void xgbe_config_sph_mode(struct xgbe_prv_data *pdata)
+{
+ struct xgbe_channel *channel;
+ unsigned int i;
+
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (!channel->rx_ring)
+ break;
+
+ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_CR, SPH, 1);
+ }
+
+ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE);
+}
+
+static int xgbe_write_rss_reg(struct xgbe_prv_data *pdata, unsigned int type,
+ unsigned int index, unsigned int val)
+{
+ unsigned int wait;
+ int ret = 0;
+
+ mutex_lock(&pdata->rss_mutex);
+
+ if (XGMAC_IOREAD_BITS(pdata, MAC_RSSAR, OB)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ XGMAC_IOWRITE(pdata, MAC_RSSDR, val);
+
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, RSSIA, index);
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, ADDRT, type);
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, CT, 0);
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSAR, OB, 1);
+
+ wait = 1000;
+ while (wait--) {
+ if (!XGMAC_IOREAD_BITS(pdata, MAC_RSSAR, OB))
+ goto unlock;
+
+ usleep_range(1000, 1500);
+ }
+
+ ret = -EBUSY;
+
+unlock:
+ mutex_unlock(&pdata->rss_mutex);
+
+ return ret;
+}
+
+static int xgbe_write_rss_hash_key(struct xgbe_prv_data *pdata)
+{
+ unsigned int key_regs = sizeof(pdata->rss_key) / sizeof(u32);
+ unsigned int *key = (unsigned int *)&pdata->rss_key;
+ int ret;
+
+ while (key_regs--) {
+ ret = xgbe_write_rss_reg(pdata, XGBE_RSS_HASH_KEY_TYPE,
+ key_regs, *key++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xgbe_write_rss_lookup_table(struct xgbe_prv_data *pdata)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) {
+ ret = xgbe_write_rss_reg(pdata,
+ XGBE_RSS_LOOKUP_TABLE_TYPE, i,
+ pdata->rss_table[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xgbe_set_rss_hash_key(struct xgbe_prv_data *pdata, const u8 *key)
+{
+ memcpy(pdata->rss_key, key, sizeof(pdata->rss_key));
+
+ return xgbe_write_rss_hash_key(pdata);
+}
+
+static int xgbe_set_rss_lookup_table(struct xgbe_prv_data *pdata,
+ const u32 *table)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
+ XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH, table[i]);
+
+ return xgbe_write_rss_lookup_table(pdata);
+}
+
+static int xgbe_enable_rss(struct xgbe_prv_data *pdata)
+{
+ int ret;
+
+ if (!pdata->hw_feat.rss)
+ return -EOPNOTSUPP;
+
+ /* Program the hash key */
+ ret = xgbe_write_rss_hash_key(pdata);
+ if (ret)
+ return ret;
+
+ /* Program the lookup table */
+ ret = xgbe_write_rss_lookup_table(pdata);
+ if (ret)
+ return ret;
+
+ /* Set the RSS options */
+ XGMAC_IOWRITE(pdata, MAC_RSSCR, pdata->rss_options);
+
+ /* Enable RSS */
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSCR, RSSE, 1);
+
+ return 0;
+}
+
+static int xgbe_disable_rss(struct xgbe_prv_data *pdata)
+{
+ if (!pdata->hw_feat.rss)
+ return -EOPNOTSUPP;
+
+ XGMAC_IOWRITE_BITS(pdata, MAC_RSSCR, RSSE, 0);
+
+ return 0;
+}
+
+static void xgbe_config_rss(struct xgbe_prv_data *pdata)
+{
+ int ret;
+
+ if (!pdata->hw_feat.rss)
+ return;
+
+ if (pdata->netdev->features & NETIF_F_RXHASH)
+ ret = xgbe_enable_rss(pdata);
+ else
+ ret = xgbe_disable_rss(pdata);
+
+ if (ret)
+ netdev_err(pdata->netdev,
+ "error configuring RSS, RSS disabled\n");
+}
+
static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
{
unsigned int max_q_count, q_count;
if (channel->tx_ring) {
/* Enable the following Tx interrupts
- * TIE - Transmit Interrupt Enable (unless polling)
+ * TIE - Transmit Interrupt Enable (unless using
+ * per channel interrupts)
*/
- XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1);
+ if (!pdata->per_channel_irq)
+ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1);
}
if (channel->rx_ring) {
/* Enable following Rx interrupts
* RBUE - Receive Buffer Unavailable Enable
- * RIE - Receive Interrupt Enable
+ * RIE - Receive Interrupt Enable (unless using
+ * per channel interrupts)
*/
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1);
- XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1);
+ if (!pdata->per_channel_irq)
+ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1);
}
XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier);
rdesc->desc1 = 0;
rdesc->desc2 = 0;
rdesc->desc3 = 0;
+
+ /* Make sure ownership is written to the descriptor */
+ wmb();
}
static void xgbe_tx_desc_init(struct xgbe_channel *channel)
{
struct xgbe_ring *ring = channel->tx_ring;
struct xgbe_ring_data *rdata;
- struct xgbe_ring_desc *rdesc;
int i;
int start_index = ring->cur;
/* Initialze all descriptors */
for (i = 0; i < ring->rdesc_count; i++) {
rdata = XGBE_GET_DESC_DATA(ring, i);
- rdesc = rdata->rdesc;
- /* Initialize Tx descriptor
- * Set buffer 1 (lo) address to zero
- * Set buffer 1 (hi) address to zero
- * Reset all other control bits (IC, TTSE, B2L & B1L)
- * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC,
- * etc)
- */
- rdesc->desc0 = 0;
- rdesc->desc1 = 0;
- rdesc->desc2 = 0;
- rdesc->desc3 = 0;
+ /* Initialize Tx descriptor */
+ xgbe_tx_desc_reset(rdata);
}
- /* Make sure everything is written to the descriptor(s) before
- * telling the device about them
- */
- wmb();
-
/* Update the total number of Tx descriptors */
XGMAC_DMA_IOWRITE(channel, DMA_CH_TDRLR, ring->rdesc_count - 1);
struct xgbe_ring_desc *rdesc = rdata->rdesc;
/* Reset the Rx descriptor
- * Set buffer 1 (lo) address to dma address (lo)
- * Set buffer 1 (hi) address to dma address (hi)
- * Set buffer 2 (lo) address to zero
- * Set buffer 2 (hi) address to zero and set control bits
- * OWN and INTE
+ * Set buffer 1 (lo) address to header dma address (lo)
+ * Set buffer 1 (hi) address to header dma address (hi)
+ * Set buffer 2 (lo) address to buffer dma address (lo)
+ * Set buffer 2 (hi) address to buffer dma address (hi) and
+ * set control bits OWN and INTE
*/
- rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma));
- rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma));
- rdesc->desc2 = 0;
+ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx_hdr.dma));
+ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx_hdr.dma));
+ rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx_buf.dma));
+ rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx_buf.dma));
- rdesc->desc3 = 0;
- if (rdata->interrupt)
- XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, 1);
+ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE,
+ rdata->interrupt ? 1 : 0);
/* Since the Rx DMA engine is likely running, make sure everything
* is written to the descriptor(s) before setting the OWN bit
struct xgbe_prv_data *pdata = channel->pdata;
struct xgbe_ring *ring = channel->rx_ring;
struct xgbe_ring_data *rdata;
- struct xgbe_ring_desc *rdesc;
unsigned int start_index = ring->cur;
unsigned int rx_coalesce, rx_frames;
unsigned int i;
/* Initialize all descriptors */
for (i = 0; i < ring->rdesc_count; i++) {
rdata = XGBE_GET_DESC_DATA(ring, i);
- rdesc = rdata->rdesc;
- /* Initialize Rx descriptor
- * Set buffer 1 (lo) address to dma address (lo)
- * Set buffer 1 (hi) address to dma address (hi)
- * Set buffer 2 (lo) address to zero
- * Set buffer 2 (hi) address to zero and set control
- * bits OWN and INTE appropriateley
- */
- rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma));
- rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma));
- rdesc->desc2 = 0;
- rdesc->desc3 = 0;
- XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1);
- XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, 1);
- rdata->interrupt = 1;
- if (rx_coalesce && (!rx_frames || ((i + 1) % rx_frames))) {
- /* Clear interrupt on completion bit */
- XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE,
- 0);
+ /* Set interrupt on completion bit as appropriate */
+ if (rx_coalesce && (!rx_frames || ((i + 1) % rx_frames)))
rdata->interrupt = 0;
- }
- }
+ else
+ rdata->interrupt = 1;
- /* Make sure everything is written to the descriptors before
- * telling the device about them
- */
- wmb();
+ /* Initialize Rx descriptor */
+ xgbe_rx_desc_reset(rdata);
+ }
/* Update the total number of Rx descriptors */
XGMAC_DMA_IOWRITE(channel, DMA_CH_RDRLR, ring->rdesc_count - 1);
xgbe_config_flow_control(pdata);
}
-static void xgbe_pre_xmit(struct xgbe_channel *channel)
+static void xgbe_dev_xmit(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
struct xgbe_ring *ring = channel->tx_ring;
int start_index = ring->cur;
int i;
- DBGPR("-->xgbe_pre_xmit\n");
+ DBGPR("-->xgbe_dev_xmit\n");
csum = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
CSUM_ENABLE);
channel->name, start_index & (ring->rdesc_count - 1),
(ring->cur - 1) & (ring->rdesc_count - 1));
- DBGPR("<--xgbe_pre_xmit\n");
+ DBGPR("<--xgbe_dev_xmit\n");
}
static int xgbe_dev_read(struct xgbe_channel *channel)
struct xgbe_ring_desc *rdesc;
struct xgbe_packet_data *packet = &ring->packet_data;
struct net_device *netdev = channel->pdata->netdev;
- unsigned int err, etlt;
+ unsigned int err, etlt, l34t;
DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur);
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
CONTEXT_NEXT, 1);
+ /* Get the header length */
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, FD))
+ rdata->hdr_len = XGMAC_GET_BITS_LE(rdesc->desc2,
+ RX_NORMAL_DESC2, HL);
+
+ /* Get the RSS hash */
+ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, RSV)) {
+ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
+ RSS_HASH, 1);
+
+ packet->rss_hash = le32_to_cpu(rdesc->desc1);
+
+ l34t = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, L34T);
+ switch (l34t) {
+ case RX_DESC3_L34T_IPV4_TCP:
+ case RX_DESC3_L34T_IPV4_UDP:
+ case RX_DESC3_L34T_IPV6_TCP:
+ case RX_DESC3_L34T_IPV6_UDP:
+ packet->rss_hash_type = PKT_HASH_TYPE_L4;
+ break;
+ default:
+ packet->rss_hash_type = PKT_HASH_TYPE_L3;
+ }
+ }
+
/* Get the packet length */
rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
xgbe_config_tx_coalesce(pdata);
xgbe_config_rx_buffer_size(pdata);
xgbe_config_tso_mode(pdata);
+ xgbe_config_sph_mode(pdata);
+ xgbe_config_rss(pdata);
desc_if->wrapper_tx_desc_init(pdata);
desc_if->wrapper_rx_desc_init(pdata);
xgbe_enable_dma_interrupts(pdata);
hw_if->powerup_rx = xgbe_powerup_rx;
hw_if->powerdown_rx = xgbe_powerdown_rx;
- hw_if->pre_xmit = xgbe_pre_xmit;
+ hw_if->dev_xmit = xgbe_dev_xmit;
hw_if->dev_read = xgbe_dev_read;
hw_if->enable_int = xgbe_enable_int;
hw_if->disable_int = xgbe_disable_int;
hw_if->config_dcb_tc = xgbe_config_dcb_tc;
hw_if->config_dcb_pfc = xgbe_config_dcb_pfc;
+ /* For Receive Side Scaling */
+ hw_if->enable_rss = xgbe_enable_rss;
+ hw_if->disable_rss = xgbe_disable_rss;
+ hw_if->set_rss_hash_key = xgbe_set_rss_hash_key;
+ hw_if->set_rss_lookup_table = xgbe_set_rss_lookup_table;
+
DBGPR("<--xgbe_init_function_ptrs\n");
}
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/tcp.h>
#include <linux/if_vlan.h>
#include "xgbe.h"
#include "xgbe-common.h"
-static int xgbe_poll(struct napi_struct *, int);
+static int xgbe_one_poll(struct napi_struct *, int);
+static int xgbe_all_poll(struct napi_struct *, int);
static void xgbe_set_rx_mode(struct net_device *);
+static int xgbe_alloc_channels(struct xgbe_prv_data *pdata)
+{
+ struct xgbe_channel *channel_mem, *channel;
+ struct xgbe_ring *tx_ring, *rx_ring;
+ unsigned int count, i;
+ int ret = -ENOMEM;
+
+ count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count);
+
+ channel_mem = kcalloc(count, sizeof(struct xgbe_channel), GFP_KERNEL);
+ if (!channel_mem)
+ goto err_channel;
+
+ tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct xgbe_ring),
+ GFP_KERNEL);
+ if (!tx_ring)
+ goto err_tx_ring;
+
+ rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct xgbe_ring),
+ GFP_KERNEL);
+ if (!rx_ring)
+ goto err_rx_ring;
+
+ for (i = 0, channel = channel_mem; i < count; i++, channel++) {
+ snprintf(channel->name, sizeof(channel->name), "channel-%d", i);
+ channel->pdata = pdata;
+ channel->queue_index = i;
+ channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE +
+ (DMA_CH_INC * i);
+
+ if (pdata->per_channel_irq) {
+ /* Get the DMA interrupt (offset 1) */
+ ret = platform_get_irq(pdata->pdev, i + 1);
+ if (ret < 0) {
+ netdev_err(pdata->netdev,
+ "platform_get_irq %u failed\n",
+ i + 1);
+ goto err_irq;
+ }
+
+ channel->dma_irq = ret;
+ }
+
+ if (i < pdata->tx_ring_count) {
+ spin_lock_init(&tx_ring->lock);
+ channel->tx_ring = tx_ring++;
+ }
+
+ if (i < pdata->rx_ring_count) {
+ spin_lock_init(&rx_ring->lock);
+ channel->rx_ring = rx_ring++;
+ }
+
+ DBGPR(" %s: queue=%u, dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n",
+ channel->name, channel->queue_index, channel->dma_regs,
+ channel->dma_irq, channel->tx_ring, channel->rx_ring);
+ }
+
+ pdata->channel = channel_mem;
+ pdata->channel_count = count;
+
+ return 0;
+
+err_irq:
+ kfree(rx_ring);
+
+err_rx_ring:
+ kfree(tx_ring);
+
+err_tx_ring:
+ kfree(channel_mem);
+
+err_channel:
+ return ret;
+}
+
+static void xgbe_free_channels(struct xgbe_prv_data *pdata)
+{
+ if (!pdata->channel)
+ return;
+
+ kfree(pdata->channel->rx_ring);
+ kfree(pdata->channel->tx_ring);
+ kfree(pdata->channel);
+
+ pdata->channel = NULL;
+ pdata->channel_count = 0;
+}
+
static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring)
{
return (ring->rdesc_count - (ring->cur - ring->dirty));
}
rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
- if (rx_buf_size < XGBE_RX_MIN_BUF_SIZE)
- rx_buf_size = XGBE_RX_MIN_BUF_SIZE;
+ rx_buf_size = clamp_val(rx_buf_size, XGBE_RX_MIN_BUF_SIZE, PAGE_SIZE);
+
rx_buf_size = (rx_buf_size + XGBE_RX_BUF_ALIGN - 1) &
~(XGBE_RX_BUF_ALIGN - 1);
if (!dma_isr)
goto isr_done;
- DBGPR("-->xgbe_isr\n");
-
DBGPR(" DMA_ISR = %08x\n", dma_isr);
- DBGPR(" DMA_DS0 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR0));
- DBGPR(" DMA_DS1 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR1));
for (i = 0; i < pdata->channel_count; i++) {
if (!(dma_isr & (1 << i)))
dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR);
DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr);
+ /* If we get a TI or RI interrupt that means per channel DMA
+ * interrupts are not enabled, so we use the private data napi
+ * structure, not the per channel napi structure
+ */
if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) ||
XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) {
if (napi_schedule_prep(&pdata->napi)) {
DBGPR(" DMA_ISR = %08x\n", XGMAC_IOREAD(pdata, DMA_ISR));
- DBGPR("<--xgbe_isr\n");
-
isr_done:
return IRQ_HANDLED;
}
+static irqreturn_t xgbe_dma_isr(int irq, void *data)
+{
+ struct xgbe_channel *channel = data;
+
+ /* Per channel DMA interrupts are enabled, so we use the per
+ * channel napi structure and not the private data napi structure
+ */
+ if (napi_schedule_prep(&channel->napi)) {
+ /* Disable Tx and Rx interrupts */
+ disable_irq(channel->dma_irq);
+
+ /* Turn on polling */
+ __napi_schedule(&channel->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer)
{
struct xgbe_channel *channel = container_of(timer,
tx_timer);
struct xgbe_ring *ring = channel->tx_ring;
struct xgbe_prv_data *pdata = channel->pdata;
+ struct napi_struct *napi;
unsigned long flags;
DBGPR("-->xgbe_tx_timer\n");
+ napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
+
spin_lock_irqsave(&ring->lock, flags);
- if (napi_schedule_prep(&pdata->napi)) {
+ if (napi_schedule_prep(napi)) {
/* Disable Tx and Rx interrupts */
- xgbe_disable_rx_tx_ints(pdata);
+ if (pdata->per_channel_irq)
+ disable_irq(channel->dma_irq);
+ else
+ xgbe_disable_rx_tx_ints(pdata);
/* Turn on polling */
- __napi_schedule(&pdata->napi);
+ __napi_schedule(napi);
}
channel->tx_timer_active = 0;
static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add)
{
- if (add)
- netif_napi_add(pdata->netdev, &pdata->napi, xgbe_poll,
- NAPI_POLL_WEIGHT);
- napi_enable(&pdata->napi);
+ struct xgbe_channel *channel;
+ unsigned int i;
+
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (add)
+ netif_napi_add(pdata->netdev, &channel->napi,
+ xgbe_one_poll, NAPI_POLL_WEIGHT);
+
+ napi_enable(&channel->napi);
+ }
+ } else {
+ if (add)
+ netif_napi_add(pdata->netdev, &pdata->napi,
+ xgbe_all_poll, NAPI_POLL_WEIGHT);
+
+ napi_enable(&pdata->napi);
+ }
}
static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del)
{
- napi_disable(&pdata->napi);
+ struct xgbe_channel *channel;
+ unsigned int i;
+
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ napi_disable(&channel->napi);
+
+ if (del)
+ netif_napi_del(&channel->napi);
+ }
+ } else {
+ napi_disable(&pdata->napi);
- if (del)
- netif_napi_del(&pdata->napi);
+ if (del)
+ netif_napi_del(&pdata->napi);
+ }
}
void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata)
DBGPR("<--xgbe_init_rx_coalesce\n");
}
-static void xgbe_free_tx_skbuff(struct xgbe_prv_data *pdata)
+static void xgbe_free_tx_data(struct xgbe_prv_data *pdata)
{
struct xgbe_desc_if *desc_if = &pdata->desc_if;
struct xgbe_channel *channel;
struct xgbe_ring_data *rdata;
unsigned int i, j;
- DBGPR("-->xgbe_free_tx_skbuff\n");
+ DBGPR("-->xgbe_free_tx_data\n");
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
for (j = 0; j < ring->rdesc_count; j++) {
rdata = XGBE_GET_DESC_DATA(ring, j);
- desc_if->unmap_skb(pdata, rdata);
+ desc_if->unmap_rdata(pdata, rdata);
}
}
- DBGPR("<--xgbe_free_tx_skbuff\n");
+ DBGPR("<--xgbe_free_tx_data\n");
}
-static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata)
+static void xgbe_free_rx_data(struct xgbe_prv_data *pdata)
{
struct xgbe_desc_if *desc_if = &pdata->desc_if;
struct xgbe_channel *channel;
struct xgbe_ring_data *rdata;
unsigned int i, j;
- DBGPR("-->xgbe_free_rx_skbuff\n");
+ DBGPR("-->xgbe_free_rx_data\n");
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
for (j = 0; j < ring->rdesc_count; j++) {
rdata = XGBE_GET_DESC_DATA(ring, j);
- desc_if->unmap_skb(pdata, rdata);
+ desc_if->unmap_rdata(pdata, rdata);
}
}
- DBGPR("<--xgbe_free_rx_skbuff\n");
+ DBGPR("<--xgbe_free_rx_data\n");
}
static void xgbe_adjust_link(struct net_device *netdev)
static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset)
{
+ struct xgbe_channel *channel;
struct xgbe_hw_if *hw_if = &pdata->hw_if;
+ unsigned int i;
DBGPR("-->xgbe_restart_dev\n");
return;
xgbe_stop(pdata);
- synchronize_irq(pdata->irq_number);
+ synchronize_irq(pdata->dev_irq);
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++)
+ synchronize_irq(channel->dma_irq);
+ }
- xgbe_free_tx_skbuff(pdata);
- xgbe_free_rx_skbuff(pdata);
+ xgbe_free_tx_data(pdata);
+ xgbe_free_rx_data(pdata);
/* Issue software reset to device if requested */
if (reset)
packet->rdesc_count = 0;
if (xgbe_is_tso(skb)) {
- /* TSO requires an extra desriptor if mss is different */
+ /* TSO requires an extra descriptor if mss is different */
if (skb_shinfo(skb)->gso_size != ring->tx.cur_mss) {
context_desc = 1;
packet->rdesc_count++;
}
- /* TSO requires an extra desriptor for TSO header */
+ /* TSO requires an extra descriptor for TSO header */
packet->rdesc_count++;
XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_desc_if *desc_if = &pdata->desc_if;
+ struct xgbe_channel *channel = NULL;
+ char dma_irq_name[IFNAMSIZ + 32];
+ unsigned int i = 0;
int ret;
DBGPR("-->xgbe_open\n");
goto err_ptpclk;
pdata->rx_buf_size = ret;
+ /* Allocate the channel and ring structures */
+ ret = xgbe_alloc_channels(pdata);
+ if (ret)
+ goto err_ptpclk;
+
/* Allocate the ring descriptors and buffers */
ret = desc_if->alloc_ring_resources(pdata);
if (ret)
- goto err_ptpclk;
+ goto err_channels;
/* Initialize the device restart and Tx timestamp work struct */
INIT_WORK(&pdata->restart_work, xgbe_restart);
INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
/* Request interrupts */
- ret = devm_request_irq(pdata->dev, netdev->irq, xgbe_isr, 0,
+ ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
netdev->name, pdata);
if (ret) {
netdev_alert(netdev, "error requesting irq %d\n",
- pdata->irq_number);
- goto err_irq;
+ pdata->dev_irq);
+ goto err_rings;
+ }
+
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ snprintf(dma_irq_name, sizeof(dma_irq_name) - 1,
+ "%s-TxRx-%u", netdev_name(netdev),
+ channel->queue_index);
+
+ ret = devm_request_irq(pdata->dev, channel->dma_irq,
+ xgbe_dma_isr, 0, dma_irq_name,
+ channel);
+ if (ret) {
+ netdev_alert(netdev,
+ "error requesting irq %d\n",
+ channel->dma_irq);
+ goto err_irq;
+ }
+ }
}
- pdata->irq_number = netdev->irq;
ret = xgbe_start(pdata);
if (ret)
err_start:
hw_if->exit(pdata);
- devm_free_irq(pdata->dev, pdata->irq_number, pdata);
- pdata->irq_number = 0;
-
err_irq:
+ if (pdata->per_channel_irq) {
+ /* Using an unsigned int, 'i' will go to UINT_MAX and exit */
+ for (i--, channel--; i < pdata->channel_count; i--, channel--)
+ devm_free_irq(pdata->dev, channel->dma_irq, channel);
+ }
+
+ devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+
+err_rings:
desc_if->free_ring_resources(pdata);
+err_channels:
+ xgbe_free_channels(pdata);
+
err_ptpclk:
clk_disable_unprepare(pdata->ptpclk);
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_desc_if *desc_if = &pdata->desc_if;
+ struct xgbe_channel *channel;
+ unsigned int i;
DBGPR("-->xgbe_close\n");
/* Issue software reset to device */
hw_if->exit(pdata);
- /* Free all the ring data */
+ /* Free the ring descriptors and buffers */
desc_if->free_ring_resources(pdata);
- /* Release the interrupt */
- if (pdata->irq_number != 0) {
- devm_free_irq(pdata->dev, pdata->irq_number, pdata);
- pdata->irq_number = 0;
+ /* Release the interrupts */
+ devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++)
+ devm_free_irq(pdata->dev, channel->dma_irq, channel);
}
+ /* Free the channel and ring structures */
+ xgbe_free_channels(pdata);
+
/* Disable the clocks */
clk_disable_unprepare(pdata->ptpclk);
clk_disable_unprepare(pdata->sysclk);
xgbe_prep_tx_tstamp(pdata, skb, packet);
/* Configure required descriptor fields for transmission */
- hw_if->pre_xmit(channel);
+ hw_if->dev_xmit(channel);
#ifdef XGMAC_ENABLE_TX_PKT_DUMP
xgbe_print_pkt(netdev, skb, true);
static void xgbe_poll_controller(struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ struct xgbe_channel *channel;
+ unsigned int i;
DBGPR("-->xgbe_poll_controller\n");
- disable_irq(pdata->irq_number);
-
- xgbe_isr(pdata->irq_number, pdata);
-
- enable_irq(pdata->irq_number);
+ if (pdata->per_channel_irq) {
+ channel = pdata->channel;
+ for (i = 0; i < pdata->channel_count; i++, channel++)
+ xgbe_dma_isr(channel->dma_irq, channel);
+ } else {
+ disable_irq(pdata->dev_irq);
+ xgbe_isr(pdata->dev_irq, pdata);
+ enable_irq(pdata->dev_irq);
+ }
DBGPR("<--xgbe_poll_controller\n");
}
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- netdev_features_t rxcsum, rxvlan, rxvlan_filter;
+ netdev_features_t rxhash, rxcsum, rxvlan, rxvlan_filter;
+ int ret = 0;
+ rxhash = pdata->netdev_features & NETIF_F_RXHASH;
rxcsum = pdata->netdev_features & NETIF_F_RXCSUM;
rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX;
rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER;
+ if ((features & NETIF_F_RXHASH) && !rxhash)
+ ret = hw_if->enable_rss(pdata);
+ else if (!(features & NETIF_F_RXHASH) && rxhash)
+ ret = hw_if->disable_rss(pdata);
+ if (ret)
+ return ret;
+
if ((features & NETIF_F_RXCSUM) && !rxcsum)
hw_if->enable_rx_csum(pdata);
else if (!(features & NETIF_F_RXCSUM) && rxcsum)
struct xgbe_ring *ring = channel->rx_ring;
struct xgbe_ring_data *rdata;
- desc_if->realloc_skb(channel);
+ desc_if->realloc_rx_buffer(channel);
/* Update the Rx Tail Pointer Register with address of
* the last cleaned entry */
lower_32_bits(rdata->rdesc_dma));
}
+static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata,
+ struct xgbe_ring_data *rdata,
+ unsigned int *len)
+{
+ struct net_device *netdev = pdata->netdev;
+ struct sk_buff *skb;
+ u8 *packet;
+ unsigned int copy_len;
+
+ skb = netdev_alloc_skb_ip_align(netdev, rdata->rx_hdr.dma_len);
+ if (!skb)
+ return NULL;
+
+ packet = page_address(rdata->rx_hdr.pa.pages) +
+ rdata->rx_hdr.pa.pages_offset;
+ copy_len = (rdata->hdr_len) ? rdata->hdr_len : *len;
+ copy_len = min(rdata->rx_hdr.dma_len, copy_len);
+ skb_copy_to_linear_data(skb, packet, copy_len);
+ skb_put(skb, copy_len);
+
+ *len -= copy_len;
+
+ return skb;
+}
+
static int xgbe_tx_poll(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
#endif
/* Free the SKB and reset the descriptor for re-use */
- desc_if->unmap_skb(pdata, rdata);
+ desc_if->unmap_rdata(pdata, rdata);
hw_if->tx_desc_reset(rdata);
processed++;
struct xgbe_ring_data *rdata;
struct xgbe_packet_data *packet;
struct net_device *netdev = pdata->netdev;
+ struct napi_struct *napi;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwtstamps;
unsigned int incomplete, error, context_next, context;
if (!ring)
return 0;
+ napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
+
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
packet = &ring->packet_data;
while (packet_count < budget) {
ring->cur++;
ring->dirty++;
- dma_unmap_single(pdata->dev, rdata->skb_dma,
- rdata->skb_dma_len, DMA_FROM_DEVICE);
- rdata->skb_dma = 0;
-
incomplete = XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES,
INCOMPLETE);
if (!context) {
put_len = rdata->len - len;
- if (skb) {
- if (pskb_expand_head(skb, 0, put_len,
- GFP_ATOMIC)) {
- DBGPR("pskb_expand_head error\n");
- if (incomplete) {
- error = 1;
- goto read_again;
- }
-
- dev_kfree_skb(skb);
- goto next_packet;
+ len += put_len;
+
+ if (!skb) {
+ dma_sync_single_for_cpu(pdata->dev,
+ rdata->rx_hdr.dma,
+ rdata->rx_hdr.dma_len,
+ DMA_FROM_DEVICE);
+
+ skb = xgbe_create_skb(pdata, rdata, &put_len);
+ if (!skb) {
+ error = 1;
+ goto skip_data;
}
- memcpy(skb_tail_pointer(skb), rdata->skb->data,
- put_len);
- } else {
- skb = rdata->skb;
- rdata->skb = NULL;
}
- skb_put(skb, put_len);
- len += put_len;
+
+ if (put_len) {
+ dma_sync_single_for_cpu(pdata->dev,
+ rdata->rx_buf.dma,
+ rdata->rx_buf.dma_len,
+ DMA_FROM_DEVICE);
+
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+ rdata->rx_buf.pa.pages,
+ rdata->rx_buf.pa.pages_offset,
+ put_len, rdata->rx_buf.dma_len);
+ rdata->rx_buf.pa.pages = NULL;
+ }
}
+skip_data:
if (incomplete || context_next)
goto read_again;
- /* Stray Context Descriptor? */
if (!skb)
goto next_packet;
hwtstamps->hwtstamp = ns_to_ktime(nsec);
}
+ if (XGMAC_GET_BITS(packet->attributes,
+ RX_PACKET_ATTRIBUTES, RSS_HASH))
+ skb_set_hash(skb, packet->rss_hash,
+ packet->rss_hash_type);
+
skb->dev = netdev;
skb->protocol = eth_type_trans(skb, netdev);
skb_record_rx_queue(skb, channel->queue_index);
- skb_mark_napi_id(skb, &pdata->napi);
+ skb_mark_napi_id(skb, napi);
netdev->last_rx = jiffies;
- napi_gro_receive(&pdata->napi, skb);
+ napi_gro_receive(napi, skb);
next_packet:
packet_count++;
return packet_count;
}
-static int xgbe_poll(struct napi_struct *napi, int budget)
+static int xgbe_one_poll(struct napi_struct *napi, int budget)
+{
+ struct xgbe_channel *channel = container_of(napi, struct xgbe_channel,
+ napi);
+ int processed = 0;
+
+ DBGPR("-->xgbe_one_poll: budget=%d\n", budget);
+
+ /* Cleanup Tx ring first */
+ xgbe_tx_poll(channel);
+
+ /* Process Rx ring next */
+ processed = xgbe_rx_poll(channel, budget);
+
+ /* If we processed everything, we are done */
+ if (processed < budget) {
+ /* Turn off polling */
+ napi_complete(napi);
+
+ /* Enable Tx and Rx interrupts */
+ enable_irq(channel->dma_irq);
+ }
+
+ DBGPR("<--xgbe_one_poll: received = %d\n", processed);
+
+ return processed;
+}
+
+static int xgbe_all_poll(struct napi_struct *napi, int budget)
{
struct xgbe_prv_data *pdata = container_of(napi, struct xgbe_prv_data,
napi);
int processed, last_processed;
unsigned int i;
- DBGPR("-->xgbe_poll: budget=%d\n", budget);
+ DBGPR("-->xgbe_all_poll: budget=%d\n", budget);
processed = 0;
ring_budget = budget / pdata->rx_ring_count;
xgbe_enable_rx_tx_ints(pdata);
}
- DBGPR("<--xgbe_poll: received = %d\n", processed);
+ DBGPR("<--xgbe_all_poll: received = %d\n", processed);
return processed;
}
while (count--) {
rdata = XGBE_GET_DESC_DATA(ring, idx);
rdesc = rdata->rdesc;
- DBGPR("TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx,
- (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE",
- le32_to_cpu(rdesc->desc0), le32_to_cpu(rdesc->desc1),
- le32_to_cpu(rdesc->desc2), le32_to_cpu(rdesc->desc3));
+ pr_alert("TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx,
+ (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE",
+ le32_to_cpu(rdesc->desc0), le32_to_cpu(rdesc->desc1),
+ le32_to_cpu(rdesc->desc2), le32_to_cpu(rdesc->desc3));
idx++;
}
}
void xgbe_dump_rx_desc(struct xgbe_ring *ring, struct xgbe_ring_desc *desc,
unsigned int idx)
{
- DBGPR("RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n", idx,
- le32_to_cpu(desc->desc0), le32_to_cpu(desc->desc1),
- le32_to_cpu(desc->desc2), le32_to_cpu(desc->desc3));
+ pr_alert("RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n", idx,
+ le32_to_cpu(desc->desc0), le32_to_cpu(desc->desc1),
+ le32_to_cpu(desc->desc2), le32_to_cpu(desc->desc3));
}
void xgbe_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx)
rx_usecs);
return -EINVAL;
}
- if (rx_frames > pdata->channel->rx_ring->rdesc_count) {
+ if (rx_frames > pdata->rx_desc_count) {
netdev_alert(netdev, "rx-frames is limited to %d frames\n",
- pdata->channel->rx_ring->rdesc_count);
+ pdata->rx_desc_count);
return -EINVAL;
}
tx_frames = ec->tx_max_coalesced_frames;
/* Check the bounds of values for Tx */
- if (tx_frames > pdata->channel->tx_ring->rdesc_count) {
+ if (tx_frames > pdata->tx_desc_count) {
netdev_alert(netdev, "tx-frames is limited to %d frames\n",
- pdata->channel->tx_ring->rdesc_count);
+ pdata->tx_desc_count);
return -EINVAL;
}
return 0;
}
+static int xgbe_get_rxnfc(struct net_device *netdev,
+ struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ switch (rxnfc->cmd) {
+ case ETHTOOL_GRXRINGS:
+ rxnfc->data = pdata->rx_ring_count;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static u32 xgbe_get_rxfh_key_size(struct net_device *netdev)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ return sizeof(pdata->rss_key);
+}
+
+static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ return ARRAY_SIZE(pdata->rss_table);
+}
+
+static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ unsigned int i;
+
+ if (indir) {
+ for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
+ indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
+ MAC_RSSDR, DMCH);
+ }
+
+ if (key)
+ memcpy(key, pdata->rss_key, sizeof(pdata->rss_key));
+
+ return 0;
+}
+
+static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
+ const u8 *key)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ struct xgbe_hw_if *hw_if = &pdata->hw_if;
+ unsigned int ret;
+
+ if (indir) {
+ ret = hw_if->set_rss_lookup_table(pdata, indir);
+ if (ret)
+ return ret;
+ }
+
+ if (key) {
+ ret = hw_if->set_rss_hash_key(pdata, key);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int xgbe_get_ts_info(struct net_device *netdev,
struct ethtool_ts_info *ts_info)
{
.get_strings = xgbe_get_strings,
.get_ethtool_stats = xgbe_get_ethtool_stats,
.get_sset_count = xgbe_get_sset_count,
+ .get_rxnfc = xgbe_get_rxnfc,
+ .get_rxfh_key_size = xgbe_get_rxfh_key_size,
+ .get_rxfh_indir_size = xgbe_get_rxfh_indir_size,
+ .get_rxfh = xgbe_get_rxfh,
+ .set_rxfh = xgbe_set_rxfh,
.get_ts_info = xgbe_get_ts_info,
};
MODULE_VERSION(XGBE_DRV_VERSION);
MODULE_DESCRIPTION(XGBE_DRV_DESC);
-static struct xgbe_channel *xgbe_alloc_rings(struct xgbe_prv_data *pdata)
-{
- struct xgbe_channel *channel_mem, *channel;
- struct xgbe_ring *tx_ring, *rx_ring;
- unsigned int count, i;
-
- DBGPR("-->xgbe_alloc_rings\n");
-
- count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count);
-
- channel_mem = devm_kcalloc(pdata->dev, count,
- sizeof(struct xgbe_channel), GFP_KERNEL);
- if (!channel_mem)
- return NULL;
-
- tx_ring = devm_kcalloc(pdata->dev, pdata->tx_ring_count,
- sizeof(struct xgbe_ring), GFP_KERNEL);
- if (!tx_ring)
- return NULL;
-
- rx_ring = devm_kcalloc(pdata->dev, pdata->rx_ring_count,
- sizeof(struct xgbe_ring), GFP_KERNEL);
- if (!rx_ring)
- return NULL;
-
- for (i = 0, channel = channel_mem; i < count; i++, channel++) {
- snprintf(channel->name, sizeof(channel->name), "channel-%d", i);
- channel->pdata = pdata;
- channel->queue_index = i;
- channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE +
- (DMA_CH_INC * i);
-
- if (i < pdata->tx_ring_count) {
- spin_lock_init(&tx_ring->lock);
- channel->tx_ring = tx_ring++;
- }
-
- if (i < pdata->rx_ring_count) {
- spin_lock_init(&rx_ring->lock);
- channel->rx_ring = rx_ring++;
- }
-
- DBGPR(" %s - queue_index=%u, dma_regs=%p, tx=%p, rx=%p\n",
- channel->name, channel->queue_index, channel->dma_regs,
- channel->tx_ring, channel->rx_ring);
- }
-
- pdata->channel_count = count;
-
- DBGPR("<--xgbe_alloc_rings\n");
-
- return channel_mem;
-}
-
static void xgbe_default_config(struct xgbe_prv_data *pdata)
{
DBGPR("-->xgbe_default_config\n");
struct device *dev = &pdev->dev;
struct resource *res;
const u8 *mac_addr;
+ unsigned int i;
int ret;
DBGPR("--> xgbe_probe\n");
spin_lock_init(&pdata->lock);
mutex_init(&pdata->xpcs_mutex);
+ mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
/* Set and validate the number of descriptors for a ring */
pdata->awcache = XGBE_DMA_SYS_AWCACHE;
}
+ /* Check for per channel interrupt support */
+ if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS))
+ pdata->per_channel_irq = 1;
+
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
- dev_err(dev, "platform_get_irq failed\n");
+ dev_err(dev, "platform_get_irq 0 failed\n");
goto err_io;
}
- netdev->irq = ret;
+ pdata->dev_irq = ret;
+
+ netdev->irq = pdata->dev_irq;
netdev->base_addr = (unsigned long)pdata->xgmac_regs;
/* Set all the function pointers */
goto err_io;
}
- /* Allocate the rings for the DMA channels */
- pdata->channel = xgbe_alloc_rings(pdata);
- if (!pdata->channel) {
- dev_err(dev, "ring allocation failed\n");
- ret = -ENOMEM;
- goto err_io;
- }
+ /* Initialize RSS hash key and lookup table */
+ get_random_bytes(pdata->rss_key, sizeof(pdata->rss_key));
+
+ for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
+ XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
+ i % pdata->rx_ring_count);
+
+ XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
+ XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
+ XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
/* Prepare to regsiter with MDIO */
pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name);
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_FILTER;
+ if (pdata->hw_feat.rss)
+ netdev->hw_features |= NETIF_F_RXHASH;
+
netdev->vlan_features |= NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
#define XGBE_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
#define XGBE_RX_BUF_ALIGN 64
+#define XGBE_SKB_ALLOC_SIZE 256
+#define XGBE_SPH_HDSMS_SIZE 2 /* Keep in sync with SKB_ALLOC_SIZE */
#define XGBE_MAX_DMA_CHANNELS 16
#define XGBE_MAX_QUEUES 16
/* Device-tree clock names */
#define XGBE_DMA_CLOCK "dma_clk"
#define XGBE_PTP_CLOCK "ptp_clk"
+#define XGBE_DMA_IRQS "amd,per-channel-interrupt"
/* Timestamp support - values based on 50MHz PTP clock
* 50MHz => 20 nsec
/* Maximum MAC address hash table size (256 bits = 8 bytes) */
#define XGBE_MAC_HASH_TABLE_SIZE 8
+/* Receive Side Scaling */
+#define XGBE_RSS_HASH_KEY_SIZE 40
+#define XGBE_RSS_MAX_TABLE_SIZE 256
+#define XGBE_RSS_LOOKUP_TABLE_TYPE 0
+#define XGBE_RSS_HASH_KEY_TYPE 1
+
struct xgbe_prv_data;
struct xgbe_packet_data {
unsigned short vlan_ctag;
u64 rx_tstamp;
+
+ u32 rss_hash;
+ enum pkt_hash_types rss_hash_type;
};
/* Common Rx and Tx descriptor mapping */
struct xgbe_ring_desc {
- unsigned int desc0;
- unsigned int desc1;
- unsigned int desc2;
- unsigned int desc3;
+ __le32 desc0;
+ __le32 desc1;
+ __le32 desc2;
+ __le32 desc3;
+};
+
+/* Page allocation related values */
+struct xgbe_page_alloc {
+ struct page *pages;
+ unsigned int pages_len;
+ unsigned int pages_offset;
+
+ dma_addr_t pages_dma;
+};
+
+/* Ring entry buffer data */
+struct xgbe_buffer_data {
+ struct xgbe_page_alloc pa;
+ struct xgbe_page_alloc pa_unmap;
+
+ dma_addr_t dma;
+ unsigned int dma_len;
};
/* Structure used to hold information related to the descriptor
unsigned int skb_dma_len; /* Length of SKB DMA area */
unsigned int tso_header; /* TSO header indicator */
+ struct xgbe_buffer_data rx_hdr; /* Header locations */
+ struct xgbe_buffer_data rx_buf; /* Payload locations */
+
+ unsigned short hdr_len; /* Length of received header */
unsigned short len; /* Length of received Rx packet */
unsigned int interrupt; /* Interrupt indicator */
*/
struct xgbe_ring_data *rdata;
+ /* Page allocation for RX buffers */
+ struct xgbe_page_alloc rx_hdr_pa;
+ struct xgbe_page_alloc rx_buf_pa;
+
/* Ring index values
* cur - Tx: index of descriptor to be used for current transfer
* Rx: index of descriptor to check for packet availability
unsigned int queue_index;
void __iomem *dma_regs;
+ /* Per channel interrupt irq number */
+ int dma_irq;
+
+ /* Netdev related settings */
+ struct napi_struct napi;
+
unsigned int saved_ier;
unsigned int tx_timer_active;
int (*enable_int)(struct xgbe_channel *, enum xgbe_int);
int (*disable_int)(struct xgbe_channel *, enum xgbe_int);
- void (*pre_xmit)(struct xgbe_channel *);
+ void (*dev_xmit)(struct xgbe_channel *);
int (*dev_read)(struct xgbe_channel *);
void (*tx_desc_init)(struct xgbe_channel *);
void (*rx_desc_init)(struct xgbe_channel *);
/* For Data Center Bridging config */
void (*config_dcb_tc)(struct xgbe_prv_data *);
void (*config_dcb_pfc)(struct xgbe_prv_data *);
+
+ /* For Receive Side Scaling */
+ int (*enable_rss)(struct xgbe_prv_data *);
+ int (*disable_rss)(struct xgbe_prv_data *);
+ int (*set_rss_hash_key)(struct xgbe_prv_data *, const u8 *);
+ int (*set_rss_lookup_table)(struct xgbe_prv_data *, const u32 *);
};
struct xgbe_desc_if {
int (*alloc_ring_resources)(struct xgbe_prv_data *);
void (*free_ring_resources)(struct xgbe_prv_data *);
int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *);
- void (*realloc_skb)(struct xgbe_channel *);
- void (*unmap_skb)(struct xgbe_prv_data *, struct xgbe_ring_data *);
+ void (*realloc_rx_buffer)(struct xgbe_channel *);
+ void (*unmap_rdata)(struct xgbe_prv_data *, struct xgbe_ring_data *);
void (*wrapper_tx_desc_init)(struct xgbe_prv_data *);
void (*wrapper_rx_desc_init)(struct xgbe_prv_data *);
};
/* XPCS indirect addressing mutex */
struct mutex xpcs_mutex;
- int irq_number;
+ /* RSS addressing mutex */
+ struct mutex rss_mutex;
+
+ int dev_irq;
+ unsigned int per_channel_irq;
struct xgbe_hw_if hw_if;
struct xgbe_desc_if desc_if;
unsigned int rx_riwt;
unsigned int rx_frames;
- /* Current MTU */
+ /* Current Rx buffer size */
unsigned int rx_buf_size;
/* Flow control settings */
unsigned int tx_pause;
unsigned int rx_pause;
+ /* Receive Side Scaling settings */
+ u8 rss_key[XGBE_RSS_HASH_KEY_SIZE];
+ u32 rss_table[XGBE_RSS_MAX_TABLE_SIZE];
+ u32 rss_options;
+
/* MDIO settings */
struct module *phy_module;
char *mii_bus_id;
ndev = pdata->ndev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr");
- if (!res) {
- dev_err(dev, "Resource enet_csr not defined\n");
- return -ENODEV;
- }
pdata->base_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->base_addr)) {
dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr");
- if (!res) {
- dev_err(dev, "Resource ring_csr not defined\n");
- return -ENODEV;
- }
pdata->ring_csr_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->ring_csr_addr)) {
dev_err(dev, "Unable to retrieve ENET Ring CSR region\n");
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd");
- if (!res) {
- dev_err(dev, "Resource ring_cmd not defined\n");
- return -ENODEV;
- }
pdata->ring_cmd_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->ring_cmd_addr)) {
dev_err(dev, "Unable to retrieve ENET Ring command region\n");
napi_complete(napi);
/* re-enable TX interrupt */
intrl2_1_mask_clear(ring->priv, BIT(ring->index));
+
+ return 0;
}
- return 0;
+ return budget;
}
static void bcm_sysport_tx_reclaim_all(struct bcm_sysport_priv *priv)
prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
prefetch(&fp->sb_running_index[SM_RX_ID]);
- napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+ napi_schedule_irqoff(&bnx2x_fp(bp, fp->index, napi));
return IRQ_HANDLED;
}
for_each_cos_in_tx_queue(fp, cos)
prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
prefetch(&fp->sb_running_index[SM_RX_ID]);
- napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+ napi_schedule_irqoff(&bnx2x_fp(bp, fp->index, napi));
status &= ~mask;
}
}
cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
+cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
unsigned char link_ok; /* link up? */
};
-#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
enum {
MAX_ETH_QSETS = 32, /* # of Ethernet Tx/Rx queue sets */
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val);
void t4_sge_decode_idma_state(struct adapter *adapter, int state);
+void t4_free_mem(void *addr);
#endif /* __CXGB4_H__ */
do { \
memset(&(__pcmd), 0, sizeof(__pcmd)); \
(__pcmd).op_to_portid = \
- cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | \
- FW_CMD_REQUEST | \
- FW_CMD_##__op | \
+ cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | \
+ FW_CMD_REQUEST_F | \
+ FW_CMD_##__op##_F | \
FW_PORT_CMD_PORTID(__port)); \
(__pcmd).action_to_len16 = \
cpu_to_be32(FW_PORT_CMD_ACTION(__action) | \
--- /dev/null
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/string_helpers.h>
+#include <linux/sort.h>
+
+#include "cxgb4.h"
+#include "t4_regs.h"
+#include "t4fw_api.h"
+#include "cxgb4_debugfs.h"
+#include "l2t.h"
+
+static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ loff_t pos = *ppos;
+ loff_t avail = file_inode(file)->i_size;
+ unsigned int mem = (uintptr_t)file->private_data & 3;
+ struct adapter *adap = file->private_data - mem;
+ __be32 *data;
+ int ret;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= avail)
+ return 0;
+ if (count > avail - pos)
+ count = avail - pos;
+
+ data = t4_alloc_mem(count);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock(&adap->win0_lock);
+ ret = t4_memory_rw(adap, 0, mem, pos, count, data, T4_MEMORY_READ);
+ spin_unlock(&adap->win0_lock);
+ if (ret) {
+ t4_free_mem(data);
+ return ret;
+ }
+ ret = copy_to_user(buf, data, count);
+
+ t4_free_mem(data);
+ if (ret)
+ return -EFAULT;
+
+ *ppos = pos + count;
+ return count;
+}
+
+static const struct file_operations mem_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = mem_read,
+ .llseek = default_llseek,
+};
+
+static void add_debugfs_mem(struct adapter *adap, const char *name,
+ unsigned int idx, unsigned int size_mb)
+{
+ struct dentry *de;
+
+ de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root,
+ (void *)adap + idx, &mem_debugfs_fops);
+ if (de && de->d_inode)
+ de->d_inode->i_size = size_mb << 20;
+}
+
+/* Add an array of Debug FS files.
+ */
+void add_debugfs_files(struct adapter *adap,
+ struct t4_debugfs_entry *files,
+ unsigned int nfiles)
+{
+ int i;
+
+ /* debugfs support is best effort */
+ for (i = 0; i < nfiles; i++)
+ debugfs_create_file(files[i].name, files[i].mode,
+ adap->debugfs_root,
+ (void *)adap + files[i].data,
+ files[i].ops);
+}
+
+int t4_setup_debugfs(struct adapter *adap)
+{
+ int i;
+ u32 size;
+
+ static struct t4_debugfs_entry t4_debugfs_files[] = {
+ { "l2t", &t4_l2t_fops, S_IRUSR, 0},
+ };
+
+ add_debugfs_files(adap,
+ t4_debugfs_files,
+ ARRAY_SIZE(t4_debugfs_files));
+
+ i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+ if (i & EDRAM0_ENABLE_F) {
+ size = t4_read_reg(adap, MA_EDRAM0_BAR_A);
+ add_debugfs_mem(adap, "edc0", MEM_EDC0, EDRAM0_SIZE_G(size));
+ }
+ if (i & EDRAM1_ENABLE_F) {
+ size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
+ add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM1_SIZE_G(size));
+ }
+ if (is_t4(adap->params.chip)) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
+ if (i & EXT_MEM_ENABLE_F)
+ add_debugfs_mem(adap, "mc", MEM_MC,
+ EXT_MEM_SIZE_G(size));
+ } else {
+ if (i & EXT_MEM0_ENABLE_F) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
+ add_debugfs_mem(adap, "mc0", MEM_MC0,
+ EXT_MEM0_SIZE_G(size));
+ }
+ if (i & EXT_MEM1_ENABLE_F) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+ add_debugfs_mem(adap, "mc1", MEM_MC1,
+ EXT_MEM1_SIZE_G(size));
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CXGB4_DEBUGFS_H
+#define __CXGB4_DEBUGFS_H
+
+#include <linux/export.h>
+
+struct t4_debugfs_entry {
+ const char *name;
+ const struct file_operations *ops;
+ mode_t mode;
+ unsigned char data;
+};
+
+int t4_setup_debugfs(struct adapter *adap);
+void add_debugfs_files(struct adapter *adap,
+ struct t4_debugfs_entry *files,
+ unsigned int nfiles);
+
+#endif
#include <net/neighbour.h>
#include <net/netevent.h>
#include <net/addrconf.h>
+#include <net/bonding.h>
#include <asm/uaccess.h>
#include "cxgb4.h"
#include "t4_msg.h"
#include "t4fw_api.h"
#include "cxgb4_dcb.h"
+#include "cxgb4_debugfs.h"
#include "l2t.h"
-#include <../drivers/net/bonding/bonding.h>
-
#ifdef DRV_VERSION
#undef DRV_VERSION
#endif
#ifdef CONFIG_CHELSIO_T4_DCB
const struct fw_port_cmd *pcmd = (const void *)p->data;
- unsigned int cmd = FW_CMD_OP_GET(ntohl(pcmd->op_to_portid));
+ unsigned int cmd = FW_CMD_OP_G(ntohl(pcmd->op_to_portid));
unsigned int action =
FW_PORT_CMD_ACTION_GET(ntohl(pcmd->action_to_len16));
/*
* Free memory allocated through alloc_mem().
*/
-static void t4_free_mem(void *addr)
+void t4_free_mem(void *addr)
{
if (is_vmalloc_addr(addr))
vfree(addr);
* filter specification structure but for now it's easiest to simply
* put this fairly direct code in line ...
*/
- fwr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
- fwr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*fwr)/16));
+ fwr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
+ fwr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*fwr)/16));
fwr->tid_to_iq =
htonl(V_FW_FILTER_WR_TID(ftid) |
V_FW_FILTER_WR_RQTYPE(f->fs.type) |
.flash_device = set_flash,
};
-/*
- * debugfs support
- */
-static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- loff_t pos = *ppos;
- loff_t avail = file_inode(file)->i_size;
- unsigned int mem = (uintptr_t)file->private_data & 3;
- struct adapter *adap = file->private_data - mem;
- __be32 *data;
- int ret;
-
- if (pos < 0)
- return -EINVAL;
- if (pos >= avail)
- return 0;
- if (count > avail - pos)
- count = avail - pos;
-
- data = t4_alloc_mem(count);
- if (!data)
- return -ENOMEM;
-
- spin_lock(&adap->win0_lock);
- ret = t4_memory_rw(adap, 0, mem, pos, count, data, T4_MEMORY_READ);
- spin_unlock(&adap->win0_lock);
- if (ret) {
- t4_free_mem(data);
- return ret;
- }
- ret = copy_to_user(buf, data, count);
-
- t4_free_mem(data);
- if (ret)
- return -EFAULT;
-
- *ppos = pos + count;
- return count;
-}
-
-static const struct file_operations mem_debugfs_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = mem_read,
- .llseek = default_llseek,
-};
-
-static void add_debugfs_mem(struct adapter *adap, const char *name,
- unsigned int idx, unsigned int size_mb)
-{
- struct dentry *de;
-
- de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root,
- (void *)adap + idx, &mem_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = size_mb << 20;
-}
-
static int setup_debugfs(struct adapter *adap)
{
- int i;
- u32 size;
-
if (IS_ERR_OR_NULL(adap->debugfs_root))
return -1;
- i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE);
- if (i & EDRAM0_ENABLE) {
- size = t4_read_reg(adap, MA_EDRAM0_BAR);
- add_debugfs_mem(adap, "edc0", MEM_EDC0, EDRAM_SIZE_GET(size));
- }
- if (i & EDRAM1_ENABLE) {
- size = t4_read_reg(adap, MA_EDRAM1_BAR);
- add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM_SIZE_GET(size));
- }
- if (is_t4(adap->params.chip)) {
- size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
- if (i & EXT_MEM_ENABLE)
- add_debugfs_mem(adap, "mc", MEM_MC,
- EXT_MEM_SIZE_GET(size));
- } else {
- if (i & EXT_MEM_ENABLE) {
- size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
- add_debugfs_mem(adap, "mc0", MEM_MC0,
- EXT_MEM_SIZE_GET(size));
- }
- if (i & EXT_MEM1_ENABLE) {
- size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR);
- add_debugfs_mem(adap, "mc1", MEM_MC1,
- EXT_MEM_SIZE_GET(size));
- }
- }
- if (adap->l2t)
- debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap,
- &t4_l2t_fops);
+#ifdef CONFIG_DEBUG_FS
+ t4_setup_debugfs(adap);
+#endif
return 0;
}
adap = netdev2adap(dev);
memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
+ c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
c.ip_hi = *(__be64 *)(lip->s6_addr);
c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
adap = netdev2adap(dev);
memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
+ c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
c.ip_hi = *(__be64 *)(lip->s6_addr);
c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
req->local_ip = sip;
req->peer_ip = htonl(0);
chan = rxq_to_chan(&adap->sge, queue);
- req->opt0 = cpu_to_be64(TX_CHAN(chan));
+ req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
ret = t4_mgmt_tx(adap, skb);
req->peer_ip_hi = cpu_to_be64(0);
req->peer_ip_lo = cpu_to_be64(0);
chan = rxq_to_chan(&adap->sge, queue);
- req->opt0 = cpu_to_be64(TX_CHAN(chan));
+ req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
ret = t4_mgmt_tx(adap, skb);
{
struct adapter *adap;
u32 offset, memtype, memaddr;
- u32 edc0_size, edc1_size, mc0_size, mc1_size;
+ u32 edc0_size, edc1_size, mc0_size, mc1_size, size;
u32 edc0_end, edc1_end, mc0_end, mc1_end;
int ret;
* and EDC1. Some cards will have neither MC0 nor MC1, most cards have
* MC0, and some have both MC0 and MC1.
*/
- edc0_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR)) << 20;
- edc1_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM1_BAR)) << 20;
- mc0_size = EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR)) << 20;
+ size = t4_read_reg(adap, MA_EDRAM0_BAR_A);
+ edc0_size = EDRAM0_SIZE_G(size) << 20;
+ size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
+ edc1_size = EDRAM1_SIZE_G(size) << 20;
+ size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
+ mc0_size = EXT_MEM0_SIZE_G(size) << 20;
edc0_end = edc0_size;
edc1_end = edc0_end + edc1_size;
/* T4 only has a single memory channel */
goto err;
} else {
- mc1_size = EXT_MEM_SIZE_GET(
- t4_read_reg(adap,
- MA_EXT_MEMORY1_BAR)) << 20;
+ size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+ mc1_size = EXT_MEM1_SIZE_G(size) << 20;
mc1_end = mc0_end + mc1_size;
if (offset < mc1_end) {
memtype = MEM_MC1;
if (cxgb4_netdev(event_dev)) {
switch (event) {
case NETDEV_UP:
- ret = cxgb4_clip_get(event_dev,
- (const struct in6_addr *)ifa->addr.s6_addr);
+ ret = cxgb4_clip_get(event_dev, &ifa->addr);
if (ret < 0) {
rcu_read_unlock();
return ret;
ret = NOTIFY_OK;
break;
case NETDEV_DOWN:
- cxgb4_clip_release(event_dev,
- (const struct in6_addr *)ifa->addr.s6_addr);
+ cxgb4_clip_release(event_dev, &ifa->addr);
ret = NOTIFY_OK;
break;
default:
read_lock_bh(&idev->lock);
list_for_each_entry(ifa, &idev->addr_list, if_list) {
- ret = cxgb4_clip_get(dev,
- (const struct in6_addr *)ifa->addr.s6_addr);
+ ret = cxgb4_clip_get(dev, &ifa->addr);
if (ret < 0)
break;
}
*/
memset(&ldst_cmd, 0, sizeof(ldst_cmd));
ldst_cmd.op_to_addrspace =
- htonl(FW_CMD_OP(FW_LDST_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ htonl(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
/* get device capabilities */
memset(c, 0, sizeof(*c));
- c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
+ c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
if (ret < 0)
dev_err(adap->pdev_dev, "virtualization ACLs not supported");
return ret;
}
- c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
+ c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL);
if (ret < 0)
return ret;
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
caps_cmd.op_to_write =
- htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
caps_cmd.cfvalid_to_len16 =
htonl(FW_CAPS_CONFIG_CMD_CFVALID |
FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
if (ret == -ENOENT) {
memset(&caps_cmd, 0, sizeof(caps_cmd));
caps_cmd.op_to_write =
- htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd,
sizeof(caps_cmd), &caps_cmd);
* And now tell the firmware to use the configuration we just loaded.
*/
caps_cmd.op_to_write =
- htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE);
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F);
caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
NULL);
* Get device capabilities and select which we'll be using.
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
- caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
+ caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
&caps_cmd);
dev_err(adapter->pdev_dev, "virtualization ACLs not supported");
goto bye;
}
- caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
+ caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
NULL);
if (ret < 0)
} else {
dev_info(adap->pdev_dev, "Coming up as MASTER: "\
"Initializing adapter\n");
-
/*
* If the firmware doesn't support Configuration
* Files warn user and exit,
* to manage.
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
- caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
+ caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
&caps_cmd);
};
#define INIT_TP_WR(w, tid) do { \
- (w)->wr.wr_hi = htonl(FW_WR_OP(FW_TP_WR) | \
- FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \
- (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \
- FW_WR_FLOWID(tid)); \
+ (w)->wr.wr_hi = htonl(FW_WR_OP_V(FW_TP_WR) | \
+ FW_WR_IMMDLEN_V(sizeof(*w) - sizeof(w->wr))); \
+ (w)->wr.wr_mid = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*w), 16)) | \
+ FW_WR_FLOWID_V(tid)); \
(w)->wr.wr_lo = cpu_to_be64(0); \
} while (0)
} while (0)
#define INIT_ULPTX_WR(w, wrlen, atomic, tid) do { \
- (w)->wr.wr_hi = htonl(FW_WR_OP(FW_ULPTX_WR) | FW_WR_ATOMIC(atomic)); \
- (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(wrlen, 16)) | \
- FW_WR_FLOWID(tid)); \
+ (w)->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) | \
+ FW_WR_ATOMIC_V(atomic)); \
+ (w)->wr.wr_mid = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(wrlen, 16)) | \
+ FW_WR_FLOWID_V(tid)); \
(w)->wr.wr_lo = cpu_to_be64(0); \
} while (0)
if (tp->vnic_shift >= 0) {
u32 viid = cxgb4_port_viid(dev);
u32 vf = FW_VIID_VIN_GET(viid);
- u32 pf = FW_VIID_PFN_GET(viid);
+ u32 pf = FW_VIID_PFN_G(viid);
u32 vld = FW_VIID_VIVLD_GET(viid);
ntuple |= (u64)(V_FT_VNID_ID_VF(vf) |
__be64 *d = &q->desc[q->pidx];
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
- gfp |= __GFP_NOWARN | __GFP_COLD;
+ gfp |= __GFP_NOWARN;
if (s->fl_pg_order == 0)
goto alloc_small_pages;
* Prefer large buffers
*/
while (n) {
- pg = alloc_pages(gfp | __GFP_COMP, s->fl_pg_order);
+ pg = __dev_alloc_pages(gfp, s->fl_pg_order);
if (unlikely(!pg)) {
q->large_alloc_failed++;
break; /* fall back to single pages */
alloc_small_pages:
while (n--) {
- pg = __skb_alloc_page(gfp, NULL);
+ pg = __dev_alloc_page(gfp);
if (unlikely(!pg)) {
q->alloc_failed++;
break;
sgl->addr0 = cpu_to_be64(addr[1]);
}
- sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags));
+ sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags));
if (likely(--nfrags == 0))
return;
/*
goto out_free;
}
- wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+ wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2));
if (unlikely(credits < ETHTXQ_STOP_THRES)) {
eth_txq_stop(q);
- wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+ wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
}
wr = (void *)&q->q.desc[q->q.pidx];
int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
len += sizeof(*lso);
- wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
- FW_WR_IMMDLEN(len));
+ wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
+ FW_WR_IMMDLEN_V(len));
lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
LSO_FIRST_SLICE | LSO_LAST_SLICE |
LSO_IPV6(v6) |
q->tx_cso += ssi->gso_segs;
} else {
len += sizeof(*cpl);
- wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
- FW_WR_IMMDLEN(len));
+ wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
+ FW_WR_IMMDLEN_V(len));
cpl = (void *)(wr + 1);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
{
reclaim_completed_tx_imm(&q->q);
if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) {
- wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ);
+ wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F);
q->q.stops++;
q->full = 1;
}
{
struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data;
- wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ);
+ wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F);
q->q.stops++;
q->full = 1;
}
return -ENOMEM;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_CMD_EXEC |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) |
FW_LEN16(c));
return -ENOMEM;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_CMD_EXEC |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
if (!txq->q.desc)
return -ENOMEM;
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_CMD_EXEC |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_EQ_CTRL_CMD_PFN(adap->fn) |
FW_EQ_CTRL_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC |
return -ENOMEM;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_CMD_EXEC |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_EQ_OFLD_CMD_PFN(adap->fn) |
FW_EQ_OFLD_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC |
}
res = t4_read_reg64(adap, data_reg);
- if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) {
+ if (FW_CMD_OP_G(res >> 32) == FW_DEBUG_CMD) {
fw_asrt(adap, data_reg);
- res = FW_CMD_RETVAL(EIO);
- } else if (rpl)
+ res = FW_CMD_RETVAL_V(EIO);
+ } else if (rpl) {
get_mbox_rpl(adap, rpl, size / 8, data_reg);
+ }
- if (FW_CMD_RETVAL_GET((int)res))
+ if (FW_CMD_RETVAL_G((int)res))
dump_mbox(adap, mbox, data_reg);
t4_write_reg(adap, ctl_reg, 0);
- return -FW_CMD_RETVAL_GET((int)res);
+ return -FW_CMD_RETVAL_G((int)res);
}
}
* MEM_MC0 = 2 -- For T5
* MEM_MC1 = 3 -- For T5
*/
- edc_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR));
+ edc_size = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
if (mtype != MEM_MC1)
memoffset = (mtype * (edc_size * 1024 * 1024));
else {
- mc_size = EXT_MEM_SIZE_GET(t4_read_reg(adap,
- MA_EXT_MEMORY_BAR));
+ mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
+ MA_EXT_MEMORY1_BAR_A));
memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
}
fc |= FW_PORT_CAP_FC_TX;
memset(&c, 0, sizeof(c));
- c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
+ c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_PORT_CMD_PORTID(port));
c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
FW_LEN16(c));
struct fw_port_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
+ c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_PORT_CMD_PORTID(port));
c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
FW_LEN16(c));
c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
struct fw_rss_ind_tbl_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE |
+ cmd.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
FW_RSS_IND_TBL_CMD_VIID(viid));
cmd.retval_len16 = htonl(FW_LEN16(cmd));
struct fw_rss_glb_config_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
+ c.op_to_write = htonl(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
c.retval_len16 = htonl(FW_LEN16(c));
if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
{
memset(wr, 0, sizeof(*wr));
- wr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
- wr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*wr) / 16));
+ wr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
+ wr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*wr) / 16));
wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
V_FW_FILTER_WR_NOREPLY(qid < 0));
wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
}
#define INIT_CMD(var, cmd, rd_wr) do { \
- (var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \
- FW_CMD_REQUEST | FW_CMD_##rd_wr); \
+ (var).op_to_write = htonl(FW_CMD_OP_V(FW_##cmd##_CMD) | \
+ FW_CMD_REQUEST_F | FW_CMD_##rd_wr##_F); \
(var).retval_len16 = htonl(FW_LEN16(var)); \
} while (0)
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.addrval.addr = htonl(addr);
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
- FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
+ c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_READ_F | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
FW_LDST_CMD_MMD(mmd));
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
+ c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
FW_LDST_CMD_MMD(mmd));
return -EINVAL;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
- FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_READ_F | FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
for (i = 0; i < nparams; i++, p += 2)
return -EINVAL;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE |
+ c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
c.retval_len16 = cpu_to_be32(FW_LEN16(c));
return -EINVAL;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
while (nparams--) {
struct fw_pfvf_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PFVF_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_PFVF_CMD_PFN(pf) |
FW_PFVF_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) |
struct fw_vi_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_CMD_EXEC |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_VI_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c));
c.portid_pkd = FW_VI_CMD_PORTID(port);
vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid));
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_VI_RXMODE_CMD_VIID(viid));
c.retval_len16 = htonl(FW_LEN16(c));
c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) |
FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
return -EINVAL;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) |
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | (free ? FW_CMD_EXEC_F : 0) |
FW_VI_MAC_CMD_VIID(viid));
c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) |
- FW_CMD_LEN16((naddr + 2) / 2));
+ FW_CMD_LEN16_V((naddr + 2) / 2));
for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid));
- c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1));
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_VI_MAC_CMD_VIID(viid));
+ c.freemacs_to_len16 = htonl(FW_CMD_LEN16_V(1));
p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
FW_VI_MAC_CMD_SMAC_RESULT(mode) |
FW_VI_MAC_CMD_IDX(idx));
struct fw_vi_mac_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
- FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid));
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F | FW_VI_ENABLE_CMD_VIID(viid));
c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN |
FW_VI_MAC_CMD_HASHUNIEN(ucast) |
- FW_CMD_LEN16(1));
+ FW_CMD_LEN16_V(1));
c.u.hash.hashvec = cpu_to_be64(vec);
return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}
struct fw_vi_enable_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID(viid));
c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) |
FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c) |
struct fw_vi_enable_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
+ c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID(viid));
c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
c.blinkdur = htons(nblinks);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
struct fw_iq_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_IQ_CMD_PFN(pf) |
FW_IQ_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c));
c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype));
struct fw_eq_eth_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_EQ_ETH_CMD_PFN(pf) |
FW_EQ_ETH_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid));
struct fw_eq_ctrl_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_EQ_CTRL_CMD_PFN(pf) |
FW_EQ_CTRL_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid));
struct fw_eq_ofld_cmd c;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
- FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) |
+ c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F | FW_EQ_OFLD_CMD_PFN(pf) |
FW_EQ_OFLD_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid));
while ((adap->params.portvec & (1 << j)) == 0)
j++;
- c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ |
+ c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
FW_PORT_CMD_PORTID(j));
c.action_to_len16 = htonl(
FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
p->port_type = FW_PORT_CMD_PTYPE_GET(ret);
p->mod_type = FW_PORT_MOD_TYPE_NA;
- rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ |
+ rvc.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F |
FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
rvc.retval_len16 = htonl(FW_LEN16(rvc));
ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
#define WR_HDR struct work_request_hdr wr
/* option 0 fields */
-#define S_MSS_IDX 60
-#define M_MSS_IDX 0xF
-#define V_MSS_IDX(x) ((__u64)(x) << S_MSS_IDX)
-#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+#define TX_CHAN_S 2
+#define TX_CHAN_V(x) ((x) << TX_CHAN_S)
+
+#define ULP_MODE_S 8
+#define ULP_MODE_V(x) ((x) << ULP_MODE_S)
+
+#define RCV_BUFSIZ_S 12
+#define RCV_BUFSIZ_M 0x3FFU
+#define RCV_BUFSIZ_V(x) ((x) << RCV_BUFSIZ_S)
+
+#define SMAC_SEL_S 28
+#define SMAC_SEL_V(x) ((__u64)(x) << SMAC_SEL_S)
+
+#define L2T_IDX_S 36
+#define L2T_IDX_V(x) ((__u64)(x) << L2T_IDX_S)
+
+#define WND_SCALE_S 50
+#define WND_SCALE_V(x) ((__u64)(x) << WND_SCALE_S)
+
+#define KEEP_ALIVE_S 54
+#define KEEP_ALIVE_V(x) ((__u64)(x) << KEEP_ALIVE_S)
+#define KEEP_ALIVE_F KEEP_ALIVE_V(1ULL)
+
+#define MSS_IDX_S 60
+#define MSS_IDX_M 0xF
+#define MSS_IDX_V(x) ((__u64)(x) << MSS_IDX_S)
+#define MSS_IDX_G(x) (((x) >> MSS_IDX_S) & MSS_IDX_M)
/* option 2 fields */
-#define S_RSS_QUEUE 0
-#define M_RSS_QUEUE 0x3FF
-#define V_RSS_QUEUE(x) ((x) << S_RSS_QUEUE)
-#define G_RSS_QUEUE(x) (((x) >> S_RSS_QUEUE) & M_RSS_QUEUE)
+#define RSS_QUEUE_S 0
+#define RSS_QUEUE_M 0x3FF
+#define RSS_QUEUE_V(x) ((x) << RSS_QUEUE_S)
+#define RSS_QUEUE_G(x) (((x) >> RSS_QUEUE_S) & RSS_QUEUE_M)
+
+#define RSS_QUEUE_VALID_S 10
+#define RSS_QUEUE_VALID_V(x) ((x) << RSS_QUEUE_VALID_S)
+#define RSS_QUEUE_VALID_F RSS_QUEUE_VALID_V(1U)
+
+#define RX_FC_DISABLE_S 20
+#define RX_FC_DISABLE_V(x) ((x) << RX_FC_DISABLE_S)
+#define RX_FC_DISABLE_F RX_FC_DISABLE_V(1U)
+
+#define RX_FC_VALID_S 22
+#define RX_FC_VALID_V(x) ((x) << RX_FC_VALID_S)
+#define RX_FC_VALID_F RX_FC_VALID_V(1U)
+
+#define RX_CHANNEL_S 26
+#define RX_CHANNEL_V(x) ((x) << RX_CHANNEL_S)
+
+#define WND_SCALE_EN_S 28
+#define WND_SCALE_EN_V(x) ((x) << WND_SCALE_EN_S)
+#define WND_SCALE_EN_F WND_SCALE_EN_V(1U)
+
+#define T5_OPT_2_VALID_S 31
+#define T5_OPT_2_VALID_V(x) ((x) << T5_OPT_2_VALID_S)
+#define T5_OPT_2_VALID_F T5_OPT_2_VALID_V(1U)
struct cpl_pass_open_req {
WR_HDR;
__be32 local_ip;
__be32 peer_ip;
__be64 opt0;
-#define TX_CHAN(x) ((x) << 2)
#define NO_CONG(x) ((x) << 4)
#define DELACK(x) ((x) << 5)
-#define ULP_MODE(x) ((x) << 8)
-#define RCV_BUFSIZ(x) ((x) << 12)
-#define RCV_BUFSIZ_MASK 0x3FFU
#define DSCP(x) ((x) << 22)
-#define SMAC_SEL(x) ((u64)(x) << 28)
-#define L2T_IDX(x) ((u64)(x) << 36)
#define TCAM_BYPASS(x) ((u64)(x) << 48)
#define NAGLE(x) ((u64)(x) << 49)
-#define WND_SCALE(x) ((u64)(x) << 50)
-#define KEEP_ALIVE(x) ((u64)(x) << 54)
-#define MSS_IDX(x) ((u64)(x) << 60)
__be64 opt1;
#define SYN_RSS_ENABLE (1 << 0)
#define SYN_RSS_QUEUE(x) ((x) << 2)
WR_HDR;
union opcode_tid ot;
__be32 opt2;
-#define RSS_QUEUE(x) ((x) << 0)
-#define RSS_QUEUE_VALID (1 << 10)
#define RX_COALESCE_VALID(x) ((x) << 11)
#define RX_COALESCE(x) ((x) << 12)
#define PACE(x) ((x) << 16)
-#define RX_FC_VALID ((1U) << 19)
-#define RX_FC_DISABLE ((1U) << 20)
#define TX_QUEUE(x) ((x) << 23)
-#define RX_CHANNEL(x) ((x) << 26)
#define CCTRL_ECN(x) ((x) << 27)
-#define WND_SCALE_EN(x) ((x) << 28)
#define TSTAMPS_EN(x) ((x) << 29)
#define SACK_EN(x) ((x) << 30)
-#define T5_OPT_2_VALID ((1U) << 31)
__be64 opt0;
};
__be32 opt2;
};
-#define S_FILTER_TUPLE 24
-#define M_FILTER_TUPLE 0xFFFFFFFFFF
-#define V_FILTER_TUPLE(x) ((x) << S_FILTER_TUPLE)
-#define G_FILTER_TUPLE(x) (((x) >> S_FILTER_TUPLE) & M_FILTER_TUPLE)
+#define FILTER_TUPLE_S 24
+#define FILTER_TUPLE_M 0xFFFFFFFFFF
+#define FILTER_TUPLE_V(x) ((x) << FILTER_TUPLE_S)
+#define FILTER_TUPLE_G(x) (((x) >> FILTER_TUPLE_S) & FILTER_TUPLE_M)
struct cpl_t5_act_open_req {
WR_HDR;
union opcode_tid ot;
WR_HDR;
union opcode_tid ot;
__be32 credit_dack;
-#define RX_CREDITS(x) ((x) << 0)
-#define RX_FORCE_ACK(x) ((x) << 28)
};
+/* cpl_rx_data_ack.ack_seq fields */
+#define RX_CREDITS_S 0
+#define RX_CREDITS_V(x) ((x) << RX_CREDITS_S)
+
+#define RX_FORCE_ACK_S 28
+#define RX_FORCE_ACK_V(x) ((x) << RX_FORCE_ACK_S)
+#define RX_FORCE_ACK_F RX_FORCE_ACK_V(1U)
+
struct cpl_rx_pkt {
struct rss_header rsshdr;
u8 opcode;
ULP_TX_SC_ISGL = 0x83
};
+#define ULPTX_CMD_S 24
+#define ULPTX_CMD_V(x) ((x) << ULPTX_CMD_S)
+
struct ulptx_sge_pair {
__be32 len[2];
__be64 addr[2];
struct ulptx_sgl {
__be32 cmd_nsge;
-#define ULPTX_CMD(x) ((x) << 24)
#define ULPTX_NSGE(x) ((x) << 0)
#define ULPTX_MORE (1U << 23)
__be32 len0;
struct ulp_mem_io {
WR_HDR;
__be32 cmd;
-#define ULP_MEMIO_ORDER(x) ((x) << 23)
__be32 len16; /* command length */
__be32 dlen; /* data length in 32-byte units */
-#define ULP_MEMIO_DATA_LEN(x) ((x) << 0)
__be32 lock_addr;
-#define ULP_MEMIO_ADDR(x) ((x) << 0)
#define ULP_MEMIO_LOCK(x) ((x) << 31)
};
+/* additional ulp_mem_io.cmd fields */
+#define ULP_MEMIO_ORDER_S 23
+#define ULP_MEMIO_ORDER_V(x) ((x) << ULP_MEMIO_ORDER_S)
+#define ULP_MEMIO_ORDER_F ULP_MEMIO_ORDER_V(1U)
+
+#define T5_ULP_MEMIO_IMM_S 23
+#define T5_ULP_MEMIO_IMM_V(x) ((x) << T5_ULP_MEMIO_IMM_S)
+#define T5_ULP_MEMIO_IMM_F T5_ULP_MEMIO_IMM_V(1U)
+
#define S_T5_ULP_MEMIO_IMM 23
#define V_T5_ULP_MEMIO_IMM(x) ((x) << S_T5_ULP_MEMIO_IMM)
#define F_T5_ULP_MEMIO_IMM V_T5_ULP_MEMIO_IMM(1U)
#define V_T5_ULP_MEMIO_ORDER(x) ((x) << S_T5_ULP_MEMIO_ORDER)
#define F_T5_ULP_MEMIO_ORDER V_T5_ULP_MEMIO_ORDER(1U)
+/* ulp_mem_io.lock_addr fields */
+#define ULP_MEMIO_ADDR_S 0
+#define ULP_MEMIO_ADDR_V(x) ((x) << ULP_MEMIO_ADDR_S)
+
+/* ulp_mem_io.dlen fields */
+#define ULP_MEMIO_DATA_LEN_S 0
+#define ULP_MEMIO_DATA_LEN_V(x) ((x) << ULP_MEMIO_DATA_LEN_S)
+
#endif /* __T4_MSG_H */
#define MC_BIST_STATUS_RDATA 0x7688
-#define MA_EDRAM0_BAR 0x77c0
-#define MA_EDRAM1_BAR 0x77c4
-#define EDRAM_SIZE_MASK 0xfffU
-#define EDRAM_SIZE_GET(x) ((x) & EDRAM_SIZE_MASK)
-
-#define MA_EXT_MEMORY_BAR 0x77c8
-#define EXT_MEM_SIZE_MASK 0x00000fffU
-#define EXT_MEM_SIZE_SHIFT 0
-#define EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT)
-
-#define MA_TARGET_MEM_ENABLE 0x77d8
-#define EXT_MEM1_ENABLE 0x00000010U
-#define EXT_MEM_ENABLE 0x00000004U
-#define EDRAM1_ENABLE 0x00000002U
-#define EDRAM0_ENABLE 0x00000001U
+#define MA_EDRAM0_BAR_A 0x77c0
+
+#define EDRAM0_SIZE_S 0
+#define EDRAM0_SIZE_M 0xfffU
+#define EDRAM0_SIZE_V(x) ((x) << EDRAM0_SIZE_S)
+#define EDRAM0_SIZE_G(x) (((x) >> EDRAM0_SIZE_S) & EDRAM0_SIZE_M)
+
+#define MA_EDRAM1_BAR_A 0x77c4
+
+#define EDRAM1_SIZE_S 0
+#define EDRAM1_SIZE_M 0xfffU
+#define EDRAM1_SIZE_V(x) ((x) << EDRAM1_SIZE_S)
+#define EDRAM1_SIZE_G(x) (((x) >> EDRAM1_SIZE_S) & EDRAM1_SIZE_M)
+
+#define MA_EXT_MEMORY_BAR_A 0x77c8
+
+#define EXT_MEM_SIZE_S 0
+#define EXT_MEM_SIZE_M 0xfffU
+#define EXT_MEM_SIZE_V(x) ((x) << EXT_MEM_SIZE_S)
+#define EXT_MEM_SIZE_G(x) (((x) >> EXT_MEM_SIZE_S) & EXT_MEM_SIZE_M)
+
+#define MA_EXT_MEMORY1_BAR_A 0x7808
+
+#define EXT_MEM1_SIZE_S 0
+#define EXT_MEM1_SIZE_M 0xfffU
+#define EXT_MEM1_SIZE_V(x) ((x) << EXT_MEM1_SIZE_S)
+#define EXT_MEM1_SIZE_G(x) (((x) >> EXT_MEM1_SIZE_S) & EXT_MEM1_SIZE_M)
+
+#define MA_EXT_MEMORY0_BAR_A 0x77c8
+
+#define EXT_MEM0_SIZE_S 0
+#define EXT_MEM0_SIZE_M 0xfffU
+#define EXT_MEM0_SIZE_V(x) ((x) << EXT_MEM0_SIZE_S)
+#define EXT_MEM0_SIZE_G(x) (((x) >> EXT_MEM0_SIZE_S) & EXT_MEM0_SIZE_M)
+
+#define MA_TARGET_MEM_ENABLE_A 0x77d8
+
+#define EXT_MEM_ENABLE_S 2
+#define EXT_MEM_ENABLE_V(x) ((x) << EXT_MEM_ENABLE_S)
+#define EXT_MEM_ENABLE_F EXT_MEM_ENABLE_V(1U)
+
+#define EDRAM1_ENABLE_S 1
+#define EDRAM1_ENABLE_V(x) ((x) << EDRAM1_ENABLE_S)
+#define EDRAM1_ENABLE_F EDRAM1_ENABLE_V(1U)
+
+#define EDRAM0_ENABLE_S 0
+#define EDRAM0_ENABLE_V(x) ((x) << EDRAM0_ENABLE_S)
+#define EDRAM0_ENABLE_F EDRAM0_ENABLE_V(1U)
+
+#define EXT_MEM1_ENABLE_S 4
+#define EXT_MEM1_ENABLE_V(x) ((x) << EXT_MEM1_ENABLE_S)
+#define EXT_MEM1_ENABLE_F EXT_MEM1_ENABLE_V(1U)
+
+#define EXT_MEM0_ENABLE_S 2
+#define EXT_MEM0_ENABLE_V(x) ((x) << EXT_MEM0_ENABLE_S)
+#define EXT_MEM0_ENABLE_F EXT_MEM0_ENABLE_V(1U)
#define MA_INT_CAUSE 0x77e0
#define MEM_PERR_INT_CAUSE 0x00000002U
#define MA_PARITY_ERROR_STATUS 0x77f4
#define MA_PARITY_ERROR_STATUS2 0x7804
-#define MA_EXT_MEMORY1_BAR 0x7808
#define EDC_0_BASE_ADDR 0x7900
#define EDC_BIST_CMD 0x7904
__be32 lo;
};
-#define FW_WR_OP(x) ((x) << 24)
-#define FW_WR_OP_GET(x) (((x) >> 24) & 0xff)
-#define FW_WR_ATOMIC(x) ((x) << 23)
-#define FW_WR_FLUSH(x) ((x) << 22)
-#define FW_WR_COMPL(x) ((x) << 21)
-#define FW_WR_IMMDLEN_MASK 0xff
-#define FW_WR_IMMDLEN(x) ((x) << 0)
-
-#define FW_WR_EQUIQ (1U << 31)
-#define FW_WR_EQUEQ (1U << 30)
-#define FW_WR_FLOWID(x) ((x) << 8)
-#define FW_WR_LEN16(x) ((x) << 0)
+/* work request opcode (hi) */
+#define FW_WR_OP_S 24
+#define FW_WR_OP_M 0xff
+#define FW_WR_OP_V(x) ((x) << FW_WR_OP_S)
+#define FW_WR_OP_G(x) (((x) >> FW_WR_OP_S) & FW_WR_OP_M)
+
+/* atomic flag (hi) - firmware encapsulates CPLs in CPL_BARRIER */
+#define FW_WR_ATOMIC_S 23
+#define FW_WR_ATOMIC_V(x) ((x) << FW_WR_ATOMIC_S)
+
+/* flush flag (hi) - firmware flushes flushable work request buffered
+ * in the flow context.
+ */
+#define FW_WR_FLUSH_S 22
+#define FW_WR_FLUSH_V(x) ((x) << FW_WR_FLUSH_S)
+
+/* completion flag (hi) - firmware generates a cpl_fw6_ack */
+#define FW_WR_COMPL_S 21
+#define FW_WR_COMPL_V(x) ((x) << FW_WR_COMPL_S)
+#define FW_WR_COMPL_F FW_WR_COMPL_V(1U)
+
+/* work request immediate data length (hi) */
+#define FW_WR_IMMDLEN_S 0
+#define FW_WR_IMMDLEN_M 0xff
+#define FW_WR_IMMDLEN_V(x) ((x) << FW_WR_IMMDLEN_S)
+
+/* egress queue status update to associated ingress queue entry (lo) */
+#define FW_WR_EQUIQ_S 31
+#define FW_WR_EQUIQ_V(x) ((x) << FW_WR_EQUIQ_S)
+#define FW_WR_EQUIQ_F FW_WR_EQUIQ_V(1U)
+
+/* egress queue status update to egress queue status entry (lo) */
+#define FW_WR_EQUEQ_S 30
+#define FW_WR_EQUEQ_V(x) ((x) << FW_WR_EQUEQ_S)
+#define FW_WR_EQUEQ_F FW_WR_EQUEQ_V(1U)
+
+/* flow context identifier (lo) */
+#define FW_WR_FLOWID_S 8
+#define FW_WR_FLOWID_V(x) ((x) << FW_WR_FLOWID_S)
+
+/* length in units of 16-bytes (lo) */
+#define FW_WR_LEN16_S 0
+#define FW_WR_LEN16_V(x) ((x) << FW_WR_LEN16_S)
#define HW_TPL_FR_MT_PR_IV_P_FC 0X32B
#define HW_TPL_FR_MT_PR_OV_P_FC 0X327
struct fw_flowc_wr {
__be32 op_to_nparams;
-#define FW_FLOWC_WR_NPARAMS(x) ((x) << 0)
__be32 flowid_len16;
struct fw_flowc_mnemval mnemval[0];
};
+#define FW_FLOWC_WR_NPARAMS_S 0
+#define FW_FLOWC_WR_NPARAMS_V(x) ((x) << FW_FLOWC_WR_NPARAMS_S)
+
struct fw_ofld_tx_data_wr {
__be32 op_to_immdlen;
__be32 flowid_len16;
__be32 plen;
__be32 tunnel_to_proxy;
-#define FW_OFLD_TX_DATA_WR_TUNNEL(x) ((x) << 19)
-#define FW_OFLD_TX_DATA_WR_SAVE(x) ((x) << 18)
-#define FW_OFLD_TX_DATA_WR_FLUSH(x) ((x) << 17)
-#define FW_OFLD_TX_DATA_WR_URGENT(x) ((x) << 16)
-#define FW_OFLD_TX_DATA_WR_MORE(x) ((x) << 15)
-#define FW_OFLD_TX_DATA_WR_SHOVE(x) ((x) << 14)
-#define FW_OFLD_TX_DATA_WR_ULPMODE(x) ((x) << 10)
-#define FW_OFLD_TX_DATA_WR_ULPSUBMODE(x) ((x) << 6)
};
+#define FW_OFLD_TX_DATA_WR_TUNNEL_S 19
+#define FW_OFLD_TX_DATA_WR_TUNNEL_V(x) ((x) << FW_OFLD_TX_DATA_WR_TUNNEL_S)
+
+#define FW_OFLD_TX_DATA_WR_SAVE_S 18
+#define FW_OFLD_TX_DATA_WR_SAVE_V(x) ((x) << FW_OFLD_TX_DATA_WR_SAVE_S)
+
+#define FW_OFLD_TX_DATA_WR_FLUSH_S 17
+#define FW_OFLD_TX_DATA_WR_FLUSH_V(x) ((x) << FW_OFLD_TX_DATA_WR_FLUSH_S)
+#define FW_OFLD_TX_DATA_WR_FLUSH_F FW_OFLD_TX_DATA_WR_FLUSH_V(1U)
+
+#define FW_OFLD_TX_DATA_WR_URGENT_S 16
+#define FW_OFLD_TX_DATA_WR_URGENT_V(x) ((x) << FW_OFLD_TX_DATA_WR_URGENT_S)
+
+#define FW_OFLD_TX_DATA_WR_MORE_S 15
+#define FW_OFLD_TX_DATA_WR_MORE_V(x) ((x) << FW_OFLD_TX_DATA_WR_MORE_S)
+
+#define FW_OFLD_TX_DATA_WR_SHOVE_S 14
+#define FW_OFLD_TX_DATA_WR_SHOVE_V(x) ((x) << FW_OFLD_TX_DATA_WR_SHOVE_S)
+#define FW_OFLD_TX_DATA_WR_SHOVE_F FW_OFLD_TX_DATA_WR_SHOVE_V(1U)
+
+#define FW_OFLD_TX_DATA_WR_ULPMODE_S 10
+#define FW_OFLD_TX_DATA_WR_ULPMODE_V(x) ((x) << FW_OFLD_TX_DATA_WR_ULPMODE_S)
+
+#define FW_OFLD_TX_DATA_WR_ULPSUBMODE_S 6
+#define FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(x) \
+ ((x) << FW_OFLD_TX_DATA_WR_ULPSUBMODE_S)
+
struct fw_cmd_wr {
__be32 op_dma;
#define FW_CMD_WR_DMA (1U << 17)
__be64 cookie_daddr;
};
+#define FW_CMD_WR_DMA_S 17
+#define FW_CMD_WR_DMA_V(x) ((x) << FW_CMD_WR_DMA_S)
+
struct fw_eth_tx_pkt_vm_wr {
__be32 op_immdlen;
__be32 equiq_to_len16;
__be32 lo;
};
-#define FW_CMD_OP(x) ((x) << 24)
-#define FW_CMD_OP_GET(x) (((x) >> 24) & 0xff)
-#define FW_CMD_REQUEST (1U << 23)
-#define FW_CMD_REQUEST_GET(x) (((x) >> 23) & 0x1)
-#define FW_CMD_READ (1U << 22)
-#define FW_CMD_WRITE (1U << 21)
-#define FW_CMD_EXEC (1U << 20)
-#define FW_CMD_RAMASK(x) ((x) << 20)
-#define FW_CMD_RETVAL(x) ((x) << 8)
-#define FW_CMD_RETVAL_GET(x) (((x) >> 8) & 0xff)
-#define FW_CMD_LEN16(x) ((x) << 0)
-#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_CMD_OP_S 24
+#define FW_CMD_OP_M 0xff
+#define FW_CMD_OP_V(x) ((x) << FW_CMD_OP_S)
+#define FW_CMD_OP_G(x) (((x) >> FW_CMD_OP_S) & FW_CMD_OP_M)
+
+#define FW_CMD_REQUEST_S 23
+#define FW_CMD_REQUEST_V(x) ((x) << FW_CMD_REQUEST_S)
+#define FW_CMD_REQUEST_F FW_CMD_REQUEST_V(1U)
+
+#define FW_CMD_READ_S 22
+#define FW_CMD_READ_V(x) ((x) << FW_CMD_READ_S)
+#define FW_CMD_READ_F FW_CMD_READ_V(1U)
+
+#define FW_CMD_WRITE_S 21
+#define FW_CMD_WRITE_V(x) ((x) << FW_CMD_WRITE_S)
+#define FW_CMD_WRITE_F FW_CMD_WRITE_V(1U)
+
+#define FW_CMD_EXEC_S 20
+#define FW_CMD_EXEC_V(x) ((x) << FW_CMD_EXEC_S)
+#define FW_CMD_EXEC_F FW_CMD_EXEC_V(1U)
+
+#define FW_CMD_RAMASK_S 20
+#define FW_CMD_RAMASK_V(x) ((x) << FW_CMD_RAMASK_S)
+
+#define FW_CMD_RETVAL_S 8
+#define FW_CMD_RETVAL_M 0xff
+#define FW_CMD_RETVAL_V(x) ((x) << FW_CMD_RETVAL_S)
+#define FW_CMD_RETVAL_G(x) (((x) >> FW_CMD_RETVAL_S) & FW_CMD_RETVAL_M)
+
+#define FW_CMD_LEN16_S 0
+#define FW_CMD_LEN16_V(x) ((x) << FW_CMD_LEN16_S)
+
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
enum fw_ldst_addrspc {
FW_LDST_ADDRSPC_FIRMWARE = 0x0001,
* Macros for VIID parsing:
* VIID - [10:8] PFN, [7] VI Valid, [6:0] VI number
*/
-#define FW_VIID_PFN_GET(x) (((x) >> 8) & 0x7)
+
+#define FW_VIID_PFN_S 8
+#define FW_VIID_PFN_M 0x7
+#define FW_VIID_PFN_G(x) (((x) >> FW_VIID_PFN_S) & FW_VIID_PFN_M)
+
#define FW_VIID_VIVLD_GET(x) (((x) >> 7) & 0x1)
#define FW_VIID_VIN_GET(x) (((x) >> 0) & 0x7F)
* we can specify for immediate data in the firmware Ethernet TX
* Work Request.
*/
- MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK,
+ MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_M,
/*
* Max size of a WR sent through a control TX queue.
*/
BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT);
+ gfp |= __GFP_NOWARN;
+
/*
* If we support large pages, prefer large buffers and fail over to
* small pages if we can't allocate large pages to satisfy the refill.
goto alloc_small_pages;
while (n) {
- page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
- s->fl_pg_order);
+ page = __dev_alloc_pages(gfp, s->fl_pg_order);
if (unlikely(!page)) {
/*
* We've failed inour attempt to allocate a "large
alloc_small_pages:
while (n--) {
- page = __skb_alloc_page(gfp | __GFP_NOWARN, NULL);
+ page = __dev_alloc_page(gfp);
if (unlikely(!page)) {
fl->alloc_failed++;
break;
sgl->addr0 = cpu_to_be64(addr[1]);
}
- sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) |
+ sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
ULPTX_NSGE(nfrags));
if (likely(--nfrags == 0))
return;
goto out_free;
}
- wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+ wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2));
if (unlikely(credits < ETHTXQ_STOP_THRES)) {
/*
* After we're done injecting the Work Request for this
* has opened up.
*/
txq_stop(txq);
- wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+ wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
}
/*
int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
wr->op_immdlen =
- cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
- FW_WR_IMMDLEN(sizeof(*lso) +
- sizeof(*cpl)));
+ cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) |
+ FW_WR_IMMDLEN_V(sizeof(*lso) +
+ sizeof(*cpl)));
/*
* Fill in the LSO CPL message.
*/
len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
wr->op_immdlen =
- cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
- FW_WR_IMMDLEN(len));
+ cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) |
+ FW_WR_IMMDLEN_V(len));
/*
* Set up TX Packet CPL pointer, control word and perform
* into OS-independent common code ...
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC |
FW_IQ_CMD_IQSTART(1) |
FW_LEN16(cmd));
* into the common code ...
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
FW_EQ_ETH_CMD_EQSTART |
FW_LEN16(cmd));
/*
* The "len16" field of a Firmware Command Structure ...
*/
-#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
/*
* Per-VF statistics.
/* return value in low-order little-endian word */
v = t4_read_reg(adapter, mbox_data);
- if (FW_CMD_RETVAL_GET(v))
+ if (FW_CMD_RETVAL_G(v))
dump_mbox(adapter, "FW Error", mbox_data);
if (rpl) {
/* request bit in high-order BE word */
WARN_ON((be32_to_cpu(*(const u32 *)cmd)
- & FW_CMD_REQUEST) == 0);
+ & FW_CMD_REQUEST_F) == 0);
get_mbox_rpl(adapter, rpl, size, mbox_data);
WARN_ON((be32_to_cpu(*(u32 *)rpl)
- & FW_CMD_REQUEST) != 0);
+ & FW_CMD_REQUEST_F) != 0);
}
t4_write_reg(adapter, mbox_ctl,
MBOWNER(MBOX_OWNER_NONE));
- return -FW_CMD_RETVAL_GET(v);
+ return -FW_CMD_RETVAL_G(v);
}
}
* like MAC address, etc.
*/
memset(&vi_cmd, 0, sizeof(vi_cmd));
- vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd));
vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid));
v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
return 0;
memset(&port_cmd, 0, sizeof(port_cmd));
- port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_PORT_CMD_PORTID(pi->port_id));
port_cmd.action_to_len16 =
cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
struct fw_reset_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) |
- FW_CMD_WRITE);
+ cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RESET_CMD) |
+ FW_CMD_WRITE_F);
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
}
return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
param[nparams].mnem), 16);
- cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++)
p->mnem = htonl(*params++);
return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F);
len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
param[nparams]), 16);
- cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) {
p->mnem = cpu_to_be32(*params++);
p->val = cpu_to_be32(*vals++);
* our RSS configuration.
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
if (v)
* with error on command failure.
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
if (v)
int v;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_RSS_VI_CONFIG_CMD_VIID(viid));
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
struct fw_rss_vi_config_cmd cmd, rpl;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_RSS_VI_CONFIG_CMD_VIID(viid));
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
switch (adapter->params.rss.mode) {
* Initialize firmware command template to write the RSS table.
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_RSS_IND_TBL_CMD_VIID(viid));
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
* VIID.
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
FW_VI_CMD_ALLOC);
cmd.portid_pkd = FW_VI_CMD_PORTID(port_id);
* Execute a VI command to free the Virtual Interface.
*/
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
FW_VI_CMD_FREE);
cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid));
struct fw_vi_enable_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F |
FW_VI_ENABLE_CMD_VIID(viid));
cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) |
FW_VI_ENABLE_CMD_EEN(tx_en) |
struct fw_vi_enable_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F |
FW_VI_ENABLE_CMD_VIID(viid));
cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED |
FW_LEN16(cmd));
vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_VI_RXMODE_CMD_VIID(viid));
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
cmd.mtu_to_vlanexen =
int i;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
- (free ? FW_CMD_EXEC : 0) |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
+ (free ? FW_CMD_EXEC_F : 0) |
FW_VI_MAC_CMD_VIID(viid));
cmd.freemacs_to_len16 =
cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
- FW_CMD_LEN16(len16));
+ FW_CMD_LEN16_V(len16));
for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
p->valid_to_idx = cpu_to_be16(
idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_VI_MAC_CMD_VIID(viid));
- cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID |
FW_VI_MAC_CMD_IDX(idx));
memcpy(p->macaddr, addr, sizeof(p->macaddr));
u.exact[0]), 16);
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_VI_ENABLE_CMD_VIID(viid));
cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN |
FW_VI_MAC_CMD_HASHUNIEN(ucast) |
- FW_CMD_LEN16(len16));
+ FW_CMD_LEN16_V(len16));
cmd.u.hash.hashvec = cpu_to_be64(vec);
return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
}
int ret;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) |
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_STATS_CMD) |
FW_VI_STATS_CMD_VIID(pi->viid) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
- cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
cmd.u.ctl.nstats_ix =
cpu_to_be16(FW_VI_STATS_CMD_IX(ix) |
FW_VI_STATS_CMD_NSTATS(nstats));
struct fw_iq_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE |
FW_LEN16(cmd));
cmd.type_to_iqandstindex =
struct fw_eq_eth_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC);
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE |
FW_LEN16(cmd));
cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid));
int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
{
const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
- u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
+ u8 opcode = FW_CMD_OP_G(be32_to_cpu(cmd_hdr->hi));
switch (opcode) {
case FW_PORT_CMD: {
ioaddr = (unsigned long)
nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
{
- unsigned long flags;
int card_present;
- local_irq_save(flags);
- card_present = (hwreg_present((void*) ioaddr+4) &&
- hwreg_present((void*) ioaddr + DATA_PORT));
- local_irq_restore(flags);
-
+ card_present = (hwreg_present((void *)ioaddr + 4) &&
+ hwreg_present((void *)ioaddr + DATA_PORT));
if (!card_present)
goto out;
}
if (!wq_work_done) {
napi_complete(napi);
vnic_intr_unmask(&enic->intr[intr]);
+ return 0;
}
- return 0;
+ return budget;
}
static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
static int gfar_init_bds(struct net_device *ndev)
{
struct gfar_private *priv = netdev_priv(ndev);
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
+ u32 *rfbptr;
int i, j;
for (i = 0; i < priv->num_tx_queues; i++) {
txbdp->status |= TXBD_WRAP;
}
+ rfbptr = ®s->rfbptr0;
for (i = 0; i < priv->num_rx_queues; i++) {
rx_queue = priv->rx_queue[i];
rx_queue->cur_rx = rx_queue->rx_bd_base;
rxbdp++;
}
+ rx_queue->rfbptr = rfbptr;
+ rfbptr += 2;
}
return 0;
}
}
+static void gfar_init_rqprm(struct gfar_private *priv)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+ u32 __iomem *baddr;
+ int i;
+
+ baddr = ®s->rqprm0;
+ for (i = 0; i < priv->num_rx_queues; i++) {
+ gfar_write(baddr, priv->rx_queue[i]->rx_ring_size |
+ (DEFAULT_RX_LFC_THR << FBTHR_SHIFT));
+ baddr++;
+ }
+}
+
static void gfar_rx_buff_size_config(struct gfar_private *priv)
{
int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN;
if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
+ /* Clear the LFC bit */
+ gfar_write(®s->rctrl, rctrl);
+ /* Init flow control threshold values */
+ gfar_init_rqprm(priv);
+ gfar_write(®s->ptv, DEFAULT_LFC_PTVVAL);
+ rctrl |= RCTRL_LFC;
+
/* Init rctrl based on our settings */
gfar_write(®s->rctrl, rctrl);
}
priv->phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
priv->phydev->advertising = priv->phydev->supported;
+ /* Add support for flow control, but don't advertise it by default */
+ priv->phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+
return 0;
}
/* Setup the new bdp */
gfar_new_rxbdp(rx_queue, bdp, newskb);
+ /* Update Last Free RxBD pointer for LFC */
+ if (unlikely(rx_queue->rfbptr && priv->tx_actual_en))
+ gfar_write(rx_queue->rfbptr, (u32)bdp);
+
/* Update to the next pointer */
bdp = next_bd(bdp, base, rx_queue->rx_ring_size);
if (phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
- lcl_adv = mii_advertise_flowctrl(phydev->advertising);
+ lcl_adv = 0;
+ if (phydev->advertising & ADVERTISED_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
+ if (phydev->advertising & ADVERTISED_Asym_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_TX)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
struct phy_device *phydev = priv->phydev;
+ struct gfar_priv_rx_q *rx_queue = NULL;
+ int i;
+ struct rxbd8 *bdp;
if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
return;
u32 tempval1 = gfar_read(®s->maccfg1);
u32 tempval = gfar_read(®s->maccfg2);
u32 ecntrl = gfar_read(®s->ecntrl);
+ u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);
if (phydev->duplex != priv->oldduplex) {
if (!(phydev->duplex))
tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
tempval1 |= gfar_get_flowctrl_cfg(priv);
+ /* Turn last free buffer recording on */
+ if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) {
+ for (i = 0; i < priv->num_rx_queues; i++) {
+ rx_queue = priv->rx_queue[i];
+ bdp = rx_queue->cur_rx;
+ /* skip to previous bd */
+ bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1,
+ rx_queue->rx_bd_base,
+ rx_queue->rx_ring_size);
+
+ if (rx_queue->rfbptr)
+ gfar_write(rx_queue->rfbptr, (u32)bdp);
+ }
+
+ priv->tx_actual_en = 1;
+ }
+
+ if (unlikely(!(tempval1 & MACCFG1_TX_FLOW) && tx_flow_oldval))
+ priv->tx_actual_en = 0;
+
gfar_write(®s->maccfg1, tempval1);
gfar_write(®s->maccfg2, tempval);
gfar_write(®s->ecntrl, ecntrl);
#define GFAR_MAX_FIFO_STARVE 511
#define GFAR_MAX_FIFO_STARVE_OFF 511
+#define FBTHR_SHIFT 24
+#define DEFAULT_RX_LFC_THR 16
+#define DEFAULT_LFC_PTVVAL 4
+
#define DEFAULT_RX_BUFFER_SIZE 1536
#define TX_RING_MOD_MASK(size) (size-1)
#define RX_RING_MOD_MASK(size) (size-1)
| SUPPORTED_Autoneg \
| SUPPORTED_MII)
-#define GFAR_SUPPORTED_GBIT (SUPPORTED_1000baseT_Full \
- | SUPPORTED_Pause \
- | SUPPORTED_Asym_Pause)
+#define GFAR_SUPPORTED_GBIT SUPPORTED_1000baseT_Full
/* TBI register addresses */
#define MII_TBICON 0x11
#define RCTRL_TS_ENABLE 0x01000000
#define RCTRL_PAL_MASK 0x001f0000
+#define RCTRL_LFC 0x00004000
#define RCTRL_VLEX 0x00002000
#define RCTRL_FILREN 0x00001000
#define RCTRL_GHTX 0x00000400
u8 res23c[248];
u32 attr; /* 0x.bf8 - Attributes Register */
u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
- u8 res24[688];
+ u32 rqprm0; /* 0x.c00 - Receive queue parameters register 0 */
+ u32 rqprm1; /* 0x.c04 - Receive queue parameters register 1 */
+ u32 rqprm2; /* 0x.c08 - Receive queue parameters register 2 */
+ u32 rqprm3; /* 0x.c0c - Receive queue parameters register 3 */
+ u32 rqprm4; /* 0x.c10 - Receive queue parameters register 4 */
+ u32 rqprm5; /* 0x.c14 - Receive queue parameters register 5 */
+ u32 rqprm6; /* 0x.c18 - Receive queue parameters register 6 */
+ u32 rqprm7; /* 0x.c1c - Receive queue parameters register 7 */
+ u8 res24[36];
+ u32 rfbptr0; /* 0x.c44 - Last free RxBD pointer for ring 0 */
+ u8 res24a[4];
+ u32 rfbptr1; /* 0x.c4c - Last free RxBD pointer for ring 1 */
+ u8 res24b[4];
+ u32 rfbptr2; /* 0x.c54 - Last free RxBD pointer for ring 2 */
+ u8 res24c[4];
+ u32 rfbptr3; /* 0x.c5c - Last free RxBD pointer for ring 3 */
+ u8 res24d[4];
+ u32 rfbptr4; /* 0x.c64 - Last free RxBD pointer for ring 4 */
+ u8 res24e[4];
+ u32 rfbptr5; /* 0x.c6c - Last free RxBD pointer for ring 5 */
+ u8 res24f[4];
+ u32 rfbptr6; /* 0x.c74 - Last free RxBD pointer for ring 6 */
+ u8 res24g[4];
+ u32 rfbptr7; /* 0x.c7c - Last free RxBD pointer for ring 7 */
+ u8 res24h[4];
+ u8 res24x[556];
u32 isrg0; /* 0x.eb0 - Interrupt steering group 0 register */
u32 isrg1; /* 0x.eb4 - Interrupt steering group 1 register */
u32 isrg2; /* 0x.eb8 - Interrupt steering group 2 register */
/* RX Coalescing values */
unsigned char rxcoalescing;
unsigned long rxic;
+ u32 *rfbptr;
};
enum gfar_irqinfo_id {
unsigned int num_tx_queues;
unsigned int num_rx_queues;
unsigned int num_grps;
+ int tx_actual_en;
/* Network Statistics */
struct gfar_extra_stats extra_stats;
u32 tempval;
tempval = gfar_read(®s->maccfg1);
tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
- if (priv->tx_pause_en)
+
+ priv->tx_actual_en = 0;
+ if (priv->tx_pause_en) {
+ priv->tx_actual_en = 1;
tempval |= MACCFG1_TX_FLOW;
+ }
+
if (priv->rx_pause_en)
tempval |= MACCFG1_RX_FLOW;
gfar_write(®s->maccfg1, tempval);
return true;
/* alloc new page for storage */
- page = alloc_page(GFP_ATOMIC | __GFP_COLD);
+ page = dev_alloc_page();
if (unlikely(!page)) {
rx_ring->rx_stats.alloc_failed++;
return false;
u16 msg_enable;
char misc_int_name[IFNAMSIZ + 9];
u16 adminq_work_limit; /* num of admin receive queue desc to process */
- int service_timer_period;
+ unsigned long service_timer_period;
+ unsigned long service_timer_previous;
struct timer_list service_timer;
struct work_struct service_task;
*/
if (!details->async && !details->postpone) {
u32 total_delay = 0;
- u32 delay_len = 10;
do {
/* AQ designers suggest use of head for better
*/
if (i40e_asq_done(hw))
break;
- /* ugh! delay while spin_lock */
- udelay(delay_len);
- total_delay += delay_len;
+ usleep_range(1000, 2000);
+ total_delay++;
} while (total_delay < hw->aq.asq_cmd_timeout);
}
/* general information */
#define I40E_AQ_LARGE_BUF 512
-#define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */
+#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */
void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
u16 opcode);
* This file needs to comply with the Linux Kernel coding style.
*/
-#define I40E_FW_API_VERSION_MAJOR 0x0001
-#define I40E_FW_API_VERSION_MINOR 0x0002
+#define I40E_FW_API_VERSION_MAJOR 0x0001
+#define I40E_FW_API_VERSION_MINOR 0x0002
struct i40e_aq_desc {
__le16 flags;
*/
/* command flags and offsets*/
-#define I40E_AQ_FLAG_DD_SHIFT 0
-#define I40E_AQ_FLAG_CMP_SHIFT 1
-#define I40E_AQ_FLAG_ERR_SHIFT 2
-#define I40E_AQ_FLAG_VFE_SHIFT 3
-#define I40E_AQ_FLAG_LB_SHIFT 9
-#define I40E_AQ_FLAG_RD_SHIFT 10
-#define I40E_AQ_FLAG_VFC_SHIFT 11
-#define I40E_AQ_FLAG_BUF_SHIFT 12
-#define I40E_AQ_FLAG_SI_SHIFT 13
-#define I40E_AQ_FLAG_EI_SHIFT 14
-#define I40E_AQ_FLAG_FE_SHIFT 15
-
-#define I40E_AQ_FLAG_DD (1 << I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
-#define I40E_AQ_FLAG_CMP (1 << I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
-#define I40E_AQ_FLAG_ERR (1 << I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
-#define I40E_AQ_FLAG_VFE (1 << I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
-#define I40E_AQ_FLAG_LB (1 << I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
-#define I40E_AQ_FLAG_RD (1 << I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
-#define I40E_AQ_FLAG_VFC (1 << I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
-#define I40E_AQ_FLAG_BUF (1 << I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
-#define I40E_AQ_FLAG_SI (1 << I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
-#define I40E_AQ_FLAG_EI (1 << I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
-#define I40E_AQ_FLAG_FE (1 << I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
+#define I40E_AQ_FLAG_DD_SHIFT 0
+#define I40E_AQ_FLAG_CMP_SHIFT 1
+#define I40E_AQ_FLAG_ERR_SHIFT 2
+#define I40E_AQ_FLAG_VFE_SHIFT 3
+#define I40E_AQ_FLAG_LB_SHIFT 9
+#define I40E_AQ_FLAG_RD_SHIFT 10
+#define I40E_AQ_FLAG_VFC_SHIFT 11
+#define I40E_AQ_FLAG_BUF_SHIFT 12
+#define I40E_AQ_FLAG_SI_SHIFT 13
+#define I40E_AQ_FLAG_EI_SHIFT 14
+#define I40E_AQ_FLAG_FE_SHIFT 15
+
+#define I40E_AQ_FLAG_DD (1 << I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
+#define I40E_AQ_FLAG_CMP (1 << I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
+#define I40E_AQ_FLAG_ERR (1 << I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
+#define I40E_AQ_FLAG_VFE (1 << I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
+#define I40E_AQ_FLAG_LB (1 << I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
+#define I40E_AQ_FLAG_RD (1 << I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
+#define I40E_AQ_FLAG_VFC (1 << I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
+#define I40E_AQ_FLAG_BUF (1 << I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
+#define I40E_AQ_FLAG_SI (1 << I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
+#define I40E_AQ_FLAG_EI (1 << I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
+#define I40E_AQ_FLAG_FE (1 << I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
/* error codes */
enum i40e_admin_queue_err {
- I40E_AQ_RC_OK = 0, /* success */
- I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
- I40E_AQ_RC_ENOENT = 2, /* No such element */
- I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
- I40E_AQ_RC_EINTR = 4, /* operation interrupted */
- I40E_AQ_RC_EIO = 5, /* I/O error */
- I40E_AQ_RC_ENXIO = 6, /* No such resource */
- I40E_AQ_RC_E2BIG = 7, /* Arg too long */
- I40E_AQ_RC_EAGAIN = 8, /* Try again */
- I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
- I40E_AQ_RC_EACCES = 10, /* Permission denied */
- I40E_AQ_RC_EFAULT = 11, /* Bad address */
- I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
- I40E_AQ_RC_EEXIST = 13, /* object already exists */
- I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
- I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
- I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
- I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
- I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
- I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed because of prev cmd error */
- I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
- I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
- I40E_AQ_RC_EFBIG = 22, /* File too large */
+ I40E_AQ_RC_OK = 0, /* success */
+ I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
+ I40E_AQ_RC_ENOENT = 2, /* No such element */
+ I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
+ I40E_AQ_RC_EINTR = 4, /* operation interrupted */
+ I40E_AQ_RC_EIO = 5, /* I/O error */
+ I40E_AQ_RC_ENXIO = 6, /* No such resource */
+ I40E_AQ_RC_E2BIG = 7, /* Arg too long */
+ I40E_AQ_RC_EAGAIN = 8, /* Try again */
+ I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
+ I40E_AQ_RC_EACCES = 10, /* Permission denied */
+ I40E_AQ_RC_EFAULT = 11, /* Bad address */
+ I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
+ I40E_AQ_RC_EEXIST = 13, /* object already exists */
+ I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
+ I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
+ I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
+ I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
+ I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
+ I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
+ I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
+ I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
+ I40E_AQ_RC_EFBIG = 22, /* File too large */
};
/* Admin Queue command opcodes */
enum i40e_admin_queue_opc {
/* aq commands */
- i40e_aqc_opc_get_version = 0x0001,
- i40e_aqc_opc_driver_version = 0x0002,
- i40e_aqc_opc_queue_shutdown = 0x0003,
- i40e_aqc_opc_set_pf_context = 0x0004,
+ i40e_aqc_opc_get_version = 0x0001,
+ i40e_aqc_opc_driver_version = 0x0002,
+ i40e_aqc_opc_queue_shutdown = 0x0003,
+ i40e_aqc_opc_set_pf_context = 0x0004,
/* resource ownership */
- i40e_aqc_opc_request_resource = 0x0008,
- i40e_aqc_opc_release_resource = 0x0009,
+ i40e_aqc_opc_request_resource = 0x0008,
+ i40e_aqc_opc_release_resource = 0x0009,
- i40e_aqc_opc_list_func_capabilities = 0x000A,
- i40e_aqc_opc_list_dev_capabilities = 0x000B,
+ i40e_aqc_opc_list_func_capabilities = 0x000A,
+ i40e_aqc_opc_list_dev_capabilities = 0x000B,
- i40e_aqc_opc_set_cppm_configuration = 0x0103,
- i40e_aqc_opc_set_arp_proxy_entry = 0x0104,
- i40e_aqc_opc_set_ns_proxy_entry = 0x0105,
+ i40e_aqc_opc_set_cppm_configuration = 0x0103,
+ i40e_aqc_opc_set_arp_proxy_entry = 0x0104,
+ i40e_aqc_opc_set_ns_proxy_entry = 0x0105,
/* LAA */
- i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */
- i40e_aqc_opc_mac_address_read = 0x0107,
- i40e_aqc_opc_mac_address_write = 0x0108,
+ i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */
+ i40e_aqc_opc_mac_address_read = 0x0107,
+ i40e_aqc_opc_mac_address_write = 0x0108,
/* PXE */
- i40e_aqc_opc_clear_pxe_mode = 0x0110,
+ i40e_aqc_opc_clear_pxe_mode = 0x0110,
/* internal switch commands */
- i40e_aqc_opc_get_switch_config = 0x0200,
- i40e_aqc_opc_add_statistics = 0x0201,
- i40e_aqc_opc_remove_statistics = 0x0202,
- i40e_aqc_opc_set_port_parameters = 0x0203,
- i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
-
- i40e_aqc_opc_add_vsi = 0x0210,
- i40e_aqc_opc_update_vsi_parameters = 0x0211,
- i40e_aqc_opc_get_vsi_parameters = 0x0212,
-
- i40e_aqc_opc_add_pv = 0x0220,
- i40e_aqc_opc_update_pv_parameters = 0x0221,
- i40e_aqc_opc_get_pv_parameters = 0x0222,
-
- i40e_aqc_opc_add_veb = 0x0230,
- i40e_aqc_opc_update_veb_parameters = 0x0231,
- i40e_aqc_opc_get_veb_parameters = 0x0232,
-
- i40e_aqc_opc_delete_element = 0x0243,
-
- i40e_aqc_opc_add_macvlan = 0x0250,
- i40e_aqc_opc_remove_macvlan = 0x0251,
- i40e_aqc_opc_add_vlan = 0x0252,
- i40e_aqc_opc_remove_vlan = 0x0253,
- i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
- i40e_aqc_opc_add_tag = 0x0255,
- i40e_aqc_opc_remove_tag = 0x0256,
- i40e_aqc_opc_add_multicast_etag = 0x0257,
- i40e_aqc_opc_remove_multicast_etag = 0x0258,
- i40e_aqc_opc_update_tag = 0x0259,
- i40e_aqc_opc_add_control_packet_filter = 0x025A,
- i40e_aqc_opc_remove_control_packet_filter = 0x025B,
- i40e_aqc_opc_add_cloud_filters = 0x025C,
- i40e_aqc_opc_remove_cloud_filters = 0x025D,
-
- i40e_aqc_opc_add_mirror_rule = 0x0260,
- i40e_aqc_opc_delete_mirror_rule = 0x0261,
+ i40e_aqc_opc_get_switch_config = 0x0200,
+ i40e_aqc_opc_add_statistics = 0x0201,
+ i40e_aqc_opc_remove_statistics = 0x0202,
+ i40e_aqc_opc_set_port_parameters = 0x0203,
+ i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
+
+ i40e_aqc_opc_add_vsi = 0x0210,
+ i40e_aqc_opc_update_vsi_parameters = 0x0211,
+ i40e_aqc_opc_get_vsi_parameters = 0x0212,
+
+ i40e_aqc_opc_add_pv = 0x0220,
+ i40e_aqc_opc_update_pv_parameters = 0x0221,
+ i40e_aqc_opc_get_pv_parameters = 0x0222,
+
+ i40e_aqc_opc_add_veb = 0x0230,
+ i40e_aqc_opc_update_veb_parameters = 0x0231,
+ i40e_aqc_opc_get_veb_parameters = 0x0232,
+
+ i40e_aqc_opc_delete_element = 0x0243,
+
+ i40e_aqc_opc_add_macvlan = 0x0250,
+ i40e_aqc_opc_remove_macvlan = 0x0251,
+ i40e_aqc_opc_add_vlan = 0x0252,
+ i40e_aqc_opc_remove_vlan = 0x0253,
+ i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
+ i40e_aqc_opc_add_tag = 0x0255,
+ i40e_aqc_opc_remove_tag = 0x0256,
+ i40e_aqc_opc_add_multicast_etag = 0x0257,
+ i40e_aqc_opc_remove_multicast_etag = 0x0258,
+ i40e_aqc_opc_update_tag = 0x0259,
+ i40e_aqc_opc_add_control_packet_filter = 0x025A,
+ i40e_aqc_opc_remove_control_packet_filter = 0x025B,
+ i40e_aqc_opc_add_cloud_filters = 0x025C,
+ i40e_aqc_opc_remove_cloud_filters = 0x025D,
+
+ i40e_aqc_opc_add_mirror_rule = 0x0260,
+ i40e_aqc_opc_delete_mirror_rule = 0x0261,
/* DCB commands */
- i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
- i40e_aqc_opc_dcb_updated = 0x0302,
+ i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
+ i40e_aqc_opc_dcb_updated = 0x0302,
/* TX scheduler */
- i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
- i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
- i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
- i40e_aqc_opc_query_vsi_bw_config = 0x0408,
- i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
- i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
-
- i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
- i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
- i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
- i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
- i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
- i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
- i40e_aqc_opc_query_port_ets_config = 0x0419,
- i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
- i40e_aqc_opc_suspend_port_tx = 0x041B,
- i40e_aqc_opc_resume_port_tx = 0x041C,
- i40e_aqc_opc_configure_partition_bw = 0x041D,
+ i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
+ i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
+ i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
+ i40e_aqc_opc_query_vsi_bw_config = 0x0408,
+ i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
+ i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
+
+ i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
+ i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
+ i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
+ i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
+ i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
+ i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
+ i40e_aqc_opc_query_port_ets_config = 0x0419,
+ i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
+ i40e_aqc_opc_suspend_port_tx = 0x041B,
+ i40e_aqc_opc_resume_port_tx = 0x041C,
+ i40e_aqc_opc_configure_partition_bw = 0x041D,
/* hmc */
- i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
- i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
+ i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
+ i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
/* phy commands*/
- i40e_aqc_opc_get_phy_abilities = 0x0600,
- i40e_aqc_opc_set_phy_config = 0x0601,
- i40e_aqc_opc_set_mac_config = 0x0603,
- i40e_aqc_opc_set_link_restart_an = 0x0605,
- i40e_aqc_opc_get_link_status = 0x0607,
- i40e_aqc_opc_set_phy_int_mask = 0x0613,
- i40e_aqc_opc_get_local_advt_reg = 0x0614,
- i40e_aqc_opc_set_local_advt_reg = 0x0615,
- i40e_aqc_opc_get_partner_advt = 0x0616,
- i40e_aqc_opc_set_lb_modes = 0x0618,
- i40e_aqc_opc_get_phy_wol_caps = 0x0621,
- i40e_aqc_opc_set_phy_debug = 0x0622,
- i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
+ i40e_aqc_opc_get_phy_abilities = 0x0600,
+ i40e_aqc_opc_set_phy_config = 0x0601,
+ i40e_aqc_opc_set_mac_config = 0x0603,
+ i40e_aqc_opc_set_link_restart_an = 0x0605,
+ i40e_aqc_opc_get_link_status = 0x0607,
+ i40e_aqc_opc_set_phy_int_mask = 0x0613,
+ i40e_aqc_opc_get_local_advt_reg = 0x0614,
+ i40e_aqc_opc_set_local_advt_reg = 0x0615,
+ i40e_aqc_opc_get_partner_advt = 0x0616,
+ i40e_aqc_opc_set_lb_modes = 0x0618,
+ i40e_aqc_opc_get_phy_wol_caps = 0x0621,
+ i40e_aqc_opc_set_phy_debug = 0x0622,
+ i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
/* NVM commands */
- i40e_aqc_opc_nvm_read = 0x0701,
- i40e_aqc_opc_nvm_erase = 0x0702,
- i40e_aqc_opc_nvm_update = 0x0703,
- i40e_aqc_opc_nvm_config_read = 0x0704,
- i40e_aqc_opc_nvm_config_write = 0x0705,
+ i40e_aqc_opc_nvm_read = 0x0701,
+ i40e_aqc_opc_nvm_erase = 0x0702,
+ i40e_aqc_opc_nvm_update = 0x0703,
+ i40e_aqc_opc_nvm_config_read = 0x0704,
+ i40e_aqc_opc_nvm_config_write = 0x0705,
/* virtualization commands */
- i40e_aqc_opc_send_msg_to_pf = 0x0801,
- i40e_aqc_opc_send_msg_to_vf = 0x0802,
- i40e_aqc_opc_send_msg_to_peer = 0x0803,
+ i40e_aqc_opc_send_msg_to_pf = 0x0801,
+ i40e_aqc_opc_send_msg_to_vf = 0x0802,
+ i40e_aqc_opc_send_msg_to_peer = 0x0803,
/* alternate structure */
- i40e_aqc_opc_alternate_write = 0x0900,
- i40e_aqc_opc_alternate_write_indirect = 0x0901,
- i40e_aqc_opc_alternate_read = 0x0902,
- i40e_aqc_opc_alternate_read_indirect = 0x0903,
- i40e_aqc_opc_alternate_write_done = 0x0904,
- i40e_aqc_opc_alternate_set_mode = 0x0905,
- i40e_aqc_opc_alternate_clear_port = 0x0906,
+ i40e_aqc_opc_alternate_write = 0x0900,
+ i40e_aqc_opc_alternate_write_indirect = 0x0901,
+ i40e_aqc_opc_alternate_read = 0x0902,
+ i40e_aqc_opc_alternate_read_indirect = 0x0903,
+ i40e_aqc_opc_alternate_write_done = 0x0904,
+ i40e_aqc_opc_alternate_set_mode = 0x0905,
+ i40e_aqc_opc_alternate_clear_port = 0x0906,
/* LLDP commands */
- i40e_aqc_opc_lldp_get_mib = 0x0A00,
- i40e_aqc_opc_lldp_update_mib = 0x0A01,
- i40e_aqc_opc_lldp_add_tlv = 0x0A02,
- i40e_aqc_opc_lldp_update_tlv = 0x0A03,
- i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
- i40e_aqc_opc_lldp_stop = 0x0A05,
- i40e_aqc_opc_lldp_start = 0x0A06,
+ i40e_aqc_opc_lldp_get_mib = 0x0A00,
+ i40e_aqc_opc_lldp_update_mib = 0x0A01,
+ i40e_aqc_opc_lldp_add_tlv = 0x0A02,
+ i40e_aqc_opc_lldp_update_tlv = 0x0A03,
+ i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
+ i40e_aqc_opc_lldp_stop = 0x0A05,
+ i40e_aqc_opc_lldp_start = 0x0A06,
/* Tunnel commands */
- i40e_aqc_opc_add_udp_tunnel = 0x0B00,
- i40e_aqc_opc_del_udp_tunnel = 0x0B01,
- i40e_aqc_opc_tunnel_key_structure = 0x0B10,
+ i40e_aqc_opc_add_udp_tunnel = 0x0B00,
+ i40e_aqc_opc_del_udp_tunnel = 0x0B01,
+ i40e_aqc_opc_tunnel_key_structure = 0x0B10,
/* Async Events */
- i40e_aqc_opc_event_lan_overflow = 0x1001,
+ i40e_aqc_opc_event_lan_overflow = 0x1001,
/* OEM commands */
- i40e_aqc_opc_oem_parameter_change = 0xFE00,
- i40e_aqc_opc_oem_device_status_change = 0xFE01,
+ i40e_aqc_opc_oem_parameter_change = 0xFE00,
+ i40e_aqc_opc_oem_device_status_change = 0xFE01,
/* debug commands */
- i40e_aqc_opc_debug_get_deviceid = 0xFF00,
- i40e_aqc_opc_debug_set_mode = 0xFF01,
- i40e_aqc_opc_debug_read_reg = 0xFF03,
- i40e_aqc_opc_debug_write_reg = 0xFF04,
- i40e_aqc_opc_debug_modify_reg = 0xFF07,
- i40e_aqc_opc_debug_dump_internals = 0xFF08,
- i40e_aqc_opc_debug_modify_internals = 0xFF09,
+ i40e_aqc_opc_debug_get_deviceid = 0xFF00,
+ i40e_aqc_opc_debug_set_mode = 0xFF01,
+ i40e_aqc_opc_debug_read_reg = 0xFF03,
+ i40e_aqc_opc_debug_write_reg = 0xFF04,
+ i40e_aqc_opc_debug_modify_reg = 0xFF07,
+ i40e_aqc_opc_debug_dump_internals = 0xFF08,
+ i40e_aqc_opc_debug_modify_internals = 0xFF09,
};
/* command structures and indirect data structures */
/* This macro is used extensively to ensure that command structures are 16
* bytes in length as they have to map to the raw array of that size.
*/
-#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
+#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
/* internal (0x00XX) commands */
/* Send driver version (indirect 0x0002) */
struct i40e_aqc_driver_version {
- u8 driver_major_ver;
- u8 driver_minor_ver;
- u8 driver_build_ver;
- u8 driver_subbuild_ver;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
+ u8 driver_major_ver;
+ u8 driver_minor_ver;
+ u8 driver_build_ver;
+ u8 driver_subbuild_ver;
+ u8 reserved[4];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_driver_version);
/* Queue Shutdown (direct 0x0003) */
struct i40e_aqc_queue_shutdown {
- __le32 driver_unloading;
-#define I40E_AQ_DRIVER_UNLOADING 0x1
- u8 reserved[12];
+ __le32 driver_unloading;
+#define I40E_AQ_DRIVER_UNLOADING 0x1
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
/* Request resource ownership (direct 0x0008)
* Release resource ownership (direct 0x0009)
*/
-#define I40E_AQ_RESOURCE_NVM 1
-#define I40E_AQ_RESOURCE_SDP 2
-#define I40E_AQ_RESOURCE_ACCESS_READ 1
-#define I40E_AQ_RESOURCE_ACCESS_WRITE 2
-#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000
-#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
+#define I40E_AQ_RESOURCE_NVM 1
+#define I40E_AQ_RESOURCE_SDP 2
+#define I40E_AQ_RESOURCE_ACCESS_READ 1
+#define I40E_AQ_RESOURCE_ACCESS_WRITE 2
+#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000
+#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
struct i40e_aqc_request_resource {
- __le16 resource_id;
- __le16 access_type;
- __le32 timeout;
- __le32 resource_number;
- u8 reserved[4];
+ __le16 resource_id;
+ __le16 access_type;
+ __le32 timeout;
+ __le32 resource_number;
+ u8 reserved[4];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_request_resource);
*/
struct i40e_aqc_list_capabilites {
u8 command_flags;
-#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1
+#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1
u8 pf_index;
u8 reserved[2];
__le32 count;
I40E_CHECK_CMD_LENGTH(i40e_aqc_list_capabilites);
struct i40e_aqc_list_capabilities_element_resp {
- __le16 id;
- u8 major_rev;
- u8 minor_rev;
- __le32 number;
- __le32 logical_id;
- __le32 phys_id;
- u8 reserved[16];
+ __le16 id;
+ u8 major_rev;
+ u8 minor_rev;
+ __le32 number;
+ __le32 logical_id;
+ __le32 phys_id;
+ u8 reserved[16];
};
/* list of caps */
-#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001
-#define I40E_AQ_CAP_ID_MNG_MODE 0x0002
-#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003
-#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004
-#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005
-#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006
-#define I40E_AQ_CAP_ID_SRIOV 0x0012
-#define I40E_AQ_CAP_ID_VF 0x0013
-#define I40E_AQ_CAP_ID_VMDQ 0x0014
-#define I40E_AQ_CAP_ID_8021QBG 0x0015
-#define I40E_AQ_CAP_ID_8021QBR 0x0016
-#define I40E_AQ_CAP_ID_VSI 0x0017
-#define I40E_AQ_CAP_ID_DCB 0x0018
-#define I40E_AQ_CAP_ID_FCOE 0x0021
-#define I40E_AQ_CAP_ID_RSS 0x0040
-#define I40E_AQ_CAP_ID_RXQ 0x0041
-#define I40E_AQ_CAP_ID_TXQ 0x0042
-#define I40E_AQ_CAP_ID_MSIX 0x0043
-#define I40E_AQ_CAP_ID_VF_MSIX 0x0044
-#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045
-#define I40E_AQ_CAP_ID_1588 0x0046
-#define I40E_AQ_CAP_ID_IWARP 0x0051
-#define I40E_AQ_CAP_ID_LED 0x0061
-#define I40E_AQ_CAP_ID_SDP 0x0062
-#define I40E_AQ_CAP_ID_MDIO 0x0063
-#define I40E_AQ_CAP_ID_FLEX10 0x00F1
-#define I40E_AQ_CAP_ID_CEM 0x00F2
+#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001
+#define I40E_AQ_CAP_ID_MNG_MODE 0x0002
+#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003
+#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004
+#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005
+#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006
+#define I40E_AQ_CAP_ID_SRIOV 0x0012
+#define I40E_AQ_CAP_ID_VF 0x0013
+#define I40E_AQ_CAP_ID_VMDQ 0x0014
+#define I40E_AQ_CAP_ID_8021QBG 0x0015
+#define I40E_AQ_CAP_ID_8021QBR 0x0016
+#define I40E_AQ_CAP_ID_VSI 0x0017
+#define I40E_AQ_CAP_ID_DCB 0x0018
+#define I40E_AQ_CAP_ID_FCOE 0x0021
+#define I40E_AQ_CAP_ID_RSS 0x0040
+#define I40E_AQ_CAP_ID_RXQ 0x0041
+#define I40E_AQ_CAP_ID_TXQ 0x0042
+#define I40E_AQ_CAP_ID_MSIX 0x0043
+#define I40E_AQ_CAP_ID_VF_MSIX 0x0044
+#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045
+#define I40E_AQ_CAP_ID_1588 0x0046
+#define I40E_AQ_CAP_ID_IWARP 0x0051
+#define I40E_AQ_CAP_ID_LED 0x0061
+#define I40E_AQ_CAP_ID_SDP 0x0062
+#define I40E_AQ_CAP_ID_MDIO 0x0063
+#define I40E_AQ_CAP_ID_FLEX10 0x00F1
+#define I40E_AQ_CAP_ID_CEM 0x00F2
/* Set CPPM Configuration (direct 0x0103) */
struct i40e_aqc_cppm_configuration {
- __le16 command_flags;
-#define I40E_AQ_CPPM_EN_LTRC 0x0800
-#define I40E_AQ_CPPM_EN_DMCTH 0x1000
-#define I40E_AQ_CPPM_EN_DMCTLX 0x2000
-#define I40E_AQ_CPPM_EN_HPTC 0x4000
-#define I40E_AQ_CPPM_EN_DMARC 0x8000
- __le16 ttlx;
- __le32 dmacr;
- __le16 dmcth;
- u8 hptc;
- u8 reserved;
- __le32 pfltrc;
+ __le16 command_flags;
+#define I40E_AQ_CPPM_EN_LTRC 0x0800
+#define I40E_AQ_CPPM_EN_DMCTH 0x1000
+#define I40E_AQ_CPPM_EN_DMCTLX 0x2000
+#define I40E_AQ_CPPM_EN_HPTC 0x4000
+#define I40E_AQ_CPPM_EN_DMARC 0x8000
+ __le16 ttlx;
+ __le32 dmacr;
+ __le16 dmcth;
+ u8 hptc;
+ u8 reserved;
+ __le32 pfltrc;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_cppm_configuration);
/* Set ARP Proxy command / response (indirect 0x0104) */
struct i40e_aqc_arp_proxy_data {
- __le16 command_flags;
-#define I40E_AQ_ARP_INIT_IPV4 0x0008
-#define I40E_AQ_ARP_UNSUP_CTL 0x0010
-#define I40E_AQ_ARP_ENA 0x0020
-#define I40E_AQ_ARP_ADD_IPV4 0x0040
-#define I40E_AQ_ARP_DEL_IPV4 0x0080
- __le16 table_id;
- __le32 pfpm_proxyfc;
- __le32 ip_addr;
- u8 mac_addr[6];
+ __le16 command_flags;
+#define I40E_AQ_ARP_INIT_IPV4 0x0008
+#define I40E_AQ_ARP_UNSUP_CTL 0x0010
+#define I40E_AQ_ARP_ENA 0x0020
+#define I40E_AQ_ARP_ADD_IPV4 0x0040
+#define I40E_AQ_ARP_DEL_IPV4 0x0080
+ __le16 table_id;
+ __le32 pfpm_proxyfc;
+ __le32 ip_addr;
+ u8 mac_addr[6];
};
/* Set NS Proxy Table Entry Command (indirect 0x0105) */
struct i40e_aqc_ns_proxy_data {
- __le16 table_idx_mac_addr_0;
- __le16 table_idx_mac_addr_1;
- __le16 table_idx_ipv6_0;
- __le16 table_idx_ipv6_1;
- __le16 control;
-#define I40E_AQ_NS_PROXY_ADD_0 0x0100
-#define I40E_AQ_NS_PROXY_DEL_0 0x0200
-#define I40E_AQ_NS_PROXY_ADD_1 0x0400
-#define I40E_AQ_NS_PROXY_DEL_1 0x0800
-#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x1000
-#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x2000
-#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x4000
-#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x8000
-#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0001
-#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0002
-#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0004
- u8 mac_addr_0[6];
- u8 mac_addr_1[6];
- u8 local_mac_addr[6];
- u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
- u8 ipv6_addr_1[16];
+ __le16 table_idx_mac_addr_0;
+ __le16 table_idx_mac_addr_1;
+ __le16 table_idx_ipv6_0;
+ __le16 table_idx_ipv6_1;
+ __le16 control;
+#define I40E_AQ_NS_PROXY_ADD_0 0x0100
+#define I40E_AQ_NS_PROXY_DEL_0 0x0200
+#define I40E_AQ_NS_PROXY_ADD_1 0x0400
+#define I40E_AQ_NS_PROXY_DEL_1 0x0800
+#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x1000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x2000
+#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x4000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x8000
+#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0001
+#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0002
+#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0004
+ u8 mac_addr_0[6];
+ u8 mac_addr_1[6];
+ u8 local_mac_addr[6];
+ u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
+ u8 ipv6_addr_1[16];
};
/* Manage LAA Command (0x0106) - obsolete */
struct i40e_aqc_mng_laa {
__le16 command_flags;
-#define I40E_AQ_LAA_FLAG_WR 0x8000
- u8 reserved[2];
- __le32 sal;
- __le16 sah;
- u8 reserved2[6];
+#define I40E_AQ_LAA_FLAG_WR 0x8000
+ u8 reserved[2];
+ __le32 sal;
+ __le16 sah;
+ u8 reserved2[6];
};
/* Manage MAC Address Read Command (indirect 0x0107) */
struct i40e_aqc_mac_address_read {
__le16 command_flags;
-#define I40E_AQC_LAN_ADDR_VALID 0x10
-#define I40E_AQC_SAN_ADDR_VALID 0x20
-#define I40E_AQC_PORT_ADDR_VALID 0x40
-#define I40E_AQC_WOL_ADDR_VALID 0x80
-#define I40E_AQC_ADDR_VALID_MASK 0xf0
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+#define I40E_AQC_LAN_ADDR_VALID 0x10
+#define I40E_AQC_SAN_ADDR_VALID 0x20
+#define I40E_AQC_PORT_ADDR_VALID 0x40
+#define I40E_AQC_WOL_ADDR_VALID 0x80
+#define I40E_AQC_ADDR_VALID_MASK 0xf0
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_read);
/* Manage MAC Address Write Command (0x0108) */
struct i40e_aqc_mac_address_write {
- __le16 command_flags;
-#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000
-#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000
-#define I40E_AQC_WRITE_TYPE_PORT 0x8000
-#define I40E_AQC_WRITE_TYPE_MASK 0xc000
- __le16 mac_sah;
- __le32 mac_sal;
- u8 reserved[8];
+ __le16 command_flags;
+#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000
+#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000
+#define I40E_AQC_WRITE_TYPE_PORT 0x8000
+#define I40E_AQC_WRITE_TYPE_MASK 0xc000
+ __le16 mac_sah;
+ __le32 mac_sal;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_write);
* command
*/
struct i40e_aqc_switch_seid {
- __le16 seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 seid;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_switch_seid);
* uses i40e_aqc_switch_seid for the descriptor
*/
struct i40e_aqc_get_switch_config_header_resp {
- __le16 num_reported;
- __le16 num_total;
- u8 reserved[12];
+ __le16 num_reported;
+ __le16 num_total;
+ u8 reserved[12];
};
struct i40e_aqc_switch_config_element_resp {
- u8 element_type;
-#define I40E_AQ_SW_ELEM_TYPE_MAC 1
-#define I40E_AQ_SW_ELEM_TYPE_PF 2
-#define I40E_AQ_SW_ELEM_TYPE_VF 3
-#define I40E_AQ_SW_ELEM_TYPE_EMP 4
-#define I40E_AQ_SW_ELEM_TYPE_BMC 5
-#define I40E_AQ_SW_ELEM_TYPE_PV 16
-#define I40E_AQ_SW_ELEM_TYPE_VEB 17
-#define I40E_AQ_SW_ELEM_TYPE_PA 18
-#define I40E_AQ_SW_ELEM_TYPE_VSI 19
- u8 revision;
-#define I40E_AQ_SW_ELEM_REV_1 1
- __le16 seid;
- __le16 uplink_seid;
- __le16 downlink_seid;
- u8 reserved[3];
- u8 connection_type;
-#define I40E_AQ_CONN_TYPE_REGULAR 0x1
-#define I40E_AQ_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_CONN_TYPE_CASCADED 0x3
- __le16 scheduler_id;
- __le16 element_info;
+ u8 element_type;
+#define I40E_AQ_SW_ELEM_TYPE_MAC 1
+#define I40E_AQ_SW_ELEM_TYPE_PF 2
+#define I40E_AQ_SW_ELEM_TYPE_VF 3
+#define I40E_AQ_SW_ELEM_TYPE_EMP 4
+#define I40E_AQ_SW_ELEM_TYPE_BMC 5
+#define I40E_AQ_SW_ELEM_TYPE_PV 16
+#define I40E_AQ_SW_ELEM_TYPE_VEB 17
+#define I40E_AQ_SW_ELEM_TYPE_PA 18
+#define I40E_AQ_SW_ELEM_TYPE_VSI 19
+ u8 revision;
+#define I40E_AQ_SW_ELEM_REV_1 1
+ __le16 seid;
+ __le16 uplink_seid;
+ __le16 downlink_seid;
+ u8 reserved[3];
+ u8 connection_type;
+#define I40E_AQ_CONN_TYPE_REGULAR 0x1
+#define I40E_AQ_CONN_TYPE_DEFAULT 0x2
+#define I40E_AQ_CONN_TYPE_CASCADED 0x3
+ __le16 scheduler_id;
+ __le16 element_info;
};
/* Get Switch Configuration (indirect 0x0200)
* the first in the array is the header, remainder are elements
*/
struct i40e_aqc_get_switch_config_resp {
- struct i40e_aqc_get_switch_config_header_resp header;
- struct i40e_aqc_switch_config_element_resp element[1];
+ struct i40e_aqc_get_switch_config_header_resp header;
+ struct i40e_aqc_switch_config_element_resp element[1];
};
/* Add Statistics (direct 0x0201)
* Remove Statistics (direct 0x0202)
*/
struct i40e_aqc_add_remove_statistics {
- __le16 seid;
- __le16 vlan;
- __le16 stat_index;
- u8 reserved[10];
+ __le16 seid;
+ __le16 vlan;
+ __le16 stat_index;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_statistics);
/* Set Port Parameters command (direct 0x0203) */
struct i40e_aqc_set_port_parameters {
- __le16 command_flags;
-#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1
-#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
-#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
- __le16 bad_frame_vsi;
- __le16 default_seid; /* reserved for command */
- u8 reserved[10];
+ __le16 command_flags;
+#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1
+#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
+#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
+ __le16 bad_frame_vsi;
+ __le16 default_seid; /* reserved for command */
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_port_parameters);
/* Get Switch Resource Allocation (indirect 0x0204) */
struct i40e_aqc_get_switch_resource_alloc {
- u8 num_entries; /* reserved for command */
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
+ u8 num_entries; /* reserved for command */
+ u8 reserved[7];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_resource_alloc);
/* expect an array of these structs in the response buffer */
struct i40e_aqc_switch_resource_alloc_element_resp {
- u8 resource_type;
-#define I40E_AQ_RESOURCE_TYPE_VEB 0x0
-#define I40E_AQ_RESOURCE_TYPE_VSI 0x1
-#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2
-#define I40E_AQ_RESOURCE_TYPE_STAG 0x3
-#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4
-#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5
-#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6
-#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7
-#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8
-#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9
-#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA
-#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB
-#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC
-#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD
-#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF
-#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10
-#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11
-#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12
-#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13
- u8 reserved1;
- __le16 guaranteed;
- __le16 total;
- __le16 used;
- __le16 total_unalloced;
- u8 reserved2[6];
+ u8 resource_type;
+#define I40E_AQ_RESOURCE_TYPE_VEB 0x0
+#define I40E_AQ_RESOURCE_TYPE_VSI 0x1
+#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2
+#define I40E_AQ_RESOURCE_TYPE_STAG 0x3
+#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4
+#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5
+#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6
+#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7
+#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8
+#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9
+#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA
+#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB
+#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC
+#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD
+#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF
+#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10
+#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11
+#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12
+#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13
+ u8 reserved1;
+ __le16 guaranteed;
+ __le16 total;
+ __le16 used;
+ __le16 total_unalloced;
+ u8 reserved2[6];
};
/* Add VSI (indirect 0x0210)
* uses the same completion and data structure as Add VSI
*/
struct i40e_aqc_add_get_update_vsi {
- __le16 uplink_seid;
- u8 connection_type;
-#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1
-#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3
- u8 reserved1;
- u8 vf_id;
- u8 reserved2;
- __le16 vsi_flags;
-#define I40E_AQ_VSI_TYPE_SHIFT 0x0
-#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
-#define I40E_AQ_VSI_TYPE_VF 0x0
-#define I40E_AQ_VSI_TYPE_VMDQ2 0x1
-#define I40E_AQ_VSI_TYPE_PF 0x2
-#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3
-#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4
- __le32 addr_high;
- __le32 addr_low;
+ __le16 uplink_seid;
+ u8 connection_type;
+#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1
+#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2
+#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3
+ u8 reserved1;
+ u8 vf_id;
+ u8 reserved2;
+ __le16 vsi_flags;
+#define I40E_AQ_VSI_TYPE_SHIFT 0x0
+#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
+#define I40E_AQ_VSI_TYPE_VF 0x0
+#define I40E_AQ_VSI_TYPE_VMDQ2 0x1
+#define I40E_AQ_VSI_TYPE_PF 0x2
+#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3
+#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi);
struct i40e_aqc_vsi_properties_data {
/* first 96 byte are written by SW */
- __le16 valid_sections;
-#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
-#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
-#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
-#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
-#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
-#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
-#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
-#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
-#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
-#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
+ __le16 valid_sections;
+#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
+#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
+#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
+#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
+#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
+#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
+#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
+#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
+#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
+#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
/* switch section */
- __le16 switch_id; /* 12bit id combined with flags below */
-#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
-#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
-#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
-#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
-#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
- u8 sw_reserved[2];
+ __le16 switch_id; /* 12bit id combined with flags below */
+#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
+#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
+#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
+#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
+#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
+ u8 sw_reserved[2];
/* security section */
- u8 sec_flags;
-#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
- u8 sec_reserved;
+ u8 sec_flags;
+#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
+ u8 sec_reserved;
/* VLAN section */
- __le16 pvid; /* VLANS include priority bits */
- __le16 fcoe_pvid;
- u8 port_vlan_flags;
-#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
-#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
- I40E_AQ_VSI_PVLAN_MODE_SHIFT)
-#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
-#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
-#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
-#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
-#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
-#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
- I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
-#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
-#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
- u8 pvlan_reserved[3];
+ __le16 pvid; /* VLANS include priority bits */
+ __le16 fcoe_pvid;
+ u8 port_vlan_flags;
+#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
+#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
+ I40E_AQ_VSI_PVLAN_MODE_SHIFT)
+#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
+#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
+#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
+#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
+#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
+#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
+ I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
+#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
+#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
+ u8 pvlan_reserved[3];
/* ingress egress up sections */
- __le32 ingress_table; /* bitmap, 3 bits per up */
-#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
-#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
-#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
-#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
-#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
-#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
-#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
-#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
-#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
- __le32 egress_table; /* same defines as for ingress table */
+ __le32 ingress_table; /* bitmap, 3 bits per up */
+#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
+#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
+#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
+#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
+#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
+#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
+#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
+#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
+#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
+ __le32 egress_table; /* same defines as for ingress table */
/* cascaded PV section */
- __le16 cas_pv_tag;
- u8 cas_pv_flags;
-#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
- I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
-#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
-#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
-#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
-#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
-#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
- u8 cas_pv_reserved;
+ __le16 cas_pv_tag;
+ u8 cas_pv_flags;
+#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
+ I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
+#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
+#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
+#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
+#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
+#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
+ u8 cas_pv_reserved;
/* queue mapping section */
- __le16 mapping_flags;
-#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
-#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
- __le16 queue_mapping[16];
-#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
-#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
- __le16 tc_mapping[8];
-#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
-#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
- I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
-#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
-#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
- I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
+ __le16 mapping_flags;
+#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
+#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
+ __le16 queue_mapping[16];
+#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
+#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
+ __le16 tc_mapping[8];
+#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
+#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
+ I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
+#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
+ I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
/* queueing option section */
- u8 queueing_opt_flags;
-#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
-#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
- u8 queueing_opt_reserved[3];
+ u8 queueing_opt_flags;
+#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
+#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
+ u8 queueing_opt_reserved[3];
/* scheduler section */
- u8 up_enable_bits;
- u8 sched_reserved;
+ u8 up_enable_bits;
+ u8 sched_reserved;
/* outer up section */
- __le32 outer_up_table; /* same structure and defines as ingress table */
- u8 cmd_reserved[8];
+ __le32 outer_up_table; /* same structure and defines as ingress tbl */
+ u8 cmd_reserved[8];
/* last 32 bytes are written by FW */
- __le16 qs_handle[8];
+ __le16 qs_handle[8];
#define I40E_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
- __le16 stat_counter_idx;
- __le16 sched_id;
- u8 resp_reserved[12];
+ __le16 stat_counter_idx;
+ __le16 sched_id;
+ u8 resp_reserved[12];
};
I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
* (IS_CTRL_PORT only works on add PV)
*/
struct i40e_aqc_add_update_pv {
- __le16 command_flags;
-#define I40E_AQC_PV_FLAG_PV_TYPE 0x1
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4
-#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8
- __le16 uplink_seid;
- __le16 connected_seid;
- u8 reserved[10];
+ __le16 command_flags;
+#define I40E_AQC_PV_FLAG_PV_TYPE 0x1
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4
+#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8
+ __le16 uplink_seid;
+ __le16 connected_seid;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv);
struct i40e_aqc_add_update_pv_completion {
/* reserved for update; for add also encodes error if rc == ENOSPC */
- __le16 pv_seid;
-#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1
-#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8
- u8 reserved[14];
+ __le16 pv_seid;
+#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1
+#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2
+#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4
+#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv_completion);
*/
struct i40e_aqc_get_pv_params_completion {
- __le16 seid;
- __le16 default_stag;
- __le16 pv_flags; /* same flags as add_pv */
-#define I40E_AQC_GET_PV_PV_TYPE 0x1
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4
- u8 reserved[8];
- __le16 default_port_seid;
+ __le16 seid;
+ __le16 default_stag;
+ __le16 pv_flags; /* same flags as add_pv */
+#define I40E_AQC_GET_PV_PV_TYPE 0x1
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4
+ u8 reserved[8];
+ __le16 default_port_seid;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_pv_params_completion);
/* Add VEB (direct 0x0230) */
struct i40e_aqc_add_veb {
- __le16 uplink_seid;
- __le16 downlink_seid;
- __le16 veb_flags;
-#define I40E_AQC_ADD_VEB_FLOATING 0x1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \
+ __le16 uplink_seid;
+ __le16 downlink_seid;
+ __le16 veb_flags;
+#define I40E_AQC_ADD_VEB_FLOATING 0x1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \
I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8
- u8 enable_tcs;
- u8 reserved[9];
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8
+ u8 enable_tcs;
+ u8 reserved[9];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb);
struct i40e_aqc_add_veb_completion {
- u8 reserved[6];
- __le16 switch_seid;
+ u8 reserved[6];
+ __le16 switch_seid;
/* also encodes error if rc == ENOSPC; codes are the same as add_pv */
- __le16 veb_seid;
-#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1
-#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
+ __le16 veb_seid;
+#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1
+#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2
+#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4
+#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb_completion);
* uses i40e_aqc_switch_seid for the descriptor
*/
struct i40e_aqc_get_veb_parameters_completion {
- __le16 seid;
- __le16 switch_id;
- __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
- u8 reserved[4];
+ __le16 seid;
+ __le16 switch_id;
+ __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
+ u8 reserved[4];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
/* used for the command for most vlan commands */
struct i40e_aqc_macvlan {
- __le16 num_addresses;
- __le16 seid[3];
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 num_addresses;
+ __le16 seid[3];
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
-#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000
- __le32 addr_high;
- __le32 addr_low;
+#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_macvlan);
/* indirect data for command and response */
struct i40e_aqc_add_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- __le16 flags;
-#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001
-#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002
-#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004
-#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008
- __le16 queue_number;
-#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \
+ u8 mac_addr[6];
+ __le16 vlan_tag;
+ __le16 flags;
+#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001
+#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002
+#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004
+#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008
+ __le16 queue_number;
+#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0
+#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \
I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
/* response section */
- u8 match_method;
-#define I40E_AQC_MM_PERFECT_MATCH 0x01
-#define I40E_AQC_MM_HASH_MATCH 0x02
-#define I40E_AQC_MM_ERR_NO_RES 0xFF
- u8 reserved1[3];
+ u8 match_method;
+#define I40E_AQC_MM_PERFECT_MATCH 0x01
+#define I40E_AQC_MM_HASH_MATCH 0x02
+#define I40E_AQC_MM_ERR_NO_RES 0xFF
+ u8 reserved1[3];
};
struct i40e_aqc_add_remove_macvlan_completion {
*/
struct i40e_aqc_remove_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- u8 flags;
-#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01
-#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02
-#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08
-#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10
- u8 reserved[3];
+ u8 mac_addr[6];
+ __le16 vlan_tag;
+ u8 flags;
+#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01
+#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02
+#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08
+#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10
+ u8 reserved[3];
/* reply section */
- u8 error_code;
-#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF
- u8 reply_reserved[3];
+ u8 error_code;
+#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0
+#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF
+ u8 reply_reserved[3];
};
/* Add VLAN (indirect 0x0252)
* use the generic i40e_aqc_macvlan for the command
*/
struct i40e_aqc_add_remove_vlan_element_data {
- __le16 vlan_tag;
- u8 vlan_flags;
+ __le16 vlan_tag;
+ u8 vlan_flags;
/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_LOCAL 0x1
-#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1
-#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << \
- I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
-#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0
-#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2
-#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4
-#define I40E_AQC_VLAN_PTYPE_SHIFT 3
-#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
-#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0
-#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8
-#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10
-#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18
+#define I40E_AQC_ADD_VLAN_LOCAL 0x1
+#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1
+#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
+#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0
+#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2
+#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4
+#define I40E_AQC_VLAN_PTYPE_SHIFT 3
+#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
+#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0
+#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8
+#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10
+#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18
/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_ALL 0x1
- u8 reserved;
- u8 result;
+#define I40E_AQC_REMOVE_VLAN_ALL 0x1
+ u8 reserved;
+ u8 result;
/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_SUCCESS 0x0
-#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE
-#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
+#define I40E_AQC_ADD_VLAN_SUCCESS 0x0
+#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE
+#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF
- u8 reserved1[3];
+#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0
+#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF
+ u8 reserved1[3];
};
struct i40e_aqc_add_remove_vlan_completion {
- u8 reserved[4];
- __le16 vlans_used;
- __le16 vlans_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[4];
+ __le16 vlans_used;
+ __le16 vlans_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
/* Set VSI Promiscuous Modes (direct 0x0254) */
struct i40e_aqc_set_vsi_promiscuous_modes {
- __le16 promiscuous_flags;
- __le16 valid_flags;
+ __le16 promiscuous_flags;
+ __le16 valid_flags;
/* flags used for both fields above */
-#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01
-#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02
-#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04
-#define I40E_AQC_SET_VSI_DEFAULT 0x08
-#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10
- __le16 seid;
-#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF
- __le16 vlan_tag;
-#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000
- u8 reserved[8];
+#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01
+#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02
+#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04
+#define I40E_AQC_SET_VSI_DEFAULT 0x08
+#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10
+ __le16 seid;
+#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF
+ __le16 vlan_tag;
+#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_vsi_promiscuous_modes);
* Uses generic i40e_aqc_add_remove_tag_completion for completion
*/
struct i40e_aqc_add_tag {
- __le16 flags;
-#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001
- __le16 seid;
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 flags;
+#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001
+ __le16 seid;
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- __le16 queue_number;
- u8 reserved[8];
+ __le16 tag;
+ __le16 queue_number;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_tag);
struct i40e_aqc_add_remove_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
+ u8 reserved[12];
+ __le16 tags_used;
+ __le16 tags_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_tag_completion);
* Uses generic i40e_aqc_add_remove_tag_completion for completion
*/
struct i40e_aqc_remove_tag {
- __le16 seid;
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 seid;
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- u8 reserved[12];
+ __le16 tag;
+ u8 reserved[12];
};
/* Add multicast E-Tag (direct 0x0257)
* and no external data
*/
struct i40e_aqc_add_remove_mcast_etag {
- __le16 pv_seid;
- __le16 etag;
- u8 num_unicast_etags;
- u8 reserved[3];
- __le32 addr_high; /* address of array of 2-byte s-tags */
- __le32 addr_low;
+ __le16 pv_seid;
+ __le16 etag;
+ u8 num_unicast_etags;
+ u8 reserved[3];
+ __le32 addr_high; /* address of array of 2-byte s-tags */
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag);
struct i40e_aqc_add_remove_mcast_etag_completion {
- u8 reserved[4];
- __le16 mcast_etags_used;
- __le16 mcast_etags_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[4];
+ __le16 mcast_etags_used;
+ __le16 mcast_etags_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
/* Update S/E-Tag (direct 0x0259) */
struct i40e_aqc_update_tag {
- __le16 seid;
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 seid;
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 old_tag;
- __le16 new_tag;
- u8 reserved[10];
+ __le16 old_tag;
+ __le16 new_tag;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag);
struct i40e_aqc_update_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
+ u8 reserved[12];
+ __le16 tags_used;
+ __le16 tags_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag_completion);
* and the generic direct completion structure
*/
struct i40e_aqc_add_remove_control_packet_filter {
- u8 mac[6];
- __le16 etype;
- __le16 flags;
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000
- __le16 seid;
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \
+ u8 mac[6];
+ __le16 etype;
+ __le16 flags;
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000
+ __le16 seid;
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT)
- __le16 queue;
- u8 reserved[2];
+ __le16 queue;
+ u8 reserved[2];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter);
struct i40e_aqc_add_remove_control_packet_filter_completion {
- __le16 mac_etype_used;
- __le16 etype_used;
- __le16 mac_etype_free;
- __le16 etype_free;
- u8 reserved[8];
+ __le16 mac_etype_used;
+ __le16 etype_used;
+ __le16 mac_etype_free;
+ __le16 etype_free;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter_completion);
* and the generic indirect completion structure
*/
struct i40e_aqc_add_remove_cloud_filters {
- u8 num_filters;
- u8 reserved;
- __le16 seid;
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \
+ u8 num_filters;
+ u8 reserved;
+ __le16 seid;
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
- u8 reserved2[4];
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved2[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
struct i40e_aqc_add_remove_cloud_filters_element_data {
- u8 outer_mac[6];
- u8 inner_mac[6];
- __le16 inner_vlan;
+ u8 outer_mac[6];
+ u8 inner_mac[6];
+ __le16 inner_vlan;
union {
struct {
u8 reserved[12];
u8 data[16];
} v6;
} ipaddr;
- __le16 flags;
-#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
+ __le16 flags;
+#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
/* 0x0000 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
+#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
/* 0x0002 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004
/* 0x0005 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006
/* 0x0007 reserved */
/* 0x0008 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B
-#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C
-
-#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080
-#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6
-#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100
-
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN 0
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
-
- __le32 tenant_id;
- u8 reserved[4];
- __le16 queue_number;
-#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
- I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
- u8 reserved2[14];
+#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A
+#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B
+#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080
+#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6
+#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100
+
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN 0
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
+
+ __le32 tenant_id;
+ u8 reserved[4];
+ __le16 queue_number;
+#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
+ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
+ u8 reserved2[14];
/* response section */
- u8 allocation_result;
-#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0
-#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF
- u8 response_reserved[7];
+ u8 allocation_result;
+#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0
+#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF
+ u8 response_reserved[7];
};
struct i40e_aqc_remove_cloud_filters_completion {
struct i40e_aqc_add_delete_mirror_rule {
__le16 seid;
__le16 rule_type;
-#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0
-#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \
+#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0
+#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \
I40E_AQC_MIRROR_RULE_TYPE_SHIFT)
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2
-#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2
+#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5
__le16 num_entries;
__le16 destination; /* VSI for add, rule id for delete */
__le32 addr_high; /* address of array of 2-byte VSI or VLAN ids */
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule);
struct i40e_aqc_add_delete_mirror_rule_completion {
- u8 reserved[2];
- __le16 rule_id; /* only used on add */
- __le16 mirror_rules_used;
- __le16 mirror_rules_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[2];
+ __le16 rule_id; /* only used on add */
+ __le16 mirror_rules_used;
+ __le16 mirror_rules_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
* the command and response use the same descriptor structure
*/
struct i40e_aqc_pfc_ignore {
- u8 tc_bitmap;
- u8 command_flags; /* unused on response */
-#define I40E_AQC_PFC_IGNORE_SET 0x80
-#define I40E_AQC_PFC_IGNORE_CLEAR 0x0
- u8 reserved[14];
+ u8 tc_bitmap;
+ u8 command_flags; /* unused on response */
+#define I40E_AQC_PFC_IGNORE_SET 0x80
+#define I40E_AQC_PFC_IGNORE_CLEAR 0x0
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_pfc_ignore);
* this generic struct to pass the SEID in param0
*/
struct i40e_aqc_tx_sched_ind {
- __le16 vsi_seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 vsi_seid;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_tx_sched_ind);
/* Configure VSI BW limits (direct 0x0400) */
struct i40e_aqc_configure_vsi_bw_limit {
- __le16 vsi_seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_credit; /* 0-3, limit = 2^max */
- u8 reserved2[7];
+ __le16 vsi_seid;
+ u8 reserved[2];
+ __le16 credit;
+ u8 reserved1[2];
+ u8 max_credit; /* 0-3, limit = 2^max */
+ u8 reserved2[7];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_vsi_bw_limit);
* responds with i40e_aqc_qs_handles_resp
*/
struct i40e_aqc_configure_vsi_ets_sla_bw_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
+ u8 tc_valid_bits;
+ u8 reserved[15];
+ __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
+ __le16 tc_bw_max[2];
+ u8 reserved1[28];
};
/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
* responds with i40e_aqc_qs_handles_resp
*/
struct i40e_aqc_configure_vsi_tc_bw_data {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 tc_bw_credits[8];
- u8 reserved1[4];
- __le16 qs_handles[8];
+ u8 tc_valid_bits;
+ u8 reserved[3];
+ u8 tc_bw_credits[8];
+ u8 reserved1[4];
+ __le16 qs_handles[8];
};
/* Query vsi bw configuration (indirect 0x0408) */
struct i40e_aqc_query_vsi_bw_config_resp {
- u8 tc_valid_bits;
- u8 tc_suspended_bits;
- u8 reserved[14];
- __le16 qs_handles[8];
- u8 reserved1[4];
- __le16 port_bw_limit;
- u8 reserved2[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved3[23];
+ u8 tc_valid_bits;
+ u8 tc_suspended_bits;
+ u8 reserved[14];
+ __le16 qs_handles[8];
+ u8 reserved1[4];
+ __le16 port_bw_limit;
+ u8 reserved2[2];
+ u8 max_bw; /* 0-3, limit = 2^max */
+ u8 reserved3[23];
};
/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
struct i40e_aqc_query_vsi_ets_sla_config_resp {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 share_credits[8];
- __le16 credits[8];
+ u8 tc_valid_bits;
+ u8 reserved[3];
+ u8 share_credits[8];
+ __le16 credits[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
+ __le16 tc_bw_max[2];
};
/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
struct i40e_aqc_configure_switching_comp_bw_limit {
- __le16 seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved2[7];
+ __le16 seid;
+ u8 reserved[2];
+ __le16 credit;
+ u8 reserved1[2];
+ u8 max_bw; /* 0-3, limit = 2^max */
+ u8 reserved2[7];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_switching_comp_bw_limit);
* Disable Physical Port ETS (indirect 0x0415)
*/
struct i40e_aqc_configure_switching_comp_ets_data {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 seepage;
-#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1
- u8 tc_strict_priority_flags;
- u8 reserved1[17];
- u8 tc_bw_share_credits[8];
- u8 reserved2[96];
+ u8 reserved[4];
+ u8 tc_valid_bits;
+ u8 seepage;
+#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1
+ u8 tc_strict_priority_flags;
+ u8 reserved1[17];
+ u8 tc_bw_share_credits[8];
+ u8 reserved2[96];
};
/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credit[8];
+ u8 tc_valid_bits;
+ u8 reserved[15];
+ __le16 tc_bw_credit[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
+ __le16 tc_bw_max[2];
+ u8 reserved1[28];
};
/* Configure Switching Component Bandwidth Allocation per Tc
* (indirect 0x0417)
*/
struct i40e_aqc_configure_switching_comp_bw_config_data {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits; /* bool */
- u8 tc_bw_share_credits[8];
- u8 reserved1[20];
+ u8 tc_valid_bits;
+ u8 reserved[2];
+ u8 absolute_credits; /* bool */
+ u8 tc_bw_share_credits[8];
+ u8 reserved1[20];
};
/* Query Switching Component Configuration (indirect 0x0418) */
struct i40e_aqc_query_switching_comp_ets_config_resp {
- u8 tc_valid_bits;
- u8 reserved[35];
- __le16 port_bw_limit;
- u8 reserved1[2];
- u8 tc_bw_max; /* 0-3, limit = 2^max */
- u8 reserved2[23];
+ u8 tc_valid_bits;
+ u8 reserved[35];
+ __le16 port_bw_limit;
+ u8 reserved1[2];
+ u8 tc_bw_max; /* 0-3, limit = 2^max */
+ u8 reserved2[23];
};
/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
struct i40e_aqc_query_port_ets_config_resp {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 reserved1;
- u8 tc_strict_priority_bits;
- u8 reserved2;
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
+ u8 reserved[4];
+ u8 tc_valid_bits;
+ u8 reserved1;
+ u8 tc_strict_priority_bits;
+ u8 reserved2;
+ u8 tc_bw_share_credits[8];
+ __le16 tc_bw_limits[8];
/* 4 bits per tc 0-7, 4th bit reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved3[32];
+ __le16 tc_bw_max[2];
+ u8 reserved3[32];
};
/* Query Switching Component Bandwidth Allocation per Traffic Type
* (indirect 0x041A)
*/
struct i40e_aqc_query_switching_comp_bw_config_resp {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits_enable; /* bool */
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
+ u8 tc_valid_bits;
+ u8 reserved[2];
+ u8 absolute_credits_enable; /* bool */
+ u8 tc_bw_share_credits[8];
+ __le16 tc_bw_limits[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
+ __le16 tc_bw_max[2];
};
/* Suspend/resume port TX traffic
* (indirect 0x041D)
*/
struct i40e_aqc_configure_partition_bw_data {
- __le16 pf_valid_bits;
- u8 min_bw[16]; /* guaranteed bandwidth */
- u8 max_bw[16]; /* bandwidth limit */
+ __le16 pf_valid_bits;
+ u8 min_bw[16]; /* guaranteed bandwidth */
+ u8 max_bw[16]; /* bandwidth limit */
};
/* Get and set the active HMC resource profile and status.
* (direct 0x0500) and (direct 0x0501)
*/
struct i40e_aq_get_set_hmc_resource_profile {
- u8 pm_profile;
- u8 pe_vf_enabled;
- u8 reserved[14];
+ u8 pm_profile;
+ u8 pe_vf_enabled;
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_get_set_hmc_resource_profile);
enum i40e_aq_hmc_profile {
/* I40E_HMC_PROFILE_NO_CHANGE = 0, reserved */
- I40E_HMC_PROFILE_DEFAULT = 1,
- I40E_HMC_PROFILE_FAVOR_VF = 2,
- I40E_HMC_PROFILE_EQUAL = 3,
+ I40E_HMC_PROFILE_DEFAULT = 1,
+ I40E_HMC_PROFILE_FAVOR_VF = 2,
+ I40E_HMC_PROFILE_EQUAL = 3,
};
-#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_PM_MASK 0xF
-#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_COUNT_MASK 0x3F
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_PM_MASK 0xF
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_COUNT_MASK 0x3F
/* Get PHY Abilities (indirect 0x0600) uses the generic indirect struct */
/* set in param0 for get phy abilities to report qualified modules */
-#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001
-#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002
+#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001
+#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002
enum i40e_aq_phy_type {
I40E_PHY_TYPE_SGMII = 0x0,
};
struct i40e_aq_get_phy_abilities_resp {
- __le32 phy_type; /* bitmap using the above enum for offsets */
- u8 link_speed; /* bitmap using the above enum bit patterns */
- u8 abilities;
-#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01
-#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02
-#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04
-#define I40E_AQ_PHY_LINK_ENABLED 0x08
-#define I40E_AQ_PHY_AN_ENABLED 0x10
-#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20
- __le16 eee_capability;
-#define I40E_AQ_EEE_100BASE_TX 0x0002
-#define I40E_AQ_EEE_1000BASE_T 0x0004
-#define I40E_AQ_EEE_10GBASE_T 0x0008
-#define I40E_AQ_EEE_1000BASE_KX 0x0010
-#define I40E_AQ_EEE_10GBASE_KX4 0x0020
-#define I40E_AQ_EEE_10GBASE_KR 0x0040
- __le32 eeer_val;
- u8 d3_lpan;
-#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01
- u8 reserved[3];
- u8 phy_id[4];
- u8 module_type[3];
- u8 qualified_module_count;
-#define I40E_AQ_PHY_MAX_QMS 16
- struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
+ __le32 phy_type; /* bitmap using the above enum for offsets */
+ u8 link_speed; /* bitmap using the above enum bit patterns */
+ u8 abilities;
+#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01
+#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02
+#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04
+#define I40E_AQ_PHY_LINK_ENABLED 0x08
+#define I40E_AQ_PHY_AN_ENABLED 0x10
+#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20
+ __le16 eee_capability;
+#define I40E_AQ_EEE_100BASE_TX 0x0002
+#define I40E_AQ_EEE_1000BASE_T 0x0004
+#define I40E_AQ_EEE_10GBASE_T 0x0008
+#define I40E_AQ_EEE_1000BASE_KX 0x0010
+#define I40E_AQ_EEE_10GBASE_KX4 0x0020
+#define I40E_AQ_EEE_10GBASE_KR 0x0040
+ __le32 eeer_val;
+ u8 d3_lpan;
+#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01
+ u8 reserved[3];
+ u8 phy_id[4];
+ u8 module_type[3];
+ u8 qualified_module_count;
+#define I40E_AQ_PHY_MAX_QMS 16
+ struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
};
/* Set PHY Config (direct 0x0601) */
struct i40e_aq_set_phy_config { /* same bits as above in all */
- __le32 phy_type;
- u8 link_speed;
- u8 abilities;
+ __le32 phy_type;
+ u8 link_speed;
+ u8 abilities;
/* bits 0-2 use the values from get_phy_abilities_resp */
#define I40E_AQ_PHY_ENABLE_LINK 0x08
#define I40E_AQ_PHY_ENABLE_AN 0x10
#define I40E_AQ_PHY_ENABLE_ATOMIC_LINK 0x20
- __le16 eee_capability;
- __le32 eeer;
- u8 low_power_ctrl;
- u8 reserved[3];
+ __le16 eee_capability;
+ __le32 eeer;
+ u8 low_power_ctrl;
+ u8 reserved[3];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_set_phy_config);
/* Set MAC Config command data structure (direct 0x0603) */
struct i40e_aq_set_mac_config {
- __le16 max_frame_size;
- u8 params;
-#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04
-#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78
-#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7
-#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4
-#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2
-#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1
- u8 tx_timer_priority; /* bitmap */
- __le16 tx_timer_value;
- __le16 fc_refresh_threshold;
- u8 reserved[8];
+ __le16 max_frame_size;
+ u8 params;
+#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04
+#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78
+#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7
+#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4
+#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2
+#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1
+ u8 tx_timer_priority; /* bitmap */
+ __le16 tx_timer_value;
+ __le16 fc_refresh_threshold;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_set_mac_config);
/* Restart Auto-Negotiation (direct 0x605) */
struct i40e_aqc_set_link_restart_an {
- u8 command;
-#define I40E_AQ_PHY_RESTART_AN 0x02
-#define I40E_AQ_PHY_LINK_ENABLE 0x04
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_PHY_RESTART_AN 0x02
+#define I40E_AQ_PHY_LINK_ENABLE 0x04
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_link_restart_an);
/* Get Link Status cmd & response data structure (direct 0x0607) */
struct i40e_aqc_get_link_status {
- __le16 command_flags; /* only field set on command */
-#define I40E_AQ_LSE_MASK 0x3
-#define I40E_AQ_LSE_NOP 0x0
-#define I40E_AQ_LSE_DISABLE 0x2
-#define I40E_AQ_LSE_ENABLE 0x3
+ __le16 command_flags; /* only field set on command */
+#define I40E_AQ_LSE_MASK 0x3
+#define I40E_AQ_LSE_NOP 0x0
+#define I40E_AQ_LSE_DISABLE 0x2
+#define I40E_AQ_LSE_ENABLE 0x3
/* only response uses this flag */
-#define I40E_AQ_LSE_IS_ENABLED 0x1
- u8 phy_type; /* i40e_aq_phy_type */
- u8 link_speed; /* i40e_aq_link_speed */
- u8 link_info;
-#define I40E_AQ_LINK_UP 0x01
-#define I40E_AQ_LINK_FAULT 0x02
-#define I40E_AQ_LINK_FAULT_TX 0x04
-#define I40E_AQ_LINK_FAULT_RX 0x08
-#define I40E_AQ_LINK_FAULT_REMOTE 0x10
-#define I40E_AQ_MEDIA_AVAILABLE 0x40
-#define I40E_AQ_SIGNAL_DETECT 0x80
- u8 an_info;
-#define I40E_AQ_AN_COMPLETED 0x01
-#define I40E_AQ_LP_AN_ABILITY 0x02
-#define I40E_AQ_PD_FAULT 0x04
-#define I40E_AQ_FEC_EN 0x08
-#define I40E_AQ_PHY_LOW_POWER 0x10
-#define I40E_AQ_LINK_PAUSE_TX 0x20
-#define I40E_AQ_LINK_PAUSE_RX 0x40
-#define I40E_AQ_QUALIFIED_MODULE 0x80
- u8 ext_info;
-#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01
-#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
-#define I40E_AQ_LINK_TX_SHIFT 0x02
-#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT)
-#define I40E_AQ_LINK_TX_ACTIVE 0x00
-#define I40E_AQ_LINK_TX_DRAINED 0x01
-#define I40E_AQ_LINK_TX_FLUSHED 0x03
-#define I40E_AQ_LINK_FORCED_40G 0x10
- u8 loopback; /* use defines from i40e_aqc_set_lb_mode */
- __le16 max_frame_size;
- u8 config;
-#define I40E_AQ_CONFIG_CRC_ENA 0x04
-#define I40E_AQ_CONFIG_PACING_MASK 0x78
- u8 reserved[5];
+#define I40E_AQ_LSE_IS_ENABLED 0x1
+ u8 phy_type; /* i40e_aq_phy_type */
+ u8 link_speed; /* i40e_aq_link_speed */
+ u8 link_info;
+#define I40E_AQ_LINK_UP 0x01
+#define I40E_AQ_LINK_FAULT 0x02
+#define I40E_AQ_LINK_FAULT_TX 0x04
+#define I40E_AQ_LINK_FAULT_RX 0x08
+#define I40E_AQ_LINK_FAULT_REMOTE 0x10
+#define I40E_AQ_MEDIA_AVAILABLE 0x40
+#define I40E_AQ_SIGNAL_DETECT 0x80
+ u8 an_info;
+#define I40E_AQ_AN_COMPLETED 0x01
+#define I40E_AQ_LP_AN_ABILITY 0x02
+#define I40E_AQ_PD_FAULT 0x04
+#define I40E_AQ_FEC_EN 0x08
+#define I40E_AQ_PHY_LOW_POWER 0x10
+#define I40E_AQ_LINK_PAUSE_TX 0x20
+#define I40E_AQ_LINK_PAUSE_RX 0x40
+#define I40E_AQ_QUALIFIED_MODULE 0x80
+ u8 ext_info;
+#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01
+#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
+#define I40E_AQ_LINK_TX_SHIFT 0x02
+#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT)
+#define I40E_AQ_LINK_TX_ACTIVE 0x00
+#define I40E_AQ_LINK_TX_DRAINED 0x01
+#define I40E_AQ_LINK_TX_FLUSHED 0x03
+#define I40E_AQ_LINK_FORCED_40G 0x10
+ u8 loopback; /* use defines from i40e_aqc_set_lb_mode */
+ __le16 max_frame_size;
+ u8 config;
+#define I40E_AQ_CONFIG_CRC_ENA 0x04
+#define I40E_AQ_CONFIG_PACING_MASK 0x78
+ u8 reserved[5];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
/* Set event mask command (direct 0x613) */
struct i40e_aqc_set_phy_int_mask {
- u8 reserved[8];
- __le16 event_mask;
-#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002
-#define I40E_AQ_EVENT_MEDIA_NA 0x0004
-#define I40E_AQ_EVENT_LINK_FAULT 0x0008
-#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010
-#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020
-#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040
-#define I40E_AQ_EVENT_AN_COMPLETED 0x0080
-#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100
-#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
- u8 reserved1[6];
+ u8 reserved[8];
+ __le16 event_mask;
+#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002
+#define I40E_AQ_EVENT_MEDIA_NA 0x0004
+#define I40E_AQ_EVENT_LINK_FAULT 0x0008
+#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010
+#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020
+#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040
+#define I40E_AQ_EVENT_AN_COMPLETED 0x0080
+#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100
+#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
+ u8 reserved1[6];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_int_mask);
* Get Link Partner AN advt register (direct 0x0616)
*/
struct i40e_aqc_an_advt_reg {
- __le32 local_an_reg0;
- __le16 local_an_reg1;
- u8 reserved[10];
+ __le32 local_an_reg0;
+ __le16 local_an_reg1;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_an_advt_reg);
/* Set Loopback mode (0x0618) */
struct i40e_aqc_set_lb_mode {
- __le16 lb_mode;
-#define I40E_AQ_LB_PHY_LOCAL 0x01
-#define I40E_AQ_LB_PHY_REMOTE 0x02
-#define I40E_AQ_LB_MAC_LOCAL 0x04
- u8 reserved[14];
+ __le16 lb_mode;
+#define I40E_AQ_LB_PHY_LOCAL 0x01
+#define I40E_AQ_LB_PHY_REMOTE 0x02
+#define I40E_AQ_LB_MAC_LOCAL 0x04
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_lb_mode);
/* Set PHY Debug command (0x0622) */
struct i40e_aqc_set_phy_debug {
- u8 command_flags;
+ u8 command_flags;
#define I40E_AQ_PHY_DEBUG_RESET_INTERNAL 0x02
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT 2
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_MASK (0x03 << \
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_HARD 0x01
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SOFT 0x02
#define I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW 0x10
- u8 reserved[15];
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_debug);
enum i40e_aq_phy_reg_type {
- I40E_AQC_PHY_REG_INTERNAL = 0x1,
- I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2,
- I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3
+ I40E_AQC_PHY_REG_INTERNAL = 0x1,
+ I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2,
+ I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3
};
/* NVM Read command (indirect 0x0701)
* NVM Update commands (indirect 0x0703)
*/
struct i40e_aqc_nvm_update {
- u8 command_flags;
-#define I40E_AQ_NVM_LAST_CMD 0x01
-#define I40E_AQ_NVM_FLASH_ONLY 0x80
- u8 module_pointer;
- __le16 length;
- __le32 offset;
- __le32 addr_high;
- __le32 addr_low;
+ u8 command_flags;
+#define I40E_AQ_NVM_LAST_CMD 0x01
+#define I40E_AQ_NVM_FLASH_ONLY 0x80
+ u8 module_pointer;
+ __le16 length;
+ __le32 offset;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
/* NVM Config Read (indirect 0x0704) */
struct i40e_aqc_nvm_config_read {
- __le16 cmd_flags;
+ __le16 cmd_flags;
#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
#define ANVM_READ_SINGLE_FEATURE 0
#define ANVM_READ_MULTIPLE_FEATURES 1
- __le16 element_count;
- __le16 element_id; /* Feature/field ID */
- u8 reserved[2];
- __le32 address_high;
- __le32 address_low;
+ __le16 element_count;
+ __le16 element_id; /* Feature/field ID */
+ u8 reserved[2];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_read);
/* NVM Config Write (indirect 0x0705) */
struct i40e_aqc_nvm_config_write {
- __le16 cmd_flags;
- __le16 element_count;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
+ __le16 cmd_flags;
+ __le16 element_count;
+ u8 reserved[4];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write);
* Send to Peer PF command (indirect 0x0803)
*/
struct i40e_aqc_pf_vf_message {
- __le32 id;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
+ __le32 id;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
* uses i40e_aq_desc
*/
struct i40e_aqc_alternate_write_done {
- __le16 cmd_flags;
+ __le16 cmd_flags;
#define I40E_AQ_ALTERNATE_MODE_BIOS_MASK 1
#define I40E_AQ_ALTERNATE_MODE_BIOS_LEGACY 0
#define I40E_AQ_ALTERNATE_MODE_BIOS_UEFI 1
#define I40E_AQ_ALTERNATE_RESET_NEEDED 2
- u8 reserved[14];
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write_done);
/* Set OEM mode (direct 0x0905) */
struct i40e_aqc_alternate_set_mode {
- __le32 mode;
+ __le32 mode;
#define I40E_AQ_ALTERNATE_MODE_NONE 0
#define I40E_AQ_ALTERNATE_MODE_OEM 1
- u8 reserved[12];
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_set_mode);
/* Lan Queue Overflow Event (direct, 0x1001) */
struct i40e_aqc_lan_overflow {
- __le32 prtdcb_rupto;
- __le32 otx_ctl;
- u8 reserved[8];
+ __le32 prtdcb_rupto;
+ __le32 otx_ctl;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lan_overflow);
/* Get LLDP MIB (indirect 0x0A00) */
struct i40e_aqc_lldp_get_mib {
- u8 type;
- u8 reserved1;
-#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3
-#define I40E_AQ_LLDP_MIB_LOCAL 0x0
-#define I40E_AQ_LLDP_MIB_REMOTE 0x1
-#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC
-#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1
-#define I40E_AQ_LLDP_TX_SHIFT 0x4
-#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT)
+ u8 type;
+ u8 reserved1;
+#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3
+#define I40E_AQ_LLDP_MIB_LOCAL 0x0
+#define I40E_AQ_LLDP_MIB_REMOTE 0x1
+#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC
+#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1
+#define I40E_AQ_LLDP_TX_SHIFT 0x4
+#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT)
/* TX pause flags use I40E_AQ_LINK_TX_* above */
- __le16 local_len;
- __le16 remote_len;
- u8 reserved2[2];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 local_len;
+ __le16 remote_len;
+ u8 reserved2[2];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_get_mib);
* also used for the event (with type in the command field)
*/
struct i40e_aqc_lldp_update_mib {
- u8 command;
-#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0
-#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
+ u8 command;
+#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0
+#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1
+ u8 reserved[7];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_mib);
* Delete LLDP TLV (indirect 0x0A04)
*/
struct i40e_aqc_lldp_add_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved1[1];
- __le16 len;
- u8 reserved2[4];
- __le32 addr_high;
- __le32 addr_low;
+ u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
+ u8 reserved1[1];
+ __le16 len;
+ u8 reserved2[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_add_tlv);
/* Update LLDP TLV (indirect 0x0A03) */
struct i40e_aqc_lldp_update_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved;
- __le16 old_len;
- __le16 new_offset;
- __le16 new_len;
- __le32 addr_high;
- __le32 addr_low;
+ u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
+ u8 reserved;
+ __le16 old_len;
+ __le16 new_offset;
+ __le16 new_len;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_tlv);
/* Stop LLDP (direct 0x0A05) */
struct i40e_aqc_lldp_stop {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_STOP 0x0
-#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_LLDP_AGENT_STOP 0x0
+#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop);
/* Start LLDP (direct 0x0A06) */
struct i40e_aqc_lldp_start {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_START 0x1
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_LLDP_AGENT_START 0x1
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start);
/* Add Udp Tunnel command and completion (direct 0x0B00) */
struct i40e_aqc_add_udp_tunnel {
- __le16 udp_port;
- u8 reserved0[3];
- u8 protocol_type;
+ __le16 udp_port;
+ u8 reserved0[3];
+ u8 protocol_type;
#define I40E_AQC_TUNNEL_TYPE_VXLAN 0x00
#define I40E_AQC_TUNNEL_TYPE_NGE 0x01
#define I40E_AQC_TUNNEL_TYPE_TEREDO 0x10
- u8 reserved1[10];
+ u8 reserved1[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel);
struct i40e_aqc_add_udp_tunnel_completion {
- __le16 udp_port;
- u8 filter_entry_index;
- u8 multiple_pfs;
-#define I40E_AQC_SINGLE_PF 0x0
-#define I40E_AQC_MULTIPLE_PFS 0x1
- u8 total_filters;
- u8 reserved[11];
+ __le16 udp_port;
+ u8 filter_entry_index;
+ u8 multiple_pfs;
+#define I40E_AQC_SINGLE_PF 0x0
+#define I40E_AQC_MULTIPLE_PFS 0x1
+ u8 total_filters;
+ u8 reserved[11];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel_completion);
/* remove UDP Tunnel command (0x0B01) */
struct i40e_aqc_remove_udp_tunnel {
- u8 reserved[2];
- u8 index; /* 0 to 15 */
- u8 reserved2[13];
+ u8 reserved[2];
+ u8 index; /* 0 to 15 */
+ u8 reserved2[13];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_udp_tunnel);
struct i40e_aqc_del_udp_tunnel_completion {
- __le16 udp_port;
- u8 index; /* 0 to 15 */
- u8 multiple_pfs;
- u8 total_filters_used;
- u8 reserved1[11];
+ __le16 udp_port;
+ u8 index; /* 0 to 15 */
+ u8 multiple_pfs;
+ u8 total_filters_used;
+ u8 reserved1[11];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion);
u8 key1_len; /* 0 to 15 */
u8 key2_len; /* 0 to 15 */
u8 flags;
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
/* response flags */
-#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
-#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
+#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
+#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
u8 network_key_index;
#define I40E_AQC_NETWORK_KEY_INDEX_VXLAN 0x0
#define I40E_AQC_NETWORK_KEY_INDEX_NGE 0x1
/* OEM mode commands (direct 0xFE0x) */
struct i40e_aqc_oem_param_change {
- __le32 param_type;
-#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0
-#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
-#define I40E_AQ_OEM_PARAM_MAC 2
- __le32 param_value1;
- u8 param_value2[8];
+ __le32 param_type;
+#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0
+#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
+#define I40E_AQ_OEM_PARAM_MAC 2
+ __le32 param_value1;
+ u8 param_value2[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
struct i40e_aqc_oem_state_change {
- __le32 state;
-#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0
-#define I40E_AQ_OEM_STATE_LINK_UP 0x1
- u8 reserved[12];
+ __le32 state;
+#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0
+#define I40E_AQ_OEM_STATE_LINK_UP 0x1
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
/* set test more (0xFF01, internal) */
struct i40e_acq_set_test_mode {
- u8 mode;
-#define I40E_AQ_TEST_PARTIAL 0
-#define I40E_AQ_TEST_FULL 1
-#define I40E_AQ_TEST_NVM 2
- u8 reserved[3];
- u8 command;
-#define I40E_AQ_TEST_OPEN 0
-#define I40E_AQ_TEST_CLOSE 1
-#define I40E_AQ_TEST_INC 2
- u8 reserved2[3];
- __le32 address_high;
- __le32 address_low;
+ u8 mode;
+#define I40E_AQ_TEST_PARTIAL 0
+#define I40E_AQ_TEST_FULL 1
+#define I40E_AQ_TEST_NVM 2
+ u8 reserved[3];
+ u8 command;
+#define I40E_AQ_TEST_OPEN 0
+#define I40E_AQ_TEST_CLOSE 1
+#define I40E_AQ_TEST_INC 2
+ u8 reserved2[3];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_acq_set_test_mode);
#define I40E_AQ_CLUSTER_ID_ALTRAM 11
struct i40e_aqc_debug_dump_internals {
- u8 cluster_id;
- u8 table_id;
- __le16 data_size;
- __le32 idx;
- __le32 address_high;
- __le32 address_low;
+ u8 cluster_id;
+ u8 table_id;
+ __le16 data_size;
+ __le32 idx;
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_dump_internals);
struct i40e_aqc_debug_modify_internals {
- u8 cluster_id;
- u8 cluster_specific_params[7];
- __le32 address_high;
- __le32 address_low;
+ u8 cluster_id;
+ u8 cluster_specific_params[7];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
case I40E_DEV_ID_QSFP_A:
case I40E_DEV_ID_QSFP_B:
case I40E_DEV_ID_QSFP_C:
+ case I40E_DEV_ID_10G_BASE_T:
hw->mac.type = I40E_MAC_XL710;
break;
case I40E_DEV_ID_VF:
return status;
}
+/**
+ * i40e_aq_set_phy_int_mask
+ * @hw: pointer to the hw struct
+ * @mask: interrupt mask to be set
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Set link interrupt mask.
+ **/
+i40e_status i40e_aq_set_phy_int_mask(struct i40e_hw *hw,
+ u16 mask,
+ struct i40e_asq_cmd_details *cmd_details)
+{
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_set_phy_int_mask *cmd =
+ (struct i40e_aqc_set_phy_int_mask *)&desc.params.raw;
+ i40e_status status;
+
+ i40e_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_set_phy_int_mask);
+
+ cmd->event_mask = cpu_to_le16(mask);
+
+ status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+ return status;
+}
+
/**
* i40e_aq_add_vsi
* @hw: pointer to the hw struct
estats->tx_discards, estats->tx_errors);
}
-/**
- * i40e_dbg_dump_stats - handles dump stats write into command datum
- * @pf: the i40e_pf created in command write
- * @stats: the stats structure to be dumped
- **/
-static void i40e_dbg_dump_stats(struct i40e_pf *pf,
- struct i40e_hw_port_stats *stats)
-{
- int i;
-
- dev_info(&pf->pdev->dev, " stats:\n");
- dev_info(&pf->pdev->dev,
- " crc_errors = \t\t%lld \tillegal_bytes = \t%lld \terror_bytes = \t\t%lld\n",
- stats->crc_errors, stats->illegal_bytes, stats->error_bytes);
- dev_info(&pf->pdev->dev,
- " mac_local_faults = \t%lld \tmac_remote_faults = \t%lld \trx_length_errors = \t%lld\n",
- stats->mac_local_faults, stats->mac_remote_faults,
- stats->rx_length_errors);
- dev_info(&pf->pdev->dev,
- " link_xon_rx = \t\t%lld \tlink_xoff_rx = \t\t%lld \tlink_xon_tx = \t\t%lld\n",
- stats->link_xon_rx, stats->link_xoff_rx, stats->link_xon_tx);
- dev_info(&pf->pdev->dev,
- " link_xoff_tx = \t\t%lld \trx_size_64 = \t\t%lld \trx_size_127 = \t\t%lld\n",
- stats->link_xoff_tx, stats->rx_size_64, stats->rx_size_127);
- dev_info(&pf->pdev->dev,
- " rx_size_255 = \t\t%lld \trx_size_511 = \t\t%lld \trx_size_1023 = \t\t%lld\n",
- stats->rx_size_255, stats->rx_size_511, stats->rx_size_1023);
- dev_info(&pf->pdev->dev,
- " rx_size_big = \t\t%lld \trx_undersize = \t\t%lld \trx_jabber = \t\t%lld\n",
- stats->rx_size_big, stats->rx_undersize, stats->rx_jabber);
- dev_info(&pf->pdev->dev,
- " rx_fragments = \t\t%lld \trx_oversize = \t\t%lld \ttx_size_64 = \t\t%lld\n",
- stats->rx_fragments, stats->rx_oversize, stats->tx_size_64);
- dev_info(&pf->pdev->dev,
- " tx_size_127 = \t\t%lld \ttx_size_255 = \t\t%lld \ttx_size_511 = \t\t%lld\n",
- stats->tx_size_127, stats->tx_size_255, stats->tx_size_511);
- dev_info(&pf->pdev->dev,
- " tx_size_1023 = \t\t%lld \ttx_size_big = \t\t%lld \tmac_short_packet_dropped = \t%lld\n",
- stats->tx_size_1023, stats->tx_size_big,
- stats->mac_short_packet_dropped);
- for (i = 0; i < 8; i += 4) {
- dev_info(&pf->pdev->dev,
- " priority_xon_rx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
- i, stats->priority_xon_rx[i],
- i+1, stats->priority_xon_rx[i+1],
- i+2, stats->priority_xon_rx[i+2],
- i+3, stats->priority_xon_rx[i+3]);
- }
- for (i = 0; i < 8; i += 4) {
- dev_info(&pf->pdev->dev,
- " priority_xoff_rx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
- i, stats->priority_xoff_rx[i],
- i+1, stats->priority_xoff_rx[i+1],
- i+2, stats->priority_xoff_rx[i+2],
- i+3, stats->priority_xoff_rx[i+3]);
- }
- for (i = 0; i < 8; i += 4) {
- dev_info(&pf->pdev->dev,
- " priority_xon_tx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
- i, stats->priority_xon_tx[i],
- i+1, stats->priority_xon_tx[i+1],
- i+2, stats->priority_xon_tx[i+2],
- i+3, stats->priority_xon_rx[i+3]);
- }
- for (i = 0; i < 8; i += 4) {
- dev_info(&pf->pdev->dev,
- " priority_xoff_tx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
- i, stats->priority_xoff_tx[i],
- i+1, stats->priority_xoff_tx[i+1],
- i+2, stats->priority_xoff_tx[i+2],
- i+3, stats->priority_xoff_tx[i+3]);
- }
- for (i = 0; i < 8; i += 4) {
- dev_info(&pf->pdev->dev,
- " priority_xon_2_xoff[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
- i, stats->priority_xon_2_xoff[i],
- i+1, stats->priority_xon_2_xoff[i+1],
- i+2, stats->priority_xon_2_xoff[i+2],
- i+3, stats->priority_xon_2_xoff[i+3]);
- }
-
- i40e_dbg_dump_eth_stats(pf, &stats->eth);
-}
-
/**
* i40e_dbg_dump_veb_seid - handles dump stats of a single given veb
* @pf: the i40e_pf created in command write
"dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
dev_info(&pf->pdev->dev, "dump desc aq\n");
}
- } else if (strncmp(&cmd_buf[5], "stats", 5) == 0) {
- dev_info(&pf->pdev->dev, "pf stats:\n");
- i40e_dbg_dump_stats(pf, &pf->stats);
- dev_info(&pf->pdev->dev, "pf stats_offsets:\n");
- i40e_dbg_dump_stats(pf, &pf->stats_offsets);
} else if (strncmp(&cmd_buf[5], "reset stats", 11) == 0) {
dev_info(&pf->pdev->dev,
"core reset count: %d\n", pf->corer_count);
} else {
dev_info(&pf->pdev->dev,
"dump desc tx <vsi_seid> <ring_id> [<desc_n>], dump desc rx <vsi_seid> <ring_id> [<desc_n>],\n");
- dev_info(&pf->pdev->dev, "dump switch, dump vsi [seid] or\n");
- dev_info(&pf->pdev->dev, "dump stats\n");
+ dev_info(&pf->pdev->dev, "dump switch\n");
+ dev_info(&pf->pdev->dev, "dump vsi [seid]\n");
dev_info(&pf->pdev->dev, "dump reset stats\n");
dev_info(&pf->pdev->dev, "dump port\n");
dev_info(&pf->pdev->dev,
ecmd->supported = SUPPORTED_10000baseKR_Full;
ecmd->advertising = ADVERTISED_10000baseKR_Full;
break;
+ case I40E_DEV_ID_10G_BASE_T:
+ ecmd->supported = SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full;
+ ecmd->advertising = ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full;
+ break;
default:
/* all the rest are 10G/1G */
ecmd->supported = SUPPORTED_10000baseT_Full |
case I40E_PHY_TYPE_10GBASE_CR1:
case I40E_PHY_TYPE_10GBASE_T:
ecmd->supported = SUPPORTED_Autoneg |
- SUPPORTED_10000baseT_Full;
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full;
ecmd->advertising = ADVERTISED_Autoneg |
- ADVERTISED_10000baseT_Full;
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full;
break;
case I40E_PHY_TYPE_XAUI:
case I40E_PHY_TYPE_XFI:
case I40E_PHY_TYPE_1000BASE_KX:
case I40E_PHY_TYPE_1000BASE_T:
ecmd->supported = SUPPORTED_Autoneg |
- SUPPORTED_1000baseT_Full;
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full;
ecmd->advertising = ADVERTISED_Autoneg |
- ADVERTISED_1000baseT_Full;
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full;
break;
case I40E_PHY_TYPE_100BASE_TX:
ecmd->supported = SUPPORTED_Autoneg |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
SUPPORTED_100baseT_Full;
ecmd->advertising = ADVERTISED_Autoneg |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full |
ADVERTISED_100baseT_Full;
break;
case I40E_PHY_TYPE_SGMII:
case I40E_LINK_SPEED_1GB:
ethtool_cmd_speed_set(ecmd, SPEED_1000);
break;
+ case I40E_LINK_SPEED_100MB:
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
+ break;
default:
break;
}
}
/* If autoneg is currently enabled */
if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) {
- config.abilities = abilities.abilities |
+ config.abilities = abilities.abilities &
~I40E_AQ_PHY_ENABLE_AN;
change = true;
}
vsi->rx_itr_setting = ec->rx_coalesce_usecs;
} else if (ec->rx_coalesce_usecs == 0) {
vsi->rx_itr_setting = ec->rx_coalesce_usecs;
- i40e_irq_dynamic_disable(vsi, vector);
if (ec->use_adaptive_rx_coalesce)
- netif_info(pf, drv, netdev,
- "Rx-secs=0, need to disable adaptive-Rx for a complete disable\n");
+ netif_info(pf, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
} else {
- netif_info(pf, drv, netdev,
- "Invalid value, Rx-usecs range is 0, 8-8160\n");
+ netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
return -EINVAL;
}
vsi->tx_itr_setting = ec->tx_coalesce_usecs;
} else if (ec->tx_coalesce_usecs == 0) {
vsi->tx_itr_setting = ec->tx_coalesce_usecs;
- i40e_irq_dynamic_disable(vsi, vector);
if (ec->use_adaptive_tx_coalesce)
- netif_info(pf, drv, netdev,
- "Tx-secs=0, need to disable adaptive-Tx for a complete disable\n");
+ netif_info(pf, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
} else {
netif_info(pf, drv, netdev,
- "Invalid value, Tx-usecs range is 0, 8-8160\n");
+ "Invalid value, tx-usecs range is 0-8160\n");
return -EINVAL;
}
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 0
-#define DRV_VERSION_BUILD 11
+#define DRV_VERSION_BUILD 21
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A), 0},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_B), 0},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0},
+ {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0},
/* required last entry */
{0, }
};
struct i40e_eth_stats *oes;
struct i40e_eth_stats *es; /* device's eth stats */
u32 tx_restart, tx_busy;
+ struct i40e_ring *p;
u32 rx_page, rx_buf;
+ u64 bytes, packets;
+ unsigned int start;
u64 rx_p, rx_b;
u64 tx_p, tx_b;
u16 q;
rx_buf = 0;
rcu_read_lock();
for (q = 0; q < vsi->num_queue_pairs; q++) {
- struct i40e_ring *p;
- u64 bytes, packets;
- unsigned int start;
-
/* locate Tx ring */
p = ACCESS_ONCE(vsi->tx_rings[q]);
}
/* Now associate this queue with this PCI function */
- if (vsi->type == I40E_VSI_VMDQ2)
+ if (vsi->type == I40E_VSI_VMDQ2) {
qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
- else
+ qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+ I40E_QTX_CTL_VFVM_INDX_MASK;
+ } else {
qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+ }
+
qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
I40E_QTX_CTL_PF_INDX_MASK);
wr32(hw, I40E_QTX_CTL(pf_q), qtx_ctl);
if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
break;
- udelay(10);
+ usleep_range(10, 20);
}
if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT)
return -ETIMEDOUT;
/* warn the TX unit of coming changes */
i40e_pre_tx_queue_cfg(&pf->hw, pf_q, enable);
if (!enable)
- udelay(10);
+ usleep_range(10, 20);
for (j = 0; j < 50; j++) {
tx_reg = rd32(hw, I40E_QTX_ENA(pf_q));
if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
break;
- udelay(10);
+ usleep_range(10, 20);
}
if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT)
return -ETIMEDOUT;
case I40E_LINK_SPEED_1GB:
strlcpy(speed, "1000 Mbps", SPEED_SIZE);
break;
+ case I40E_LINK_SPEED_100MB:
+ strncpy(speed, "100 Mbps", SPEED_SIZE);
+ break;
default:
break;
}
static int i40e_up_complete(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
- u8 set_fc_aq_fail = 0;
int err;
- /* force flow control off */
- i40e_set_fc(&pf->hw, &set_fc_aq_fail, true);
-
if (pf->flags & I40E_FLAG_MSIX_ENABLED)
i40e_vsi_configure_msix(vsi);
else
int flush_wait_retry = 50;
int reg;
+ if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)))
+ return;
+
if (time_after(jiffies, pf->fd_flush_timestamp +
(I40E_MIN_FD_FLUSH_INTERVAL * HZ))) {
set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
if (test_bit(__I40E_DOWN, &pf->state))
return;
+ if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)))
+ return;
+
if ((pf->fd_add_err >= I40E_MAX_FD_PROGRAM_ERROR) &&
(i40e_get_current_atr_cnt(pf) >= pf->fd_atr_cnt) &&
(i40e_get_current_atr_cnt(pf) > pf->fdir_pf_filter_count))
static void i40e_link_event(struct i40e_pf *pf)
{
bool new_link, old_link;
+ struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+
+ /* set this to force the get_link_status call to refresh state */
+ pf->hw.phy.get_link_info = true;
- new_link = (pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP);
old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
+ new_link = i40e_get_link_status(&pf->hw);
- if (new_link == old_link)
+ if (new_link == old_link &&
+ (test_bit(__I40E_DOWN, &vsi->state) ||
+ new_link == netif_carrier_ok(vsi->netdev)))
return;
- if (!test_bit(__I40E_DOWN, &pf->vsi[pf->lan_vsi]->state))
- i40e_print_link_message(pf->vsi[pf->lan_vsi], new_link);
+
+ if (!test_bit(__I40E_DOWN, &vsi->state))
+ i40e_print_link_message(vsi, new_link);
/* Notify the base of the switch tree connected to
* the link. Floating VEBs are not notified.
if (pf->lan_veb != I40E_NO_VEB && pf->veb[pf->lan_veb])
i40e_veb_link_event(pf->veb[pf->lan_veb], new_link);
else
- i40e_vsi_link_event(pf->vsi[pf->lan_vsi], new_link);
+ i40e_vsi_link_event(vsi, new_link);
if (pf->vf)
i40e_vc_notify_link_state(pf);
}
/**
- * i40e_watchdog_subtask - Check and bring link up
+ * i40e_watchdog_subtask - periodic checks not using event driven response
* @pf: board private structure
**/
static void i40e_watchdog_subtask(struct i40e_pf *pf)
test_bit(__I40E_CONFIG_BUSY, &pf->state))
return;
+ /* make sure we don't do these things too often */
+ if (time_before(jiffies, (pf->service_timer_previous +
+ pf->service_timer_period)))
+ return;
+ pf->service_timer_previous = jiffies;
+
+ i40e_check_hang_subtask(pf);
+ i40e_link_event(pf);
+
/* Update the stats for active netdevs so the network stack
* can look at updated numbers whenever it cares to
*/
memcpy(&pf->hw.phy.link_info_old, hw_link_info,
sizeof(pf->hw.phy.link_info_old));
+ /* Do a new status request to re-enable LSE reporting
+ * and load new status information into the hw struct
+ * This completely ignores any state information
+ * in the ARQ event info, instead choosing to always
+ * issue the AQ update link status command.
+ */
+ i40e_link_event(pf);
+
/* check for unqualified module, if link is down */
if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
(!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
(!(status->link_info & I40E_AQ_LINK_UP)))
dev_err(&pf->pdev->dev,
"The driver failed to link because an unqualified module was detected.\n");
-
- /* update link status */
- hw_link_info->phy_type = (enum i40e_aq_phy_type)status->phy_type;
- hw_link_info->link_speed = (enum i40e_aq_link_speed)status->link_speed;
- hw_link_info->link_info = status->link_info;
- hw_link_info->an_info = status->an_info;
- hw_link_info->ext_info = status->ext_info;
- hw_link_info->lse_enable =
- le16_to_cpu(status->command_flags) &
- I40E_AQ_LSE_ENABLE;
-
- /* process the event */
- i40e_link_event(pf);
-
- /* Do a new status request to re-enable LSE reporting
- * and load new status information into the hw struct,
- * then see if the status changed while processing the
- * initial event.
- */
- i40e_update_link_info(&pf->hw, true);
- i40e_link_event(pf);
}
/**
static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
{
struct i40e_hw *hw = &pf->hw;
+ u8 set_fc_aq_fail = 0;
i40e_status ret;
u32 v;
if (ret)
goto end_core_reset;
+ /* driver is only interested in link up/down and module qualification
+ * reports from firmware
+ */
+ ret = i40e_aq_set_phy_int_mask(&pf->hw,
+ I40E_AQ_EVENT_LINK_UPDOWN |
+ I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+ if (ret)
+ dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", ret);
+
+ /* make sure our flow control settings are restored */
+ ret = i40e_set_fc(&pf->hw, &set_fc_aq_fail, true);
+ if (ret)
+ dev_info(&pf->pdev->dev, "set fc fail, aq_err %d\n", ret);
+
/* Rebuild the VSIs and VEBs that existed before reset.
* They are still in our local switch element arrays, so only
* need to rebuild the switch model in the HW.
}
}
+ msleep(75);
+ ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
+ if (ret) {
+ dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n",
+ pf->hw.aq.asq_last_status);
+ }
+
/* reinit the misc interrupt */
if (pf->flags & I40E_FLAG_MSIX_ENABLED)
ret = i40e_setup_misc_vector(pf);
if (reg & I40E_GL_MDET_TX_VALID_MASK) {
u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
I40E_GL_MDET_TX_PF_NUM_SHIFT;
- u8 vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
+ u16 vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
I40E_GL_MDET_TX_VF_NUM_SHIFT;
u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
I40E_GL_MDET_TX_EVENT_SHIFT;
- u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
- I40E_GL_MDET_TX_QUEUE_SHIFT;
+ u16 queue = ((reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
+ I40E_GL_MDET_TX_QUEUE_SHIFT) -
+ pf->hw.func_caps.base_queue;
if (netif_msg_tx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n",
event, queue, pf_num, vf_num);
I40E_GL_MDET_RX_FUNCTION_SHIFT;
u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
I40E_GL_MDET_RX_EVENT_SHIFT;
- u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
- I40E_GL_MDET_RX_QUEUE_SHIFT;
+ u16 queue = ((reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
+ I40E_GL_MDET_RX_QUEUE_SHIFT) -
+ pf->hw.func_caps.base_queue;
if (netif_msg_rx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
event, queue, func);
i40e_vc_process_vflr_event(pf);
i40e_watchdog_subtask(pf);
i40e_fdir_reinit_subtask(pf);
- i40e_check_hang_subtask(pf);
i40e_sync_filters_subtask(pf);
#ifdef CONFIG_I40E_VXLAN
i40e_sync_vxlan_filters_subtask(pf);
{
i40e_status err = 0;
struct i40e_hw *hw = &pf->hw;
+ int other_vecs = 0;
int v_budget, i;
int vec;
*/
pf->num_lan_msix = pf->num_lan_qps - (pf->rss_size_max - pf->rss_size);
pf->num_vmdq_msix = pf->num_vmdq_qps;
- v_budget = 1 + pf->num_lan_msix;
- v_budget += (pf->num_vmdq_vsis * pf->num_vmdq_msix);
+ other_vecs = 1;
+ other_vecs += (pf->num_vmdq_vsis * pf->num_vmdq_msix);
if (pf->flags & I40E_FLAG_FD_SB_ENABLED)
- v_budget++;
+ other_vecs++;
#ifdef I40E_FCOE
if (pf->flags & I40E_FLAG_FCOE_ENABLED) {
#endif
/* Scale down if necessary, and the rings will share vectors */
- v_budget = min_t(int, v_budget, hw->func_caps.num_msix_vectors);
+ pf->num_lan_msix = min_t(int, pf->num_lan_msix,
+ (hw->func_caps.num_msix_vectors - other_vecs));
+ v_budget = pf->num_lan_msix + other_vecs;
pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
GFP_KERNEL);
vsi->num_q_vectors, vsi->idx);
if (vsi->base_vector < 0) {
dev_info(&pf->pdev->dev,
- "failed to get queue tracking for VSI %d, err=%d\n",
- vsi->seid, vsi->base_vector);
+ "failed to get tracking for %d vectors for VSI %d, err=%d\n",
+ vsi->num_q_vectors, vsi->seid, vsi->base_vector);
i40e_vsi_free_q_vectors(vsi);
ret = -ENOENT;
goto vector_setup_out;
ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx);
if (ret < 0) {
- dev_info(&pf->pdev->dev, "VSI %d get_lump failed %d\n",
- vsi->seid, ret);
+ dev_info(&pf->pdev->dev,
+ "failed to get tracking for %d queues for VSI %d err=%d\n",
+ vsi->alloc_queue_pairs, vsi->seid, ret);
goto err_vsi;
}
vsi->base_queue = ret;
ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs,
vsi->idx);
if (ret < 0) {
- dev_info(&pf->pdev->dev, "VSI %d get_lump failed %d\n",
- vsi->seid, ret);
+ dev_info(&pf->pdev->dev,
+ "failed to get tracking for %d queues for VSI %d err=%d\n",
+ vsi->alloc_queue_pairs, vsi->seid, ret);
goto err_vsi;
}
vsi->base_queue = ret;
i40e_update_link_info(&pf->hw, true);
i40e_link_event(pf);
+ /* Initialize user-specific link properties */
+ pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info &
+ I40E_AQ_AN_COMPLETED) ? true : false);
+
+ /* fill in link information and enable LSE reporting */
+ i40e_update_link_info(&pf->hw, true);
+ i40e_link_event(pf);
+
/* Initialize user-specific link properties */
pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info &
I40E_AQ_AN_COMPLETED) ? true : false);
hw->bus.func = PCI_FUNC(pdev->devfn);
pf->instance = pfs_found;
+ if (debug != -1) {
+ pf->msg_enable = pf->hw.debug_mask;
+ pf->msg_enable = debug;
+ }
+
/* do a special CORER for clearing PXE mode once at init */
if (hw->revision_id == 0 &&
(rd32(hw, I40E_GLLAN_RCTL_0) & I40E_GLLAN_RCTL_0_PXE_MODE_MASK)) {
}
}
+ /* driver is only interested in link up/down and module qualification
+ * reports from firmware
+ */
+ err = i40e_aq_set_phy_int_mask(&pf->hw,
+ I40E_AQ_EVENT_LINK_UPDOWN |
+ I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+ if (err)
+ dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", err);
+
+ msleep(75);
+ err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
+ if (err) {
+ dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n",
+ pf->hw.aq.asq_last_status);
+ }
+
/* The main driver is (mostly) up and happy. We need to set this state
* before setting up the misc vector or we get a race and the vector
* ends up disabled forever.
struct i40e_asq_cmd_details *cmd_details);
enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
bool atomic_reset);
+i40e_status i40e_aq_set_phy_int_mask(struct i40e_hw *hw, u16 mask,
+ struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
/* Interrupt Throttling and Rate Limiting Goodies */
#define I40E_MAX_ITR 0x0FF0 /* reg uses 2 usec resolution */
-#define I40E_MIN_ITR 0x0004 /* reg uses 2 usec resolution */
-#define I40E_MAX_IRATE 0x03F
-#define I40E_MIN_IRATE 0x001
-#define I40E_IRATE_USEC_RESOLUTION 4
+#define I40E_MIN_ITR 0x0001 /* reg uses 2 usec resolution */
#define I40E_ITR_100K 0x0005
#define I40E_ITR_20K 0x0019
#define I40E_ITR_8K 0x003E
#define I40E_DEV_ID_QSFP_A 0x1583
#define I40E_DEV_ID_QSFP_B 0x1584
#define I40E_DEV_ID_QSFP_C 0x1585
+#define I40E_DEV_ID_10G_BASE_T 0x1586
#define I40E_DEV_ID_VF 0x154C
#define I40E_DEV_ID_VF_HV 0x1571
* that the requested op was completed
* successfully
*/
- udelay(10);
+ usleep_range(10, 20);
reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) {
rsd = true;
*/
if (!details->async && !details->postpone) {
u32 total_delay = 0;
- u32 delay_len = 10;
do {
/* AQ designers suggest use of head for better
*/
if (i40evf_asq_done(hw))
break;
- /* ugh! delay while spin_lock */
- udelay(delay_len);
- total_delay += delay_len;
+ usleep_range(1000, 2000);
+ total_delay++;
} while (total_delay < hw->aq.asq_cmd_timeout);
}
/* general information */
#define I40E_AQ_LARGE_BUF 512
-#define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */
+#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */
void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
u16 opcode);
* This file needs to comply with the Linux Kernel coding style.
*/
-#define I40E_FW_API_VERSION_MAJOR 0x0001
-#define I40E_FW_API_VERSION_MINOR 0x0002
+#define I40E_FW_API_VERSION_MAJOR 0x0001
+#define I40E_FW_API_VERSION_MINOR 0x0002
#define I40E_FW_API_VERSION_A0_MINOR 0x0000
struct i40e_aq_desc {
*/
/* command flags and offsets*/
-#define I40E_AQ_FLAG_DD_SHIFT 0
-#define I40E_AQ_FLAG_CMP_SHIFT 1
-#define I40E_AQ_FLAG_ERR_SHIFT 2
-#define I40E_AQ_FLAG_VFE_SHIFT 3
-#define I40E_AQ_FLAG_LB_SHIFT 9
-#define I40E_AQ_FLAG_RD_SHIFT 10
-#define I40E_AQ_FLAG_VFC_SHIFT 11
-#define I40E_AQ_FLAG_BUF_SHIFT 12
-#define I40E_AQ_FLAG_SI_SHIFT 13
-#define I40E_AQ_FLAG_EI_SHIFT 14
-#define I40E_AQ_FLAG_FE_SHIFT 15
-
-#define I40E_AQ_FLAG_DD (1 << I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
-#define I40E_AQ_FLAG_CMP (1 << I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
-#define I40E_AQ_FLAG_ERR (1 << I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
-#define I40E_AQ_FLAG_VFE (1 << I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
-#define I40E_AQ_FLAG_LB (1 << I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
-#define I40E_AQ_FLAG_RD (1 << I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
-#define I40E_AQ_FLAG_VFC (1 << I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
-#define I40E_AQ_FLAG_BUF (1 << I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
-#define I40E_AQ_FLAG_SI (1 << I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
-#define I40E_AQ_FLAG_EI (1 << I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
-#define I40E_AQ_FLAG_FE (1 << I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
+#define I40E_AQ_FLAG_DD_SHIFT 0
+#define I40E_AQ_FLAG_CMP_SHIFT 1
+#define I40E_AQ_FLAG_ERR_SHIFT 2
+#define I40E_AQ_FLAG_VFE_SHIFT 3
+#define I40E_AQ_FLAG_LB_SHIFT 9
+#define I40E_AQ_FLAG_RD_SHIFT 10
+#define I40E_AQ_FLAG_VFC_SHIFT 11
+#define I40E_AQ_FLAG_BUF_SHIFT 12
+#define I40E_AQ_FLAG_SI_SHIFT 13
+#define I40E_AQ_FLAG_EI_SHIFT 14
+#define I40E_AQ_FLAG_FE_SHIFT 15
+
+#define I40E_AQ_FLAG_DD (1 << I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
+#define I40E_AQ_FLAG_CMP (1 << I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
+#define I40E_AQ_FLAG_ERR (1 << I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
+#define I40E_AQ_FLAG_VFE (1 << I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
+#define I40E_AQ_FLAG_LB (1 << I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
+#define I40E_AQ_FLAG_RD (1 << I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
+#define I40E_AQ_FLAG_VFC (1 << I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
+#define I40E_AQ_FLAG_BUF (1 << I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
+#define I40E_AQ_FLAG_SI (1 << I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
+#define I40E_AQ_FLAG_EI (1 << I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
+#define I40E_AQ_FLAG_FE (1 << I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
/* error codes */
enum i40e_admin_queue_err {
- I40E_AQ_RC_OK = 0, /* success */
- I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
- I40E_AQ_RC_ENOENT = 2, /* No such element */
- I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
- I40E_AQ_RC_EINTR = 4, /* operation interrupted */
- I40E_AQ_RC_EIO = 5, /* I/O error */
- I40E_AQ_RC_ENXIO = 6, /* No such resource */
- I40E_AQ_RC_E2BIG = 7, /* Arg too long */
- I40E_AQ_RC_EAGAIN = 8, /* Try again */
- I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
- I40E_AQ_RC_EACCES = 10, /* Permission denied */
- I40E_AQ_RC_EFAULT = 11, /* Bad address */
- I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
- I40E_AQ_RC_EEXIST = 13, /* object already exists */
- I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
- I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
- I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
- I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
- I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
- I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed because of prev cmd error */
- I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
- I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
- I40E_AQ_RC_EFBIG = 22, /* File too large */
+ I40E_AQ_RC_OK = 0, /* success */
+ I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
+ I40E_AQ_RC_ENOENT = 2, /* No such element */
+ I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
+ I40E_AQ_RC_EINTR = 4, /* operation interrupted */
+ I40E_AQ_RC_EIO = 5, /* I/O error */
+ I40E_AQ_RC_ENXIO = 6, /* No such resource */
+ I40E_AQ_RC_E2BIG = 7, /* Arg too long */
+ I40E_AQ_RC_EAGAIN = 8, /* Try again */
+ I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
+ I40E_AQ_RC_EACCES = 10, /* Permission denied */
+ I40E_AQ_RC_EFAULT = 11, /* Bad address */
+ I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
+ I40E_AQ_RC_EEXIST = 13, /* object already exists */
+ I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
+ I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
+ I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
+ I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
+ I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
+ I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
+ I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
+ I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
+ I40E_AQ_RC_EFBIG = 22, /* File too large */
};
/* Admin Queue command opcodes */
enum i40e_admin_queue_opc {
/* aq commands */
- i40e_aqc_opc_get_version = 0x0001,
- i40e_aqc_opc_driver_version = 0x0002,
- i40e_aqc_opc_queue_shutdown = 0x0003,
- i40e_aqc_opc_set_pf_context = 0x0004,
+ i40e_aqc_opc_get_version = 0x0001,
+ i40e_aqc_opc_driver_version = 0x0002,
+ i40e_aqc_opc_queue_shutdown = 0x0003,
+ i40e_aqc_opc_set_pf_context = 0x0004,
/* resource ownership */
- i40e_aqc_opc_request_resource = 0x0008,
- i40e_aqc_opc_release_resource = 0x0009,
+ i40e_aqc_opc_request_resource = 0x0008,
+ i40e_aqc_opc_release_resource = 0x0009,
- i40e_aqc_opc_list_func_capabilities = 0x000A,
- i40e_aqc_opc_list_dev_capabilities = 0x000B,
+ i40e_aqc_opc_list_func_capabilities = 0x000A,
+ i40e_aqc_opc_list_dev_capabilities = 0x000B,
- i40e_aqc_opc_set_cppm_configuration = 0x0103,
- i40e_aqc_opc_set_arp_proxy_entry = 0x0104,
- i40e_aqc_opc_set_ns_proxy_entry = 0x0105,
+ i40e_aqc_opc_set_cppm_configuration = 0x0103,
+ i40e_aqc_opc_set_arp_proxy_entry = 0x0104,
+ i40e_aqc_opc_set_ns_proxy_entry = 0x0105,
/* LAA */
- i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */
- i40e_aqc_opc_mac_address_read = 0x0107,
- i40e_aqc_opc_mac_address_write = 0x0108,
+ i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */
+ i40e_aqc_opc_mac_address_read = 0x0107,
+ i40e_aqc_opc_mac_address_write = 0x0108,
/* PXE */
- i40e_aqc_opc_clear_pxe_mode = 0x0110,
+ i40e_aqc_opc_clear_pxe_mode = 0x0110,
/* internal switch commands */
- i40e_aqc_opc_get_switch_config = 0x0200,
- i40e_aqc_opc_add_statistics = 0x0201,
- i40e_aqc_opc_remove_statistics = 0x0202,
- i40e_aqc_opc_set_port_parameters = 0x0203,
- i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
-
- i40e_aqc_opc_add_vsi = 0x0210,
- i40e_aqc_opc_update_vsi_parameters = 0x0211,
- i40e_aqc_opc_get_vsi_parameters = 0x0212,
-
- i40e_aqc_opc_add_pv = 0x0220,
- i40e_aqc_opc_update_pv_parameters = 0x0221,
- i40e_aqc_opc_get_pv_parameters = 0x0222,
-
- i40e_aqc_opc_add_veb = 0x0230,
- i40e_aqc_opc_update_veb_parameters = 0x0231,
- i40e_aqc_opc_get_veb_parameters = 0x0232,
-
- i40e_aqc_opc_delete_element = 0x0243,
-
- i40e_aqc_opc_add_macvlan = 0x0250,
- i40e_aqc_opc_remove_macvlan = 0x0251,
- i40e_aqc_opc_add_vlan = 0x0252,
- i40e_aqc_opc_remove_vlan = 0x0253,
- i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
- i40e_aqc_opc_add_tag = 0x0255,
- i40e_aqc_opc_remove_tag = 0x0256,
- i40e_aqc_opc_add_multicast_etag = 0x0257,
- i40e_aqc_opc_remove_multicast_etag = 0x0258,
- i40e_aqc_opc_update_tag = 0x0259,
- i40e_aqc_opc_add_control_packet_filter = 0x025A,
- i40e_aqc_opc_remove_control_packet_filter = 0x025B,
- i40e_aqc_opc_add_cloud_filters = 0x025C,
- i40e_aqc_opc_remove_cloud_filters = 0x025D,
-
- i40e_aqc_opc_add_mirror_rule = 0x0260,
- i40e_aqc_opc_delete_mirror_rule = 0x0261,
+ i40e_aqc_opc_get_switch_config = 0x0200,
+ i40e_aqc_opc_add_statistics = 0x0201,
+ i40e_aqc_opc_remove_statistics = 0x0202,
+ i40e_aqc_opc_set_port_parameters = 0x0203,
+ i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
+
+ i40e_aqc_opc_add_vsi = 0x0210,
+ i40e_aqc_opc_update_vsi_parameters = 0x0211,
+ i40e_aqc_opc_get_vsi_parameters = 0x0212,
+
+ i40e_aqc_opc_add_pv = 0x0220,
+ i40e_aqc_opc_update_pv_parameters = 0x0221,
+ i40e_aqc_opc_get_pv_parameters = 0x0222,
+
+ i40e_aqc_opc_add_veb = 0x0230,
+ i40e_aqc_opc_update_veb_parameters = 0x0231,
+ i40e_aqc_opc_get_veb_parameters = 0x0232,
+
+ i40e_aqc_opc_delete_element = 0x0243,
+
+ i40e_aqc_opc_add_macvlan = 0x0250,
+ i40e_aqc_opc_remove_macvlan = 0x0251,
+ i40e_aqc_opc_add_vlan = 0x0252,
+ i40e_aqc_opc_remove_vlan = 0x0253,
+ i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
+ i40e_aqc_opc_add_tag = 0x0255,
+ i40e_aqc_opc_remove_tag = 0x0256,
+ i40e_aqc_opc_add_multicast_etag = 0x0257,
+ i40e_aqc_opc_remove_multicast_etag = 0x0258,
+ i40e_aqc_opc_update_tag = 0x0259,
+ i40e_aqc_opc_add_control_packet_filter = 0x025A,
+ i40e_aqc_opc_remove_control_packet_filter = 0x025B,
+ i40e_aqc_opc_add_cloud_filters = 0x025C,
+ i40e_aqc_opc_remove_cloud_filters = 0x025D,
+
+ i40e_aqc_opc_add_mirror_rule = 0x0260,
+ i40e_aqc_opc_delete_mirror_rule = 0x0261,
/* DCB commands */
- i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
- i40e_aqc_opc_dcb_updated = 0x0302,
+ i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
+ i40e_aqc_opc_dcb_updated = 0x0302,
/* TX scheduler */
- i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
- i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
- i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
- i40e_aqc_opc_query_vsi_bw_config = 0x0408,
- i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
- i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
-
- i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
- i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
- i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
- i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
- i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
- i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
- i40e_aqc_opc_query_port_ets_config = 0x0419,
- i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
- i40e_aqc_opc_suspend_port_tx = 0x041B,
- i40e_aqc_opc_resume_port_tx = 0x041C,
- i40e_aqc_opc_configure_partition_bw = 0x041D,
+ i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
+ i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
+ i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
+ i40e_aqc_opc_query_vsi_bw_config = 0x0408,
+ i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
+ i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
+
+ i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
+ i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
+ i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
+ i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
+ i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
+ i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
+ i40e_aqc_opc_query_port_ets_config = 0x0419,
+ i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
+ i40e_aqc_opc_suspend_port_tx = 0x041B,
+ i40e_aqc_opc_resume_port_tx = 0x041C,
+ i40e_aqc_opc_configure_partition_bw = 0x041D,
/* hmc */
- i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
- i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
+ i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
+ i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
/* phy commands*/
- i40e_aqc_opc_get_phy_abilities = 0x0600,
- i40e_aqc_opc_set_phy_config = 0x0601,
- i40e_aqc_opc_set_mac_config = 0x0603,
- i40e_aqc_opc_set_link_restart_an = 0x0605,
- i40e_aqc_opc_get_link_status = 0x0607,
- i40e_aqc_opc_set_phy_int_mask = 0x0613,
- i40e_aqc_opc_get_local_advt_reg = 0x0614,
- i40e_aqc_opc_set_local_advt_reg = 0x0615,
- i40e_aqc_opc_get_partner_advt = 0x0616,
- i40e_aqc_opc_set_lb_modes = 0x0618,
- i40e_aqc_opc_get_phy_wol_caps = 0x0621,
- i40e_aqc_opc_set_phy_debug = 0x0622,
- i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
+ i40e_aqc_opc_get_phy_abilities = 0x0600,
+ i40e_aqc_opc_set_phy_config = 0x0601,
+ i40e_aqc_opc_set_mac_config = 0x0603,
+ i40e_aqc_opc_set_link_restart_an = 0x0605,
+ i40e_aqc_opc_get_link_status = 0x0607,
+ i40e_aqc_opc_set_phy_int_mask = 0x0613,
+ i40e_aqc_opc_get_local_advt_reg = 0x0614,
+ i40e_aqc_opc_set_local_advt_reg = 0x0615,
+ i40e_aqc_opc_get_partner_advt = 0x0616,
+ i40e_aqc_opc_set_lb_modes = 0x0618,
+ i40e_aqc_opc_get_phy_wol_caps = 0x0621,
+ i40e_aqc_opc_set_phy_debug = 0x0622,
+ i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
/* NVM commands */
- i40e_aqc_opc_nvm_read = 0x0701,
- i40e_aqc_opc_nvm_erase = 0x0702,
- i40e_aqc_opc_nvm_update = 0x0703,
- i40e_aqc_opc_nvm_config_read = 0x0704,
- i40e_aqc_opc_nvm_config_write = 0x0705,
+ i40e_aqc_opc_nvm_read = 0x0701,
+ i40e_aqc_opc_nvm_erase = 0x0702,
+ i40e_aqc_opc_nvm_update = 0x0703,
+ i40e_aqc_opc_nvm_config_read = 0x0704,
+ i40e_aqc_opc_nvm_config_write = 0x0705,
/* virtualization commands */
- i40e_aqc_opc_send_msg_to_pf = 0x0801,
- i40e_aqc_opc_send_msg_to_vf = 0x0802,
- i40e_aqc_opc_send_msg_to_peer = 0x0803,
+ i40e_aqc_opc_send_msg_to_pf = 0x0801,
+ i40e_aqc_opc_send_msg_to_vf = 0x0802,
+ i40e_aqc_opc_send_msg_to_peer = 0x0803,
/* alternate structure */
- i40e_aqc_opc_alternate_write = 0x0900,
- i40e_aqc_opc_alternate_write_indirect = 0x0901,
- i40e_aqc_opc_alternate_read = 0x0902,
- i40e_aqc_opc_alternate_read_indirect = 0x0903,
- i40e_aqc_opc_alternate_write_done = 0x0904,
- i40e_aqc_opc_alternate_set_mode = 0x0905,
- i40e_aqc_opc_alternate_clear_port = 0x0906,
+ i40e_aqc_opc_alternate_write = 0x0900,
+ i40e_aqc_opc_alternate_write_indirect = 0x0901,
+ i40e_aqc_opc_alternate_read = 0x0902,
+ i40e_aqc_opc_alternate_read_indirect = 0x0903,
+ i40e_aqc_opc_alternate_write_done = 0x0904,
+ i40e_aqc_opc_alternate_set_mode = 0x0905,
+ i40e_aqc_opc_alternate_clear_port = 0x0906,
/* LLDP commands */
- i40e_aqc_opc_lldp_get_mib = 0x0A00,
- i40e_aqc_opc_lldp_update_mib = 0x0A01,
- i40e_aqc_opc_lldp_add_tlv = 0x0A02,
- i40e_aqc_opc_lldp_update_tlv = 0x0A03,
- i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
- i40e_aqc_opc_lldp_stop = 0x0A05,
- i40e_aqc_opc_lldp_start = 0x0A06,
+ i40e_aqc_opc_lldp_get_mib = 0x0A00,
+ i40e_aqc_opc_lldp_update_mib = 0x0A01,
+ i40e_aqc_opc_lldp_add_tlv = 0x0A02,
+ i40e_aqc_opc_lldp_update_tlv = 0x0A03,
+ i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
+ i40e_aqc_opc_lldp_stop = 0x0A05,
+ i40e_aqc_opc_lldp_start = 0x0A06,
/* Tunnel commands */
- i40e_aqc_opc_add_udp_tunnel = 0x0B00,
- i40e_aqc_opc_del_udp_tunnel = 0x0B01,
- i40e_aqc_opc_tunnel_key_structure = 0x0B10,
+ i40e_aqc_opc_add_udp_tunnel = 0x0B00,
+ i40e_aqc_opc_del_udp_tunnel = 0x0B01,
+ i40e_aqc_opc_tunnel_key_structure = 0x0B10,
/* Async Events */
- i40e_aqc_opc_event_lan_overflow = 0x1001,
+ i40e_aqc_opc_event_lan_overflow = 0x1001,
/* OEM commands */
- i40e_aqc_opc_oem_parameter_change = 0xFE00,
- i40e_aqc_opc_oem_device_status_change = 0xFE01,
+ i40e_aqc_opc_oem_parameter_change = 0xFE00,
+ i40e_aqc_opc_oem_device_status_change = 0xFE01,
/* debug commands */
- i40e_aqc_opc_debug_get_deviceid = 0xFF00,
- i40e_aqc_opc_debug_set_mode = 0xFF01,
- i40e_aqc_opc_debug_read_reg = 0xFF03,
- i40e_aqc_opc_debug_write_reg = 0xFF04,
- i40e_aqc_opc_debug_modify_reg = 0xFF07,
- i40e_aqc_opc_debug_dump_internals = 0xFF08,
- i40e_aqc_opc_debug_modify_internals = 0xFF09,
+ i40e_aqc_opc_debug_get_deviceid = 0xFF00,
+ i40e_aqc_opc_debug_set_mode = 0xFF01,
+ i40e_aqc_opc_debug_read_reg = 0xFF03,
+ i40e_aqc_opc_debug_write_reg = 0xFF04,
+ i40e_aqc_opc_debug_modify_reg = 0xFF07,
+ i40e_aqc_opc_debug_dump_internals = 0xFF08,
+ i40e_aqc_opc_debug_modify_internals = 0xFF09,
};
/* command structures and indirect data structures */
/* This macro is used extensively to ensure that command structures are 16
* bytes in length as they have to map to the raw array of that size.
*/
-#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
+#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
/* internal (0x00XX) commands */
/* Send driver version (indirect 0x0002) */
struct i40e_aqc_driver_version {
- u8 driver_major_ver;
- u8 driver_minor_ver;
- u8 driver_build_ver;
- u8 driver_subbuild_ver;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
+ u8 driver_major_ver;
+ u8 driver_minor_ver;
+ u8 driver_build_ver;
+ u8 driver_subbuild_ver;
+ u8 reserved[4];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_driver_version);
/* Queue Shutdown (direct 0x0003) */
struct i40e_aqc_queue_shutdown {
- __le32 driver_unloading;
-#define I40E_AQ_DRIVER_UNLOADING 0x1
- u8 reserved[12];
+ __le32 driver_unloading;
+#define I40E_AQ_DRIVER_UNLOADING 0x1
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
/* Request resource ownership (direct 0x0008)
* Release resource ownership (direct 0x0009)
*/
-#define I40E_AQ_RESOURCE_NVM 1
-#define I40E_AQ_RESOURCE_SDP 2
-#define I40E_AQ_RESOURCE_ACCESS_READ 1
-#define I40E_AQ_RESOURCE_ACCESS_WRITE 2
-#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000
-#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
+#define I40E_AQ_RESOURCE_NVM 1
+#define I40E_AQ_RESOURCE_SDP 2
+#define I40E_AQ_RESOURCE_ACCESS_READ 1
+#define I40E_AQ_RESOURCE_ACCESS_WRITE 2
+#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000
+#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
struct i40e_aqc_request_resource {
- __le16 resource_id;
- __le16 access_type;
- __le32 timeout;
- __le32 resource_number;
- u8 reserved[4];
+ __le16 resource_id;
+ __le16 access_type;
+ __le32 timeout;
+ __le32 resource_number;
+ u8 reserved[4];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_request_resource);
*/
struct i40e_aqc_list_capabilites {
u8 command_flags;
-#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1
+#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1
u8 pf_index;
u8 reserved[2];
__le32 count;
I40E_CHECK_CMD_LENGTH(i40e_aqc_list_capabilites);
struct i40e_aqc_list_capabilities_element_resp {
- __le16 id;
- u8 major_rev;
- u8 minor_rev;
- __le32 number;
- __le32 logical_id;
- __le32 phys_id;
- u8 reserved[16];
+ __le16 id;
+ u8 major_rev;
+ u8 minor_rev;
+ __le32 number;
+ __le32 logical_id;
+ __le32 phys_id;
+ u8 reserved[16];
};
/* list of caps */
-#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001
-#define I40E_AQ_CAP_ID_MNG_MODE 0x0002
-#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003
-#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004
-#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005
-#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006
-#define I40E_AQ_CAP_ID_SRIOV 0x0012
-#define I40E_AQ_CAP_ID_VF 0x0013
-#define I40E_AQ_CAP_ID_VMDQ 0x0014
-#define I40E_AQ_CAP_ID_8021QBG 0x0015
-#define I40E_AQ_CAP_ID_8021QBR 0x0016
-#define I40E_AQ_CAP_ID_VSI 0x0017
-#define I40E_AQ_CAP_ID_DCB 0x0018
-#define I40E_AQ_CAP_ID_FCOE 0x0021
-#define I40E_AQ_CAP_ID_RSS 0x0040
-#define I40E_AQ_CAP_ID_RXQ 0x0041
-#define I40E_AQ_CAP_ID_TXQ 0x0042
-#define I40E_AQ_CAP_ID_MSIX 0x0043
-#define I40E_AQ_CAP_ID_VF_MSIX 0x0044
-#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045
-#define I40E_AQ_CAP_ID_1588 0x0046
-#define I40E_AQ_CAP_ID_IWARP 0x0051
-#define I40E_AQ_CAP_ID_LED 0x0061
-#define I40E_AQ_CAP_ID_SDP 0x0062
-#define I40E_AQ_CAP_ID_MDIO 0x0063
-#define I40E_AQ_CAP_ID_FLEX10 0x00F1
-#define I40E_AQ_CAP_ID_CEM 0x00F2
+#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001
+#define I40E_AQ_CAP_ID_MNG_MODE 0x0002
+#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003
+#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004
+#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005
+#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006
+#define I40E_AQ_CAP_ID_SRIOV 0x0012
+#define I40E_AQ_CAP_ID_VF 0x0013
+#define I40E_AQ_CAP_ID_VMDQ 0x0014
+#define I40E_AQ_CAP_ID_8021QBG 0x0015
+#define I40E_AQ_CAP_ID_8021QBR 0x0016
+#define I40E_AQ_CAP_ID_VSI 0x0017
+#define I40E_AQ_CAP_ID_DCB 0x0018
+#define I40E_AQ_CAP_ID_FCOE 0x0021
+#define I40E_AQ_CAP_ID_RSS 0x0040
+#define I40E_AQ_CAP_ID_RXQ 0x0041
+#define I40E_AQ_CAP_ID_TXQ 0x0042
+#define I40E_AQ_CAP_ID_MSIX 0x0043
+#define I40E_AQ_CAP_ID_VF_MSIX 0x0044
+#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045
+#define I40E_AQ_CAP_ID_1588 0x0046
+#define I40E_AQ_CAP_ID_IWARP 0x0051
+#define I40E_AQ_CAP_ID_LED 0x0061
+#define I40E_AQ_CAP_ID_SDP 0x0062
+#define I40E_AQ_CAP_ID_MDIO 0x0063
+#define I40E_AQ_CAP_ID_FLEX10 0x00F1
+#define I40E_AQ_CAP_ID_CEM 0x00F2
/* Set CPPM Configuration (direct 0x0103) */
struct i40e_aqc_cppm_configuration {
- __le16 command_flags;
-#define I40E_AQ_CPPM_EN_LTRC 0x0800
-#define I40E_AQ_CPPM_EN_DMCTH 0x1000
-#define I40E_AQ_CPPM_EN_DMCTLX 0x2000
-#define I40E_AQ_CPPM_EN_HPTC 0x4000
-#define I40E_AQ_CPPM_EN_DMARC 0x8000
- __le16 ttlx;
- __le32 dmacr;
- __le16 dmcth;
- u8 hptc;
- u8 reserved;
- __le32 pfltrc;
+ __le16 command_flags;
+#define I40E_AQ_CPPM_EN_LTRC 0x0800
+#define I40E_AQ_CPPM_EN_DMCTH 0x1000
+#define I40E_AQ_CPPM_EN_DMCTLX 0x2000
+#define I40E_AQ_CPPM_EN_HPTC 0x4000
+#define I40E_AQ_CPPM_EN_DMARC 0x8000
+ __le16 ttlx;
+ __le32 dmacr;
+ __le16 dmcth;
+ u8 hptc;
+ u8 reserved;
+ __le32 pfltrc;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_cppm_configuration);
/* Set ARP Proxy command / response (indirect 0x0104) */
struct i40e_aqc_arp_proxy_data {
- __le16 command_flags;
-#define I40E_AQ_ARP_INIT_IPV4 0x0008
-#define I40E_AQ_ARP_UNSUP_CTL 0x0010
-#define I40E_AQ_ARP_ENA 0x0020
-#define I40E_AQ_ARP_ADD_IPV4 0x0040
-#define I40E_AQ_ARP_DEL_IPV4 0x0080
- __le16 table_id;
- __le32 pfpm_proxyfc;
- __le32 ip_addr;
- u8 mac_addr[6];
+ __le16 command_flags;
+#define I40E_AQ_ARP_INIT_IPV4 0x0008
+#define I40E_AQ_ARP_UNSUP_CTL 0x0010
+#define I40E_AQ_ARP_ENA 0x0020
+#define I40E_AQ_ARP_ADD_IPV4 0x0040
+#define I40E_AQ_ARP_DEL_IPV4 0x0080
+ __le16 table_id;
+ __le32 pfpm_proxyfc;
+ __le32 ip_addr;
+ u8 mac_addr[6];
};
/* Set NS Proxy Table Entry Command (indirect 0x0105) */
struct i40e_aqc_ns_proxy_data {
- __le16 table_idx_mac_addr_0;
- __le16 table_idx_mac_addr_1;
- __le16 table_idx_ipv6_0;
- __le16 table_idx_ipv6_1;
- __le16 control;
-#define I40E_AQ_NS_PROXY_ADD_0 0x0100
-#define I40E_AQ_NS_PROXY_DEL_0 0x0200
-#define I40E_AQ_NS_PROXY_ADD_1 0x0400
-#define I40E_AQ_NS_PROXY_DEL_1 0x0800
-#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x1000
-#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x2000
-#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x4000
-#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x8000
-#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0001
-#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0002
-#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0004
- u8 mac_addr_0[6];
- u8 mac_addr_1[6];
- u8 local_mac_addr[6];
- u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
- u8 ipv6_addr_1[16];
+ __le16 table_idx_mac_addr_0;
+ __le16 table_idx_mac_addr_1;
+ __le16 table_idx_ipv6_0;
+ __le16 table_idx_ipv6_1;
+ __le16 control;
+#define I40E_AQ_NS_PROXY_ADD_0 0x0100
+#define I40E_AQ_NS_PROXY_DEL_0 0x0200
+#define I40E_AQ_NS_PROXY_ADD_1 0x0400
+#define I40E_AQ_NS_PROXY_DEL_1 0x0800
+#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x1000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x2000
+#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x4000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x8000
+#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0001
+#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0002
+#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0004
+ u8 mac_addr_0[6];
+ u8 mac_addr_1[6];
+ u8 local_mac_addr[6];
+ u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
+ u8 ipv6_addr_1[16];
};
/* Manage LAA Command (0x0106) - obsolete */
struct i40e_aqc_mng_laa {
__le16 command_flags;
-#define I40E_AQ_LAA_FLAG_WR 0x8000
- u8 reserved[2];
- __le32 sal;
- __le16 sah;
- u8 reserved2[6];
+#define I40E_AQ_LAA_FLAG_WR 0x8000
+ u8 reserved[2];
+ __le32 sal;
+ __le16 sah;
+ u8 reserved2[6];
};
/* Manage MAC Address Read Command (indirect 0x0107) */
struct i40e_aqc_mac_address_read {
__le16 command_flags;
-#define I40E_AQC_LAN_ADDR_VALID 0x10
-#define I40E_AQC_SAN_ADDR_VALID 0x20
-#define I40E_AQC_PORT_ADDR_VALID 0x40
-#define I40E_AQC_WOL_ADDR_VALID 0x80
-#define I40E_AQC_ADDR_VALID_MASK 0xf0
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+#define I40E_AQC_LAN_ADDR_VALID 0x10
+#define I40E_AQC_SAN_ADDR_VALID 0x20
+#define I40E_AQC_PORT_ADDR_VALID 0x40
+#define I40E_AQC_WOL_ADDR_VALID 0x80
+#define I40E_AQC_ADDR_VALID_MASK 0xf0
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_read);
/* Manage MAC Address Write Command (0x0108) */
struct i40e_aqc_mac_address_write {
- __le16 command_flags;
-#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000
-#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000
-#define I40E_AQC_WRITE_TYPE_PORT 0x8000
-#define I40E_AQC_WRITE_TYPE_MASK 0xc000
- __le16 mac_sah;
- __le32 mac_sal;
- u8 reserved[8];
+ __le16 command_flags;
+#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000
+#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000
+#define I40E_AQC_WRITE_TYPE_PORT 0x8000
+#define I40E_AQC_WRITE_TYPE_MASK 0xc000
+ __le16 mac_sah;
+ __le32 mac_sal;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_write);
* command
*/
struct i40e_aqc_switch_seid {
- __le16 seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 seid;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_switch_seid);
* uses i40e_aqc_switch_seid for the descriptor
*/
struct i40e_aqc_get_switch_config_header_resp {
- __le16 num_reported;
- __le16 num_total;
- u8 reserved[12];
+ __le16 num_reported;
+ __le16 num_total;
+ u8 reserved[12];
};
struct i40e_aqc_switch_config_element_resp {
- u8 element_type;
-#define I40E_AQ_SW_ELEM_TYPE_MAC 1
-#define I40E_AQ_SW_ELEM_TYPE_PF 2
-#define I40E_AQ_SW_ELEM_TYPE_VF 3
-#define I40E_AQ_SW_ELEM_TYPE_EMP 4
-#define I40E_AQ_SW_ELEM_TYPE_BMC 5
-#define I40E_AQ_SW_ELEM_TYPE_PV 16
-#define I40E_AQ_SW_ELEM_TYPE_VEB 17
-#define I40E_AQ_SW_ELEM_TYPE_PA 18
-#define I40E_AQ_SW_ELEM_TYPE_VSI 19
- u8 revision;
-#define I40E_AQ_SW_ELEM_REV_1 1
- __le16 seid;
- __le16 uplink_seid;
- __le16 downlink_seid;
- u8 reserved[3];
- u8 connection_type;
-#define I40E_AQ_CONN_TYPE_REGULAR 0x1
-#define I40E_AQ_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_CONN_TYPE_CASCADED 0x3
- __le16 scheduler_id;
- __le16 element_info;
+ u8 element_type;
+#define I40E_AQ_SW_ELEM_TYPE_MAC 1
+#define I40E_AQ_SW_ELEM_TYPE_PF 2
+#define I40E_AQ_SW_ELEM_TYPE_VF 3
+#define I40E_AQ_SW_ELEM_TYPE_EMP 4
+#define I40E_AQ_SW_ELEM_TYPE_BMC 5
+#define I40E_AQ_SW_ELEM_TYPE_PV 16
+#define I40E_AQ_SW_ELEM_TYPE_VEB 17
+#define I40E_AQ_SW_ELEM_TYPE_PA 18
+#define I40E_AQ_SW_ELEM_TYPE_VSI 19
+ u8 revision;
+#define I40E_AQ_SW_ELEM_REV_1 1
+ __le16 seid;
+ __le16 uplink_seid;
+ __le16 downlink_seid;
+ u8 reserved[3];
+ u8 connection_type;
+#define I40E_AQ_CONN_TYPE_REGULAR 0x1
+#define I40E_AQ_CONN_TYPE_DEFAULT 0x2
+#define I40E_AQ_CONN_TYPE_CASCADED 0x3
+ __le16 scheduler_id;
+ __le16 element_info;
};
/* Get Switch Configuration (indirect 0x0200)
* the first in the array is the header, remainder are elements
*/
struct i40e_aqc_get_switch_config_resp {
- struct i40e_aqc_get_switch_config_header_resp header;
- struct i40e_aqc_switch_config_element_resp element[1];
+ struct i40e_aqc_get_switch_config_header_resp header;
+ struct i40e_aqc_switch_config_element_resp element[1];
};
/* Add Statistics (direct 0x0201)
* Remove Statistics (direct 0x0202)
*/
struct i40e_aqc_add_remove_statistics {
- __le16 seid;
- __le16 vlan;
- __le16 stat_index;
- u8 reserved[10];
+ __le16 seid;
+ __le16 vlan;
+ __le16 stat_index;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_statistics);
/* Set Port Parameters command (direct 0x0203) */
struct i40e_aqc_set_port_parameters {
- __le16 command_flags;
-#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1
-#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
-#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
- __le16 bad_frame_vsi;
- __le16 default_seid; /* reserved for command */
- u8 reserved[10];
+ __le16 command_flags;
+#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1
+#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
+#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
+ __le16 bad_frame_vsi;
+ __le16 default_seid; /* reserved for command */
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_port_parameters);
/* Get Switch Resource Allocation (indirect 0x0204) */
struct i40e_aqc_get_switch_resource_alloc {
- u8 num_entries; /* reserved for command */
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
+ u8 num_entries; /* reserved for command */
+ u8 reserved[7];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_resource_alloc);
/* expect an array of these structs in the response buffer */
struct i40e_aqc_switch_resource_alloc_element_resp {
- u8 resource_type;
-#define I40E_AQ_RESOURCE_TYPE_VEB 0x0
-#define I40E_AQ_RESOURCE_TYPE_VSI 0x1
-#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2
-#define I40E_AQ_RESOURCE_TYPE_STAG 0x3
-#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4
-#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5
-#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6
-#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7
-#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8
-#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9
-#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA
-#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB
-#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC
-#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD
-#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF
-#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10
-#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11
-#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12
-#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13
- u8 reserved1;
- __le16 guaranteed;
- __le16 total;
- __le16 used;
- __le16 total_unalloced;
- u8 reserved2[6];
+ u8 resource_type;
+#define I40E_AQ_RESOURCE_TYPE_VEB 0x0
+#define I40E_AQ_RESOURCE_TYPE_VSI 0x1
+#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2
+#define I40E_AQ_RESOURCE_TYPE_STAG 0x3
+#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4
+#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5
+#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6
+#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7
+#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8
+#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9
+#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA
+#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB
+#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC
+#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD
+#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF
+#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10
+#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11
+#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12
+#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13
+ u8 reserved1;
+ __le16 guaranteed;
+ __le16 total;
+ __le16 used;
+ __le16 total_unalloced;
+ u8 reserved2[6];
};
/* Add VSI (indirect 0x0210)
* uses the same completion and data structure as Add VSI
*/
struct i40e_aqc_add_get_update_vsi {
- __le16 uplink_seid;
- u8 connection_type;
-#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1
-#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3
- u8 reserved1;
- u8 vf_id;
- u8 reserved2;
- __le16 vsi_flags;
-#define I40E_AQ_VSI_TYPE_SHIFT 0x0
-#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
-#define I40E_AQ_VSI_TYPE_VF 0x0
-#define I40E_AQ_VSI_TYPE_VMDQ2 0x1
-#define I40E_AQ_VSI_TYPE_PF 0x2
-#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3
-#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4
- __le32 addr_high;
- __le32 addr_low;
+ __le16 uplink_seid;
+ u8 connection_type;
+#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1
+#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2
+#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3
+ u8 reserved1;
+ u8 vf_id;
+ u8 reserved2;
+ __le16 vsi_flags;
+#define I40E_AQ_VSI_TYPE_SHIFT 0x0
+#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
+#define I40E_AQ_VSI_TYPE_VF 0x0
+#define I40E_AQ_VSI_TYPE_VMDQ2 0x1
+#define I40E_AQ_VSI_TYPE_PF 0x2
+#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3
+#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi);
struct i40e_aqc_vsi_properties_data {
/* first 96 byte are written by SW */
- __le16 valid_sections;
-#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
-#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
-#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
-#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
-#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
-#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
-#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
-#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
-#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
-#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
+ __le16 valid_sections;
+#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
+#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
+#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
+#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
+#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
+#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
+#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
+#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
+#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
+#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
/* switch section */
- __le16 switch_id; /* 12bit id combined with flags below */
-#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
-#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
-#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
-#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
-#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
- u8 sw_reserved[2];
+ __le16 switch_id; /* 12bit id combined with flags below */
+#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
+#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
+#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
+#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
+#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
+ u8 sw_reserved[2];
/* security section */
- u8 sec_flags;
-#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
- u8 sec_reserved;
+ u8 sec_flags;
+#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
+ u8 sec_reserved;
/* VLAN section */
- __le16 pvid; /* VLANS include priority bits */
- __le16 fcoe_pvid;
- u8 port_vlan_flags;
-#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
-#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
- I40E_AQ_VSI_PVLAN_MODE_SHIFT)
-#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
-#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
-#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
-#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
-#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
-#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
- I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
-#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
-#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
- u8 pvlan_reserved[3];
+ __le16 pvid; /* VLANS include priority bits */
+ __le16 fcoe_pvid;
+ u8 port_vlan_flags;
+#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
+#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
+ I40E_AQ_VSI_PVLAN_MODE_SHIFT)
+#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
+#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
+#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
+#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
+#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
+#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
+ I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
+#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
+#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
+ u8 pvlan_reserved[3];
/* ingress egress up sections */
- __le32 ingress_table; /* bitmap, 3 bits per up */
-#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
-#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
-#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
-#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
-#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
-#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
-#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
-#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
-#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
- __le32 egress_table; /* same defines as for ingress table */
+ __le32 ingress_table; /* bitmap, 3 bits per up */
+#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
+#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
+#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
+#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
+#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
+#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
+#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
+#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
+#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
+ __le32 egress_table; /* same defines as for ingress table */
/* cascaded PV section */
- __le16 cas_pv_tag;
- u8 cas_pv_flags;
-#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
- I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
-#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
-#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
-#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
-#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
-#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
- u8 cas_pv_reserved;
+ __le16 cas_pv_tag;
+ u8 cas_pv_flags;
+#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
+ I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
+#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
+#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
+#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
+#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
+#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
+ u8 cas_pv_reserved;
/* queue mapping section */
- __le16 mapping_flags;
-#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
-#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
- __le16 queue_mapping[16];
-#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
-#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
- __le16 tc_mapping[8];
-#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
-#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
- I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
-#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
-#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
- I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
+ __le16 mapping_flags;
+#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
+#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
+ __le16 queue_mapping[16];
+#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
+#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
+ __le16 tc_mapping[8];
+#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
+#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
+ I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
+#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
+ I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
/* queueing option section */
- u8 queueing_opt_flags;
-#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
-#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
- u8 queueing_opt_reserved[3];
+ u8 queueing_opt_flags;
+#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
+#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
+ u8 queueing_opt_reserved[3];
/* scheduler section */
- u8 up_enable_bits;
- u8 sched_reserved;
+ u8 up_enable_bits;
+ u8 sched_reserved;
/* outer up section */
- __le32 outer_up_table; /* same structure and defines as ingress table */
- u8 cmd_reserved[8];
+ __le32 outer_up_table; /* same structure and defines as ingress tbl */
+ u8 cmd_reserved[8];
/* last 32 bytes are written by FW */
- __le16 qs_handle[8];
+ __le16 qs_handle[8];
#define I40E_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
- __le16 stat_counter_idx;
- __le16 sched_id;
- u8 resp_reserved[12];
+ __le16 stat_counter_idx;
+ __le16 sched_id;
+ u8 resp_reserved[12];
};
I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
* (IS_CTRL_PORT only works on add PV)
*/
struct i40e_aqc_add_update_pv {
- __le16 command_flags;
-#define I40E_AQC_PV_FLAG_PV_TYPE 0x1
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4
-#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8
- __le16 uplink_seid;
- __le16 connected_seid;
- u8 reserved[10];
+ __le16 command_flags;
+#define I40E_AQC_PV_FLAG_PV_TYPE 0x1
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4
+#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8
+ __le16 uplink_seid;
+ __le16 connected_seid;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv);
struct i40e_aqc_add_update_pv_completion {
/* reserved for update; for add also encodes error if rc == ENOSPC */
- __le16 pv_seid;
-#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1
-#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8
- u8 reserved[14];
+ __le16 pv_seid;
+#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1
+#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2
+#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4
+#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv_completion);
*/
struct i40e_aqc_get_pv_params_completion {
- __le16 seid;
- __le16 default_stag;
- __le16 pv_flags; /* same flags as add_pv */
-#define I40E_AQC_GET_PV_PV_TYPE 0x1
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4
- u8 reserved[8];
- __le16 default_port_seid;
+ __le16 seid;
+ __le16 default_stag;
+ __le16 pv_flags; /* same flags as add_pv */
+#define I40E_AQC_GET_PV_PV_TYPE 0x1
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4
+ u8 reserved[8];
+ __le16 default_port_seid;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_pv_params_completion);
/* Add VEB (direct 0x0230) */
struct i40e_aqc_add_veb {
- __le16 uplink_seid;
- __le16 downlink_seid;
- __le16 veb_flags;
-#define I40E_AQC_ADD_VEB_FLOATING 0x1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \
+ __le16 uplink_seid;
+ __le16 downlink_seid;
+ __le16 veb_flags;
+#define I40E_AQC_ADD_VEB_FLOATING 0x1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \
I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8
- u8 enable_tcs;
- u8 reserved[9];
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8
+ u8 enable_tcs;
+ u8 reserved[9];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb);
struct i40e_aqc_add_veb_completion {
- u8 reserved[6];
- __le16 switch_seid;
+ u8 reserved[6];
+ __le16 switch_seid;
/* also encodes error if rc == ENOSPC; codes are the same as add_pv */
- __le16 veb_seid;
-#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1
-#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
+ __le16 veb_seid;
+#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1
+#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2
+#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4
+#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb_completion);
* uses i40e_aqc_switch_seid for the descriptor
*/
struct i40e_aqc_get_veb_parameters_completion {
- __le16 seid;
- __le16 switch_id;
- __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
- u8 reserved[4];
+ __le16 seid;
+ __le16 switch_id;
+ __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
+ u8 reserved[4];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
/* used for the command for most vlan commands */
struct i40e_aqc_macvlan {
- __le16 num_addresses;
- __le16 seid[3];
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 num_addresses;
+ __le16 seid[3];
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
-#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000
- __le32 addr_high;
- __le32 addr_low;
+#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_macvlan);
/* indirect data for command and response */
struct i40e_aqc_add_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- __le16 flags;
-#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001
-#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002
-#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004
-#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008
- __le16 queue_number;
-#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \
+ u8 mac_addr[6];
+ __le16 vlan_tag;
+ __le16 flags;
+#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001
+#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002
+#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004
+#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008
+ __le16 queue_number;
+#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0
+#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \
I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
/* response section */
- u8 match_method;
-#define I40E_AQC_MM_PERFECT_MATCH 0x01
-#define I40E_AQC_MM_HASH_MATCH 0x02
-#define I40E_AQC_MM_ERR_NO_RES 0xFF
- u8 reserved1[3];
+ u8 match_method;
+#define I40E_AQC_MM_PERFECT_MATCH 0x01
+#define I40E_AQC_MM_HASH_MATCH 0x02
+#define I40E_AQC_MM_ERR_NO_RES 0xFF
+ u8 reserved1[3];
};
struct i40e_aqc_add_remove_macvlan_completion {
*/
struct i40e_aqc_remove_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- u8 flags;
-#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01
-#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02
-#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08
-#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10
- u8 reserved[3];
+ u8 mac_addr[6];
+ __le16 vlan_tag;
+ u8 flags;
+#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01
+#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02
+#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08
+#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10
+ u8 reserved[3];
/* reply section */
- u8 error_code;
-#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF
- u8 reply_reserved[3];
+ u8 error_code;
+#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0
+#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF
+ u8 reply_reserved[3];
};
/* Add VLAN (indirect 0x0252)
* use the generic i40e_aqc_macvlan for the command
*/
struct i40e_aqc_add_remove_vlan_element_data {
- __le16 vlan_tag;
- u8 vlan_flags;
+ __le16 vlan_tag;
+ u8 vlan_flags;
/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_LOCAL 0x1
-#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1
-#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << \
- I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
-#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0
-#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2
-#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4
-#define I40E_AQC_VLAN_PTYPE_SHIFT 3
-#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
-#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0
-#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8
-#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10
-#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18
+#define I40E_AQC_ADD_VLAN_LOCAL 0x1
+#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1
+#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
+#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0
+#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2
+#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4
+#define I40E_AQC_VLAN_PTYPE_SHIFT 3
+#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
+#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0
+#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8
+#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10
+#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18
/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_ALL 0x1
- u8 reserved;
- u8 result;
+#define I40E_AQC_REMOVE_VLAN_ALL 0x1
+ u8 reserved;
+ u8 result;
/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_SUCCESS 0x0
-#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE
-#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
+#define I40E_AQC_ADD_VLAN_SUCCESS 0x0
+#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE
+#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF
- u8 reserved1[3];
+#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0
+#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF
+ u8 reserved1[3];
};
struct i40e_aqc_add_remove_vlan_completion {
- u8 reserved[4];
- __le16 vlans_used;
- __le16 vlans_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[4];
+ __le16 vlans_used;
+ __le16 vlans_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
/* Set VSI Promiscuous Modes (direct 0x0254) */
struct i40e_aqc_set_vsi_promiscuous_modes {
- __le16 promiscuous_flags;
- __le16 valid_flags;
+ __le16 promiscuous_flags;
+ __le16 valid_flags;
/* flags used for both fields above */
-#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01
-#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02
-#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04
-#define I40E_AQC_SET_VSI_DEFAULT 0x08
-#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10
- __le16 seid;
-#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF
- __le16 vlan_tag;
-#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000
- u8 reserved[8];
+#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01
+#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02
+#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04
+#define I40E_AQC_SET_VSI_DEFAULT 0x08
+#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10
+ __le16 seid;
+#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF
+ __le16 vlan_tag;
+#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_vsi_promiscuous_modes);
* Uses generic i40e_aqc_add_remove_tag_completion for completion
*/
struct i40e_aqc_add_tag {
- __le16 flags;
-#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001
- __le16 seid;
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 flags;
+#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001
+ __le16 seid;
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- __le16 queue_number;
- u8 reserved[8];
+ __le16 tag;
+ __le16 queue_number;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_tag);
struct i40e_aqc_add_remove_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
+ u8 reserved[12];
+ __le16 tags_used;
+ __le16 tags_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_tag_completion);
* Uses generic i40e_aqc_add_remove_tag_completion for completion
*/
struct i40e_aqc_remove_tag {
- __le16 seid;
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 seid;
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- u8 reserved[12];
+ __le16 tag;
+ u8 reserved[12];
};
/* Add multicast E-Tag (direct 0x0257)
* and no external data
*/
struct i40e_aqc_add_remove_mcast_etag {
- __le16 pv_seid;
- __le16 etag;
- u8 num_unicast_etags;
- u8 reserved[3];
- __le32 addr_high; /* address of array of 2-byte s-tags */
- __le32 addr_low;
+ __le16 pv_seid;
+ __le16 etag;
+ u8 num_unicast_etags;
+ u8 reserved[3];
+ __le32 addr_high; /* address of array of 2-byte s-tags */
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag);
struct i40e_aqc_add_remove_mcast_etag_completion {
- u8 reserved[4];
- __le16 mcast_etags_used;
- __le16 mcast_etags_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[4];
+ __le16 mcast_etags_used;
+ __le16 mcast_etags_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
/* Update S/E-Tag (direct 0x0259) */
struct i40e_aqc_update_tag {
- __le16 seid;
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
+ __le16 seid;
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 old_tag;
- __le16 new_tag;
- u8 reserved[10];
+ __le16 old_tag;
+ __le16 new_tag;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag);
struct i40e_aqc_update_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
+ u8 reserved[12];
+ __le16 tags_used;
+ __le16 tags_free;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag_completion);
* and the generic direct completion structure
*/
struct i40e_aqc_add_remove_control_packet_filter {
- u8 mac[6];
- __le16 etype;
- __le16 flags;
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000
- __le16 seid;
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \
+ u8 mac[6];
+ __le16 etype;
+ __le16 flags;
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000
+ __le16 seid;
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT)
- __le16 queue;
- u8 reserved[2];
+ __le16 queue;
+ u8 reserved[2];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter);
struct i40e_aqc_add_remove_control_packet_filter_completion {
- __le16 mac_etype_used;
- __le16 etype_used;
- __le16 mac_etype_free;
- __le16 etype_free;
- u8 reserved[8];
+ __le16 mac_etype_used;
+ __le16 etype_used;
+ __le16 mac_etype_free;
+ __le16 etype_free;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter_completion);
* and the generic indirect completion structure
*/
struct i40e_aqc_add_remove_cloud_filters {
- u8 num_filters;
- u8 reserved;
- __le16 seid;
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \
+ u8 num_filters;
+ u8 reserved;
+ __le16 seid;
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \
I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
- u8 reserved2[4];
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved2[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
struct i40e_aqc_add_remove_cloud_filters_element_data {
- u8 outer_mac[6];
- u8 inner_mac[6];
- __le16 inner_vlan;
+ u8 outer_mac[6];
+ u8 inner_mac[6];
+ __le16 inner_vlan;
union {
struct {
u8 reserved[12];
u8 data[16];
} v6;
} ipaddr;
- __le16 flags;
-#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
+ __le16 flags;
+#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
-#define I40E_AQC_ADD_CLOUD_FILTER_OIP_GRE 0x0002
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_GRE 0x0004
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_VNL 0x0007
/* 0x0000 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
+#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
/* 0x0002 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004
/* 0x0005 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006
/* 0x0007 reserved */
/* 0x0008 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B
-#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C
-
-#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080
-#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6
-#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100
-
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN 0
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
-
- __le32 tenant_id;
- u8 reserved[4];
- __le16 queue_number;
-#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
- I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
- u8 reserved2[14];
+#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A
+#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B
+#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080
+#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6
+#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100
+
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN 0
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
+
+ __le32 tenant_id;
+ u8 reserved[4];
+ __le16 queue_number;
+#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
+#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
+ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
+ u8 reserved2[14];
/* response section */
- u8 allocation_result;
-#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0
-#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF
- u8 response_reserved[7];
+ u8 allocation_result;
+#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0
+#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF
+ u8 response_reserved[7];
};
struct i40e_aqc_remove_cloud_filters_completion {
struct i40e_aqc_add_delete_mirror_rule {
__le16 seid;
__le16 rule_type;
-#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0
-#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \
+#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0
+#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \
I40E_AQC_MIRROR_RULE_TYPE_SHIFT)
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2
-#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2
+#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5
__le16 num_entries;
__le16 destination; /* VSI for add, rule id for delete */
__le32 addr_high; /* address of array of 2-byte VSI or VLAN ids */
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule);
struct i40e_aqc_add_delete_mirror_rule_completion {
- u8 reserved[2];
- __le16 rule_id; /* only used on add */
- __le16 mirror_rules_used;
- __le16 mirror_rules_free;
- __le32 addr_high;
- __le32 addr_low;
+ u8 reserved[2];
+ __le16 rule_id; /* only used on add */
+ __le16 mirror_rules_used;
+ __le16 mirror_rules_free;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
* the command and response use the same descriptor structure
*/
struct i40e_aqc_pfc_ignore {
- u8 tc_bitmap;
- u8 command_flags; /* unused on response */
-#define I40E_AQC_PFC_IGNORE_SET 0x80
-#define I40E_AQC_PFC_IGNORE_CLEAR 0x0
- u8 reserved[14];
+ u8 tc_bitmap;
+ u8 command_flags; /* unused on response */
+#define I40E_AQC_PFC_IGNORE_SET 0x80
+#define I40E_AQC_PFC_IGNORE_CLEAR 0x0
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_pfc_ignore);
* this generic struct to pass the SEID in param0
*/
struct i40e_aqc_tx_sched_ind {
- __le16 vsi_seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 vsi_seid;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_tx_sched_ind);
/* Configure VSI BW limits (direct 0x0400) */
struct i40e_aqc_configure_vsi_bw_limit {
- __le16 vsi_seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_credit; /* 0-3, limit = 2^max */
- u8 reserved2[7];
+ __le16 vsi_seid;
+ u8 reserved[2];
+ __le16 credit;
+ u8 reserved1[2];
+ u8 max_credit; /* 0-3, limit = 2^max */
+ u8 reserved2[7];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_vsi_bw_limit);
* responds with i40e_aqc_qs_handles_resp
*/
struct i40e_aqc_configure_vsi_ets_sla_bw_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
+ u8 tc_valid_bits;
+ u8 reserved[15];
+ __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
+ __le16 tc_bw_max[2];
+ u8 reserved1[28];
};
/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
* responds with i40e_aqc_qs_handles_resp
*/
struct i40e_aqc_configure_vsi_tc_bw_data {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 tc_bw_credits[8];
- u8 reserved1[4];
- __le16 qs_handles[8];
+ u8 tc_valid_bits;
+ u8 reserved[3];
+ u8 tc_bw_credits[8];
+ u8 reserved1[4];
+ __le16 qs_handles[8];
};
/* Query vsi bw configuration (indirect 0x0408) */
struct i40e_aqc_query_vsi_bw_config_resp {
- u8 tc_valid_bits;
- u8 tc_suspended_bits;
- u8 reserved[14];
- __le16 qs_handles[8];
- u8 reserved1[4];
- __le16 port_bw_limit;
- u8 reserved2[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved3[23];
+ u8 tc_valid_bits;
+ u8 tc_suspended_bits;
+ u8 reserved[14];
+ __le16 qs_handles[8];
+ u8 reserved1[4];
+ __le16 port_bw_limit;
+ u8 reserved2[2];
+ u8 max_bw; /* 0-3, limit = 2^max */
+ u8 reserved3[23];
};
/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
struct i40e_aqc_query_vsi_ets_sla_config_resp {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 share_credits[8];
- __le16 credits[8];
+ u8 tc_valid_bits;
+ u8 reserved[3];
+ u8 share_credits[8];
+ __le16 credits[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
+ __le16 tc_bw_max[2];
};
/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
struct i40e_aqc_configure_switching_comp_bw_limit {
- __le16 seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved2[7];
+ __le16 seid;
+ u8 reserved[2];
+ __le16 credit;
+ u8 reserved1[2];
+ u8 max_bw; /* 0-3, limit = 2^max */
+ u8 reserved2[7];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_switching_comp_bw_limit);
* Disable Physical Port ETS (indirect 0x0415)
*/
struct i40e_aqc_configure_switching_comp_ets_data {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 seepage;
-#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1
- u8 tc_strict_priority_flags;
- u8 reserved1[17];
- u8 tc_bw_share_credits[8];
- u8 reserved2[96];
+ u8 reserved[4];
+ u8 tc_valid_bits;
+ u8 seepage;
+#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1
+ u8 tc_strict_priority_flags;
+ u8 reserved1[17];
+ u8 tc_bw_share_credits[8];
+ u8 reserved2[96];
};
/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credit[8];
+ u8 tc_valid_bits;
+ u8 reserved[15];
+ __le16 tc_bw_credit[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
+ __le16 tc_bw_max[2];
+ u8 reserved1[28];
};
/* Configure Switching Component Bandwidth Allocation per Tc
* (indirect 0x0417)
*/
struct i40e_aqc_configure_switching_comp_bw_config_data {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits; /* bool */
- u8 tc_bw_share_credits[8];
- u8 reserved1[20];
+ u8 tc_valid_bits;
+ u8 reserved[2];
+ u8 absolute_credits; /* bool */
+ u8 tc_bw_share_credits[8];
+ u8 reserved1[20];
};
/* Query Switching Component Configuration (indirect 0x0418) */
struct i40e_aqc_query_switching_comp_ets_config_resp {
- u8 tc_valid_bits;
- u8 reserved[35];
- __le16 port_bw_limit;
- u8 reserved1[2];
- u8 tc_bw_max; /* 0-3, limit = 2^max */
- u8 reserved2[23];
+ u8 tc_valid_bits;
+ u8 reserved[35];
+ __le16 port_bw_limit;
+ u8 reserved1[2];
+ u8 tc_bw_max; /* 0-3, limit = 2^max */
+ u8 reserved2[23];
};
/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
struct i40e_aqc_query_port_ets_config_resp {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 reserved1;
- u8 tc_strict_priority_bits;
- u8 reserved2;
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
+ u8 reserved[4];
+ u8 tc_valid_bits;
+ u8 reserved1;
+ u8 tc_strict_priority_bits;
+ u8 reserved2;
+ u8 tc_bw_share_credits[8];
+ __le16 tc_bw_limits[8];
/* 4 bits per tc 0-7, 4th bit reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved3[32];
+ __le16 tc_bw_max[2];
+ u8 reserved3[32];
};
/* Query Switching Component Bandwidth Allocation per Traffic Type
* (indirect 0x041A)
*/
struct i40e_aqc_query_switching_comp_bw_config_resp {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits_enable; /* bool */
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
+ u8 tc_valid_bits;
+ u8 reserved[2];
+ u8 absolute_credits_enable; /* bool */
+ u8 tc_bw_share_credits[8];
+ __le16 tc_bw_limits[8];
/* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
+ __le16 tc_bw_max[2];
};
/* Suspend/resume port TX traffic
* (indirect 0x041D)
*/
struct i40e_aqc_configure_partition_bw_data {
- __le16 pf_valid_bits;
- u8 min_bw[16]; /* guaranteed bandwidth */
- u8 max_bw[16]; /* bandwidth limit */
+ __le16 pf_valid_bits;
+ u8 min_bw[16]; /* guaranteed bandwidth */
+ u8 max_bw[16]; /* bandwidth limit */
};
/* Get and set the active HMC resource profile and status.
* (direct 0x0500) and (direct 0x0501)
*/
struct i40e_aq_get_set_hmc_resource_profile {
- u8 pm_profile;
- u8 pe_vf_enabled;
- u8 reserved[14];
+ u8 pm_profile;
+ u8 pe_vf_enabled;
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_get_set_hmc_resource_profile);
enum i40e_aq_hmc_profile {
/* I40E_HMC_PROFILE_NO_CHANGE = 0, reserved */
- I40E_HMC_PROFILE_DEFAULT = 1,
- I40E_HMC_PROFILE_FAVOR_VF = 2,
- I40E_HMC_PROFILE_EQUAL = 3,
+ I40E_HMC_PROFILE_DEFAULT = 1,
+ I40E_HMC_PROFILE_FAVOR_VF = 2,
+ I40E_HMC_PROFILE_EQUAL = 3,
};
-#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_PM_MASK 0xF
-#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_COUNT_MASK 0x3F
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_PM_MASK 0xF
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_COUNT_MASK 0x3F
/* Get PHY Abilities (indirect 0x0600) uses the generic indirect struct */
/* set in param0 for get phy abilities to report qualified modules */
-#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001
-#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002
+#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001
+#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002
enum i40e_aq_phy_type {
I40E_PHY_TYPE_SGMII = 0x0,
};
struct i40e_aq_get_phy_abilities_resp {
- __le32 phy_type; /* bitmap using the above enum for offsets */
- u8 link_speed; /* bitmap using the above enum bit patterns */
- u8 abilities;
-#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01
-#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02
-#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04
-#define I40E_AQ_PHY_LINK_ENABLED 0x08
-#define I40E_AQ_PHY_AN_ENABLED 0x10
-#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20
- __le16 eee_capability;
-#define I40E_AQ_EEE_100BASE_TX 0x0002
-#define I40E_AQ_EEE_1000BASE_T 0x0004
-#define I40E_AQ_EEE_10GBASE_T 0x0008
-#define I40E_AQ_EEE_1000BASE_KX 0x0010
-#define I40E_AQ_EEE_10GBASE_KX4 0x0020
-#define I40E_AQ_EEE_10GBASE_KR 0x0040
- __le32 eeer_val;
- u8 d3_lpan;
-#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01
- u8 reserved[3];
- u8 phy_id[4];
- u8 module_type[3];
- u8 qualified_module_count;
-#define I40E_AQ_PHY_MAX_QMS 16
- struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
+ __le32 phy_type; /* bitmap using the above enum for offsets */
+ u8 link_speed; /* bitmap using the above enum bit patterns */
+ u8 abilities;
+#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01
+#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02
+#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04
+#define I40E_AQ_PHY_LINK_ENABLED 0x08
+#define I40E_AQ_PHY_AN_ENABLED 0x10
+#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20
+ __le16 eee_capability;
+#define I40E_AQ_EEE_100BASE_TX 0x0002
+#define I40E_AQ_EEE_1000BASE_T 0x0004
+#define I40E_AQ_EEE_10GBASE_T 0x0008
+#define I40E_AQ_EEE_1000BASE_KX 0x0010
+#define I40E_AQ_EEE_10GBASE_KX4 0x0020
+#define I40E_AQ_EEE_10GBASE_KR 0x0040
+ __le32 eeer_val;
+ u8 d3_lpan;
+#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01
+ u8 reserved[3];
+ u8 phy_id[4];
+ u8 module_type[3];
+ u8 qualified_module_count;
+#define I40E_AQ_PHY_MAX_QMS 16
+ struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
};
/* Set PHY Config (direct 0x0601) */
struct i40e_aq_set_phy_config { /* same bits as above in all */
- __le32 phy_type;
- u8 link_speed;
- u8 abilities;
+ __le32 phy_type;
+ u8 link_speed;
+ u8 abilities;
/* bits 0-2 use the values from get_phy_abilities_resp */
#define I40E_AQ_PHY_ENABLE_LINK 0x08
#define I40E_AQ_PHY_ENABLE_AN 0x10
#define I40E_AQ_PHY_ENABLE_ATOMIC_LINK 0x20
- __le16 eee_capability;
- __le32 eeer;
- u8 low_power_ctrl;
- u8 reserved[3];
+ __le16 eee_capability;
+ __le32 eeer;
+ u8 low_power_ctrl;
+ u8 reserved[3];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_set_phy_config);
/* Set MAC Config command data structure (direct 0x0603) */
struct i40e_aq_set_mac_config {
- __le16 max_frame_size;
- u8 params;
-#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04
-#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78
-#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7
-#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4
-#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2
-#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1
- u8 tx_timer_priority; /* bitmap */
- __le16 tx_timer_value;
- __le16 fc_refresh_threshold;
- u8 reserved[8];
+ __le16 max_frame_size;
+ u8 params;
+#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04
+#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78
+#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7
+#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4
+#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2
+#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1
+ u8 tx_timer_priority; /* bitmap */
+ __le16 tx_timer_value;
+ __le16 fc_refresh_threshold;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aq_set_mac_config);
/* Restart Auto-Negotiation (direct 0x605) */
struct i40e_aqc_set_link_restart_an {
- u8 command;
-#define I40E_AQ_PHY_RESTART_AN 0x02
-#define I40E_AQ_PHY_LINK_ENABLE 0x04
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_PHY_RESTART_AN 0x02
+#define I40E_AQ_PHY_LINK_ENABLE 0x04
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_link_restart_an);
/* Get Link Status cmd & response data structure (direct 0x0607) */
struct i40e_aqc_get_link_status {
- __le16 command_flags; /* only field set on command */
-#define I40E_AQ_LSE_MASK 0x3
-#define I40E_AQ_LSE_NOP 0x0
-#define I40E_AQ_LSE_DISABLE 0x2
-#define I40E_AQ_LSE_ENABLE 0x3
+ __le16 command_flags; /* only field set on command */
+#define I40E_AQ_LSE_MASK 0x3
+#define I40E_AQ_LSE_NOP 0x0
+#define I40E_AQ_LSE_DISABLE 0x2
+#define I40E_AQ_LSE_ENABLE 0x3
/* only response uses this flag */
-#define I40E_AQ_LSE_IS_ENABLED 0x1
- u8 phy_type; /* i40e_aq_phy_type */
- u8 link_speed; /* i40e_aq_link_speed */
- u8 link_info;
-#define I40E_AQ_LINK_UP 0x01
-#define I40E_AQ_LINK_FAULT 0x02
-#define I40E_AQ_LINK_FAULT_TX 0x04
-#define I40E_AQ_LINK_FAULT_RX 0x08
-#define I40E_AQ_LINK_FAULT_REMOTE 0x10
-#define I40E_AQ_MEDIA_AVAILABLE 0x40
-#define I40E_AQ_SIGNAL_DETECT 0x80
- u8 an_info;
-#define I40E_AQ_AN_COMPLETED 0x01
-#define I40E_AQ_LP_AN_ABILITY 0x02
-#define I40E_AQ_PD_FAULT 0x04
-#define I40E_AQ_FEC_EN 0x08
-#define I40E_AQ_PHY_LOW_POWER 0x10
-#define I40E_AQ_LINK_PAUSE_TX 0x20
-#define I40E_AQ_LINK_PAUSE_RX 0x40
-#define I40E_AQ_QUALIFIED_MODULE 0x80
- u8 ext_info;
-#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01
-#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
-#define I40E_AQ_LINK_TX_SHIFT 0x02
-#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT)
-#define I40E_AQ_LINK_TX_ACTIVE 0x00
-#define I40E_AQ_LINK_TX_DRAINED 0x01
-#define I40E_AQ_LINK_TX_FLUSHED 0x03
-#define I40E_AQ_LINK_FORCED_40G 0x10
- u8 loopback; /* use defines from i40e_aqc_set_lb_mode */
- __le16 max_frame_size;
- u8 config;
-#define I40E_AQ_CONFIG_CRC_ENA 0x04
-#define I40E_AQ_CONFIG_PACING_MASK 0x78
- u8 reserved[5];
+#define I40E_AQ_LSE_IS_ENABLED 0x1
+ u8 phy_type; /* i40e_aq_phy_type */
+ u8 link_speed; /* i40e_aq_link_speed */
+ u8 link_info;
+#define I40E_AQ_LINK_UP 0x01
+#define I40E_AQ_LINK_FAULT 0x02
+#define I40E_AQ_LINK_FAULT_TX 0x04
+#define I40E_AQ_LINK_FAULT_RX 0x08
+#define I40E_AQ_LINK_FAULT_REMOTE 0x10
+#define I40E_AQ_MEDIA_AVAILABLE 0x40
+#define I40E_AQ_SIGNAL_DETECT 0x80
+ u8 an_info;
+#define I40E_AQ_AN_COMPLETED 0x01
+#define I40E_AQ_LP_AN_ABILITY 0x02
+#define I40E_AQ_PD_FAULT 0x04
+#define I40E_AQ_FEC_EN 0x08
+#define I40E_AQ_PHY_LOW_POWER 0x10
+#define I40E_AQ_LINK_PAUSE_TX 0x20
+#define I40E_AQ_LINK_PAUSE_RX 0x40
+#define I40E_AQ_QUALIFIED_MODULE 0x80
+ u8 ext_info;
+#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01
+#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
+#define I40E_AQ_LINK_TX_SHIFT 0x02
+#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT)
+#define I40E_AQ_LINK_TX_ACTIVE 0x00
+#define I40E_AQ_LINK_TX_DRAINED 0x01
+#define I40E_AQ_LINK_TX_FLUSHED 0x03
+#define I40E_AQ_LINK_FORCED_40G 0x10
+ u8 loopback; /* use defines from i40e_aqc_set_lb_mode */
+ __le16 max_frame_size;
+ u8 config;
+#define I40E_AQ_CONFIG_CRC_ENA 0x04
+#define I40E_AQ_CONFIG_PACING_MASK 0x78
+ u8 reserved[5];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
/* Set event mask command (direct 0x613) */
struct i40e_aqc_set_phy_int_mask {
- u8 reserved[8];
- __le16 event_mask;
-#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002
-#define I40E_AQ_EVENT_MEDIA_NA 0x0004
-#define I40E_AQ_EVENT_LINK_FAULT 0x0008
-#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010
-#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020
-#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040
-#define I40E_AQ_EVENT_AN_COMPLETED 0x0080
-#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100
-#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
- u8 reserved1[6];
+ u8 reserved[8];
+ __le16 event_mask;
+#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002
+#define I40E_AQ_EVENT_MEDIA_NA 0x0004
+#define I40E_AQ_EVENT_LINK_FAULT 0x0008
+#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010
+#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020
+#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040
+#define I40E_AQ_EVENT_AN_COMPLETED 0x0080
+#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100
+#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
+ u8 reserved1[6];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_int_mask);
* Get Link Partner AN advt register (direct 0x0616)
*/
struct i40e_aqc_an_advt_reg {
- __le32 local_an_reg0;
- __le16 local_an_reg1;
- u8 reserved[10];
+ __le32 local_an_reg0;
+ __le16 local_an_reg1;
+ u8 reserved[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_an_advt_reg);
/* Set Loopback mode (0x0618) */
struct i40e_aqc_set_lb_mode {
- __le16 lb_mode;
-#define I40E_AQ_LB_PHY_LOCAL 0x01
-#define I40E_AQ_LB_PHY_REMOTE 0x02
-#define I40E_AQ_LB_MAC_LOCAL 0x04
- u8 reserved[14];
+ __le16 lb_mode;
+#define I40E_AQ_LB_PHY_LOCAL 0x01
+#define I40E_AQ_LB_PHY_REMOTE 0x02
+#define I40E_AQ_LB_MAC_LOCAL 0x04
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_lb_mode);
/* Set PHY Debug command (0x0622) */
struct i40e_aqc_set_phy_debug {
- u8 command_flags;
+ u8 command_flags;
#define I40E_AQ_PHY_DEBUG_RESET_INTERNAL 0x02
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT 2
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_MASK (0x03 << \
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_HARD 0x01
#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SOFT 0x02
#define I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW 0x10
- u8 reserved[15];
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_debug);
enum i40e_aq_phy_reg_type {
- I40E_AQC_PHY_REG_INTERNAL = 0x1,
- I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2,
- I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3
+ I40E_AQC_PHY_REG_INTERNAL = 0x1,
+ I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2,
+ I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3
};
/* NVM Read command (indirect 0x0701)
* NVM Update commands (indirect 0x0703)
*/
struct i40e_aqc_nvm_update {
- u8 command_flags;
-#define I40E_AQ_NVM_LAST_CMD 0x01
-#define I40E_AQ_NVM_FLASH_ONLY 0x80
- u8 module_pointer;
- __le16 length;
- __le32 offset;
- __le32 addr_high;
- __le32 addr_low;
+ u8 command_flags;
+#define I40E_AQ_NVM_LAST_CMD 0x01
+#define I40E_AQ_NVM_FLASH_ONLY 0x80
+ u8 module_pointer;
+ __le16 length;
+ __le32 offset;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
/* NVM Config Read (indirect 0x0704) */
struct i40e_aqc_nvm_config_read {
- __le16 cmd_flags;
+ __le16 cmd_flags;
#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
#define ANVM_READ_SINGLE_FEATURE 0
#define ANVM_READ_MULTIPLE_FEATURES 1
- __le16 element_count;
- __le16 element_id; /* Feature/field ID */
- u8 reserved[2];
- __le32 address_high;
- __le32 address_low;
+ __le16 element_count;
+ __le16 element_id; /* Feature/field ID */
+ u8 reserved[2];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_read);
/* NVM Config Write (indirect 0x0705) */
struct i40e_aqc_nvm_config_write {
- __le16 cmd_flags;
- __le16 element_count;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
+ __le16 cmd_flags;
+ __le16 element_count;
+ u8 reserved[4];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write);
* Send to Peer PF command (indirect 0x0803)
*/
struct i40e_aqc_pf_vf_message {
- __le32 id;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
+ __le32 id;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
* uses i40e_aq_desc
*/
struct i40e_aqc_alternate_write_done {
- __le16 cmd_flags;
+ __le16 cmd_flags;
#define I40E_AQ_ALTERNATE_MODE_BIOS_MASK 1
#define I40E_AQ_ALTERNATE_MODE_BIOS_LEGACY 0
#define I40E_AQ_ALTERNATE_MODE_BIOS_UEFI 1
#define I40E_AQ_ALTERNATE_RESET_NEEDED 2
- u8 reserved[14];
+ u8 reserved[14];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write_done);
/* Set OEM mode (direct 0x0905) */
struct i40e_aqc_alternate_set_mode {
- __le32 mode;
+ __le32 mode;
#define I40E_AQ_ALTERNATE_MODE_NONE 0
#define I40E_AQ_ALTERNATE_MODE_OEM 1
- u8 reserved[12];
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_set_mode);
/* Lan Queue Overflow Event (direct, 0x1001) */
struct i40e_aqc_lan_overflow {
- __le32 prtdcb_rupto;
- __le32 otx_ctl;
- u8 reserved[8];
+ __le32 prtdcb_rupto;
+ __le32 otx_ctl;
+ u8 reserved[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lan_overflow);
/* Get LLDP MIB (indirect 0x0A00) */
struct i40e_aqc_lldp_get_mib {
- u8 type;
- u8 reserved1;
-#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3
-#define I40E_AQ_LLDP_MIB_LOCAL 0x0
-#define I40E_AQ_LLDP_MIB_REMOTE 0x1
-#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC
-#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1
-#define I40E_AQ_LLDP_TX_SHIFT 0x4
-#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT)
+ u8 type;
+ u8 reserved1;
+#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3
+#define I40E_AQ_LLDP_MIB_LOCAL 0x0
+#define I40E_AQ_LLDP_MIB_REMOTE 0x1
+#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC
+#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1
+#define I40E_AQ_LLDP_TX_SHIFT 0x4
+#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT)
/* TX pause flags use I40E_AQ_LINK_TX_* above */
- __le16 local_len;
- __le16 remote_len;
- u8 reserved2[2];
- __le32 addr_high;
- __le32 addr_low;
+ __le16 local_len;
+ __le16 remote_len;
+ u8 reserved2[2];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_get_mib);
* also used for the event (with type in the command field)
*/
struct i40e_aqc_lldp_update_mib {
- u8 command;
-#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0
-#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
+ u8 command;
+#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0
+#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1
+ u8 reserved[7];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_mib);
* Delete LLDP TLV (indirect 0x0A04)
*/
struct i40e_aqc_lldp_add_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved1[1];
- __le16 len;
- u8 reserved2[4];
- __le32 addr_high;
- __le32 addr_low;
+ u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
+ u8 reserved1[1];
+ __le16 len;
+ u8 reserved2[4];
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_add_tlv);
/* Update LLDP TLV (indirect 0x0A03) */
struct i40e_aqc_lldp_update_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved;
- __le16 old_len;
- __le16 new_offset;
- __le16 new_len;
- __le32 addr_high;
- __le32 addr_low;
+ u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
+ u8 reserved;
+ __le16 old_len;
+ __le16 new_offset;
+ __le16 new_len;
+ __le32 addr_high;
+ __le32 addr_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_tlv);
/* Stop LLDP (direct 0x0A05) */
struct i40e_aqc_lldp_stop {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_STOP 0x0
-#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_LLDP_AGENT_STOP 0x0
+#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop);
/* Start LLDP (direct 0x0A06) */
struct i40e_aqc_lldp_start {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_START 0x1
- u8 reserved[15];
+ u8 command;
+#define I40E_AQ_LLDP_AGENT_START 0x1
+ u8 reserved[15];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start);
/* Add Udp Tunnel command and completion (direct 0x0B00) */
struct i40e_aqc_add_udp_tunnel {
- __le16 udp_port;
- u8 reserved0[3];
- u8 protocol_type;
+ __le16 udp_port;
+ u8 reserved0[3];
+ u8 protocol_type;
#define I40E_AQC_TUNNEL_TYPE_VXLAN 0x00
#define I40E_AQC_TUNNEL_TYPE_NGE 0x01
#define I40E_AQC_TUNNEL_TYPE_TEREDO 0x10
- u8 reserved1[10];
+ u8 reserved1[10];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel);
__le16 udp_port;
u8 filter_entry_index;
u8 multiple_pfs;
-#define I40E_AQC_SINGLE_PF 0x0
-#define I40E_AQC_MULTIPLE_PFS 0x1
+#define I40E_AQC_SINGLE_PF 0x0
+#define I40E_AQC_MULTIPLE_PFS 0x1
u8 total_filters;
u8 reserved[11];
};
/* remove UDP Tunnel command (0x0B01) */
struct i40e_aqc_remove_udp_tunnel {
- u8 reserved[2];
- u8 index; /* 0 to 15 */
- u8 pf_filters;
- u8 total_filters;
- u8 reserved2[11];
+ u8 reserved[2];
+ u8 index; /* 0 to 15 */
+ u8 reserved2[13];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_udp_tunnel);
struct i40e_aqc_del_udp_tunnel_completion {
- __le16 udp_port;
- u8 index; /* 0 to 15 */
- u8 multiple_pfs;
- u8 total_filters_used;
- u8 reserved;
- u8 tunnels_free;
- u8 reserved1[9];
+ __le16 udp_port;
+ u8 index; /* 0 to 15 */
+ u8 multiple_pfs;
+ u8 total_filters_used;
+ u8 reserved1[11];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion);
u8 key1_len; /* 0 to 15 */
u8 key2_len; /* 0 to 15 */
u8 flags;
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
/* response flags */
-#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
-#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
+#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
+#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
u8 network_key_index;
#define I40E_AQC_NETWORK_KEY_INDEX_VXLAN 0x0
#define I40E_AQC_NETWORK_KEY_INDEX_NGE 0x1
/* OEM mode commands (direct 0xFE0x) */
struct i40e_aqc_oem_param_change {
- __le32 param_type;
-#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0
-#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
-#define I40E_AQ_OEM_PARAM_MAC 2
- __le32 param_value1;
- u8 param_value2[8];
+ __le32 param_type;
+#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0
+#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
+#define I40E_AQ_OEM_PARAM_MAC 2
+ __le32 param_value1;
+ u8 param_value2[8];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
struct i40e_aqc_oem_state_change {
- __le32 state;
-#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0
-#define I40E_AQ_OEM_STATE_LINK_UP 0x1
- u8 reserved[12];
+ __le32 state;
+#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0
+#define I40E_AQ_OEM_STATE_LINK_UP 0x1
+ u8 reserved[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
/* set test more (0xFF01, internal) */
struct i40e_acq_set_test_mode {
- u8 mode;
-#define I40E_AQ_TEST_PARTIAL 0
-#define I40E_AQ_TEST_FULL 1
-#define I40E_AQ_TEST_NVM 2
- u8 reserved[3];
- u8 command;
-#define I40E_AQ_TEST_OPEN 0
-#define I40E_AQ_TEST_CLOSE 1
-#define I40E_AQ_TEST_INC 2
- u8 reserved2[3];
- __le32 address_high;
- __le32 address_low;
+ u8 mode;
+#define I40E_AQ_TEST_PARTIAL 0
+#define I40E_AQ_TEST_FULL 1
+#define I40E_AQ_TEST_NVM 2
+ u8 reserved[3];
+ u8 command;
+#define I40E_AQ_TEST_OPEN 0
+#define I40E_AQ_TEST_CLOSE 1
+#define I40E_AQ_TEST_INC 2
+ u8 reserved2[3];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_acq_set_test_mode);
#define I40E_AQ_CLUSTER_ID_ALTRAM 11
struct i40e_aqc_debug_dump_internals {
- u8 cluster_id;
- u8 table_id;
- __le16 data_size;
- __le32 idx;
- __le32 address_high;
- __le32 address_low;
+ u8 cluster_id;
+ u8 table_id;
+ __le16 data_size;
+ __le32 idx;
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_dump_internals);
struct i40e_aqc_debug_modify_internals {
- u8 cluster_id;
- u8 cluster_specific_params[7];
- __le32 address_high;
- __le32 address_low;
+ u8 cluster_id;
+ u8 cluster_specific_params[7];
+ __le32 address_high;
+ __le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
case I40E_DEV_ID_QSFP_A:
case I40E_DEV_ID_QSFP_B:
case I40E_DEV_ID_QSFP_C:
+ case I40E_DEV_ID_10G_BASE_T:
hw->mac.type = I40E_MAC_XL710;
break;
case I40E_DEV_ID_VF:
/* Interrupt Throttling and Rate Limiting Goodies */
#define I40E_MAX_ITR 0x0FF0 /* reg uses 2 usec resolution */
-#define I40E_MIN_ITR 0x0004 /* reg uses 2 usec resolution */
-#define I40E_MAX_IRATE 0x03F
-#define I40E_MIN_IRATE 0x001
-#define I40E_IRATE_USEC_RESOLUTION 4
+#define I40E_MIN_ITR 0x0001 /* reg uses 2 usec resolution */
#define I40E_ITR_100K 0x0005
#define I40E_ITR_20K 0x0019
#define I40E_ITR_8K 0x003E
#define I40E_DEV_ID_QSFP_A 0x1583
#define I40E_DEV_ID_QSFP_B 0x1584
#define I40E_DEV_ID_QSFP_C 0x1585
+#define I40E_DEV_ID_10G_BASE_T 0x1586
#define I40E_DEV_ID_VF 0x154C
#define I40E_DEV_ID_VF_HV 0x1571
struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
struct list_head vlan_filter_list;
char misc_vector_name[IFNAMSIZ + 9];
+ int num_active_queues;
/* TX */
struct i40e_ring *tx_rings[I40E_MAX_VSI_QP];
#define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats)
#define I40EVF_QUEUE_STATS_LEN(_dev) \
(((struct i40evf_adapter *) \
- netdev_priv(_dev))->vsi_res->num_queue_pairs \
+ netdev_priv(_dev))->num_active_queues \
* 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64)))
#define I40EVF_STATS_LEN(_dev) \
(I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))
p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset;
data[i] = *(u64 *)p;
}
- for (j = 0; j < adapter->vsi_res->num_queue_pairs; j++) {
+ for (j = 0; j < adapter->num_active_queues; j++) {
data[i++] = adapter->tx_rings[j]->stats.packets;
data[i++] = adapter->tx_rings[j]->stats.bytes;
}
- for (j = 0; j < adapter->vsi_res->num_queue_pairs; j++) {
+ for (j = 0; j < adapter->num_active_queues; j++) {
data[i++] = adapter->rx_rings[j]->stats.packets;
data[i++] = adapter->rx_rings[j]->stats.bytes;
}
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i);
p += ETH_GSTRING_LEN;
snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i);
p += ETH_GSTRING_LEN;
}
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i);
p += ETH_GSTRING_LEN;
snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
- cmd->data = adapter->vsi_res->num_queue_pairs;
+ cmd->data = adapter->num_active_queues;
ret = 0;
break;
case ETHTOOL_GRXFH:
struct i40evf_adapter *adapter = netdev_priv(netdev);
/* Report maximum channels */
- ch->max_combined = adapter->vsi_res->num_queue_pairs;
+ ch->max_combined = adapter->num_active_queues;
ch->max_other = NONQ_VECS;
ch->other_count = NONQ_VECS;
- ch->combined_count = adapter->vsi_res->num_queue_pairs;
+ ch->combined_count = adapter->num_active_queues;
}
/**
int q_vectors;
int v_start = 0;
int rxr_idx = 0, txr_idx = 0;
- int rxr_remaining = adapter->vsi_res->num_queue_pairs;
- int txr_remaining = adapter->vsi_res->num_queue_pairs;
+ int rxr_remaining = adapter->num_active_queues;
+ int txr_remaining = adapter->num_active_queues;
int i, j;
int rqpv, tqpv;
int err = 0;
{
struct i40e_hw *hw = &adapter->hw;
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++)
+ for (i = 0; i < adapter->num_active_queues; i++)
adapter->tx_rings[i]->tail = hw->hw_addr + I40E_QTX_TAIL1(i);
}
rx_buf_len = ALIGN(max_frame, 1024);
}
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
adapter->rx_rings[i]->tail = hw->hw_addr + I40E_QRX_TAIL1(i);
adapter->rx_rings[i]->rx_buf_len = rx_buf_len;
}
i40evf_configure_rx(adapter);
adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
struct i40e_ring *ring = adapter->rx_rings[i];
i40evf_alloc_rx_buffers(ring, ring->count);
ring->next_to_use = ring->count - 1;
{
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++)
+ for (i = 0; i < adapter->num_active_queues; i++)
i40evf_clean_rx_ring(adapter->rx_rings[i]);
}
{
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++)
+ for (i = 0; i < adapter->num_active_queues; i++)
i40evf_clean_tx_ring(adapter->tx_rings[i]);
}
if (!adapter->vsi_res)
return;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
if (adapter->tx_rings[i])
kfree_rcu(adapter->tx_rings[i], rcu);
adapter->tx_rings[i] = NULL;
{
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
struct i40e_ring *tx_ring;
struct i40e_ring *rx_ring;
err = -EIO;
goto out;
}
- pairs = adapter->vsi_res->num_queue_pairs;
+ pairs = adapter->num_active_queues;
/* It's easy to be greedy for MSI-X vectors, but it really
* doesn't do us much good if we have a lot more vectors
int napi_vectors;
num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
- napi_vectors = adapter->vsi_res->num_queue_pairs;
+ napi_vectors = adapter->num_active_queues;
for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
struct i40e_q_vector *q_vector = adapter->q_vector[q_idx];
}
dev_info(&adapter->pdev->dev, "Multiqueue %s: Queue pair count = %u",
- (adapter->vsi_res->num_queue_pairs > 1) ? "Enabled" :
- "Disabled", adapter->vsi_res->num_queue_pairs);
+ (adapter->num_active_queues > 1) ? "Enabled" :
+ "Disabled", adapter->num_active_queues);
return 0;
err_alloc_queues:
{
j += 1;
- return j >= adapter->vsi_res->num_queue_pairs ? 0 : j;
+ return j >= adapter->num_active_queues ? 0 : j;
}
/**
0xc135cafa, 0x7a6f7e2d, 0xe7102d28, 0x163cd12e,
0x4954b126 };
- /* Hash type is configured by the PF - we just supply the key */
+ /* No RSS for single queue. */
+ if (adapter->num_active_queues == 1) {
+ wr32(hw, I40E_VFQF_HENA(0), 0);
+ wr32(hw, I40E_VFQF_HENA(1), 0);
+ return;
+ }
- /* Fill out hash function seed */
+ /* Hash type is configured by the PF - we just supply the key */
for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
wr32(hw, I40E_VFQF_HKEY(i), seed[i]);
wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
/* Populate the LUT with max no. of queues in round robin fashion */
- j = adapter->vsi_res->num_queue_pairs;
+ j = adapter->num_active_queues;
for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
j = next_queue(adapter, j);
lut = j;
while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
&adapter->crit_section))
- udelay(500);
+ usleep_range(500, 1000);
if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) {
dev_info(&adapter->pdev->dev, "Requesting reset from PF\n");
v_msg->v_retval, event.msg_buf,
event.msg_size);
if (pending != 0) {
- dev_info(&adapter->pdev->dev,
- "%s: ARQ: Pending events %d\n",
- __func__, pending);
memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE);
+ event.msg_size = I40EVF_MAX_AQ_BUF_SIZE;
}
} while (pending);
{
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++)
+ for (i = 0; i < adapter->num_active_queues; i++)
if (adapter->tx_rings[i]->desc)
i40evf_free_tx_resources(adapter->tx_rings[i]);
{
int i, err = 0;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
adapter->tx_rings[i]->count = adapter->tx_desc_count;
err = i40evf_setup_tx_descriptors(adapter->tx_rings[i]);
if (!err)
{
int i, err = 0;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+ for (i = 0; i < adapter->num_active_queues; i++) {
adapter->rx_rings[i]->count = adapter->rx_desc_count;
err = i40evf_setup_rx_descriptors(adapter->rx_rings[i]);
if (!err)
{
int i;
- for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++)
+ for (i = 0; i < adapter->num_active_queues; i++)
if (adapter->rx_rings[i]->desc)
i40evf_free_rx_resources(adapter->rx_rings[i]);
}
if ((rstat == I40E_VFR_VFACTIVE) ||
(rstat == I40E_VFR_COMPLETED))
return 0;
- udelay(10);
+ usleep_range(10, 20);
}
return -EBUSY;
}
adapter->watchdog_timer.data = (unsigned long)adapter;
mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ adapter->num_active_queues = min_t(int,
+ adapter->vsi_res->num_queue_pairs,
+ (int)(num_online_cpus()));
adapter->tx_desc_count = I40EVF_DEFAULT_TXD;
adapter->rx_desc_count = I40EVF_DEFAULT_RXD;
err = i40evf_init_interrupt_scheme(adapter);
struct i40e_virtchnl_version_info *pf_vvi;
struct i40e_hw *hw = &adapter->hw;
struct i40e_arq_event_info event;
+ enum i40e_virtchnl_ops op;
i40e_status err;
event.msg_size = I40EVF_MAX_AQ_BUF_SIZE;
goto out;
}
- err = i40evf_clean_arq_element(hw, &event, NULL);
- if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
- goto out_alloc;
+ while (1) {
+ err = i40evf_clean_arq_element(hw, &event, NULL);
+ /* When the AQ is empty, i40evf_clean_arq_element will return
+ * nonzero and this loop will terminate.
+ */
+ if (err)
+ goto out_alloc;
+ op =
+ (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
+ if (op == I40E_VIRTCHNL_OP_VERSION)
+ break;
+ }
+
err = (i40e_status)le32_to_cpu(event.desc.cookie_low);
if (err)
goto out_alloc;
- if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) !=
- I40E_VIRTCHNL_OP_VERSION) {
+ if (op != I40E_VIRTCHNL_OP_VERSION) {
dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n",
- le32_to_cpu(event.desc.cookie_high));
+ op);
err = -EIO;
goto out_alloc;
}
{
struct i40e_hw *hw = &adapter->hw;
struct i40e_arq_event_info event;
- u16 len;
+ enum i40e_virtchnl_ops op;
i40e_status err;
+ u16 len;
len = sizeof(struct i40e_virtchnl_vf_resource) +
I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource);
goto out;
}
- err = i40evf_clean_arq_element(hw, &event, NULL);
- if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
- goto out_alloc;
-
- err = (i40e_status)le32_to_cpu(event.desc.cookie_low);
- if (err) {
- dev_err(&adapter->pdev->dev,
- "%s: Error returned from PF, %d, %d\n", __func__,
- le32_to_cpu(event.desc.cookie_high),
- le32_to_cpu(event.desc.cookie_low));
- err = -EIO;
- goto out_alloc;
+ while (1) {
+ event.msg_size = len;
+ /* When the AQ is empty, i40evf_clean_arq_element will return
+ * nonzero and this loop will terminate.
+ */
+ err = i40evf_clean_arq_element(hw, &event, NULL);
+ if (err)
+ goto out_alloc;
+ op =
+ (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
+ if (op == I40E_VIRTCHNL_OP_GET_VF_RESOURCES)
+ break;
}
- if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) !=
- I40E_VIRTCHNL_OP_GET_VF_RESOURCES) {
- dev_err(&adapter->pdev->dev,
- "%s: Invalid response from PF, %d, %d\n", __func__,
- le32_to_cpu(event.desc.cookie_high),
- le32_to_cpu(event.desc.cookie_low));
- err = -EIO;
- goto out_alloc;
- }
+ err = (i40e_status)le32_to_cpu(event.desc.cookie_low);
memcpy(adapter->vf_res, event.msg_buf, min(event.msg_size, len));
i40e_vf_parse_hw_config(hw, adapter->vf_res);
{
struct i40e_virtchnl_vsi_queue_config_info *vqci;
struct i40e_virtchnl_queue_pair_info *vqpi;
- int pairs = adapter->vsi_res->num_queue_pairs;
+ int pairs = adapter->num_active_queues;
int i, len;
if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
}
adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES;
vqs.vsi_id = adapter->vsi_res->vsi_id;
- vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1;
+ vqs.tx_queues = (1 << adapter->num_active_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
adapter->aq_pending |= I40EVF_FLAG_AQ_ENABLE_QUEUES;
adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES;
}
adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES;
vqs.vsi_id = adapter->vsi_res->vsi_id;
- vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1;
+ vqs.tx_queues = (1 << adapter->num_active_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
adapter->aq_pending |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES;
return true;
/* alloc new page for storage */
- page = __skb_alloc_page(GFP_ATOMIC | __GFP_COLD, NULL);
+ page = dev_alloc_page();
if (unlikely(!page)) {
rx_ring->rx_stats.alloc_failed++;
return false;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS;
max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
break;
*link_up = false;
}
- if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
- IXGBE_LINKS_SPEED_10G_82599)
- *speed = IXGBE_LINK_SPEED_10GB_FULL;
- else if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
- IXGBE_LINKS_SPEED_1G_82599)
+ switch (links_reg & IXGBE_LINKS_SPEED_82599) {
+ case IXGBE_LINKS_SPEED_10G_82599:
+ if ((hw->mac.type >= ixgbe_mac_X550) &&
+ (links_reg & IXGBE_LINKS_SPEED_NON_STD))
+ *speed = IXGBE_LINK_SPEED_2_5GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ break;
+ case IXGBE_LINKS_SPEED_1G_82599:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
- else if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
- IXGBE_LINKS_SPEED_100_82599)
- *speed = IXGBE_LINK_SPEED_100_FULL;
- else
+ break;
+ case IXGBE_LINKS_SPEED_100_82599:
+ if ((hw->mac.type >= ixgbe_mac_X550) &&
+ (links_reg & IXGBE_LINKS_SPEED_NON_STD))
+ *speed = IXGBE_LINK_SPEED_5GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_100_FULL;
+ break;
+ default:
*speed = IXGBE_LINK_SPEED_UNKNOWN;
+ }
return 0;
}
**/
void ixgbe_clear_tx_pending(struct ixgbe_hw *hw)
{
- u32 gcr_ext, hlreg0;
+ u32 gcr_ext, hlreg0, i, poll;
+ u16 value;
/*
* If double reset is not requested then all transactions should
hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0 | IXGBE_HLREG0_LPBK);
+ /* wait for a last completion before clearing buffers */
+ IXGBE_WRITE_FLUSH(hw);
+ usleep_range(3000, 6000);
+
+ /* Before proceeding, make sure that the PCIe block does not have
+ * transactions pending.
+ */
+ poll = ixgbe_pcie_timeout_poll(hw);
+ for (i = 0; i < poll; i++) {
+ usleep_range(100, 200);
+ value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS);
+ if (ixgbe_removed(hw->hw_addr))
+ break;
+ if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
+ break;
+ }
+
/* initiate cleaning flow for buffers in the PCIe transaction layer */
gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT,
bwgid, ptype);
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
return ixgbe_dcb_hw_config_82599(hw, pfc_en, refill, max,
bwgid, ptype, prio_tc);
default:
return ixgbe_dcb_config_pfc_82598(hw, pfc_en);
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
return ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc);
default:
break;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max,
bwg_id, prio_type, prio_tc);
ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
ixgbe_dcb_read_rtrup2tc_82599(hw, map);
break;
default:
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
for (j = 0; j < netdev->addr_len; j++, i++)
perm_addr[i] = adapter->hw.mac.san_addr[j];
break;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
break;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RTRPCS);
for (i = 0; i < 8; i++)
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
toggle = 0x7FFFF30F;
test = reg_test_82599;
break;
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
reg_ctl &= ~IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl);
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
reg_data |= IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_data);
- /* X540 needs to set the MACC.FLU bit to force link up */
- if (adapter->hw.mac.type == ixgbe_mac_X540) {
+ /* X540 and X550 needs to set the MACC.FLU bit to force link up */
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
reg_data |= IXGBE_MACC_FLU;
IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
- } else {
+ break;
+ default:
if (hw->mac.orig_autoc) {
reg_data = hw->mac.orig_autoc | IXGBE_AUTOC_FLU;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
/* if we changed something we need to update flags */
if (flags2 != adapter->flags2) {
struct ixgbe_hw *hw = &adapter->hw;
- u32 mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
+ u32 mrqc;
+ unsigned int pf_pool = adapter->num_vfs;
+
+ if ((hw->mac.type >= ixgbe_mac_X550) &&
+ (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+ mrqc = IXGBE_READ_REG(hw, IXGBE_PFVFMRQC(pf_pool));
+ else
+ mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
if ((flags2 & UDP_RSS_FLAGS) &&
!(adapter->flags2 & UDP_RSS_FLAGS))
if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
- IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+ if ((hw->mac.type >= ixgbe_mac_X550) &&
+ (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFMRQC(pf_pool), mrqc);
+ else
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
}
return 0;
struct ixgbe_adapter *adapter = netdev_priv(dev);
switch (adapter->hw.mac.type) {
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
case ixgbe_mac_X540:
case ixgbe_mac_82599EB:
info->so_timestamping =
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
if (num_tcs > 4) {
/*
* TCs : TC0/1 TC2/3 TC4-7
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
if (direction == -1) {
/* other causes */
msix_vector |= IXGBE_IVAR_ALLOC_VAL;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask = (qmask & 0xFFFFFFFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
mask = (qmask >> 32);
/* alloc new page for storage */
if (likely(!page)) {
- page = __skb_alloc_pages(GFP_ATOMIC | __GFP_COLD | __GFP_COMP,
- bi->skb, ixgbe_rx_pg_order(rx_ring));
+ page = dev_alloc_pages(ixgbe_rx_pg_order(rx_ring));
if (unlikely(!page)) {
rx_ring->rx_stats.alloc_rx_page_failed++;
return false;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
ixgbe_set_ivar(adapter, -1, 1, v_idx);
break;
default:
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
/*
* set the WDIS bit to not clear the timer bits and cause an
* immediate assertion of the interrupt
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask = (qmask & 0xFFFFFFFF);
if (mask)
IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask = (qmask & 0xFFFFFFFF);
if (mask)
IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
mask |= IXGBE_EIMS_GPI_SDP0;
break;
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask |= IXGBE_EIMS_TS;
break;
default:
case ixgbe_mac_82599EB:
mask |= IXGBE_EIMS_GPI_SDP1;
mask |= IXGBE_EIMS_GPI_SDP2;
+ /* fall through */
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
mask |= IXGBE_EIMS_ECC;
mask |= IXGBE_EIMS_MAILBOX;
break;
break;
}
- if (adapter->hw.mac.type == ixgbe_mac_X540)
- mask |= IXGBE_EIMS_TIMESYNC;
-
if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) &&
!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
mask |= IXGBE_EIMS_FLOW_DIR;
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
if (eicr & IXGBE_EICR_ECC) {
e_info(link, "Received ECC Err, initiating reset\n");
adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
ixgbe_check_sfp_event(adapter, eicr);
/* Fall through */
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
if (eicr & IXGBE_EICR_ECC) {
e_info(link, "Received ECC Err, initiating reset\n");
adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
}
-static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
+static void ixgbe_setup_reta(struct ixgbe_adapter *adapter, const u32 *seed)
{
struct ixgbe_hw *hw = &adapter->hw;
- static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
- 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
- 0x6A3E67EA, 0x14364D17, 0x3BED200D};
- u32 mrqc = 0, reta = 0;
- u32 rxcsum;
+ u32 reta = 0;
int i, j;
u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
if ((i & 3) == 3)
IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
}
+}
+
+static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
+ 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
+ 0x6A3E67EA, 0x14364D17, 0x3BED200D};
+ u32 mrqc = 0, rss_field = 0;
+ u32 rxcsum;
/* Disable indicating checksum in descriptor, enables RSS hash */
rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
}
/* Perform hash on these packet types */
- mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4 |
- IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
- IXGBE_MRQC_RSS_FIELD_IPV6 |
- IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
+ rss_field |= IXGBE_MRQC_RSS_FIELD_IPV4 |
+ IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
+ IXGBE_MRQC_RSS_FIELD_IPV6 |
+ IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
- mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
+ rss_field |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP;
if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
- mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
+ rss_field |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
+ ixgbe_setup_reta(adapter, seed);
+ mrqc |= rss_field;
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
}
u32 rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
switch (hw->mac.type) {
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
case ixgbe_mac_82598EB:
/*
* For VMDq support of different descriptor types or
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
for (i = 0; i < adapter->num_rx_queues; i++) {
struct ixgbe_ring *ring = adapter->rx_ring[i];
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
for (i = 0; i < adapter->num_rx_queues; i++) {
struct ixgbe_ring *ring = adapter->rx_ring[i];
/* Calculate delay value for device */
switch (hw->mac.type) {
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
dv_id = IXGBE_DV_X540(link, tc);
break;
default:
/* Calculate delay value for device */
switch (hw->mac.type) {
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
dv_id = IXGBE_LOW_DV_X540(tc);
break;
default:
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
default:
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH);
}
- /* Disable the Tx DMA engine on 82599 and X540 */
+ /* Disable the Tx DMA engine on 82599 and later MAC */
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
(IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
~IXGBE_DMATXCTL_TE));
if (fwsm & IXGBE_FWSM_TS_ENABLED)
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
break;
+ case ixgbe_mac_X550EM_x:
+ case ixgbe_mac_X550:
+#ifdef CONFIG_IXGBE_DCA
+ adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE;
+#endif
+ break;
default:
break;
}
#ifdef CONFIG_IXGBE_DCB
switch (hw->mac.type) {
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
adapter->dcb_cfg.num_tcs.pg_tcs = X540_TRAFFIC_CLASS;
adapter->dcb_cfg.num_tcs.pfc_tcs = X540_TRAFFIC_CLASS;
break;
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
pci_wake_from_d3(pdev, !!wufc);
break;
default:
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
hwstats->pxonrxc[i] +=
IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
break;
hwstats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
if ((hw->mac.type == ixgbe_mac_82599EB) ||
- (hw->mac.type == ixgbe_mac_X540)) {
+ (hw->mac.type == ixgbe_mac_X540) ||
+ (hw->mac.type == ixgbe_mac_X550) ||
+ (hw->mac.type == ixgbe_mac_X550EM_x)) {
hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); /* to clear */
hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
break;
case ixgbe_mac_X540:
- /* OS2BMC stats are X540 only*/
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ /* OS2BMC stats are X540 and later */
hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC);
}
break;
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
case ixgbe_mac_82599EB: {
u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
if (!adapter->num_vfs)
return false;
+ /* resetting the PF is only needed for MAC before X550 */
+ if (hw->mac.type >= ixgbe_mac_X550)
+ return false;
+
for (i = 0; i < adapter->num_vfs; i++) {
for (j = 0; j < q_per_pool; j++) {
u32 h, t;
ciaa = (vf << 16) | 0x80000000;
/* 32 bit read so align, we really want status at offset 6 */
ciaa |= PCI_COMMAND;
- IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
- ciad = IXGBE_READ_REG(hw, IXGBE_CIAD_82599);
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_BY_MAC(hw), ciaa);
+ ciad = IXGBE_READ_REG(hw, IXGBE_CIAD_BY_MAC(hw));
ciaa &= 0x7FFFFFFF;
/* disable debug mode asap after reading data */
- IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_BY_MAC(hw), ciaa);
/* Get the upper 16 bits which will be the PCI status reg */
ciad >>= 16;
if (ciad & PCI_STATUS_REC_MASTER_ABORT) {
/* Issue VFLR */
ciaa = (vf << 16) | 0x80000000;
ciaa |= 0xA8;
- IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_BY_MAC(hw), ciaa);
ciad = 0x00008000; /* VFLR */
- IXGBE_WRITE_REG(hw, IXGBE_CIAD_82599, ciad);
+ IXGBE_WRITE_REG(hw, IXGBE_CIAD_BY_MAC(hw), ciad);
ciaa &= 0x7FFFFFFF;
- IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_BY_MAC(hw), ciaa);
}
}
}
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
break;
default:
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
netdev->features |= NETIF_F_SCTP_CSUM;
netdev->hw_features |= NETIF_F_SCTP_CSUM |
NETIF_F_NTUPLE;
case ixgbe_mac_X540:
device_id = IXGBE_X540_VF_DEVICE_ID;
break;
+ case ixgbe_mac_X550:
+ device_id = IXGBE_DEV_ID_X550_VF;
+ break;
+ case ixgbe_mac_X550EM_x:
+ device_id = IXGBE_DEV_ID_X550EM_X_VF;
+ break;
default:
device_id = 0;
break;
vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset));
break;
case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
break;
default:
struct ixgbe_mbx_info *mbx = &hw->mbx;
if (hw->mac.type != ixgbe_mac_82599EB &&
+ hw->mac.type != ixgbe_mac_X550 &&
+ hw->mac.type != ixgbe_mac_X550EM_x &&
hw->mac.type != ixgbe_mac_X540)
return;
static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
-static bool ixgbe_get_i2c_data(u32 *i2cctl);
+static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl);
static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
*speed |= IXGBE_LINK_SPEED_100_FULL;
}
+ /* Internal PHY does not support 100 Mbps */
+ if (hw->mac.type == ixgbe_mac_X550EM_x)
+ *speed &= ~IXGBE_LINK_SPEED_100_FULL;
+
return status;
}
* @hw: pointer to hardware structure
*
* Restart autonegotiation and PHY and waits for completion.
+ * This function always returns success, this is nessary since
+ * it is called via a function pointer that could call other
+ * functions that could return an error.
**/
s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
{
**/
static void ixgbe_i2c_start(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
/* Start condition must begin with data and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 1);
**/
static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
/* Stop condition must begin with data low and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 0);
}
/* Release SDA line (set high) */
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- i2cctl |= IXGBE_I2C_DATA_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw);
return status;
{
s32 status = 0;
u32 i = 0;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
u32 timeout = 10;
bool ack = true;
/* Poll for ACK. Note that ACK in I2C spec is
* transition from 1 to 0 */
for (i = 0; i < timeout; i++) {
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- ack = ixgbe_get_i2c_data(&i2cctl);
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ ack = ixgbe_get_i2c_data(hw, &i2cctl);
udelay(1);
if (ack == 0)
**/
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH);
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- *data = ixgbe_get_i2c_data(&i2cctl);
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ *data = ixgbe_get_i2c_data(hw, &i2cctl);
ixgbe_lower_i2c_clk(hw, &i2cctl);
static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
{
s32 status;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
status = ixgbe_set_i2c_data(hw, &i2cctl, data);
if (status == 0) {
u32 i2cctl_r = 0;
for (i = 0; i < timeout; i++) {
- *i2cctl |= IXGBE_I2C_CLK_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+ *i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* SCL rise time (1000ns) */
udelay(IXGBE_I2C_T_RISE);
- i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- if (i2cctl_r & IXGBE_I2C_CLK_IN)
+ i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw))
break;
}
}
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
{
- *i2cctl &= ~IXGBE_I2C_CLK_OUT;
+ *i2cctl &= ~IXGBE_I2C_CLK_OUT_BY_MAC(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* SCL fall time (300ns) */
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
{
if (data)
- *i2cctl |= IXGBE_I2C_DATA_OUT;
+ *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw);
else
- *i2cctl &= ~IXGBE_I2C_DATA_OUT;
+ *i2cctl &= ~IXGBE_I2C_DATA_OUT_BY_MAC(hw);
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
/* Verify data was set correctly */
- *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- if (data != ixgbe_get_i2c_data(i2cctl)) {
+ *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
+ if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
return IXGBE_ERR_I2C;
}
*
* Returns the I2C data bit value
**/
-static bool ixgbe_get_i2c_data(u32 *i2cctl)
+static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
{
- if (*i2cctl & IXGBE_I2C_DATA_IN)
+ if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw))
return true;
return false;
}
**/
static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
{
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+ u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw));
u32 i;
ixgbe_i2c_start(hw);
return 0;
}
+static inline void ixgbe_write_qde(struct ixgbe_adapter *adapter, u32 vf,
+ u32 qde)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+ u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+ int i;
+
+ for (i = vf * q_per_pool; i < ((vf + 1) * q_per_pool); i++) {
+ u32 reg;
+
+ /* flush previous write */
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* indicate to hardware that we want to set drop enable */
+ reg = IXGBE_QDE_WRITE | IXGBE_QDE_ENABLE;
+ reg |= i << IXGBE_QDE_IDX_SHIFT;
+ IXGBE_WRITE_REG(hw, IXGBE_QDE, reg);
+ }
+}
+
static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg);
/* force drop enable for all VF Rx queues */
- for (i = vf * q_per_pool; i < ((vf + 1) * q_per_pool); i++) {
- /* flush previous write */
- IXGBE_WRITE_FLUSH(hw);
-
- /* indicate to hardware that we want to set drop enable */
- reg = IXGBE_QDE_WRITE | IXGBE_QDE_ENABLE;
- reg |= i << IXGBE_QDE_IDX_SHIFT;
- IXGBE_WRITE_REG(hw, IXGBE_QDE, reg);
- }
+ ixgbe_write_qde(adapter, vf, IXGBE_QDE_ENABLE);
/* enable receive for vf */
reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
return ixgbe_set_vf_mac(adapter, vf, mac);
}
+static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf,
+ u16 vlan, u8 qos)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err = 0;
+
+ if (adapter->vfinfo[vf].pf_vlan)
+ err = ixgbe_set_vf_vlan(adapter, false,
+ adapter->vfinfo[vf].pf_vlan,
+ vf);
+ if (err)
+ goto out;
+ ixgbe_set_vmvir(adapter, vlan, qos, vf);
+ ixgbe_set_vmolr(hw, vf, false);
+ if (adapter->vfinfo[vf].spoofchk_enabled)
+ hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+ adapter->vfinfo[vf].vlan_count++;
+
+ /* enable hide vlan on X550 */
+ if (hw->mac.type >= ixgbe_mac_X550)
+ ixgbe_write_qde(adapter, vf, IXGBE_QDE_ENABLE |
+ IXGBE_QDE_HIDE_VLAN);
+
+ adapter->vfinfo[vf].pf_vlan = vlan;
+ adapter->vfinfo[vf].pf_qos = qos;
+ dev_info(&adapter->pdev->dev,
+ "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+ if (test_bit(__IXGBE_DOWN, &adapter->state)) {
+ dev_warn(&adapter->pdev->dev,
+ "The VF VLAN has been set, but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev,
+ "Bring the PF device up before attempting to use the VF device.\n");
+ }
+
+out:
+ return err;
+}
+
+static int ixgbe_disable_port_vlan(struct ixgbe_adapter *adapter, int vf)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ err = ixgbe_set_vf_vlan(adapter, false,
+ adapter->vfinfo[vf].pf_vlan, vf);
+ ixgbe_clear_vmvir(adapter, vf);
+ ixgbe_set_vmolr(hw, vf, true);
+ hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
+ if (adapter->vfinfo[vf].vlan_count)
+ adapter->vfinfo[vf].vlan_count--;
+ adapter->vfinfo[vf].pf_vlan = 0;
+ adapter->vfinfo[vf].pf_qos = 0;
+
+ return err;
+}
+
int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
{
int err = 0;
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- struct ixgbe_hw *hw = &adapter->hw;
if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
return -EINVAL;
if (vlan || qos) {
+ /* Check if there is already a port VLAN set, if so
+ * we have to delete the old one first before we
+ * can set the new one. The usage model had
+ * previously assumed the user would delete the
+ * old port VLAN before setting a new one but this
+ * is not necessarily the case.
+ */
if (adapter->vfinfo[vf].pf_vlan)
- err = ixgbe_set_vf_vlan(adapter, false,
- adapter->vfinfo[vf].pf_vlan,
- vf);
- if (err)
- goto out;
- err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
+ err = ixgbe_disable_port_vlan(adapter, vf);
if (err)
goto out;
- ixgbe_set_vmvir(adapter, vlan, qos, vf);
- ixgbe_set_vmolr(hw, vf, false);
- if (adapter->vfinfo[vf].spoofchk_enabled)
- hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
- adapter->vfinfo[vf].vlan_count++;
- adapter->vfinfo[vf].pf_vlan = vlan;
- adapter->vfinfo[vf].pf_qos = qos;
- dev_info(&adapter->pdev->dev,
- "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
- if (test_bit(__IXGBE_DOWN, &adapter->state)) {
- dev_warn(&adapter->pdev->dev,
- "The VF VLAN has been set,"
- " but the PF device is not up.\n");
- dev_warn(&adapter->pdev->dev,
- "Bring the PF device up before"
- " attempting to use the VF device.\n");
- }
+ err = ixgbe_enable_port_vlan(adapter, vf, vlan, qos);
} else {
- err = ixgbe_set_vf_vlan(adapter, false,
- adapter->vfinfo[vf].pf_vlan, vf);
- ixgbe_clear_vmvir(adapter, vf);
- ixgbe_set_vmolr(hw, vf, true);
- hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
- if (adapter->vfinfo[vf].vlan_count)
- adapter->vfinfo[vf].vlan_count--;
- adapter->vfinfo[vf].pf_vlan = 0;
- adapter->vfinfo[vf].pf_qos = 0;
+ err = ixgbe_disable_port_vlan(adapter, vf);
}
+
out:
return err;
}
/* VF Device IDs */
#define IXGBE_DEV_ID_82599_VF 0x10ED
#define IXGBE_DEV_ID_X540_VF 0x1515
+#define IXGBE_DEV_ID_X550_VF 0x1565
+#define IXGBE_DEV_ID_X550EM_X_VF 0x15A8
/* General Registers */
#define IXGBE_CTRL 0x00000
#define IXGBE_CTRL_EXT 0x00018
#define IXGBE_ESDP 0x00020
#define IXGBE_EODSDP 0x00028
-#define IXGBE_I2CCTL 0x00028
+#define IXGBE_I2CCTL_BY_MAC(_hw)((((_hw)->mac.type >= ixgbe_mac_X550) ? \
+ 0x15F5C : 0x00028))
#define IXGBE_LEDCTL 0x00200
#define IXGBE_FRTIMER 0x00048
#define IXGBE_TCPTIMER 0x0004C
#define IXGBE_VPDDIAG1 0x10208
/* I2CCTL Bit Masks */
-#define IXGBE_I2C_CLK_IN 0x00000001
-#define IXGBE_I2C_CLK_OUT 0x00000002
-#define IXGBE_I2C_DATA_IN 0x00000004
-#define IXGBE_I2C_DATA_OUT 0x00000008
+#define IXGBE_I2C_CLK_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
+ 0x00004000 : 0x00000001)
+#define IXGBE_I2C_CLK_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
+ 0x00000200 : 0x00000002)
+#define IXGBE_I2C_DATA_IN_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
+ 0x00001000 : 0x00000004)
+#define IXGBE_I2C_DATA_OUT_BY_MAC(_hw)(((_hw)->mac.type) >= ixgbe_mac_X550 ? \
+ 0x00000400 : 0x00000008)
#define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT 500
#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8
#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */
#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */
+/* Registers for setting up RSS on X550 with SRIOV
+ * _p - pool number (0..63)
+ * _i - index (0..10 for PFVFRSSRK, 0..15 for PFVFRETA)
+ */
+#define IXGBE_PFVFMRQC(_p) (0x03400 + ((_p) * 4))
+#define IXGBE_PFVFRSSRK(_i, _p) (0x018000 + ((_i) * 4) + ((_p) * 0x40))
+#define IXGBE_PFVFRETA(_i, _p) (0x019000 + ((_i) * 4) + ((_p) * 0x40))
+
/* Flow Director registers */
#define IXGBE_FDIRCTRL 0x0EE00
#define IXGBE_FDIRHKEY 0x0EE68
#define IXGBE_PBACLR_82599 0x11068
#define IXGBE_CIAA_82599 0x11088
#define IXGBE_CIAD_82599 0x1108C
+#define IXGBE_CIAA_X550 0x11508
+#define IXGBE_CIAD_X550 0x11510
+#define IXGBE_CIAA_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
+ IXGBE_CIAA_X550 : IXGBE_CIAA_82599))
+#define IXGBE_CIAD_BY_MAC(_hw) ((((_hw)->mac.type >= ixgbe_mac_X550) ? \
+ IXGBE_CIAD_X550 : IXGBE_CIAD_82599))
#define IXGBE_PICAUSE 0x110B0
#define IXGBE_PIENA 0x110B8
#define IXGBE_CDQ_MBR_82599 0x110B4
#define IXGBE_LINKS_TL_FAULT 0x00001000
#define IXGBE_LINKS_SIGNAL 0x00000F00
+#define IXGBE_LINKS_SPEED_NON_STD 0x08000000
#define IXGBE_LINKS_SPEED_82599 0x30000000
#define IXGBE_LINKS_SPEED_10G_82599 0x30000000
#define IXGBE_LINKS_SPEED_1G_82599 0x20000000
/* Queue Drop Enable */
#define IXGBE_QDE_ENABLE 0x00000001
+#define IXGBE_QDE_HIDE_VLAN 0x00000002
#define IXGBE_QDE_IDX_MASK 0x00007F00
#define IXGBE_QDE_IDX_SHIFT 8
#define IXGBE_QDE_WRITE 0x00010000
typedef u32 ixgbe_autoneg_advertised;
/* Link speed */
typedef u32 ixgbe_link_speed;
-#define IXGBE_LINK_SPEED_UNKNOWN 0
-#define IXGBE_LINK_SPEED_100_FULL 0x0008
-#define IXGBE_LINK_SPEED_1GB_FULL 0x0020
-#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+#define IXGBE_LINK_SPEED_UNKNOWN 0
+#define IXGBE_LINK_SPEED_100_FULL 0x0008
+#define IXGBE_LINK_SPEED_1GB_FULL 0x0020
+#define IXGBE_LINK_SPEED_2_5GB_FULL 0x0400
+#define IXGBE_LINK_SPEED_5GB_FULL 0x0800
+#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
#define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \
IXGBE_LINK_SPEED_10GB_FULL)
#define IXGBE_LINK_SPEED_82599_AUTONEG (IXGBE_LINK_SPEED_100_FULL | \
ixgbe_mac_82598EB,
ixgbe_mac_82599EB,
ixgbe_mac_X540,
+ ixgbe_mac_X550,
+ ixgbe_mac_X550EM_x,
ixgbe_num_macs
};
MVNETA_GMAC_FORCE_LINK_DOWN);
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
mvneta_port_up(pp);
- netdev_info(pp->dev, "link up\n");
} else {
mvneta_port_down(pp);
- netdev_info(pp->dev, "link down\n");
}
+ phy_print_status(phydev);
}
}
#define SDMA_CMD_ERD (1 << 7)
/* Bit definitions of the Port Config Reg */
+#define PCR_DUPLEX_FULL (1 << 15)
#define PCR_HS (1 << 12)
#define PCR_EN (1 << 7)
#define PCR_PM (1 << 0)
/* Bit definitions of the Port Config Extend Reg */
#define PCXR_2BSM (1 << 28)
#define PCXR_DSCP_EN (1 << 21)
+#define PCXR_RMII_EN (1 << 20)
+#define PCXR_AN_SPEED_DIS (1 << 19)
+#define PCXR_SPEED_100 (1 << 18)
#define PCXR_MFL_1518 (0 << 14)
#define PCXR_MFL_1536 (1 << 14)
#define PCXR_MFL_2048 (2 << 14)
#define PCXR_MFL_64K (3 << 14)
+#define PCXR_FLOWCTL_DIS (1 << 12)
#define PCXR_FLP (1 << 11)
+#define PCXR_AN_FLOWCTL_DIS (1 << 10)
+#define PCXR_AN_DUPLEX_DIS (1 << 9)
#define PCXR_PRIO_TX_OFF 3
#define PCXR_TX_HIGH_PRI (7 << PCXR_PRIO_TX_OFF)
#define LINK_UP (1 << 3)
/* Bit definitions for work to be done */
-#define WORK_LINK (1 << 0)
#define WORK_TX_DONE (1 << 1)
/*
struct pxa168_eth_private {
int port_num; /* User Ethernet port number */
int phy_addr;
+ int phy_speed;
+ int phy_duplex;
+ phy_interface_t phy_intf;
int rx_resource_err; /* Rx ring resource error flag */
static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static int pxa168_init_hw(struct pxa168_eth_private *pep);
+static int pxa168_init_phy(struct net_device *dev);
static void eth_port_reset(struct net_device *dev);
static void eth_port_start(struct net_device *dev);
static int pxa168_eth_open(struct net_device *dev);
static int pxa168_eth_stop(struct net_device *dev);
-static int ethernet_phy_setup(struct net_device *dev);
static inline u32 rdl(struct pxa168_eth_private *pep, int offset)
{
netdev_err(pep->dev, "%s : DMA Stuck\n", __func__);
}
-static int ethernet_phy_get(struct pxa168_eth_private *pep)
-{
- unsigned int reg_data;
-
- reg_data = rdl(pep, PHY_ADDRESS);
-
- return (reg_data >> (5 * pep->port_num)) & 0x1f;
-}
-
-static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr)
-{
- u32 reg_data;
- int addr_shift = 5 * pep->port_num;
-
- reg_data = rdl(pep, PHY_ADDRESS);
- reg_data &= ~(0x1f << addr_shift);
- reg_data |= (phy_addr & 0x1f) << addr_shift;
- wrl(pep, PHY_ADDRESS, reg_data);
-}
-
static void rxq_refill(struct net_device *dev)
{
struct pxa168_eth_private *pep = netdev_priv(dev);
struct pxa168_eth_private *pep = netdev_priv(dev);
int tx_curr_desc, rx_curr_desc;
- /* Perform PHY reset, if there is a PHY. */
- if (pep->phy != NULL) {
- struct ethtool_cmd cmd;
-
- pxa168_get_settings(pep->dev, &cmd);
- phy_init_hw(pep->phy);
- pxa168_set_settings(pep->dev, &cmd);
- }
+ phy_start(pep->phy);
/* Assignment of Tx CTRP of given queue */
tx_curr_desc = pep->tx_curr_desc_q;
val = rdl(pep, PORT_CONFIG);
val &= ~PCR_EN;
wrl(pep, PORT_CONFIG, val);
+
+ phy_stop(pep->phy);
}
/*
}
if (icr & ICR_RXBUF)
ret = 1;
- if (icr & ICR_MII_CH) {
- pep->work_todo |= WORK_LINK;
- ret = 1;
- }
return ret;
}
-static void handle_link_event(struct pxa168_eth_private *pep)
-{
- struct net_device *dev = pep->dev;
- u32 port_status;
- int speed;
- int duplex;
- int fc;
-
- port_status = rdl(pep, PORT_STATUS);
- if (!(port_status & LINK_UP)) {
- if (netif_carrier_ok(dev)) {
- netdev_info(dev, "link down\n");
- netif_carrier_off(dev);
- txq_reclaim(dev, 1);
- }
- return;
- }
- if (port_status & PORT_SPEED_100)
- speed = 100;
- else
- speed = 10;
-
- duplex = (port_status & FULL_DUPLEX) ? 1 : 0;
- fc = (port_status & FLOW_CONTROL_DISABLED) ? 0 : 1;
- netdev_info(dev, "link up, %d Mb/s, %s duplex, flow control %sabled\n",
- speed, duplex ? "full" : "half", fc ? "en" : "dis");
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
-}
-
static irqreturn_t pxa168_eth_int_handler(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
skb_size = PCXR_MFL_64K;
/* Extended Port Configuration */
- wrl(pep,
- PORT_CONFIG_EXT, PCXR_2BSM | /* Two byte prefix aligns IP hdr */
+ wrl(pep, PORT_CONFIG_EXT,
+ PCXR_AN_SPEED_DIS | /* Disable HW AN */
+ PCXR_AN_DUPLEX_DIS |
+ PCXR_AN_FLOWCTL_DIS |
+ PCXR_2BSM | /* Two byte prefix aligns IP hdr */
PCXR_DSCP_EN | /* Enable DSCP in IP */
skb_size | PCXR_FLP | /* do not force link pass */
PCXR_TX_HIGH_PRI); /* Transmit - high priority queue */
return 0;
}
+static void pxa168_eth_adjust_link(struct net_device *dev)
+{
+ struct pxa168_eth_private *pep = netdev_priv(dev);
+ struct phy_device *phy = pep->phy;
+ u32 cfg, cfg_o = rdl(pep, PORT_CONFIG);
+ u32 cfgext, cfgext_o = rdl(pep, PORT_CONFIG_EXT);
+
+ cfg = cfg_o & ~PCR_DUPLEX_FULL;
+ cfgext = cfgext_o & ~(PCXR_SPEED_100 | PCXR_FLOWCTL_DIS | PCXR_RMII_EN);
+
+ if (phy->interface == PHY_INTERFACE_MODE_RMII)
+ cfgext |= PCXR_RMII_EN;
+ if (phy->speed == SPEED_100)
+ cfgext |= PCXR_SPEED_100;
+ if (phy->duplex)
+ cfg |= PCR_DUPLEX_FULL;
+ if (!phy->pause)
+ cfgext |= PCXR_FLOWCTL_DIS;
+
+ /* Bail out if there has nothing changed */
+ if (cfg == cfg_o && cfgext == cfgext_o)
+ return;
+
+ wrl(pep, PORT_CONFIG, cfg);
+ wrl(pep, PORT_CONFIG_EXT, cfgext);
+
+ phy_print_status(phy);
+}
+
+static int pxa168_init_phy(struct net_device *dev)
+{
+ struct pxa168_eth_private *pep = netdev_priv(dev);
+ struct ethtool_cmd cmd;
+ int err;
+
+ if (pep->phy)
+ return 0;
+
+ pep->phy = mdiobus_scan(pep->smi_bus, pep->phy_addr);
+ if (!pep->phy)
+ return -ENODEV;
+
+ err = phy_connect_direct(dev, pep->phy, pxa168_eth_adjust_link,
+ pep->phy_intf);
+ if (err)
+ return err;
+
+ err = pxa168_get_settings(dev, &cmd);
+ if (err)
+ return err;
+
+ cmd.phy_address = pep->phy_addr;
+ cmd.speed = pep->phy_speed;
+ cmd.duplex = pep->phy_duplex;
+ cmd.advertising = PHY_BASIC_FEATURES;
+ cmd.autoneg = AUTONEG_ENABLE;
+
+ if (cmd.speed != 0)
+ cmd.autoneg = AUTONEG_DISABLE;
+
+ return pxa168_set_settings(dev, &cmd);
+}
+
static int pxa168_init_hw(struct pxa168_eth_private *pep)
{
int err = 0;
struct pxa168_eth_private *pep = netdev_priv(dev);
int err;
+ err = pxa168_init_phy(dev);
+ if (err)
+ return err;
+
err = request_irq(dev->irq, pxa168_eth_int_handler, 0, dev->name, dev);
if (err) {
dev_err(&dev->dev, "can't assign irq\n");
struct net_device *dev = pep->dev;
int work_done = 0;
- if (unlikely(pep->work_todo & WORK_LINK)) {
- pep->work_todo &= ~(WORK_LINK);
- handle_link_event(pep);
- }
/*
* We call txq_reclaim every time since in NAPI interupts are disabled
* and due to this we miss the TX_DONE interrupt,which is not updated in
return -EOPNOTSUPP;
}
-static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr)
-{
- struct mii_bus *bus = pep->smi_bus;
- struct phy_device *phydev;
- int start;
- int num;
- int i;
-
- if (phy_addr == PXA168_ETH_PHY_ADDR_DEFAULT) {
- /* Scan entire range */
- start = ethernet_phy_get(pep);
- num = 32;
- } else {
- /* Use phy addr specific to platform */
- start = phy_addr & 0x1f;
- num = 1;
- }
- phydev = NULL;
- for (i = 0; i < num; i++) {
- int addr = (start + i) & 0x1f;
- if (bus->phy_map[addr] == NULL)
- mdiobus_scan(bus, addr);
-
- if (phydev == NULL) {
- phydev = bus->phy_map[addr];
- if (phydev != NULL)
- ethernet_phy_set_addr(pep, addr);
- }
- }
-
- return phydev;
-}
-
-static void phy_init(struct pxa168_eth_private *pep)
-{
- struct phy_device *phy = pep->phy;
-
- phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII);
-
- if (pep->pd && pep->pd->speed != 0) {
- phy->autoneg = AUTONEG_DISABLE;
- phy->advertising = 0;
- phy->speed = pep->pd->speed;
- phy->duplex = pep->pd->duplex;
- } else {
- phy->autoneg = AUTONEG_ENABLE;
- phy->speed = 0;
- phy->duplex = 0;
- phy->supported &= PHY_BASIC_FEATURES;
- phy->advertising = phy->supported | ADVERTISED_Autoneg;
- }
-
- phy_start_aneg(phy);
-}
-
-static int ethernet_phy_setup(struct net_device *dev)
-{
- struct pxa168_eth_private *pep = netdev_priv(dev);
-
- if (pep->pd && pep->pd->init)
- pep->pd->init();
-
- pep->phy = phy_scan(pep, pep->phy_addr & 0x1f);
- if (pep->phy != NULL)
- phy_init(pep);
-
- update_hash_table_mac_address(pep, NULL, dev->dev_addr);
-
- return 0;
-}
-
static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct pxa168_eth_private *pep = netdev_priv(dev);
pep = netdev_priv(dev);
pep->dev = dev;
pep->clk = clk;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- err = -ENODEV;
- goto err_netdev;
- }
pep->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pep->base)) {
err = -ENOMEM;
goto err_netdev;
}
+
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
BUG_ON(!res);
dev->irq = res->start;
pep->port_num = pep->pd->port_number;
pep->phy_addr = pep->pd->phy_addr;
+ pep->phy_speed = pep->pd->speed;
+ pep->phy_duplex = pep->pd->duplex;
+ pep->phy_intf = pep->pd->intf;
+
+ if (pep->pd->init)
+ pep->pd->init();
} else if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node, "port-id",
&pep->port_num);
np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
- if (np)
- of_property_read_u32(np, "reg", &pep->phy_addr);
+ if (!np) {
+ dev_err(&pdev->dev, "missing phy-handle\n");
+ return -EINVAL;
+ }
+ of_property_read_u32(np, "reg", &pep->phy_addr);
+ pep->phy_intf = of_get_phy_mode(pdev->dev.of_node);
}
/* Hardware supports only 3 ports */
if (err)
goto err_free_mdio;
- pxa168_init_hw(pep);
- err = ethernet_phy_setup(dev);
- if (err)
- goto err_mdiobus;
SET_NETDEV_DEV(dev, &pdev->dev);
+ pxa168_init_hw(pep);
err = register_netdev(dev);
if (err)
goto err_mdiobus;
pep->htpr, pep->htpr_dma);
pep->htpr = NULL;
}
+ if (pep->phy)
+ phy_disconnect(pep->phy);
if (pep->clk) {
clk_disable(pep->clk);
clk_put(pep->clk);
pep->clk = NULL;
}
- if (pep->phy != NULL)
- phy_detach(pep->phy);
iounmap(pep->base);
pep->base = NULL;
{
.opcode = MLX4_CMD_CONFIG_DEV,
.has_inbox = false,
- .has_outbox = false,
+ .has_outbox = true,
.out_is_imm = false,
.encode_slave_id = false,
.verify = NULL,
- .wrapper = mlx4_CMD_EPERM_wrapper
+ .wrapper = mlx4_CONFIG_DEV_wrapper
},
{
.opcode = MLX4_CMD_ALLOC_RES,
.verify = NULL,
.wrapper = mlx4_QUERY_IF_STAT_wrapper
},
+ {
+ .opcode = MLX4_CMD_ACCESS_REG,
+ .has_inbox = true,
+ .has_outbox = true,
+ .out_is_imm = false,
+ .encode_slave_id = false,
+ .verify = NULL,
+ .wrapper = mlx4_ACCESS_REG_wrapper,
+ },
/* Native multicast commands are not available for guests */
{
.opcode = MLX4_CMD_QP_ATTACH,
int mlx4_cmd_init(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
+ int flags = 0;
+
+ if (!priv->cmd.initialized) {
+ mutex_init(&priv->cmd.hcr_mutex);
+ mutex_init(&priv->cmd.slave_cmd_mutex);
+ sema_init(&priv->cmd.poll_sem, 1);
+ priv->cmd.use_events = 0;
+ priv->cmd.toggle = 1;
+ priv->cmd.initialized = 1;
+ flags |= MLX4_CMD_CLEANUP_STRUCT;
+ }
- mutex_init(&priv->cmd.hcr_mutex);
- mutex_init(&priv->cmd.slave_cmd_mutex);
- sema_init(&priv->cmd.poll_sem, 1);
- priv->cmd.use_events = 0;
- priv->cmd.toggle = 1;
-
- priv->cmd.hcr = NULL;
- priv->mfunc.vhcr = NULL;
-
- if (!mlx4_is_slave(dev)) {
+ if (!mlx4_is_slave(dev) && !priv->cmd.hcr) {
priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) +
MLX4_HCR_BASE, MLX4_HCR_SIZE);
if (!priv->cmd.hcr) {
mlx4_err(dev, "Couldn't map command register\n");
- return -ENOMEM;
+ goto err;
}
+ flags |= MLX4_CMD_CLEANUP_HCR;
}
- if (mlx4_is_mfunc(dev)) {
+ if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) {
priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE,
&priv->mfunc.vhcr_dma,
GFP_KERNEL);
if (!priv->mfunc.vhcr)
- goto err_hcr;
+ goto err;
+
+ flags |= MLX4_CMD_CLEANUP_VHCR;
}
- priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
- MLX4_MAILBOX_SIZE,
- MLX4_MAILBOX_SIZE, 0);
- if (!priv->cmd.pool)
- goto err_vhcr;
+ if (!priv->cmd.pool) {
+ priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
+ MLX4_MAILBOX_SIZE,
+ MLX4_MAILBOX_SIZE, 0);
+ if (!priv->cmd.pool)
+ goto err;
- return 0;
+ flags |= MLX4_CMD_CLEANUP_POOL;
+ }
-err_vhcr:
- if (mlx4_is_mfunc(dev))
- dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
- priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
- priv->mfunc.vhcr = NULL;
+ return 0;
-err_hcr:
- if (!mlx4_is_slave(dev))
- iounmap(priv->cmd.hcr);
+err:
+ mlx4_cmd_cleanup(dev, flags);
return -ENOMEM;
}
iounmap(priv->mfunc.comm);
}
-void mlx4_cmd_cleanup(struct mlx4_dev *dev)
+void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- pci_pool_destroy(priv->cmd.pool);
+ if (priv->cmd.pool && (cleanup_mask & MLX4_CMD_CLEANUP_POOL)) {
+ pci_pool_destroy(priv->cmd.pool);
+ priv->cmd.pool = NULL;
+ }
- if (!mlx4_is_slave(dev))
+ if (!mlx4_is_slave(dev) && priv->cmd.hcr &&
+ (cleanup_mask & MLX4_CMD_CLEANUP_HCR)) {
iounmap(priv->cmd.hcr);
- if (mlx4_is_mfunc(dev))
+ priv->cmd.hcr = NULL;
+ }
+ if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr &&
+ (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) {
dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
- priv->mfunc.vhcr = NULL;
+ priv->mfunc.vhcr = NULL;
+ }
+ if (priv->cmd.initialized && (cleanup_mask & MLX4_CMD_CLEANUP_STRUCT))
+ priv->cmd.initialized = 0;
}
/*
#include "mlx4_en.h"
-int mlx4_en_timestamp_config(struct net_device *dev, int tx_type, int rx_filter)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int port_up = 0;
- int err = 0;
-
- if (priv->hwtstamp_config.tx_type == tx_type &&
- priv->hwtstamp_config.rx_filter == rx_filter)
- return 0;
-
- mutex_lock(&mdev->state_lock);
- if (priv->port_up) {
- port_up = 1;
- mlx4_en_stop_port(dev, 1);
- }
-
- mlx4_en_free_resources(priv);
-
- en_warn(priv, "Changing Time Stamp configuration\n");
-
- priv->hwtstamp_config.tx_type = tx_type;
- priv->hwtstamp_config.rx_filter = rx_filter;
-
- if (rx_filter != HWTSTAMP_FILTER_NONE)
- dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
- else
- dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
-
- err = mlx4_en_alloc_resources(priv);
- if (err) {
- en_err(priv, "Failed reallocating port resources\n");
- goto out;
- }
- if (port_up) {
- err = mlx4_en_start_port(dev);
- if (err)
- en_err(priv, "Failed starting port\n");
- }
-
-out:
- mutex_unlock(&mdev->state_lock);
- netdev_features_change(dev);
- return err;
-}
-
/* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
*/
static cycle_t mlx4_en_read_clock(const struct cyclecounter *tc)
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/mlx4/driver.h>
+#include <linux/mlx4/device.h>
#include <linux/in.h>
#include <net/ip.h>
"tso_packets",
"xmit_more",
"queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
- "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
+ "rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload",
/* packet statistics */
"broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
}
}
-static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static u32 mlx4_en_autoneg_get(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ u32 autoneg = AUTONEG_DISABLE;
+
+ if ((mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP) &&
+ (priv->port_state.flags & MLX4_EN_PORT_ANE))
+ autoneg = AUTONEG_ENABLE;
+
+ return autoneg;
+}
+
+static u32 ptys_get_supported_port(struct mlx4_ptys_reg *ptys_reg)
+{
+ u32 eth_proto = be32_to_cpu(ptys_reg->eth_proto_cap);
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_T)
+ | MLX4_PROT_MASK(MLX4_1000BASE_T)
+ | MLX4_PROT_MASK(MLX4_100BASE_TX))) {
+ return SUPPORTED_TP;
+ }
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR)
+ | MLX4_PROT_MASK(MLX4_10GBASE_SR)
+ | MLX4_PROT_MASK(MLX4_56GBASE_SR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_CR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_SR4)
+ | MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII))) {
+ return SUPPORTED_FIBRE;
+ }
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_KR4)
+ | MLX4_PROT_MASK(MLX4_20GBASE_KR2)
+ | MLX4_PROT_MASK(MLX4_10GBASE_KR)
+ | MLX4_PROT_MASK(MLX4_10GBASE_KX4)
+ | MLX4_PROT_MASK(MLX4_1000BASE_KX))) {
+ return SUPPORTED_Backplane;
+ }
+ return 0;
+}
+
+static u32 ptys_get_active_port(struct mlx4_ptys_reg *ptys_reg)
+{
+ u32 eth_proto = be32_to_cpu(ptys_reg->eth_proto_oper);
+
+ if (!eth_proto) /* link down */
+ eth_proto = be32_to_cpu(ptys_reg->eth_proto_cap);
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_T)
+ | MLX4_PROT_MASK(MLX4_1000BASE_T)
+ | MLX4_PROT_MASK(MLX4_100BASE_TX))) {
+ return PORT_TP;
+ }
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_SR)
+ | MLX4_PROT_MASK(MLX4_56GBASE_SR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_SR4)
+ | MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII))) {
+ return PORT_FIBRE;
+ }
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR)
+ | MLX4_PROT_MASK(MLX4_56GBASE_CR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_CR4))) {
+ return PORT_DA;
+ }
+
+ if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4)
+ | MLX4_PROT_MASK(MLX4_40GBASE_KR4)
+ | MLX4_PROT_MASK(MLX4_20GBASE_KR2)
+ | MLX4_PROT_MASK(MLX4_10GBASE_KR)
+ | MLX4_PROT_MASK(MLX4_10GBASE_KX4)
+ | MLX4_PROT_MASK(MLX4_1000BASE_KX))) {
+ return PORT_NONE;
+ }
+ return PORT_OTHER;
+}
+
+#define MLX4_LINK_MODES_SZ \
+ (FIELD_SIZEOF(struct mlx4_ptys_reg, eth_proto_cap) * 8)
+
+enum ethtool_report {
+ SUPPORTED = 0,
+ ADVERTISED = 1,
+ SPEED = 2
+};
+
+/* Translates mlx4 link mode to equivalent ethtool Link modes/speed */
+static u32 ptys2ethtool_map[MLX4_LINK_MODES_SZ][3] = {
+ [MLX4_100BASE_TX] = {
+ SUPPORTED_100baseT_Full,
+ ADVERTISED_100baseT_Full,
+ SPEED_100
+ },
+
+ [MLX4_1000BASE_T] = {
+ SUPPORTED_1000baseT_Full,
+ ADVERTISED_1000baseT_Full,
+ SPEED_1000
+ },
+ [MLX4_1000BASE_CX_SGMII] = {
+ SUPPORTED_1000baseKX_Full,
+ ADVERTISED_1000baseKX_Full,
+ SPEED_1000
+ },
+ [MLX4_1000BASE_KX] = {
+ SUPPORTED_1000baseKX_Full,
+ ADVERTISED_1000baseKX_Full,
+ SPEED_1000
+ },
+
+ [MLX4_10GBASE_T] = {
+ SUPPORTED_10000baseT_Full,
+ ADVERTISED_10000baseT_Full,
+ SPEED_10000
+ },
+ [MLX4_10GBASE_CX4] = {
+ SUPPORTED_10000baseKX4_Full,
+ ADVERTISED_10000baseKX4_Full,
+ SPEED_10000
+ },
+ [MLX4_10GBASE_KX4] = {
+ SUPPORTED_10000baseKX4_Full,
+ ADVERTISED_10000baseKX4_Full,
+ SPEED_10000
+ },
+ [MLX4_10GBASE_KR] = {
+ SUPPORTED_10000baseKR_Full,
+ ADVERTISED_10000baseKR_Full,
+ SPEED_10000
+ },
+ [MLX4_10GBASE_CR] = {
+ SUPPORTED_10000baseKR_Full,
+ ADVERTISED_10000baseKR_Full,
+ SPEED_10000
+ },
+ [MLX4_10GBASE_SR] = {
+ SUPPORTED_10000baseKR_Full,
+ ADVERTISED_10000baseKR_Full,
+ SPEED_10000
+ },
+
+ [MLX4_20GBASE_KR2] = {
+ SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full,
+ ADVERTISED_20000baseMLD2_Full | ADVERTISED_20000baseKR2_Full,
+ SPEED_20000
+ },
+
+ [MLX4_40GBASE_CR4] = {
+ SUPPORTED_40000baseCR4_Full,
+ ADVERTISED_40000baseCR4_Full,
+ SPEED_40000
+ },
+ [MLX4_40GBASE_KR4] = {
+ SUPPORTED_40000baseKR4_Full,
+ ADVERTISED_40000baseKR4_Full,
+ SPEED_40000
+ },
+ [MLX4_40GBASE_SR4] = {
+ SUPPORTED_40000baseSR4_Full,
+ ADVERTISED_40000baseSR4_Full,
+ SPEED_40000
+ },
+
+ [MLX4_56GBASE_KR4] = {
+ SUPPORTED_56000baseKR4_Full,
+ ADVERTISED_56000baseKR4_Full,
+ SPEED_56000
+ },
+ [MLX4_56GBASE_CR4] = {
+ SUPPORTED_56000baseCR4_Full,
+ ADVERTISED_56000baseCR4_Full,
+ SPEED_56000
+ },
+ [MLX4_56GBASE_SR4] = {
+ SUPPORTED_56000baseSR4_Full,
+ ADVERTISED_56000baseSR4_Full,
+ SPEED_56000
+ },
+};
+
+static u32 ptys2ethtool_link_modes(u32 eth_proto, enum ethtool_report report)
+{
+ int i;
+ u32 link_modes = 0;
+
+ for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
+ if (eth_proto & MLX4_PROT_MASK(i))
+ link_modes |= ptys2ethtool_map[i][report];
+ }
+ return link_modes;
+}
+
+static u32 ethtool2ptys_link_modes(u32 link_modes, enum ethtool_report report)
+{
+ int i;
+ u32 ptys_modes = 0;
+
+ for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
+ if (ptys2ethtool_map[i][report] & link_modes)
+ ptys_modes |= 1 << i;
+ }
+ return ptys_modes;
+}
+
+/* Convert actual speed (SPEED_XXX) to ptys link modes */
+static u32 speed2ptys_link_modes(u32 speed)
+{
+ int i;
+ u32 ptys_modes = 0;
+
+ for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
+ if (ptys2ethtool_map[i][SPEED] == speed)
+ ptys_modes |= 1 << i;
+ }
+ return ptys_modes;
+}
+
+static int ethtool_get_ptys_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_ptys_reg ptys_reg;
+ u32 eth_proto;
+ int ret;
+
+ memset(&ptys_reg, 0, sizeof(ptys_reg));
+ ptys_reg.local_port = priv->port;
+ ptys_reg.proto_mask = MLX4_PTYS_EN;
+ ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev,
+ MLX4_ACCESS_REG_QUERY, &ptys_reg);
+ if (ret) {
+ en_warn(priv, "Failed to run mlx4_ACCESS_PTYS_REG status(%x)",
+ ret);
+ return ret;
+ }
+ en_dbg(DRV, priv, "ptys_reg.proto_mask %x\n",
+ ptys_reg.proto_mask);
+ en_dbg(DRV, priv, "ptys_reg.eth_proto_cap %x\n",
+ be32_to_cpu(ptys_reg.eth_proto_cap));
+ en_dbg(DRV, priv, "ptys_reg.eth_proto_admin %x\n",
+ be32_to_cpu(ptys_reg.eth_proto_admin));
+ en_dbg(DRV, priv, "ptys_reg.eth_proto_oper %x\n",
+ be32_to_cpu(ptys_reg.eth_proto_oper));
+ en_dbg(DRV, priv, "ptys_reg.eth_proto_lp_adv %x\n",
+ be32_to_cpu(ptys_reg.eth_proto_lp_adv));
+
+ cmd->supported = 0;
+ cmd->advertising = 0;
+
+ cmd->supported |= ptys_get_supported_port(&ptys_reg);
+
+ eth_proto = be32_to_cpu(ptys_reg.eth_proto_cap);
+ cmd->supported |= ptys2ethtool_link_modes(eth_proto, SUPPORTED);
+
+ eth_proto = be32_to_cpu(ptys_reg.eth_proto_admin);
+ cmd->advertising |= ptys2ethtool_link_modes(eth_proto, ADVERTISED);
+
+ cmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ cmd->advertising |= (priv->prof->tx_pause) ? ADVERTISED_Pause : 0;
+
+ cmd->advertising |= (priv->prof->tx_pause ^ priv->prof->rx_pause) ?
+ ADVERTISED_Asym_Pause : 0;
+
+ cmd->port = ptys_get_active_port(&ptys_reg);
+ cmd->transceiver = (SUPPORTED_TP & cmd->supported) ?
+ XCVR_EXTERNAL : XCVR_INTERNAL;
+
+ if (mlx4_en_autoneg_get(dev)) {
+ cmd->supported |= SUPPORTED_Autoneg;
+ cmd->advertising |= ADVERTISED_Autoneg;
+ }
+
+ cmd->autoneg = (priv->port_state.flags & MLX4_EN_PORT_ANC) ?
+ AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ eth_proto = be32_to_cpu(ptys_reg.eth_proto_lp_adv);
+ cmd->lp_advertising = ptys2ethtool_link_modes(eth_proto, ADVERTISED);
+
+ cmd->lp_advertising |= (priv->port_state.flags & MLX4_EN_PORT_ANC) ?
+ ADVERTISED_Autoneg : 0;
+
+ cmd->phy_address = 0;
+ cmd->mdio_support = 0;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
+ cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
+
+ return ret;
+}
+
+static void ethtool_get_default_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
int trans_type;
cmd->autoneg = AUTONEG_DISABLE;
cmd->supported = SUPPORTED_10000baseT_Full;
cmd->advertising = ADVERTISED_10000baseT_Full;
-
- if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
- return -ENOMEM;
-
- trans_type = priv->port_state.transciver;
- if (netif_carrier_ok(dev)) {
- ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
- cmd->duplex = DUPLEX_FULL;
- } else {
- ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
- cmd->duplex = DUPLEX_UNKNOWN;
- }
+ trans_type = priv->port_state.transceiver;
if (trans_type > 0 && trans_type <= 0xC) {
cmd->port = PORT_FIBRE;
cmd->port = -1;
cmd->transceiver = -1;
}
+}
+
+static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ int ret = -EINVAL;
+
+ if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+ return -ENOMEM;
+
+ en_dbg(DRV, priv, "query port state.flags ANC(%x) ANE(%x)\n",
+ priv->port_state.flags & MLX4_EN_PORT_ANC,
+ priv->port_state.flags & MLX4_EN_PORT_ANE);
+
+ if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL)
+ ret = ethtool_get_ptys_settings(dev, cmd);
+ if (ret) /* ETH PROT CRTL is not supported or PTYS CMD failed */
+ ethtool_get_default_settings(dev, cmd);
+
+ if (netif_carrier_ok(dev)) {
+ ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
+ cmd->duplex = DUPLEX_FULL;
+ } else {
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ cmd->duplex = DUPLEX_UNKNOWN;
+ }
return 0;
}
+/* Calculate PTYS admin according ethtool speed (SPEED_XXX) */
+static __be32 speed_set_ptys_admin(struct mlx4_en_priv *priv, u32 speed,
+ __be32 proto_cap)
+{
+ __be32 proto_admin = 0;
+
+ if (!speed) { /* Speed = 0 ==> Reset Link modes */
+ proto_admin = proto_cap;
+ en_info(priv, "Speed was set to 0, Reset advertised Link Modes to default (%x)\n",
+ be32_to_cpu(proto_cap));
+ } else {
+ u32 ptys_link_modes = speed2ptys_link_modes(speed);
+
+ proto_admin = cpu_to_be32(ptys_link_modes) & proto_cap;
+ en_info(priv, "Setting Speed to %d\n", speed);
+ }
+ return proto_admin;
+}
+
static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- if ((cmd->autoneg == AUTONEG_ENABLE) ||
- (ethtool_cmd_speed(cmd) != SPEED_10000) ||
- (cmd->duplex != DUPLEX_FULL))
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_ptys_reg ptys_reg;
+ __be32 proto_admin;
+ int ret;
+
+ u32 ptys_adv = ethtool2ptys_link_modes(cmd->advertising, ADVERTISED);
+ int speed = ethtool_cmd_speed(cmd);
+
+ en_dbg(DRV, priv, "Set Speed=%d adv=0x%x autoneg=%d duplex=%d\n",
+ speed, cmd->advertising, cmd->autoneg, cmd->duplex);
+
+ if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL) ||
+ (cmd->autoneg == AUTONEG_ENABLE) || (cmd->duplex == DUPLEX_HALF))
return -EINVAL;
- /* Nothing to change */
+ memset(&ptys_reg, 0, sizeof(ptys_reg));
+ ptys_reg.local_port = priv->port;
+ ptys_reg.proto_mask = MLX4_PTYS_EN;
+ ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev,
+ MLX4_ACCESS_REG_QUERY, &ptys_reg);
+ if (ret) {
+ en_warn(priv, "Failed to QUERY mlx4_ACCESS_PTYS_REG status(%x)\n",
+ ret);
+ return 0;
+ }
+
+ proto_admin = cpu_to_be32(ptys_adv);
+ if (speed >= 0 && speed != priv->port_state.link_speed)
+ /* If speed was set then speed decides :-) */
+ proto_admin = speed_set_ptys_admin(priv, speed,
+ ptys_reg.eth_proto_cap);
+
+ proto_admin &= ptys_reg.eth_proto_cap;
+
+ if (proto_admin == ptys_reg.eth_proto_admin)
+ return 0; /* Nothing to change */
+
+ if (!proto_admin) {
+ en_warn(priv, "Not supported link mode(s) requested, check supported link modes.\n");
+ return -EINVAL; /* nothing to change due to bad input */
+ }
+
+ en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n",
+ be32_to_cpu(proto_admin));
+
+ ptys_reg.eth_proto_admin = proto_admin;
+ ret = mlx4_ACCESS_PTYS_REG(priv->mdev->dev, MLX4_ACCESS_REG_WRITE,
+ &ptys_reg);
+ if (ret) {
+ en_warn(priv, "Failed to write mlx4_ACCESS_PTYS_REG eth_proto_admin(0x%x) status(0x%x)",
+ be32_to_cpu(ptys_reg.eth_proto_admin), ret);
+ return ret;
+ }
+
+ en_warn(priv, "Port link mode changed, restarting port...\n");
+ mutex_lock(&priv->mdev->state_lock);
+ if (priv->port_up) {
+ mlx4_en_stop_port(dev, 1);
+ if (mlx4_en_start_port(dev))
+ en_err(priv, "Failed restarting port %d\n", priv->port);
+ }
+ mutex_unlock(&priv->mdev->state_lock);
return 0;
}
int err = 0;
rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num;
+ rss_rings = 1 << ilog2(rss_rings);
while (n--) {
ring_index[n] = rss_map->qps[n % rss_rings].qpn -
return ret;
}
+static int mlx4_en_get_module_info(struct net_device *dev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int ret;
+ u8 data[4];
+
+ /* Read first 2 bytes to get Module & REV ID */
+ ret = mlx4_get_module_info(mdev->dev, priv->port,
+ 0/*offset*/, 2/*size*/, data);
+ if (ret < 2)
+ return -EIO;
+
+ switch (data[0] /* identifier */) {
+ case MLX4_MODULE_ID_QSFP:
+ modinfo->type = ETH_MODULE_SFF_8436;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+ break;
+ case MLX4_MODULE_ID_QSFP_PLUS:
+ if (data[1] >= 0x3) { /* revision id */
+ modinfo->type = ETH_MODULE_SFF_8636;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ } else {
+ modinfo->type = ETH_MODULE_SFF_8436;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+ }
+ break;
+ case MLX4_MODULE_ID_QSFP28:
+ modinfo->type = ETH_MODULE_SFF_8636;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ break;
+ case MLX4_MODULE_ID_SFP:
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+static int mlx4_en_get_module_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *ee,
+ u8 *data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int offset = ee->offset;
+ int i = 0, ret;
+
+ if (ee->len == 0)
+ return -EINVAL;
+
+ memset(data, 0, ee->len);
+
+ while (i < ee->len) {
+ en_dbg(DRV, priv,
+ "mlx4_get_module_info i(%d) offset(%d) len(%d)\n",
+ i, offset, ee->len - i);
+
+ ret = mlx4_get_module_info(mdev->dev, priv->port,
+ offset, ee->len - i, data + i);
+
+ if (!ret) /* Done reading */
+ return 0;
+
+ if (ret < 0) {
+ en_err(priv,
+ "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n",
+ i, offset, ee->len - i, ret);
+ return 0;
+ }
+
+ i += ret;
+ offset += ret;
+ }
+ return 0;
+}
const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo,
.get_priv_flags = mlx4_en_get_priv_flags,
.get_tunable = mlx4_en_get_tunable,
.set_tunable = mlx4_en_set_tunable,
+ .get_module_info = mlx4_en_get_module_info,
+ .get_module_eeprom = mlx4_en_get_module_eeprom
};
{
struct mlx4_en_dev *mdev;
int i;
- int err;
printk_once(KERN_INFO "%s", mlx4_en_version);
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
- if (!mdev) {
- err = -ENOMEM;
+ if (!mdev)
goto err_free_res;
- }
if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
goto err_free_dev;
}
/* Build device profile according to supplied module parameters */
- err = mlx4_en_get_profile(mdev);
- if (err) {
+ if (mlx4_en_get_profile(mdev)) {
mlx4_err(mdev, "Bad module parameters, aborting\n");
goto err_mr;
}
* Note: we cannot use the shared workqueue because of deadlocks caused
* by the rtnl lock */
mdev->workqueue = create_singlethread_workqueue("mlx4_en");
- if (!mdev->workqueue) {
- err = -ENOMEM;
+ if (!mdev->workqueue)
goto err_mr;
- }
/* At this stage all non-port specific tasks are complete:
* mark the card state as up */
struct mlx4_mac_entry *entry;
int index = 0;
int err = 0;
- u64 reg_id;
+ u64 reg_id = 0;
int *qpn = &priv->base_qpn;
u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr);
}
local_bh_enable();
- while (test_bit(NAPI_STATE_SCHED, &cq->napi.state))
- msleep(1);
+ napi_synchronize(&cq->napi);
mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]);
mlx4_en_deactivate_cq(priv, cq);
priv->rx_ring[i]->packets = 0;
priv->rx_ring[i]->csum_ok = 0;
priv->rx_ring[i]->csum_none = 0;
+ priv->rx_ring[i]->csum_complete = 0;
}
}
return -ERANGE;
}
- if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
+ if (mlx4_en_reset_config(dev, config, dev->features)) {
config.tx_type = HWTSTAMP_TX_OFF;
config.rx_filter = HWTSTAMP_FILTER_NONE;
}
netdev_features_t features)
{
struct mlx4_en_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) {
+ en_info(priv, "Turn %s RX vlan strip offload\n",
+ (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF");
+ ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config,
+ features);
+ if (ret)
+ return ret;
+ }
if (features & NETIF_F_LOOPBACK)
priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
priv = netdev_priv(dev);
memset(priv, 0, sizeof(struct mlx4_en_priv));
+ spin_lock_init(&priv->stats_lock);
+ INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
+ INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
+ INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
+ INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
+ INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
+#ifdef CONFIG_MLX4_EN_VXLAN
+ INIT_WORK(&priv->vxlan_add_task, mlx4_en_add_vxlan_offloads);
+ INIT_WORK(&priv->vxlan_del_task, mlx4_en_del_vxlan_offloads);
+#endif
+#ifdef CONFIG_RFS_ACCEL
+ INIT_LIST_HEAD(&priv->filters);
+ spin_lock_init(&priv->filters_lock);
+#endif
+
priv->dev = dev;
priv->mdev = mdev;
priv->ddev = &mdev->pdev->dev;
priv->cqe_size = mdev->dev->caps.cqe_size;
priv->mac_index = -1;
priv->msg_enable = MLX4_EN_MSG_LEVEL;
- spin_lock_init(&priv->stats_lock);
- INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
- INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
- INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
- INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
- INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
-#ifdef CONFIG_MLX4_EN_VXLAN
- INIT_WORK(&priv->vxlan_add_task, mlx4_en_add_vxlan_offloads);
- INIT_WORK(&priv->vxlan_del_task, mlx4_en_del_vxlan_offloads);
-#endif
#ifdef CONFIG_MLX4_EN_DCB
if (!mlx4_is_slave(priv->mdev->dev)) {
if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
/* Query for default mac and max mtu */
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
+ if (mdev->dev->caps.rx_checksum_flags_port[priv->port] &
+ MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP)
+ priv->flags |= MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP;
+
/* Set default MAC */
dev->addr_len = ETH_ALEN;
mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
if (err)
goto out;
-#ifdef CONFIG_RFS_ACCEL
- INIT_LIST_HEAD(&priv->filters);
- spin_lock_init(&priv->filters_lock);
-#endif
-
/* Initialize time stamping config */
priv->hwtstamp_config.flags = 0;
priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
dev->features = dev->hw_features | NETIF_F_HIGHDMA |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
- dev->hw_features |= NETIF_F_LOOPBACK;
+ dev->hw_features |= NETIF_F_LOOPBACK |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED)
return err;
}
+int mlx4_en_reset_config(struct net_device *dev,
+ struct hwtstamp_config ts_config,
+ netdev_features_t features)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int port_up = 0;
+ int err = 0;
+
+ if (priv->hwtstamp_config.tx_type == ts_config.tx_type &&
+ priv->hwtstamp_config.rx_filter == ts_config.rx_filter &&
+ !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX))
+ return 0; /* Nothing to change */
+
+ if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) &&
+ (features & NETIF_F_HW_VLAN_CTAG_RX) &&
+ (priv->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE)) {
+ en_warn(priv, "Can't turn ON rx vlan offload while time-stamping rx filter is ON\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&mdev->state_lock);
+ if (priv->port_up) {
+ port_up = 1;
+ mlx4_en_stop_port(dev, 1);
+ }
+
+ mlx4_en_free_resources(priv);
+
+ en_warn(priv, "Changing device configuration rx filter(%x) rx vlan(%x)\n",
+ ts_config.rx_filter, !!(features & NETIF_F_HW_VLAN_CTAG_RX));
+
+ priv->hwtstamp_config.tx_type = ts_config.tx_type;
+ priv->hwtstamp_config.rx_filter = ts_config.rx_filter;
+
+ if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+ else
+ dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+ } else if (ts_config.rx_filter == HWTSTAMP_FILTER_NONE) {
+ /* RX time-stamping is OFF, update the RX vlan offload
+ * to the latest wanted state
+ */
+ if (dev->wanted_features & NETIF_F_HW_VLAN_CTAG_RX)
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+ else
+ dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+ }
+
+ /* RX vlan offload and RX time-stamping can't co-exist !
+ * Regardless of the caller's choice,
+ * Turn Off RX vlan offload in case of time-stamping is ON
+ */
+ if (ts_config.rx_filter != HWTSTAMP_FILTER_NONE) {
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
+ en_warn(priv, "Turning off RX vlan offload since RX time-stamping is ON\n");
+ dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+ }
+
+ err = mlx4_en_alloc_resources(priv);
+ if (err) {
+ en_err(priv, "Failed reallocating port resources\n");
+ goto out;
+ }
+ if (port_up) {
+ err = mlx4_en_start_port(dev);
+ if (err)
+ en_err(priv, "Failed starting port\n");
+ }
+
+out:
+ mutex_unlock(&mdev->state_lock);
+ netdev_features_change(dev);
+ return err;
+}
* already synchronized, no need in locking */
state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK);
switch (qport_context->link_speed & MLX4_EN_SPEED_MASK) {
+ case MLX4_EN_100M_SPEED:
+ state->link_speed = SPEED_100;
+ break;
case MLX4_EN_1G_SPEED:
- state->link_speed = 1000;
+ state->link_speed = SPEED_1000;
break;
case MLX4_EN_10G_SPEED_XAUI:
case MLX4_EN_10G_SPEED_XFI:
- state->link_speed = 10000;
+ state->link_speed = SPEED_10000;
+ break;
+ case MLX4_EN_20G_SPEED:
+ state->link_speed = SPEED_20000;
break;
case MLX4_EN_40G_SPEED:
- state->link_speed = 40000;
+ state->link_speed = SPEED_40000;
+ break;
+ case MLX4_EN_56G_SPEED:
+ state->link_speed = SPEED_56000;
break;
default:
state->link_speed = -1;
break;
}
- state->transciver = qport_context->transceiver;
+
+ state->transceiver = qport_context->transceiver;
+
+ state->flags = 0; /* Reset and recalculate the port flags */
+ state->flags |= (qport_context->link_up & MLX4_EN_ANC_MASK) ?
+ MLX4_EN_PORT_ANC : 0;
+ state->flags |= (qport_context->autoneg & MLX4_EN_AUTONEG_MASK) ?
+ MLX4_EN_PORT_ANE : 0;
out:
mlx4_free_cmd_mailbox(mdev->dev, mailbox);
stats->rx_bytes = 0;
priv->port_stats.rx_chksum_good = 0;
priv->port_stats.rx_chksum_none = 0;
+ priv->port_stats.rx_chksum_complete = 0;
for (i = 0; i < priv->rx_ring_num; i++) {
stats->rx_packets += priv->rx_ring[i]->packets;
stats->rx_bytes += priv->rx_ring[i]->bytes;
priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok;
priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none;
+ priv->port_stats.rx_chksum_complete += priv->rx_ring[i]->csum_complete;
}
stats->tx_packets = 0;
stats->tx_bytes = 0;
MLX4_MCAST_ENABLE = 2,
};
+enum mlx4_link_mode {
+ MLX4_1000BASE_CX_SGMII = 0,
+ MLX4_1000BASE_KX = 1,
+ MLX4_10GBASE_CX4 = 2,
+ MLX4_10GBASE_KX4 = 3,
+ MLX4_10GBASE_KR = 4,
+ MLX4_20GBASE_KR2 = 5,
+ MLX4_40GBASE_CR4 = 6,
+ MLX4_40GBASE_KR4 = 7,
+ MLX4_56GBASE_KR4 = 8,
+ MLX4_10GBASE_CR = 12,
+ MLX4_10GBASE_SR = 13,
+ MLX4_40GBASE_SR4 = 15,
+ MLX4_56GBASE_CR4 = 17,
+ MLX4_56GBASE_SR4 = 18,
+ MLX4_100BASE_TX = 24,
+ MLX4_1000BASE_T = 25,
+ MLX4_10GBASE_T = 26,
+};
+
+#define MLX4_PROT_MASK(link_mode) (1<<link_mode)
+
enum {
- MLX4_EN_1G_SPEED = 0x02,
- MLX4_EN_10G_SPEED_XFI = 0x01,
+ MLX4_EN_100M_SPEED = 0x04,
MLX4_EN_10G_SPEED_XAUI = 0x00,
+ MLX4_EN_10G_SPEED_XFI = 0x01,
+ MLX4_EN_1G_SPEED = 0x02,
+ MLX4_EN_20G_SPEED = 0x08,
MLX4_EN_40G_SPEED = 0x40,
+ MLX4_EN_56G_SPEED = 0x20,
MLX4_EN_OTHER_SPEED = 0x0f,
};
struct mlx4_en_query_port_context {
u8 link_up;
#define MLX4_EN_LINK_UP_MASK 0x80
- u8 reserved;
+#define MLX4_EN_ANC_MASK 0x40
+ u8 autoneg;
+#define MLX4_EN_AUTONEG_MASK 0x80
__be16 mtu;
u8 reserved2;
u8 link_speed;
-#define MLX4_EN_SPEED_MASK 0x43
+#define MLX4_EN_SPEED_MASK 0x6f
u16 reserved3[5];
__be64 mac;
u8 transceiver;
#include <linux/vmalloc.h>
#include <linux/irq.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_checksum.h>
+#endif
+
#include "mlx4_en.h"
static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
page_alloc->page_size = PAGE_SIZE << order;
page_alloc->page = page;
page_alloc->dma = dma;
- page_alloc->page_offset = frag_info->frag_align;
+ page_alloc->page_offset = 0;
/* Not doing get_page() for each frag is a big win
* on asymetric workloads. Note we can not use atomic_set().
*/
out:
while (i--) {
- frag_info = &priv->frag_info[i];
if (page_alloc[i].page != ring_alloc[i].page) {
dma_unmap_page(priv->ddev, page_alloc[i].dma,
page_alloc[i].page_size, PCI_DMA_FROMDEVICE);
const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
if (mlx4_alloc_pages(priv, &ring->page_alloc[i],
- frag_info, GFP_KERNEL))
+ frag_info, GFP_KERNEL | __GFP_COLD))
goto out;
}
return 0;
if (mlx4_en_prepare_rx_desc(priv, ring,
ring->actual_size,
- GFP_KERNEL)) {
+ GFP_KERNEL | __GFP_COLD)) {
if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) {
en_err(priv, "Failed to allocate enough rx buffers\n");
return -ENOMEM;
int index = ring->prod & ring->size_mask;
while ((u32) (ring->prod - ring->cons) < ring->actual_size) {
- if (mlx4_en_prepare_rx_desc(priv, ring, index, GFP_ATOMIC))
+ if (mlx4_en_prepare_rx_desc(priv, ring, index,
+ GFP_ATOMIC | __GFP_COLD))
break;
ring->prod++;
index = ring->prod & ring->size_mask;
}
}
+/* When hardware doesn't strip the vlan, we need to calculate the checksum
+ * over it and add it to the hardware's checksum calculation
+ */
+static inline __wsum get_fixed_vlan_csum(__wsum hw_checksum,
+ struct vlan_hdr *vlanh)
+{
+ return csum_add(hw_checksum, *(__wsum *)vlanh);
+}
+
+/* Although the stack expects checksum which doesn't include the pseudo
+ * header, the HW adds it. To address that, we are subtracting the pseudo
+ * header checksum from the checksum value provided by the HW.
+ */
+static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
+ struct iphdr *iph)
+{
+ __u16 length_for_csum = 0;
+ __wsum csum_pseudo_header = 0;
+
+ length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2));
+ csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+ length_for_csum, iph->protocol, 0);
+ skb->csum = csum_sub(hw_checksum, csum_pseudo_header);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+/* In IPv6 packets, besides subtracting the pseudo header checksum,
+ * we also compute/add the IP header checksum which
+ * is not added by the HW.
+ */
+static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
+ struct ipv6hdr *ipv6h)
+{
+ __wsum csum_pseudo_hdr = 0;
+
+ if (ipv6h->nexthdr == IPPROTO_FRAGMENT || ipv6h->nexthdr == IPPROTO_HOPOPTS)
+ return -1;
+ hw_checksum = csum_add(hw_checksum, (__force __wsum)(ipv6h->nexthdr << 8));
+
+ csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
+ sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
+ csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len);
+ csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr));
+
+ skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr);
+ skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0));
+ return 0;
+}
+#endif
+static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
+ int hwtstamp_rx_filter)
+{
+ __wsum hw_checksum = 0;
+
+ void *hdr = (u8 *)va + sizeof(struct ethhdr);
+
+ hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
+
+ if (((struct ethhdr *)va)->h_proto == htons(ETH_P_8021Q) &&
+ hwtstamp_rx_filter != HWTSTAMP_FILTER_NONE) {
+ /* next protocol non IPv4 or IPv6 */
+ if (((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
+ != htons(ETH_P_IP) &&
+ ((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
+ != htons(ETH_P_IPV6))
+ return -1;
+ hw_checksum = get_fixed_vlan_csum(hw_checksum, hdr);
+ hdr += sizeof(struct vlan_hdr);
+ }
+
+ if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4))
+ get_fixed_ipv4_csum(hw_checksum, skb, hdr);
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
+ if (get_fixed_ipv6_csum(hw_checksum, skb, hdr))
+ return -1;
+#endif
+ return 0;
+}
+
int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
(cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
if (likely(dev->features & NETIF_F_RXCSUM)) {
- if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
- (cqe->checksum == cpu_to_be16(0xffff))) {
- ring->csum_ok++;
- /* This packet is eligible for GRO if it is:
- * - DIX Ethernet (type interpretation)
- * - TCP/IP (v4)
- * - without IP options
- * - not an IP fragment
- * - no LLS polling in progress
- */
- if (!mlx4_en_cq_busy_polling(cq) &&
- (dev->features & NETIF_F_GRO)) {
- struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
- if (!gro_skb)
- goto next;
-
- nr = mlx4_en_complete_rx_desc(priv,
- rx_desc, frags, gro_skb,
- length);
- if (!nr)
- goto next;
-
- skb_shinfo(gro_skb)->nr_frags = nr;
- gro_skb->len = length;
- gro_skb->data_len = length;
- gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
+ MLX4_CQE_STATUS_UDP)) {
+ if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
+ cqe->checksum == cpu_to_be16(0xffff)) {
+ ip_summed = CHECKSUM_UNNECESSARY;
+ ring->csum_ok++;
+ } else {
+ ip_summed = CHECKSUM_NONE;
+ ring->csum_none++;
+ }
+ } else {
+ if (priv->flags & MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP &&
+ (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 |
+ MLX4_CQE_STATUS_IPV6))) {
+ ip_summed = CHECKSUM_COMPLETE;
+ ring->csum_complete++;
+ } else {
+ ip_summed = CHECKSUM_NONE;
+ ring->csum_none++;
+ }
+ }
+ } else {
+ ip_summed = CHECKSUM_NONE;
+ ring->csum_none++;
+ }
- if (l2_tunnel)
- gro_skb->csum_level = 1;
- if ((cqe->vlan_my_qpn &
- cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
- (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
- u16 vid = be16_to_cpu(cqe->sl_vid);
+ /* This packet is eligible for GRO if it is:
+ * - DIX Ethernet (type interpretation)
+ * - TCP/IP (v4)
+ * - without IP options
+ * - not an IP fragment
+ * - no LLS polling in progress
+ */
+ if (!mlx4_en_cq_busy_polling(cq) &&
+ (dev->features & NETIF_F_GRO)) {
+ struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
+ if (!gro_skb)
+ goto next;
+
+ nr = mlx4_en_complete_rx_desc(priv,
+ rx_desc, frags, gro_skb,
+ length);
+ if (!nr)
+ goto next;
+
+ if (ip_summed == CHECKSUM_COMPLETE) {
+ void *va = skb_frag_address(skb_shinfo(gro_skb)->frags);
+ if (check_csum(cqe, gro_skb, va, ring->hwtstamp_rx_filter)) {
+ ip_summed = CHECKSUM_NONE;
+ ring->csum_none++;
+ ring->csum_complete--;
+ }
+ }
- __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
- }
+ skb_shinfo(gro_skb)->nr_frags = nr;
+ gro_skb->len = length;
+ gro_skb->data_len = length;
+ gro_skb->ip_summed = ip_summed;
- if (dev->features & NETIF_F_RXHASH)
- skb_set_hash(gro_skb,
- be32_to_cpu(cqe->immed_rss_invalid),
- PKT_HASH_TYPE_L3);
+ if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
+ gro_skb->encapsulation = 1;
+ if ((cqe->vlan_my_qpn &
+ cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
+ (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
+ u16 vid = be16_to_cpu(cqe->sl_vid);
- skb_record_rx_queue(gro_skb, cq->ring);
- skb_mark_napi_id(gro_skb, &cq->napi);
+ __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
+ }
- if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
- timestamp = mlx4_en_get_cqe_ts(cqe);
- mlx4_en_fill_hwtstamps(mdev,
- skb_hwtstamps(gro_skb),
- timestamp);
- }
+ if (dev->features & NETIF_F_RXHASH)
+ skb_set_hash(gro_skb,
+ be32_to_cpu(cqe->immed_rss_invalid),
+ PKT_HASH_TYPE_L3);
- napi_gro_frags(&cq->napi);
- goto next;
- }
+ skb_record_rx_queue(gro_skb, cq->ring);
+ skb_mark_napi_id(gro_skb, &cq->napi);
- /* GRO not possible, complete processing here */
- ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- ip_summed = CHECKSUM_NONE;
- ring->csum_none++;
+ if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
+ timestamp = mlx4_en_get_cqe_ts(cqe);
+ mlx4_en_fill_hwtstamps(mdev,
+ skb_hwtstamps(gro_skb),
+ timestamp);
}
- } else {
- ip_summed = CHECKSUM_NONE;
- ring->csum_none++;
+
+ napi_gro_frags(&cq->napi);
+ goto next;
}
+ /* GRO not possible, complete processing here */
skb = mlx4_en_rx_skb(priv, rx_desc, frags, length);
if (!skb) {
priv->stats.rx_dropped++;
goto next;
}
+ if (ip_summed == CHECKSUM_COMPLETE) {
+ if (check_csum(cqe, skb, skb->data, ring->hwtstamp_rx_filter)) {
+ ip_summed = CHECKSUM_NONE;
+ ring->csum_complete--;
+ ring->csum_none++;
+ }
+ }
+
skb->ip_summed = ip_summed;
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, cq->ring);
struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq);
struct mlx4_en_priv *priv = netdev_priv(cq->dev);
- if (priv->port_up)
- napi_schedule(&cq->napi);
+ if (likely(priv->port_up))
+ napi_schedule_irqoff(&cq->napi);
else
mlx4_en_arm_cq(priv, cq);
}
cpu_curr = smp_processor_id();
aff = irq_desc_get_irq_data(cq->irq_desc)->affinity;
- if (unlikely(!cpumask_test_cpu(cpu_curr, aff))) {
- /* Current cpu is not according to smp_irq_affinity -
- * probably affinity changed. need to stop this NAPI
- * poll, and restart it on the right CPU
- */
- napi_complete(napi);
- mlx4_en_arm_cq(priv, cq);
- return 0;
- }
- } else {
- /* Done for now */
- napi_complete(napi);
- mlx4_en_arm_cq(priv, cq);
+ if (likely(cpumask_test_cpu(cpu_curr, aff)))
+ return budget;
+
+ /* Current cpu is not according to smp_irq_affinity -
+ * probably affinity changed. need to stop this NAPI
+ * poll, and restart it on the right CPU
+ */
+ done = 0;
}
+ /* Done for now */
+ napi_complete_done(napi, done);
+ mlx4_en_arm_cq(priv, cq);
return done;
}
(eff_mtu > buf_size + frag_sizes[i]) ?
frag_sizes[i] : eff_mtu - buf_size;
priv->frag_info[i].frag_prefix_size = buf_size;
- if (!i) {
- priv->frag_info[i].frag_align = NET_IP_ALIGN;
- priv->frag_info[i].frag_stride =
- ALIGN(frag_sizes[i] + NET_IP_ALIGN, SMP_CACHE_BYTES);
- } else {
- priv->frag_info[i].frag_align = 0;
- priv->frag_info[i].frag_stride =
- ALIGN(frag_sizes[i], SMP_CACHE_BYTES);
- }
+ priv->frag_info[i].frag_stride = ALIGN(frag_sizes[i],
+ SMP_CACHE_BYTES);
buf_size += priv->frag_info[i].frag_size;
i++;
}
eff_mtu, priv->num_frags);
for (i = 0; i < priv->num_frags; i++) {
en_err(priv,
- " frag:%d - size:%d prefix:%d align:%d stride:%d\n",
+ " frag:%d - size:%d prefix:%d stride:%d\n",
i,
priv->frag_info[i].frag_size,
priv->frag_info[i].frag_prefix_size,
- priv->frag_info[i].frag_align,
priv->frag_info[i].frag_stride);
}
}
if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
return -ENOMEM;
- /* The device supports 1G, 10G and 40G speeds */
- if (priv->port_state.link_speed != 1000 &&
- priv->port_state.link_speed != 10000 &&
- priv->port_state.link_speed != 40000)
+ /* The device supports 100M, 1G, 10G, 20G, 40G and 56G speed */
+ if (priv->port_state.link_speed != SPEED_100 &&
+ priv->port_state.link_speed != SPEED_1000 &&
+ priv->port_state.link_speed != SPEED_10000 &&
+ priv->port_state.link_speed != SPEED_20000 &&
+ priv->port_state.link_speed != SPEED_40000 &&
+ priv->port_state.link_speed != SPEED_56000)
return priv->port_state.link_speed;
+
return 0;
}
struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq);
struct mlx4_en_priv *priv = netdev_priv(cq->dev);
- if (priv->port_up)
- napi_schedule(&cq->napi);
+ if (likely(priv->port_up))
+ napi_schedule_irqoff(&cq->napi);
else
mlx4_en_arm_cq(priv, cq);
}
goto err_out_free;
}
- err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
- dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0);
+ err = mlx4_bitmap_init(&priv->eq_table.bitmap,
+ roundup_pow_of_two(dev->caps.num_eqs),
+ dev->caps.num_eqs - 1,
+ dev->caps.reserved_eqs,
+ roundup_pow_of_two(dev->caps.num_eqs) -
+ dev->caps.num_eqs);
if (err)
goto err_out_free;
[10] = "TCP/IP offloads/flow-steering for VXLAN support",
[11] = "MAD DEMUX (Secure-Host) support",
[12] = "Large cache line (>64B) CQE stride support",
- [13] = "Large cache line (>64B) EQE stride support"
+ [13] = "Large cache line (>64B) EQE stride support",
+ [14] = "Ethernet protocol control support",
+ [15] = "Ethernet Backplane autoneg support",
+ [16] = "CONFIG DEV support",
+ [17] = "Asymmetric EQs support",
+ [18] = "More than 80 VFs support"
};
int i;
return err;
}
+int mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ u32 *outbox;
+ u8 in_modifier;
+ u8 field;
+ u16 field16;
+ int err;
+
+#define QUERY_FUNC_BUS_OFFSET 0x00
+#define QUERY_FUNC_DEVICE_OFFSET 0x01
+#define QUERY_FUNC_FUNCTION_OFFSET 0x01
+#define QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET 0x03
+#define QUERY_FUNC_RSVD_EQS_OFFSET 0x04
+#define QUERY_FUNC_MAX_EQ_OFFSET 0x06
+#define QUERY_FUNC_RSVD_UARS_OFFSET 0x0b
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
+
+ in_modifier = slave;
+
+ err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, 0,
+ MLX4_CMD_QUERY_FUNC,
+ MLX4_CMD_TIME_CLASS_A,
+ MLX4_CMD_NATIVE);
+ if (err)
+ goto out;
+
+ MLX4_GET(field, outbox, QUERY_FUNC_BUS_OFFSET);
+ func->bus = field & 0xf;
+ MLX4_GET(field, outbox, QUERY_FUNC_DEVICE_OFFSET);
+ func->device = field & 0xf1;
+ MLX4_GET(field, outbox, QUERY_FUNC_FUNCTION_OFFSET);
+ func->function = field & 0x7;
+ MLX4_GET(field, outbox, QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET);
+ func->physical_function = field & 0xf;
+ MLX4_GET(field16, outbox, QUERY_FUNC_RSVD_EQS_OFFSET);
+ func->rsvd_eqs = field16 & 0xffff;
+ MLX4_GET(field16, outbox, QUERY_FUNC_MAX_EQ_OFFSET);
+ func->max_eq = field16 & 0xffff;
+ MLX4_GET(field, outbox, QUERY_FUNC_RSVD_UARS_OFFSET);
+ func->rsvd_uars = field & 0x0f;
+
+ mlx4_dbg(dev, "Bus: %d, Device: %d, Function: %d, Physical function: %d, Max EQs: %d, Reserved EQs: %d, Reserved UARs: %d\n",
+ func->bus, func->device, func->function, func->physical_function,
+ func->max_eq, func->rsvd_eqs, func->rsvd_uars);
+
+out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
u8 field, port;
u32 size, proxy_qp, qkey;
int err = 0;
+ struct mlx4_func func;
#define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0
#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET 0x1
#define QUERY_FUNC_CAP_VF_ENABLE_QP0 0x08
#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
+#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31)
if (vhcr->op_modifier == 1) {
struct mlx4_active_ports actv_ports =
size = dev->caps.num_cqs;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
- size = dev->caps.num_eqs;
- MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
-
- size = dev->caps.reserved_eqs;
- MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+ if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) ||
+ mlx4_QUERY_FUNC(dev, &func, slave)) {
+ size = vhcr->in_modifier &
+ QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
+ dev->caps.num_eqs :
+ rounddown_pow_of_two(dev->caps.num_eqs);
+ MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
+ size = dev->caps.reserved_eqs;
+ MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+ } else {
+ size = vhcr->in_modifier &
+ QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
+ func.max_eq :
+ rounddown_pow_of_two(func.max_eq);
+ MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
+ size = func.rsvd_eqs;
+ MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
+ }
size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave];
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
return err;
}
-int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
+int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
struct mlx4_func_cap *func_cap)
{
struct mlx4_cmd_mailbox *mailbox;
u8 field, op_modifier;
u32 size, qkey;
int err = 0, quotas = 0;
+ u32 in_modifier;
op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
+ in_modifier = op_modifier ? gen_or_port :
+ QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
- err = mlx4_cmd_box(dev, 0, mailbox->dma, gen_or_port, op_modifier,
+ err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, op_modifier,
MLX4_CMD_QUERY_FUNC_CAP,
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
if (err)
#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21
#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22
#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23
+#define QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET 0x26
#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27
#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29
#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b
#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76
#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77
#define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE 0x7a
+#define QUERY_DEV_CAP_ETH_PROT_CTRL_OFFSET 0x7a
#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80
#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82
#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84
#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90
#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92
#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94
+#define QUERY_DEV_CAP_CONFIG_DEV_OFFSET 0x94
#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98
#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0
+#define QUERY_DEV_CAP_ETH_BACKPL_OFFSET 0x9c
#define QUERY_DEV_CAP_FW_REASSIGN_MAC 0x9d
#define QUERY_DEV_CAP_VXLAN 0x9e
#define QUERY_DEV_CAP_MAD_DEMUX_OFFSET 0xb0
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
dev_cap->max_mpts = 1 << (field & 0x3f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
- dev_cap->reserved_eqs = field & 0xf;
+ dev_cap->reserved_eqs = 1 << (field & 0xf);
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
dev_cap->max_eqs = 1 << (field & 0xf);
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
dev_cap->reserved_mrws = 1 << (field & 0xf);
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
dev_cap->max_mtt_seg = 1 << (field & 0x3f);
+ MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET);
+ dev_cap->num_sys_eqs = size & 0xfff;
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
dev_cap->max_rq_desc_sz = size;
MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
+ if (field & (1 << 5))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL;
if (field & (1 << 6))
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CQE_STRIDE;
if (field & (1 << 7))
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE;
-
MLX4_GET(dev_cap->bmme_flags, outbox,
QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
+ if (field & 0x20)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV;
MLX4_GET(dev_cap->reserved_lkey, outbox,
QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
+ MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET);
+ if (field32 & (1 << 0))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
if (field & 1<<6)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
if (field32 & (1 << 20))
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
+ if (field32 & (1 << 21))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS;
if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
for (i = 1; i <= dev_cap->num_ports; ++i) {
* we can't use any EQs whose doorbell falls on that page,
* even if the EQ itself isn't reserved.
*/
- dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
- dev_cap->reserved_eqs);
+ if (dev_cap->num_sys_eqs == 0)
+ dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
+ dev_cap->reserved_eqs);
+ else
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS;
mlx4_dbg(dev, "Max ICM size %lld MB\n",
(unsigned long long) dev_cap->max_icm_sz >> 20);
dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
- mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
- dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz);
+ mlx4_dbg(dev, "Num sys EQs: %d, max EQs: %d, reserved EQs: %d, entry size: %d\n",
+ dev_cap->num_sys_eqs, dev_cap->max_eqs, dev_cap->reserved_eqs,
+ dev_cap->eqc_entry_sz);
mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
dev_cap->reserved_mrws, dev_cap->reserved_mtts);
mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50)
#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60)
#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67)
+#define INIT_HCA_NUM_SYS_EQS_OFFSET (INIT_HCA_QPC_OFFSET + 0x6a)
#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70)
#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77)
#define INIT_HCA_MCAST_OFFSET 0x0c0
MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET);
MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET);
MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET);
+ MLX4_PUT(inbox, param->num_sys_eqs, INIT_HCA_NUM_SYS_EQS_OFFSET);
MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET);
MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
MLX4_GET(param->auxc_base, outbox, INIT_HCA_AUXC_BASE_OFFSET);
MLX4_GET(param->eqc_base, outbox, INIT_HCA_EQC_BASE_OFFSET);
MLX4_GET(param->log_num_eqs, outbox, INIT_HCA_LOG_EQ_OFFSET);
+ MLX4_GET(param->num_sys_eqs, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
MLX4_GET(param->rdmarc_base, outbox, INIT_HCA_RDMARC_BASE_OFFSET);
MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET);
struct mlx4_config_dev {
__be32 update_flags;
- __be32 rsdv1[3];
+ __be32 rsvd1[3];
__be16 vxlan_udp_dport;
__be16 rsvd2;
+ __be32 rsvd3[27];
+ __be16 rsvd4;
+ u8 rsvd5;
+ u8 rx_checksum_val;
};
#define MLX4_VXLAN_UDP_DPORT (1 << 0)
-static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
{
int err;
struct mlx4_cmd_mailbox *mailbox;
return err;
}
+static int mlx4_CONFIG_DEV_get(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+{
+ int err;
+ struct mlx4_cmd_mailbox *mailbox;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 1, MLX4_CMD_CONFIG_DEV,
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
+
+ if (!err)
+ memcpy(config_dev, mailbox->buf, sizeof(*config_dev));
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+/* Conversion between the HW values and the actual functionality.
+ * The value represented by the array index,
+ * and the functionality determined by the flags.
+ */
+static const u8 config_dev_csum_flags[] = {
+ [0] = 0,
+ [1] = MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP,
+ [2] = MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP |
+ MLX4_RX_CSUM_MODE_L4,
+ [3] = MLX4_RX_CSUM_MODE_L4 |
+ MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP |
+ MLX4_RX_CSUM_MODE_MULTI_VLAN
+};
+
+int mlx4_config_dev_retrieval(struct mlx4_dev *dev,
+ struct mlx4_config_dev_params *params)
+{
+ struct mlx4_config_dev config_dev;
+ int err;
+ u8 csum_mask;
+
+#define CONFIG_DEV_RX_CSUM_MODE_MASK 0x7
+#define CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET 0
+#define CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET 4
+
+ if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CONFIG_DEV))
+ return -ENOTSUPP;
+
+ err = mlx4_CONFIG_DEV_get(dev, &config_dev);
+ if (err)
+ return err;
+
+ csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET) &
+ CONFIG_DEV_RX_CSUM_MODE_MASK;
+
+ if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0]))
+ return -EINVAL;
+ params->rx_csum_flags_port_1 = config_dev_csum_flags[csum_mask];
+
+ csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET) &
+ CONFIG_DEV_RX_CSUM_MODE_MASK;
+
+ if (csum_mask >= sizeof(config_dev_csum_flags)/sizeof(config_dev_csum_flags[0]))
+ return -EINVAL;
+ params->rx_csum_flags_port_2 = config_dev_csum_flags[csum_mask];
+
+ params->vxlan_udp_dport = be16_to_cpu(config_dev.vxlan_udp_dport);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_config_dev_retrieval);
+
int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
{
struct mlx4_config_dev config_dev;
config_dev.update_flags = cpu_to_be32(MLX4_VXLAN_UDP_DPORT);
config_dev.vxlan_udp_dport = udp_port;
- return mlx4_CONFIG_DEV(dev, &config_dev);
+ return mlx4_CONFIG_DEV_set(dev, &config_dev);
}
EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
mlx4_free_cmd_mailbox(dev, mailbox);
return err;
}
+
+/* Access Reg commands */
+enum mlx4_access_reg_masks {
+ MLX4_ACCESS_REG_STATUS_MASK = 0x7f,
+ MLX4_ACCESS_REG_METHOD_MASK = 0x7f,
+ MLX4_ACCESS_REG_LEN_MASK = 0x7ff
+};
+
+struct mlx4_access_reg {
+ __be16 constant1;
+ u8 status;
+ u8 resrvd1;
+ __be16 reg_id;
+ u8 method;
+ u8 constant2;
+ __be32 resrvd2[2];
+ __be16 len_const;
+ __be16 resrvd3;
+#define MLX4_ACCESS_REG_HEADER_SIZE (20)
+ u8 reg_data[MLX4_MAILBOX_SIZE-MLX4_ACCESS_REG_HEADER_SIZE];
+} __attribute__((__packed__));
+
+/**
+ * mlx4_ACCESS_REG - Generic access reg command.
+ * @dev: mlx4_dev.
+ * @reg_id: register ID to access.
+ * @method: Access method Read/Write.
+ * @reg_len: register length to Read/Write in bytes.
+ * @reg_data: reg_data pointer to Read/Write From/To.
+ *
+ * Access ConnectX registers FW command.
+ * Returns 0 on success and copies outbox mlx4_access_reg data
+ * field into reg_data or a negative error code.
+ */
+static int mlx4_ACCESS_REG(struct mlx4_dev *dev, u16 reg_id,
+ enum mlx4_access_reg_method method,
+ u16 reg_len, void *reg_data)
+{
+ struct mlx4_cmd_mailbox *inbox, *outbox;
+ struct mlx4_access_reg *inbuf, *outbuf;
+ int err;
+
+ inbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(inbox))
+ return PTR_ERR(inbox);
+
+ outbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(outbox)) {
+ mlx4_free_cmd_mailbox(dev, inbox);
+ return PTR_ERR(outbox);
+ }
+
+ inbuf = inbox->buf;
+ outbuf = outbox->buf;
+
+ inbuf->constant1 = cpu_to_be16(0x1<<11 | 0x4);
+ inbuf->constant2 = 0x1;
+ inbuf->reg_id = cpu_to_be16(reg_id);
+ inbuf->method = method & MLX4_ACCESS_REG_METHOD_MASK;
+
+ reg_len = min(reg_len, (u16)(sizeof(inbuf->reg_data)));
+ inbuf->len_const =
+ cpu_to_be16(((reg_len/4 + 1) & MLX4_ACCESS_REG_LEN_MASK) |
+ ((0x3) << 12));
+
+ memcpy(inbuf->reg_data, reg_data, reg_len);
+ err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 0, 0,
+ MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
+ MLX4_CMD_WRAPPED);
+ if (err)
+ goto out;
+
+ if (outbuf->status & MLX4_ACCESS_REG_STATUS_MASK) {
+ err = outbuf->status & MLX4_ACCESS_REG_STATUS_MASK;
+ mlx4_err(dev,
+ "MLX4_CMD_ACCESS_REG(%x) returned REG status (%x)\n",
+ reg_id, err);
+ goto out;
+ }
+
+ memcpy(reg_data, outbuf->reg_data, reg_len);
+out:
+ mlx4_free_cmd_mailbox(dev, inbox);
+ mlx4_free_cmd_mailbox(dev, outbox);
+ return err;
+}
+
+/* ConnectX registers IDs */
+enum mlx4_reg_id {
+ MLX4_REG_ID_PTYS = 0x5004,
+};
+
+/**
+ * mlx4_ACCESS_PTYS_REG - Access PTYs (Port Type and Speed)
+ * register
+ * @dev: mlx4_dev.
+ * @method: Access method Read/Write.
+ * @ptys_reg: PTYS register data pointer.
+ *
+ * Access ConnectX PTYS register, to Read/Write Port Type/Speed
+ * configuration
+ * Returns 0 on success or a negative error code.
+ */
+int mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev,
+ enum mlx4_access_reg_method method,
+ struct mlx4_ptys_reg *ptys_reg)
+{
+ return mlx4_ACCESS_REG(dev, MLX4_REG_ID_PTYS,
+ method, sizeof(*ptys_reg), ptys_reg);
+}
+EXPORT_SYMBOL_GPL(mlx4_ACCESS_PTYS_REG);
+
+int mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave,
+ struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox,
+ struct mlx4_cmd_info *cmd)
+{
+ struct mlx4_access_reg *inbuf = inbox->buf;
+ u8 method = inbuf->method & MLX4_ACCESS_REG_METHOD_MASK;
+ u16 reg_id = be16_to_cpu(inbuf->reg_id);
+
+ if (slave != mlx4_master_func_num(dev) &&
+ method == MLX4_ACCESS_REG_WRITE)
+ return -EPERM;
+
+ if (reg_id == MLX4_REG_ID_PTYS) {
+ struct mlx4_ptys_reg *ptys_reg =
+ (struct mlx4_ptys_reg *)inbuf->reg_data;
+
+ ptys_reg->local_port =
+ mlx4_slave_convert_port(dev, slave,
+ ptys_reg->local_port);
+ }
+
+ return mlx4_cmd_box(dev, inbox->dma, outbox->dma, vhcr->in_modifier,
+ 0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
+ MLX4_CMD_NATIVE);
+}
int max_mpts;
int reserved_eqs;
int max_eqs;
+ int num_sys_eqs;
int reserved_mtts;
int max_mrw_sz;
int reserved_mrws;
u64 phys_port_id;
};
+struct mlx4_func {
+ int bus;
+ int device;
+ int function;
+ int physical_function;
+ int rsvd_eqs;
+ int max_eq;
+ int rsvd_uars;
+};
+
struct mlx4_adapter {
char board_id[MLX4_BOARD_ID_LEN];
u8 inta_pin;
u8 log_num_srqs;
u8 log_num_cqs;
u8 log_num_eqs;
+ u16 num_sys_eqs;
u8 log_rd_per_qp;
u8 log_mc_table_sz;
u8 log_mpt_sz;
};
int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
-int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port,
+int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
struct mlx4_func_cap *func_cap);
int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd);
+int mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave);
int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm);
int mlx4_UNMAP_FA(struct mlx4_dev *dev);
int mlx4_RUN_FW(struct mlx4_dev *dev);
dev->caps.port_mask[i] = dev->caps.port_type[i];
}
+enum {
+ MLX4_QUERY_FUNC_NUM_SYS_EQS = 1 << 0,
+};
+
+static int mlx4_query_func(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+{
+ int err = 0;
+ struct mlx4_func func;
+
+ if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) {
+ err = mlx4_QUERY_FUNC(dev, &func, 0);
+ if (err) {
+ mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
+ return err;
+ }
+ dev_cap->max_eqs = func.max_eq;
+ dev_cap->reserved_eqs = func.rsvd_eqs;
+ dev_cap->reserved_uars = func.rsvd_uars;
+ err |= MLX4_QUERY_FUNC_NUM_SYS_EQS;
+ }
+ return err;
+}
+
static void mlx4_enable_cqe_eqe_stride(struct mlx4_dev *dev)
{
struct mlx4_caps *dev_cap = &dev->caps;
}
dev->caps.num_ports = dev_cap->num_ports;
- dev->phys_caps.num_phys_eqs = MLX4_MAX_EQ_NUM;
+ dev->caps.num_sys_eqs = dev_cap->num_sys_eqs;
+ dev->phys_caps.num_phys_eqs = dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS ?
+ dev->caps.num_sys_eqs :
+ MLX4_MAX_EQ_NUM;
for (i = 1; i <= dev->caps.num_ports; ++i) {
dev->caps.vl_cap[i] = dev_cap->max_vl[i];
dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i];
struct mlx4_dev_cap dev_cap;
struct mlx4_func_cap func_cap;
struct mlx4_init_hca_param hca_param;
- int i;
+ u8 i;
memset(&hca_param, 0, sizeof(hca_param));
err = mlx4_QUERY_HCA(dev, &hca_param);
}
for (i = 1; i <= dev->caps.num_ports; ++i) {
- err = mlx4_QUERY_FUNC_CAP(dev, (u32) i, &func_cap);
+ err = mlx4_QUERY_FUNC_CAP(dev, i, &func_cap);
if (err) {
mlx4_err(dev, "QUERY_FUNC_CAP port command failed for port %d, aborting (%d)\n",
i, err);
struct mlx4_priv *priv = mlx4_priv(mdev);
enum mlx4_port_type types[MLX4_MAX_PORTS];
enum mlx4_port_type new_types[MLX4_MAX_PORTS];
+ static DEFINE_MUTEX(set_port_type_mutex);
int i;
int err = 0;
+ mutex_lock(&set_port_type_mutex);
+
if (!strcmp(buf, "ib\n"))
info->tmp_type = MLX4_PORT_TYPE_IB;
else if (!strcmp(buf, "eth\n"))
info->tmp_type = MLX4_PORT_TYPE_AUTO;
else {
mlx4_err(mdev, "%s is not supported port type\n", buf);
- return -EINVAL;
+ err = -EINVAL;
+ goto err_out;
}
mlx4_stop_sense(mdev);
out:
mlx4_start_sense(mdev);
mutex_unlock(&priv->port_mutex);
+err_out:
+ mutex_unlock(&set_port_type_mutex);
+
return err ? err : count;
}
if (err)
goto err_srq;
- num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs :
- dev->caps.num_eqs;
+ num_eqs = dev->phys_caps.num_phys_eqs;
err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table,
cmpt_base +
((u64) (MLX4_CMPT_TYPE_EQ *
}
- num_eqs = (mlx4_is_master(dev)) ? dev->phys_caps.num_phys_eqs :
- dev->caps.num_eqs;
+ num_eqs = dev->phys_caps.num_phys_eqs;
err = mlx4_init_icm_table(dev, &priv->eq_table.table,
init_hca->eqc_base, dev_cap->eqc_entry_sz,
num_eqs, num_eqs, 0, 0);
else {
mlx4_CLOSE_HCA(dev, 0);
mlx4_free_icms(dev);
+ }
+}
+
+static void mlx4_close_fw(struct mlx4_dev *dev)
+{
+ if (!mlx4_is_slave(dev)) {
mlx4_UNMAP_FA(dev);
mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);
}
== MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) ? "vxlan" : "none");
}
-static int mlx4_init_hca(struct mlx4_dev *dev)
+static int mlx4_init_fw(struct mlx4_dev *dev)
{
- struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_adapter adapter;
- struct mlx4_dev_cap dev_cap;
struct mlx4_mod_stat_cfg mlx4_cfg;
- struct mlx4_profile profile;
- struct mlx4_init_hca_param init_hca;
- u64 icm_size;
- int err;
+ int err = 0;
if (!mlx4_is_slave(dev)) {
err = mlx4_QUERY_FW(dev);
err = mlx4_MOD_STAT_CFG(dev, &mlx4_cfg);
if (err)
mlx4_warn(dev, "Failed to override log_pg_sz parameter\n");
+ }
+
+ return err;
+}
+
+static int mlx4_init_hca(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_adapter adapter;
+ struct mlx4_dev_cap dev_cap;
+ struct mlx4_profile profile;
+ struct mlx4_init_hca_param init_hca;
+ u64 icm_size;
+ struct mlx4_config_dev_params params;
+ int err;
+ if (!mlx4_is_slave(dev)) {
err = mlx4_dev_cap(dev, &dev_cap);
if (err) {
mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n");
mlx4_err(dev, "INIT_HCA command failed, aborting\n");
goto err_free_icm;
}
+
+ if (dev_cap.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) {
+ err = mlx4_query_func(dev, &dev_cap);
+ if (err < 0) {
+ mlx4_err(dev, "QUERY_FUNC command failed, aborting.\n");
+ goto err_stop_fw;
+ } else if (err & MLX4_QUERY_FUNC_NUM_SYS_EQS) {
+ dev->caps.num_eqs = dev_cap.max_eqs;
+ dev->caps.reserved_eqs = dev_cap.reserved_eqs;
+ dev->caps.reserved_uars = dev_cap.reserved_uars;
+ }
+ }
+
/*
* If TS is supported by FW
* read HCA frequency by QUERY_HCA command
goto unmap_bf;
}
+ /* Query CONFIG_DEV parameters */
+ err = mlx4_config_dev_retrieval(dev, ¶ms);
+ if (err && err != -ENOTSUPP) {
+ mlx4_err(dev, "Failed to query CONFIG_DEV parameters\n");
+ } else if (!err) {
+ dev->caps.rx_checksum_flags_port[1] = params.rx_csum_flags_port_1;
+ dev->caps.rx_checksum_flags_port[2] = params.rx_csum_flags_port_2;
+ }
priv->eq_table.inta_pin = adapter.inta_pin;
memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct msix_entry *entries;
- int nreq = min_t(int, dev->caps.num_ports *
- min_t(int, num_online_cpus() + 1,
- MAX_MSIX_P_PORT) + MSIX_LEGACY_SZ, MAX_MSIX);
int i;
if (msi_x) {
+ int nreq = dev->caps.num_ports * num_online_cpus() + MSIX_LEGACY_SZ;
+
nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
nreq);
iounmap(owner);
}
+#define SRIOV_VALID_STATE(flags) (!!((flags) & MLX4_FLAG_SRIOV) ==\
+ !!((flags) & MLX4_FLAG_MASTER))
+
+static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev,
+ u8 total_vfs, int existing_vfs)
+{
+ u64 dev_flags = dev->flags;
+
+ dev->dev_vfs = kzalloc(
+ total_vfs * sizeof(*dev->dev_vfs),
+ GFP_KERNEL);
+ if (NULL == dev->dev_vfs) {
+ mlx4_err(dev, "Failed to allocate memory for VFs\n");
+ goto disable_sriov;
+ } else if (!(dev->flags & MLX4_FLAG_SRIOV)) {
+ int err = 0;
+
+ atomic_inc(&pf_loading);
+ if (existing_vfs) {
+ if (existing_vfs != total_vfs)
+ mlx4_err(dev, "SR-IOV was already enabled, but with num_vfs (%d) different than requested (%d)\n",
+ existing_vfs, total_vfs);
+ } else {
+ mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", total_vfs);
+ err = pci_enable_sriov(pdev, total_vfs);
+ }
+ if (err) {
+ mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d)\n",
+ err);
+ atomic_dec(&pf_loading);
+ goto disable_sriov;
+ } else {
+ mlx4_warn(dev, "Running in master mode\n");
+ dev_flags |= MLX4_FLAG_SRIOV |
+ MLX4_FLAG_MASTER;
+ dev_flags &= ~MLX4_FLAG_SLAVE;
+ dev->num_vfs = total_vfs;
+ }
+ }
+ return dev_flags;
+
+disable_sriov:
+ dev->num_vfs = 0;
+ kfree(dev->dev_vfs);
+ return dev_flags & ~MLX4_FLAG_MASTER;
+}
+
+enum {
+ MLX4_DEV_CAP_CHECK_NUM_VFS_ABOVE_64 = -1,
+};
+
+static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
+ int *nvfs)
+{
+ int requested_vfs = nvfs[0] + nvfs[1] + nvfs[2];
+ /* Checking for 64 VFs as a limitation of CX2 */
+ if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_80_VFS) &&
+ requested_vfs >= 64) {
+ mlx4_err(dev, "Requested %d VFs, but FW does not support more than 64\n",
+ requested_vfs);
+ return MLX4_DEV_CAP_CHECK_NUM_VFS_ABOVE_64;
+ }
+ return 0;
+}
+
static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
int total_vfs, int *nvfs, struct mlx4_priv *priv)
{
int err;
int port;
int i;
+ struct mlx4_dev_cap *dev_cap = NULL;
int existing_vfs = 0;
dev = &priv->dev;
}
}
- if (total_vfs) {
- mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n",
- total_vfs);
- dev->dev_vfs = kzalloc(
- total_vfs * sizeof(*dev->dev_vfs),
- GFP_KERNEL);
- if (NULL == dev->dev_vfs) {
- mlx4_err(dev, "Failed to allocate memory for VFs\n");
- err = -ENOMEM;
- goto err_free_own;
- } else {
- atomic_inc(&pf_loading);
- existing_vfs = pci_num_vf(pdev);
- if (existing_vfs) {
- err = 0;
- if (existing_vfs != total_vfs)
- mlx4_err(dev, "SR-IOV was already enabled, but with num_vfs (%d) different than requested (%d)\n",
- existing_vfs, total_vfs);
- } else {
- err = pci_enable_sriov(pdev, total_vfs);
- }
- if (err) {
- mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d)\n",
- err);
- atomic_dec(&pf_loading);
- } else {
- mlx4_warn(dev, "Running in master mode\n");
- dev->flags |= MLX4_FLAG_SRIOV |
- MLX4_FLAG_MASTER;
- dev->num_vfs = total_vfs;
- }
- }
- }
-
atomic_set(&priv->opreq_count, 0);
INIT_WORK(&priv->opreq_task, mlx4_opreq_action);
mlx4_err(dev, "Failed to reset HCA, aborting\n");
goto err_sriov;
}
+
+ if (total_vfs) {
+ existing_vfs = pci_num_vf(pdev);
+ dev->flags = MLX4_FLAG_MASTER;
+ dev->num_vfs = total_vfs;
+ }
}
slave_start:
* before posting commands. Also, init num_slaves before calling
* mlx4_init_hca */
if (mlx4_is_mfunc(dev)) {
- if (mlx4_is_master(dev))
+ if (mlx4_is_master(dev)) {
dev->num_slaves = MLX4_MAX_NUM_SLAVES;
- else {
+
+ } else {
dev->num_slaves = 0;
err = mlx4_multi_func_init(dev);
if (err) {
}
}
+ err = mlx4_init_fw(dev);
+ if (err) {
+ mlx4_err(dev, "Failed to init fw, aborting.\n");
+ goto err_mfunc;
+ }
+
+ if (mlx4_is_master(dev)) {
+ if (!dev_cap) {
+ dev_cap = kzalloc(sizeof(*dev_cap), GFP_KERNEL);
+
+ if (!dev_cap) {
+ err = -ENOMEM;
+ goto err_fw;
+ }
+
+ err = mlx4_QUERY_DEV_CAP(dev, dev_cap);
+ if (err) {
+ mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
+ goto err_fw;
+ }
+
+ if (mlx4_check_dev_cap(dev, dev_cap, nvfs))
+ goto err_fw;
+
+ if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs,
+ existing_vfs);
+
+ mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
+ dev->flags = dev_flags;
+ if (!SRIOV_VALID_STATE(dev->flags)) {
+ mlx4_err(dev, "Invalid SRIOV state\n");
+ goto err_sriov;
+ }
+ err = mlx4_reset(dev);
+ if (err) {
+ mlx4_err(dev, "Failed to reset HCA, aborting.\n");
+ goto err_sriov;
+ }
+ goto slave_start;
+ }
+ } else {
+ /* Legacy mode FW requires SRIOV to be enabled before
+ * doing QUERY_DEV_CAP, since max_eq's value is different if
+ * SRIOV is enabled.
+ */
+ memset(dev_cap, 0, sizeof(*dev_cap));
+ err = mlx4_QUERY_DEV_CAP(dev, dev_cap);
+ if (err) {
+ mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
+ goto err_fw;
+ }
+
+ if (mlx4_check_dev_cap(dev, dev_cap, nvfs))
+ goto err_fw;
+ }
+ }
+
err = mlx4_init_hca(dev);
if (err) {
if (err == -EACCES) {
/* Not primary Physical function
* Running in slave mode */
- mlx4_cmd_cleanup(dev);
+ mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
+ /* We're not a PF */
+ if (dev->flags & MLX4_FLAG_SRIOV) {
+ if (!existing_vfs)
+ pci_disable_sriov(pdev);
+ if (mlx4_is_master(dev))
+ atomic_dec(&pf_loading);
+ dev->flags &= ~MLX4_FLAG_SRIOV;
+ }
+ if (!mlx4_is_slave(dev))
+ mlx4_free_ownership(dev);
dev->flags |= MLX4_FLAG_SLAVE;
dev->flags &= ~MLX4_FLAG_MASTER;
goto slave_start;
} else
- goto err_mfunc;
+ goto err_fw;
+ }
+
+ if (mlx4_is_master(dev) && (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, existing_vfs);
+
+ if ((dev->flags ^ dev_flags) & (MLX4_FLAG_MASTER | MLX4_FLAG_SLAVE)) {
+ mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_VHCR);
+ dev->flags = dev_flags;
+ err = mlx4_cmd_init(dev);
+ if (err) {
+ /* Only VHCR is cleaned up, so could still
+ * send FW commands
+ */
+ mlx4_err(dev, "Failed to init VHCR command interface, aborting\n");
+ goto err_close;
+ }
+ } else {
+ dev->flags = dev_flags;
+ }
+
+ if (!SRIOV_VALID_STATE(dev->flags)) {
+ mlx4_err(dev, "Invalid SRIOV state\n");
+ goto err_close;
+ }
}
/* check if the device is functioning at its maximum possible speed.
err_close:
mlx4_close_hca(dev);
+err_fw:
+ mlx4_close_fw(dev);
+
err_mfunc:
if (mlx4_is_slave(dev))
mlx4_multi_func_cleanup(dev);
err_cmd:
- mlx4_cmd_cleanup(dev);
+ mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
err_sriov:
if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs)
kfree(priv->dev.dev_vfs);
-err_free_own:
if (!mlx4_is_slave(dev))
mlx4_free_ownership(dev);
+ kfree(dev_cap);
return err;
}
if (mlx4_is_master(dev))
mlx4_multi_func_cleanup(dev);
mlx4_close_hca(dev);
+ mlx4_close_fw(dev);
if (mlx4_is_slave(dev))
mlx4_multi_func_cleanup(dev);
- mlx4_cmd_cleanup(dev);
+ mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
if (dev->flags & MLX4_FLAG_MSI_X)
pci_disable_msix(pdev);
if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) {
mlx4_warn(dev, "Disabling SR-IOV\n");
pci_disable_sriov(pdev);
+ dev->flags &= ~MLX4_FLAG_SRIOV;
dev->num_vfs = 0;
}
u8 use_events;
u8 toggle;
u8 comm_toggle;
+ u8 initialized;
};
enum {
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd);
+int mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave,
+ struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox,
+ struct mlx4_cmd_info *cmd);
int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe);
+enum {
+ MLX4_CMD_CLEANUP_STRUCT = 1UL << 0,
+ MLX4_CMD_CLEANUP_POOL = 1UL << 1,
+ MLX4_CMD_CLEANUP_HCR = 1UL << 2,
+ MLX4_CMD_CLEANUP_VHCR = 1UL << 3,
+ MLX4_CMD_CLEANUP_ALL = (MLX4_CMD_CLEANUP_VHCR << 1) - 1
+};
+
int mlx4_cmd_init(struct mlx4_dev *dev);
-void mlx4_cmd_cleanup(struct mlx4_dev *dev);
+void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask);
int mlx4_multi_func_init(struct mlx4_dev *dev);
void mlx4_multi_func_cleanup(struct mlx4_dev *dev);
void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd);
+int mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave,
+ struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox,
+ struct mlx4_cmd_info *cmd);
int mlx4_get_mgm_entry_size(struct mlx4_dev *dev);
int mlx4_get_qp_per_mgm(struct mlx4_dev *dev);
#endif
unsigned long csum_ok;
unsigned long csum_none;
+ unsigned long csum_complete;
int hwtstamp_rx_filter;
cpumask_var_t affinity_mask;
};
enum mlx4_qp_state indir_state;
};
+enum mlx4_en_port_flag {
+ MLX4_EN_PORT_ANC = 1<<0, /* Auto-negotiation complete */
+ MLX4_EN_PORT_ANE = 1<<1, /* Auto-negotiation enabled */
+};
+
struct mlx4_en_port_state {
int link_state;
int link_speed;
- int transciver;
+ int transceiver;
+ u32 flags;
};
struct mlx4_en_pkt_stats {
unsigned long rx_alloc_failed;
unsigned long rx_chksum_good;
unsigned long rx_chksum_none;
+ unsigned long rx_chksum_complete;
unsigned long tx_chksum_offload;
#define NUM_PORT_STATS 9
};
u16 frag_size;
u16 frag_prefix_size;
u16 frag_stride;
- u16 frag_align;
};
#ifdef CONFIG_MLX4_EN_DCB
MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
/* whether we need to drop packets that hardware loopback-ed */
MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3),
- MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4)
+ MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4),
+ MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP = (1 << 5),
};
#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev);
+#define DEV_FEATURE_CHANGED(dev, new_features, feature) \
+ ((dev->features & feature) ^ (new_features & feature))
+
+int mlx4_en_reset_config(struct net_device *dev,
+ struct hwtstamp_config ts_config,
+ netdev_features_t new_features);
+
/*
* Functions for time stamping
*/
u64 timestamp);
void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev);
void mlx4_en_remove_timestamp(struct mlx4_en_dev *mdev);
-int mlx4_en_timestamp_config(struct net_device *dev,
- int tx_type,
- int rx_filter);
/* Globals
*/
return 0;
}
EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
+
+/* Cable Module Info */
+#define MODULE_INFO_MAX_READ 48
+
+#define I2C_ADDR_LOW 0x50
+#define I2C_ADDR_HIGH 0x51
+#define I2C_PAGE_SIZE 256
+
+/* Module Info Data */
+struct mlx4_cable_info {
+ u8 i2c_addr;
+ u8 page_num;
+ __be16 dev_mem_address;
+ __be16 reserved1;
+ __be16 size;
+ __be32 reserved2[2];
+ u8 data[MODULE_INFO_MAX_READ];
+};
+
+enum cable_info_err {
+ CABLE_INF_INV_PORT = 0x1,
+ CABLE_INF_OP_NOSUP = 0x2,
+ CABLE_INF_NOT_CONN = 0x3,
+ CABLE_INF_NO_EEPRM = 0x4,
+ CABLE_INF_PAGE_ERR = 0x5,
+ CABLE_INF_INV_ADDR = 0x6,
+ CABLE_INF_I2C_ADDR = 0x7,
+ CABLE_INF_QSFP_VIO = 0x8,
+ CABLE_INF_I2C_BUSY = 0x9,
+};
+
+#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
+
+static inline const char *cable_info_mad_err_str(u16 mad_status)
+{
+ u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
+
+ switch (err) {
+ case CABLE_INF_INV_PORT:
+ return "invalid port selected";
+ case CABLE_INF_OP_NOSUP:
+ return "operation not supported for this port (the port is of type CX4 or internal)";
+ case CABLE_INF_NOT_CONN:
+ return "cable is not connected";
+ case CABLE_INF_NO_EEPRM:
+ return "the connected cable has no EPROM (passive copper cable)";
+ case CABLE_INF_PAGE_ERR:
+ return "page number is greater than 15";
+ case CABLE_INF_INV_ADDR:
+ return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
+ case CABLE_INF_I2C_ADDR:
+ return "invalid I2C slave address";
+ case CABLE_INF_QSFP_VIO:
+ return "at least one cable violates the QSFP specification and ignores the modsel signal";
+ case CABLE_INF_I2C_BUSY:
+ return "I2C bus is constantly busy";
+ }
+ return "Unknown Error";
+}
+
+/**
+ * mlx4_get_module_info - Read cable module eeprom data
+ * @dev: mlx4_dev.
+ * @port: port number.
+ * @offset: byte offset in eeprom to start reading data from.
+ * @size: num of bytes to read.
+ * @data: output buffer to put the requested data into.
+ *
+ * Reads cable module eeprom data, puts the outcome data into
+ * data pointer paramer.
+ * Returns num of read bytes on success or a negative error
+ * code.
+ */
+int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
+ u16 offset, u16 size, u8 *data)
+{
+ struct mlx4_cmd_mailbox *inbox, *outbox;
+ struct mlx4_mad_ifc *inmad, *outmad;
+ struct mlx4_cable_info *cable_info;
+ u16 i2c_addr;
+ int ret;
+
+ if (size > MODULE_INFO_MAX_READ)
+ size = MODULE_INFO_MAX_READ;
+
+ inbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(inbox))
+ return PTR_ERR(inbox);
+
+ outbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(outbox)) {
+ mlx4_free_cmd_mailbox(dev, inbox);
+ return PTR_ERR(outbox);
+ }
+
+ inmad = (struct mlx4_mad_ifc *)(inbox->buf);
+ outmad = (struct mlx4_mad_ifc *)(outbox->buf);
+
+ inmad->method = 0x1; /* Get */
+ inmad->class_version = 0x1;
+ inmad->mgmt_class = 0x1;
+ inmad->base_version = 0x1;
+ inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
+
+ if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
+ /* Cross pages reads are not allowed
+ * read until offset 256 in low page
+ */
+ size -= offset + size - I2C_PAGE_SIZE;
+
+ i2c_addr = I2C_ADDR_LOW;
+ if (offset >= I2C_PAGE_SIZE) {
+ /* Reset offset to high page */
+ i2c_addr = I2C_ADDR_HIGH;
+ offset -= I2C_PAGE_SIZE;
+ }
+
+ cable_info = (struct mlx4_cable_info *)inmad->data;
+ cable_info->dev_mem_address = cpu_to_be16(offset);
+ cable_info->page_num = 0;
+ cable_info->i2c_addr = i2c_addr;
+ cable_info->size = cpu_to_be16(size);
+
+ ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
+ MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
+ MLX4_CMD_NATIVE);
+ if (ret)
+ goto out;
+
+ if (be16_to_cpu(outmad->status)) {
+ /* Mad returned with bad status */
+ ret = be16_to_cpu(outmad->status);
+ mlx4_warn(dev,
+ "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
+ 0xFF60, port, i2c_addr, offset, size,
+ ret, cable_info_mad_err_str(ret));
+
+ if (i2c_addr == I2C_ADDR_HIGH &&
+ MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
+ /* Some SFP cables do not support i2c slave
+ * address 0x51 (high page), abort silently.
+ */
+ ret = 0;
+ else
+ ret = -ret;
+ goto out;
+ }
+ cable_info = (struct mlx4_cable_info *)outmad->data;
+ memcpy(data, cable_info->data, size);
+ ret = size;
+out:
+ mlx4_free_cmd_mailbox(dev, inbox);
+ mlx4_free_cmd_mailbox(dev, outbox);
+ return ret;
+}
+EXPORT_SYMBOL(mlx4_get_module_info);
profile[MLX4_RES_AUXC].num = request->num_qp;
profile[MLX4_RES_SRQ].num = request->num_srq;
profile[MLX4_RES_CQ].num = request->num_cq;
- profile[MLX4_RES_EQ].num = mlx4_is_mfunc(dev) ?
- dev->phys_caps.num_phys_eqs :
+ profile[MLX4_RES_EQ].num = mlx4_is_mfunc(dev) ? dev->phys_caps.num_phys_eqs :
min_t(unsigned, dev_cap->max_eqs, MAX_MSIX);
profile[MLX4_RES_DMPT].num = request->num_mpt;
profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS;
init_hca->log_num_cqs = profile[i].log_num;
break;
case MLX4_RES_EQ:
- dev->caps.num_eqs = roundup_pow_of_two(min_t(unsigned, dev_cap->max_eqs,
- MAX_MSIX));
- init_hca->eqc_base = profile[i].start;
- init_hca->log_num_eqs = ilog2(dev->caps.num_eqs);
+ if (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) {
+ init_hca->log_num_eqs = 0x1f;
+ init_hca->eqc_base = profile[i].start;
+ init_hca->num_sys_eqs = dev_cap->num_sys_eqs;
+ } else {
+ dev->caps.num_eqs = roundup_pow_of_two(
+ min_t(unsigned,
+ dev_cap->max_eqs,
+ MAX_MSIX));
+ init_hca->eqc_base = profile[i].start;
+ init_hca->log_num_eqs = ilog2(dev->caps.num_eqs);
+ }
break;
case MLX4_RES_DMPT:
dev->caps.num_mpts = profile[i].num;
return err;
}
+int mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave,
+ struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox,
+ struct mlx4_cmd_info *cmd)
+{
+ int err;
+ u8 get = vhcr->op_modifier;
+
+ if (get != 1)
+ return -EPERM;
+
+ err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
+
+ return err;
+}
+
static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,
int len, struct res_mtt **res)
{
macintosh_config->ident == MAC_MODEL_P588 ||
macintosh_config->ident == MAC_MODEL_P575 ||
macintosh_config->ident == MAC_MODEL_C610) {
- unsigned long flags;
int card_present;
- local_irq_save(flags);
card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS);
- local_irq_restore(flags);
-
if (!card_present) {
printk("none.\n");
return -ENODEV;
#define NUM_TX_DESC 4
/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
+#define MAX_ETH_FRAME_SIZE 1792
+
+/* max supported payload size */
+#define MAX_ETH_DATA_SIZE (MAX_ETH_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN)
/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
return 0;
}
+static int rtl8139_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < 68 || new_mtu > MAX_ETH_DATA_SIZE)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
static const struct net_device_ops rtl8139_netdev_ops = {
.ndo_open = rtl8139_open,
.ndo_stop = rtl8139_close,
.ndo_get_stats64 = rtl8139_get_stats64,
- .ndo_change_mtu = eth_change_mtu,
+ .ndo_change_mtu = rtl8139_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = rtl8139_set_mac_address,
.ndo_start_xmit = rtl8139_start_xmit,
/* The header prepended to received packets. */
struct rx_header {
- ushort pad; /* Pad. */
- ushort rx_count;
- ushort rx_status; /* Unknown bit assignments :-<. */
- ushort cur_addr; /* Apparently the current buffer address(?) */
+ ushort pad; /* Pad. */
+ ushort rx_count;
+ ushort rx_status; /* Unknown bit assignments :-<. */
+ ushort cur_addr; /* Apparently the current buffer address(?) */
};
#define PAR_DATA 0
#define RdAddr 0xC0
#define HNib 0x10
-enum page0_regs
-{
- /* The first six registers hold the ethernet physical station address. */
- PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
- TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */
- TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */
- ISR = 10, IMR = 11, /* Interrupt status and mask. */
- CMR1 = 12, /* Command register 1. */
- CMR2 = 13, /* Command register 2. */
- MODSEL = 14, /* Mode select register. */
- MAR = 14, /* Memory address register (?). */
- CMR2_h = 0x1d, };
-
-enum eepage_regs
-{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */
+enum page0_regs {
+ /* The first six registers hold
+ * the ethernet physical station address.
+ */
+ PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
+ TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */
+ TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */
+ ISR = 10, IMR = 11, /* Interrupt status and mask. */
+ CMR1 = 12, /* Command register 1. */
+ CMR2 = 13, /* Command register 2. */
+ MODSEL = 14, /* Mode select register. */
+ MAR = 14, /* Memory address register (?). */
+ CMR2_h = 0x1d,
+};
+enum eepage_regs {
+ PROM_CMD = 6,
+ PROM_DATA = 7 /* Note that PROM_CMD is in the "high" bits. */
+};
#define ISR_TxOK 0x01
#define ISR_RxOK 0x04
#define CMR2h_Normal 2 /* Accept physical and broadcast address. */
#define CMR2h_PROMISC 3 /* Promiscuous mode. */
-/* An inline function used below: it differs from inb() by explicitly return an unsigned
- char, saving a truncation. */
+/* An inline function used below: it differs from inb() by explicitly
+ * return an unsigned char, saving a truncation.
+ */
static inline unsigned char inbyte(unsigned short port)
{
- unsigned char _v;
- __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
- return _v;
+ unsigned char _v;
+
+ __asm__ __volatile__ ("inb %w1,%b0" : "=a" (_v) : "d" (port));
+ return _v;
}
/* Read register OFFSET.
- This command should always be terminated with read_end(). */
+ * This command should always be terminated with read_end().
+ */
static inline unsigned char read_nibble(short port, unsigned char offset)
{
- unsigned char retval;
- outb(EOC+offset, port + PAR_DATA);
- outb(RdAddr+offset, port + PAR_DATA);
- inbyte(port + PAR_STATUS); /* Settling time delay */
- retval = inbyte(port + PAR_STATUS);
- outb(EOC+offset, port + PAR_DATA);
-
- return retval;
+ unsigned char retval;
+
+ outb(EOC+offset, port + PAR_DATA);
+ outb(RdAddr+offset, port + PAR_DATA);
+ inbyte(port + PAR_STATUS); /* Settling time delay */
+ retval = inbyte(port + PAR_STATUS);
+ outb(EOC+offset, port + PAR_DATA);
+
+ return retval;
}
/* Functions for bulk data read. The interrupt line is always disabled. */
/* Get a byte using read mode 0, reading data from the control lines. */
static inline unsigned char read_byte_mode0(short ioaddr)
{
- unsigned char low_nib;
-
- outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
- inbyte(ioaddr + PAR_STATUS);
- low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
- outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
- inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
- inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
- return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+ unsigned char low_nib;
+
+ outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+ inbyte(ioaddr + PAR_STATUS);
+ low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+ outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+ inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
+ inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
+ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
}
/* The same as read_byte_mode0(), but does multiple inb()s for stability. */
static inline unsigned char read_byte_mode2(short ioaddr)
{
- unsigned char low_nib;
-
- outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
- inbyte(ioaddr + PAR_STATUS);
- low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
- outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
- inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
- return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+ unsigned char low_nib;
+
+ outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+ inbyte(ioaddr + PAR_STATUS);
+ low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+ outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+ inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */
+ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
}
/* Read a byte through the data register. */
static inline unsigned char read_byte_mode4(short ioaddr)
{
- unsigned char low_nib;
+ unsigned char low_nib;
- outb(RdAddr | MAR, ioaddr + PAR_DATA);
- low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
- outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
- return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+ outb(RdAddr | MAR, ioaddr + PAR_DATA);
+ low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+ outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
}
/* Read a byte through the data register, double reading to allow settling. */
static inline unsigned char read_byte_mode6(short ioaddr)
{
- unsigned char low_nib;
-
- outb(RdAddr | MAR, ioaddr + PAR_DATA);
- inbyte(ioaddr + PAR_STATUS);
- low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
- outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
- inbyte(ioaddr + PAR_STATUS);
- return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+ unsigned char low_nib;
+
+ outb(RdAddr | MAR, ioaddr + PAR_DATA);
+ inbyte(ioaddr + PAR_STATUS);
+ low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+ outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+ inbyte(ioaddr + PAR_STATUS);
+ return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
}
static inline void
write_reg(short port, unsigned char reg, unsigned char value)
{
- unsigned char outval;
- outb(EOC | reg, port + PAR_DATA);
- outval = WrAddr | reg;
- outb(outval, port + PAR_DATA);
- outb(outval, port + PAR_DATA); /* Double write for PS/2. */
-
- outval &= 0xf0;
- outval |= value;
- outb(outval, port + PAR_DATA);
- outval &= 0x1f;
- outb(outval, port + PAR_DATA);
- outb(outval, port + PAR_DATA);
-
- outb(EOC | outval, port + PAR_DATA);
+ unsigned char outval;
+
+ outb(EOC | reg, port + PAR_DATA);
+ outval = WrAddr | reg;
+ outb(outval, port + PAR_DATA);
+ outb(outval, port + PAR_DATA); /* Double write for PS/2. */
+
+ outval &= 0xf0;
+ outval |= value;
+ outb(outval, port + PAR_DATA);
+ outval &= 0x1f;
+ outb(outval, port + PAR_DATA);
+ outb(outval, port + PAR_DATA);
+
+ outb(EOC | outval, port + PAR_DATA);
}
static inline void
write_reg_high(short port, unsigned char reg, unsigned char value)
{
- unsigned char outval = EOC | HNib | reg;
+ unsigned char outval = EOC | HNib | reg;
- outb(outval, port + PAR_DATA);
- outval &= WrAddr | HNib | 0x0f;
- outb(outval, port + PAR_DATA);
- outb(outval, port + PAR_DATA); /* Double write for PS/2. */
+ outb(outval, port + PAR_DATA);
+ outval &= WrAddr | HNib | 0x0f;
+ outb(outval, port + PAR_DATA);
+ outb(outval, port + PAR_DATA); /* Double write for PS/2. */
- outval = WrAddr | HNib | value;
- outb(outval, port + PAR_DATA);
- outval &= HNib | 0x0f; /* HNib | value */
- outb(outval, port + PAR_DATA);
- outb(outval, port + PAR_DATA);
+ outval = WrAddr | HNib | value;
+ outb(outval, port + PAR_DATA);
+ outval &= HNib | 0x0f; /* HNib | value */
+ outb(outval, port + PAR_DATA);
+ outb(outval, port + PAR_DATA);
- outb(EOC | HNib | outval, port + PAR_DATA);
+ outb(EOC | HNib | outval, port + PAR_DATA);
}
/* Write a byte out using nibble mode. The low nibble is written first. */
static inline void
write_reg_byte(short port, unsigned char reg, unsigned char value)
{
- unsigned char outval;
- outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */
- outval = WrAddr | reg;
- outb(outval, port + PAR_DATA);
- outb(outval, port + PAR_DATA); /* Double write for PS/2. */
-
- outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
- outb(value & 0x0f, port + PAR_DATA);
- value >>= 4;
- outb(value, port + PAR_DATA);
- outb(0x10 | value, port + PAR_DATA);
- outb(0x10 | value, port + PAR_DATA);
-
- outb(EOC | value, port + PAR_DATA); /* Reset the address register. */
+ unsigned char outval;
+
+ outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */
+ outval = WrAddr | reg;
+ outb(outval, port + PAR_DATA);
+ outb(outval, port + PAR_DATA); /* Double write for PS/2. */
+
+ outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
+ outb(value & 0x0f, port + PAR_DATA);
+ value >>= 4;
+ outb(value, port + PAR_DATA);
+ outb(0x10 | value, port + PAR_DATA);
+ outb(0x10 | value, port + PAR_DATA);
+
+ outb(EOC | value, port + PAR_DATA); /* Reset the address register. */
}
-/*
- * Bulk data writes to the packet buffer. The interrupt line remains enabled.
+/* Bulk data writes to the packet buffer. The interrupt line remains enabled.
* The first, faster method uses only the dataport (data modes 0, 2 & 4).
* The second (backup) method uses data and control regs (modes 1, 3 & 5).
* It should only be needed when there is skew between the individual data
*/
static inline void write_byte_mode0(short ioaddr, unsigned char value)
{
- outb(value & 0x0f, ioaddr + PAR_DATA);
- outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+ outb(value & 0x0f, ioaddr + PAR_DATA);
+ outb((value>>4) | 0x10, ioaddr + PAR_DATA);
}
static inline void write_byte_mode1(short ioaddr, unsigned char value)
{
- outb(value & 0x0f, ioaddr + PAR_DATA);
- outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
- outb((value>>4) | 0x10, ioaddr + PAR_DATA);
- outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
+ outb(value & 0x0f, ioaddr + PAR_DATA);
+ outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
+ outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+ outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
}
/* Write 16bit VALUE to the packet buffer: the same as above just doubled. */
static inline void write_word_mode0(short ioaddr, unsigned short value)
{
- outb(value & 0x0f, ioaddr + PAR_DATA);
- value >>= 4;
- outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
- value >>= 4;
- outb(value & 0x0f, ioaddr + PAR_DATA);
- value >>= 4;
- outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+ outb(value & 0x0f, ioaddr + PAR_DATA);
+ value >>= 4;
+ outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+ value >>= 4;
+ outb(value & 0x0f, ioaddr + PAR_DATA);
+ value >>= 4;
+ outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
}
/* EEPROM_Ctrl bits. */
/* Delay between EEPROM clock transitions. */
#define eeprom_delay(ticks) \
-do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; } } while (0)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17)
-#define EE_READ(offset) (((6 << 6) + (offset)) << 17)
+#define EE_READ(offset) (((6 << 6) + (offset)) << 17)
#define EE_ERASE(offset) (((7 << 6) + (offset)) << 17)
#define EE_CMD_SIZE 27 /* The command+address+data size. */
/* SuperH Ethernet device driver
*
+ * Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2006-2012 Nobuhiro Iwamatsu
* Copyright (C) 2008-2014 Renesas Solutions Corp.
* Copyright (C) 2013-2014 Cogent Embedded, Inc.
{ .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data },
{ .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data },
{ .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data },
+ { .compatible = "renesas,ether-r8a7793", .data = &r8a779x_data },
{ .compatible = "renesas,ether-r8a7794", .data = &r8a779x_data },
{ .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data },
{ }
/* get base addr */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(res == NULL)) {
- dev_err(&pdev->dev, "invalid resource\n");
- return -EINVAL;
- }
ndev = alloc_etherdev(sizeof(struct sh_eth_private));
if (!ndev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- /* The sh Ether-specific entries in the device structure. */
- ndev->base_addr = res->start;
devno = pdev->id;
if (devno < 0)
devno = 0;
goto out_release;
}
+ ndev->base_addr = res->start;
+
spin_lock_init(&mdp->lock);
mdp->pdev = pdev;
}
}
+ if (mdp->cd->rmiimode)
+ sh_eth_write(ndev, 0x1, RMIIMODE);
+
/* MDIO bus init */
ret = sh_mdio_init(mdp, pd);
if (ret) {
{ "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
{ "r8a7790-ether", (kernel_ulong_t)&r8a779x_data },
{ "r8a7791-ether", (kernel_ulong_t)&r8a779x_data },
+ { "r8a7793-ether", (kernel_ulong_t)&r8a779x_data },
{ "r8a7794-ether", (kernel_ulong_t)&r8a779x_data },
{ }
};
/* Get memory resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto err_out;
-
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr))
return PTR_ERR(addr);
.ptp_write_host_time = efx_ef10_ptp_write_host_time,
.ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events,
.ptp_set_ts_config = efx_ef10_ptp_set_ts_config,
+ .sriov_init = efx_ef10_sriov_init,
+ .sriov_fini = efx_ef10_sriov_fini,
+ .sriov_mac_address_changed = efx_ef10_sriov_mac_address_changed,
+ .sriov_wanted = efx_ef10_sriov_wanted,
+ .sriov_reset = efx_ef10_sriov_reset,
.revision = EFX_REV_HUNT_A0,
.max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH),
/* If RSS is requested for the PF *and* VFs then we can't write RSS
* table entries that are inaccessible to VFs
*/
- if (efx_sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
+ if (efx->type->sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
count > efx_vf_size(efx)) {
netif_warn(efx, probe, efx->net_dev,
"Reducing number of RSS channels from %u to %u for "
}
/* RSS might be usable on VFs even if it is disabled on the PF */
- efx->rss_spread = ((efx->n_rx_channels > 1 || !efx_sriov_wanted(efx)) ?
+
+ efx->rss_spread = ((efx->n_rx_channels > 1 ||
+ !efx->type->sriov_wanted(efx)) ?
efx->n_rx_channels : efx_vf_size(efx));
return 0;
}
ether_addr_copy(net_dev->dev_addr, new_addr);
- efx_sriov_mac_address_changed(efx);
+ efx->type->sriov_mac_address_changed(efx);
/* Reconfigure the MAC */
mutex_lock(&efx->mac_lock);
.ndo_set_rx_mode = efx_set_rx_mode,
.ndo_set_features = efx_set_features,
#ifdef CONFIG_SFC_SRIOV
- .ndo_set_vf_mac = efx_sriov_set_vf_mac,
- .ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
- .ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk,
- .ndo_get_vf_config = efx_sriov_get_vf_config,
+ .ndo_set_vf_mac = efx_siena_sriov_set_vf_mac,
+ .ndo_set_vf_vlan = efx_siena_sriov_set_vf_vlan,
+ .ndo_set_vf_spoofchk = efx_siena_sriov_set_vf_spoofchk,
+ .ndo_get_vf_config = efx_siena_sriov_get_vf_config,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
if (rc)
goto fail;
efx_restore_filters(efx);
- efx_sriov_reset(efx);
+ efx->type->sriov_reset(efx);
mutex_unlock(&efx->mac_lock);
efx_disable_interrupts(efx);
rtnl_unlock();
- efx_sriov_fini(efx);
+ efx->type->sriov_fini(efx);
efx_unregister_netdev(efx);
efx_mtd_remove(efx);
if (rc)
goto fail4;
- rc = efx_sriov_init(efx);
+ rc = efx->type->sriov_init(efx);
if (rc)
netif_err(efx, probe, efx->net_dev,
"SR-IOV can't be enabled rc %d\n", rc);
.mtd_write = falcon_mtd_write,
.mtd_sync = falcon_mtd_sync,
#endif
+ .sriov_init = efx_falcon_sriov_init,
+ .sriov_fini = efx_falcon_sriov_fini,
+ .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed,
+ .sriov_wanted = efx_falcon_sriov_wanted,
+ .sriov_reset = efx_falcon_sriov_reset,
.revision = EFX_REV_FALCON_A1,
.txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
.mtd_write = falcon_mtd_write,
.mtd_sync = falcon_mtd_sync,
#endif
+ .sriov_init = efx_falcon_sriov_init,
+ .sriov_fini = efx_falcon_sriov_fini,
+ .sriov_mac_address_changed = efx_falcon_sriov_mac_address_changed,
+ .sriov_wanted = efx_falcon_sriov_wanted,
+ .sriov_reset = efx_falcon_sriov_reset,
.revision = EFX_REV_FALCON_B0,
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
struct efx_special_buffer *buffer,
unsigned int len)
{
+#ifdef CONFIG_SFC_SRIOV
+ struct siena_nic_data *nic_data = efx->nic_data;
+#endif
len = ALIGN(len, EFX_BUF_SIZE);
if (efx_nic_alloc_buffer(efx, &buffer->buf, len, GFP_KERNEL))
buffer->index = efx->next_buffer_table;
efx->next_buffer_table += buffer->entries;
#ifdef CONFIG_SFC_SRIOV
- BUG_ON(efx_sriov_enabled(efx) &&
- efx->vf_buftbl_base < efx->next_buffer_table);
+ BUG_ON(efx_siena_sriov_enabled(efx) &&
+ nic_data->vf_buftbl_base < efx->next_buffer_table);
#endif
netif_dbg(efx, probe, efx->net_dev,
* the firmware (though we will still have to poll for
* completion). If that fails, fall back to the old scheme.
*/
- if (efx_sriov_enabled(efx)) {
+ if (efx_siena_sriov_enabled(efx)) {
rc = efx_mcdi_flush_rxqs(efx);
if (!rc)
goto wait;
netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_farch_handle_tx_flush_done(efx, event);
- efx_sriov_tx_flush_done(efx, event);
+ efx_siena_sriov_tx_flush_done(efx, event);
break;
case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_farch_handle_rx_flush_done(efx, event);
- efx_sriov_rx_flush_done(efx, event);
+ efx_siena_sriov_rx_flush_done(efx, event);
break;
case FSE_AZ_EVQ_INIT_DONE_EV:
netif_dbg(efx, hw, efx->net_dev,
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
} else
- efx_sriov_desc_fetch_err(efx, ev_sub_data);
+ efx_siena_sriov_desc_fetch_err(efx, ev_sub_data);
break;
case FSE_BZ_TX_DSC_ERROR_EV:
if (ev_sub_data < EFX_VI_BASE) {
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
} else
- efx_sriov_desc_fetch_err(efx, ev_sub_data);
+ efx_siena_sriov_desc_fetch_err(efx, ev_sub_data);
break;
default:
netif_vdbg(efx, hw, efx->net_dev,
efx_farch_handle_driver_event(channel, &event);
break;
case FSE_CZ_EV_CODE_USER_EV:
- efx_sriov_event(channel, &event);
+ efx_siena_sriov_event(channel, &event);
break;
case FSE_CZ_EV_CODE_MCDI_EV:
efx_mcdi_process_event(channel, &event);
{
unsigned vi_count, buftbl_min;
+#ifdef CONFIG_SFC_SRIOV
+ struct siena_nic_data *nic_data = efx->nic_data;
+#endif
+
/* Account for the buffer table entries backing the datapath channels
* and the descriptor caches for those channels.
*/
vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES);
#ifdef CONFIG_SFC_SRIOV
- if (efx_sriov_wanted(efx)) {
+ if (efx->type->sriov_wanted(efx)) {
unsigned vi_dc_entries, buftbl_free, entries_per_vf, vf_limit;
- efx->vf_buftbl_base = buftbl_min;
+ nic_data->vf_buftbl_base = buftbl_min;
vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES;
vi_count = max(vi_count, EFX_VI_BASE);
/* MAC stats are gather lazily. We can ignore this. */
break;
case MCDI_EVENT_CODE_FLR:
- efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
+ efx_siena_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
break;
case MCDI_EVENT_CODE_PTP_RX:
case MCDI_EVENT_CODE_PTP_FAULT:
* @vf_count: Number of VFs intended to be enabled.
* @vf_init_count: Number of VFs that have been fully initialised.
* @vi_scale: log2 number of vnics per VF.
- * @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
- * @vfdi_status: Common VFDI status page to be dmad to VF address space.
- * @local_addr_list: List of local addresses. Protected by %local_lock.
- * @local_page_list: List of DMA addressable pages used to broadcast
- * %local_addr_list. Protected by %local_lock.
- * @local_lock: Mutex protecting %local_addr_list and %local_page_list.
- * @peer_work: Work item to broadcast peer addresses to VMs.
* @ptp_data: PTP state data
* @vpd_sn: Serial number read from VPD
* @monitor_work: Hardware monitor workitem
wait_queue_head_t flush_wq;
#ifdef CONFIG_SFC_SRIOV
- struct efx_channel *vfdi_channel;
struct efx_vf *vf;
unsigned vf_count;
unsigned vf_init_count;
unsigned vi_scale;
- unsigned vf_buftbl_base;
- struct efx_buffer vfdi_status;
- struct list_head local_addr_list;
- struct list_head local_page_list;
- struct mutex local_lock;
- struct work_struct peer_work;
#endif
struct efx_ptp_data *ptp_data;
int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp);
int (*ptp_set_ts_config)(struct efx_nic *efx,
struct hwtstamp_config *init);
+ int (*sriov_init)(struct efx_nic *efx);
+ void (*sriov_fini)(struct efx_nic *efx);
+ void (*sriov_mac_address_changed)(struct efx_nic *efx);
+ bool (*sriov_wanted)(struct efx_nic *efx);
+ void (*sriov_reset)(struct efx_nic *efx);
int revision;
unsigned int txd_ptr_tbl_base;
/**
* struct siena_nic_data - Siena NIC state
+ * @efx: Pointer back to main interface structure
* @wol_filter_id: Wake-on-LAN packet filter id
* @stats: Hardware statistics
+ * @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
+ * @vfdi_status: Common VFDI status page to be dmad to VF address space.
+ * @local_addr_list: List of local addresses. Protected by %local_lock.
+ * @local_page_list: List of DMA addressable pages used to broadcast
+ * %local_addr_list. Protected by %local_lock.
+ * @local_lock: Mutex protecting %local_addr_list and %local_page_list.
+ * @peer_work: Work item to broadcast peer addresses to VMs.
*/
struct siena_nic_data {
+ struct efx_nic *efx;
int wol_filter_id;
u64 stats[SIENA_STAT_COUNT];
+#ifdef CONFIG_SFC_SRIOV
+ struct efx_channel *vfdi_channel;
+ unsigned vf_buftbl_base;
+ struct efx_buffer vfdi_status;
+ struct list_head local_addr_list;
+ struct list_head local_page_list;
+ struct mutex local_lock;
+ struct work_struct peer_work;
+#endif
};
enum {
#ifdef CONFIG_SFC_SRIOV
-static inline bool efx_sriov_wanted(struct efx_nic *efx)
+/* SIENA */
+static inline bool efx_siena_sriov_wanted(struct efx_nic *efx)
{
return efx->vf_count != 0;
}
-static inline bool efx_sriov_enabled(struct efx_nic *efx)
+
+static inline bool efx_siena_sriov_enabled(struct efx_nic *efx)
{
return efx->vf_init_count != 0;
}
+
static inline unsigned int efx_vf_size(struct efx_nic *efx)
{
return 1 << efx->vi_scale;
}
int efx_init_sriov(void);
-void efx_sriov_probe(struct efx_nic *efx);
-int efx_sriov_init(struct efx_nic *efx);
-void efx_sriov_mac_address_changed(struct efx_nic *efx);
-void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
-void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
-void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event);
-void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
-void efx_sriov_flr(struct efx_nic *efx, unsigned flr);
-void efx_sriov_reset(struct efx_nic *efx);
-void efx_sriov_fini(struct efx_nic *efx);
+void efx_siena_sriov_probe(struct efx_nic *efx);
+int efx_siena_sriov_init(struct efx_nic *efx);
+void efx_siena_sriov_mac_address_changed(struct efx_nic *efx);
+void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
+void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
+void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event);
+void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
+void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr);
+void efx_siena_sriov_reset(struct efx_nic *efx);
+void efx_siena_sriov_fini(struct efx_nic *efx);
void efx_fini_sriov(void);
+/* EF10 */
+static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; }
+static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
+static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {}
+static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
+static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {}
+
#else
-static inline bool efx_sriov_wanted(struct efx_nic *efx) { return false; }
-static inline bool efx_sriov_enabled(struct efx_nic *efx) { return false; }
+/* SIENA */
+static inline bool efx_siena_sriov_wanted(struct efx_nic *efx) { return false; }
+static inline bool efx_siena_sriov_enabled(struct efx_nic *efx) { return false; }
static inline unsigned int efx_vf_size(struct efx_nic *efx) { return 0; }
-
static inline int efx_init_sriov(void) { return 0; }
-static inline void efx_sriov_probe(struct efx_nic *efx) {}
-static inline int efx_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
-static inline void efx_sriov_mac_address_changed(struct efx_nic *efx) {}
-static inline void efx_sriov_tx_flush_done(struct efx_nic *efx,
- efx_qword_t *event) {}
-static inline void efx_sriov_rx_flush_done(struct efx_nic *efx,
- efx_qword_t *event) {}
-static inline void efx_sriov_event(struct efx_channel *channel,
- efx_qword_t *event) {}
-static inline void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) {}
-static inline void efx_sriov_flr(struct efx_nic *efx, unsigned flr) {}
-static inline void efx_sriov_reset(struct efx_nic *efx) {}
-static inline void efx_sriov_fini(struct efx_nic *efx) {}
+static inline void efx_siena_sriov_probe(struct efx_nic *efx) {}
+static inline int efx_siena_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
+static inline void efx_siena_sriov_mac_address_changed(struct efx_nic *efx) {}
+static inline void efx_siena_sriov_tx_flush_done(struct efx_nic *efx,
+ efx_qword_t *event) {}
+static inline void efx_siena_sriov_rx_flush_done(struct efx_nic *efx,
+ efx_qword_t *event) {}
+static inline void efx_siena_sriov_event(struct efx_channel *channel,
+ efx_qword_t *event) {}
+static inline void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx,
+ unsigned dmaq) {}
+static inline void efx_siena_sriov_flr(struct efx_nic *efx, unsigned flr) {}
+static inline void efx_siena_sriov_reset(struct efx_nic *efx) {}
+static inline void efx_siena_sriov_fini(struct efx_nic *efx) {}
static inline void efx_fini_sriov(void) {}
+/* EF10 */
+static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx) { return false; }
+static inline int efx_ef10_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
+static inline void efx_ef10_sriov_mac_address_changed(struct efx_nic *efx) {}
+static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
+static inline void efx_ef10_sriov_fini(struct efx_nic *efx) {}
+
#endif
-int efx_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
-int efx_sriov_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos);
-int efx_sriov_get_vf_config(struct net_device *dev, int vf,
- struct ifla_vf_info *ivf);
-int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
- bool spoofchk);
+/* FALCON */
+static inline bool efx_falcon_sriov_wanted(struct efx_nic *efx) { return false; }
+static inline int efx_falcon_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
+static inline void efx_falcon_sriov_mac_address_changed(struct efx_nic *efx) {}
+static inline void efx_falcon_sriov_reset(struct efx_nic *efx) {}
+static inline void efx_falcon_sriov_fini(struct efx_nic *efx) {}
+
+int efx_siena_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
+int efx_siena_sriov_set_vf_vlan(struct net_device *dev, int vf,
+ u16 vlan, u8 qos);
+int efx_siena_sriov_get_vf_config(struct net_device *dev, int vf,
+ struct ifla_vf_info *ivf);
+int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
+ bool spoofchk);
struct ethtool_ts_info;
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL);
if (!nic_data)
return -ENOMEM;
+ nic_data->efx = efx;
efx->nic_data = nic_data;
if (efx_farch_fpga_ver(efx) != 0) {
if (rc)
goto fail5;
- efx_sriov_probe(efx);
+ efx_siena_sriov_probe(efx);
efx_ptp_defer_probe_with_channel(efx);
return 0;
#endif
.ptp_write_host_time = siena_ptp_write_host_time,
.ptp_set_ts_config = siena_ptp_set_ts_config,
+ .sriov_init = efx_siena_sriov_init,
+ .sriov_fini = efx_siena_sriov_fini,
+ .sriov_mac_address_changed = efx_siena_sriov_mac_address_changed,
+ .sriov_wanted = efx_siena_sriov_wanted,
+ .sriov_reset = efx_siena_sriov_reset,
.revision = EFX_REV_SIENA_A0,
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
* @status_lock: Mutex protecting @msg_seqno, @status_addr, @addr,
* @peer_page_addrs and @peer_page_count from simultaneous
* updates by the VM and consumption by
- * efx_sriov_update_vf_addr()
+ * efx_siena_sriov_update_vf_addr()
* @peer_page_addrs: Pointer to an array of guest pages for local addresses.
* @peer_page_count: Number of entries in @peer_page_count.
* @evq0_addrs: Array of guest pages backing evq0.
return EFX_VI_BASE + vf->index * efx_vf_size(vf->efx) + index;
}
-static int efx_sriov_cmd(struct efx_nic *efx, bool enable,
- unsigned *vi_scale_out, unsigned *vf_total_out)
+static int efx_siena_sriov_cmd(struct efx_nic *efx, bool enable,
+ unsigned *vi_scale_out, unsigned *vf_total_out)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_SRIOV_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_SRIOV_OUT_LEN);
return 0;
}
-static void efx_sriov_usrev(struct efx_nic *efx, bool enabled)
+static void efx_siena_sriov_usrev(struct efx_nic *efx, bool enabled)
{
+ struct siena_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
EFX_POPULATE_OWORD_2(reg,
FRF_CZ_USREV_DIS, enabled ? 0 : 1,
- FRF_CZ_DFLT_EVQ, efx->vfdi_channel->channel);
+ FRF_CZ_DFLT_EVQ, nic_data->vfdi_channel->channel);
efx_writeo(efx, ®, FR_CZ_USR_EV_CFG);
}
-static int efx_sriov_memcpy(struct efx_nic *efx, struct efx_memcpy_req *req,
- unsigned int count)
+static int efx_siena_sriov_memcpy(struct efx_nic *efx,
+ struct efx_memcpy_req *req,
+ unsigned int count)
{
MCDI_DECLARE_BUF(inbuf, MCDI_CTL_SDU_LEN_MAX_V1);
MCDI_DECLARE_STRUCT_PTR(record);
/* The TX filter is entirely controlled by this driver, and is modified
* underneath the feet of the VF
*/
-static void efx_sriov_reset_tx_filter(struct efx_vf *vf)
+static void efx_siena_sriov_reset_tx_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
}
/* The RX filter is managed here on behalf of the VF driver */
-static void efx_sriov_reset_rx_filter(struct efx_vf *vf)
+static void efx_siena_sriov_reset_rx_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
}
}
-static void __efx_sriov_update_vf_addr(struct efx_vf *vf)
+static void __efx_siena_sriov_update_vf_addr(struct efx_vf *vf)
{
- efx_sriov_reset_tx_filter(vf);
- efx_sriov_reset_rx_filter(vf);
- queue_work(vfdi_workqueue, &vf->efx->peer_work);
+ struct efx_nic *efx = vf->efx;
+ struct siena_nic_data *nic_data = efx->nic_data;
+
+ efx_siena_sriov_reset_tx_filter(vf);
+ efx_siena_sriov_reset_rx_filter(vf);
+ queue_work(vfdi_workqueue, &nic_data->peer_work);
}
/* Push the peer list to this VF. The caller must hold status_lock to interlock
* with VFDI requests, and they must be serialised against manipulation of
* local_page_list, either by acquiring local_lock or by running from
- * efx_sriov_peer_work()
+ * efx_siena_sriov_peer_work()
*/
-static void __efx_sriov_push_vf_status(struct efx_vf *vf)
+static void __efx_siena_sriov_push_vf_status(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
- struct vfdi_status *status = efx->vfdi_status.addr;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct vfdi_status *status = nic_data->vfdi_status.addr;
struct efx_memcpy_req copy[4];
struct efx_endpoint_page *epp;
unsigned int pos, count;
*/
data_offset = offsetof(struct vfdi_status, version);
copy[1].from_rid = efx->pci_dev->devfn;
- copy[1].from_addr = efx->vfdi_status.dma_addr + data_offset;
+ copy[1].from_addr = nic_data->vfdi_status.dma_addr + data_offset;
copy[1].to_rid = vf->pci_rid;
copy[1].to_addr = vf->status_addr + data_offset;
copy[1].length = status->length - data_offset;
/* Copy the peer pages */
pos = 2;
count = 0;
- list_for_each_entry(epp, &efx->local_page_list, link) {
+ list_for_each_entry(epp, &nic_data->local_page_list, link) {
if (count == vf->peer_page_count) {
/* The VF driver will know they need to provide more
* pages because peer_addr_count is too large.
copy[pos].length = EFX_PAGE_SIZE;
if (++pos == ARRAY_SIZE(copy)) {
- efx_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
+ efx_siena_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
pos = 0;
}
++count;
copy[pos].to_addr = vf->status_addr + offsetof(struct vfdi_status,
generation_end);
copy[pos].length = sizeof(status->generation_end);
- efx_sriov_memcpy(efx, copy, pos + 1);
+ efx_siena_sriov_memcpy(efx, copy, pos + 1);
/* Notify the guest */
EFX_POPULATE_QWORD_3(event,
&event);
}
-static void efx_sriov_bufs(struct efx_nic *efx, unsigned offset,
- u64 *addr, unsigned count)
+static void efx_siena_sriov_bufs(struct efx_nic *efx, unsigned offset,
+ u64 *addr, unsigned count)
{
efx_qword_t buf;
unsigned pos;
return VFDI_RC_EINVAL;
}
- efx_sriov_bufs(efx, buftbl, req->u.init_evq.addr, buf_count);
+ efx_siena_sriov_bufs(efx, buftbl, req->u.init_evq.addr, buf_count);
EFX_POPULATE_OWORD_3(reg,
FRF_CZ_TIMER_Q_EN, 1,
}
if (__test_and_set_bit(req->u.init_rxq.index, vf->rxq_mask))
++vf->rxq_count;
- efx_sriov_bufs(efx, buftbl, req->u.init_rxq.addr, buf_count);
+ efx_siena_sriov_bufs(efx, buftbl, req->u.init_rxq.addr, buf_count);
label = req->u.init_rxq.label & EFX_FIELD_MASK(FRF_AZ_RX_DESCQ_LABEL);
EFX_POPULATE_OWORD_6(reg,
if (__test_and_set_bit(req->u.init_txq.index, vf->txq_mask))
++vf->txq_count;
mutex_unlock(&vf->txq_lock);
- efx_sriov_bufs(efx, buftbl, req->u.init_txq.addr, buf_count);
+ efx_siena_sriov_bufs(efx, buftbl, req->u.init_txq.addr, buf_count);
eth_filt_en = vf->tx_filter_mode == VF_TX_FILTER_ON;
efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL,
vf_offset + index);
}
- efx_sriov_bufs(efx, vf->buftbl_base, NULL,
- EFX_VF_BUFTBL_PER_VI * efx_vf_size(efx));
+ efx_siena_sriov_bufs(efx, vf->buftbl_base, NULL,
+ EFX_VF_BUFTBL_PER_VI * efx_vf_size(efx));
efx_vfdi_flush_clear(vf);
vf->evq0_count = 0;
static int efx_vfdi_insert_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
+ struct siena_nic_data *nic_data = efx->nic_data;
struct vfdi_req *req = vf->buf.addr;
unsigned vf_rxq = req->u.mac_filter.rxq;
unsigned flags;
vf->rx_filter_qid = vf_rxq;
vf->rx_filtering = true;
- efx_sriov_reset_rx_filter(vf);
- queue_work(vfdi_workqueue, &efx->peer_work);
+ efx_siena_sriov_reset_rx_filter(vf);
+ queue_work(vfdi_workqueue, &nic_data->peer_work);
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_remove_all_filters(struct efx_vf *vf)
{
+ struct efx_nic *efx = vf->efx;
+ struct siena_nic_data *nic_data = efx->nic_data;
+
vf->rx_filtering = false;
- efx_sriov_reset_rx_filter(vf);
- queue_work(vfdi_workqueue, &vf->efx->peer_work);
+ efx_siena_sriov_reset_rx_filter(vf);
+ queue_work(vfdi_workqueue, &nic_data->peer_work);
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_set_status_page(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
+ struct siena_nic_data *nic_data = efx->nic_data;
struct vfdi_req *req = vf->buf.addr;
u64 page_count = req->u.set_status_page.peer_page_count;
u64 max_page_count =
return VFDI_RC_EINVAL;
}
- mutex_lock(&efx->local_lock);
+ mutex_lock(&nic_data->local_lock);
mutex_lock(&vf->status_lock);
vf->status_addr = req->u.set_status_page.dma_addr;
}
}
- __efx_sriov_push_vf_status(vf);
+ __efx_siena_sriov_push_vf_status(vf);
mutex_unlock(&vf->status_lock);
- mutex_unlock(&efx->local_lock);
+ mutex_unlock(&nic_data->local_lock);
return VFDI_RC_SUCCESS;
}
[VFDI_OP_CLEAR_STATUS_PAGE] = efx_vfdi_clear_status_page,
};
-static void efx_sriov_vfdi(struct work_struct *work)
+static void efx_siena_sriov_vfdi(struct work_struct *work)
{
struct efx_vf *vf = container_of(work, struct efx_vf, req);
struct efx_nic *efx = vf->efx;
copy[0].to_rid = efx->pci_dev->devfn;
copy[0].to_addr = vf->buf.dma_addr;
copy[0].length = EFX_PAGE_SIZE;
- rc = efx_sriov_memcpy(efx, copy, 1);
+ rc = efx_siena_sriov_memcpy(efx, copy, 1);
if (rc) {
/* If we can't get the request, we can't reply to the caller */
if (net_ratelimit())
copy[1].to_addr = vf->req_addr + offsetof(struct vfdi_req, op);
copy[1].length = sizeof(req->op);
- (void) efx_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
+ (void)efx_siena_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
}
* event ring in guest memory with VFDI reset events, then (re-initialise) the
* event queue to raise an interrupt. The guest driver will then recover.
*/
-static void efx_sriov_reset_vf(struct efx_vf *vf, struct efx_buffer *buffer)
+static void efx_siena_sriov_reset_vf(struct efx_vf *vf,
+ struct efx_buffer *buffer)
{
struct efx_nic *efx = vf->efx;
struct efx_memcpy_req copy_req[4];
copy_req[k].to_addr = vf->evq0_addrs[pos + k];
copy_req[k].length = EFX_PAGE_SIZE;
}
- rc = efx_sriov_memcpy(efx, copy_req, count);
+ rc = efx_siena_sriov_memcpy(efx, copy_req, count);
if (rc) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
/* Reinitialise, arm and trigger evq0 */
abs_evq = abs_index(vf, 0);
buftbl = EFX_BUFTBL_EVQ_BASE(vf, 0);
- efx_sriov_bufs(efx, buftbl, vf->evq0_addrs, vf->evq0_count);
+ efx_siena_sriov_bufs(efx, buftbl, vf->evq0_addrs, vf->evq0_count);
EFX_POPULATE_OWORD_3(reg,
FRF_CZ_TIMER_Q_EN, 1,
mutex_unlock(&vf->status_lock);
}
-static void efx_sriov_reset_vf_work(struct work_struct *work)
+static void efx_siena_sriov_reset_vf_work(struct work_struct *work)
{
struct efx_vf *vf = container_of(work, struct efx_vf, req);
struct efx_nic *efx = vf->efx;
struct efx_buffer buf;
if (!efx_nic_alloc_buffer(efx, &buf, EFX_PAGE_SIZE, GFP_NOIO)) {
- efx_sriov_reset_vf(vf, &buf);
+ efx_siena_sriov_reset_vf(vf, &buf);
efx_nic_free_buffer(efx, &buf);
}
}
-static void efx_sriov_handle_no_channel(struct efx_nic *efx)
+static void efx_siena_sriov_handle_no_channel(struct efx_nic *efx)
{
netif_err(efx, drv, efx->net_dev,
"ERROR: IOV requires MSI-X and 1 additional interrupt"
efx->vf_count = 0;
}
-static int efx_sriov_probe_channel(struct efx_channel *channel)
+static int efx_siena_sriov_probe_channel(struct efx_channel *channel)
{
- channel->efx->vfdi_channel = channel;
+ struct siena_nic_data *nic_data = channel->efx->nic_data;
+ nic_data->vfdi_channel = channel;
+
return 0;
}
static void
-efx_sriov_get_channel_name(struct efx_channel *channel, char *buf, size_t len)
+efx_siena_sriov_get_channel_name(struct efx_channel *channel,
+ char *buf, size_t len)
{
snprintf(buf, len, "%s-iov", channel->efx->name);
}
-static const struct efx_channel_type efx_sriov_channel_type = {
- .handle_no_channel = efx_sriov_handle_no_channel,
- .pre_probe = efx_sriov_probe_channel,
+static const struct efx_channel_type efx_siena_sriov_channel_type = {
+ .handle_no_channel = efx_siena_sriov_handle_no_channel,
+ .pre_probe = efx_siena_sriov_probe_channel,
.post_remove = efx_channel_dummy_op_void,
- .get_name = efx_sriov_get_channel_name,
+ .get_name = efx_siena_sriov_get_channel_name,
/* no copy operation; channel must not be reallocated */
.keep_eventq = true,
};
-void efx_sriov_probe(struct efx_nic *efx)
+void efx_siena_sriov_probe(struct efx_nic *efx)
{
unsigned count;
if (!max_vfs)
return;
- if (efx_sriov_cmd(efx, false, &efx->vi_scale, &count))
+ if (efx_siena_sriov_cmd(efx, false, &efx->vi_scale, &count))
return;
if (count > 0 && count > max_vfs)
count = max_vfs;
/* efx_nic_dimension_resources() will reduce vf_count as appopriate */
efx->vf_count = count;
- efx->extra_channel_type[EFX_EXTRA_CHANNEL_IOV] = &efx_sriov_channel_type;
+ efx->extra_channel_type[EFX_EXTRA_CHANNEL_IOV] = &efx_siena_sriov_channel_type;
}
/* Copy the list of individual addresses into the vfdi_status.peers
* array and auxillary pages, protected by %local_lock. Drop that lock
* and then broadcast the address list to every VF.
*/
-static void efx_sriov_peer_work(struct work_struct *data)
+static void efx_siena_sriov_peer_work(struct work_struct *data)
{
- struct efx_nic *efx = container_of(data, struct efx_nic, peer_work);
- struct vfdi_status *vfdi_status = efx->vfdi_status.addr;
+ struct siena_nic_data *nic_data = container_of(data,
+ struct siena_nic_data,
+ peer_work);
+ struct efx_nic *efx = nic_data->efx;
+ struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr;
struct efx_vf *vf;
struct efx_local_addr *local_addr;
struct vfdi_endpoint *peer;
unsigned int peer_count;
unsigned int pos;
- mutex_lock(&efx->local_lock);
+ mutex_lock(&nic_data->local_lock);
/* Move the existing peer pages off %local_page_list */
INIT_LIST_HEAD(&pages);
- list_splice_tail_init(&efx->local_page_list, &pages);
+ list_splice_tail_init(&nic_data->local_page_list, &pages);
/* Populate the VF addresses starting from entry 1 (entry 0 is
* the PF address)
}
/* Fill the remaining addresses */
- list_for_each_entry(local_addr, &efx->local_addr_list, link) {
+ list_for_each_entry(local_addr, &nic_data->local_addr_list, link) {
ether_addr_copy(peer->mac_addr, local_addr->addr);
peer->tci = 0;
++peer;
list_del(&epp->link);
}
- list_add_tail(&epp->link, &efx->local_page_list);
+ list_add_tail(&epp->link, &nic_data->local_page_list);
peer = (struct vfdi_endpoint *)epp->ptr;
peer_space = EFX_PAGE_SIZE / sizeof(struct vfdi_endpoint);
}
}
vfdi_status->peer_count = peer_count;
- mutex_unlock(&efx->local_lock);
+ mutex_unlock(&nic_data->local_lock);
/* Free any now unused endpoint pages */
while (!list_empty(&pages)) {
mutex_lock(&vf->status_lock);
if (vf->status_addr)
- __efx_sriov_push_vf_status(vf);
+ __efx_siena_sriov_push_vf_status(vf);
mutex_unlock(&vf->status_lock);
}
}
-static void efx_sriov_free_local(struct efx_nic *efx)
+static void efx_siena_sriov_free_local(struct efx_nic *efx)
{
+ struct siena_nic_data *nic_data = efx->nic_data;
struct efx_local_addr *local_addr;
struct efx_endpoint_page *epp;
- while (!list_empty(&efx->local_addr_list)) {
- local_addr = list_first_entry(&efx->local_addr_list,
+ while (!list_empty(&nic_data->local_addr_list)) {
+ local_addr = list_first_entry(&nic_data->local_addr_list,
struct efx_local_addr, link);
list_del(&local_addr->link);
kfree(local_addr);
}
- while (!list_empty(&efx->local_page_list)) {
- epp = list_first_entry(&efx->local_page_list,
+ while (!list_empty(&nic_data->local_page_list)) {
+ epp = list_first_entry(&nic_data->local_page_list,
struct efx_endpoint_page, link);
list_del(&epp->link);
dma_free_coherent(&efx->pci_dev->dev, EFX_PAGE_SIZE,
}
}
-static int efx_sriov_vf_alloc(struct efx_nic *efx)
+static int efx_siena_sriov_vf_alloc(struct efx_nic *efx)
{
unsigned index;
struct efx_vf *vf;
vf->rx_filter_id = -1;
vf->tx_filter_mode = VF_TX_FILTER_AUTO;
vf->tx_filter_id = -1;
- INIT_WORK(&vf->req, efx_sriov_vfdi);
- INIT_WORK(&vf->reset_work, efx_sriov_reset_vf_work);
+ INIT_WORK(&vf->req, efx_siena_sriov_vfdi);
+ INIT_WORK(&vf->reset_work, efx_siena_sriov_reset_vf_work);
init_waitqueue_head(&vf->flush_waitq);
mutex_init(&vf->status_lock);
mutex_init(&vf->txq_lock);
return 0;
}
-static void efx_sriov_vfs_fini(struct efx_nic *efx)
+static void efx_siena_sriov_vfs_fini(struct efx_nic *efx)
{
struct efx_vf *vf;
unsigned int pos;
}
}
-static int efx_sriov_vfs_init(struct efx_nic *efx)
+static int efx_siena_sriov_vfs_init(struct efx_nic *efx)
{
struct pci_dev *pci_dev = efx->pci_dev;
+ struct siena_nic_data *nic_data = efx->nic_data;
unsigned index, devfn, sriov, buftbl_base;
u16 offset, stride;
struct efx_vf *vf;
pci_read_config_word(pci_dev, sriov + PCI_SRIOV_VF_OFFSET, &offset);
pci_read_config_word(pci_dev, sriov + PCI_SRIOV_VF_STRIDE, &stride);
- buftbl_base = efx->vf_buftbl_base;
+ buftbl_base = nic_data->vf_buftbl_base;
devfn = pci_dev->devfn + offset;
for (index = 0; index < efx->vf_count; ++index) {
vf = efx->vf + index;
return 0;
fail:
- efx_sriov_vfs_fini(efx);
+ efx_siena_sriov_vfs_fini(efx);
return rc;
}
-int efx_sriov_init(struct efx_nic *efx)
+int efx_siena_sriov_init(struct efx_nic *efx)
{
struct net_device *net_dev = efx->net_dev;
+ struct siena_nic_data *nic_data = efx->nic_data;
struct vfdi_status *vfdi_status;
int rc;
if (efx->vf_count == 0)
return 0;
- rc = efx_sriov_cmd(efx, true, NULL, NULL);
+ rc = efx_siena_sriov_cmd(efx, true, NULL, NULL);
if (rc)
goto fail_cmd;
- rc = efx_nic_alloc_buffer(efx, &efx->vfdi_status, sizeof(*vfdi_status),
- GFP_KERNEL);
+ rc = efx_nic_alloc_buffer(efx, &nic_data->vfdi_status,
+ sizeof(*vfdi_status), GFP_KERNEL);
if (rc)
goto fail_status;
- vfdi_status = efx->vfdi_status.addr;
+ vfdi_status = nic_data->vfdi_status.addr;
memset(vfdi_status, 0, sizeof(*vfdi_status));
vfdi_status->version = 1;
vfdi_status->length = sizeof(*vfdi_status);
vfdi_status->peer_count = 1 + efx->vf_count;
vfdi_status->timer_quantum_ns = efx->timer_quantum_ns;
- rc = efx_sriov_vf_alloc(efx);
+ rc = efx_siena_sriov_vf_alloc(efx);
if (rc)
goto fail_alloc;
- mutex_init(&efx->local_lock);
- INIT_WORK(&efx->peer_work, efx_sriov_peer_work);
- INIT_LIST_HEAD(&efx->local_addr_list);
- INIT_LIST_HEAD(&efx->local_page_list);
+ mutex_init(&nic_data->local_lock);
+ INIT_WORK(&nic_data->peer_work, efx_siena_sriov_peer_work);
+ INIT_LIST_HEAD(&nic_data->local_addr_list);
+ INIT_LIST_HEAD(&nic_data->local_page_list);
- rc = efx_sriov_vfs_init(efx);
+ rc = efx_siena_sriov_vfs_init(efx);
if (rc)
goto fail_vfs;
efx->vf_init_count = efx->vf_count;
rtnl_unlock();
- efx_sriov_usrev(efx, true);
+ efx_siena_sriov_usrev(efx, true);
/* At this point we must be ready to accept VFDI requests */
return 0;
fail_pci:
- efx_sriov_usrev(efx, false);
+ efx_siena_sriov_usrev(efx, false);
rtnl_lock();
efx->vf_init_count = 0;
rtnl_unlock();
- efx_sriov_vfs_fini(efx);
+ efx_siena_sriov_vfs_fini(efx);
fail_vfs:
- cancel_work_sync(&efx->peer_work);
- efx_sriov_free_local(efx);
+ cancel_work_sync(&nic_data->peer_work);
+ efx_siena_sriov_free_local(efx);
kfree(efx->vf);
fail_alloc:
- efx_nic_free_buffer(efx, &efx->vfdi_status);
+ efx_nic_free_buffer(efx, &nic_data->vfdi_status);
fail_status:
- efx_sriov_cmd(efx, false, NULL, NULL);
+ efx_siena_sriov_cmd(efx, false, NULL, NULL);
fail_cmd:
return rc;
}
-void efx_sriov_fini(struct efx_nic *efx)
+void efx_siena_sriov_fini(struct efx_nic *efx)
{
struct efx_vf *vf;
unsigned int pos;
+ struct siena_nic_data *nic_data = efx->nic_data;
if (efx->vf_init_count == 0)
return;
/* Disable all interfaces to reconfiguration */
- BUG_ON(efx->vfdi_channel->enabled);
- efx_sriov_usrev(efx, false);
+ BUG_ON(nic_data->vfdi_channel->enabled);
+ efx_siena_sriov_usrev(efx, false);
rtnl_lock();
efx->vf_init_count = 0;
rtnl_unlock();
cancel_work_sync(&vf->req);
cancel_work_sync(&vf->reset_work);
}
- cancel_work_sync(&efx->peer_work);
+ cancel_work_sync(&nic_data->peer_work);
pci_disable_sriov(efx->pci_dev);
/* Tear down back-end state */
- efx_sriov_vfs_fini(efx);
- efx_sriov_free_local(efx);
+ efx_siena_sriov_vfs_fini(efx);
+ efx_siena_sriov_free_local(efx);
kfree(efx->vf);
- efx_nic_free_buffer(efx, &efx->vfdi_status);
- efx_sriov_cmd(efx, false, NULL, NULL);
+ efx_nic_free_buffer(efx, &nic_data->vfdi_status);
+ efx_siena_sriov_cmd(efx, false, NULL, NULL);
}
-void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event)
+void efx_siena_sriov_event(struct efx_channel *channel, efx_qword_t *event)
{
struct efx_nic *efx = channel->efx;
struct efx_vf *vf;
vf->req_seqno = seq + 1;
}
-void efx_sriov_flr(struct efx_nic *efx, unsigned vf_i)
+void efx_siena_sriov_flr(struct efx_nic *efx, unsigned vf_i)
{
struct efx_vf *vf;
vf->evq0_count = 0;
}
-void efx_sriov_mac_address_changed(struct efx_nic *efx)
+void efx_siena_sriov_mac_address_changed(struct efx_nic *efx)
{
- struct vfdi_status *vfdi_status = efx->vfdi_status.addr;
+ struct siena_nic_data *nic_data = efx->nic_data;
+ struct vfdi_status *vfdi_status = nic_data->vfdi_status.addr;
if (!efx->vf_init_count)
return;
ether_addr_copy(vfdi_status->peers[0].mac_addr,
efx->net_dev->dev_addr);
- queue_work(vfdi_workqueue, &efx->peer_work);
+ queue_work(vfdi_workqueue, &nic_data->peer_work);
}
-void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
+void efx_siena_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_vf *vf;
unsigned queue, qid;
wake_up(&vf->flush_waitq);
}
-void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
+void efx_siena_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_vf *vf;
unsigned ev_failed, queue, qid;
}
/* Called from napi. Schedule the reset work item */
-void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq)
+void efx_siena_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq)
{
struct efx_vf *vf;
unsigned int rel;
}
/* Reset all VFs */
-void efx_sriov_reset(struct efx_nic *efx)
+void efx_siena_sriov_reset(struct efx_nic *efx)
{
unsigned int vf_i;
struct efx_buffer buf;
if (efx->vf_init_count == 0)
return;
- efx_sriov_usrev(efx, true);
- (void)efx_sriov_cmd(efx, true, NULL, NULL);
+ efx_siena_sriov_usrev(efx, true);
+ (void)efx_siena_sriov_cmd(efx, true, NULL, NULL);
if (efx_nic_alloc_buffer(efx, &buf, EFX_PAGE_SIZE, GFP_NOIO))
return;
for (vf_i = 0; vf_i < efx->vf_init_count; ++vf_i) {
vf = efx->vf + vf_i;
- efx_sriov_reset_vf(vf, &buf);
+ efx_siena_sriov_reset_vf(vf, &buf);
}
efx_nic_free_buffer(efx, &buf);
int efx_init_sriov(void)
{
- /* A single threaded workqueue is sufficient. efx_sriov_vfdi() and
- * efx_sriov_peer_work() spend almost all their time sleeping for
+ /* A single threaded workqueue is sufficient. efx_siena_sriov_vfdi() and
+ * efx_siena_sriov_peer_work() spend almost all their time sleeping for
* MCDI to complete anyway
*/
vfdi_workqueue = create_singlethread_workqueue("sfc_vfdi");
destroy_workqueue(vfdi_workqueue);
}
-int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
+int efx_siena_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
mutex_lock(&vf->status_lock);
ether_addr_copy(vf->addr.mac_addr, mac);
- __efx_sriov_update_vf_addr(vf);
+ __efx_siena_sriov_update_vf_addr(vf);
mutex_unlock(&vf->status_lock);
return 0;
}
-int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i,
- u16 vlan, u8 qos)
+int efx_siena_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i,
+ u16 vlan, u8 qos)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
mutex_lock(&vf->status_lock);
tci = (vlan & VLAN_VID_MASK) | ((qos & 0x7) << VLAN_PRIO_SHIFT);
vf->addr.tci = htons(tci);
- __efx_sriov_update_vf_addr(vf);
+ __efx_siena_sriov_update_vf_addr(vf);
mutex_unlock(&vf->status_lock);
return 0;
}
-int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
- bool spoofchk)
+int efx_siena_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
+ bool spoofchk)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
return rc;
}
-int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
- struct ifla_vf_info *ivi)
+int efx_siena_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
+ struct ifla_vf_info *ivi)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
if STMMAC_ETH
config STMMAC_PLATFORM
- bool "STMMAC Platform bus support"
+ tristate "STMMAC Platform bus support"
depends on STMMAC_ETH
default y
---help---
- This selects the platform specific bus support for
- the stmmac device driver. This is the driver used
- on many embedded STM platforms based on ARM and SuperH
- processors.
+ This selects the platform specific bus support for the stmmac driver.
+ This is the driver used on several SoCs:
+ STi, Allwinner, Amlogic Meson, Altera SOCFPGA.
+
If you have a controller with this interface, say Y or M here.
If unsure, say N.
-config DWMAC_MESON
- bool "Amlogic Meson dwmac support"
- depends on STMMAC_PLATFORM && ARCH_MESON
- help
- Support for Ethernet controller on Amlogic Meson SoCs.
-
- This selects the Amlogic Meson SoC glue layer support for
- the stmmac device driver. This driver is used for Meson6 and
- Meson8 SoCs.
-
-config DWMAC_SOCFPGA
- bool "SOCFPGA dwmac support"
- depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST)
- help
- Support for ethernet controller on Altera SOCFPGA
-
- This selects the Altera SOCFPGA SoC glue layer support
- for the stmmac device driver. This driver is used for
- arria5 and cyclone5 FPGA SoCs.
-
-config DWMAC_SUNXI
- bool "Allwinner GMAC support"
- depends on STMMAC_PLATFORM && ARCH_SUNXI
- default y
- ---help---
- Support for Allwinner A20/A31 GMAC ethernet controllers.
-
- This selects Allwinner SoC glue layer support for the
- stmmac device driver. This driver is used for A20/A31
- GMAC ethernet controller.
-
-config DWMAC_STI
- bool "STi GMAC support"
- depends on STMMAC_PLATFORM && ARCH_STI
- default y
- ---help---
- Support for ethernet controller on STi SOCs.
-
- This selects STi SoC glue layer support for the stmmac
- device driver. This driver is used on for the STi series
- SOCs GMAC ethernet controller.
-
config STMMAC_PCI
- bool "STMMAC PCI bus support"
+ tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
---help---
This is to select the Synopsys DWMAC available on PCI devices,
D1215994A VIRTEX FPGA board.
If unsure, say N.
-
-config STMMAC_DEBUG_FS
- bool "Enable monitoring via sysFS "
- default n
- depends on STMMAC_ETH && DEBUG_FS
- ---help---
- The stmmac entry in /sys reports DMA TX/RX rings
- or (if supported) the HW cap register.
-
-config STMMAC_DA
- bool "STMMAC DMA arbitration scheme"
- default n
- ---help---
- Selecting this option, rx has priority over Tx (only for Giga
- Ethernet device).
- By default, the DMA arbitration scheme is based on Round-robin
- (rx:tx priority is 1:1).
-
endif
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
-stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
-stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-stmmac-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
-stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
-stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
-stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
- chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
- dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
+ chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
+
+obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
+stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \
+ dwmac-sti.o dwmac-socfpga.o
+
+obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
+stmmac-pci-objs:= stmmac_pci.o
int (*get_rx_timestamp_status) (void *desc, u32 ats);
};
+extern const struct stmmac_desc_ops enh_desc_ops;
+extern const struct stmmac_desc_ops ndesc_ops;
+
struct stmmac_dma_ops {
/* DMA core initialization */
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
u64(*get_systime) (void __iomem *ioaddr);
};
+extern const struct stmmac_hwtimestamp stmmac_ptp;
+
struct mac_link {
int port;
int duplex;
#include <linux/platform_device.h>
#include <linux/stmmac.h>
+#include "stmmac_platform.h"
+
#define ETHMAC_SPEED_100 BIT(1)
struct meson_dwmac {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dwmac->reg))
- return dwmac->reg;
+ return ERR_CAST(dwmac->reg);
return dwmac;
}
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/stmmac.h>
+
#include "stmmac.h"
+#include "stmmac_platform.h"
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
#include <linux/of.h>
#include <linux/of_net.h>
+#include "stmmac_platform.h"
+
#define DWMAC_125MHZ 125000000
#define DWMAC_50MHZ 50000000
#define DWMAC_25MHZ 25000000
#include <linux/of_net.h>
#include <linux/regulator/consumer.h>
+#include "stmmac_platform.h"
+
struct sunxi_priv_data {
int interface;
int clk_enabled;
if (mb)
value |= DMA_BUS_MODE_MB;
-#ifdef CONFIG_STMMAC_DA
- value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
-#endif
-
if (atds)
value |= DMA_BUS_MODE_ATDS;
int stmmac_mdio_register(struct net_device *ndev);
int stmmac_mdio_reset(struct mii_bus *mii);
void stmmac_set_ethtool_ops(struct net_device *netdev);
-extern const struct stmmac_desc_ops enh_desc_ops;
-extern const struct stmmac_desc_ops ndesc_ops;
-extern const struct stmmac_hwtimestamp stmmac_ptp;
+
int stmmac_ptp_register(struct stmmac_priv *priv);
void stmmac_ptp_unregister(struct stmmac_priv *priv);
int stmmac_resume(struct net_device *ndev);
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);
-#ifdef CONFIG_STMMAC_PLATFORM
-#ifdef CONFIG_DWMAC_MESON
-extern const struct stmmac_of_data meson6_dwmac_data;
-#endif
-#ifdef CONFIG_DWMAC_SUNXI
-extern const struct stmmac_of_data sun7i_gmac_data;
-#endif
-#ifdef CONFIG_DWMAC_STI
-extern const struct stmmac_of_data stih4xx_dwmac_data;
-extern const struct stmmac_of_data stid127_dwmac_data;
-#endif
-#ifdef CONFIG_DWMAC_SOCFPGA
-extern const struct stmmac_of_data socfpga_gmac_data;
-#endif
-extern struct platform_driver stmmac_pltfr_driver;
-static inline int stmmac_register_platform(void)
-{
- int err;
-
- err = platform_driver_register(&stmmac_pltfr_driver);
- if (err)
- pr_err("stmmac: failed to register the platform driver\n");
-
- return err;
-}
-
-static inline void stmmac_unregister_platform(void)
-{
- platform_driver_unregister(&stmmac_pltfr_driver);
-}
-#else
-static inline int stmmac_register_platform(void)
-{
- pr_debug("stmmac: do not register the platf driver\n");
-
- return 0;
-}
-
-static inline void stmmac_unregister_platform(void)
-{
-}
-#endif /* CONFIG_STMMAC_PLATFORM */
-
-#ifdef CONFIG_STMMAC_PCI
-extern struct pci_driver stmmac_pci_driver;
-static inline int stmmac_register_pci(void)
-{
- int err;
-
- err = pci_register_driver(&stmmac_pci_driver);
- if (err)
- pr_err("stmmac: failed to register the PCI driver\n");
-
- return err;
-}
-
-static inline void stmmac_unregister_pci(void)
-{
- pci_unregister_driver(&stmmac_pci_driver);
-}
-#else
-static inline int stmmac_register_pci(void)
-{
- pr_debug("stmmac: do not register the PCI driver\n");
-
- return 0;
-}
-
-static inline void stmmac_unregister_pci(void)
-{
-}
-#endif /* CONFIG_STMMAC_PCI */
-
#endif /* __STMMAC_H__ */
#include <linux/slab.h>
#include <linux/prefetch.h>
#include <linux/pinctrl/consumer.h>
-#ifdef CONFIG_STMMAC_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#endif /* CONFIG_STMMAC_DEBUG_FS */
+#endif /* CONFIG_DEBUG_FS */
#include <linux/net_tstamp.h>
#include "stmmac_ptp.h"
#include "stmmac.h"
static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
-#ifdef CONFIG_STMMAC_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
static int stmmac_init_fs(struct net_device *dev);
static void stmmac_exit_fs(void);
#endif
static void print_pkt(unsigned char *buf, int len)
{
- int j;
- pr_debug("len = %d byte, buf addr: 0x%p", len, buf);
- for (j = 0; j < len; j++) {
- if ((j % 16) == 0)
- pr_debug("\n %03x:", j);
- pr_debug(" %02x", buf[j]);
- }
- pr_debug("\n");
+ pr_debug("len = %d byte, buf addr: 0x%p\n", len, buf);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
}
/* minimum number of free TX descriptors required to wake up TX process */
if (ret && ret != -EOPNOTSUPP)
pr_warn("%s: failed PTP initialisation\n", __func__);
-#ifdef CONFIG_STMMAC_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
ret = stmmac_init_fs(dev);
if (ret < 0)
pr_warn("%s: failed debugFS registration\n", __func__);
netif_carrier_off(dev);
-#ifdef CONFIG_STMMAC_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
stmmac_exit_fs();
#endif
return ret;
}
-#ifdef CONFIG_STMMAC_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
static struct dentry *stmmac_fs_dir;
static struct dentry *stmmac_rings_status;
static struct dentry *stmmac_dma_cap;
debugfs_remove(stmmac_dma_cap);
debugfs_remove(stmmac_fs_dir);
}
-#endif /* CONFIG_STMMAC_DEBUG_FS */
+#endif /* CONFIG_DEBUG_FS */
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(stmmac_dvr_probe);
/**
* stmmac_dvr_remove
return 0;
}
+EXPORT_SYMBOL_GPL(stmmac_dvr_remove);
-#ifdef CONFIG_PM
int stmmac_suspend(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
priv->oldduplex = -1;
return 0;
}
+EXPORT_SYMBOL_GPL(stmmac_suspend);
int stmmac_resume(struct net_device *ndev)
{
return 0;
}
-#endif /* CONFIG_PM */
-
-/* Driver can be configured w/ and w/ both PCI and Platf drivers
- * depending on the configuration selected.
- */
-static int __init stmmac_init(void)
-{
- int ret;
-
- ret = stmmac_register_platform();
- if (ret)
- goto err;
- ret = stmmac_register_pci();
- if (ret)
- goto err_pci;
- return 0;
-err_pci:
- stmmac_unregister_platform();
-err:
- pr_err("stmmac: driver registration failed\n");
- return ret;
-}
-
-static void __exit stmmac_exit(void)
-{
- stmmac_unregister_platform();
- stmmac_unregister_pci();
-}
-
-module_init(stmmac_init);
-module_exit(stmmac_exit);
+EXPORT_SYMBOL_GPL(stmmac_resume);
#ifndef MODULE
static int __init stmmac_cmdline_opt(char *str)
static int stmmac_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- int ret = 0;
- void __iomem *addr = NULL;
- struct stmmac_priv *priv = NULL;
+ struct stmmac_priv *priv;
int i;
+ int ret;
/* Enable pci device */
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret) {
- pr_err("%s : ERROR: failed to enable %s device\n", __func__,
- pci_name(pdev));
+ dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
+ __func__);
return ret;
}
- if (pci_request_regions(pdev, STMMAC_RESOURCE_NAME)) {
- pr_err("%s: ERROR: failed to get PCI region\n", __func__);
- ret = -ENODEV;
- goto err_out_req_reg_failed;
- }
/* Get the base address of device */
- for (i = 0; i <= 5; i++) {
+ for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
if (pci_resource_len(pdev, i) == 0)
continue;
- addr = pci_iomap(pdev, i, 0);
- if (addr == NULL) {
- pr_err("%s: ERROR: cannot map register memory aborting",
- __func__);
- ret = -EIO;
- goto err_out_map_failed;
- }
+ ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
+ if (ret)
+ return ret;
break;
}
+
pci_set_master(pdev);
stmmac_default_data();
- priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
+ priv = stmmac_dvr_probe(&pdev->dev, &plat_dat,
+ pcim_iomap_table(pdev)[i]);
if (IS_ERR(priv)) {
- pr_err("%s: main driver probe failed", __func__);
- ret = PTR_ERR(priv);
- goto err_out;
+ dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__);
+ return PTR_ERR(priv);
}
priv->dev->irq = pdev->irq;
priv->wol_irq = pdev->irq;
pci_set_drvdata(pdev, priv->dev);
- pr_debug("STMMAC platform driver registration completed");
+ dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n");
return 0;
-
-err_out:
- pci_clear_master(pdev);
-err_out_map_failed:
- pci_release_regions(pdev);
-err_out_req_reg_failed:
- pci_disable_device(pdev);
-
- return ret;
}
/**
static void stmmac_pci_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
- struct stmmac_priv *priv = netdev_priv(ndev);
stmmac_dvr_remove(ndev);
-
- pci_iounmap(pdev, priv->ioaddr);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
}
-#ifdef CONFIG_PM
-static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int stmmac_pci_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *ndev = pci_get_drvdata(pdev);
- int ret;
-
- ret = stmmac_suspend(ndev);
- pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return ret;
+ return stmmac_suspend(ndev);
}
-static int stmmac_pci_resume(struct pci_dev *pdev)
+static int stmmac_pci_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *ndev = pci_get_drvdata(pdev);
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
return stmmac_resume(ndev);
}
#endif
+static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
+
#define STMMAC_VENDOR_ID 0x700
#define STMMAC_DEVICE_ID 0x1108
MODULE_DEVICE_TABLE(pci, stmmac_id_table);
-struct pci_driver stmmac_pci_driver = {
+static struct pci_driver stmmac_pci_driver = {
.name = STMMAC_RESOURCE_NAME,
.id_table = stmmac_id_table,
.probe = stmmac_pci_probe,
.remove = stmmac_pci_remove,
-#ifdef CONFIG_PM
- .suspend = stmmac_pci_suspend,
- .resume = stmmac_pci_resume,
-#endif
+ .driver = {
+ .pm = &stmmac_pm_ops,
+ },
};
+module_pci_driver(stmmac_pci_driver);
+
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_device.h>
+
#include "stmmac.h"
+#include "stmmac_platform.h"
static const struct of_device_id stmmac_dt_ids[] = {
-#ifdef CONFIG_DWMAC_MESON
+ /* SoC specific glue layers should come before generic bindings */
{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
-#endif
-#ifdef CONFIG_DWMAC_SUNXI
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
-#endif
-#ifdef CONFIG_DWMAC_STI
{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
{ .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
{ .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
{ .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
-#endif
-#ifdef CONFIG_DWMAC_SOCFPGA
{ .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
-#endif
- /* SoC specific glue layers should come before generic bindings */
{ .compatible = "st,spear600-gmac"},
{ .compatible = "snps,dwmac-3.610"},
{ .compatible = "snps,dwmac-3.70a"},
return ret;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int stmmac_pltfr_suspend(struct device *dev)
{
int ret;
return stmmac_resume(ndev);
}
-
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
- stmmac_pltfr_suspend, stmmac_pltfr_resume);
+ stmmac_pltfr_suspend, stmmac_pltfr_resume);
-struct platform_driver stmmac_pltfr_driver = {
+static struct platform_driver stmmac_pltfr_driver = {
.probe = stmmac_pltfr_probe,
.remove = stmmac_pltfr_remove,
.driver = {
.owner = THIS_MODULE,
.pm = &stmmac_pltfr_pm_ops,
.of_match_table = of_match_ptr(stmmac_dt_ids),
- },
+ },
};
+module_platform_driver(stmmac_pltfr_driver);
+
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");
--- /dev/null
+/*******************************************************************************
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#ifndef __STMMAC_PLATFORM_H__
+#define __STMMAC_PLATFORM_H__
+
+extern const struct stmmac_of_data meson6_dwmac_data;
+extern const struct stmmac_of_data sun7i_gmac_data;
+extern const struct stmmac_of_data stih4xx_dwmac_data;
+extern const struct stmmac_of_data stid127_dwmac_data;
+extern const struct stmmac_of_data socfpga_gmac_data;
+
+#endif /* __STMMAC_PLATFORM_H__ */
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
+#define VNET_MAX_TXQS 16
+
/* Heuristic for the number of times to exponentially backoff and
* retry sending an LDC trigger when EAGAIN is encountered
*/
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
-
- netif_rx(skb);
-
+ napi_gro_receive(&port->napi, skb);
return 0;
out_free_skb:
struct vio_driver_state *vio = &port->vio;
int err;
+ BUG_ON(desc == NULL);
if (IS_ERR(desc))
return PTR_ERR(desc);
}
static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
- u32 start, u32 end)
+ u32 start, u32 end, int *npkts, int budget)
{
struct vio_driver_state *vio = &port->vio;
int ack_start = -1, ack_end = -1;
+ bool send_ack = true;
end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr);
return err;
if (err != 0)
break;
+ (*npkts)++;
if (ack_start == -1)
ack_start = start;
ack_end = start;
return err;
ack_start = -1;
}
+ if ((*npkts) >= budget) {
+ send_ack = false;
+ break;
+ }
}
if (unlikely(ack_start == -1))
ack_start = ack_end = prev_idx(start, dr);
- return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED);
+ if (send_ack) {
+ port->napi_resume = false;
+ return vnet_send_ack(port, dr, ack_start, ack_end,
+ VIO_DRING_STOPPED);
+ } else {
+ port->napi_resume = true;
+ port->napi_stop_idx = ack_end;
+ return 1;
+ }
}
-static int vnet_rx(struct vnet_port *port, void *msgbuf)
+static int vnet_rx(struct vnet_port *port, void *msgbuf, int *npkts,
+ int budget)
{
struct vio_dring_data *pkt = msgbuf;
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING];
return 0;
}
- dr->rcv_nxt++;
+ if (!port->napi_resume)
+ dr->rcv_nxt++;
/* XXX Validate pkt->start_idx and pkt->end_idx XXX */
- return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx);
+ return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx,
+ npkts, budget);
}
static int idx_is_pending(struct vio_dring_state *dr, u32 end)
struct vnet *vp;
u32 end;
struct vio_net_desc *desc;
+ struct netdev_queue *txq;
+
if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
return 0;
end = pkt->end_idx;
- if (unlikely(!idx_is_pending(dr, end)))
+ vp = port->vp;
+ dev = vp->dev;
+ netif_tx_lock(dev);
+ if (unlikely(!idx_is_pending(dr, end))) {
+ netif_tx_unlock(dev);
return 0;
+ }
/* sync for race conditions with vnet_start_xmit() and tell xmit it
* is time to send a trigger.
*/
dr->cons = next_idx(end, dr);
desc = vio_dring_entry(dr, dr->cons);
- if (desc->hdr.state == VIO_DESC_READY && port->start_cons) {
+ if (desc->hdr.state == VIO_DESC_READY && !port->start_cons) {
/* vnet_start_xmit() just populated this dring but missed
* sending the "start" LDC message to the consumer.
* Send a "start" trigger on its behalf.
} else {
port->start_cons = true;
}
+ netif_tx_unlock(dev);
-
- vp = port->vp;
- dev = vp->dev;
- if (unlikely(netif_queue_stopped(dev) &&
+ txq = netdev_get_tx_queue(dev, port->q_index);
+ if (unlikely(netif_tx_queue_stopped(txq) &&
vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr)))
return 1;
return 0;
}
-static void maybe_tx_wakeup(unsigned long param)
+/* Got back a STOPPED LDC message on port. If the queue is stopped,
+ * wake it up so that we'll send out another START message at the
+ * next TX.
+ */
+static void maybe_tx_wakeup(struct vnet_port *port)
{
- struct vnet *vp = (struct vnet *)param;
- struct net_device *dev = vp->dev;
-
- netif_tx_lock(dev);
- if (likely(netif_queue_stopped(dev))) {
- struct vnet_port *port;
- int wake = 1;
+ struct netdev_queue *txq;
- list_for_each_entry(port, &vp->port_list, list) {
- struct vio_dring_state *dr;
+ txq = netdev_get_tx_queue(port->vp->dev, port->q_index);
+ __netif_tx_lock(txq, smp_processor_id());
+ if (likely(netif_tx_queue_stopped(txq))) {
+ struct vio_dring_state *dr;
- dr = &port->vio.drings[VIO_DRIVER_TX_RING];
- if (vnet_tx_dring_avail(dr) <
- VNET_TX_WAKEUP_THRESH(dr)) {
- wake = 0;
- break;
- }
- }
- if (wake)
- netif_wake_queue(dev);
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ netif_tx_wake_queue(txq);
}
- netif_tx_unlock(dev);
+ __netif_tx_unlock(txq);
}
-static void vnet_event(void *arg, int event)
+static inline bool port_is_up(struct vnet_port *vnet)
+{
+ struct vio_driver_state *vio = &vnet->vio;
+
+ return !!(vio->hs_state & VIO_HS_COMPLETE);
+}
+
+static int vnet_event_napi(struct vnet_port *port, int budget)
{
- struct vnet_port *port = arg;
struct vio_driver_state *vio = &port->vio;
- unsigned long flags;
int tx_wakeup, err;
+ int npkts = 0;
+ int event = (port->rx_event & LDC_EVENT_RESET);
- spin_lock_irqsave(&vio->lock, flags);
-
+ldc_ctrl:
if (unlikely(event == LDC_EVENT_RESET ||
event == LDC_EVENT_UP)) {
vio_link_state_change(vio, event);
- spin_unlock_irqrestore(&vio->lock, flags);
if (event == LDC_EVENT_RESET) {
port->rmtu = 0;
vio_port_up(vio);
}
- return;
+ port->rx_event = 0;
+ return 0;
}
+ /* We may have multiple LDC events in rx_event. Unroll send_events() */
+ event = (port->rx_event & LDC_EVENT_UP);
+ port->rx_event &= ~(LDC_EVENT_RESET|LDC_EVENT_UP);
+ if (event == LDC_EVENT_UP)
+ goto ldc_ctrl;
+ event = port->rx_event;
+ if (!(event & LDC_EVENT_DATA_READY))
+ return 0;
- if (unlikely(event != LDC_EVENT_DATA_READY)) {
- pr_warn("Unexpected LDC event %d\n", event);
- spin_unlock_irqrestore(&vio->lock, flags);
- return;
- }
+ /* we dont expect any other bits than RESET, UP, DATA_READY */
+ BUG_ON(event != LDC_EVENT_DATA_READY);
tx_wakeup = err = 0;
while (1) {
u64 raw[8];
} msgbuf;
+ if (port->napi_resume) {
+ struct vio_dring_data *pkt =
+ (struct vio_dring_data *)&msgbuf;
+ struct vio_dring_state *dr =
+ &port->vio.drings[VIO_DRIVER_RX_RING];
+
+ pkt->tag.type = VIO_TYPE_DATA;
+ pkt->tag.stype = VIO_SUBTYPE_INFO;
+ pkt->tag.stype_env = VIO_DRING_DATA;
+ pkt->seq = dr->rcv_nxt;
+ pkt->start_idx = next_idx(port->napi_stop_idx, dr);
+ pkt->end_idx = -1;
+ goto napi_resume;
+ }
err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
if (unlikely(err < 0)) {
if (err == -ECONNRESET)
err = vio_validate_sid(vio, &msgbuf.tag);
if (err < 0)
break;
-
+napi_resume:
if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) {
- err = vnet_rx(port, &msgbuf);
+ if (!port_is_up(port)) {
+ /* failures like handshake_failure()
+ * may have cleaned up dring, but
+ * NAPI polling may bring us here.
+ */
+ err = -ECONNRESET;
+ break;
+ }
+ err = vnet_rx(port, &msgbuf, &npkts, budget);
+ if (npkts >= budget)
+ break;
+ if (npkts == 0)
+ break;
} else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) {
err = vnet_ack(port, &msgbuf);
if (err > 0)
if (err == -ECONNRESET)
break;
}
- spin_unlock(&vio->lock);
- /* Kick off a tasklet to wake the queue. We cannot call
- * maybe_tx_wakeup directly here because we could deadlock on
- * netif_tx_lock() with dev_watchdog()
- */
if (unlikely(tx_wakeup && err != -ECONNRESET))
- tasklet_schedule(&port->vp->vnet_tx_wakeup);
+ maybe_tx_wakeup(port);
+ return npkts;
+}
+
+static int vnet_poll(struct napi_struct *napi, int budget)
+{
+ struct vnet_port *port = container_of(napi, struct vnet_port, napi);
+ struct vio_driver_state *vio = &port->vio;
+ int processed = vnet_event_napi(port, budget);
+
+ if (processed < budget) {
+ napi_complete(napi);
+ port->rx_event &= ~LDC_EVENT_DATA_READY;
+ vio_set_intr(vio->vdev->rx_ino, HV_INTR_ENABLED);
+ }
+ return processed;
+}
+
+static void vnet_event(void *arg, int event)
+{
+ struct vnet_port *port = arg;
+ struct vio_driver_state *vio = &port->vio;
+
+ port->rx_event |= event;
+ vio_set_intr(vio->vdev->rx_ino, HV_INTR_DISABLED);
+ napi_schedule(&port->napi);
- local_irq_restore(flags);
}
static int __vnet_tx_trigger(struct vnet_port *port, u32 start)
return err;
}
-static inline bool port_is_up(struct vnet_port *vnet)
-{
- struct vio_driver_state *vio = &vnet->vio;
-
- return !!(vio->hs_state & VIO_HS_COMPLETE);
-}
-
struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)
{
unsigned int hash = vnet_hashfn(skb->data);
struct hlist_head *hp = &vp->port_hash[hash];
struct vnet_port *port;
- hlist_for_each_entry(port, hp, hash) {
+ hlist_for_each_entry_rcu(port, hp, hash) {
if (!port_is_up(port))
continue;
if (ether_addr_equal(port->raddr, skb->data))
return port;
}
- list_for_each_entry(port, &vp->port_list, list) {
+ list_for_each_entry_rcu(port, &vp->port_list, list) {
if (!port->switch_port)
continue;
if (!port_is_up(port))
return NULL;
}
-struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb)
-{
- struct vnet_port *ret;
- unsigned long flags;
-
- spin_lock_irqsave(&vp->lock, flags);
- ret = __tx_port_find(vp, skb);
- spin_unlock_irqrestore(&vp->lock, flags);
-
- return ret;
-}
-
static struct sk_buff *vnet_clean_tx_ring(struct vnet_port *port,
unsigned *pending)
{
struct vnet_port *port = (struct vnet_port *)port0;
struct sk_buff *freeskbs;
unsigned pending;
- unsigned long flags;
- spin_lock_irqsave(&port->vio.lock, flags);
+ netif_tx_lock(port->vp->dev);
freeskbs = vnet_clean_tx_ring(port, &pending);
- spin_unlock_irqrestore(&port->vio.lock, flags);
+ netif_tx_unlock(port->vp->dev);
vnet_free_skbs(freeskbs);
return skb;
}
+static u16
+vnet_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port = __tx_port_find(vp, skb);
+
+ if (port == NULL)
+ return 0;
+ return port->q_index;
+}
+
static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct vnet *vp = netdev_priv(dev);
- struct vnet_port *port = tx_port_find(vp, skb);
+ struct vnet_port *port = NULL;
struct vio_dring_state *dr;
struct vio_net_desc *d;
- unsigned long flags;
unsigned int len;
struct sk_buff *freeskbs = NULL;
int i, err, txi;
void *start = NULL;
int nlen = 0;
unsigned pending = 0;
-
- if (unlikely(!port))
- goto out_dropped;
+ struct netdev_queue *txq;
skb = vnet_skb_shape(skb, &start, &nlen);
-
if (unlikely(!skb))
goto out_dropped;
+ rcu_read_lock();
+ port = __tx_port_find(vp, skb);
+ if (unlikely(!port)) {
+ rcu_read_unlock();
+ goto out_dropped;
+ }
+
if (skb->len > port->rmtu) {
unsigned long localmtu = port->rmtu - ETH_HLEN;
fl4.saddr = ip_hdr(skb)->saddr;
rt = ip_route_output_key(dev_net(dev), &fl4);
+ rcu_read_unlock();
if (!IS_ERR(rt)) {
skb_dst_set(skb, &rt->dst);
icmp_send(skb, ICMP_DEST_UNREACH,
goto out_dropped;
}
- spin_lock_irqsave(&port->vio.lock, flags);
-
dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ i = skb_get_queue_mapping(skb);
+ txq = netdev_get_tx_queue(dev, i);
if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
- if (!netif_queue_stopped(dev)) {
- netif_stop_queue(dev);
+ if (!netif_tx_queue_stopped(txq)) {
+ netif_tx_stop_queue(txq);
/* This is a hard error, log it. */
netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
dev->stats.tx_errors++;
}
- spin_unlock_irqrestore(&port->vio.lock, flags);
+ rcu_read_unlock();
return NETDEV_TX_BUSY;
}
(LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_RW));
if (err < 0) {
netdev_info(dev, "tx buffer map error %d\n", err);
- goto out_dropped_unlock;
+ goto out_dropped;
}
port->tx_bufs[txi].ncookies = err;
netdev_info(dev, "TX trigger error %d\n", err);
d->hdr.state = VIO_DESC_FREE;
dev->stats.tx_carrier_errors++;
- goto out_dropped_unlock;
+ goto out_dropped;
}
ldc_start_done:
dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
- netif_stop_queue(dev);
+ netif_tx_stop_queue(txq);
if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr))
- netif_wake_queue(dev);
+ netif_tx_wake_queue(txq);
}
- spin_unlock_irqrestore(&port->vio.lock, flags);
+ (void)mod_timer(&port->clean_timer, jiffies + VNET_CLEAN_TIMEOUT);
+ rcu_read_unlock();
vnet_free_skbs(freeskbs);
- (void)mod_timer(&port->clean_timer, jiffies + VNET_CLEAN_TIMEOUT);
-
return NETDEV_TX_OK;
-out_dropped_unlock:
- spin_unlock_irqrestore(&port->vio.lock, flags);
-
out_dropped:
- if (skb)
- dev_kfree_skb(skb);
- vnet_free_skbs(freeskbs);
if (pending)
(void)mod_timer(&port->clean_timer,
jiffies + VNET_CLEAN_TIMEOUT);
else if (port)
del_timer(&port->clean_timer);
+ if (port)
+ rcu_read_unlock();
+ if (skb)
+ dev_kfree_skb(skb);
+ vnet_free_skbs(freeskbs);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
static int vnet_open(struct net_device *dev)
{
netif_carrier_on(dev);
- netif_start_queue(dev);
+ netif_tx_start_all_queues(dev);
return 0;
}
static int vnet_close(struct net_device *dev)
{
- netif_stop_queue(dev);
+ netif_tx_stop_all_queues(dev);
netif_carrier_off(dev);
return 0;
{
struct vnet *vp = netdev_priv(dev);
struct vnet_port *port;
- unsigned long flags;
- spin_lock_irqsave(&vp->lock, flags);
- if (!list_empty(&vp->port_list)) {
- port = list_entry(vp->port_list.next, struct vnet_port, list);
+ rcu_read_lock();
+ list_for_each_entry_rcu(port, &vp->port_list, list) {
if (port->switch_port) {
__update_mc_list(vp, dev);
__send_mc_list(vp, port);
+ break;
}
}
- spin_unlock_irqrestore(&vp->lock, flags);
+ rcu_read_unlock();
}
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
return err;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void vnet_poll_controller(struct net_device *dev)
+{
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ if (!list_empty(&vp->port_list)) {
+ port = list_entry(vp->port_list.next, struct vnet_port, list);
+ napi_schedule(&port->napi);
+ }
+ spin_unlock_irqrestore(&vp->lock, flags);
+}
+#endif
static LIST_HEAD(vnet_list);
static DEFINE_MUTEX(vnet_list_mutex);
.ndo_tx_timeout = vnet_tx_timeout,
.ndo_change_mtu = vnet_change_mtu,
.ndo_start_xmit = vnet_start_xmit,
+ .ndo_select_queue = vnet_select_queue,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = vnet_poll_controller,
+#endif
};
static struct vnet *vnet_new(const u64 *local_mac)
struct vnet *vp;
int err, i;
- dev = alloc_etherdev(sizeof(*vp));
+ dev = alloc_etherdev_mqs(sizeof(*vp), VNET_MAX_TXQS, 1);
if (!dev)
return ERR_PTR(-ENOMEM);
dev->needed_headroom = VNET_PACKET_SKIP + 8;
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
- tasklet_init(&vp->vnet_tx_wakeup, maybe_tx_wakeup, (unsigned long)vp);
vp->dev = dev;
INIT_LIST_HEAD(&vp->port_list);
vp = list_first_entry(&vnet_list, struct vnet, list);
list_del(&vp->list);
dev = vp->dev;
- tasklet_kill(&vp->vnet_tx_wakeup);
/* vio_unregister_driver() should have cleaned up port_list */
BUG_ON(!list_empty(&vp->port_list));
unregister_netdev(dev);
const char *remote_macaddr_prop = "remote-mac-address";
+static void
+vnet_port_add_txq(struct vnet_port *port)
+{
+ struct vnet *vp = port->vp;
+ int n;
+
+ n = vp->nports++;
+ n = n & (VNET_MAX_TXQS - 1);
+ port->q_index = n;
+ netif_tx_wake_queue(netdev_get_tx_queue(vp->dev, port->q_index));
+}
+
+static void
+vnet_port_rm_txq(struct vnet_port *port)
+{
+ port->vp->nports--;
+ netif_tx_stop_queue(netdev_get_tx_queue(port->vp->dev, port->q_index));
+}
+
static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
struct mdesc_handle *hp;
if (err)
goto err_out_free_port;
+ netif_napi_add(port->vp->dev, &port->napi, vnet_poll, NAPI_POLL_WEIGHT);
+
err = vnet_port_alloc_tx_bufs(port);
if (err)
goto err_out_free_ldc;
spin_lock_irqsave(&vp->lock, flags);
if (switch_port)
- list_add(&port->list, &vp->port_list);
+ list_add_rcu(&port->list, &vp->port_list);
else
- list_add_tail(&port->list, &vp->port_list);
- hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]);
+ list_add_tail_rcu(&port->list, &vp->port_list);
+ hlist_add_head_rcu(&port->hash,
+ &vp->port_hash[vnet_hashfn(port->raddr)]);
+ vnet_port_add_txq(port);
spin_unlock_irqrestore(&vp->lock, flags);
dev_set_drvdata(&vdev->dev, port);
setup_timer(&port->clean_timer, vnet_clean_timer_expire,
(unsigned long)port);
+ napi_enable(&port->napi);
vio_port_up(&port->vio);
mdesc_release(hp);
return 0;
err_out_free_ldc:
+ netif_napi_del(&port->napi);
vio_ldc_free(&port->vio);
err_out_free_port:
struct vnet_port *port = dev_get_drvdata(&vdev->dev);
if (port) {
- struct vnet *vp = port->vp;
- unsigned long flags;
del_timer_sync(&port->vio.timer);
- del_timer_sync(&port->clean_timer);
- spin_lock_irqsave(&vp->lock, flags);
- list_del(&port->list);
- hlist_del(&port->hash);
- spin_unlock_irqrestore(&vp->lock, flags);
+ napi_disable(&port->napi);
+
+ list_del_rcu(&port->list);
+ hlist_del_rcu(&port->hash);
+ synchronize_rcu();
+ del_timer_sync(&port->clean_timer);
+ vnet_port_rm_txq(port);
+ netif_napi_del(&port->napi);
vnet_port_free_tx_bufs(port);
vio_ldc_free(&port->vio);
struct timer_list clean_timer;
u64 rmtu;
+
+ struct napi_struct napi;
+ u32 napi_stop_idx;
+ bool napi_resume;
+ int rx_event;
+ u16 q_index;
};
static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)
struct list_head list;
u64 local_mac;
- struct tasklet_struct vnet_tx_wakeup;
+ int nports;
};
#endif /* _SUNVNET_H */
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENXIO;
- mem_size = resource_size(mem);
-
priv->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
+ mem_size = resource_size(mem);
+
spin_lock_init(&priv->reg_lock);
priv->indirect = mem_size < W5100_BUS_DIRECT_SIZE;
if (priv->indirect) {
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENXIO;
- mem_size = resource_size(mem);
-
priv->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
+ mem_size = resource_size(mem);
+
spin_lock_init(&priv->reg_lock);
priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE;
if (priv->indirect) {
kfree(xbuff);
kfree(rbuff);
- if (dev)
- free_netdev(dev);
+ free_netdev(dev);
out:
return err;
/* NVSPv2 only: Send NDIS config */
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
- init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
+ init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu +
+ ETH_HLEN;
init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
ret = vmbus_sendpacket(device->channel, init_packet,
struct flow_keys flow;
int data_len;
- if (!skb_flow_dissect(skb, &flow) || flow.n_proto != htons(ETH_P_IP))
+ if (!skb_flow_dissect(skb, &flow) ||
+ !(flow.n_proto == htons(ETH_P_IP) ||
+ flow.n_proto == htons(ETH_P_IPV6)))
return false;
if (flow.ip_proto == IPPROTO_TCP)
return -ENODEV;
if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
- limit = NETVSC_MTU;
+ limit = NETVSC_MTU - ETH_HLEN;
- if (mtu < 68 || mtu > limit)
+ /* Hyper-V hosts don't support MTU < ETH_DATA_LEN (1500) */
+ if (mtu < ETH_DATA_LEN || mtu > limit)
return -EINVAL;
nvdev->start_remove = true;
rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
rssp->flag = 0;
rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
- NDIS_HASH_TCP_IPV4;
+ NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 |
+ NDIS_HASH_TCP_IPV6;
rssp->indirect_tabsize = 4*ITAB_NUM;
rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
rssp->hashkey_size = HASH_KEYLEN;
int t;
struct ndis_recv_scale_cap rsscap;
u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
+ u32 mtu, size;
rndis_device = get_rndis_device();
if (!rndis_device)
return ret;
}
+ /* Get the MTU from the host */
+ size = sizeof(u32);
+ ret = rndis_filter_query_device(rndis_device,
+ RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
+ &mtu, &size);
+ if (ret == 0 && size == sizeof(u32))
+ net_device->ndev->mtu = mtu;
+
/* Get the mac address */
ret = rndis_filter_query_device_mac(rndis_device);
if (ret != 0) {
If you say N, all options in this submenu will be skipped and
disabled.
-config IEEE802154_FAKEHARD
- tristate "Fake LR-WPAN driver with several interconnected devices"
- depends on IEEE802154_DRIVERS
- ---help---
- Say Y here to enable the fake driver that serves as an example
- of HardMAC device driver.
-
- This driver can also be built as a module. To do so say M here.
- The module will be called 'fakehard'.
-
config IEEE802154_FAKELB
depends on IEEE802154_DRIVERS && MAC802154
tristate "IEEE 802.15.4 loopback driver"
-obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
#include <linux/regmap.h>
#include <linux/skbuff.h>
#include <linux/of_gpio.h>
+#include <linux/ieee802154.h>
-#include <net/ieee802154.h>
#include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
struct at86rf230_local;
/* at86rf2xx chip depend data.
u16 t_tx_timeout;
int rssi_base_val;
- int (*set_channel)(struct at86rf230_local *, int, int);
+ int (*set_channel)(struct at86rf230_local *, u8, u8);
int (*get_desense_steps)(struct at86rf230_local *, s32);
};
void (*complete)(void *context);
u8 from_state;
u8 to_state;
+
+ bool irq_enable;
};
struct at86rf230_local {
struct spi_device *spi;
- struct ieee802154_dev *dev;
+ struct ieee802154_hw *hw;
struct at86rf2xx_chip_data *data;
struct regmap *regmap;
struct at86rf230_state_change irq;
bool tx_aret;
+ s8 max_frame_retries;
bool is_tx;
/* spinlock for is_tx protection */
spinlock_t lock;
- struct completion tx_complete;
struct sk_buff *tx_skb;
struct at86rf230_state_change tx;
};
#define AT86RF2XX_NUMREGS 0x3F
-static int
+static void
at86rf230_async_state_change(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx,
- const u8 state, void (*complete)(void *context));
+ const u8 state, void (*complete)(void *context),
+ const bool irq_enable);
static inline int
__at86rf230_write(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL);
+ at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false);
+ ieee802154_wake_queue(lp->hw);
}
static void
dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
- at86rf230_async_error_recover);
+ at86rf230_async_error_recover, false);
}
/* Generic function to get some register value in async mode */
-static int
+static void
at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
struct at86rf230_state_change *ctx,
- void (*complete)(void *context))
+ void (*complete)(void *context),
+ const bool irq_enable)
{
+ int rc;
+
u8 *tx_buf = ctx->buf;
tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
ctx->trx.len = 2;
ctx->msg.complete = complete;
- return spi_async(lp->spi, &ctx->msg);
+ ctx->irq_enable = irq_enable;
+ rc = spi_async(lp->spi, &ctx->msg);
+ if (rc) {
+ if (irq_enable)
+ enable_irq(lp->spi->irq);
+
+ at86rf230_async_error(lp, ctx, rc);
+ }
}
static void
if (ctx->to_state == STATE_TX_ON) {
at86rf230_async_state_change(lp, ctx,
STATE_FORCE_TX_ON,
- ctx->complete);
+ ctx->complete,
+ ctx->irq_enable);
return;
}
}
struct at86rf230_local *lp = ctx->lp;
struct at86rf2xx_chip_data *c = lp->data;
bool force = false;
- int rc;
/* The force state changes are will show as normal states in the
* state status subregister. We change the to_state to the
udelay(1);
change:
- rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
- at86rf230_async_state_assert);
- if (rc)
- dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+ at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+ at86rf230_async_state_assert,
+ ctx->irq_enable);
}
static void
/* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
udelay(1);
- rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
- at86rf230_async_state_change_start);
- if (rc)
- dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+ at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+ at86rf230_async_state_change_start,
+ ctx->irq_enable);
return;
}
ctx->trx.len = 2;
ctx->msg.complete = at86rf230_async_state_delay;
rc = spi_async(lp->spi, &ctx->msg);
- if (rc)
- dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+ if (rc) {
+ if (ctx->irq_enable)
+ enable_irq(lp->spi->irq);
+
+ at86rf230_async_error(lp, &lp->state, rc);
+ }
}
-static int
+static void
at86rf230_async_state_change(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx,
- const u8 state, void (*complete)(void *context))
+ const u8 state, void (*complete)(void *context),
+ const bool irq_enable)
{
/* Initialization for the state change context */
ctx->to_state = state;
ctx->complete = complete;
- return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
- at86rf230_async_state_change_start);
+ ctx->irq_enable = irq_enable;
+ at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+ at86rf230_async_state_change_start,
+ irq_enable);
}
static void
{
int rc;
- rc = at86rf230_async_state_change(lp, &lp->state, state,
- at86rf230_sync_state_change_complete);
- if (rc) {
- at86rf230_async_error(lp, &lp->state, rc);
- return rc;
- }
+ at86rf230_async_state_change(lp, &lp->state, state,
+ at86rf230_sync_state_change_complete,
+ false);
rc = wait_for_completion_timeout(&lp->state_complete,
msecs_to_jiffies(100));
- if (!rc)
+ if (!rc) {
+ at86rf230_async_error(lp, &lp->state, -ETIMEDOUT);
return -ETIMEDOUT;
+ }
return 0;
}
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
+ struct sk_buff *skb = lp->tx_skb;
+
+ enable_irq(lp->spi->irq);
+
+ if (lp->max_frame_retries <= 0) {
+ /* Interfame spacing time, which is phy depend.
+ * TODO
+ * Move this handling in MAC 802.15.4 layer.
+ * This is currently a workaround to avoid fragmenation issues.
+ */
+ if (skb->len > 18)
+ udelay(lp->data->t_lifs);
+ else
+ udelay(lp->data->t_sifs);
+ }
- complete(&lp->tx_complete);
+ ieee802154_xmit_complete(lp->hw, skb);
}
static void
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- int rc;
- rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
- at86rf230_tx_complete);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
+ at86rf230_tx_complete, true);
}
static void
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- int rc;
- rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
- at86rf230_tx_on);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
+ at86rf230_tx_on, true);
}
static void
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = ctx->buf;
const u8 trac = (buf[1] & 0xe0) >> 5;
- int rc;
/* If trac status is different than zero we need to do a state change
* to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
* state to TX_ON.
*/
if (trac) {
- rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
- at86rf230_tx_trac_error);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
+ at86rf230_tx_trac_error, true);
return;
}
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- int rc;
- rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
- at86rf230_tx_trac_check);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
+ at86rf230_tx_trac_check, true);
}
static void
at86rf230_rx(struct at86rf230_local *lp,
- const u8 *data, u8 len)
+ const u8 *data, const u8 len, const u8 lqi)
{
- u8 lqi;
struct sk_buff *skb;
u8 rx_local_buf[AT86RF2XX_MAX_BUF];
- if (len < 2)
- return;
-
- /* read full frame buffer and invalid lqi value to lowest
- * indicator if frame was is in a corrupted state.
- */
- if (len > IEEE802154_MTU) {
- lqi = 0;
- len = IEEE802154_MTU;
- dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
- } else {
- lqi = data[len];
- }
-
memcpy(rx_local_buf, data, len);
enable_irq(lp->spi->irq);
- skb = alloc_skb(IEEE802154_MTU, GFP_ATOMIC);
+ skb = dev_alloc_skb(IEEE802154_MTU);
if (!skb) {
dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n");
return;
}
memcpy(skb_put(skb, len), rx_local_buf, len);
-
- /* We do not put CRC into the frame */
- skb_trim(skb, len - 2);
-
- ieee802154_rx_irqsafe(lp->dev, skb, lqi);
+ ieee802154_rx_irqsafe(lp->hw, skb, lqi);
}
static void
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = lp->irq.buf;
- const u8 len = buf[1];
+ u8 len = buf[1];
- at86rf230_rx(lp, buf + 2, len);
+ if (!ieee802154_is_valid_psdu_len(len)) {
+ dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
+ len = IEEE802154_MTU;
+ }
+
+ at86rf230_rx(lp, buf + 2, len, buf[2 + len]);
}
-static int
+static void
at86rf230_rx_read_frame(struct at86rf230_local *lp)
{
+ int rc;
+
u8 *buf = lp->irq.buf;
buf[0] = CMD_FB;
lp->irq.trx.len = AT86RF2XX_MAX_BUF;
lp->irq.msg.complete = at86rf230_rx_read_frame_complete;
- return spi_async(lp->spi, &lp->irq.msg);
+ rc = spi_async(lp->spi, &lp->irq.msg);
+ if (rc) {
+ enable_irq(lp->spi->irq);
+ at86rf230_async_error(lp, &lp->irq, rc);
+ }
}
static void
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- int rc;
/* Possible check on trac status here. This could be useful to make
* some stats why receive is failed. Not used at the moment, but it's
* The programming guide say do it so.
*/
- rc = at86rf230_rx_read_frame(lp);
- if (rc) {
- enable_irq(lp->spi->irq);
- at86rf230_async_error(lp, ctx, rc);
- }
+ at86rf230_rx_read_frame(lp);
}
-static int
+static void
at86rf230_irq_trx_end(struct at86rf230_local *lp)
{
spin_lock(&lp->lock);
if (lp->is_tx) {
lp->is_tx = 0;
spin_unlock(&lp->lock);
- enable_irq(lp->spi->irq);
if (lp->tx_aret)
- return at86rf230_async_state_change(lp, &lp->irq,
- STATE_FORCE_TX_ON,
- at86rf230_tx_trac_status);
+ at86rf230_async_state_change(lp, &lp->irq,
+ STATE_FORCE_TX_ON,
+ at86rf230_tx_trac_status,
+ true);
else
- return at86rf230_async_state_change(lp, &lp->irq,
- STATE_RX_AACK_ON,
- at86rf230_tx_complete);
+ at86rf230_async_state_change(lp, &lp->irq,
+ STATE_RX_AACK_ON,
+ at86rf230_tx_complete,
+ true);
} else {
spin_unlock(&lp->lock);
- return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
- at86rf230_rx_trac_check);
+ at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
+ at86rf230_rx_trac_check, true);
}
}
struct at86rf230_local *lp = ctx->lp;
const u8 *buf = lp->irq.buf;
const u8 irq = buf[1];
- int rc;
if (irq & IRQ_TRX_END) {
- rc = at86rf230_irq_trx_end(lp);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_irq_trx_end(lp);
} else {
enable_irq(lp->spi->irq);
dev_err(&lp->spi->dev, "not supported irq %02x received\n",
u8 *buf = ctx->buf;
int rc;
- disable_irq_nosync(lp->spi->irq);
+ disable_irq_nosync(irq);
buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
ctx->trx.len = 2;
ctx->msg.complete = at86rf230_irq_status;
rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
+ enable_irq(irq);
at86rf230_async_error(lp, ctx, rc);
return IRQ_NONE;
}
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- int rc;
- rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
- at86rf230_write_frame);
- if (rc)
- at86rf230_async_error(lp, ctx, rc);
+ at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
+ at86rf230_write_frame, false);
}
static int
-at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
struct at86rf230_state_change *ctx = &lp->tx;
void (*tx_complete)(void *context) = at86rf230_write_frame;
- int rc;
lp->tx_skb = skb;
if (lp->tx_aret)
tx_complete = at86rf230_xmit_tx_on;
- rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
- tx_complete);
- if (rc) {
- at86rf230_async_error(lp, ctx, rc);
- return rc;
- }
- rc = wait_for_completion_interruptible_timeout(&lp->tx_complete,
- msecs_to_jiffies(lp->data->t_tx_timeout));
- if (!rc) {
- at86rf230_async_error(lp, ctx, rc);
- return -ETIMEDOUT;
- }
-
- /* Interfame spacing time, which is phy depend.
- * TODO
- * Move this handling in MAC 802.15.4 layer.
- * This is currently a workaround to avoid fragmenation issues.
- */
- if (skb->len > 18)
- usleep_range(lp->data->t_lifs, lp->data->t_lifs + 10);
- else
- usleep_range(lp->data->t_sifs, lp->data->t_sifs + 10);
+ at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);
return 0;
}
static int
-at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
+at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
{
- might_sleep();
BUG_ON(!level);
*level = 0xbe;
return 0;
}
static int
-at86rf230_start(struct ieee802154_dev *dev)
+at86rf230_start(struct ieee802154_hw *hw)
{
- return at86rf230_sync_state_change(dev->priv, STATE_RX_AACK_ON);
+ return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
}
static void
-at86rf230_stop(struct ieee802154_dev *dev)
+at86rf230_stop(struct ieee802154_hw *hw)
{
- at86rf230_sync_state_change(dev->priv, STATE_FORCE_TRX_OFF);
+ at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF);
}
static int
-at86rf23x_set_channel(struct at86rf230_local *lp, int page, int channel)
+at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
{
return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
}
static int
-at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
+at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
{
int rc;
}
static int
-at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
+at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
int rc;
- might_sleep();
-
if (page < 0 || page > 31 ||
- !(lp->dev->phy->channels_supported[page] & BIT(channel))) {
+ !(lp->hw->phy->channels_supported[page] & BIT(channel))) {
WARN_ON(1);
return -EINVAL;
}
/* Wait for PLL */
usleep_range(lp->data->t_channel_switch,
lp->data->t_channel_switch + 10);
- dev->phy->current_channel = channel;
- dev->phy->current_page = page;
+ hw->phy->current_channel = channel;
+ hw->phy->current_page = page;
return 0;
}
static int
-at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
+at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
- if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&lp->spi->dev,
__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
}
- if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANID_CHANGED) {
u16 pan = le16_to_cpu(filt->pan_id);
dev_vdbg(&lp->spi->dev,
__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
}
- if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
}
- if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for panc change\n");
if (filt->pan_coord)
}
static int
-at86rf230_set_txpower(struct ieee802154_dev *dev, int db)
+at86rf230_set_txpower(struct ieee802154_hw *hw, int db)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
/* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
* bits decrease power in 1dB steps. 0x60 represents extra PA gain of
}
static int
-at86rf230_set_lbt(struct ieee802154_dev *dev, bool on)
+at86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
}
static int
-at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
+at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
}
}
static int
-at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
+at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
if (level < lp->data->rssi_base_val || level > 30)
return -EINVAL;
}
static int
-at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
+at86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
u8 retries)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
int rc;
if (min_be > max_be || max_be > 8 || retries > 5)
}
static int
-at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
+at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
{
- struct at86rf230_local *lp = dev->priv;
+ struct at86rf230_local *lp = hw->priv;
int rc = 0;
if (retries < -1 || retries > 15)
return -EINVAL;
lp->tx_aret = retries >= 0;
+ lp->max_frame_retries = retries;
if (retries >= 0)
rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
return rc;
}
-static struct ieee802154_ops at86rf230_ops = {
+static int
+at86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
+{
+ struct at86rf230_local *lp = hw->priv;
+ int rc;
+
+ if (on) {
+ rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1);
+ if (rc < 0)
+ return rc;
+
+ rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1);
+ if (rc < 0)
+ return rc;
+ } else {
+ rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0);
+ if (rc < 0)
+ return rc;
+
+ rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+static const struct ieee802154_ops at86rf230_ops = {
.owner = THIS_MODULE,
- .xmit = at86rf230_xmit,
+ .xmit_async = at86rf230_xmit,
.ed = at86rf230_ed,
.set_channel = at86rf230_channel,
.start = at86rf230_start,
.set_cca_ed_level = at86rf230_set_cca_ed_level,
.set_csma_params = at86rf230_set_csma_params,
.set_frame_retries = at86rf230_set_frame_retries,
+ .set_promiscuous_mode = at86rf230_set_promiscuous_mode,
};
static struct at86rf2xx_chip_data at86rf233_data = {
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
- .t_lifs = 480,
+ .t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
- .t_lifs = 480,
+ .t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -91,
.set_channel = at86rf23x_set_channel,
.t_frame = 4096,
.t_p_ack = 545,
.t_sifs = 192,
- .t_lifs = 480,
+ .t_lifs = 640,
.t_tx_timeout = 2000,
.rssi_base_val = -100,
.set_channel = at86rf212_set_channel,
return -EINVAL;
}
- lp->dev->extra_tx_headroom = 0;
- lp->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
- IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA;
+ lp->hw->extra_tx_headroom = 0;
+ lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK |
+ IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET |
+ IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS;
switch (part) {
case 2:
case 3:
chip = "at86rf231";
lp->data = &at86rf231_data;
- lp->dev->phy->channels_supported[0] = 0x7FFF800;
+ lp->hw->phy->channels_supported[0] = 0x7FFF800;
break;
case 7:
chip = "at86rf212";
if (version == 1) {
lp->data = &at86rf212_data;
- lp->dev->flags |= IEEE802154_HW_LBT;
- lp->dev->phy->channels_supported[0] = 0x00007FF;
- lp->dev->phy->channels_supported[2] = 0x00007FF;
+ lp->hw->flags |= IEEE802154_HW_LBT;
+ lp->hw->phy->channels_supported[0] = 0x00007FF;
+ lp->hw->phy->channels_supported[2] = 0x00007FF;
} else {
rc = -ENOTSUPP;
}
case 11:
chip = "at86rf233";
lp->data = &at86rf233_data;
- lp->dev->phy->channels_supported[0] = 0x7FFF800;
+ lp->hw->phy->channels_supported[0] = 0x7FFF800;
break;
default:
chip = "unkown";
static int at86rf230_probe(struct spi_device *spi)
{
struct at86rf230_platform_data *pdata;
- struct ieee802154_dev *dev;
+ struct ieee802154_hw *hw;
struct at86rf230_local *lp;
unsigned int status;
int rc, irq_type;
usleep_range(120, 240);
}
- dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
- if (!dev)
+ hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops);
+ if (!hw)
return -ENOMEM;
- lp = dev->priv;
- lp->dev = dev;
+ lp = hw->priv;
+ lp->hw = hw;
lp->spi = spi;
- dev->parent = &spi->dev;
+ hw->parent = &spi->dev;
lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
if (IS_ERR(lp->regmap)) {
goto free_dev;
spin_lock_init(&lp->lock);
- init_completion(&lp->tx_complete);
init_completion(&lp->state_complete);
spi_set_drvdata(spi, lp);
if (rc)
goto free_dev;
- rc = ieee802154_register_device(lp->dev);
+ rc = ieee802154_register_hw(lp->hw);
if (rc)
goto free_dev;
return rc;
free_dev:
- ieee802154_free_device(lp->dev);
+ ieee802154_free_hw(lp->hw);
return rc;
}
/* mask all at86rf230 irq's */
at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
- ieee802154_unregister_device(lp->dev);
- ieee802154_free_device(lp->dev);
+ ieee802154_unregister_hw(lp->hw);
+ ieee802154_free_hw(lp->hw);
dev_dbg(&spi->dev, "unregistered at86rf230\n");
return 0;
#include <linux/skbuff.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_gpio.h>
+#include <linux/ieee802154.h>
#include <net/mac802154.h>
-#include <net/wpan-phy.h>
-#include <net/ieee802154.h>
+#include <net/cfg802154.h>
#define SPI_COMMAND_BUFFER 3
#define HIGH 1
/* Driver private information */
struct cc2520_private {
struct spi_device *spi; /* SPI device structure */
- struct ieee802154_dev *dev; /* IEEE-802.15.4 device */
+ struct ieee802154_hw *hw; /* IEEE-802.15.4 device */
u8 *buf; /* SPI TX/Rx data buffer */
struct mutex buffer_mutex; /* SPI buffer mutex */
bool is_tx; /* Flag for sync b/w Tx and Rx */
return status;
}
-static int cc2520_start(struct ieee802154_dev *dev)
+static int cc2520_start(struct ieee802154_hw *hw)
{
- return cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRXON);
+ return cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRXON);
}
-static void cc2520_stop(struct ieee802154_dev *dev)
+static void cc2520_stop(struct ieee802154_hw *hw)
{
- cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRFOFF);
+ cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRFOFF);
}
static int
-cc2520_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
- struct cc2520_private *priv = dev->priv;
+ struct cc2520_private *priv = hw->priv;
unsigned long flags;
int rc;
u8 status = 0;
if (len < 2 || len > IEEE802154_MTU)
return -EINVAL;
- skb = alloc_skb(len, GFP_KERNEL);
+ skb = dev_alloc_skb(len);
if (!skb)
return -ENOMEM;
skb_trim(skb, skb->len - 2);
- ieee802154_rx_irqsafe(priv->dev, skb, lqi);
+ ieee802154_rx_irqsafe(priv->hw, skb, lqi);
dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi);
}
static int
-cc2520_ed(struct ieee802154_dev *dev, u8 *level)
+cc2520_ed(struct ieee802154_hw *hw, u8 *level)
{
- struct cc2520_private *priv = dev->priv;
+ struct cc2520_private *priv = hw->priv;
u8 status = 0xff;
u8 rssi;
int ret;
}
static int
-cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel)
+cc2520_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
- struct cc2520_private *priv = dev->priv;
+ struct cc2520_private *priv = hw->priv;
int ret;
- might_sleep();
dev_dbg(&priv->spi->dev, "trying to set channel\n");
BUG_ON(page != 0);
}
static int
-cc2520_filter(struct ieee802154_dev *dev,
+cc2520_filter(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt, unsigned long changed)
{
- struct cc2520_private *priv = dev->priv;
+ struct cc2520_private *priv = hw->priv;
- if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANID_CHANGED) {
u16 panid = le16_to_cpu(filt->pan_id);
dev_vdbg(&priv->spi->dev,
sizeof(panid), (u8 *)&panid);
}
- if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for IEEE addr\n");
cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
(u8 *)&filt->ieee_addr);
}
- if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&priv->spi->dev,
sizeof(addr), (u8 *)&addr);
}
- if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&priv->spi->dev,
"cc2520_filter called for panc change\n");
if (filt->pan_coord)
return 0;
}
-static struct ieee802154_ops cc2520_ops = {
+static const struct ieee802154_ops cc2520_ops = {
.owner = THIS_MODULE,
.start = cc2520_start,
.stop = cc2520_stop,
- .xmit = cc2520_tx,
+ .xmit_sync = cc2520_tx,
.ed = cc2520_ed,
.set_channel = cc2520_set_channel,
.set_hw_addr_filt = cc2520_filter,
{
int ret = -ENOMEM;
- priv->dev = ieee802154_alloc_device(sizeof(*priv), &cc2520_ops);
- if (!priv->dev)
+ priv->hw = ieee802154_alloc_hw(sizeof(*priv), &cc2520_ops);
+ if (!priv->hw)
goto err_ret;
- priv->dev->priv = priv;
- priv->dev->parent = &priv->spi->dev;
- priv->dev->extra_tx_headroom = 0;
+ priv->hw->priv = priv;
+ priv->hw->parent = &priv->spi->dev;
+ priv->hw->extra_tx_headroom = 0;
/* We do support only 2.4 Ghz */
- priv->dev->phy->channels_supported[0] = 0x7FFF800;
- priv->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
+ priv->hw->phy->channels_supported[0] = 0x7FFF800;
+ priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
+ IEEE802154_HW_AFILT;
dev_vdbg(&priv->spi->dev, "registered cc2520\n");
- ret = ieee802154_register_device(priv->dev);
+ ret = ieee802154_register_hw(priv->hw);
if (ret)
goto err_free_device;
return 0;
err_free_device:
- ieee802154_free_device(priv->dev);
+ ieee802154_free_hw(priv->hw);
err_ret:
return ret;
}
mutex_destroy(&priv->buffer_mutex);
flush_work(&priv->fifop_irqwork);
- ieee802154_unregister_device(priv->dev);
- ieee802154_free_device(priv->dev);
+ ieee802154_unregister_hw(priv->hw);
+ ieee802154_free_hw(priv->hw);
return 0;
}
+++ /dev/null
-/*
- * Sample driver for HardMAC IEEE 802.15.4 devices
- *
- * Copyright (C) 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-
-#include <net/af_ieee802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ieee802154.h>
-#include <net/nl802154.h>
-#include <net/wpan-phy.h>
-
-struct fakehard_priv {
- struct wpan_phy *phy;
-};
-
-static struct wpan_phy *fake_to_phy(const struct net_device *dev)
-{
- struct fakehard_priv *priv = netdev_priv(dev);
- return priv->phy;
-}
-
-/**
- * fake_get_phy - Return a phy corresponding to this device.
- * @dev: The network device for which to return the wan-phy object
- *
- * This function returns a wpan-phy object corresponding to the passed
- * network device. Reference counter for wpan-phy object is incremented,
- * so when the wpan-phy isn't necessary, you should drop the reference
- * via @wpan_phy_put() call.
- */
-static struct wpan_phy *fake_get_phy(const struct net_device *dev)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
- return to_phy(get_device(&phy->dev));
-}
-
-/**
- * fake_get_pan_id - Retrieve the PAN ID of the device.
- * @dev: The network device to retrieve the PAN of.
- *
- * Return the ID of the PAN from the PIB.
- */
-static __le16 fake_get_pan_id(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return cpu_to_le16(0xeba1);
-}
-
-/**
- * fake_get_short_addr - Retrieve the short address of the device.
- * @dev: The network device to retrieve the short address of.
- *
- * Returns the IEEE 802.15.4 short-form address cached for this
- * device. If the device has not yet had a short address assigned
- * then this should return 0xFFFF to indicate a lack of association.
- */
-static __le16 fake_get_short_addr(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return cpu_to_le16(0x1);
-}
-
-/**
- * fake_get_dsn - Retrieve the DSN of the device.
- * @dev: The network device to retrieve the DSN for.
- *
- * Returns the IEEE 802.15.4 DSN for the network device.
- * The DSN is the sequence number which will be added to each
- * packet or MAC command frame by the MAC during transmission.
- *
- * DSN means 'Data Sequence Number'.
- *
- * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
- * document.
- */
-static u8 fake_get_dsn(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0x00; /* DSN are implemented in HW, so return just 0 */
-}
-
-/**
- * fake_assoc_req - Make an association request to the HW.
- * @dev: The network device which we are associating to a network.
- * @addr: The coordinator with which we wish to associate.
- * @channel: The channel on which to associate.
- * @cap: The capability information field to use in the association.
- *
- * Start an association with a coordinator. The coordinator's address
- * and PAN ID can be found in @addr.
- *
- * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
- * 802.15.4-2006 document.
- */
-static int fake_assoc_req(struct net_device *dev,
- struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- mutex_lock(&phy->pib_lock);
- phy->current_channel = channel;
- phy->current_page = page;
- mutex_unlock(&phy->pib_lock);
-
- /* We simply emulate it here */
- return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
- IEEE802154_SUCCESS);
-}
-
-/**
- * fake_assoc_resp - Send an association response to a device.
- * @dev: The network device on which to send the response.
- * @addr: The address of the device to respond to.
- * @short_addr: The assigned short address for the device (if any).
- * @status: The result of the association request.
- *
- * Queue the association response of the coordinator to another
- * device's attempt to associate with the network which we
- * coordinate. This is then added to the indirect-send queue to be
- * transmitted to the end device when it polls for data.
- *
- * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
- * 802.15.4-2006 document.
- */
-static int fake_assoc_resp(struct net_device *dev,
- struct ieee802154_addr *addr, __le16 short_addr, u8 status)
-{
- return 0;
-}
-
-/**
- * fake_disassoc_req - Disassociate a device from a network.
- * @dev: The network device on which we're disassociating a device.
- * @addr: The device to disassociate from the network.
- * @reason: The reason to give to the device for being disassociated.
- *
- * This sends a disassociation notification to the device being
- * disassociated from the network.
- *
- * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
- * document, with the reason described in 7.3.3.2.
- */
-static int fake_disassoc_req(struct net_device *dev,
- struct ieee802154_addr *addr, u8 reason)
-{
- return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
-}
-
-/**
- * fake_start_req - Start an IEEE 802.15.4 PAN.
- * @dev: The network device on which to start the PAN.
- * @addr: The coordinator address to use when starting the PAN.
- * @channel: The channel on which to start the PAN.
- * @bcn_ord: Beacon order.
- * @sf_ord: Superframe order.
- * @pan_coord: Whether or not we are the PAN coordinator or just
- * requesting a realignment perhaps?
- * @blx: Battery Life Extension feature bitfield.
- * @coord_realign: Something to realign something else.
- *
- * If pan_coord is non-zero then this starts a network with the
- * provided parameters, otherwise it attempts a coordinator
- * realignment of the stated network instead.
- *
- * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
- * document, with 7.3.8 describing coordinator realignment.
- */
-static int fake_start_req(struct net_device *dev,
- struct ieee802154_addr *addr, u8 channel, u8 page,
- u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
- u8 coord_realign)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- mutex_lock(&phy->pib_lock);
- phy->current_channel = channel;
- phy->current_page = page;
- mutex_unlock(&phy->pib_lock);
-
- /* We don't emulate beacons here at all, so START should fail */
- ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
- return 0;
-}
-
-/**
- * fake_scan_req - Start a channel scan.
- * @dev: The network device on which to perform a channel scan.
- * @type: The type of scan to perform.
- * @channels: The channel bitmask to scan.
- * @duration: How long to spend on each channel.
- *
- * This starts either a passive (energy) scan or an active (PAN) scan
- * on the channels indicated in the @channels bitmask. The duration of
- * the scan is measured in terms of superframe duration. Specifically,
- * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
- * channel.
- *
- * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
- */
-static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
- u8 page, u8 duration)
-{
- u8 edl[27] = {};
- return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
- channels, page,
- type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
-}
-
-static struct ieee802154_mlme_ops fake_mlme = {
- .assoc_req = fake_assoc_req,
- .assoc_resp = fake_assoc_resp,
- .disassoc_req = fake_disassoc_req,
- .start_req = fake_start_req,
- .scan_req = fake_scan_req,
-
- .get_phy = fake_get_phy,
-
- .get_pan_id = fake_get_pan_id,
- .get_short_addr = fake_get_short_addr,
- .get_dsn = fake_get_dsn,
-};
-
-static int ieee802154_fake_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int ieee802154_fake_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
-
- /* FIXME: do hardware work here ... */
-
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-
-static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
- int cmd)
-{
- struct sockaddr_ieee802154 *sa =
- (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
- u16 pan_id, short_addr;
-
- switch (cmd) {
- case SIOCGIFADDR:
- /* FIXME: fixed here, get from device IRL */
- pan_id = le16_to_cpu(fake_get_pan_id(dev));
- short_addr = le16_to_cpu(fake_get_short_addr(dev));
- if (pan_id == IEEE802154_PANID_BROADCAST ||
- short_addr == IEEE802154_ADDR_BROADCAST)
- return -EADDRNOTAVAIL;
-
- sa->family = AF_IEEE802154;
- sa->addr.addr_type = IEEE802154_ADDR_SHORT;
- sa->addr.pan_id = pan_id;
- sa->addr.short_addr = short_addr;
- return 0;
- }
- return -ENOIOCTLCMD;
-}
-
-static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
-{
- return -EBUSY; /* HW address is built into the device */
-}
-
-static const struct net_device_ops fake_ops = {
- .ndo_open = ieee802154_fake_open,
- .ndo_stop = ieee802154_fake_close,
- .ndo_start_xmit = ieee802154_fake_xmit,
- .ndo_do_ioctl = ieee802154_fake_ioctl,
- .ndo_set_mac_address = ieee802154_fake_mac_addr,
-};
-
-static void ieee802154_fake_destruct(struct net_device *dev)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- wpan_phy_unregister(phy);
- free_netdev(dev);
- wpan_phy_free(phy);
-}
-
-static void ieee802154_fake_setup(struct net_device *dev)
-{
- dev->addr_len = IEEE802154_ADDR_LEN;
- memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
- dev->features = NETIF_F_HW_CSUM;
- dev->needed_tailroom = 2; /* FCS */
- dev->mtu = 127;
- dev->tx_queue_len = 10;
- dev->type = ARPHRD_IEEE802154;
- dev->flags = IFF_NOARP | IFF_BROADCAST;
- dev->watchdog_timeo = 0;
- dev->destructor = ieee802154_fake_destruct;
-}
-
-
-static int ieee802154fake_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct fakehard_priv *priv;
- struct wpan_phy *phy = wpan_phy_alloc(0);
- int err;
-
- if (!phy)
- return -ENOMEM;
-
- dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d",
- NET_NAME_UNKNOWN, ieee802154_fake_setup);
- if (!dev) {
- wpan_phy_free(phy);
- return -ENOMEM;
- }
-
- memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
- dev->addr_len);
-
- /*
- * For now we'd like to emulate 2.4 GHz-only device,
- * both O-QPSK and CSS
- */
- /* 2.4 GHz O-QPSK 802.15.4-2003 */
- phy->channels_supported[0] |= 0x7FFF800;
- /* 2.4 GHz CSS 802.15.4a-2007 */
- phy->channels_supported[3] |= 0x3fff;
-
- phy->transmit_power = 0xbf;
-
- dev->netdev_ops = &fake_ops;
- dev->ml_priv = &fake_mlme;
-
- priv = netdev_priv(dev);
- priv->phy = phy;
-
- wpan_phy_set_dev(phy, &pdev->dev);
- SET_NETDEV_DEV(dev, &phy->dev);
-
- platform_set_drvdata(pdev, dev);
-
- err = wpan_phy_register(phy);
- if (err)
- goto out;
-
- err = register_netdev(dev);
- if (err < 0)
- goto out;
-
- dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
- return 0;
-
-out:
- unregister_netdev(dev);
- return err;
-}
-
-static int ieee802154fake_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- unregister_netdev(dev);
- return 0;
-}
-
-static struct platform_device *ieee802154fake_dev;
-
-static struct platform_driver ieee802154fake_driver = {
- .probe = ieee802154fake_probe,
- .remove = ieee802154fake_remove,
- .driver = {
- .name = "ieee802154hardmac",
- .owner = THIS_MODULE,
- },
-};
-
-static __init int fake_init(void)
-{
- ieee802154fake_dev = platform_device_register_simple(
- "ieee802154hardmac", -1, NULL, 0);
- return platform_driver_register(&ieee802154fake_driver);
-}
-
-static __exit void fake_exit(void)
-{
- platform_driver_unregister(&ieee802154fake_driver);
- platform_device_unregister(ieee802154fake_dev);
-}
-
-module_init(fake_init);
-module_exit(fake_exit);
-MODULE_LICENSE("GPL");
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
static int numlbs = 1;
struct fakelb_dev_priv {
- struct ieee802154_dev *dev;
+ struct ieee802154_hw *hw;
struct list_head list;
struct fakelb_priv *fake;
};
static int
-fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
+fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
{
- might_sleep();
BUG_ON(!level);
*level = 0xbe;
}
static int
-fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel)
+fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
pr_debug("set channel to %d\n", channel);
- might_sleep();
- dev->phy->current_page = page;
- dev->phy->current_channel = channel;
+ hw->phy->current_page = page;
+ hw->phy->current_channel = channel;
return 0;
}
spin_lock(&priv->lock);
if (priv->working) {
newskb = pskb_copy(skb, GFP_ATOMIC);
- ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+ ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc);
}
spin_unlock(&priv->lock);
}
static int
-fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
- struct fakelb_dev_priv *priv = dev->priv;
+ struct fakelb_dev_priv *priv = hw->priv;
struct fakelb_priv *fake = priv->fake;
- might_sleep();
-
read_lock_bh(&fake->lock);
if (priv->list.next == priv->list.prev) {
/* we are the only one device */
struct fakelb_dev_priv *dp;
list_for_each_entry(dp, &priv->fake->list, list) {
if (dp != priv &&
- (dp->dev->phy->current_channel ==
- priv->dev->phy->current_channel))
+ (dp->hw->phy->current_channel ==
+ priv->hw->phy->current_channel))
fakelb_hw_deliver(dp, skb);
}
}
}
static int
-fakelb_hw_start(struct ieee802154_dev *dev) {
- struct fakelb_dev_priv *priv = dev->priv;
+fakelb_hw_start(struct ieee802154_hw *hw) {
+ struct fakelb_dev_priv *priv = hw->priv;
int ret = 0;
spin_lock(&priv->lock);
}
static void
-fakelb_hw_stop(struct ieee802154_dev *dev) {
- struct fakelb_dev_priv *priv = dev->priv;
+fakelb_hw_stop(struct ieee802154_hw *hw) {
+ struct fakelb_dev_priv *priv = hw->priv;
spin_lock(&priv->lock);
priv->working = 0;
spin_unlock(&priv->lock);
}
-static struct ieee802154_ops fakelb_ops = {
+static const struct ieee802154_ops fakelb_ops = {
.owner = THIS_MODULE,
- .xmit = fakelb_hw_xmit,
+ .xmit_sync = fakelb_hw_xmit,
.ed = fakelb_hw_ed,
.set_channel = fakelb_hw_channel,
.start = fakelb_hw_start,
{
struct fakelb_dev_priv *priv;
int err;
- struct ieee802154_dev *ieee;
+ struct ieee802154_hw *hw;
- ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops);
- if (!ieee)
+ hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops);
+ if (!hw)
return -ENOMEM;
- priv = ieee->priv;
- priv->dev = ieee;
+ priv = hw->priv;
+ priv->hw = hw;
/* 868 MHz BPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 1;
+ hw->phy->channels_supported[0] |= 1;
/* 915 MHz BPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 0x7fe;
+ hw->phy->channels_supported[0] |= 0x7fe;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 0x7FFF800;
+ hw->phy->channels_supported[0] |= 0x7FFF800;
/* 868 MHz ASK 802.15.4-2006 */
- ieee->phy->channels_supported[1] |= 1;
+ hw->phy->channels_supported[1] |= 1;
/* 915 MHz ASK 802.15.4-2006 */
- ieee->phy->channels_supported[1] |= 0x7fe;
+ hw->phy->channels_supported[1] |= 0x7fe;
/* 868 MHz O-QPSK 802.15.4-2006 */
- ieee->phy->channels_supported[2] |= 1;
+ hw->phy->channels_supported[2] |= 1;
/* 915 MHz O-QPSK 802.15.4-2006 */
- ieee->phy->channels_supported[2] |= 0x7fe;
+ hw->phy->channels_supported[2] |= 0x7fe;
/* 2.4 GHz CSS 802.15.4a-2007 */
- ieee->phy->channels_supported[3] |= 0x3fff;
+ hw->phy->channels_supported[3] |= 0x3fff;
/* UWB Sub-gigahertz 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 1;
+ hw->phy->channels_supported[4] |= 1;
/* UWB Low band 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 0x1e;
+ hw->phy->channels_supported[4] |= 0x1e;
/* UWB High band 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 0xffe0;
+ hw->phy->channels_supported[4] |= 0xffe0;
/* 750 MHz O-QPSK 802.15.4c-2009 */
- ieee->phy->channels_supported[5] |= 0xf;
+ hw->phy->channels_supported[5] |= 0xf;
/* 750 MHz MPSK 802.15.4c-2009 */
- ieee->phy->channels_supported[5] |= 0xf0;
+ hw->phy->channels_supported[5] |= 0xf0;
/* 950 MHz BPSK 802.15.4d-2009 */
- ieee->phy->channels_supported[6] |= 0x3ff;
+ hw->phy->channels_supported[6] |= 0x3ff;
/* 950 MHz GFSK 802.15.4d-2009 */
- ieee->phy->channels_supported[6] |= 0x3ffc00;
+ hw->phy->channels_supported[6] |= 0x3ffc00;
INIT_LIST_HEAD(&priv->list);
priv->fake = fake;
spin_lock_init(&priv->lock);
- ieee->parent = dev;
+ hw->parent = dev;
- err = ieee802154_register_device(ieee);
+ err = ieee802154_register_hw(hw);
if (err)
goto err_reg;
return 0;
err_reg:
- ieee802154_free_device(priv->dev);
+ ieee802154_free_hw(priv->hw);
return err;
}
list_del(&priv->list);
write_unlock_bh(&priv->fake->lock);
- ieee802154_unregister_device(priv->dev);
- ieee802154_free_device(priv->dev);
+ ieee802154_unregister_hw(priv->hw);
+ ieee802154_free_hw(priv->hw);
}
static int fakelb_probe(struct platform_device *pdev)
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <net/wpan-phy.h>
+#include <linux/ieee802154.h>
+#include <net/cfg802154.h>
#include <net/mac802154.h>
-#include <net/ieee802154.h>
/* MRF24J40 Short Address Registers */
#define REG_RXMCR 0x00 /* Receive MAC control */
#define REG_TXSTBL 0x2E /* TX Stabilization */
#define REG_INTSTAT 0x31 /* Interrupt Status */
#define REG_INTCON 0x32 /* Interrupt Control */
+#define REG_GPIO 0x33 /* GPIO */
+#define REG_TRISGPIO 0x34 /* GPIO direction */
#define REG_RFCTL 0x36 /* RF Control Mode Register */
#define REG_BBREG1 0x39 /* Baseband Registers */
#define REG_BBREG2 0x3A /* */
#define REG_SLPCON1 0x220
#define REG_WAKETIMEL 0x222 /* Wake-up Time Match Value Low */
#define REG_WAKETIMEH 0x223 /* Wake-up Time Match Value High */
+#define REG_TESTMODE 0x22F /* Test mode */
#define REG_RX_FIFO 0x300 /* Receive FIFO */
/* Device configuration: Only channels 11-26 on page 0 are supported. */
#define RX_FIFO_SIZE 144 /* From datasheet */
#define SET_CHANNEL_DELAY_US 192 /* From datasheet */
+enum mrf24j40_modules { MRF24J40, MRF24J40MA, MRF24J40MC };
+
/* Device Private Data */
struct mrf24j40 {
struct spi_device *spi;
- struct ieee802154_dev *dev;
+ struct ieee802154_hw *hw;
struct mutex buffer_mutex; /* only used to protect buf */
struct completion tx_complete;
return ret;
}
-static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+static int mrf24j40_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
- struct mrf24j40 *devrec = dev->priv;
+ struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret = 0;
return ret;
}
-static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
+static int mrf24j40_ed(struct ieee802154_hw *hw, u8 *level)
{
/* TODO: */
pr_warn("mrf24j40: ed not implemented\n");
return 0;
}
-static int mrf24j40_start(struct ieee802154_dev *dev)
+static int mrf24j40_start(struct ieee802154_hw *hw)
{
- struct mrf24j40 *devrec = dev->priv;
+ struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
return 0;
}
-static void mrf24j40_stop(struct ieee802154_dev *dev)
+static void mrf24j40_stop(struct ieee802154_hw *hw)
{
- struct mrf24j40 *devrec = dev->priv;
+ struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
write_short_reg(devrec, REG_INTCON, val);
}
-static int mrf24j40_set_channel(struct ieee802154_dev *dev,
- int page, int channel)
+static int mrf24j40_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
- struct mrf24j40 *devrec = dev->priv;
+ struct mrf24j40 *devrec = hw->priv;
u8 val;
int ret;
return 0;
}
-static int mrf24j40_filter(struct ieee802154_dev *dev,
+static int mrf24j40_filter(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed)
{
- struct mrf24j40 *devrec = dev->priv;
+ struct mrf24j40 *devrec = hw->priv;
dev_dbg(printdev(devrec), "filter\n");
- if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
/* Short Addr */
u8 addrh, addrl;
"Set short addr to %04hx\n", filt->short_addr);
}
- if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+ if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
/* Device Address */
u8 i, addr[8];
#endif
}
- if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANID_CHANGED) {
/* PAN ID */
u8 panidl, panidh;
dev_dbg(printdev(devrec), "Set PANID to %04hx\n", filt->pan_id);
}
- if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+ if (changed & IEEE802154_AFILT_PANC_CHANGED) {
/* Pan Coordinator */
u8 val;
int ret;
val |= 4; /* SET RXDECINV */
write_short_reg(devrec, REG_BBREG1, val);
- skb = alloc_skb(len, GFP_KERNEL);
+ skb = dev_alloc_skb(len);
if (!skb) {
ret = -ENOMEM;
goto out;
/* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040,
* also from a workqueue). I think irqsafe is not necessary here.
* Can someone confirm? */
- ieee802154_rx_irqsafe(devrec->dev, skb, lqi);
+ ieee802154_rx_irqsafe(devrec->hw, skb, lqi);
dev_dbg(printdev(devrec), "RX Handled\n");
return ret;
}
-static struct ieee802154_ops mrf24j40_ops = {
+static const struct ieee802154_ops mrf24j40_ops = {
.owner = THIS_MODULE,
- .xmit = mrf24j40_tx,
+ .xmit_sync = mrf24j40_tx,
.ed = mrf24j40_ed,
.start = mrf24j40_start,
.stop = mrf24j40_stop,
if (ret)
goto err_ret;
+ if (spi_get_device_id(devrec->spi)->driver_data == MRF24J40MC) {
+ /* Enable external amplifier.
+ * From MRF24J40MC datasheet section 1.3: Operation.
+ */
+ read_long_reg(devrec, REG_TESTMODE, &val);
+ val |= 0x7; /* Configure GPIO 0-2 to control amplifier */
+ write_long_reg(devrec, REG_TESTMODE, val);
+
+ read_short_reg(devrec, REG_TRISGPIO, &val);
+ val |= 0x8; /* Set GPIO3 as output. */
+ write_short_reg(devrec, REG_TRISGPIO, val);
+
+ read_short_reg(devrec, REG_GPIO, &val);
+ val |= 0x8; /* Set GPIO3 HIGH to enable U5 voltage regulator */
+ write_short_reg(devrec, REG_GPIO, val);
+
+ /* Reduce TX pwr to meet FCC requirements.
+ * From MRF24J40MC datasheet section 3.1.1
+ */
+ write_long_reg(devrec, REG_RFCON3, 0x28);
+ }
+
return 0;
err_ret:
/* Register with the 802154 subsystem */
- devrec->dev = ieee802154_alloc_device(0, &mrf24j40_ops);
- if (!devrec->dev)
+ devrec->hw = ieee802154_alloc_hw(0, &mrf24j40_ops);
+ if (!devrec->hw)
goto err_ret;
- devrec->dev->priv = devrec;
- devrec->dev->parent = &devrec->spi->dev;
- devrec->dev->phy->channels_supported[0] = CHANNEL_MASK;
- devrec->dev->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK;
+ devrec->hw->priv = devrec;
+ devrec->hw->parent = &devrec->spi->dev;
+ devrec->hw->phy->channels_supported[0] = CHANNEL_MASK;
+ devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
+ IEEE802154_HW_AFILT;
dev_dbg(printdev(devrec), "registered mrf24j40\n");
- ret = ieee802154_register_device(devrec->dev);
+ ret = ieee802154_register_hw(devrec->hw);
if (ret)
goto err_register_device;
err_irq:
err_hw_init:
- ieee802154_unregister_device(devrec->dev);
+ ieee802154_unregister_hw(devrec->hw);
err_register_device:
- ieee802154_free_device(devrec->dev);
+ ieee802154_free_hw(devrec->hw);
err_ret:
return ret;
}
dev_dbg(printdev(devrec), "remove\n");
- ieee802154_unregister_device(devrec->dev);
- ieee802154_free_device(devrec->dev);
+ ieee802154_unregister_hw(devrec->hw);
+ ieee802154_free_hw(devrec->hw);
/* TODO: Will ieee802154_free_device() wait until ->xmit() is
* complete? */
}
static const struct spi_device_id mrf24j40_ids[] = {
- { "mrf24j40", 0 },
- { "mrf24j40ma", 0 },
+ { "mrf24j40", MRF24J40 },
+ { "mrf24j40ma", MRF24J40MA },
+ { "mrf24j40mc", MRF24J40MC },
{ },
};
MODULE_DEVICE_TABLE(spi, mrf24j40_ids);
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Power on the dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
static int act200l_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Power off the dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
u8 control[3];
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Clear DTR and set RTS to enter command mode */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
};
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
/* Reset the dongle : set RTS low for 25 ms */
dev->speed = 9600;
break;
default:
- IRDA_ERROR("%s(), unknown state %d\n", __func__, state);
+ net_err_ratelimited("%s(), unknown state %d\n",
+ __func__, state);
ret = -1;
break;
}
int ret = 0;
int i = 0;
- IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __func__,
- speed, dev->speed);
+ pr_debug("%s(), speed=%d (was %d)\n", __func__, speed, dev->speed);
/* dongle was already resetted from irda_request state machine,
* we are in known state (dongle default)
int reg, revision;
int i = 0;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
-
ret = platform_driver_register(&ali_ircc_driver);
if (ret) {
- IRDA_ERROR("%s, Can't register driver!\n",
- ALI_IRCC_DRIVER_NAME);
+ net_err_ratelimited("%s, Can't register driver!\n",
+ ALI_IRCC_DRIVER_NAME);
return ret;
}
/* Probe for all the ALi chipsets we know about */
for (chip= chips; chip->name; chip++, i++)
{
- IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __func__, chip->name);
+ pr_debug("%s(), Probing for %s ...\n", __func__, chip->name);
/* Try all config registers for this chip */
for (cfg=0; cfg<2; cfg++)
if (reg == chip->cid_value)
{
- IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __func__, cfg_base);
+ pr_debug("%s(), Chip found at 0x%03x\n",
+ __func__, cfg_base);
outb(0x1F, cfg_base);
revision = inb(cfg_base+1);
- IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __func__,
- chip->name, revision);
+ pr_debug("%s(), Found %s chip, revision=%d\n",
+ __func__, chip->name, revision);
/*
* If the user supplies the base address, then
}
else
{
- IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __func__, chip->name, cfg_base);
+ pr_debug("%s(), No %s chip at 0x%03x\n",
+ __func__, chip->name, cfg_base);
}
/* Exit configuration */
outb(0xbb, cfg_base);
}
}
- IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
-
if (ret)
platform_driver_unregister(&ali_ircc_driver);
{
int i;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
-
for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
ali_ircc_close(dev_self[i]);
platform_driver_unregister(&ali_ircc_driver);
- IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
}
static const struct net_device_ops ali_ircc_sir_ops = {
int dongle_id;
int err;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
-
if (i >= ARRAY_SIZE(dev_self)) {
- IRDA_ERROR("%s(), maximum number of supported chips reached!\n",
- __func__);
+ net_err_ratelimited("%s(), maximum number of supported chips reached!\n",
+ __func__);
return -ENOMEM;
}
dev = alloc_irdadev(sizeof(*self));
if (dev == NULL) {
- IRDA_ERROR("%s(), can't allocate memory for control block!\n",
- __func__);
+ net_err_ratelimited("%s(), can't allocate memory for control block!\n",
+ __func__);
return -ENOMEM;
}
/* Reserve the ioports that we need */
if (!request_region(self->io.fir_base, self->io.fir_ext,
ALI_IRCC_DRIVER_NAME)) {
- IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __func__,
- self->io.fir_base);
+ net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n",
+ __func__, self->io.fir_base);
err = -ENODEV;
goto err_out1;
}
err = register_netdev(dev);
if (err) {
- IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
+ net_err_ratelimited("%s(), register_netdev() failed!\n",
+ __func__);
goto err_out4;
}
- IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
/* Check dongle id */
dongle_id = ali_ircc_read_dongle_id(i, info);
- IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __func__,
- ALI_IRCC_DRIVER_NAME, dongle_types[dongle_id]);
+ net_info_ratelimited("%s(), %s, Found dongle: %s\n",
+ __func__, ALI_IRCC_DRIVER_NAME,
+ dongle_types[dongle_id]);
self->io.dongle_id = dongle_id;
- IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
return 0;
{
int iobase;
- IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
iobase = self->io.fir_base;
unregister_netdev(self->netdev);
/* Release the PORT that this driver is using */
- IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __func__, self->io.fir_base);
+ pr_debug("%s(), Releasing Region %03x\n", __func__, self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
dev_self[self->index] = NULL;
free_netdev(self->netdev);
- IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
return 0;
}
int cfg_base = info->cfg_base;
int hi, low, reg;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
/* Enter Configuration */
outb(chip->entr1, cfg_base);
info->sir_base = info->fir_base;
- IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __func__, info->fir_base);
+ pr_debug("%s(), probing fir_base=0x%03x\n", __func__, info->fir_base);
/* Read IRQ control register */
outb(0x70, cfg_base);
reg = inb(cfg_base+1);
info->irq = reg & 0x0f;
- IRDA_DEBUG(2, "%s(), probing irq=%d\n", __func__, info->irq);
+ pr_debug("%s(), probing irq=%d\n", __func__, info->irq);
/* Read DMA channel */
outb(0x74, cfg_base);
info->dma = reg & 0x07;
if(info->dma == 0x04)
- IRDA_WARNING("%s(), No DMA channel assigned !\n", __func__);
+ net_warn_ratelimited("%s(), No DMA channel assigned !\n",
+ __func__);
else
- IRDA_DEBUG(2, "%s(), probing dma=%d\n", __func__, info->dma);
+ pr_debug("%s(), probing dma=%d\n", __func__, info->dma);
/* Read Enabled Status */
outb(0x30, cfg_base);
reg = inb(cfg_base+1);
info->enabled = (reg & 0x80) && (reg & 0x01);
- IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __func__, info->enabled);
+ pr_debug("%s(), probing enabled=%d\n", __func__, info->enabled);
/* Read Power Status */
outb(0x22, cfg_base);
reg = inb(cfg_base+1);
info->suspended = (reg & 0x20);
- IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __func__, info->suspended);
+ pr_debug("%s(), probing suspended=%d\n", __func__, info->suspended);
/* Exit configuration */
outb(0xbb, cfg_base);
- IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
return 0;
}
int version;
int iobase = info->fir_base;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
/* Locking comments :
* Most operations here need to be protected. We are called before
/* Should be 0x00 in the M1535/M1535D */
if(version != 0x00)
{
- IRDA_ERROR("%s, Wrong chip version %02x\n",
- ALI_IRCC_DRIVER_NAME, version);
+ net_err_ratelimited("%s, Wrong chip version %02x\n",
+ ALI_IRCC_DRIVER_NAME, version);
return -1;
}
/* Switch to SIR space */
FIR2SIR(iobase);
- IRDA_MESSAGE("%s, driver loaded (Benjamin Kong)\n",
- ALI_IRCC_DRIVER_NAME);
+ net_info_ratelimited("%s, driver loaded (Benjamin Kong)\n",
+ ALI_IRCC_DRIVER_NAME);
/* Enable receive interrupts */
// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
// Turn on the interrupts in ali_ircc_net_open
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__);
return 0;
}
int dongle_id, reg;
int cfg_base = info->cfg_base;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
/* Enter Configuration */
outb(chips[i].entr1, cfg_base);
outb(0xf0, cfg_base);
reg = inb(cfg_base+1);
dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01);
- IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __func__,
- dongle_id, dongle_types[dongle_id]);
+ pr_debug("%s(), probing dongle_id=%d, dongle_types=%s\n",
+ __func__, dongle_id, dongle_types[dongle_id]);
/* Exit configuration */
outb(0xbb, cfg_base);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__);
return dongle_id;
}
struct ali_ircc_cb *self;
int ret;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
self = netdev_priv(dev);
spin_unlock(&self->lock);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__);
return ret;
}
/*
__u8 eir, OldMessageCount;
int iobase, tmp;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__);
iobase = self->io.fir_base;
//self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM
eir = self->InterruptID & self->ier; /* Mask out the interesting ones */
- IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __func__,self->InterruptID);
- IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __func__,self->LineStatus);
- IRDA_DEBUG(1, "%s(), self->ier = %x\n", __func__,self->ier);
- IRDA_DEBUG(1, "%s(), eir = %x\n", __func__,eir);
+ pr_debug("%s(), self->InterruptID = %x\n", __func__, self->InterruptID);
+ pr_debug("%s(), self->LineStatus = %x\n", __func__, self->LineStatus);
+ pr_debug("%s(), self->ier = %x\n", __func__, self->ier);
+ pr_debug("%s(), eir = %x\n", __func__, eir);
/* Disable interrupts */
SetCOMInterrupts(self, FALSE);
{
if (self->io.direction == IO_XMIT) /* TX */
{
- IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __func__);
+ pr_debug("%s(), ******* IIR_EOM (Tx) *******\n",
+ __func__);
if(ali_ircc_dma_xmit_complete(self))
{
}
else /* RX */
{
- IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __func__);
+ pr_debug("%s(), ******* IIR_EOM (Rx) *******\n",
+ __func__);
if(OldMessageCount > ((self->LineStatus+1) & 0x07))
{
self->rcvFramesOverflow = TRUE;
- IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ********\n", __func__);
+ pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE ********\n",
+ __func__);
}
if (ali_ircc_dma_receive_complete(self))
{
- IRDA_DEBUG(1, "%s(), ******* receive complete ********\n", __func__);
+ pr_debug("%s(), ******* receive complete ********\n",
+ __func__);
self->ier = IER_EOM;
}
else
{
- IRDA_DEBUG(1, "%s(), ******* Not receive complete ********\n", __func__);
+ pr_debug("%s(), ******* Not receive complete ********\n",
+ __func__);
self->ier = IER_EOM | IER_TIMER;
}
if(OldMessageCount > ((self->LineStatus+1) & 0x07))
{
self->rcvFramesOverflow = TRUE;
- IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE *******\n", __func__);
+ pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE *******\n",
+ __func__);
}
/* Disable Timer */
switch_bank(iobase, BANK1);
/* Restore Interrupt */
SetCOMInterrupts(self, TRUE);
- IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __func__);
return IRQ_RETVAL(eir);
}
int iobase;
int iir, lsr;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
iobase = self->io.sir_base;
/* Clear interrupt */
lsr = inb(iobase+UART_LSR);
- IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __func__,
- iir, lsr, iobase);
+ pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ __func__, iir, lsr, iobase);
switch (iir)
{
case UART_IIR_RLSI:
- IRDA_DEBUG(2, "%s(), RLSI\n", __func__);
+ pr_debug("%s(), RLSI\n", __func__);
break;
case UART_IIR_RDI:
/* Receive interrupt */
}
break;
default:
- IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __func__, iir);
+ pr_debug("%s(), unhandled IIR=%#x\n",
+ __func__, iir);
break;
}
}
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__);
-
return IRQ_RETVAL(iir);
}
int boguscount = 0;
int iobase;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__);
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
/* Make sure we don't stay here too long */
if (boguscount++ > 32) {
- IRDA_DEBUG(2,"%s(), breaking!\n", __func__);
+ pr_debug("%s(), breaking!\n", __func__);
break;
}
} while (inb(iobase+UART_LSR) & UART_LSR_DR);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
}
/*
IRDA_ASSERT(self != NULL, return;);
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
iobase = self->io.sir_base;
{
/* We must wait until all data are gone */
while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT))
- IRDA_DEBUG(1, "%s(), UART_LSR_THRE\n", __func__ );
+ pr_debug("%s(), UART_LSR_THRE\n", __func__);
- IRDA_DEBUG(1, "%s(), Changing speed! self->new_speed = %d\n", __func__ , self->new_speed);
+ pr_debug("%s(), Changing speed! self->new_speed = %d\n",
+ __func__, self->new_speed);
ali_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
// benjamin 2000/11/10 06:32PM
if (self->io.speed > 115200)
{
- IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT\n", __func__ );
+ pr_debug("%s(), ali_ircc_change_speed from UART_LSR_TEMT\n",
+ __func__);
self->ier = IER_EOM;
// SetCOMInterrupts(self, TRUE);
outb(UART_IER_RDI, iobase+UART_IER);
}
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
}
static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
struct net_device *dev = self->netdev;
int iobase;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
- IRDA_DEBUG(2, "%s(), setting speed = %d\n", __func__ , baud);
+ pr_debug("%s(), setting speed = %d\n", __func__, baud);
/* This function *must* be called with irq off and spin-lock.
* - Jean II */
netif_wake_queue(self->netdev);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
}
static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
struct ali_ircc_cb *self = priv;
struct net_device *dev;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
iobase = self->io.fir_base;
- IRDA_DEBUG(1, "%s(), self->io.speed = %d, change to speed = %d\n", __func__ ,self->io.speed,baud);
+ pr_debug("%s(), self->io.speed = %d, change to speed = %d\n",
+ __func__, self->io.speed, baud);
/* Come from SIR speed */
if(self->io.speed <=115200)
// Set Dongle Speed mode
ali_ircc_change_dongle_speed(self, baud);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
/*
int lcr; /* Line control reg */
int divisor;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
- IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __func__ , speed);
+ pr_debug("%s(), Setting speed to: %d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return;);
spin_unlock_irqrestore(&self->lock, flags);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
int iobase,dongle_id;
int tmp = 0;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */
dongle_id = self->io.dongle_id;
/* We are already locked, no need to do it again */
- IRDA_DEBUG(1, "%s(), Set Speed for %s , Speed = %d\n", __func__ , dongle_types[dongle_id], speed);
+ pr_debug("%s(), Set Speed for %s , Speed = %d\n",
+ __func__, dongle_types[dongle_id], speed);
switch_bank(iobase, BANK2);
tmp = inb(iobase+FIR_IRDA_CR);
switch_bank(iobase, BANK0);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
/*
{
int actual = 0;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __func__ );
+ pr_debug("%s(), failed, fifo not empty!\n", __func__);
return 0;
}
actual++;
}
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return actual;
}
int iobase;
char hwname[32];
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
IRDA_ASSERT(dev != NULL, return -1;);
/* Request IRQ and install Interrupt Handler */
if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev))
{
- IRDA_WARNING("%s, unable to allocate irq=%d\n",
- ALI_IRCC_DRIVER_NAME,
- self->io.irq);
+ net_warn_ratelimited("%s, unable to allocate irq=%d\n",
+ ALI_IRCC_DRIVER_NAME, self->io.irq);
return -EAGAIN;
}
* failure.
*/
if (request_dma(self->io.dma, dev->name)) {
- IRDA_WARNING("%s, unable to allocate dma=%d\n",
- ALI_IRCC_DRIVER_NAME,
- self->io.dma);
+ net_warn_ratelimited("%s, unable to allocate dma=%d\n",
+ ALI_IRCC_DRIVER_NAME, self->io.dma);
free_irq(self->io.irq, dev);
return -EAGAIN;
}
*/
self->irlap = irlap_open(dev, &self->qos, hwname);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return 0;
}
struct ali_ircc_cb *self;
//int iobase;
- IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __func__ );
IRDA_ASSERT(dev != NULL, return -1;);
free_irq(self->io.irq, dev);
free_dma(self->io.dma);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return 0;
}
__u32 speed;
int mtt, diff;
- IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
self = netdev_priv(dev);
iobase = self->io.fir_base;
diff = self->now.tv_usec - self->stamp.tv_usec;
/* self->stamp is set from ali_ircc_dma_receive_complete() */
- IRDA_DEBUG(1, "%s(), ******* diff = %d *******\n", __func__ , diff);
+ pr_debug("%s(), ******* diff = %d *******\n",
+ __func__, diff);
if (diff < 0)
diff += 1000000;
/* Adjust for timer resolution */
mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */
- IRDA_DEBUG(1, "%s(), ************** mtt = %d ***********\n", __func__ , mtt);
+ pr_debug("%s(), ************** mtt = %d ***********\n",
+ __func__, mtt);
/* Setup timer */
if (mtt == 1) /* 500 us */
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
return NETDEV_TX_OK;
}
unsigned char FIFO_OPTI, Hi, Lo;
- IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
iobase = self->io.fir_base;
tmp = inb(iobase+FIR_LCR_B);
tmp &= ~0x20; // Disable SIP
outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B);
- IRDA_DEBUG(1, "%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n", __func__ , inb(iobase+FIR_LCR_B));
+ pr_debug("%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n",
+ __func__, inb(iobase + FIR_LCR_B));
outb(0, iobase+FIR_LSR);
switch_bank(iobase, BANK0);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self)
int iobase;
int ret = TRUE;
- IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
iobase = self->io.fir_base;
if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
{
- IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __func__);
+ net_err_ratelimited("%s(), ********* LSR_FRAME_ABORT *********\n",
+ __func__);
self->netdev->stats.tx_errors++;
self->netdev->stats.tx_fifo_errors++;
}
switch_bank(iobase, BANK0);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
return ret;
}
{
int iobase, tmp;
- IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
iobase = self->io.fir_base;
//switch_bank(iobase, BANK0);
tmp = inb(iobase+FIR_LCR_B);
outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM
- IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n", __func__ , inb(iobase+FIR_LCR_B));
+ pr_debug("%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n",
+ __func__, inb(iobase + FIR_LCR_B));
/* Set Rx Threshold */
switch_bank(iobase, BANK1);
outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
switch_bank(iobase, BANK0);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
return 0;
}
__u8 status, MessageCount;
int len, i, iobase, val;
- IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ );
-
st_fifo = &self->st_fifo;
iobase = self->io.fir_base;
MessageCount = inb(iobase+ FIR_LSR)&0x07;
if (MessageCount > 0)
- IRDA_DEBUG(0, "%s(), Message count = %d,\n", __func__ , MessageCount);
+ pr_debug("%s(), Message count = %d\n", __func__, MessageCount);
for (i=0; i<=MessageCount; i++)
{
len = len << 8;
len |= inb(iobase+FIR_RX_DSR_LO);
- IRDA_DEBUG(1, "%s(), RX Length = 0x%.2x,\n", __func__ , len);
- IRDA_DEBUG(1, "%s(), RX Status = 0x%.2x,\n", __func__ , status);
+ pr_debug("%s(), RX Length = 0x%.2x,\n", __func__ , len);
+ pr_debug("%s(), RX Status = 0x%.2x,\n", __func__ , status);
if (st_fifo->tail >= MAX_RX_WINDOW) {
- IRDA_DEBUG(0, "%s(), window is full!\n", __func__ );
+ pr_debug("%s(), window is full!\n", __func__);
continue;
}
/* Check for errors */
if ((status & 0xd8) || self->rcvFramesOverflow || (len==0))
{
- IRDA_DEBUG(0,"%s(), ************* RX Errors ************\n", __func__ );
+ pr_debug("%s(), ************* RX Errors ************\n",
+ __func__);
/* Skip frame */
self->netdev->stats.rx_errors++;
if (status & LSR_FIFO_UR)
{
self->netdev->stats.rx_frame_errors++;
- IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************\n", __func__ );
+ pr_debug("%s(), ************* FIFO Errors ************\n",
+ __func__);
}
if (status & LSR_FRAME_ERROR)
{
self->netdev->stats.rx_frame_errors++;
- IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************\n", __func__ );
+ pr_debug("%s(), ************* FRAME Errors ************\n",
+ __func__);
}
if (status & LSR_CRC_ERROR)
{
self->netdev->stats.rx_crc_errors++;
- IRDA_DEBUG(0,"%s(), ************* CRC Errors ************\n", __func__ );
+ pr_debug("%s(), ************* CRC Errors ************\n",
+ __func__);
}
if(self->rcvFramesOverflow)
{
self->netdev->stats.rx_frame_errors++;
- IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************\n", __func__ );
+ pr_debug("%s(), ************* Overran DMA buffer ************\n",
+ __func__);
}
if(len == 0)
{
self->netdev->stats.rx_frame_errors++;
- IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 *********\n", __func__ );
+ pr_debug("%s(), ********** Receive Frame Size = 0 *********\n",
+ __func__);
}
}
else
val = inb(iobase+FIR_BSR);
if ((val& BSR_FIFO_NOT_EMPTY)== 0x80)
{
- IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************\n", __func__ );
+ pr_debug("%s(), ************* BSR_FIFO_NOT_EMPTY ************\n",
+ __func__);
/* Put this entry back in fifo */
st_fifo->head--;
skb = dev_alloc_skb(len+1);
if (skb == NULL)
{
- IRDA_WARNING("%s(), memory squeeze, "
- "dropping frame.\n",
- __func__);
self->netdev->stats.rx_dropped++;
return FALSE;
switch_bank(iobase, BANK0);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
return TRUE;
}
int iobase;
__u32 speed;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
dev_kfree_skb(skb);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return NETDEV_TX_OK;
}
unsigned long flags;
int ret = 0;
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
IRDA_ASSERT(dev != NULL, return -1;);
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
- IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __func__ );
+ pr_debug("%s(), SIOCSBANDWIDTH\n", __func__);
/*
* This function will also be used by IrLAP to change the
* speed, so we still must allow for speed change within
spin_unlock_irqrestore(&self->lock, flags);
break;
case SIOCSMEDIABUSY: /* Set media busy */
- IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __func__ );
+ pr_debug("%s(), SIOCSMEDIABUSY\n", __func__);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
- IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __func__ );
+ pr_debug("%s(), SIOCGRECEIVING\n", __func__);
/* This is protected */
irq->ifr_receiving = ali_ircc_is_receiving(self);
break;
ret = -EOPNOTSUPP;
}
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return ret;
}
int status = FALSE;
int iobase;
- IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __func__ );
IRDA_ASSERT(self != NULL, return FALSE;);
if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0)
{
/* We are receiving something */
- IRDA_DEBUG(1, "%s(), We are receiving something\n", __func__ );
+ pr_debug("%s(), We are receiving something\n",
+ __func__);
status = TRUE;
}
switch_bank(iobase, BANK0);
spin_unlock_irqrestore(&self->lock, flags);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
return status;
}
{
struct ali_ircc_cb *self = platform_get_drvdata(dev);
- IRDA_MESSAGE("%s, Suspending\n", ALI_IRCC_DRIVER_NAME);
+ net_info_ratelimited("%s, Suspending\n", ALI_IRCC_DRIVER_NAME);
if (self->io.suspended)
return 0;
ali_ircc_net_open(self->netdev);
- IRDA_MESSAGE("%s, Waking up\n", ALI_IRCC_DRIVER_NAME);
+ net_info_ratelimited("%s, Waking up\n", ALI_IRCC_DRIVER_NAME);
self->io.suspended = 0;
int iobase = self->io.fir_base; /* or sir_base */
- IRDA_DEBUG(2, "%s(), -------- Start -------- ( Enable = %d )\n", __func__ , enable);
+ pr_debug("%s(), -------- Start -------- ( Enable = %d )\n",
+ __func__, enable);
/* Enable the interrupt which we wish to */
if (enable){
else
outb(newMask, iobase+UART_IER);
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
}
static void SIR2FIR(int iobase)
{
//unsigned char tmp;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
/* Already protected (change_speed() or setup()), no need to lock.
* Jean II */
//tmp |= 0x20;
//outb(tmp, iobase+FIR_LCR_B);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
static void FIR2SIR(int iobase)
{
unsigned char val;
- IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
/* Already protected (change_speed() or setup()), no need to lock.
* Jean II */
val = inb(iobase+UART_LSR);
val = inb(iobase+UART_MSR);
- IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
}
MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>");
for (i=0;i<len;i+=16) {
for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); }
dump [3*j]=0;
- IRDA_DEBUG (2, "%c%s\n",head , dump);
+ pr_debug("%c%s\n", head, dump);
head='+';
}
}
{
__u32 ringbase;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
ringbase = INB (OBOE_RING_BASE0) << 10;
ringbase |= INB (OBOE_RING_BASE1) << 18;
ringbase |= INB (OBOE_RING_BASE2) << 26;
toshoboe_disablebm (struct toshoboe_cb *self)
{
__u8 command;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
command &= ~PCI_COMMAND_MASTER;
pci_write_config_byte (self->pdev, PCI_COMMAND, command);
static void
toshoboe_stopchip (struct toshoboe_cb *self)
{
- IRDA_DEBUG (4, "%s()\n", __func__);
-
/*Disable interrupts */
OUTB (0x0, OBOE_IER);
/*Disable DMA, Disable Rx, Disable Tx */
__u16 pconfig = 0;
__u8 config0l = 0;
- IRDA_DEBUG (2, "%s(%d/%d)\n", __func__, self->speed, self->io.speed);
+ pr_debug("%s(%d/%d)\n", __func__, self->speed, self->io.speed);
switch (self->speed)
{
static void
toshoboe_enablebm (struct toshoboe_cb *self)
{
- IRDA_DEBUG (4, "%s()\n", __func__);
pci_set_master (self->pdev);
}
{
int i;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
for (i = 0; i < TX_SLOTS; ++i)
{
self->ring->tx[i].len = 0;
{
__u32 physaddr;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
toshoboe_initring (self);
toshoboe_enablebm (self);
OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1);
xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/
xbofs++;
- IRDA_DEBUG (2, DRIVER_NAME
- ": generated mtt of %d bytes for %d us at %d baud\n"
- , xbofs,mtt,self->speed);
+ pr_debug(DRIVER_NAME ": generated mtt of %d bytes for %d us at %d baud\n",
+ xbofs, mtt, self->speed);
if (xbofs > TX_LEN)
{
#endif
unsigned long flags;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
if (request_irq (self->io.irq, toshoboe_probeinterrupt,
self->io.irqflags, "toshoboe", (void *) self))
{
IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
- IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__
- ,skb->len,self->txpending,INB (OBOE_ENABLEH));
+ pr_debug("%s.tx:%x(%x)%x\n",
+ __func__, skb->len, self->txpending, INB(OBOE_ENABLEH));
if (!cb->magic) {
- IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __func__, cb->magic);
+ pr_debug("%s.Not IrLAP:%x\n", __func__, cb->magic);
#ifdef DUMP_PACKETS
_dumpbufs(skb->data,skb->len,'>');
#endif
if (self->txpending || skb->len)
{
self->new_speed = speed;
- IRDA_DEBUG (1, "%s: Queued TxDone scheduled speed change %d\n" ,
- __func__, speed);
+ pr_debug("%s: Queued TxDone scheduled speed change %d\n" ,
+ __func__, speed);
/* if no data, that's all! */
if (!skb->len)
{
/* which we will add a wrong checksum to */
mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt);
- IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __func__
- ,skb->len,mtt,self->txpending);
+ pr_debug("%s.mtt:%x(%x)%d\n", __func__, skb->len, mtt, self->txpending);
if (mtt)
{
self->ring->tx[self->txs].len = mtt & 0xfff;
if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS)
{
- IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __func__
- ,skb->len, self->ring->tx[self->txs].control, self->txpending);
+ pr_debug("%s.ful:%x(%x)%x\n",
+ __func__, skb->len, self->ring->tx[self->txs].control,
+ self->txpending);
toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
spin_unlock_irqrestore(&self->spinlock, flags);
return NETDEV_TX_BUSY;
if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS)
self->txpending++;
}
- IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __func__
- ,irqstat,txp,self->txpending);
+ pr_debug("%s.txd(%x)%x/%x\n", __func__, irqstat, txp, self->txpending);
txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
if ((!self->txpending) && (self->new_speed))
{
self->speed = self->new_speed;
- IRDA_DEBUG (1, "%s: Executed TxDone scheduled speed change %d\n",
- __func__, self->speed);
+ pr_debug("%s: Executed TxDone scheduled speed change %d\n",
+ __func__, self->speed);
toshoboe_setbaud (self);
}
{
int len = self->ring->rx[self->rxs].len;
skb = NULL;
- IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __func__
- ,len,self->ring->rx[self->rxs].control);
+ pr_debug("%s.rcv:%x(%x)\n", __func__
+ , len, self->ring->rx[self->rxs].control);
#ifdef DUMP_PACKETS
dumpbufs(self->rx_bufs[self->rxs],len,'<');
len -= 2;
else
len = 0;
- IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __func__, len,enable);
+ pr_debug("%s.SIR:%x(%x)\n", __func__, len, enable);
}
#ifdef USE_MIR
len -= 2;
else
len = 0;
- IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __func__, len,enable);
+ pr_debug("%s.MIR:%x(%x)\n", __func__, len, enable);
}
#endif
else if (enable & OBOE_ENABLEH_FIRON)
len -= 4; /*FIXME: check this */
else
len = 0;
- IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __func__, len,enable);
+ pr_debug("%s.FIR:%x(%x)\n", __func__, len, enable);
}
else
- IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __func__, len,enable);
+ pr_debug("%s.?IR:%x(%x)\n", __func__, len, enable);
if (len)
{
/* (SIR) data is splitted in several slots. */
/* we have to join all the received buffers received */
/*in a large buffer before checking CRC. */
- IRDA_DEBUG (0, "%s.err:%x(%x)\n", __func__
- ,len,self->ring->rx[self->rxs].control);
+ pr_debug("%s.err:%x(%x)\n", __func__
+ , len, self->ring->rx[self->rxs].control);
}
self->ring->rx[self->rxs].len = 0x0;
if (irqstat & OBOE_INT_SIP)
{
self->int_sip++;
- IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __func__
- ,self->int_sip,irqstat,self->txpending);
+ pr_debug("%s.sip:%x(%x)%x\n",
+ __func__, self->int_sip, irqstat, self->txpending);
}
return IRQ_HANDLED;
}
unsigned long flags;
int rc;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
self = netdev_priv(dev);
if (self->async)
{
struct toshoboe_cb *self;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
IRDA_ASSERT (dev != NULL, return -1; );
self = netdev_priv(dev);
IRDA_ASSERT (self != NULL, return -1; );
- IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
/* Disable interrupts & save flags */
spin_lock_irqsave(&self->spinlock, flags);
* speed, so we still must allow for speed change within
* interrupt context.
*/
- IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __func__
- ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
+ pr_debug("%s(BANDWIDTH), %s, (%X/%ld\n",
+ __func__, dev->name, INB(OBOE_STATUS), irq->ifr_baudrate);
if (!in_interrupt () && !capable (CAP_NET_ADMIN)) {
ret = -EPERM;
goto out;
self->new_speed = irq->ifr_baudrate;
break;
case SIOCSMEDIABUSY: /* Set media busy */
- IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __func__
- ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
+ pr_debug("%s(MEDIABUSY), %s, (%X/%x)\n",
+ __func__, dev->name,
+ INB(OBOE_STATUS), capable(CAP_NET_ADMIN));
if (!capable (CAP_NET_ADMIN)) {
ret = -EPERM;
goto out;
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0;
- IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __func__
- ,dev->name, INB (OBOE_STATUS), irq->ifr_receiving );
+ pr_debug("%s(RECEIVING), %s, (%X/%x)\n",
+ __func__, dev->name, INB(OBOE_STATUS), irq->ifr_receiving);
break;
default:
- IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
+ pr_debug("%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
ret = -EOPNOTSUPP;
}
out:
int i;
struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
- IRDA_DEBUG (4, "%s()\n", __func__);
-
IRDA_ASSERT (self != NULL, return; );
if (!self->stopped)
int ok = 0;
int err;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
if ((err=pci_enable_device(pci_dev)))
return err;
unsigned long flags;
int i = 10;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
if (!self || self->stopped)
return 0;
struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
unsigned long flags;
- IRDA_DEBUG (4, "%s()\n", __func__);
-
if (!self || !self->stopped)
return 0;
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power on dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
static int girbil_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
u8 control[2];
static int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* dongle alread reset - port and dongle at default speed */
switch(state) {
break;
default:
- IRDA_ERROR("%s - undefined state %d\n", __func__, state);
+ net_err_ratelimited("%s - undefined state %d\n",
+ __func__, state);
ret = -EINVAL;
break;
}
u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
/* Reset dongle */
break;
default:
- IRDA_ERROR("%s(), undefined state %d\n", __func__, state);
+ net_err_ratelimited("%s(), undefined state %d\n",
+ __func__, state);
ret = -1;
break;
}
(!force) && (self->speed != -1)) {
/* No speed and xbofs change here
* (we'll do it later in the write callback) */
- IRDA_DEBUG(2, "%s(), not changing speed yet\n", __func__);
+ pr_debug("%s(), not changing speed yet\n", __func__);
*header = 0;
return;
}
- IRDA_DEBUG(2, "%s(), changing speed to %d\n", __func__, self->new_speed);
+ pr_debug("%s(), changing speed to %d\n",
+ __func__, self->new_speed);
self->speed = self->new_speed;
/* We will do ` self->new_speed = -1; ' in the completion
* handler just in case the current URB fail - Jean II */
/* Set the negotiated additional XBOFS */
if (self->new_xbofs != -1) {
- IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __func__, self->new_xbofs);
+ pr_debug("%s(), changing xbofs to %d\n",
+ __func__, self->new_xbofs);
self->xbofs = self->new_xbofs;
/* We will do ` self->new_xbofs = -1; ' in the completion
* handler just in case the current URB fail - Jean II */
struct urb *urb;
int ret;
- IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n", __func__,
- self->new_speed, self->new_xbofs);
+ pr_debug("%s(), speed=%d, xbofs=%d\n", __func__,
+ self->new_speed, self->new_xbofs);
/* Grab the speed URB */
urb = self->speed_urb;
if (urb->status != 0) {
- IRDA_WARNING("%s(), URB still in use!\n", __func__);
+ net_warn_ratelimited("%s(), URB still in use!\n", __func__);
return;
}
/* Irq disabled -> GFP_ATOMIC */
if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
- IRDA_WARNING("%s(), failed Speed URB\n", __func__);
+ net_warn_ratelimited("%s(), failed Speed URB\n", __func__);
}
}
{
struct irda_usb_cb *self = urb->context;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* We should always have a context */
IRDA_ASSERT(self != NULL, return;);
/* We should always be called for the speed URB */
/* Check for timeout and other USB nasties */
if (urb->status != 0) {
/* I get a lot of -ECONNABORTED = -103 here - Jean II */
- IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags);
+ pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n",
+ __func__, urb->status, urb->transfer_flags);
/* Don't do anything here, that might confuse the USB layer.
* Instead, we will wait for irda_usb_net_timeout(), the
s16 xbofs;
int res, mtt;
- IRDA_DEBUG(4, "%s() on %s\n", __func__, netdev->name);
+ pr_debug("%s() on %s\n", __func__, netdev->name);
netif_stop_queue(netdev);
* We need to check self->present under the spinlock because
* of irda_usb_disconnect() is synchronous - Jean II */
if (!self->present) {
- IRDA_DEBUG(0, "%s(), Device is gone...\n", __func__);
+ pr_debug("%s(), Device is gone...\n", __func__);
goto drop;
}
}
if (urb->status != 0) {
- IRDA_WARNING("%s(), URB still in use!\n", __func__);
+ net_warn_ratelimited("%s(), URB still in use!\n", __func__);
goto drop;
}
/* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */
if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {
- IRDA_WARNING("%s(), failed Tx URB\n", __func__);
+ net_warn_ratelimited("%s(), failed Tx URB\n", __func__);
netdev->stats.tx_errors++;
/* Let USB recover : We will catch that in the watchdog */
/*netif_start_queue(netdev);*/
struct sk_buff *skb = urb->context;
struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* We should always have a context */
IRDA_ASSERT(self != NULL, return;);
/* We should always be called for the speed URB */
/* Check for timeout and other USB nasties */
if (urb->status != 0) {
/* I get a lot of -ECONNABORTED = -103 here - Jean II */
- IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags);
+ pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n",
+ __func__, urb->status, urb->transfer_flags);
/* Don't do anything here, that might confuse the USB layer,
* and we could go in recursion and blow the kernel stack...
/* If the network is closed, stop everything */
if ((!self->netopen) || (!self->present)) {
- IRDA_DEBUG(0, "%s(), Network is gone...\n", __func__);
+ pr_debug("%s(), Network is gone...\n", __func__);
spin_unlock_irqrestore(&self->lock, flags);
return;
}
(self->new_xbofs != self->xbofs)) {
/* We haven't changed speed yet (because of
* IUC_SPEED_BUG), so do it now - Jean II */
- IRDA_DEBUG(1, "%s(), Changing speed now...\n", __func__);
+ pr_debug("%s(), Changing speed now...\n", __func__);
irda_usb_change_speed_xbofs(self);
} else {
/* New speed and xbof is now committed in hardware */
struct urb *urb;
int done = 0; /* If we have made any progress */
- IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __func__);
+ pr_debug("%s(), Network layer thinks we timed out!\n", __func__);
IRDA_ASSERT(self != NULL, return;);
/* Protect us from USB callbacks, net Tx and else. */
/* self->present *MUST* be read under spinlock */
if (!self->present) {
- IRDA_WARNING("%s(), device not present!\n", __func__);
+ net_warn_ratelimited("%s(), device not present!\n", __func__);
netif_stop_queue(netdev);
spin_unlock_irqrestore(&self->lock, flags);
return;
/* Check speed URB */
urb = self->speed_urb;
if (urb->status != 0) {
- IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
+ pr_debug("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n",
+ netdev->name, urb->status, urb->transfer_flags);
switch (urb->status) {
case -EINPROGRESS:
if (urb->status != 0) {
struct sk_buff *skb = urb->context;
- IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
+ pr_debug("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n",
+ netdev->name, urb->status, urb->transfer_flags);
/* Increase error count */
netdev->stats.tx_errors++;
struct irda_skb_cb *cb;
int ret;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* This should never happen */
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(urb != NULL, return;);
if (ret) {
/* If this ever happen, we are in deep s***.
* Basically, the Rx path will stop... */
- IRDA_WARNING("%s(), Failed to submit Rx URB %d\n",
- __func__, ret);
+ net_warn_ratelimited("%s(), Failed to submit Rx URB %d\n",
+ __func__, ret);
}
}
struct urb *next_urb;
unsigned int len, docopy;
- IRDA_DEBUG(2, "%s(), len=%d\n", __func__, urb->actual_length);
+ pr_debug("%s(), len=%d\n", __func__, urb->actual_length);
/* Find ourselves */
cb = (struct irda_skb_cb *) skb->cb;
/* If the network is closed or the device gone, stop everything */
if ((!self->netopen) || (!self->present)) {
- IRDA_DEBUG(0, "%s(), Network is gone!\n", __func__);
+ pr_debug("%s(), Network is gone!\n", __func__);
/* Don't re-submit the URB : will stall the Rx path */
return;
}
/* Usually precursor to a hot-unplug on OHCI. */
default:
self->netdev->stats.rx_errors++;
- IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags);
+ pr_debug("%s(), RX status %d, transfer_flags 0x%04X\n",
+ __func__, urb->status, urb->transfer_flags);
break;
}
/* If we received an error, we don't want to resubmit the
/* Check for empty frames */
if (urb->actual_length <= self->header_length) {
- IRDA_WARNING("%s(), empty frame!\n", __func__);
+ net_warn_ratelimited("%s(), empty frame!\n", __func__);
goto done;
}
struct irda_skb_cb *cb;
struct urb *next_urb;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Find ourselves */
cb = (struct irda_skb_cb *) skb->cb;
IRDA_ASSERT(cb != NULL, return;);
self->bulk_out_ep),
patch_block, block_size,
&actual_len, msecs_to_jiffies(500));
- IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n",
- __func__, actual_len, ret);
+ pr_debug("%s(): Bulk send %u bytes, ret=%d\n",
+ __func__, actual_len, ret);
if (ret < 0)
break;
return ret;
/* We get a patch from userspace */
- IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",
- __func__, stir421x_fw_name, fw->size);
+ net_info_ratelimited("%s(): Received firmware %s (%zu bytes)\n",
+ __func__, stir421x_fw_name, fw->size);
ret = -EINVAL;
+ ((build / 10) << 4)
+ (build % 10);
- IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n",
- __func__, fw_version);
+ pr_debug("%s(): Firmware Product version %ld\n",
+ __func__, fw_version);
}
}
char hwname[16];
int i;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(netdev != NULL, return -1;);
self = netdev_priv(netdev);
IRDA_ASSERT(self != NULL, return -1;);
/* Can only open the device if it's there */
if(!self->present) {
spin_unlock_irqrestore(&self->lock, flags);
- IRDA_WARNING("%s(), device not present!\n", __func__);
+ net_warn_ratelimited("%s(), device not present!\n", __func__);
return -1;
}
if(self->needspatch) {
spin_unlock_irqrestore(&self->lock, flags);
- IRDA_WARNING("%s(), device needs patch\n", __func__) ;
+ net_warn_ratelimited("%s(), device needs patch\n", __func__);
return -EIO ;
}
if (!skb) {
/* If this ever happen, we are in deep s***.
* Basically, we can't start the Rx path... */
- IRDA_WARNING("%s(), Failed to allocate Rx skb\n",
- __func__);
return -1;
}
//skb_reserve(newskb, USB_IRDA_HEADER - 1);
struct irda_usb_cb *self;
int i;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(netdev != NULL, return -1;);
self = netdev_priv(netdev);
IRDA_ASSERT(self != NULL, return -1;);
self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
{
struct irda_class_desc *desc;
- IRDA_DEBUG(3, "%s()\n", __func__);
desc = self->irda_desc;
self->qos.window_size.bits = desc->bmWindowSize;
self->qos.data_size.bits = desc->bmDataSize;
- IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n",
- __func__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+ pr_debug("%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n",
+ __func__, self->qos.baud_rate.bits, self->qos.data_size.bits,
+ self->qos.window_size.bits, self->qos.additional_bofs.bits,
+ self->qos.min_turn_time.bits);
/* Don't always trust what the dongle tell us */
if(self->capability & IUC_SIR_ONLY)
{
struct net_device *netdev = self->netdev;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
netdev->netdev_ops = &irda_usb_netdev_ops;
irda_usb_init_qos(self);
*/
static inline void irda_usb_close(struct irda_usb_cb *self)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
-
/* Remove netdevice */
unregister_netdev(self->netdev);
/* This is our interrupt endpoint */
self->bulk_int_ep = ep;
} else {
- IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __func__, ep);
+ net_err_ratelimited("%s(), Unrecognised endpoint %02X\n",
+ __func__, ep);
}
}
}
- IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
- __func__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
+ pr_debug("%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
+ __func__, self->bulk_in_ep, self->bulk_out_ep,
+ self->bulk_out_mtu, self->bulk_int_ep);
return (self->bulk_in_ep != 0) && (self->bulk_out_ep != 0);
}
0, intf->altsetting->desc.bInterfaceNumber, desc,
sizeof(*desc), 500);
- IRDA_DEBUG(1, "%s(), ret=%d\n", __func__, ret);
+ pr_debug("%s(), ret=%d\n", __func__, ret);
if (ret < sizeof(*desc)) {
- IRDA_WARNING("usb-irda: class_descriptor read %s (%d)\n",
- (ret<0) ? "failed" : "too short", ret);
+ net_warn_ratelimited("usb-irda: class_descriptor read %s (%d)\n",
+ ret < 0 ? "failed" : "too short", ret);
}
else if (desc->bDescriptorType != USB_DT_IRDA) {
- IRDA_WARNING("usb-irda: bad class_descriptor type\n");
+ net_warn_ratelimited("usb-irda: bad class_descriptor type\n");
}
else {
#ifdef IU_DUMP_CLASS_DESC
* don't need to check if the dongle is really ours.
* Jean II */
- IRDA_MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
+ net_info_ratelimited("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
net = alloc_irdadev(sizeof(*self));
if (!net)
* specify an alternate, but very few driver do like this.
* Jean II */
ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0);
- IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->desc.bInterfaceNumber, ret);
+ pr_debug("usb-irda: set interface %d result %d\n",
+ intf->altsetting->desc.bInterfaceNumber, ret);
switch (ret) {
case 0:
break;
/* Martin Diehl says if we get a -EPIPE we should
* be fine and we don't need to do a usb_clear_halt().
* - Jean II */
- IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __func__);
+ pr_debug("%s(), Received -EPIPE, ignoring...\n",
+ __func__);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown error %d\n", __func__, ret);
+ pr_debug("%s(), Unknown error %d\n", __func__, ret);
ret = -EIO;
goto err_out_3;
}
interface = intf->cur_altsetting;
if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->desc.bNumEndpoints)) {
- IRDA_ERROR("%s(), Bogus endpoints...\n", __func__);
+ net_err_ratelimited("%s(), Bogus endpoints...\n", __func__);
ret = -EIO;
goto err_out_3;
}
ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),
0x02, 0x40, 0, 0, NULL, 0, 500);
if (ret < 0) {
- IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret);
+ pr_debug("usb_control_msg failed %d\n", ret);
goto err_out_3;
} else {
mdelay(10);
if (ret)
goto err_out_5;
- IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
+ net_info_ratelimited("IrDA: Registered device %s\n", net->name);
usb_set_intfdata(intf, self);
if (self->needspatch) {
ret = stir421x_patch_device(self);
self->needspatch = (ret < 0);
if (self->needspatch) {
- IRDA_ERROR("STIR421X: Couldn't upload patch\n");
+ net_err_ratelimited("STIR421X: Couldn't upload patch\n");
goto err_out_6;
}
struct irda_usb_cb *self = usb_get_intfdata(intf);
int i;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
usb_set_intfdata(intf, NULL);
if (!self)
return;
/* Free self and network device */
free_netdev(self->netdev);
- IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__);
+ pr_debug("%s(), USB IrDA Disconnected\n", __func__);
}
#ifdef CONFIG_PM
dev = priv->dev;
if (!dev) {
- IRDA_WARNING("%s(), not ready yet!\n", __func__);
+ net_warn_ratelimited("%s(), not ready yet!\n", __func__);
return;
}
* Characters received with a parity error, etc?
*/
if (fp && *fp++) {
- IRDA_DEBUG(0, "Framing or parity error!\n");
+ pr_debug("Framing or parity error!\n");
sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */
return;
}
IRDA_ASSERT(priv != NULL, return -ENODEV;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
- IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __func__, cmd);
+ pr_debug("%s(cmd=0x%X)\n", __func__, cmd);
dev = priv->dev;
IRDA_ASSERT(dev != NULL, return -1;);
mutex_unlock(&irtty_mutex);
- IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __func__, tty->name);
+ pr_debug("%s - %s: irda line discipline opened\n", __func__, tty->name);
return 0;
kfree(priv);
- IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __func__, tty->name);
+ pr_debug("%s - %s: irda line discipline closed\n", __func__, tty->name);
}
/* ------------------------------------------------------- */
int err;
if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)
- IRDA_ERROR("IrDA: can't register line discipline (err = %d)\n",
- err);
+ net_err_ratelimited("IrDA: can't register line discipline (err = %d)\n",
+ err);
return err;
}
int err;
if ((err = tty_unregister_ldisc(N_IRDA))) {
- IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n",
- __func__, err);
+ net_err_ratelimited("%s(), can't unregister line discipline (err = %d)\n",
+ __func__, err);
}
}
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power up dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
static int litelink_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
{
int i;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* dongle already reset by irda-thread - current speed (dongle and
* port) is the default speed (115200 for litelink!)
*/
*/
static int litelink_reset(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* probably the power-up can be dropped here, but with only
* 15 usec delay it's not worth the risk unless somebody with
* the hardware confirms it doesn't break anything...
static int __init ma600_sir_init(void)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
return irda_register_dongle(&ma600);
}
static void __exit ma600_sir_cleanup(void)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
irda_unregister_dongle(&ma600);
}
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Explicitly set the speeds we can accept */
static int ma600_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
{
u8 byte;
- IRDA_DEBUG(2, "%s(), speed=%d (was %d)\n", __func__,
- speed, dev->speed);
+ pr_debug("%s(), speed=%d (was %d)\n", __func__,
+ speed, dev->speed);
/* dongle already reset, dongle and port at default speed (9600) */
sirdev_raw_read(dev, &byte, sizeof(byte));
if (byte != get_control_byte(speed)) {
- IRDA_WARNING("%s(): bad control byte read-back %02x != %02x\n",
- __func__, (unsigned) byte,
- (unsigned) get_control_byte(speed));
+ net_warn_ratelimited("%s(): bad control byte read-back %02x != %02x\n",
+ __func__, (unsigned)byte,
+ (unsigned)get_control_byte(speed));
return -1;
}
else
- IRDA_DEBUG(2, "%s() control byte write read OK\n", __func__);
+ pr_debug("%s() control byte write read OK\n", __func__);
#endif
/* Set DTR, Set RTS */
static int ma600_reset(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Reset the dongle : set DTR low for 10 ms */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
msleep(10);
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* seems no explicit power-on required here and reset switching it on anyway */
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
static int mcp2120_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
/* reset and inhibit mcp2120 */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
u8 control[2];
static int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
switch (state) {
case SIRDEV_STATE_DONGLE_SPEED:
/* Set DTR to enter command mode */
break;
default:
- IRDA_ERROR("%s(), undefine state %d\n", __func__, state);
+ net_err_ratelimited("%s(), undefine state %d\n",
+ __func__, state);
ret = -EINVAL;
break;
}
unsigned delay = 0;
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
//printk("mcp2120_reset: dongle_reset\n");
break;
default:
- IRDA_ERROR("%s(), undefined state %d\n", __func__, state);
+ net_err_ratelimited("%s(), undefined state %d\n",
+ __func__, state);
ret = -EINVAL;
break;
}
/* Setup a communication between mcs7780 and agilent chip. */
static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs)
{
- IRDA_WARNING("This transceiver type is not supported yet.\n");
+ net_warn_ratelimited("This transceiver type is not supported yet\n");
return 1;
}
/* Setup a communication between mcs7780 and sharp chip. */
static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs)
{
- IRDA_WARNING("This transceiver type is not supported yet.\n");
+ net_warn_ratelimited("This transceiver type is not supported yet\n");
return 1;
}
{
int ret = 0;
__u16 rval;
- char *msg;
+ const char *msg;
- msg = "Basic transceiver setup error.";
+ msg = "Basic transceiver setup error";
/* read value of MODE Register, set the DRIVER and RESET bits
* and write value back out to MODE Register
if(unlikely(ret))
goto error;
- msg = "transceiver model specific setup error.";
+ msg = "transceiver model specific setup error";
switch (mcs->transceiver_type) {
case MCS_TSC_VISHAY:
ret = mcs_setup_transceiver_vishay(mcs);
break;
default:
- IRDA_WARNING("Unknown transceiver type: %d\n",
- mcs->transceiver_type);
+ net_warn_ratelimited("Unknown transceiver type: %d\n",
+ mcs->transceiver_type);
ret = 1;
}
if (unlikely(ret))
goto error;
}
- msg = "transceiver reset.";
+ msg = "transceiver reset";
ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
if (unlikely(ret != 2))
return ret;
error:
- IRDA_ERROR("%s\n", msg);
+ net_err_ratelimited("%s\n", msg);
return ret;
}
new_len = len - 2;
if(unlikely(new_len <= 0)) {
- IRDA_ERROR("%s short frame length %d\n",
- mcs->netdev->name, new_len);
+ net_err_ratelimited("%s short frame length %d\n",
+ mcs->netdev->name, new_len);
++mcs->netdev->stats.rx_errors;
++mcs->netdev->stats.rx_length_errors;
return;
fcs = irda_calc_crc16(~fcs, buf, len);
if(fcs != GOOD_FCS) {
- IRDA_ERROR("crc error calc 0x%x len %d\n",
- fcs, new_len);
+ net_err_ratelimited("crc error calc 0x%x len %d\n",
+ fcs, new_len);
mcs->netdev->stats.rx_errors++;
mcs->netdev->stats.rx_crc_errors++;
return;
new_len = len - 4;
if(unlikely(new_len <= 0)) {
- IRDA_ERROR("%s short frame length %d\n",
- mcs->netdev->name, new_len);
+ net_err_ratelimited("%s short frame length %d\n",
+ mcs->netdev->name, new_len);
++mcs->netdev->stats.rx_errors;
++mcs->netdev->stats.rx_length_errors;
return;
fcs = ~(crc32_le(~0, buf, new_len));
if(fcs != get_unaligned_le32(buf + new_len)) {
- IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
+ net_err_ratelimited("crc error calc 0x%x len %d\n",
+ fcs, new_len);
mcs->netdev->stats.rx_errors++;
mcs->netdev->stats.rx_crc_errors++;
return;
} while(cnt++ < 100 && (rval & MCS_IRINTX));
if (cnt > 100) {
- IRDA_ERROR("unable to change speed\n");
+ net_err_ratelimited("unable to change speed\n");
ret = -EIO;
goto error;
}
default:
ret = 1;
- IRDA_WARNING("Unknown transceiver type: %d\n",
- mcs->transceiver_type);
+ net_warn_ratelimited("Unknown transceiver type: %d\n",
+ mcs->transceiver_type);
}
if (unlikely(ret))
goto error;
sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
if (!mcs->irlap) {
- IRDA_ERROR("mcs7780: irlap_open failed\n");
+ net_err_ratelimited("mcs7780: irlap_open failed\n");
goto error2;
}
mcs->out_buf, wraplen, mcs_send_irq, mcs);
if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {
- IRDA_ERROR("failed tx_urb: %d\n", ret);
+ net_err_ratelimited("failed tx_urb: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
if (!ndev)
goto error1;
- IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
+ pr_debug("MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
SET_NETDEV_DEV(ndev, &intf->dev);
ret = usb_reset_configuration(udev);
if (ret != 0) {
- IRDA_ERROR("mcs7780: usb reset configuration failed\n");
+ net_err_ratelimited("mcs7780: usb reset configuration failed\n");
goto error2;
}
if (ret != 0)
goto error2;
- IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s\n",
- ndev->name);
+ pr_debug("IrDA: Registered MosChip MCS7780 device as %s\n",
+ ndev->name);
mcs->transceiver_type = transceiver_type;
mcs->sir_tweak = sir_tweak;
free_netdev(mcs->netdev);
usb_set_intfdata(intf, NULL);
- IRDA_DEBUG(0, "MCS7780 now disconnected.\n");
+ pr_debug("MCS7780 now disconnected.\n");
}
module_usb_driver(mcs_driver);
ret = platform_driver_register(&nsc_ircc_driver);
if (ret) {
- IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+ net_err_ratelimited("%s, Can't register driver!\n",
+ driver_name);
return ret;
}
/* Probe for all the NSC chipsets we know about */
for (chip = chips; chip->name ; chip++) {
- IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __func__,
- chip->name);
+ pr_debug("%s(), Probing for %s ...\n", __func__,
+ chip->name);
/* Try all config registers for this chip */
for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
/* Read index register */
reg = inb(cfg_base);
if (reg == 0xff) {
- IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __func__, cfg_base);
+ pr_debug("%s() no chip at 0x%03x\n",
+ __func__, cfg_base);
continue;
}
outb(chip->cid_index, cfg_base);
id = inb(cfg_base+1);
if ((id & chip->cid_mask) == chip->cid_value) {
- IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
- __func__, chip->name, id & ~chip->cid_mask);
+ pr_debug("%s() Found %s chip, revision=%d\n",
+ __func__, chip->name,
+ id & ~chip->cid_mask);
/*
* If we found a correct PnP setting,
info.irq = pnp_info.irq;
if (info.fir_base < 0x2000) {
- IRDA_MESSAGE("%s, chip->init\n", driver_name);
+ net_info_ratelimited("%s, chip->init\n",
+ driver_name);
chip->init(chip, &info);
} else
chip->probe(chip, &info);
* the chip.
*/
if (ret) {
- IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
+ pr_debug("%s, PnP init failed\n",
+ driver_name);
memset(&info, 0, sizeof(chipio_t));
info.cfg_base = cfg_base;
info.fir_base = io[i];
}
i++;
} else {
- IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __func__, id);
+ pr_debug("%s(), Wrong chip id=0x%02x\n",
+ __func__, id);
}
}
}
void *ret;
int err, chip_index;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
-
for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
if (!dev_self[chip_index])
break;
}
if (chip_index == ARRAY_SIZE(dev_self)) {
- IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __func__);
+ net_err_ratelimited("%s(), maximum number of supported chips reached!\n",
+ __func__);
return -ENOMEM;
}
- IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
- info->cfg_base);
+ net_info_ratelimited("%s, Found chip at base=0x%03x\n",
+ driver_name, info->cfg_base);
if ((nsc_ircc_setup(info)) == -1)
return -1;
- IRDA_MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+ net_info_ratelimited("%s, driver loaded (Dag Brattli)\n", driver_name);
dev = alloc_irdadev(sizeof(struct nsc_ircc_cb));
if (dev == NULL) {
- IRDA_ERROR("%s(), can't allocate memory for "
- "control block!\n", __func__);
+ net_err_ratelimited("%s(), can't allocate memory for control block!\n",
+ __func__);
return -ENOMEM;
}
/* Reserve the ioports that we need */
ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
if (!ret) {
- IRDA_WARNING("%s(), can't get iobase of 0x%03x\n",
- __func__, self->io.fir_base);
+ net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n",
+ __func__, self->io.fir_base);
err = -ENODEV;
goto out1;
}
err = register_netdev(dev);
if (err) {
- IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
+ net_err_ratelimited("%s(), register_netdev() failed!\n",
+ __func__);
goto out4;
}
- IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
/* Check if user has supplied a valid dongle id or not */
if ((dongle_id <= 0) ||
(dongle_id >= ARRAY_SIZE(dongle_types))) {
dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
- IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
- dongle_types[dongle_id]);
+ net_info_ratelimited("%s, Found dongle: %s\n",
+ driver_name, dongle_types[dongle_id]);
} else {
- IRDA_MESSAGE("%s, Using dongle: %s\n", driver_name,
- dongle_types[dongle_id]);
+ net_info_ratelimited("%s, Using dongle: %s\n",
+ driver_name, dongle_types[dongle_id]);
}
self->io.dongle_id = dongle_id;
{
int iobase;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
iobase = self->io.fir_base;
unregister_netdev(self->netdev);
/* Release the PORT that this driver is using */
- IRDA_DEBUG(4, "%s(), Releasing Region %03x\n",
- __func__, self->io.fir_base);
+ pr_debug("%s(), Releasing Region %03x\n",
+ __func__, self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
case 0x2e8: outb(0x15, cfg_base+1); break;
case 0x3f8: outb(0x16, cfg_base+1); break;
case 0x2f8: outb(0x17, cfg_base+1); break;
- default: IRDA_ERROR("%s(), invalid base_address", __func__);
+ default: net_err_ratelimited("%s(), invalid base_address\n", __func__);
}
/* Control Signal Routing Register (CSRT) */
case 9: temp = 0x05; break;
case 11: temp = 0x06; break;
case 15: temp = 0x07; break;
- default: IRDA_ERROR("%s(), invalid irq", __func__);
+ default: net_err_ratelimited("%s(), invalid irq\n", __func__);
}
outb(CFG_108_CSRT, cfg_base);
case 0: outb(0x08+temp, cfg_base+1); break;
case 1: outb(0x10+temp, cfg_base+1); break;
case 3: outb(0x18+temp, cfg_base+1); break;
- default: IRDA_ERROR("%s(), invalid dma", __func__);
+ default: net_err_ratelimited("%s(), invalid dma\n", __func__);
}
outb(CFG_108_MCTL, cfg_base); /* Mode Control Register (MCTL) */
break;
}
info->sir_base = info->fir_base;
- IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __func__,
- info->fir_base);
+ pr_debug("%s(), probing fir_base=0x%03x\n", __func__,
+ info->fir_base);
/* Read control signals routing register (CSRT) */
outb(CFG_108_CSRT, cfg_base);
info->irq = 15;
break;
}
- IRDA_DEBUG(2, "%s(), probing irq=%d\n", __func__, info->irq);
+ pr_debug("%s(), probing irq=%d\n", __func__, info->irq);
/* Currently we only read Rx DMA but it will also be used for Tx */
switch ((reg >> 3) & 0x03) {
info->dma = 3;
break;
}
- IRDA_DEBUG(2, "%s(), probing dma=%d\n", __func__, info->dma);
+ pr_debug("%s(), probing dma=%d\n", __func__, info->dma);
/* Read mode control register (MCTL) */
outb(CFG_108_MCTL, cfg_base);
pnp = (reg >> 3) & 0x01;
if (pnp) {
- IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
+ pr_debug("(), Chip is in PnP mode\n");
outb(0x46, cfg_base);
reg = (inb(cfg_base+1) & 0xfe) << 2;
int enabled;
/* User is sure about his config... accept it. */
- IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): "
- "io=0x%04x, irq=%d, dma=%d\n",
- __func__, info->fir_base, info->irq, info->dma);
+ pr_debug("%s(): nsc_ircc_init_39x (user settings): io=0x%04x, irq=%d, dma=%d\n",
+ __func__, info->fir_base, info->irq, info->dma);
/* Access bank for SP2 */
outb(CFG_39X_LDN, cfg_base);
int reg1, reg2, irq, irqt, dma1, dma2;
int enabled, susp;
- IRDA_DEBUG(2, "%s(), nsc_ircc_probe_39x, base=%d\n",
- __func__, cfg_base);
+ pr_debug("%s(), nsc_ircc_probe_39x, base=%d\n",
+ __func__, cfg_base);
/* This function should be executed with irq off to avoid
* another driver messing with the Super I/O bank - Jean II */
outb(CFG_39X_SPC, cfg_base);
susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1);
- IRDA_DEBUG(2, "%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", __func__, reg1,reg2,irq,irqt,dma1,dma2,enabled,susp);
+ pr_debug("%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n",
+ __func__, reg1, reg2, irq, irqt, dma1, dma2, enabled, susp);
/* Configure SP2 */
!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
pnp_info.dma = pnp_dma(dev, 0);
- IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
- __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
+ pr_debug("%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
+ __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
if((pnp_info.fir_base == 0) ||
(pnp_info.irq == -1) || (pnp_info.dma == -1)) {
switch_bank(iobase, BANK3);
version = inb(iobase+MID);
- IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n",
- __func__, driver_name, version);
+ pr_debug("%s() Driver %s Found chip version %02x\n",
+ __func__, driver_name, version);
/* Should be 0x2? */
if (0x20 != (version & 0xf0)) {
- IRDA_ERROR("%s, Wrong chip version %02x\n",
- driver_name, version);
+ net_err_ratelimited("%s, Wrong chip version %02x\n",
+ driver_name, version);
return -1;
}
switch (dongle_id) {
case 0x00: /* same as */
case 0x01: /* Differential serial interface */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x02: /* same as */
case 0x03: /* Reserved */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x04: /* Sharp RY5HD01 */
break;
case 0x05: /* Reserved, but this is what the Thinkpad reports */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x06: /* Single-ended serial interface */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x07: /* Consumer-IR only */
- IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s is not for IrDA mode\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- IRDA_DEBUG(0, "%s(), %s\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
outb(0x28, iobase+7); /* Set irsl[0-2] as output */
break;
case 0x0A: /* same as */
case 0x0B: /* Reserved */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x0C: /* same as */
case 0x0D: /* HP HSDL-1100/HSDL-2100 */
outb(0x28, iobase+7); /* Set irsl[0-2] as output */
break;
case 0x0F: /* No dongle connected */
- IRDA_DEBUG(0, "%s(), %s\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s\n",
+ __func__, dongle_types[dongle_id]);
switch_bank(iobase, BANK0);
outb(0x62, iobase+MCR);
break;
default:
- IRDA_DEBUG(0, "%s(), invalid dongle_id %#x",
- __func__, dongle_id);
+ pr_debug("%s(), invalid dongle_id %#x",
+ __func__, dongle_id);
}
/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
switch (dongle_id) {
case 0x00: /* same as */
case 0x01: /* Differential serial interface */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x02: /* same as */
case 0x03: /* Reserved */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x04: /* Sharp RY5HD01 */
break;
case 0x05: /* Reserved */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x06: /* Single-ended serial interface */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x07: /* Consumer-IR only */
- IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s is not for IrDA mode\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- IRDA_DEBUG(0, "%s(), %s\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s\n",
+ __func__, dongle_types[dongle_id]);
outb(0x00, iobase+4);
if (speed > 115200)
outb(0x01, iobase+4);
break;
case 0x0A: /* same as */
case 0x0B: /* Reserved */
- IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s not defined by irda yet\n",
+ __func__, dongle_types[dongle_id]);
break;
case 0x0C: /* same as */
case 0x0D: /* HP HSDL-1100/HSDL-2100 */
case 0x0E: /* Supports SIR Mode only */
break;
case 0x0F: /* No dongle connected */
- IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
+ pr_debug("%s(), %s is not for IrDA mode\n",
+ __func__, dongle_types[dongle_id]);
switch_bank(iobase, BANK0);
outb(0x62, iobase+MCR);
break;
default:
- IRDA_DEBUG(0, "%s(), invalid data_rate\n", __func__);
+ pr_debug("%s(), invalid data_rate\n", __func__);
}
/* Restore bank register */
outb(bank, iobase+BSR);
__u8 bank;
__u8 ier; /* Interrupt enable register */
- IRDA_DEBUG(2, "%s(), speed=%d\n", __func__, speed);
+ pr_debug("%s(), speed=%d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return 0;);
outb(inb(iobase+4) | 0x04, iobase+4);
mcr = MCR_MIR;
- IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__);
+ pr_debug("%s(), handling baud of 576000\n", __func__);
break;
case 1152000:
mcr = MCR_MIR;
- IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __func__);
+ pr_debug("%s(), handling baud of 1152000\n", __func__);
break;
case 4000000:
mcr = MCR_FIR;
- IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __func__);
+ pr_debug("%s(), handling baud of 4000000\n", __func__);
break;
default:
mcr = MCR_FIR;
- IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n",
- __func__, speed);
+ pr_debug("%s(), unknown baud rate of %d\n",
+ __func__, speed);
break;
}
int actual = 0;
__u8 bank;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* Save current bank */
bank = inb(iobase+BSR);
switch_bank(iobase, BANK0);
if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
- IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n",
- __func__);
+ pr_debug("%s(), warning, FIFO not empty yet!\n",
+ __func__);
/* FIFO may still be filled to the Tx interrupt threshold */
fifo_size -= 17;
outb(buf[actual++], iobase+TXD);
}
- IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n",
- __func__, fifo_size, actual, len);
+ pr_debug("%s(), fifo_size %d ; %d sent of %d\n",
+ __func__, fifo_size, actual, len);
/* Restore bank */
outb(bank, iobase+BSR);
__u8 bank;
int ret = TRUE;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
iobase = self->io.fir_base;
/* Save current bank */
len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
if (st_fifo->tail >= MAX_RX_WINDOW) {
- IRDA_DEBUG(0, "%s(), window is full!\n", __func__);
+ pr_debug("%s(), window is full!\n", __func__);
continue;
}
skb = dev_alloc_skb(len+1);
if (skb == NULL) {
- IRDA_WARNING("%s(), memory squeeze, "
- "dropping frame.\n",
- __func__);
self->netdev->stats.rx_dropped++;
/* Restore bank register */
* Need to be after self->io.direction to avoid race with
* nsc_ircc_hard_xmit_sir() - Jean II */
if (self->new_speed) {
- IRDA_DEBUG(2, "%s(), Changing speed!\n", __func__);
+ pr_debug("%s(), Changing speed!\n", __func__);
self->ier = nsc_ircc_change_speed(self,
self->new_speed);
self->new_speed = 0;
nsc_ircc_dma_receive(self);
self->ier = IER_SFIF_IE;
} else
- IRDA_WARNING("%s(), potential "
- "Tx queue lockup !\n",
- __func__);
+ net_warn_ratelimited("%s(), potential Tx queue lockup !\n",
+ __func__);
}
} else {
/* Not finished yet, so interrupt on DMA again */
char hwname[32];
__u8 bank;
- IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
iobase = self->io.fir_base;
if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
- IRDA_WARNING("%s, unable to allocate irq=%d\n",
- driver_name, self->io.irq);
+ net_warn_ratelimited("%s, unable to allocate irq=%d\n",
+ driver_name, self->io.irq);
return -EAGAIN;
}
/*
* failure.
*/
if (request_dma(self->io.dma, dev->name)) {
- IRDA_WARNING("%s, unable to allocate dma=%d\n",
- driver_name, self->io.dma);
+ net_warn_ratelimited("%s, unable to allocate dma=%d\n",
+ driver_name, self->io.dma);
free_irq(self->io.irq, dev);
return -EAGAIN;
}
int iobase;
__u8 bank;
- IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(dev != NULL, return -1;);
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (self->io.suspended)
return 0;
- IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
+ pr_debug("%s, Suspending\n", driver_name);
rtnl_lock();
if (netif_running(self->netdev)) {
if (!self->io.suspended)
return 0;
- IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
+ pr_debug("%s, Waking up\n", driver_name);
rtnl_lock();
nsc_ircc_setup(&self->io);
if (netif_running(self->netdev)) {
if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
self->netdev->name, self->netdev)) {
- IRDA_WARNING("%s, unable to allocate irq=%d\n",
- driver_name, self->io.irq);
+ net_warn_ratelimited("%s, unable to allocate irq=%d\n",
+ driver_name, self->io.irq);
/*
* Don't fail resume process, just kill this
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power on dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
static int old_belkin_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
*/
static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
dev->speed = 9600;
return (speed==dev->speed) ? 0 : -EINVAL;
}
*/
static int old_belkin_reset(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* This dongles speed "defaults" to 9600 bps ;-) */
dev->speed = 9600;
return 0;
default:
- IRDA_ERROR("%s - undefined state\n", __func__);
+ net_err_ratelimited("%s - undefined state\n", __func__);
return -EINVAL;
}
fsm->substate = next_state;
int ret = -1;
unsigned delay;
- IRDA_DEBUG(2, "%s(), <%ld>\n", __func__, jiffies);
+ pr_debug("%s(), <%ld>\n", __func__, jiffies);
do {
- IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
- __func__, fsm->state, fsm->substate);
+ pr_debug("%s - state=0x%04x / substate=0x%04x\n",
+ __func__, fsm->state, fsm->substate);
next_state = fsm->state;
delay = 0;
break;
default:
- IRDA_ERROR("%s - undefined state\n", __func__);
+ net_err_ratelimited("%s - undefined state\n", __func__);
fsm->result = -EINVAL;
/* fall thru */
case SIRDEV_STATE_ERROR:
- IRDA_ERROR("%s - error: %d\n", __func__, fsm->result);
+ net_err_ratelimited("%s - error: %d\n",
+ __func__, fsm->result);
#if 0 /* don't enable this before we have netdev->tx_timeout to recover */
netif_stop_queue(dev->netdev);
{
struct sir_fsm *fsm = &dev->fsm;
- IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __func__,
- initial_state, param);
+ pr_debug("%s - state=0x%04x / param=%u\n", __func__,
+ initial_state, param);
if (down_trylock(&fsm->sem)) {
if (in_interrupt() || in_atomic() || irqs_disabled()) {
- IRDA_DEBUG(1, "%s(), state machine busy!\n", __func__);
+ pr_debug("%s(), state machine busy!\n", __func__);
return -EWOULDBLOCK;
} else
down(&fsm->sem);
if (fsm->state == SIRDEV_STATE_DEAD) {
/* race with sirdev_close should never happen */
- IRDA_ERROR("%s(), instance staled!\n", __func__);
+ net_err_ratelimited("%s(), instance staled!\n", __func__);
up(&fsm->sem);
return -ESTALE; /* or better EPIPE? */
}
{
int err;
- IRDA_DEBUG(3, "%s : requesting dongle %d.\n", __func__, type);
+ pr_debug("%s : requesting dongle %d.\n", __func__, type);
err = sirdev_schedule_dongle_open(dev, type);
if (unlikely(err))
ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
if (ret > 0) {
- IRDA_DEBUG(3, "%s(), raw-tx started\n", __func__);
+ pr_debug("%s(), raw-tx started\n", __func__);
dev->tx_buff.data += ret;
dev->tx_buff.len -= ret;
spin_lock_irqsave(&dev->tx_lock, flags);
- IRDA_DEBUG(3, "%s() - dev->tx_buff.len = %d\n",
- __func__, dev->tx_buff.len);
+ pr_debug("%s() - dev->tx_buff.len = %d\n",
+ __func__, dev->tx_buff.len);
if (likely(dev->tx_buff.len > 0)) {
/* Write data left in transmit buffer */
}
else if (unlikely(actual<0)) {
/* could be dropped later when we have tx_timeout to recover */
- IRDA_ERROR("%s: drv->do_write failed (%d)\n",
- __func__, actual);
+ net_err_ratelimited("%s: drv->do_write failed (%d)\n",
+ __func__, actual);
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
dev_kfree_skb_any(skb);
* restarted when the irda-thread has completed the request.
*/
- IRDA_DEBUG(3, "%s(), raw-tx done\n", __func__);
+ pr_debug("%s(), raw-tx done\n", __func__);
dev->raw_tx = 0;
goto done; /* no post-frame handling in raw mode */
}
* re-activated.
*/
- IRDA_DEBUG(5, "%s(), finished with frame!\n", __func__);
+ pr_debug("%s(), finished with frame!\n", __func__);
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
}
if (unlikely(dev->new_speed > 0)) {
- IRDA_DEBUG(5, "%s(), Changing speed!\n", __func__);
+ pr_debug("%s(), Changing speed!\n", __func__);
err = sirdev_schedule_speed(dev, dev->new_speed);
if (unlikely(err)) {
/* should never happen
* forget the speed change and hope the stack recovers
*/
- IRDA_ERROR("%s - schedule speed change failed: %d\n",
- __func__, err);
+ net_err_ratelimited("%s - schedule speed change failed: %d\n",
+ __func__, err);
netif_wake_queue(dev->netdev);
}
/* else: success
int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count)
{
if (!dev || !dev->netdev) {
- IRDA_WARNING("%s(), not ready yet!\n", __func__);
+ net_warn_ratelimited("%s(), not ready yet!\n", __func__);
return -1;
}
if (!dev->irlap) {
- IRDA_WARNING("%s - too early: %p / %zd!\n",
- __func__, cp, count);
+ net_warn_ratelimited("%s - too early: %p / %zd!\n",
+ __func__, cp, count);
return -1;
}
*/
irda_device_set_media_busy(dev->netdev, TRUE);
dev->netdev->stats.rx_dropped++;
- IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __func__, count);
+ pr_debug("%s; rx-drop: %zd\n", __func__, count);
return 0;
}
netif_stop_queue(ndev);
- IRDA_DEBUG(3, "%s(), skb->len = %d\n", __func__, skb->len);
+ pr_debug("%s(), skb->len = %d\n", __func__, skb->len);
speed = irda_get_next_speed(skb);
if ((speed != dev->speed) && (speed != -1)) {
/* Check problems */
if(spin_is_locked(&dev->tx_lock)) {
- IRDA_DEBUG(3, "%s(), write not completed\n", __func__);
+ pr_debug("%s(), write not completed\n", __func__);
}
/* serialize with write completion */
}
else if (unlikely(actual < 0)) {
/* could be dropped later when we have tx_timeout to recover */
- IRDA_ERROR("%s: drv->do_write failed (%d)\n",
- __func__, actual);
+ net_err_ratelimited("%s: drv->do_write failed (%d)\n",
+ __func__, actual);
dev_kfree_skb_any(skb);
dev->netdev->stats.tx_errors++;
dev->netdev->stats.tx_dropped++;
IRDA_ASSERT(dev != NULL, return -1;);
- IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!try_module_get(drv->owner))
return -ESTALE;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
if (sirdev_alloc_buffers(dev))
goto errout_dec;
netif_wake_queue(ndev);
- IRDA_DEBUG(2, "%s - done, speed = %d\n", __func__, dev->speed);
+ pr_debug("%s - done, speed = %d\n", __func__, dev->speed);
return 0;
struct sir_dev *dev = netdev_priv(ndev);
const struct sir_driver *drv;
-// IRDA_DEBUG(0, "%s\n", __func__);
+/* pr_debug("%s\n", __func__); */
netif_stop_queue(ndev);
struct net_device *ndev;
struct sir_dev *dev;
- IRDA_DEBUG(0, "%s - %s\n", __func__, name);
+ pr_debug("%s - %s\n", __func__, name);
/* instead of adding tests to protect against drv->do_write==NULL
* at several places we refuse to create a sir_dev instance for
*/
ndev = alloc_irdadev(sizeof(*dev));
if (ndev == NULL) {
- IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__);
+ net_err_ratelimited("%s - Can't allocate memory for IrDA control block!\n",
+ __func__);
goto out;
}
dev = netdev_priv(ndev);
ndev->netdev_ops = &sirdev_ops;
if (register_netdev(ndev)) {
- IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
+ net_err_ratelimited("%s(), register_netdev() failed!\n",
+ __func__);
goto out_freenetdev;
}
{
int err = 0;
- IRDA_DEBUG(0, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
atomic_set(&dev->enable_rx, 0);
if (dev->dongle_drv)
err = sirdev_schedule_dongle_close(dev);
if (err)
- IRDA_ERROR("%s - error %d\n", __func__, err);
+ net_err_ratelimited("%s - error %d\n", __func__, err);
sirdev_close(dev->netdev);
struct list_head *entry;
struct dongle_driver *drv;
- IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
- __func__, new->driver_name, new->type);
+ pr_debug("%s : registering dongle \"%s\" (%d).\n",
+ __func__, new->driver_name, new->type);
mutex_lock(&dongle_list_lock);
list_for_each(entry, &dongle_list) {
#ifdef CONFIG_PCI
if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) {
/* Ignore errors from preconfiguration */
- IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name);
+ net_err_ratelimited("%s, Preconfiguration failed !\n",
+ driver_name);
}
#endif
if (ircc_fir > 0 && ircc_sir > 0) {
- IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
- IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+ net_info_ratelimited(" Overriding FIR address 0x%04x\n",
+ ircc_fir);
+ net_info_ratelimited(" Overriding SIR address 0x%04x\n",
+ ircc_sir);
if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
ret = -ENODEV;
/* try user provided configuration register base address */
if (ircc_cfg > 0) {
- IRDA_MESSAGE(" Overriding configuration address "
- "0x%04x\n", ircc_cfg);
+ net_info_ratelimited(" Overriding configuration address 0x%04x\n",
+ ircc_cfg);
if (!smsc_superio_fdc(ircc_cfg))
ret = 0;
if (!smsc_superio_lpc(ircc_cfg))
{
int ret;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
ret = platform_driver_register(&smsc_ircc_driver);
if (ret) {
- IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+ net_err_ratelimited("%s, Can't register driver!\n",
+ driver_name);
return ret;
}
struct net_device *dev;
int err;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
err = smsc_ircc_present(fir_base, sir_base);
if (err)
err = -ENOMEM;
if (dev_count >= ARRAY_SIZE(dev_self)) {
- IRDA_WARNING("%s(), too many devices!\n", __func__);
+ net_warn_ratelimited("%s(), too many devices!\n", __func__);
goto err_out1;
}
*/
dev = alloc_irdadev(sizeof(struct smsc_ircc_cb));
if (!dev) {
- IRDA_WARNING("%s() can't allocate net device\n", __func__);
+ net_warn_ratelimited("%s() can't allocate net device\n",
+ __func__);
goto err_out1;
}
err = register_netdev(self->netdev);
if (err) {
- IRDA_ERROR("%s, Network device registration failed!\n",
- driver_name);
+ net_err_ratelimited("%s, Network device registration failed!\n",
+ driver_name);
goto err_out4;
}
}
platform_set_drvdata(self->pldev, self);
- IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
dev_count++;
return 0;
if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT,
driver_name)) {
- IRDA_WARNING("%s: can't get fir_base of 0x%03x\n",
- __func__, fir_base);
+ net_warn_ratelimited("%s: can't get fir_base of 0x%03x\n",
+ __func__, fir_base);
goto out1;
}
if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT,
driver_name)) {
- IRDA_WARNING("%s: can't get sir_base of 0x%03x\n",
- __func__, sir_base);
+ net_warn_ratelimited("%s: can't get sir_base of 0x%03x\n",
+ __func__, sir_base);
goto out2;
}
irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
- IRDA_WARNING("%s(), addr 0x%04x - no device found!\n",
- __func__, fir_base);
+ net_warn_ratelimited("%s(), addr 0x%04x - no device found!\n",
+ __func__, fir_base);
goto out3;
}
- IRDA_MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
- "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
- chip & 0x0f, version, fir_base, sir_base, dma, irq);
+ net_info_ratelimited("SMsC IrDA Controller found\n IrCC version %d.%d, firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
+ chip & 0x0f, version,
+ fir_base, sir_base, dma, irq);
return 0;
if (irq != IRQ_INVAL) {
if (irq != chip_irq)
- IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
- driver_name, chip_irq, irq);
+ net_info_ratelimited("%s, Overriding IRQ - chip says %d, using %d\n",
+ driver_name, chip_irq, irq);
self->io.irq = irq;
} else
self->io.irq = chip_irq;
if (dma != DMA_INVAL) {
if (dma != chip_dma)
- IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
- driver_name, chip_dma, dma);
+ net_info_ratelimited("%s, Overriding DMA - chip says %d, using %d\n",
+ driver_name, chip_dma, dma);
self->io.dma = dma;
} else
self->io.dma = chip_dma;
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
struct smsc_ircc_cb *self = netdev_priv(dev);
unsigned long flags;
- IRDA_WARNING("%s: transmit timed out, changing speed to: %d\n",
- dev->name, self->io.speed);
+ net_warn_ratelimited("%s: transmit timed out, changing speed to: %d\n",
+ dev->name, self->io.speed);
spin_lock_irqsave(&self->lock, flags);
smsc_ircc_sir_start(self);
smsc_ircc_change_speed(self, self->io.speed);
unsigned long flags;
s32 speed;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_CRC;
fast = 0;
- IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__);
+ pr_debug("%s(), handling baud of 576000\n", __func__);
break;
case 1152000:
ir_mode = IRCC_CFGA_IRDA_HDLC;
ctrl = IRCC_1152 | IRCC_CRC;
fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA;
- IRDA_DEBUG(0, "%s(), handling baud of 1152000\n",
- __func__);
+ pr_debug("%s(), handling baud of 1152000\n",
+ __func__);
break;
case 4000000:
ir_mode = IRCC_CFGA_IRDA_4PPM;
ctrl = IRCC_CRC;
fast = IRCC_LCR_A_FAST;
- IRDA_DEBUG(0, "%s(), handling baud of 4000000\n",
- __func__);
+ pr_debug("%s(), handling baud of 4000000\n",
+ __func__);
break;
}
#if 0
struct net_device *dev;
int fir_base;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
{
int fir_base;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(self != NULL, return;);
struct net_device *dev;
int last_speed_was_sir;
- IRDA_DEBUG(0, "%s() changing speed to: %d\n", __func__, speed);
+ pr_debug("%s() changing speed to: %d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
int lcr; /* Line control reg */
int divisor;
- IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __func__, speed);
+ pr_debug("%s(), Setting speed to: %d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
/* Turn on interrups */
outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
- IRDA_DEBUG(2, "%s() speed changed to: %d\n", __func__, speed);
+ pr_debug("%s() speed changed to: %d\n", __func__, speed);
}
int iobase = self->io.fir_base;
u8 ctrl;
- IRDA_DEBUG(3, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
#if 1
/* Disable Rx */
register_bank(iobase, 0);
{
int iobase = self->io.fir_base;
- IRDA_DEBUG(3, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
#if 0
/* Disable Tx */
register_bank(iobase, 0);
register_bank(iobase, 0);
- IRDA_DEBUG(3, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
#if 0
/* Disable Rx */
register_bank(iobase, 0);
lsr= inb(iobase + IRCC_LSR);
msgcnt = inb(iobase + IRCC_LCR_B) & 0x08;
- IRDA_DEBUG(2, "%s: dma count = %d\n", __func__,
- get_dma_residue(self->io.dma));
+ pr_debug("%s: dma count = %d\n", __func__,
+ get_dma_residue(self->io.dma));
len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
len -= self->io.speed < 4000000 ? 2 : 4;
if (len < 2 || len > 2050) {
- IRDA_WARNING("%s(), bogus len=%d\n", __func__, len);
+ net_warn_ratelimited("%s(), bogus len=%d\n", __func__, len);
return;
}
- IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len);
+ pr_debug("%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len);
skb = dev_alloc_skb(len + 1);
- if (!skb) {
- IRDA_WARNING("%s(), memory squeeze, dropping frame.\n",
- __func__);
+ if (!skb)
return;
- }
+
/* Make sure IP header gets aligned */
skb_reserve(skb, 1);
/* Make sure we don't stay here to long */
if (boguscount++ > 32) {
- IRDA_DEBUG(2, "%s(), breaking!\n", __func__);
+ pr_debug("%s(), breaking!\n", __func__);
break;
}
} while (inb(iobase + UART_LSR) & UART_LSR_DR);
lcra = inb(iobase + IRCC_LCR_A);
lsr = inb(iobase + IRCC_LSR);
- IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __func__, iir);
+ pr_debug("%s(), iir = 0x%02x\n", __func__, iir);
if (iir & IRCC_IIR_EOM) {
if (self->io.direction == IO_RECV)
/* Clear interrupt */
lsr = inb(iobase + UART_LSR);
- IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
- __func__, iir, lsr, iobase);
+ pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ __func__, iir, lsr, iobase);
switch (iir) {
case UART_IIR_RLSI:
- IRDA_DEBUG(2, "%s(), RLSI\n", __func__);
+ pr_debug("%s(), RLSI\n", __func__);
break;
case UART_IIR_RDI:
/* Receive interrupt */
smsc_ircc_sir_write_wakeup(self);
break;
default:
- IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
- __func__, iir);
+ pr_debug("%s(), unhandled IIR=%#x\n",
+ __func__, iir);
break;
}
int status = FALSE;
/* int iobase; */
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(self != NULL, return FALSE;);
- IRDA_DEBUG(0, "%s: dma count = %d\n", __func__,
- get_dma_residue(self->io.dma));
+ pr_debug("%s: dma count = %d\n", __func__,
+ get_dma_residue(self->io.dma));
status = (self->rx_buff.state != OUTSIDE_FRAME);
error = request_irq(self->io.irq, smsc_ircc_interrupt, 0,
self->netdev->name, self->netdev);
if (error)
- IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n",
- __func__, self->io.irq, error);
+ pr_debug("%s(), unable to allocate irq=%d, err=%d\n",
+ __func__, self->io.irq, error);
return error;
}
struct smsc_ircc_cb *self;
char hwname[16];
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
if (self->io.suspended) {
- IRDA_DEBUG(0, "%s(), device is suspended\n", __func__);
+ pr_debug("%s(), device is suspended\n", __func__);
return -EAGAIN;
}
if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
(void *) dev)) {
- IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
- __func__, self->io.irq);
+ pr_debug("%s(), unable to allocate irq=%d\n",
+ __func__, self->io.irq);
return -EAGAIN;
}
if (request_dma(self->io.dma, dev->name)) {
smsc_ircc_net_close(dev);
- IRDA_WARNING("%s(), unable to allocate DMA=%d\n",
- __func__, self->io.dma);
+ net_warn_ratelimited("%s(), unable to allocate DMA=%d\n",
+ __func__, self->io.dma);
return -EAGAIN;
}
{
struct smsc_ircc_cb *self;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
struct smsc_ircc_cb *self = platform_get_drvdata(dev);
if (!self->io.suspended) {
- IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
+ pr_debug("%s, Suspending\n", driver_name);
rtnl_lock();
if (netif_running(self->netdev)) {
struct smsc_ircc_cb *self = platform_get_drvdata(dev);
if (self->io.suspended) {
- IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
+ pr_debug("%s, Waking up\n", driver_name);
rtnl_lock();
smsc_ircc_init_chip(self);
*/
static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
{
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(self != NULL, return -1;);
smsc_ircc_stop_interrupts(self);
/* Release the PORTS that this driver is using */
- IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __func__,
- self->io.fir_base);
+ pr_debug("%s(), releasing 0x%03x\n", __func__,
+ self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
- IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __func__,
- self->io.sir_base);
+ pr_debug("%s(), releasing 0x%03x\n", __func__,
+ self->io.sir_base);
release_region(self->io.sir_base, self->io.sir_ext);
{
int i;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
for (i = 0; i < 2; i++) {
if (dev_self[i])
struct net_device *dev;
int fir_base, sir_base;
- IRDA_DEBUG(3, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
IRDA_ASSERT(self != NULL, return;);
dev = self->netdev;
/* Turn on interrups */
outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);
- IRDA_DEBUG(3, "%s() - exit\n", __func__);
+ pr_debug("%s() - exit\n", __func__);
outb(0x00, fir_base + IRCC_MASTER);
}
{
int iobase;
- IRDA_DEBUG(3, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
iobase = self->io.sir_base;
/* Reset UART */
IRDA_ASSERT(self != NULL, return;);
- IRDA_DEBUG(4, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
iobase = self->io.sir_base;
* if we need to change the speed of the hardware
*/
if (self->new_speed) {
- IRDA_DEBUG(5, "%s(), Changing speed to %d.\n",
- __func__, self->new_speed);
+ pr_debug("%s(), Changing speed to %d.\n",
+ __func__, self->new_speed);
smsc_ircc_sir_wait_hw_transmitter_finish(self);
smsc_ircc_change_speed(self, self->new_speed);
self->new_speed = 0;
/* Tx FIFO should be empty! */
if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {
- IRDA_WARNING("%s(), failed, fifo not empty!\n", __func__);
+ net_warn_ratelimited("%s(), failed, fifo not empty!\n",
+ __func__);
return 0;
}
for (i = 0; smsc_transceivers[i].name != NULL; i++)
if (smsc_transceivers[i].probe(self->io.fir_base)) {
- IRDA_MESSAGE(" %s transceiver found\n",
- smsc_transceivers[i].name);
+ net_info_ratelimited(" %s transceiver found\n",
+ smsc_transceivers[i].name);
self->transceiver= i + 1;
return;
}
- IRDA_MESSAGE("No transceiver found. Defaulting to %s\n",
- smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
+ net_info_ratelimited("No transceiver found. Defaulting to %s\n",
+ smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
}
udelay(1);
if (count < 0)
- IRDA_DEBUG(0, "%s(): stuck transmitter\n", __func__);
+ pr_debug("%s(): stuck transmitter\n", __func__);
}
u8 mode, dma, irq;
int ret = -ENODEV;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)
return ret;
/*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __func__, mode);*/
if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
- IRDA_WARNING("%s(): IrDA not enabled\n", __func__);
+ net_warn_ratelimited("%s(): IrDA not enabled\n", __func__);
outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
sirbase = inb(cfgbase + 1) << 2;
outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
- IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __func__, firbase, sirbase, dma, irq, mode);
+ net_info_ratelimited("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n",
+ __func__, firbase, sirbase, dma, irq, mode);
if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
ret = 0;
unsigned short fir_io, sir_io;
int ret = -ENODEV;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)
return ret;
static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
{
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
outb(reg, cfg_base);
return inb(cfg_base) != reg ? -1 : 0;
{
u8 devid, xdevid, rev;
- IRDA_DEBUG(1, "%s\n", __func__);
+ pr_debug("%s\n", __func__);
/* Leave configuration */
return NULL;
}
- IRDA_MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
- devid, rev, cfg_base, type, chip->name);
+ net_info_ratelimited("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
+ devid, rev, cfg_base, type, chip->name);
if (chip->rev > rev) {
- IRDA_MESSAGE("Revision higher than expected\n");
+ net_info_ratelimited("Revision higher than expected\n");
return NULL;
}
if (chip->flags & NoIRDA)
- IRDA_MESSAGE("chipset does not support IRDA\n");
+ net_info_ratelimited("chipset does not support IRDA\n");
return chip;
}
int ret = -1;
if (!request_region(cfg_base, 2, driver_name)) {
- IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
- __func__, cfg_base);
+ net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n",
+ __func__, cfg_base);
} else {
if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||
!smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))
int ret = -1;
if (!request_region(cfg_base, 2, driver_name)) {
- IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n",
- __func__, cfg_base);
+ net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n",
+ __func__, cfg_base);
} else {
if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||
!smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))
outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state
outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID
tmpbyte = inb(iobase +1); // Read device ID
- IRDA_DEBUG(0,
- "Detected Chip id: 0x%02x, setting up registers...\n",
- tmpbyte);
+ pr_debug("Detected Chip id: 0x%02x, setting up registers...\n",
+ tmpbyte);
/* Disable UART1 and set up SIR I/O port */
outb(0x24, iobase); // select CR24 - UART1 base addr
outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8
tmpbyte = inb(iobase + 1);
if (tmpbyte != (conf->sir_io >> 2) ) {
- IRDA_WARNING("ERROR: could not configure SIR ioport.\n");
- IRDA_WARNING("Try to supply ircc_cfg argument.\n");
+ net_warn_ratelimited("ERROR: could not configure SIR ioport\n");
+ net_warn_ratelimited("Try to supply ircc_cfg argument\n");
return -ENXIO;
}
outb(tmpbyte, iobase + 1);
tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
if (tmpbyte != conf->fir_irq) {
- IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n");
+ net_warn_ratelimited("ERROR: could not configure FIR IRQ channel\n");
return -ENXIO;
}
outb((conf->fir_io >> 3), iobase + 1);
tmpbyte = inb(iobase + 1);
if (tmpbyte != (conf->fir_io >> 3) ) {
- IRDA_WARNING("ERROR: could not configure FIR I/O port.\n");
+ net_warn_ratelimited("ERROR: could not configure FIR I/O port\n");
return -ENXIO;
}
outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA
tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK;
if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) {
- IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n");
+ net_warn_ratelimited("ERROR: could not configure FIR DMA channel\n");
return -ENXIO;
}
unsigned short tmpword;
unsigned char tmpbyte;
- IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n");
+ net_info_ratelimited("Setting up Intel 82801 controller and SMSC device\n");
/*
* Select the range for the COMA COM port (SIR)
* Register COM_DEC:
default:
tmpbyte |= 0x01; /* COM2 default */
}
- IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte);
+ pr_debug("COM_DEC (write): 0x%02x\n", tmpbyte);
pci_write_config_byte(dev, COM_DEC, tmpbyte);
/* Enable Low Pin Count interface */
tmpword |= 0x0400;
break;
default:
- IRDA_WARNING("Uncommon I/O base address: 0x%04x\n",
- conf->cfg_base);
+ net_warn_ratelimited("Uncommon I/O base address: 0x%04x\n",
+ conf->cfg_base);
break;
}
tmpword &= 0xfffd; /* disable LPC COMB */
tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */
- IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword);
+ pr_debug("LPC_EN (write): 0x%04x\n", tmpword);
pci_write_config_word(dev, LPC_EN, tmpword);
/*
default:
break; /* do not change settings */
}
- IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword);
+ pr_debug("PCI_DMA_C (write): 0x%04x\n", tmpword);
pci_write_config_word(dev, PCI_DMA_C, tmpword);
/*
*/
tmpword = conf->fir_io & 0xfff8;
tmpword |= 0x0001;
- IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword);
+ pr_debug("GEN2_DEC (write): 0x%04x\n", tmpword);
pci_write_config_word(dev, GEN2_DEC, tmpword);
/* Pre-configure chip */
mask = 0x08;
break;
default:
- IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port);
+ net_err_ratelimited("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n",
+ port);
return;
}
/* Turn on the right bits */
tmpbyte |= mask;
pci_write_config_byte(dev, reg, tmpbyte);
- IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port);
+ net_info_ratelimited("Activated ALi 1533 ISA bridge port 0x%04x\n",
+ port);
}
static int __init preconfigure_through_ali(struct pci_dev *dev,
if (ircc_irq != IRQ_INVAL)
tmpconf.fir_irq = ircc_irq;
- IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name);
+ net_info_ratelimited("Detected unconfigured %s SMSC IrDA chip, pre-configuring device\n",
+ conf->name);
if (conf->preconfigure)
ret = conf->preconfigure(dev, &tmpconf);
else
/* empty */;
if (val)
- IRDA_WARNING("%s(): ATC: 0x%02x\n", __func__,
- inb(fir_base + IRCC_ATC));
+ net_warn_ratelimited("%s(): ATC: 0x%02x\n",
+ __func__, inb(fir_base + IRCC_ATC));
}
/*
{
if (tekram_delay < 1 || tekram_delay > 500)
tekram_delay = 200;
- IRDA_DEBUG(1, "%s - using %d ms delay\n",
- tekram.driver_name, tekram_delay);
+ pr_debug("%s - using %d ms delay\n",
+ tekram.driver_name, tekram_delay);
return irda_register_dongle(&tekram);
}
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
sirdev_set_dtr_rts(dev, TRUE, TRUE);
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
static int tekram_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
u8 byte;
static int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
switch(state) {
case SIRDEV_STATE_DONGLE_SPEED:
break;
default:
- IRDA_ERROR("%s - undefined state %d\n", __func__, state);
+ net_err_ratelimited("%s - undefined state %d\n",
+ __func__, state);
ret = -EINVAL;
break;
}
static int tekram_reset(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Clear DTR, Set RTS */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
{
if (toim3232delay < 1 || toim3232delay > 500)
toim3232delay = 200;
- IRDA_DEBUG(1, "%s - using %d ms delay\n",
- toim3232.driver_name, toim3232delay);
+ pr_debug("%s - using %d ms delay\n",
+ toim3232.driver_name, toim3232delay);
return irda_register_dongle(&toim3232);
}
{
struct qos_info *qos = &dev->qos;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Pull the lines high to start with.
*
* For the IR320ST-2, we need to charge the main supply capacitor to
static int toim3232_close(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
u8 byte;
static int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
switch(state) {
case SIRDEV_STATE_DONGLE_SPEED:
static int toim3232_reset(struct sir_dev *dev)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Switch off both DTR and RTS to switch off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
{
int rc;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
rc = pci_register_driver(&via_driver);
if (rc < 0) {
- IRDA_DEBUG(0, "%s(): error rc = %d, returning -ENODEV...\n",
- __func__, rc);
+ pr_debug("%s(): error rc = %d, returning -ENODEV...\n",
+ __func__, rc);
return -ENODEV;
}
return 0;
u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase;
chipio_t info;
- IRDA_DEBUG(2, "%s(): Device ID=(0X%X)\n", __func__, id->device);
+ pr_debug("%s(): Device ID=(0X%X)\n", __func__, id->device);
rc = pci_enable_device (pcidev);
if (rc) {
- IRDA_DEBUG(0, "%s(): error rc = %d\n", __func__, rc);
+ pr_debug("%s(): error rc = %d\n", __func__, rc);
return -ENODEV;
}
Chipset=0x3076;
if (Chipset==0x3076) {
- IRDA_DEBUG(2, "%s(): Chipset = 3076\n", __func__);
+ pr_debug("%s(): Chipset = 3076\n", __func__);
WriteLPCReg(7,0x0c );
temp=ReadLPCReg(0x30);//check if BIOS Enable Fir
} else
rc = -ENODEV; //IR not turn on
} else { //Not VT1211
- IRDA_DEBUG(2, "%s(): Chipset = 3096\n", __func__);
+ pr_debug("%s(): Chipset = 3096\n", __func__);
pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir
if((bTmp&0x01)==1) { // BIOS enable FIR
rc = -ENODEV; //IR not turn on !!!!!
}//Not VT1211
- IRDA_DEBUG(2, "%s(): End - rc = %d\n", __func__, rc);
+ pr_debug("%s(): End - rc = %d\n", __func__, rc);
return rc;
}
static void __exit via_ircc_cleanup(void)
{
- IRDA_DEBUG(3, "%s()\n", __func__);
-
/* Cleanup all instances of the driver */
pci_unregister_driver (&via_driver);
}
struct via_ircc_cb *self;
int err;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
/* Allocate new instance of the driver */
dev = alloc_irdadev(sizeof(struct via_ircc_cb));
if (dev == NULL)
/* Reserve the ioports that we need */
if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
- IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
- __func__, self->io.fir_base);
+ pr_debug("%s(), can't get iobase of 0x%03x\n",
+ __func__, self->io.fir_base);
err = -ENODEV;
goto err_out1;
}
if (err)
goto err_out4;
- IRDA_MESSAGE("IrDA: Registered device %s (via-ircc)\n", dev->name);
+ net_info_ratelimited("IrDA: Registered device %s (via-ircc)\n",
+ dev->name);
/* Initialise the hardware..
*/
struct via_ircc_cb *self = pci_get_drvdata(pdev);
int iobase;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
iobase = self->io.fir_base;
ResetChip(iobase, 5); //hardware reset.
unregister_netdev(self->netdev);
/* Release the PORT that this driver is using */
- IRDA_DEBUG(2, "%s(), Releasing Region %03x\n",
- __func__, self->io.fir_base);
+ pr_debug("%s(), Releasing Region %03x\n",
+ __func__, self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
dma_free_coherent(&pdev->dev, self->tx_buff.truesize,
{
int iobase = self->io.fir_base;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095
// FIFO Init
EnRXFIFOReadyInt(iobase, OFF);
*/
static int via_ircc_read_dongle_id(int iobase)
{
- IRDA_ERROR("via-ircc: dongle probing not supported, please specify dongle_id module parameter.\n");
+ net_err_ratelimited("via-ircc: dongle probing not supported, please specify dongle_id module parameter\n");
return 9; /* Default to IBM */
}
/* speed is unused, as we use IsSIROn()/IsMIROn() */
speed = speed;
- IRDA_DEBUG(1, "%s(): change_dongle_speed to %d for 0x%x, %d\n",
- __func__, speed, iobase, dongle_id);
+ pr_debug("%s(): change_dongle_speed to %d for 0x%x, %d\n",
+ __func__, speed, iobase, dongle_id);
switch (dongle_id) {
case 0x11: /* Temic TFDS4500 */
- IRDA_DEBUG(2, "%s: Temic TFDS4500: One RX pin, TX normal, RX inverted.\n", __func__);
+ pr_debug("%s: Temic TFDS4500: One RX pin, TX normal, RX inverted\n",
+ __func__);
UseOneRX(iobase, ON); //use ONE RX....RX1
InvertTX(iobase, OFF);
SlowIRRXLowActive(iobase, OFF);
} else{
- IRDA_DEBUG(0, "%s: Warning: TFDS4500 not running in SIR mode !\n", __func__);
+ pr_debug("%s: Warning: TFDS4500 not running in SIR mode !\n",
+ __func__);
}
break;
break;
default:
- IRDA_ERROR("%s: Error: dongle_id %d unsupported !\n",
- __func__, dongle_id);
+ net_err_ratelimited("%s: Error: dongle_id %d unsupported !\n",
+ __func__, dongle_id);
}
}
iobase = self->io.fir_base;
/* Update accounting for new speed */
self->io.speed = speed;
- IRDA_DEBUG(1, "%s: change_speed to %d bps.\n", __func__, speed);
+ pr_debug("%s: change_speed to %d bps.\n", __func__, speed);
WriteReg(iobase, I_ST_CT_0, 0x0);
((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start -
self->tx_buff.head) + self->tx_buff_dma,
self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE);
- IRDA_DEBUG(1, "%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n",
- __func__, self->tx_fifo.ptr,
- self->tx_fifo.queue[self->tx_fifo.ptr].len,
- self->tx_fifo.len);
+ pr_debug("%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n",
+ __func__, self->tx_fifo.ptr,
+ self->tx_fifo.queue[self->tx_fifo.ptr].len,
+ self->tx_fifo.len);
SetSendByte(iobase, self->tx_fifo.queue[self->tx_fifo.ptr].len);
RXStart(iobase, OFF);
int iobase;
u8 Tx_status;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
iobase = self->io.fir_base;
/* Disable DMA */
// DisableDmaChannel(self->io.dma);
self->tx_fifo.ptr++;
}
}
- IRDA_DEBUG(1,
- "%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n",
- __func__,
- self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free);
+ pr_debug("%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n",
+ __func__,
+ self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free);
/* F01_S
// Any frames to be sent back-to-back?
if (self->tx_fifo.len) {
iobase = self->io.fir_base;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
self->tx_fifo.tail = self->tx_buff.head;
self->RxDataReady = 0;
if (len == 0)
return TRUE; //interrupt only, data maybe move by RxT
if (((len - 4) < 2) || ((len - 4) > 2048)) {
- IRDA_DEBUG(1, "%s(): Trouble:len=%x,CurCount=%x,LastCount=%x..\n",
- __func__, len, RxCurCount(iobase, self),
- self->RxLastCount);
+ pr_debug("%s(): Trouble:len=%x,CurCount=%x,LastCount=%x\n",
+ __func__, len, RxCurCount(iobase, self),
+ self->RxLastCount);
hwreset(self);
return FALSE;
}
- IRDA_DEBUG(2, "%s(): fifo.len=%x,len=%x,CurCount=%x..\n",
- __func__,
- st_fifo->len, len - 4, RxCurCount(iobase, self));
+ pr_debug("%s(): fifo.len=%x,len=%x,CurCount=%x..\n",
+ __func__,
+ st_fifo->len, len - 4, RxCurCount(iobase, self));
st_fifo->entries[st_fifo->tail].status = status;
st_fifo->entries[st_fifo->tail].len = len;
skb_put(skb, len - 4);
skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
- IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __func__,
- len - 4, self->rx_buff.data);
+ pr_debug("%s(): len=%x.rx_buff=%p\n", __func__,
+ len - 4, self->rx_buff.data);
// Move to next frame
self->rx_buff.data += len;
len = GetRecvByte(iobase, self);
- IRDA_DEBUG(2, "%s(): len=%x\n", __func__, len);
+ pr_debug("%s(): len=%x\n", __func__, len);
if ((len - 4) < 2) {
self->netdev->stats.rx_dropped++;
skb_put(skb, len - 4);
skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
- IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __func__,
- len - 4, st_fifo->head);
+ pr_debug("%s(): len=%x.head=%x\n", __func__,
+ len - 4, st_fifo->head);
// Move to next frame
self->rx_buff.data += len;
} //while
self->RetryCount = 0;
- IRDA_DEBUG(2,
- "%s(): End of upload HostStatus=%x,RxStatus=%x\n",
- __func__,
- GetHostStatus(iobase), GetRXStatus(iobase));
+ pr_debug("%s(): End of upload HostStatus=%x,RxStatus=%x\n",
+ __func__, GetHostStatus(iobase), GetRXStatus(iobase));
/*
* if frame is receive complete at this routine ,then upload
spin_lock(&self->lock);
iHostIntType = GetHostStatus(iobase);
- IRDA_DEBUG(4, "%s(): iHostIntType %02x: %s %s %s %02x\n",
- __func__, iHostIntType,
- (iHostIntType & 0x40) ? "Timer" : "",
- (iHostIntType & 0x20) ? "Tx" : "",
- (iHostIntType & 0x10) ? "Rx" : "",
- (iHostIntType & 0x0e) >> 1);
+ pr_debug("%s(): iHostIntType %02x: %s %s %s %02x\n",
+ __func__, iHostIntType,
+ (iHostIntType & 0x40) ? "Timer" : "",
+ (iHostIntType & 0x20) ? "Tx" : "",
+ (iHostIntType & 0x10) ? "Rx" : "",
+ (iHostIntType & 0x0e) >> 1);
if ((iHostIntType & 0x40) != 0) { //Timer Event
self->EventFlag.TimeOut++;
if ((iHostIntType & 0x20) != 0) { //Tx Event
iTxIntType = GetTXStatus(iobase);
- IRDA_DEBUG(4, "%s(): iTxIntType %02x: %s %s %s %s\n",
- __func__, iTxIntType,
- (iTxIntType & 0x08) ? "FIFO underr." : "",
- (iTxIntType & 0x04) ? "EOM" : "",
- (iTxIntType & 0x02) ? "FIFO ready" : "",
- (iTxIntType & 0x01) ? "Early EOM" : "");
+ pr_debug("%s(): iTxIntType %02x: %s %s %s %s\n",
+ __func__, iTxIntType,
+ (iTxIntType & 0x08) ? "FIFO underr." : "",
+ (iTxIntType & 0x04) ? "EOM" : "",
+ (iTxIntType & 0x02) ? "FIFO ready" : "",
+ (iTxIntType & 0x01) ? "Early EOM" : "");
if (iTxIntType & 0x4) {
self->EventFlag.EOMessage++; // read and will auto clean
/* Check if DMA has finished */
iRxIntType = GetRXStatus(iobase);
- IRDA_DEBUG(4, "%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n",
- __func__, iRxIntType,
- (iRxIntType & 0x80) ? "PHY err." : "",
- (iRxIntType & 0x40) ? "CRC err" : "",
- (iRxIntType & 0x20) ? "FIFO overr." : "",
- (iRxIntType & 0x10) ? "EOF" : "",
- (iRxIntType & 0x08) ? "RxData" : "",
- (iRxIntType & 0x02) ? "RxMaxLen" : "",
- (iRxIntType & 0x01) ? "SIR bad" : "");
+ pr_debug("%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n",
+ __func__, iRxIntType,
+ (iRxIntType & 0x80) ? "PHY err." : "",
+ (iRxIntType & 0x40) ? "CRC err" : "",
+ (iRxIntType & 0x20) ? "FIFO overr." : "",
+ (iRxIntType & 0x10) ? "EOF" : "",
+ (iRxIntType & 0x08) ? "RxData" : "",
+ (iRxIntType & 0x02) ? "RxMaxLen" : "",
+ (iRxIntType & 0x01) ? "SIR bad" : "");
if (!iRxIntType)
- IRDA_DEBUG(3, "%s(): RxIRQ =0\n", __func__);
+ pr_debug("%s(): RxIRQ =0\n", __func__);
if (iRxIntType & 0x10) {
if (via_ircc_dma_receive_complete(self, iobase)) {
}
} // No ERR
else { //ERR
- IRDA_DEBUG(4, "%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n",
- __func__, iRxIntType, iHostIntType,
- RxCurCount(iobase, self),
- self->RxLastCount);
+ pr_debug("%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n",
+ __func__, iRxIntType, iHostIntType,
+ RxCurCount(iobase, self), self->RxLastCount);
if (iRxIntType & 0x20) { //FIFO OverRun ERR
ResetChip(iobase, 0);
int iobase;
iobase = self->io.fir_base;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
ResetChip(iobase, 5);
EnableDMA(iobase, OFF);
EnableTX(iobase, OFF);
if (CkRxRecv(iobase, self))
status = TRUE;
- IRDA_DEBUG(2, "%s(): status=%x....\n", __func__, status);
+ pr_debug("%s(): status=%x....\n", __func__, status);
return status;
}
int iobase;
char hwname[32];
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
dev->stats.rx_packets = 0;
IRDA_ASSERT(self != NULL, return 0;);
iobase = self->io.fir_base;
if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) {
- IRDA_WARNING("%s, unable to allocate irq=%d\n", driver_name,
- self->io.irq);
+ net_warn_ratelimited("%s, unable to allocate irq=%d\n",
+ driver_name, self->io.irq);
return -EAGAIN;
}
/*
* failure.
*/
if (request_dma(self->io.dma, dev->name)) {
- IRDA_WARNING("%s, unable to allocate dma=%d\n", driver_name,
- self->io.dma);
+ net_warn_ratelimited("%s, unable to allocate dma=%d\n",
+ driver_name, self->io.dma);
free_irq(self->io.irq, dev);
return -EAGAIN;
}
if (self->io.dma2 != self->io.dma) {
if (request_dma(self->io.dma2, dev->name)) {
- IRDA_WARNING("%s, unable to allocate dma2=%d\n",
- driver_name, self->io.dma2);
+ net_warn_ratelimited("%s, unable to allocate dma2=%d\n",
+ driver_name, self->io.dma2);
free_irq(self->io.irq, dev);
free_dma(self->io.dma);
return -EAGAIN;
struct via_ircc_cb *self;
int iobase;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return 0;);
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name,
- cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name,
+ cmd);
/* Disable interrupts & save flags */
spin_lock_irqsave(&self->lock, flags);
switch (cmd) {
if (rd->buf == NULL ||
!(busaddr = pci_map_single(pdev, rd->buf, len, dir))) {
if (rd->buf) {
- IRDA_ERROR("%s: failed to create PCI-MAP for %p",
- __func__, rd->buf);
+ net_err_ratelimited("%s: failed to create PCI-MAP for %p\n",
+ __func__, rd->buf);
kfree(rd->buf);
rd->buf = NULL;
}
ringarea = pci_zalloc_consistent(idev->pdev, HW_RING_AREA_SIZE,
&idev->busaddr);
- if (!ringarea) {
- IRDA_ERROR("%s: insufficient memory for descriptor rings\n",
- __func__);
+ if (!ringarea)
goto out;
- }
hwmap = (struct ring_descr_hw *)ringarea;
idev->rx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[1],
crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16);
len -= crclen; /* remove trailing CRC */
if (len <= 0) {
- IRDA_DEBUG(0, "%s: strange frame (len=%d)\n", __func__, len);
+ pr_debug("%s: strange frame (len=%d)\n", __func__, len);
ret |= VLSI_RX_DROP;
goto done;
}
*/
le16_to_cpus(rd->buf+len);
if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) {
- IRDA_DEBUG(0, "%s: crc error\n", __func__);
+ pr_debug("%s: crc error\n", __func__);
ret |= VLSI_RX_CRC;
goto done;
}
}
if (!rd->skb) {
- IRDA_WARNING("%s: rx packet lost\n", __func__);
+ net_warn_ratelimited("%s: rx packet lost\n", __func__);
ret |= VLSI_RX_DROP;
goto done;
}
for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) {
if (rd_is_active(rd)) {
- IRDA_WARNING("%s: driver bug: rx descr race with hw\n",
- __func__);
+ net_warn_ratelimited("%s: driver bug: rx descr race with hw\n",
+ __func__);
vlsi_ring_debug(r);
break;
}
if (ring_first(r) == NULL) {
/* we are in big trouble, if this should ever happen */
- IRDA_ERROR("%s: rx ring exhausted!\n", __func__);
+ net_err_ratelimited("%s: rx ring exhausted!\n", __func__);
vlsi_ring_debug(r);
}
else
if (rd_is_active(rd)) {
rd_set_status(rd, 0);
if (rd_get_count(rd)) {
- IRDA_DEBUG(0, "%s - dropping rx packet\n", __func__);
+ pr_debug("%s - dropping rx packet\n", __func__);
ret = -VLSI_RX_DROP;
}
rd_set_count(rd, 0);
int fifocnt;
baudrate = idev->new_baud;
- IRDA_DEBUG(2, "%s: %d -> %d\n", __func__, idev->baud, idev->new_baud);
+ pr_debug("%s: %d -> %d\n", __func__, idev->baud, idev->new_baud);
if (baudrate == 4000000) {
mode = IFF_FIR;
config = IRCFG_FIR;
config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY;
switch(baudrate) {
default:
- IRDA_WARNING("%s: undefined baudrate %d - fallback to 9600!\n",
- __func__, baudrate);
+ net_warn_ratelimited("%s: undefined baudrate %d - fallback to 9600!\n",
+ __func__, baudrate);
baudrate = 9600;
/* fallthru */
case 2400:
fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
if (fifocnt != 0) {
- IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __func__, fifocnt);
+ pr_debug("%s: rx fifo not empty(%d)\n", __func__, fifocnt);
}
outw(0, iobase+VLSI_PIO_IRENABLE);
config ^= IRENABLE_SIR_ON;
if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) {
- IRDA_WARNING("%s: failed to set %s mode!\n", __func__,
- (mode==IFF_SIR)?"SIR":((mode==IFF_MIR)?"MIR":"FIR"));
+ net_warn_ratelimited("%s: failed to set %s mode!\n",
+ __func__,
+ mode == IFF_SIR ? "SIR" :
+ mode == IFF_MIR ? "MIR" : "FIR");
ret = -1;
}
else {
if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) {
- IRDA_WARNING("%s: failed to apply baudrate %d\n",
- __func__, baudrate);
+ net_warn_ratelimited("%s: failed to apply baudrate %d\n",
+ __func__, baudrate);
ret = -1;
}
else {
*/
if (len >= r->len-5)
- IRDA_WARNING("%s: possible buffer overflow with SIR wrapping!\n",
- __func__);
+ net_warn_ratelimited("%s: possible buffer overflow with SIR wrapping!\n",
+ __func__);
}
else {
/* hw deals with MIR/FIR mode wrapping */
fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
if (fifocnt != 0) {
- IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __func__, fifocnt);
+ pr_debug("%s: rx fifo not empty(%d)\n",
+ __func__, fifocnt);
}
config = inw(iobase+VLSI_PIO_IRCFG);
if (ring_put(r) == NULL) {
netif_stop_queue(ndev);
- IRDA_DEBUG(3, "%s: tx ring full - queue stopped\n", __func__);
+ pr_debug("%s: tx ring full - queue stopped\n", __func__);
}
spin_unlock_irqrestore(&idev->lock, flags);
drop_unlock:
spin_unlock_irqrestore(&idev->lock, flags);
drop:
- IRDA_WARNING("%s: dropping packet - %s\n", __func__, msg);
+ net_warn_ratelimited("%s: dropping packet - %s\n", __func__, msg);
dev_kfree_skb_any(skb);
ndev->stats.tx_errors++;
ndev->stats.tx_dropped++;
fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
if (fifocnt != 0) {
- IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n",
- __func__, fifocnt);
+ pr_debug("%s: rx fifo not empty(%d)\n",
+ __func__, fifocnt);
}
outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
}
if (netif_queue_stopped(ndev) && !idev->new_baud) {
netif_wake_queue(ndev);
- IRDA_DEBUG(3, "%s: queue awoken\n", __func__);
+ pr_debug("%s: queue awoken\n", __func__);
}
}
dev_kfree_skb_any(rd->skb);
rd->skb = NULL;
}
- IRDA_DEBUG(0, "%s - dropping tx packet\n", __func__);
+ pr_debug("%s - dropping tx packet\n", __func__);
ret = -VLSI_TX_DROP;
}
else
}
if (count < 3) {
if (clksrc == 1) { /* explicitly asked for PLL hence bail out */
- IRDA_ERROR("%s: no PLL or failed to lock!\n",
- __func__);
+ net_err_ratelimited("%s: no PLL or failed to lock!\n",
+ __func__);
clkctl = CLKCTL_CLKSTP;
pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
return -1;
else /* was: clksrc=0(auto) */
clksrc = 3; /* fallback to 40MHz XCLK (OB800) */
- IRDA_DEBUG(0, "%s: PLL not locked, fallback to clksrc=%d\n",
- __func__, clksrc);
+ pr_debug("%s: PLL not locked, fallback to clksrc=%d\n",
+ __func__, clksrc);
}
else
clksrc = 1; /* got successful PLL lock */
/* start the clock and clean the registers */
if (vlsi_start_clock(pdev)) {
- IRDA_ERROR("%s: no valid clock source\n", __func__);
+ net_err_ratelimited("%s: no valid clock source\n", __func__);
return -1;
}
iobase = ndev->base_addr;
idev->new_baud = idev->baud; /* keep current baudrate */
if (vlsi_start_hw(idev))
- IRDA_ERROR("%s: failed to restart hw - %s(%s) unusable!\n",
- __func__, pci_name(idev->pdev), ndev->name);
+ net_err_ratelimited("%s: failed to restart hw - %s(%s) unusable!\n",
+ __func__, pci_name(idev->pdev), ndev->name);
else
netif_start_queue(ndev);
}
irq->ifr_receiving = (fifocnt!=0) ? 1 : 0;
break;
default:
- IRDA_WARNING("%s: notsupp - cmd=%04x\n",
- __func__, cmd);
+ net_warn_ratelimited("%s: notsupp - cmd=%04x\n",
+ __func__, cmd);
ret = -EOPNOTSUPP;
}
spin_unlock_irqrestore(&idev->lock,flags);
if (boguscount <= 0)
- IRDA_MESSAGE("%s: too much work in interrupt!\n",
- __func__);
+ net_info_ratelimited("%s: too much work in interrupt!\n",
+ __func__);
return IRQ_RETVAL(handled);
}
char hwname[32];
if (pci_request_regions(idev->pdev, drivername)) {
- IRDA_WARNING("%s: io resource busy\n", __func__);
+ net_warn_ratelimited("%s: io resource busy\n", __func__);
goto errout;
}
ndev->base_addr = pci_resource_start(idev->pdev,0);
if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED,
drivername, ndev)) {
- IRDA_WARNING("%s: couldn't get IRQ: %d\n",
- __func__, ndev->irq);
+ net_warn_ratelimited("%s: couldn't get IRQ: %d\n",
+ __func__, ndev->irq);
goto errout_io;
}
netif_start_queue(ndev);
- IRDA_MESSAGE("%s: device %s operational\n", __func__, ndev->name);
+ net_info_ratelimited("%s: device %s operational\n",
+ __func__, ndev->name);
return 0;
pci_release_regions(idev->pdev);
- IRDA_MESSAGE("%s: device %s stopped\n", __func__, ndev->name);
+ net_info_ratelimited("%s: device %s stopped\n", __func__, ndev->name);
return 0;
}
if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) ||
pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) {
- IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __func__);
+ net_err_ratelimited("%s: aborting due to PCI BM-DMA address limitations\n",
+ __func__);
return -1;
}
else
pdev->current_state = 0; /* hw must be running now */
- IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n",
- drivername, pci_name(pdev));
+ net_info_ratelimited("%s: IrDA PCI controller %s detected\n",
+ drivername, pci_name(pdev));
if ( !pci_resource_start(pdev,0) ||
!(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) {
- IRDA_ERROR("%s: bar 0 invalid", __func__);
+ net_err_ratelimited("%s: bar 0 invalid", __func__);
goto out_disable;
}
ndev = alloc_irdadev(sizeof(*idev));
if (ndev==NULL) {
- IRDA_ERROR("%s: Unable to allocate device memory.\n",
- __func__);
+ net_err_ratelimited("%s: Unable to allocate device memory.\n",
+ __func__);
goto out_disable;
}
goto out_freedev;
if (register_netdev(ndev) < 0) {
- IRDA_ERROR("%s: register_netdev failed\n", __func__);
+ net_err_ratelimited("%s: register_netdev failed\n", __func__);
goto out_freedev;
}
ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO,
vlsi_proc_root, VLSI_PROC_FOPS, ndev);
if (!ent) {
- IRDA_WARNING("%s: failed to create proc entry\n",
- __func__);
+ net_warn_ratelimited("%s: failed to create proc entry\n",
+ __func__);
} else {
proc_set_size(ent, 0);
}
idev->proc_entry = ent;
}
- IRDA_MESSAGE("%s: registered device %s\n", drivername, ndev->name);
+ net_info_ratelimited("%s: registered device %s\n",
+ drivername, ndev->name);
pci_set_drvdata(pdev, ndev);
mutex_unlock(&idev->mtx);
vlsi_irda_dev_t *idev;
if (!ndev) {
- IRDA_ERROR("%s: lost netdevice?\n", drivername);
+ net_err_ratelimited("%s: lost netdevice?\n", drivername);
return;
}
free_netdev(ndev);
- IRDA_MESSAGE("%s: %s removed\n", drivername, pci_name(pdev));
+ net_info_ratelimited("%s: %s removed\n", drivername, pci_name(pdev));
}
#ifdef CONFIG_PM
vlsi_irda_dev_t *idev;
if (!ndev) {
- IRDA_ERROR("%s - %s: no netdevice\n",
- __func__, pci_name(pdev));
+ net_err_ratelimited("%s - %s: no netdevice\n",
+ __func__, pci_name(pdev));
return 0;
}
idev = netdev_priv(ndev);
pdev->current_state = state.event;
}
else
- IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __func__, pci_name(pdev), pdev->current_state, state.event);
+ net_err_ratelimited("%s - %s: invalid suspend request %u -> %u\n",
+ __func__, pci_name(pdev),
+ pdev->current_state, state.event);
mutex_unlock(&idev->mtx);
return 0;
}
vlsi_irda_dev_t *idev;
if (!ndev) {
- IRDA_ERROR("%s - %s: no netdevice\n",
- __func__, pci_name(pdev));
+ net_err_ratelimited("%s - %s: no netdevice\n",
+ __func__, pci_name(pdev));
return 0;
}
idev = netdev_priv(ndev);
mutex_lock(&idev->mtx);
if (pdev->current_state == 0) {
mutex_unlock(&idev->mtx);
- IRDA_WARNING("%s - %s: already resumed\n",
- __func__, pci_name(pdev));
+ net_warn_ratelimited("%s - %s: already resumed\n",
+ __func__, pci_name(pdev));
return 0;
}
* now we explicitly set pdev->current_state = 0 after enabling the
* device and independently resume_ok should catch any garbage config.
*/
- IRDA_WARNING("%s - hm, nothing to resume?\n", __func__);
+ net_warn_ratelimited("%s - hm, nothing to resume?\n", __func__);
mutex_unlock(&idev->mtx);
return 0;
}
int i, ret;
if (clksrc < 0 || clksrc > 3) {
- IRDA_ERROR("%s: invalid clksrc=%d\n", drivername, clksrc);
+ net_err_ratelimited("%s: invalid clksrc=%d\n",
+ drivername, clksrc);
return -1;
}
case 64:
break;
default:
- IRDA_WARNING("%s: invalid %s ringsize %d, using default=8", drivername, (i)?"rx":"tx", ringsize[i]);
+ net_warn_ratelimited("%s: invalid %s ringsize %d, using default=8\n",
+ drivername,
+ i ? "rx" : "tx",
+ ringsize[i]);
ringsize[i] = 8;
break;
}
*/
if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {
- IRDA_ERROR("%s: pci busaddr inconsistency!\n", __func__);
+ net_err_ratelimited("%s: pci busaddr inconsistency!\n",
+ __func__);
dump_stack();
return;
}
{
int i;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
for (i=0; i < ARRAY_SIZE(dev_self) && io[i] < 2000; i++) {
if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)
return 0;
{
int i;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
w83977af_close(dev_self[i]);
struct w83977af_ir *self;
int err;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
/* Lock the port that we need */
if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) {
- IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
- __func__ , iobase);
+ pr_debug("%s(), can't get iobase of 0x%03x\n",
+ __func__ , iobase);
return -ENODEV;
}
err = register_netdev(dev);
if (err) {
- IRDA_ERROR("%s(), register_netdevice() failed!\n", __func__);
+ net_err_ratelimited("%s(), register_netdevice() failed!\n",
+ __func__);
goto err_out3;
}
- IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name);
+ net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
/* Need to store self somewhere */
dev_self[i] = self;
{
int iobase;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
iobase = self->io.fir_base;
#ifdef CONFIG_USE_W977_PNP
unregister_netdev(self->netdev);
/* Release the PORT that this driver is using */
- IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n",
- __func__ , self->io.fir_base);
+ pr_debug("%s(), Releasing Region %03x\n",
+ __func__ , self->io.fir_base);
release_region(self->io.fir_base, self->io.fir_ext);
if (self->tx_buff.head)
int i;
for (i=0; i < 2; i++) {
- IRDA_DEBUG( 0, "%s()\n", __func__ );
#ifdef CONFIG_USE_W977_PNP
/* Enter PnP configuration mode */
w977_efm_enter(efbase[i]);
switch_bank(iobase, SET7);
outb(0x40, iobase+7);
- IRDA_MESSAGE("W83977AF (IR) driver loaded. "
- "Version: 0x%02x\n", version);
+ net_info_ratelimited("W83977AF (IR) driver loaded. Version: 0x%02x\n",
+ version);
return 0;
} else {
/* Try next extented function register address */
- IRDA_DEBUG( 0, "%s(), Wrong chip version", __func__ );
+ pr_debug("%s(), Wrong chip version", __func__);
}
}
return -1;
case 115200: outb(0x01, iobase+ABLL); break;
case 576000:
ir_mode = HCR_MIR_576;
- IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__ );
+ pr_debug("%s(), handling baud of 576000\n", __func__);
break;
case 1152000:
ir_mode = HCR_MIR_1152;
- IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __func__ );
+ pr_debug("%s(), handling baud of 1152000\n", __func__);
break;
case 4000000:
ir_mode = HCR_FIR;
- IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __func__ );
+ pr_debug("%s(), handling baud of 4000000\n", __func__);
break;
default:
ir_mode = HCR_FIR;
- IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __func__ , speed);
+ pr_debug("%s(), unknown baud rate of %d\n", __func__ , speed);
break;
}
iobase = self->io.fir_base;
- IRDA_DEBUG(4, "%s(%ld), skb->len=%d\n", __func__ , jiffies,
- (int) skb->len);
+ pr_debug("%s(%ld), skb->len=%d\n", __func__ , jiffies,
+ (int)skb->len);
/* Lock transmit buffer */
netif_stop_queue(dev);
self->tx_buff.len = skb->len;
mtt = irda_get_mtt(skb);
- IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);
+ pr_debug("%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);
if (mtt)
udelay(mtt);
static void w83977af_dma_write(struct w83977af_ir *self, int iobase)
{
__u8 set;
- IRDA_DEBUG(4, "%s(), len=%d\n", __func__ , self->tx_buff.len);
+ pr_debug("%s(), len=%d\n", __func__ , self->tx_buff.len);
/* Save current set */
set = inb(iobase+SSR);
int actual = 0;
__u8 set;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
/* Save current bank */
set = inb(iobase+SSR);
switch_bank(iobase, SET0);
if (!(inb_p(iobase+USR) & USR_TSRE)) {
- IRDA_DEBUG(4,
- "%s(), warning, FIFO not empty yet!\n", __func__ );
+ pr_debug("%s(), warning, FIFO not empty yet!\n", __func__);
fifo_size -= 17;
- IRDA_DEBUG(4, "%s(), %d bytes left in tx fifo\n",
- __func__ , fifo_size);
+ pr_debug("%s(), %d bytes left in tx fifo\n",
+ __func__ , fifo_size);
}
/* Fill FIFO with current frame */
outb(buf[actual++], iobase+TBR);
}
- IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n",
- __func__ , fifo_size, actual, len);
+ pr_debug("%s(), fifo_size %d ; %d sent of %d\n",
+ __func__ , fifo_size, actual, len);
/* Restore bank */
outb(set, iobase+SSR);
int iobase;
__u8 set;
- IRDA_DEBUG(4, "%s(%ld)\n", __func__ , jiffies);
+ pr_debug("%s(%ld)\n", __func__ , jiffies);
IRDA_ASSERT(self != NULL, return;);
/* Check for underrun! */
if (inb(iobase+AUDR) & AUDR_UNDR) {
- IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __func__ );
+ pr_debug("%s(), Transmit underrun!\n", __func__);
self->netdev->stats.tx_errors++;
self->netdev->stats.tx_fifo_errors++;
#endif
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(4, "%s\n", __func__ );
+ pr_debug("%s\n", __func__);
iobase= self->io.fir_base;
__u8 set;
__u8 status;
- IRDA_DEBUG(4, "%s\n", __func__ );
+ pr_debug("%s\n", __func__);
st_fifo = &self->st_fifo;
__u8 byte = 0x00;
int iobase;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
iobase = self->io.fir_base;
__u8 set;
int iobase;
- IRDA_DEBUG(4, "%s(), isr=%#x\n", __func__ , isr);
+ pr_debug("%s(), isr=%#x\n", __func__ , isr);
iobase = self->io.fir_base;
/* Transmit FIFO low on data */
if (isr & ISR_TXEMP_I) {
/* Check if we need to change the speed? */
if (self->new_speed) {
- IRDA_DEBUG(2,
- "%s(), Changing speed!\n", __func__ );
+ pr_debug("%s(), Changing speed!\n", __func__);
w83977af_change_speed(self, self->new_speed);
self->new_speed = 0;
}
char hwname[32];
__u8 set;
- IRDA_DEBUG(0, "%s()\n", __func__ );
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
int iobase;
__u8 set;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
IRDA_ASSERT(self != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd);
+ pr_debug("%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd);
spin_lock_irqsave(&self->lock, flags);
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/fs.h>
+#include <linux/uio.h>
#include <net/ipv6.h>
#include <net/net_namespace.h>
/* Put packet to the user space buffer */
static ssize_t macvtap_put_user(struct macvtap_queue *q,
const struct sk_buff *skb,
- const struct iovec *iv, int len)
+ struct iov_iter *iter)
{
int ret;
int vnet_hdr_len = 0;
int vlan_offset = 0;
- int copied, total;
+ int total;
if (q->flags & IFF_VNET_HDR) {
struct virtio_net_hdr vnet_hdr;
vnet_hdr_len = q->vnet_hdr_sz;
- if ((len -= vnet_hdr_len) < 0)
+ if (iov_iter_count(iter) < vnet_hdr_len)
return -EINVAL;
macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
- if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
+ if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
+ sizeof(vnet_hdr))
return -EFAULT;
}
- total = copied = vnet_hdr_len;
+ total = vnet_hdr_len;
total += skb->len;
- if (!vlan_tx_tag_present(skb))
- len = min_t(int, skb->len, len);
- else {
- int copy;
+ if (vlan_tx_tag_present(skb)) {
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
- len = min_t(int, skb->len + VLAN_HLEN, len);
total += VLAN_HLEN;
- copy = min_t(int, vlan_offset, len);
- ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
- len -= copy;
- copied += copy;
- if (ret || !len)
+ ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
+ if (ret || !iov_iter_count(iter))
goto done;
- copy = min_t(int, sizeof(veth), len);
- ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy);
- len -= copy;
- copied += copy;
- if (ret || !len)
+ ret = copy_to_iter(&veth, sizeof(veth), iter);
+ if (ret != sizeof(veth) || !iov_iter_count(iter))
goto done;
}
- ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
+ ret = skb_copy_datagram_iter(skb, vlan_offset, iter,
+ skb->len - vlan_offset);
done:
return ret ? ret : total;
}
static ssize_t macvtap_do_read(struct macvtap_queue *q,
- const struct iovec *iv, unsigned long len,
+ const struct iovec *iv, unsigned long segs,
+ unsigned long len,
int noblock)
{
DEFINE_WAIT(wait);
struct sk_buff *skb;
ssize_t ret = 0;
+ struct iov_iter iter;
while (len) {
if (!noblock)
schedule();
continue;
}
- ret = macvtap_put_user(q, skb, iv, len);
+ iov_iter_init(&iter, READ, iv, segs, len);
+ ret = macvtap_put_user(q, skb, &iter);
kfree_skb(skb);
break;
}
goto out;
}
- ret = macvtap_do_read(q, iv, len, file->f_flags & O_NONBLOCK);
+ ret = macvtap_do_read(q, iv, count, len, file->f_flags & O_NONBLOCK);
ret = min_t(ssize_t, ret, len);
if (ret > 0)
iocb->ki_pos = ret;
int ret;
if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
return -EINVAL;
- ret = macvtap_do_read(q, m->msg_iov, total_len,
+ ret = macvtap_do_read(q, m->msg_iov, m->msg_iovlen, total_len,
flags & MSG_DONTWAIT);
if (ret > total_len) {
m->msg_flags |= MSG_TRUNC;
config AMD_XGBE_PHY
tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
- depends on OF
+ depends on OF && HAS_IOMEM
---help---
Currently supports the AMD 10GbE PHY
if (ret & MDIO_CTRL1_RESET)
return -ETIMEDOUT;
- return 0;
+ /* Make sure the XPCS and SerDes are in compatible states */
+ return amd_xgbe_phy_xgmii_mode(phydev);
}
static int amd_xgbe_phy_config_init(struct phy_device *phydev)
},
};
-static int __init amd_xgbe_phy_init(void)
-{
- return phy_drivers_register(amd_xgbe_phy_driver,
- ARRAY_SIZE(amd_xgbe_phy_driver));
-}
-
-static void __exit amd_xgbe_phy_exit(void)
-{
- phy_drivers_unregister(amd_xgbe_phy_driver,
- ARRAY_SIZE(amd_xgbe_phy_driver));
-}
-
-module_init(amd_xgbe_phy_init);
-module_exit(amd_xgbe_phy_exit);
+module_phy_driver(amd_xgbe_phy_driver);
static struct mdio_device_id __maybe_unused amd_xgbe_phy_ids[] = {
{ XGBE_PHY_ID, XGBE_PHY_MASK },
return err;
}
-static struct phy_driver am79c_driver = {
+static struct phy_driver am79c_driver[] = { {
.phy_id = PHY_ID_AM79C874,
.name = "AM79C874",
.phy_id_mask = 0xfffffff0,
.ack_interrupt = am79c_ack_interrupt,
.config_intr = am79c_config_intr,
.driver = { .owner = THIS_MODULE,},
-};
-
-static int __init am79c_init(void)
-{
- return phy_driver_register(&am79c_driver);
-}
-
-static void __exit am79c_exit(void)
-{
- phy_driver_unregister(&am79c_driver);
-}
+} };
-module_init(am79c_init);
-module_exit(am79c_exit);
+module_phy_driver(am79c_driver);
static struct mdio_device_id __maybe_unused amd_tbl[] = {
{ PHY_ID_AM79C874, 0xfffffff0 },
},
} };
-static int __init atheros_init(void)
-{
- return phy_drivers_register(at803x_driver,
- ARRAY_SIZE(at803x_driver));
-}
-
-static void __exit atheros_exit(void)
-{
- phy_drivers_unregister(at803x_driver, ARRAY_SIZE(at803x_driver));
-}
-
-module_init(atheros_init);
-module_exit(atheros_exit);
+module_phy_driver(at803x_driver);
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
{ ATH8030_PHY_ID, 0xffffffef },
.driver = { .owner = THIS_MODULE },
} };
-static int __init bcm63xx_phy_init(void)
-{
- return phy_drivers_register(bcm63xx_driver,
- ARRAY_SIZE(bcm63xx_driver));
-}
-
-static void __exit bcm63xx_phy_exit(void)
-{
- phy_drivers_unregister(bcm63xx_driver,
- ARRAY_SIZE(bcm63xx_driver));
-}
-
-module_init(bcm63xx_phy_init);
-module_exit(bcm63xx_phy_exit);
+module_phy_driver(bcm63xx_driver);
static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = {
{ 0x00406000, 0xfffffc00 },
#define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0)
#define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1)
+#define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2)
#define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3)
#define AFE_TX_CONFIG MISC_ADDR(0x39, 0)
+#define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1)
+#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3)
#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0)
#define CORE_EXPB0 0xb0
-static int bcm7445_config_init(struct phy_device *phydev)
-{
- int ret;
- const struct bcm7445_regs {
- int reg;
- u16 value;
- } bcm7445_regs_cfg[] = {
- /* increases ADC latency by 24ns */
- { MII_BCM54XX_EXP_SEL, 0x0038 },
- { MII_BCM54XX_EXP_DATA, 0xAB95 },
- /* increases internal 1V LDO voltage by 5% */
- { MII_BCM54XX_EXP_SEL, 0x2038 },
- { MII_BCM54XX_EXP_DATA, 0xBB22 },
- /* reduce RX low pass filter corner frequency */
- { MII_BCM54XX_EXP_SEL, 0x6038 },
- { MII_BCM54XX_EXP_DATA, 0xFFC5 },
- /* reduce RX high pass filter corner frequency */
- { MII_BCM54XX_EXP_SEL, 0x003a },
- { MII_BCM54XX_EXP_DATA, 0x2002 },
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) {
- ret = phy_write(phydev,
- bcm7445_regs_cfg[i].reg,
- bcm7445_regs_cfg[i].value);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static void phy_write_exp(struct phy_device *phydev,
u16 reg, u16 value)
{
phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
}
-static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
+static void r_rc_cal_reset(struct phy_device *phydev)
+{
+ /* Reset R_CAL/RC_CAL Engine */
+ phy_write_exp(phydev, 0x00b0, 0x0010);
+
+ /* Disable Reset R_AL/RC_CAL Engine */
+ phy_write_exp(phydev, 0x00b0, 0x0000);
+}
+
+static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
{
/* Increase VCO range to prevent unlocking problem of PLL at low
* temp
/* Switch to CORE_BASE1E */
phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
- /* Reset R_CAL/RC_CAL Engine */
- phy_write_exp(phydev, CORE_EXPB0, 0x0010);
-
- /* Disable Reset R_CAL/RC_CAL Engine */
- phy_write_exp(phydev, CORE_EXPB0, 0x0000);
+ r_rc_cal_reset(phydev);
/* write AFE_RXCONFIG_0 */
phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
return 0;
}
+static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
+{
+ /* AFE_RXCONFIG_0 */
+ phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
+
+ /* AFE_RXCONFIG_1 */
+ phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
+
+ /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
+ phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
+
+ /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
+ phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
+
+ /* AFE_TX_CONFIG, set 1000BT Cfeed=110 for all ports */
+ phy_write_misc(phydev, AFE_TX_CONFIG, 0x0061);
+
+ /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
+ phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
+
+ /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
+ phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
+
+ /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
+ * offset for HT=0 code
+ */
+ phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
+
+ /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
+ phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
+
+ /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
+ phy_write_misc(phydev, DSP_TAP10, 0x011b);
+
+ /* Reset R_CAL/RC_CAL engine */
+ r_rc_cal_reset(phydev);
+
+ return 0;
+}
+
+static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
+{
+ /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
+ phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
+
+ /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
+ phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
+
+ /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
+ * offset for HT=0 code
+ */
+ phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
+
+ /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
+ phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
+
+ /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
+ phy_write_misc(phydev, DSP_TAP10, 0x011b);
+
+ /* Reset R_CAL/RC_CAL engine */
+ r_rc_cal_reset(phydev);
+
+ return 0;
+}
+
static int bcm7xxx_apd_enable(struct phy_device *phydev)
{
int val;
u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
int ret = 0;
- dev_info(&phydev->dev, "PHY revision: 0x%02x, patch: %d\n", rev, patch);
+ pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
+ dev_name(&phydev->dev), phydev->drv->name, rev, patch);
switch (rev) {
- case 0xa0:
case 0xb0:
- ret = bcm7445_config_init(phydev);
+ ret = bcm7xxx_28nm_b0_afe_config_init(phydev);
+ break;
+ case 0xd0:
+ ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
+ break;
+ case 0xe0:
+ case 0xf0:
+ ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
break;
default:
- ret = bcm7xxx_28nm_afe_config_init(phydev);
break;
}
.features = PHY_GBIT_FEATURES | \
SUPPORTED_Pause | SUPPORTED_Asym_Pause, \
.flags = PHY_IS_INTERNAL, \
- .config_init = bcm7xxx_28nm_afe_config_init, \
+ .config_init = bcm7xxx_28nm_config_init, \
.config_aneg = genphy_config_aneg, \
.read_status = genphy_read_status, \
.resume = bcm7xxx_28nm_resume, \
{ }
};
-static int __init bcm7xxx_phy_init(void)
-{
- return phy_drivers_register(bcm7xxx_driver,
- ARRAY_SIZE(bcm7xxx_driver));
-}
-
-static void __exit bcm7xxx_phy_exit(void)
-{
- phy_drivers_unregister(bcm7xxx_driver,
- ARRAY_SIZE(bcm7xxx_driver));
-}
-
-module_init(bcm7xxx_phy_init);
-module_exit(bcm7xxx_phy_exit);
+module_phy_driver(bcm7xxx_driver);
MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
.driver = { .owner = THIS_MODULE },
} };
-static int __init bcm87xx_init(void)
-{
- return phy_drivers_register(bcm87xx_driver,
- ARRAY_SIZE(bcm87xx_driver));
-}
-module_init(bcm87xx_init);
-
-static void __exit bcm87xx_exit(void)
-{
- phy_drivers_unregister(bcm87xx_driver,
- ARRAY_SIZE(bcm87xx_driver));
-}
-module_exit(bcm87xx_exit);
+module_phy_driver(bcm87xx_driver);
MODULE_LICENSE("GPL");
.driver = { .owner = THIS_MODULE },
} };
-static int __init broadcom_init(void)
-{
- return phy_drivers_register(broadcom_drivers,
- ARRAY_SIZE(broadcom_drivers));
-}
-
-static void __exit broadcom_exit(void)
-{
- phy_drivers_unregister(broadcom_drivers,
- ARRAY_SIZE(broadcom_drivers));
-}
-
-module_init(broadcom_init);
-module_exit(broadcom_exit);
+module_phy_driver(broadcom_drivers);
static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM5411, 0xfffffff0 },
.driver = { .owner = THIS_MODULE,},
} };
-static int __init cicada_init(void)
-{
- return phy_drivers_register(cis820x_driver,
- ARRAY_SIZE(cis820x_driver));
-}
-
-static void __exit cicada_exit(void)
-{
- phy_drivers_unregister(cis820x_driver,
- ARRAY_SIZE(cis820x_driver));
-}
-
-module_init(cicada_init);
-module_exit(cicada_exit);
+module_phy_driver(cis820x_driver);
static struct mdio_device_id __maybe_unused cicada_tbl[] = {
{ 0x000fc410, 0x000ffff0 },
.driver = { .owner = THIS_MODULE,},
} };
-static int __init davicom_init(void)
-{
- return phy_drivers_register(dm91xx_driver,
- ARRAY_SIZE(dm91xx_driver));
-}
-
-static void __exit davicom_exit(void)
-{
- phy_drivers_unregister(dm91xx_driver,
- ARRAY_SIZE(dm91xx_driver));
-}
-
-module_init(davicom_init);
-module_exit(davicom_exit);
+module_phy_driver(dm91xx_driver);
static struct mdio_device_id __maybe_unused davicom_tbl[] = {
{ 0x0181b880, 0x0ffffff0 },
return ret;
}
-static struct phy_driver et1011c_driver = {
+static struct phy_driver et1011c_driver[] = { {
.phy_id = 0x0282f014,
.name = "ET1011C",
.phy_id_mask = 0xfffffff0,
.config_aneg = et1011c_config_aneg,
.read_status = et1011c_read_status,
.driver = { .owner = THIS_MODULE,},
-};
-
-static int __init et1011c_init(void)
-{
- return phy_driver_register(&et1011c_driver);
-}
-
-static void __exit et1011c_exit(void)
-{
- phy_driver_unregister(&et1011c_driver);
-}
+} };
-module_init(et1011c_init);
-module_exit(et1011c_exit);
+module_phy_driver(et1011c_driver);
static struct mdio_device_id __maybe_unused et1011c_tbl[] = {
{ 0x0282f014, 0xfffffff0 },
.driver = { .owner = THIS_MODULE,},
} };
-static int __init icplus_init(void)
-{
- return phy_drivers_register(icplus_driver,
- ARRAY_SIZE(icplus_driver));
-}
-
-static void __exit icplus_exit(void)
-{
- phy_drivers_unregister(icplus_driver,
- ARRAY_SIZE(icplus_driver));
-}
-
-module_init(icplus_init);
-module_exit(icplus_exit);
+module_phy_driver(icplus_driver);
static struct mdio_device_id __maybe_unused icplus_tbl[] = {
{ 0x02430d80, 0x0ffffff0 },
.driver = { .owner = THIS_MODULE,},
} };
-static int __init lxt_init(void)
-{
- return phy_drivers_register(lxt97x_driver,
- ARRAY_SIZE(lxt97x_driver));
-}
-
-static void __exit lxt_exit(void)
-{
- phy_drivers_unregister(lxt97x_driver,
- ARRAY_SIZE(lxt97x_driver));
-}
-
-module_init(lxt_init);
-module_exit(lxt_exit);
+module_phy_driver(lxt97x_driver);
static struct mdio_device_id __maybe_unused lxt_tbl[] = {
{ 0x78100000, 0xfffffff0 },
#define MII_M1145_PHY_EXT_CR 0x14
#define MII_M1145_RGMII_RX_DELAY 0x0080
#define MII_M1145_RGMII_TX_DELAY 0x0002
+#define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4
+#define MII_M1145_HWCFG_MODE_MASK 0xf
+#define MII_M1145_HWCFG_FIBER_COPPER_AUTO 0x8000
#define MII_M1145_HWCFG_MODE_SGMII_NO_CLK 0x4
#define MII_M1145_HWCFG_MODE_MASK 0xf
#define MII_M1116R_CONTROL_REG_MAC 21
+#define MII_88E3016_PHY_SPEC_CTRL 0x10
+#define MII_88E3016_DISABLE_SCRAMBLER 0x0200
+#define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
return 0;
}
+static int m88e3016_config_init(struct phy_device *phydev)
+{
+ int reg;
+
+ /* Enable Scrambler and Auto-Crossover */
+ reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~MII_88E3016_DISABLE_SCRAMBLER;
+ reg |= MII_88E3016_AUTO_MDIX_CROSSOVER;
+
+ reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg);
+ if (reg < 0)
+ return reg;
+
+ return 0;
+}
+
static int m88e1111_config_init(struct phy_device *phydev)
{
int err;
static int m88e1145_config_init(struct phy_device *phydev)
{
int err;
+ int temp;
/* Take care of errata E0 & E1 */
err = phy_write(phydev, 0x1d, 0x001b);
}
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
- int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
+ temp = phy_read(phydev, MII_M1145_PHY_EXT_SR);
if (temp < 0)
return temp;
return 0;
}
+static int marvell_aneg_done(struct phy_device *phydev)
+{
+ int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
+ return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED);
+}
+
static int m88e1121_did_interrupt(struct phy_device *phydev)
{
int imask;
.suspend = &genphy_suspend,
.driver = { .owner = THIS_MODULE },
},
+ {
+ .phy_id = MARVELL_PHY_ID_88E3016,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E3016",
+ .features = PHY_BASIC_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .config_init = &m88e3016_config_init,
+ .aneg_done = &marvell_aneg_done,
+ .read_status = &marvell_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .did_interrupt = &m88e1121_did_interrupt,
+ .resume = &genphy_resume,
+ .suspend = &genphy_suspend,
+ .driver = { .owner = THIS_MODULE },
+ },
};
-static int __init marvell_init(void)
-{
- return phy_drivers_register(marvell_drivers,
- ARRAY_SIZE(marvell_drivers));
-}
-
-static void __exit marvell_exit(void)
-{
- phy_drivers_unregister(marvell_drivers,
- ARRAY_SIZE(marvell_drivers));
-}
-
-module_init(marvell_init);
-module_exit(marvell_exit);
+module_phy_driver(marvell_drivers);
static struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
{ }
};
/* Operation Mode Strap Override */
#define MII_KSZPHY_OMSO 0x16
-#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
-#define KSZPHY_OMSO_RMII_OVERRIDE (1 << 1)
-#define KSZPHY_OMSO_MII_OVERRIDE (1 << 0)
+#define KSZPHY_OMSO_B_CAST_OFF BIT(9)
+#define KSZPHY_OMSO_RMII_OVERRIDE BIT(1)
+#define KSZPHY_OMSO_MII_OVERRIDE BIT(0)
/* general Interrupt control/status reg in vendor specific block. */
#define MII_KSZPHY_INTCS 0x1B
-#define KSZPHY_INTCS_JABBER (1 << 15)
-#define KSZPHY_INTCS_RECEIVE_ERR (1 << 14)
-#define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13)
-#define KSZPHY_INTCS_PARELLEL (1 << 12)
-#define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11)
-#define KSZPHY_INTCS_LINK_DOWN (1 << 10)
-#define KSZPHY_INTCS_REMOTE_FAULT (1 << 9)
-#define KSZPHY_INTCS_LINK_UP (1 << 8)
+#define KSZPHY_INTCS_JABBER BIT(15)
+#define KSZPHY_INTCS_RECEIVE_ERR BIT(14)
+#define KSZPHY_INTCS_PAGE_RECEIVE BIT(13)
+#define KSZPHY_INTCS_PARELLEL BIT(12)
+#define KSZPHY_INTCS_LINK_PARTNER_ACK BIT(11)
+#define KSZPHY_INTCS_LINK_DOWN BIT(10)
+#define KSZPHY_INTCS_REMOTE_FAULT BIT(9)
+#define KSZPHY_INTCS_LINK_UP BIT(8)
#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\
KSZPHY_INTCS_LINK_DOWN)
-/* general PHY control reg in vendor specific block. */
-#define MII_KSZPHY_CTRL 0x1F
+/* PHY Control 1 */
+#define MII_KSZPHY_CTRL_1 0x1e
+
+/* PHY Control 2 / PHY Control (if no PHY Control 1) */
+#define MII_KSZPHY_CTRL_2 0x1f
+#define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2
/* bitmap of PHY register to set interrupt mode */
-#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9)
-#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14)
-#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
-#define KSZ8051_RMII_50MHZ_CLK (1 << 7)
+#define KSZPHY_CTRL_INT_ACTIVE_HIGH BIT(9)
+#define KSZ9021_CTRL_INT_ACTIVE_HIGH BIT(14)
+#define KS8737_CTRL_INT_ACTIVE_HIGH BIT(14)
+#define KSZ8051_RMII_50MHZ_CLK BIT(7)
/* Write/read to/from extended registers */
#define MII_KSZPHY_EXTREG 0x0b
/* set the interrupt pin active low */
temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ if (temp < 0)
+ return temp;
temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
phy_write(phydev, MII_KSZPHY_CTRL, temp);
rc = kszphy_set_interrupt(phydev);
/* set the interrupt pin active low */
temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ if (temp < 0)
+ return temp;
temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
phy_write(phydev, MII_KSZPHY_CTRL, temp);
rc = kszphy_set_interrupt(phydev);
/* set the interrupt pin active low */
temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ if (temp < 0)
+ return temp;
temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
phy_write(phydev, MII_KSZPHY_CTRL, temp);
rc = kszphy_set_interrupt(phydev);
return rc < 0 ? rc : 0;
}
-static int kszphy_setup_led(struct phy_device *phydev,
- unsigned int reg, unsigned int shift)
+static int kszphy_setup_led(struct phy_device *phydev, u32 reg)
{
struct device *dev = &phydev->dev;
struct device_node *of_node = dev->of_node;
- int rc, temp;
+ int rc, temp, shift;
u32 val;
if (!of_node && dev->parent->of_node)
if (of_property_read_u32(of_node, "micrel,led-mode", &val))
return 0;
+ if (val > 3) {
+ dev_err(&phydev->dev, "invalid led mode: 0x%02x\n", val);
+ return -EINVAL;
+ }
+
+ switch (reg) {
+ case MII_KSZPHY_CTRL_1:
+ shift = 14;
+ break;
+ case MII_KSZPHY_CTRL_2:
+ shift = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
temp = phy_read(phydev, reg);
- if (temp < 0)
- return temp;
+ if (temp < 0) {
+ rc = temp;
+ goto out;
+ }
temp &= ~(3 << shift);
temp |= val << shift;
rc = phy_write(phydev, reg, temp);
+out:
+ if (rc < 0)
+ dev_err(&phydev->dev, "failed to set led mode\n");
- return rc < 0 ? rc : 0;
+ return rc;
+}
+
+/* Disable PHY address 0 as the broadcast address, so that it can be used as a
+ * unique (non-broadcast) address on a shared bus.
+ */
+static int kszphy_broadcast_disable(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_KSZPHY_OMSO);
+ if (ret < 0)
+ goto out;
+
+ ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
+out:
+ if (ret)
+ dev_err(&phydev->dev, "failed to disable broadcast address\n");
+
+ return ret;
}
static int kszphy_config_init(struct phy_device *phydev)
static int kszphy_config_init_led8041(struct phy_device *phydev)
{
- /* single led control, register 0x1e bits 15..14 */
- return kszphy_setup_led(phydev, 0x1e, 14);
+ return kszphy_setup_led(phydev, MII_KSZPHY_CTRL_1);
}
static int ksz8021_config_init(struct phy_device *phydev)
{
- const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
int rc;
- rc = kszphy_setup_led(phydev, 0x1f, 4);
- if (rc)
- dev_err(&phydev->dev, "failed to set led mode\n");
+ kszphy_setup_led(phydev, MII_KSZPHY_CTRL_2);
rc = ksz_config_flags(phydev);
if (rc < 0)
return rc;
- rc = phy_write(phydev, MII_KSZPHY_OMSO, val);
+
+ rc = kszphy_broadcast_disable(phydev);
+
return rc < 0 ? rc : 0;
}
{
int rc;
- rc = kszphy_setup_led(phydev, 0x1f, 4);
- if (rc)
- dev_err(&phydev->dev, "failed to set led mode\n");
+ kszphy_setup_led(phydev, MII_KSZPHY_CTRL_2);
rc = ksz_config_flags(phydev);
return rc < 0 ? rc : 0;
}
+static int ksz8081_config_init(struct phy_device *phydev)
+{
+ kszphy_broadcast_disable(phydev);
+ kszphy_setup_led(phydev, MII_KSZPHY_CTRL_2);
+
+ return 0;
+}
+
static int ksz9021_load_values_from_of(struct phy_device *phydev,
struct device_node *of_node, u16 reg,
char *field1, char *field2,
}
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
-#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6)
-#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4)
+#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX BIT(6)
+#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED BIT(4)
static int ksz8873mll_read_status(struct phy_device *phydev)
{
int regval;
.phy_id_mask = 0x00fffff0,
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = kszphy_config_init,
+ .config_init = ksz8081_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
.driver = { .owner = THIS_MODULE, },
} };
-static int __init ksphy_init(void)
-{
- return phy_drivers_register(ksphy_driver,
- ARRAY_SIZE(ksphy_driver));
-}
-
-static void __exit ksphy_exit(void)
-{
- phy_drivers_unregister(ksphy_driver,
- ARRAY_SIZE(ksphy_driver));
-}
-
-module_init(ksphy_init);
-module_exit(ksphy_exit);
+module_phy_driver(ksphy_driver);
MODULE_DESCRIPTION("Micrel PHY driver");
MODULE_AUTHOR("David J. Choi");
return ns_ack_interrupt(phydev);
}
-static struct phy_driver dp83865_driver = {
+static struct phy_driver dp83865_driver[] = { {
.phy_id = DP83865_PHY_ID,
.phy_id_mask = 0xfffffff0,
.name = "NatSemi DP83865",
.ack_interrupt = ns_ack_interrupt,
.config_intr = ns_config_intr,
.driver = {.owner = THIS_MODULE,}
-};
+} };
-static int __init ns_init(void)
-{
- return phy_driver_register(&dp83865_driver);
-}
-
-static void __exit ns_exit(void)
-{
- phy_driver_unregister(&dp83865_driver);
-}
+module_phy_driver(dp83865_driver);
MODULE_DESCRIPTION("NatSemi PHY driver");
MODULE_AUTHOR("Stuart Menefy");
MODULE_LICENSE("GPL");
-module_init(ns_init);
-module_exit(ns_exit);
-
static struct mdio_device_id __maybe_unused ns_tbl[] = {
{ DP83865_PHY_ID, 0xfffffff0 },
{ }
}
-static struct phy_driver qs6612_driver = {
+static struct phy_driver qs6612_driver[] = { {
.phy_id = 0x00181440,
.name = "QS6612",
.phy_id_mask = 0xfffffff0,
.ack_interrupt = qs6612_ack_interrupt,
.config_intr = qs6612_config_intr,
.driver = { .owner = THIS_MODULE,},
-};
-
-static int __init qs6612_init(void)
-{
- return phy_driver_register(&qs6612_driver);
-}
-
-static void __exit qs6612_exit(void)
-{
- phy_driver_unregister(&qs6612_driver);
-}
+} };
-module_init(qs6612_init);
-module_exit(qs6612_exit);
+module_phy_driver(qs6612_driver);
static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
{ 0x00181440, 0xfffffff0 },
},
};
-static int __init realtek_init(void)
-{
- return phy_drivers_register(realtek_drvs, ARRAY_SIZE(realtek_drvs));
-}
-
-static void __exit realtek_exit(void)
-{
- phy_drivers_unregister(realtek_drvs, ARRAY_SIZE(realtek_drvs));
-}
-
-module_init(realtek_init);
-module_exit(realtek_exit);
+module_phy_driver(realtek_drvs);
static struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ 0x001cc912, 0x001fffff },
.driver = { .owner = THIS_MODULE, }
} };
-static int __init smsc_init(void)
-{
- return phy_drivers_register(smsc_phy_driver,
- ARRAY_SIZE(smsc_phy_driver));
-}
-
-static void __exit smsc_exit(void)
-{
- phy_drivers_unregister(smsc_phy_driver, ARRAY_SIZE(smsc_phy_driver));
-}
+module_phy_driver(smsc_phy_driver);
MODULE_DESCRIPTION("SMSC PHY driver");
MODULE_AUTHOR("Herbert Valerio Riedel");
MODULE_LICENSE("GPL");
-module_init(smsc_init);
-module_exit(smsc_exit);
-
static struct mdio_device_id __maybe_unused smsc_tbl[] = {
{ 0x0007c0a0, 0xfffffff0 },
{ 0x0007c0b0, 0xfffffff0 },
static int ks8995_remove(struct spi_device *spi)
{
- sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
+ struct ks8995_switch *ks = spi_get_drvdata(spi);
+
+ sysfs_remove_bin_file(&spi->dev.kobj, &ks->regs_attr);
return 0;
}
.driver = {.owner = THIS_MODULE,}
} };
-static int __init ste10Xp_init(void)
-{
- return phy_drivers_register(ste10xp_pdriver,
- ARRAY_SIZE(ste10xp_pdriver));
-}
-
-static void __exit ste10Xp_exit(void)
-{
- phy_drivers_unregister(ste10xp_pdriver,
- ARRAY_SIZE(ste10xp_pdriver));
-}
-
-module_init(ste10Xp_init);
-module_exit(ste10Xp_exit);
+module_phy_driver(ste10xp_pdriver);
static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
{ STE101P_PHY_ID, 0xfffffff0 },
.driver = { .owner = THIS_MODULE,},
} };
-static int __init vsc82xx_init(void)
-{
- return phy_drivers_register(vsc82xx_driver,
- ARRAY_SIZE(vsc82xx_driver));
-}
-
-static void __exit vsc82xx_exit(void)
-{
- phy_drivers_unregister(vsc82xx_driver, ARRAY_SIZE(vsc82xx_driver));
-}
-
-module_init(vsc82xx_init);
-module_exit(vsc82xx_exit);
+module_phy_driver(vsc82xx_driver);
static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
{ PHY_ID_VSC8234, 0x000ffff0 },
if (skb) {
total_len = min_t(size_t, total_len, skb->len);
- error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
+ error = skb_copy_datagram_msg(skb, 0, m, total_len);
if (error == 0) {
consume_skb(skb);
return total_len;
goto err_enable_netpoll;
}
+ if (!(dev->features & NETIF_F_LRO))
+ dev_disable_lro(port_dev);
+
err = netdev_rx_handler_register(port_dev, team_handle_frame,
port);
if (err) {
#include <net/rtnetlink.h>
#include <net/sock.h>
#include <linux/seq_file.h>
+#include <linux/uio.h>
#include <asm/uaccess.h>
static ssize_t tun_put_user(struct tun_struct *tun,
struct tun_file *tfile,
struct sk_buff *skb,
- const struct iovec *iv, int len)
+ struct iov_iter *iter)
{
struct tun_pi pi = { 0, skb->protocol };
- ssize_t total = 0;
- int vlan_offset = 0, copied;
+ ssize_t total;
+ int vlan_offset = 0;
int vlan_hlen = 0;
int vnet_hdr_sz = 0;
if (tun->flags & TUN_VNET_HDR)
vnet_hdr_sz = tun->vnet_hdr_sz;
+ total = skb->len + vlan_hlen + vnet_hdr_sz;
+
if (!(tun->flags & TUN_NO_PI)) {
- if ((len -= sizeof(pi)) < 0)
+ if (iov_iter_count(iter) < sizeof(pi))
return -EINVAL;
- if (len < skb->len + vlan_hlen + vnet_hdr_sz) {
+ total += sizeof(pi);
+ if (iov_iter_count(iter) < total) {
/* Packet will be striped */
pi.flags |= TUN_PKT_STRIP;
}
- if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi)))
+ if (copy_to_iter(&pi, sizeof(pi), iter) != sizeof(pi))
return -EFAULT;
- total += sizeof(pi);
}
if (vnet_hdr_sz) {
struct virtio_net_hdr gso = { 0 }; /* no info leak */
- if ((len -= vnet_hdr_sz) < 0)
+ if (iov_iter_count(iter) < vnet_hdr_sz)
return -EINVAL;
if (skb_is_gso(skb)) {
gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
} /* else everything is zero */
- if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
- sizeof(gso))))
+ if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
return -EFAULT;
- total += vnet_hdr_sz;
+
+ iov_iter_advance(iter, vnet_hdr_sz - sizeof(gso));
}
- copied = total;
- len = min_t(int, skb->len + vlan_hlen, len);
- total += skb->len + vlan_hlen;
if (vlan_hlen) {
- int copy, ret;
+ int ret;
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
- copy = min_t(int, vlan_offset, len);
- ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
- len -= copy;
- copied += copy;
- if (ret || !len)
+ ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
+ if (ret || !iov_iter_count(iter))
goto done;
- copy = min_t(int, sizeof(veth), len);
- ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy);
- len -= copy;
- copied += copy;
- if (ret || !len)
+ ret = copy_to_iter(&veth, sizeof(veth), iter);
+ if (ret != sizeof(veth) || !iov_iter_count(iter))
goto done;
}
- skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
+ skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
done:
tun->dev->stats.tx_packets++;
- tun->dev->stats.tx_bytes += len;
+ tun->dev->stats.tx_bytes += skb->len + vlan_hlen;
return total;
}
static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
- const struct iovec *iv, ssize_t len, int noblock)
+ const struct iovec *iv, unsigned long segs,
+ ssize_t len, int noblock)
{
struct sk_buff *skb;
ssize_t ret = 0;
int peeked, err, off = 0;
+ struct iov_iter iter;
tun_debug(KERN_INFO, tun, "tun_do_read\n");
/* Read frames from queue */
skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
&peeked, &off, &err);
- if (skb) {
- ret = tun_put_user(tun, tfile, skb, iv, len);
- kfree_skb(skb);
- } else
- ret = err;
+ if (!skb)
+ return ret;
+
+ iov_iter_init(&iter, READ, iv, segs, len);
+ ret = tun_put_user(tun, tfile, skb, &iter);
+ kfree_skb(skb);
return ret;
}
goto out;
}
- ret = tun_do_read(tun, tfile, iv, len,
+ ret = tun_do_read(tun, tfile, iv, count, len,
file->f_flags & O_NONBLOCK);
ret = min_t(ssize_t, ret, len);
if (ret > 0)
SOL_PACKET, TUN_TX_TIMESTAMP);
goto out;
}
- ret = tun_do_read(tun, tfile, m->msg_iov, total_len,
+ ret = tun_do_read(tun, tfile, m->msg_iov, m->msg_iovlen, total_len,
flags & MSG_DONTWAIT);
if (ret > total_len) {
m->msg_flags |= MSG_TRUNC;
struct page *page;
int err;
- page = __skb_alloc_page(gfp_flags | __GFP_NOMEMALLOC, NULL);
+ page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
if (!page)
return -ENOMEM;
if (page)
put_page(page);
if (req)
- rx_submit(pnd, req, GFP_ATOMIC | __GFP_COLD);
+ rx_submit(pnd, req, GFP_ATOMIC);
}
static int usbpn_close(struct net_device *dev);
for (i = 0; i < rxq_size; i++) {
struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
- if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) {
+ if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
usb_free_urb(req);
usbpn_close(dev);
return -ENOMEM;
{
struct cdc_state *info = (void *) &dev->data;
struct usb_interface *intf = info->control;
+ struct net_device *net = dev->net;
- u16 cdc_filter =
- USB_CDC_PACKET_TYPE_ALL_MULTICAST | USB_CDC_PACKET_TYPE_DIRECTED |
- USB_CDC_PACKET_TYPE_BROADCAST;
+ u16 cdc_filter = USB_CDC_PACKET_TYPE_DIRECTED
+ | USB_CDC_PACKET_TYPE_BROADCAST;
- if (dev->net->flags & IFF_PROMISC)
- cdc_filter |= USB_CDC_PACKET_TYPE_PROMISCUOUS;
-
- /* FIXME cdc-ether has some multicast code too, though it complains
- * in routine cases. info->ether describes the multicast support.
- * Implement that here, manipulating the cdc filter as needed.
+ /* filtering on the device is an optional feature and not worth
+ * the hassle so we just roughly care about snooping and if any
+ * multicast is requested, we take every multicast
*/
+ if (net->flags & IFF_PROMISC)
+ cdc_filter |= USB_CDC_PACKET_TYPE_PROMISCUOUS;
+ if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI))
+ cdc_filter |= USB_CDC_PACKET_TYPE_ALL_MULTICAST;
usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
/* Define these values to match your device */
#define VENDOR_ID_REALTEK 0x0bda
-#define PRODUCT_ID_RTL8152 0x8152
-#define PRODUCT_ID_RTL8153 0x8153
-
#define VENDOR_ID_SAMSUNG 0x04e8
-#define PRODUCT_ID_SAMSUNG 0xa101
#define MCU_TYPE_PLA 0x0100
#define MCU_TYPE_USB 0x0000
__le64 rx_broadcast;
__le32 rx_multicast;
__le16 tx_aborted;
- __le16 tx_underun;
+ __le16 tx_underrun;
};
struct rx_desc {
}
}
+ if (ret == -ENODEV)
+ set_bit(RTL8152_UNPLUG, &tp->flags);
+
return ret;
}
}
error1:
+ if (ret == -ENODEV)
+ set_bit(RTL8152_UNPLUG, &tp->flags);
+
return ret;
}
result = r8152_submit_rx(tp, agg, GFP_ATOMIC);
if (result == -ENODEV) {
+ set_bit(RTL8152_UNPLUG, &tp->flags);
netif_device_detach(tp->netdev);
} else if (result) {
spin_lock(&tp->rx_lock);
resubmit:
res = usb_submit_urb(urb, GFP_ATOMIC);
- if (res == -ENODEV)
+ if (res == -ENODEV) {
+ set_bit(RTL8152_UNPLUG, &tp->flags);
netif_device_detach(tp->netdev);
- else if (res)
+ } else if (res) {
netif_err(tp, intr, tp->netdev,
"can't resubmit intr, status %d\n", res);
+ }
}
static inline void *rx_agg_align(void *data)
spin_lock_init(&tp->rx_lock);
spin_lock_init(&tp->tx_lock);
- INIT_LIST_HEAD(&tp->rx_done);
INIT_LIST_HEAD(&tp->tx_free);
skb_queue_head_init(&tp->tx_queue);
struct net_device *netdev = tp->netdev;
if (res == -ENODEV) {
+ set_bit(RTL8152_UNPLUG, &tp->flags);
netif_device_detach(netdev);
} else {
struct net_device_stats *stats = &netdev->stats;
if (!netif_carrier_ok(tp->netdev))
return;
+ clear_bit(SCHEDULE_TASKLET, &tp->flags);
+
rx_bottom(tp);
tx_bottom(tp);
}
{
struct r8152 *tp = container_of(work, struct r8152, schedule.work);
+ /* If the device is unplugged or !netif_running(), the workqueue
+ * doesn't need to wake the device, and could return directly.
+ */
+ if (test_bit(RTL8152_UNPLUG, &tp->flags) || !netif_running(tp->netdev))
+ return;
+
if (usb_autopm_get_interface(tp->intf) < 0)
return;
if (!test_bit(WORK_ENABLE, &tp->flags))
goto out1;
- if (test_bit(RTL8152_UNPLUG, &tp->flags))
- goto out1;
-
if (!mutex_trylock(&tp->control)) {
schedule_delayed_work(&tp->schedule, 0);
goto out1;
netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
res);
free_all_mem(tp);
+ } else {
+ tasklet_enable(&tp->tl);
}
mutex_unlock(&tp->control);
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
+ tasklet_disable(&tp->tl);
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
*/
rtl_runtime_suspend_enable(tp, false);
- tasklet_disable(&tp->tl);
tp->rtl_ops.down(tp);
- tasklet_enable(&tp->tl);
mutex_unlock(&tp->control);
data[9] = le64_to_cpu(tally.rx_broadcast);
data[10] = le32_to_cpu(tally.rx_multicast);
data[11] = le16_to_cpu(tally.tx_aborted);
- data[12] = le16_to_cpu(tally.tx_underun);
+ data[12] = le16_to_cpu(tally.tx_underrun);
}
static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
return ret;
}
+static int rtl8152_nway_reset(struct net_device *dev)
+{
+ struct r8152 *tp = netdev_priv(dev);
+ int ret;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ goto out;
+
+ mutex_lock(&tp->control);
+
+ ret = mii_nway_restart(&tp->mii);
+
+ mutex_unlock(&tp->control);
+
+ usb_autopm_put_interface(tp->intf);
+
+out:
+ return ret;
+}
+
static struct ethtool_ops ops = {
.get_drvinfo = rtl8152_get_drvinfo,
.get_settings = rtl8152_get_settings,
.set_settings = rtl8152_set_settings,
.get_link = ethtool_op_get_link,
+ .nway_reset = rtl8152_nway_reset,
.get_msglevel = rtl8152_get_msglevel,
.set_msglevel = rtl8152_set_msglevel,
.get_wol = rtl8152_get_wol,
r8153_power_cut_en(tp, false);
}
-static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
+static int rtl_ops_init(struct r8152 *tp)
{
struct rtl_ops *ops = &tp->rtl_ops;
- int ret = -ENODEV;
-
- switch (id->idVendor) {
- case VENDOR_ID_REALTEK:
- switch (id->idProduct) {
- case PRODUCT_ID_RTL8152:
- ops->init = r8152b_init;
- ops->enable = rtl8152_enable;
- ops->disable = rtl8152_disable;
- ops->up = rtl8152_up;
- ops->down = rtl8152_down;
- ops->unload = rtl8152_unload;
- ops->eee_get = r8152_get_eee;
- ops->eee_set = r8152_set_eee;
- ret = 0;
- break;
- case PRODUCT_ID_RTL8153:
- ops->init = r8153_init;
- ops->enable = rtl8153_enable;
- ops->disable = rtl8153_disable;
- ops->up = rtl8153_up;
- ops->down = rtl8153_down;
- ops->unload = rtl8153_unload;
- ops->eee_get = r8153_get_eee;
- ops->eee_set = r8153_set_eee;
- ret = 0;
- break;
- default:
- break;
- }
+ int ret = 0;
+
+ switch (tp->version) {
+ case RTL_VER_01:
+ case RTL_VER_02:
+ ops->init = r8152b_init;
+ ops->enable = rtl8152_enable;
+ ops->disable = rtl8152_disable;
+ ops->up = rtl8152_up;
+ ops->down = rtl8152_down;
+ ops->unload = rtl8152_unload;
+ ops->eee_get = r8152_get_eee;
+ ops->eee_set = r8152_set_eee;
break;
- case VENDOR_ID_SAMSUNG:
- switch (id->idProduct) {
- case PRODUCT_ID_SAMSUNG:
- ops->init = r8153_init;
- ops->enable = rtl8153_enable;
- ops->disable = rtl8153_disable;
- ops->up = rtl8153_up;
- ops->down = rtl8153_down;
- ops->unload = rtl8153_unload;
- ops->eee_get = r8153_get_eee;
- ops->eee_set = r8153_set_eee;
- ret = 0;
- break;
- default:
- break;
- }
+ case RTL_VER_03:
+ case RTL_VER_04:
+ case RTL_VER_05:
+ ops->init = r8153_init;
+ ops->enable = rtl8153_enable;
+ ops->disable = rtl8153_disable;
+ ops->up = rtl8153_up;
+ ops->down = rtl8153_down;
+ ops->unload = rtl8153_unload;
+ ops->eee_get = r8153_get_eee;
+ ops->eee_set = r8153_set_eee;
break;
default:
+ ret = -ENODEV;
+ netif_err(tp, probe, tp->netdev, "Unknown Device\n");
break;
}
- if (ret)
- netif_err(tp, probe, tp->netdev, "Unknown Device\n");
-
return ret;
}
tp->netdev = netdev;
tp->intf = intf;
- ret = rtl_ops_init(tp, id);
+ r8152b_get_version(tp);
+ ret = rtl_ops_init(tp);
if (ret)
goto out;
tp->mii.phy_id_mask = 0x3f;
tp->mii.reg_num_mask = 0x1f;
tp->mii.phy_id = R8152_PHY_ID;
- tp->mii.supports_gmii = 0;
intf->needs_remote_wakeup = 1;
- r8152b_get_version(tp);
tp->rtl_ops.init(tp);
set_ethernet_addr(tp);
else
device_set_wakeup_enable(&udev->dev, false);
+ tasklet_disable(&tp->tl);
+
netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0;
out1:
usb_set_intfdata(intf, NULL);
+ tasklet_kill(&tp->tl);
out:
free_netdev(netdev);
return ret;
/* table of devices that work with this driver */
static struct usb_device_id rtl8152_table[] = {
- {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
- {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
- {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
+ {USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
{}
};
static int smsc95xx_resume(struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- u8 suspend_flags = pdata->suspend_flags;
+ struct smsc95xx_priv *pdata;
+ u8 suspend_flags;
int ret;
u32 val;
BUG_ON(!dev);
+ pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ suspend_flags = pdata->suspend_flags;
netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
[IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
[IFLA_VXLAN_PORT] = { .type = NLA_U16 },
+ [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
};
static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
u16 cachelsz;
u16 curaid;
u8 macaddr[ETH_ALEN];
- u8 curbssid[ETH_ALEN];
+ u8 curbssid[ETH_ALEN] __aligned(2);
u8 bssidmask[ETH_ALEN];
u32 rx_bufsize;
* Guts of ath10k_ce_completed_recv_next.
* The caller takes responsibility for any necessary locking.
*/
-static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp,
- unsigned int *flagsp)
+int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
+ void **per_transfer_contextp,
+ u32 *bufferp,
+ unsigned int *nbytesp,
+ unsigned int *transfer_idp,
+ unsigned int *flagsp)
{
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
unsigned int nentries_mask = dest_ring->nentries_mask;
* Guts of ath10k_ce_completed_send_next.
* The caller takes responsibility for any necessary locking.
*/
-static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp)
+int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
+ void **per_transfer_contextp,
+ u32 *bufferp,
+ unsigned int *nbytesp,
+ unsigned int *transfer_idp)
{
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
u32 ctrl_addr = ce_state->ctrl_addr;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ce_id;
- for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+ /* Skip the last copy engine, CE7 the diagnostic window, as that
+ * uses polling and isn't initialized for interrupts.
+ */
+ for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++)
ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
}
* initialized by software/firmware.
*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr,
- void (*send_cb)(struct ath10k_ce_pipe *),
- void (*recv_cb)(struct ath10k_ce_pipe *))
+ const struct ce_attr *attr)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
int ret;
- /*
- * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
- * additional TX locking checks.
- *
- * For the lack of a better place do the check here.
- */
- BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
-
- spin_lock_bh(&ar_pci->ce_lock);
- ce_state->ar = ar;
- ce_state->id = ce_id;
- ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
- ce_state->attr_flags = attr->flags;
- ce_state->src_sz_max = attr->src_sz_max;
- if (attr->src_nentries)
- ce_state->send_cb = send_cb;
- if (attr->dest_nentries)
- ce_state->recv_cb = recv_cb;
- spin_unlock_bh(&ar_pci->ce_lock);
-
if (attr->src_nentries) {
ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
if (ret) {
}
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
- const struct ce_attr *attr)
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *))
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
int ret;
+ /*
+ * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
+ * additional TX locking checks.
+ *
+ * For the lack of a better place do the check here.
+ */
+ BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
+ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+ BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
+ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+
+ ce_state->ar = ar;
+ ce_state->id = ce_id;
+ ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
+ ce_state->attr_flags = attr->flags;
+ ce_state->src_sz_max = attr->src_sz_max;
+
+ if (attr->src_nentries)
+ ce_state->send_cb = send_cb;
+
+ if (attr->dest_nentries)
+ ce_state->recv_cb = recv_cb;
+
if (attr->src_nentries) {
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
if (IS_ERR(ce_state->src_ring)) {
unsigned int *nbytesp,
unsigned int *transfer_idp);
+int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
+ void **per_transfer_contextp,
+ u32 *bufferp,
+ unsigned int *nbytesp,
+ unsigned int *transfer_idp);
+
/*==================CE Engine Initialization=======================*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr,
- void (*send_cb)(struct ath10k_ce_pipe *),
- void (*recv_cb)(struct ath10k_ce_pipe *));
+ const struct ce_attr *attr);
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
- const struct ce_attr *attr);
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *));
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
/*==================CE Engine Shutdown=======================*/
void **per_transfer_contextp,
u32 *bufferp);
+int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
+ void **per_transfer_contextp,
+ u32 *bufferp,
+ unsigned int *nbytesp,
+ unsigned int *transfer_idp,
+ unsigned int *flagsp);
+
/*
* Support clean shutdown by allowing the caller to cancel
* pending sends. Target DMA must be stopped before using
return fw;
}
-static int ath10k_push_board_ext_data(struct ath10k *ar)
+static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
+ size_t data_len)
{
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
if (board_ext_data_addr == 0)
return 0;
- if (ar->board_len != (board_data_size + board_ext_data_size)) {
+ if (data_len != (board_data_size + board_ext_data_size)) {
ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
- ar->board_len, board_data_size, board_ext_data_size);
+ data_len, board_data_size, board_ext_data_size);
return -EINVAL;
}
ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
- ar->board_data + board_data_size,
+ data + board_data_size,
board_ext_data_size);
if (ret) {
ath10k_err(ar, "could not write board ext data (%d)\n", ret);
return 0;
}
-static int ath10k_download_board_data(struct ath10k *ar)
+static int ath10k_download_board_data(struct ath10k *ar, const void *data,
+ size_t data_len)
{
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address;
int ret;
- ret = ath10k_push_board_ext_data(ar);
+ ret = ath10k_push_board_ext_data(ar, data, data_len);
if (ret) {
ath10k_err(ar, "could not push board ext data (%d)\n", ret);
goto exit;
goto exit;
}
- ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
+ ret = ath10k_bmi_write_memory(ar, address, data,
min_t(u32, board_data_size,
- ar->board_len));
+ data_len));
if (ret) {
ath10k_err(ar, "could not write board data (%d)\n", ret);
goto exit;
return ret;
}
+static int ath10k_download_cal_file(struct ath10k *ar)
+{
+ int ret;
+
+ if (!ar->cal_file)
+ return -ENOENT;
+
+ if (IS_ERR(ar->cal_file))
+ return PTR_ERR(ar->cal_file);
+
+ ret = ath10k_download_board_data(ar, ar->cal_file->data,
+ ar->cal_file->size);
+ if (ret) {
+ ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
+
+ return 0;
+}
+
static int ath10k_download_and_run_otp(struct ath10k *ar)
{
u32 result, address = ar->hw_params.patch_load_addr;
int ret;
+ ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len);
+ if (ret) {
+ ath10k_err(ar, "failed to download board data: %d\n", ret);
+ return ret;
+ }
+
/* OTP is optional */
if (!ar->otp_data || !ar->otp_len) {
if (ar->firmware && !IS_ERR(ar->firmware))
release_firmware(ar->firmware);
+ if (ar->cal_file && !IS_ERR(ar->cal_file))
+ release_firmware(ar->cal_file);
+
ar->board = NULL;
ar->board_data = NULL;
ar->board_len = 0;
ar->firmware = NULL;
ar->firmware_data = NULL;
ar->firmware_len = 0;
+
+ ar->cal_file = NULL;
+}
+
+static int ath10k_fetch_cal_file(struct ath10k *ar)
+{
+ char filename[100];
+
+ /* cal-<bus>-<id>.bin */
+ scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",
+ ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
+
+ ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);
+ if (IS_ERR(ar->cal_file))
+ /* calibration file is optional, don't print any warnings */
+ return PTR_ERR(ar->cal_file);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",
+ ATH10K_FW_DIR, filename);
+
+ return 0;
}
static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
{
int ret;
+ /* calibration file is optional, don't check for any errors */
+ ath10k_fetch_cal_file(ar);
+
ar->fw_api = 3;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
return 0;
}
-static int ath10k_init_download_firmware(struct ath10k *ar,
- enum ath10k_firmware_mode mode)
+static int ath10k_download_cal_data(struct ath10k *ar)
{
int ret;
- ret = ath10k_download_board_data(ar);
- if (ret) {
- ath10k_err(ar, "failed to download board data: %d\n", ret);
- return ret;
+ ret = ath10k_download_cal_file(ar);
+ if (ret == 0) {
+ ar->cal_mode = ATH10K_CAL_MODE_FILE;
+ goto done;
}
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot did not find a calibration file, try OTP next: %d\n",
+ ret);
+
ret = ath10k_download_and_run_otp(ar);
if (ret) {
ath10k_err(ar, "failed to run otp: %d\n", ret);
return ret;
}
- ret = ath10k_download_fw(ar, mode);
- if (ret) {
- ath10k_err(ar, "failed to download firmware: %d\n", ret);
- return ret;
- }
+ ar->cal_mode = ATH10K_CAL_MODE_OTP;
- return ret;
+done:
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",
+ ath10k_cal_mode_str(ar->cal_mode));
+ return 0;
}
static int ath10k_init_uart(struct ath10k *ar)
goto err;
}
- status = ath10k_init_download_firmware(ar, mode);
+ status = ath10k_download_cal_data(ar);
+ if (status)
+ goto err;
+
+ status = ath10k_download_fw(ar, mode);
if (status)
goto err;
goto err_hif_stop;
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
+ ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1;
else
- ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
+ ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
INIT_LIST_HEAD(&ar->arvifs);
EXPORT_SYMBOL(ath10k_core_unregister);
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
+ enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
ar->dev = dev;
ar->hif.ops = hif_ops;
+ ar->hif.bus = bus;
init_completion(&ar->scan.started);
init_completion(&ar->scan.completed);
struct ath10k;
+enum ath10k_bus {
+ ATH10K_BUS_PCI,
+};
+
+static inline const char *ath10k_bus_str(enum ath10k_bus bus)
+{
+ switch (bus) {
+ case ATH10K_BUS_PCI:
+ return "pci";
+ }
+
+ return "unknown";
+}
+
struct ath10k_skb_cb {
dma_addr_t paddr;
u8 vdev_id;
bool done_sent;
};
-#define ATH10K_MAX_MEM_REQS 16
-
struct ath10k_mem_chunk {
void *vaddr;
dma_addr_t paddr;
struct wmi_pdev_param_map *pdev_param;
u32 num_mem_chunks;
- struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
+ struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
};
-struct ath10k_peer_stat {
+struct ath10k_fw_stats_peer {
+ struct list_head list;
+
u8 peer_macaddr[ETH_ALEN];
u32 peer_rssi;
u32 peer_tx_rate;
u32 peer_rx_rate; /* 10x only */
};
-struct ath10k_target_stats {
+struct ath10k_fw_stats_pdev {
+ struct list_head list;
+
/* PDEV stats */
s32 ch_noise_floor;
u32 tx_frame_count;
s32 phy_errs;
s32 phy_err_drop;
s32 mpdu_errs;
+};
- /* VDEV STATS */
-
- /* PEER STATS */
- u8 peers;
- struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS];
-
- /* TODO: Beacon filter stats */
-
+struct ath10k_fw_stats {
+ struct list_head pdevs;
+ struct list_head peers;
};
struct ath10k_dfs_stats {
struct sk_buff *beacon;
/* protected by data_lock */
bool beacon_sent;
+ void *beacon_buf;
+ dma_addr_t beacon_paddr;
struct ath10k *ar;
struct ieee80211_vif *vif;
u8 force_sgi;
bool use_cts_prot;
int num_legacy_stations;
+ int txpower;
};
struct ath10k_vif_iter {
struct ath10k_debug {
struct dentry *debugfs_phy;
- struct ath10k_target_stats target_stats;
+ struct ath10k_fw_stats fw_stats;
+ struct completion fw_stats_complete;
+ bool fw_stats_done;
DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
- struct completion event_stats_compl;
-
unsigned long htt_stats_mask;
struct delayed_work htt_stats_dwork;
struct ath10k_dfs_stats dfs_stats;
struct ath_dfs_pool_stats dfs_pool_stats;
+ /* protected by conf_mutex */
u32 fw_dbglog_mask;
+ u32 pktlog_filter;
u8 htt_max_amsdu;
u8 htt_max_ampdu;
* stopped in ath10k_core_restart() work holding conf_mutex. The state
* RESTARTED means that the device is up and mac80211 has started hw
* reconfiguration. Once mac80211 is done with the reconfiguration we
- * set the state to STATE_ON in restart_complete(). */
+ * set the state to STATE_ON in reconfig_complete(). */
ATH10K_STATE_RESTARTING,
ATH10K_STATE_RESTARTED,
ATH10K_FLAG_CORE_REGISTERED,
};
+enum ath10k_cal_mode {
+ ATH10K_CAL_MODE_FILE,
+ ATH10K_CAL_MODE_OTP,
+};
+
+static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
+{
+ switch (mode) {
+ case ATH10K_CAL_MODE_FILE:
+ return "file";
+ case ATH10K_CAL_MODE_OTP:
+ return "otp";
+ }
+
+ return "unknown";
+}
+
enum ath10k_scan_state {
ATH10K_SCAN_IDLE,
ATH10K_SCAN_STARTING,
bool p2p;
struct {
+ enum ath10k_bus bus;
const struct ath10k_hif_ops *ops;
} hif;
const void *firmware_data;
size_t firmware_len;
+ const struct firmware *cal_file;
+
int fw_api;
+ enum ath10k_cal_mode cal_mode;
struct {
struct completion started;
/* current operating channel definition */
struct cfg80211_chan_def chandef;
- int free_vdev_map;
+ unsigned long long free_vdev_map;
bool monitor;
int monitor_vdev_id;
bool monitor_started;
bool utf_monitor;
} testmode;
+ struct {
+ /* protected by data_lock */
+ u32 fw_crash_counter;
+ u32 fw_warm_reset_counter;
+ u32 fw_cold_reset_counter;
+ } stats;
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
+ enum ath10k_bus bus,
const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar);
#include "core.h"
#include "debug.h"
+#include "hif.h"
/* ms */
#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
u8 data[0];
} __packed;
-int ath10k_info(struct ath10k *ar, const char *fmt, ...)
+void ath10k_info(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = dev_info(ar->dev, "%pV", &vaf);
+ dev_info(ar->dev, "%pV", &vaf);
trace_ath10k_log_info(ar, &vaf);
va_end(args);
-
- return ret;
}
EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar)
{
- ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
ar->hw->wiphy->fw_version,
ar->fw_api,
ar->htt.target_version_major,
- ar->htt.target_version_minor);
+ ar->htt.target_version_minor,
+ ar->fw_version_major,
+ ar->fw_version_minor,
+ ar->fw_version_release,
+ ar->fw_version_build,
+ ath10k_cal_mode_str(ar->cal_mode));
ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
config_enabled(CONFIG_ATH10K_DEBUG),
config_enabled(CONFIG_ATH10K_DEBUGFS),
}
EXPORT_SYMBOL(ath10k_print_driver_info);
-int ath10k_err(struct ath10k *ar, const char *fmt, ...)
+void ath10k_err(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = dev_err(ar->dev, "%pV", &vaf);
+ dev_err(ar->dev, "%pV", &vaf);
trace_ath10k_log_err(ar, &vaf);
va_end(args);
-
- return ret;
}
EXPORT_SYMBOL(ath10k_err);
-int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
+void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
trace_ath10k_log_warn(ar, &vaf);
va_end(args);
-
- return 0;
}
EXPORT_SYMBOL(ath10k_warn);
#ifdef CONFIG_ATH10K_DEBUGFS
void ath10k_debug_read_service_map(struct ath10k *ar,
- void *service_map,
+ const void *service_map,
size_t map_size)
{
memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
.llseek = default_llseek,
};
-void ath10k_debug_read_target_stats(struct ath10k *ar,
- struct wmi_stats_event *ev)
+static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
{
- u8 *tmp = ev->data;
- struct ath10k_target_stats *stats;
- int num_pdev_stats, num_vdev_stats, num_peer_stats;
- struct wmi_pdev_stats_10x *ps;
- int i;
+ struct ath10k_fw_stats_pdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
+{
+ struct ath10k_fw_stats_peer *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
+{
spin_lock_bh(&ar->data_lock);
+ ar->debug.fw_stats_done = false;
+ ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+ ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
+ spin_unlock_bh(&ar->data_lock);
+}
- stats = &ar->debug.target_stats;
-
- num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
- num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
- num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
-
- if (num_pdev_stats) {
- ps = (struct wmi_pdev_stats_10x *)tmp;
-
- stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
- stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
- stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
- stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
- stats->cycle_count = __le32_to_cpu(ps->cycle_count);
- stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
- stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
-
- stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
- stats->comp_delivered =
- __le32_to_cpu(ps->wal.tx.comp_delivered);
- stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
- stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
- stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
- stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
- stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
- stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
- stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
- stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
- stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
- stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
- stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
- stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
- stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
- stats->sw_retry_failure =
- __le32_to_cpu(ps->wal.tx.sw_retry_failure);
- stats->illgl_rate_phy_err =
- __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
- stats->pdev_cont_xretry =
- __le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
- stats->pdev_tx_timeout =
- __le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
- stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
- stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
- stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
-
- stats->mid_ppdu_route_change =
- __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
- stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
- stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
- stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
- stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
- stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
- stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
- stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
- stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
- stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
- stats->oversize_amsdu =
- __le32_to_cpu(ps->wal.rx.oversize_amsdu);
- stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
- stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
- stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
- ar->fw_features)) {
- stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
- stats->rts_bad = __le32_to_cpu(ps->rts_bad);
- stats->rts_good = __le32_to_cpu(ps->rts_good);
- stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
- stats->no_beacons = __le32_to_cpu(ps->no_beacons);
- stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
- tmp += sizeof(struct wmi_pdev_stats_10x);
- } else {
- tmp += sizeof(struct wmi_pdev_stats_old);
- }
+static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
+{
+ struct ath10k_fw_stats_peer *i;
+ size_t num = 0;
+
+ list_for_each_entry(i, head, list)
+ ++num;
+
+ return num;
+}
+
+void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ath10k_fw_stats stats = {};
+ bool is_start, is_started, is_end;
+ size_t num_peers;
+ int ret;
+
+ INIT_LIST_HEAD(&stats.pdevs);
+ INIT_LIST_HEAD(&stats.peers);
+
+ spin_lock_bh(&ar->data_lock);
+ ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
+ if (ret) {
+ ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
+ goto unlock;
}
- /* 0 or max vdevs */
- /* Currently firmware does not support VDEV stats */
- if (num_vdev_stats) {
- struct wmi_vdev_stats *vdev_stats;
+ /* Stat data may exceed htc-wmi buffer limit. In such case firmware
+ * splits the stats data and delivers it in a ping-pong fashion of
+ * request cmd-update event.
+ *
+ * However there is no explicit end-of-data. Instead start-of-data is
+ * used as an implicit one. This works as follows:
+ * a) discard stat update events until one with pdev stats is
+ * delivered - this skips session started at end of (b)
+ * b) consume stat update events until another one with pdev stats is
+ * delivered which is treated as end-of-data and is itself discarded
+ */
- for (i = 0; i < num_vdev_stats; i++) {
- vdev_stats = (struct wmi_vdev_stats *)tmp;
- tmp += sizeof(struct wmi_vdev_stats);
- }
+ if (ar->debug.fw_stats_done) {
+ ath10k_warn(ar, "received unsolicited stats update event\n");
+ goto free;
}
- if (num_peer_stats) {
- struct wmi_peer_stats_10x *peer_stats;
- struct ath10k_peer_stat *s;
-
- stats->peers = num_peer_stats;
-
- for (i = 0; i < num_peer_stats; i++) {
- peer_stats = (struct wmi_peer_stats_10x *)tmp;
- s = &stats->peer_stat[i];
-
- memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
- ETH_ALEN);
- s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
- s->peer_tx_rate =
- __le32_to_cpu(peer_stats->peer_tx_rate);
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
- ar->fw_features)) {
- s->peer_rx_rate =
- __le32_to_cpu(peer_stats->peer_rx_rate);
- tmp += sizeof(struct wmi_peer_stats_10x);
-
- } else {
- tmp += sizeof(struct wmi_peer_stats_old);
- }
+ num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
+ is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
+ !list_empty(&stats.pdevs));
+ is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
+ !list_empty(&stats.pdevs));
+
+ if (is_start)
+ list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
+
+ if (is_end)
+ ar->debug.fw_stats_done = true;
+
+ is_started = !list_empty(&ar->debug.fw_stats.pdevs);
+
+ if (is_started && !is_end) {
+ if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {
+ /* Although this is unlikely impose a sane limit to
+ * prevent firmware from DoS-ing the host.
+ */
+ ath10k_warn(ar, "dropping fw peer stats\n");
+ goto free;
}
+
+ list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
}
+ complete(&ar->debug.fw_stats_complete);
+
+free:
+ /* In some cases lists have been spliced and cleared. Free up
+ * resources if that is not the case.
+ */
+ ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
+ ath10k_debug_fw_stats_peers_free(&stats.peers);
+
+unlock:
spin_unlock_bh(&ar->data_lock);
- complete(&ar->debug.event_stats_compl);
}
-static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+static int ath10k_debug_fw_stats_request(struct ath10k *ar)
{
- struct ath10k *ar = file->private_data;
- struct ath10k_target_stats *fw_stats;
- char *buf = NULL;
- unsigned int len = 0, buf_len = 8000;
- ssize_t ret_cnt = 0;
- long left;
- int i;
+ unsigned long timeout;
int ret;
- fw_stats = &ar->debug.target_stats;
+ lockdep_assert_held(&ar->conf_mutex);
- mutex_lock(&ar->conf_mutex);
+ timeout = jiffies + msecs_to_jiffies(1*HZ);
- if (ar->state != ATH10K_STATE_ON)
- goto exit;
+ ath10k_debug_fw_stats_reset(ar);
- buf = kzalloc(buf_len, GFP_KERNEL);
- if (!buf)
- goto exit;
+ for (;;) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
- ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
- if (ret) {
- ath10k_warn(ar, "could not request stats (%d)\n", ret);
- goto exit;
+ reinit_completion(&ar->debug.fw_stats_complete);
+
+ ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
+ if (ret) {
+ ath10k_warn(ar, "could not request stats (%d)\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+ 1*HZ);
+ if (ret <= 0)
+ return -ETIMEDOUT;
+
+ spin_lock_bh(&ar->data_lock);
+ if (ar->debug.fw_stats_done) {
+ spin_unlock_bh(&ar->data_lock);
+ break;
+ }
+ spin_unlock_bh(&ar->data_lock);
}
- left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
- if (left <= 0)
- goto exit;
+ return 0;
+}
+
+/* FIXME: How to calculate the buffer size sanely? */
+#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
+
+static void ath10k_fw_stats_fill(struct ath10k *ar,
+ struct ath10k_fw_stats *fw_stats,
+ char *buf)
+{
+ unsigned int len = 0;
+ unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
+ const struct ath10k_fw_stats_pdev *pdev;
+ const struct ath10k_fw_stats_peer *peer;
+ size_t num_peers;
spin_lock_bh(&ar->data_lock);
+
+ pdev = list_first_entry_or_null(&fw_stats->pdevs,
+ struct ath10k_fw_stats_pdev, list);
+ if (!pdev) {
+ ath10k_warn(ar, "failed to get pdev stats\n");
+ goto unlock;
+ }
+
+ num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
+
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n",
"ath10k PDEV stats");
"=================");
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Channel noise floor", fw_stats->ch_noise_floor);
+ "Channel noise floor", pdev->ch_noise_floor);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "Channel TX power", fw_stats->chan_tx_power);
+ "Channel TX power", pdev->chan_tx_power);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "TX frame count", fw_stats->tx_frame_count);
+ "TX frame count", pdev->tx_frame_count);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "RX frame count", fw_stats->rx_frame_count);
+ "RX frame count", pdev->rx_frame_count);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "RX clear count", fw_stats->rx_clear_count);
+ "RX clear count", pdev->rx_clear_count);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "Cycle count", fw_stats->cycle_count);
+ "Cycle count", pdev->cycle_count);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "PHY error count", fw_stats->phy_err_count);
+ "PHY error count", pdev->phy_err_count);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "RTS bad count", fw_stats->rts_bad);
+ "RTS bad count", pdev->rts_bad);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "RTS good count", fw_stats->rts_good);
+ "RTS good count", pdev->rts_good);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "FCS bad count", fw_stats->fcs_bad);
+ "FCS bad count", pdev->fcs_bad);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "No beacon count", fw_stats->no_beacons);
+ "No beacon count", pdev->no_beacons);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- "MIB int count", fw_stats->mib_int_count);
+ "MIB int count", pdev->mib_int_count);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n",
"=================");
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "HTT cookies queued", fw_stats->comp_queued);
+ "HTT cookies queued", pdev->comp_queued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "HTT cookies disp.", fw_stats->comp_delivered);
+ "HTT cookies disp.", pdev->comp_delivered);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MSDU queued", fw_stats->msdu_enqued);
+ "MSDU queued", pdev->msdu_enqued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDU queued", fw_stats->mpdu_enqued);
+ "MPDU queued", pdev->mpdu_enqued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MSDUs dropped", fw_stats->wmm_drop);
+ "MSDUs dropped", pdev->wmm_drop);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Local enqued", fw_stats->local_enqued);
+ "Local enqued", pdev->local_enqued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Local freed", fw_stats->local_freed);
+ "Local freed", pdev->local_freed);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "HW queued", fw_stats->hw_queued);
+ "HW queued", pdev->hw_queued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PPDUs reaped", fw_stats->hw_reaped);
+ "PPDUs reaped", pdev->hw_reaped);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Num underruns", fw_stats->underrun);
+ "Num underruns", pdev->underrun);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PPDUs cleaned", fw_stats->tx_abort);
+ "PPDUs cleaned", pdev->tx_abort);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDUs requed", fw_stats->mpdus_requed);
+ "MPDUs requed", pdev->mpdus_requed);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Excessive retries", fw_stats->tx_ko);
+ "Excessive retries", pdev->tx_ko);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "HW rate", fw_stats->data_rc);
+ "HW rate", pdev->data_rc);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Sched self tiggers", fw_stats->self_triggers);
+ "Sched self tiggers", pdev->self_triggers);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Dropped due to SW retries",
- fw_stats->sw_retry_failure);
+ pdev->sw_retry_failure);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Illegal rate phy errors",
- fw_stats->illgl_rate_phy_err);
+ pdev->illgl_rate_phy_err);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Pdev continous xretry", fw_stats->pdev_cont_xretry);
+ "Pdev continous xretry", pdev->pdev_cont_xretry);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "TX timeout", fw_stats->pdev_tx_timeout);
+ "TX timeout", pdev->pdev_tx_timeout);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PDEV resets", fw_stats->pdev_resets);
+ "PDEV resets", pdev->pdev_resets);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PHY underrun", fw_stats->phy_underrun);
+ "PHY underrun", pdev->phy_underrun);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDU is more than txop limit", fw_stats->txop_ovf);
+ "MPDU is more than txop limit", pdev->txop_ovf);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n",
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Mid PPDU route change",
- fw_stats->mid_ppdu_route_change);
+ pdev->mid_ppdu_route_change);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Tot. number of statuses", fw_stats->status_rcvd);
+ "Tot. number of statuses", pdev->status_rcvd);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Extra frags on rings 0", fw_stats->r0_frags);
+ "Extra frags on rings 0", pdev->r0_frags);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Extra frags on rings 1", fw_stats->r1_frags);
+ "Extra frags on rings 1", pdev->r1_frags);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Extra frags on rings 2", fw_stats->r2_frags);
+ "Extra frags on rings 2", pdev->r2_frags);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Extra frags on rings 3", fw_stats->r3_frags);
+ "Extra frags on rings 3", pdev->r3_frags);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MSDUs delivered to HTT", fw_stats->htt_msdus);
+ "MSDUs delivered to HTT", pdev->htt_msdus);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDUs delivered to HTT", fw_stats->htt_mpdus);
+ "MPDUs delivered to HTT", pdev->htt_mpdus);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MSDUs delivered to stack", fw_stats->loc_msdus);
+ "MSDUs delivered to stack", pdev->loc_msdus);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDUs delivered to stack", fw_stats->loc_mpdus);
+ "MPDUs delivered to stack", pdev->loc_mpdus);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "Oversized AMSUs", fw_stats->oversize_amsdu);
+ "Oversized AMSUs", pdev->oversize_amsdu);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PHY errors", fw_stats->phy_errs);
+ "PHY errors", pdev->phy_errs);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "PHY errors drops", fw_stats->phy_err_drop);
+ "PHY errors drops", pdev->phy_err_drop);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
+ "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
len += scnprintf(buf + len, buf_len - len, "\n");
- len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
- "ath10k PEER stats", fw_stats->peers);
+ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+ "ath10k PEER stats", num_peers);
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
"=================");
- for (i = 0; i < fw_stats->peers; i++) {
+ list_for_each_entry(peer, &fw_stats->peers, list) {
len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
- "Peer MAC address",
- fw_stats->peer_stat[i].peer_macaddr);
+ "Peer MAC address", peer->peer_macaddr);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
+ "Peer RSSI", peer->peer_rssi);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- "Peer TX rate",
- fw_stats->peer_stat[i].peer_tx_rate);
+ "Peer TX rate", peer->peer_tx_rate);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- "Peer RX rate",
- fw_stats->peer_stat[i].peer_rx_rate);
+ "Peer RX rate", peer->peer_rx_rate);
len += scnprintf(buf + len, buf_len - len, "\n");
}
+
+unlock:
spin_unlock_bh(&ar->data_lock);
- if (len > buf_len)
- len = buf_len;
+ if (len >= buf_len)
+ buf[len - 1] = 0;
+ else
+ buf[len] = 0;
+}
- ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ void *buf = NULL;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ ret = ath10k_debug_fw_stats_request(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to request fw stats: %d\n", ret);
+ goto err_free;
+ }
+
+ ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
+ file->private_data = buf;
-exit:
mutex_unlock(&ar->conf_mutex);
- kfree(buf);
- return ret_cnt;
+ return 0;
+
+err_free:
+ vfree(buf);
+
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ unsigned int len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_fw_stats = {
- .read = ath10k_read_fw_stats,
+ .open = ath10k_fw_stats_open,
+ .release = ath10k_fw_stats_release,
+ .read = ath10k_fw_stats_read,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int ret, len, buf_len;
+ char *buf;
+
+ buf_len = 500;
+ buf = kmalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ spin_lock_bh(&ar->data_lock);
+
+ len = 0;
+ len += scnprintf(buf + len, buf_len - len,
+ "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
+ len += scnprintf(buf + len, buf_len - len,
+ "fw_warm_reset_counter\t\t%d\n",
+ ar->stats.fw_warm_reset_counter);
+ len += scnprintf(buf + len, buf_len - len,
+ "fw_cold_reset_counter\t\t%d\n",
+ ar->stats.fw_cold_reset_counter);
+
+ spin_unlock_bh(&ar->data_lock);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations fops_fw_reset_stats = {
.open = simple_open,
+ .read = ath10k_debug_fw_reset_stats_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
return ret;
}
+/* TODO: Would be nice to always support ethtool stats, would need to
+ * move the stats storage out of ath10k_debug, or always have ath10k_debug
+ * struct available..
+ */
+
+/* This generally cooresponds to the debugfs fw_stats file */
+static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "tx_pkts_nic",
+ "tx_bytes_nic",
+ "rx_pkts_nic",
+ "rx_bytes_nic",
+ "d_noise_floor",
+ "d_cycle_count",
+ "d_phy_error",
+ "d_rts_bad",
+ "d_rts_good",
+ "d_tx_power", /* in .5 dbM I think */
+ "d_rx_crc_err", /* fcs_bad */
+ "d_no_beacon",
+ "d_tx_mpdus_queued",
+ "d_tx_msdu_queued",
+ "d_tx_msdu_dropped",
+ "d_local_enqued",
+ "d_local_freed",
+ "d_tx_ppdu_hw_queued",
+ "d_tx_ppdu_reaped",
+ "d_tx_fifo_underrun",
+ "d_tx_ppdu_abort",
+ "d_tx_mpdu_requed",
+ "d_tx_excessive_retries",
+ "d_tx_hw_rate",
+ "d_tx_dropped_sw_retries",
+ "d_tx_illegal_rate",
+ "d_tx_continuous_xretries",
+ "d_tx_timeout",
+ "d_tx_mpdu_txop_limit",
+ "d_pdev_resets",
+ "d_rx_mid_ppdu_route_change",
+ "d_rx_status",
+ "d_rx_extra_frags_ring0",
+ "d_rx_extra_frags_ring1",
+ "d_rx_extra_frags_ring2",
+ "d_rx_extra_frags_ring3",
+ "d_rx_msdu_htt",
+ "d_rx_mpdu_htt",
+ "d_rx_msdu_stack",
+ "d_rx_mpdu_stack",
+ "d_rx_phy_err",
+ "d_rx_phy_err_drops",
+ "d_rx_mpdu_errors", /* FCS, MIC, ENC */
+ "d_fw_crash_count",
+ "d_fw_warm_reset_count",
+ "d_fw_cold_reset_count",
+};
+
+#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
+
+void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u32 sset, u8 *data)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(data, *ath10k_gstrings_stats,
+ sizeof(ath10k_gstrings_stats));
+}
+
+int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return ATH10K_SSTATS_LEN;
+
+ return 0;
+}
+
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ath10k *ar = hw->priv;
+ static const struct ath10k_fw_stats_pdev zero_stats = {};
+ const struct ath10k_fw_stats_pdev *pdev_stats;
+ int i = 0, ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state == ATH10K_STATE_ON) {
+ ret = ath10k_debug_fw_stats_request(ar);
+ if (ret) {
+ /* just print a warning and try to use older results */
+ ath10k_warn(ar,
+ "failed to get fw stats for ethtool: %d\n",
+ ret);
+ }
+ }
+
+ pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,
+ struct ath10k_fw_stats_pdev,
+ list);
+ if (!pdev_stats) {
+ /* no results available so just return zeroes */
+ pdev_stats = &zero_stats;
+ }
+
+ spin_lock_bh(&ar->data_lock);
+
+ data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
+ data[i++] = 0; /* tx bytes */
+ data[i++] = pdev_stats->htt_mpdus;
+ data[i++] = 0; /* rx bytes */
+ data[i++] = pdev_stats->ch_noise_floor;
+ data[i++] = pdev_stats->cycle_count;
+ data[i++] = pdev_stats->phy_err_count;
+ data[i++] = pdev_stats->rts_bad;
+ data[i++] = pdev_stats->rts_good;
+ data[i++] = pdev_stats->chan_tx_power;
+ data[i++] = pdev_stats->fcs_bad;
+ data[i++] = pdev_stats->no_beacons;
+ data[i++] = pdev_stats->mpdu_enqued;
+ data[i++] = pdev_stats->msdu_enqued;
+ data[i++] = pdev_stats->wmm_drop;
+ data[i++] = pdev_stats->local_enqued;
+ data[i++] = pdev_stats->local_freed;
+ data[i++] = pdev_stats->hw_queued;
+ data[i++] = pdev_stats->hw_reaped;
+ data[i++] = pdev_stats->underrun;
+ data[i++] = pdev_stats->tx_abort;
+ data[i++] = pdev_stats->mpdus_requed;
+ data[i++] = pdev_stats->tx_ko;
+ data[i++] = pdev_stats->data_rc;
+ data[i++] = pdev_stats->sw_retry_failure;
+ data[i++] = pdev_stats->illgl_rate_phy_err;
+ data[i++] = pdev_stats->pdev_cont_xretry;
+ data[i++] = pdev_stats->pdev_tx_timeout;
+ data[i++] = pdev_stats->txop_ovf;
+ data[i++] = pdev_stats->pdev_resets;
+ data[i++] = pdev_stats->mid_ppdu_route_change;
+ data[i++] = pdev_stats->status_rcvd;
+ data[i++] = pdev_stats->r0_frags;
+ data[i++] = pdev_stats->r1_frags;
+ data[i++] = pdev_stats->r2_frags;
+ data[i++] = pdev_stats->r3_frags;
+ data[i++] = pdev_stats->htt_msdus;
+ data[i++] = pdev_stats->htt_mpdus;
+ data[i++] = pdev_stats->loc_msdus;
+ data[i++] = pdev_stats->loc_mpdus;
+ data[i++] = pdev_stats->phy_errs;
+ data[i++] = pdev_stats->phy_err_drop;
+ data[i++] = pdev_stats->mpdu_errs;
+ data[i++] = ar->stats.fw_crash_counter;
+ data[i++] = ar->stats.fw_warm_reset_counter;
+ data[i++] = ar->stats.fw_cold_reset_counter;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ WARN_ON(i != ATH10K_SSTATS_LEN);
+}
+
static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
.llseek = default_llseek,
};
+static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ void *buf;
+ u32 hi_addr;
+ __le32 addr;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON &&
+ ar->state != ATH10K_STATE_UTF) {
+ ret = -ENETDOWN;
+ goto err;
+ }
+
+ buf = vmalloc(QCA988X_CAL_DATA_LEN);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
+
+ ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
+ if (ret) {
+ ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret);
+ goto err_vfree;
+ }
+
+ ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
+ QCA988X_CAL_DATA_LEN);
+ if (ret) {
+ ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
+ goto err_vfree;
+ }
+
+ file->private_data = buf;
+
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+
+err_vfree:
+ vfree(buf);
+
+err:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static ssize_t ath10k_debug_cal_data_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ void *buf = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ buf, QCA988X_CAL_DATA_LEN);
+}
+
+static int ath10k_debug_cal_data_release(struct inode *inode,
+ struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static const struct file_operations fops_cal_data = {
+ .open = ath10k_debug_cal_data_open,
+ .read = ath10k_debug_cal_data_read,
+ .release = ath10k_debug_cal_data_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_start(struct ath10k *ar)
{
int ret;
ret);
}
- return 0;
+ if (ar->debug.pktlog_filter) {
+ ret = ath10k_wmi_pdev_pktlog_enable(ar,
+ ar->debug.pktlog_filter);
+ if (ret)
+ /* not serious */
+ ath10k_warn(ar,
+ "failed to enable pktlog filter %x: %d\n",
+ ar->debug.pktlog_filter, ret);
+ } else {
+ ret = ath10k_wmi_pdev_pktlog_disable(ar);
+ if (ret)
+ /* not serious */
+ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
+ }
+
+ return ret;
}
void ath10k_debug_stop(struct ath10k *ar)
ar->debug.htt_max_amsdu = 0;
ar->debug.htt_max_ampdu = 0;
+
+ ath10k_wmi_pdev_pktlog_disable(ar);
}
static ssize_t ath10k_write_simulate_radar(struct file *file,
.llseek = default_llseek,
};
+static ssize_t ath10k_write_pktlog_filter(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 filter;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &filter))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ar->debug.pktlog_filter = filter;
+ ret = count;
+ goto out;
+ }
+
+ if (filter && (filter != ar->debug.pktlog_filter)) {
+ ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
+ ar->debug.pktlog_filter, ret);
+ goto out;
+ }
+ } else {
+ ret = ath10k_wmi_pdev_pktlog_disable(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
+ goto out;
+ }
+ }
+
+ ar->debug.pktlog_filter = filter;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+ ar->debug.pktlog_filter);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pktlog_filter = {
+ .read = ath10k_read_pktlog_filter,
+ .write = ath10k_write_pktlog_filter,
+ .open = simple_open
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
if (!ar->debug.fw_crash_data)
return -ENOMEM;
+ INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
+ INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
+
return 0;
}
{
vfree(ar->debug.fw_crash_data);
ar->debug.fw_crash_data = NULL;
+
+ ath10k_debug_fw_stats_reset(ar);
}
int ath10k_debug_register(struct ath10k *ar)
INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
ath10k_debug_htt_stats_dwork);
- init_completion(&ar->debug.event_stats_compl);
+ init_completion(&ar->debug.fw_stats_complete);
debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_fw_stats);
+ debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_fw_reset_stats);
+
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services);
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_dbglog);
+ debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_cal_data);
+
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
debugfs_create_file("dfs_simulate_radar", S_IWUSR,
ar->debug.debugfs_phy, ar,
&fops_dfs_stats);
}
+ debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
+
return 0;
}
const char *msg, const char *prefix,
const void *buf, size_t len)
{
+ char linebuf[256];
+ unsigned int linebuflen;
+ const void *ptr;
+
if (ath10k_debug_mask & mask) {
if (msg)
ath10k_dbg(ar, mask, "%s\n", msg);
- print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
+ for (ptr = buf; (ptr - buf) < len; ptr += 16) {
+ linebuflen = 0;
+ linebuflen += scnprintf(linebuf + linebuflen,
+ sizeof(linebuf) - linebuflen,
+ "%s%08x: ",
+ (prefix ? prefix : ""),
+ (unsigned int)(ptr - buf));
+ hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
+ linebuf + linebuflen,
+ sizeof(linebuf) - linebuflen, true);
+ dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
+ }
}
/* tracing code doesn't like null strings :/ */
ATH10K_DBG_ANY = 0xffffffff,
};
+enum ath10k_pktlog_filter {
+ ATH10K_PKTLOG_RX = 0x000000001,
+ ATH10K_PKTLOG_TX = 0x000000002,
+ ATH10K_PKTLOG_RCFIND = 0x000000004,
+ ATH10K_PKTLOG_RCUPDATE = 0x000000008,
+ ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
+ ATH10K_PKTLOG_ANY = 0x00000001f,
+};
+
extern unsigned int ath10k_debug_mask;
-__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
-__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
-__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_debug_register(struct ath10k *ar);
void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_read_service_map(struct ath10k *ar,
- void *service_map,
+ const void *service_map,
size_t map_size);
-void ath10k_debug_read_target_stats(struct ath10k *ar,
- struct wmi_stats_event *ev);
+void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
struct ath10k_fw_crash_data *
ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
-
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
+void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u32 sset, u8 *data);
+int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int sset);
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data);
+
#else
static inline int ath10k_debug_start(struct ath10k *ar)
{
}
static inline void ath10k_debug_read_service_map(struct ath10k *ar,
- void *service_map,
+ const void *service_map,
size_t map_size)
{
}
-static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
- struct wmi_stats_event *ev)
+static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
+ struct sk_buff *skb)
{
}
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
+#define ath10k_debug_get_et_strings NULL
+#define ath10k_debug_get_et_sset_count NULL
+#define ath10k_debug_get_et_stats NULL
+
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
struct ath10k_hif_sg_item *items, int n_items);
+ /* read firmware memory through the diagnose interface */
+ int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
+ size_t buf_len);
+
/*
* API to handle HIF-specific BMI message exchanges, this API is
* synchronous and only allowed to be called from a context that
return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
}
+static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+ size_t buf_len)
+{
+ return ar->hif.ops->diag_read(ar, address, buf, buf_len);
+}
+
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
void *request, u32 request_len,
void *response, u32 *response_len)
*/
struct htt_pktlog_msg {
u8 pad[3];
- __le32 payload[1 /* or more */];
+ u8 payload[0];
} __packed;
struct htt_dbg_stats_rx_reorder_stats {
htt->rx_ring.sw_rd_idx.msdu_payld = idx;
htt->rx_ring.fill_cnt--;
+ trace_ath10k_htt_rx_pop_msdu(ar, msdu->data, msdu->len +
+ skb_tailroom(msdu));
+
return msdu;
}
int msdu_len, msdu_chaining = 0;
struct sk_buff *msdu, *next;
struct htt_rx_desc *rx_desc;
+ u32 tsf;
lockdep_assert_held(&htt->rx_ring.lock);
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
RX_MSDU_END_INFO0_LAST_MSDU;
+ tsf = __le32_to_cpu(rx_desc->ppdu_end.tsf_timestamp);
+ trace_ath10k_htt_rx_desc(ar, tsf, &rx_desc->attention,
+ sizeof(*rx_desc) - sizeof(u32));
if (last_msdu) {
msdu->next = NULL;
break;
case HTT_T2H_MSG_TYPE_RX_DELBA:
ath10k_htt_rx_delba(ar, resp);
break;
+ case HTT_T2H_MSG_TYPE_PKTLOG: {
+ struct ath10k_pktlog_hdr *hdr =
+ (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
+
+ trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
+ sizeof(*hdr) +
+ __le16_to_cpu(hdr->size));
+ break;
+ }
case HTT_T2H_MSG_TYPE_RX_FLUSH: {
/* Ignore this event because mac80211 takes care of Rx
* aggregation reordering.
break;
}
default:
- ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
- resp->hdr.msg_type);
+ ath10k_warn(ar, "htt event (%d) not handled\n",
+ resp->hdr.msg_type);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
break;
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
+ trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
+ trace_ath10k_htt_tx_msdu(ar, msdu->data, msdu->len);
sg_items[0].transfer_id = 0;
sg_items[0].transfer_context = NULL;
#include "targaddrs.h"
+#define ATH10K_FW_DIR "ath10k"
+
/* QCA988X 1.0 definitions (unsupported) */
#define QCA988X_HW_1_0_CHIP_ID_REV 0x0
/* QCA988X 2.0 definitions */
#define QCA988X_HW_2_0_VERSION 0x4100016c
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
-#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
+#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
-#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
#define REG_DUMP_COUNT_QCA988X 60
+#define QCA988X_CAL_DATA_LEN 2116
+
struct ath10k_fw_ie {
__le32 id;
__le32 len;
ATH10K_MCAST2UCAST_ENABLED = 1,
};
+struct ath10k_pktlog_hdr {
+ __le16 flags;
+ __le16 missed_cnt;
+ __le16 log_type;
+ __le16 size;
+ __le32 timestamp;
+ u8 payload[0];
+} __packed;
+
/* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2
#define SI_RX_DATA1_OFFSET 0x00000014
#define CORE_CTRL_CPU_INTR_MASK 0x00002000
+#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800
#define CORE_CTRL_ADDRESS 0x0000
#define PCIE_INTR_ENABLE_ADDRESS 0x0008
#define PCIE_INTR_CAUSE_ADDRESS 0x000c
/* Interface management */
/************************/
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!arvif->beacon)
+ return;
+
+ if (!arvif->beacon_buf)
+ dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
+ arvif->beacon->len, DMA_TO_DEVICE);
+
+ dev_kfree_skb_any(arvif->beacon);
+
+ arvif->beacon = NULL;
+ arvif->beacon_sent = false;
+}
+
+static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ath10k_mac_vif_beacon_free(arvif);
+
+ if (arvif->beacon_buf) {
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf, arvif->beacon_paddr);
+ arvif->beacon_buf = NULL;
+ }
+}
+
static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
int ret;
return -ENOMEM;
}
- bit = ffs(ar->free_vdev_map);
+ bit = __ffs64(ar->free_vdev_map);
- ar->monitor_vdev_id = bit - 1;
+ ar->monitor_vdev_id = bit;
ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
WMI_VDEV_TYPE_MONITOR,
return ret;
}
- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+ ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
ar->monitor_vdev_id);
return ret;
}
- ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
+ ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
ar->monitor_vdev_id);
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
- if (arvif->beacon) {
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
-
- arvif->beacon = NULL;
- arvif->beacon_sent = false;
- }
+ ath10k_mac_vif_beacon_free(arvif);
spin_unlock_bh(&arvif->ar->data_lock);
return;
if (is_zero_ether_addr(arvif->bssid))
return;
- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
- arvif->bssid);
- if (ret) {
- ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
- arvif->bssid, arvif->vdev_id, ret);
- return;
- }
-
memset(arvif->bssid, 0, ETH_ALEN);
return;
/* Station management */
/**********************/
+static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
+ struct ieee80211_vif *vif)
+{
+ /* Some firmware revisions have unstable STA powersave when listen
+ * interval is set too high (e.g. 5). The symptoms are firmware doesn't
+ * generate NullFunc frames properly even if buffered frames have been
+ * indicated in Beacon TIM. Firmware would seldom wake up to pull
+ * buffered frames. Often pinging the device from AP would simply fail.
+ *
+ * As a workaround set it to 1.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION)
+ return 1;
+
+ return ar->hw->conf.listen_interval;
+}
+
static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
lockdep_assert_held(&ar->conf_mutex);
ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
arg->peer_aid = sta->aid;
arg->peer_flags |= WMI_PEER_AUTH;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
- /*
- * Seems FW have problems with Power Save in STA
- * mode when we setup this parameter to high (eg. 5).
- * Often we see that FW don't send NULL (with clean P flags)
- * frame even there is info about buffered frames in beacons.
- * Sometimes we have to wait more than 10 seconds before FW
- * will wakeup. Often sending one ping from AP to our device
- * just fail (more than 50%).
- *
- * Seems setting this FW parameter to 1 couse FW
- * will check every beacon and will wakup immediately
- * after detection buffered data.
- */
- arg->peer_listen_intval = 1;
- else
- arg->peer_listen_intval = ar->hw->conf.listen_interval;
-
+ arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
-
- /*
- * The assoc capabilities are available only in managed mode.
- */
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
- arg->peer_caps = bss_conf->assoc_capability;
+ arg->peer_caps = vif->bss_conf.assoc_capability;
}
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct wmi_peer_assoc_complete_arg *arg)
{
- struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_bss *bss;
const u8 *rsnie = NULL;
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
if (sta->wme)
}
break;
case WMI_VDEV_TYPE_STA:
- if (bss_conf->qos)
+ if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS;
break;
default:
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
}
static int ath10k_peer_assoc_prepare(struct ath10k *ar,
- struct ath10k_vif *arvif,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_bss_conf *bss_conf,
struct wmi_peer_assoc_complete_arg *arg)
{
lockdep_assert_held(&ar->conf_mutex);
memset(arg, 0, sizeof(*arg));
- ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
- ath10k_peer_assoc_h_crypto(ar, arvif, arg);
+ ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_crypto(ar, vif, arg);
ath10k_peer_assoc_h_rates(ar, sta, arg);
ath10k_peer_assoc_h_ht(ar, sta, arg);
ath10k_peer_assoc_h_vht(ar, sta, arg);
- ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
- ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
+ ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
return 0;
}
lockdep_assert_held(&ar->conf_mutex);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
+ arvif->vdev_id, arvif->bssid, arvif->aid);
+
rcu_read_lock();
ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
* before calling ath10k_setup_peer_smps() which might sleep. */
ht_cap = ap_sta->ht_cap;
- ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
- bss_conf, &peer_arg);
+ ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
"mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
+ WARN_ON(arvif->is_up);
+
arvif->aid = bss_conf->aid;
ether_addr_copy(arvif->bssid, bss_conf->bssid);
arvif->is_up = true;
}
-/*
- * FIXME: flush TIDs
- */
static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
lockdep_assert_held(&ar->conf_mutex);
- /*
- * For some reason, calling VDEV-DOWN before VDEV-STOP
- * makes the FW to send frames via HTT after disassociation.
- * No idea why this happens, even though VDEV-DOWN is supposed
- * to be analogous to link down, so just stop the VDEV.
- */
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
- arvif->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
+ arvif->vdev_id, arvif->bssid);
- /* FIXME: check return value */
- ret = ath10k_vdev_stop(arvif);
-
- /*
- * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
- * report beacons from previously associated network through HTT.
- * This in turn would spam mac80211 WARN_ON if we bring down all
- * interfaces as it expects there is no rx when no interface is
- * running.
- */
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
-
- /* FIXME: why don't we print error if wmi call fails? */
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret)
+ ath10k_warn(ar, "faield to down vdev %i: %d\n",
+ arvif->vdev_id, ret);
arvif->def_wep_key_idx = 0;
-
- arvif->is_started = false;
arvif->is_up = false;
}
-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
- struct ieee80211_sta *sta, bool reassoc)
+static int ath10k_station_assoc(struct ath10k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool reassoc)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_peer_assoc_complete_arg peer_arg;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
- ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
+ ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
- ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
- if (ret) {
- ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
-
- if (!sta->wme && !reassoc) {
- arvif->num_legacy_stations++;
- ret = ath10k_recalc_rtscts_prot(arvif);
+ /* Re-assoc is run only to update supported rates for given station. It
+ * doesn't make much sense to reconfigure the peer completely.
+ */
+ if (!reassoc) {
+ ret = ath10k_setup_peer_smps(ar, arvif, sta->addr,
+ &sta->ht_cap);
if (ret) {
- ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
- }
- ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
- if (ret) {
- ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
+ ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
+ if (ret) {
+ ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
+ sta->addr, arvif->vdev_id, ret);
+ return ret;
+ }
- ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
- if (ret) {
- ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
- sta->addr, arvif->vdev_id, ret);
- return ret;
+ if (!sta->wme) {
+ arvif->num_legacy_stations++;
+ ret = ath10k_recalc_rtscts_prot(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
}
return ret;
}
-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
+static int ath10k_station_disassoc(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
ch->passive = passive;
ch->freq = channel->center_freq;
+ ch->band_center_freq1 = channel->center_freq;
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
ath10k_hif_power_down(ar);
spin_lock_bh(&ar->data_lock);
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->beacon)
- continue;
-
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
- }
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
}
ath10k_monitor_recalc(ar);
}
+static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
+{
+ int ret;
+ u32 param;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower);
+
+ param = ar->wmi.pdev_param->txpower_limit2g;
+ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+ if (ret) {
+ ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
+ txpower, ret);
+ return ret;
+ }
+
+ param = ar->wmi.pdev_param->txpower_limit5g;
+ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+ if (ret) {
+ ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
+ txpower, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_mac_txpower_recalc(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int ret, txpower = -1;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ WARN_ON(arvif->txpower < 0);
+
+ if (txpower == -1)
+ txpower = arvif->txpower;
+ else
+ txpower = min(txpower, arvif->txpower);
+ }
+
+ if (WARN_ON(txpower == -1))
+ return -EINVAL;
+
+ ret = ath10k_mac_txpower_setup(ar, txpower);
+ if (ret) {
+ ath10k_warn(ar, "failed to setup tx power %d: %d\n",
+ txpower, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath10k *ar = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
- u32 param;
mutex_lock(&ar->conf_mutex);
}
}
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
- hw->conf.power_level);
-
- param = ar->wmi.pdev_param->txpower_limit2g;
- ret = ath10k_wmi_pdev_set_param(ar, param,
- hw->conf.power_level * 2);
- if (ret)
- ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
- hw->conf.power_level, ret);
-
- param = ar->wmi.pdev_param->txpower_limit5g;
- ret = ath10k_wmi_pdev_set_param(ar, param,
- hw->conf.power_level * 2);
- if (ret)
- ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
- hw->conf.power_level, ret);
- }
-
if (changed & IEEE80211_CONF_CHANGE_PS)
ath10k_config_ps(ar);
ret = -EBUSY;
goto err;
}
- bit = ffs(ar->free_vdev_map);
+ bit = __ffs64(ar->free_vdev_map);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
+ bit, ar->free_vdev_map);
- arvif->vdev_id = bit - 1;
+ arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
if (ar->p2p)
break;
}
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
- arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
+ /* Some firmware revisions don't wait for beacon tx completion before
+ * sending another SWBA event. This could lead to hardware using old
+ * (freed) beacon data in some cases, e.g. tx credit starvation
+ * combined with missed TBTT. This is very very rare.
+ *
+ * On non-IOMMU-enabled hosts this could be a possible security issue
+ * because hw could beacon some random data on the air. On
+ * IOMMU-enabled hosts DMAR faults would occur in most cases and target
+ * device would crash.
+ *
+ * Since there are no beacon tx completions (implicit nor explicit)
+ * propagated to host the only workaround for this is to allocate a
+ * DMA-coherent buffer for a lifetime of a vif and use it for all
+ * beacon tx commands. Worst case for this approach is some beacons may
+ * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC ||
+ vif->type == NL80211_IFTYPE_AP) {
+ arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
+ IEEE80211_MAX_FRAME_LEN,
+ &arvif->beacon_paddr,
+ GFP_ATOMIC);
+ if (!arvif->beacon_buf) {
+ ret = -ENOMEM;
+ ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
+ arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+ arvif->beacon_buf ? "single-buf" : "per-skb");
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
goto err;
}
- ar->free_vdev_map &= ~(1 << arvif->vdev_id);
+ ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
vdev_param = ar->wmi.vdev_param->def_keyid;
goto err_peer_delete;
}
+ arvif->txpower = vif->bss_conf.txpower;
+ ret = ath10k_mac_txpower_recalc(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+ goto err_peer_delete;
+ }
+
mutex_unlock(&ar->conf_mutex);
return 0;
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- ar->free_vdev_map |= 1 << arvif->vdev_id;
+ ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
err:
+ if (arvif->beacon_buf) {
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf, arvif->beacon_paddr);
+ arvif->beacon_buf = NULL;
+ }
+
mutex_unlock(&ar->conf_mutex);
return ret;
cancel_work_sync(&arvif->wep_key_work);
spin_lock_bh(&ar->data_lock);
- if (arvif->beacon) {
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
- }
-
+ ath10k_mac_vif_beacon_cleanup(arvif);
spin_unlock_bh(&ar->data_lock);
ret = ath10k_spectral_vif_stop(arvif);
ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
arvif->vdev_id, ret);
- ar->free_vdev_map |= 1 << arvif->vdev_id;
+ ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arvif->u.ap.hidden_ssid = info->hidden_ssid;
}
- /*
- * Firmware manages AP self-peer internally so make sure to not create
- * it in driver. Otherwise AP self-peer deletion may timeout later.
- */
- if (changed & BSS_CHANGED_BSSID &&
- vif->type != NL80211_IFTYPE_AP) {
- if (!is_zero_ether_addr(info->bssid)) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac vdev %d create peer %pM\n",
- arvif->vdev_id, info->bssid);
-
- ret = ath10k_peer_create(ar, arvif->vdev_id,
- info->bssid);
- if (ret)
- ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
- info->bssid, arvif->vdev_id, ret);
-
- if (vif->type == NL80211_IFTYPE_STATION) {
- /*
- * this is never erased as we it for crypto key
- * clearing; this is FW requirement
- */
- ether_addr_copy(arvif->bssid, info->bssid);
-
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac vdev %d start %pM\n",
- arvif->vdev_id, info->bssid);
-
- ret = ath10k_vdev_start(arvif);
- if (ret) {
- ath10k_warn(ar, "failed to start vdev %i: %d\n",
- arvif->vdev_id, ret);
- goto exit;
- }
-
- arvif->is_started = true;
- }
-
- /*
- * Mac80211 does not keep IBSS bssid when leaving IBSS,
- * so driver need to store it. It is needed when leaving
- * IBSS in order to remove BSSID peer.
- */
- if (vif->type == NL80211_IFTYPE_ADHOC)
- memcpy(arvif->bssid, info->bssid,
- ETH_ALEN);
- }
- }
+ if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
+ ether_addr_copy(arvif->bssid, info->bssid);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath10k_control_beaconing(arvif, info);
ath10k_monitor_stop(ar);
ath10k_bss_assoc(hw, vif, info);
ath10k_monitor_recalc(ar);
+ } else {
+ ath10k_bss_disassoc(hw, vif);
}
}
-exit:
+ if (changed & BSS_CHANGED_TXPOWER) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n",
+ arvif->vdev_id, info->txpower);
+
+ arvif->txpower = info->txpower;
+ ret = ath10k_mac_txpower_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+ }
+
mutex_unlock(&ar->conf_mutex);
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
- err = ath10k_station_assoc(ar, arvif, sta, true);
+ err = ath10k_station_assoc(ar, arvif->vif, sta, true);
if (err)
ath10k_warn(ar, "failed to reassociate station: %pM\n",
sta->addr);
mutex_lock(&ar->conf_mutex);
if (old_state == IEEE80211_STA_NOTEXIST &&
- new_state == IEEE80211_STA_NONE &&
- vif->type != NL80211_IFTYPE_STATION) {
+ new_state == IEEE80211_STA_NONE) {
/*
* New station addition.
*/
if (ret)
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ WARN_ON(arvif->is_started);
+
+ ret = ath10k_vdev_start(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to start vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
+ sta->addr));
+ goto exit;
+ }
+
+ arvif->is_started = true;
+ }
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
/*
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ WARN_ON(!arvif->is_started);
+
+ ret = ath10k_vdev_stop(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to stop vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ arvif->is_started = false;
+ }
+
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
- if (vif->type == NL80211_IFTYPE_STATION)
- ath10k_bss_disassoc(hw, vif);
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
sta->addr);
- ret = ath10k_station_assoc(ar, arvif, sta, false);
+ ret = ath10k_station_assoc(ar, vif, sta, false);
if (ret)
ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
sta->addr);
- ret = ath10k_station_disassoc(ar, arvif, sta);
+ ret = ath10k_station_disassoc(ar, vif, sta);
if (ret)
ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
}
#endif
-static void ath10k_restart_complete(struct ieee80211_hw *hw)
+static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
+ enum ieee80211_reconfig_type reconfig_type)
{
struct ath10k *ar = hw->priv;
+ if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
+ return;
+
mutex_lock(&ar->conf_mutex);
/* If device failed to restart it will be in a different state, e.g.
.tx_last_beacon = ath10k_tx_last_beacon,
.set_antenna = ath10k_set_antenna,
.get_antenna = ath10k_get_antenna,
- .restart_complete = ath10k_restart_complete,
+ .reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
+ .get_et_sset_count = ath10k_debug_get_et_sset_count,
+ .get_et_stats = ath10k_debug_get_et_stats,
+ .get_et_strings = ath10k_debug_get_et_strings,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- /* TODO: Have to deal with 2x2 chips if/when the come out. */
- ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
- ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
- } else {
- ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
- ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
- }
-
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
void ath10k_halt(struct ath10k *ar);
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
void *data_buf = NULL;
int i;
+ spin_lock_bh(&ar_pci->ce_lock);
+
ce_diag = ar_pci->ce_diag;
/*
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
- ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
+ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
if (ret != 0)
goto done;
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
address);
- ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
- 0);
+ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
+ 0);
if (ret)
goto done;
i = 0;
- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id) != 0) {
+ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
+ &completed_nbytes,
+ &id) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
ret = -EBUSY;
}
i = 0;
- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id, &flags) != 0) {
+ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
+ &completed_nbytes,
+ &id, &flags) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
dma_free_coherent(ar->dev, orig_nbytes, data_buf,
ce_data_base);
+ spin_unlock_bh(&ar_pci->ce_lock);
+
return ret;
}
dma_addr_t ce_data_base = 0;
int i;
+ spin_lock_bh(&ar_pci->ce_lock);
+
ce_diag = ar_pci->ce_diag;
/*
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
/* Set up to receive directly into Target(!) address */
- ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
+ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address);
if (ret != 0)
goto done;
* Request CE to send caller-supplied data that
* was copied to bounce buffer to Target(!) address.
*/
- ret = ath10k_ce_send(ce_diag, NULL, (u32)ce_data,
- nbytes, 0, 0);
+ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
+ nbytes, 0, 0);
if (ret != 0)
goto done;
i = 0;
- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id) != 0) {
+ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
+ &completed_nbytes,
+ &id) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
}
i = 0;
- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id, &flags) != 0) {
+ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
+ &completed_nbytes,
+ &id, &flags) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
address, ret);
+ spin_unlock_bh(&ar_pci->ce_lock);
+
return ret;
}
}
skb_put(skb, nbytes);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
+ ce_state->id, skb->len);
+ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
+ skb->data, skb->len);
+
cb->rx_completion(ar, skb, pipe_info->pipe_num);
}
return err;
}
+static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+ size_t buf_len)
+{
+ return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
+}
+
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
spin_lock_bh(&ar->data_lock);
+ ar->stats.fw_crash_counter++;
+
crash_data = ath10k_debug_get_new_fw_crash_data(ar);
if (crash_data)
&dl_is_polled);
}
-static void ath10k_pci_irq_disable(struct ath10k *ar)
+static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- int i;
+ u32 val;
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+ val &= ~CORE_CTRL_PCIE_REG_31_MASK;
+
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
+
+static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
+{
+ u32 val;
+
+ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+ val |= CORE_CTRL_PCIE_REG_31_MASK;
+
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
+
+static void ath10k_pci_irq_disable(struct ath10k *ar)
+{
ath10k_ce_disable_interrupts(ar);
ath10k_pci_disable_and_clear_legacy_irq(ar);
- /* FIXME: How to mask all MSI interrupts? */
+ ath10k_pci_irq_msi_fw_mask(ar);
+}
+
+static void ath10k_pci_irq_sync(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int i;
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
synchronize_irq(ar_pci->pdev->irq + i);
{
ath10k_ce_enable_interrupts(ar);
ath10k_pci_enable_legacy_irq(ar);
- /* FIXME: How to unmask all MSI interrupts? */
+ ath10k_pci_irq_msi_fw_unmask(ar);
}
static int ath10k_pci_hif_start(struct ath10k *ar)
ath10k_pci_warm_reset(ar);
ath10k_pci_irq_disable(ar);
+ ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
}
return 0;
}
-static int ath10k_pci_alloc_ce(struct ath10k *ar)
+static int ath10k_pci_alloc_pipes(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_pci_pipe *pipe;
int i, ret;
for (i = 0; i < CE_COUNT; i++) {
- ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
+ pipe = &ar_pci->pipe_info[i];
+ pipe->ce_hdl = &ar_pci->ce_states[i];
+ pipe->pipe_num = i;
+ pipe->hif_ce_state = ar;
+
+ ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i],
+ ath10k_pci_ce_send_done,
+ ath10k_pci_ce_recv_data);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
i, ret);
return ret;
}
+
+ /* Last CE is Diagnostic Window */
+ if (i == CE_COUNT - 1) {
+ ar_pci->ce_diag = pipe->ce_hdl;
+ continue;
+ }
+
+ pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
}
return 0;
}
-static void ath10k_pci_free_ce(struct ath10k *ar)
+static void ath10k_pci_free_pipes(struct ath10k *ar)
{
int i;
ath10k_ce_free_pipe(ar, i);
}
-static int ath10k_pci_ce_init(struct ath10k *ar)
+static int ath10k_pci_init_pipes(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info;
- const struct ce_attr *attr;
- int pipe_num, ret;
+ int i, ret;
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
- pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
- pipe_info->pipe_num = pipe_num;
- pipe_info->hif_ce_state = ar;
- attr = &host_ce_config_wlan[pipe_num];
-
- ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
- ath10k_pci_ce_send_done,
- ath10k_pci_ce_recv_data);
+ for (i = 0; i < CE_COUNT; i++) {
+ ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
if (ret) {
ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
- pipe_num, ret);
+ i, ret);
return ret;
}
-
- if (pipe_num == CE_COUNT - 1) {
- /*
- * Reserve the ultimate CE for
- * diagnostic Window support
- */
- ar_pci->ce_diag = pipe_info->ce_hdl;
- continue;
- }
-
- pipe_info->buf_sz = (size_t)(attr->src_sz_max);
}
return 0;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
+ spin_lock_bh(&ar->data_lock);
+
+ ar->stats.fw_warm_reset_counter++;
+
+ spin_unlock_bh(&ar->data_lock);
+
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
goto err;
}
- ret = ath10k_pci_ce_init(ar);
+ ret = ath10k_pci_init_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to initialize CE: %d\n", ret);
goto err;
static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.tx_sg = ath10k_pci_hif_tx_sg,
+ .diag_read = ath10k_pci_hif_diag_read,
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
.start = ath10k_pci_hif_start,
.stop = ath10k_pci_hif_stop,
if (ar_pci->num_msi_intrs == 0)
/* Fix potential race by repeating CORE_BASE writes */
- ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
- PCIE_INTR_ENABLE_ADDRESS,
- PCIE_INTR_FIRMWARE_MASK |
- PCIE_INTR_CE_MASK_ALL);
+ ath10k_pci_enable_legacy_irq(ar);
mdelay(10);
} while (time_before(jiffies, timeout));
+ ath10k_pci_disable_and_clear_legacy_irq(ar);
+ ath10k_pci_irq_msi_fw_mask(ar);
+
if (val == 0xffffffff) {
ath10k_err(ar, "failed to read device register, device is gone\n");
return -EIO;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
+ spin_lock_bh(&ar->data_lock);
+
+ ar->stats.fw_cold_reset_counter++;
+
+ spin_unlock_bh(&ar->data_lock);
+
/* Put Target, including PCIe, into RESET. */
val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
val |= 1;
u32 chip_id;
ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+ ATH10K_BUS_PCI,
&ath10k_pci_hif_ops);
if (!ar) {
dev_err(&pdev->dev, "failed to allocate core\n");
goto err_sleep;
}
- ret = ath10k_pci_alloc_ce(ar);
+ ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
ret);
}
ath10k_pci_ce_deinit(ar);
-
- ret = ath10k_ce_disable_interrupts(ar);
- if (ret) {
- ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
- ret);
- goto err_free_ce;
- }
-
- /* Workaround: There's no known way to mask all possible interrupts via
- * device CSR. The only way to make sure device doesn't assert
- * interrupts is to reset it. Interrupts are then disabled on host
- * after handlers are registered.
- */
- ath10k_pci_warm_reset(ar);
+ ath10k_pci_irq_disable(ar);
ret = ath10k_pci_init_irq(ar);
if (ret) {
ath10k_err(ar, "failed to init irqs: %d\n", ret);
- goto err_free_ce;
+ goto err_free_pipes;
}
ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
goto err_deinit_irq;
}
- /* This shouldn't race as the device has been reset above. */
- ath10k_pci_irq_disable(ar);
-
ret = ath10k_core_register(ar, chip_id);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
err_deinit_irq:
ath10k_pci_deinit_irq(ar);
-err_free_ce:
- ath10k_pci_free_ce(ar);
+err_free_pipes:
+ ath10k_pci_free_pipes(ar);
err_sleep:
ath10k_pci_sleep(ar);
ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar);
ath10k_pci_ce_deinit(ar);
- ath10k_pci_free_ce(ar);
+ ath10k_pci_free_pipes(ar);
ath10k_pci_sleep(ar);
ath10k_pci_release(ar);
ath10k_core_destroy(ar);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
}
int ath10k_spectral_process_fft(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
- struct phyerr_fft_report *fftr,
+ const struct wmi_phyerr *phyerr,
+ const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf)
{
struct fft_sample_ath10k *fft_sample;
u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
- u32 reg0, reg1, nf_list1, nf_list2;
+ u32 reg0, reg1;
u8 chain_idx, *bins;
int dc_pos;
/* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
* but the results/plots suggest that its actually 22/44/88 MHz.
*/
- switch (event->hdr.chan_width_mhz) {
+ switch (phyerr->chan_width_mhz) {
case 20:
fft_sample->chan_width_mhz = 22;
break;
fft_sample->chan_width_mhz = 88;
break;
default:
- fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+ fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
}
fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
- fft_sample->rssi = event->hdr.rssi_combined;
+ fft_sample->rssi = phyerr->rssi_combined;
total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
- freq1 = __le16_to_cpu(event->hdr.freq1);
- freq2 = __le16_to_cpu(event->hdr.freq2);
+ freq1 = __le16_to_cpu(phyerr->freq1);
+ freq2 = __le16_to_cpu(phyerr->freq2);
fft_sample->freq1 = __cpu_to_be16(freq1);
fft_sample->freq2 = __cpu_to_be16(freq2);
- nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
- nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
- switch (chain_idx) {
- case 0:
- fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
- break;
- case 1:
- fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
- break;
- case 2:
- fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
- break;
- case 3:
- fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
- break;
- }
+ fft_sample->noise = __cpu_to_be16(
+ __le16_to_cpu(phyerr->nf_chains[chain_idx]));
bins = (u8 *)fftr;
bins += sizeof(*fftr);
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_spectral_process_fft(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
- struct phyerr_fft_report *fftr,
+ const struct wmi_phyerr *phyerr,
+ const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf);
int ath10k_spectral_start(struct ath10k *ar);
int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
static inline int
ath10k_spectral_process_fft(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
- struct phyerr_fft_report *fftr,
+ const struct wmi_phyerr *phyerr,
+ const struct phyerr_fft_report *fftr,
size_t bin_len, u64 tsf)
{
return 0;
)
);
+TRACE_EVENT(ath10k_htt_pktlog,
+ TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len),
+
+ TP_ARGS(ar, buf, buf_len),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u16, buf_len)
+ __dynamic_array(u8, pktlog, buf_len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(pktlog), buf, buf_len);
+ ),
+
+ TP_printk(
+ "%s %s size %hu",
+ __get_str(driver),
+ __get_str(device),
+ __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath10k_htt_rx_desc,
+ TP_PROTO(struct ath10k *ar, u32 tsf, void *rxdesc, u16 len),
+
+ TP_ARGS(ar, tsf, rxdesc, len),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u32, tsf)
+ __field(u16, len)
+ __dynamic_array(u8, rxdesc, len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->tsf = tsf;
+ __entry->len = len;
+ memcpy(__get_dynamic_array(rxdesc), rxdesc, len);
+ ),
+
+ TP_printk(
+ "%s %s %u len %hu",
+ __get_str(driver),
+ __get_str(device),
+ __entry->tsf,
+ __entry->len
+ )
+);
+
+TRACE_EVENT(ath10k_htt_tx,
+ TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len,
+ u8 vdev_id, u8 tid),
+
+ TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u16, msdu_id)
+ __field(u16, msdu_len)
+ __field(u8, vdev_id)
+ __field(u8, tid)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->msdu_id = msdu_id;
+ __entry->msdu_len = msdu_len;
+ __entry->vdev_id = vdev_id;
+ __entry->tid = tid;
+ ),
+
+ TP_printk(
+ "%s %s msdu_id %d msdu_len %d vdev_id %d tid %d",
+ __get_str(driver),
+ __get_str(device),
+ __entry->msdu_id,
+ __entry->msdu_len,
+ __entry->vdev_id,
+ __entry->tid
+ )
+);
+
+TRACE_EVENT(ath10k_txrx_tx_unref,
+ TP_PROTO(struct ath10k *ar, u16 msdu_id),
+
+ TP_ARGS(ar, msdu_id),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u16, msdu_id)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->msdu_id = msdu_id;
+ ),
+
+ TP_printk(
+ "%s %s msdu_id %d",
+ __get_str(driver),
+ __get_str(device),
+ __entry->msdu_id
+ )
+);
+
+DECLARE_EVENT_CLASS(ath10k_data_event,
+ TP_PROTO(struct ath10k *ar, void *data, size_t len),
+
+ TP_ARGS(ar, data, len),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(size_t, len)
+ __dynamic_array(u8, data, len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->len = len;
+ memcpy(__get_dynamic_array(data), data, len);
+ ),
+
+ TP_printk(
+ "%s %s len %zu\n",
+ __get_str(driver),
+ __get_str(device),
+ __entry->len
+ )
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_htt_tx_msdu,
+ TP_PROTO(struct ath10k *ar, void *data, size_t len),
+ TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_pop_msdu,
+ TP_PROTO(struct ath10k *ar, void *data, size_t len),
+ TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_wmi_mgmt_tx,
+ TP_PROTO(struct ath10k *ar, void *data, size_t len),
+ TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_wmi_bcn_tx,
+ TP_PROTO(struct ath10k *ar, void *data, size_t len),
+ TP_ARGS(ar, data, len)
+);
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
/* we don't want to use include/trace/events */
info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
+ trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
if (tx_done->discard) {
ieee80211_free_txskb(htt->ar->hw, msdu);
.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
};
+static void
+ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+ const struct wmi_channel_arg *arg)
+{
+ u32 flags = 0;
+
+ memset(ch, 0, sizeof(*ch));
+
+ if (arg->passive)
+ flags |= WMI_CHAN_FLAG_PASSIVE;
+ if (arg->allow_ibss)
+ flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
+ if (arg->allow_ht)
+ flags |= WMI_CHAN_FLAG_ALLOW_HT;
+ if (arg->allow_vht)
+ flags |= WMI_CHAN_FLAG_ALLOW_VHT;
+ if (arg->ht40plus)
+ flags |= WMI_CHAN_FLAG_HT40_PLUS;
+ if (arg->chan_radar)
+ flags |= WMI_CHAN_FLAG_DFS;
+
+ ch->mhz = __cpu_to_le32(arg->freq);
+ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
+ ch->band_center_freq2 = 0;
+ ch->min_power = arg->min_power;
+ ch->max_power = arg->max_power;
+ ch->reg_power = arg->max_reg_power;
+ ch->antenna_max = arg->max_antenna_gain;
+
+ /* mode & flags share storage */
+ ch->mode = arg->mode;
+ ch->flags |= __cpu_to_le32(flags);
+}
+
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
{
int ret;
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
fc & IEEE80211_FCTL_STYPE);
+ trace_ath10k_wmi_mgmt_tx(ar, skb->data, skb->len);
/* Send the management frame buffer to the target */
ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
struct wmi_mgmt_rx_event_v2 *ev_v2;
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- struct ieee80211_channel *ch;
struct ieee80211_hdr *hdr;
u32 rx_status;
u32 channel;
if (rx_status & WMI_RX_STATUS_ERR_MIC)
status->flag |= RX_FLAG_MMIC_ERROR;
- /* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to
+ /* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to
* MODE_11B. This means phy_mode is not a reliable source for the band
- * of mgmt rx. */
-
- ch = ar->scan_channel;
- if (!ch)
- ch = ar->rx_channel;
-
- if (ch) {
- status->band = ch->band;
-
- if (phy_mode == MODE_11B &&
- status->band == IEEE80211_BAND_5GHZ)
- ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+ * of mgmt rx.
+ */
+ if (channel >= 1 && channel <= 14) {
+ status->band = IEEE80211_BAND_2GHZ;
+ } else if (channel >= 36 && channel <= 165) {
+ status->band = IEEE80211_BAND_5GHZ;
} else {
- ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
- status->band = phy_mode_to_band(phy_mode);
+ /* Shouldn't happen unless list of advertised channels to
+ * mac80211 has been changed.
+ */
+ WARN_ON_ONCE(1);
+ dev_kfree_skb(skb);
+ return 0;
}
+ if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ)
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+
status->freq = ieee80211_channel_to_frequency(channel, status->band);
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
status->rate_idx = get_rate_idx(rate, status->band);
return 0;
}
+static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
+ struct ath10k_fw_stats_pdev *dst)
+{
+ const struct wal_dbg_tx_stats *tx = &src->wal.tx;
+ const struct wal_dbg_rx_stats *rx = &src->wal.rx;
+
+ dst->ch_noise_floor = __le32_to_cpu(src->chan_nf);
+ dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count);
+ dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count);
+ dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count);
+ dst->cycle_count = __le32_to_cpu(src->cycle_count);
+ dst->phy_err_count = __le32_to_cpu(src->phy_err_count);
+ dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr);
+
+ dst->comp_queued = __le32_to_cpu(tx->comp_queued);
+ dst->comp_delivered = __le32_to_cpu(tx->comp_delivered);
+ dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued);
+ dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued);
+ dst->wmm_drop = __le32_to_cpu(tx->wmm_drop);
+ dst->local_enqued = __le32_to_cpu(tx->local_enqued);
+ dst->local_freed = __le32_to_cpu(tx->local_freed);
+ dst->hw_queued = __le32_to_cpu(tx->hw_queued);
+ dst->hw_reaped = __le32_to_cpu(tx->hw_reaped);
+ dst->underrun = __le32_to_cpu(tx->underrun);
+ dst->tx_abort = __le32_to_cpu(tx->tx_abort);
+ dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed);
+ dst->tx_ko = __le32_to_cpu(tx->tx_ko);
+ dst->data_rc = __le32_to_cpu(tx->data_rc);
+ dst->self_triggers = __le32_to_cpu(tx->self_triggers);
+ dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure);
+ dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err);
+ dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry);
+ dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout);
+ dst->pdev_resets = __le32_to_cpu(tx->pdev_resets);
+ dst->phy_underrun = __le32_to_cpu(tx->phy_underrun);
+ dst->txop_ovf = __le32_to_cpu(tx->txop_ovf);
+
+ dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change);
+ dst->status_rcvd = __le32_to_cpu(rx->status_rcvd);
+ dst->r0_frags = __le32_to_cpu(rx->r0_frags);
+ dst->r1_frags = __le32_to_cpu(rx->r1_frags);
+ dst->r2_frags = __le32_to_cpu(rx->r2_frags);
+ dst->r3_frags = __le32_to_cpu(rx->r3_frags);
+ dst->htt_msdus = __le32_to_cpu(rx->htt_msdus);
+ dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus);
+ dst->loc_msdus = __le32_to_cpu(rx->loc_msdus);
+ dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus);
+ dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu);
+ dst->phy_errs = __le32_to_cpu(rx->phy_errs);
+ dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop);
+ dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs);
+}
+
+static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+ struct ath10k_fw_stats_peer *dst)
+{
+ ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
+ dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
+ dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
+}
+
+static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ const struct wmi_stats_event *ev = (void *)skb->data;
+ u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+ int i;
+
+ if (!skb_pull(skb, sizeof(*ev)))
+ return -EPROTO;
+
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ for (i = 0; i < num_pdev_stats; i++) {
+ const struct wmi_pdev_stats *src;
+ struct ath10k_fw_stats_pdev *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_pdev_stats(src, dst);
+ list_add_tail(&dst->list, &stats->pdevs);
+ }
+
+ /* fw doesn't implement vdev stats */
+
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_peer_stats *src;
+ struct ath10k_fw_stats_peer *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_peer_stats(src, dst);
+ list_add_tail(&dst->list, &stats->peers);
+ }
+
+ return 0;
+}
+
+static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ const struct wmi_stats_event *ev = (void *)skb->data;
+ u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+ int i;
+
+ if (!skb_pull(skb, sizeof(*ev)))
+ return -EPROTO;
+
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ for (i = 0; i < num_pdev_stats; i++) {
+ const struct wmi_10x_pdev_stats *src;
+ struct ath10k_fw_stats_pdev *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_pdev_stats(&src->old, dst);
+
+ dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad);
+ dst->rts_bad = __le32_to_cpu(src->rts_bad);
+ dst->rts_good = __le32_to_cpu(src->rts_good);
+ dst->fcs_bad = __le32_to_cpu(src->fcs_bad);
+ dst->no_beacons = __le32_to_cpu(src->no_beacons);
+ dst->mib_int_count = __le32_to_cpu(src->mib_int_count);
+
+ list_add_tail(&dst->list, &stats->pdevs);
+ }
+
+ /* fw doesn't implement vdev stats */
+
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_10x_peer_stats *src;
+ struct ath10k_fw_stats_peer *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_peer_stats(&src->old, dst);
+
+ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
+
+ list_add_tail(&dst->list, &stats->peers);
+ }
+
+ return 0;
+}
+
+int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+ return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats);
+ else
+ return ath10k_wmi_main_pull_fw_stats(ar, skb, stats);
+}
+
static void ath10k_wmi_event_update_stats(struct ath10k *ar,
struct sk_buff *skb)
{
- struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
-
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
-
- ath10k_debug_read_target_stats(ar, ev);
+ ath10k_debug_fw_stats_process(ar, skb);
}
static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
struct wmi_bcn_info *bcn_info;
struct ath10k_vif *arvif;
struct sk_buff *bcn;
+ dma_addr_t paddr;
int ret, vdev_id = 0;
ev = (struct wmi_host_swba_event *)skb->data;
ath10k_warn(ar, "SWBA overrun on vdev %d\n",
arvif->vdev_id);
- dma_unmap_single(arvif->ar->dev,
- ATH10K_SKB_CB(arvif->beacon)->paddr,
- arvif->beacon->len, DMA_TO_DEVICE);
- dev_kfree_skb_any(arvif->beacon);
- arvif->beacon = NULL;
+ ath10k_mac_vif_beacon_free(arvif);
}
- ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev,
- bcn->data, bcn->len,
- DMA_TO_DEVICE);
- ret = dma_mapping_error(arvif->ar->dev,
- ATH10K_SKB_CB(bcn)->paddr);
- if (ret) {
- ath10k_warn(ar, "failed to map beacon: %d\n", ret);
- dev_kfree_skb_any(bcn);
- goto skip;
+ if (!arvif->beacon_buf) {
+ paddr = dma_map_single(arvif->ar->dev, bcn->data,
+ bcn->len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(arvif->ar->dev, paddr);
+ if (ret) {
+ ath10k_warn(ar, "failed to map beacon: %d\n",
+ ret);
+ dev_kfree_skb_any(bcn);
+ goto skip;
+ }
+
+ ATH10K_SKB_CB(bcn)->paddr = paddr;
+ } else {
+ if (bcn->len > IEEE80211_MAX_FRAME_LEN) {
+ ath10k_warn(ar, "trimming beacon %d -> %d bytes!\n",
+ bcn->len, IEEE80211_MAX_FRAME_LEN);
+ skb_trim(bcn, IEEE80211_MAX_FRAME_LEN);
+ }
+ memcpy(arvif->beacon_buf, bcn->data, bcn->len);
+ ATH10K_SKB_CB(bcn)->paddr = arvif->beacon_paddr;
}
arvif->beacon = bcn;
arvif->beacon_sent = false;
+ trace_ath10k_wmi_bcn_tx(ar, bcn->data, bcn->len);
ath10k_wmi_tx_beacon_nowait(arvif);
skip:
spin_unlock_bh(&ar->data_lock);
}
static void ath10k_dfs_radar_report(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
- struct phyerr_radar_report *rr,
+ const struct wmi_phyerr *phyerr,
+ const struct phyerr_radar_report *rr,
u64 tsf)
{
u32 reg0, reg1, tsf32l;
return;
/* report event to DFS pattern detector */
- tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
+ tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
tsf64 = tsf & (~0xFFFFFFFFULL);
tsf64 |= tsf32l;
width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
- rssi = event->hdr.rssi_combined;
+ rssi = phyerr->rssi_combined;
/* hardware store this as 8 bit signed value,
* set to zero if negative number
}
static int ath10k_dfs_fft_report(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
- struct phyerr_fft_report *fftr,
+ const struct wmi_phyerr *phyerr,
+ const struct phyerr_fft_report *fftr,
u64 tsf)
{
u32 reg0, reg1;
reg0 = __le32_to_cpu(fftr->reg0);
reg1 = __le32_to_cpu(fftr->reg1);
- rssi = event->hdr.rssi_combined;
+ rssi = phyerr->rssi_combined;
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
}
static void ath10k_wmi_event_dfs(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
+ const struct wmi_phyerr *phyerr,
u64 tsf)
{
int buf_len, tlv_len, res, i = 0;
- struct phyerr_tlv *tlv;
- struct phyerr_radar_report *rr;
- struct phyerr_fft_report *fftr;
- u8 *tlv_buf;
+ const struct phyerr_tlv *tlv;
+ const struct phyerr_radar_report *rr;
+ const struct phyerr_fft_report *fftr;
+ const u8 *tlv_buf;
- buf_len = __le32_to_cpu(event->hdr.buf_len);
+ buf_len = __le32_to_cpu(phyerr->buf_len);
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
- event->hdr.phy_err_code, event->hdr.rssi_combined,
- __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
+ phyerr->phy_err_code, phyerr->rssi_combined,
+ __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len);
/* Skip event if DFS disabled */
if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED))
return;
}
- tlv = (struct phyerr_tlv *)&event->bufp[i];
+ tlv = (struct phyerr_tlv *)&phyerr->buf[i];
tlv_len = __le16_to_cpu(tlv->len);
- tlv_buf = &event->bufp[i + sizeof(*tlv)];
+ tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
tlv_len, tlv->tag, tlv->sig);
}
rr = (struct phyerr_radar_report *)tlv_buf;
- ath10k_dfs_radar_report(ar, event, rr, tsf);
+ ath10k_dfs_radar_report(ar, phyerr, rr, tsf);
break;
case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
}
fftr = (struct phyerr_fft_report *)tlv_buf;
- res = ath10k_dfs_fft_report(ar, event, fftr, tsf);
+ res = ath10k_dfs_fft_report(ar, phyerr, fftr, tsf);
if (res)
return;
break;
static void
ath10k_wmi_event_spectral_scan(struct ath10k *ar,
- struct wmi_single_phyerr_rx_event *event,
+ const struct wmi_phyerr *phyerr,
u64 tsf)
{
int buf_len, tlv_len, res, i = 0;
struct phyerr_tlv *tlv;
- u8 *tlv_buf;
- struct phyerr_fft_report *fftr;
+ const void *tlv_buf;
+ const struct phyerr_fft_report *fftr;
size_t fftr_len;
- buf_len = __le32_to_cpu(event->hdr.buf_len);
+ buf_len = __le32_to_cpu(phyerr->buf_len);
while (i < buf_len) {
if (i + sizeof(*tlv) > buf_len) {
return;
}
- tlv = (struct phyerr_tlv *)&event->bufp[i];
+ tlv = (struct phyerr_tlv *)&phyerr->buf[i];
tlv_len = __le16_to_cpu(tlv->len);
- tlv_buf = &event->bufp[i + sizeof(*tlv)];
+ tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
if (i + sizeof(*tlv) + tlv_len > buf_len) {
ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
}
fftr_len = tlv_len - sizeof(*fftr);
- fftr = (struct phyerr_fft_report *)tlv_buf;
- res = ath10k_spectral_process_fft(ar, event,
+ fftr = tlv_buf;
+ res = ath10k_spectral_process_fft(ar, phyerr,
fftr, fftr_len,
tsf);
if (res < 0) {
static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
{
- struct wmi_comb_phyerr_rx_event *comb_event;
- struct wmi_single_phyerr_rx_event *event;
+ const struct wmi_phyerr_event *ev;
+ const struct wmi_phyerr *phyerr;
u32 count, i, buf_len, phy_err_code;
u64 tsf;
int left_len = skb->len;
ATH10K_DFS_STAT_INC(ar, phy_errors);
/* Check if combined event available */
- if (left_len < sizeof(*comb_event)) {
+ if (left_len < sizeof(*ev)) {
ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
return;
}
- left_len -= sizeof(*comb_event);
+ left_len -= sizeof(*ev);
/* Check number of included events */
- comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data;
- count = __le32_to_cpu(comb_event->hdr.num_phyerr_events);
+ ev = (const struct wmi_phyerr_event *)skb->data;
+ count = __le32_to_cpu(ev->num_phyerrs);
- tsf = __le32_to_cpu(comb_event->hdr.tsf_u32);
+ tsf = __le32_to_cpu(ev->tsf_u32);
tsf <<= 32;
- tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
+ tsf |= __le32_to_cpu(ev->tsf_l32);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event phyerr count %d tsf64 0x%llX\n",
count, tsf);
- event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp;
+ phyerr = ev->phyerrs;
for (i = 0; i < count; i++) {
/* Check if we can read event header */
- if (left_len < sizeof(*event)) {
+ if (left_len < sizeof(*phyerr)) {
ath10k_warn(ar, "single event (%d) wrong head len\n",
i);
return;
}
- left_len -= sizeof(*event);
+ left_len -= sizeof(*phyerr);
- buf_len = __le32_to_cpu(event->hdr.buf_len);
- phy_err_code = event->hdr.phy_err_code;
+ buf_len = __le32_to_cpu(phyerr->buf_len);
+ phy_err_code = phyerr->phy_err_code;
if (left_len < buf_len) {
ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
switch (phy_err_code) {
case PHY_ERROR_RADAR:
- ath10k_wmi_event_dfs(ar, event, tsf);
+ ath10k_wmi_event_dfs(ar, phyerr, tsf);
break;
case PHY_ERROR_SPECTRAL_SCAN:
- ath10k_wmi_event_spectral_scan(ar, event, tsf);
+ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
break;
case PHY_ERROR_FALSE_RADAR_EXT:
- ath10k_wmi_event_dfs(ar, event, tsf);
- ath10k_wmi_event_spectral_scan(ar, event, tsf);
+ ath10k_wmi_event_dfs(ar, phyerr, tsf);
+ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
break;
default:
break;
}
- event += sizeof(*event) + buf_len;
+ phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len;
}
}
return 0;
}
-static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
- struct sk_buff *skb)
+static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
{
- struct wmi_service_ready_event *ev = (void *)skb->data;
+ struct wmi_service_ready_event *ev;
+ size_t i, n;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ ev = (void *)skb->data;
+ skb_pull(skb, sizeof(*ev));
+ arg->min_tx_power = ev->hw_min_tx_power;
+ arg->max_tx_power = ev->hw_max_tx_power;
+ arg->ht_cap = ev->ht_cap_info;
+ arg->vht_cap = ev->vht_cap_info;
+ arg->sw_ver0 = ev->sw_version;
+ arg->sw_ver1 = ev->sw_version_1;
+ arg->phy_capab = ev->phy_capability;
+ arg->num_rf_chains = ev->num_rf_chains;
+ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+ arg->num_mem_reqs = ev->num_mem_reqs;
+ arg->service_map = ev->wmi_service_bitmap;
+
+ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+ ARRAY_SIZE(arg->mem_reqs));
+ for (i = 0; i < n; i++)
+ arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+ if (skb->len <
+ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+ return -EPROTO;
+
+ return 0;
+}
+
+static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
+{
+ struct wmi_10x_service_ready_event *ev;
+ int i, n;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ ev = (void *)skb->data;
+ skb_pull(skb, sizeof(*ev));
+ arg->min_tx_power = ev->hw_min_tx_power;
+ arg->max_tx_power = ev->hw_max_tx_power;
+ arg->ht_cap = ev->ht_cap_info;
+ arg->vht_cap = ev->vht_cap_info;
+ arg->sw_ver0 = ev->sw_version;
+ arg->phy_capab = ev->phy_capability;
+ arg->num_rf_chains = ev->num_rf_chains;
+ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+ arg->num_mem_reqs = ev->num_mem_reqs;
+ arg->service_map = ev->wmi_service_bitmap;
+
+ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+ ARRAY_SIZE(arg->mem_reqs));
+ for (i = 0; i < n; i++)
+ arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+ if (skb->len <
+ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+ return -EPROTO;
+
+ return 0;
+}
+
+static void ath10k_wmi_event_service_ready(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ struct wmi_svc_rdy_ev_arg arg = {};
+ u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
+ int ret;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
+ wmi_10x_svc_map(arg.service_map, svc_bmap);
+ } else {
+ ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
+ wmi_main_svc_map(arg.service_map, svc_bmap);
+ }
- if (skb->len < sizeof(*ev)) {
- ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
- skb->len, sizeof(*ev));
+ if (ret) {
+ ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
return;
}
- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
+ ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
+ ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
+ ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
+ ar->vht_cap_info = __le32_to_cpu(arg.vht_cap);
ar->fw_version_major =
- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
+ (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24;
+ ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff);
ar->fw_version_release =
- (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16;
- ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff);
- ar->phy_capability = __le32_to_cpu(ev->phy_capability);
- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
+ (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16;
+ ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff);
+ ar->phy_capability = __le32_to_cpu(arg.phy_capab);
+ ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
+ ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
+
+ ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+ arg.service_map, sizeof(arg.service_map));
/* only manually set fw features when not using FW IE format */
if (ar->fw_api == 1 && ar->fw_version_build > 636)
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
- ar->ath_common.regulatory.current_rd =
- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
- wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
- ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
- ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
- ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
+ ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
+ ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
ar->fw_version_build);
}
- /* FIXME: it probably should be better to support this */
- if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
- ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
- __le32_to_cpu(ev->num_mem_reqs));
- }
-
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
- __le32_to_cpu(ev->sw_version),
- __le32_to_cpu(ev->sw_version_1),
- __le32_to_cpu(ev->abi_version),
- __le32_to_cpu(ev->phy_capability),
- __le32_to_cpu(ev->ht_cap_info),
- __le32_to_cpu(ev->vht_cap_info),
- __le32_to_cpu(ev->vht_supp_mcs),
- __le32_to_cpu(ev->sys_cap_info),
- __le32_to_cpu(ev->num_mem_reqs),
- __le32_to_cpu(ev->num_rf_chains));
-
- complete(&ar->wmi.service_ready);
-}
-
-static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
- struct sk_buff *skb)
-{
- u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
- int ret;
- struct wmi_service_ready_event_10x *ev = (void *)skb->data;
- DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
-
- if (skb->len < sizeof(*ev)) {
- ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
- skb->len, sizeof(*ev));
- return;
- }
-
- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
- ar->fw_version_major =
- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
- ar->phy_capability = __le32_to_cpu(ev->phy_capability);
- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
-
- if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
- ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
- ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
- }
-
- ar->ath_common.regulatory.current_rd =
- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
- wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
- ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
- ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
- ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
-
- if (strlen(ar->hw->wiphy->fw_version) == 0) {
- snprintf(ar->hw->wiphy->fw_version,
- sizeof(ar->hw->wiphy->fw_version),
- "%u.%u",
- ar->fw_version_major,
- ar->fw_version_minor);
- }
-
- num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
-
- if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
+ num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs);
+ if (num_mem_reqs > WMI_MAX_MEM_REQS) {
ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
num_mem_reqs);
return;
}
- if (!num_mem_reqs)
- goto exit;
-
- ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
- num_mem_reqs);
-
for (i = 0; i < num_mem_reqs; ++i) {
- req_id = __le32_to_cpu(ev->mem_reqs[i].req_id);
- num_units = __le32_to_cpu(ev->mem_reqs[i].num_units);
- unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size);
- num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info);
+ req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
+ num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
+ unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size);
+ num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info);
if (num_unit_info & NUM_UNITS_IS_NUM_PEERS)
/* number of units to allocate is number of
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
req_id,
- __le32_to_cpu(ev->mem_reqs[i].num_units),
+ __le32_to_cpu(arg.mem_reqs[i]->num_units),
num_unit_info,
unit_size,
num_units);
return;
}
-exit:
ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
- __le32_to_cpu(ev->sw_version),
- __le32_to_cpu(ev->abi_version),
- __le32_to_cpu(ev->phy_capability),
- __le32_to_cpu(ev->ht_cap_info),
- __le32_to_cpu(ev->vht_cap_info),
- __le32_to_cpu(ev->vht_supp_mcs),
- __le32_to_cpu(ev->sys_cap_info),
- __le32_to_cpu(ev->num_mem_reqs),
- __le32_to_cpu(ev->num_rf_chains));
+ "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
+ __le32_to_cpu(arg.min_tx_power),
+ __le32_to_cpu(arg.max_tx_power),
+ __le32_to_cpu(arg.ht_cap),
+ __le32_to_cpu(arg.vht_cap),
+ __le32_to_cpu(arg.sw_ver0),
+ __le32_to_cpu(arg.sw_ver1),
+ __le32_to_cpu(arg.phy_capab),
+ __le32_to_cpu(arg.num_rf_chains),
+ __le32_to_cpu(arg.eeprom_rd),
+ __le32_to_cpu(arg.num_mem_reqs));
complete(&ar->wmi.service_ready);
}
-static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data;
ath10k_wmi_event_vdev_install_key_complete(ar, skb);
break;
case WMI_SERVICE_READY_EVENTID:
- ath10k_wmi_service_ready_event_rx(ar, skb);
+ ath10k_wmi_event_service_ready(ar, skb);
break;
case WMI_READY_EVENTID:
- ath10k_wmi_ready_event_rx(ar, skb);
+ ath10k_wmi_event_ready(ar, skb);
break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
ath10k_wmi_event_vdev_resume_req(ar, skb);
break;
case WMI_10X_SERVICE_READY_EVENTID:
- ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+ ath10k_wmi_event_service_ready(ar, skb);
break;
case WMI_10X_READY_EVENTID:
- ath10k_wmi_ready_event_rx(ar, skb);
+ ath10k_wmi_event_ready(ar, skb);
break;
case WMI_10X_PDEV_UTF_EVENTID:
/* ignore utf events */
ath10k_wmi_event_vdev_resume_req(ar, skb);
break;
case WMI_10_2_SERVICE_READY_EVENTID:
- ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+ ath10k_wmi_event_service_ready(ar, skb);
break;
case WMI_10_2_READY_EVENTID:
- ath10k_wmi_ready_event_rx(ar, skb);
+ ath10k_wmi_event_ready(ar, skb);
break;
case WMI_10_2_RTT_KEEPALIVE_EVENTID:
case WMI_10_2_GPIO_INPUT_EVENTID:
}
}
-/* WMI Initialization functions */
-int ath10k_wmi_attach(struct ath10k *ar)
-{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- ar->wmi.cmd = &wmi_10_2_cmd_map;
- else
- ar->wmi.cmd = &wmi_10x_cmd_map;
-
- ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
- ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
- } else {
- ar->wmi.cmd = &wmi_cmd_map;
- ar->wmi.vdev_param = &wmi_vdev_param_map;
- ar->wmi.pdev_param = &wmi_pdev_param_map;
- }
-
- init_completion(&ar->wmi.service_ready);
- init_completion(&ar->wmi.unified_ready);
- init_waitqueue_head(&ar->wmi.tx_credits_wq);
-
- return 0;
-}
-
-void ath10k_wmi_detach(struct ath10k *ar)
-{
- int i;
-
- /* free the host memory chunks requested by firmware */
- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- dma_free_coherent(ar->dev,
- ar->wmi.mem_chunks[i].len,
- ar->wmi.mem_chunks[i].vaddr,
- ar->wmi.mem_chunks[i].paddr);
- }
-
- ar->wmi.num_mem_chunks = 0;
-}
-
int ath10k_wmi_connect(struct ath10k *ar)
{
int status;
ctl2g, ctl5g);
}
-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
- const struct wmi_channel_arg *arg)
-{
- struct wmi_set_channel_cmd *cmd;
- struct sk_buff *skb;
- u32 ch_flags = 0;
-
- if (arg->passive)
- return -EINVAL;
-
- skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- if (!skb)
- return -ENOMEM;
-
- if (arg->chan_radar)
- ch_flags |= WMI_CHAN_FLAG_DFS;
-
- cmd = (struct wmi_set_channel_cmd *)skb->data;
- cmd->chan.mhz = __cpu_to_le32(arg->freq);
- cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq);
- cmd->chan.mode = arg->mode;
- cmd->chan.flags |= __cpu_to_le32(ch_flags);
- cmd->chan.min_power = arg->min_power;
- cmd->chan.max_power = arg->max_power;
- cmd->chan.reg_power = arg->max_reg_power;
- cmd->chan.reg_classid = arg->reg_class_id;
- cmd->chan.antenna_max = arg->max_antenna_gain;
-
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi set channel mode %d freq %d\n",
- arg->mode, arg->freq);
-
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_set_channel_cmdid);
-}
-
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
{
struct wmi_pdev_suspend_cmd *cmd;
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
}
+static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+ struct wmi_host_mem_chunks *chunks)
+{
+ struct host_memory_chunk *chunk;
+ int i;
+
+ chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+ chunk = &chunks->items[i];
+ chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+ chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+ chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi chunk %d len %d requested, addr 0x%llx\n",
+ i,
+ ar->wmi.mem_chunks[i].len,
+ (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+ }
+}
+
static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
{
struct wmi_init_cmd *cmd;
struct sk_buff *buf;
struct wmi_resource_config config = {};
u32 len, val;
- int i;
config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
cmd = (struct wmi_init_cmd *)buf->data;
- if (ar->wmi.num_mem_chunks == 0) {
- cmd->num_host_mem_chunks = 0;
- goto out;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
- ar->wmi.num_mem_chunks);
-
- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- cmd->host_mem_chunks[i].ptr =
- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- cmd->host_mem_chunks[i].size =
- __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- cmd->host_mem_chunks[i].req_id =
- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi chunk %d len %d requested, addr 0x%llx\n",
- i,
- ar->wmi.mem_chunks[i].len,
- (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- }
-out:
memcpy(&cmd->resource_config, &config, sizeof(config));
+ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
struct sk_buff *buf;
struct wmi_resource_config_10x config = {};
u32 len, val;
- int i;
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
cmd = (struct wmi_init_cmd_10x *)buf->data;
- if (ar->wmi.num_mem_chunks == 0) {
- cmd->num_host_mem_chunks = 0;
- goto out;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
- ar->wmi.num_mem_chunks);
-
- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- cmd->host_mem_chunks[i].ptr =
- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- cmd->host_mem_chunks[i].size =
- __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- cmd->host_mem_chunks[i].req_id =
- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi chunk %d len %d requested, addr 0x%llx\n",
- i,
- ar->wmi.mem_chunks[i].len,
- (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- }
-out:
memcpy(&cmd->resource_config, &config, sizeof(config));
+ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
struct sk_buff *buf;
struct wmi_resource_config_10x config = {};
u32 len, val;
- int i;
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
cmd = (struct wmi_init_cmd_10_2 *)buf->data;
- if (ar->wmi.num_mem_chunks == 0) {
- cmd->num_host_mem_chunks = 0;
- goto out;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
- ar->wmi.num_mem_chunks);
-
- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- cmd->host_mem_chunks[i].ptr =
- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- cmd->host_mem_chunks[i].size =
- __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- cmd->host_mem_chunks[i].req_id =
- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi chunk %d len %d requested, addr 0x%llx\n",
- i,
- ar->wmi.mem_chunks[i].len,
- (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- }
-out:
memcpy(&cmd->resource_config.common, &config, sizeof(config));
+ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
return ret;
}
-static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar,
- const struct wmi_start_scan_arg *arg)
+static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
{
- int len;
+ if (arg->ie_len && !arg->ie)
+ return -EINVAL;
+ if (arg->n_channels && !arg->channels)
+ return -EINVAL;
+ if (arg->n_ssids && !arg->ssids)
+ return -EINVAL;
+ if (arg->n_bssids && !arg->bssids)
+ return -EINVAL;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- len = sizeof(struct wmi_start_scan_cmd_10x);
- else
- len = sizeof(struct wmi_start_scan_cmd);
+ if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
+ return -EINVAL;
+ if (arg->n_channels > ARRAY_SIZE(arg->channels))
+ return -EINVAL;
+ if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
+ return -EINVAL;
+ if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
+ return -EINVAL;
- if (arg->ie_len) {
- if (!arg->ie)
- return -EINVAL;
- if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
- return -EINVAL;
+ return 0;
+}
+static size_t
+ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg)
+{
+ int len = 0;
+
+ if (arg->ie_len) {
len += sizeof(struct wmi_ie_data);
len += roundup(arg->ie_len, 4);
}
if (arg->n_channels) {
- if (!arg->channels)
- return -EINVAL;
- if (arg->n_channels > ARRAY_SIZE(arg->channels))
- return -EINVAL;
-
len += sizeof(struct wmi_chan_list);
len += sizeof(__le32) * arg->n_channels;
}
if (arg->n_ssids) {
- if (!arg->ssids)
- return -EINVAL;
- if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
- return -EINVAL;
-
len += sizeof(struct wmi_ssid_list);
len += sizeof(struct wmi_ssid) * arg->n_ssids;
}
if (arg->n_bssids) {
- if (!arg->bssids)
- return -EINVAL;
- if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
- return -EINVAL;
-
len += sizeof(struct wmi_bssid_list);
len += sizeof(struct wmi_mac_addr) * arg->n_bssids;
}
return len;
}
-int ath10k_wmi_start_scan(struct ath10k *ar,
- const struct wmi_start_scan_arg *arg)
+static void
+ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+ const struct wmi_start_scan_arg *arg)
{
- struct wmi_start_scan_cmd *cmd;
- struct sk_buff *skb;
- struct wmi_ie_data *ie;
- struct wmi_chan_list *channels;
- struct wmi_ssid_list *ssids;
- struct wmi_bssid_list *bssids;
u32 scan_id;
u32 scan_req_id;
- int off;
- int len = 0;
- int i;
-
- len = ath10k_wmi_start_scan_calc_len(ar, arg);
- if (len < 0)
- return len; /* len contains error code here */
-
- skb = ath10k_wmi_alloc_skb(ar, len);
- if (!skb)
- return -ENOMEM;
scan_id = WMI_HOST_SCAN_REQ_ID_PREFIX;
scan_id |= arg->scan_id;
scan_req_id = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
scan_req_id |= arg->scan_req_id;
- cmd = (struct wmi_start_scan_cmd *)skb->data;
- cmd->scan_id = __cpu_to_le32(scan_id);
- cmd->scan_req_id = __cpu_to_le32(scan_req_id);
- cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
- cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
- cmd->dwell_time_active = __cpu_to_le32(arg->dwell_time_active);
- cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
- cmd->min_rest_time = __cpu_to_le32(arg->min_rest_time);
- cmd->max_rest_time = __cpu_to_le32(arg->max_rest_time);
- cmd->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time);
- cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
- cmd->idle_time = __cpu_to_le32(arg->idle_time);
- cmd->max_scan_time = __cpu_to_le32(arg->max_scan_time);
- cmd->probe_delay = __cpu_to_le32(arg->probe_delay);
- cmd->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags);
-
- /* TLV list starts after fields included in the struct */
- /* There's just one filed that differes the two start_scan
- * structures - burst_duration, which we are not using btw,
- no point to make the split here, just shift the buffer to fit with
- given FW */
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- off = sizeof(struct wmi_start_scan_cmd_10x);
- else
- off = sizeof(struct wmi_start_scan_cmd);
+ cmn->scan_id = __cpu_to_le32(scan_id);
+ cmn->scan_req_id = __cpu_to_le32(scan_req_id);
+ cmn->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmn->scan_priority = __cpu_to_le32(arg->scan_priority);
+ cmn->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
+ cmn->dwell_time_active = __cpu_to_le32(arg->dwell_time_active);
+ cmn->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
+ cmn->min_rest_time = __cpu_to_le32(arg->min_rest_time);
+ cmn->max_rest_time = __cpu_to_le32(arg->max_rest_time);
+ cmn->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time);
+ cmn->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
+ cmn->idle_time = __cpu_to_le32(arg->idle_time);
+ cmn->max_scan_time = __cpu_to_le32(arg->max_scan_time);
+ cmn->probe_delay = __cpu_to_le32(arg->probe_delay);
+ cmn->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags);
+}
+
+static void
+ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
+ const struct wmi_start_scan_arg *arg)
+{
+ struct wmi_ie_data *ie;
+ struct wmi_chan_list *channels;
+ struct wmi_ssid_list *ssids;
+ struct wmi_bssid_list *bssids;
+ void *ptr = tlvs->tlvs;
+ int i;
if (arg->n_channels) {
- channels = (void *)skb->data + off;
+ channels = ptr;
channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG);
channels->num_chan = __cpu_to_le32(arg->n_channels);
channels->channel_list[i].freq =
__cpu_to_le16(arg->channels[i]);
- off += sizeof(*channels);
- off += sizeof(__le32) * arg->n_channels;
+ ptr += sizeof(*channels);
+ ptr += sizeof(__le32) * arg->n_channels;
}
if (arg->n_ssids) {
- ssids = (void *)skb->data + off;
+ ssids = ptr;
ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG);
ssids->num_ssids = __cpu_to_le32(arg->n_ssids);
arg->ssids[i].len);
}
- off += sizeof(*ssids);
- off += sizeof(struct wmi_ssid) * arg->n_ssids;
+ ptr += sizeof(*ssids);
+ ptr += sizeof(struct wmi_ssid) * arg->n_ssids;
}
if (arg->n_bssids) {
- bssids = (void *)skb->data + off;
+ bssids = ptr;
bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG);
bssids->num_bssid = __cpu_to_le32(arg->n_bssids);
arg->bssids[i].bssid,
ETH_ALEN);
- off += sizeof(*bssids);
- off += sizeof(struct wmi_mac_addr) * arg->n_bssids;
+ ptr += sizeof(*bssids);
+ ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids;
}
if (arg->ie_len) {
- ie = (void *)skb->data + off;
+ ie = ptr;
ie->tag = __cpu_to_le32(WMI_IE_TAG);
ie->ie_len = __cpu_to_le32(arg->ie_len);
memcpy(ie->ie_data, arg->ie, arg->ie_len);
- off += sizeof(*ie);
- off += roundup(arg->ie_len, 4);
+ ptr += sizeof(*ie);
+ ptr += roundup(arg->ie_len, 4);
}
+}
- if (off != skb->len) {
- dev_kfree_skb(skb);
- return -EINVAL;
+int ath10k_wmi_start_scan(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg)
+{
+ struct sk_buff *skb;
+ size_t len;
+ int ret;
+
+ ret = ath10k_wmi_start_scan_verify(arg);
+ if (ret)
+ return ret;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+ len = sizeof(struct wmi_10x_start_scan_cmd) +
+ ath10k_wmi_start_scan_tlvs_len(arg);
+ else
+ len = sizeof(struct wmi_start_scan_cmd) +
+ ath10k_wmi_start_scan_tlvs_len(arg);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return -ENOMEM;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ struct wmi_10x_start_scan_cmd *cmd;
+
+ cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
+ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+ } else {
+ struct wmi_start_scan_cmd *cmd;
+
+ cmd = (struct wmi_start_scan_cmd *)skb->data;
+ cmd->burst_duration_ms = __cpu_to_le32(0);
+
+ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
}
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
struct sk_buff *skb;
const char *cmdname;
u32 flags = 0;
- u32 ch_flags = 0;
if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
flags |= WMI_VDEV_START_HIDDEN_SSID;
if (arg->pmf_enabled)
flags |= WMI_VDEV_START_PMF_ENABLED;
- if (arg->channel.chan_radar)
- ch_flags |= WMI_CHAN_FLAG_DFS;
cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
}
- cmd->chan.mhz = __cpu_to_le32(arg->channel.freq);
-
- cmd->chan.band_center_freq1 =
- __cpu_to_le32(arg->channel.band_center_freq1);
-
- cmd->chan.mode = arg->channel.mode;
- cmd->chan.flags |= __cpu_to_le32(ch_flags);
- cmd->chan.min_power = arg->channel.min_power;
- cmd->chan.max_power = arg->channel.max_power;
- cmd->chan.reg_power = arg->channel.max_reg_power;
- cmd->chan.reg_classid = arg->channel.reg_class_id;
- cmd->chan.antenna_max = arg->channel.max_antenna_gain;
+ ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
for (i = 0; i < arg->n_channels; i++) {
- u32 flags = 0;
-
ch = &arg->channels[i];
ci = &cmd->chan_info[i];
- if (ch->passive)
- flags |= WMI_CHAN_FLAG_PASSIVE;
- if (ch->allow_ibss)
- flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
- if (ch->allow_ht)
- flags |= WMI_CHAN_FLAG_ALLOW_HT;
- if (ch->allow_vht)
- flags |= WMI_CHAN_FLAG_ALLOW_VHT;
- if (ch->ht40plus)
- flags |= WMI_CHAN_FLAG_HT40_PLUS;
- if (ch->chan_radar)
- flags |= WMI_CHAN_FLAG_DFS;
-
- ci->mhz = __cpu_to_le32(ch->freq);
- ci->band_center_freq1 = __cpu_to_le32(ch->freq);
- ci->band_center_freq2 = 0;
- ci->min_power = ch->min_power;
- ci->max_power = ch->max_power;
- ci->reg_power = ch->max_reg_power;
- ci->antenna_max = ch->max_antenna_gain;
-
- /* mode & flags share storage */
- ci->mode = ch->mode;
- ci->flags |= __cpu_to_le32(flags);
+ ath10k_wmi_put_wmi_channel(ci, ch);
}
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
}
+
+int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
+{
+ struct wmi_pdev_pktlog_enable_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ ev_bitmap &= ATH10K_PKTLOG_ANY;
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi enable pktlog filter:%x\n", ev_bitmap);
+
+ cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data;
+ cmd->ev_bitmap = __cpu_to_le32(ev_bitmap);
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+}
+
+int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, 0);
+ if (!skb)
+ return -ENOMEM;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n");
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+}
+
+int ath10k_wmi_attach(struct ath10k *ar)
+{
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ar->wmi.cmd = &wmi_10_2_cmd_map;
+ else
+ ar->wmi.cmd = &wmi_10x_cmd_map;
+
+ ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
+ ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+ } else {
+ ar->wmi.cmd = &wmi_cmd_map;
+ ar->wmi.vdev_param = &wmi_vdev_param_map;
+ ar->wmi.pdev_param = &wmi_pdev_param_map;
+ }
+
+ init_completion(&ar->wmi.service_ready);
+ init_completion(&ar->wmi.unified_ready);
+ init_waitqueue_head(&ar->wmi.tx_credits_wq);
+
+ return 0;
+}
+
+void ath10k_wmi_detach(struct ath10k *ar)
+{
+ int i;
+
+ /* free the host memory chunks requested by firmware */
+ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+ dma_free_coherent(ar->dev,
+ ar->wmi.mem_chunks[i].len,
+ ar->wmi.mem_chunks[i].vaddr,
+ ar->wmi.mem_chunks[i].paddr);
+ }
+
+ ar->wmi.num_mem_chunks = 0;
+}
* where FW can access this memory directly (or) by DMA.
*/
__le32 num_mem_reqs;
- struct wlan_host_mem_req mem_reqs[1];
+ struct wlan_host_mem_req mem_reqs[0];
} __packed;
/* This is the definition from 10.X firmware branch */
-struct wmi_service_ready_event_10x {
+struct wmi_10x_service_ready_event {
__le32 sw_version;
__le32 abi_version;
*/
__le32 num_mem_reqs;
- struct wlan_host_mem_req mem_reqs[1];
+ struct wlan_host_mem_req mem_reqs[0];
} __packed;
#define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
__le32 size;
} __packed;
+struct wmi_host_mem_chunks {
+ __le32 count;
+ /* some fw revisions require at least 1 chunk regardless of count */
+ struct host_memory_chunk items[1];
+} __packed;
+
struct wmi_init_cmd {
struct wmi_resource_config resource_config;
- __le32 num_host_mem_chunks;
-
- /*
- * variable number of host memory chunks.
- * This should be the last element in the structure
- */
- struct host_memory_chunk host_mem_chunks[1];
+ struct wmi_host_mem_chunks mem_chunks;
} __packed;
/* _10x stucture is from 10.X FW API */
struct wmi_init_cmd_10x {
struct wmi_resource_config_10x resource_config;
- __le32 num_host_mem_chunks;
-
- /*
- * variable number of host memory chunks.
- * This should be the last element in the structure
- */
- struct host_memory_chunk host_mem_chunks[1];
+ struct wmi_host_mem_chunks mem_chunks;
} __packed;
struct wmi_init_cmd_10_2 {
struct wmi_resource_config_10_2 resource_config;
- __le32 num_host_mem_chunks;
-
- /*
- * variable number of host memory chunks.
- * This should be the last element in the structure
- */
- struct host_memory_chunk host_mem_chunks[1];
+ struct wmi_host_mem_chunks mem_chunks;
} __packed;
struct wmi_chan_list_entry {
WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */
};
-struct wmi_start_scan_cmd {
+struct wmi_start_scan_common {
/* Scan ID */
__le32 scan_id;
/* Scan requestor ID */
__le32 probe_delay;
/* Scan control flags */
__le32 scan_ctrl_flags;
-
- /* Burst duration time in msecs */
- __le32 burst_duration;
- /*
- * TLV (tag length value ) paramerters follow the scan_cmd structure.
- * TLV can contain channel list, bssid list, ssid list and
- * ie. the TLV tags are defined above;
- */
} __packed;
-/* This is the definition from 10.X firmware branch */
-struct wmi_start_scan_cmd_10x {
- /* Scan ID */
- __le32 scan_id;
-
- /* Scan requestor ID */
- __le32 scan_req_id;
-
- /* VDEV id(interface) that is requesting scan */
- __le32 vdev_id;
-
- /* Scan Priority, input to scan scheduler */
- __le32 scan_priority;
-
- /* Scan events subscription */
- __le32 notify_scan_events;
-
- /* dwell time in msec on active channels */
- __le32 dwell_time_active;
-
- /* dwell time in msec on passive channels */
- __le32 dwell_time_passive;
-
- /*
- * min time in msec on the BSS channel,only valid if atleast one
- * VDEV is active
- */
- __le32 min_rest_time;
-
- /*
- * max rest time in msec on the BSS channel,only valid if at least
- * one VDEV is active
- */
- /*
- * the scanner will rest on the bss channel at least min_rest_time
- * after min_rest_time the scanner will start checking for tx/rx
- * activity on all VDEVs. if there is no activity the scanner will
- * switch to off channel. if there is activity the scanner will let
- * the radio on the bss channel until max_rest_time expires.at
- * max_rest_time scanner will switch to off channel irrespective of
- * activity. activity is determined by the idle_time parameter.
- */
- __le32 max_rest_time;
-
- /*
- * time before sending next set of probe requests.
- * The scanner keeps repeating probe requests transmission with
- * period specified by repeat_probe_time.
- * The number of probe requests specified depends on the ssid_list
- * and bssid_list
- */
- __le32 repeat_probe_time;
-
- /* time in msec between 2 consequetive probe requests with in a set. */
- __le32 probe_spacing_time;
-
- /*
- * data inactivity time in msec on bss channel that will be used by
- * scanner for measuring the inactivity.
- */
- __le32 idle_time;
-
- /* maximum time in msec allowed for scan */
- __le32 max_scan_time;
-
- /*
- * delay in msec before sending first probe request after switching
- * to a channel
+struct wmi_start_scan_tlvs {
+ /* TLV parameters. These includes channel list, ssid list, bssid list,
+ * extra ies.
*/
- __le32 probe_delay;
+ u8 tlvs[0];
+} __packed;
- /* Scan control flags */
- __le32 scan_ctrl_flags;
+struct wmi_start_scan_cmd {
+ struct wmi_start_scan_common common;
+ __le32 burst_duration_ms;
+ struct wmi_start_scan_tlvs tlvs;
+} __packed;
- /*
- * TLV (tag length value ) paramerters follow the scan_cmd structure.
- * TLV can contain channel list, bssid list, ssid list and
- * ie. the TLV tags are defined above;
- */
+/* This is the definition from 10.X firmware branch */
+struct wmi_10x_start_scan_cmd {
+ struct wmi_start_scan_common common;
+ struct wmi_start_scan_tlvs tlvs;
} __packed;
struct wmi_ssid_arg {
#define PHY_ERROR_FALSE_RADAR_EXT 0x24
#define PHY_ERROR_RADAR 0x05
-struct wmi_single_phyerr_rx_hdr {
- /* TSF timestamp */
+struct wmi_phyerr {
__le32 tsf_timestamp;
-
- /*
- * Current freq1, freq2
- *
- * [7:0]: freq1[lo]
- * [15:8] : freq1[hi]
- * [23:16]: freq2[lo]
- * [31:24]: freq2[hi]
- */
__le16 freq1;
__le16 freq2;
-
- /*
- * Combined RSSI over all chains and channel width for this PHY error
- *
- * [7:0]: RSSI combined
- * [15:8]: Channel width (MHz)
- * [23:16]: PHY error code
- * [24:16]: reserved (future use)
- */
u8 rssi_combined;
u8 chan_width_mhz;
u8 phy_err_code;
u8 rsvd0;
-
- /*
- * RSSI on chain 0 through 3
- *
- * This is formatted the same as the PPDU_START RX descriptor
- * field:
- *
- * [7:0]: pri20
- * [15:8]: sec20
- * [23:16]: sec40
- * [31:24]: sec80
- */
-
- __le32 rssi_chain0;
- __le32 rssi_chain1;
- __le32 rssi_chain2;
- __le32 rssi_chain3;
-
- /*
- * Last calibrated NF value for chain 0 through 3
- *
- * nf_list_1:
- *
- * + [15:0] - chain 0
- * + [31:16] - chain 1
- *
- * nf_list_2:
- *
- * + [15:0] - chain 2
- * + [31:16] - chain 3
- */
- __le32 nf_list_1;
- __le32 nf_list_2;
-
- /* Length of the frame */
+ __le32 rssi_chains[4];
+ __le16 nf_chains[4];
__le32 buf_len;
+ u8 buf[0];
} __packed;
-struct wmi_single_phyerr_rx_event {
- /* Phy error event header */
- struct wmi_single_phyerr_rx_hdr hdr;
- /* frame buffer */
- u8 bufp[0];
-} __packed;
-
-struct wmi_comb_phyerr_rx_hdr {
- /* Phy error phy error count */
- __le32 num_phyerr_events;
+struct wmi_phyerr_event {
+ __le32 num_phyerrs;
__le32 tsf_l32;
__le32 tsf_u32;
-} __packed;
-
-struct wmi_comb_phyerr_rx_event {
- /* Phy error phy error count */
- struct wmi_comb_phyerr_rx_hdr hdr;
- /*
- * frame buffer - contains multiple payloads in the order:
- * header - payload, header - payload...
- * (The header is of type: wmi_single_phyerr_rx_hdr)
- */
- u8 bufp[0];
+ struct wmi_phyerr phyerrs[0];
} __packed;
#define PHYERR_TLV_SIG 0xBB
WMI_TP_SCALE_SIZE = 5, /* max num of enum */
};
-struct wmi_set_channel_cmd {
- /* channel (only frequency and mode info are used) */
- struct wmi_channel chan;
-} __packed;
-
struct wmi_pdev_chanlist_update_event {
/* number of channels */
__le32 num_chan;
struct wmi_channel chan;
} __packed;
+struct wmi_pdev_pktlog_enable_cmd {
+ __le32 ev_bitmap;
+} __packed;
+
/* Customize the DSCP (bit) to TID (0-7) mapping for QOS */
#define WMI_DSCP_MAP_MAX (64)
struct wmi_pdev_set_dscp_tid_map_cmd {
* PDEV statistics
* TODO: add all PDEV stats here
*/
-struct wmi_pdev_stats_old {
+struct wmi_pdev_stats {
__le32 chan_nf; /* Channel noise floor */
__le32 tx_frame_count; /* TX frame count */
__le32 rx_frame_count; /* RX frame count */
struct wal_dbg_stats wal; /* WAL dbg stats */
} __packed;
-struct wmi_pdev_stats_10x {
- __le32 chan_nf; /* Channel noise floor */
- __le32 tx_frame_count; /* TX frame count */
- __le32 rx_frame_count; /* RX frame count */
- __le32 rx_clear_count; /* rx clear count */
- __le32 cycle_count; /* cycle count */
- __le32 phy_err_count; /* Phy error count */
- __le32 chan_tx_pwr; /* channel tx power */
- struct wal_dbg_stats wal; /* WAL dbg stats */
+struct wmi_10x_pdev_stats {
+ struct wmi_pdev_stats old;
__le32 ack_rx_bad;
__le32 rts_bad;
__le32 rts_good;
* peer statistics.
* TODO: add more stats
*/
-struct wmi_peer_stats_old {
+struct wmi_peer_stats {
struct wmi_mac_addr peer_macaddr;
__le32 peer_rssi;
__le32 peer_tx_rate;
} __packed;
-struct wmi_peer_stats_10x {
- struct wmi_mac_addr peer_macaddr;
- __le32 peer_rssi;
- __le32 peer_tx_rate;
+struct wmi_10x_peer_stats {
+ struct wmi_peer_stats old;
__le32 peer_rx_rate;
} __packed;
/* By default disable power save for IBSS */
#define ATH10K_DEFAULT_ATIM 0
+#define WMI_MAX_MEM_REQS 16
+
+struct wmi_svc_rdy_ev_arg {
+ __le32 min_tx_power;
+ __le32 max_tx_power;
+ __le32 ht_cap;
+ __le32 vht_cap;
+ __le32 sw_ver0;
+ __le32 sw_ver1;
+ __le32 phy_capab;
+ __le32 num_rf_chains;
+ __le32 eeprom_rd;
+ __le32 num_mem_reqs;
+ const __le32 *service_map;
+ const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
+};
+
struct ath10k;
struct ath10k_vif;
+struct ath10k_fw_stats;
int ath10k_wmi_attach(struct ath10k *ar);
void ath10k_wmi_detach(struct ath10k *ar);
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
- const struct wmi_channel_arg *);
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
enum wmi_force_fw_hang_type type, u32 delay_ms);
int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
+int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+ struct ath10k_fw_stats *stats);
+int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list);
+int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar);
#endif /* _WMI_H_ */
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac)
+ struct station_del_parameters *params)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
- const u8 *addr = mac ? mac : bcast_addr;
+ const u8 *addr = params->mac ? params->mac : bcast_addr;
return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
#define ATH6KL_MAX_IE 256
-__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
+__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
/*
* Reflects the version of binary interface exposed by ATH6KL target
#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
-int ath6kl_printk(const char *level, const char *fmt, ...)
+void ath6kl_printk(const char *level, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
- int rtn;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- rtn = printk("%sath6kl: %pV", level, &vaf);
+ printk("%sath6kl: %pV", level, &vaf);
va_end(args);
-
- return rtn;
}
EXPORT_SYMBOL(ath6kl_printk);
-int ath6kl_info(const char *fmt, ...)
+void ath6kl_info(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = ath6kl_printk(KERN_INFO, "%pV", &vaf);
+ ath6kl_printk(KERN_INFO, "%pV", &vaf);
trace_ath6kl_log_info(&vaf);
va_end(args);
-
- return ret;
}
EXPORT_SYMBOL(ath6kl_info);
-int ath6kl_err(const char *fmt, ...)
+void ath6kl_err(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = ath6kl_printk(KERN_ERR, "%pV", &vaf);
+ ath6kl_printk(KERN_ERR, "%pV", &vaf);
trace_ath6kl_log_err(&vaf);
va_end(args);
-
- return ret;
}
EXPORT_SYMBOL(ath6kl_err);
-int ath6kl_warn(const char *fmt, ...)
+void ath6kl_warn(const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf);
+ ath6kl_printk(KERN_WARNING, "%pV", &vaf);
trace_ath6kl_log_warn(&vaf);
va_end(args);
-
- return ret;
}
EXPORT_SYMBOL(ath6kl_warn);
};
extern unsigned int debug_mask;
-__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
-__printf(1, 2) int ath6kl_info(const char *fmt, ...);
-__printf(1, 2) int ath6kl_err(const char *fmt, ...);
-__printf(1, 2) int ath6kl_warn(const char *fmt, ...);
+__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
+__printf(1, 2) void ath6kl_info(const char *fmt, ...);
+__printf(1, 2) void ath6kl_err(const char *fmt, ...);
+__printf(1, 2) void ath6kl_warn(const char *fmt, ...);
enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
void ath6kl_debug_cleanup(struct ath6kl *ar);
#else
-static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
- const char *fmt, ...)
+static inline void ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
+ const char *fmt, ...)
{
- return 0;
}
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
for multi-channel concurrency. Enable this if P2P PowerSave support
is required.
+config ATH9K_PCOEM
+ bool "Atheros ath9k support for PC OEM cards" if EXPERT
+ depends on ATH9K
+ default y
+
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
ar5008_phy.o \
ar9002_calib.o \
ar9003_calib.o \
- ar9003_rtt.o \
calib.o \
eeprom.o \
eeprom_def.o \
ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
ar9003_mci.o
+ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o
+
ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
static void ar5008_hw_set_radar_params(struct ath_hw *ah,
struct ath_hw_radar_conf *conf)
{
- u32 radar_0 = 0, radar_1 = 0;
+ u32 radar_0 = 0, radar_1;
if (!conf) {
REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+ radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
+ radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
+ AR_PHY_RADAR_1_RELPWR_THRESH);
radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
conf->fir_power = -33;
conf->radar_rssi = 20;
conf->pulse_height = 10;
- conf->pulse_rssi = 24;
+ conf->pulse_rssi = 15;
conf->pulse_inband = 15;
conf->pulse_maxlen = 255;
conf->pulse_inband_step = 12;
ar9280_hw_olc_temp_compensation(ah);
}
-static bool ar9002_hw_calibrate(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u8 rxchainmask,
- bool longcal)
+static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal)
{
- bool iscaldone = true;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
- bool nfcal, nfcal_pending = false;
+ bool nfcal, nfcal_pending = false, percal_pending;
+ int ret;
nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
if (ah->caldata)
nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
- if (currCal && !nfcal &&
- (currCal->calState == CAL_RUNNING ||
- currCal->calState == CAL_WAITING)) {
- iscaldone = ar9002_hw_per_calibration(ah, chan,
- rxchainmask, currCal);
- if (iscaldone) {
- ah->cal_list_curr = currCal = currCal->calNext;
-
- if (currCal->calState == CAL_WAITING) {
- iscaldone = false;
- ath9k_hw_reset_calibration(ah, currCal);
- }
+ percal_pending = (currCal &&
+ (currCal->calState == CAL_RUNNING ||
+ currCal->calState == CAL_WAITING));
+
+ if (percal_pending && !nfcal) {
+ if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
+ return 0;
+
+ ah->cal_list_curr = currCal = currCal->calNext;
+ if (currCal->calState == CAL_WAITING) {
+ ath9k_hw_reset_calibration(ah, currCal);
+ return 0;
}
}
* NF is slow time-variant, so it is OK to use a
* historical value.
*/
- ath9k_hw_loadnf(ah, ah->curchan);
+ ret = ath9k_hw_loadnf(ah, ah->curchan);
+ if (ret < 0)
+ return ret;
}
if (longcal) {
}
}
- return iscaldone;
+ return !percal_pending;
}
/* Carrier leakage Calibration fix */
/* Do PA Calibration */
ar9002_hw_pa_cal(ah, true);
+ ath9k_hw_loadnf(ah, chan);
+ ath9k_hw_start_nfcal(ah, true);
if (ah->caldata)
set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
return iscaldone;
}
-static bool ar9003_hw_calibrate(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u8 rxchainmask,
- bool longcal)
+static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal)
{
bool iscaldone = true;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
+ int ret;
/*
* For given calibration:
* NF is slow time-variant, so it is OK to use a historical
* value.
*/
- ath9k_hw_loadnf(ah, ah->curchan);
+ ret = ath9k_hw_loadnf(ah, ah->curchan);
+ if (ret < 0)
+ return ret;
/* start NF calibration, without updating BB NF register */
ath9k_hw_start_nfcal(ah, false);
if (AR_SREV_9485_11_OR_LATER(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485Modes_green_ob_db_tx_gain_1_1);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_ub124_tx_gain_table_1p0);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type5_tx_gain_table);
struct ath_hw_radar_conf *conf)
{
unsigned int regWrites = 0;
- u32 radar_0 = 0, radar_1 = 0;
+ u32 radar_0 = 0, radar_1;
if (!conf) {
REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+ radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
+ radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
+ AR_PHY_RADAR_1_RELPWR_THRESH);
radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
conf->fir_power = -28;
conf->radar_rssi = 0;
conf->pulse_height = 10;
- conf->pulse_rssi = 24;
+ conf->pulse_rssi = 15;
conf->pulse_inband = 8;
conf->pulse_maxlen = 255;
conf->pulse_inband_step = 12;
#ifndef AR9003_RTT_H
#define AR9003_RTT_H
+#ifdef CONFIG_ATH9K_PCOEM
void ar9003_hw_rtt_enable(struct ath_hw *ah);
void ar9003_hw_rtt_disable(struct ath_hw *ah);
void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
+#else
+static inline void ar9003_hw_rtt_enable(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_disable(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
+{
+}
+
+static inline bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
+{
+ return false;
+}
+
+static inline void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
+{
+}
+
+static inline bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ return false;
+}
+#endif
#endif
{0x00009d04, 0x40206c10},
{0x00009d08, 0x009c4060},
{0x00009d0c, 0x9883800a},
- {0x00009d10, 0x01834061},
+ {0x00009d10, 0x01884061},
{0x00009d14, 0x00c0040b},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0038230c},
{0x0000a370, 0x00000000},
{0x0000a390, 0x00000001},
{0x0000a394, 0x00000444},
- {0x0000a398, 0x1f020503},
- {0x0000a39c, 0x29180c03},
- {0x0000a3a0, 0x9a8b6844},
+ {0x0000a398, 0x001f0e0f},
+ {0x0000a39c, 0x0075393f},
+ {0x0000a3a0, 0xb79f6427},
{0x0000a3a4, 0x00000000},
{0x0000a3a8, 0xaaaaaaaa},
{0x0000a3ac, 0x3c466478},
#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
-#define ar9580_1p0_radio_core ar9300_2p2_radio_core
+static const u32 ar9580_1p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db2db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x0001604c, 0x76d005b5},
+ {0x00016050, 0x556cf031},
+ {0x00016054, 0x13449440},
+ {0x00016058, 0x0c51c92c},
+ {0x0001605c, 0x3db7fffc},
+ {0x00016060, 0xfffffffc},
+ {0x00016064, 0x000f0278},
+ {0x0001606c, 0x6db60000},
+ {0x00016080, 0x00000000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x54214514},
+ {0x0001608c, 0x119f481e},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd2888888},
+ {0x000160a0, 0x0a108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480080},
+ {0x000160c0, 0x00adb6d0},
+ {0x000160c4, 0x6db6db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x01e6c000},
+ {0x00016100, 0x3fffbe01},
+ {0x00016104, 0xfff80000},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x02084080},
+ {0x00016148, 0x00000000},
+ {0x00016280, 0x058a0001},
+ {0x00016284, 0x3d840208},
+ {0x00016288, 0x05a20408},
+ {0x0001628c, 0x00038c07},
+ {0x00016290, 0x00000004},
+ {0x00016294, 0x458a214f},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db2db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x7f80fff8},
+ {0x0001644c, 0x76d005b5},
+ {0x00016450, 0x556cf031},
+ {0x00016454, 0x13449440},
+ {0x00016458, 0x0c51c92c},
+ {0x0001645c, 0x3db7fffc},
+ {0x00016460, 0xfffffffc},
+ {0x00016464, 0x000f0278},
+ {0x0001646c, 0x6db60000},
+ {0x00016500, 0x3fffbe01},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x02084080},
+ {0x00016548, 0x00000000},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db2db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x7f80fff8},
+ {0x0001684c, 0x76d005b5},
+ {0x00016850, 0x556cf031},
+ {0x00016854, 0x13449440},
+ {0x00016858, 0x0c51c92c},
+ {0x0001685c, 0x3db7fffc},
+ {0x00016860, 0xfffffffc},
+ {0x00016864, 0x000f0278},
+ {0x0001686c, 0x6db60000},
+ {0x00016900, 0x3fffbe01},
+ {0x00016904, 0xfff80000},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x02084080},
+ {0x00016948, 0x00000000},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
u64 tsf_val;
u32 last_beacon;
+ int flush_timeout;
u16 txpower;
bool offchannel;
bool stopped;
ATH_CHANCTX_EVENT_BEACON_SENT,
ATH_CHANCTX_EVENT_TSF_TIMER,
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
- ATH_CHANCTX_EVENT_ASSOC,
+ ATH_CHANCTX_EVENT_AUTHORIZED,
ATH_CHANCTX_EVENT_SWITCH,
ATH_CHANCTX_EVENT_ASSIGN,
ATH_CHANCTX_EVENT_UNASSIGN,
bool wait_switch;
bool force_noa_update;
bool extend_absence;
+ bool mgd_prepare_tx;
enum ath_chanctx_state state;
u8 beacon_miss;
void ath_offchannel_next(struct ath_softc *sc);
void ath_scan_complete(struct ath_softc *sc, bool abort);
void ath_roc_complete(struct ath_softc *sc, bool abort);
+struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc);
#else
#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
-int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
void ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
u16 seq_no;
/* BSS info */
- u8 bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN] __aligned(2);
u16 aid;
bool assoc;
u32 noa_start;
u32 noa_duration;
bool periodic_noa;
+ bool oneshot_noa;
};
struct ath9k_vif_iter_data {
void ath_update_survey_nf(struct ath_softc *sc, int channel);
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
void ath_ps_full_sleep(unsigned long data);
-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
+void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
+ bool sw_pending, bool timeout_override);
/**********/
/* BTCOEX */
struct ath_chanctx_sched sched;
struct ath_offchannel offchannel;
struct ath_chanctx *next_chan;
+ struct completion go_beacon;
#endif
unsigned long driver_data;
int ath_cabq_update(struct ath_softc *);
u8 ath9k_parse_mpdudensity(u8 mpdudensity);
irqreturn_t ath_isr(int irq, void *dev);
-int ath_reset(struct ath_softc *sc);
+int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan);
void ath_cancel_work(struct ath_softc *sc);
void ath_restart_work(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc,
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_nfcal_hist *h = NULL;
unsigned i, j;
ath_dbg(common, ANY,
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));
- return;
+ return -ETIMEDOUT;
}
/*
}
}
REGWRITE_BUFFER_FLUSH(ah);
+
+ return 0;
}
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
+int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan);
}
hchan = &sc->sc_ah->channels[pos];
- r = ath_reset_internal(sc, hchan);
+ r = ath_reset(sc, hchan);
if (r)
return r;
cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
INIT_LIST_HEAD(&ctx->vifs);
ctx->txpower = ATH_TXPOWER_MAX;
+ ctx->flush_timeout = HZ / 5; /* 200ms */
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
INIT_LIST_HEAD(&ctx->acq[j]);
}
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+/*************/
+/* Utilities */
+/*************/
+
+struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc)
+{
+ struct ath_chanctx *ctx;
+ struct ath_vif *avp;
+ struct ieee80211_vif *vif;
+
+ spin_lock_bh(&sc->chan_lock);
+
+ ath_for_each_chanctx(sc, ctx) {
+ if (!ctx->active)
+ continue;
+
+ list_for_each_entry(avp, &ctx->vifs, list) {
+ vif = avp->vif;
+
+ if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO) {
+ spin_unlock_bh(&sc->chan_lock);
+ return ctx;
+ }
+ }
+ }
+
+ spin_unlock_bh(&sc->chan_lock);
+ return NULL;
+}
+
/**********************************************************/
/* Functions to handle the channel context state machine. */
/**********************************************************/
case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
- case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+ case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED);
case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_chanctx *ictx;
struct ath_vif *avp;
bool active = false;
u8 n_active = 0;
if (!ctx)
return;
+ if (ctx == &sc->offchannel.chan) {
+ spin_lock_bh(&sc->chan_lock);
+
+ if (likely(sc->sched.channel_switch_time))
+ ctx->flush_timeout =
+ usecs_to_jiffies(sc->sched.channel_switch_time);
+ else
+ ctx->flush_timeout =
+ msecs_to_jiffies(10);
+
+ spin_unlock_bh(&sc->chan_lock);
+
+ /*
+ * There is no need to iterate over the
+ * active/assigned channel contexts if
+ * the current context is offchannel.
+ */
+ return;
+ }
+
+ ictx = ctx;
+
list_for_each_entry(avp, &ctx->vifs, list) {
struct ieee80211_vif *vif = avp->vif;
n_active++;
}
+ spin_lock_bh(&sc->chan_lock);
+
if (n_active <= 1) {
+ ictx->flush_timeout = HZ / 5;
clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
+ spin_unlock_bh(&sc->chan_lock);
return;
}
- if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+
+ ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time);
+
+ if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
+ spin_unlock_bh(&sc->chan_lock);
return;
+ }
+
+ spin_unlock_bh(&sc->chan_lock);
if (ath9k_is_chanctx_enabled()) {
ath_chanctx_event(sc, NULL,
"Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
}
+static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
+ struct ath_chanctx *ctx,
+ struct ath_vif *avp)
+{
+ /*
+ * Clear the extend_absence flag if it had been
+ * set during the previous beacon transmission,
+ * since we need to revert to the normal NoA
+ * schedule.
+ */
+ if (ctx->active && sc->sched.extend_absence) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = false;
+ }
+
+ /* If at least two consecutive beacons were missed on the STA
+ * chanctx, stay on the STA channel for one extra beacon period,
+ * to resync the timer properly.
+ */
+ if (ctx->active && sc->sched.beacon_miss >= 2) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = true;
+ }
+}
+
+static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
+ struct ath_chanctx *ctx,
+ struct ath_vif *avp,
+ u32 tsf_time)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ avp->noa_index++;
+ avp->offchannel_start = tsf_time;
+ avp->offchannel_duration = sc->sched.offchannel_duration;
+
+ ath_dbg(common, CHAN_CTX,
+ "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+ avp->offchannel_duration,
+ avp->offchannel_start,
+ avp->noa_index);
+
+ /*
+ * When multiple contexts are active, the NoA
+ * has to be recalculated and advertised after
+ * an offchannel operation.
+ */
+ if (ctx->active && avp->noa_duration)
+ avp->noa_duration = 0;
+}
+
+static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
+ struct ath_vif *avp,
+ struct ath_beacon_config *cur_conf,
+ u32 tsf_time,
+ u32 beacon_int)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ avp->noa_index++;
+ avp->noa_start = tsf_time;
+
+ if (sc->sched.extend_absence)
+ avp->noa_duration = (3 * beacon_int / 2) +
+ sc->sched.channel_switch_time;
+ else
+ avp->noa_duration =
+ TU_TO_USEC(cur_conf->beacon_interval) / 2 +
+ sc->sched.channel_switch_time;
+
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
+ sc->sched.extend_absence)
+ avp->periodic_noa = false;
+ else
+ avp->periodic_noa = true;
+
+ ath_dbg(common, CHAN_CTX,
+ "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ avp->noa_duration,
+ avp->noa_start,
+ avp->noa_index,
+ avp->periodic_noa);
+}
+
+static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
+ struct ath_vif *avp,
+ u32 tsf_time,
+ u32 duration)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ avp->noa_index++;
+ avp->noa_start = tsf_time;
+ avp->periodic_noa = false;
+ avp->oneshot_noa = true;
+ avp->noa_duration = duration + sc->sched.channel_switch_time;
+
+ ath_dbg(common, CHAN_CTX,
+ "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ avp->noa_duration,
+ avp->noa_start,
+ avp->noa_index,
+ avp->periodic_noa);
+}
+
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
enum ath_chanctx_event ev)
{
if (avp->offchannel_duration)
avp->offchannel_duration = 0;
+ if (avp->oneshot_noa) {
+ avp->noa_duration = 0;
+ avp->oneshot_noa = false;
+
+ ath_dbg(common, CHAN_CTX,
+ "Clearing oneshot NoA\n");
+ }
+
if (avp->chanctx != sc->cur_chan) {
ath_dbg(common, CHAN_CTX,
"Contexts differ, not preparing beacon\n");
"Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
}
+ if (sc->sched.mgd_prepare_tx)
+ sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+
+ /*
+ * When a context becomes inactive, for example,
+ * disassociation of a station context, the NoA
+ * attribute needs to be removed from subsequent
+ * beacons.
+ */
+ if (!ctx->active && avp->noa_duration &&
+ sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) {
+ avp->noa_duration = 0;
+ avp->periodic_noa = false;
+
+ ath_dbg(common, CHAN_CTX,
+ "Clearing NoA schedule\n");
+ }
+
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
* values and increment the index.
*/
if (sc->next_chan == &sc->offchannel.chan) {
- avp->noa_index++;
- avp->offchannel_start = tsf_time;
- avp->offchannel_duration = sc->sched.offchannel_duration;
-
- ath_dbg(common, CHAN_CTX,
- "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
- avp->offchannel_duration,
- avp->offchannel_start,
- avp->noa_index);
-
- /*
- * When multiple contexts are active, the NoA
- * has to be recalculated and advertised after
- * an offchannel operation.
- */
- if (ctx->active && avp->noa_duration)
- avp->noa_duration = 0;
-
+ ath_chanctx_offchannel_noa(sc, ctx, avp, tsf_time);
break;
}
- /*
- * Clear the extend_absence flag if it had been
- * set during the previous beacon transmission,
- * since we need to revert to the normal NoA
- * schedule.
- */
- if (ctx->active && sc->sched.extend_absence) {
- avp->noa_duration = 0;
- sc->sched.extend_absence = false;
- }
+ ath_chanctx_handle_bmiss(sc, ctx, avp);
- /* If at least two consecutive beacons were missed on the STA
- * chanctx, stay on the STA channel for one extra beacon period,
- * to resync the timer properly.
+ /*
+ * If a mgd_prepare_tx() has been called by mac80211,
+ * a one-shot NoA needs to be sent. This can happen
+ * with one or more active channel contexts - in both
+ * cases, a new NoA schedule has to be advertised.
*/
- if (ctx->active && sc->sched.beacon_miss >= 2) {
- avp->noa_duration = 0;
- sc->sched.extend_absence = true;
+ if (sc->sched.mgd_prepare_tx) {
+ ath_chanctx_set_oneshot_noa(sc, avp, tsf_time,
+ jiffies_to_usecs(HZ / 5));
+ break;
}
/* Prevent wrap-around issues */
* announcement.
*/
if (ctx->active &&
- (!avp->noa_duration || sc->sched.force_noa_update)) {
- avp->noa_index++;
- avp->noa_start = tsf_time;
-
- if (sc->sched.extend_absence)
- avp->noa_duration = (3 * beacon_int / 2) +
- sc->sched.channel_switch_time;
- else
- avp->noa_duration =
- TU_TO_USEC(cur_conf->beacon_interval) / 2 +
- sc->sched.channel_switch_time;
-
- if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
- sc->sched.extend_absence)
- avp->periodic_noa = false;
- else
- avp->periodic_noa = true;
-
- ath_dbg(common, CHAN_CTX,
- "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
- avp->noa_duration,
- avp->noa_start,
- avp->noa_index,
- avp->periodic_noa);
- }
+ (!avp->noa_duration || sc->sched.force_noa_update))
+ ath_chanctx_set_periodic_noa(sc, avp, cur_conf,
+ tsf_time, beacon_int);
if (ctx->active && sc->sched.force_noa_update)
sc->sched.force_noa_update = false;
}
sc->sched.beacon_pending = false;
+
+ if (sc->sched.mgd_prepare_tx) {
+ sc->sched.mgd_prepare_tx = false;
+ complete(&sc->go_beacon);
+ ath_dbg(common, CHAN_CTX,
+ "Beacon sent, complete go_beacon\n");
+ break;
+ }
+
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
sc->cur_chan == &sc->offchannel.chan)
break;
- ath_chanctx_adjust_tbtt_delta(sc);
sc->sched.beacon_pending = false;
sc->sched.beacon_miss = 0;
+ if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
+ !sc->cur_chan->tsf_val)
+ break;
+
+ ath_chanctx_adjust_tbtt_delta(sc);
+
/* TSF time might have been updated by the incoming beacon,
* need update the channel switch timer to reflect the change.
*/
ath_chanctx_setup_timer(sc, tsf_time);
break;
- case ATH_CHANCTX_EVENT_ASSOC:
+ case ATH_CHANCTX_EVENT_AUTHORIZED:
if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
avp->chanctx != sc->cur_chan)
break;
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
case ATH_CHANCTX_EVENT_ASSIGN:
- /*
- * When adding a new channel context, check if a scan
- * is in progress and abort it since the addition of
- * a new channel context is usually followed by VIF
- * assignment, in which case we have to start multi-channel
- * operation.
- */
- if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
- ath_dbg(common, CHAN_CTX,
- "Aborting HW scan to add new context\n");
-
- spin_unlock_bh(&sc->chan_lock);
- del_timer_sync(&sc->offchannel.timer);
- ath_scan_complete(sc, true);
- spin_lock_bh(&sc->chan_lock);
- }
break;
case ATH_CHANCTX_EVENT_CHANGE:
break;
sc->offchannel.roc_vif = NULL;
sc->offchannel.roc_chan = NULL;
- if (!abort)
+ if (abort)
ieee80211_remain_on_channel_expired(sc->hw);
ath_offchannel_next(sc);
ath9k_ps_restore(sc);
case ATH_OFFCHANNEL_ROC_WAIT:
ctx = ath_chanctx_get_oper_chan(sc, false);
sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+ ieee80211_remain_on_channel_expired(sc->hw);
ath_chanctx_switch(sc, ctx, NULL);
break;
default:
ath9k_chanctx_stop_queues(sc, sc->cur_chan);
queues_stopped = true;
- __ath9k_flush(sc->hw, ~0, true);
+ __ath9k_flush(sc->hw, ~0, true, false, false);
if (ath_chanctx_send_ps_frame(sc, true))
- __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+ __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO),
+ false, false, false);
send_ps = true;
spin_lock_bh(&sc->chan_lock);
(unsigned long)sc);
setup_timer(&sc->sched.timer, ath_chanctx_timer,
(unsigned long)sc);
+
+ init_completion(&sc->go_beacon);
}
void ath9k_deinit_channel_context(struct ath_softc *sc)
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ static const char * const reset_cause[__RESET_TYPE_MAX] = {
+ [RESET_TYPE_BB_HANG] = "Baseband Hang",
+ [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
+ [RESET_TYPE_FATAL_INT] = "Fatal HW Error",
+ [RESET_TYPE_TX_ERROR] = "TX HW error",
+ [RESET_TYPE_TX_GTT] = "Transmit timeout",
+ [RESET_TYPE_TX_HANG] = "TX Path Hang",
+ [RESET_TYPE_PLL_HANG] = "PLL RX Hang",
+ [RESET_TYPE_MAC_HANG] = "MAC Hang",
+ [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
+ [RESET_TYPE_MCI] = "MCI Reset",
+ [RESET_TYPE_CALIBRATION] = "Calibration error",
+ };
char buf[512];
unsigned int len = 0;
+ int i;
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "Baseband Hang",
- sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "Baseband Watchdog",
- sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "Fatal HW Error",
- sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "TX HW error",
- sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "TX Path Hang",
- sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "PLL RX Hang",
- sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "MAC Hang",
- sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "Stuck Beacon",
- sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%17s: %2d\n", "MCI Reset",
- sc->debug.stats.reset[RESET_TYPE_MCI]);
+ for (i = 0; i < ARRAY_SIZE(reset_cause); i++) {
+ if (!reset_cause[i])
+ continue;
+
+ len += scnprintf(buf + len, sizeof(buf) - len,
+ "%17s: %2d\n", reset_cause[i],
+ sc->debug.stats.reset[i]);
+ }
if (len > sizeof(buf))
len = sizeof(buf);
RESET_TYPE_MAC_HANG,
RESET_TYPE_BEACON_STUCK,
RESET_TYPE_MCI,
+ RESET_TYPE_CALIBRATION,
__RESET_TYPE_MAX
};
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct ath_common *common = ath9k_hw_common(ah);
- u16 *eepdata, temp, magic, magic2;
+ u16 *eepdata, temp, magic;
u32 sum = 0, el;
bool need_swap = false;
int i, addr, size;
return false;
}
- if (!ath9k_hw_use_flash(ah)) {
- ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- size = sizeof(struct ar5416_eeprom_def);
- need_swap = true;
- eepdata = (u16 *) (&ah->eeprom);
+ if (swab16(magic) == AR5416_EEPROM_MAGIC &&
+ !(ah->ah_flags & AH_NO_EEP_SWAP)) {
+ size = sizeof(struct ar5416_eeprom_def);
+ need_swap = true;
+ eepdata = (u16 *) (&ah->eeprom);
- for (addr = 0; addr < size / sizeof(u16); addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- } else {
- ath_err(common,
- "Invalid EEPROM Magic. Endianness mismatch.\n");
- return -EINVAL;
- }
+ for (addr = 0; addr < size / sizeof(u16); addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
}
}
ath9k_hw_ops(ah)->set_desc_link(ds, link);
}
-static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u8 rxchainmask,
- bool longcal)
+static inline int ath9k_hw_calibrate(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal)
{
return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
}
#include <linux/module.h>
#include <linux/time.h>
#include <linux/bitops.h>
+#include <linux/etherdevice.h>
#include <asm/unaligned.h>
#include "hw.h"
common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff;
}
- if (sum == 0 || sum == 0xffff * 3)
- return -EADDRNOTAVAIL;
+ if (!is_valid_ether_addr(common->macaddr)) {
+ ath_err(common,
+ "eeprom contains invalid mac address: %pM\n",
+ common->macaddr);
+
+ random_ether_addr(common->macaddr);
+ ath_err(common,
+ "random mac address will be used: %pM\n",
+ common->macaddr);
+ }
return 0;
}
if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_check_bt(ah);
- ath9k_hw_loadnf(ah, chan);
- ath9k_hw_start_nfcal(ah, true);
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ath9k_hw_loadnf(ah, chan);
+ ath9k_hw_start_nfcal(ah, true);
+ }
if (AR_SREV_9300_20_OR_LATER(ah))
ar9003_hw_bb_watchdog_config(ah);
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
- if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
- ath_err(common,
- "no band has been marked as supported in EEPROM\n");
- return -EINVAL;
+
+ if (eeval & AR5416_OPFLAGS_11A) {
+ if (ah->disable_5ghz)
+ ath_warn(common, "disabling 5GHz band\n");
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
}
- if (eeval & AR5416_OPFLAGS_11A)
- pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
+ if (eeval & AR5416_OPFLAGS_11G) {
+ if (ah->disable_2ghz)
+ ath_warn(common, "disabling 2GHz band\n");
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
+ }
- if (eeval & AR5416_OPFLAGS_11G)
- pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
+ if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
+ ath_err(common, "both bands are disabled\n");
+ return -EINVAL;
+ }
if (AR_SREV_9485(ah) ||
AR_SREV_9285(ah) ||
ATH9K_HW_CAP_2GHZ = BIT(11),
ATH9K_HW_CAP_5GHZ = BIT(12),
ATH9K_HW_CAP_APM = BIT(13),
+#ifdef CONFIG_ATH9K_PCOEM
ATH9K_HW_CAP_RTT = BIT(14),
ATH9K_HW_CAP_MCI = BIT(15),
- ATH9K_HW_CAP_DFS = BIT(16),
- ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17),
- ATH9K_HW_CAP_PAPRD = BIT(18),
- ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19),
- ATH9K_HW_CAP_BT_ANT_DIV = BIT(20),
+ ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16),
+ ATH9K_HW_CAP_BT_ANT_DIV = BIT(17),
+#else
+ ATH9K_HW_CAP_RTT = 0,
+ ATH9K_HW_CAP_MCI = 0,
+ ATH9K_HW_WOW_DEVICE_CAPABLE = 0,
+ ATH9K_HW_CAP_BT_ANT_DIV = 0,
+#endif
+ ATH9K_HW_CAP_DFS = BIT(18),
+ ATH9K_HW_CAP_PAPRD = BIT(19),
+ ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(20),
};
/*
bool power_off);
void (*rx_enable)(struct ath_hw *ah);
void (*set_desc_link)(void *ds, u32 link);
- bool (*calibrate)(struct ath_hw *ah,
- struct ath9k_channel *chan,
- u8 rxchainmask,
- bool longcal);
+ int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
u32 *sync_cause_p);
void (*set_txdesc)(struct ath_hw *ah, void *ds,
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
#define AH_FASTCC 0x4
+#define AH_NO_EEP_SWAP 0x8 /* Do not swap EEPROM data */
struct ath_hw {
struct ath_ops reg_ops;
bool is_clk_25mhz;
int (*get_mac_revision)(void);
int (*external_reset)(void);
+ bool disable_2ghz;
+ bool disable_5ghz;
const struct firmware *eeprom_blob;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
+ if (!IS_ENABLED(CONFIG_ATH9K_PCOEM))
+ return;
+
if (common->bus_ops->ath_bus_type != ATH_PCI)
return;
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
ah->external_reset = pdata->external_reset;
+ ah->disable_2ghz = pdata->disable_2ghz;
+ ah->disable_5ghz = pdata->disable_5ghz;
+ if (!pdata->endian_check)
+ ah->ah_flags |= AH_NO_EEP_SWAP;
}
common->ops = &ah->reg_ops;
/* Perform calibration if necessary */
if (longcal || shortcal) {
- common->ani.caldone =
- ath9k_hw_calibrate(ah, ah->curchan,
- ah->rxchainmask, longcal);
+ int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
+ longcal);
+ if (ret < 0) {
+ common->ani.caldone = 0;
+ ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
+ return;
+ }
+
+ common->ani.caldone = ret;
}
ath_dbg(common, ANI,
}
}
-static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
+static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq,
+ bool sw_pending)
{
bool pending = false;
goto out;
}
+ if (!sw_pending)
+ goto out;
+
if (txq->mac80211_qnum >= 0) {
struct list_head *list;
return true;
}
-int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
__ath_cancel_work(sc);
tasklet_disable(&sc->intr_tq);
+ tasklet_disable(&sc->bcon_tasklet);
spin_lock_bh(&sc->sc_pcu_lock);
if (!sc->cur_chan->offchannel) {
out:
spin_unlock_bh(&sc->sc_pcu_lock);
+ tasklet_enable(&sc->bcon_tasklet);
tasklet_enable(&sc->intr_tq);
return r;
sched = true;
/*
- * If a FATAL or RXORN interrupt is received, we have to reset the
- * chip immediately.
+ * If a FATAL interrupt is received, we have to reset the chip
+ * immediately.
*/
- if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
- !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
+ if (status & ATH9K_INT_FATAL)
goto chip_reset;
if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
#undef SCHED_INTR
}
-int ath_reset(struct ath_softc *sc)
+/*
+ * This function is called when a HW reset cannot be deferred
+ * and has to be immediate.
+ */
+int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int r;
+ set_bit(ATH_OP_HW_RESET, &common->op_flags);
+
ath9k_ps_wakeup(sc);
- r = ath_reset_internal(sc, NULL);
+ r = ath_reset_internal(sc, hchan);
ath9k_ps_restore(sc);
return r;
}
+/*
+ * When a HW reset can be deferred, it is added to the
+ * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
+ * queueing.
+ */
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
{
struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
- ath_reset(sc);
+ ath9k_ps_wakeup(sc);
+ ath_reset_internal(sc, NULL);
+ ath9k_ps_restore(sc);
}
/**********************/
eth_zero_addr(common->curbssid);
eth_broadcast_addr(common->bssidmask);
- ether_addr_copy(common->macaddr, vif->addr);
+ memcpy(common->macaddr, vif->addr, ETH_ALEN);
common->curaid = 0;
ah->opmode = vif->type;
ah->imask &= ~ATH9K_INT_SWBA;
ath9k_calculate_iter_data(sc, ctx, &iter_data);
if (iter_data.has_hw_macaddr)
- ether_addr_copy(common->macaddr, iter_data.hw_macaddr);
+ memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
return 0;
}
+static int ath9k_sta_state(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int ret = 0;
+
+ if (old_state == IEEE80211_STA_AUTH &&
+ new_state == IEEE80211_STA_ASSOC) {
+ ret = ath9k_sta_add(hw, vif, sta);
+ ath_dbg(common, CONFIG,
+ "Add station: %pM\n", sta->addr);
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTH) {
+ ret = ath9k_sta_remove(hw, vif, sta);
+ ath_dbg(common, CONFIG,
+ "Remove station: %pM\n", sta->addr);
+ }
+
+ if (ath9k_is_chanctx_enabled()) {
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTHORIZED)
+ ath_chanctx_event(sc, vif,
+ ATH_CHANCTX_EVENT_AUTHORIZED);
+ }
+ }
+
+ return ret;
+}
+
static void ath9k_sta_set_tx_filter(struct ath_hw *ah,
struct ath_node *an,
bool set)
ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
bss_conf->bssid, bss_conf->assoc);
- ether_addr_copy(avp->bssid, bss_conf->bssid);
+ memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
avp->aid = bss_conf->aid;
avp->assoc = bss_conf->assoc;
ath9k_calculate_summary_state(sc, avp->chanctx);
-
- if (ath9k_is_chanctx_enabled()) {
- if (bss_conf->assoc)
- ath_chanctx_event(sc, vif,
- ATH_CHANCTX_EVENT_ASSOC);
- }
}
if (changed & BSS_CHANGED_IBSS) {
u16 tid, u16 *ssn, u8 buf_size)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
bool flush = false;
int ret = 0;
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
+ if (ath9k_is_chanctx_enabled()) {
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+ ret = -EBUSY;
+ break;
+ }
+ }
ath9k_ps_wakeup(sc);
ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (!ret)
mutex_unlock(&sc->mutex);
}
-static bool ath9k_has_tx_pending(struct ath_softc *sc)
+static bool ath9k_has_tx_pending(struct ath_softc *sc,
+ bool sw_pending)
{
int i, npend = 0;
if (!ATH_TXQ_SETUP(sc, i))
continue;
- npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+ npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i],
+ sw_pending);
if (npend)
break;
}
u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ if (ath9k_is_chanctx_enabled()) {
+ if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ goto flush;
+
+ /*
+ * If MCC is active, extend the flush timeout
+ * and wait for the HW/SW queues to become
+ * empty. This needs to be done outside the
+ * sc->mutex lock to allow the channel scheduler
+ * to switch channel contexts.
+ *
+ * The vif queues have been stopped in mac80211,
+ * so there won't be any incoming frames.
+ */
+ __ath9k_flush(hw, queues, drop, true, true);
+ return;
+ }
+flush:
mutex_lock(&sc->mutex);
- __ath9k_flush(hw, queues, drop);
+ __ath9k_flush(hw, queues, drop, true, false);
mutex_unlock(&sc->mutex);
}
-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
+ bool sw_pending, bool timeout_override)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- int timeout = HZ / 5; /* 200 ms */
+ int timeout;
bool drain_txq;
cancel_delayed_work_sync(&sc->tx_complete_work);
return;
}
- if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
+ spin_lock_bh(&sc->chan_lock);
+ if (timeout_override)
+ timeout = HZ / 5;
+ else
+ timeout = sc->cur_chan->flush_timeout;
+ spin_unlock_bh(&sc->chan_lock);
+
+ ath_dbg(common, CHAN_CTX,
+ "Flush timeout: %d\n", jiffies_to_msecs(timeout));
+
+ if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending),
timeout) > 0)
drop = false;
spin_unlock_bh(&sc->sc_pcu_lock);
if (!drain_txq)
- ath_reset(sc);
+ ath_reset(sc, NULL);
ath9k_ps_restore(sc);
}
{
struct ath_softc *sc = hw->priv;
- return ath9k_has_tx_pending(sc);
+ return ath9k_has_tx_pending(sc, true);
}
static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
conf->def.chan->center_freq);
ath_chanctx_set_channel(sc, ctx, &conf->def);
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
mutex_unlock(&sc->mutex);
return 0;
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+ struct ath_beacon_config *cur_conf;
+ struct ath_chanctx *go_ctx;
+ unsigned long timeout;
bool changed = false;
+ u32 beacon_int;
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
return;
mutex_lock(&sc->mutex);
spin_lock_bh(&sc->chan_lock);
- if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
- sc->next_chan = avp->chanctx;
+ if (sc->next_chan || (sc->cur_chan != avp->chanctx))
changed = true;
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (!changed)
+ goto out;
+
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+ ath_dbg(common, CHAN_CTX,
+ "%s: Aborting HW scan\n", __func__);
+
+ mutex_unlock(&sc->mutex);
+
+ del_timer_sync(&sc->offchannel.timer);
+ ath_scan_complete(sc, true);
+ flush_work(&sc->chanctx_work);
+
+ mutex_lock(&sc->mutex);
+ }
+
+ go_ctx = ath_is_go_chanctx_present(sc);
+
+ if (go_ctx) {
+ /*
+ * Wait till the GO interface gets a chance
+ * to send out an NoA.
+ */
+ spin_lock_bh(&sc->chan_lock);
+ sc->sched.mgd_prepare_tx = true;
+ cur_conf = &go_ctx->beacon;
+ beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
+ spin_unlock_bh(&sc->chan_lock);
+
+ timeout = usecs_to_jiffies(beacon_int);
+ init_completion(&sc->go_beacon);
+
+ if (wait_for_completion_timeout(&sc->go_beacon,
+ timeout) == 0)
+ ath_dbg(common, CHAN_CTX,
+ "Failed to send new NoA\n");
}
+
ath_dbg(common, CHAN_CTX,
- "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
- __func__, changed);
+ "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
+ __func__, vif->addr);
+
+ spin_lock_bh(&sc->chan_lock);
+ sc->next_chan = avp->chanctx;
sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
spin_unlock_bh(&sc->chan_lock);
- if (changed)
- ath_chanctx_set_next(sc, true);
-
+ ath_chanctx_set_next(sc, true);
+out:
mutex_unlock(&sc->mutex);
}
.remove_interface = ath9k_remove_interface,
.config = ath9k_config,
.configure_filter = ath9k_configure_filter,
- .sta_add = ath9k_sta_add,
- .sta_remove = ath9k_sta_remove,
+ .sta_state = ath9k_sta_state,
.sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+#ifdef CONFIG_ATH9K_PCOEM
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x002A,
PCI_VENDOR_ID_AZWAVE,
PCI_VENDOR_ID_AZWAVE,
0x2C37),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
+#endif
{ PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
+#ifdef CONFIG_ATH9K_PCOEM
/* PCI-E CUS198 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0032,
PCI_VENDOR_ID_ASUSTEK,
0x850D),
.driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+#endif
{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */
{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */
+#ifdef CONFIG_ATH9K_PCOEM
/* PCI-E CUS217 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0034,
/* PCI-E AR9565 (WB335) */
{ PCI_VDEVICE(ATHEROS, 0x0036),
.driver_data = ATH9K_PCI_BT_ANT_DIV },
+#endif
{ 0 }
};
(AR_SREV_9330((_ah)) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_12))
+#ifdef CONFIG_ATH9K_PCOEM
+#define AR_SREV_9462(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
+#define AR_SREV_9565(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
+#else
+#define AR_SREV_9462(_ah) 0
+#define AR_SREV_9485(_ah) 0
+#define AR_SREV_9565(_ah) 0
+#endif
+
#define AR_SREV_9485_11_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \
+ (AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11))
#define AR_SREV_9485_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
(AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
-#define AR_SREV_9462(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
#define AR_SREV_9462_20(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+ (AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
#define AR_SREV_9462_21(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+ (AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_21))
#define AR_SREV_9462_20_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+ (AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20))
#define AR_SREV_9462_21_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+ (AR_SREV_9462(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_21))
-#define AR_SREV_9565(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
#define AR_SREV_9565_10(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+ (AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10))
#define AR_SREV_9565_101(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+ (AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101))
#define AR_SREV_9565_11(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+ (AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11))
#define AR_SREV_9565_11_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+ (AR_SREV_9565(_ah) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))
#define AR_SREV_9550(_ah) \
static void ath9k_tx99_deinit(struct ath_softc *sc)
{
- ath_reset(sc);
+ ath_reset(sc, NULL);
ath9k_ps_wakeup(sc);
ath9k_tx99_stop(sc);
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- ath_reset(sc);
+ ath_reset(sc, NULL);
ath9k_ps_wakeup(sc);
refsel0 = 0;
refsel1 = 1;
}
- chansel = byte_rev_table[chansel];
+ chansel = bitrev8(chansel);
} else {
if (freq == 2484) {
chansel = 10 + (freq - 2274) / 5;
} else
chansel = 16 + (freq - 2272) / 5;
chansel *= 4;
- chansel = byte_rev_table[chansel];
+ chansel = bitrev8(chansel);
}
d1 = chansel;
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
- struct net_device *dev, const u8 *mac)
+ struct net_device *dev,
+ struct station_del_parameters *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, mac);
+ wil6210_disconnect(wil, params->mac, false);
mutex_unlock(&wil->mutex);
return 0;
module_param(itr_trsh, uint, S_IRUGO);
MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
+/* We allow allocation of more than 1 page buffers to support large packets.
+ * It is suboptimal behavior performance wise in case MTU above page size.
+ */
+unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
+static int mtu_max_set(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+
+ /* sets mtu_max directly. no need to restore it in case of
+ * illegal value since we assume this will fail insmod
+ */
+ ret = param_set_uint(val, kp);
+ if (ret)
+ return ret;
+
+ if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static struct kernel_param_ops mtu_max_ops = {
+ .set = mtu_max_set,
+ .get = param_get_uint,
+};
+
+module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
+MODULE_PARM_DESC(mtu_max, " Max MTU value.");
+
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
__raw_writel(*s++, d++);
}
-static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
+static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
+ bool from_event)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
sta->data_port_open = false;
if (sta->status != wil_sta_unused) {
- wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
+ if (!from_event)
+ wmi_disconnect_sta(wil, sta->addr,
+ WLAN_REASON_DEAUTH_LEAVING);
+
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
memset(&sta->stats, 0, sizeof(sta->stats));
}
-static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+ bool from_event)
{
int cid = -ENOENT;
struct net_device *ndev = wil_to_ndev(wil);
}
if (cid >= 0) /* disconnect 1 peer */
- wil_disconnect_cid(wil, cid);
+ wil_disconnect_cid(wil, cid, from_event);
else /* disconnect all */
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
- wil_disconnect_cid(wil, cid);
+ wil_disconnect_cid(wil, cid, from_event);
/* link state */
switch (wdev->iftype) {
struct wil6210_priv, disconnect_worker);
mutex_lock(&wil->mutex);
- _wil6210_disconnect(wil, NULL);
+ _wil6210_disconnect(wil, NULL, false);
mutex_unlock(&wil->mutex);
}
wil_dbg_misc(wil, "fw error worker\n");
+ if (!netif_running(wil_to_ndev(wil))) {
+ wil_info(wil, "No recovery - interface is down\n");
+ return;
+ }
+
/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
* passed since last recovery attempt
*/
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
+ wil_info(wil, "No recovery for AP-like interface\n");
/* recovery in these modes is done by upper layers */
break;
default:
+ wil_err(wil, "No recovery - unknown interface type %d\n",
+ wdev->iftype);
break;
}
mutex_unlock(&wil->mutex);
return 0;
}
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+/**
+ * wil6210_disconnect - disconnect one connection
+ * @wil: driver context
+ * @bssid: peer to disconnect, NULL to disconnect all
+ * @from_event: whether is invoked from FW event handler
+ *
+ * Disconnect and release associated resources. If invoked not from the
+ * FW event handler, issue WMI command(s) to trigger MAC disconnect.
+ */
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+ bool from_event)
{
wil_dbg_misc(wil, "%s()\n", __func__);
del_timer_sync(&wil->connect_timer);
- _wil6210_disconnect(wil, bssid);
+ _wil6210_disconnect(wil, bssid, from_event);
}
void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, NULL);
+ wil6210_disconnect(wil, NULL, false);
mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn);
static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
- u32 hw_state;
+ u32 x;
u32 rev_id;
bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
wil_halt_cpu(wil);
- C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
if (is_sparrow) {
+ S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
+ /* XTAL stabilization should take about 3ms */
+ usleep_range(5000, 7000);
+ x = R(RGF_CAF_PLL_LOCK_STATUS);
+ if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {
+ wil_err(wil, "Xtal stabilization timeout\n"
+ "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);
+ return -ETIME;
+ }
+ /* switch 10k to XTAL*/
+ C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);
+ /* 40 MHz */
+ C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL);
+
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
}
/* wait until device ready. typical time is 200..250 msec */
do {
msleep(RST_DELAY);
- hw_state = R(RGF_USER_HW_MACHINE_STATE);
+ x = R(RGF_USER_HW_MACHINE_STATE);
if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
- hw_state);
+ x);
return -ETIME;
}
- } while (hw_state != HW_MACHINE_BOOT_DONE);
+ } while (x != HW_MACHINE_BOOT_DONE);
/* TODO: Erez check rev_id != 1 */
if (!is_sparrow && (rev_id != 1))
WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
- wil6210_disconnect(wil, NULL);
+ wil6210_disconnect(wil, NULL, false);
wil->status = 0; /* prevent NAPI from being scheduled */
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
+ if (new_mtu < 68 || new_mtu > mtu_max) {
wil_err(wil, "invalid MTU %d\n", new_mtu);
return -EINVAL;
}
u32 i, int headroom)
{
struct device *dev = wil_to_dev(wil);
- unsigned int sz = RX_BUF_LEN;
+ unsigned int sz = mtu_max + ETH_HLEN;
struct vring_rx_desc dd, *d = ⅆ
volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
struct vring_rx_desc *d;
struct sk_buff *skb;
dma_addr_t pa;
- unsigned int sz = RX_BUF_LEN;
+ unsigned int sz = mtu_max + ETH_HLEN;
u16 dmalen;
u8 ftype;
u8 ds_bits;
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
.vring_cfg = {
.tx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
+ .max_mpdu_size =
+ cpu_to_le16(mtu_max + ETH_HLEN),
.ring_size = cpu_to_le16(size),
},
.ringid = id,
#define BUF_HW_OWNED (0)
/* size of max. Tx/Rx buffers, as supported by FW */
-#define RX_BUF_LEN (2242)
-#define TX_BUF_LEN (2242)
+#define TXRX_BUF_LEN_DEFAULT (2242)
+
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
#include "wil_platform.h"
extern bool no_fw_recovery;
+extern unsigned int mtu_max;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
+#define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */
+ #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
+#define RGF_CAF_OSC_CONTROL (0x88afa4)
+ #define BIT_CAF_OSC_XTAL_EN BIT(0)
+#define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
+ #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_to_pcie_dev(i) (&i->pdev->dev)
+__printf(2, 3)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+__printf(2, 3)
void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
+__printf(2, 3)
void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+ bool from_event);
int wil_rx_init(struct wil6210_priv *wil);
void wil_rx_fini(struct wil6210_priv *wil);
wil->sinfo_gen++;
mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, evt->bssid);
+ wil6210_disconnect(wil, evt->bssid, true);
mutex_unlock(&wil->mutex);
}
struct wmi_cfg_rx_chain_cmd cmd = {
.action = WMI_RX_CHAIN_ADD,
.rx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+ .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
.ring_mem_base = cpu_to_le64(vring->pa),
.ring_size = cpu_to_le16(vring->size),
},
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += \
- wl_cfg80211.o \
+ cfg80211.o \
chip.o \
fwil.o \
fweh.o \
fwsignal.o \
p2p.o \
proto.o \
- dhd_common.o \
- dhd_linux.o \
+ common.o \
+ core.o \
firmware.o \
feature.o \
btcoex.o \
flowring.o \
msgbuf.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
- dhd_sdio.o \
+ sdio.o \
bcmsdh.o
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o
brcmfmac-$(CONFIG_BRCMFMAC_PCIE) += \
pcie.o
brcmfmac-$(CONFIG_BRCMDBG) += \
- dhd_dbg.o
+ debug.o
brcmfmac-$(CONFIG_BRCM_TRACING) += \
tracepoint.o
brcmfmac-$(CONFIG_OF) += \
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "bus.h"
#include "fwsignal.h"
-#include "dhd_dbg.h"
+#include "debug.h"
#include "tracepoint.h"
#include "proto.h"
#include "bcdc.h"
#include <chipcommon.h>
#include <soc.h>
#include "chip.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "sdio_host.h"
+#include "bus.h"
+#include "debug.h"
+#include "sdio.h"
#include "of.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
if (!sdiodev->pdata)
brcmf_of_probe(sdiodev);
+#ifdef CONFIG_PM_SLEEP
+ /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
+ * is true or when platform data OOB irq is true).
+ */
+ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
+ ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
+ (sdiodev->pdata->oob_irq_supported)))
+ bus_if->wowl_supported = true;
+#endif
+
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
brcmf_dbg(SDIO, "Exit\n");
}
+void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+
+ brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
+ sdiodev->wowl_enabled = enabled;
+}
+
#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
- mmc_pm_flag_t sdio_flags;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- int ret = 0;
+ mmc_pm_flag_t sdio_flags;
brcmf_dbg(SDIO, "Enter\n");
- sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
- if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
- brcmf_err("Host can't keep power while suspended\n");
- return -EINVAL;
- }
-
atomic_set(&sdiodev->suspend, true);
- ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
- if (ret) {
- brcmf_err("Failed to set pm_flags\n");
- atomic_set(&sdiodev->suspend, false);
- return ret;
+ if (sdiodev->wowl_enabled) {
+ sdio_flags = MMC_PM_KEEP_POWER;
+ if (sdiodev->pdata->oob_irq_supported)
+ enable_irq_wake(sdiodev->pdata->oob_irq_nr);
+ else
+ sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
+ if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
}
brcmf_sdio_wd_timer(sdiodev->bus, 0);
- return ret;
+ return 0;
}
static int brcmf_ops_sdio_resume(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
brcmf_dbg(SDIO, "Enter\n");
+ if (sdiodev->pdata->oob_irq_supported)
+ disable_irq_wake(sdiodev->pdata->oob_irq_nr);
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
atomic_set(&sdiodev->suspend, false);
return 0;
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include <defs.h>
-#include <dhd.h>
-#include <dhd_dbg.h>
+#include "core.h"
+#include "debug.h"
#include "fwil.h"
#include "fwil_types.h"
#include "btcoex.h"
#include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
/* T1 start SCO/eSCO priority suppression */
#define BRCMF_BTCOEX_OPPR_WIN_TIME 2000
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BRCMFMAC_BUS_H
+#define BRCMFMAC_BUS_H
+
+#include "debug.h"
+
+/* IDs of the 6 default common rings of msgbuf protocol */
+#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0
+#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1
+#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2
+#define BRCMF_D2H_MSGRING_TX_COMPLETE 3
+#define BRCMF_D2H_MSGRING_RX_COMPLETE 4
+
+#define BRCMF_NROF_H2D_COMMON_MSGRINGS 2
+#define BRCMF_NROF_D2H_COMMON_MSGRINGS 3
+#define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \
+ BRCMF_NROF_D2H_COMMON_MSGRINGS)
+
+/* The level of bus communication with the dongle */
+enum brcmf_bus_state {
+ BRCMF_BUS_UNKNOWN, /* Not determined yet */
+ BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */
+ BRCMF_BUS_DOWN, /* Not ready for frame transfers */
+ BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
+ BRCMF_BUS_DATA /* Ready for frame transfers */
+};
+
+/* The level of bus communication with the dongle */
+enum brcmf_bus_protocol_type {
+ BRCMF_PROTO_BCDC,
+ BRCMF_PROTO_MSGBUF
+};
+
+struct brcmf_bus_dcmd {
+ char *name;
+ char *param;
+ int param_len;
+ struct list_head list;
+};
+
+/**
+ * struct brcmf_bus_ops - bus callback operations.
+ *
+ * @preinit: execute bus/device specific dongle init commands (optional).
+ * @init: prepare for communication with dongle.
+ * @stop: clear pending frames, disable data flow.
+ * @txdata: send a data frame to the dongle. When the data
+ * has been transferred, the common driver must be
+ * notified using brcmf_txcomplete(). The common
+ * driver calls this function with interrupts
+ * disabled.
+ * @txctl: transmit a control request message to dongle.
+ * @rxctl: receive a control response message from dongle.
+ * @gettxq: obtain a reference of bus transmit queue (optional).
+ * @wowl_config: specify if dongle is configured for wowl when going to suspend
+ *
+ * This structure provides an abstract interface towards the
+ * bus specific driver. For control messages to common driver
+ * will assure there is only one active transaction. Unless
+ * indicated otherwise these callbacks are mandatory.
+ */
+struct brcmf_bus_ops {
+ int (*preinit)(struct device *dev);
+ void (*stop)(struct device *dev);
+ int (*txdata)(struct device *dev, struct sk_buff *skb);
+ int (*txctl)(struct device *dev, unsigned char *msg, uint len);
+ int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
+ struct pktq * (*gettxq)(struct device *dev);
+ void (*wowl_config)(struct device *dev, bool enabled);
+};
+
+
+/**
+ * struct brcmf_bus_msgbuf - bus ringbuf if in case of msgbuf.
+ *
+ * @commonrings: commonrings which are always there.
+ * @flowrings: commonrings which are dynamically created and destroyed for data.
+ * @rx_dataoffset: if set then all rx data has this this offset.
+ * @max_rxbufpost: maximum number of buffers to post for rx.
+ * @nrof_flowrings: number of flowrings.
+ */
+struct brcmf_bus_msgbuf {
+ struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS];
+ struct brcmf_commonring **flowrings;
+ u32 rx_dataoffset;
+ u32 max_rxbufpost;
+ u32 nrof_flowrings;
+};
+
+
+/**
+ * struct brcmf_bus - interface structure between common and bus layer
+ *
+ * @bus_priv: pointer to private bus device.
+ * @proto_type: protocol type, bcdc or msgbuf
+ * @dev: device pointer of bus device.
+ * @drvr: public driver information.
+ * @state: operational state of the bus interface.
+ * @maxctl: maximum size for rxctl request message.
+ * @tx_realloc: number of tx packets realloced for headroom.
+ * @dstats: dongle-based statistical data.
+ * @dcmd_list: bus/device specific dongle initialization commands.
+ * @chip: device identifier of the dongle chip.
+ * @wowl_supported: is wowl supported by bus driver.
+ * @chiprev: revision of the dongle chip.
+ */
+struct brcmf_bus {
+ union {
+ struct brcmf_sdio_dev *sdio;
+ struct brcmf_usbdev *usb;
+ struct brcmf_pciedev *pcie;
+ } bus_priv;
+ enum brcmf_bus_protocol_type proto_type;
+ struct device *dev;
+ struct brcmf_pub *drvr;
+ enum brcmf_bus_state state;
+ uint maxctl;
+ unsigned long tx_realloc;
+ u32 chip;
+ u32 chiprev;
+ bool always_use_fws_queue;
+ bool wowl_supported;
+
+ struct brcmf_bus_ops *ops;
+ struct brcmf_bus_msgbuf *msgbuf;
+};
+
+/*
+ * callback wrappers
+ */
+static inline int brcmf_bus_preinit(struct brcmf_bus *bus)
+{
+ if (!bus->ops->preinit)
+ return 0;
+ return bus->ops->preinit(bus->dev);
+}
+
+static inline void brcmf_bus_stop(struct brcmf_bus *bus)
+{
+ bus->ops->stop(bus->dev);
+}
+
+static inline int brcmf_bus_txdata(struct brcmf_bus *bus, struct sk_buff *skb)
+{
+ return bus->ops->txdata(bus->dev, skb);
+}
+
+static inline
+int brcmf_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
+{
+ return bus->ops->txctl(bus->dev, msg, len);
+}
+
+static inline
+int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
+{
+ return bus->ops->rxctl(bus->dev, msg, len);
+}
+
+static inline
+struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)
+{
+ if (!bus->ops->gettxq)
+ return ERR_PTR(-ENOENT);
+
+ return bus->ops->gettxq(bus->dev);
+}
+
+static inline
+void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
+{
+ if (bus->ops->wowl_config)
+ bus->ops->wowl_config(bus->dev, enabled);
+}
+
+static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
+{
+ return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
+}
+
+static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
+ enum brcmf_bus_state new_state)
+{
+ /* NOMEDIUM is permanent */
+ if (bus->state == BRCMF_BUS_NOMEDIUM)
+ return;
+
+ brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
+ bus->state = new_state;
+}
+
+/*
+ * interface functions from common layer
+ */
+
+bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
+ int prec);
+
+/* Receive frame for delivery to OS. Callee disposes of rxp. */
+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
+
+/* Indication from bus module regarding presence/insertion of dongle. */
+int brcmf_attach(struct device *dev);
+/* Indication from bus module regarding removal/absence of dongle */
+void brcmf_detach(struct device *dev);
+/* Indication from bus module that dongle should be reset */
+void brcmf_dev_reset(struct device *dev);
+/* Indication from bus module to change flow-control state */
+void brcmf_txflowblock(struct device *dev, bool state);
+
+/* Notify the bus has transferred the tx packet to firmware */
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
+
+int brcmf_bus_start(struct device *dev);
+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
+void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+void brcmf_sdio_exit(void);
+void brcmf_sdio_init(void);
+void brcmf_sdio_register(void);
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+void brcmf_usb_exit(void);
+void brcmf_usb_register(void);
+#endif
+
+#endif /* BRCMFMAC_BUS_H */
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
+
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <net/cfg80211.h>
+#include <net/netlink.h>
+
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include "core.h"
+#include "debug.h"
+#include "tracepoint.h"
+#include "fwil_types.h"
+#include "p2p.h"
+#include "btcoex.h"
+#include "cfg80211.h"
+#include "feature.h"
+#include "fwil.h"
+#include "proto.h"
+#include "vendor.h"
+#include "bus.h"
+
+#define BRCMF_SCAN_IE_LEN_MAX 2048
+#define BRCMF_PNO_VERSION 2
+#define BRCMF_PNO_TIME 30
+#define BRCMF_PNO_REPEAT 4
+#define BRCMF_PNO_FREQ_EXPO_MAX 3
+#define BRCMF_PNO_MAX_PFN_COUNT 16
+#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
+#define BRCMF_PNO_HIDDEN_BIT 2
+#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
+#define BRCMF_PNO_SCAN_COMPLETE 1
+#define BRCMF_PNO_SCAN_INCOMPLETE 0
+
+#define BRCMF_IFACE_MAX_CNT 3
+
+#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
+#define WPA_OUI_TYPE 1
+#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
+#define WME_OUI_TYPE 2
+#define WPS_OUI_TYPE 4
+
+#define VS_IE_FIXED_HDR_LEN 6
+#define WPA_IE_VERSION_LEN 2
+#define WPA_IE_MIN_OUI_LEN 4
+#define WPA_IE_SUITE_COUNT_LEN 2
+
+#define WPA_CIPHER_NONE 0 /* None */
+#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
+#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
+#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
+#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
+
+#define RSN_AKM_NONE 0 /* None (IBSS) */
+#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
+#define RSN_AKM_PSK 2 /* Pre-shared Key */
+#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
+#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
+
+#define VNDR_IE_CMD_LEN 4 /* length of the set command
+ * string :"add", "del" (+ NUL)
+ */
+#define VNDR_IE_COUNT_OFFSET 4
+#define VNDR_IE_PKTFLAG_OFFSET 8
+#define VNDR_IE_VSIE_OFFSET 12
+#define VNDR_IE_HDR_SIZE 12
+#define VNDR_IE_PARSE_LIMIT 5
+
+#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
+#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
+
+#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
+#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
+#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
+
+#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
+ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
+
+static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
+{
+ if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
+ brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
+ vif->sme_state);
+ return false;
+ }
+ return true;
+}
+
+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+static struct ieee80211_rate __wl_rates[] = {
+ RATETAB_ENT(BRCM_RATE_1M, 0),
+ RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_6M, 0),
+ RATETAB_ENT(BRCM_RATE_9M, 0),
+ RATETAB_ENT(BRCM_RATE_12M, 0),
+ RATETAB_ENT(BRCM_RATE_18M, 0),
+ RATETAB_ENT(BRCM_RATE_24M, 0),
+ RATETAB_ENT(BRCM_RATE_36M, 0),
+ RATETAB_ENT(BRCM_RATE_48M, 0),
+ RATETAB_ENT(BRCM_RATE_54M, 0),
+};
+
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size 8
+#define wl_g_rates (__wl_rates + 0)
+#define wl_g_rates_size 12
+
+/* Band templates duplicated per wiphy. The channel info
+ * is filled in after querying the device.
+ */
+static const struct ieee80211_supported_band __wl_band_2ghz = {
+ .band = IEEE80211_BAND_2GHZ,
+ .bitrates = wl_g_rates,
+ .n_bitrates = wl_g_rates_size,
+};
+
+static const struct ieee80211_supported_band __wl_band_5ghz_a = {
+ .band = IEEE80211_BAND_5GHZ,
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size,
+};
+
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags
+ * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't * start p2p
+ * operations on 5GHz channels. All the changes in world regulatory
+ * domain are to be done here.
+ */
+static const struct ieee80211_regdomain brcmf_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
+};
+
+static const u32 __wl_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+/* Vendor specific ie. id = 221, oui and type defines exact ie */
+struct brcmf_vs_tlv {
+ u8 id;
+ u8 len;
+ u8 oui[3];
+ u8 oui_type;
+};
+
+struct parsed_vndr_ie_info {
+ u8 *ie_ptr;
+ u32 ie_len; /* total length including id & length field */
+ struct brcmf_vs_tlv vndrie;
+};
+
+struct parsed_vndr_ies {
+ u32 count;
+ struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
+};
+
+static int brcmf_roamoff;
+module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
+/* Quarter dBm units to mW
+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+ * Table is offset so the last entry is largest mW value that fits in
+ * a u16.
+ */
+
+#define QDBM_OFFSET 153 /* Offset for first entry */
+#define QDBM_TABLE_LEN 40 /* Table size */
+
+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+ */
+#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+
+/* Largest mW value that will round down to the last table entry,
+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
+ * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+ */
+#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+
+static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+};
+
+static u16 brcmf_qdbm_to_mw(u8 qdbm)
+{
+ uint factor = 1;
+ int idx = qdbm - QDBM_OFFSET;
+
+ if (idx >= QDBM_TABLE_LEN)
+ /* clamp to max u16 mW value */
+ return 0xFFFF;
+
+ /* scale the qdBm index up to the range of the table 0-40
+ * where an offset of 40 qdBm equals a factor of 10 mW.
+ */
+ while (idx < 0) {
+ idx += 40;
+ factor *= 10;
+ }
+
+ /* return the mW value scaled down to the correct factor of 10,
+ * adding in factor/2 to get proper rounding.
+ */
+ return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
+}
+
+static u8 brcmf_mw_to_qdbm(u16 mw)
+{
+ u8 qdbm;
+ int offset;
+ uint mw_uint = mw;
+ uint boundary;
+
+ /* handle boundary case */
+ if (mw_uint <= 1)
+ return 0;
+
+ offset = QDBM_OFFSET;
+
+ /* move mw into the range of the table */
+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+ mw_uint *= 10;
+ offset -= 40;
+ }
+
+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
+ nqdBm_to_mW_map[qdbm]) / 2;
+ if (mw_uint < boundary)
+ break;
+ }
+
+ qdbm += (u8) offset;
+
+ return qdbm;
+}
+
+static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct cfg80211_chan_def *ch)
+{
+ struct brcmu_chan ch_inf;
+ s32 primary_offset;
+
+ brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
+ ch->chan->center_freq, ch->center_freq1, ch->width);
+ ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
+ primary_offset = ch->center_freq1 - ch->chan->center_freq;
+ switch (ch->width) {
+ case NL80211_CHAN_WIDTH_20:
+ ch_inf.bw = BRCMU_CHAN_BW_20;
+ WARN_ON(primary_offset != 0);
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ ch_inf.bw = BRCMU_CHAN_BW_40;
+ if (primary_offset < 0)
+ ch_inf.sb = BRCMU_CHAN_SB_U;
+ else
+ ch_inf.sb = BRCMU_CHAN_SB_L;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ ch_inf.bw = BRCMU_CHAN_BW_80;
+ if (primary_offset < 0) {
+ if (primary_offset < -CH_10MHZ_APART)
+ ch_inf.sb = BRCMU_CHAN_SB_UU;
+ else
+ ch_inf.sb = BRCMU_CHAN_SB_UL;
+ } else {
+ if (primary_offset > CH_10MHZ_APART)
+ ch_inf.sb = BRCMU_CHAN_SB_LL;
+ else
+ ch_inf.sb = BRCMU_CHAN_SB_LU;
+ }
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+ switch (ch->chan->band) {
+ case IEEE80211_BAND_2GHZ:
+ ch_inf.band = BRCMU_CHAN_BAND_2G;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ ch_inf.band = BRCMU_CHAN_BAND_5G;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+ d11inf->encchspec(&ch_inf);
+
+ return ch_inf.chspec;
+}
+
+u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct ieee80211_channel *ch)
+{
+ struct brcmu_chan ch_inf;
+
+ ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
+ ch_inf.bw = BRCMU_CHAN_BW_20;
+ d11inf->encchspec(&ch_inf);
+
+ return ch_inf.chspec;
+}
+
+/* Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key)
+{
+ const struct brcmf_tlv *elt = buf;
+ int totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ int len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
+ return elt;
+
+ elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+
+ return NULL;
+}
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
+ const u8 *oui, u32 oui_len, u8 type)
+{
+ /* If the contents match the OUI and the type */
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+ !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+ type == ie[TLV_BODY_OFF + oui_len]) {
+ return true;
+ }
+
+ if (tlvs == NULL)
+ return false;
+ /* point to the next ie */
+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return false;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpaie(const u8 *parse, u32 len)
+{
+ const struct brcmf_tlv *ie;
+
+ while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+ if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
+ WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
+ return (struct brcmf_vs_tlv *)ie;
+ }
+ return NULL;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpsie(const u8 *parse, u32 len)
+{
+ const struct brcmf_tlv *ie;
+
+ while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+ if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+ WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
+ return (struct brcmf_vs_tlv *)ie;
+ }
+ return NULL;
+}
+
+
+static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+ struct brcmf_wsec_key_le *key_le)
+{
+ key_le->index = cpu_to_le32(key->index);
+ key_le->len = cpu_to_le32(key->len);
+ key_le->algo = cpu_to_le32(key->algo);
+ key_le->flags = cpu_to_le32(key->flags);
+ key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
+ key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
+ key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
+ memcpy(key_le->data, key->data, sizeof(key->data));
+ memcpy(key_le->ea, key->ea, sizeof(key->ea));
+}
+
+static int
+send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
+{
+ int err;
+ struct brcmf_wsec_key_le key_le;
+
+ convert_key_from_CPU(key, &key_le);
+
+ brcmf_netdev_wait_pend8021x(ndev);
+
+ err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
+ sizeof(key_le));
+
+ if (err)
+ brcmf_err("wsec_key error (%d)\n", err);
+ return err;
+}
+
+static s32
+brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
+{
+ s32 err;
+ u32 mode;
+
+ if (enable)
+ mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
+ else
+ mode = 0;
+
+ /* Try to set and enable ARP offload feature, this may fail, then it */
+ /* is simply not supported and err 0 will be returned */
+ err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
+ if (err) {
+ brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
+ mode, err);
+ err = 0;
+ } else {
+ err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
+ if (err) {
+ brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
+ enable, err);
+ err = 0;
+ } else
+ brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
+ enable, mode);
+ }
+
+ return err;
+}
+
+static void
+brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_if *ifp;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ ifp = vif->ifp;
+
+ if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
+ (wdev->iftype == NL80211_IFTYPE_AP) ||
+ (wdev->iftype == NL80211_IFTYPE_P2P_GO))
+ brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
+ ADDR_DIRECT);
+ else
+ brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
+ ADDR_INDIRECT);
+}
+
+static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
+{
+ enum nl80211_iftype iftype;
+
+ iftype = vif->wdev.iftype;
+ return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
+}
+
+static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
+{
+ return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
+}
+
+static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+ const char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params)
+{
+ struct wireless_dev *wdev;
+
+ brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ return ERR_PTR(-EOPNOTSUPP);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+ if (!IS_ERR(wdev))
+ brcmf_cfg80211_update_proto_addr_mode(wdev);
+ return wdev;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
+{
+ if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
+ brcmf_set_mpc(ifp, mpc);
+}
+
+void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
+{
+ s32 err = 0;
+
+ if (check_vif_up(ifp->vif)) {
+ err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
+ if (err) {
+ brcmf_err("fail to set mpc\n");
+ return;
+ }
+ brcmf_dbg(INFO, "MPC : %d\n", mpc);
+ }
+}
+
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort)
+{
+ struct brcmf_scan_params_le params_le;
+ struct cfg80211_scan_request *scan_request;
+ s32 err = 0;
+
+ brcmf_dbg(SCAN, "Enter\n");
+
+ /* clear scan request, because the FW abort can cause a second call */
+ /* to this functon and might cause a double cfg80211_scan_done */
+ scan_request = cfg->scan_request;
+ cfg->scan_request = NULL;
+
+ if (timer_pending(&cfg->escan_timeout))
+ del_timer_sync(&cfg->escan_timeout);
+
+ if (fw_abort) {
+ /* Do a scan abort to stop the driver's scan engine */
+ brcmf_dbg(SCAN, "ABORT scan in firmware\n");
+ memset(¶ms_le, 0, sizeof(params_le));
+ memset(params_le.bssid, 0xFF, ETH_ALEN);
+ params_le.bss_type = DOT11_BSSTYPE_ANY;
+ params_le.scan_type = 0;
+ params_le.channel_num = cpu_to_le32(1);
+ params_le.nprobes = cpu_to_le32(1);
+ params_le.active_time = cpu_to_le32(-1);
+ params_le.passive_time = cpu_to_le32(-1);
+ params_le.home_time = cpu_to_le32(-1);
+ /* Scan is aborted by setting channel_list[0] to -1 */
+ params_le.channel_list[0] = cpu_to_le16(-1);
+ /* E-Scan (or anyother type) can be aborted by SCAN */
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+ ¶ms_le, sizeof(params_le));
+ if (err)
+ brcmf_err("Scan abort failed\n");
+ }
+
+ brcmf_scan_config_mpc(ifp, 1);
+
+ /*
+ * e-scan can be initiated by scheduled scan
+ * which takes precedence.
+ */
+ if (cfg->sched_escan) {
+ brcmf_dbg(SCAN, "scheduled scan completed\n");
+ cfg->sched_escan = false;
+ if (!aborted)
+ cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
+ } else if (scan_request) {
+ brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
+ aborted ? "Aborted" : "Done");
+ cfg80211_scan_done(scan_request, aborted);
+ }
+ if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+ brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
+
+ return err;
+}
+
+static
+int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = wdev->netdev;
+
+ /* vif event pending in firmware */
+ if (brcmf_cfg80211_vif_event_armed(cfg))
+ return -EBUSY;
+
+ if (ndev) {
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
+ cfg->escan_info.ifp == netdev_priv(ndev))
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
+ true, true);
+
+ brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
+ }
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return brcmf_p2p_del_vif(wiphy, wdev);
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ return -EINVAL;
+ }
+ return -EOPNOTSUPP;
+}
+
+static s32
+brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_vif *vif = ifp->vif;
+ s32 infra = 0;
+ s32 ap = 0;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ brcmf_err("type (%d) : currently we do not support this type\n",
+ type);
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_ADHOC:
+ infra = 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ /* Ignore change for p2p IF. Unclear why supplicant does this */
+ if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+ (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+ brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+ /* WAR: It is unexpected to get a change of VIF for P2P
+ * IF, but it happens. The request can not be handled
+ * but returning EPERM causes a crash. Returning 0
+ * without setting ieee80211_ptr->iftype causes trace
+ * (WARN_ON) but it works with wpa_supplicant
+ */
+ return 0;
+ }
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ ap = 1;
+ break;
+ default:
+ err = -EINVAL;
+ goto done;
+ }
+
+ if (ap) {
+ if (type == NL80211_IFTYPE_P2P_GO) {
+ brcmf_dbg(INFO, "IF Type = P2P GO\n");
+ err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
+ }
+ if (!err) {
+ set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
+ brcmf_dbg(INFO, "IF Type = AP\n");
+ }
+ } else {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
+ if (err) {
+ brcmf_err("WLC_SET_INFRA error (%d)\n", err);
+ err = -EAGAIN;
+ goto done;
+ }
+ brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
+ "Adhoc" : "Infra");
+ }
+ ndev->ieee80211_ptr->iftype = type;
+
+ brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+
+ return err;
+}
+
+static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_scan_params_le *params_le,
+ struct cfg80211_scan_request *request)
+{
+ u32 n_ssids;
+ u32 n_channels;
+ s32 i;
+ s32 offset;
+ u16 chanspec;
+ char *ptr;
+ struct brcmf_ssid_le ssid_le;
+
+ memset(params_le->bssid, 0xFF, ETH_ALEN);
+ params_le->bss_type = DOT11_BSSTYPE_ANY;
+ params_le->scan_type = 0;
+ params_le->channel_num = 0;
+ params_le->nprobes = cpu_to_le32(-1);
+ params_le->active_time = cpu_to_le32(-1);
+ params_le->passive_time = cpu_to_le32(-1);
+ params_le->home_time = cpu_to_le32(-1);
+ memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le));
+
+ /* if request is null exit so it will be all channel broadcast scan */
+ if (!request)
+ return;
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+ /* Copy channel array if applicable */
+ brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
+ n_channels);
+ if (n_channels > 0) {
+ for (i = 0; i < n_channels; i++) {
+ chanspec = channel_to_chanspec(&cfg->d11inf,
+ request->channels[i]);
+ brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
+ request->channels[i]->hw_value, chanspec);
+ params_le->channel_list[i] = cpu_to_le16(chanspec);
+ }
+ } else {
+ brcmf_dbg(SCAN, "Scanning all channels\n");
+ }
+ /* Copy ssid array if applicable */
+ brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
+ if (n_ssids > 0) {
+ offset = offsetof(struct brcmf_scan_params_le, channel_list) +
+ n_channels * sizeof(u16);
+ offset = roundup(offset, sizeof(u32));
+ ptr = (char *)params_le + offset;
+ for (i = 0; i < n_ssids; i++) {
+ memset(&ssid_le, 0, sizeof(ssid_le));
+ ssid_le.SSID_len =
+ cpu_to_le32(request->ssids[i].ssid_len);
+ memcpy(ssid_le.SSID, request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ if (!ssid_le.SSID_len)
+ brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
+ else
+ brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
+ i, ssid_le.SSID, ssid_le.SSID_len);
+ memcpy(ptr, &ssid_le, sizeof(ssid_le));
+ ptr += sizeof(ssid_le);
+ }
+ } else {
+ brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
+ if ((request->ssids) && request->ssids->ssid_len) {
+ brcmf_dbg(SCAN, "SSID %s len=%d\n",
+ params_le->ssid_le.SSID,
+ request->ssids->ssid_len);
+ params_le->ssid_le.SSID_len =
+ cpu_to_le32(request->ssids->ssid_len);
+ memcpy(¶ms_le->ssid_le.SSID, request->ssids->ssid,
+ request->ssids->ssid_len);
+ }
+ }
+ /* Adding mask to channel numbers */
+ params_le->channel_num =
+ cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
+ (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
+}
+
+static s32
+brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
+ struct cfg80211_scan_request *request, u16 action)
+{
+ s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
+ offsetof(struct brcmf_escan_params_le, params_le);
+ struct brcmf_escan_params_le *params;
+ s32 err = 0;
+
+ brcmf_dbg(SCAN, "E-SCAN START\n");
+
+ if (request != NULL) {
+ /* Allocate space for populating ssids in struct */
+ params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
+
+ /* Allocate space for populating ssids in struct */
+ params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
+ }
+
+ params = kzalloc(params_size, GFP_KERNEL);
+ if (!params) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
+ brcmf_escan_prep(cfg, ¶ms->params_le, request);
+ params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+ params->action = cpu_to_le16(action);
+ params->sync_id = cpu_to_le16(0x1234);
+
+ err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
+ if (err) {
+ if (err == -EBUSY)
+ brcmf_dbg(INFO, "system busy : escan canceled\n");
+ else
+ brcmf_err("error (%d)\n", err);
+ }
+
+ kfree(params);
+exit:
+ return err;
+}
+
+static s32
+brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
+ struct brcmf_if *ifp, struct cfg80211_scan_request *request)
+{
+ s32 err;
+ u32 passive_scan;
+ struct brcmf_scan_results *results;
+ struct escan_info *escan = &cfg->escan_info;
+
+ brcmf_dbg(SCAN, "Enter\n");
+ escan->ifp = ifp;
+ escan->wiphy = wiphy;
+ escan->escan_state = WL_ESCAN_STATE_SCANNING;
+ passive_scan = cfg->active_scan ? 0 : 1;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
+ passive_scan);
+ if (err) {
+ brcmf_err("error (%d)\n", err);
+ return err;
+ }
+ brcmf_scan_config_mpc(ifp, 0);
+ results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
+ results->version = 0;
+ results->count = 0;
+ results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
+
+ err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
+ if (err)
+ brcmf_scan_config_mpc(ifp, 1);
+ return err;
+}
+
+static s32
+brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid)
+{
+ struct brcmf_if *ifp = vif->ifp;
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct cfg80211_ssid *ssids;
+ struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
+ u32 passive_scan;
+ bool escan_req;
+ bool spec_scan;
+ s32 err;
+ u32 SSID_len;
+
+ brcmf_dbg(SCAN, "START ESCAN\n");
+
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
+ return -EAGAIN;
+ }
+ if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
+ brcmf_err("Scanning being aborted: status (%lu)\n",
+ cfg->scan_status);
+ return -EAGAIN;
+ }
+ if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
+ brcmf_err("Scanning suppressed: status (%lu)\n",
+ cfg->scan_status);
+ return -EAGAIN;
+ }
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
+ brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
+ return -EAGAIN;
+ }
+
+ /* If scan req comes for p2p0, send it over primary I/F */
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+
+ /* Arm scan timeout timer */
+ mod_timer(&cfg->escan_timeout, jiffies +
+ WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
+
+ escan_req = false;
+ if (request) {
+ /* scan bss */
+ ssids = request->ssids;
+ escan_req = true;
+ } else {
+ /* scan in ibss */
+ /* we don't do escan in ibss */
+ ssids = this_ssid;
+ }
+
+ cfg->scan_request = request;
+ set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+ if (escan_req) {
+ cfg->escan_info.run = brcmf_run_escan;
+ err = brcmf_p2p_scan_prep(wiphy, request, vif);
+ if (err)
+ goto scan_out;
+
+ err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
+ if (err)
+ goto scan_out;
+ } else {
+ brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
+ ssids->ssid, ssids->ssid_len);
+ memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
+ SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(0);
+ spec_scan = false;
+ if (SSID_len) {
+ memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
+ spec_scan = true;
+ } else
+ brcmf_dbg(SCAN, "Broadcast scan\n");
+
+ passive_scan = cfg->active_scan ? 0 : 1;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
+ passive_scan);
+ if (err) {
+ brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
+ goto scan_out;
+ }
+ brcmf_scan_config_mpc(ifp, 0);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
+ &sr->ssid_le, sizeof(sr->ssid_le));
+ if (err) {
+ if (err == -EBUSY)
+ brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
+ sr->ssid_le.SSID);
+ else
+ brcmf_err("WLC_SCAN error (%d)\n", err);
+
+ brcmf_scan_config_mpc(ifp, 1);
+ goto scan_out;
+ }
+ }
+
+ return 0;
+
+scan_out:
+ clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+ if (timer_pending(&cfg->escan_timeout))
+ del_timer_sync(&cfg->escan_timeout);
+ cfg->scan_request = NULL;
+ return err;
+}
+
+static s32
+brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+{
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
+ if (!check_vif_up(vif))
+ return -EIO;
+
+ err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
+
+ if (err)
+ brcmf_err("scan error (%d)\n", err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
+{
+ s32 err = 0;
+
+ err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
+ rts_threshold);
+ if (err)
+ brcmf_err("Error (%d)\n", err);
+
+ return err;
+}
+
+static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
+{
+ s32 err = 0;
+
+ err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
+ frag_threshold);
+ if (err)
+ brcmf_err("Error (%d)\n", err);
+
+ return err;
+}
+
+static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
+{
+ s32 err = 0;
+ u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
+
+ err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
+ if (err) {
+ brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
+ return err;
+ }
+ return err;
+}
+
+static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+ (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
+ cfg->conf->rts_threshold = wiphy->rts_threshold;
+ err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+ (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
+ cfg->conf->frag_threshold = wiphy->frag_threshold;
+ err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG
+ && (cfg->conf->retry_long != wiphy->retry_long)) {
+ cfg->conf->retry_long = wiphy->retry_long;
+ err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_RETRY_SHORT
+ && (cfg->conf->retry_short != wiphy->retry_short)) {
+ cfg->conf->retry_short = wiphy->retry_short;
+ err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
+ if (!err)
+ goto done;
+ }
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
+{
+ memset(prof, 0, sizeof(*prof));
+}
+
+static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
+ brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
+ err = brcmf_fil_cmd_data_set(vif->ifp,
+ BRCMF_C_DISASSOC, NULL, 0);
+ if (err) {
+ brcmf_err("WLC_DISASSOC failed (%d)\n", err);
+ }
+ clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
+ cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+
+ }
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
+ clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+ brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
+ brcmf_dbg(TRACE, "Exit\n");
+}
+
+static s32
+brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_ibss_params *params)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_join_params join_params;
+ size_t join_params_size = 0;
+ s32 err = 0;
+ s32 wsec = 0;
+ s32 bcnprd;
+ u16 chanspec;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (params->ssid)
+ brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
+ else {
+ brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
+
+ if (params->bssid)
+ brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
+ else
+ brcmf_dbg(CONN, "No BSSID specified\n");
+
+ if (params->chandef.chan)
+ brcmf_dbg(CONN, "channel: %d\n",
+ params->chandef.chan->center_freq);
+ else
+ brcmf_dbg(CONN, "no channel specified\n");
+
+ if (params->channel_fixed)
+ brcmf_dbg(CONN, "fixed channel required\n");
+ else
+ brcmf_dbg(CONN, "no fixed channel required\n");
+
+ if (params->ie && params->ie_len)
+ brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
+ else
+ brcmf_dbg(CONN, "no ie specified\n");
+
+ if (params->beacon_interval)
+ brcmf_dbg(CONN, "beacon interval: %d\n",
+ params->beacon_interval);
+ else
+ brcmf_dbg(CONN, "no beacon interval specified\n");
+
+ if (params->basic_rates)
+ brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
+ else
+ brcmf_dbg(CONN, "no basic rates specified\n");
+
+ if (params->privacy)
+ brcmf_dbg(CONN, "privacy required\n");
+ else
+ brcmf_dbg(CONN, "no privacy required\n");
+
+ /* Configure Privacy for starter */
+ if (params->privacy)
+ wsec |= WEP_ENABLED;
+
+ err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
+ if (err) {
+ brcmf_err("wsec failed (%d)\n", err);
+ goto done;
+ }
+
+ /* Configure Beacon Interval for starter */
+ if (params->beacon_interval)
+ bcnprd = params->beacon_interval;
+ else
+ bcnprd = 100;
+
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
+ if (err) {
+ brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
+ goto done;
+ }
+
+ /* Configure required join parameter */
+ memset(&join_params, 0, sizeof(struct brcmf_join_params));
+
+ /* SSID */
+ profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
+ memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
+ memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
+ join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+ join_params_size = sizeof(join_params.ssid_le);
+
+ /* BSSID */
+ if (params->bssid) {
+ memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
+ join_params_size = sizeof(join_params.ssid_le) +
+ BRCMF_ASSOC_PARAMS_FIXED_SIZE;
+ memcpy(profile->bssid, params->bssid, ETH_ALEN);
+ } else {
+ memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
+ memset(profile->bssid, 0, ETH_ALEN);
+ }
+
+ /* Channel */
+ if (params->chandef.chan) {
+ u32 target_channel;
+
+ cfg->channel =
+ ieee80211_frequency_to_channel(
+ params->chandef.chan->center_freq);
+ if (params->channel_fixed) {
+ /* adding chanspec */
+ chanspec = chandef_to_chanspec(&cfg->d11inf,
+ ¶ms->chandef);
+ join_params.params_le.chanspec_list[0] =
+ cpu_to_le16(chanspec);
+ join_params.params_le.chanspec_num = cpu_to_le32(1);
+ join_params_size += sizeof(join_params.params_le);
+ }
+
+ /* set channel for starter */
+ target_channel = cfg->channel;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
+ target_channel);
+ if (err) {
+ brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
+ goto done;
+ }
+ } else
+ cfg->channel = 0;
+
+ cfg->ibss_starter = false;
+
+
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, join_params_size);
+ if (err) {
+ brcmf_err("WLC_SET_SSID failed (%d)\n", err);
+ goto done;
+ }
+
+done:
+ if (err)
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ brcmf_link_down(ifp->vif);
+
+ brcmf_dbg(TRACE, "Exit\n");
+
+ return 0;
+}
+
+static s32 brcmf_set_wpa_version(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+ else
+ val = WPA_AUTH_DISABLED;
+ brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
+ if (err) {
+ brcmf_err("set wpa_auth failed (%d)\n", err);
+ return err;
+ }
+ sec = &profile->sec;
+ sec->wpa_versions = sme->crypto.wpa_versions;
+ return err;
+}
+
+static s32 brcmf_set_auth_type(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ val = 0;
+ brcmf_dbg(CONN, "open system\n");
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ val = 1;
+ brcmf_dbg(CONN, "shared key\n");
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ val = 2;
+ brcmf_dbg(CONN, "automatic\n");
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ brcmf_dbg(CONN, "network eap\n");
+ default:
+ val = 2;
+ brcmf_err("invalid auth type (%d)\n", sme->auth_type);
+ break;
+ }
+
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
+ if (err) {
+ brcmf_err("set auth failed (%d)\n", err);
+ return err;
+ }
+ sec = &profile->sec;
+ sec->auth_type = sme->auth_type;
+ return err;
+}
+
+static s32
+brcmf_set_wsec_mode(struct net_device *ndev,
+ struct cfg80211_connect_params *sme, bool mfp)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 pval = 0;
+ s32 gval = 0;
+ s32 wsec;
+ s32 err = 0;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ switch (sme->crypto.ciphers_pairwise[0]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ pval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ pval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ pval = AES_ENABLED;
+ break;
+ default:
+ brcmf_err("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
+ return -EINVAL;
+ }
+ }
+ if (sme->crypto.cipher_group) {
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ gval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ gval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ gval = AES_ENABLED;
+ break;
+ default:
+ brcmf_err("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ }
+
+ brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
+ /* In case of privacy, but no security and WPS then simulate */
+ /* setting AES. WPS-2.0 allows no security */
+ if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
+ sme->privacy)
+ pval = AES_ENABLED;
+
+ if (mfp)
+ wsec = pval | gval | MFP_CAPABLE;
+ else
+ wsec = pval | gval;
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
+ if (err) {
+ brcmf_err("error (%d)\n", err);
+ return err;
+ }
+
+ sec = &profile->sec;
+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
+ sec->cipher_group = sme->crypto.cipher_group;
+
+ return err;
+}
+
+static s32
+brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ if (sme->crypto.n_akm_suites) {
+ err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
+ "wpa_auth", &val);
+ if (err) {
+ brcmf_err("could not get wpa_auth (%d)\n", err);
+ return err;
+ }
+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA_AUTH_PSK;
+ break;
+ default:
+ brcmf_err("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA2_AUTH_PSK;
+ break;
+ default:
+ brcmf_err("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ }
+
+ brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
+ "wpa_auth", val);
+ if (err) {
+ brcmf_err("could not set wpa_auth (%d)\n", err);
+ return err;
+ }
+ }
+ sec = &profile->sec;
+ sec->wpa_auth = sme->crypto.akm_suites[0];
+
+ return err;
+}
+
+static s32
+brcmf_set_sharedkey(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
+ struct brcmf_cfg80211_security *sec;
+ struct brcmf_wsec_key key;
+ s32 val;
+ s32 err = 0;
+
+ brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
+
+ if (sme->key_len == 0)
+ return 0;
+
+ sec = &profile->sec;
+ brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
+ sec->wpa_versions, sec->cipher_pairwise);
+
+ if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
+ return 0;
+
+ if (!(sec->cipher_pairwise &
+ (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
+ return 0;
+
+ memset(&key, 0, sizeof(key));
+ key.len = (u32) sme->key_len;
+ key.index = (u32) sme->key_idx;
+ if (key.len > sizeof(key.data)) {
+ brcmf_err("Too long key length (%u)\n", key.len);
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = BRCMF_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ default:
+ brcmf_err("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo);
+ brcmf_dbg(CONN, "key \"%s\"\n", key.data);
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ return err;
+
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
+ brcmf_dbg(CONN, "set auth_type to shared key\n");
+ val = WL_AUTH_SHARED_KEY; /* shared key */
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
+ if (err)
+ brcmf_err("set auth failed (%d)\n", err);
+ }
+ return err;
+}
+
+static
+enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
+ enum nl80211_auth_type type)
+{
+ if (type == NL80211_AUTHTYPE_AUTOMATIC &&
+ brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
+ brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ }
+ return type;
+}
+
+static s32
+brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct ieee80211_channel *chan = sme->channel;
+ struct brcmf_join_params join_params;
+ size_t join_params_size;
+ const struct brcmf_tlv *rsn_ie;
+ const struct brcmf_vs_tlv *wpa_ie;
+ const void *ie;
+ u32 ie_len;
+ struct brcmf_ext_join_params_le *ext_join_params;
+ u16 chanspec;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (!sme->ssid) {
+ brcmf_err("Invalid ssid\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
+ /* A normal (non P2P) connection request setup. */
+ ie = NULL;
+ ie_len = 0;
+ /* find the WPA_IE */
+ wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
+ if (wpa_ie) {
+ ie = wpa_ie;
+ ie_len = wpa_ie->len + TLV_HDR_LEN;
+ } else {
+ /* find the RSN_IE */
+ rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
+ sme->ie_len,
+ WLAN_EID_RSN);
+ if (rsn_ie) {
+ ie = rsn_ie;
+ ie_len = rsn_ie->len + TLV_HDR_LEN;
+ }
+ }
+ brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
+ }
+
+ err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
+ sme->ie, sme->ie_len);
+ if (err)
+ brcmf_err("Set Assoc REQ IE Failed\n");
+ else
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
+
+ set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
+
+ if (chan) {
+ cfg->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+ chanspec = channel_to_chanspec(&cfg->d11inf, chan);
+ brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
+ cfg->channel, chan->center_freq, chanspec);
+ } else {
+ cfg->channel = 0;
+ chanspec = 0;
+ }
+
+ brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
+
+ err = brcmf_set_wpa_version(ndev, sme);
+ if (err) {
+ brcmf_err("wl_set_wpa_version failed (%d)\n", err);
+ goto done;
+ }
+
+ sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
+ err = brcmf_set_auth_type(ndev, sme);
+ if (err) {
+ brcmf_err("wl_set_auth_type failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
+ if (err) {
+ brcmf_err("wl_set_set_cipher failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_key_mgmt(ndev, sme);
+ if (err) {
+ brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_sharedkey(ndev, sme);
+ if (err) {
+ brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
+ goto done;
+ }
+
+ profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
+ (u32)sme->ssid_len);
+ memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
+ if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ profile->ssid.SSID[profile->ssid.SSID_len] = 0;
+ brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
+ profile->ssid.SSID_len);
+ }
+
+ /* Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
+ offsetof(struct brcmf_assoc_params_le, chanspec_list);
+ if (cfg->channel)
+ join_params_size += sizeof(u16);
+ ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
+ if (ext_join_params == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+ ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+ memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
+ profile->ssid.SSID_len);
+
+ /* Set up join scan parameters */
+ ext_join_params->scan_le.scan_type = -1;
+ ext_join_params->scan_le.home_time = cpu_to_le32(-1);
+
+ if (sme->bssid)
+ memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
+ else
+ memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
+
+ if (cfg->channel) {
+ ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
+
+ ext_join_params->assoc_le.chanspec_list[0] =
+ cpu_to_le16(chanspec);
+ /* Increase dwell time to receive probe response or detect
+ * beacon from target AP at a noisy air only during connect
+ * command.
+ */
+ ext_join_params->scan_le.active_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
+ ext_join_params->scan_le.passive_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+ /* To sync with presence period of VSDB GO send probe request
+ * more frequently. Probe request will be stopped when it gets
+ * probe response from target AP/GO.
+ */
+ ext_join_params->scan_le.nprobes =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
+ BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
+ } else {
+ ext_join_params->scan_le.active_time = cpu_to_le32(-1);
+ ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
+ ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
+ }
+
+ err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
+ join_params_size);
+ kfree(ext_join_params);
+ if (!err)
+ /* This is it. join command worked, we are done */
+ goto done;
+
+ /* join command failed, fallback to set ssid */
+ memset(&join_params, 0, sizeof(join_params));
+ join_params_size = sizeof(join_params.ssid_le);
+
+ memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
+ join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+
+ if (sme->bssid)
+ memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
+ else
+ memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
+
+ if (cfg->channel) {
+ join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+ join_params.params_le.chanspec_num = cpu_to_le32(1);
+ join_params_size += sizeof(join_params.params_le);
+ }
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, join_params_size);
+ if (err)
+ brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
+
+done:
+ if (err)
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
+ u16 reason_code)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_scb_val_le scbval;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
+ cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
+
+ memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
+ scbval.val = cpu_to_le32(reason_code);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
+ &scbval, sizeof(scbval));
+ if (err)
+ brcmf_err("error (%d)\n", err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm)
+{
+
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ u16 txpwrmw;
+ s32 err = 0;
+ s32 disable = 0;
+ s32 dbm = MBM_TO_DBM(mbm);
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ case NL80211_TX_POWER_FIXED:
+ if (dbm < 0) {
+ brcmf_err("TX_POWER_FIXED - dbm is negative\n");
+ err = -EINVAL;
+ goto done;
+ }
+ break;
+ }
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
+ if (err)
+ brcmf_err("WLC_SET_RADIO error (%d)\n", err);
+
+ if (dbm > 0xffff)
+ txpwrmw = 0xffff;
+ else
+ txpwrmw = (u16) dbm;
+ err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
+ (s32)brcmf_mw_to_qdbm(txpwrmw));
+ if (err)
+ brcmf_err("qtxpower error (%d)\n", err);
+ cfg->conf->tx_power = dbm;
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ s32 *dbm)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ s32 txpwrdbm;
+ u8 result;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
+ if (err) {
+ brcmf_err("error (%d)\n", err);
+ goto done;
+ }
+
+ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
+ *dbm = (s32) brcmf_qdbm_to_mw(result);
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool unicast, bool multicast)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ u32 index;
+ u32 wsec;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
+ if (err) {
+ brcmf_err("WLC_GET_WSEC error (%d)\n", err);
+ goto done;
+ }
+
+ if (wsec & WEP_ENABLED) {
+ /* Just select a new current key */
+ index = key_idx;
+ err = brcmf_fil_cmd_int_set(ifp,
+ BRCMF_C_SET_KEY_PRIMARY, index);
+ if (err)
+ brcmf_err("error (%d)\n", err);
+ }
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, const u8 *mac_addr, struct key_params *params)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_wsec_key key;
+ s32 err = 0;
+ u8 keybuf[8];
+
+ memset(&key, 0, sizeof(key));
+ key.index = (u32) key_idx;
+ /* Instead of bcast for ea address for default wep keys,
+ driver needs it to be Null */
+ if (!is_multicast_ether_addr(mac_addr))
+ memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
+ key.len = (u32) params->key_len;
+ /* check for key index change */
+ if (key.len == 0) {
+ /* key delete */
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ brcmf_err("key delete error (%d)\n", err);
+ } else {
+ if (key.len > sizeof(key.data)) {
+ brcmf_err("Invalid key length (%d)\n", key.len);
+ return -EINVAL;
+ }
+
+ brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
+ memcpy(key.data, params->key, key.len);
+
+ if (!brcmf_is_apmode(ifp->vif) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+
+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
+ if (params->seq && params->seq_len == 6) {
+ /* rx iv */
+ u8 *ivptr;
+ ivptr = (u8 *) params->seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = true;
+ }
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
+ break;
+ default:
+ brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
+ return -EINVAL;
+ }
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ brcmf_err("wsec_key error (%d)\n", err);
+ }
+ return err;
+}
+
+static s32
+brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_wsec_key key;
+ s32 val;
+ s32 wsec;
+ s32 err = 0;
+ u8 keybuf[8];
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (mac_addr &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
+ brcmf_dbg(TRACE, "Exit");
+ return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
+ }
+ memset(&key, 0, sizeof(key));
+
+ key.len = (u32) params->key_len;
+ key.index = (u32) key_idx;
+
+ if (key.len > sizeof(key.data)) {
+ brcmf_err("Too long key length (%u)\n", key.len);
+ err = -EINVAL;
+ goto done;
+ }
+ memcpy(key.data, params->key, key.len);
+
+ key.flags = BRCMF_PRIMARY_KEY;
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ val = WEP_ENABLED;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ val = WEP_ENABLED;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (!brcmf_is_apmode(ifp->vif)) {
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+ key.algo = CRYPTO_ALGO_TKIP;
+ val = TKIP_ENABLED;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
+ break;
+ default:
+ brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
+ err = -EINVAL;
+ goto done;
+ }
+
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ goto done;
+
+ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
+ if (err) {
+ brcmf_err("get wsec error (%d)\n", err);
+ goto done;
+ }
+ wsec |= val;
+ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
+ if (err) {
+ brcmf_err("set wsec error (%d)\n", err);
+ goto done;
+ }
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_wsec_key key;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
+ /* we ignore this key index in this case */
+ brcmf_err("invalid key index (%d)\n", key_idx);
+ return -EINVAL;
+ }
+
+ memset(&key, 0, sizeof(key));
+
+ key.index = (u32) key_idx;
+ key.flags = BRCMF_PRIMARY_KEY;
+ key.algo = CRYPTO_ALGO_OFF;
+
+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
+
+ /* Set the new key/index */
+ err = send_key_to_dongle(ndev, &key);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback) (void *cookie, struct key_params * params))
+{
+ struct key_params params;
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_cfg80211_security *sec;
+ s32 wsec;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CONN, "key index (%d)\n", key_idx);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ memset(¶ms, 0, sizeof(params));
+
+ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
+ if (err) {
+ brcmf_err("WLC_GET_WSEC error (%d)\n", err);
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ goto done;
+ }
+ if (wsec & WEP_ENABLED) {
+ sec = &profile->sec;
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
+ }
+ } else if (wsec & TKIP_ENABLED) {
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
+ } else if (wsec & AES_ENABLED) {
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
+ } else {
+ brcmf_err("Invalid algo (0x%x)\n", wsec);
+ err = -EINVAL;
+ goto done;
+ }
+ callback(cookie, ¶ms);
+
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *ndev, u8 key_idx)
+{
+ brcmf_dbg(INFO, "Not supported\n");
+
+ return -EOPNOTSUPP;
+}
+
+static s32
+brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ const u8 *mac, struct station_info *sinfo)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_scb_val_le scb_val;
+ int rssi;
+ s32 rate;
+ s32 err = 0;
+ u8 *bssid = profile->bssid;
+ struct brcmf_sta_info_le sta_info_le;
+ u32 beacon_period;
+ u32 dtim_period;
+
+ brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ if (brcmf_is_apmode(ifp->vif)) {
+ memcpy(&sta_info_le, mac, ETH_ALEN);
+ err = brcmf_fil_iovar_data_get(ifp, "sta_info",
+ &sta_info_le,
+ sizeof(sta_info_le));
+ if (err < 0) {
+ brcmf_err("GET STA INFO failed, %d\n", err);
+ goto done;
+ }
+ sinfo->filled = STATION_INFO_INACTIVE_TIME;
+ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+ if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
+ sinfo->filled |= STATION_INFO_CONNECTED_TIME;
+ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
+ }
+ brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
+ sinfo->inactive_time, sinfo->connected_time);
+ } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
+ if (memcmp(mac, bssid, ETH_ALEN)) {
+ brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
+ mac, bssid);
+ err = -ENOENT;
+ goto done;
+ }
+ /* Report the current tx rate */
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+ if (err) {
+ brcmf_err("Could not get rate (%d)\n", err);
+ goto done;
+ } else {
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
+ }
+
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
+ &ifp->vif->sme_state)) {
+ memset(&scb_val, 0, sizeof(scb_val));
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
+ &scb_val, sizeof(scb_val));
+ if (err) {
+ brcmf_err("Could not get rssi (%d)\n", err);
+ goto done;
+ } else {
+ rssi = le32_to_cpu(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
+ }
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
+ &beacon_period);
+ if (err) {
+ brcmf_err("Could not get beacon period (%d)\n",
+ err);
+ goto done;
+ } else {
+ sinfo->bss_param.beacon_interval =
+ beacon_period;
+ brcmf_dbg(CONN, "Beacon peroid %d\n",
+ beacon_period);
+ }
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
+ &dtim_period);
+ if (err) {
+ brcmf_err("Could not get DTIM period (%d)\n",
+ err);
+ goto done;
+ } else {
+ sinfo->bss_param.dtim_period = dtim_period;
+ brcmf_dbg(CONN, "DTIM peroid %d\n",
+ dtim_period);
+ }
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
+ }
+ } else
+ err = -EPERM;
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
+ bool enabled, s32 timeout)
+{
+ s32 pm;
+ s32 err = 0;
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /*
+ * Powersave enable/disable request is coming from the
+ * cfg80211 even before the interface is up. In that
+ * scenario, driver will be storing the power save
+ * preference in cfg struct to apply this to
+ * FW later while initializing the dongle
+ */
+ cfg->pwr_save = enabled;
+ if (!check_vif_up(ifp->vif)) {
+
+ brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
+ goto done;
+ }
+
+ pm = enabled ? PM_FAST : PM_OFF;
+ /* Do not enable the power save after assoc if it is a p2p interface */
+ if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
+ brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
+ pm = PM_OFF;
+ }
+ brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
+
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
+ if (err) {
+ if (err == -ENODEV)
+ brcmf_err("net_device is not ready yet\n");
+ else
+ brcmf_err("error (%d)\n", err);
+ }
+done:
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_bss_info_le *bi)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg);
+ struct ieee80211_channel *notify_channel;
+ struct cfg80211_bss *bss;
+ struct ieee80211_supported_band *band;
+ struct brcmu_chan ch;
+ u16 channel;
+ u32 freq;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
+ brcmf_err("Bss info is larger than buffer. Discarding\n");
+ return 0;
+ }
+
+ if (!bi->ctl_ch) {
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
+ bi->ctl_ch = ch.chnum;
+ }
+ channel = bi->ctl_ch;
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
+ brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
+ brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
+ brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
+ brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
+
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ (const u8 *)bi->BSSID,
+ 0, notify_capability,
+ notify_interval, notify_ie,
+ notify_ielen, notify_signal,
+ GFP_KERNEL);
+
+ if (!bss)
+ return -ENOMEM;
+
+ cfg80211_put_bss(wiphy, bss);
+
+ return 0;
+}
+
+static struct brcmf_bss_info_le *
+next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
+{
+ if (bss == NULL)
+ return list->bss_info_le;
+ return (struct brcmf_bss_info_le *)((unsigned long)bss +
+ le32_to_cpu(bss->length));
+}
+
+static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_scan_results *bss_list;
+ struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
+ s32 err = 0;
+ int i;
+
+ bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
+ if (bss_list->count != 0 &&
+ bss_list->version != BRCMF_BSS_INFO_VERSION) {
+ brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
+ bss_list->version);
+ return -EOPNOTSUPP;
+ }
+ brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
+ for (i = 0; i < bss_list->count; i++) {
+ bi = next_bss_le(bss_list, bi);
+ err = brcmf_inform_single_bss(cfg, bi);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev, const u8 *bssid)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg);
+ struct ieee80211_channel *notify_channel;
+ struct brcmf_bss_info_le *bi = NULL;
+ struct ieee80211_supported_band *band;
+ struct cfg80211_bss *bss;
+ struct brcmu_chan ch;
+ u8 *buf = NULL;
+ s32 err = 0;
+ u32 freq;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto CleanUp;
+ }
+
+ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+
+ err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
+ buf, WL_BSS_INFO_MAX);
+ if (err) {
+ brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
+ goto CleanUp;
+ }
+
+ bi = (struct brcmf_bss_info_le *)(buf + 4);
+
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
+
+ if (ch.band == BRCMU_CHAN_BAND_2G)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
+ brcmf_dbg(CONN, "capability: %X\n", notify_capability);
+ brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
+ brcmf_dbg(CONN, "signal: %d\n", notify_signal);
+
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
+ notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal,
+ GFP_KERNEL);
+
+ if (!bss) {
+ err = -ENOMEM;
+ goto CleanUp;
+ }
+
+ cfg80211_put_bss(wiphy, bss);
+
+CleanUp:
+
+ kfree(buf);
+
+ brcmf_dbg(TRACE, "Exit\n");
+
+ return err;
+}
+
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp)
+{
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
+ struct brcmf_bss_info_le *bi;
+ struct brcmf_ssid *ssid;
+ const struct brcmf_tlv *tim;
+ u16 beacon_interval;
+ u8 dtim_period;
+ size_t ie_len;
+ u8 *ie;
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (brcmf_is_ibssmode(ifp->vif))
+ return err;
+
+ ssid = &profile->ssid;
+
+ *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+ cfg->extra_buf, WL_EXTRA_BUF_MAX);
+ if (err) {
+ brcmf_err("Could not get bss info %d\n", err);
+ goto update_bss_info_out;
+ }
+
+ bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
+ err = brcmf_inform_single_bss(cfg, bi);
+ if (err)
+ goto update_bss_info_out;
+
+ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+ ie_len = le32_to_cpu(bi->ie_length);
+ beacon_interval = le16_to_cpu(bi->beacon_period);
+
+ tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
+ if (tim)
+ dtim_period = tim->data[1];
+ else {
+ /*
+ * active scan was done so we could not get dtim
+ * information out of probe response.
+ * so we speficially query dtim information to dongle.
+ */
+ u32 var;
+ err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
+ if (err) {
+ brcmf_err("wl dtim_assoc failed (%d)\n", err);
+ goto update_bss_info_out;
+ }
+ dtim_period = (u8)var;
+ }
+
+update_bss_info_out:
+ brcmf_dbg(TRACE, "Exit");
+ return err;
+}
+
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
+{
+ struct escan_info *escan = &cfg->escan_info;
+
+ set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
+ if (cfg->scan_request) {
+ escan->escan_state = WL_ESCAN_STATE_IDLE;
+ brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
+ }
+ clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+ clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
+}
+
+static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
+{
+ struct brcmf_cfg80211_info *cfg =
+ container_of(work, struct brcmf_cfg80211_info,
+ escan_timeout_work);
+
+ brcmf_inform_bss(cfg);
+ brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
+}
+
+static void brcmf_escan_timeout(unsigned long data)
+{
+ struct brcmf_cfg80211_info *cfg =
+ (struct brcmf_cfg80211_info *)data;
+
+ if (cfg->scan_request) {
+ brcmf_err("timer expired\n");
+ schedule_work(&cfg->escan_timeout_work);
+ }
+}
+
+static s32
+brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_bss_info_le *bss,
+ struct brcmf_bss_info_le *bss_info_le)
+{
+ struct brcmu_chan ch_bss, ch_bss_info_le;
+
+ ch_bss.chspec = le16_to_cpu(bss->chanspec);
+ cfg->d11inf.decchspec(&ch_bss);
+ ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
+ cfg->d11inf.decchspec(&ch_bss_info_le);
+
+ if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
+ ch_bss.band == ch_bss_info_le.band &&
+ bss_info_le->SSID_len == bss->SSID_len &&
+ !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
+ if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
+ (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
+ s16 bss_rssi = le16_to_cpu(bss->RSSI);
+ s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
+
+ /* preserve max RSSI if the measurements are
+ * both on-channel or both off-channel
+ */
+ if (bss_info_rssi > bss_rssi)
+ bss->RSSI = bss_info_le->RSSI;
+ } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
+ (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
+ /* preserve the on-channel rssi measurement
+ * if the new measurement is off channel
+ */
+ bss->RSSI = bss_info_le->RSSI;
+ bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static s32
+brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ s32 status;
+ struct brcmf_escan_result_le *escan_result_le;
+ struct brcmf_bss_info_le *bss_info_le;
+ struct brcmf_bss_info_le *bss = NULL;
+ u32 bi_length;
+ struct brcmf_scan_results *list;
+ u32 i;
+ bool aborted;
+
+ status = e->status;
+
+ if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
+ return -EPERM;
+ }
+
+ if (status == BRCMF_E_STATUS_PARTIAL) {
+ brcmf_dbg(SCAN, "ESCAN Partial result\n");
+ escan_result_le = (struct brcmf_escan_result_le *) data;
+ if (!escan_result_le) {
+ brcmf_err("Invalid escan result (NULL pointer)\n");
+ goto exit;
+ }
+ if (le16_to_cpu(escan_result_le->bss_count) != 1) {
+ brcmf_err("Invalid bss_count %d: ignoring\n",
+ escan_result_le->bss_count);
+ goto exit;
+ }
+ bss_info_le = &escan_result_le->bss_info_le;
+
+ if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
+ goto exit;
+
+ if (!cfg->scan_request) {
+ brcmf_dbg(SCAN, "result without cfg80211 request\n");
+ goto exit;
+ }
+
+ bi_length = le32_to_cpu(bss_info_le->length);
+ if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
+ WL_ESCAN_RESULTS_FIXED_SIZE)) {
+ brcmf_err("Invalid bss_info length %d: ignoring\n",
+ bi_length);
+ goto exit;
+ }
+
+ if (!(cfg_to_wiphy(cfg)->interface_modes &
+ BIT(NL80211_IFTYPE_ADHOC))) {
+ if (le16_to_cpu(bss_info_le->capability) &
+ WLAN_CAPABILITY_IBSS) {
+ brcmf_err("Ignoring IBSS result\n");
+ goto exit;
+ }
+ }
+
+ list = (struct brcmf_scan_results *)
+ cfg->escan_info.escan_buf;
+ if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
+ brcmf_err("Buffer is too small: ignoring\n");
+ goto exit;
+ }
+
+ for (i = 0; i < list->count; i++) {
+ bss = bss ? (struct brcmf_bss_info_le *)
+ ((unsigned char *)bss +
+ le32_to_cpu(bss->length)) : list->bss_info_le;
+ if (brcmf_compare_update_same_bss(cfg, bss,
+ bss_info_le))
+ goto exit;
+ }
+ memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
+ bss_info_le, bi_length);
+ list->version = le32_to_cpu(bss_info_le->version);
+ list->buflen += bi_length;
+ list->count++;
+ } else {
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
+ goto exit;
+ if (cfg->scan_request) {
+ brcmf_inform_bss(cfg);
+ aborted = status != BRCMF_E_STATUS_SUCCESS;
+ brcmf_notify_escan_complete(cfg, ifp, aborted, false);
+ } else
+ brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
+ status);
+ }
+exit:
+ return 0;
+}
+
+static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
+{
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
+ brcmf_cfg80211_escan_handler);
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ /* Init scan_timeout timer */
+ init_timer(&cfg->escan_timeout);
+ cfg->escan_timeout.data = (unsigned long) cfg;
+ cfg->escan_timeout.function = brcmf_escan_timeout;
+ INIT_WORK(&cfg->escan_timeout_work,
+ brcmf_cfg80211_escan_timeout_worker);
+}
+
+static __always_inline void brcmf_delay(u32 ms)
+{
+ if (ms < 1000 / HZ) {
+ cond_resched();
+ mdelay(ms);
+ } else {
+ msleep(ms);
+ }
+}
+
+static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
+ u8 *pattern, u32 patternsize, u8 *mask,
+ u32 packet_offset)
+{
+ struct brcmf_fil_wowl_pattern_le *filter;
+ u32 masksize;
+ u32 patternoffset;
+ u8 *buf;
+ u32 bufsize;
+ s32 ret;
+
+ masksize = (patternsize + 7) / 8;
+ patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
+
+ bufsize = sizeof(*filter) + patternsize + masksize;
+ buf = kzalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ filter = (struct brcmf_fil_wowl_pattern_le *)buf;
+
+ memcpy(filter->cmd, cmd, 4);
+ filter->masksize = cpu_to_le32(masksize);
+ filter->offset = cpu_to_le32(packet_offset);
+ filter->patternoffset = cpu_to_le32(patternoffset);
+ filter->patternsize = cpu_to_le32(patternsize);
+ filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
+
+ if ((mask) && (masksize))
+ memcpy(buf + sizeof(*filter), mask, masksize);
+ if ((pattern) && (patternsize))
+ memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
+
+ ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
+
+ kfree(buf);
+ return ret;
+}
+
+static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (cfg->wowl_enabled) {
+ brcmf_configure_arp_offload(ifp, true);
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
+ cfg->pre_wowl_pmmode);
+ brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
+ brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
+ cfg->wowl_enabled = false;
+ }
+ return 0;
+}
+
+static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp,
+ struct cfg80211_wowlan *wowl)
+{
+ u32 wowl_config;
+ u32 i;
+
+ brcmf_dbg(TRACE, "Suspend, wowl config.\n");
+
+ brcmf_configure_arp_offload(ifp, false);
+ brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
+
+ wowl_config = 0;
+ if (wowl->disconnect)
+ wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
+ if (wowl->magic_pkt)
+ wowl_config |= BRCMF_WOWL_MAGIC;
+ if ((wowl->patterns) && (wowl->n_patterns)) {
+ wowl_config |= BRCMF_WOWL_NET;
+ for (i = 0; i < wowl->n_patterns; i++) {
+ brcmf_config_wowl_pattern(ifp, "add",
+ (u8 *)wowl->patterns[i].pattern,
+ wowl->patterns[i].pattern_len,
+ (u8 *)wowl->patterns[i].mask,
+ wowl->patterns[i].pkt_offset);
+ }
+ }
+ brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
+ brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
+ brcmf_bus_wowl_config(cfg->pub->bus_if, true);
+ cfg->wowl_enabled = true;
+}
+
+static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wowl)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_vif *vif;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* if the primary net_device is not READY there is nothing
+ * we can do but pray resume goes smoothly.
+ */
+ if (!check_vif_up(ifp->vif))
+ goto exit;
+
+ /* end any scanning */
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+ brcmf_abort_scanning(cfg);
+
+ if (wowl == NULL) {
+ brcmf_bus_wowl_config(cfg->pub->bus_if, false);
+ list_for_each_entry(vif, &cfg->vif_list, list) {
+ if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
+ continue;
+ /* While going to suspend if associated with AP
+ * disassociate from AP to save power while system is
+ * in suspended state
+ */
+ brcmf_link_down(vif);
+ /* Make sure WPA_Supplicant receives all the event
+ * generated due to DISASSOC call to the fw to keep
+ * the state fw and WPA_Supplicant state consistent
+ */
+ brcmf_delay(500);
+ }
+ /* Configure MPC */
+ brcmf_set_mpc(ifp, 1);
+
+ } else {
+ /* Configure WOWL paramaters */
+ brcmf_configure_wowl(cfg, ifp, wowl);
+ }
+
+exit:
+ brcmf_dbg(TRACE, "Exit\n");
+ /* clear any scanning activity */
+ cfg->scan_status = 0;
+ return 0;
+}
+
+static __used s32
+brcmf_update_pmklist(struct net_device *ndev,
+ struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
+{
+ int i, j;
+ int pmkid_len;
+
+ pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
+
+ brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
+ for (i = 0; i < pmkid_len; i++) {
+ brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
+ &pmk_list->pmkids.pmkid[i].BSSID);
+ for (j = 0; j < WLAN_PMKID_LEN; j++)
+ brcmf_dbg(CONN, "%02x\n",
+ pmk_list->pmkids.pmkid[i].PMKID[j]);
+ }
+
+ if (!err)
+ brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
+ (char *)pmk_list, sizeof(*pmk_list));
+
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
+ s32 err = 0;
+ int i;
+ int pmkid_len;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ pmkid_len = le32_to_cpu(pmkids->npmkid);
+ for (i = 0; i < pmkid_len; i++)
+ if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
+ break;
+ if (i < WL_NUM_PMKIDS_MAX) {
+ memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
+ memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
+ if (i == pmkid_len) {
+ pmkid_len++;
+ pmkids->npmkid = cpu_to_le32(pmkid_len);
+ }
+ } else
+ err = -EINVAL;
+
+ brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
+ pmkids->pmkid[pmkid_len].BSSID);
+ for (i = 0; i < WLAN_PMKID_LEN; i++)
+ brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
+
+ err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct pmkid_list pmkid;
+ s32 err = 0;
+ int i, pmkid_len;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
+ memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
+
+ brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
+ &pmkid.pmkid[0].BSSID);
+ for (i = 0; i < WLAN_PMKID_LEN; i++)
+ brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
+
+ pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
+ for (i = 0; i < pmkid_len; i++)
+ if (!memcmp
+ (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ ETH_ALEN))
+ break;
+
+ if ((pmkid_len > 0)
+ && (i < pmkid_len)) {
+ memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
+ sizeof(struct pmkid));
+ for (; i < (pmkid_len - 1); i++) {
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
+ ETH_ALEN);
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
+ WLAN_PMKID_LEN);
+ }
+ cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
+ } else
+ err = -EINVAL;
+
+ err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+
+}
+
+static s32
+brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
+ err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+
+}
+
+/*
+ * PFN result doesn't have all the info which are
+ * required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+static s32
+brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
+ struct cfg80211_scan_request *request = NULL;
+ struct cfg80211_ssid *ssid = NULL;
+ struct ieee80211_channel *channel = NULL;
+ struct wiphy *wiphy = cfg_to_wiphy(cfg);
+ int err = 0;
+ int channel_req = 0;
+ int band = 0;
+ struct brcmf_pno_scanresults_le *pfn_result;
+ u32 result_count;
+ u32 status;
+
+ brcmf_dbg(SCAN, "Enter\n");
+
+ if (e->event_code == BRCMF_E_PFN_NET_LOST) {
+ brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
+ return 0;
+ }
+
+ pfn_result = (struct brcmf_pno_scanresults_le *)data;
+ result_count = le32_to_cpu(pfn_result->count);
+ status = le32_to_cpu(pfn_result->status);
+
+ /*
+ * PFN event is limited to fit 512 bytes so we may get
+ * multiple NET_FOUND events. For now place a warning here.
+ */
+ WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
+ brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
+ if (result_count > 0) {
+ int i;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
+ channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
+ if (!request || !ssid || !channel) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ request->wiphy = wiphy;
+ data += sizeof(struct brcmf_pno_scanresults_le);
+ netinfo_start = (struct brcmf_pno_net_info_le *)data;
+
+ for (i = 0; i < result_count; i++) {
+ netinfo = &netinfo_start[i];
+ if (!netinfo) {
+ brcmf_err("Invalid netinfo ptr. index: %d\n",
+ i);
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
+ netinfo->SSID, netinfo->channel);
+ memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
+ ssid[i].ssid_len = netinfo->SSID_len;
+ request->n_ssids++;
+
+ channel_req = netinfo->channel;
+ if (channel_req <= CH_MAX_2G_CHANNEL)
+ band = NL80211_BAND_2GHZ;
+ else
+ band = NL80211_BAND_5GHZ;
+ channel[i].center_freq =
+ ieee80211_channel_to_frequency(channel_req,
+ band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request->channels[i] = &channel[i];
+ request->n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request->n_ssids)
+ request->ssids = &ssid[0];
+
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ /* Abort any on-going scan */
+ brcmf_abort_scanning(cfg);
+ }
+
+ set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+ cfg->escan_info.run = brcmf_run_escan;
+ err = brcmf_do_escan(cfg, wiphy, ifp, request);
+ if (err) {
+ clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+ goto out_err;
+ }
+ cfg->sched_escan = true;
+ cfg->scan_request = request;
+ } else {
+ brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
+ goto out_err;
+ }
+
+ kfree(ssid);
+ kfree(channel);
+ kfree(request);
+ return 0;
+
+out_err:
+ kfree(ssid);
+ kfree(channel);
+ kfree(request);
+ cfg80211_sched_scan_stopped(wiphy);
+ return err;
+}
+
+static int brcmf_dev_pno_clean(struct net_device *ndev)
+{
+ int ret;
+
+ /* Disable pfn */
+ ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
+ if (ret == 0) {
+ /* clear pfn */
+ ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
+ NULL, 0);
+ }
+ if (ret < 0)
+ brcmf_err("failed code %d\n", ret);
+
+ return ret;
+}
+
+static int brcmf_dev_pno_config(struct net_device *ndev)
+{
+ struct brcmf_pno_param_le pfn_param;
+
+ memset(&pfn_param, 0, sizeof(pfn_param));
+ pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
+
+ /* set extra pno params */
+ pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
+ pfn_param.repeat = BRCMF_PNO_REPEAT;
+ pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
+
+ /* set up pno scan fr */
+ pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
+
+ return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
+ &pfn_param, sizeof(pfn_param));
+}
+
+static int
+brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_sched_scan_request *request)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_pno_net_param_le pfn;
+ int i;
+ int ret = 0;
+
+ brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
+ request->n_match_sets, request->n_ssids);
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
+ return -EAGAIN;
+ }
+ if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
+ brcmf_err("Scanning suppressed: status (%lu)\n",
+ cfg->scan_status);
+ return -EAGAIN;
+ }
+
+ if (!request->n_ssids || !request->n_match_sets) {
+ brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
+ request->n_ssids);
+ return -EINVAL;
+ }
+
+ if (request->n_ssids > 0) {
+ for (i = 0; i < request->n_ssids; i++) {
+ /* Active scan req for ssids */
+ brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
+ request->ssids[i].ssid);
+
+ /*
+ * match_set ssids is a supert set of n_ssid list,
+ * so we need not add these set seperately.
+ */
+ }
+ }
+
+ if (request->n_match_sets > 0) {
+ /* clean up everything */
+ ret = brcmf_dev_pno_clean(ndev);
+ if (ret < 0) {
+ brcmf_err("failed error=%d\n", ret);
+ return ret;
+ }
+
+ /* configure pno */
+ ret = brcmf_dev_pno_config(ndev);
+ if (ret < 0) {
+ brcmf_err("PNO setup failed!! ret=%d\n", ret);
+ return -EINVAL;
+ }
+
+ /* configure each match set */
+ for (i = 0; i < request->n_match_sets; i++) {
+ struct cfg80211_ssid *ssid;
+ u32 ssid_len;
+
+ ssid = &request->match_sets[i].ssid;
+ ssid_len = ssid->ssid_len;
+
+ if (!ssid_len) {
+ brcmf_err("skip broadcast ssid\n");
+ continue;
+ }
+ pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
+ pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
+ pfn.wsec = cpu_to_le32(0);
+ pfn.infra = cpu_to_le32(1);
+ pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
+ pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
+ memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
+ ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
+ sizeof(pfn));
+ brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
+ ret == 0 ? "set" : "failed", ssid->ssid);
+ }
+ /* Enable the PNO */
+ if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
+ brcmf_err("PNO enable failed!! ret=%d\n", ret);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
+ struct net_device *ndev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+
+ brcmf_dbg(SCAN, "enter\n");
+ brcmf_dev_pno_clean(ndev);
+ if (cfg->sched_escan)
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
+ return 0;
+}
+
+static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
+{
+ s32 err;
+
+ /* set auth */
+ err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
+ if (err < 0) {
+ brcmf_err("auth error %d\n", err);
+ return err;
+ }
+ /* set wsec */
+ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
+ if (err < 0) {
+ brcmf_err("wsec error %d\n", err);
+ return err;
+ }
+ /* set upper-layer auth */
+ err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
+ if (err < 0) {
+ brcmf_err("wpa_auth error %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
+{
+ if (is_rsn_ie)
+ return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
+
+ return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
+}
+
+static s32
+brcmf_configure_wpaie(struct net_device *ndev,
+ const struct brcmf_vs_tlv *wpa_ie,
+ bool is_rsn_ie)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ u32 auth = 0; /* d11 open authentication */
+ u16 count;
+ s32 err = 0;
+ s32 len = 0;
+ u32 i;
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ u32 offset;
+ u8 *data;
+ u16 rsn_cap;
+ u32 wme_bss_disable;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (wpa_ie == NULL)
+ goto exit;
+
+ len = wpa_ie->len + TLV_HDR_LEN;
+ data = (u8 *)wpa_ie;
+ offset = TLV_HDR_LEN;
+ if (!is_rsn_ie)
+ offset += VS_IE_FIXED_HDR_LEN;
+ else
+ offset += WPA_IE_VERSION_LEN;
+
+ /* check for multicast cipher suite */
+ if (offset + WPA_IE_MIN_OUI_LEN > len) {
+ err = -EINVAL;
+ brcmf_err("no multicast cipher suite\n");
+ goto exit;
+ }
+
+ if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
+ err = -EINVAL;
+ brcmf_err("ivalid OUI\n");
+ goto exit;
+ }
+ offset += TLV_OUI_LEN;
+
+ /* pick up multicast cipher */
+ switch (data[offset]) {
+ case WPA_CIPHER_NONE:
+ gval = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ gval = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ gval = AES_ENABLED;
+ break;
+ default:
+ err = -EINVAL;
+ brcmf_err("Invalid multi cast cipher info\n");
+ goto exit;
+ }
+
+ offset++;
+ /* walk thru unicast cipher list and pick up what we recognize */
+ count = data[offset] + (data[offset + 1] << 8);
+ offset += WPA_IE_SUITE_COUNT_LEN;
+ /* Check for unicast suite(s) */
+ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
+ err = -EINVAL;
+ brcmf_err("no unicast cipher suite\n");
+ goto exit;
+ }
+ for (i = 0; i < count; i++) {
+ if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
+ err = -EINVAL;
+ brcmf_err("ivalid OUI\n");
+ goto exit;
+ }
+ offset += TLV_OUI_LEN;
+ switch (data[offset]) {
+ case WPA_CIPHER_NONE:
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ pval |= WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ pval |= TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ pval |= AES_ENABLED;
+ break;
+ default:
+ brcmf_err("Ivalid unicast security info\n");
+ }
+ offset++;
+ }
+ /* walk thru auth management suite list and pick up what we recognize */
+ count = data[offset] + (data[offset + 1] << 8);
+ offset += WPA_IE_SUITE_COUNT_LEN;
+ /* Check for auth key management suite(s) */
+ if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
+ err = -EINVAL;
+ brcmf_err("no auth key mgmt suite\n");
+ goto exit;
+ }
+ for (i = 0; i < count; i++) {
+ if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
+ err = -EINVAL;
+ brcmf_err("ivalid OUI\n");
+ goto exit;
+ }
+ offset += TLV_OUI_LEN;
+ switch (data[offset]) {
+ case RSN_AKM_NONE:
+ brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
+ wpa_auth |= WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
+ is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
+ (wpa_auth |= WPA_AUTH_UNSPECIFIED);
+ break;
+ case RSN_AKM_PSK:
+ brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
+ is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
+ (wpa_auth |= WPA_AUTH_PSK);
+ break;
+ default:
+ brcmf_err("Ivalid key mgmt info\n");
+ }
+ offset++;
+ }
+
+ if (is_rsn_ie) {
+ wme_bss_disable = 1;
+ if ((offset + RSN_CAP_LEN) <= len) {
+ rsn_cap = data[offset] + (data[offset + 1] << 8);
+ if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
+ wme_bss_disable = 0;
+ }
+ /* set wme_bss_disable to sync RSN Capabilities */
+ err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
+ wme_bss_disable);
+ if (err < 0) {
+ brcmf_err("wme_bss_disable error %d\n", err);
+ goto exit;
+ }
+ }
+ /* FOR WPS , set SES_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+
+ /* set auth */
+ err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
+ if (err < 0) {
+ brcmf_err("auth error %d\n", err);
+ goto exit;
+ }
+ /* set wsec */
+ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
+ if (err < 0) {
+ brcmf_err("wsec error %d\n", err);
+ goto exit;
+ }
+ /* set upper-layer auth */
+ err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
+ if (err < 0) {
+ brcmf_err("wpa_auth error %d\n", err);
+ goto exit;
+ }
+
+exit:
+ return err;
+}
+
+static s32
+brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
+ struct parsed_vndr_ies *vndr_ies)
+{
+ struct brcmf_vs_tlv *vndrie;
+ struct brcmf_tlv *ie;
+ struct parsed_vndr_ie_info *parsed_info;
+ s32 remaining_len;
+
+ remaining_len = (s32)vndr_ie_len;
+ memset(vndr_ies, 0, sizeof(*vndr_ies));
+
+ ie = (struct brcmf_tlv *)vndr_ie_buf;
+ while (ie) {
+ if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
+ goto next;
+ vndrie = (struct brcmf_vs_tlv *)ie;
+ /* len should be bigger than OUI length + one */
+ if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
+ brcmf_err("invalid vndr ie. length is too small %d\n",
+ vndrie->len);
+ goto next;
+ }
+ /* if wpa or wme ie, do not add ie */
+ if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
+ ((vndrie->oui_type == WPA_OUI_TYPE) ||
+ (vndrie->oui_type == WME_OUI_TYPE))) {
+ brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
+ goto next;
+ }
+
+ parsed_info = &vndr_ies->ie_info[vndr_ies->count];
+
+ /* save vndr ie information */
+ parsed_info->ie_ptr = (char *)vndrie;
+ parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
+ memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
+
+ vndr_ies->count++;
+
+ brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
+ parsed_info->vndrie.oui[0],
+ parsed_info->vndrie.oui[1],
+ parsed_info->vndrie.oui[2],
+ parsed_info->vndrie.oui_type);
+
+ if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
+ break;
+next:
+ remaining_len -= (ie->len + TLV_HDR_LEN);
+ if (remaining_len <= TLV_HDR_LEN)
+ ie = NULL;
+ else
+ ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
+ TLV_HDR_LEN);
+ }
+ return 0;
+}
+
+static u32
+brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
+{
+
+ __le32 iecount_le;
+ __le32 pktflag_le;
+
+ strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
+ iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ iecount_le = cpu_to_le32(1);
+ memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
+
+ pktflag_le = cpu_to_le32(pktflag);
+ memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
+
+ memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
+
+ return ie_len + VNDR_IE_HDR_SIZE;
+}
+
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+ const u8 *vndr_ie_buf, u32 vndr_ie_len)
+{
+ struct brcmf_if *ifp;
+ struct vif_saved_ie *saved_ie;
+ s32 err = 0;
+ u8 *iovar_ie_buf;
+ u8 *curr_ie_buf;
+ u8 *mgmt_ie_buf = NULL;
+ int mgmt_ie_buf_len;
+ u32 *mgmt_ie_len;
+ u32 del_add_ie_buf_len = 0;
+ u32 total_ie_buf_len = 0;
+ u32 parsed_ie_buf_len = 0;
+ struct parsed_vndr_ies old_vndr_ies;
+ struct parsed_vndr_ies new_vndr_ies;
+ struct parsed_vndr_ie_info *vndrie_info;
+ s32 i;
+ u8 *ptr;
+ int remained_buf_len;
+
+ if (!vif)
+ return -ENODEV;
+ ifp = vif->ifp;
+ saved_ie = &vif->saved_ie;
+
+ brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
+ iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (!iovar_ie_buf)
+ return -ENOMEM;
+ curr_ie_buf = iovar_ie_buf;
+ switch (pktflag) {
+ case BRCMF_VNDR_IE_PRBREQ_FLAG:
+ mgmt_ie_buf = saved_ie->probe_req_ie;
+ mgmt_ie_len = &saved_ie->probe_req_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
+ break;
+ case BRCMF_VNDR_IE_PRBRSP_FLAG:
+ mgmt_ie_buf = saved_ie->probe_res_ie;
+ mgmt_ie_len = &saved_ie->probe_res_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
+ break;
+ case BRCMF_VNDR_IE_BEACON_FLAG:
+ mgmt_ie_buf = saved_ie->beacon_ie;
+ mgmt_ie_len = &saved_ie->beacon_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
+ break;
+ case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
+ mgmt_ie_buf = saved_ie->assoc_req_ie;
+ mgmt_ie_len = &saved_ie->assoc_req_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
+ break;
+ default:
+ err = -EPERM;
+ brcmf_err("not suitable type\n");
+ goto exit;
+ }
+
+ if (vndr_ie_len > mgmt_ie_buf_len) {
+ err = -ENOMEM;
+ brcmf_err("extra IE size too big\n");
+ goto exit;
+ }
+
+ /* parse and save new vndr_ie in curr_ie_buff before comparing it */
+ if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
+ ptr = curr_ie_buf;
+ brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ vndrie_info = &new_vndr_ies.ie_info[i];
+ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ parsed_ie_buf_len += vndrie_info->ie_len;
+ }
+ }
+
+ if (mgmt_ie_buf && *mgmt_ie_len) {
+ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
+ (memcmp(mgmt_ie_buf, curr_ie_buf,
+ parsed_ie_buf_len) == 0)) {
+ brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
+ goto exit;
+ }
+
+ /* parse old vndr_ie */
+ brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
+
+ /* make a command to delete old ie */
+ for (i = 0; i < old_vndr_ies.count; i++) {
+ vndrie_info = &old_vndr_ies.ie_info[i];
+
+ brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id,
+ vndrie_info->vndrie.len,
+ vndrie_info->vndrie.oui[0],
+ vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]);
+
+ del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
+ vndrie_info->ie_ptr,
+ vndrie_info->ie_len,
+ "del");
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+
+ *mgmt_ie_len = 0;
+ /* Add if there is any extra IE */
+ if (mgmt_ie_buf && parsed_ie_buf_len) {
+ ptr = mgmt_ie_buf;
+
+ remained_buf_len = mgmt_ie_buf_len;
+
+ /* make a command to add new ie */
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ vndrie_info = &new_vndr_ies.ie_info[i];
+
+ /* verify remained buf size before copy data */
+ if (remained_buf_len < (vndrie_info->vndrie.len +
+ VNDR_IE_VSIE_OFFSET)) {
+ brcmf_err("no space in mgmt_ie_buf: len left %d",
+ remained_buf_len);
+ break;
+ }
+ remained_buf_len -= (vndrie_info->ie_len +
+ VNDR_IE_VSIE_OFFSET);
+
+ brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id,
+ vndrie_info->vndrie.len,
+ vndrie_info->vndrie.oui[0],
+ vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]);
+
+ del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
+ vndrie_info->ie_ptr,
+ vndrie_info->ie_len,
+ "add");
+
+ /* save the parsed IE in wl struct */
+ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ *mgmt_ie_len += vndrie_info->ie_len;
+
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+ if (total_ie_buf_len) {
+ err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
+ total_ie_buf_len);
+ if (err)
+ brcmf_err("vndr ie set error : %d\n", err);
+ }
+
+exit:
+ kfree(iovar_ie_buf);
+ return err;
+}
+
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
+{
+ s32 pktflags[] = {
+ BRCMF_VNDR_IE_PRBREQ_FLAG,
+ BRCMF_VNDR_IE_PRBRSP_FLAG,
+ BRCMF_VNDR_IE_BEACON_FLAG
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pktflags); i++)
+ brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
+
+ memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
+ return 0;
+}
+
+static s32
+brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
+ struct cfg80211_beacon_data *beacon)
+{
+ s32 err;
+
+ /* Set Beacon IEs to FW */
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
+ beacon->tail, beacon->tail_len);
+ if (err) {
+ brcmf_err("Set Beacon IE Failed\n");
+ return err;
+ }
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
+
+ /* Set Probe Response IEs to FW */
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
+ beacon->proberesp_ies,
+ beacon->proberesp_ies_len);
+ if (err)
+ brcmf_err("Set Probe Resp IE Failed\n");
+ else
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+
+ return err;
+}
+
+static s32
+brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_ap_settings *settings)
+{
+ s32 ie_offset;
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ const struct brcmf_tlv *ssid_ie;
+ struct brcmf_ssid_le ssid_le;
+ s32 err = -EPERM;
+ const struct brcmf_tlv *rsn_ie;
+ const struct brcmf_vs_tlv *wpa_ie;
+ struct brcmf_join_params join_params;
+ enum nl80211_iftype dev_role;
+ struct brcmf_fil_bss_enable_le bss_enable;
+ u16 chanspec;
+
+ brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
+ settings->chandef.chan->hw_value,
+ settings->chandef.center_freq1, settings->chandef.width,
+ settings->beacon_interval, settings->dtim_period);
+ brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
+ settings->ssid, settings->ssid_len, settings->auth_type,
+ settings->inactivity_timeout);
+
+ dev_role = ifp->vif->wdev.iftype;
+
+ memset(&ssid_le, 0, sizeof(ssid_le));
+ if (settings->ssid == NULL || settings->ssid_len == 0) {
+ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ ssid_ie = brcmf_parse_tlvs(
+ (u8 *)&settings->beacon.head[ie_offset],
+ settings->beacon.head_len - ie_offset,
+ WLAN_EID_SSID);
+ if (!ssid_ie)
+ return -EINVAL;
+
+ memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
+ ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
+ brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
+ } else {
+ memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
+ ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
+ }
+
+ brcmf_set_mpc(ifp, 0);
+ brcmf_configure_arp_offload(ifp, false);
+
+ /* find the RSN_IE */
+ rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
+ settings->beacon.tail_len, WLAN_EID_RSN);
+
+ /* find the WPA_IE */
+ wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
+ settings->beacon.tail_len);
+
+ if ((wpa_ie != NULL || rsn_ie != NULL)) {
+ brcmf_dbg(TRACE, "WPA(2) IE is found\n");
+ if (wpa_ie != NULL) {
+ /* WPA IE */
+ err = brcmf_configure_wpaie(ndev, wpa_ie, false);
+ if (err < 0)
+ goto exit;
+ } else {
+ /* RSN IE */
+ err = brcmf_configure_wpaie(ndev,
+ (struct brcmf_vs_tlv *)rsn_ie, true);
+ if (err < 0)
+ goto exit;
+ }
+ } else {
+ brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
+ brcmf_configure_opensecurity(ifp);
+ }
+
+ brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
+
+ chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
+ err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
+ if (err < 0) {
+ brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err);
+ goto exit;
+ }
+
+ if (settings->beacon_interval) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
+ settings->beacon_interval);
+ if (err < 0) {
+ brcmf_err("Beacon Interval Set Error, %d\n", err);
+ goto exit;
+ }
+ }
+ if (settings->dtim_period) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
+ settings->dtim_period);
+ if (err < 0) {
+ brcmf_err("DTIM Interval Set Error, %d\n", err);
+ goto exit;
+ }
+ }
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
+ if (err < 0) {
+ brcmf_err("BRCMF_C_DOWN error %d\n", err);
+ goto exit;
+ }
+ brcmf_fil_iovar_int_set(ifp, "apsta", 0);
+ }
+
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
+ if (err < 0) {
+ brcmf_err("SET INFRA error %d\n", err);
+ goto exit;
+ }
+ if (dev_role == NL80211_IFTYPE_AP) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
+ if (err < 0) {
+ brcmf_err("setting AP mode failed %d\n", err);
+ goto exit;
+ }
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+ if (err < 0) {
+ brcmf_err("BRCMF_C_UP error (%d)\n", err);
+ goto exit;
+ }
+
+ memset(&join_params, 0, sizeof(join_params));
+ /* join parameters starts with ssid */
+ memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
+ /* create softap */
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, sizeof(join_params));
+ if (err < 0) {
+ brcmf_err("SET SSID error (%d)\n", err);
+ goto exit;
+ }
+ brcmf_dbg(TRACE, "AP mode configuration complete\n");
+ } else {
+ err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
+ sizeof(ssid_le));
+ if (err < 0) {
+ brcmf_err("setting ssid failed %d\n", err);
+ goto exit;
+ }
+ bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+ bss_enable.enable = cpu_to_le32(1);
+ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+ sizeof(bss_enable));
+ if (err < 0) {
+ brcmf_err("bss_enable config failed %d\n", err);
+ goto exit;
+ }
+
+ brcmf_dbg(TRACE, "GO mode configuration complete\n");
+ }
+ clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+ set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
+exit:
+ if (err) {
+ brcmf_set_mpc(ifp, 1);
+ brcmf_configure_arp_offload(ifp, true);
+ }
+ return err;
+}
+
+static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err;
+ struct brcmf_fil_bss_enable_le bss_enable;
+ struct brcmf_join_params join_params;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
+ /* Due to most likely deauths outstanding we sleep */
+ /* first to make sure they get processed by fw. */
+ msleep(400);
+
+ memset(&join_params, 0, sizeof(join_params));
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, sizeof(join_params));
+ if (err < 0)
+ brcmf_err("SET SSID error (%d)\n", err);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+ if (err < 0)
+ brcmf_err("BRCMF_C_UP error %d\n", err);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
+ if (err < 0)
+ brcmf_err("setting AP mode failed %d\n", err);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
+ if (err < 0)
+ brcmf_err("setting INFRA mode failed %d\n", err);
+ } else {
+ bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+ bss_enable.enable = cpu_to_le32(0);
+ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+ sizeof(bss_enable));
+ if (err < 0)
+ brcmf_err("bss_enable config failed %d\n", err);
+ }
+ brcmf_set_mpc(ifp, 1);
+ brcmf_configure_arp_offload(ifp, true);
+ set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+ clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
+ return err;
+}
+
+static s32
+brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_beacon_data *info)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
+
+ return err;
+}
+
+static int
+brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
+ struct station_del_parameters *params)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_scb_val_le scbval;
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err;
+
+ if (!params->mac)
+ return -EFAULT;
+
+ brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
+
+ if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+ memcpy(&scbval.ea, params->mac, ETH_ALEN);
+ scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
+ &scbval, sizeof(scbval));
+ if (err)
+ brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+
+static void
+brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u16 frame_type, bool reg)
+{
+ struct brcmf_cfg80211_vif *vif;
+ u16 mgmt_type;
+
+ brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
+
+ mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ if (reg)
+ vif->mgmt_rx_reg |= BIT(mgmt_type);
+ else
+ vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+}
+
+
+static int
+brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct cfg80211_mgmt_tx_params *params, u64 *cookie)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct ieee80211_channel *chan = params->chan;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+ const struct ieee80211_mgmt *mgmt;
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
+ s32 ie_offset;
+ s32 ie_len;
+ struct brcmf_fil_action_frame_le *action_frame;
+ struct brcmf_fil_af_params_le *af_params;
+ bool ack;
+ s32 chan_nr;
+ u32 freq;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ *cookie = 0;
+
+ mgmt = (const struct ieee80211_mgmt *)buf;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control)) {
+ brcmf_err("Driver only allows MGMT packet type\n");
+ return -EPERM;
+ }
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+ /* Right now the only reason to get a probe response */
+ /* is for p2p listen response or for p2p GO from */
+ /* wpa_supplicant. Unfortunately the probe is send */
+ /* on primary ndev, while dongle wants it on the p2p */
+ /* vif. Since this is only reason for a probe */
+ /* response to be sent, the vif is taken from cfg. */
+ /* If ever desired to send proberesp for non p2p */
+ /* response then data should be checked for */
+ /* "DIRECT-". Note in future supplicant will take */
+ /* dedicated p2p wdev to do this and then this 'hack'*/
+ /* is not needed anymore. */
+ ie_offset = DOT11_MGMT_HDR_LEN +
+ DOT11_BCN_PRB_FIXED_LEN;
+ ie_len = len - ie_offset;
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ err = brcmf_vif_set_mgmt_ie(vif,
+ BRCMF_VNDR_IE_PRBRSP_FLAG,
+ &buf[ie_offset],
+ ie_len);
+ cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
+ GFP_KERNEL);
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
+ if (af_params == NULL) {
+ brcmf_err("unable to allocate frame\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ action_frame = &af_params->action_frame;
+ /* Add the packet Id */
+ action_frame->packet_id = cpu_to_le32(*cookie);
+ /* Add BSSID */
+ memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
+ memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
+ /* Add the length exepted for 802.11 header */
+ action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
+ /* Add the channel. Use the one specified as parameter if any or
+ * the current one (got from the firmware) otherwise
+ */
+ if (chan)
+ freq = chan->center_freq;
+ else
+ brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
+ &freq);
+ chan_nr = ieee80211_frequency_to_channel(freq);
+ af_params->channel = cpu_to_le32(chan_nr);
+
+ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
+ le16_to_cpu(action_frame->len));
+
+ brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
+ *cookie, le16_to_cpu(action_frame->len), freq);
+
+ ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
+ af_params);
+
+ cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
+ GFP_KERNEL);
+ kfree(af_params);
+ } else {
+ brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
+ brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
+ }
+
+exit:
+ return err;
+}
+
+
+static int
+brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+ int err = 0;
+
+ brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
+
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif == NULL) {
+ brcmf_err("No p2p device available for probe response\n");
+ err = -ENODEV;
+ goto exit;
+ }
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+exit:
+ return err;
+}
+
+static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ enum nl80211_crit_proto_id proto,
+ u16 duration)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ /* only DHCP support for now */
+ if (proto != NL80211_CRIT_PROTO_DHCP)
+ return -EINVAL;
+
+ /* suppress and abort scanning */
+ set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+ brcmf_abort_scanning(cfg);
+
+ return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
+}
+
+static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
+ clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+}
+
+static s32
+brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ switch (e->reason) {
+ case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
+ brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
+ break;
+ case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
+ brcmf_dbg(TRACE, "TDLS Peer Connected\n");
+ brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
+ break;
+ case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
+ brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
+ brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
+ break;
+ }
+
+ return 0;
+}
+
+static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
+{
+ int ret;
+
+ switch (oper) {
+ case NL80211_TDLS_DISCOVERY_REQ:
+ ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
+ break;
+ case NL80211_TDLS_SETUP:
+ ret = BRCMF_TDLS_MANUAL_EP_CREATE;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ ret = BRCMF_TDLS_MANUAL_EP_DELETE;
+ break;
+ default:
+ brcmf_err("unsupported operation: %d\n", oper);
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
+ struct net_device *ndev, const u8 *peer,
+ enum nl80211_tdls_operation oper)
+{
+ struct brcmf_if *ifp;
+ struct brcmf_tdls_iovar_le info;
+ int ret = 0;
+
+ ret = brcmf_convert_nl80211_tdls_oper(oper);
+ if (ret < 0)
+ return ret;
+
+ ifp = netdev_priv(ndev);
+ memset(&info, 0, sizeof(info));
+ info.mode = (u8)ret;
+ if (peer)
+ memcpy(info.ea, peer, ETH_ALEN);
+
+ ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
+ &info, sizeof(info));
+ if (ret < 0)
+ brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
+
+ return ret;
+}
+
+static struct cfg80211_ops wl_cfg80211_ops = {
+ .add_virtual_intf = brcmf_cfg80211_add_iface,
+ .del_virtual_intf = brcmf_cfg80211_del_iface,
+ .change_virtual_intf = brcmf_cfg80211_change_iface,
+ .scan = brcmf_cfg80211_scan,
+ .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
+ .join_ibss = brcmf_cfg80211_join_ibss,
+ .leave_ibss = brcmf_cfg80211_leave_ibss,
+ .get_station = brcmf_cfg80211_get_station,
+ .set_tx_power = brcmf_cfg80211_set_tx_power,
+ .get_tx_power = brcmf_cfg80211_get_tx_power,
+ .add_key = brcmf_cfg80211_add_key,
+ .del_key = brcmf_cfg80211_del_key,
+ .get_key = brcmf_cfg80211_get_key,
+ .set_default_key = brcmf_cfg80211_config_default_key,
+ .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
+ .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
+ .connect = brcmf_cfg80211_connect,
+ .disconnect = brcmf_cfg80211_disconnect,
+ .suspend = brcmf_cfg80211_suspend,
+ .resume = brcmf_cfg80211_resume,
+ .set_pmksa = brcmf_cfg80211_set_pmksa,
+ .del_pmksa = brcmf_cfg80211_del_pmksa,
+ .flush_pmksa = brcmf_cfg80211_flush_pmksa,
+ .start_ap = brcmf_cfg80211_start_ap,
+ .stop_ap = brcmf_cfg80211_stop_ap,
+ .change_beacon = brcmf_cfg80211_change_beacon,
+ .del_station = brcmf_cfg80211_del_station,
+ .sched_scan_start = brcmf_cfg80211_sched_scan_start,
+ .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
+ .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+ .mgmt_tx = brcmf_cfg80211_mgmt_tx,
+ .remain_on_channel = brcmf_p2p_remain_on_channel,
+ .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
+ .start_p2p_device = brcmf_p2p_start_device,
+ .stop_p2p_device = brcmf_p2p_stop_device,
+ .crit_proto_start = brcmf_cfg80211_crit_proto_start,
+ .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
+ .tdls_oper = brcmf_cfg80211_tdls_oper,
+};
+
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+ enum nl80211_iftype type,
+ bool pm_block)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
+ sizeof(*vif));
+ vif = kzalloc(sizeof(*vif), GFP_KERNEL);
+ if (!vif)
+ return ERR_PTR(-ENOMEM);
+
+ vif->wdev.wiphy = cfg->wiphy;
+ vif->wdev.iftype = type;
+
+ vif->pm_block = pm_block;
+ vif->roam_off = -1;
+
+ brcmf_init_prof(&vif->profile);
+
+ list_add_tail(&vif->list, &cfg->vif_list);
+ return vif;
+}
+
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
+{
+ list_del(&vif->list);
+ kfree(vif);
+}
+
+void brcmf_cfg80211_free_netdev(struct net_device *ndev)
+{
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_if *ifp;
+
+ ifp = netdev_priv(ndev);
+ vif = ifp->vif;
+
+ brcmf_free_vif(vif);
+ free_netdev(ndev);
+}
+
+static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
+{
+ u32 event = e->event_code;
+ u32 status = e->status;
+
+ if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
+ brcmf_dbg(CONN, "Processing set ssid\n");
+ return true;
+ }
+
+ return false;
+}
+
+static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
+{
+ u32 event = e->event_code;
+ u16 flags = e->flags;
+
+ if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
+ (event == BRCMF_E_DISASSOC_IND) ||
+ ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
+ brcmf_dbg(CONN, "Processing link down\n");
+ return true;
+ }
+ return false;
+}
+
+static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
+ const struct brcmf_event_msg *e)
+{
+ u32 event = e->event_code;
+ u32 status = e->status;
+
+ if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
+ brcmf_dbg(CONN, "Processing Link %s & no network found\n",
+ e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
+ return true;
+ }
+
+ if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
+ brcmf_dbg(CONN, "Processing connecting & no network found\n");
+ return true;
+ }
+
+ return false;
+}
+
+static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+
+ kfree(conn_info->req_ie);
+ conn_info->req_ie = NULL;
+ conn_info->req_ie_len = 0;
+ kfree(conn_info->resp_ie);
+ conn_info->resp_ie = NULL;
+ conn_info->resp_ie_len = 0;
+}
+
+static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp)
+{
+ struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+ u32 req_len;
+ u32 resp_len;
+ s32 err = 0;
+
+ brcmf_clear_assoc_ies(cfg);
+
+ err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
+ cfg->extra_buf, WL_ASSOC_INFO_MAX);
+ if (err) {
+ brcmf_err("could not get assoc info (%d)\n", err);
+ return err;
+ }
+ assoc_info =
+ (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
+ req_len = le32_to_cpu(assoc_info->req_len);
+ resp_len = le32_to_cpu(assoc_info->resp_len);
+ if (req_len) {
+ err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
+ cfg->extra_buf,
+ WL_ASSOC_INFO_MAX);
+ if (err) {
+ brcmf_err("could not get assoc req (%d)\n", err);
+ return err;
+ }
+ conn_info->req_ie_len = req_len;
+ conn_info->req_ie =
+ kmemdup(cfg->extra_buf, conn_info->req_ie_len,
+ GFP_KERNEL);
+ } else {
+ conn_info->req_ie_len = 0;
+ conn_info->req_ie = NULL;
+ }
+ if (resp_len) {
+ err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
+ cfg->extra_buf,
+ WL_ASSOC_INFO_MAX);
+ if (err) {
+ brcmf_err("could not get assoc resp (%d)\n", err);
+ return err;
+ }
+ conn_info->resp_ie_len = resp_len;
+ conn_info->resp_ie =
+ kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
+ GFP_KERNEL);
+ } else {
+ conn_info->resp_ie_len = 0;
+ conn_info->resp_ie = NULL;
+ }
+ brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
+ conn_info->req_ie_len, conn_info->resp_ie_len);
+
+ return err;
+}
+
+static s32
+brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+ struct wiphy *wiphy = cfg_to_wiphy(cfg);
+ struct ieee80211_channel *notify_channel = NULL;
+ struct ieee80211_supported_band *band;
+ struct brcmf_bss_info_le *bi;
+ struct brcmu_chan ch;
+ u32 freq;
+ s32 err = 0;
+ u8 *buf;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_get_assoc_ies(cfg, ifp);
+ memcpy(profile->bssid, e->addr, ETH_ALEN);
+ brcmf_update_bss_info(cfg, ifp);
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ /* data sent to dongle has to be little endian */
+ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+ buf, WL_BSS_INFO_MAX);
+
+ if (err)
+ goto done;
+
+ bi = (struct brcmf_bss_info_le *)(buf + 4);
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
+
+ if (ch.band == BRCMU_CHAN_BAND_2G)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+done:
+ kfree(buf);
+ cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+ brcmf_dbg(CONN, "Report roaming result\n");
+
+ set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
+ brcmf_dbg(TRACE, "Exit\n");
+ return err;
+}
+
+static s32
+brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev, const struct brcmf_event_msg *e,
+ bool completed)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+ &ifp->vif->sme_state)) {
+ if (completed) {
+ brcmf_get_assoc_ies(cfg, ifp);
+ memcpy(profile->bssid, e->addr, ETH_ALEN);
+ brcmf_update_bss_info(cfg, ifp);
+ set_bit(BRCMF_VIF_STATUS_CONNECTED,
+ &ifp->vif->sme_state);
+ }
+ cfg80211_connect_result(ndev,
+ (u8 *)profile->bssid,
+ conn_info->req_ie,
+ conn_info->req_ie_len,
+ conn_info->resp_ie,
+ conn_info->resp_ie_len,
+ completed ? WLAN_STATUS_SUCCESS :
+ WLAN_STATUS_AUTH_TIMEOUT,
+ GFP_KERNEL);
+ brcmf_dbg(CONN, "Report connect result - connection %s\n",
+ completed ? "succeeded" : "failed");
+ }
+ brcmf_dbg(TRACE, "Exit\n");
+ return 0;
+}
+
+static s32
+brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ static int generation;
+ u32 event = e->event_code;
+ u32 reason = e->reason;
+ struct station_info sinfo;
+
+ brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
+ if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
+ ndev != cfg_to_ndev(cfg)) {
+ brcmf_dbg(CONN, "AP mode link down\n");
+ complete(&cfg->vif_disabled);
+ return 0;
+ }
+
+ if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
+ (reason == BRCMF_E_STATUS_SUCCESS)) {
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ if (!data) {
+ brcmf_err("No IEs present in ASSOC/REASSOC_IND");
+ return -EINVAL;
+ }
+ sinfo.assoc_req_ies = data;
+ sinfo.assoc_req_ies_len = e->datalen;
+ generation++;
+ sinfo.generation = generation;
+ cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
+ } else if ((event == BRCMF_E_DISASSOC_IND) ||
+ (event == BRCMF_E_DEAUTH_IND) ||
+ (event == BRCMF_E_DEAUTH)) {
+ cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
+ }
+ return 0;
+}
+
+static s32
+brcmf_notify_connect_status(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct net_device *ndev = ifp->ndev;
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct ieee80211_channel *chan;
+ s32 err = 0;
+
+ if ((e->event_code == BRCMF_E_DEAUTH) ||
+ (e->event_code == BRCMF_E_DEAUTH_IND) ||
+ (e->event_code == BRCMF_E_DISASSOC_IND) ||
+ ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
+ brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
+ }
+
+ if (brcmf_is_apmode(ifp->vif)) {
+ err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
+ } else if (brcmf_is_linkup(e)) {
+ brcmf_dbg(CONN, "Linkup\n");
+ if (brcmf_is_ibssmode(ifp->vif)) {
+ chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
+ memcpy(profile->bssid, e->addr, ETH_ALEN);
+ wl_inform_ibss(cfg, ndev, e->addr);
+ cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+ &ifp->vif->sme_state);
+ set_bit(BRCMF_VIF_STATUS_CONNECTED,
+ &ifp->vif->sme_state);
+ } else
+ brcmf_bss_connect_done(cfg, ndev, e, true);
+ } else if (brcmf_is_linkdown(e)) {
+ brcmf_dbg(CONN, "Linkdown\n");
+ if (!brcmf_is_ibssmode(ifp->vif)) {
+ brcmf_bss_connect_done(cfg, ndev, e, false);
+ }
+ brcmf_link_down(ifp->vif);
+ brcmf_init_prof(ndev_to_prof(ndev));
+ if (ndev != cfg_to_ndev(cfg))
+ complete(&cfg->vif_disabled);
+ } else if (brcmf_is_nonetwork(cfg, e)) {
+ if (brcmf_is_ibssmode(ifp->vif))
+ clear_bit(BRCMF_VIF_STATUS_CONNECTING,
+ &ifp->vif->sme_state);
+ else
+ brcmf_bss_connect_done(cfg, ndev, e, false);
+ }
+
+ return err;
+}
+
+static s32
+brcmf_notify_roaming_status(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ u32 event = e->event_code;
+ u32 status = e->status;
+
+ if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
+ brcmf_bss_roaming_done(cfg, ifp->ndev, e);
+ else
+ brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
+ }
+
+ return 0;
+}
+
+static s32
+brcmf_notify_mic_status(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ u16 flags = e->flags;
+ enum nl80211_key_type key_type;
+
+ if (flags & BRCMF_EVENT_MSG_GROUP)
+ key_type = NL80211_KEYTYPE_GROUP;
+ else
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
+ NULL, GFP_KERNEL);
+
+ return 0;
+}
+
+static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+ struct brcmf_cfg80211_vif *vif;
+
+ brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
+ ifevent->action, ifevent->flags, ifevent->ifidx,
+ ifevent->bssidx);
+
+ mutex_lock(&event->vif_event_lock);
+ event->action = ifevent->action;
+ vif = event->vif;
+
+ switch (ifevent->action) {
+ case BRCMF_E_IF_ADD:
+ /* waiting process may have timed out */
+ if (!cfg->vif_event.vif) {
+ mutex_unlock(&event->vif_event_lock);
+ return -EBADF;
+ }
+
+ ifp->vif = vif;
+ vif->ifp = ifp;
+ if (ifp->ndev) {
+ vif->wdev.netdev = ifp->ndev;
+ ifp->ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ }
+ mutex_unlock(&event->vif_event_lock);
+ wake_up(&event->vif_wq);
+ return 0;
+
+ case BRCMF_E_IF_DEL:
+ mutex_unlock(&event->vif_event_lock);
+ /* event may not be upon user request */
+ if (brcmf_cfg80211_vif_event_armed(cfg))
+ wake_up(&event->vif_wq);
+ return 0;
+
+ case BRCMF_E_IF_CHANGE:
+ mutex_unlock(&event->vif_event_lock);
+ wake_up(&event->vif_wq);
+ return 0;
+
+ default:
+ mutex_unlock(&event->vif_event_lock);
+ break;
+ }
+ return -EINVAL;
+}
+
+static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
+{
+ conf->frag_threshold = (u32)-1;
+ conf->rts_threshold = (u32)-1;
+ conf->retry_short = (u32)-1;
+ conf->retry_long = (u32)-1;
+ conf->tx_power = -1;
+}
+
+static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
+{
+ brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
+ brcmf_notify_roaming_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
+ brcmf_notify_mic_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
+ brcmf_notify_sched_scan_results);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
+ brcmf_notify_vif_event);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
+ brcmf_p2p_notify_rx_mgmt_p2p_probereq);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
+ brcmf_p2p_notify_listen_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
+ brcmf_p2p_notify_action_frame_rx);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
+ brcmf_p2p_notify_action_tx_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
+ brcmf_p2p_notify_action_tx_complete);
+}
+
+static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
+{
+ kfree(cfg->conf);
+ cfg->conf = NULL;
+ kfree(cfg->escan_ioctl_buf);
+ cfg->escan_ioctl_buf = NULL;
+ kfree(cfg->extra_buf);
+ cfg->extra_buf = NULL;
+ kfree(cfg->pmk_list);
+ cfg->pmk_list = NULL;
+}
+
+static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
+{
+ cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
+ if (!cfg->conf)
+ goto init_priv_mem_out;
+ cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+ if (!cfg->escan_ioctl_buf)
+ goto init_priv_mem_out;
+ cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (!cfg->extra_buf)
+ goto init_priv_mem_out;
+ cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
+ if (!cfg->pmk_list)
+ goto init_priv_mem_out;
+
+ return 0;
+
+init_priv_mem_out:
+ brcmf_deinit_priv_mem(cfg);
+
+ return -ENOMEM;
+}
+
+static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
+{
+ s32 err = 0;
+
+ cfg->scan_request = NULL;
+ cfg->pwr_save = true;
+ cfg->active_scan = true; /* we do active scan per default */
+ cfg->dongle_up = false; /* dongle is not up yet */
+ err = brcmf_init_priv_mem(cfg);
+ if (err)
+ return err;
+ brcmf_register_event_handlers(cfg);
+ mutex_init(&cfg->usr_sync);
+ brcmf_init_escan(cfg);
+ brcmf_init_conf(cfg->conf);
+ init_completion(&cfg->vif_disabled);
+ return err;
+}
+
+static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
+{
+ cfg->dongle_up = false; /* dongle down */
+ brcmf_abort_scanning(cfg);
+ brcmf_deinit_priv_mem(cfg);
+}
+
+static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
+{
+ init_waitqueue_head(&event->vif_wq);
+ mutex_init(&event->vif_event_lock);
+}
+
+static s32
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
+{
+ s32 err = 0;
+ __le32 roamtrigger[2];
+ __le32 roam_delta[2];
+
+ /*
+ * Setup timeout if Beacons are lost and roam is
+ * off to report link down
+ */
+ if (brcmf_roamoff) {
+ err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
+ if (err) {
+ brcmf_err("bcn_timeout error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+ }
+
+ /*
+ * Enable/Disable built-in roaming to allow supplicant
+ * to take care of roaming
+ */
+ brcmf_dbg(INFO, "Internal Roaming = %s\n",
+ brcmf_roamoff ? "Off" : "On");
+ err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
+ if (err) {
+ brcmf_err("roam_off error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
+ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
+ (void *)roamtrigger, sizeof(roamtrigger));
+ if (err) {
+ brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
+ roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
+ (void *)roam_delta, sizeof(roam_delta));
+ if (err) {
+ brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+dongle_rom_out:
+ return err;
+}
+
+static s32
+brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
+ s32 scan_unassoc_time, s32 scan_passive_time)
+{
+ s32 err = 0;
+
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ scan_assoc_time);
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ brcmf_dbg(INFO, "Scan assoc time is not supported\n");
+ else
+ brcmf_err("Scan assoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ scan_unassoc_time);
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
+ else
+ brcmf_err("Scan unassoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
+ scan_passive_time);
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ brcmf_dbg(INFO, "Scan passive time is not supported\n");
+ else
+ brcmf_err("Scan passive time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+dongle_scantime_out:
+ return err;
+}
+
+/* Filter the list of channels received from firmware counting only
+ * the 20MHz channels. The wiphy band data only needs those which get
+ * flagged to indicate if they can take part in higher bandwidth.
+ */
+static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_chanspec_list *chlist,
+ u32 chcnt[])
+{
+ u32 total = le32_to_cpu(chlist->count);
+ struct brcmu_chan ch;
+ int i;
+
+ for (i = 0; i < total; i++) {
+ ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
+ cfg->d11inf.decchspec(&ch);
+
+ /* Firmware gives a ordered list. We skip non-20MHz
+ * channels is 2G. For 5G we can abort upon reaching
+ * a non-20MHz channel in the list.
+ */
+ if (ch.bw != BRCMU_CHAN_BW_20) {
+ if (ch.band == BRCMU_CHAN_BAND_5G)
+ break;
+ else
+ continue;
+ }
+
+ if (ch.band == BRCMU_CHAN_BAND_2G)
+ chcnt[0] += 1;
+ else if (ch.band == BRCMU_CHAN_BAND_5G)
+ chcnt[1] += 1;
+ }
+}
+
+static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
+ struct brcmu_chan *ch)
+{
+ u32 ht40_flag;
+
+ ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
+ if (ch->sb == BRCMU_CHAN_SB_U) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40;
+ channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or
+ * IEEE80211_CHAN_NO_HT40PLUS
+ */
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
+ }
+}
+
+static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
+ u32 bw_cap[])
+{
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel *channel;
+ struct wiphy *wiphy;
+ struct brcmf_chanspec_list *list;
+ struct brcmu_chan ch;
+ int err;
+ u8 *pbuf;
+ u32 i, j;
+ u32 total;
+ u32 chaninfo;
+ u32 chcnt[2] = { 0, 0 };
+ u32 index;
+
+ pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+
+ if (pbuf == NULL)
+ return -ENOMEM;
+
+ list = (struct brcmf_chanspec_list *)pbuf;
+
+ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
+ BRCMF_DCMD_MEDLEN);
+ if (err) {
+ brcmf_err("get chanspecs error (%d)\n", err);
+ goto fail_pbuf;
+ }
+
+ brcmf_count_20mhz_channels(cfg, list, chcnt);
+ wiphy = cfg_to_wiphy(cfg);
+ if (chcnt[0]) {
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
+ GFP_KERNEL);
+ if (band == NULL) {
+ err = -ENOMEM;
+ goto fail_pbuf;
+ }
+ band->channels = kcalloc(chcnt[0], sizeof(*channel),
+ GFP_KERNEL);
+ if (band->channels == NULL) {
+ kfree(band);
+ err = -ENOMEM;
+ goto fail_pbuf;
+ }
+ band->n_channels = 0;
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ }
+ if (chcnt[1]) {
+ band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
+ GFP_KERNEL);
+ if (band == NULL) {
+ err = -ENOMEM;
+ goto fail_band2g;
+ }
+ band->channels = kcalloc(chcnt[1], sizeof(*channel),
+ GFP_KERNEL);
+ if (band->channels == NULL) {
+ kfree(band);
+ err = -ENOMEM;
+ goto fail_band2g;
+ }
+ band->n_channels = 0;
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ }
+
+ total = le32_to_cpu(list->count);
+ for (i = 0; i < total; i++) {
+ ch.chspec = (u16)le32_to_cpu(list->element[i]);
+ cfg->d11inf.decchspec(&ch);
+
+ if (ch.band == BRCMU_CHAN_BAND_2G) {
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ } else if (ch.band == BRCMU_CHAN_BAND_5G) {
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ } else {
+ brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
+ continue;
+ }
+ if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
+ ch.bw == BRCMU_CHAN_BW_40)
+ continue;
+ if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
+ ch.bw == BRCMU_CHAN_BW_80)
+ continue;
+
+ channel = band->channels;
+ index = band->n_channels;
+ for (j = 0; j < band->n_channels; j++) {
+ if (channel[j].hw_value == ch.chnum) {
+ index = j;
+ break;
+ }
+ }
+ channel[index].center_freq =
+ ieee80211_channel_to_frequency(ch.chnum, band->band);
+ channel[index].hw_value = ch.chnum;
+
+ /* assuming the chanspecs order is HT20,
+ * HT40 upper, HT40 lower, and VHT80.
+ */
+ if (ch.bw == BRCMU_CHAN_BW_80) {
+ channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
+ } else if (ch.bw == BRCMU_CHAN_BW_40) {
+ brcmf_update_bw40_channel_flag(&channel[index], &ch);
+ } else {
+ /* disable other bandwidths for now as mentioned
+ * order assure they are enabled for subsequent
+ * chanspecs.
+ */
+ channel[index].flags = IEEE80211_CHAN_NO_HT40 |
+ IEEE80211_CHAN_NO_80MHZ;
+ ch.bw = BRCMU_CHAN_BW_20;
+ cfg->d11inf.encchspec(&ch);
+ chaninfo = ch.chspec;
+ err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
+ &chaninfo);
+ if (!err) {
+ if (chaninfo & WL_CHAN_RADAR)
+ channel[index].flags |=
+ (IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IR);
+ if (chaninfo & WL_CHAN_PASSIVE)
+ channel[index].flags |=
+ IEEE80211_CHAN_NO_IR;
+ }
+ }
+ if (index == band->n_channels)
+ band->n_channels++;
+ }
+ kfree(pbuf);
+ return 0;
+
+fail_band2g:
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+fail_pbuf:
+ kfree(pbuf);
+ return err;
+}
+
+static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct ieee80211_supported_band *band;
+ struct brcmf_fil_bwcap_le band_bwcap;
+ struct brcmf_chanspec_list *list;
+ u8 *pbuf;
+ u32 val;
+ int err;
+ struct brcmu_chan ch;
+ u32 num_chan;
+ int i, j;
+
+ /* verify support for bw_cap command */
+ val = WLC_BAND_5G;
+ err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
+
+ if (!err) {
+ /* only set 2G bandwidth using bw_cap command */
+ band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
+ band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
+ err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
+ sizeof(band_bwcap));
+ } else {
+ brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
+ val = WLC_N_BW_40ALL;
+ err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
+ }
+
+ if (!err) {
+ /* update channel info in 2G band */
+ pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+
+ if (pbuf == NULL)
+ return -ENOMEM;
+
+ ch.band = BRCMU_CHAN_BAND_2G;
+ ch.bw = BRCMU_CHAN_BW_40;
+ ch.sb = BRCMU_CHAN_SB_NONE;
+ ch.chnum = 0;
+ cfg->d11inf.encchspec(&ch);
+
+ /* pass encoded chanspec in query */
+ *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
+
+ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
+ BRCMF_DCMD_MEDLEN);
+ if (err) {
+ brcmf_err("get chanspecs error (%d)\n", err);
+ kfree(pbuf);
+ return err;
+ }
+
+ band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
+ list = (struct brcmf_chanspec_list *)pbuf;
+ num_chan = le32_to_cpu(list->count);
+ for (i = 0; i < num_chan; i++) {
+ ch.chspec = (u16)le32_to_cpu(list->element[i]);
+ cfg->d11inf.decchspec(&ch);
+ if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
+ continue;
+ if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
+ continue;
+ for (j = 0; j < band->n_channels; j++) {
+ if (band->channels[j].hw_value == ch.chnum)
+ break;
+ }
+ if (WARN_ON(j == band->n_channels))
+ continue;
+
+ brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
+ }
+ kfree(pbuf);
+ }
+ return err;
+}
+
+static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
+{
+ u32 band, mimo_bwcap;
+ int err;
+
+ band = WLC_BAND_2G;
+ err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+ if (!err) {
+ bw_cap[IEEE80211_BAND_2GHZ] = band;
+ band = WLC_BAND_5G;
+ err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+ if (!err) {
+ bw_cap[IEEE80211_BAND_5GHZ] = band;
+ return;
+ }
+ WARN_ON(1);
+ return;
+ }
+ brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
+ mimo_bwcap = 0;
+ err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
+ if (err)
+ /* assume 20MHz if firmware does not give a clue */
+ mimo_bwcap = WLC_N_BW_20ALL;
+
+ switch (mimo_bwcap) {
+ case WLC_N_BW_40ALL:
+ bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
+ /* fall-thru */
+ case WLC_N_BW_20IN2G_40IN5G:
+ bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
+ /* fall-thru */
+ case WLC_N_BW_20ALL:
+ bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
+ bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
+ break;
+ default:
+ brcmf_err("invalid mimo_bw_cap value\n");
+ }
+}
+
+static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
+ u32 bw_cap[2], u32 nchain)
+{
+ band->ht_cap.ht_supported = true;
+ if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+ band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+ memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
+ band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
+{
+ u16 mcs_map;
+ int i;
+
+ for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
+ mcs_map = (mcs_map << 2) | supp;
+
+ return cpu_to_le16(mcs_map);
+}
+
+static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
+ u32 bw_cap[2], u32 nchain)
+{
+ __le16 mcs_map;
+
+ /* not allowed in 2.4G band */
+ if (band->band == IEEE80211_BAND_2GHZ)
+ return;
+
+ band->vht_cap.vht_supported = true;
+ /* 80MHz is mandatory */
+ band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+ if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
+ band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+ }
+ /* all support 256-QAM */
+ mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
+ band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
+ band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
+}
+
+static int brcmf_setup_wiphybands(struct wiphy *wiphy)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ u32 nmode = 0;
+ u32 vhtmode = 0;
+ u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
+ u32 rxchain;
+ u32 nchain;
+ int err;
+ s32 i;
+ struct ieee80211_supported_band *band;
+
+ (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
+ err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
+ if (err) {
+ brcmf_err("nmode error (%d)\n", err);
+ } else {
+ brcmf_get_bwcap(ifp, bw_cap);
+ }
+ brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
+ nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
+ bw_cap[IEEE80211_BAND_5GHZ]);
+
+ err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
+ if (err) {
+ brcmf_err("rxchain error (%d)\n", err);
+ nchain = 1;
+ } else {
+ for (nchain = 0; rxchain; nchain++)
+ rxchain = rxchain & (rxchain - 1);
+ }
+ brcmf_dbg(INFO, "nchain=%d\n", nchain);
+
+ err = brcmf_construct_chaninfo(cfg, bw_cap);
+ if (err) {
+ brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
+ return err;
+ }
+
+ wiphy = cfg_to_wiphy(cfg);
+ for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
+ band = wiphy->bands[i];
+ if (band == NULL)
+ continue;
+
+ if (nmode)
+ brcmf_update_ht_cap(band, bw_cap, nchain);
+ if (vhtmode)
+ brcmf_update_vht_cap(band, bw_cap, nchain);
+ }
+
+ return 0;
+}
+
+static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ }
+};
+static struct ieee80211_iface_combination brcmf_iface_combos[] = {
+ {
+ .max_interfaces = BRCMF_IFACE_MAX_CNT,
+ .num_different_channels = 1,
+ .n_limits = ARRAY_SIZE(brcmf_iface_limits),
+ .limits = brcmf_iface_limits
+ }
+};
+
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ }
+};
+
+static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
+{
+ /* scheduled scan settings */
+ wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
+ wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+}
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support brcmf_wowlan_support = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+ .n_patterns = BRCMF_WOWL_MAXPATTERNS,
+ .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
+ .pattern_min_len = 1,
+ .max_pkt_offset = 1500,
+};
+#endif
+
+static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
+{
+#ifdef CONFIG_PM
+ /* wowl settings */
+ wiphy->wowlan = &brcmf_wowlan_support;
+#endif
+}
+
+static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+ struct ieee80211_iface_combination ifc_combo;
+ wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+ wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ /* need VSDB firmware feature for concurrent channels */
+ ifc_combo = brcmf_iface_combos[0];
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+ ifc_combo.num_different_channels = 2;
+ wiphy->iface_combinations = kmemdup(&ifc_combo,
+ sizeof(ifc_combo),
+ GFP_KERNEL);
+ wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->cipher_suites = __wl_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+ WIPHY_FLAG_OFFCHAN_TX |
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_SUPPORTS_TDLS;
+ if (!brcmf_roamoff)
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+ wiphy->mgmt_stypes = brcmf_txrx_stypes;
+ wiphy->max_remain_on_channel_duration = 5000;
+ brcmf_wiphy_pno_params(wiphy);
+
+ /* vendor commands/events support */
+ wiphy->vendor_commands = brcmf_vendor_cmds;
+ wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
+ brcmf_wiphy_wowl_params(wiphy);
+
+ return brcmf_setup_wiphybands(wiphy);
+}
+
+static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
+{
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ struct brcmf_if *ifp;
+ s32 power_mode;
+ s32 err = 0;
+
+ if (cfg->dongle_up)
+ return err;
+
+ ndev = cfg_to_ndev(cfg);
+ wdev = ndev->ieee80211_ptr;
+ ifp = netdev_priv(ndev);
+
+ /* make sure RF is ready for work */
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+
+ brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
+ WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+
+ power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
+ if (err)
+ goto default_conf_out;
+ brcmf_dbg(INFO, "power save set to %s\n",
+ (power_mode ? "enabled" : "disabled"));
+
+ err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
+ if (err)
+ goto default_conf_out;
+ err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
+ NULL, NULL);
+ if (err)
+ goto default_conf_out;
+
+ brcmf_configure_arp_offload(ifp, true);
+
+ cfg->dongle_up = true;
+default_conf_out:
+
+ return err;
+
+}
+
+static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
+{
+ set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
+
+ return brcmf_config_dongle(ifp->drvr->config);
+}
+
+static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+
+ /*
+ * While going down, if associated with AP disassociate
+ * from AP to save power
+ */
+ if (check_vif_up(ifp->vif)) {
+ brcmf_link_down(ifp->vif);
+
+ /* Make sure WPA_Supplicant receives all the event
+ generated due to DISASSOC call to the fw to keep
+ the state fw and WPA_Supplicant state consistent
+ */
+ brcmf_delay(500);
+ }
+
+ brcmf_abort_scanning(cfg);
+ clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
+
+ return 0;
+}
+
+s32 brcmf_cfg80211_up(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ s32 err = 0;
+
+ mutex_lock(&cfg->usr_sync);
+ err = __brcmf_cfg80211_up(ifp);
+ mutex_unlock(&cfg->usr_sync);
+
+ return err;
+}
+
+s32 brcmf_cfg80211_down(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ s32 err = 0;
+
+ mutex_lock(&cfg->usr_sync);
+ err = __brcmf_cfg80211_down(ifp);
+ mutex_unlock(&cfg->usr_sync);
+
+ return err;
+}
+
+enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
+{
+ struct wireless_dev *wdev = &ifp->vif->wdev;
+
+ return wdev->iftype;
+}
+
+bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
+ unsigned long state)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ list_for_each_entry(vif, &cfg->vif_list, list) {
+ if (test_bit(state, &vif->sme_state))
+ return true;
+ }
+ return false;
+}
+
+static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
+ u8 action)
+{
+ u8 evt_action;
+
+ mutex_lock(&event->vif_event_lock);
+ evt_action = event->action;
+ mutex_unlock(&event->vif_event_lock);
+ return evt_action == action;
+}
+
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+ mutex_lock(&event->vif_event_lock);
+ event->vif = vif;
+ event->action = 0;
+ mutex_unlock(&event->vif_event_lock);
+}
+
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+ bool armed;
+
+ mutex_lock(&event->vif_event_lock);
+ armed = event->vif != NULL;
+ mutex_unlock(&event->vif_event_lock);
+
+ return armed;
+}
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+ u8 action, ulong timeout)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+ return wait_event_timeout(event->vif_wq,
+ vif_event_equals(event, action), timeout);
+}
+
+static void brcmf_free_wiphy(struct wiphy *wiphy)
+{
+ kfree(wiphy->iface_combinations);
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
+ }
+ if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
+ kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
+ }
+ wiphy_free(wiphy);
+}
+
+struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+ struct device *busdev)
+{
+ struct net_device *ndev = drvr->iflist[0]->ndev;
+ struct brcmf_cfg80211_info *cfg;
+ struct wiphy *wiphy;
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_if *ifp;
+ s32 err = 0;
+ s32 io_type;
+ u16 *cap = NULL;
+
+ if (!ndev) {
+ brcmf_err("ndev is invalid\n");
+ return NULL;
+ }
+
+ ifp = netdev_priv(ndev);
+ wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
+ if (!wiphy) {
+ brcmf_err("Could not allocate wiphy device\n");
+ return NULL;
+ }
+ set_wiphy_dev(wiphy, busdev);
+
+ cfg = wiphy_priv(wiphy);
+ cfg->wiphy = wiphy;
+ cfg->pub = drvr;
+ init_vif_event(&cfg->vif_event);
+ INIT_LIST_HEAD(&cfg->vif_list);
+
+ vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
+ if (IS_ERR(vif))
+ goto wiphy_out;
+
+ vif->ifp = ifp;
+ vif->wdev.netdev = ndev;
+ ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
+ err = wl_init_priv(cfg);
+ if (err) {
+ brcmf_err("Failed to init iwm_priv (%d)\n", err);
+ brcmf_free_vif(vif);
+ goto wiphy_out;
+ }
+ ifp->vif = vif;
+
+ /* determine d11 io type before wiphy setup */
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
+ if (err) {
+ brcmf_err("Failed to get D11 version (%d)\n", err);
+ goto priv_out;
+ }
+ cfg->d11inf.io_type = (u8)io_type;
+ brcmu_d11_attach(&cfg->d11inf);
+
+ err = brcmf_setup_wiphy(wiphy, ifp);
+ if (err < 0)
+ goto priv_out;
+
+ brcmf_dbg(INFO, "Registering custom regulatory\n");
+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
+
+ /* firmware defaults to 40MHz disabled in 2G band. We signal
+ * cfg80211 here that we do and have it decide we can enable
+ * it. But first check if device does support 2G operation.
+ */
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
+ *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ err = wiphy_register(wiphy);
+ if (err < 0) {
+ brcmf_err("Could not register wiphy device (%d)\n", err);
+ goto priv_out;
+ }
+
+ /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
+ * setup 40MHz in 2GHz band and enable OBSS scanning.
+ */
+ if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
+ err = brcmf_enable_bw40_2g(cfg);
+ if (!err)
+ err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
+ BRCMF_OBSS_COEX_AUTO);
+ else
+ *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+
+ err = brcmf_p2p_attach(cfg);
+ if (err) {
+ brcmf_err("P2P initilisation failed (%d)\n", err);
+ goto wiphy_unreg_out;
+ }
+ err = brcmf_btcoex_attach(cfg);
+ if (err) {
+ brcmf_err("BT-coex initialisation failed (%d)\n", err);
+ brcmf_p2p_detach(&cfg->p2p);
+ goto wiphy_unreg_out;
+ }
+
+ err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
+ if (err) {
+ brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
+ wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
+ } else {
+ brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
+ brcmf_notify_tdls_peer_event);
+ }
+
+ return cfg;
+
+wiphy_unreg_out:
+ wiphy_unregister(cfg->wiphy);
+priv_out:
+ wl_deinit_priv(cfg);
+ brcmf_free_vif(vif);
+wiphy_out:
+ brcmf_free_wiphy(wiphy);
+ return NULL;
+}
+
+void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
+{
+ if (!cfg)
+ return;
+
+ WARN_ON(!list_empty(&cfg->vif_list));
+ wiphy_unregister(cfg->wiphy);
+ brcmf_btcoex_detach(cfg);
+ brcmf_p2p_detach(&cfg->p2p);
+ wl_deinit_priv(cfg);
+ brcmf_free_wiphy(cfg->wiphy);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BRCMFMAC_CFG80211_H
+#define BRCMFMAC_CFG80211_H
+
+/* for brcmu_d11inf */
+#include <brcmu_d11.h>
+
+#define WL_NUM_SCAN_MAX 10
+#define WL_NUM_PMKIDS_MAX MAXPMKID
+#define WL_TLV_INFO_MAX 1024
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512 /* assoc related fil max buf */
+#define WL_EXTRA_BUF_MAX 2048
+#define WL_ROAM_TRIGGER_LEVEL -75
+#define WL_ROAM_DELTA 20
+#define WL_BEACON_TIMEOUT 3
+
+#define WL_SCAN_CHANNEL_TIME 40
+#define WL_SCAN_UNASSOC_TIME 40
+#define WL_SCAN_PASSIVE_TIME 120
+
+#define WL_ESCAN_BUF_SIZE (1024 * 64)
+#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
+
+#define WL_ESCAN_ACTION_START 1
+#define WL_ESCAN_ACTION_CONTINUE 2
+#define WL_ESCAN_ACTION_ABORT 3
+
+#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
+#define IE_MAX_LEN 512
+
+/* IE TLV processing */
+#define TLV_LEN_OFF 1 /* length offset */
+#define TLV_HDR_LEN 2 /* header length */
+#define TLV_BODY_OFF 2 /* body offset */
+#define TLV_OUI_LEN 3 /* oui id length */
+
+/* 802.11 Mgmt Packet flags */
+#define BRCMF_VNDR_IE_BEACON_FLAG 0x1
+#define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2
+#define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4
+#define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8
+#define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10
+#define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20
+/* vendor IE in IW advertisement protocol ID field */
+#define BRCMF_VNDR_IE_IWAPID_FLAG 0x40
+/* allow custom IE id */
+#define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100
+
+/* P2P Action Frames flags (spec ordered) */
+#define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000
+#define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000
+#define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000
+#define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000
+#define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000
+#define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000
+#define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000
+#define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000
+#define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000
+
+#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
+
+
+/**
+ * enum brcmf_scan_status - scan engine status
+ *
+ * @BRCMF_SCAN_STATUS_BUSY: scanning in progress on dongle.
+ * @BRCMF_SCAN_STATUS_ABORT: scan being aborted on dongle.
+ * @BRCMF_SCAN_STATUS_SUPPRESS: scanning is suppressed in driver.
+ */
+enum brcmf_scan_status {
+ BRCMF_SCAN_STATUS_BUSY,
+ BRCMF_SCAN_STATUS_ABORT,
+ BRCMF_SCAN_STATUS_SUPPRESS,
+};
+
+/* dongle configuration */
+struct brcmf_cfg80211_conf {
+ u32 frag_threshold;
+ u32 rts_threshold;
+ u32 retry_short;
+ u32 retry_long;
+ s32 tx_power;
+ struct ieee80211_channel channel;
+};
+
+/* basic structure of scan request */
+struct brcmf_cfg80211_scan_req {
+ struct brcmf_ssid_le ssid_le;
+};
+
+/* basic structure of information element */
+struct brcmf_cfg80211_ie {
+ u16 offset;
+ u8 buf[WL_TLV_INFO_MAX];
+};
+
+/* security information with currently associated ap */
+struct brcmf_cfg80211_security {
+ u32 wpa_versions;
+ u32 auth_type;
+ u32 cipher_pairwise;
+ u32 cipher_group;
+ u32 wpa_auth;
+};
+
+/**
+ * struct brcmf_cfg80211_profile - profile information.
+ *
+ * @ssid: ssid of associated/associating ap.
+ * @bssid: bssid of joined/joining ibss.
+ * @sec: security information.
+ */
+struct brcmf_cfg80211_profile {
+ struct brcmf_ssid ssid;
+ u8 bssid[ETH_ALEN];
+ struct brcmf_cfg80211_security sec;
+};
+
+/**
+ * enum brcmf_vif_status - bit indices for vif status.
+ *
+ * @BRCMF_VIF_STATUS_READY: ready for operation.
+ * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
+ * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
+ * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
+ * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
+ */
+enum brcmf_vif_status {
+ BRCMF_VIF_STATUS_READY,
+ BRCMF_VIF_STATUS_CONNECTING,
+ BRCMF_VIF_STATUS_CONNECTED,
+ BRCMF_VIF_STATUS_DISCONNECTING,
+ BRCMF_VIF_STATUS_AP_CREATING,
+ BRCMF_VIF_STATUS_AP_CREATED
+};
+
+/**
+ * struct vif_saved_ie - holds saved IEs for a virtual interface.
+ *
+ * @probe_req_ie: IE info for probe request.
+ * @probe_res_ie: IE info for probe response.
+ * @beacon_ie: IE info for beacon frame.
+ * @probe_req_ie_len: IE info length for probe request.
+ * @probe_res_ie_len: IE info length for probe response.
+ * @beacon_ie_len: IE info length for beacon frame.
+ */
+struct vif_saved_ie {
+ u8 probe_req_ie[IE_MAX_LEN];
+ u8 probe_res_ie[IE_MAX_LEN];
+ u8 beacon_ie[IE_MAX_LEN];
+ u8 assoc_req_ie[IE_MAX_LEN];
+ u32 probe_req_ie_len;
+ u32 probe_res_ie_len;
+ u32 beacon_ie_len;
+ u32 assoc_req_ie_len;
+};
+
+/**
+ * struct brcmf_cfg80211_vif - virtual interface specific information.
+ *
+ * @ifp: lower layer interface pointer
+ * @wdev: wireless device.
+ * @profile: profile information.
+ * @roam_off: roaming state.
+ * @sme_state: SME state using enum brcmf_vif_status bits.
+ * @pm_block: power-management blocked.
+ * @list: linked list.
+ * @mgmt_rx_reg: registered rx mgmt frame types.
+ */
+struct brcmf_cfg80211_vif {
+ struct brcmf_if *ifp;
+ struct wireless_dev wdev;
+ struct brcmf_cfg80211_profile profile;
+ s32 roam_off;
+ unsigned long sme_state;
+ bool pm_block;
+ struct vif_saved_ie saved_ie;
+ struct list_head list;
+ u16 mgmt_rx_reg;
+};
+
+/* association inform */
+struct brcmf_cfg80211_connect_info {
+ u8 *req_ie;
+ s32 req_ie_len;
+ u8 *resp_ie;
+ s32 resp_ie_len;
+};
+
+/* assoc ie length */
+struct brcmf_cfg80211_assoc_ielen_le {
+ __le32 req_len;
+ __le32 resp_len;
+};
+
+/* wpa2 pmk list */
+struct brcmf_cfg80211_pmk_list {
+ struct pmkid_list pmkids;
+ struct pmkid foo[MAXPMKID - 1];
+};
+
+/* dongle escan state */
+enum wl_escan_state {
+ WL_ESCAN_STATE_IDLE,
+ WL_ESCAN_STATE_SCANNING
+};
+
+struct escan_info {
+ u32 escan_state;
+ u8 escan_buf[WL_ESCAN_BUF_SIZE];
+ struct wiphy *wiphy;
+ struct brcmf_if *ifp;
+ s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
+ struct cfg80211_scan_request *request, u16 action);
+};
+
+/**
+ * struct brcmf_pno_param_le - PNO scan configuration parameters
+ *
+ * @version: PNO parameters version.
+ * @scan_freq: scan frequency.
+ * @lost_network_timeout: #sec. to declare discovered network as lost.
+ * @flags: Bit field to control features of PFN such as sort criteria auto
+ * enable switch and background scan.
+ * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort
+ * criteria.
+ * @bestn: number of best networks in each scan.
+ * @mscan: number of scans recorded.
+ * @repeat: minimum number of scan intervals before scan frequency changes
+ * in adaptive scan.
+ * @exp: exponent of 2 for maximum scan interval.
+ * @slow_freq: slow scan period.
+ */
+struct brcmf_pno_param_le {
+ __le32 version;
+ __le32 scan_freq;
+ __le32 lost_network_timeout;
+ __le16 flags;
+ __le16 rssi_margin;
+ u8 bestn;
+ u8 mscan;
+ u8 repeat;
+ u8 exp;
+ __le32 slow_freq;
+};
+
+/**
+ * struct brcmf_pno_net_param_le - scan parameters per preferred network.
+ *
+ * @ssid: ssid name and its length.
+ * @flags: bit2: hidden.
+ * @infra: BSS vs IBSS.
+ * @auth: Open vs Closed.
+ * @wpa_auth: WPA type.
+ * @wsec: wsec value.
+ */
+struct brcmf_pno_net_param_le {
+ struct brcmf_ssid_le ssid;
+ __le32 flags;
+ __le32 infra;
+ __le32 auth;
+ __le32 wpa_auth;
+ __le32 wsec;
+};
+
+/**
+ * struct brcmf_pno_net_info_le - information per found network.
+ *
+ * @bssid: BSS network identifier.
+ * @channel: channel number only.
+ * @SSID_len: length of ssid.
+ * @SSID: ssid characters.
+ * @RSSI: receive signal strength (in dBm).
+ * @timestamp: age in seconds.
+ */
+struct brcmf_pno_net_info_le {
+ u8 bssid[ETH_ALEN];
+ u8 channel;
+ u8 SSID_len;
+ u8 SSID[32];
+ __le16 RSSI;
+ __le16 timestamp;
+};
+
+/**
+ * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event.
+ *
+ * @version: PNO version identifier.
+ * @status: indicates completion status of PNO scan.
+ * @count: amount of brcmf_pno_net_info_le entries appended.
+ */
+struct brcmf_pno_scanresults_le {
+ __le32 version;
+ __le32 status;
+ __le32 count;
+};
+
+/**
+ * struct brcmf_cfg80211_vif_event - virtual interface event information.
+ *
+ * @vif_wq: waitqueue awaiting interface event from firmware.
+ * @vif_event_lock: protects other members in this structure.
+ * @vif_complete: completion for net attach.
+ * @action: either add, change, or delete.
+ * @vif: virtual interface object related to the event.
+ */
+struct brcmf_cfg80211_vif_event {
+ wait_queue_head_t vif_wq;
+ struct mutex vif_event_lock;
+ u8 action;
+ struct brcmf_cfg80211_vif *vif;
+};
+
+/**
+ * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
+ *
+ * @wiphy: wiphy object for cfg80211 interface.
+ * @conf: dongle configuration.
+ * @p2p: peer-to-peer specific information.
+ * @btcoex: Bluetooth coexistence information.
+ * @scan_request: cfg80211 scan request object.
+ * @usr_sync: mainly for dongle up/down synchronization.
+ * @bss_list: bss_list holding scanned ap information.
+ * @scan_req_int: internal scan request object.
+ * @bss_info: bss information for cfg80211 layer.
+ * @ie: information element object for internal purpose.
+ * @conn_info: association info.
+ * @pmk_list: wpa2 pmk list.
+ * @scan_status: scan activity on the dongle.
+ * @pub: common driver information.
+ * @channel: current channel.
+ * @active_scan: current scan mode.
+ * @sched_escan: e-scan for scheduled scan support running.
+ * @ibss_starter: indicates this sta is ibss starter.
+ * @pwr_save: indicate whether dongle to support power save mode.
+ * @dongle_up: indicate whether dongle up or not.
+ * @roam_on: on/off switch for dongle self-roaming.
+ * @scan_tried: indicates if first scan attempted.
+ * @dcmd_buf: dcmd buffer.
+ * @extra_buf: mainly to grab assoc information.
+ * @debugfsdir: debugfs folder for this device.
+ * @escan_info: escan information.
+ * @escan_timeout: Timer for catch scan timeout.
+ * @escan_timeout_work: scan timeout worker.
+ * @escan_ioctl_buf: dongle command buffer for escan commands.
+ * @vif_list: linked list of vif instances.
+ * @vif_cnt: number of vif instances.
+ * @vif_event: vif event signalling.
+ * @wowl_enabled; set during suspend, is wowl used.
+ * @pre_wowl_pmmode: intermediate storage of pm mode during wowl.
+ */
+struct brcmf_cfg80211_info {
+ struct wiphy *wiphy;
+ struct brcmf_cfg80211_conf *conf;
+ struct brcmf_p2p_info p2p;
+ struct brcmf_btcoex_info *btcoex;
+ struct cfg80211_scan_request *scan_request;
+ struct mutex usr_sync;
+ struct brcmf_cfg80211_scan_req scan_req_int;
+ struct wl_cfg80211_bss_info *bss_info;
+ struct brcmf_cfg80211_ie ie;
+ struct brcmf_cfg80211_connect_info conn_info;
+ struct brcmf_cfg80211_pmk_list *pmk_list;
+ unsigned long scan_status;
+ struct brcmf_pub *pub;
+ u32 channel;
+ bool active_scan;
+ bool sched_escan;
+ bool ibss_starter;
+ bool pwr_save;
+ bool dongle_up;
+ bool scan_tried;
+ u8 *dcmd_buf;
+ u8 *extra_buf;
+ struct dentry *debugfsdir;
+ struct escan_info escan_info;
+ struct timer_list escan_timeout;
+ struct work_struct escan_timeout_work;
+ u8 *escan_ioctl_buf;
+ struct list_head vif_list;
+ struct brcmf_cfg80211_vif_event vif_event;
+ struct completion vif_disabled;
+ struct brcmu_d11inf d11inf;
+ bool wowl_enabled;
+ u32 pre_wowl_pmmode;
+};
+
+/**
+ * struct brcmf_tlv - tag_ID/length/value_buffer tuple.
+ *
+ * @id: tag identifier.
+ * @len: number of bytes in value buffer.
+ * @data: value buffer.
+ */
+struct brcmf_tlv {
+ u8 id;
+ u8 len;
+ u8 data[1];
+};
+
+static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
+{
+ return cfg->wiphy;
+}
+
+static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
+{
+ return (struct brcmf_cfg80211_info *)(wiphy_priv(w));
+}
+
+static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
+{
+ return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
+}
+
+static inline
+struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_cfg80211_vif *vif;
+ vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
+ return vif->wdev.netdev;
+}
+
+static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
+{
+ return wdev_to_cfg(ndev->ieee80211_ptr);
+}
+
+static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd)
+{
+ struct brcmf_if *ifp = netdev_priv(nd);
+ return &ifp->vif->profile;
+}
+
+static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ return ifp->vif;
+}
+
+static inline struct
+brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
+{
+ return &cfg->conn_info;
+}
+
+struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+ struct device *busdev);
+void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
+s32 brcmf_cfg80211_up(struct net_device *ndev);
+s32 brcmf_cfg80211_down(struct net_device *ndev);
+enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
+
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+ enum nl80211_iftype type,
+ bool pm_block);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
+
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+ const u8 *vndr_ie_buf, u32 vndr_ie_len);
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key);
+u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct ieee80211_channel *ch);
+bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
+ unsigned long state);
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_cfg80211_vif *vif);
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+ u8 action, ulong timeout);
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort);
+void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+void brcmf_cfg80211_free_netdev(struct net_device *ndev);
+
+#endif /* BRCMFMAC_CFG80211_H */
#include <brcm_hw_ids.h>
#include <brcmu_utils.h>
#include <chipcommon.h>
-#include "dhd_dbg.h"
+#include "debug.h"
#include "chip.h"
/* SOC Interconnect types (aka chip types) */
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
+#include "fwil.h"
+#include "fwil_types.h"
+#include "tracepoint.h"
+
+#define BRCMF_DEFAULT_BCN_TIMEOUT 3
+#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
+#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
+
+/* boost value for RSSI_DELTA in preferred join selection */
+#define BRCMF_JOIN_PREF_RSSI_BOOST 8
+
+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
+{
+ s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+ u8 buf[BRCMF_DCMD_SMLEN];
+ struct brcmf_join_pref_params join_pref_params[2];
+ char *ptr;
+ s32 err;
+
+ /* retreive mac address */
+ err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
+ sizeof(ifp->mac_addr));
+ if (err < 0) {
+ brcmf_err("Retreiving cur_etheraddr failed, %d\n",
+ err);
+ goto done;
+ }
+ memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ strcpy(buf, "ver");
+ err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
+ if (err < 0) {
+ brcmf_err("Retreiving version information failed, %d\n",
+ err);
+ goto done;
+ }
+ ptr = (char *)buf;
+ strsep(&ptr, "\n");
+
+ /* Print fw version info */
+ brcmf_err("Firmware version = %s\n", buf);
+
+ /* locate firmware version number for ethtool */
+ ptr = strrchr(buf, ' ') + 1;
+ strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
+
+ /* set mpc */
+ err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
+ if (err) {
+ brcmf_err("failed setting mpc\n");
+ goto done;
+ }
+
+ /*
+ * Setup timeout if Beacons are lost and roam is off to report
+ * link down
+ */
+ err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
+ BRCMF_DEFAULT_BCN_TIMEOUT);
+ if (err) {
+ brcmf_err("bcn_timeout error (%d)\n", err);
+ goto done;
+ }
+
+ /* Enable/Disable build-in roaming to allowed ext supplicant to take
+ * of romaing
+ */
+ err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+ if (err) {
+ brcmf_err("roam_off error (%d)\n", err);
+ goto done;
+ }
+
+ /* Setup join_pref to select target by RSSI(with boost on 5GHz) */
+ join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
+ join_pref_params[0].len = 2;
+ join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
+ join_pref_params[0].band = WLC_BAND_5G;
+ join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
+ join_pref_params[1].len = 2;
+ join_pref_params[1].rssi_gain = 0;
+ join_pref_params[1].band = 0;
+ err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
+ sizeof(join_pref_params));
+ if (err)
+ brcmf_err("Set join_pref error (%d)\n", err);
+
+ /* Setup event_msgs, enable E_IF */
+ err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
+ BRCMF_EVENTING_MASK_LEN);
+ if (err) {
+ brcmf_err("Get event_msgs error (%d)\n", err);
+ goto done;
+ }
+ setbit(eventmask, BRCMF_E_IF);
+ err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
+ BRCMF_EVENTING_MASK_LEN);
+ if (err) {
+ brcmf_err("Set event_msgs error (%d)\n", err);
+ goto done;
+ }
+
+ /* Setup default scan channel time */
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
+ if (err) {
+ brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
+ err);
+ goto done;
+ }
+
+ /* Setup default scan unassoc time */
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
+ if (err) {
+ brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
+ err);
+ goto done;
+ }
+
+ /* do bus specific preinit here */
+ err = brcmf_bus_preinit(ifp->drvr->bus_if);
+done:
+ return err;
+}
+
+#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ if (brcmf_msg_level & level)
+ pr_debug("%s %pV", func, &vaf);
+ trace_brcmf_dbg(level, func, &vaf);
+ va_end(args);
+}
+#endif
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
+#include "core.h"
#include "commonring.h"
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
+#include "fwil_types.h"
+#include "p2p.h"
+#include "cfg80211.h"
+#include "fwil.h"
+#include "fwsignal.h"
+#include "feature.h"
+#include "proto.h"
+#include "pcie.h"
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */
+
+/* AMPDU rx reordering definitions */
+#define BRCMF_RXREORDER_FLOWID_OFFSET 0
+#define BRCMF_RXREORDER_MAXIDX_OFFSET 2
+#define BRCMF_RXREORDER_FLAGS_OFFSET 4
+#define BRCMF_RXREORDER_CURIDX_OFFSET 6
+#define BRCMF_RXREORDER_EXPIDX_OFFSET 8
+
+#define BRCMF_RXREORDER_DEL_FLOW 0x01
+#define BRCMF_RXREORDER_FLUSH_ALL 0x02
+#define BRCMF_RXREORDER_CURIDX_VALID 0x04
+#define BRCMF_RXREORDER_EXPIDX_VALID 0x08
+#define BRCMF_RXREORDER_NEW_HOLE 0x10
+
+/* Error bits */
+int brcmf_msg_level;
+module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(debug, "level of debug output");
+
+/* P2P0 enable */
+static int brcmf_p2p_enable;
+#ifdef CONFIG_BRCMDBG
+module_param_named(p2pon, brcmf_p2p_enable, int, 0);
+MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
+#endif
+
+char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
+{
+ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+ brcmf_err("ifidx %d out of range\n", ifidx);
+ return "<if_bad>";
+ }
+
+ if (drvr->iflist[ifidx] == NULL) {
+ brcmf_err("null i/f %d\n", ifidx);
+ return "<if_null>";
+ }
+
+ if (drvr->iflist[ifidx]->ndev)
+ return drvr->iflist[ifidx]->ndev->name;
+
+ return "<if_none>";
+}
+
+static void _brcmf_set_multicast_list(struct work_struct *work)
+{
+ struct brcmf_if *ifp;
+ struct net_device *ndev;
+ struct netdev_hw_addr *ha;
+ u32 cmd_value, cnt;
+ __le32 cnt_le;
+ char *buf, *bufp;
+ u32 buflen;
+ s32 err;
+
+ ifp = container_of(work, struct brcmf_if, multicast_work);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
+ ndev = ifp->ndev;
+
+ /* Determine initial value of allmulti flag */
+ cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
+
+ /* Send down the multicast list first. */
+ cnt = netdev_mc_count(ndev);
+ buflen = sizeof(cnt) + (cnt * ETH_ALEN);
+ buf = kmalloc(buflen, GFP_ATOMIC);
+ if (!buf)
+ return;
+ bufp = buf;
+
+ cnt_le = cpu_to_le32(cnt);
+ memcpy(bufp, &cnt_le, sizeof(cnt_le));
+ bufp += sizeof(cnt_le);
+
+ netdev_for_each_mc_addr(ha, ndev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETH_ALEN);
+ bufp += ETH_ALEN;
+ cnt--;
+ }
+
+ err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
+ if (err < 0) {
+ brcmf_err("Setting mcast_list failed, %d\n", err);
+ cmd_value = cnt ? true : cmd_value;
+ }
+
+ kfree(buf);
+
+ /*
+ * Now send the allmulti setting. This is based on the setting in the
+ * net_device flags, but might be modified above to be turned on if we
+ * were trying to set some addresses and dongle rejected it...
+ */
+ err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
+ if (err < 0)
+ brcmf_err("Setting allmulti failed, %d\n", err);
+
+ /*Finally, pick up the PROMISC flag */
+ cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
+ if (err < 0)
+ brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
+ err);
+}
+
+static void
+_brcmf_set_mac_address(struct work_struct *work)
+{
+ struct brcmf_if *ifp;
+ s32 err;
+
+ ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
+ err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
+ ETH_ALEN);
+ if (err < 0) {
+ brcmf_err("Setting cur_etheraddr failed, %d\n", err);
+ } else {
+ brcmf_dbg(TRACE, "MAC address updated to %pM\n",
+ ifp->mac_addr);
+ memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+ }
+}
+
+static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct sockaddr *sa = (struct sockaddr *)addr;
+
+ memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
+ schedule_work(&ifp->setmacaddr_work);
+ return 0;
+}
+
+static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ schedule_work(&ifp->multicast_work);
+}
+
+static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ int ret;
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct ethhdr *eh = (struct ethhdr *)(skb->data);
+
+ brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
+
+ /* Can the device send data? */
+ if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
+ netif_stop_queue(ndev);
+ dev_kfree_skb(skb);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (!drvr->iflist[ifp->bssidx]) {
+ brcmf_err("bad ifidx %d\n", ifp->bssidx);
+ netif_stop_queue(ndev);
+ dev_kfree_skb(skb);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ /* Make sure there's enough room for any header */
+ if (skb_headroom(skb) < drvr->hdrlen) {
+ struct sk_buff *skb2;
+
+ brcmf_dbg(INFO, "%s: insufficient headroom\n",
+ brcmf_ifname(drvr, ifp->bssidx));
+ drvr->bus_if->tx_realloc++;
+ skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
+ dev_kfree_skb(skb);
+ skb = skb2;
+ if (skb == NULL) {
+ brcmf_err("%s: skb_realloc_headroom failed\n",
+ brcmf_ifname(drvr, ifp->bssidx));
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ /* validate length for ether packet */
+ if (skb->len < sizeof(*eh)) {
+ ret = -EINVAL;
+ dev_kfree_skb(skb);
+ goto done;
+ }
+
+ if (eh->h_proto == htons(ETH_P_PAE))
+ atomic_inc(&ifp->pend_8021x_cnt);
+
+ ret = brcmf_fws_process_skb(ifp, skb);
+
+done:
+ if (ret) {
+ ifp->stats.tx_dropped++;
+ } else {
+ ifp->stats.tx_packets++;
+ ifp->stats.tx_bytes += skb->len;
+ }
+
+ /* Return ok: we always eat the packet */
+ return NETDEV_TX_OK;
+}
+
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state)
+{
+ unsigned long flags;
+
+ if (!ifp || !ifp->ndev)
+ return;
+
+ brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
+ ifp->bssidx, ifp->netif_stop, reason, state);
+
+ spin_lock_irqsave(&ifp->netif_stop_lock, flags);
+ if (state) {
+ if (!ifp->netif_stop)
+ netif_stop_queue(ifp->ndev);
+ ifp->netif_stop |= reason;
+ } else {
+ ifp->netif_stop &= ~reason;
+ if (!ifp->netif_stop)
+ netif_wake_queue(ifp->ndev);
+ }
+ spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
+}
+
+void brcmf_txflowblock(struct device *dev, bool state)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_fws_bus_blocked(drvr, state);
+}
+
+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+ skb->dev = ifp->ndev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if (skb->pkt_type == PACKET_MULTICAST)
+ ifp->stats.multicast++;
+
+ /* Process special event packets */
+ brcmf_fweh_process_skb(ifp->drvr, skb);
+
+ if (!(ifp->ndev->flags & IFF_UP)) {
+ brcmu_pkt_buf_free_skb(skb);
+ return;
+ }
+
+ ifp->stats.rx_bytes += skb->len;
+ ifp->stats.rx_packets++;
+
+ brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ /* If the receive is not processed inside an ISR,
+ * the softirqd must be woken explicitly to service
+ * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni().
+ */
+ netif_rx_ni(skb);
+}
+
+static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
+ u8 start, u8 end,
+ struct sk_buff_head *skb_list)
+{
+ /* initialize return list */
+ __skb_queue_head_init(skb_list);
+
+ if (rfi->pend_pkts == 0) {
+ brcmf_dbg(INFO, "no packets in reorder queue\n");
+ return;
+ }
+
+ do {
+ if (rfi->pktslots[start]) {
+ __skb_queue_tail(skb_list, rfi->pktslots[start]);
+ rfi->pktslots[start] = NULL;
+ }
+ start++;
+ if (start > rfi->max_idx)
+ start = 0;
+ } while (start != end);
+ rfi->pend_pkts -= skb_queue_len(skb_list);
+}
+
+static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
+ struct sk_buff *pkt)
+{
+ u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
+ struct brcmf_ampdu_rx_reorder *rfi;
+ struct sk_buff_head reorder_list;
+ struct sk_buff *pnext;
+ u8 flags;
+ u32 buf_size;
+
+ flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
+ flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
+
+ /* validate flags and flow id */
+ if (flags == 0xFF) {
+ brcmf_err("invalid flags...so ignore this packet\n");
+ brcmf_netif_rx(ifp, pkt);
+ return;
+ }
+
+ rfi = ifp->drvr->reorder_flows[flow_id];
+ if (flags & BRCMF_RXREORDER_DEL_FLOW) {
+ brcmf_dbg(INFO, "flow-%d: delete\n",
+ flow_id);
+
+ if (rfi == NULL) {
+ brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
+ flow_id);
+ brcmf_netif_rx(ifp, pkt);
+ return;
+ }
+
+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
+ &reorder_list);
+ /* add the last packet */
+ __skb_queue_tail(&reorder_list, pkt);
+ kfree(rfi);
+ ifp->drvr->reorder_flows[flow_id] = NULL;
+ goto netif_rx;
+ }
+ /* from here on we need a flow reorder instance */
+ if (rfi == NULL) {
+ buf_size = sizeof(*rfi);
+ max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+
+ buf_size += (max_idx + 1) * sizeof(pkt);
+
+ /* allocate space for flow reorder info */
+ brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
+ flow_id, max_idx);
+ rfi = kzalloc(buf_size, GFP_ATOMIC);
+ if (rfi == NULL) {
+ brcmf_err("failed to alloc buffer\n");
+ brcmf_netif_rx(ifp, pkt);
+ return;
+ }
+
+ ifp->drvr->reorder_flows[flow_id] = rfi;
+ rfi->pktslots = (struct sk_buff **)(rfi+1);
+ rfi->max_idx = max_idx;
+ }
+ if (flags & BRCMF_RXREORDER_NEW_HOLE) {
+ if (rfi->pend_pkts) {
+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
+ rfi->exp_idx,
+ &reorder_list);
+ WARN_ON(rfi->pend_pkts);
+ } else {
+ __skb_queue_head_init(&reorder_list);
+ }
+ rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+ rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+ rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+ rfi->pktslots[rfi->cur_idx] = pkt;
+ rfi->pend_pkts++;
+ brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
+ flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
+ } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
+ cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+ if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
+ /* still in the current hole */
+ /* enqueue the current on the buffer chain */
+ if (rfi->pktslots[cur_idx] != NULL) {
+ brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
+ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+ rfi->pktslots[cur_idx] = NULL;
+ }
+ rfi->pktslots[cur_idx] = pkt;
+ rfi->pend_pkts++;
+ rfi->cur_idx = cur_idx;
+ brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
+ flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+ /* can return now as there is no reorder
+ * list to process.
+ */
+ return;
+ }
+ if (rfi->exp_idx == cur_idx) {
+ if (rfi->pktslots[cur_idx] != NULL) {
+ brcmf_dbg(INFO, "error buffer pending..free it\n");
+ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+ rfi->pktslots[cur_idx] = NULL;
+ }
+ rfi->pktslots[cur_idx] = pkt;
+ rfi->pend_pkts++;
+
+ /* got the expected one. flush from current to expected
+ * and update expected
+ */
+ brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
+ flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+ rfi->cur_idx = cur_idx;
+ rfi->exp_idx = exp_idx;
+
+ brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
+ &reorder_list);
+ brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
+ flow_id, skb_queue_len(&reorder_list),
+ rfi->pend_pkts);
+ } else {
+ u8 end_idx;
+
+ brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
+ flow_id, flags, rfi->cur_idx, rfi->exp_idx,
+ cur_idx, exp_idx);
+ if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+ end_idx = rfi->exp_idx;
+ else
+ end_idx = exp_idx;
+
+ /* flush pkts first */
+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+ &reorder_list);
+
+ if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
+ __skb_queue_tail(&reorder_list, pkt);
+ } else {
+ rfi->pktslots[cur_idx] = pkt;
+ rfi->pend_pkts++;
+ }
+ rfi->exp_idx = exp_idx;
+ rfi->cur_idx = cur_idx;
+ }
+ } else {
+ /* explicity window move updating the expected index */
+ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+ brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
+ flow_id, flags, rfi->exp_idx, exp_idx);
+ if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+ end_idx = rfi->exp_idx;
+ else
+ end_idx = exp_idx;
+
+ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+ &reorder_list);
+ __skb_queue_tail(&reorder_list, pkt);
+ /* set the new expected idx */
+ rfi->exp_idx = exp_idx;
+ }
+netif_rx:
+ skb_queue_walk_safe(&reorder_list, pkt, pnext) {
+ __skb_unlink(pkt, &reorder_list);
+ brcmf_netif_rx(ifp, pkt);
+ }
+}
+
+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
+{
+ struct brcmf_if *ifp;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+ struct brcmf_skb_reorder_data *rd;
+ u8 ifidx;
+ int ret;
+
+ brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
+
+ /* process and remove protocol-specific header */
+ ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
+ ifp = drvr->iflist[ifidx];
+
+ if (ret || !ifp || !ifp->ndev) {
+ if ((ret != -ENODATA) && ifp)
+ ifp->stats.rx_errors++;
+ brcmu_pkt_buf_free_skb(skb);
+ return;
+ }
+
+ rd = (struct brcmf_skb_reorder_data *)skb->cb;
+ if (rd->reorder)
+ brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
+ else
+ brcmf_netif_rx(ifp, skb);
+}
+
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
+ bool success)
+{
+ struct brcmf_if *ifp;
+ struct ethhdr *eh;
+ u16 type;
+
+ ifp = drvr->iflist[ifidx];
+ if (!ifp)
+ goto done;
+
+ eh = (struct ethhdr *)(txp->data);
+ type = ntohs(eh->h_proto);
+
+ if (type == ETH_P_PAE) {
+ atomic_dec(&ifp->pend_8021x_cnt);
+ if (waitqueue_active(&ifp->pend_8021x_wait))
+ wake_up(&ifp->pend_8021x_wait);
+ }
+
+ if (!success)
+ ifp->stats.tx_errors++;
+done:
+ brcmu_pkt_buf_free_skb(txp);
+}
+
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+ u8 ifidx;
+
+ /* await txstatus signal for firmware if active */
+ if (brcmf_fws_fc_active(drvr->fws)) {
+ if (!success)
+ brcmf_fws_bustxfail(drvr->fws, txp);
+ } else {
+ if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
+ brcmu_pkt_buf_free_skb(txp);
+ else
+ brcmf_txfinalize(drvr, txp, ifidx, success);
+ }
+}
+
+static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
+ return &ifp->stats;
+}
+
+static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ snprintf(info->version, sizeof(info->version), "n/a");
+ strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
+ strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
+ sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops brcmf_ethtool_ops = {
+ .get_drvinfo = brcmf_ethtool_get_drvinfo,
+};
+
+static int brcmf_netdev_stop(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
+ brcmf_cfg80211_down(ndev);
+
+ /* Set state and stop OS transmissions */
+ netif_stop_queue(ndev);
+
+ return 0;
+}
+
+static int brcmf_netdev_open(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_bus *bus_if = drvr->bus_if;
+ u32 toe_ol;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
+ /* If bus is not ready, can't continue */
+ if (bus_if->state != BRCMF_BUS_DATA) {
+ brcmf_err("failed bus is not ready\n");
+ return -EAGAIN;
+ }
+
+ atomic_set(&ifp->pend_8021x_cnt, 0);
+
+ /* Get current TOE mode from dongle */
+ if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
+ && (toe_ol & TOE_TX_CSUM_OL) != 0)
+ ndev->features |= NETIF_F_IP_CSUM;
+ else
+ ndev->features &= ~NETIF_F_IP_CSUM;
+
+ if (brcmf_cfg80211_up(ndev)) {
+ brcmf_err("failed to bring up cfg80211\n");
+ return -EIO;
+ }
+
+ /* Allow transmit calls */
+ netif_start_queue(ndev);
+ return 0;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_pri = {
+ .ndo_open = brcmf_netdev_open,
+ .ndo_stop = brcmf_netdev_stop,
+ .ndo_get_stats = brcmf_netdev_get_stats,
+ .ndo_start_xmit = brcmf_netdev_start_xmit,
+ .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+ .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
+int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
+{
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct net_device *ndev;
+ s32 err;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+ ifp->mac_addr);
+ ndev = ifp->ndev;
+
+ /* set appropriate operations */
+ ndev->netdev_ops = &brcmf_netdev_ops_pri;
+
+ ndev->hard_header_len += drvr->hdrlen;
+ ndev->ethtool_ops = &brcmf_ethtool_ops;
+
+ drvr->rxsz = ndev->mtu + ndev->hard_header_len +
+ drvr->hdrlen;
+
+ /* set the mac address */
+ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+ INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+ INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
+ if (rtnl_locked)
+ err = register_netdevice(ndev);
+ else
+ err = register_netdev(ndev);
+ if (err != 0) {
+ brcmf_err("couldn't register the net device\n");
+ goto fail;
+ }
+
+ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+ ndev->destructor = brcmf_cfg80211_free_netdev;
+ return 0;
+
+fail:
+ drvr->iflist[ifp->bssidx] = NULL;
+ ndev->netdev_ops = NULL;
+ free_netdev(ndev);
+ return -EBADE;
+}
+
+static int brcmf_net_p2p_open(struct net_device *ndev)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ return brcmf_cfg80211_up(ndev);
+}
+
+static int brcmf_net_p2p_stop(struct net_device *ndev)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ return brcmf_cfg80211_down(ndev);
+}
+
+static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ if (skb)
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_p2p = {
+ .ndo_open = brcmf_net_p2p_open,
+ .ndo_stop = brcmf_net_p2p_stop,
+ .ndo_start_xmit = brcmf_net_p2p_start_xmit
+};
+
+static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
+{
+ struct net_device *ndev;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+ ifp->mac_addr);
+ ndev = ifp->ndev;
+
+ ndev->netdev_ops = &brcmf_netdev_ops_p2p;
+
+ /* set the mac address */
+ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+ if (register_netdev(ndev) != 0) {
+ brcmf_err("couldn't register the p2p net device\n");
+ goto fail;
+ }
+
+ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+ return 0;
+
+fail:
+ ifp->drvr->iflist[ifp->bssidx] = NULL;
+ ndev->netdev_ops = NULL;
+ free_netdev(ndev);
+ return -EBADE;
+}
+
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+ char *name, u8 *mac_addr)
+{
+ struct brcmf_if *ifp;
+ struct net_device *ndev;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
+
+ ifp = drvr->iflist[bssidx];
+ /*
+ * Delete the existing interface before overwriting it
+ * in case we missed the BRCMF_E_IF_DEL event.
+ */
+ if (ifp) {
+ brcmf_err("ERROR: netdev:%s already exists\n",
+ ifp->ndev->name);
+ if (ifidx) {
+ netif_stop_queue(ifp->ndev);
+ unregister_netdev(ifp->ndev);
+ free_netdev(ifp->ndev);
+ drvr->iflist[bssidx] = NULL;
+ } else {
+ brcmf_err("ignore IF event\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ if (!brcmf_p2p_enable && bssidx == 1) {
+ /* this is P2P_DEVICE interface */
+ brcmf_dbg(INFO, "allocate non-netdev interface\n");
+ ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
+ if (!ifp)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ brcmf_dbg(INFO, "allocate netdev interface\n");
+ /* Allocate netdev, including space for private structure */
+ ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN,
+ ether_setup);
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ ifp = netdev_priv(ndev);
+ ifp->ndev = ndev;
+ }
+
+ ifp->drvr = drvr;
+ drvr->iflist[bssidx] = ifp;
+ ifp->ifidx = ifidx;
+ ifp->bssidx = bssidx;
+
+ init_waitqueue_head(&ifp->pend_8021x_wait);
+ spin_lock_init(&ifp->netif_stop_lock);
+
+ if (mac_addr != NULL)
+ memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
+
+ brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
+ current->pid, name, ifp->mac_addr);
+
+ return ifp;
+}
+
+void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
+{
+ struct brcmf_if *ifp;
+
+ ifp = drvr->iflist[bssidx];
+ drvr->iflist[bssidx] = NULL;
+ if (!ifp) {
+ brcmf_err("Null interface, idx=%d\n", bssidx);
+ return;
+ }
+ brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
+ if (ifp->ndev) {
+ if (bssidx == 0) {
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+ rtnl_lock();
+ brcmf_netdev_stop(ifp->ndev);
+ rtnl_unlock();
+ }
+ } else {
+ netif_stop_queue(ifp->ndev);
+ }
+
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+ cancel_work_sync(&ifp->setmacaddr_work);
+ cancel_work_sync(&ifp->multicast_work);
+ }
+ /* unregister will take care of freeing it */
+ unregister_netdev(ifp->ndev);
+ } else {
+ kfree(ifp);
+ }
+}
+
+int brcmf_attach(struct device *dev)
+{
+ struct brcmf_pub *drvr = NULL;
+ int ret = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Allocate primary brcmf_info */
+ drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
+ if (!drvr)
+ return -ENOMEM;
+
+ mutex_init(&drvr->proto_block);
+
+ /* Link to bus module */
+ drvr->hdrlen = 0;
+ drvr->bus_if = dev_get_drvdata(dev);
+ drvr->bus_if->drvr = drvr;
+
+ /* create device debugfs folder */
+ brcmf_debugfs_attach(drvr);
+
+ /* Attach and link in the protocol */
+ ret = brcmf_proto_attach(drvr);
+ if (ret != 0) {
+ brcmf_err("brcmf_prot_attach failed\n");
+ goto fail;
+ }
+
+ /* attach firmware event handler */
+ brcmf_fweh_attach(drvr);
+
+ return ret;
+
+fail:
+ brcmf_detach(dev);
+
+ return ret;
+}
+
+int brcmf_bus_start(struct device *dev)
+{
+ int ret = -1;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+ struct brcmf_if *ifp;
+ struct brcmf_if *p2p_ifp;
+
+ brcmf_dbg(TRACE, "\n");
+
+ /* add primary networking interface */
+ ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
+ if (IS_ERR(ifp))
+ return PTR_ERR(ifp);
+
+ if (brcmf_p2p_enable)
+ p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+ else
+ p2p_ifp = NULL;
+ if (IS_ERR(p2p_ifp))
+ p2p_ifp = NULL;
+
+ /* signal bus ready */
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
+
+ /* Bus is ready, do any initialization */
+ ret = brcmf_c_preinit_dcmds(ifp);
+ if (ret < 0)
+ goto fail;
+
+ brcmf_feat_attach(drvr);
+
+ ret = brcmf_fws_init(drvr);
+ if (ret < 0)
+ goto fail;
+
+ brcmf_fws_add_interface(ifp);
+
+ drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
+ if (drvr->config == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = brcmf_fweh_activate_events(ifp);
+ if (ret < 0)
+ goto fail;
+
+ ret = brcmf_net_attach(ifp, false);
+fail:
+ if (ret < 0) {
+ brcmf_err("failed: %d\n", ret);
+ brcmf_cfg80211_detach(drvr->config);
+ if (drvr->fws) {
+ brcmf_fws_del_interface(ifp);
+ brcmf_fws_deinit(drvr);
+ }
+ if (drvr->iflist[0]) {
+ free_netdev(ifp->ndev);
+ drvr->iflist[0] = NULL;
+ }
+ if (p2p_ifp) {
+ free_netdev(p2p_ifp->ndev);
+ drvr->iflist[1] = NULL;
+ }
+ return ret;
+ }
+ if ((brcmf_p2p_enable) && (p2p_ifp))
+ if (brcmf_net_p2p_attach(p2p_ifp) < 0)
+ brcmf_p2p_enable = 0;
+
+ return 0;
+}
+
+void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ if (drvr) {
+ drvr->hdrlen += len;
+ }
+}
+
+static void brcmf_bus_detach(struct brcmf_pub *drvr)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (drvr) {
+ /* Stop the bus module */
+ brcmf_bus_stop(drvr->bus_if);
+ }
+}
+
+void brcmf_dev_reset(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ if (drvr == NULL)
+ return;
+
+ if (drvr->iflist[0])
+ brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+}
+
+void brcmf_detach(struct device *dev)
+{
+ s32 i;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (drvr == NULL)
+ return;
+
+ /* stop firmware event handling */
+ brcmf_fweh_detach(drvr);
+
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
+
+ /* make sure primary interface removed last */
+ for (i = BRCMF_MAX_IFS-1; i > -1; i--)
+ if (drvr->iflist[i]) {
+ brcmf_fws_del_interface(drvr->iflist[i]);
+ brcmf_del_if(drvr, i);
+ }
+
+ brcmf_cfg80211_detach(drvr->config);
+
+ brcmf_fws_deinit(drvr);
+
+ brcmf_bus_detach(drvr);
+
+ brcmf_proto_detach(drvr);
+
+ brcmf_debugfs_detach(drvr);
+ bus_if->drvr = NULL;
+ kfree(drvr);
+}
+
+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_if *ifp = bus_if->drvr->iflist[0];
+
+ return brcmf_fil_iovar_data_set(ifp, name, data, len);
+}
+
+static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
+{
+ return atomic_read(&ifp->pend_8021x_cnt);
+}
+
+int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ int err;
+
+ err = wait_event_timeout(ifp->pend_8021x_wait,
+ !brcmf_get_pend_8021x_cnt(ifp),
+ msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
+
+ WARN_ON(!err);
+
+ return !err;
+}
+
+static void brcmf_driver_register(struct work_struct *work)
+{
+#ifdef CONFIG_BRCMFMAC_SDIO
+ brcmf_sdio_register();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+ brcmf_usb_register();
+#endif
+#ifdef CONFIG_BRCMFMAC_PCIE
+ brcmf_pcie_register();
+#endif
+}
+static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
+
+static int __init brcmfmac_module_init(void)
+{
+ brcmf_debugfs_init();
+#ifdef CONFIG_BRCMFMAC_SDIO
+ brcmf_sdio_init();
+#endif
+ if (!schedule_work(&brcmf_driver_work))
+ return -EBUSY;
+
+ return 0;
+}
+
+static void __exit brcmfmac_module_exit(void)
+{
+ cancel_work_sync(&brcmf_driver_work);
+
+#ifdef CONFIG_BRCMFMAC_SDIO
+ brcmf_sdio_exit();
+#endif
+#ifdef CONFIG_BRCMFMAC_USB
+ brcmf_usb_exit();
+#endif
+#ifdef CONFIG_BRCMFMAC_PCIE
+ brcmf_pcie_exit();
+#endif
+ brcmf_debugfs_exit();
+}
+
+module_init(brcmfmac_module_init);
+module_exit(brcmfmac_module_exit);
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef BRCMFMAC_CORE_H
+#define BRCMFMAC_CORE_H
+
+#include "fweh.h"
+
+#define TOE_TX_CSUM_OL 0x00000001
+#define TOE_RX_CSUM_OL 0x00000002
+
+/* For supporting multiple interfaces */
+#define BRCMF_MAX_IFS 16
+
+#define DOT11_MAX_DEFAULT_KEYS 4
+
+/* Small, medium and maximum buffer size for dcmd
+ */
+#define BRCMF_DCMD_SMLEN 256
+#define BRCMF_DCMD_MEDLEN 1536
+#define BRCMF_DCMD_MAXLEN 8192
+
+/* IOCTL from host to device are limited in lenght. A device can only handle
+ * ethernet frame size. This limitation is to be applied by protocol layer.
+ */
+#define BRCMF_TX_IOCTL_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
+
+#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256
+
+/* Length of firmware version string stored for
+ * ethtool driver info which uses 32 bytes as well.
+ */
+#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
+
+/**
+ * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
+ *
+ * @pktslots: dynamic allocated array for ordering AMPDU packets.
+ * @flow_id: AMPDU flow identifier.
+ * @cur_idx: last AMPDU index from firmware.
+ * @exp_idx: expected next AMPDU index.
+ * @max_idx: maximum amount of packets per AMPDU.
+ * @pend_pkts: number of packets currently in @pktslots.
+ */
+struct brcmf_ampdu_rx_reorder {
+ struct sk_buff **pktslots;
+ u8 flow_id;
+ u8 cur_idx;
+ u8 exp_idx;
+ u8 max_idx;
+ u8 pend_pkts;
+};
+
+/* Forward decls for struct brcmf_pub (see below) */
+struct brcmf_proto; /* device communication protocol info */
+struct brcmf_cfg80211_dev; /* cfg80211 device info */
+struct brcmf_fws_info; /* firmware signalling info */
+
+/* Common structure for module and instance linkage */
+struct brcmf_pub {
+ /* Linkage ponters */
+ struct brcmf_bus *bus_if;
+ struct brcmf_proto *proto;
+ struct brcmf_cfg80211_info *config;
+
+ /* Internal brcmf items */
+ uint hdrlen; /* Total BRCMF header length (proto + bus) */
+ uint rxsz; /* Rx buffer size bus module should use */
+
+ /* Dongle media info */
+ char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
+ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
+
+ /* Multicast data packets sent to dongle */
+ unsigned long tx_multicast;
+
+ struct brcmf_if *iflist[BRCMF_MAX_IFS];
+
+ struct mutex proto_block;
+ unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
+
+ struct brcmf_fweh_info fweh;
+
+ struct brcmf_fws_info *fws;
+
+ struct brcmf_ampdu_rx_reorder
+ *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
+
+ u32 feat_flags;
+ u32 chip_quirks;
+
+#ifdef DEBUG
+ struct dentry *dbgfs_dir;
+#endif
+};
+
+/* forward declarations */
+struct brcmf_cfg80211_vif;
+struct brcmf_fws_mac_descriptor;
+
+/**
+ * enum brcmf_netif_stop_reason - reason for stopping netif queue.
+ *
+ * @BRCMF_NETIF_STOP_REASON_FWS_FC:
+ * netif stopped due to firmware signalling flow control.
+ * @BRCMF_NETIF_STOP_REASON_FLOW:
+ * netif stopped due to flowring full.
+ */
+enum brcmf_netif_stop_reason {
+ BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
+ BRCMF_NETIF_STOP_REASON_FLOW = 2
+};
+
+/**
+ * struct brcmf_if - interface control information.
+ *
+ * @drvr: points to device related information.
+ * @vif: points to cfg80211 specific interface information.
+ * @ndev: associated network device.
+ * @stats: interface specific network statistics.
+ * @setmacaddr_work: worker object for setting mac address.
+ * @multicast_work: worker object for multicast provisioning.
+ * @fws_desc: interface specific firmware-signalling descriptor.
+ * @ifidx: interface index in device firmware.
+ * @bssidx: index of bss associated with this interface.
+ * @mac_addr: assigned mac address.
+ * @netif_stop: bitmap indicates reason why netif queues are stopped.
+ * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
+ * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
+ * @pend_8021x_wait: used for signalling change in count.
+ */
+struct brcmf_if {
+ struct brcmf_pub *drvr;
+ struct brcmf_cfg80211_vif *vif;
+ struct net_device *ndev;
+ struct net_device_stats stats;
+ struct work_struct setmacaddr_work;
+ struct work_struct multicast_work;
+ struct brcmf_fws_mac_descriptor *fws_desc;
+ int ifidx;
+ s32 bssidx;
+ u8 mac_addr[ETH_ALEN];
+ u8 netif_stop;
+ spinlock_t netif_stop_lock;
+ atomic_t pend_8021x_cnt;
+ wait_queue_head_t pend_8021x_wait;
+};
+
+struct brcmf_skb_reorder_data {
+ u8 *reorder;
+};
+
+int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
+
+/* Return pointer to interface name */
+char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
+
+int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+ char *name, u8 *mac_addr);
+void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state);
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
+ bool success);
+void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+
+/* Sets dongle media info (drv_version, mac address). */
+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+
+#endif /* BRCMFMAC_CORE_H */
--- /dev/null
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/debugfs.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
+
+static struct dentry *root_folder;
+
+void brcmf_debugfs_init(void)
+{
+ root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(root_folder))
+ root_folder = NULL;
+}
+
+void brcmf_debugfs_exit(void)
+{
+ if (!root_folder)
+ return;
+
+ debugfs_remove_recursive(root_folder);
+ root_folder = NULL;
+}
+
+static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus = dev_get_drvdata(seq->private);
+
+ seq_printf(seq, "chip: %x(%u) rev %u\n",
+ bus->chip, bus->chip, bus->chiprev);
+ return 0;
+}
+
+int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+ struct device *dev = drvr->bus_if->dev;
+
+ if (!root_folder)
+ return -ENODEV;
+
+ drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
+ brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
+
+ return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
+}
+
+void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+ if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+ debugfs_remove_recursive(drvr->dbgfs_dir);
+}
+
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
+{
+ return drvr->dbgfs_dir;
+}
+
+struct brcmf_debugfs_entry {
+ int (*read)(struct seq_file *seq, void *data);
+ struct brcmf_pub *drvr;
+};
+
+static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
+{
+ struct brcmf_debugfs_entry *entry = inode->i_private;
+
+ return single_open(f, entry->read, entry->drvr->bus_if->dev);
+}
+
+static const struct file_operations brcmf_debugfs_def_ops = {
+ .owner = THIS_MODULE,
+ .open = brcmf_debugfs_entry_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek
+};
+
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data))
+{
+ struct dentry *dentry = drvr->dbgfs_dir;
+ struct brcmf_debugfs_entry *entry;
+
+ if (IS_ERR_OR_NULL(dentry))
+ return -ENOENT;
+
+ entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->read = read_fn;
+ entry->drvr = drvr;
+
+ dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+ &brcmf_debugfs_def_ops);
+
+ return PTR_ERR_OR_ZERO(dentry);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BRCMFMAC_DEBUG_H
+#define BRCMFMAC_DEBUG_H
+
+/* message levels */
+#define BRCMF_TRACE_VAL 0x00000002
+#define BRCMF_INFO_VAL 0x00000004
+#define BRCMF_DATA_VAL 0x00000008
+#define BRCMF_CTL_VAL 0x00000010
+#define BRCMF_TIMER_VAL 0x00000020
+#define BRCMF_HDRS_VAL 0x00000040
+#define BRCMF_BYTES_VAL 0x00000080
+#define BRCMF_INTR_VAL 0x00000100
+#define BRCMF_GLOM_VAL 0x00000200
+#define BRCMF_EVENT_VAL 0x00000400
+#define BRCMF_BTA_VAL 0x00000800
+#define BRCMF_FIL_VAL 0x00001000
+#define BRCMF_USB_VAL 0x00002000
+#define BRCMF_SCAN_VAL 0x00004000
+#define BRCMF_CONN_VAL 0x00008000
+#define BRCMF_BCDC_VAL 0x00010000
+#define BRCMF_SDIO_VAL 0x00020000
+#define BRCMF_MSGBUF_VAL 0x00040000
+#define BRCMF_PCIE_VAL 0x00080000
+
+/* set default print format */
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/* Macro for error messages. net_ratelimit() is used when driver
+ * debugging is not selected. When debugging the driver error
+ * messages are as important as other tracing or even more so.
+ */
+#ifndef CONFIG_BRCM_TRACING
+#ifdef CONFIG_BRCMDBG
+#define brcmf_err(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
+#else
+#define brcmf_err(fmt, ...) \
+ do { \
+ if (net_ratelimit()) \
+ pr_err("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+#endif
+#else
+__printf(2, 3)
+void __brcmf_err(const char *func, const char *fmt, ...);
+#define brcmf_err(fmt, ...) \
+ __brcmf_err(__func__, fmt, ##__VA_ARGS__)
+#endif
+
+#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
+__printf(3, 4)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...);
+#define brcmf_dbg(level, fmt, ...) \
+do { \
+ __brcmf_dbg(BRCMF_##level##_VAL, __func__, \
+ fmt, ##__VA_ARGS__); \
+} while (0)
+#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL)
+#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL)
+#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL)
+#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL)
+#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL)
+#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
+#define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL)
+
+#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
+
+#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+
+#define BRCMF_DATA_ON() 0
+#define BRCMF_CTL_ON() 0
+#define BRCMF_HDRS_ON() 0
+#define BRCMF_BYTES_ON() 0
+#define BRCMF_GLOM_ON() 0
+#define BRCMF_EVENT_ON() 0
+#define BRCMF_FIL_ON() 0
+
+#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
+
+#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \
+do { \
+ trace_brcmf_hexdump((void *)data, len); \
+ if (test) \
+ brcmu_dbg_hex_dump(data, len, fmt, ##__VA_ARGS__); \
+} while (0)
+
+extern int brcmf_msg_level;
+
+struct brcmf_pub;
+#ifdef DEBUG
+void brcmf_debugfs_init(void);
+void brcmf_debugfs_exit(void);
+int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+void brcmf_debugfs_detach(struct brcmf_pub *drvr);
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data));
+#else
+static inline void brcmf_debugfs_init(void)
+{
+}
+static inline void brcmf_debugfs_exit(void)
+{
+}
+static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+ return 0;
+}
+static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+}
+static inline
+int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data))
+{
+ return 0;
+}
+#endif
+
+#endif /* BRCMFMAC_DEBUG_H */
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/****************
- * Common types *
- */
-
-#ifndef _BRCMF_H_
-#define _BRCMF_H_
-
-#include "fweh.h"
-
-#define TOE_TX_CSUM_OL 0x00000001
-#define TOE_RX_CSUM_OL 0x00000002
-
-/* For supporting multiple interfaces */
-#define BRCMF_MAX_IFS 16
-
-#define DOT11_MAX_DEFAULT_KEYS 4
-
-/* Small, medium and maximum buffer size for dcmd
- */
-#define BRCMF_DCMD_SMLEN 256
-#define BRCMF_DCMD_MEDLEN 1536
-#define BRCMF_DCMD_MAXLEN 8192
-
-/* IOCTL from host to device are limited in lenght. A device can only handle
- * ethernet frame size. This limitation is to be applied by protocol layer.
- */
-#define BRCMF_TX_IOCTL_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
-
-#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256
-
-/* Length of firmware version string stored for
- * ethtool driver info which uses 32 bytes as well.
- */
-#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
-
-/**
- * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
- *
- * @pktslots: dynamic allocated array for ordering AMPDU packets.
- * @flow_id: AMPDU flow identifier.
- * @cur_idx: last AMPDU index from firmware.
- * @exp_idx: expected next AMPDU index.
- * @max_idx: maximum amount of packets per AMPDU.
- * @pend_pkts: number of packets currently in @pktslots.
- */
-struct brcmf_ampdu_rx_reorder {
- struct sk_buff **pktslots;
- u8 flow_id;
- u8 cur_idx;
- u8 exp_idx;
- u8 max_idx;
- u8 pend_pkts;
-};
-
-/* Forward decls for struct brcmf_pub (see below) */
-struct brcmf_proto; /* device communication protocol info */
-struct brcmf_cfg80211_dev; /* cfg80211 device info */
-struct brcmf_fws_info; /* firmware signalling info */
-
-/* Common structure for module and instance linkage */
-struct brcmf_pub {
- /* Linkage ponters */
- struct brcmf_bus *bus_if;
- struct brcmf_proto *proto;
- struct brcmf_cfg80211_info *config;
-
- /* Internal brcmf items */
- uint hdrlen; /* Total BRCMF header length (proto + bus) */
- uint rxsz; /* Rx buffer size bus module should use */
- u8 wme_dp; /* wme discard priority */
-
- /* Dongle media info */
- char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
- u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
-
- /* Multicast data packets sent to dongle */
- unsigned long tx_multicast;
-
- struct brcmf_if *iflist[BRCMF_MAX_IFS];
-
- struct mutex proto_block;
- unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
-
- struct brcmf_fweh_info fweh;
-
- struct brcmf_fws_info *fws;
-
- struct brcmf_ampdu_rx_reorder
- *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
-
- u32 feat_flags;
- u32 chip_quirks;
-
-#ifdef DEBUG
- struct dentry *dbgfs_dir;
-#endif
-};
-
-/* forward declarations */
-struct brcmf_cfg80211_vif;
-struct brcmf_fws_mac_descriptor;
-
-/**
- * enum brcmf_netif_stop_reason - reason for stopping netif queue.
- *
- * @BRCMF_NETIF_STOP_REASON_FWS_FC:
- * netif stopped due to firmware signalling flow control.
- * @BRCMF_NETIF_STOP_REASON_FLOW:
- * netif stopped due to flowring full.
- */
-enum brcmf_netif_stop_reason {
- BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
- BRCMF_NETIF_STOP_REASON_FLOW = 2
-};
-
-/**
- * struct brcmf_if - interface control information.
- *
- * @drvr: points to device related information.
- * @vif: points to cfg80211 specific interface information.
- * @ndev: associated network device.
- * @stats: interface specific network statistics.
- * @setmacaddr_work: worker object for setting mac address.
- * @multicast_work: worker object for multicast provisioning.
- * @fws_desc: interface specific firmware-signalling descriptor.
- * @ifidx: interface index in device firmware.
- * @bssidx: index of bss associated with this interface.
- * @mac_addr: assigned mac address.
- * @netif_stop: bitmap indicates reason why netif queues are stopped.
- * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
- * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
- * @pend_8021x_wait: used for signalling change in count.
- */
-struct brcmf_if {
- struct brcmf_pub *drvr;
- struct brcmf_cfg80211_vif *vif;
- struct net_device *ndev;
- struct net_device_stats stats;
- struct work_struct setmacaddr_work;
- struct work_struct multicast_work;
- struct brcmf_fws_mac_descriptor *fws_desc;
- int ifidx;
- s32 bssidx;
- u8 mac_addr[ETH_ALEN];
- u8 netif_stop;
- spinlock_t netif_stop_lock;
- atomic_t pend_8021x_cnt;
- wait_queue_head_t pend_8021x_wait;
-};
-
-struct brcmf_skb_reorder_data {
- u8 *reorder;
-};
-
-int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
-
-/* Return pointer to interface name */
-char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
-
-int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
-struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
- char *name, u8 *mac_addr);
-void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
-void brcmf_txflowblock_if(struct brcmf_if *ifp,
- enum brcmf_netif_stop_reason reason, bool state);
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
- bool success);
-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
-
-/* Sets dongle media info (drv_version, mac address). */
-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
-
-#endif /* _BRCMF_H_ */
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCMF_BUS_H_
-#define _BRCMF_BUS_H_
-
-#include "dhd_dbg.h"
-
-/* IDs of the 6 default common rings of msgbuf protocol */
-#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0
-#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1
-#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2
-#define BRCMF_D2H_MSGRING_TX_COMPLETE 3
-#define BRCMF_D2H_MSGRING_RX_COMPLETE 4
-
-#define BRCMF_NROF_H2D_COMMON_MSGRINGS 2
-#define BRCMF_NROF_D2H_COMMON_MSGRINGS 3
-#define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \
- BRCMF_NROF_D2H_COMMON_MSGRINGS)
-
-/* The level of bus communication with the dongle */
-enum brcmf_bus_state {
- BRCMF_BUS_UNKNOWN, /* Not determined yet */
- BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */
- BRCMF_BUS_DOWN, /* Not ready for frame transfers */
- BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
- BRCMF_BUS_DATA /* Ready for frame transfers */
-};
-
-/* The level of bus communication with the dongle */
-enum brcmf_bus_protocol_type {
- BRCMF_PROTO_BCDC,
- BRCMF_PROTO_MSGBUF
-};
-
-struct brcmf_bus_dcmd {
- char *name;
- char *param;
- int param_len;
- struct list_head list;
-};
-
-/**
- * struct brcmf_bus_ops - bus callback operations.
- *
- * @preinit: execute bus/device specific dongle init commands (optional).
- * @init: prepare for communication with dongle.
- * @stop: clear pending frames, disable data flow.
- * @txdata: send a data frame to the dongle. When the data
- * has been transferred, the common driver must be
- * notified using brcmf_txcomplete(). The common
- * driver calls this function with interrupts
- * disabled.
- * @txctl: transmit a control request message to dongle.
- * @rxctl: receive a control response message from dongle.
- * @gettxq: obtain a reference of bus transmit queue (optional).
- * @wowl_config: specify if dongle is configured for wowl when going to suspend
- *
- * This structure provides an abstract interface towards the
- * bus specific driver. For control messages to common driver
- * will assure there is only one active transaction. Unless
- * indicated otherwise these callbacks are mandatory.
- */
-struct brcmf_bus_ops {
- int (*preinit)(struct device *dev);
- void (*stop)(struct device *dev);
- int (*txdata)(struct device *dev, struct sk_buff *skb);
- int (*txctl)(struct device *dev, unsigned char *msg, uint len);
- int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
- struct pktq * (*gettxq)(struct device *dev);
- void (*wowl_config)(struct device *dev, bool enabled);
-};
-
-
-/**
- * struct brcmf_bus_msgbuf - bus ringbuf if in case of msgbuf.
- *
- * @commonrings: commonrings which are always there.
- * @flowrings: commonrings which are dynamically created and destroyed for data.
- * @rx_dataoffset: if set then all rx data has this this offset.
- * @max_rxbufpost: maximum number of buffers to post for rx.
- * @nrof_flowrings: number of flowrings.
- */
-struct brcmf_bus_msgbuf {
- struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS];
- struct brcmf_commonring **flowrings;
- u32 rx_dataoffset;
- u32 max_rxbufpost;
- u32 nrof_flowrings;
-};
-
-
-/**
- * struct brcmf_bus - interface structure between common and bus layer
- *
- * @bus_priv: pointer to private bus device.
- * @proto_type: protocol type, bcdc or msgbuf
- * @dev: device pointer of bus device.
- * @drvr: public driver information.
- * @state: operational state of the bus interface.
- * @maxctl: maximum size for rxctl request message.
- * @tx_realloc: number of tx packets realloced for headroom.
- * @dstats: dongle-based statistical data.
- * @dcmd_list: bus/device specific dongle initialization commands.
- * @chip: device identifier of the dongle chip.
- * @wowl_supported: is wowl supported by bus driver.
- * @chiprev: revision of the dongle chip.
- */
-struct brcmf_bus {
- union {
- struct brcmf_sdio_dev *sdio;
- struct brcmf_usbdev *usb;
- struct brcmf_pciedev *pcie;
- } bus_priv;
- enum brcmf_bus_protocol_type proto_type;
- struct device *dev;
- struct brcmf_pub *drvr;
- enum brcmf_bus_state state;
- uint maxctl;
- unsigned long tx_realloc;
- u32 chip;
- u32 chiprev;
- bool always_use_fws_queue;
- bool wowl_supported;
-
- struct brcmf_bus_ops *ops;
- struct brcmf_bus_msgbuf *msgbuf;
-};
-
-/*
- * callback wrappers
- */
-static inline int brcmf_bus_preinit(struct brcmf_bus *bus)
-{
- if (!bus->ops->preinit)
- return 0;
- return bus->ops->preinit(bus->dev);
-}
-
-static inline void brcmf_bus_stop(struct brcmf_bus *bus)
-{
- bus->ops->stop(bus->dev);
-}
-
-static inline int brcmf_bus_txdata(struct brcmf_bus *bus, struct sk_buff *skb)
-{
- return bus->ops->txdata(bus->dev, skb);
-}
-
-static inline
-int brcmf_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
-{
- return bus->ops->txctl(bus->dev, msg, len);
-}
-
-static inline
-int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
-{
- return bus->ops->rxctl(bus->dev, msg, len);
-}
-
-static inline
-struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)
-{
- if (!bus->ops->gettxq)
- return ERR_PTR(-ENOENT);
-
- return bus->ops->gettxq(bus->dev);
-}
-
-static inline
-void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
-{
- if (bus->ops->wowl_config)
- bus->ops->wowl_config(bus->dev, enabled);
-}
-
-static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
-{
- return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
-}
-
-static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
- enum brcmf_bus_state new_state)
-{
- /* NOMEDIUM is permanent */
- if (bus->state == BRCMF_BUS_NOMEDIUM)
- return;
-
- brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
- bus->state = new_state;
-}
-
-/*
- * interface functions from common layer
- */
-
-bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
- int prec);
-
-/* Receive frame for delivery to OS. Callee disposes of rxp. */
-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
-
-/* Indication from bus module regarding presence/insertion of dongle. */
-int brcmf_attach(struct device *dev);
-/* Indication from bus module regarding removal/absence of dongle */
-void brcmf_detach(struct device *dev);
-/* Indication from bus module that dongle should be reset */
-void brcmf_dev_reset(struct device *dev);
-/* Indication from bus module to change flow-control state */
-void brcmf_txflowblock(struct device *dev, bool state);
-
-/* Notify the bus has transferred the tx packet to firmware */
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
-
-int brcmf_bus_start(struct device *dev);
-s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,
- u32 len);
-void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
-
-#ifdef CONFIG_BRCMFMAC_SDIO
-void brcmf_sdio_exit(void);
-void brcmf_sdio_init(void);
-void brcmf_sdio_register(void);
-#endif
-#ifdef CONFIG_BRCMFMAC_USB
-void brcmf_usb_exit(void);
-void brcmf_usb_register(void);
-#endif
-
-#endif /* _BRCMF_BUS_H_ */
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <brcmu_wifi.h>
-#include <brcmu_utils.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "fwil.h"
-#include "fwil_types.h"
-#include "tracepoint.h"
-
-#define PKTFILTER_BUF_SIZE 128
-#define BRCMF_DEFAULT_BCN_TIMEOUT 3
-#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
-#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
-#define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00"
-
-/* boost value for RSSI_DELTA in preferred join selection */
-#define BRCMF_JOIN_PREF_RSSI_BOOST 8
-
-
-bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
- struct sk_buff *pkt, int prec)
-{
- struct sk_buff *p;
- int eprec = -1; /* precedence to evict from */
- bool discard_oldest;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- /* Fast case, precedence queue is not full and we are also not
- * exceeding total queue length
- */
- if (!pktq_pfull(q, prec) && !pktq_full(q)) {
- brcmu_pktq_penq(q, prec, pkt);
- return true;
- }
-
- /* Determine precedence from which to evict packet, if any */
- if (pktq_pfull(q, prec))
- eprec = prec;
- else if (pktq_full(q)) {
- p = brcmu_pktq_peek_tail(q, &eprec);
- if (eprec > prec)
- return false;
- }
-
- /* Evict if needed */
- if (eprec >= 0) {
- /* Detect queueing to unconfigured precedence */
- discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
- if (eprec == prec && !discard_oldest)
- return false; /* refuse newer (incoming) packet */
- /* Evict packet according to discard policy */
- p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
- brcmu_pktq_pdeq_tail(q, eprec);
- if (p == NULL)
- brcmf_err("brcmu_pktq_penq() failed, oldest %d\n",
- discard_oldest);
-
- brcmu_pkt_buf_free_skb(p);
- }
-
- /* Enqueue */
- p = brcmu_pktq_penq(q, prec, pkt);
- if (p == NULL)
- brcmf_err("brcmu_pktq_penq() failed\n");
-
- return p != NULL;
-}
-
-/* Convert user's input in hex pattern to byte-size mask */
-static int brcmf_c_pattern_atoh(char *src, char *dst)
-{
- int i;
- if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
- brcmf_err("Mask invalid format. Needs to start with 0x\n");
- return -EINVAL;
- }
- src = src + 2; /* Skip past 0x */
- if (strlen(src) % 2 != 0) {
- brcmf_err("Mask invalid format. Length must be even.\n");
- return -EINVAL;
- }
- for (i = 0; *src != '\0'; i++) {
- unsigned long res;
- char num[3];
- strncpy(num, src, 2);
- num[2] = '\0';
- if (kstrtoul(num, 16, &res))
- return -EINVAL;
- dst[i] = (u8)res;
- src += 2;
- }
- return i;
-}
-
-static void
-brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
- int master_mode)
-{
- unsigned long res;
- char *argv;
- char *arg_save = NULL, *arg_org = NULL;
- s32 err;
- struct brcmf_pkt_filter_enable_le enable_parm;
-
- arg_save = kstrdup(arg, GFP_ATOMIC);
- if (!arg_save)
- goto fail;
-
- arg_org = arg_save;
-
- argv = strsep(&arg_save, " ");
-
- if (argv == NULL) {
- brcmf_err("No args provided\n");
- goto fail;
- }
-
- /* Parse packet filter id. */
- enable_parm.id = 0;
- if (!kstrtoul(argv, 0, &res))
- enable_parm.id = cpu_to_le32((u32)res);
-
- /* Enable/disable the specified filter. */
- enable_parm.enable = cpu_to_le32(enable);
-
- err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
- sizeof(enable_parm));
- if (err)
- brcmf_err("Set pkt_filter_enable error (%d)\n", err);
-
- /* Control the master mode */
- err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
- if (err)
- brcmf_err("Set pkt_filter_mode error (%d)\n", err);
-
-fail:
- kfree(arg_org);
-}
-
-static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
-{
- struct brcmf_pkt_filter_le *pkt_filter;
- unsigned long res;
- int buf_len;
- s32 err;
- u32 mask_size;
- u32 pattern_size;
- char *argv[8], *buf = NULL;
- int i = 0;
- char *arg_save = NULL, *arg_org = NULL;
-
- arg_save = kstrdup(arg, GFP_ATOMIC);
- if (!arg_save)
- goto fail;
-
- arg_org = arg_save;
-
- buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
- if (!buf)
- goto fail;
-
- argv[i] = strsep(&arg_save, " ");
- while (argv[i]) {
- i++;
- if (i >= 8) {
- brcmf_err("Too many parameters\n");
- goto fail;
- }
- argv[i] = strsep(&arg_save, " ");
- }
-
- if (i != 6) {
- brcmf_err("Not enough args provided %d\n", i);
- goto fail;
- }
-
- pkt_filter = (struct brcmf_pkt_filter_le *)buf;
-
- /* Parse packet filter id. */
- pkt_filter->id = 0;
- if (!kstrtoul(argv[0], 0, &res))
- pkt_filter->id = cpu_to_le32((u32)res);
-
- /* Parse filter polarity. */
- pkt_filter->negate_match = 0;
- if (!kstrtoul(argv[1], 0, &res))
- pkt_filter->negate_match = cpu_to_le32((u32)res);
-
- /* Parse filter type. */
- pkt_filter->type = 0;
- if (!kstrtoul(argv[2], 0, &res))
- pkt_filter->type = cpu_to_le32((u32)res);
-
- /* Parse pattern filter offset. */
- pkt_filter->u.pattern.offset = 0;
- if (!kstrtoul(argv[3], 0, &res))
- pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
-
- /* Parse pattern filter mask. */
- mask_size = brcmf_c_pattern_atoh(argv[4],
- (char *)pkt_filter->u.pattern.mask_and_pattern);
-
- /* Parse pattern filter pattern. */
- pattern_size = brcmf_c_pattern_atoh(argv[5],
- (char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);
-
- if (mask_size != pattern_size) {
- brcmf_err("Mask and pattern not the same size\n");
- goto fail;
- }
-
- pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
- buf_len = offsetof(struct brcmf_pkt_filter_le,
- u.pattern.mask_and_pattern);
- buf_len += mask_size + pattern_size;
-
- err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
- buf_len);
- if (err)
- brcmf_err("Set pkt_filter_add error (%d)\n", err);
-
-fail:
- kfree(arg_org);
-
- kfree(buf);
-}
-
-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
-{
- s8 eventmask[BRCMF_EVENTING_MASK_LEN];
- u8 buf[BRCMF_DCMD_SMLEN];
- struct brcmf_join_pref_params join_pref_params[2];
- char *ptr;
- s32 err;
-
- /* retreive mac address */
- err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
- sizeof(ifp->mac_addr));
- if (err < 0) {
- brcmf_err("Retreiving cur_etheraddr failed, %d\n",
- err);
- goto done;
- }
- memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
-
- /* query for 'ver' to get version info from firmware */
- memset(buf, 0, sizeof(buf));
- strcpy(buf, "ver");
- err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
- if (err < 0) {
- brcmf_err("Retreiving version information failed, %d\n",
- err);
- goto done;
- }
- ptr = (char *)buf;
- strsep(&ptr, "\n");
-
- /* Print fw version info */
- brcmf_err("Firmware version = %s\n", buf);
-
- /* locate firmware version number for ethtool */
- ptr = strrchr(buf, ' ') + 1;
- strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
-
- /* set mpc */
- err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
- if (err) {
- brcmf_err("failed setting mpc\n");
- goto done;
- }
-
- /*
- * Setup timeout if Beacons are lost and roam is off to report
- * link down
- */
- err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
- BRCMF_DEFAULT_BCN_TIMEOUT);
- if (err) {
- brcmf_err("bcn_timeout error (%d)\n", err);
- goto done;
- }
-
- /* Enable/Disable build-in roaming to allowed ext supplicant to take
- * of romaing
- */
- err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
- if (err) {
- brcmf_err("roam_off error (%d)\n", err);
- goto done;
- }
-
- /* Setup join_pref to select target by RSSI(with boost on 5GHz) */
- join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
- join_pref_params[0].len = 2;
- join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
- join_pref_params[0].band = WLC_BAND_5G;
- join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
- join_pref_params[1].len = 2;
- join_pref_params[1].rssi_gain = 0;
- join_pref_params[1].band = 0;
- err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
- sizeof(join_pref_params));
- if (err)
- brcmf_err("Set join_pref error (%d)\n", err);
-
- /* Setup event_msgs, enable E_IF */
- err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
- BRCMF_EVENTING_MASK_LEN);
- if (err) {
- brcmf_err("Get event_msgs error (%d)\n", err);
- goto done;
- }
- setbit(eventmask, BRCMF_E_IF);
- err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
- BRCMF_EVENTING_MASK_LEN);
- if (err) {
- brcmf_err("Set event_msgs error (%d)\n", err);
- goto done;
- }
-
- /* Setup default scan channel time */
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
- BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
- if (err) {
- brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
- err);
- goto done;
- }
-
- /* Setup default scan unassoc time */
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
- BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
- if (err) {
- brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
- err);
- goto done;
- }
-
- /* Setup packet filter */
- brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
- brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
- 0, true);
-
- /* do bus specific preinit here */
- err = brcmf_bus_preinit(ifp->drvr->bus_if);
-done:
- return err;
-}
-
-#ifdef CONFIG_BRCM_TRACING
-void __brcmf_err(const char *func, const char *fmt, ...)
-{
- struct va_format vaf = {
- .fmt = fmt,
- };
- va_list args;
-
- va_start(args, fmt);
- vaf.va = &args;
- pr_err("%s: %pV", func, &vaf);
- trace_brcmf_err(func, &vaf);
- va_end(args);
-}
-#endif
-#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
-void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
-{
- struct va_format vaf = {
- .fmt = fmt,
- };
- va_list args;
-
- va_start(args, fmt);
- vaf.va = &args;
- if (brcmf_msg_level & level)
- pr_debug("%s %pV", func, &vaf);
- trace_brcmf_dbg(level, func, &vaf);
- va_end(args);
-}
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2012 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <linux/debugfs.h>
-#include <linux/netdevice.h>
-#include <linux/module.h>
-
-#include <brcmu_wifi.h>
-#include <brcmu_utils.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-
-static struct dentry *root_folder;
-
-void brcmf_debugfs_init(void)
-{
- root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (IS_ERR(root_folder))
- root_folder = NULL;
-}
-
-void brcmf_debugfs_exit(void)
-{
- if (!root_folder)
- return;
-
- debugfs_remove_recursive(root_folder);
- root_folder = NULL;
-}
-
-static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
-{
- struct brcmf_bus *bus = dev_get_drvdata(seq->private);
-
- seq_printf(seq, "chip: %x(%u) rev %u\n",
- bus->chip, bus->chip, bus->chiprev);
- return 0;
-}
-
-int brcmf_debugfs_attach(struct brcmf_pub *drvr)
-{
- struct device *dev = drvr->bus_if->dev;
-
- if (!root_folder)
- return -ENODEV;
-
- drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
- brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
-
- return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
-}
-
-void brcmf_debugfs_detach(struct brcmf_pub *drvr)
-{
- if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
- debugfs_remove_recursive(drvr->dbgfs_dir);
-}
-
-struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
-{
- return drvr->dbgfs_dir;
-}
-
-struct brcmf_debugfs_entry {
- int (*read)(struct seq_file *seq, void *data);
- struct brcmf_pub *drvr;
-};
-
-static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
-{
- struct brcmf_debugfs_entry *entry = inode->i_private;
-
- return single_open(f, entry->read, entry->drvr->bus_if->dev);
-}
-
-static const struct file_operations brcmf_debugfs_def_ops = {
- .owner = THIS_MODULE,
- .open = brcmf_debugfs_entry_open,
- .release = single_release,
- .read = seq_read,
- .llseek = seq_lseek
-};
-
-int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
- int (*read_fn)(struct seq_file *seq, void *data))
-{
- struct dentry *dentry = drvr->dbgfs_dir;
- struct brcmf_debugfs_entry *entry;
-
- if (IS_ERR_OR_NULL(dentry))
- return -ENOENT;
-
- entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->read = read_fn;
- entry->drvr = drvr;
-
- dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
- &brcmf_debugfs_def_ops);
-
- return PTR_ERR_OR_ZERO(dentry);
-}
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCMF_DBG_H_
-#define _BRCMF_DBG_H_
-
-/* message levels */
-#define BRCMF_TRACE_VAL 0x00000002
-#define BRCMF_INFO_VAL 0x00000004
-#define BRCMF_DATA_VAL 0x00000008
-#define BRCMF_CTL_VAL 0x00000010
-#define BRCMF_TIMER_VAL 0x00000020
-#define BRCMF_HDRS_VAL 0x00000040
-#define BRCMF_BYTES_VAL 0x00000080
-#define BRCMF_INTR_VAL 0x00000100
-#define BRCMF_GLOM_VAL 0x00000200
-#define BRCMF_EVENT_VAL 0x00000400
-#define BRCMF_BTA_VAL 0x00000800
-#define BRCMF_FIL_VAL 0x00001000
-#define BRCMF_USB_VAL 0x00002000
-#define BRCMF_SCAN_VAL 0x00004000
-#define BRCMF_CONN_VAL 0x00008000
-#define BRCMF_BCDC_VAL 0x00010000
-#define BRCMF_SDIO_VAL 0x00020000
-#define BRCMF_MSGBUF_VAL 0x00040000
-#define BRCMF_PCIE_VAL 0x00080000
-
-/* set default print format */
-#undef pr_fmt
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-/* Macro for error messages. net_ratelimit() is used when driver
- * debugging is not selected. When debugging the driver error
- * messages are as important as other tracing or even more so.
- */
-#ifndef CONFIG_BRCM_TRACING
-#ifdef CONFIG_BRCMDBG
-#define brcmf_err(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
-#else
-#define brcmf_err(fmt, ...) \
- do { \
- if (net_ratelimit()) \
- pr_err("%s: " fmt, __func__, ##__VA_ARGS__); \
- } while (0)
-#endif
-#else
-__printf(2, 3)
-void __brcmf_err(const char *func, const char *fmt, ...);
-#define brcmf_err(fmt, ...) \
- __brcmf_err(__func__, fmt, ##__VA_ARGS__)
-#endif
-
-#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
-__printf(3, 4)
-void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...);
-#define brcmf_dbg(level, fmt, ...) \
-do { \
- __brcmf_dbg(BRCMF_##level##_VAL, __func__, \
- fmt, ##__VA_ARGS__); \
-} while (0)
-#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL)
-#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL)
-#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL)
-#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL)
-#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL)
-#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
-#define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL)
-
-#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
-
-#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-
-#define BRCMF_DATA_ON() 0
-#define BRCMF_CTL_ON() 0
-#define BRCMF_HDRS_ON() 0
-#define BRCMF_BYTES_ON() 0
-#define BRCMF_GLOM_ON() 0
-#define BRCMF_EVENT_ON() 0
-#define BRCMF_FIL_ON() 0
-
-#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
-
-#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \
-do { \
- trace_brcmf_hexdump((void *)data, len); \
- if (test) \
- brcmu_dbg_hex_dump(data, len, fmt, ##__VA_ARGS__); \
-} while (0)
-
-extern int brcmf_msg_level;
-
-struct brcmf_pub;
-#ifdef DEBUG
-void brcmf_debugfs_init(void);
-void brcmf_debugfs_exit(void);
-int brcmf_debugfs_attach(struct brcmf_pub *drvr);
-void brcmf_debugfs_detach(struct brcmf_pub *drvr);
-struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
-int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
- int (*read_fn)(struct seq_file *seq, void *data));
-#else
-static inline void brcmf_debugfs_init(void)
-{
-}
-static inline void brcmf_debugfs_exit(void)
-{
-}
-static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
-{
- return 0;
-}
-static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
-{
-}
-static inline
-int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
- int (*read_fn)(struct seq_file *seq, void *data))
-{
- return 0;
-}
-#endif
-
-#endif /* _BRCMF_DBG_H_ */
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <net/cfg80211.h>
-#include <net/rtnetlink.h>
-#include <brcmu_utils.h>
-#include <brcmu_wifi.h>
-
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "fwil_types.h"
-#include "p2p.h"
-#include "wl_cfg80211.h"
-#include "fwil.h"
-#include "fwsignal.h"
-#include "feature.h"
-#include "proto.h"
-#include "pcie.h"
-
-MODULE_AUTHOR("Broadcom Corporation");
-MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
-MODULE_LICENSE("Dual BSD/GPL");
-
-#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */
-
-/* AMPDU rx reordering definitions */
-#define BRCMF_RXREORDER_FLOWID_OFFSET 0
-#define BRCMF_RXREORDER_MAXIDX_OFFSET 2
-#define BRCMF_RXREORDER_FLAGS_OFFSET 4
-#define BRCMF_RXREORDER_CURIDX_OFFSET 6
-#define BRCMF_RXREORDER_EXPIDX_OFFSET 8
-
-#define BRCMF_RXREORDER_DEL_FLOW 0x01
-#define BRCMF_RXREORDER_FLUSH_ALL 0x02
-#define BRCMF_RXREORDER_CURIDX_VALID 0x04
-#define BRCMF_RXREORDER_EXPIDX_VALID 0x08
-#define BRCMF_RXREORDER_NEW_HOLE 0x10
-
-/* Error bits */
-int brcmf_msg_level;
-module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
-MODULE_PARM_DESC(debug, "level of debug output");
-
-/* P2P0 enable */
-static int brcmf_p2p_enable;
-#ifdef CONFIG_BRCMDBG
-module_param_named(p2pon, brcmf_p2p_enable, int, 0);
-MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
-#endif
-
-char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
-{
- if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
- brcmf_err("ifidx %d out of range\n", ifidx);
- return "<if_bad>";
- }
-
- if (drvr->iflist[ifidx] == NULL) {
- brcmf_err("null i/f %d\n", ifidx);
- return "<if_null>";
- }
-
- if (drvr->iflist[ifidx]->ndev)
- return drvr->iflist[ifidx]->ndev->name;
-
- return "<if_none>";
-}
-
-static void _brcmf_set_multicast_list(struct work_struct *work)
-{
- struct brcmf_if *ifp;
- struct net_device *ndev;
- struct netdev_hw_addr *ha;
- u32 cmd_value, cnt;
- __le32 cnt_le;
- char *buf, *bufp;
- u32 buflen;
- s32 err;
-
- ifp = container_of(work, struct brcmf_if, multicast_work);
-
- brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
- ndev = ifp->ndev;
-
- /* Determine initial value of allmulti flag */
- cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
-
- /* Send down the multicast list first. */
- cnt = netdev_mc_count(ndev);
- buflen = sizeof(cnt) + (cnt * ETH_ALEN);
- buf = kmalloc(buflen, GFP_ATOMIC);
- if (!buf)
- return;
- bufp = buf;
-
- cnt_le = cpu_to_le32(cnt);
- memcpy(bufp, &cnt_le, sizeof(cnt_le));
- bufp += sizeof(cnt_le);
-
- netdev_for_each_mc_addr(ha, ndev) {
- if (!cnt)
- break;
- memcpy(bufp, ha->addr, ETH_ALEN);
- bufp += ETH_ALEN;
- cnt--;
- }
-
- err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
- if (err < 0) {
- brcmf_err("Setting mcast_list failed, %d\n", err);
- cmd_value = cnt ? true : cmd_value;
- }
-
- kfree(buf);
-
- /*
- * Now send the allmulti setting. This is based on the setting in the
- * net_device flags, but might be modified above to be turned on if we
- * were trying to set some addresses and dongle rejected it...
- */
- err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
- if (err < 0)
- brcmf_err("Setting allmulti failed, %d\n", err);
-
- /*Finally, pick up the PROMISC flag */
- cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
- if (err < 0)
- brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
- err);
-}
-
-static void
-_brcmf_set_mac_address(struct work_struct *work)
-{
- struct brcmf_if *ifp;
- s32 err;
-
- ifp = container_of(work, struct brcmf_if, setmacaddr_work);
-
- brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
- err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
- ETH_ALEN);
- if (err < 0) {
- brcmf_err("Setting cur_etheraddr failed, %d\n", err);
- } else {
- brcmf_dbg(TRACE, "MAC address updated to %pM\n",
- ifp->mac_addr);
- memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
- }
-}
-
-static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct sockaddr *sa = (struct sockaddr *)addr;
-
- memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
- schedule_work(&ifp->setmacaddr_work);
- return 0;
-}
-
-static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- schedule_work(&ifp->multicast_work);
-}
-
-static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
- struct net_device *ndev)
-{
- int ret;
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_pub *drvr = ifp->drvr;
- struct ethhdr *eh = (struct ethhdr *)(skb->data);
-
- brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
-
- /* Can the device send data? */
- if (drvr->bus_if->state != BRCMF_BUS_DATA) {
- brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
- netif_stop_queue(ndev);
- dev_kfree_skb(skb);
- ret = -ENODEV;
- goto done;
- }
-
- if (!drvr->iflist[ifp->bssidx]) {
- brcmf_err("bad ifidx %d\n", ifp->bssidx);
- netif_stop_queue(ndev);
- dev_kfree_skb(skb);
- ret = -ENODEV;
- goto done;
- }
-
- /* Make sure there's enough room for any header */
- if (skb_headroom(skb) < drvr->hdrlen) {
- struct sk_buff *skb2;
-
- brcmf_dbg(INFO, "%s: insufficient headroom\n",
- brcmf_ifname(drvr, ifp->bssidx));
- drvr->bus_if->tx_realloc++;
- skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
- dev_kfree_skb(skb);
- skb = skb2;
- if (skb == NULL) {
- brcmf_err("%s: skb_realloc_headroom failed\n",
- brcmf_ifname(drvr, ifp->bssidx));
- ret = -ENOMEM;
- goto done;
- }
- }
-
- /* validate length for ether packet */
- if (skb->len < sizeof(*eh)) {
- ret = -EINVAL;
- dev_kfree_skb(skb);
- goto done;
- }
-
- if (eh->h_proto == htons(ETH_P_PAE))
- atomic_inc(&ifp->pend_8021x_cnt);
-
- ret = brcmf_fws_process_skb(ifp, skb);
-
-done:
- if (ret) {
- ifp->stats.tx_dropped++;
- } else {
- ifp->stats.tx_packets++;
- ifp->stats.tx_bytes += skb->len;
- }
-
- /* Return ok: we always eat the packet */
- return NETDEV_TX_OK;
-}
-
-void brcmf_txflowblock_if(struct brcmf_if *ifp,
- enum brcmf_netif_stop_reason reason, bool state)
-{
- unsigned long flags;
-
- if (!ifp || !ifp->ndev)
- return;
-
- brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
- ifp->bssidx, ifp->netif_stop, reason, state);
-
- spin_lock_irqsave(&ifp->netif_stop_lock, flags);
- if (state) {
- if (!ifp->netif_stop)
- netif_stop_queue(ifp->ndev);
- ifp->netif_stop |= reason;
- } else {
- ifp->netif_stop &= ~reason;
- if (!ifp->netif_stop)
- netif_wake_queue(ifp->ndev);
- }
- spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
-}
-
-void brcmf_txflowblock(struct device *dev, bool state)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- brcmf_fws_bus_blocked(drvr, state);
-}
-
-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
-{
- skb->dev = ifp->ndev;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
- if (skb->pkt_type == PACKET_MULTICAST)
- ifp->stats.multicast++;
-
- /* Process special event packets */
- brcmf_fweh_process_skb(ifp->drvr, skb);
-
- if (!(ifp->ndev->flags & IFF_UP)) {
- brcmu_pkt_buf_free_skb(skb);
- return;
- }
-
- ifp->stats.rx_bytes += skb->len;
- ifp->stats.rx_packets++;
-
- brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
- if (in_interrupt())
- netif_rx(skb);
- else
- /* If the receive is not processed inside an ISR,
- * the softirqd must be woken explicitly to service
- * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni().
- */
- netif_rx_ni(skb);
-}
-
-static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
- u8 start, u8 end,
- struct sk_buff_head *skb_list)
-{
- /* initialize return list */
- __skb_queue_head_init(skb_list);
-
- if (rfi->pend_pkts == 0) {
- brcmf_dbg(INFO, "no packets in reorder queue\n");
- return;
- }
-
- do {
- if (rfi->pktslots[start]) {
- __skb_queue_tail(skb_list, rfi->pktslots[start]);
- rfi->pktslots[start] = NULL;
- }
- start++;
- if (start > rfi->max_idx)
- start = 0;
- } while (start != end);
- rfi->pend_pkts -= skb_queue_len(skb_list);
-}
-
-static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
- struct sk_buff *pkt)
-{
- u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
- struct brcmf_ampdu_rx_reorder *rfi;
- struct sk_buff_head reorder_list;
- struct sk_buff *pnext;
- u8 flags;
- u32 buf_size;
-
- flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
- flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
-
- /* validate flags and flow id */
- if (flags == 0xFF) {
- brcmf_err("invalid flags...so ignore this packet\n");
- brcmf_netif_rx(ifp, pkt);
- return;
- }
-
- rfi = ifp->drvr->reorder_flows[flow_id];
- if (flags & BRCMF_RXREORDER_DEL_FLOW) {
- brcmf_dbg(INFO, "flow-%d: delete\n",
- flow_id);
-
- if (rfi == NULL) {
- brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
- flow_id);
- brcmf_netif_rx(ifp, pkt);
- return;
- }
-
- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
- &reorder_list);
- /* add the last packet */
- __skb_queue_tail(&reorder_list, pkt);
- kfree(rfi);
- ifp->drvr->reorder_flows[flow_id] = NULL;
- goto netif_rx;
- }
- /* from here on we need a flow reorder instance */
- if (rfi == NULL) {
- buf_size = sizeof(*rfi);
- max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-
- buf_size += (max_idx + 1) * sizeof(pkt);
-
- /* allocate space for flow reorder info */
- brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
- flow_id, max_idx);
- rfi = kzalloc(buf_size, GFP_ATOMIC);
- if (rfi == NULL) {
- brcmf_err("failed to alloc buffer\n");
- brcmf_netif_rx(ifp, pkt);
- return;
- }
-
- ifp->drvr->reorder_flows[flow_id] = rfi;
- rfi->pktslots = (struct sk_buff **)(rfi+1);
- rfi->max_idx = max_idx;
- }
- if (flags & BRCMF_RXREORDER_NEW_HOLE) {
- if (rfi->pend_pkts) {
- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
- rfi->exp_idx,
- &reorder_list);
- WARN_ON(rfi->pend_pkts);
- } else {
- __skb_queue_head_init(&reorder_list);
- }
- rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
- rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
- rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
- rfi->pktslots[rfi->cur_idx] = pkt;
- rfi->pend_pkts++;
- brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
- flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
- } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
- cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-
- if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
- /* still in the current hole */
- /* enqueue the current on the buffer chain */
- if (rfi->pktslots[cur_idx] != NULL) {
- brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
- rfi->pktslots[cur_idx] = NULL;
- }
- rfi->pktslots[cur_idx] = pkt;
- rfi->pend_pkts++;
- rfi->cur_idx = cur_idx;
- brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
- flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-
- /* can return now as there is no reorder
- * list to process.
- */
- return;
- }
- if (rfi->exp_idx == cur_idx) {
- if (rfi->pktslots[cur_idx] != NULL) {
- brcmf_dbg(INFO, "error buffer pending..free it\n");
- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
- rfi->pktslots[cur_idx] = NULL;
- }
- rfi->pktslots[cur_idx] = pkt;
- rfi->pend_pkts++;
-
- /* got the expected one. flush from current to expected
- * and update expected
- */
- brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
- flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-
- rfi->cur_idx = cur_idx;
- rfi->exp_idx = exp_idx;
-
- brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
- &reorder_list);
- brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
- flow_id, skb_queue_len(&reorder_list),
- rfi->pend_pkts);
- } else {
- u8 end_idx;
-
- brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
- flow_id, flags, rfi->cur_idx, rfi->exp_idx,
- cur_idx, exp_idx);
- if (flags & BRCMF_RXREORDER_FLUSH_ALL)
- end_idx = rfi->exp_idx;
- else
- end_idx = exp_idx;
-
- /* flush pkts first */
- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
- &reorder_list);
-
- if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
- __skb_queue_tail(&reorder_list, pkt);
- } else {
- rfi->pktslots[cur_idx] = pkt;
- rfi->pend_pkts++;
- }
- rfi->exp_idx = exp_idx;
- rfi->cur_idx = cur_idx;
- }
- } else {
- /* explicity window move updating the expected index */
- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-
- brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
- flow_id, flags, rfi->exp_idx, exp_idx);
- if (flags & BRCMF_RXREORDER_FLUSH_ALL)
- end_idx = rfi->exp_idx;
- else
- end_idx = exp_idx;
-
- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
- &reorder_list);
- __skb_queue_tail(&reorder_list, pkt);
- /* set the new expected idx */
- rfi->exp_idx = exp_idx;
- }
-netif_rx:
- skb_queue_walk_safe(&reorder_list, pkt, pnext) {
- __skb_unlink(pkt, &reorder_list);
- brcmf_netif_rx(ifp, pkt);
- }
-}
-
-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
-{
- struct brcmf_if *ifp;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_skb_reorder_data *rd;
- u8 ifidx;
- int ret;
-
- brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-
- /* process and remove protocol-specific header */
- ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
- ifp = drvr->iflist[ifidx];
-
- if (ret || !ifp || !ifp->ndev) {
- if ((ret != -ENODATA) && ifp)
- ifp->stats.rx_errors++;
- brcmu_pkt_buf_free_skb(skb);
- return;
- }
-
- rd = (struct brcmf_skb_reorder_data *)skb->cb;
- if (rd->reorder)
- brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
- else
- brcmf_netif_rx(ifp, skb);
-}
-
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
- bool success)
-{
- struct brcmf_if *ifp;
- struct ethhdr *eh;
- u16 type;
-
- ifp = drvr->iflist[ifidx];
- if (!ifp)
- goto done;
-
- eh = (struct ethhdr *)(txp->data);
- type = ntohs(eh->h_proto);
-
- if (type == ETH_P_PAE) {
- atomic_dec(&ifp->pend_8021x_cnt);
- if (waitqueue_active(&ifp->pend_8021x_wait))
- wake_up(&ifp->pend_8021x_wait);
- }
-
- if (!success)
- ifp->stats.tx_errors++;
-done:
- brcmu_pkt_buf_free_skb(txp);
-}
-
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- u8 ifidx;
-
- /* await txstatus signal for firmware if active */
- if (brcmf_fws_fc_active(drvr->fws)) {
- if (!success)
- brcmf_fws_bustxfail(drvr->fws, txp);
- } else {
- if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
- brcmu_pkt_buf_free_skb(txp);
- else
- brcmf_txfinalize(drvr, txp, ifidx, success);
- }
-}
-
-static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
- return &ifp->stats;
-}
-
-static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
- struct ethtool_drvinfo *info)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_pub *drvr = ifp->drvr;
-
- strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- snprintf(info->version, sizeof(info->version), "n/a");
- strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
- strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
- sizeof(info->bus_info));
-}
-
-static const struct ethtool_ops brcmf_ethtool_ops = {
- .get_drvinfo = brcmf_ethtool_get_drvinfo,
-};
-
-static int brcmf_netdev_stop(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
- brcmf_cfg80211_down(ndev);
-
- /* Set state and stop OS transmissions */
- netif_stop_queue(ndev);
-
- return 0;
-}
-
-static int brcmf_netdev_open(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_pub *drvr = ifp->drvr;
- struct brcmf_bus *bus_if = drvr->bus_if;
- u32 toe_ol;
-
- brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
- /* If bus is not ready, can't continue */
- if (bus_if->state != BRCMF_BUS_DATA) {
- brcmf_err("failed bus is not ready\n");
- return -EAGAIN;
- }
-
- atomic_set(&ifp->pend_8021x_cnt, 0);
-
- /* Get current TOE mode from dongle */
- if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
- && (toe_ol & TOE_TX_CSUM_OL) != 0)
- ndev->features |= NETIF_F_IP_CSUM;
- else
- ndev->features &= ~NETIF_F_IP_CSUM;
-
- if (brcmf_cfg80211_up(ndev)) {
- brcmf_err("failed to bring up cfg80211\n");
- return -EIO;
- }
-
- /* Allow transmit calls */
- netif_start_queue(ndev);
- return 0;
-}
-
-static const struct net_device_ops brcmf_netdev_ops_pri = {
- .ndo_open = brcmf_netdev_open,
- .ndo_stop = brcmf_netdev_stop,
- .ndo_get_stats = brcmf_netdev_get_stats,
- .ndo_start_xmit = brcmf_netdev_start_xmit,
- .ndo_set_mac_address = brcmf_netdev_set_mac_address,
- .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
-int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
-{
- struct brcmf_pub *drvr = ifp->drvr;
- struct net_device *ndev;
- s32 err;
-
- brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
- ifp->mac_addr);
- ndev = ifp->ndev;
-
- /* set appropriate operations */
- ndev->netdev_ops = &brcmf_netdev_ops_pri;
-
- ndev->hard_header_len += drvr->hdrlen;
- ndev->ethtool_ops = &brcmf_ethtool_ops;
-
- drvr->rxsz = ndev->mtu + ndev->hard_header_len +
- drvr->hdrlen;
-
- /* set the mac address */
- memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
-
- INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
- INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
-
- if (rtnl_locked)
- err = register_netdevice(ndev);
- else
- err = register_netdev(ndev);
- if (err != 0) {
- brcmf_err("couldn't register the net device\n");
- goto fail;
- }
-
- brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
-
- ndev->destructor = brcmf_cfg80211_free_netdev;
- return 0;
-
-fail:
- drvr->iflist[ifp->bssidx] = NULL;
- ndev->netdev_ops = NULL;
- free_netdev(ndev);
- return -EBADE;
-}
-
-static int brcmf_net_p2p_open(struct net_device *ndev)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- return brcmf_cfg80211_up(ndev);
-}
-
-static int brcmf_net_p2p_stop(struct net_device *ndev)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- return brcmf_cfg80211_down(ndev);
-}
-
-static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
- struct net_device *ndev)
-{
- if (skb)
- dev_kfree_skb_any(skb);
-
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops brcmf_netdev_ops_p2p = {
- .ndo_open = brcmf_net_p2p_open,
- .ndo_stop = brcmf_net_p2p_stop,
- .ndo_start_xmit = brcmf_net_p2p_start_xmit
-};
-
-static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
-{
- struct net_device *ndev;
-
- brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
- ifp->mac_addr);
- ndev = ifp->ndev;
-
- ndev->netdev_ops = &brcmf_netdev_ops_p2p;
-
- /* set the mac address */
- memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
-
- if (register_netdev(ndev) != 0) {
- brcmf_err("couldn't register the p2p net device\n");
- goto fail;
- }
-
- brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
-
- return 0;
-
-fail:
- ifp->drvr->iflist[ifp->bssidx] = NULL;
- ndev->netdev_ops = NULL;
- free_netdev(ndev);
- return -EBADE;
-}
-
-struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
- char *name, u8 *mac_addr)
-{
- struct brcmf_if *ifp;
- struct net_device *ndev;
-
- brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
-
- ifp = drvr->iflist[bssidx];
- /*
- * Delete the existing interface before overwriting it
- * in case we missed the BRCMF_E_IF_DEL event.
- */
- if (ifp) {
- brcmf_err("ERROR: netdev:%s already exists\n",
- ifp->ndev->name);
- if (ifidx) {
- netif_stop_queue(ifp->ndev);
- unregister_netdev(ifp->ndev);
- free_netdev(ifp->ndev);
- drvr->iflist[bssidx] = NULL;
- } else {
- brcmf_err("ignore IF event\n");
- return ERR_PTR(-EINVAL);
- }
- }
-
- if (!brcmf_p2p_enable && bssidx == 1) {
- /* this is P2P_DEVICE interface */
- brcmf_dbg(INFO, "allocate non-netdev interface\n");
- ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
- if (!ifp)
- return ERR_PTR(-ENOMEM);
- } else {
- brcmf_dbg(INFO, "allocate netdev interface\n");
- /* Allocate netdev, including space for private structure */
- ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN,
- ether_setup);
- if (!ndev)
- return ERR_PTR(-ENOMEM);
-
- ifp = netdev_priv(ndev);
- ifp->ndev = ndev;
- }
-
- ifp->drvr = drvr;
- drvr->iflist[bssidx] = ifp;
- ifp->ifidx = ifidx;
- ifp->bssidx = bssidx;
-
- init_waitqueue_head(&ifp->pend_8021x_wait);
- spin_lock_init(&ifp->netif_stop_lock);
-
- if (mac_addr != NULL)
- memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
-
- brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
- current->pid, name, ifp->mac_addr);
-
- return ifp;
-}
-
-void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
-{
- struct brcmf_if *ifp;
-
- ifp = drvr->iflist[bssidx];
- drvr->iflist[bssidx] = NULL;
- if (!ifp) {
- brcmf_err("Null interface, idx=%d\n", bssidx);
- return;
- }
- brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
- if (ifp->ndev) {
- if (bssidx == 0) {
- if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
- rtnl_lock();
- brcmf_netdev_stop(ifp->ndev);
- rtnl_unlock();
- }
- } else {
- netif_stop_queue(ifp->ndev);
- }
-
- if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
- cancel_work_sync(&ifp->setmacaddr_work);
- cancel_work_sync(&ifp->multicast_work);
- }
- /* unregister will take care of freeing it */
- unregister_netdev(ifp->ndev);
- } else {
- kfree(ifp);
- }
-}
-
-int brcmf_attach(struct device *dev)
-{
- struct brcmf_pub *drvr = NULL;
- int ret = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Allocate primary brcmf_info */
- drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
- if (!drvr)
- return -ENOMEM;
-
- mutex_init(&drvr->proto_block);
-
- /* Link to bus module */
- drvr->hdrlen = 0;
- drvr->bus_if = dev_get_drvdata(dev);
- drvr->bus_if->drvr = drvr;
-
- /* create device debugfs folder */
- brcmf_debugfs_attach(drvr);
-
- /* Attach and link in the protocol */
- ret = brcmf_proto_attach(drvr);
- if (ret != 0) {
- brcmf_err("brcmf_prot_attach failed\n");
- goto fail;
- }
-
- /* attach firmware event handler */
- brcmf_fweh_attach(drvr);
-
- return ret;
-
-fail:
- brcmf_detach(dev);
-
- return ret;
-}
-
-int brcmf_bus_start(struct device *dev)
-{
- int ret = -1;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_if *ifp;
- struct brcmf_if *p2p_ifp;
-
- brcmf_dbg(TRACE, "\n");
-
- /* add primary networking interface */
- ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
- if (IS_ERR(ifp))
- return PTR_ERR(ifp);
-
- if (brcmf_p2p_enable)
- p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
- else
- p2p_ifp = NULL;
- if (IS_ERR(p2p_ifp))
- p2p_ifp = NULL;
-
- /* signal bus ready */
- brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
-
- /* Bus is ready, do any initialization */
- ret = brcmf_c_preinit_dcmds(ifp);
- if (ret < 0)
- goto fail;
-
- brcmf_feat_attach(drvr);
-
- ret = brcmf_fws_init(drvr);
- if (ret < 0)
- goto fail;
-
- brcmf_fws_add_interface(ifp);
-
- drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
- if (drvr->config == NULL) {
- ret = -ENOMEM;
- goto fail;
- }
-
- ret = brcmf_fweh_activate_events(ifp);
- if (ret < 0)
- goto fail;
-
- ret = brcmf_net_attach(ifp, false);
-fail:
- if (ret < 0) {
- brcmf_err("failed: %d\n", ret);
- brcmf_cfg80211_detach(drvr->config);
- if (drvr->fws) {
- brcmf_fws_del_interface(ifp);
- brcmf_fws_deinit(drvr);
- }
- if (drvr->iflist[0]) {
- free_netdev(ifp->ndev);
- drvr->iflist[0] = NULL;
- }
- if (p2p_ifp) {
- free_netdev(p2p_ifp->ndev);
- drvr->iflist[1] = NULL;
- }
- return ret;
- }
- if ((brcmf_p2p_enable) && (p2p_ifp))
- if (brcmf_net_p2p_attach(p2p_ifp) < 0)
- brcmf_p2p_enable = 0;
-
- return 0;
-}
-
-void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- if (drvr) {
- drvr->hdrlen += len;
- }
-}
-
-static void brcmf_bus_detach(struct brcmf_pub *drvr)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- if (drvr) {
- /* Stop the bus module */
- brcmf_bus_stop(drvr->bus_if);
- }
-}
-
-void brcmf_dev_reset(struct device *dev)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- if (drvr == NULL)
- return;
-
- if (drvr->iflist[0])
- brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
-}
-
-void brcmf_detach(struct device *dev)
-{
- s32 i;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (drvr == NULL)
- return;
-
- /* stop firmware event handling */
- brcmf_fweh_detach(drvr);
-
- brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
-
- /* make sure primary interface removed last */
- for (i = BRCMF_MAX_IFS-1; i > -1; i--)
- if (drvr->iflist[i]) {
- brcmf_fws_del_interface(drvr->iflist[i]);
- brcmf_del_if(drvr, i);
- }
-
- brcmf_cfg80211_detach(drvr->config);
-
- brcmf_fws_deinit(drvr);
-
- brcmf_bus_detach(drvr);
-
- brcmf_proto_detach(drvr);
-
- brcmf_debugfs_detach(drvr);
- bus_if->drvr = NULL;
- kfree(drvr);
-}
-
-s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_if *ifp = bus_if->drvr->iflist[0];
-
- return brcmf_fil_iovar_data_set(ifp, name, data, len);
-}
-
-static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
-{
- return atomic_read(&ifp->pend_8021x_cnt);
-}
-
-int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- int err;
-
- err = wait_event_timeout(ifp->pend_8021x_wait,
- !brcmf_get_pend_8021x_cnt(ifp),
- msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
-
- WARN_ON(!err);
-
- return !err;
-}
-
-static void brcmf_driver_register(struct work_struct *work)
-{
-#ifdef CONFIG_BRCMFMAC_SDIO
- brcmf_sdio_register();
-#endif
-#ifdef CONFIG_BRCMFMAC_USB
- brcmf_usb_register();
-#endif
-#ifdef CONFIG_BRCMFMAC_PCIE
- brcmf_pcie_register();
-#endif
-}
-static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
-
-static int __init brcmfmac_module_init(void)
-{
- brcmf_debugfs_init();
-#ifdef CONFIG_BRCMFMAC_SDIO
- brcmf_sdio_init();
-#endif
- if (!schedule_work(&brcmf_driver_work))
- return -EBUSY;
-
- return 0;
-}
-
-static void __exit brcmfmac_module_exit(void)
-{
- cancel_work_sync(&brcmf_driver_work);
-
-#ifdef CONFIG_BRCMFMAC_SDIO
- brcmf_sdio_exit();
-#endif
-#ifdef CONFIG_BRCMFMAC_USB
- brcmf_usb_exit();
-#endif
-#ifdef CONFIG_BRCMFMAC_PCIE
- brcmf_pcie_exit();
-#endif
- brcmf_debugfs_exit();
-}
-
-module_init(brcmfmac_module_init);
-module_exit(brcmfmac_module_exit);
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/printk.h>
-#include <linux/pci_ids.h>
-#include <linux/netdevice.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/card.h>
-#include <linux/semaphore.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/bcma/bcma.h>
-#include <linux/debugfs.h>
-#include <linux/vmalloc.h>
-#include <linux/platform_data/brcmfmac-sdio.h>
-#include <linux/moduleparam.h>
-#include <asm/unaligned.h>
-#include <defs.h>
-#include <brcmu_wifi.h>
-#include <brcmu_utils.h>
-#include <brcm_hw_ids.h>
-#include <soc.h>
-#include "sdio_host.h"
-#include "chip.h"
-#include "firmware.h"
-
-#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
-
-#ifdef DEBUG
-
-#define BRCMF_TRAP_INFO_SIZE 80
-
-#define CBUF_LEN (128)
-
-/* Device console log buffer state */
-#define CONSOLE_BUFFER_MAX 2024
-
-struct rte_log_le {
- __le32 buf; /* Can't be pointer on (64-bit) hosts */
- __le32 buf_size;
- __le32 idx;
- char *_buf_compat; /* Redundant pointer for backward compat. */
-};
-
-struct rte_console {
- /* Virtual UART
- * When there is no UART (e.g. Quickturn),
- * the host should write a complete
- * input line directly into cbuf and then write
- * the length into vcons_in.
- * This may also be used when there is a real UART
- * (at risk of conflicting with
- * the real UART). vcons_out is currently unused.
- */
- uint vcons_in;
- uint vcons_out;
-
- /* Output (logging) buffer
- * Console output is written to a ring buffer log_buf at index log_idx.
- * The host may read the output when it sees log_idx advance.
- * Output will be lost if the output wraps around faster than the host
- * polls.
- */
- struct rte_log_le log_le;
-
- /* Console input line buffer
- * Characters are read one at a time into cbuf
- * until <CR> is received, then
- * the buffer is processed as a command line.
- * Also used for virtual UART.
- */
- uint cbuf_idx;
- char cbuf[CBUF_LEN];
-};
-
-#endif /* DEBUG */
-#include <chipcommon.h>
-
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "tracepoint.h"
-
-#define TXQLEN 2048 /* bulk tx queue length */
-#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
-#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
-#define PRIOMASK 7
-
-#define TXRETRIES 2 /* # of retries for tx frames */
-
-#define BRCMF_RXBOUND 50 /* Default for max rx frames in
- one scheduling */
-
-#define BRCMF_TXBOUND 20 /* Default for max tx frames in
- one scheduling */
-
-#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
-
-#define MEMBLOCK 2048 /* Block size used for downloading
- of dongle image */
-#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
- biggest possible glom */
-
-#define BRCMF_FIRSTREAD (1 << 6)
-
-
-/* SBSDIO_DEVICE_CTL */
-
-/* 1: device will assert busy signal when receiving CMD53 */
-#define SBSDIO_DEVCTL_SETBUSY 0x01
-/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
-#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
-/* 1: mask all interrupts to host except the chipActive (rev 8) */
-#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04
-/* 1: isolate internal sdio signals, put external pads in tri-state; requires
- * sdio bus power cycle to clear (rev 9) */
-#define SBSDIO_DEVCTL_PADS_ISO 0x08
-/* Force SD->SB reset mapping (rev 11) */
-#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
-/* Determined by CoreControl bit */
-#define SBSDIO_DEVCTL_RST_CORECTL 0x00
-/* Force backplane reset */
-#define SBSDIO_DEVCTL_RST_BPRESET 0x10
-/* Force no backplane reset */
-#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
-
-/* direct(mapped) cis space */
-
-/* MAPPED common CIS address */
-#define SBSDIO_CIS_BASE_COMMON 0x1000
-/* maximum bytes in one CIS */
-#define SBSDIO_CIS_SIZE_LIMIT 0x200
-/* cis offset addr is < 17 bits */
-#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
-
-/* manfid tuple length, include tuple, link bytes */
-#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
-
-#define CORE_BUS_REG(base, field) \
- (base + offsetof(struct sdpcmd_regs, field))
-
-/* SDIO function 1 register CHIPCLKCSR */
-/* Force ALP request to backplane */
-#define SBSDIO_FORCE_ALP 0x01
-/* Force HT request to backplane */
-#define SBSDIO_FORCE_HT 0x02
-/* Force ILP request to backplane */
-#define SBSDIO_FORCE_ILP 0x04
-/* Make ALP ready (power up xtal) */
-#define SBSDIO_ALP_AVAIL_REQ 0x08
-/* Make HT ready (power up PLL) */
-#define SBSDIO_HT_AVAIL_REQ 0x10
-/* Squelch clock requests from HW */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
-/* Status: ALP is ready */
-#define SBSDIO_ALP_AVAIL 0x40
-/* Status: HT is ready */
-#define SBSDIO_HT_AVAIL 0x80
-#define SBSDIO_CSR_MASK 0x1F
-#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-#define SBSDIO_CLKAV(regval, alponly) \
- (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
-
-/* intstatus */
-#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
-#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
-#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
-#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
-#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
-#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
-#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
-#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
-#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
-#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
-#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
-#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
-#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
-#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
-#define I_PC (1 << 10) /* descriptor error */
-#define I_PD (1 << 11) /* data error */
-#define I_DE (1 << 12) /* Descriptor protocol Error */
-#define I_RU (1 << 13) /* Receive descriptor Underflow */
-#define I_RO (1 << 14) /* Receive fifo Overflow */
-#define I_XU (1 << 15) /* Transmit fifo Underflow */
-#define I_RI (1 << 16) /* Receive Interrupt */
-#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
-#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
-#define I_XI (1 << 24) /* Transmit Interrupt */
-#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
-#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
-#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
-#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
-#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */
-#define I_SRESET (1 << 30) /* CCCR RES interrupt */
-#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
-#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
-#define I_DMA (I_RI | I_XI | I_ERRORS)
-
-/* corecontrol */
-#define CC_CISRDY (1 << 0) /* CIS Ready */
-#define CC_BPRESEN (1 << 1) /* CCCR RES signal */
-#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
-#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */
-#define CC_XMTDATAAVAIL_MODE (1 << 4)
-#define CC_XMTDATAAVAIL_CTRL (1 << 5)
-
-/* SDA_FRAMECTRL */
-#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
-#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
-#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
-#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
-
-/*
- * Software allocation of To SB Mailbox resources
- */
-
-/* tosbmailbox bits corresponding to intstatus bits */
-#define SMB_NAK (1 << 0) /* Frame NAK */
-#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
-#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
-#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
-
-/* tosbmailboxdata */
-#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
-
-/*
- * Software allocation of To Host Mailbox resources
- */
-
-/* intstatus bits */
-#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
-#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
-#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
-#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
-
-/* tohostmailboxdata */
-#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
-#define HMB_DATA_DEVREADY 2 /* talk to host after enable */
-#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
-#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
-
-#define HMB_DATA_FCDATA_MASK 0xff000000
-#define HMB_DATA_FCDATA_SHIFT 24
-
-#define HMB_DATA_VERSION_MASK 0x00ff0000
-#define HMB_DATA_VERSION_SHIFT 16
-
-/*
- * Software-defined protocol header
- */
-
-/* Current protocol version */
-#define SDPCM_PROT_VERSION 4
-
-/*
- * Shared structure between dongle and the host.
- * The structure contains pointers to trap or assert information.
- */
-#define SDPCM_SHARED_VERSION 0x0003
-#define SDPCM_SHARED_VERSION_MASK 0x00FF
-#define SDPCM_SHARED_ASSERT_BUILT 0x0100
-#define SDPCM_SHARED_ASSERT 0x0200
-#define SDPCM_SHARED_TRAP 0x0400
-
-/* Space for header read, limit for data packets */
-#define MAX_HDR_READ (1 << 6)
-#define MAX_RX_DATASZ 2048
-
-/* Bump up limit on waiting for HT to account for first startup;
- * if the image is doing a CRC calculation before programming the PMU
- * for HT availability, it could take a couple hundred ms more, so
- * max out at a 1 second (1000000us).
- */
-#undef PMU_MAX_TRANSITION_DLY
-#define PMU_MAX_TRANSITION_DLY 1000000
-
-/* Value for ChipClockCSR during initial setup */
-#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
- SBSDIO_ALP_AVAIL_REQ)
-
-/* Flags for SDH calls */
-#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
-
-#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
- * when idle
- */
-#define BRCMF_IDLE_INTERVAL 1
-
-#define KSO_WAIT_US 50
-#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
-
-/*
- * Conversion of 802.1D priority to precedence level
- */
-static uint prio2prec(u32 prio)
-{
- return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
- (prio^2) : prio;
-}
-
-#ifdef DEBUG
-/* Device console log buffer state */
-struct brcmf_console {
- uint count; /* Poll interval msec counter */
- uint log_addr; /* Log struct address (fixed) */
- struct rte_log_le log_le; /* Log struct (host copy) */
- uint bufsize; /* Size of log buffer */
- u8 *buf; /* Log buffer (host copy) */
- uint last; /* Last buffer read index */
-};
-
-struct brcmf_trap_info {
- __le32 type;
- __le32 epc;
- __le32 cpsr;
- __le32 spsr;
- __le32 r0; /* a1 */
- __le32 r1; /* a2 */
- __le32 r2; /* a3 */
- __le32 r3; /* a4 */
- __le32 r4; /* v1 */
- __le32 r5; /* v2 */
- __le32 r6; /* v3 */
- __le32 r7; /* v4 */
- __le32 r8; /* v5 */
- __le32 r9; /* sb/v6 */
- __le32 r10; /* sl/v7 */
- __le32 r11; /* fp/v8 */
- __le32 r12; /* ip */
- __le32 r13; /* sp */
- __le32 r14; /* lr */
- __le32 pc; /* r15 */
-};
-#endif /* DEBUG */
-
-struct sdpcm_shared {
- u32 flags;
- u32 trap_addr;
- u32 assert_exp_addr;
- u32 assert_file_addr;
- u32 assert_line;
- u32 console_addr; /* Address of struct rte_console */
- u32 msgtrace_addr;
- u8 tag[32];
- u32 brpt_addr;
-};
-
-struct sdpcm_shared_le {
- __le32 flags;
- __le32 trap_addr;
- __le32 assert_exp_addr;
- __le32 assert_file_addr;
- __le32 assert_line;
- __le32 console_addr; /* Address of struct rte_console */
- __le32 msgtrace_addr;
- u8 tag[32];
- __le32 brpt_addr;
-};
-
-/* dongle SDIO bus specific header info */
-struct brcmf_sdio_hdrinfo {
- u8 seq_num;
- u8 channel;
- u16 len;
- u16 len_left;
- u16 len_nxtfrm;
- u8 dat_offset;
- bool lastfrm;
- u16 tail_pad;
-};
-
-/*
- * hold counter variables
- */
-struct brcmf_sdio_count {
- uint intrcount; /* Count of device interrupt callbacks */
- uint lastintrs; /* Count as of last watchdog timer */
- uint pollcnt; /* Count of active polls */
- uint regfails; /* Count of R_REG failures */
- uint tx_sderrs; /* Count of tx attempts with sd errors */
- uint fcqueued; /* Tx packets that got queued */
- uint rxrtx; /* Count of rtx requests (NAK to dongle) */
- uint rx_toolong; /* Receive frames too long to receive */
- uint rxc_errors; /* SDIO errors when reading control frames */
- uint rx_hdrfail; /* SDIO errors on header reads */
- uint rx_badhdr; /* Bad received headers (roosync?) */
- uint rx_badseq; /* Mismatched rx sequence number */
- uint fc_rcvd; /* Number of flow-control events received */
- uint fc_xoff; /* Number which turned on flow-control */
- uint fc_xon; /* Number which turned off flow-control */
- uint rxglomfail; /* Failed deglom attempts */
- uint rxglomframes; /* Number of glom frames (superframes) */
- uint rxglompkts; /* Number of packets from glom frames */
- uint f2rxhdrs; /* Number of header reads */
- uint f2rxdata; /* Number of frame data reads */
- uint f2txdata; /* Number of f2 frame writes */
- uint f1regdata; /* Number of f1 register accesses */
- uint tickcnt; /* Number of watchdog been schedule */
- ulong tx_ctlerrs; /* Err of sending ctrl frames */
- ulong tx_ctlpkts; /* Ctrl frames sent to dongle */
- ulong rx_ctlerrs; /* Err of processing rx ctrl frames */
- ulong rx_ctlpkts; /* Ctrl frames processed from dongle */
- ulong rx_readahead_cnt; /* packets where header read-ahead was used */
-};
-
-/* misc chip info needed by some of the routines */
-/* Private data for SDIO bus interaction */
-struct brcmf_sdio {
- struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
- struct brcmf_chip *ci; /* Chip info struct */
-
- u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
-
- u32 hostintmask; /* Copy of Host Interrupt Mask */
- atomic_t intstatus; /* Intstatus bits (events) pending */
- atomic_t fcstate; /* State of dongle flow-control */
-
- uint blocksize; /* Block size of SDIO transfers */
- uint roundup; /* Max roundup limit */
-
- struct pktq txq; /* Queue length used for flow-control */
- u8 flowcontrol; /* per prio flow control bitmask */
- u8 tx_seq; /* Transmit sequence number (next) */
- u8 tx_max; /* Maximum transmit sequence allowed */
-
- u8 *hdrbuf; /* buffer for handling rx frame */
- u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
- u8 rx_seq; /* Receive sequence number (expected) */
- struct brcmf_sdio_hdrinfo cur_read;
- /* info of current read frame */
- bool rxskip; /* Skip receive (awaiting NAK ACK) */
- bool rxpending; /* Data frame pending in dongle */
-
- uint rxbound; /* Rx frames to read before resched */
- uint txbound; /* Tx frames to send before resched */
- uint txminmax;
-
- struct sk_buff *glomd; /* Packet containing glomming descriptor */
- struct sk_buff_head glom; /* Packet list for glommed superframe */
- uint glomerr; /* Glom packet read errors */
-
- u8 *rxbuf; /* Buffer for receiving control packets */
- uint rxblen; /* Allocated length of rxbuf */
- u8 *rxctl; /* Aligned pointer into rxbuf */
- u8 *rxctl_orig; /* pointer for freeing rxctl */
- uint rxlen; /* Length of valid data in buffer */
- spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */
-
- u8 sdpcm_ver; /* Bus protocol reported by dongle */
-
- bool intr; /* Use interrupts */
- bool poll; /* Use polling */
- atomic_t ipend; /* Device interrupt is pending */
- uint spurious; /* Count of spurious interrupts */
- uint pollrate; /* Ticks between device polls */
- uint polltick; /* Tick counter */
-
-#ifdef DEBUG
- uint console_interval;
- struct brcmf_console console; /* Console output polling support */
- uint console_addr; /* Console address from shared struct */
-#endif /* DEBUG */
-
- uint clkstate; /* State of sd and backplane clock(s) */
- bool activity; /* Activity flag for clock down */
- s32 idletime; /* Control for activity timeout */
- s32 idlecount; /* Activity timeout counter */
- s32 idleclock; /* How to set bus driver when idle */
- bool rxflow_mode; /* Rx flow control mode */
- bool rxflow; /* Is rx flow control on */
- bool alp_only; /* Don't use HT clock (ALP only) */
-
- u8 *ctrl_frame_buf;
- u16 ctrl_frame_len;
- bool ctrl_frame_stat;
-
- spinlock_t txq_lock; /* protect bus->txq */
- struct semaphore tx_seq_lock; /* protect bus->tx_seq */
- wait_queue_head_t ctrl_wait;
- wait_queue_head_t dcmd_resp_wait;
-
- struct timer_list timer;
- struct completion watchdog_wait;
- struct task_struct *watchdog_tsk;
- bool wd_timer_valid;
- uint save_ms;
-
- struct workqueue_struct *brcmf_wq;
- struct work_struct datawork;
- atomic_t dpc_tskcnt;
-
- bool txoff; /* Transmit flow-controlled */
- struct brcmf_sdio_count sdcnt;
- bool sr_enabled; /* SaveRestore enabled */
- bool sleeping; /* SDIO bus sleeping */
-
- u8 tx_hdrlen; /* sdio bus header length for tx packet */
- bool txglom; /* host tx glomming enable flag */
- u16 head_align; /* buffer pointer alignment */
- u16 sgentry_align; /* scatter-gather buffer alignment */
-};
-
-/* clkstate */
-#define CLK_NONE 0
-#define CLK_SDONLY 1
-#define CLK_PENDING 2
-#define CLK_AVAIL 3
-
-#ifdef DEBUG
-static int qcount[NUMPRIO];
-#endif /* DEBUG */
-
-#define DEFAULT_SDIO_DRIVE_STRENGTH 6 /* in milliamps */
-
-#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
-
-/* Retry count for register access failures */
-static const uint retry_limit = 2;
-
-/* Limit on rounding up frames */
-static const uint max_roundup = 512;
-
-#define ALIGNMENT 4
-
-enum brcmf_sdio_frmtype {
- BRCMF_SDIO_FT_NORMAL,
- BRCMF_SDIO_FT_SUPER,
- BRCMF_SDIO_FT_SUB,
-};
-
-#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
-
-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
- u8 strength; /* Pad Drive Strength in mA */
- u8 sel; /* Chip-specific select value */
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
-static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
- {32, 0x6},
- {26, 0x7},
- {22, 0x4},
- {16, 0x5},
- {12, 0x2},
- {8, 0x3},
- {4, 0x0},
- {0, 0x1}
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
- {6, 0x7},
- {5, 0x6},
- {4, 0x5},
- {3, 0x4},
- {2, 0x2},
- {1, 0x1},
- {0, 0x0}
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
-static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
- {3, 0x3},
- {2, 0x2},
- {1, 0x1},
- {0, 0x0} };
-
-/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
-static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
- {16, 0x7},
- {12, 0x5},
- {8, 0x3},
- {4, 0x1}
-};
-
-#define BCM43143_FIRMWARE_NAME "brcm/brcmfmac43143-sdio.bin"
-#define BCM43143_NVRAM_NAME "brcm/brcmfmac43143-sdio.txt"
-#define BCM43241B0_FIRMWARE_NAME "brcm/brcmfmac43241b0-sdio.bin"
-#define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt"
-#define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin"
-#define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt"
-#define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin"
-#define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt"
-#define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin"
-#define BCM4330_NVRAM_NAME "brcm/brcmfmac4330-sdio.txt"
-#define BCM4334_FIRMWARE_NAME "brcm/brcmfmac4334-sdio.bin"
-#define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt"
-#define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin"
-#define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt"
-#define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin"
-#define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt"
-#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin"
-#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
-#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin"
-#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt"
-
-MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
-MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
-MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4330_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
-MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
-MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
-MODULE_FIRMWARE(BCM4354_NVRAM_NAME);
-
-struct brcmf_firmware_names {
- u32 chipid;
- u32 revmsk;
- const char *bin;
- const char *nv;
-};
-
-enum brcmf_firmware_type {
- BRCMF_FIRMWARE_BIN,
- BRCMF_FIRMWARE_NVRAM
-};
-
-#define BRCMF_FIRMWARE_NVRAM(name) \
- name ## _FIRMWARE_NAME, name ## _NVRAM_NAME
-
-static const struct brcmf_firmware_names brcmf_fwname_data[] = {
- { BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
- { BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
- { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
- { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
- { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
- { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
- { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
- { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
- { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
- { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
-};
-
-static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci,
- struct brcmf_sdio_dev *sdiodev)
-{
- int i;
- char end;
-
- for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) {
- if (brcmf_fwname_data[i].chipid == ci->chip &&
- brcmf_fwname_data[i].revmsk & BIT(ci->chiprev))
- break;
- }
-
- if (i == ARRAY_SIZE(brcmf_fwname_data)) {
- brcmf_err("Unknown chipid %d [%d]\n", ci->chip, ci->chiprev);
- return -ENODEV;
- }
-
- /* check if firmware path is provided by module parameter */
- if (brcmf_firmware_path[0] != '\0') {
- strlcpy(sdiodev->fw_name, brcmf_firmware_path,
- sizeof(sdiodev->fw_name));
- strlcpy(sdiodev->nvram_name, brcmf_firmware_path,
- sizeof(sdiodev->nvram_name));
-
- end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1];
- if (end != '/') {
- strlcat(sdiodev->fw_name, "/",
- sizeof(sdiodev->fw_name));
- strlcat(sdiodev->nvram_name, "/",
- sizeof(sdiodev->nvram_name));
- }
- }
- strlcat(sdiodev->fw_name, brcmf_fwname_data[i].bin,
- sizeof(sdiodev->fw_name));
- strlcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv,
- sizeof(sdiodev->nvram_name));
-
- return 0;
-}
-
-static void pkt_align(struct sk_buff *p, int len, int align)
-{
- uint datalign;
- datalign = (unsigned long)(p->data);
- datalign = roundup(datalign, (align)) - datalign;
- if (datalign)
- skb_pull(p, datalign);
- __skb_trim(p, len);
-}
-
-/* To check if there's window offered */
-static bool data_ok(struct brcmf_sdio *bus)
-{
- return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
- ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
-}
-
-/*
- * Reads a register in the SDIO hardware block. This block occupies a series of
- * adresses on the 32 bit backplane bus.
- */
-static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
-{
- struct brcmf_core *core;
- int ret;
-
- core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
- *regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret);
-
- return ret;
-}
-
-static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
-{
- struct brcmf_core *core;
- int ret;
-
- core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
- brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret);
-
- return ret;
-}
-
-static int
-brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
-{
- u8 wr_val = 0, rd_val, cmp_val, bmask;
- int err = 0;
- int try_cnt = 0;
-
- brcmf_dbg(TRACE, "Enter: on=%d\n", on);
-
- wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
- /* 1st KSO write goes to AOS wake up core if device is asleep */
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
- wr_val, &err);
-
- if (on) {
- /* device WAKEUP through KSO:
- * write bit 0 & read back until
- * both bits 0 (kso bit) & 1 (dev on status) are set
- */
- cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |
- SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
- bmask = cmp_val;
- usleep_range(2000, 3000);
- } else {
- /* Put device to sleep, turn off KSO */
- cmp_val = 0;
- /* only check for bit0, bit1(dev on status) may not
- * get cleared right away
- */
- bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
- }
-
- do {
- /* reliable KSO bit set/clr:
- * the sdiod sleep write access is synced to PMU 32khz clk
- * just one write attempt may fail,
- * read it back until it matches written value
- */
- rd_val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
- &err);
- if (((rd_val & bmask) == cmp_val) && !err)
- break;
-
- udelay(KSO_WAIT_US);
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
- wr_val, &err);
- } while (try_cnt++ < MAX_KSO_ATTEMPTS);
-
- if (try_cnt > 2)
- brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt,
- rd_val, err);
-
- if (try_cnt > MAX_KSO_ATTEMPTS)
- brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
-
- return err;
-}
-
-#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
-
-/* Turn backplane clock on or off */
-static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
-{
- int err;
- u8 clkctl, clkreq, devctl;
- unsigned long timeout;
-
- brcmf_dbg(SDIO, "Enter\n");
-
- clkctl = 0;
-
- if (bus->sr_enabled) {
- bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
- return 0;
- }
-
- if (on) {
- /* Request HT Avail */
- clkreq =
- bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- clkreq, &err);
- if (err) {
- brcmf_err("HT Avail request error: %d\n", err);
- return -EBADE;
- }
-
- /* Check current status */
- clkctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (err) {
- brcmf_err("HT Avail read error: %d\n", err);
- return -EBADE;
- }
-
- /* Go to pending and await interrupt if appropriate */
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
- /* Allow only clock-available interrupt */
- devctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_DEVICE_CTL, &err);
- if (err) {
- brcmf_err("Devctl error setting CA: %d\n",
- err);
- return -EBADE;
- }
-
- devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
- devctl, &err);
- brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
- bus->clkstate = CLK_PENDING;
-
- return 0;
- } else if (bus->clkstate == CLK_PENDING) {
- /* Cancel CA-only interrupt filter */
- devctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
- devctl, &err);
- }
-
- /* Otherwise, wait here (polling) for HT Avail */
- timeout = jiffies +
- msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
- while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- clkctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR,
- &err);
- if (time_after(jiffies, timeout))
- break;
- else
- usleep_range(5000, 10000);
- }
- if (err) {
- brcmf_err("HT Avail request error: %d\n", err);
- return -EBADE;
- }
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- brcmf_err("HT Avail timeout (%d): clkctl 0x%02x\n",
- PMU_MAX_TRANSITION_DLY, clkctl);
- return -EBADE;
- }
-
- /* Mark clock available */
- bus->clkstate = CLK_AVAIL;
- brcmf_dbg(SDIO, "CLKCTL: turned ON\n");
-
-#if defined(DEBUG)
- if (!bus->alp_only) {
- if (SBSDIO_ALPONLY(clkctl))
- brcmf_err("HT Clock should be on\n");
- }
-#endif /* defined (DEBUG) */
-
- } else {
- clkreq = 0;
-
- if (bus->clkstate == CLK_PENDING) {
- /* Cancel CA-only interrupt filter */
- devctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
- devctl, &err);
- }
-
- bus->clkstate = CLK_SDONLY;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- clkreq, &err);
- brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
- if (err) {
- brcmf_err("Failed access turning clock off: %d\n",
- err);
- return -EBADE;
- }
- }
- return 0;
-}
-
-/* Change idle/active SD state */
-static int brcmf_sdio_sdclk(struct brcmf_sdio *bus, bool on)
-{
- brcmf_dbg(SDIO, "Enter\n");
-
- if (on)
- bus->clkstate = CLK_SDONLY;
- else
- bus->clkstate = CLK_NONE;
-
- return 0;
-}
-
-/* Transition SD and backplane clock readiness */
-static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
-{
-#ifdef DEBUG
- uint oldstate = bus->clkstate;
-#endif /* DEBUG */
-
- brcmf_dbg(SDIO, "Enter\n");
-
- /* Early exit if we're already there */
- if (bus->clkstate == target) {
- if (target == CLK_AVAIL) {
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
- bus->activity = true;
- }
- return 0;
- }
-
- switch (target) {
- case CLK_AVAIL:
- /* Make sure SD clock is available */
- if (bus->clkstate == CLK_NONE)
- brcmf_sdio_sdclk(bus, true);
- /* Now request HT Avail on the backplane */
- brcmf_sdio_htclk(bus, true, pendok);
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
- bus->activity = true;
- break;
-
- case CLK_SDONLY:
- /* Remove HT request, or bring up SD clock */
- if (bus->clkstate == CLK_NONE)
- brcmf_sdio_sdclk(bus, true);
- else if (bus->clkstate == CLK_AVAIL)
- brcmf_sdio_htclk(bus, false, false);
- else
- brcmf_err("request for %d -> %d\n",
- bus->clkstate, target);
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
- break;
-
- case CLK_NONE:
- /* Make sure to remove HT request */
- if (bus->clkstate == CLK_AVAIL)
- brcmf_sdio_htclk(bus, false, false);
- /* Now remove the SD clock */
- brcmf_sdio_sdclk(bus, false);
- brcmf_sdio_wd_timer(bus, 0);
- break;
- }
-#ifdef DEBUG
- brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate);
-#endif /* DEBUG */
-
- return 0;
-}
-
-static int
-brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
-{
- int err = 0;
- u8 clkcsr;
-
- brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
- (sleep ? "SLEEP" : "WAKE"),
- (bus->sleeping ? "SLEEP" : "WAKE"));
-
- /* If SR is enabled control bus state with KSO */
- if (bus->sr_enabled) {
- /* Done if we're already in the requested state */
- if (sleep == bus->sleeping)
- goto end;
-
- /* Going to sleep */
- if (sleep) {
- /* Don't sleep if something is pending */
- if (atomic_read(&bus->intstatus) ||
- atomic_read(&bus->ipend) > 0 ||
- (!atomic_read(&bus->fcstate) &&
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
- data_ok(bus))) {
- err = -EBUSY;
- goto done;
- }
-
- clkcsr = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR,
- &err);
- if ((clkcsr & SBSDIO_CSR_MASK) == 0) {
- brcmf_dbg(SDIO, "no clock, set ALP\n");
- brcmf_sdiod_regwb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR,
- SBSDIO_ALP_AVAIL_REQ, &err);
- }
- err = brcmf_sdio_kso_control(bus, false);
- /* disable watchdog */
- if (!err)
- brcmf_sdio_wd_timer(bus, 0);
- } else {
- bus->idlecount = 0;
- err = brcmf_sdio_kso_control(bus, true);
- }
- if (!err) {
- /* Change state */
- bus->sleeping = sleep;
- brcmf_dbg(SDIO, "new state %s\n",
- (sleep ? "SLEEP" : "WAKE"));
- } else {
- brcmf_err("error while changing bus sleep state %d\n",
- err);
- goto done;
- }
- }
-
-end:
- /* control clocks */
- if (sleep) {
- if (!bus->sr_enabled)
- brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
- } else {
- brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
- }
-done:
- brcmf_dbg(SDIO, "Exit: err=%d\n", err);
- return err;
-
-}
-
-#ifdef DEBUG
-static inline bool brcmf_sdio_valid_shared_address(u32 addr)
-{
- return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
-}
-
-static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
- struct sdpcm_shared *sh)
-{
- u32 addr;
- int rv;
- u32 shaddr = 0;
- struct sdpcm_shared_le sh_le;
- __le32 addr_le;
-
- shaddr = bus->ci->rambase + bus->ramsize - 4;
-
- /*
- * Read last word in socram to determine
- * address of sdpcm_shared structure
- */
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
- sdio_release_host(bus->sdiodev->func[1]);
- if (rv < 0)
- return rv;
-
- addr = le32_to_cpu(addr_le);
-
- brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
-
- /*
- * Check if addr is valid.
- * NVRAM length at the end of memory should have been overwritten.
- */
- if (!brcmf_sdio_valid_shared_address(addr)) {
- brcmf_err("invalid sdpcm_shared address 0x%08X\n",
- addr);
- return -EINVAL;
- }
-
- /* Read hndrte_shared structure */
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
- sizeof(struct sdpcm_shared_le));
- if (rv < 0)
- return rv;
-
- /* Endianness */
- sh->flags = le32_to_cpu(sh_le.flags);
- sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
- sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
- sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
- sh->assert_line = le32_to_cpu(sh_le.assert_line);
- sh->console_addr = le32_to_cpu(sh_le.console_addr);
- sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
-
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
- brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
- SDPCM_SHARED_VERSION,
- sh->flags & SDPCM_SHARED_VERSION_MASK);
- return -EPROTO;
- }
-
- return 0;
-}
-
-static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
-{
- struct sdpcm_shared sh;
-
- if (brcmf_sdio_readshared(bus, &sh) == 0)
- bus->console_addr = sh.console_addr;
-}
-#else
-static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
-{
-}
-#endif /* DEBUG */
-
-static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
-{
- u32 intstatus = 0;
- u32 hmb_data;
- u8 fcbits;
- int ret;
-
- brcmf_dbg(SDIO, "Enter\n");
-
- /* Read mailbox data and ack that we did so */
- ret = r_sdreg32(bus, &hmb_data,
- offsetof(struct sdpcmd_regs, tohostmailboxdata));
-
- if (ret == 0)
- w_sdreg32(bus, SMB_INT_ACK,
- offsetof(struct sdpcmd_regs, tosbmailbox));
- bus->sdcnt.f1regdata += 2;
-
- /* Dongle recomposed rx frames, accept them again */
- if (hmb_data & HMB_DATA_NAKHANDLED) {
- brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
- bus->rx_seq);
- if (!bus->rxskip)
- brcmf_err("unexpected NAKHANDLED!\n");
-
- bus->rxskip = false;
- intstatus |= I_HMB_FRAME_IND;
- }
-
- /*
- * DEVREADY does not occur with gSPI.
- */
- if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
- bus->sdpcm_ver =
- (hmb_data & HMB_DATA_VERSION_MASK) >>
- HMB_DATA_VERSION_SHIFT;
- if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
- brcmf_err("Version mismatch, dongle reports %d, "
- "expecting %d\n",
- bus->sdpcm_ver, SDPCM_PROT_VERSION);
- else
- brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
- bus->sdpcm_ver);
-
- /*
- * Retrieve console state address now that firmware should have
- * updated it.
- */
- brcmf_sdio_get_console_addr(bus);
- }
-
- /*
- * Flow Control has been moved into the RX headers and this out of band
- * method isn't used any more.
- * remaining backward compatible with older dongles.
- */
- if (hmb_data & HMB_DATA_FC) {
- fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
- HMB_DATA_FCDATA_SHIFT;
-
- if (fcbits & ~bus->flowcontrol)
- bus->sdcnt.fc_xoff++;
-
- if (bus->flowcontrol & ~fcbits)
- bus->sdcnt.fc_xon++;
-
- bus->sdcnt.fc_rcvd++;
- bus->flowcontrol = fcbits;
- }
-
- /* Shouldn't be any others */
- if (hmb_data & ~(HMB_DATA_DEVREADY |
- HMB_DATA_NAKHANDLED |
- HMB_DATA_FC |
- HMB_DATA_FWREADY |
- HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
- brcmf_err("Unknown mailbox data content: 0x%02x\n",
- hmb_data);
-
- return intstatus;
-}
-
-static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
-{
- uint retries = 0;
- u16 lastrbc;
- u8 hi, lo;
- int err;
-
- brcmf_err("%sterminate frame%s\n",
- abort ? "abort command, " : "",
- rtx ? ", send NAK" : "");
-
- if (abort)
- brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
- SFC_RF_TERM, &err);
- bus->sdcnt.f1regdata++;
-
- /* Wait until the packet has been flushed (device/FIFO stable) */
- for (lastrbc = retries = 0xffff; retries > 0; retries--) {
- hi = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_RFRAMEBCHI, &err);
- lo = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_RFRAMEBCLO, &err);
- bus->sdcnt.f1regdata += 2;
-
- if ((hi == 0) && (lo == 0))
- break;
-
- if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
- brcmf_err("count growing: last 0x%04x now 0x%04x\n",
- lastrbc, (hi << 8) + lo);
- }
- lastrbc = (hi << 8) + lo;
- }
-
- if (!retries)
- brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);
- else
- brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
-
- if (rtx) {
- bus->sdcnt.rxrtx++;
- err = w_sdreg32(bus, SMB_NAK,
- offsetof(struct sdpcmd_regs, tosbmailbox));
-
- bus->sdcnt.f1regdata++;
- if (err == 0)
- bus->rxskip = true;
- }
-
- /* Clear partial in any case */
- bus->cur_read.len = 0;
-}
-
-static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
-{
- struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
- u8 i, hi, lo;
-
- /* On failure, abort the command and terminate the frame */
- brcmf_err("sdio error, abort command and terminate frame\n");
- bus->sdcnt.tx_sderrs++;
-
- brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
- bus->sdcnt.f1regdata++;
-
- for (i = 0; i < 3; i++) {
- hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->sdcnt.f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
-}
-
-/* return total length of buffer chain */
-static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
-{
- struct sk_buff *p;
- uint total;
-
- total = 0;
- skb_queue_walk(&bus->glom, p)
- total += p->len;
- return total;
-}
-
-static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)
-{
- struct sk_buff *cur, *next;
-
- skb_queue_walk_safe(&bus->glom, cur, next) {
- skb_unlink(cur, &bus->glom);
- brcmu_pkt_buf_free_skb(cur);
- }
-}
-
-/**
- * brcmfmac sdio bus specific header
- * This is the lowest layer header wrapped on the packets transmitted between
- * host and WiFi dongle which contains information needed for SDIO core and
- * firmware
- *
- * It consists of 3 parts: hardware header, hardware extension header and
- * software header
- * hardware header (frame tag) - 4 bytes
- * Byte 0~1: Frame length
- * Byte 2~3: Checksum, bit-wise inverse of frame length
- * hardware extension header - 8 bytes
- * Tx glom mode only, N/A for Rx or normal Tx
- * Byte 0~1: Packet length excluding hw frame tag
- * Byte 2: Reserved
- * Byte 3: Frame flags, bit 0: last frame indication
- * Byte 4~5: Reserved
- * Byte 6~7: Tail padding length
- * software header - 8 bytes
- * Byte 0: Rx/Tx sequence number
- * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
- * Byte 2: Length of next data frame, reserved for Tx
- * Byte 3: Data offset
- * Byte 4: Flow control bits, reserved for Tx
- * Byte 5: Maximum Sequence number allowed by firmware for Tx, N/A for Tx packet
- * Byte 6~7: Reserved
- */
-#define SDPCM_HWHDR_LEN 4
-#define SDPCM_HWEXT_LEN 8
-#define SDPCM_SWHDR_LEN 8
-#define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
-/* software header */
-#define SDPCM_SEQ_MASK 0x000000ff
-#define SDPCM_SEQ_WRAP 256
-#define SDPCM_CHANNEL_MASK 0x00000f00
-#define SDPCM_CHANNEL_SHIFT 8
-#define SDPCM_CONTROL_CHANNEL 0 /* Control */
-#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication */
-#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv */
-#define SDPCM_GLOM_CHANNEL 3 /* Coalesced packets */
-#define SDPCM_TEST_CHANNEL 15 /* Test/debug packets */
-#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
-#define SDPCM_NEXTLEN_MASK 0x00ff0000
-#define SDPCM_NEXTLEN_SHIFT 16
-#define SDPCM_DOFFSET_MASK 0xff000000
-#define SDPCM_DOFFSET_SHIFT 24
-#define SDPCM_FCMASK_MASK 0x000000ff
-#define SDPCM_WINDOW_MASK 0x0000ff00
-#define SDPCM_WINDOW_SHIFT 8
-
-static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
-{
- u32 hdrvalue;
- hdrvalue = *(u32 *)swheader;
- return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
-}
-
-static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
- struct brcmf_sdio_hdrinfo *rd,
- enum brcmf_sdio_frmtype type)
-{
- u16 len, checksum;
- u8 rx_seq, fc, tx_seq_max;
- u32 swheader;
-
- trace_brcmf_sdpcm_hdr(SDPCM_RX, header);
-
- /* hw header */
- len = get_unaligned_le16(header);
- checksum = get_unaligned_le16(header + sizeof(u16));
- /* All zero means no more to read */
- if (!(len | checksum)) {
- bus->rxpending = false;
- return -ENODATA;
- }
- if ((u16)(~(len ^ checksum))) {
- brcmf_err("HW header checksum error\n");
- bus->sdcnt.rx_badhdr++;
- brcmf_sdio_rxfail(bus, false, false);
- return -EIO;
- }
- if (len < SDPCM_HDRLEN) {
- brcmf_err("HW header length error\n");
- return -EPROTO;
- }
- if (type == BRCMF_SDIO_FT_SUPER &&
- (roundup(len, bus->blocksize) != rd->len)) {
- brcmf_err("HW superframe header length error\n");
- return -EPROTO;
- }
- if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
- brcmf_err("HW subframe header length error\n");
- return -EPROTO;
- }
- rd->len = len;
-
- /* software header */
- header += SDPCM_HWHDR_LEN;
- swheader = le32_to_cpu(*(__le32 *)header);
- if (type == BRCMF_SDIO_FT_SUPER && SDPCM_GLOMDESC(header)) {
- brcmf_err("Glom descriptor found in superframe head\n");
- rd->len = 0;
- return -EINVAL;
- }
- rx_seq = (u8)(swheader & SDPCM_SEQ_MASK);
- rd->channel = (swheader & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT;
- if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
- type != BRCMF_SDIO_FT_SUPER) {
- brcmf_err("HW header length too long\n");
- bus->sdcnt.rx_toolong++;
- brcmf_sdio_rxfail(bus, false, false);
- rd->len = 0;
- return -EPROTO;
- }
- if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
- brcmf_err("Wrong channel for superframe\n");
- rd->len = 0;
- return -EINVAL;
- }
- if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
- rd->channel != SDPCM_EVENT_CHANNEL) {
- brcmf_err("Wrong channel for subframe\n");
- rd->len = 0;
- return -EINVAL;
- }
- rd->dat_offset = brcmf_sdio_getdatoffset(header);
- if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
- brcmf_err("seq %d: bad data offset\n", rx_seq);
- bus->sdcnt.rx_badhdr++;
- brcmf_sdio_rxfail(bus, false, false);
- rd->len = 0;
- return -ENXIO;
- }
- if (rd->seq_num != rx_seq) {
- brcmf_err("seq %d: sequence number error, expect %d\n",
- rx_seq, rd->seq_num);
- bus->sdcnt.rx_badseq++;
- rd->seq_num = rx_seq;
- }
- /* no need to check the reset for subframe */
- if (type == BRCMF_SDIO_FT_SUB)
- return 0;
- rd->len_nxtfrm = (swheader & SDPCM_NEXTLEN_MASK) >> SDPCM_NEXTLEN_SHIFT;
- if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
- /* only warm for NON glom packet */
- if (rd->channel != SDPCM_GLOM_CHANNEL)
- brcmf_err("seq %d: next length error\n", rx_seq);
- rd->len_nxtfrm = 0;
- }
- swheader = le32_to_cpu(*(__le32 *)(header + 4));
- fc = swheader & SDPCM_FCMASK_MASK;
- if (bus->flowcontrol != fc) {
- if (~bus->flowcontrol & fc)
- bus->sdcnt.fc_xoff++;
- if (bus->flowcontrol & ~fc)
- bus->sdcnt.fc_xon++;
- bus->sdcnt.fc_rcvd++;
- bus->flowcontrol = fc;
- }
- tx_seq_max = (swheader & SDPCM_WINDOW_MASK) >> SDPCM_WINDOW_SHIFT;
- if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) {
- brcmf_err("seq %d: max tx seq number error\n", rx_seq);
- tx_seq_max = bus->tx_seq + 2;
- }
- bus->tx_max = tx_seq_max;
-
- return 0;
-}
-
-static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)
-{
- *(__le16 *)header = cpu_to_le16(frm_length);
- *(((__le16 *)header) + 1) = cpu_to_le16(~frm_length);
-}
-
-static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
- struct brcmf_sdio_hdrinfo *hd_info)
-{
- u32 hdrval;
- u8 hdr_offset;
-
- brcmf_sdio_update_hwhdr(header, hd_info->len);
- hdr_offset = SDPCM_HWHDR_LEN;
-
- if (bus->txglom) {
- hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24);
- *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
- hdrval = (u16)hd_info->tail_pad << 16;
- *(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval);
- hdr_offset += SDPCM_HWEXT_LEN;
- }
-
- hdrval = hd_info->seq_num;
- hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
- SDPCM_CHANNEL_MASK;
- hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
- SDPCM_DOFFSET_MASK;
- *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
- *(((__le32 *)(header + hdr_offset)) + 1) = 0;
- trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);
-}
-
-static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
-{
- u16 dlen, totlen;
- u8 *dptr, num = 0;
- u16 sublen;
- struct sk_buff *pfirst, *pnext;
-
- int errcode;
- u8 doff, sfdoff;
-
- struct brcmf_sdio_hdrinfo rd_new;
-
- /* If packets, issue read(s) and send up packet chain */
- /* Return sequence numbers consumed? */
-
- brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
- bus->glomd, skb_peek(&bus->glom));
-
- /* If there's a descriptor, generate the packet chain */
- if (bus->glomd) {
- pfirst = pnext = NULL;
- dlen = (u16) (bus->glomd->len);
- dptr = bus->glomd->data;
- if (!dlen || (dlen & 1)) {
- brcmf_err("bad glomd len(%d), ignore descriptor\n",
- dlen);
- dlen = 0;
- }
-
- for (totlen = num = 0; dlen; num++) {
- /* Get (and move past) next length */
- sublen = get_unaligned_le16(dptr);
- dlen -= sizeof(u16);
- dptr += sizeof(u16);
- if ((sublen < SDPCM_HDRLEN) ||
- ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
- brcmf_err("descriptor len %d bad: %d\n",
- num, sublen);
- pnext = NULL;
- break;
- }
- if (sublen % bus->sgentry_align) {
- brcmf_err("sublen %d not multiple of %d\n",
- sublen, bus->sgentry_align);
- }
- totlen += sublen;
-
- /* For last frame, adjust read len so total
- is a block multiple */
- if (!dlen) {
- sublen +=
- (roundup(totlen, bus->blocksize) - totlen);
- totlen = roundup(totlen, bus->blocksize);
- }
-
- /* Allocate/chain packet for next subframe */
- pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align);
- if (pnext == NULL) {
- brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
- num, sublen);
- break;
- }
- skb_queue_tail(&bus->glom, pnext);
-
- /* Adhere to start alignment requirements */
- pkt_align(pnext, sublen, bus->sgentry_align);
- }
-
- /* If all allocations succeeded, save packet chain
- in bus structure */
- if (pnext) {
- brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
- totlen, num);
- if (BRCMF_GLOM_ON() && bus->cur_read.len &&
- totlen != bus->cur_read.len) {
- brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
- bus->cur_read.len, totlen, rxseq);
- }
- pfirst = pnext = NULL;
- } else {
- brcmf_sdio_free_glom(bus);
- num = 0;
- }
-
- /* Done with descriptor packet */
- brcmu_pkt_buf_free_skb(bus->glomd);
- bus->glomd = NULL;
- bus->cur_read.len = 0;
- }
-
- /* Ok -- either we just generated a packet chain,
- or had one from before */
- if (!skb_queue_empty(&bus->glom)) {
- if (BRCMF_GLOM_ON()) {
- brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
- skb_queue_walk(&bus->glom, pnext) {
- brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
- pnext, (u8 *) (pnext->data),
- pnext->len, pnext->len);
- }
- }
-
- pfirst = skb_peek(&bus->glom);
- dlen = (u16) brcmf_sdio_glom_len(bus);
-
- /* Do an SDIO read for the superframe. Configurable iovar to
- * read directly into the chained packet, or allocate a large
- * packet and and copy into the chain.
- */
- sdio_claim_host(bus->sdiodev->func[1]);
- errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
- &bus->glom, dlen);
- sdio_release_host(bus->sdiodev->func[1]);
- bus->sdcnt.f2rxdata++;
-
- /* On failure, kill the superframe, allow a couple retries */
- if (errcode < 0) {
- brcmf_err("glom read of %d bytes failed: %d\n",
- dlen, errcode);
-
- sdio_claim_host(bus->sdiodev->func[1]);
- if (bus->glomerr++ < 3) {
- brcmf_sdio_rxfail(bus, true, true);
- } else {
- bus->glomerr = 0;
- brcmf_sdio_rxfail(bus, true, false);
- bus->sdcnt.rxglomfail++;
- brcmf_sdio_free_glom(bus);
- }
- sdio_release_host(bus->sdiodev->func[1]);
- return 0;
- }
-
- brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
- pfirst->data, min_t(int, pfirst->len, 48),
- "SUPERFRAME:\n");
-
- rd_new.seq_num = rxseq;
- rd_new.len = dlen;
- sdio_claim_host(bus->sdiodev->func[1]);
- errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
- BRCMF_SDIO_FT_SUPER);
- sdio_release_host(bus->sdiodev->func[1]);
- bus->cur_read.len = rd_new.len_nxtfrm << 4;
-
- /* Remove superframe header, remember offset */
- skb_pull(pfirst, rd_new.dat_offset);
- sfdoff = rd_new.dat_offset;
- num = 0;
-
- /* Validate all the subframe headers */
- skb_queue_walk(&bus->glom, pnext) {
- /* leave when invalid subframe is found */
- if (errcode)
- break;
-
- rd_new.len = pnext->len;
- rd_new.seq_num = rxseq++;
- sdio_claim_host(bus->sdiodev->func[1]);
- errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
- BRCMF_SDIO_FT_SUB);
- sdio_release_host(bus->sdiodev->func[1]);
- brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
- pnext->data, 32, "subframe:\n");
-
- num++;
- }
-
- if (errcode) {
- /* Terminate frame on error, request
- a couple retries */
- sdio_claim_host(bus->sdiodev->func[1]);
- if (bus->glomerr++ < 3) {
- /* Restore superframe header space */
- skb_push(pfirst, sfdoff);
- brcmf_sdio_rxfail(bus, true, true);
- } else {
- bus->glomerr = 0;
- brcmf_sdio_rxfail(bus, true, false);
- bus->sdcnt.rxglomfail++;
- brcmf_sdio_free_glom(bus);
- }
- sdio_release_host(bus->sdiodev->func[1]);
- bus->cur_read.len = 0;
- return 0;
- }
-
- /* Basic SD framing looks ok - process each packet (header) */
-
- skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
- dptr = (u8 *) (pfirst->data);
- sublen = get_unaligned_le16(dptr);
- doff = brcmf_sdio_getdatoffset(&dptr[SDPCM_HWHDR_LEN]);
-
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
- dptr, pfirst->len,
- "Rx Subframe Data:\n");
-
- __skb_trim(pfirst, sublen);
- skb_pull(pfirst, doff);
-
- if (pfirst->len == 0) {
- skb_unlink(pfirst, &bus->glom);
- brcmu_pkt_buf_free_skb(pfirst);
- continue;
- }
-
- brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
- pfirst->data,
- min_t(int, pfirst->len, 32),
- "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
- bus->glom.qlen, pfirst, pfirst->data,
- pfirst->len, pfirst->next,
- pfirst->prev);
- skb_unlink(pfirst, &bus->glom);
- brcmf_rx_frame(bus->sdiodev->dev, pfirst);
- bus->sdcnt.rxglompkts++;
- }
-
- bus->sdcnt.rxglomframes++;
- }
- return num;
-}
-
-static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
- bool *pending)
-{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
-
- /* Wait until control frame is available */
- add_wait_queue(&bus->dcmd_resp_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- while (!(*condition) && (!signal_pending(current) && timeout))
- timeout = schedule_timeout(timeout);
-
- if (signal_pending(current))
- *pending = true;
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&bus->dcmd_resp_wait, &wait);
-
- return timeout;
-}
-
-static int brcmf_sdio_dcmd_resp_wake(struct brcmf_sdio *bus)
-{
- if (waitqueue_active(&bus->dcmd_resp_wait))
- wake_up_interruptible(&bus->dcmd_resp_wait);
-
- return 0;
-}
-static void
-brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
-{
- uint rdlen, pad;
- u8 *buf = NULL, *rbuf;
- int sdret;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (bus->rxblen)
- buf = vzalloc(bus->rxblen);
- if (!buf)
- goto done;
-
- rbuf = bus->rxbuf;
- pad = ((unsigned long)rbuf % bus->head_align);
- if (pad)
- rbuf += (bus->head_align - pad);
-
- /* Copy the already-read portion over */
- memcpy(buf, hdr, BRCMF_FIRSTREAD);
- if (len <= BRCMF_FIRSTREAD)
- goto gotpkt;
-
- /* Raise rdlen to next SDIO block to avoid tail command */
- rdlen = len - BRCMF_FIRSTREAD;
- if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
- pad = bus->blocksize - (rdlen % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
- ((len + pad) < bus->sdiodev->bus_if->maxctl))
- rdlen += pad;
- } else if (rdlen % bus->head_align) {
- rdlen += bus->head_align - (rdlen % bus->head_align);
- }
-
- /* Drop if the read is too big or it exceeds our maximum */
- if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
- brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
- rdlen, bus->sdiodev->bus_if->maxctl);
- brcmf_sdio_rxfail(bus, false, false);
- goto done;
- }
-
- if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
- brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
- len, len - doff, bus->sdiodev->bus_if->maxctl);
- bus->sdcnt.rx_toolong++;
- brcmf_sdio_rxfail(bus, false, false);
- goto done;
- }
-
- /* Read remain of frame body */
- sdret = brcmf_sdiod_recv_buf(bus->sdiodev, rbuf, rdlen);
- bus->sdcnt.f2rxdata++;
-
- /* Control frame failures need retransmission */
- if (sdret < 0) {
- brcmf_err("read %d control bytes failed: %d\n",
- rdlen, sdret);
- bus->sdcnt.rxc_errors++;
- brcmf_sdio_rxfail(bus, true, true);
- goto done;
- } else
- memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
-
-gotpkt:
-
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
- buf, len, "RxCtrl:\n");
-
- /* Point to valid data and indicate its length */
- spin_lock_bh(&bus->rxctl_lock);
- if (bus->rxctl) {
- brcmf_err("last control frame is being processed.\n");
- spin_unlock_bh(&bus->rxctl_lock);
- vfree(buf);
- goto done;
- }
- bus->rxctl = buf + doff;
- bus->rxctl_orig = buf;
- bus->rxlen = len - doff;
- spin_unlock_bh(&bus->rxctl_lock);
-
-done:
- /* Awake any waiters */
- brcmf_sdio_dcmd_resp_wake(bus);
-}
-
-/* Pad read to blocksize for efficiency */
-static void brcmf_sdio_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
-{
- if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
- *pad = bus->blocksize - (*rdlen % bus->blocksize);
- if (*pad <= bus->roundup && *pad < bus->blocksize &&
- *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
- *rdlen += *pad;
- } else if (*rdlen % bus->head_align) {
- *rdlen += bus->head_align - (*rdlen % bus->head_align);
- }
-}
-
-static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
-{
- struct sk_buff *pkt; /* Packet for event or data frames */
- u16 pad; /* Number of pad bytes to read */
- uint rxleft = 0; /* Remaining number of frames allowed */
- int ret; /* Return code from calls */
- uint rxcount = 0; /* Total frames read */
- struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new;
- u8 head_read = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Not finished unless we encounter no more frames indication */
- bus->rxpending = true;
-
- for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
- !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
- rd->seq_num++, rxleft--) {
-
- /* Handle glomming separately */
- if (bus->glomd || !skb_queue_empty(&bus->glom)) {
- u8 cnt;
- brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
- bus->glomd, skb_peek(&bus->glom));
- cnt = brcmf_sdio_rxglom(bus, rd->seq_num);
- brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
- rd->seq_num += cnt - 1;
- rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
- continue;
- }
-
- rd->len_left = rd->len;
- /* read header first for unknow frame length */
- sdio_claim_host(bus->sdiodev->func[1]);
- if (!rd->len) {
- ret = brcmf_sdiod_recv_buf(bus->sdiodev,
- bus->rxhdr, BRCMF_FIRSTREAD);
- bus->sdcnt.f2rxhdrs++;
- if (ret < 0) {
- brcmf_err("RXHEADER FAILED: %d\n",
- ret);
- bus->sdcnt.rx_hdrfail++;
- brcmf_sdio_rxfail(bus, true, true);
- sdio_release_host(bus->sdiodev->func[1]);
- continue;
- }
-
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(),
- bus->rxhdr, SDPCM_HDRLEN,
- "RxHdr:\n");
-
- if (brcmf_sdio_hdparse(bus, bus->rxhdr, rd,
- BRCMF_SDIO_FT_NORMAL)) {
- sdio_release_host(bus->sdiodev->func[1]);
- if (!bus->rxpending)
- break;
- else
- continue;
- }
-
- if (rd->channel == SDPCM_CONTROL_CHANNEL) {
- brcmf_sdio_read_control(bus, bus->rxhdr,
- rd->len,
- rd->dat_offset);
- /* prepare the descriptor for the next read */
- rd->len = rd->len_nxtfrm << 4;
- rd->len_nxtfrm = 0;
- /* treat all packet as event if we don't know */
- rd->channel = SDPCM_EVENT_CHANNEL;
- sdio_release_host(bus->sdiodev->func[1]);
- continue;
- }
- rd->len_left = rd->len > BRCMF_FIRSTREAD ?
- rd->len - BRCMF_FIRSTREAD : 0;
- head_read = BRCMF_FIRSTREAD;
- }
-
- brcmf_sdio_pad(bus, &pad, &rd->len_left);
-
- pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
- bus->head_align);
- if (!pkt) {
- /* Give up on data, request rtx of events */
- brcmf_err("brcmu_pkt_buf_get_skb failed\n");
- brcmf_sdio_rxfail(bus, false,
- RETRYCHAN(rd->channel));
- sdio_release_host(bus->sdiodev->func[1]);
- continue;
- }
- skb_pull(pkt, head_read);
- pkt_align(pkt, rd->len_left, bus->head_align);
-
- ret = brcmf_sdiod_recv_pkt(bus->sdiodev, pkt);
- bus->sdcnt.f2rxdata++;
- sdio_release_host(bus->sdiodev->func[1]);
-
- if (ret < 0) {
- brcmf_err("read %d bytes from channel %d failed: %d\n",
- rd->len, rd->channel, ret);
- brcmu_pkt_buf_free_skb(pkt);
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_rxfail(bus, true,
- RETRYCHAN(rd->channel));
- sdio_release_host(bus->sdiodev->func[1]);
- continue;
- }
-
- if (head_read) {
- skb_push(pkt, head_read);
- memcpy(pkt->data, bus->rxhdr, head_read);
- head_read = 0;
- } else {
- memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
- rd_new.seq_num = rd->seq_num;
- sdio_claim_host(bus->sdiodev->func[1]);
- if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
- BRCMF_SDIO_FT_NORMAL)) {
- rd->len = 0;
- brcmu_pkt_buf_free_skb(pkt);
- }
- bus->sdcnt.rx_readahead_cnt++;
- if (rd->len != roundup(rd_new.len, 16)) {
- brcmf_err("frame length mismatch:read %d, should be %d\n",
- rd->len,
- roundup(rd_new.len, 16) >> 4);
- rd->len = 0;
- brcmf_sdio_rxfail(bus, true, true);
- sdio_release_host(bus->sdiodev->func[1]);
- brcmu_pkt_buf_free_skb(pkt);
- continue;
- }
- sdio_release_host(bus->sdiodev->func[1]);
- rd->len_nxtfrm = rd_new.len_nxtfrm;
- rd->channel = rd_new.channel;
- rd->dat_offset = rd_new.dat_offset;
-
- brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() &&
- BRCMF_DATA_ON()) &&
- BRCMF_HDRS_ON(),
- bus->rxhdr, SDPCM_HDRLEN,
- "RxHdr:\n");
-
- if (rd_new.channel == SDPCM_CONTROL_CHANNEL) {
- brcmf_err("readahead on control packet %d?\n",
- rd_new.seq_num);
- /* Force retry w/normal header read */
- rd->len = 0;
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_rxfail(bus, false, true);
- sdio_release_host(bus->sdiodev->func[1]);
- brcmu_pkt_buf_free_skb(pkt);
- continue;
- }
- }
-
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
- pkt->data, rd->len, "Rx Data:\n");
-
- /* Save superframe descriptor and allocate packet frame */
- if (rd->channel == SDPCM_GLOM_CHANNEL) {
- if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_HWHDR_LEN])) {
- brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
- rd->len);
- brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
- pkt->data, rd->len,
- "Glom Data:\n");
- __skb_trim(pkt, rd->len);
- skb_pull(pkt, SDPCM_HDRLEN);
- bus->glomd = pkt;
- } else {
- brcmf_err("%s: glom superframe w/o "
- "descriptor!\n", __func__);
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_rxfail(bus, false, false);
- sdio_release_host(bus->sdiodev->func[1]);
- }
- /* prepare the descriptor for the next read */
- rd->len = rd->len_nxtfrm << 4;
- rd->len_nxtfrm = 0;
- /* treat all packet as event if we don't know */
- rd->channel = SDPCM_EVENT_CHANNEL;
- continue;
- }
-
- /* Fill in packet len and prio, deliver upward */
- __skb_trim(pkt, rd->len);
- skb_pull(pkt, rd->dat_offset);
-
- /* prepare the descriptor for the next read */
- rd->len = rd->len_nxtfrm << 4;
- rd->len_nxtfrm = 0;
- /* treat all packet as event if we don't know */
- rd->channel = SDPCM_EVENT_CHANNEL;
-
- if (pkt->len == 0) {
- brcmu_pkt_buf_free_skb(pkt);
- continue;
- }
-
- brcmf_rx_frame(bus->sdiodev->dev, pkt);
- }
-
- rxcount = maxframes - rxleft;
- /* Message if we hit the limit */
- if (!rxleft)
- brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes);
- else
- brcmf_dbg(DATA, "processed %d frames\n", rxcount);
- /* Back off rxseq if awaiting rtx, update rx_seq */
- if (bus->rxskip)
- rd->seq_num--;
- bus->rx_seq = rd->seq_num;
-
- return rxcount;
-}
-
-static void
-brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
-{
- if (waitqueue_active(&bus->ctrl_wait))
- wake_up_interruptible(&bus->ctrl_wait);
- return;
-}
-
-static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
-{
- u16 head_pad;
- u8 *dat_buf;
-
- dat_buf = (u8 *)(pkt->data);
-
- /* Check head padding */
- head_pad = ((unsigned long)dat_buf % bus->head_align);
- if (head_pad) {
- if (skb_headroom(pkt) < head_pad) {
- bus->sdiodev->bus_if->tx_realloc++;
- head_pad = 0;
- if (skb_cow(pkt, head_pad))
- return -ENOMEM;
- }
- skb_push(pkt, head_pad);
- dat_buf = (u8 *)(pkt->data);
- memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
- }
- return head_pad;
-}
-
-/**
- * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
- * bus layer usage.
- */
-/* flag marking a dummy skb added for DMA alignment requirement */
-#define ALIGN_SKB_FLAG 0x8000
-/* bit mask of data length chopped from the previous packet */
-#define ALIGN_SKB_CHOP_LEN_MASK 0x7fff
-
-static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
- struct sk_buff_head *pktq,
- struct sk_buff *pkt, u16 total_len)
-{
- struct brcmf_sdio_dev *sdiodev;
- struct sk_buff *pkt_pad;
- u16 tail_pad, tail_chop, chain_pad;
- unsigned int blksize;
- bool lastfrm;
- int ntail, ret;
-
- sdiodev = bus->sdiodev;
- blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize;
- /* sg entry alignment should be a divisor of block size */
- WARN_ON(blksize % bus->sgentry_align);
-
- /* Check tail padding */
- lastfrm = skb_queue_is_last(pktq, pkt);
- tail_pad = 0;
- tail_chop = pkt->len % bus->sgentry_align;
- if (tail_chop)
- tail_pad = bus->sgentry_align - tail_chop;
- chain_pad = (total_len + tail_pad) % blksize;
- if (lastfrm && chain_pad)
- tail_pad += blksize - chain_pad;
- if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
- pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
- bus->head_align);
- if (pkt_pad == NULL)
- return -ENOMEM;
- ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
- if (unlikely(ret < 0)) {
- kfree_skb(pkt_pad);
- return ret;
- }
- memcpy(pkt_pad->data,
- pkt->data + pkt->len - tail_chop,
- tail_chop);
- *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
- skb_trim(pkt, pkt->len - tail_chop);
- skb_trim(pkt_pad, tail_pad + tail_chop);
- __skb_queue_after(pktq, pkt, pkt_pad);
- } else {
- ntail = pkt->data_len + tail_pad -
- (pkt->end - pkt->tail);
- if (skb_cloned(pkt) || ntail > 0)
- if (pskb_expand_head(pkt, 0, ntail, GFP_ATOMIC))
- return -ENOMEM;
- if (skb_linearize(pkt))
- return -ENOMEM;
- __skb_put(pkt, tail_pad);
- }
-
- return tail_pad;
-}
-
-/**
- * brcmf_sdio_txpkt_prep - packet preparation for transmit
- * @bus: brcmf_sdio structure pointer
- * @pktq: packet list pointer
- * @chan: virtual channel to transmit the packet
- *
- * Processes to be applied to the packet
- * - Align data buffer pointer
- * - Align data buffer length
- * - Prepare header
- * Return: negative value if there is error
- */
-static int
-brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
- uint chan)
-{
- u16 head_pad, total_len;
- struct sk_buff *pkt_next;
- u8 txseq;
- int ret;
- struct brcmf_sdio_hdrinfo hd_info = {0};
-
- txseq = bus->tx_seq;
- total_len = 0;
- skb_queue_walk(pktq, pkt_next) {
- /* alignment packet inserted in previous
- * loop cycle can be skipped as it is
- * already properly aligned and does not
- * need an sdpcm header.
- */
- if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
- continue;
-
- /* align packet data pointer */
- ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next);
- if (ret < 0)
- return ret;
- head_pad = (u16)ret;
- if (head_pad)
- memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
-
- total_len += pkt_next->len;
-
- hd_info.len = pkt_next->len;
- hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next);
- if (bus->txglom && pktq->qlen > 1) {
- ret = brcmf_sdio_txpkt_prep_sg(bus, pktq,
- pkt_next, total_len);
- if (ret < 0)
- return ret;
- hd_info.tail_pad = (u16)ret;
- total_len += (u16)ret;
- }
-
- hd_info.channel = chan;
- hd_info.dat_offset = head_pad + bus->tx_hdrlen;
- hd_info.seq_num = txseq++;
-
- /* Now fill the header */
- brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info);
-
- if (BRCMF_BYTES_ON() &&
- ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
- (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
- brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
- "Tx Frame:\n");
- else if (BRCMF_HDRS_ON())
- brcmf_dbg_hex_dump(true, pkt_next->data,
- head_pad + bus->tx_hdrlen,
- "Tx Header:\n");
- }
- /* Hardware length tag of the first packet should be total
- * length of the chain (including padding)
- */
- if (bus->txglom)
- brcmf_sdio_update_hwhdr(pktq->next->data, total_len);
- return 0;
-}
-
-/**
- * brcmf_sdio_txpkt_postp - packet post processing for transmit
- * @bus: brcmf_sdio structure pointer
- * @pktq: packet list pointer
- *
- * Processes to be applied to the packet
- * - Remove head padding
- * - Remove tail padding
- */
-static void
-brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
-{
- u8 *hdr;
- u32 dat_offset;
- u16 tail_pad;
- u16 dummy_flags, chop_len;
- struct sk_buff *pkt_next, *tmp, *pkt_prev;
-
- skb_queue_walk_safe(pktq, pkt_next, tmp) {
- dummy_flags = *(u16 *)(pkt_next->cb);
- if (dummy_flags & ALIGN_SKB_FLAG) {
- chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
- if (chop_len) {
- pkt_prev = pkt_next->prev;
- skb_put(pkt_prev, chop_len);
- }
- __skb_unlink(pkt_next, pktq);
- brcmu_pkt_buf_free_skb(pkt_next);
- } else {
- hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN;
- dat_offset = le32_to_cpu(*(__le32 *)hdr);
- dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
- SDPCM_DOFFSET_SHIFT;
- skb_pull(pkt_next, dat_offset);
- if (bus->txglom) {
- tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2));
- skb_trim(pkt_next, pkt_next->len - tail_pad);
- }
- }
- }
-}
-
-/* Writes a HW/SW header into the packet and sends it. */
-/* Assumes: (a) header space already there, (b) caller holds lock */
-static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
- uint chan)
-{
- int ret;
- struct sk_buff *pkt_next, *tmp;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- ret = brcmf_sdio_txpkt_prep(bus, pktq, chan);
- if (ret)
- goto done;
-
- sdio_claim_host(bus->sdiodev->func[1]);
- ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
- bus->sdcnt.f2txdata++;
-
- if (ret < 0)
- brcmf_sdio_txfail(bus);
-
- sdio_release_host(bus->sdiodev->func[1]);
-
-done:
- brcmf_sdio_txpkt_postp(bus, pktq);
- if (ret == 0)
- bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
- skb_queue_walk_safe(pktq, pkt_next, tmp) {
- __skb_unlink(pkt_next, pktq);
- brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
- }
- return ret;
-}
-
-static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
-{
- struct sk_buff *pkt;
- struct sk_buff_head pktq;
- u32 intstatus = 0;
- int ret = 0, prec_out, i;
- uint cnt = 0;
- u8 tx_prec_map, pkt_num;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- tx_prec_map = ~bus->flowcontrol;
-
- /* Send frames until the limit or some other event */
- for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
- pkt_num = 1;
- if (down_interruptible(&bus->tx_seq_lock))
- return cnt;
- if (bus->txglom)
- pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
- bus->sdiodev->txglomsz);
- pkt_num = min_t(u32, pkt_num,
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
- __skb_queue_head_init(&pktq);
- spin_lock_bh(&bus->txq_lock);
- for (i = 0; i < pkt_num; i++) {
- pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map,
- &prec_out);
- if (pkt == NULL)
- break;
- __skb_queue_tail(&pktq, pkt);
- }
- spin_unlock_bh(&bus->txq_lock);
- if (i == 0) {
- up(&bus->tx_seq_lock);
- break;
- }
-
- ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
- up(&bus->tx_seq_lock);
-
- cnt += i;
-
- /* In poll mode, need to check for other events */
- if (!bus->intr) {
- /* Check device status, signal pending interrupt */
- sdio_claim_host(bus->sdiodev->func[1]);
- ret = r_sdreg32(bus, &intstatus,
- offsetof(struct sdpcmd_regs,
- intstatus));
- sdio_release_host(bus->sdiodev->func[1]);
- bus->sdcnt.f2txdata++;
- if (ret != 0)
- break;
- if (intstatus & bus->hostintmask)
- atomic_set(&bus->ipend, 1);
- }
- }
-
- /* Deflow-control stack if needed */
- if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
- bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
- bus->txoff = false;
- brcmf_txflowblock(bus->sdiodev->dev, false);
- }
-
- return cnt;
-}
-
-static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len)
-{
- u8 doff;
- u16 pad;
- uint retries = 0;
- struct brcmf_sdio_hdrinfo hd_info = {0};
- int ret;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Back the pointer to make room for bus header */
- frame -= bus->tx_hdrlen;
- len += bus->tx_hdrlen;
-
- /* Add alignment padding (optional for ctl frames) */
- doff = ((unsigned long)frame % bus->head_align);
- if (doff) {
- frame -= doff;
- len += doff;
- memset(frame + bus->tx_hdrlen, 0, doff);
- }
-
- /* Round send length to next SDIO block */
- pad = 0;
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- pad = bus->blocksize - (len % bus->blocksize);
- if ((pad > bus->roundup) || (pad >= bus->blocksize))
- pad = 0;
- } else if (len % bus->head_align) {
- pad = bus->head_align - (len % bus->head_align);
- }
- len += pad;
-
- hd_info.len = len - pad;
- hd_info.channel = SDPCM_CONTROL_CHANNEL;
- hd_info.dat_offset = doff + bus->tx_hdrlen;
- hd_info.seq_num = bus->tx_seq;
- hd_info.lastfrm = true;
- hd_info.tail_pad = pad;
- brcmf_sdio_hdpack(bus, frame, &hd_info);
-
- if (bus->txglom)
- brcmf_sdio_update_hwhdr(frame, len);
-
- brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
- frame, len, "Tx Frame:\n");
- brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
- BRCMF_HDRS_ON(),
- frame, min_t(u16, len, 16), "TxHdr:\n");
-
- do {
- ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
-
- if (ret < 0)
- brcmf_sdio_txfail(bus);
- else
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
- } while (ret < 0 && retries++ < TXRETRIES);
-
- return ret;
-}
-
-static void brcmf_sdio_bus_stop(struct device *dev)
-{
- u32 local_hostintmask;
- u8 saveclk;
- int err;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (bus->watchdog_tsk) {
- send_sig(SIGTERM, bus->watchdog_tsk, 1);
- kthread_stop(bus->watchdog_tsk);
- bus->watchdog_tsk = NULL;
- }
-
- if (bus_if->state == BRCMF_BUS_DOWN) {
- sdio_claim_host(sdiodev->func[1]);
-
- /* Enable clock for device interrupts */
- brcmf_sdio_bus_sleep(bus, false, false);
-
- /* Disable and clear interrupts at the chip level also */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
- local_hostintmask = bus->hostintmask;
- bus->hostintmask = 0;
-
- /* Force backplane clocks to assure F2 interrupt propagates */
- saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- &err);
- if (!err)
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- if (err)
- brcmf_err("Failed to force clock for F2: err %d\n",
- err);
-
- /* Turn off the bus (F2), free any pending packets */
- brcmf_dbg(INTR, "disable SDIO interrupts\n");
- sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
-
- /* Clear any pending interrupts now that F2 is disabled */
- w_sdreg32(bus, local_hostintmask,
- offsetof(struct sdpcmd_regs, intstatus));
-
- sdio_release_host(sdiodev->func[1]);
- }
- /* Clear the data packet queues */
- brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
-
- /* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
- brcmf_sdio_free_glom(bus);
-
- /* Clear rx control and wake any waiters */
- spin_lock_bh(&bus->rxctl_lock);
- bus->rxlen = 0;
- spin_unlock_bh(&bus->rxctl_lock);
- brcmf_sdio_dcmd_resp_wake(bus);
-
- /* Reset some F2 state stuff */
- bus->rxskip = false;
- bus->tx_seq = bus->rx_seq = 0;
-}
-
-static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
-{
- unsigned long flags;
-
- if (bus->sdiodev->oob_irq_requested) {
- spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
- if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
- enable_irq(bus->sdiodev->pdata->oob_irq_nr);
- bus->sdiodev->irq_en = true;
- }
- spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
- }
-}
-
-static void atomic_orr(int val, atomic_t *v)
-{
- int old_val;
-
- old_val = atomic_read(v);
- while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
- old_val = atomic_read(v);
-}
-
-static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
-{
- struct brcmf_core *buscore;
- u32 addr;
- unsigned long val;
- int ret;
-
- buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
- addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
-
- val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
- bus->sdcnt.f1regdata++;
- if (ret != 0)
- return ret;
-
- val &= bus->hostintmask;
- atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
-
- /* Clear interrupts */
- if (val) {
- brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
- bus->sdcnt.f1regdata++;
- atomic_orr(val, &bus->intstatus);
- }
-
- return ret;
-}
-
-static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
-{
- u32 newstatus = 0;
- unsigned long intstatus;
- uint txlimit = bus->txbound; /* Tx frames to send before resched */
- uint framecnt; /* Temporary counter of tx/rx frames */
- int err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- sdio_claim_host(bus->sdiodev->func[1]);
-
- /* If waiting for HTAVAIL, check status */
- if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
- u8 clkctl, devctl = 0;
-
-#ifdef DEBUG
- /* Check for inconsistent device control */
- devctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_DEVICE_CTL, &err);
-#endif /* DEBUG */
-
- /* Read CSR, if clock on switch to AVAIL, else ignore */
- clkctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
-
- brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
- devctl, clkctl);
-
- if (SBSDIO_HTAV(clkctl)) {
- devctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
- devctl, &err);
- bus->clkstate = CLK_AVAIL;
- }
- }
-
- /* Make sure backplane clock is on */
- brcmf_sdio_bus_sleep(bus, false, true);
-
- /* Pending interrupt indicates new device status */
- if (atomic_read(&bus->ipend) > 0) {
- atomic_set(&bus->ipend, 0);
- err = brcmf_sdio_intr_rstatus(bus);
- }
-
- /* Start with leftover status bits */
- intstatus = atomic_xchg(&bus->intstatus, 0);
-
- /* Handle flow-control change: read new state in case our ack
- * crossed another change interrupt. If change still set, assume
- * FC ON for safety, let next loop through do the debounce.
- */
- if (intstatus & I_HMB_FC_CHANGE) {
- intstatus &= ~I_HMB_FC_CHANGE;
- err = w_sdreg32(bus, I_HMB_FC_CHANGE,
- offsetof(struct sdpcmd_regs, intstatus));
-
- err = r_sdreg32(bus, &newstatus,
- offsetof(struct sdpcmd_regs, intstatus));
- bus->sdcnt.f1regdata += 2;
- atomic_set(&bus->fcstate,
- !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)));
- intstatus |= (newstatus & bus->hostintmask);
- }
-
- /* Handle host mailbox indication */
- if (intstatus & I_HMB_HOST_INT) {
- intstatus &= ~I_HMB_HOST_INT;
- intstatus |= brcmf_sdio_hostmail(bus);
- }
-
- sdio_release_host(bus->sdiodev->func[1]);
-
- /* Generally don't ask for these, can get CRC errors... */
- if (intstatus & I_WR_OOSYNC) {
- brcmf_err("Dongle reports WR_OOSYNC\n");
- intstatus &= ~I_WR_OOSYNC;
- }
-
- if (intstatus & I_RD_OOSYNC) {
- brcmf_err("Dongle reports RD_OOSYNC\n");
- intstatus &= ~I_RD_OOSYNC;
- }
-
- if (intstatus & I_SBINT) {
- brcmf_err("Dongle reports SBINT\n");
- intstatus &= ~I_SBINT;
- }
-
- /* Would be active due to wake-wlan in gSPI */
- if (intstatus & I_CHIPACTIVE) {
- brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
- intstatus &= ~I_CHIPACTIVE;
- }
-
- /* Ignore frame indications if rxskip is set */
- if (bus->rxskip)
- intstatus &= ~I_HMB_FRAME_IND;
-
- /* On frame indication, read available frames */
- if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
- brcmf_sdio_readframes(bus, bus->rxbound);
- if (!bus->rxpending)
- intstatus &= ~I_HMB_FRAME_IND;
- }
-
- /* Keep still-pending events for next scheduling */
- if (intstatus)
- atomic_orr(intstatus, &bus->intstatus);
-
- brcmf_sdio_clrintr(bus);
-
- if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
- (down_interruptible(&bus->tx_seq_lock) == 0)) {
- if (data_ok(bus)) {
- sdio_claim_host(bus->sdiodev->func[1]);
- err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
- bus->ctrl_frame_len);
- sdio_release_host(bus->sdiodev->func[1]);
-
- bus->ctrl_frame_stat = false;
- brcmf_sdio_wait_event_wakeup(bus);
- }
- up(&bus->tx_seq_lock);
- }
- /* Send queued frames (limit 1 if rx may still be pending) */
- if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit &&
- data_ok(bus)) {
- framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
- txlimit;
- brcmf_sdio_sendfromq(bus, framecnt);
- }
-
- if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
- brcmf_err("failed backplane access over SDIO, halting operation\n");
- atomic_set(&bus->intstatus, 0);
- } else if (atomic_read(&bus->intstatus) ||
- atomic_read(&bus->ipend) > 0 ||
- (!atomic_read(&bus->fcstate) &&
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
- data_ok(bus))) {
- atomic_inc(&bus->dpc_tskcnt);
- }
-}
-
-static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
-
- return &bus->txq;
-}
-
-static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
-{
- int ret = -EBADE;
- uint prec;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
-
- brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
-
- /* Add space for the header */
- skb_push(pkt, bus->tx_hdrlen);
- /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
-
- prec = prio2prec((pkt->priority & PRIOMASK));
-
- /* Check for existing queue, current flow-control,
- pending event, or pending clock */
- brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
- bus->sdcnt.fcqueued++;
-
- /* Priority based enq */
- spin_lock_bh(&bus->txq_lock);
- /* reset bus_flags in packet cb */
- *(u16 *)(pkt->cb) = 0;
- if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
- skb_pull(pkt, bus->tx_hdrlen);
- brcmf_err("out of bus->txq !!!\n");
- ret = -ENOSR;
- } else {
- ret = 0;
- }
-
- if (pktq_len(&bus->txq) >= TXHI) {
- bus->txoff = true;
- brcmf_txflowblock(bus->sdiodev->dev, true);
- }
- spin_unlock_bh(&bus->txq_lock);
-
-#ifdef DEBUG
- if (pktq_plen(&bus->txq, prec) > qcount[prec])
- qcount[prec] = pktq_plen(&bus->txq, prec);
-#endif
-
- if (atomic_read(&bus->dpc_tskcnt) == 0) {
- atomic_inc(&bus->dpc_tskcnt);
- queue_work(bus->brcmf_wq, &bus->datawork);
- }
-
- return ret;
-}
-
-#ifdef DEBUG
-#define CONSOLE_LINE_MAX 192
-
-static int brcmf_sdio_readconsole(struct brcmf_sdio *bus)
-{
- struct brcmf_console *c = &bus->console;
- u8 line[CONSOLE_LINE_MAX], ch;
- u32 n, idx, addr;
- int rv;
-
- /* Don't do anything until FWREADY updates console address */
- if (bus->console_addr == 0)
- return 0;
-
- /* Read console log struct */
- addr = bus->console_addr + offsetof(struct rte_console, log_le);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le,
- sizeof(c->log_le));
- if (rv < 0)
- return rv;
-
- /* Allocate console buffer (one time only) */
- if (c->buf == NULL) {
- c->bufsize = le32_to_cpu(c->log_le.buf_size);
- c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
- if (c->buf == NULL)
- return -ENOMEM;
- }
-
- idx = le32_to_cpu(c->log_le.idx);
-
- /* Protect against corrupt value */
- if (idx > c->bufsize)
- return -EBADE;
-
- /* Skip reading the console buffer if the index pointer
- has not moved */
- if (idx == c->last)
- return 0;
-
- /* Read the console buffer */
- addr = le32_to_cpu(c->log_le.buf);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);
- if (rv < 0)
- return rv;
-
- while (c->last != idx) {
- for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
- if (c->last == idx) {
- /* This would output a partial line.
- * Instead, back up
- * the buffer pointer and output this
- * line next time around.
- */
- if (c->last >= n)
- c->last -= n;
- else
- c->last = c->bufsize - n;
- goto break2;
- }
- ch = c->buf[c->last];
- c->last = (c->last + 1) % c->bufsize;
- if (ch == '\n')
- break;
- line[n] = ch;
- }
-
- if (n > 0) {
- if (line[n - 1] == '\r')
- n--;
- line[n] = 0;
- pr_debug("CONSOLE: %s\n", line);
- }
- }
-break2:
-
- return 0;
-}
-#endif /* DEBUG */
-
-static int
-brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
- int ret = -1;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
-
- if (!data_ok(bus)) {
- brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
- bus->tx_max, bus->tx_seq);
- up(&bus->tx_seq_lock);
- /* Send from dpc */
- bus->ctrl_frame_buf = msg;
- bus->ctrl_frame_len = msglen;
- bus->ctrl_frame_stat = true;
-
- wait_event_interruptible_timeout(bus->ctrl_wait,
- !bus->ctrl_frame_stat,
- msecs_to_jiffies(2000));
-
- if (!bus->ctrl_frame_stat) {
- brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
- ret = 0;
- } else {
- brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
- bus->ctrl_frame_stat = false;
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
- ret = -1;
- }
- }
- if (ret == -1) {
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);
- sdio_release_host(bus->sdiodev->func[1]);
- up(&bus->tx_seq_lock);
- }
-
- if (ret)
- bus->sdcnt.tx_ctlerrs++;
- else
- bus->sdcnt.tx_ctlpkts++;
-
- return ret ? -EIO : 0;
-}
-
-#ifdef DEBUG
-static int brcmf_sdio_dump_console(struct seq_file *seq, struct brcmf_sdio *bus,
- struct sdpcm_shared *sh)
-{
- u32 addr, console_ptr, console_size, console_index;
- char *conbuf = NULL;
- __le32 sh_val;
- int rv;
-
- /* obtain console information from device memory */
- addr = sh->console_addr + offsetof(struct rte_console, log_le);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
- (u8 *)&sh_val, sizeof(u32));
- if (rv < 0)
- return rv;
- console_ptr = le32_to_cpu(sh_val);
-
- addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
- (u8 *)&sh_val, sizeof(u32));
- if (rv < 0)
- return rv;
- console_size = le32_to_cpu(sh_val);
-
- addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
- (u8 *)&sh_val, sizeof(u32));
- if (rv < 0)
- return rv;
- console_index = le32_to_cpu(sh_val);
-
- /* allocate buffer for console data */
- if (console_size <= CONSOLE_BUFFER_MAX)
- conbuf = vzalloc(console_size+1);
-
- if (!conbuf)
- return -ENOMEM;
-
- /* obtain the console data from device */
- conbuf[console_size] = '\0';
- rv = brcmf_sdiod_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf,
- console_size);
- if (rv < 0)
- goto done;
-
- rv = seq_write(seq, conbuf + console_index,
- console_size - console_index);
- if (rv < 0)
- goto done;
-
- if (console_index > 0)
- rv = seq_write(seq, conbuf, console_index - 1);
-
-done:
- vfree(conbuf);
- return rv;
-}
-
-static int brcmf_sdio_trap_info(struct seq_file *seq, struct brcmf_sdio *bus,
- struct sdpcm_shared *sh)
-{
- int error;
- struct brcmf_trap_info tr;
-
- if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
- brcmf_dbg(INFO, "no trap in firmware\n");
- return 0;
- }
-
- error = brcmf_sdiod_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr,
- sizeof(struct brcmf_trap_info));
- if (error < 0)
- return error;
-
- seq_printf(seq,
- "dongle trap info: type 0x%x @ epc 0x%08x\n"
- " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
- " lr 0x%08x pc 0x%08x offset 0x%x\n"
- " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n"
- " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n",
- le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
- le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
- le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
- le32_to_cpu(tr.pc), sh->trap_addr,
- le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
- le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
- le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
- le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
-
- return 0;
-}
-
-static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
- struct sdpcm_shared *sh)
-{
- int error = 0;
- char file[80] = "?";
- char expr[80] = "<???>";
-
- if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
- brcmf_dbg(INFO, "firmware not built with -assert\n");
- return 0;
- } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
- brcmf_dbg(INFO, "no assert in dongle\n");
- return 0;
- }
-
- sdio_claim_host(bus->sdiodev->func[1]);
- if (sh->assert_file_addr != 0) {
- error = brcmf_sdiod_ramrw(bus->sdiodev, false,
- sh->assert_file_addr, (u8 *)file, 80);
- if (error < 0)
- return error;
- }
- if (sh->assert_exp_addr != 0) {
- error = brcmf_sdiod_ramrw(bus->sdiodev, false,
- sh->assert_exp_addr, (u8 *)expr, 80);
- if (error < 0)
- return error;
- }
- sdio_release_host(bus->sdiodev->func[1]);
-
- seq_printf(seq, "dongle assert: %s:%d: assert(%s)\n",
- file, sh->assert_line, expr);
- return 0;
-}
-
-static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
-{
- int error;
- struct sdpcm_shared sh;
-
- error = brcmf_sdio_readshared(bus, &sh);
-
- if (error < 0)
- return error;
-
- if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
- brcmf_dbg(INFO, "firmware not built with -assert\n");
- else if (sh.flags & SDPCM_SHARED_ASSERT)
- brcmf_err("assertion in dongle\n");
-
- if (sh.flags & SDPCM_SHARED_TRAP)
- brcmf_err("firmware trap in dongle\n");
-
- return 0;
-}
-
-static int brcmf_sdio_died_dump(struct seq_file *seq, struct brcmf_sdio *bus)
-{
- int error = 0;
- struct sdpcm_shared sh;
-
- error = brcmf_sdio_readshared(bus, &sh);
- if (error < 0)
- goto done;
-
- error = brcmf_sdio_assert_info(seq, bus, &sh);
- if (error < 0)
- goto done;
-
- error = brcmf_sdio_trap_info(seq, bus, &sh);
- if (error < 0)
- goto done;
-
- error = brcmf_sdio_dump_console(seq, bus, &sh);
-
-done:
- return error;
-}
-
-static int brcmf_sdio_forensic_read(struct seq_file *seq, void *data)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
- struct brcmf_sdio *bus = bus_if->bus_priv.sdio->bus;
-
- return brcmf_sdio_died_dump(seq, bus);
-}
-
-static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio_count *sdcnt = &sdiodev->bus->sdcnt;
-
- seq_printf(seq,
- "intrcount: %u\nlastintrs: %u\n"
- "pollcnt: %u\nregfails: %u\n"
- "tx_sderrs: %u\nfcqueued: %u\n"
- "rxrtx: %u\nrx_toolong: %u\n"
- "rxc_errors: %u\nrx_hdrfail: %u\n"
- "rx_badhdr: %u\nrx_badseq: %u\n"
- "fc_rcvd: %u\nfc_xoff: %u\n"
- "fc_xon: %u\nrxglomfail: %u\n"
- "rxglomframes: %u\nrxglompkts: %u\n"
- "f2rxhdrs: %u\nf2rxdata: %u\n"
- "f2txdata: %u\nf1regdata: %u\n"
- "tickcnt: %u\ntx_ctlerrs: %lu\n"
- "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n"
- "rx_ctlpkts: %lu\nrx_readahead: %lu\n",
- sdcnt->intrcount, sdcnt->lastintrs,
- sdcnt->pollcnt, sdcnt->regfails,
- sdcnt->tx_sderrs, sdcnt->fcqueued,
- sdcnt->rxrtx, sdcnt->rx_toolong,
- sdcnt->rxc_errors, sdcnt->rx_hdrfail,
- sdcnt->rx_badhdr, sdcnt->rx_badseq,
- sdcnt->fc_rcvd, sdcnt->fc_xoff,
- sdcnt->fc_xon, sdcnt->rxglomfail,
- sdcnt->rxglomframes, sdcnt->rxglompkts,
- sdcnt->f2rxhdrs, sdcnt->f2rxdata,
- sdcnt->f2txdata, sdcnt->f1regdata,
- sdcnt->tickcnt, sdcnt->tx_ctlerrs,
- sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
- sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
-
- return 0;
-}
-
-static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
-{
- struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
- struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
-
- if (IS_ERR_OR_NULL(dentry))
- return;
-
- brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
- brcmf_debugfs_add_entry(drvr, "counters",
- brcmf_debugfs_sdio_count_read);
- debugfs_create_u32("console_interval", 0644, dentry,
- &bus->console_interval);
-}
-#else
-static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
-{
- return 0;
-}
-
-static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
-{
-}
-#endif /* DEBUG */
-
-static int
-brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
-{
- int timeleft;
- uint rxlen = 0;
- bool pending;
- u8 *buf;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Wait until control frame is available */
- timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
-
- spin_lock_bh(&bus->rxctl_lock);
- rxlen = bus->rxlen;
- memcpy(msg, bus->rxctl, min(msglen, rxlen));
- bus->rxctl = NULL;
- buf = bus->rxctl_orig;
- bus->rxctl_orig = NULL;
- bus->rxlen = 0;
- spin_unlock_bh(&bus->rxctl_lock);
- vfree(buf);
-
- if (rxlen) {
- brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
- rxlen, msglen);
- } else if (timeleft == 0) {
- brcmf_err("resumed on timeout\n");
- brcmf_sdio_checkdied(bus);
- } else if (pending) {
- brcmf_dbg(CTL, "cancelled\n");
- return -ERESTARTSYS;
- } else {
- brcmf_dbg(CTL, "resumed for unknown reason?\n");
- brcmf_sdio_checkdied(bus);
- }
-
- if (rxlen)
- bus->sdcnt.rx_ctlpkts++;
- else
- bus->sdcnt.rx_ctlerrs++;
-
- return rxlen ? (int)rxlen : -ETIMEDOUT;
-}
-
-#ifdef DEBUG
-static bool
-brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
- u8 *ram_data, uint ram_sz)
-{
- char *ram_cmp;
- int err;
- bool ret = true;
- int address;
- int offset;
- int len;
-
- /* read back and verify */
- brcmf_dbg(INFO, "Compare RAM dl & ul at 0x%08x; size=%d\n", ram_addr,
- ram_sz);
- ram_cmp = kmalloc(MEMBLOCK, GFP_KERNEL);
- /* do not proceed while no memory but */
- if (!ram_cmp)
- return true;
-
- address = ram_addr;
- offset = 0;
- while (offset < ram_sz) {
- len = ((offset + MEMBLOCK) < ram_sz) ? MEMBLOCK :
- ram_sz - offset;
- err = brcmf_sdiod_ramrw(sdiodev, false, address, ram_cmp, len);
- if (err) {
- brcmf_err("error %d on reading %d membytes at 0x%08x\n",
- err, len, address);
- ret = false;
- break;
- } else if (memcmp(ram_cmp, &ram_data[offset], len)) {
- brcmf_err("Downloaded RAM image is corrupted, block offset is %d, len is %d\n",
- offset, len);
- ret = false;
- break;
- }
- offset += len;
- address += len;
- }
-
- kfree(ram_cmp);
-
- return ret;
-}
-#else /* DEBUG */
-static bool
-brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
- u8 *ram_data, uint ram_sz)
-{
- return true;
-}
-#endif /* DEBUG */
-
-static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus,
- const struct firmware *fw)
-{
- int err;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- err = brcmf_sdiod_ramrw(bus->sdiodev, true, bus->ci->rambase,
- (u8 *)fw->data, fw->size);
- if (err)
- brcmf_err("error %d on writing %d membytes at 0x%08x\n",
- err, (int)fw->size, bus->ci->rambase);
- else if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase,
- (u8 *)fw->data, fw->size))
- err = -EIO;
-
- return err;
-}
-
-static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus,
- void *vars, u32 varsz)
-{
- int address;
- int err;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- address = bus->ci->ramsize - varsz + bus->ci->rambase;
- err = brcmf_sdiod_ramrw(bus->sdiodev, true, address, vars, varsz);
- if (err)
- brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
- err, varsz, address);
- else if (!brcmf_sdio_verifymemory(bus->sdiodev, address, vars, varsz))
- err = -EIO;
-
- return err;
-}
-
-static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
- const struct firmware *fw,
- void *nvram, u32 nvlen)
-{
- int bcmerror = -EFAULT;
- u32 rstvec;
-
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
-
- /* Keep arm in reset */
- brcmf_chip_enter_download(bus->ci);
-
- rstvec = get_unaligned_le32(fw->data);
- brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
-
- bcmerror = brcmf_sdio_download_code_file(bus, fw);
- release_firmware(fw);
- if (bcmerror) {
- brcmf_err("dongle image file download failed\n");
- brcmf_fw_nvram_free(nvram);
- goto err;
- }
-
- bcmerror = brcmf_sdio_download_nvram(bus, nvram, nvlen);
- brcmf_fw_nvram_free(nvram);
- if (bcmerror) {
- brcmf_err("dongle nvram file download failed\n");
- goto err;
- }
-
- /* Take arm out of reset */
- if (!brcmf_chip_exit_download(bus->ci, rstvec)) {
- brcmf_err("error getting out of ARM core reset\n");
- goto err;
- }
-
- /* Allow HT Clock now that the ARM is running. */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
- bcmerror = 0;
-
-err:
- brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
- sdio_release_host(bus->sdiodev->func[1]);
- return bcmerror;
-}
-
-static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
-{
- int err = 0;
- u8 val;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, &err);
- if (err) {
- brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n");
- return;
- }
-
- val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err);
- if (err) {
- brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");
- return;
- }
-
- /* Add CMD14 Support */
- brcmf_sdiod_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
- (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
- SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT),
- &err);
- if (err) {
- brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");
- return;
- }
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- SBSDIO_FORCE_HT, &err);
- if (err) {
- brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");
- return;
- }
-
- /* set flag */
- bus->sr_enabled = true;
- brcmf_dbg(INFO, "SR enabled\n");
-}
-
-/* enable KSO bit */
-static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)
-{
- u8 val;
- int err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* KSO bit added in SDIO core rev 12 */
- if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12)
- return 0;
-
- val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
- if (err) {
- brcmf_err("error reading SBSDIO_FUNC1_SLEEPCSR\n");
- return err;
- }
-
- if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
- val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN <<
- SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
- val, &err);
- if (err) {
- brcmf_err("error writing SBSDIO_FUNC1_SLEEPCSR\n");
- return err;
- }
- }
-
- return 0;
-}
-
-
-static int brcmf_sdio_bus_preinit(struct device *dev)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
- uint pad_size;
- u32 value;
- int err;
-
- /* the commands below use the terms tx and rx from
- * a device perspective, ie. bus:txglom affects the
- * bus transfers from device to host.
- */
- if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) {
- /* for sdio core rev < 12, disable txgloming */
- value = 0;
- err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
- sizeof(u32));
- } else {
- /* otherwise, set txglomalign */
- value = 4;
- if (sdiodev->pdata)
- value = sdiodev->pdata->sd_sgentry_align;
- /* SDIO ADMA requires at least 32 bit alignment */
- value = max_t(u32, value, 4);
- err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
- sizeof(u32));
- }
-
- if (err < 0)
- goto done;
-
- bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
- if (sdiodev->sg_support) {
- bus->txglom = false;
- value = 1;
- pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
- err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
- &value, sizeof(u32));
- if (err < 0) {
- /* bus:rxglom is allowed to fail */
- err = 0;
- } else {
- bus->txglom = true;
- bus->tx_hdrlen += SDPCM_HWEXT_LEN;
- }
- }
- brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen);
-
-done:
- return err;
-}
-
-void brcmf_sdio_isr(struct brcmf_sdio *bus)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- if (!bus) {
- brcmf_err("bus is null pointer, exiting\n");
- return;
- }
-
- if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
- brcmf_err("bus is down. we have nothing to do\n");
- return;
- }
- /* Count the interrupt call */
- bus->sdcnt.intrcount++;
- if (in_interrupt())
- atomic_set(&bus->ipend, 1);
- else
- if (brcmf_sdio_intr_rstatus(bus)) {
- brcmf_err("failed backplane access\n");
- }
-
- /* Disable additional interrupts (is this needed now)? */
- if (!bus->intr)
- brcmf_err("isr w/o interrupt configured!\n");
-
- atomic_inc(&bus->dpc_tskcnt);
- queue_work(bus->brcmf_wq, &bus->datawork);
-}
-
-static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
-{
-#ifdef DEBUG
- struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
-#endif /* DEBUG */
-
- brcmf_dbg(TIMER, "Enter\n");
-
- /* Poll period: check device if appropriate. */
- if (!bus->sr_enabled &&
- bus->poll && (++bus->polltick >= bus->pollrate)) {
- u32 intstatus = 0;
-
- /* Reset poll tick */
- bus->polltick = 0;
-
- /* Check device if no interrupts */
- if (!bus->intr ||
- (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
-
- if (atomic_read(&bus->dpc_tskcnt) == 0) {
- u8 devpend;
-
- sdio_claim_host(bus->sdiodev->func[1]);
- devpend = brcmf_sdiod_regrb(bus->sdiodev,
- SDIO_CCCR_INTx,
- NULL);
- sdio_release_host(bus->sdiodev->func[1]);
- intstatus =
- devpend & (INTR_STATUS_FUNC1 |
- INTR_STATUS_FUNC2);
- }
-
- /* If there is something, make like the ISR and
- schedule the DPC */
- if (intstatus) {
- bus->sdcnt.pollcnt++;
- atomic_set(&bus->ipend, 1);
-
- atomic_inc(&bus->dpc_tskcnt);
- queue_work(bus->brcmf_wq, &bus->datawork);
- }
- }
-
- /* Update interrupt tracking */
- bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
- }
-#ifdef DEBUG
- /* Poll for console output periodically */
- if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
- bus->console_interval != 0) {
- bus->console.count += BRCMF_WD_POLL_MS;
- if (bus->console.count >= bus->console_interval) {
- bus->console.count -= bus->console_interval;
- sdio_claim_host(bus->sdiodev->func[1]);
- /* Make sure backplane clock is on */
- brcmf_sdio_bus_sleep(bus, false, false);
- if (brcmf_sdio_readconsole(bus) < 0)
- /* stop on error */
- bus->console_interval = 0;
- sdio_release_host(bus->sdiodev->func[1]);
- }
- }
-#endif /* DEBUG */
-
- /* On idle timeout clear activity flag and/or turn off clock */
- if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
- if (++bus->idlecount >= bus->idletime) {
- bus->idlecount = 0;
- if (bus->activity) {
- bus->activity = false;
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
- } else {
- brcmf_dbg(SDIO, "idle\n");
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, true, false);
- sdio_release_host(bus->sdiodev->func[1]);
- }
- }
- }
-
- return (atomic_read(&bus->ipend) > 0);
-}
-
-static void brcmf_sdio_dataworker(struct work_struct *work)
-{
- struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
- datawork);
-
- while (atomic_read(&bus->dpc_tskcnt)) {
- atomic_set(&bus->dpc_tskcnt, 0);
- brcmf_sdio_dpc(bus);
- }
-}
-
-static void
-brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
- struct brcmf_chip *ci, u32 drivestrength)
-{
- const struct sdiod_drive_str *str_tab = NULL;
- u32 str_mask;
- u32 str_shift;
- u32 base;
- u32 i;
- u32 drivestrength_sel = 0;
- u32 cc_data_temp;
- u32 addr;
-
- if (!(ci->cc_caps & CC_CAP_PMU))
- return;
-
- switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
- case SDIOD_DRVSTR_KEY(BRCM_CC_4330_CHIP_ID, 12):
- str_tab = sdiod_drvstr_tab1_1v8;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- case SDIOD_DRVSTR_KEY(BRCM_CC_4334_CHIP_ID, 17):
- str_tab = sdiod_drvstr_tab6_1v8;
- str_mask = 0x00001800;
- str_shift = 11;
- break;
- case SDIOD_DRVSTR_KEY(BRCM_CC_43143_CHIP_ID, 17):
- /* note: 43143 does not support tristate */
- i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
- if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
- str_tab = sdiod_drvstr_tab2_3v3;
- str_mask = 0x00000007;
- str_shift = 0;
- } else
- brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
- ci->name, drivestrength);
- break;
- case SDIOD_DRVSTR_KEY(BRCM_CC_43362_CHIP_ID, 13):
- str_tab = sdiod_drive_strength_tab5_1v8;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- default:
- brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
- ci->name, ci->chiprev, ci->pmurev);
- break;
- }
-
- if (str_tab != NULL) {
- for (i = 0; str_tab[i].strength != 0; i++) {
- if (drivestrength >= str_tab[i].strength) {
- drivestrength_sel = str_tab[i].sel;
- break;
- }
- }
- base = brcmf_chip_get_chipcommon(ci)->base;
- addr = CORE_CC_REG(base, chipcontrol_addr);
- brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
- cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- cc_data_temp &= ~str_mask;
- drivestrength_sel <<= str_shift;
- cc_data_temp |= drivestrength_sel;
- brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
-
- brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
- str_tab[i].strength, drivestrength, cc_data_temp);
- }
-}
-
-static int brcmf_sdio_buscoreprep(void *ctx)
-{
- struct brcmf_sdio_dev *sdiodev = ctx;
- int err = 0;
- u8 clkval, clkset;
-
- /* Try forcing SDIO core to do ALPAvail request only */
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
- if (err) {
- brcmf_err("error writing for HT off\n");
- return err;
- }
-
- /* If register supported, wait for ALPAvail and then force ALP */
- /* This may take up to 15 milliseconds */
- clkval = brcmf_sdiod_regrb(sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL);
-
- if ((clkval & ~SBSDIO_AVBITS) != clkset) {
- brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
- clkset, clkval);
- return -EACCES;
- }
-
- SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
- !SBSDIO_ALPAV(clkval)),
- PMU_MAX_TRANSITION_DLY);
- if (!SBSDIO_ALPAV(clkval)) {
- brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
- clkval);
- return -EBUSY;
- }
-
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
- udelay(65);
-
- /* Also, disable the extra SDIO pull-ups */
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
-
- return 0;
-}
-
-static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
- u32 rstvec)
-{
- struct brcmf_sdio_dev *sdiodev = ctx;
- struct brcmf_core *core;
- u32 reg_addr;
-
- /* clear all interrupts */
- core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV);
- reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus);
- brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
-
- if (rstvec)
- /* Write reset vector to address 0 */
- brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
- sizeof(rstvec));
-}
-
-static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
-{
- struct brcmf_sdio_dev *sdiodev = ctx;
- u32 val, rev;
-
- val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID &&
- addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
- rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
- if (rev >= 2) {
- val &= ~CID_ID_MASK;
- val |= BRCM_CC_4339_CHIP_ID;
- }
- }
- return val;
-}
-
-static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
-{
- struct brcmf_sdio_dev *sdiodev = ctx;
-
- brcmf_sdiod_regwl(sdiodev, addr, val, NULL);
-}
-
-static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
- .prepare = brcmf_sdio_buscoreprep,
- .exit_dl = brcmf_sdio_buscore_exitdl,
- .read32 = brcmf_sdio_buscore_read32,
- .write32 = brcmf_sdio_buscore_write32,
-};
-
-static bool
-brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
-{
- u8 clkctl = 0;
- int err = 0;
- int reg_addr;
- u32 reg_val;
- u32 drivestrength;
-
- sdio_claim_host(bus->sdiodev->func[1]);
-
- pr_debug("F1 signature read @0x18000000=0x%4x\n",
- brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
-
- /*
- * Force PLL off until brcmf_chip_attach()
- * programs PLL control regs
- */
-
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- BRCMF_INIT_CLKCTL1, &err);
- if (!err)
- clkctl = brcmf_sdiod_regrb(bus->sdiodev,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
-
- if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
- brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
- err, BRCMF_INIT_CLKCTL1, clkctl);
- goto fail;
- }
-
- /* SDIO register access works so moving
- * state from UNKNOWN to DOWN.
- */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
-
- bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
- if (IS_ERR(bus->ci)) {
- brcmf_err("brcmf_chip_attach failed!\n");
- bus->ci = NULL;
- goto fail;
- }
-
- if (brcmf_sdio_kso_init(bus)) {
- brcmf_err("error enabling KSO\n");
- goto fail;
- }
-
- if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
- drivestrength = bus->sdiodev->pdata->drive_strength;
- else
- drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
- brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
-
- /* Get info on the SOCRAM cores... */
- bus->ramsize = bus->ci->ramsize;
- if (!(bus->ramsize)) {
- brcmf_err("failed to find SOCRAM memory!\n");
- goto fail;
- }
-
- /* Set card control so an SDIO card reset does a WLAN backplane reset */
- reg_val = brcmf_sdiod_regrb(bus->sdiodev,
- SDIO_CCCR_BRCM_CARDCTRL, &err);
- if (err)
- goto fail;
-
- reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
-
- brcmf_sdiod_regwb(bus->sdiodev,
- SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
- if (err)
- goto fail;
-
- /* set PMUControl so a backplane reset does PMU state reload */
- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
- pmucontrol);
- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
- if (err)
- goto fail;
-
- reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
-
- brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
- if (err)
- goto fail;
-
- sdio_release_host(bus->sdiodev->func[1]);
-
- brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
-
- /* allocate header buffer */
- bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
- if (!bus->hdrbuf)
- return false;
- /* Locate an appropriately-aligned portion of hdrbuf */
- bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
- bus->head_align);
-
- /* Set the poll and/or interrupt flags */
- bus->intr = true;
- bus->poll = false;
- if (bus->poll)
- bus->pollrate = 1;
-
- return true;
-
-fail:
- sdio_release_host(bus->sdiodev->func[1]);
- return false;
-}
-
-static int
-brcmf_sdio_watchdog_thread(void *data)
-{
- struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
-
- allow_signal(SIGTERM);
- /* Run until signal received */
- while (1) {
- if (kthread_should_stop())
- break;
- if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
- brcmf_sdio_bus_watchdog(bus);
- /* Count the tick for reference */
- bus->sdcnt.tickcnt++;
- reinit_completion(&bus->watchdog_wait);
- } else
- break;
- }
- return 0;
-}
-
-static void
-brcmf_sdio_watchdog(unsigned long data)
-{
- struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
-
- if (bus->watchdog_tsk) {
- complete(&bus->watchdog_wait);
- /* Reschedule the watchdog */
- if (bus->wd_timer_valid)
- mod_timer(&bus->timer,
- jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
- }
-}
-
-static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
- .stop = brcmf_sdio_bus_stop,
- .preinit = brcmf_sdio_bus_preinit,
- .txdata = brcmf_sdio_bus_txdata,
- .txctl = brcmf_sdio_bus_txctl,
- .rxctl = brcmf_sdio_bus_rxctl,
- .gettxq = brcmf_sdio_bus_gettxq,
-};
-
-static void brcmf_sdio_firmware_callback(struct device *dev,
- const struct firmware *code,
- void *nvram, u32 nvram_len)
-{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- struct brcmf_sdio *bus = sdiodev->bus;
- int err = 0;
- u8 saveclk;
-
- brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
-
- /* try to download image and nvram to the dongle */
- if (bus_if->state == BRCMF_BUS_DOWN) {
- bus->alp_only = true;
- err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
- if (err)
- goto fail;
- bus->alp_only = false;
- }
-
- if (!bus_if->drvr)
- return;
-
- /* Start the watchdog timer */
- bus->sdcnt.tickcnt = 0;
- brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
-
- sdio_claim_host(sdiodev->func[1]);
-
- /* Make sure backplane clock is on, needed to generate F2 interrupt */
- brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
- if (bus->clkstate != CLK_AVAIL)
- goto release;
-
- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- }
- if (err) {
- brcmf_err("Failed to force clock for F2: err %d\n", err);
- goto release;
- }
-
- /* Enable function 2 (frame transfers) */
- w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
- offsetof(struct sdpcmd_regs, tosbmailboxdata));
- err = sdio_enable_func(sdiodev->func[SDIO_FUNC_2]);
-
-
- brcmf_dbg(INFO, "enable F2: err=%d\n", err);
-
- /* If F2 successfully enabled, set core and enable interrupts */
- if (!err) {
- /* Set up the interrupt mask and enable interrupts */
- bus->hostintmask = HOSTINTMASK;
- w_sdreg32(bus, bus->hostintmask,
- offsetof(struct sdpcmd_regs, hostintmask));
-
- brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK, 8, &err);
- } else {
- /* Disable F2 again */
- sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
- goto release;
- }
-
- if (brcmf_chip_sr_capable(bus->ci)) {
- brcmf_sdio_sr_init(bus);
- } else {
- /* Restore previous clock setting */
- brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
- saveclk, &err);
- }
-
- if (err == 0) {
- err = brcmf_sdiod_intr_register(sdiodev);
- if (err != 0)
- brcmf_err("intr register failed:%d\n", err);
- }
-
- /* If we didn't come up, turn off backplane clock */
- if (err != 0)
- brcmf_sdio_clkctl(bus, CLK_NONE, false);
-
- sdio_release_host(sdiodev->func[1]);
-
- err = brcmf_bus_start(dev);
- if (err != 0) {
- brcmf_err("dongle is not responding\n");
- goto fail;
- }
- return;
-
-release:
- sdio_release_host(sdiodev->func[1]);
-fail:
- brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err);
- device_release_driver(dev);
-}
-
-struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
-{
- int ret;
- struct brcmf_sdio *bus;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Allocate private bus interface state */
- bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
- if (!bus)
- goto fail;
-
- bus->sdiodev = sdiodev;
- sdiodev->bus = bus;
- skb_queue_head_init(&bus->glom);
- bus->txbound = BRCMF_TXBOUND;
- bus->rxbound = BRCMF_RXBOUND;
- bus->txminmax = BRCMF_TXMINMAX;
- bus->tx_seq = SDPCM_SEQ_WRAP - 1;
-
- /* platform specific configuration:
- * alignments must be at least 4 bytes for ADMA
- */
- bus->head_align = ALIGNMENT;
- bus->sgentry_align = ALIGNMENT;
- if (sdiodev->pdata) {
- if (sdiodev->pdata->sd_head_align > ALIGNMENT)
- bus->head_align = sdiodev->pdata->sd_head_align;
- if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
- bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
- }
-
- INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
- bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
- if (bus->brcmf_wq == NULL) {
- brcmf_err("insufficient memory to create txworkqueue\n");
- goto fail;
- }
-
- /* attempt to attach to the dongle */
- if (!(brcmf_sdio_probe_attach(bus))) {
- brcmf_err("brcmf_sdio_probe_attach failed\n");
- goto fail;
- }
-
- spin_lock_init(&bus->rxctl_lock);
- spin_lock_init(&bus->txq_lock);
- sema_init(&bus->tx_seq_lock, 1);
- init_waitqueue_head(&bus->ctrl_wait);
- init_waitqueue_head(&bus->dcmd_resp_wait);
-
- /* Set up the watchdog timer */
- init_timer(&bus->timer);
- bus->timer.data = (unsigned long)bus;
- bus->timer.function = brcmf_sdio_watchdog;
-
- /* Initialize watchdog thread */
- init_completion(&bus->watchdog_wait);
- bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,
- bus, "brcmf_watchdog");
- if (IS_ERR(bus->watchdog_tsk)) {
- pr_warn("brcmf_watchdog thread failed to start\n");
- bus->watchdog_tsk = NULL;
- }
- /* Initialize DPC thread */
- atomic_set(&bus->dpc_tskcnt, 0);
-
- /* Assign bus interface call back */
- bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
- bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
- bus->sdiodev->bus_if->chip = bus->ci->chip;
- bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
-
- /* default sdio bus header length for tx packet */
- bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
-
- /* Attach to the common layer, reserve hdr space */
- ret = brcmf_attach(bus->sdiodev->dev);
- if (ret != 0) {
- brcmf_err("brcmf_attach failed\n");
- goto fail;
- }
-
- /* Query the F2 block size, set roundup accordingly */
- bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
- bus->roundup = min(max_roundup, bus->blocksize);
-
- /* Allocate buffers */
- if (bus->sdiodev->bus_if->maxctl) {
- bus->sdiodev->bus_if->maxctl += bus->roundup;
- bus->rxblen =
- roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
- ALIGNMENT) + bus->head_align;
- bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
- if (!(bus->rxbuf)) {
- brcmf_err("rxbuf allocation failed\n");
- goto fail;
- }
- }
-
- sdio_claim_host(bus->sdiodev->func[1]);
-
- /* Disable F2 to clear any intermediate frame state on the dongle */
- sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
-
- bus->rxflow = false;
-
- /* Done with backplane-dependent accesses, can drop clock... */
- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
- sdio_release_host(bus->sdiodev->func[1]);
-
- /* ...and initialize clock/power states */
- bus->clkstate = CLK_SDONLY;
- bus->idletime = BRCMF_IDLE_INTERVAL;
- bus->idleclock = BRCMF_IDLE_ACTIVE;
-
- /* SR state */
- bus->sleeping = false;
- bus->sr_enabled = false;
-
- brcmf_sdio_debugfs_create(bus);
- brcmf_dbg(INFO, "completed!!\n");
-
- ret = brcmf_sdio_get_fwnames(bus->ci, sdiodev);
- if (ret)
- goto fail;
-
- ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
- sdiodev->fw_name, sdiodev->nvram_name,
- brcmf_sdio_firmware_callback);
- if (ret != 0) {
- brcmf_err("async firmware request failed: %d\n", ret);
- goto fail;
- }
-
- return bus;
-
-fail:
- brcmf_sdio_remove(bus);
- return NULL;
-}
-
-/* Detach and free everything */
-void brcmf_sdio_remove(struct brcmf_sdio *bus)
-{
- brcmf_dbg(TRACE, "Enter\n");
-
- if (bus) {
- /* De-register interrupt handler */
- brcmf_sdiod_intr_unregister(bus->sdiodev);
-
- brcmf_detach(bus->sdiodev->dev);
-
- cancel_work_sync(&bus->datawork);
- if (bus->brcmf_wq)
- destroy_workqueue(bus->brcmf_wq);
-
- if (bus->ci) {
- if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
- /* Leave the device in state where it is
- * 'quiet'. This is done by putting it in
- * download_state which essentially resets
- * all necessary cores.
- */
- msleep(20);
- brcmf_chip_enter_download(bus->ci);
- brcmf_sdio_clkctl(bus, CLK_NONE, false);
- sdio_release_host(bus->sdiodev->func[1]);
- }
- brcmf_chip_detach(bus->ci);
- }
-
- kfree(bus->rxbuf);
- kfree(bus->hdrbuf);
- kfree(bus);
- }
-
- brcmf_dbg(TRACE, "Disconnected\n");
-}
-
-void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
-{
- /* Totally stop the timer */
- if (!wdtick && bus->wd_timer_valid) {
- del_timer_sync(&bus->timer);
- bus->wd_timer_valid = false;
- bus->save_ms = wdtick;
- return;
- }
-
- /* don't start the wd until fw is loaded */
- if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
- return;
-
- if (wdtick) {
- if (bus->save_ms != BRCMF_WD_POLL_MS) {
- if (bus->wd_timer_valid)
- /* Stop timer and restart at new value */
- del_timer_sync(&bus->timer);
-
- /* Create timer again when watchdog period is
- dynamically changed or in the first instance
- */
- bus->timer.expires =
- jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
- add_timer(&bus->timer);
-
- } else {
- /* Re arm the timer, at last watchdog period */
- mod_timer(&bus->timer,
- jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
- }
-
- bus->wd_timer_valid = true;
- bus->save_ms = wdtick;
- }
-}
#include <linux/netdevice.h>
#include <brcm_hw_ids.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
#include "fwil.h"
#include "feature.h"
-/*
- * firmware error code received if iovar is unsupported.
- */
-#define EBRCMF_FEAT_UNSUPPORTED 23
-
/*
* expand feature list to array of feature strings.
*/
#include <linux/firmware.h>
#include <linux/module.h>
-#include "dhd_dbg.h"
+#include "debug.h"
#include "firmware.h"
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
#include <linux/etherdevice.h>
#include <brcmu_utils.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "debug.h"
+#include "bus.h"
#include "proto.h"
#include "flowring.h"
#include "msgbuf.h"
#include "brcmu_wifi.h"
#include "brcmu_utils.h"
-#include "dhd.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "debug.h"
#include "tracepoint.h"
#include "fwsignal.h"
#include "fweh.h"
#include <linux/netdevice.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
#include "tracepoint.h"
#include "fwil.h"
#include "proto.h"
#define MAX_HEX_DUMP_LEN 64
+#ifdef DEBUG
+static const char * const brcmf_fil_errstr[] = {
+ "BCME_OK",
+ "BCME_ERROR",
+ "BCME_BADARG",
+ "BCME_BADOPTION",
+ "BCME_NOTUP",
+ "BCME_NOTDOWN",
+ "BCME_NOTAP",
+ "BCME_NOTSTA",
+ "BCME_BADKEYIDX",
+ "BCME_RADIOOFF",
+ "BCME_NOTBANDLOCKED",
+ "BCME_NOCLK",
+ "BCME_BADRATESET",
+ "BCME_BADBAND",
+ "BCME_BUFTOOSHORT",
+ "BCME_BUFTOOLONG",
+ "BCME_BUSY",
+ "BCME_NOTASSOCIATED",
+ "BCME_BADSSIDLEN",
+ "BCME_OUTOFRANGECHAN",
+ "BCME_BADCHAN",
+ "BCME_BADADDR",
+ "BCME_NORESOURCE",
+ "BCME_UNSUPPORTED",
+ "BCME_BADLEN",
+ "BCME_NOTREADY",
+ "BCME_EPERM",
+ "BCME_NOMEM",
+ "BCME_ASSOCIATED",
+ "BCME_RANGE",
+ "BCME_NOTFOUND",
+ "BCME_WME_NOT_ENABLED",
+ "BCME_TSPEC_NOTFOUND",
+ "BCME_ACM_NOTSUPPORTED",
+ "BCME_NOT_WME_ASSOCIATION",
+ "BCME_SDIO_ERROR",
+ "BCME_DONGLE_DOWN",
+ "BCME_VERSION",
+ "BCME_TXFAIL",
+ "BCME_RXFAIL",
+ "BCME_NODEVICE",
+ "BCME_NMODE_DISABLED",
+ "BCME_NONRESIDENT",
+ "BCME_SCANREJECT",
+ "BCME_USAGE_ERROR",
+ "BCME_IOCTL_ERROR",
+ "BCME_SERIAL_PORT_ERR",
+ "BCME_DISABLED",
+ "BCME_DECERR",
+ "BCME_ENCERR",
+ "BCME_MICERR",
+ "BCME_REPLAY",
+ "BCME_IE_NOTFOUND",
+};
+
+static const char *brcmf_fil_get_errstr(u32 err)
+{
+ if (err >= ARRAY_SIZE(brcmf_fil_errstr))
+ return "(unknown)";
+
+ return brcmf_fil_errstr[err];
+}
+#else
+static const char *brcmf_fil_get_errstr(u32 err)
+{
+ return "";
+}
+#endif /* DEBUG */
static s32
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
if (err >= 0)
- err = 0;
- else
- brcmf_dbg(FIL, "Failed err=%d\n", err);
+ return 0;
- return err;
+ brcmf_dbg(FIL, "Failed: %s (%d)\n",
+ brcmf_fil_get_errstr((u32)(-err)), err);
+ return -EBADE;
}
s32
/* WOWL bits */
/* Wakeup on Magic packet: */
-#define WL_WOWL_MAGIC (1 << 0)
+#define BRCMF_WOWL_MAGIC (1 << 0)
/* Wakeup on Netpattern */
-#define WL_WOWL_NET (1 << 1)
+#define BRCMF_WOWL_NET (1 << 1)
/* Wakeup on loss-of-link due to Disassoc/Deauth: */
-#define WL_WOWL_DIS (1 << 2)
+#define BRCMF_WOWL_DIS (1 << 2)
/* Wakeup on retrograde TSF: */
-#define WL_WOWL_RETR (1 << 3)
+#define BRCMF_WOWL_RETR (1 << 3)
/* Wakeup on loss of beacon: */
-#define WL_WOWL_BCN (1 << 4)
+#define BRCMF_WOWL_BCN (1 << 4)
/* Wakeup after test: */
-#define WL_WOWL_TST (1 << 5)
+#define BRCMF_WOWL_TST (1 << 5)
/* Wakeup after PTK refresh: */
-#define WL_WOWL_M1 (1 << 6)
+#define BRCMF_WOWL_M1 (1 << 6)
/* Wakeup after receipt of EAP-Identity Req: */
-#define WL_WOWL_EAPID (1 << 7)
+#define BRCMF_WOWL_EAPID (1 << 7)
/* Wakeind via PME(0) or GPIO(1): */
-#define WL_WOWL_PME_GPIO (1 << 8)
+#define BRCMF_WOWL_PME_GPIO (1 << 8)
/* need tkip phase 1 key to be updated by the driver: */
-#define WL_WOWL_NEEDTKIP1 (1 << 9)
+#define BRCMF_WOWL_NEEDTKIP1 (1 << 9)
/* enable wakeup if GTK fails: */
-#define WL_WOWL_GTK_FAILURE (1 << 10)
+#define BRCMF_WOWL_GTK_FAILURE (1 << 10)
/* support extended magic packets: */
-#define WL_WOWL_EXTMAGPAT (1 << 11)
+#define BRCMF_WOWL_EXTMAGPAT (1 << 11)
/* support ARP/NS/keepalive offloading: */
-#define WL_WOWL_ARPOFFLOAD (1 << 12)
+#define BRCMF_WOWL_ARPOFFLOAD (1 << 12)
/* read protocol version for EAPOL frames: */
-#define WL_WOWL_WPA2 (1 << 13)
+#define BRCMF_WOWL_WPA2 (1 << 13)
/* If the bit is set, use key rotaton: */
-#define WL_WOWL_KEYROT (1 << 14)
+#define BRCMF_WOWL_KEYROT (1 << 14)
/* If the bit is set, frm received was bcast frame: */
-#define WL_WOWL_BCAST (1 << 15)
+#define BRCMF_WOWL_BCAST (1 << 15)
/* If the bit is set, scan offload is enabled: */
-#define WL_WOWL_SCANOL (1 << 16)
+#define BRCMF_WOWL_SCANOL (1 << 16)
/* Wakeup on tcpkeep alive timeout: */
-#define WL_WOWL_TCPKEEP_TIME (1 << 17)
+#define BRCMF_WOWL_TCPKEEP_TIME (1 << 17)
/* Wakeup on mDNS Conflict Resolution: */
-#define WL_WOWL_MDNS_CONFLICT (1 << 18)
+#define BRCMF_WOWL_MDNS_CONFLICT (1 << 18)
/* Wakeup on mDNS Service Connect: */
-#define WL_WOWL_MDNS_SERVICE (1 << 19)
+#define BRCMF_WOWL_MDNS_SERVICE (1 << 19)
/* tcp keepalive got data: */
-#define WL_WOWL_TCPKEEP_DATA (1 << 20)
+#define BRCMF_WOWL_TCPKEEP_DATA (1 << 20)
/* Firmware died in wowl mode: */
-#define WL_WOWL_FW_HALT (1 << 21)
+#define BRCMF_WOWL_FW_HALT (1 << 21)
/* Enable detection of radio button changes: */
-#define WL_WOWL_ENAB_HWRADIO (1 << 22)
+#define BRCMF_WOWL_ENAB_HWRADIO (1 << 22)
/* Offloads detected MIC failure(s): */
-#define WL_WOWL_MIC_FAIL (1 << 23)
+#define BRCMF_WOWL_MIC_FAIL (1 << 23)
/* Wakeup in Unassociated state (Net/Magic Pattern): */
-#define WL_WOWL_UNASSOC (1 << 24)
+#define BRCMF_WOWL_UNASSOC (1 << 24)
/* Wakeup if received matched secured pattern: */
-#define WL_WOWL_SECURE (1 << 25)
+#define BRCMF_WOWL_SECURE (1 << 25)
/* Link Down indication in WoWL mode: */
-#define WL_WOWL_LINKDOWN (1 << 31)
+#define BRCMF_WOWL_LINKDOWN (1 << 31)
+
+#define BRCMF_WOWL_MAXPATTERNS 8
+#define BRCMF_WOWL_MAXPATTERNSIZE 128
+
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
BRCMF_FIL_P2P_IF_DEV,
};
+enum brcmf_wowl_pattern_type {
+ BRCMF_WOWL_PATTERN_TYPE_BITMAP = 0,
+ BRCMF_WOWL_PATTERN_TYPE_ARP,
+ BRCMF_WOWL_PATTERN_TYPE_NA
+};
+
struct brcmf_fil_p2p_if_le {
u8 addr[ETH_ALEN];
__le16 type;
__be32 rate;
};
+/**
+ * struct brcmf_fil_wowl_pattern_le - wowl pattern configuration struct.
+ *
+ * @cmd: "add", "del" or "clr".
+ * @masksize: Size of the mask in #of bytes
+ * @offset: Pattern byte offset in packet
+ * @patternoffset: Offset of start of pattern. Starting from field masksize.
+ * @patternsize: Size of the pattern itself in #of bytes
+ * @id: id
+ * @reasonsize: Size of the wakeup reason code
+ * @type: Type of pattern (enum brcmf_wowl_pattern_type)
+ */
+struct brcmf_fil_wowl_pattern_le {
+ u8 cmd[4];
+ __le32 masksize;
+ __le32 offset;
+ __le32 patternoffset;
+ __le32 patternsize;
+ __le32 id;
+ __le32 reasonsize;
+ __le32 type;
+ /* u8 mask[] - Mask follows the structure above */
+ /* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */
+};
+
#endif /* FWIL_TYPES_H_ */
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "debug.h"
+#include "bus.h"
#include "fwil.h"
#include "fwil_types.h"
#include "fweh.h"
#include "fwsignal.h"
#include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
#include "proto.h"
/**
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "debug.h"
#include "proto.h"
#include "msgbuf.h"
#include "commonring.h"
#include "flowring.h"
-#include "dhd_bus.h"
+#include "bus.h"
#include "tracepoint.h"
#include <linux/mmc/sdio_func.h>
#include <defs.h>
-#include "dhd_dbg.h"
-#include "sdio_host.h"
+#include "debug.h"
+#include "sdio.h"
void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
{
#include <brcmu_wifi.h>
#include <brcmu_utils.h>
#include <defs.h>
-#include <dhd.h>
-#include <dhd_dbg.h>
+#include "core.h"
+#include "debug.h"
#include "fwil.h"
#include "fwil_types.h"
#include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
/* parameters used for p2p escan */
#define P2PAPI_SCAN_NPROBES 1
#include <brcmu_wifi.h>
#include <brcm_hw_ids.h>
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "debug.h"
+#include "bus.h"
#include "commonring.h"
#include "msgbuf.h"
#include "pcie.h"
#include <linux/netdevice.h>
#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
#include "proto.h"
#include "bcdc.h"
#include "msgbuf.h"
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/printk.h>
+#include <linux/pci_ids.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/semaphore.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/bcma/bcma.h>
+#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_data/brcmfmac-sdio.h>
+#include <linux/moduleparam.h>
+#include <asm/unaligned.h>
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <brcm_hw_ids.h>
+#include <soc.h>
+#include "sdio.h"
+#include "chip.h"
+#include "firmware.h"
+
+#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+
+#ifdef DEBUG
+
+#define BRCMF_TRAP_INFO_SIZE 80
+
+#define CBUF_LEN (128)
+
+/* Device console log buffer state */
+#define CONSOLE_BUFFER_MAX 2024
+
+struct rte_log_le {
+ __le32 buf; /* Can't be pointer on (64-bit) hosts */
+ __le32 buf_size;
+ __le32 idx;
+ char *_buf_compat; /* Redundant pointer for backward compat. */
+};
+
+struct rte_console {
+ /* Virtual UART
+ * When there is no UART (e.g. Quickturn),
+ * the host should write a complete
+ * input line directly into cbuf and then write
+ * the length into vcons_in.
+ * This may also be used when there is a real UART
+ * (at risk of conflicting with
+ * the real UART). vcons_out is currently unused.
+ */
+ uint vcons_in;
+ uint vcons_out;
+
+ /* Output (logging) buffer
+ * Console output is written to a ring buffer log_buf at index log_idx.
+ * The host may read the output when it sees log_idx advance.
+ * Output will be lost if the output wraps around faster than the host
+ * polls.
+ */
+ struct rte_log_le log_le;
+
+ /* Console input line buffer
+ * Characters are read one at a time into cbuf
+ * until <CR> is received, then
+ * the buffer is processed as a command line.
+ * Also used for virtual UART.
+ */
+ uint cbuf_idx;
+ char cbuf[CBUF_LEN];
+};
+
+#endif /* DEBUG */
+#include <chipcommon.h>
+
+#include "bus.h"
+#include "debug.h"
+#include "tracepoint.h"
+
+#define TXQLEN 2048 /* bulk tx queue length */
+#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
+#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
+#define PRIOMASK 7
+
+#define TXRETRIES 2 /* # of retries for tx frames */
+
+#define BRCMF_RXBOUND 50 /* Default for max rx frames in
+ one scheduling */
+
+#define BRCMF_TXBOUND 20 /* Default for max tx frames in
+ one scheduling */
+
+#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
+
+#define MEMBLOCK 2048 /* Block size used for downloading
+ of dongle image */
+#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
+ biggest possible glom */
+
+#define BRCMF_FIRSTREAD (1 << 6)
+
+
+/* SBSDIO_DEVICE_CTL */
+
+/* 1: device will assert busy signal when receiving CMD53 */
+#define SBSDIO_DEVCTL_SETBUSY 0x01
+/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
+#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
+/* 1: mask all interrupts to host except the chipActive (rev 8) */
+#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04
+/* 1: isolate internal sdio signals, put external pads in tri-state; requires
+ * sdio bus power cycle to clear (rev 9) */
+#define SBSDIO_DEVCTL_PADS_ISO 0x08
+/* Force SD->SB reset mapping (rev 11) */
+#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
+/* Determined by CoreControl bit */
+#define SBSDIO_DEVCTL_RST_CORECTL 0x00
+/* Force backplane reset */
+#define SBSDIO_DEVCTL_RST_BPRESET 0x10
+/* Force no backplane reset */
+#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
+
+/* direct(mapped) cis space */
+
+/* MAPPED common CIS address */
+#define SBSDIO_CIS_BASE_COMMON 0x1000
+/* maximum bytes in one CIS */
+#define SBSDIO_CIS_SIZE_LIMIT 0x200
+/* cis offset addr is < 17 bits */
+#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
+
+/* manfid tuple length, include tuple, link bytes */
+#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
+
+#define CORE_BUS_REG(base, field) \
+ (base + offsetof(struct sdpcmd_regs, field))
+
+/* SDIO function 1 register CHIPCLKCSR */
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP 0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT 0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP 0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ 0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ 0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL 0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL 0x80
+#define SBSDIO_CSR_MASK 0x1F
+#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+#define SBSDIO_CLKAV(regval, alponly) \
+ (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+/* intstatus */
+#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
+#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
+#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
+#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
+#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
+#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
+#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
+#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
+#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
+#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
+#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
+#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
+#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
+#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
+#define I_PC (1 << 10) /* descriptor error */
+#define I_PD (1 << 11) /* data error */
+#define I_DE (1 << 12) /* Descriptor protocol Error */
+#define I_RU (1 << 13) /* Receive descriptor Underflow */
+#define I_RO (1 << 14) /* Receive fifo Overflow */
+#define I_XU (1 << 15) /* Transmit fifo Underflow */
+#define I_RI (1 << 16) /* Receive Interrupt */
+#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
+#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
+#define I_XI (1 << 24) /* Transmit Interrupt */
+#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
+#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
+#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
+#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
+#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */
+#define I_SRESET (1 << 30) /* CCCR RES interrupt */
+#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
+#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
+#define I_DMA (I_RI | I_XI | I_ERRORS)
+
+/* corecontrol */
+#define CC_CISRDY (1 << 0) /* CIS Ready */
+#define CC_BPRESEN (1 << 1) /* CCCR RES signal */
+#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
+#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */
+#define CC_XMTDATAAVAIL_MODE (1 << 4)
+#define CC_XMTDATAAVAIL_CTRL (1 << 5)
+
+/* SDA_FRAMECTRL */
+#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
+#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
+#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
+#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
+
+/*
+ * Software allocation of To SB Mailbox resources
+ */
+
+/* tosbmailbox bits corresponding to intstatus bits */
+#define SMB_NAK (1 << 0) /* Frame NAK */
+#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
+#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
+#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
+
+/* tosbmailboxdata */
+#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
+
+/*
+ * Software allocation of To Host Mailbox resources
+ */
+
+/* intstatus bits */
+#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
+#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
+#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
+#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
+
+/* tohostmailboxdata */
+#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
+#define HMB_DATA_DEVREADY 2 /* talk to host after enable */
+#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
+#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
+
+#define HMB_DATA_FCDATA_MASK 0xff000000
+#define HMB_DATA_FCDATA_SHIFT 24
+
+#define HMB_DATA_VERSION_MASK 0x00ff0000
+#define HMB_DATA_VERSION_SHIFT 16
+
+/*
+ * Software-defined protocol header
+ */
+
+/* Current protocol version */
+#define SDPCM_PROT_VERSION 4
+
+/*
+ * Shared structure between dongle and the host.
+ * The structure contains pointers to trap or assert information.
+ */
+#define SDPCM_SHARED_VERSION 0x0003
+#define SDPCM_SHARED_VERSION_MASK 0x00FF
+#define SDPCM_SHARED_ASSERT_BUILT 0x0100
+#define SDPCM_SHARED_ASSERT 0x0200
+#define SDPCM_SHARED_TRAP 0x0400
+
+/* Space for header read, limit for data packets */
+#define MAX_HDR_READ (1 << 6)
+#define MAX_RX_DATASZ 2048
+
+/* Bump up limit on waiting for HT to account for first startup;
+ * if the image is doing a CRC calculation before programming the PMU
+ * for HT availability, it could take a couple hundred ms more, so
+ * max out at a 1 second (1000000us).
+ */
+#undef PMU_MAX_TRANSITION_DLY
+#define PMU_MAX_TRANSITION_DLY 1000000
+
+/* Value for ChipClockCSR during initial setup */
+#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
+ SBSDIO_ALP_AVAIL_REQ)
+
+/* Flags for SDH calls */
+#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
+
+#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
+ * when idle
+ */
+#define BRCMF_IDLE_INTERVAL 1
+
+#define KSO_WAIT_US 50
+#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+
+/*
+ * Conversion of 802.1D priority to precedence level
+ */
+static uint prio2prec(u32 prio)
+{
+ return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
+ (prio^2) : prio;
+}
+
+#ifdef DEBUG
+/* Device console log buffer state */
+struct brcmf_console {
+ uint count; /* Poll interval msec counter */
+ uint log_addr; /* Log struct address (fixed) */
+ struct rte_log_le log_le; /* Log struct (host copy) */
+ uint bufsize; /* Size of log buffer */
+ u8 *buf; /* Log buffer (host copy) */
+ uint last; /* Last buffer read index */
+};
+
+struct brcmf_trap_info {
+ __le32 type;
+ __le32 epc;
+ __le32 cpsr;
+ __le32 spsr;
+ __le32 r0; /* a1 */
+ __le32 r1; /* a2 */
+ __le32 r2; /* a3 */
+ __le32 r3; /* a4 */
+ __le32 r4; /* v1 */
+ __le32 r5; /* v2 */
+ __le32 r6; /* v3 */
+ __le32 r7; /* v4 */
+ __le32 r8; /* v5 */
+ __le32 r9; /* sb/v6 */
+ __le32 r10; /* sl/v7 */
+ __le32 r11; /* fp/v8 */
+ __le32 r12; /* ip */
+ __le32 r13; /* sp */
+ __le32 r14; /* lr */
+ __le32 pc; /* r15 */
+};
+#endif /* DEBUG */
+
+struct sdpcm_shared {
+ u32 flags;
+ u32 trap_addr;
+ u32 assert_exp_addr;
+ u32 assert_file_addr;
+ u32 assert_line;
+ u32 console_addr; /* Address of struct rte_console */
+ u32 msgtrace_addr;
+ u8 tag[32];
+ u32 brpt_addr;
+};
+
+struct sdpcm_shared_le {
+ __le32 flags;
+ __le32 trap_addr;
+ __le32 assert_exp_addr;
+ __le32 assert_file_addr;
+ __le32 assert_line;
+ __le32 console_addr; /* Address of struct rte_console */
+ __le32 msgtrace_addr;
+ u8 tag[32];
+ __le32 brpt_addr;
+};
+
+/* dongle SDIO bus specific header info */
+struct brcmf_sdio_hdrinfo {
+ u8 seq_num;
+ u8 channel;
+ u16 len;
+ u16 len_left;
+ u16 len_nxtfrm;
+ u8 dat_offset;
+ bool lastfrm;
+ u16 tail_pad;
+};
+
+/*
+ * hold counter variables
+ */
+struct brcmf_sdio_count {
+ uint intrcount; /* Count of device interrupt callbacks */
+ uint lastintrs; /* Count as of last watchdog timer */
+ uint pollcnt; /* Count of active polls */
+ uint regfails; /* Count of R_REG failures */
+ uint tx_sderrs; /* Count of tx attempts with sd errors */
+ uint fcqueued; /* Tx packets that got queued */
+ uint rxrtx; /* Count of rtx requests (NAK to dongle) */
+ uint rx_toolong; /* Receive frames too long to receive */
+ uint rxc_errors; /* SDIO errors when reading control frames */
+ uint rx_hdrfail; /* SDIO errors on header reads */
+ uint rx_badhdr; /* Bad received headers (roosync?) */
+ uint rx_badseq; /* Mismatched rx sequence number */
+ uint fc_rcvd; /* Number of flow-control events received */
+ uint fc_xoff; /* Number which turned on flow-control */
+ uint fc_xon; /* Number which turned off flow-control */
+ uint rxglomfail; /* Failed deglom attempts */
+ uint rxglomframes; /* Number of glom frames (superframes) */
+ uint rxglompkts; /* Number of packets from glom frames */
+ uint f2rxhdrs; /* Number of header reads */
+ uint f2rxdata; /* Number of frame data reads */
+ uint f2txdata; /* Number of f2 frame writes */
+ uint f1regdata; /* Number of f1 register accesses */
+ uint tickcnt; /* Number of watchdog been schedule */
+ ulong tx_ctlerrs; /* Err of sending ctrl frames */
+ ulong tx_ctlpkts; /* Ctrl frames sent to dongle */
+ ulong rx_ctlerrs; /* Err of processing rx ctrl frames */
+ ulong rx_ctlpkts; /* Ctrl frames processed from dongle */
+ ulong rx_readahead_cnt; /* packets where header read-ahead was used */
+};
+
+/* misc chip info needed by some of the routines */
+/* Private data for SDIO bus interaction */
+struct brcmf_sdio {
+ struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
+ struct brcmf_chip *ci; /* Chip info struct */
+
+ u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
+
+ u32 hostintmask; /* Copy of Host Interrupt Mask */
+ atomic_t intstatus; /* Intstatus bits (events) pending */
+ atomic_t fcstate; /* State of dongle flow-control */
+
+ uint blocksize; /* Block size of SDIO transfers */
+ uint roundup; /* Max roundup limit */
+
+ struct pktq txq; /* Queue length used for flow-control */
+ u8 flowcontrol; /* per prio flow control bitmask */
+ u8 tx_seq; /* Transmit sequence number (next) */
+ u8 tx_max; /* Maximum transmit sequence allowed */
+
+ u8 *hdrbuf; /* buffer for handling rx frame */
+ u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
+ u8 rx_seq; /* Receive sequence number (expected) */
+ struct brcmf_sdio_hdrinfo cur_read;
+ /* info of current read frame */
+ bool rxskip; /* Skip receive (awaiting NAK ACK) */
+ bool rxpending; /* Data frame pending in dongle */
+
+ uint rxbound; /* Rx frames to read before resched */
+ uint txbound; /* Tx frames to send before resched */
+ uint txminmax;
+
+ struct sk_buff *glomd; /* Packet containing glomming descriptor */
+ struct sk_buff_head glom; /* Packet list for glommed superframe */
+ uint glomerr; /* Glom packet read errors */
+
+ u8 *rxbuf; /* Buffer for receiving control packets */
+ uint rxblen; /* Allocated length of rxbuf */
+ u8 *rxctl; /* Aligned pointer into rxbuf */
+ u8 *rxctl_orig; /* pointer for freeing rxctl */
+ uint rxlen; /* Length of valid data in buffer */
+ spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */
+
+ u8 sdpcm_ver; /* Bus protocol reported by dongle */
+
+ bool intr; /* Use interrupts */
+ bool poll; /* Use polling */
+ atomic_t ipend; /* Device interrupt is pending */
+ uint spurious; /* Count of spurious interrupts */
+ uint pollrate; /* Ticks between device polls */
+ uint polltick; /* Tick counter */
+
+#ifdef DEBUG
+ uint console_interval;
+ struct brcmf_console console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DEBUG */
+
+ uint clkstate; /* State of sd and backplane clock(s) */
+ bool activity; /* Activity flag for clock down */
+ s32 idletime; /* Control for activity timeout */
+ s32 idlecount; /* Activity timeout counter */
+ s32 idleclock; /* How to set bus driver when idle */
+ bool rxflow_mode; /* Rx flow control mode */
+ bool rxflow; /* Is rx flow control on */
+ bool alp_only; /* Don't use HT clock (ALP only) */
+
+ u8 *ctrl_frame_buf;
+ u16 ctrl_frame_len;
+ bool ctrl_frame_stat;
+
+ spinlock_t txq_lock; /* protect bus->txq */
+ struct semaphore tx_seq_lock; /* protect bus->tx_seq */
+ wait_queue_head_t ctrl_wait;
+ wait_queue_head_t dcmd_resp_wait;
+
+ struct timer_list timer;
+ struct completion watchdog_wait;
+ struct task_struct *watchdog_tsk;
+ bool wd_timer_valid;
+ uint save_ms;
+
+ struct workqueue_struct *brcmf_wq;
+ struct work_struct datawork;
+ atomic_t dpc_tskcnt;
+
+ bool txoff; /* Transmit flow-controlled */
+ struct brcmf_sdio_count sdcnt;
+ bool sr_enabled; /* SaveRestore enabled */
+ bool sleeping; /* SDIO bus sleeping */
+
+ u8 tx_hdrlen; /* sdio bus header length for tx packet */
+ bool txglom; /* host tx glomming enable flag */
+ u16 head_align; /* buffer pointer alignment */
+ u16 sgentry_align; /* scatter-gather buffer alignment */
+};
+
+/* clkstate */
+#define CLK_NONE 0
+#define CLK_SDONLY 1
+#define CLK_PENDING 2
+#define CLK_AVAIL 3
+
+#ifdef DEBUG
+static int qcount[NUMPRIO];
+#endif /* DEBUG */
+
+#define DEFAULT_SDIO_DRIVE_STRENGTH 6 /* in milliamps */
+
+#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
+
+/* Retry count for register access failures */
+static const uint retry_limit = 2;
+
+/* Limit on rounding up frames */
+static const uint max_roundup = 512;
+
+#define ALIGNMENT 4
+
+enum brcmf_sdio_frmtype {
+ BRCMF_SDIO_FT_NORMAL,
+ BRCMF_SDIO_FT_SUPER,
+ BRCMF_SDIO_FT_SUB,
+};
+
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+ u8 strength; /* Pad Drive Strength in mA */
+ u8 sel; /* Chip-specific select value */
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
+static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
+ {32, 0x6},
+ {26, 0x7},
+ {22, 0x4},
+ {16, 0x5},
+ {12, 0x2},
+ {8, 0x3},
+ {4, 0x0},
+ {0, 0x1}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
+ {6, 0x7},
+ {5, 0x6},
+ {4, 0x5},
+ {3, 0x4},
+ {2, 0x2},
+ {1, 0x1},
+ {0, 0x0}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
+static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
+ {3, 0x3},
+ {2, 0x2},
+ {1, 0x1},
+ {0, 0x0} };
+
+/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
+static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
+ {16, 0x7},
+ {12, 0x5},
+ {8, 0x3},
+ {4, 0x1}
+};
+
+#define BCM43143_FIRMWARE_NAME "brcm/brcmfmac43143-sdio.bin"
+#define BCM43143_NVRAM_NAME "brcm/brcmfmac43143-sdio.txt"
+#define BCM43241B0_FIRMWARE_NAME "brcm/brcmfmac43241b0-sdio.bin"
+#define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt"
+#define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin"
+#define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt"
+#define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin"
+#define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt"
+#define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin"
+#define BCM4330_NVRAM_NAME "brcm/brcmfmac4330-sdio.txt"
+#define BCM4334_FIRMWARE_NAME "brcm/brcmfmac4334-sdio.bin"
+#define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt"
+#define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin"
+#define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt"
+#define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin"
+#define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt"
+#define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin"
+#define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt"
+#define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin"
+#define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt"
+
+MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4330_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4354_NVRAM_NAME);
+
+struct brcmf_firmware_names {
+ u32 chipid;
+ u32 revmsk;
+ const char *bin;
+ const char *nv;
+};
+
+enum brcmf_firmware_type {
+ BRCMF_FIRMWARE_BIN,
+ BRCMF_FIRMWARE_NVRAM
+};
+
+#define BRCMF_FIRMWARE_NVRAM(name) \
+ name ## _FIRMWARE_NAME, name ## _NVRAM_NAME
+
+static const struct brcmf_firmware_names brcmf_fwname_data[] = {
+ { BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
+ { BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
+ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
+ { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
+ { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
+ { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
+ { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
+ { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
+ { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) }
+};
+
+static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci,
+ struct brcmf_sdio_dev *sdiodev)
+{
+ int i;
+ char end;
+
+ for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) {
+ if (brcmf_fwname_data[i].chipid == ci->chip &&
+ brcmf_fwname_data[i].revmsk & BIT(ci->chiprev))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(brcmf_fwname_data)) {
+ brcmf_err("Unknown chipid %d [%d]\n", ci->chip, ci->chiprev);
+ return -ENODEV;
+ }
+
+ /* check if firmware path is provided by module parameter */
+ if (brcmf_firmware_path[0] != '\0') {
+ strlcpy(sdiodev->fw_name, brcmf_firmware_path,
+ sizeof(sdiodev->fw_name));
+ strlcpy(sdiodev->nvram_name, brcmf_firmware_path,
+ sizeof(sdiodev->nvram_name));
+
+ end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1];
+ if (end != '/') {
+ strlcat(sdiodev->fw_name, "/",
+ sizeof(sdiodev->fw_name));
+ strlcat(sdiodev->nvram_name, "/",
+ sizeof(sdiodev->nvram_name));
+ }
+ }
+ strlcat(sdiodev->fw_name, brcmf_fwname_data[i].bin,
+ sizeof(sdiodev->fw_name));
+ strlcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv,
+ sizeof(sdiodev->nvram_name));
+
+ return 0;
+}
+
+static void pkt_align(struct sk_buff *p, int len, int align)
+{
+ uint datalign;
+ datalign = (unsigned long)(p->data);
+ datalign = roundup(datalign, (align)) - datalign;
+ if (datalign)
+ skb_pull(p, datalign);
+ __skb_trim(p, len);
+}
+
+/* To check if there's window offered */
+static bool data_ok(struct brcmf_sdio *bus)
+{
+ return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
+ ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
+}
+
+/*
+ * Reads a register in the SDIO hardware block. This block occupies a series of
+ * adresses on the 32 bit backplane bus.
+ */
+static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
+{
+ struct brcmf_core *core;
+ int ret;
+
+ core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ *regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret);
+
+ return ret;
+}
+
+static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
+{
+ struct brcmf_core *core;
+ int ret;
+
+ core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret);
+
+ return ret;
+}
+
+static int
+brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
+{
+ u8 wr_val = 0, rd_val, cmp_val, bmask;
+ int err = 0;
+ int try_cnt = 0;
+
+ brcmf_dbg(TRACE, "Enter: on=%d\n", on);
+
+ wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
+ /* 1st KSO write goes to AOS wake up core if device is asleep */
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ wr_val, &err);
+
+ if (on) {
+ /* device WAKEUP through KSO:
+ * write bit 0 & read back until
+ * both bits 0 (kso bit) & 1 (dev on status) are set
+ */
+ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |
+ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
+ bmask = cmp_val;
+ usleep_range(2000, 3000);
+ } else {
+ /* Put device to sleep, turn off KSO */
+ cmp_val = 0;
+ /* only check for bit0, bit1(dev on status) may not
+ * get cleared right away
+ */
+ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
+ }
+
+ do {
+ /* reliable KSO bit set/clr:
+ * the sdiod sleep write access is synced to PMU 32khz clk
+ * just one write attempt may fail,
+ * read it back until it matches written value
+ */
+ rd_val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ &err);
+ if (((rd_val & bmask) == cmp_val) && !err)
+ break;
+
+ udelay(KSO_WAIT_US);
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ wr_val, &err);
+ } while (try_cnt++ < MAX_KSO_ATTEMPTS);
+
+ if (try_cnt > 2)
+ brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt,
+ rd_val, err);
+
+ if (try_cnt > MAX_KSO_ATTEMPTS)
+ brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
+
+ return err;
+}
+
+#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
+
+/* Turn backplane clock on or off */
+static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
+{
+ int err;
+ u8 clkctl, clkreq, devctl;
+ unsigned long timeout;
+
+ brcmf_dbg(SDIO, "Enter\n");
+
+ clkctl = 0;
+
+ if (bus->sr_enabled) {
+ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
+ return 0;
+ }
+
+ if (on) {
+ /* Request HT Avail */
+ clkreq =
+ bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
+
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ clkreq, &err);
+ if (err) {
+ brcmf_err("HT Avail request error: %d\n", err);
+ return -EBADE;
+ }
+
+ /* Check current status */
+ clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (err) {
+ brcmf_err("HT Avail read error: %d\n", err);
+ return -EBADE;
+ }
+
+ /* Go to pending and await interrupt if appropriate */
+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
+ /* Allow only clock-available interrupt */
+ devctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_err("Devctl error setting CA: %d\n",
+ err);
+ return -EBADE;
+ }
+
+ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
+ brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
+ bus->clkstate = CLK_PENDING;
+
+ return 0;
+ } else if (bus->clkstate == CLK_PENDING) {
+ /* Cancel CA-only interrupt filter */
+ devctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
+ }
+
+ /* Otherwise, wait here (polling) for HT Avail */
+ timeout = jiffies +
+ msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
+ while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if (time_after(jiffies, timeout))
+ break;
+ else
+ usleep_range(5000, 10000);
+ }
+ if (err) {
+ brcmf_err("HT Avail request error: %d\n", err);
+ return -EBADE;
+ }
+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ brcmf_err("HT Avail timeout (%d): clkctl 0x%02x\n",
+ PMU_MAX_TRANSITION_DLY, clkctl);
+ return -EBADE;
+ }
+
+ /* Mark clock available */
+ bus->clkstate = CLK_AVAIL;
+ brcmf_dbg(SDIO, "CLKCTL: turned ON\n");
+
+#if defined(DEBUG)
+ if (!bus->alp_only) {
+ if (SBSDIO_ALPONLY(clkctl))
+ brcmf_err("HT Clock should be on\n");
+ }
+#endif /* defined (DEBUG) */
+
+ } else {
+ clkreq = 0;
+
+ if (bus->clkstate == CLK_PENDING) {
+ /* Cancel CA-only interrupt filter */
+ devctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
+ }
+
+ bus->clkstate = CLK_SDONLY;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ clkreq, &err);
+ brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
+ if (err) {
+ brcmf_err("Failed access turning clock off: %d\n",
+ err);
+ return -EBADE;
+ }
+ }
+ return 0;
+}
+
+/* Change idle/active SD state */
+static int brcmf_sdio_sdclk(struct brcmf_sdio *bus, bool on)
+{
+ brcmf_dbg(SDIO, "Enter\n");
+
+ if (on)
+ bus->clkstate = CLK_SDONLY;
+ else
+ bus->clkstate = CLK_NONE;
+
+ return 0;
+}
+
+/* Transition SD and backplane clock readiness */
+static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
+{
+#ifdef DEBUG
+ uint oldstate = bus->clkstate;
+#endif /* DEBUG */
+
+ brcmf_dbg(SDIO, "Enter\n");
+
+ /* Early exit if we're already there */
+ if (bus->clkstate == target) {
+ if (target == CLK_AVAIL) {
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
+ bus->activity = true;
+ }
+ return 0;
+ }
+
+ switch (target) {
+ case CLK_AVAIL:
+ /* Make sure SD clock is available */
+ if (bus->clkstate == CLK_NONE)
+ brcmf_sdio_sdclk(bus, true);
+ /* Now request HT Avail on the backplane */
+ brcmf_sdio_htclk(bus, true, pendok);
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
+ bus->activity = true;
+ break;
+
+ case CLK_SDONLY:
+ /* Remove HT request, or bring up SD clock */
+ if (bus->clkstate == CLK_NONE)
+ brcmf_sdio_sdclk(bus, true);
+ else if (bus->clkstate == CLK_AVAIL)
+ brcmf_sdio_htclk(bus, false, false);
+ else
+ brcmf_err("request for %d -> %d\n",
+ bus->clkstate, target);
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
+ break;
+
+ case CLK_NONE:
+ /* Make sure to remove HT request */
+ if (bus->clkstate == CLK_AVAIL)
+ brcmf_sdio_htclk(bus, false, false);
+ /* Now remove the SD clock */
+ brcmf_sdio_sdclk(bus, false);
+ brcmf_sdio_wd_timer(bus, 0);
+ break;
+ }
+#ifdef DEBUG
+ brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate);
+#endif /* DEBUG */
+
+ return 0;
+}
+
+static int
+brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
+{
+ int err = 0;
+ u8 clkcsr;
+
+ brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
+ (sleep ? "SLEEP" : "WAKE"),
+ (bus->sleeping ? "SLEEP" : "WAKE"));
+
+ /* If SR is enabled control bus state with KSO */
+ if (bus->sr_enabled) {
+ /* Done if we're already in the requested state */
+ if (sleep == bus->sleeping)
+ goto end;
+
+ /* Going to sleep */
+ if (sleep) {
+ /* Don't sleep if something is pending */
+ if (atomic_read(&bus->intstatus) ||
+ atomic_read(&bus->ipend) > 0 ||
+ (!atomic_read(&bus->fcstate) &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
+ data_ok(bus))) {
+ err = -EBUSY;
+ goto done;
+ }
+
+ clkcsr = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if ((clkcsr & SBSDIO_CSR_MASK) == 0) {
+ brcmf_dbg(SDIO, "no clock, set ALP\n");
+ brcmf_sdiod_regwb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_ALP_AVAIL_REQ, &err);
+ }
+ err = brcmf_sdio_kso_control(bus, false);
+ /* disable watchdog */
+ if (!err)
+ brcmf_sdio_wd_timer(bus, 0);
+ } else {
+ bus->idlecount = 0;
+ err = brcmf_sdio_kso_control(bus, true);
+ }
+ if (!err) {
+ /* Change state */
+ bus->sleeping = sleep;
+ brcmf_dbg(SDIO, "new state %s\n",
+ (sleep ? "SLEEP" : "WAKE"));
+ } else {
+ brcmf_err("error while changing bus sleep state %d\n",
+ err);
+ goto done;
+ }
+ }
+
+end:
+ /* control clocks */
+ if (sleep) {
+ if (!bus->sr_enabled)
+ brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
+ } else {
+ brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
+ }
+done:
+ brcmf_dbg(SDIO, "Exit: err=%d\n", err);
+ return err;
+
+}
+
+#ifdef DEBUG
+static inline bool brcmf_sdio_valid_shared_address(u32 addr)
+{
+ return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
+}
+
+static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
+{
+ u32 addr;
+ int rv;
+ u32 shaddr = 0;
+ struct sdpcm_shared_le sh_le;
+ __le32 addr_le;
+
+ shaddr = bus->ci->rambase + bus->ramsize - 4;
+
+ /*
+ * Read last word in socram to determine
+ * address of sdpcm_shared structure
+ */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_bus_sleep(bus, false, false);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
+ sdio_release_host(bus->sdiodev->func[1]);
+ if (rv < 0)
+ return rv;
+
+ addr = le32_to_cpu(addr_le);
+
+ brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
+
+ /*
+ * Check if addr is valid.
+ * NVRAM length at the end of memory should have been overwritten.
+ */
+ if (!brcmf_sdio_valid_shared_address(addr)) {
+ brcmf_err("invalid sdpcm_shared address 0x%08X\n",
+ addr);
+ return -EINVAL;
+ }
+
+ /* Read hndrte_shared structure */
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
+ sizeof(struct sdpcm_shared_le));
+ if (rv < 0)
+ return rv;
+
+ /* Endianness */
+ sh->flags = le32_to_cpu(sh_le.flags);
+ sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
+ sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
+ sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
+ sh->assert_line = le32_to_cpu(sh_le.assert_line);
+ sh->console_addr = le32_to_cpu(sh_le.console_addr);
+ sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
+
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
+ brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
+ SDPCM_SHARED_VERSION,
+ sh->flags & SDPCM_SHARED_VERSION_MASK);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
+{
+ struct sdpcm_shared sh;
+
+ if (brcmf_sdio_readshared(bus, &sh) == 0)
+ bus->console_addr = sh.console_addr;
+}
+#else
+static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
+static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
+{
+ u32 intstatus = 0;
+ u32 hmb_data;
+ u8 fcbits;
+ int ret;
+
+ brcmf_dbg(SDIO, "Enter\n");
+
+ /* Read mailbox data and ack that we did so */
+ ret = r_sdreg32(bus, &hmb_data,
+ offsetof(struct sdpcmd_regs, tohostmailboxdata));
+
+ if (ret == 0)
+ w_sdreg32(bus, SMB_INT_ACK,
+ offsetof(struct sdpcmd_regs, tosbmailbox));
+ bus->sdcnt.f1regdata += 2;
+
+ /* Dongle recomposed rx frames, accept them again */
+ if (hmb_data & HMB_DATA_NAKHANDLED) {
+ brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
+ bus->rx_seq);
+ if (!bus->rxskip)
+ brcmf_err("unexpected NAKHANDLED!\n");
+
+ bus->rxskip = false;
+ intstatus |= I_HMB_FRAME_IND;
+ }
+
+ /*
+ * DEVREADY does not occur with gSPI.
+ */
+ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
+ bus->sdpcm_ver =
+ (hmb_data & HMB_DATA_VERSION_MASK) >>
+ HMB_DATA_VERSION_SHIFT;
+ if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
+ brcmf_err("Version mismatch, dongle reports %d, "
+ "expecting %d\n",
+ bus->sdpcm_ver, SDPCM_PROT_VERSION);
+ else
+ brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
+ bus->sdpcm_ver);
+
+ /*
+ * Retrieve console state address now that firmware should have
+ * updated it.
+ */
+ brcmf_sdio_get_console_addr(bus);
+ }
+
+ /*
+ * Flow Control has been moved into the RX headers and this out of band
+ * method isn't used any more.
+ * remaining backward compatible with older dongles.
+ */
+ if (hmb_data & HMB_DATA_FC) {
+ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
+ HMB_DATA_FCDATA_SHIFT;
+
+ if (fcbits & ~bus->flowcontrol)
+ bus->sdcnt.fc_xoff++;
+
+ if (bus->flowcontrol & ~fcbits)
+ bus->sdcnt.fc_xon++;
+
+ bus->sdcnt.fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }
+
+ /* Shouldn't be any others */
+ if (hmb_data & ~(HMB_DATA_DEVREADY |
+ HMB_DATA_NAKHANDLED |
+ HMB_DATA_FC |
+ HMB_DATA_FWREADY |
+ HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
+ brcmf_err("Unknown mailbox data content: 0x%02x\n",
+ hmb_data);
+
+ return intstatus;
+}
+
+static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
+{
+ uint retries = 0;
+ u16 lastrbc;
+ u8 hi, lo;
+ int err;
+
+ brcmf_err("%sterminate frame%s\n",
+ abort ? "abort command, " : "",
+ rtx ? ", send NAK" : "");
+
+ if (abort)
+ brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
+
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_RF_TERM, &err);
+ bus->sdcnt.f1regdata++;
+
+ /* Wait until the packet has been flushed (device/FIFO stable) */
+ for (lastrbc = retries = 0xffff; retries > 0; retries--) {
+ hi = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_RFRAMEBCHI, &err);
+ lo = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_RFRAMEBCLO, &err);
+ bus->sdcnt.f1regdata += 2;
+
+ if ((hi == 0) && (lo == 0))
+ break;
+
+ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
+ brcmf_err("count growing: last 0x%04x now 0x%04x\n",
+ lastrbc, (hi << 8) + lo);
+ }
+ lastrbc = (hi << 8) + lo;
+ }
+
+ if (!retries)
+ brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);
+ else
+ brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
+
+ if (rtx) {
+ bus->sdcnt.rxrtx++;
+ err = w_sdreg32(bus, SMB_NAK,
+ offsetof(struct sdpcmd_regs, tosbmailbox));
+
+ bus->sdcnt.f1regdata++;
+ if (err == 0)
+ bus->rxskip = true;
+ }
+
+ /* Clear partial in any case */
+ bus->cur_read.len = 0;
+}
+
+static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
+{
+ struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
+ u8 i, hi, lo;
+
+ /* On failure, abort the command and terminate the frame */
+ brcmf_err("sdio error, abort command and terminate frame\n");
+ bus->sdcnt.tx_sderrs++;
+
+ brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
+ bus->sdcnt.f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+ lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+ bus->sdcnt.f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+}
+
+/* return total length of buffer chain */
+static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
+{
+ struct sk_buff *p;
+ uint total;
+
+ total = 0;
+ skb_queue_walk(&bus->glom, p)
+ total += p->len;
+ return total;
+}
+
+static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)
+{
+ struct sk_buff *cur, *next;
+
+ skb_queue_walk_safe(&bus->glom, cur, next) {
+ skb_unlink(cur, &bus->glom);
+ brcmu_pkt_buf_free_skb(cur);
+ }
+}
+
+/**
+ * brcmfmac sdio bus specific header
+ * This is the lowest layer header wrapped on the packets transmitted between
+ * host and WiFi dongle which contains information needed for SDIO core and
+ * firmware
+ *
+ * It consists of 3 parts: hardware header, hardware extension header and
+ * software header
+ * hardware header (frame tag) - 4 bytes
+ * Byte 0~1: Frame length
+ * Byte 2~3: Checksum, bit-wise inverse of frame length
+ * hardware extension header - 8 bytes
+ * Tx glom mode only, N/A for Rx or normal Tx
+ * Byte 0~1: Packet length excluding hw frame tag
+ * Byte 2: Reserved
+ * Byte 3: Frame flags, bit 0: last frame indication
+ * Byte 4~5: Reserved
+ * Byte 6~7: Tail padding length
+ * software header - 8 bytes
+ * Byte 0: Rx/Tx sequence number
+ * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
+ * Byte 2: Length of next data frame, reserved for Tx
+ * Byte 3: Data offset
+ * Byte 4: Flow control bits, reserved for Tx
+ * Byte 5: Maximum Sequence number allowed by firmware for Tx, N/A for Tx packet
+ * Byte 6~7: Reserved
+ */
+#define SDPCM_HWHDR_LEN 4
+#define SDPCM_HWEXT_LEN 8
+#define SDPCM_SWHDR_LEN 8
+#define SDPCM_HDRLEN (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
+/* software header */
+#define SDPCM_SEQ_MASK 0x000000ff
+#define SDPCM_SEQ_WRAP 256
+#define SDPCM_CHANNEL_MASK 0x00000f00
+#define SDPCM_CHANNEL_SHIFT 8
+#define SDPCM_CONTROL_CHANNEL 0 /* Control */
+#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication */
+#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv */
+#define SDPCM_GLOM_CHANNEL 3 /* Coalesced packets */
+#define SDPCM_TEST_CHANNEL 15 /* Test/debug packets */
+#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
+#define SDPCM_NEXTLEN_MASK 0x00ff0000
+#define SDPCM_NEXTLEN_SHIFT 16
+#define SDPCM_DOFFSET_MASK 0xff000000
+#define SDPCM_DOFFSET_SHIFT 24
+#define SDPCM_FCMASK_MASK 0x000000ff
+#define SDPCM_WINDOW_MASK 0x0000ff00
+#define SDPCM_WINDOW_SHIFT 8
+
+static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
+{
+ u32 hdrvalue;
+ hdrvalue = *(u32 *)swheader;
+ return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
+}
+
+static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
+ struct brcmf_sdio_hdrinfo *rd,
+ enum brcmf_sdio_frmtype type)
+{
+ u16 len, checksum;
+ u8 rx_seq, fc, tx_seq_max;
+ u32 swheader;
+
+ trace_brcmf_sdpcm_hdr(SDPCM_RX, header);
+
+ /* hw header */
+ len = get_unaligned_le16(header);
+ checksum = get_unaligned_le16(header + sizeof(u16));
+ /* All zero means no more to read */
+ if (!(len | checksum)) {
+ bus->rxpending = false;
+ return -ENODATA;
+ }
+ if ((u16)(~(len ^ checksum))) {
+ brcmf_err("HW header checksum error\n");
+ bus->sdcnt.rx_badhdr++;
+ brcmf_sdio_rxfail(bus, false, false);
+ return -EIO;
+ }
+ if (len < SDPCM_HDRLEN) {
+ brcmf_err("HW header length error\n");
+ return -EPROTO;
+ }
+ if (type == BRCMF_SDIO_FT_SUPER &&
+ (roundup(len, bus->blocksize) != rd->len)) {
+ brcmf_err("HW superframe header length error\n");
+ return -EPROTO;
+ }
+ if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
+ brcmf_err("HW subframe header length error\n");
+ return -EPROTO;
+ }
+ rd->len = len;
+
+ /* software header */
+ header += SDPCM_HWHDR_LEN;
+ swheader = le32_to_cpu(*(__le32 *)header);
+ if (type == BRCMF_SDIO_FT_SUPER && SDPCM_GLOMDESC(header)) {
+ brcmf_err("Glom descriptor found in superframe head\n");
+ rd->len = 0;
+ return -EINVAL;
+ }
+ rx_seq = (u8)(swheader & SDPCM_SEQ_MASK);
+ rd->channel = (swheader & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT;
+ if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
+ type != BRCMF_SDIO_FT_SUPER) {
+ brcmf_err("HW header length too long\n");
+ bus->sdcnt.rx_toolong++;
+ brcmf_sdio_rxfail(bus, false, false);
+ rd->len = 0;
+ return -EPROTO;
+ }
+ if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
+ brcmf_err("Wrong channel for superframe\n");
+ rd->len = 0;
+ return -EINVAL;
+ }
+ if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
+ rd->channel != SDPCM_EVENT_CHANNEL) {
+ brcmf_err("Wrong channel for subframe\n");
+ rd->len = 0;
+ return -EINVAL;
+ }
+ rd->dat_offset = brcmf_sdio_getdatoffset(header);
+ if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
+ brcmf_err("seq %d: bad data offset\n", rx_seq);
+ bus->sdcnt.rx_badhdr++;
+ brcmf_sdio_rxfail(bus, false, false);
+ rd->len = 0;
+ return -ENXIO;
+ }
+ if (rd->seq_num != rx_seq) {
+ brcmf_err("seq %d: sequence number error, expect %d\n",
+ rx_seq, rd->seq_num);
+ bus->sdcnt.rx_badseq++;
+ rd->seq_num = rx_seq;
+ }
+ /* no need to check the reset for subframe */
+ if (type == BRCMF_SDIO_FT_SUB)
+ return 0;
+ rd->len_nxtfrm = (swheader & SDPCM_NEXTLEN_MASK) >> SDPCM_NEXTLEN_SHIFT;
+ if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
+ /* only warm for NON glom packet */
+ if (rd->channel != SDPCM_GLOM_CHANNEL)
+ brcmf_err("seq %d: next length error\n", rx_seq);
+ rd->len_nxtfrm = 0;
+ }
+ swheader = le32_to_cpu(*(__le32 *)(header + 4));
+ fc = swheader & SDPCM_FCMASK_MASK;
+ if (bus->flowcontrol != fc) {
+ if (~bus->flowcontrol & fc)
+ bus->sdcnt.fc_xoff++;
+ if (bus->flowcontrol & ~fc)
+ bus->sdcnt.fc_xon++;
+ bus->sdcnt.fc_rcvd++;
+ bus->flowcontrol = fc;
+ }
+ tx_seq_max = (swheader & SDPCM_WINDOW_MASK) >> SDPCM_WINDOW_SHIFT;
+ if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) {
+ brcmf_err("seq %d: max tx seq number error\n", rx_seq);
+ tx_seq_max = bus->tx_seq + 2;
+ }
+ bus->tx_max = tx_seq_max;
+
+ return 0;
+}
+
+static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)
+{
+ *(__le16 *)header = cpu_to_le16(frm_length);
+ *(((__le16 *)header) + 1) = cpu_to_le16(~frm_length);
+}
+
+static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
+ struct brcmf_sdio_hdrinfo *hd_info)
+{
+ u32 hdrval;
+ u8 hdr_offset;
+
+ brcmf_sdio_update_hwhdr(header, hd_info->len);
+ hdr_offset = SDPCM_HWHDR_LEN;
+
+ if (bus->txglom) {
+ hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24);
+ *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
+ hdrval = (u16)hd_info->tail_pad << 16;
+ *(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval);
+ hdr_offset += SDPCM_HWEXT_LEN;
+ }
+
+ hdrval = hd_info->seq_num;
+ hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
+ SDPCM_CHANNEL_MASK;
+ hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
+ SDPCM_DOFFSET_MASK;
+ *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
+ *(((__le32 *)(header + hdr_offset)) + 1) = 0;
+ trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);
+}
+
+static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
+{
+ u16 dlen, totlen;
+ u8 *dptr, num = 0;
+ u16 sublen;
+ struct sk_buff *pfirst, *pnext;
+
+ int errcode;
+ u8 doff, sfdoff;
+
+ struct brcmf_sdio_hdrinfo rd_new;
+
+ /* If packets, issue read(s) and send up packet chain */
+ /* Return sequence numbers consumed? */
+
+ brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
+ bus->glomd, skb_peek(&bus->glom));
+
+ /* If there's a descriptor, generate the packet chain */
+ if (bus->glomd) {
+ pfirst = pnext = NULL;
+ dlen = (u16) (bus->glomd->len);
+ dptr = bus->glomd->data;
+ if (!dlen || (dlen & 1)) {
+ brcmf_err("bad glomd len(%d), ignore descriptor\n",
+ dlen);
+ dlen = 0;
+ }
+
+ for (totlen = num = 0; dlen; num++) {
+ /* Get (and move past) next length */
+ sublen = get_unaligned_le16(dptr);
+ dlen -= sizeof(u16);
+ dptr += sizeof(u16);
+ if ((sublen < SDPCM_HDRLEN) ||
+ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
+ brcmf_err("descriptor len %d bad: %d\n",
+ num, sublen);
+ pnext = NULL;
+ break;
+ }
+ if (sublen % bus->sgentry_align) {
+ brcmf_err("sublen %d not multiple of %d\n",
+ sublen, bus->sgentry_align);
+ }
+ totlen += sublen;
+
+ /* For last frame, adjust read len so total
+ is a block multiple */
+ if (!dlen) {
+ sublen +=
+ (roundup(totlen, bus->blocksize) - totlen);
+ totlen = roundup(totlen, bus->blocksize);
+ }
+
+ /* Allocate/chain packet for next subframe */
+ pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align);
+ if (pnext == NULL) {
+ brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
+ num, sublen);
+ break;
+ }
+ skb_queue_tail(&bus->glom, pnext);
+
+ /* Adhere to start alignment requirements */
+ pkt_align(pnext, sublen, bus->sgentry_align);
+ }
+
+ /* If all allocations succeeded, save packet chain
+ in bus structure */
+ if (pnext) {
+ brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
+ totlen, num);
+ if (BRCMF_GLOM_ON() && bus->cur_read.len &&
+ totlen != bus->cur_read.len) {
+ brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
+ bus->cur_read.len, totlen, rxseq);
+ }
+ pfirst = pnext = NULL;
+ } else {
+ brcmf_sdio_free_glom(bus);
+ num = 0;
+ }
+
+ /* Done with descriptor packet */
+ brcmu_pkt_buf_free_skb(bus->glomd);
+ bus->glomd = NULL;
+ bus->cur_read.len = 0;
+ }
+
+ /* Ok -- either we just generated a packet chain,
+ or had one from before */
+ if (!skb_queue_empty(&bus->glom)) {
+ if (BRCMF_GLOM_ON()) {
+ brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
+ skb_queue_walk(&bus->glom, pnext) {
+ brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
+ pnext, (u8 *) (pnext->data),
+ pnext->len, pnext->len);
+ }
+ }
+
+ pfirst = skb_peek(&bus->glom);
+ dlen = (u16) brcmf_sdio_glom_len(bus);
+
+ /* Do an SDIO read for the superframe. Configurable iovar to
+ * read directly into the chained packet, or allocate a large
+ * packet and and copy into the chain.
+ */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
+ &bus->glom, dlen);
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->sdcnt.f2rxdata++;
+
+ /* On failure, kill the superframe, allow a couple retries */
+ if (errcode < 0) {
+ brcmf_err("glom read of %d bytes failed: %d\n",
+ dlen, errcode);
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+ if (bus->glomerr++ < 3) {
+ brcmf_sdio_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdio_rxfail(bus, true, false);
+ bus->sdcnt.rxglomfail++;
+ brcmf_sdio_free_glom(bus);
+ }
+ sdio_release_host(bus->sdiodev->func[1]);
+ return 0;
+ }
+
+ brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
+ pfirst->data, min_t(int, pfirst->len, 48),
+ "SUPERFRAME:\n");
+
+ rd_new.seq_num = rxseq;
+ rd_new.len = dlen;
+ sdio_claim_host(bus->sdiodev->func[1]);
+ errcode = brcmf_sdio_hdparse(bus, pfirst->data, &rd_new,
+ BRCMF_SDIO_FT_SUPER);
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->cur_read.len = rd_new.len_nxtfrm << 4;
+
+ /* Remove superframe header, remember offset */
+ skb_pull(pfirst, rd_new.dat_offset);
+ sfdoff = rd_new.dat_offset;
+ num = 0;
+
+ /* Validate all the subframe headers */
+ skb_queue_walk(&bus->glom, pnext) {
+ /* leave when invalid subframe is found */
+ if (errcode)
+ break;
+
+ rd_new.len = pnext->len;
+ rd_new.seq_num = rxseq++;
+ sdio_claim_host(bus->sdiodev->func[1]);
+ errcode = brcmf_sdio_hdparse(bus, pnext->data, &rd_new,
+ BRCMF_SDIO_FT_SUB);
+ sdio_release_host(bus->sdiodev->func[1]);
+ brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
+ pnext->data, 32, "subframe:\n");
+
+ num++;
+ }
+
+ if (errcode) {
+ /* Terminate frame on error, request
+ a couple retries */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ if (bus->glomerr++ < 3) {
+ /* Restore superframe header space */
+ skb_push(pfirst, sfdoff);
+ brcmf_sdio_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdio_rxfail(bus, true, false);
+ bus->sdcnt.rxglomfail++;
+ brcmf_sdio_free_glom(bus);
+ }
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->cur_read.len = 0;
+ return 0;
+ }
+
+ /* Basic SD framing looks ok - process each packet (header) */
+
+ skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
+ dptr = (u8 *) (pfirst->data);
+ sublen = get_unaligned_le16(dptr);
+ doff = brcmf_sdio_getdatoffset(&dptr[SDPCM_HWHDR_LEN]);
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
+ dptr, pfirst->len,
+ "Rx Subframe Data:\n");
+
+ __skb_trim(pfirst, sublen);
+ skb_pull(pfirst, doff);
+
+ if (pfirst->len == 0) {
+ skb_unlink(pfirst, &bus->glom);
+ brcmu_pkt_buf_free_skb(pfirst);
+ continue;
+ }
+
+ brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
+ pfirst->data,
+ min_t(int, pfirst->len, 32),
+ "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
+ bus->glom.qlen, pfirst, pfirst->data,
+ pfirst->len, pfirst->next,
+ pfirst->prev);
+ skb_unlink(pfirst, &bus->glom);
+ brcmf_rx_frame(bus->sdiodev->dev, pfirst);
+ bus->sdcnt.rxglompkts++;
+ }
+
+ bus->sdcnt.rxglomframes++;
+ }
+ return num;
+}
+
+static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
+ bool *pending)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
+
+ /* Wait until control frame is available */
+ add_wait_queue(&bus->dcmd_resp_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (!(*condition) && (!signal_pending(current) && timeout))
+ timeout = schedule_timeout(timeout);
+
+ if (signal_pending(current))
+ *pending = true;
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&bus->dcmd_resp_wait, &wait);
+
+ return timeout;
+}
+
+static int brcmf_sdio_dcmd_resp_wake(struct brcmf_sdio *bus)
+{
+ if (waitqueue_active(&bus->dcmd_resp_wait))
+ wake_up_interruptible(&bus->dcmd_resp_wait);
+
+ return 0;
+}
+static void
+brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
+{
+ uint rdlen, pad;
+ u8 *buf = NULL, *rbuf;
+ int sdret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->rxblen)
+ buf = vzalloc(bus->rxblen);
+ if (!buf)
+ goto done;
+
+ rbuf = bus->rxbuf;
+ pad = ((unsigned long)rbuf % bus->head_align);
+ if (pad)
+ rbuf += (bus->head_align - pad);
+
+ /* Copy the already-read portion over */
+ memcpy(buf, hdr, BRCMF_FIRSTREAD);
+ if (len <= BRCMF_FIRSTREAD)
+ goto gotpkt;
+
+ /* Raise rdlen to next SDIO block to avoid tail command */
+ rdlen = len - BRCMF_FIRSTREAD;
+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((len + pad) < bus->sdiodev->bus_if->maxctl))
+ rdlen += pad;
+ } else if (rdlen % bus->head_align) {
+ rdlen += bus->head_align - (rdlen % bus->head_align);
+ }
+
+ /* Drop if the read is too big or it exceeds our maximum */
+ if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
+ brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
+ rdlen, bus->sdiodev->bus_if->maxctl);
+ brcmf_sdio_rxfail(bus, false, false);
+ goto done;
+ }
+
+ if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
+ brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
+ len, len - doff, bus->sdiodev->bus_if->maxctl);
+ bus->sdcnt.rx_toolong++;
+ brcmf_sdio_rxfail(bus, false, false);
+ goto done;
+ }
+
+ /* Read remain of frame body */
+ sdret = brcmf_sdiod_recv_buf(bus->sdiodev, rbuf, rdlen);
+ bus->sdcnt.f2rxdata++;
+
+ /* Control frame failures need retransmission */
+ if (sdret < 0) {
+ brcmf_err("read %d control bytes failed: %d\n",
+ rdlen, sdret);
+ bus->sdcnt.rxc_errors++;
+ brcmf_sdio_rxfail(bus, true, true);
+ goto done;
+ } else
+ memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
+
+gotpkt:
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
+ buf, len, "RxCtrl:\n");
+
+ /* Point to valid data and indicate its length */
+ spin_lock_bh(&bus->rxctl_lock);
+ if (bus->rxctl) {
+ brcmf_err("last control frame is being processed.\n");
+ spin_unlock_bh(&bus->rxctl_lock);
+ vfree(buf);
+ goto done;
+ }
+ bus->rxctl = buf + doff;
+ bus->rxctl_orig = buf;
+ bus->rxlen = len - doff;
+ spin_unlock_bh(&bus->rxctl_lock);
+
+done:
+ /* Awake any waiters */
+ brcmf_sdio_dcmd_resp_wake(bus);
+}
+
+/* Pad read to blocksize for efficiency */
+static void brcmf_sdio_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
+{
+ if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
+ *pad = bus->blocksize - (*rdlen % bus->blocksize);
+ if (*pad <= bus->roundup && *pad < bus->blocksize &&
+ *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
+ *rdlen += *pad;
+ } else if (*rdlen % bus->head_align) {
+ *rdlen += bus->head_align - (*rdlen % bus->head_align);
+ }
+}
+
+static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
+{
+ struct sk_buff *pkt; /* Packet for event or data frames */
+ u16 pad; /* Number of pad bytes to read */
+ uint rxleft = 0; /* Remaining number of frames allowed */
+ int ret; /* Return code from calls */
+ uint rxcount = 0; /* Total frames read */
+ struct brcmf_sdio_hdrinfo *rd = &bus->cur_read, rd_new;
+ u8 head_read = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Not finished unless we encounter no more frames indication */
+ bus->rxpending = true;
+
+ for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
+ !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
+ rd->seq_num++, rxleft--) {
+
+ /* Handle glomming separately */
+ if (bus->glomd || !skb_queue_empty(&bus->glom)) {
+ u8 cnt;
+ brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
+ bus->glomd, skb_peek(&bus->glom));
+ cnt = brcmf_sdio_rxglom(bus, rd->seq_num);
+ brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
+ rd->seq_num += cnt - 1;
+ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
+ continue;
+ }
+
+ rd->len_left = rd->len;
+ /* read header first for unknow frame length */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ if (!rd->len) {
+ ret = brcmf_sdiod_recv_buf(bus->sdiodev,
+ bus->rxhdr, BRCMF_FIRSTREAD);
+ bus->sdcnt.f2rxhdrs++;
+ if (ret < 0) {
+ brcmf_err("RXHEADER FAILED: %d\n",
+ ret);
+ bus->sdcnt.rx_hdrfail++;
+ brcmf_sdio_rxfail(bus, true, true);
+ sdio_release_host(bus->sdiodev->func[1]);
+ continue;
+ }
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(),
+ bus->rxhdr, SDPCM_HDRLEN,
+ "RxHdr:\n");
+
+ if (brcmf_sdio_hdparse(bus, bus->rxhdr, rd,
+ BRCMF_SDIO_FT_NORMAL)) {
+ sdio_release_host(bus->sdiodev->func[1]);
+ if (!bus->rxpending)
+ break;
+ else
+ continue;
+ }
+
+ if (rd->channel == SDPCM_CONTROL_CHANNEL) {
+ brcmf_sdio_read_control(bus, bus->rxhdr,
+ rd->len,
+ rd->dat_offset);
+ /* prepare the descriptor for the next read */
+ rd->len = rd->len_nxtfrm << 4;
+ rd->len_nxtfrm = 0;
+ /* treat all packet as event if we don't know */
+ rd->channel = SDPCM_EVENT_CHANNEL;
+ sdio_release_host(bus->sdiodev->func[1]);
+ continue;
+ }
+ rd->len_left = rd->len > BRCMF_FIRSTREAD ?
+ rd->len - BRCMF_FIRSTREAD : 0;
+ head_read = BRCMF_FIRSTREAD;
+ }
+
+ brcmf_sdio_pad(bus, &pad, &rd->len_left);
+
+ pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
+ bus->head_align);
+ if (!pkt) {
+ /* Give up on data, request rtx of events */
+ brcmf_err("brcmu_pkt_buf_get_skb failed\n");
+ brcmf_sdio_rxfail(bus, false,
+ RETRYCHAN(rd->channel));
+ sdio_release_host(bus->sdiodev->func[1]);
+ continue;
+ }
+ skb_pull(pkt, head_read);
+ pkt_align(pkt, rd->len_left, bus->head_align);
+
+ ret = brcmf_sdiod_recv_pkt(bus->sdiodev, pkt);
+ bus->sdcnt.f2rxdata++;
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ if (ret < 0) {
+ brcmf_err("read %d bytes from channel %d failed: %d\n",
+ rd->len, rd->channel, ret);
+ brcmu_pkt_buf_free_skb(pkt);
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_rxfail(bus, true,
+ RETRYCHAN(rd->channel));
+ sdio_release_host(bus->sdiodev->func[1]);
+ continue;
+ }
+
+ if (head_read) {
+ skb_push(pkt, head_read);
+ memcpy(pkt->data, bus->rxhdr, head_read);
+ head_read = 0;
+ } else {
+ memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
+ rd_new.seq_num = rd->seq_num;
+ sdio_claim_host(bus->sdiodev->func[1]);
+ if (brcmf_sdio_hdparse(bus, bus->rxhdr, &rd_new,
+ BRCMF_SDIO_FT_NORMAL)) {
+ rd->len = 0;
+ brcmu_pkt_buf_free_skb(pkt);
+ }
+ bus->sdcnt.rx_readahead_cnt++;
+ if (rd->len != roundup(rd_new.len, 16)) {
+ brcmf_err("frame length mismatch:read %d, should be %d\n",
+ rd->len,
+ roundup(rd_new.len, 16) >> 4);
+ rd->len = 0;
+ brcmf_sdio_rxfail(bus, true, true);
+ sdio_release_host(bus->sdiodev->func[1]);
+ brcmu_pkt_buf_free_skb(pkt);
+ continue;
+ }
+ sdio_release_host(bus->sdiodev->func[1]);
+ rd->len_nxtfrm = rd_new.len_nxtfrm;
+ rd->channel = rd_new.channel;
+ rd->dat_offset = rd_new.dat_offset;
+
+ brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() &&
+ BRCMF_DATA_ON()) &&
+ BRCMF_HDRS_ON(),
+ bus->rxhdr, SDPCM_HDRLEN,
+ "RxHdr:\n");
+
+ if (rd_new.channel == SDPCM_CONTROL_CHANNEL) {
+ brcmf_err("readahead on control packet %d?\n",
+ rd_new.seq_num);
+ /* Force retry w/normal header read */
+ rd->len = 0;
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_rxfail(bus, false, true);
+ sdio_release_host(bus->sdiodev->func[1]);
+ brcmu_pkt_buf_free_skb(pkt);
+ continue;
+ }
+ }
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
+ pkt->data, rd->len, "Rx Data:\n");
+
+ /* Save superframe descriptor and allocate packet frame */
+ if (rd->channel == SDPCM_GLOM_CHANNEL) {
+ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_HWHDR_LEN])) {
+ brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
+ rd->len);
+ brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
+ pkt->data, rd->len,
+ "Glom Data:\n");
+ __skb_trim(pkt, rd->len);
+ skb_pull(pkt, SDPCM_HDRLEN);
+ bus->glomd = pkt;
+ } else {
+ brcmf_err("%s: glom superframe w/o "
+ "descriptor!\n", __func__);
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_rxfail(bus, false, false);
+ sdio_release_host(bus->sdiodev->func[1]);
+ }
+ /* prepare the descriptor for the next read */
+ rd->len = rd->len_nxtfrm << 4;
+ rd->len_nxtfrm = 0;
+ /* treat all packet as event if we don't know */
+ rd->channel = SDPCM_EVENT_CHANNEL;
+ continue;
+ }
+
+ /* Fill in packet len and prio, deliver upward */
+ __skb_trim(pkt, rd->len);
+ skb_pull(pkt, rd->dat_offset);
+
+ /* prepare the descriptor for the next read */
+ rd->len = rd->len_nxtfrm << 4;
+ rd->len_nxtfrm = 0;
+ /* treat all packet as event if we don't know */
+ rd->channel = SDPCM_EVENT_CHANNEL;
+
+ if (pkt->len == 0) {
+ brcmu_pkt_buf_free_skb(pkt);
+ continue;
+ }
+
+ brcmf_rx_frame(bus->sdiodev->dev, pkt);
+ }
+
+ rxcount = maxframes - rxleft;
+ /* Message if we hit the limit */
+ if (!rxleft)
+ brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes);
+ else
+ brcmf_dbg(DATA, "processed %d frames\n", rxcount);
+ /* Back off rxseq if awaiting rtx, update rx_seq */
+ if (bus->rxskip)
+ rd->seq_num--;
+ bus->rx_seq = rd->seq_num;
+
+ return rxcount;
+}
+
+static void
+brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
+{
+ if (waitqueue_active(&bus->ctrl_wait))
+ wake_up_interruptible(&bus->ctrl_wait);
+ return;
+}
+
+static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
+{
+ u16 head_pad;
+ u8 *dat_buf;
+
+ dat_buf = (u8 *)(pkt->data);
+
+ /* Check head padding */
+ head_pad = ((unsigned long)dat_buf % bus->head_align);
+ if (head_pad) {
+ if (skb_headroom(pkt) < head_pad) {
+ bus->sdiodev->bus_if->tx_realloc++;
+ head_pad = 0;
+ if (skb_cow(pkt, head_pad))
+ return -ENOMEM;
+ }
+ skb_push(pkt, head_pad);
+ dat_buf = (u8 *)(pkt->data);
+ memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
+ }
+ return head_pad;
+}
+
+/**
+ * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
+ * bus layer usage.
+ */
+/* flag marking a dummy skb added for DMA alignment requirement */
+#define ALIGN_SKB_FLAG 0x8000
+/* bit mask of data length chopped from the previous packet */
+#define ALIGN_SKB_CHOP_LEN_MASK 0x7fff
+
+static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
+ struct sk_buff_head *pktq,
+ struct sk_buff *pkt, u16 total_len)
+{
+ struct brcmf_sdio_dev *sdiodev;
+ struct sk_buff *pkt_pad;
+ u16 tail_pad, tail_chop, chain_pad;
+ unsigned int blksize;
+ bool lastfrm;
+ int ntail, ret;
+
+ sdiodev = bus->sdiodev;
+ blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize;
+ /* sg entry alignment should be a divisor of block size */
+ WARN_ON(blksize % bus->sgentry_align);
+
+ /* Check tail padding */
+ lastfrm = skb_queue_is_last(pktq, pkt);
+ tail_pad = 0;
+ tail_chop = pkt->len % bus->sgentry_align;
+ if (tail_chop)
+ tail_pad = bus->sgentry_align - tail_chop;
+ chain_pad = (total_len + tail_pad) % blksize;
+ if (lastfrm && chain_pad)
+ tail_pad += blksize - chain_pad;
+ if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
+ pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
+ bus->head_align);
+ if (pkt_pad == NULL)
+ return -ENOMEM;
+ ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
+ if (unlikely(ret < 0)) {
+ kfree_skb(pkt_pad);
+ return ret;
+ }
+ memcpy(pkt_pad->data,
+ pkt->data + pkt->len - tail_chop,
+ tail_chop);
+ *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
+ skb_trim(pkt, pkt->len - tail_chop);
+ skb_trim(pkt_pad, tail_pad + tail_chop);
+ __skb_queue_after(pktq, pkt, pkt_pad);
+ } else {
+ ntail = pkt->data_len + tail_pad -
+ (pkt->end - pkt->tail);
+ if (skb_cloned(pkt) || ntail > 0)
+ if (pskb_expand_head(pkt, 0, ntail, GFP_ATOMIC))
+ return -ENOMEM;
+ if (skb_linearize(pkt))
+ return -ENOMEM;
+ __skb_put(pkt, tail_pad);
+ }
+
+ return tail_pad;
+}
+
+/**
+ * brcmf_sdio_txpkt_prep - packet preparation for transmit
+ * @bus: brcmf_sdio structure pointer
+ * @pktq: packet list pointer
+ * @chan: virtual channel to transmit the packet
+ *
+ * Processes to be applied to the packet
+ * - Align data buffer pointer
+ * - Align data buffer length
+ * - Prepare header
+ * Return: negative value if there is error
+ */
+static int
+brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
+ uint chan)
+{
+ u16 head_pad, total_len;
+ struct sk_buff *pkt_next;
+ u8 txseq;
+ int ret;
+ struct brcmf_sdio_hdrinfo hd_info = {0};
+
+ txseq = bus->tx_seq;
+ total_len = 0;
+ skb_queue_walk(pktq, pkt_next) {
+ /* alignment packet inserted in previous
+ * loop cycle can be skipped as it is
+ * already properly aligned and does not
+ * need an sdpcm header.
+ */
+ if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
+ continue;
+
+ /* align packet data pointer */
+ ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next);
+ if (ret < 0)
+ return ret;
+ head_pad = (u16)ret;
+ if (head_pad)
+ memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
+
+ total_len += pkt_next->len;
+
+ hd_info.len = pkt_next->len;
+ hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next);
+ if (bus->txglom && pktq->qlen > 1) {
+ ret = brcmf_sdio_txpkt_prep_sg(bus, pktq,
+ pkt_next, total_len);
+ if (ret < 0)
+ return ret;
+ hd_info.tail_pad = (u16)ret;
+ total_len += (u16)ret;
+ }
+
+ hd_info.channel = chan;
+ hd_info.dat_offset = head_pad + bus->tx_hdrlen;
+ hd_info.seq_num = txseq++;
+
+ /* Now fill the header */
+ brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info);
+
+ if (BRCMF_BYTES_ON() &&
+ ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
+ (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
+ brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
+ "Tx Frame:\n");
+ else if (BRCMF_HDRS_ON())
+ brcmf_dbg_hex_dump(true, pkt_next->data,
+ head_pad + bus->tx_hdrlen,
+ "Tx Header:\n");
+ }
+ /* Hardware length tag of the first packet should be total
+ * length of the chain (including padding)
+ */
+ if (bus->txglom)
+ brcmf_sdio_update_hwhdr(pktq->next->data, total_len);
+ return 0;
+}
+
+/**
+ * brcmf_sdio_txpkt_postp - packet post processing for transmit
+ * @bus: brcmf_sdio structure pointer
+ * @pktq: packet list pointer
+ *
+ * Processes to be applied to the packet
+ * - Remove head padding
+ * - Remove tail padding
+ */
+static void
+brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
+{
+ u8 *hdr;
+ u32 dat_offset;
+ u16 tail_pad;
+ u16 dummy_flags, chop_len;
+ struct sk_buff *pkt_next, *tmp, *pkt_prev;
+
+ skb_queue_walk_safe(pktq, pkt_next, tmp) {
+ dummy_flags = *(u16 *)(pkt_next->cb);
+ if (dummy_flags & ALIGN_SKB_FLAG) {
+ chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
+ if (chop_len) {
+ pkt_prev = pkt_next->prev;
+ skb_put(pkt_prev, chop_len);
+ }
+ __skb_unlink(pkt_next, pktq);
+ brcmu_pkt_buf_free_skb(pkt_next);
+ } else {
+ hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN;
+ dat_offset = le32_to_cpu(*(__le32 *)hdr);
+ dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
+ SDPCM_DOFFSET_SHIFT;
+ skb_pull(pkt_next, dat_offset);
+ if (bus->txglom) {
+ tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2));
+ skb_trim(pkt_next, pkt_next->len - tail_pad);
+ }
+ }
+ }
+}
+
+/* Writes a HW/SW header into the packet and sends it. */
+/* Assumes: (a) header space already there, (b) caller holds lock */
+static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
+ uint chan)
+{
+ int ret;
+ struct sk_buff *pkt_next, *tmp;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ ret = brcmf_sdio_txpkt_prep(bus, pktq, chan);
+ if (ret)
+ goto done;
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+ ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
+ bus->sdcnt.f2txdata++;
+
+ if (ret < 0)
+ brcmf_sdio_txfail(bus);
+
+ sdio_release_host(bus->sdiodev->func[1]);
+
+done:
+ brcmf_sdio_txpkt_postp(bus, pktq);
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
+ skb_queue_walk_safe(pktq, pkt_next, tmp) {
+ __skb_unlink(pkt_next, pktq);
+ brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
+ }
+ return ret;
+}
+
+static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
+{
+ struct sk_buff *pkt;
+ struct sk_buff_head pktq;
+ u32 intstatus = 0;
+ int ret = 0, prec_out, i;
+ uint cnt = 0;
+ u8 tx_prec_map, pkt_num;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ tx_prec_map = ~bus->flowcontrol;
+
+ /* Send frames until the limit or some other event */
+ for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
+ pkt_num = 1;
+ if (down_interruptible(&bus->tx_seq_lock))
+ return cnt;
+ if (bus->txglom)
+ pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
+ bus->sdiodev->txglomsz);
+ pkt_num = min_t(u32, pkt_num,
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
+ __skb_queue_head_init(&pktq);
+ spin_lock_bh(&bus->txq_lock);
+ for (i = 0; i < pkt_num; i++) {
+ pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map,
+ &prec_out);
+ if (pkt == NULL)
+ break;
+ __skb_queue_tail(&pktq, pkt);
+ }
+ spin_unlock_bh(&bus->txq_lock);
+ if (i == 0) {
+ up(&bus->tx_seq_lock);
+ break;
+ }
+
+ ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
+ up(&bus->tx_seq_lock);
+
+ cnt += i;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr) {
+ /* Check device status, signal pending interrupt */
+ sdio_claim_host(bus->sdiodev->func[1]);
+ ret = r_sdreg32(bus, &intstatus,
+ offsetof(struct sdpcmd_regs,
+ intstatus));
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->sdcnt.f2txdata++;
+ if (ret != 0)
+ break;
+ if (intstatus & bus->hostintmask)
+ atomic_set(&bus->ipend, 1);
+ }
+ }
+
+ /* Deflow-control stack if needed */
+ if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+ bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
+ bus->txoff = false;
+ brcmf_txflowblock(bus->sdiodev->dev, false);
+ }
+
+ return cnt;
+}
+
+static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len)
+{
+ u8 doff;
+ u16 pad;
+ uint retries = 0;
+ struct brcmf_sdio_hdrinfo hd_info = {0};
+ int ret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Back the pointer to make room for bus header */
+ frame -= bus->tx_hdrlen;
+ len += bus->tx_hdrlen;
+
+ /* Add alignment padding (optional for ctl frames) */
+ doff = ((unsigned long)frame % bus->head_align);
+ if (doff) {
+ frame -= doff;
+ len += doff;
+ memset(frame + bus->tx_hdrlen, 0, doff);
+ }
+
+ /* Round send length to next SDIO block */
+ pad = 0;
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad > bus->roundup) || (pad >= bus->blocksize))
+ pad = 0;
+ } else if (len % bus->head_align) {
+ pad = bus->head_align - (len % bus->head_align);
+ }
+ len += pad;
+
+ hd_info.len = len - pad;
+ hd_info.channel = SDPCM_CONTROL_CHANNEL;
+ hd_info.dat_offset = doff + bus->tx_hdrlen;
+ hd_info.seq_num = bus->tx_seq;
+ hd_info.lastfrm = true;
+ hd_info.tail_pad = pad;
+ brcmf_sdio_hdpack(bus, frame, &hd_info);
+
+ if (bus->txglom)
+ brcmf_sdio_update_hwhdr(frame, len);
+
+ brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
+ frame, len, "Tx Frame:\n");
+ brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
+ BRCMF_HDRS_ON(),
+ frame, min_t(u16, len, 16), "TxHdr:\n");
+
+ do {
+ ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
+
+ if (ret < 0)
+ brcmf_sdio_txfail(bus);
+ else
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
+ } while (ret < 0 && retries++ < TXRETRIES);
+
+ return ret;
+}
+
+static void brcmf_sdio_bus_stop(struct device *dev)
+{
+ u32 local_hostintmask;
+ u8 saveclk;
+ int err;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->watchdog_tsk) {
+ send_sig(SIGTERM, bus->watchdog_tsk, 1);
+ kthread_stop(bus->watchdog_tsk);
+ bus->watchdog_tsk = NULL;
+ }
+
+ if (bus_if->state == BRCMF_BUS_DOWN) {
+ sdio_claim_host(sdiodev->func[1]);
+
+ /* Enable clock for device interrupts */
+ brcmf_sdio_bus_sleep(bus, false, false);
+
+ /* Disable and clear interrupts at the chip level also */
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
+ local_hostintmask = bus->hostintmask;
+ bus->hostintmask = 0;
+
+ /* Force backplane clocks to assure F2 interrupt propagates */
+ saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if (!err)
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ if (err)
+ brcmf_err("Failed to force clock for F2: err %d\n",
+ err);
+
+ /* Turn off the bus (F2), free any pending packets */
+ brcmf_dbg(INTR, "disable SDIO interrupts\n");
+ sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
+
+ /* Clear any pending interrupts now that F2 is disabled */
+ w_sdreg32(bus, local_hostintmask,
+ offsetof(struct sdpcmd_regs, intstatus));
+
+ sdio_release_host(sdiodev->func[1]);
+ }
+ /* Clear the data packet queues */
+ brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
+
+ /* Clear any held glomming stuff */
+ if (bus->glomd)
+ brcmu_pkt_buf_free_skb(bus->glomd);
+ brcmf_sdio_free_glom(bus);
+
+ /* Clear rx control and wake any waiters */
+ spin_lock_bh(&bus->rxctl_lock);
+ bus->rxlen = 0;
+ spin_unlock_bh(&bus->rxctl_lock);
+ brcmf_sdio_dcmd_resp_wake(bus);
+
+ /* Reset some F2 state stuff */
+ bus->rxskip = false;
+ bus->tx_seq = bus->rx_seq = 0;
+}
+
+static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
+{
+ unsigned long flags;
+
+ if (bus->sdiodev->oob_irq_requested) {
+ spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
+ if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
+ enable_irq(bus->sdiodev->pdata->oob_irq_nr);
+ bus->sdiodev->irq_en = true;
+ }
+ spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
+ }
+}
+
+static void atomic_orr(int val, atomic_t *v)
+{
+ int old_val;
+
+ old_val = atomic_read(v);
+ while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
+ old_val = atomic_read(v);
+}
+
+static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
+{
+ struct brcmf_core *buscore;
+ u32 addr;
+ unsigned long val;
+ int ret;
+
+ buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
+ addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
+
+ val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
+ bus->sdcnt.f1regdata++;
+ if (ret != 0)
+ return ret;
+
+ val &= bus->hostintmask;
+ atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
+
+ /* Clear interrupts */
+ if (val) {
+ brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
+ bus->sdcnt.f1regdata++;
+ atomic_orr(val, &bus->intstatus);
+ }
+
+ return ret;
+}
+
+static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
+{
+ u32 newstatus = 0;
+ unsigned long intstatus;
+ uint txlimit = bus->txbound; /* Tx frames to send before resched */
+ uint framecnt; /* Temporary counter of tx/rx frames */
+ int err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+
+ /* If waiting for HTAVAIL, check status */
+ if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
+ u8 clkctl, devctl = 0;
+
+#ifdef DEBUG
+ /* Check for inconsistent device control */
+ devctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
+#endif /* DEBUG */
+
+ /* Read CSR, if clock on switch to AVAIL, else ignore */
+ clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+
+ brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ devctl, clkctl);
+
+ if (SBSDIO_HTAV(clkctl)) {
+ devctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
+ bus->clkstate = CLK_AVAIL;
+ }
+ }
+
+ /* Make sure backplane clock is on */
+ brcmf_sdio_bus_sleep(bus, false, true);
+
+ /* Pending interrupt indicates new device status */
+ if (atomic_read(&bus->ipend) > 0) {
+ atomic_set(&bus->ipend, 0);
+ err = brcmf_sdio_intr_rstatus(bus);
+ }
+
+ /* Start with leftover status bits */
+ intstatus = atomic_xchg(&bus->intstatus, 0);
+
+ /* Handle flow-control change: read new state in case our ack
+ * crossed another change interrupt. If change still set, assume
+ * FC ON for safety, let next loop through do the debounce.
+ */
+ if (intstatus & I_HMB_FC_CHANGE) {
+ intstatus &= ~I_HMB_FC_CHANGE;
+ err = w_sdreg32(bus, I_HMB_FC_CHANGE,
+ offsetof(struct sdpcmd_regs, intstatus));
+
+ err = r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus));
+ bus->sdcnt.f1regdata += 2;
+ atomic_set(&bus->fcstate,
+ !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)));
+ intstatus |= (newstatus & bus->hostintmask);
+ }
+
+ /* Handle host mailbox indication */
+ if (intstatus & I_HMB_HOST_INT) {
+ intstatus &= ~I_HMB_HOST_INT;
+ intstatus |= brcmf_sdio_hostmail(bus);
+ }
+
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ /* Generally don't ask for these, can get CRC errors... */
+ if (intstatus & I_WR_OOSYNC) {
+ brcmf_err("Dongle reports WR_OOSYNC\n");
+ intstatus &= ~I_WR_OOSYNC;
+ }
+
+ if (intstatus & I_RD_OOSYNC) {
+ brcmf_err("Dongle reports RD_OOSYNC\n");
+ intstatus &= ~I_RD_OOSYNC;
+ }
+
+ if (intstatus & I_SBINT) {
+ brcmf_err("Dongle reports SBINT\n");
+ intstatus &= ~I_SBINT;
+ }
+
+ /* Would be active due to wake-wlan in gSPI */
+ if (intstatus & I_CHIPACTIVE) {
+ brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
+ intstatus &= ~I_CHIPACTIVE;
+ }
+
+ /* Ignore frame indications if rxskip is set */
+ if (bus->rxskip)
+ intstatus &= ~I_HMB_FRAME_IND;
+
+ /* On frame indication, read available frames */
+ if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
+ brcmf_sdio_readframes(bus, bus->rxbound);
+ if (!bus->rxpending)
+ intstatus &= ~I_HMB_FRAME_IND;
+ }
+
+ /* Keep still-pending events for next scheduling */
+ if (intstatus)
+ atomic_orr(intstatus, &bus->intstatus);
+
+ brcmf_sdio_clrintr(bus);
+
+ if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
+ (down_interruptible(&bus->tx_seq_lock) == 0)) {
+ if (data_ok(bus)) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
+ bus->ctrl_frame_len);
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ bus->ctrl_frame_stat = false;
+ brcmf_sdio_wait_event_wakeup(bus);
+ }
+ up(&bus->tx_seq_lock);
+ }
+ /* Send queued frames (limit 1 if rx may still be pending) */
+ if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit &&
+ data_ok(bus)) {
+ framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
+ txlimit;
+ brcmf_sdio_sendfromq(bus, framecnt);
+ }
+
+ if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
+ brcmf_err("failed backplane access over SDIO, halting operation\n");
+ atomic_set(&bus->intstatus, 0);
+ } else if (atomic_read(&bus->intstatus) ||
+ atomic_read(&bus->ipend) > 0 ||
+ (!atomic_read(&bus->fcstate) &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
+ data_ok(bus))) {
+ atomic_inc(&bus->dpc_tskcnt);
+ }
+}
+
+static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ return &bus->txq;
+}
+
+static bool brcmf_sdio_prec_enq(struct pktq *q, struct sk_buff *pkt, int prec)
+{
+ struct sk_buff *p;
+ int eprec = -1; /* precedence to evict from */
+
+ /* Fast case, precedence queue is not full and we are also not
+ * exceeding total queue length
+ */
+ if (!pktq_pfull(q, prec) && !pktq_full(q)) {
+ brcmu_pktq_penq(q, prec, pkt);
+ return true;
+ }
+
+ /* Determine precedence from which to evict packet, if any */
+ if (pktq_pfull(q, prec)) {
+ eprec = prec;
+ } else if (pktq_full(q)) {
+ p = brcmu_pktq_peek_tail(q, &eprec);
+ if (eprec > prec)
+ return false;
+ }
+
+ /* Evict if needed */
+ if (eprec >= 0) {
+ /* Detect queueing to unconfigured precedence */
+ if (eprec == prec)
+ return false; /* refuse newer (incoming) packet */
+ /* Evict packet according to discard policy */
+ p = brcmu_pktq_pdeq_tail(q, eprec);
+ if (p == NULL)
+ brcmf_err("brcmu_pktq_pdeq_tail() failed\n");
+ brcmu_pkt_buf_free_skb(p);
+ }
+
+ /* Enqueue */
+ p = brcmu_pktq_penq(q, prec, pkt);
+ if (p == NULL)
+ brcmf_err("brcmu_pktq_penq() failed\n");
+
+ return p != NULL;
+}
+
+static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
+{
+ int ret = -EBADE;
+ uint prec;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
+
+ /* Add space for the header */
+ skb_push(pkt, bus->tx_hdrlen);
+ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
+
+ prec = prio2prec((pkt->priority & PRIOMASK));
+
+ /* Check for existing queue, current flow-control,
+ pending event, or pending clock */
+ brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
+ bus->sdcnt.fcqueued++;
+
+ /* Priority based enq */
+ spin_lock_bh(&bus->txq_lock);
+ /* reset bus_flags in packet cb */
+ *(u16 *)(pkt->cb) = 0;
+ if (!brcmf_sdio_prec_enq(&bus->txq, pkt, prec)) {
+ skb_pull(pkt, bus->tx_hdrlen);
+ brcmf_err("out of bus->txq !!!\n");
+ ret = -ENOSR;
+ } else {
+ ret = 0;
+ }
+
+ if (pktq_len(&bus->txq) >= TXHI) {
+ bus->txoff = true;
+ brcmf_txflowblock(dev, true);
+ }
+ spin_unlock_bh(&bus->txq_lock);
+
+#ifdef DEBUG
+ if (pktq_plen(&bus->txq, prec) > qcount[prec])
+ qcount[prec] = pktq_plen(&bus->txq, prec);
+#endif
+
+ if (atomic_read(&bus->dpc_tskcnt) == 0) {
+ atomic_inc(&bus->dpc_tskcnt);
+ queue_work(bus->brcmf_wq, &bus->datawork);
+ }
+
+ return ret;
+}
+
+#ifdef DEBUG
+#define CONSOLE_LINE_MAX 192
+
+static int brcmf_sdio_readconsole(struct brcmf_sdio *bus)
+{
+ struct brcmf_console *c = &bus->console;
+ u8 line[CONSOLE_LINE_MAX], ch;
+ u32 n, idx, addr;
+ int rv;
+
+ /* Don't do anything until FWREADY updates console address */
+ if (bus->console_addr == 0)
+ return 0;
+
+ /* Read console log struct */
+ addr = bus->console_addr + offsetof(struct rte_console, log_le);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le,
+ sizeof(c->log_le));
+ if (rv < 0)
+ return rv;
+
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = le32_to_cpu(c->log_le.buf_size);
+ c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
+ if (c->buf == NULL)
+ return -ENOMEM;
+ }
+
+ idx = le32_to_cpu(c->log_le.idx);
+
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return -EBADE;
+
+ /* Skip reading the console buffer if the index pointer
+ has not moved */
+ if (idx == c->last)
+ return 0;
+
+ /* Read the console buffer */
+ addr = le32_to_cpu(c->log_le.buf);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);
+ if (rv < 0)
+ return rv;
+
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line.
+ * Instead, back up
+ * the buffer pointer and output this
+ * line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
+ }
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
+
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ pr_debug("CONSOLE: %s\n", line);
+ }
+ }
+break2:
+
+ return 0;
+}
+#endif /* DEBUG */
+
+static int
+brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+ int ret = -1;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (down_interruptible(&bus->tx_seq_lock))
+ return -EINTR;
+
+ if (!data_ok(bus)) {
+ brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ bus->tx_max, bus->tx_seq);
+ up(&bus->tx_seq_lock);
+ /* Send from dpc */
+ bus->ctrl_frame_buf = msg;
+ bus->ctrl_frame_len = msglen;
+ bus->ctrl_frame_stat = true;
+
+ wait_event_interruptible_timeout(bus->ctrl_wait,
+ !bus->ctrl_frame_stat,
+ msecs_to_jiffies(2000));
+
+ if (!bus->ctrl_frame_stat) {
+ brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
+ ret = 0;
+ } else {
+ brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
+ bus->ctrl_frame_stat = false;
+ if (down_interruptible(&bus->tx_seq_lock))
+ return -EINTR;
+ ret = -1;
+ }
+ }
+ if (ret == -1) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_bus_sleep(bus, false, false);
+ ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);
+ sdio_release_host(bus->sdiodev->func[1]);
+ up(&bus->tx_seq_lock);
+ }
+
+ if (ret)
+ bus->sdcnt.tx_ctlerrs++;
+ else
+ bus->sdcnt.tx_ctlpkts++;
+
+ return ret ? -EIO : 0;
+}
+
+#ifdef DEBUG
+static int brcmf_sdio_dump_console(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
+{
+ u32 addr, console_ptr, console_size, console_index;
+ char *conbuf = NULL;
+ __le32 sh_val;
+ int rv;
+
+ /* obtain console information from device memory */
+ addr = sh->console_addr + offsetof(struct rte_console, log_le);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
+ if (rv < 0)
+ return rv;
+ console_ptr = le32_to_cpu(sh_val);
+
+ addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
+ if (rv < 0)
+ return rv;
+ console_size = le32_to_cpu(sh_val);
+
+ addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
+ if (rv < 0)
+ return rv;
+ console_index = le32_to_cpu(sh_val);
+
+ /* allocate buffer for console data */
+ if (console_size <= CONSOLE_BUFFER_MAX)
+ conbuf = vzalloc(console_size+1);
+
+ if (!conbuf)
+ return -ENOMEM;
+
+ /* obtain the console data from device */
+ conbuf[console_size] = '\0';
+ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf,
+ console_size);
+ if (rv < 0)
+ goto done;
+
+ rv = seq_write(seq, conbuf + console_index,
+ console_size - console_index);
+ if (rv < 0)
+ goto done;
+
+ if (console_index > 0)
+ rv = seq_write(seq, conbuf, console_index - 1);
+
+done:
+ vfree(conbuf);
+ return rv;
+}
+
+static int brcmf_sdio_trap_info(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
+{
+ int error;
+ struct brcmf_trap_info tr;
+
+ if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
+ brcmf_dbg(INFO, "no trap in firmware\n");
+ return 0;
+ }
+
+ error = brcmf_sdiod_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr,
+ sizeof(struct brcmf_trap_info));
+ if (error < 0)
+ return error;
+
+ seq_printf(seq,
+ "dongle trap info: type 0x%x @ epc 0x%08x\n"
+ " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
+ " lr 0x%08x pc 0x%08x offset 0x%x\n"
+ " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n"
+ " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n",
+ le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
+ le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
+ le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
+ le32_to_cpu(tr.pc), sh->trap_addr,
+ le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
+ le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
+ le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
+ le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
+
+ return 0;
+}
+
+static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus,
+ struct sdpcm_shared *sh)
+{
+ int error = 0;
+ char file[80] = "?";
+ char expr[80] = "<???>";
+
+ if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+ brcmf_dbg(INFO, "firmware not built with -assert\n");
+ return 0;
+ } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
+ brcmf_dbg(INFO, "no assert in dongle\n");
+ return 0;
+ }
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+ if (sh->assert_file_addr != 0) {
+ error = brcmf_sdiod_ramrw(bus->sdiodev, false,
+ sh->assert_file_addr, (u8 *)file, 80);
+ if (error < 0)
+ return error;
+ }
+ if (sh->assert_exp_addr != 0) {
+ error = brcmf_sdiod_ramrw(bus->sdiodev, false,
+ sh->assert_exp_addr, (u8 *)expr, 80);
+ if (error < 0)
+ return error;
+ }
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ seq_printf(seq, "dongle assert: %s:%d: assert(%s)\n",
+ file, sh->assert_line, expr);
+ return 0;
+}
+
+static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
+{
+ int error;
+ struct sdpcm_shared sh;
+
+ error = brcmf_sdio_readshared(bus, &sh);
+
+ if (error < 0)
+ return error;
+
+ if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
+ brcmf_dbg(INFO, "firmware not built with -assert\n");
+ else if (sh.flags & SDPCM_SHARED_ASSERT)
+ brcmf_err("assertion in dongle\n");
+
+ if (sh.flags & SDPCM_SHARED_TRAP)
+ brcmf_err("firmware trap in dongle\n");
+
+ return 0;
+}
+
+static int brcmf_sdio_died_dump(struct seq_file *seq, struct brcmf_sdio *bus)
+{
+ int error = 0;
+ struct sdpcm_shared sh;
+
+ error = brcmf_sdio_readshared(bus, &sh);
+ if (error < 0)
+ goto done;
+
+ error = brcmf_sdio_assert_info(seq, bus, &sh);
+ if (error < 0)
+ goto done;
+
+ error = brcmf_sdio_trap_info(seq, bus, &sh);
+ if (error < 0)
+ goto done;
+
+ error = brcmf_sdio_dump_console(seq, bus, &sh);
+
+done:
+ return error;
+}
+
+static int brcmf_sdio_forensic_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ struct brcmf_sdio *bus = bus_if->bus_priv.sdio->bus;
+
+ return brcmf_sdio_died_dump(seq, bus);
+}
+
+static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio_count *sdcnt = &sdiodev->bus->sdcnt;
+
+ seq_printf(seq,
+ "intrcount: %u\nlastintrs: %u\n"
+ "pollcnt: %u\nregfails: %u\n"
+ "tx_sderrs: %u\nfcqueued: %u\n"
+ "rxrtx: %u\nrx_toolong: %u\n"
+ "rxc_errors: %u\nrx_hdrfail: %u\n"
+ "rx_badhdr: %u\nrx_badseq: %u\n"
+ "fc_rcvd: %u\nfc_xoff: %u\n"
+ "fc_xon: %u\nrxglomfail: %u\n"
+ "rxglomframes: %u\nrxglompkts: %u\n"
+ "f2rxhdrs: %u\nf2rxdata: %u\n"
+ "f2txdata: %u\nf1regdata: %u\n"
+ "tickcnt: %u\ntx_ctlerrs: %lu\n"
+ "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n"
+ "rx_ctlpkts: %lu\nrx_readahead: %lu\n",
+ sdcnt->intrcount, sdcnt->lastintrs,
+ sdcnt->pollcnt, sdcnt->regfails,
+ sdcnt->tx_sderrs, sdcnt->fcqueued,
+ sdcnt->rxrtx, sdcnt->rx_toolong,
+ sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+ sdcnt->rx_badhdr, sdcnt->rx_badseq,
+ sdcnt->fc_rcvd, sdcnt->fc_xoff,
+ sdcnt->fc_xon, sdcnt->rxglomfail,
+ sdcnt->rxglomframes, sdcnt->rxglompkts,
+ sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+ sdcnt->f2txdata, sdcnt->f1regdata,
+ sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+ sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+ sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+ return 0;
+}
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+ struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+ struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
+
+ if (IS_ERR_OR_NULL(dentry))
+ return;
+
+ brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
+ brcmf_debugfs_add_entry(drvr, "counters",
+ brcmf_debugfs_sdio_count_read);
+ debugfs_create_u32("console_interval", 0644, dentry,
+ &bus->console_interval);
+}
+#else
+static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)
+{
+ return 0;
+}
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
+static int
+brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
+{
+ int timeleft;
+ uint rxlen = 0;
+ bool pending;
+ u8 *buf;
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Wait until control frame is available */
+ timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
+
+ spin_lock_bh(&bus->rxctl_lock);
+ rxlen = bus->rxlen;
+ memcpy(msg, bus->rxctl, min(msglen, rxlen));
+ bus->rxctl = NULL;
+ buf = bus->rxctl_orig;
+ bus->rxctl_orig = NULL;
+ bus->rxlen = 0;
+ spin_unlock_bh(&bus->rxctl_lock);
+ vfree(buf);
+
+ if (rxlen) {
+ brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
+ rxlen, msglen);
+ } else if (timeleft == 0) {
+ brcmf_err("resumed on timeout\n");
+ brcmf_sdio_checkdied(bus);
+ } else if (pending) {
+ brcmf_dbg(CTL, "cancelled\n");
+ return -ERESTARTSYS;
+ } else {
+ brcmf_dbg(CTL, "resumed for unknown reason?\n");
+ brcmf_sdio_checkdied(bus);
+ }
+
+ if (rxlen)
+ bus->sdcnt.rx_ctlpkts++;
+ else
+ bus->sdcnt.rx_ctlerrs++;
+
+ return rxlen ? (int)rxlen : -ETIMEDOUT;
+}
+
+#ifdef DEBUG
+static bool
+brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
+ u8 *ram_data, uint ram_sz)
+{
+ char *ram_cmp;
+ int err;
+ bool ret = true;
+ int address;
+ int offset;
+ int len;
+
+ /* read back and verify */
+ brcmf_dbg(INFO, "Compare RAM dl & ul at 0x%08x; size=%d\n", ram_addr,
+ ram_sz);
+ ram_cmp = kmalloc(MEMBLOCK, GFP_KERNEL);
+ /* do not proceed while no memory but */
+ if (!ram_cmp)
+ return true;
+
+ address = ram_addr;
+ offset = 0;
+ while (offset < ram_sz) {
+ len = ((offset + MEMBLOCK) < ram_sz) ? MEMBLOCK :
+ ram_sz - offset;
+ err = brcmf_sdiod_ramrw(sdiodev, false, address, ram_cmp, len);
+ if (err) {
+ brcmf_err("error %d on reading %d membytes at 0x%08x\n",
+ err, len, address);
+ ret = false;
+ break;
+ } else if (memcmp(ram_cmp, &ram_data[offset], len)) {
+ brcmf_err("Downloaded RAM image is corrupted, block offset is %d, len is %d\n",
+ offset, len);
+ ret = false;
+ break;
+ }
+ offset += len;
+ address += len;
+ }
+
+ kfree(ram_cmp);
+
+ return ret;
+}
+#else /* DEBUG */
+static bool
+brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
+ u8 *ram_data, uint ram_sz)
+{
+ return true;
+}
+#endif /* DEBUG */
+
+static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus,
+ const struct firmware *fw)
+{
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ err = brcmf_sdiod_ramrw(bus->sdiodev, true, bus->ci->rambase,
+ (u8 *)fw->data, fw->size);
+ if (err)
+ brcmf_err("error %d on writing %d membytes at 0x%08x\n",
+ err, (int)fw->size, bus->ci->rambase);
+ else if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase,
+ (u8 *)fw->data, fw->size))
+ err = -EIO;
+
+ return err;
+}
+
+static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus,
+ void *vars, u32 varsz)
+{
+ int address;
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ address = bus->ci->ramsize - varsz + bus->ci->rambase;
+ err = brcmf_sdiod_ramrw(bus->sdiodev, true, address, vars, varsz);
+ if (err)
+ brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
+ err, varsz, address);
+ else if (!brcmf_sdio_verifymemory(bus->sdiodev, address, vars, varsz))
+ err = -EIO;
+
+ return err;
+}
+
+static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
+ const struct firmware *fw,
+ void *nvram, u32 nvlen)
+{
+ int bcmerror = -EFAULT;
+ u32 rstvec;
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+
+ /* Keep arm in reset */
+ brcmf_chip_enter_download(bus->ci);
+
+ rstvec = get_unaligned_le32(fw->data);
+ brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
+
+ bcmerror = brcmf_sdio_download_code_file(bus, fw);
+ release_firmware(fw);
+ if (bcmerror) {
+ brcmf_err("dongle image file download failed\n");
+ brcmf_fw_nvram_free(nvram);
+ goto err;
+ }
+
+ bcmerror = brcmf_sdio_download_nvram(bus, nvram, nvlen);
+ brcmf_fw_nvram_free(nvram);
+ if (bcmerror) {
+ brcmf_err("dongle nvram file download failed\n");
+ goto err;
+ }
+
+ /* Take arm out of reset */
+ if (!brcmf_chip_exit_download(bus->ci, rstvec)) {
+ brcmf_err("error getting out of ARM core reset\n");
+ goto err;
+ }
+
+ /* Allow HT Clock now that the ARM is running. */
+ brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
+ bcmerror = 0;
+
+err:
+ brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
+ sdio_release_host(bus->sdiodev->func[1]);
+ return bcmerror;
+}
+
+static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
+{
+ int err = 0;
+ u8 val;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, &err);
+ if (err) {
+ brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n");
+ return;
+ }
+
+ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");
+ return;
+ }
+
+ /* Add CMD14 Support */
+ brcmf_sdiod_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
+ (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
+ SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT),
+ &err);
+ if (err) {
+ brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");
+ return;
+ }
+
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_FORCE_HT, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");
+ return;
+ }
+
+ /* set flag */
+ bus->sr_enabled = true;
+ brcmf_dbg(INFO, "SR enabled\n");
+}
+
+/* enable KSO bit */
+static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)
+{
+ u8 val;
+ int err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* KSO bit added in SDIO core rev 12 */
+ if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12)
+ return 0;
+
+ val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);
+ if (err) {
+ brcmf_err("error reading SBSDIO_FUNC1_SLEEPCSR\n");
+ return err;
+ }
+
+ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
+ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN <<
+ SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ val, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_SLEEPCSR\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
+static int brcmf_sdio_bus_preinit(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+ uint pad_size;
+ u32 value;
+ int err;
+
+ /* the commands below use the terms tx and rx from
+ * a device perspective, ie. bus:txglom affects the
+ * bus transfers from device to host.
+ */
+ if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) {
+ /* for sdio core rev < 12, disable txgloming */
+ value = 0;
+ err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
+ sizeof(u32));
+ } else {
+ /* otherwise, set txglomalign */
+ value = 4;
+ if (sdiodev->pdata)
+ value = sdiodev->pdata->sd_sgentry_align;
+ /* SDIO ADMA requires at least 32 bit alignment */
+ value = max_t(u32, value, 4);
+ err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
+ sizeof(u32));
+ }
+
+ if (err < 0)
+ goto done;
+
+ bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
+ if (sdiodev->sg_support) {
+ bus->txglom = false;
+ value = 1;
+ pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
+ err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
+ &value, sizeof(u32));
+ if (err < 0) {
+ /* bus:rxglom is allowed to fail */
+ err = 0;
+ } else {
+ bus->txglom = true;
+ bus->tx_hdrlen += SDPCM_HWEXT_LEN;
+ }
+ }
+ brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen);
+
+done:
+ return err;
+}
+
+void brcmf_sdio_isr(struct brcmf_sdio *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (!bus) {
+ brcmf_err("bus is null pointer, exiting\n");
+ return;
+ }
+
+ if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
+ brcmf_err("bus is down. we have nothing to do\n");
+ return;
+ }
+ /* Count the interrupt call */
+ bus->sdcnt.intrcount++;
+ if (in_interrupt())
+ atomic_set(&bus->ipend, 1);
+ else
+ if (brcmf_sdio_intr_rstatus(bus)) {
+ brcmf_err("failed backplane access\n");
+ }
+
+ /* Disable additional interrupts (is this needed now)? */
+ if (!bus->intr)
+ brcmf_err("isr w/o interrupt configured!\n");
+
+ atomic_inc(&bus->dpc_tskcnt);
+ queue_work(bus->brcmf_wq, &bus->datawork);
+}
+
+static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
+{
+#ifdef DEBUG
+ struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
+#endif /* DEBUG */
+
+ brcmf_dbg(TIMER, "Enter\n");
+
+ /* Poll period: check device if appropriate. */
+ if (!bus->sr_enabled &&
+ bus->poll && (++bus->polltick >= bus->pollrate)) {
+ u32 intstatus = 0;
+
+ /* Reset poll tick */
+ bus->polltick = 0;
+
+ /* Check device if no interrupts */
+ if (!bus->intr ||
+ (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
+
+ if (atomic_read(&bus->dpc_tskcnt) == 0) {
+ u8 devpend;
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+ devpend = brcmf_sdiod_regrb(bus->sdiodev,
+ SDIO_CCCR_INTx,
+ NULL);
+ sdio_release_host(bus->sdiodev->func[1]);
+ intstatus =
+ devpend & (INTR_STATUS_FUNC1 |
+ INTR_STATUS_FUNC2);
+ }
+
+ /* If there is something, make like the ISR and
+ schedule the DPC */
+ if (intstatus) {
+ bus->sdcnt.pollcnt++;
+ atomic_set(&bus->ipend, 1);
+
+ atomic_inc(&bus->dpc_tskcnt);
+ queue_work(bus->brcmf_wq, &bus->datawork);
+ }
+ }
+
+ /* Update interrupt tracking */
+ bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
+ }
+#ifdef DEBUG
+ /* Poll for console output periodically */
+ if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
+ bus->console_interval != 0) {
+ bus->console.count += BRCMF_WD_POLL_MS;
+ if (bus->console.count >= bus->console_interval) {
+ bus->console.count -= bus->console_interval;
+ sdio_claim_host(bus->sdiodev->func[1]);
+ /* Make sure backplane clock is on */
+ brcmf_sdio_bus_sleep(bus, false, false);
+ if (brcmf_sdio_readconsole(bus) < 0)
+ /* stop on error */
+ bus->console_interval = 0;
+ sdio_release_host(bus->sdiodev->func[1]);
+ }
+ }
+#endif /* DEBUG */
+
+ /* On idle timeout clear activity flag and/or turn off clock */
+ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = false;
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
+ } else {
+ brcmf_dbg(SDIO, "idle\n");
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_bus_sleep(bus, true, false);
+ sdio_release_host(bus->sdiodev->func[1]);
+ }
+ }
+ }
+
+ return (atomic_read(&bus->ipend) > 0);
+}
+
+static void brcmf_sdio_dataworker(struct work_struct *work)
+{
+ struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
+ datawork);
+
+ while (atomic_read(&bus->dpc_tskcnt)) {
+ atomic_set(&bus->dpc_tskcnt, 0);
+ brcmf_sdio_dpc(bus);
+ }
+}
+
+static void
+brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+ struct brcmf_chip *ci, u32 drivestrength)
+{
+ const struct sdiod_drive_str *str_tab = NULL;
+ u32 str_mask;
+ u32 str_shift;
+ u32 base;
+ u32 i;
+ u32 drivestrength_sel = 0;
+ u32 cc_data_temp;
+ u32 addr;
+
+ if (!(ci->cc_caps & CC_CAP_PMU))
+ return;
+
+ switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BRCM_CC_4330_CHIP_ID, 12):
+ str_tab = sdiod_drvstr_tab1_1v8;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BRCM_CC_4334_CHIP_ID, 17):
+ str_tab = sdiod_drvstr_tab6_1v8;
+ str_mask = 0x00001800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BRCM_CC_43143_CHIP_ID, 17):
+ /* note: 43143 does not support tristate */
+ i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
+ if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
+ str_tab = sdiod_drvstr_tab2_3v3;
+ str_mask = 0x00000007;
+ str_shift = 0;
+ } else
+ brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
+ ci->name, drivestrength);
+ break;
+ case SDIOD_DRVSTR_KEY(BRCM_CC_43362_CHIP_ID, 13):
+ str_tab = sdiod_drive_strength_tab5_1v8;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ default:
+ brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+ ci->name, ci->chiprev, ci->pmurev);
+ break;
+ }
+
+ if (str_tab != NULL) {
+ for (i = 0; str_tab[i].strength != 0; i++) {
+ if (drivestrength >= str_tab[i].strength) {
+ drivestrength_sel = str_tab[i].sel;
+ break;
+ }
+ }
+ base = brcmf_chip_get_chipcommon(ci)->base;
+ addr = CORE_CC_REG(base, chipcontrol_addr);
+ brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
+ cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
+ cc_data_temp &= ~str_mask;
+ drivestrength_sel <<= str_shift;
+ cc_data_temp |= drivestrength_sel;
+ brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
+
+ brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
+ str_tab[i].strength, drivestrength, cc_data_temp);
+ }
+}
+
+static int brcmf_sdio_buscoreprep(void *ctx)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ int err = 0;
+ u8 clkval, clkset;
+
+ /* Try forcing SDIO core to do ALPAvail request only */
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ if (err) {
+ brcmf_err("error writing for HT off\n");
+ return err;
+ }
+
+ /* If register supported, wait for ALPAvail and then force ALP */
+ /* This may take up to 15 milliseconds */
+ clkval = brcmf_sdiod_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+
+ if ((clkval & ~SBSDIO_AVBITS) != clkset) {
+ brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+ clkset, clkval);
+ return -EACCES;
+ }
+
+ SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+ !SBSDIO_ALPAV(clkval)),
+ PMU_MAX_TRANSITION_DLY);
+ if (!SBSDIO_ALPAV(clkval)) {
+ brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
+ clkval);
+ return -EBUSY;
+ }
+
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ udelay(65);
+
+ /* Also, disable the extra SDIO pull-ups */
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+ return 0;
+}
+
+static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip,
+ u32 rstvec)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ struct brcmf_core *core;
+ u32 reg_addr;
+
+ /* clear all interrupts */
+ core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV);
+ reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus);
+ brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+
+ if (rstvec)
+ /* Write reset vector to address 0 */
+ brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
+ sizeof(rstvec));
+}
+
+static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+ u32 val, rev;
+
+ val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
+ if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID &&
+ addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
+ rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
+ if (rev >= 2) {
+ val &= ~CID_ID_MASK;
+ val |= BRCM_CC_4339_CHIP_ID;
+ }
+ }
+ return val;
+}
+
+static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
+{
+ struct brcmf_sdio_dev *sdiodev = ctx;
+
+ brcmf_sdiod_regwl(sdiodev, addr, val, NULL);
+}
+
+static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
+ .prepare = brcmf_sdio_buscoreprep,
+ .exit_dl = brcmf_sdio_buscore_exitdl,
+ .read32 = brcmf_sdio_buscore_read32,
+ .write32 = brcmf_sdio_buscore_write32,
+};
+
+static bool
+brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
+{
+ u8 clkctl = 0;
+ int err = 0;
+ int reg_addr;
+ u32 reg_val;
+ u32 drivestrength;
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+
+ pr_debug("F1 signature read @0x18000000=0x%4x\n",
+ brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
+
+ /*
+ * Force PLL off until brcmf_chip_attach()
+ * programs PLL control regs
+ */
+
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ BRCMF_INIT_CLKCTL1, &err);
+ if (!err)
+ clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+
+ if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
+ brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
+ err, BRCMF_INIT_CLKCTL1, clkctl);
+ goto fail;
+ }
+
+ /* SDIO register access works so moving
+ * state from UNKNOWN to DOWN.
+ */
+ brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
+
+ bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
+ if (IS_ERR(bus->ci)) {
+ brcmf_err("brcmf_chip_attach failed!\n");
+ bus->ci = NULL;
+ goto fail;
+ }
+
+ if (brcmf_sdio_kso_init(bus)) {
+ brcmf_err("error enabling KSO\n");
+ goto fail;
+ }
+
+ if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
+ drivestrength = bus->sdiodev->pdata->drive_strength;
+ else
+ drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
+ brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
+
+ /* Get info on the SOCRAM cores... */
+ bus->ramsize = bus->ci->ramsize;
+ if (!(bus->ramsize)) {
+ brcmf_err("failed to find SOCRAM memory!\n");
+ goto fail;
+ }
+
+ /* Set card control so an SDIO card reset does a WLAN backplane reset */
+ reg_val = brcmf_sdiod_regrb(bus->sdiodev,
+ SDIO_CCCR_BRCM_CARDCTRL, &err);
+ if (err)
+ goto fail;
+
+ reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
+
+ brcmf_sdiod_regwb(bus->sdiodev,
+ SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
+ if (err)
+ goto fail;
+
+ /* set PMUControl so a backplane reset does PMU state reload */
+ reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
+ pmucontrol);
+ reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
+ if (err)
+ goto fail;
+
+ reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
+
+ brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
+ if (err)
+ goto fail;
+
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+
+ /* allocate header buffer */
+ bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
+ if (!bus->hdrbuf)
+ return false;
+ /* Locate an appropriately-aligned portion of hdrbuf */
+ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
+ bus->head_align);
+
+ /* Set the poll and/or interrupt flags */
+ bus->intr = true;
+ bus->poll = false;
+ if (bus->poll)
+ bus->pollrate = 1;
+
+ return true;
+
+fail:
+ sdio_release_host(bus->sdiodev->func[1]);
+ return false;
+}
+
+static int
+brcmf_sdio_watchdog_thread(void *data)
+{
+ struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
+ brcmf_sdio_bus_watchdog(bus);
+ /* Count the tick for reference */
+ bus->sdcnt.tickcnt++;
+ reinit_completion(&bus->watchdog_wait);
+ } else
+ break;
+ }
+ return 0;
+}
+
+static void
+brcmf_sdio_watchdog(unsigned long data)
+{
+ struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
+
+ if (bus->watchdog_tsk) {
+ complete(&bus->watchdog_wait);
+ /* Reschedule the watchdog */
+ if (bus->wd_timer_valid)
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
+ }
+}
+
+static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
+ .stop = brcmf_sdio_bus_stop,
+ .preinit = brcmf_sdio_bus_preinit,
+ .txdata = brcmf_sdio_bus_txdata,
+ .txctl = brcmf_sdio_bus_txctl,
+ .rxctl = brcmf_sdio_bus_rxctl,
+ .gettxq = brcmf_sdio_bus_gettxq,
+ .wowl_config = brcmf_sdio_wowl_config
+};
+
+static void brcmf_sdio_firmware_callback(struct device *dev,
+ const struct firmware *code,
+ void *nvram, u32 nvram_len)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+ int err = 0;
+ u8 saveclk;
+
+ brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
+
+ /* try to download image and nvram to the dongle */
+ if (bus_if->state == BRCMF_BUS_DOWN) {
+ bus->alp_only = true;
+ err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
+ if (err)
+ goto fail;
+ bus->alp_only = false;
+ }
+
+ if (!bus_if->drvr)
+ return;
+
+ /* Start the watchdog timer */
+ bus->sdcnt.tickcnt = 0;
+ brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
+
+ sdio_claim_host(sdiodev->func[1]);
+
+ /* Make sure backplane clock is on, needed to generate F2 interrupt */
+ brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+ if (bus->clkstate != CLK_AVAIL)
+ goto release;
+
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err) {
+ brcmf_err("Failed to force clock for F2: err %d\n", err);
+ goto release;
+ }
+
+ /* Enable function 2 (frame transfers) */
+ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
+ offsetof(struct sdpcmd_regs, tosbmailboxdata));
+ err = sdio_enable_func(sdiodev->func[SDIO_FUNC_2]);
+
+
+ brcmf_dbg(INFO, "enable F2: err=%d\n", err);
+
+ /* If F2 successfully enabled, set core and enable interrupts */
+ if (!err) {
+ /* Set up the interrupt mask and enable interrupts */
+ bus->hostintmask = HOSTINTMASK;
+ w_sdreg32(bus, bus->hostintmask,
+ offsetof(struct sdpcmd_regs, hostintmask));
+
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK, 8, &err);
+ } else {
+ /* Disable F2 again */
+ sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
+ goto release;
+ }
+
+ if (brcmf_chip_sr_capable(bus->ci)) {
+ brcmf_sdio_sr_init(bus);
+ } else {
+ /* Restore previous clock setting */
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ saveclk, &err);
+ }
+
+ if (err == 0) {
+ err = brcmf_sdiod_intr_register(sdiodev);
+ if (err != 0)
+ brcmf_err("intr register failed:%d\n", err);
+ }
+
+ /* If we didn't come up, turn off backplane clock */
+ if (err != 0)
+ brcmf_sdio_clkctl(bus, CLK_NONE, false);
+
+ sdio_release_host(sdiodev->func[1]);
+
+ err = brcmf_bus_start(dev);
+ if (err != 0) {
+ brcmf_err("dongle is not responding\n");
+ goto fail;
+ }
+ return;
+
+release:
+ sdio_release_host(sdiodev->func[1]);
+fail:
+ brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err);
+ device_release_driver(dev);
+}
+
+struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+{
+ int ret;
+ struct brcmf_sdio *bus;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Allocate private bus interface state */
+ bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
+ if (!bus)
+ goto fail;
+
+ bus->sdiodev = sdiodev;
+ sdiodev->bus = bus;
+ skb_queue_head_init(&bus->glom);
+ bus->txbound = BRCMF_TXBOUND;
+ bus->rxbound = BRCMF_RXBOUND;
+ bus->txminmax = BRCMF_TXMINMAX;
+ bus->tx_seq = SDPCM_SEQ_WRAP - 1;
+
+ /* platform specific configuration:
+ * alignments must be at least 4 bytes for ADMA
+ */
+ bus->head_align = ALIGNMENT;
+ bus->sgentry_align = ALIGNMENT;
+ if (sdiodev->pdata) {
+ if (sdiodev->pdata->sd_head_align > ALIGNMENT)
+ bus->head_align = sdiodev->pdata->sd_head_align;
+ if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
+ bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
+ }
+
+ INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
+ bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
+ if (bus->brcmf_wq == NULL) {
+ brcmf_err("insufficient memory to create txworkqueue\n");
+ goto fail;
+ }
+
+ /* attempt to attach to the dongle */
+ if (!(brcmf_sdio_probe_attach(bus))) {
+ brcmf_err("brcmf_sdio_probe_attach failed\n");
+ goto fail;
+ }
+
+ spin_lock_init(&bus->rxctl_lock);
+ spin_lock_init(&bus->txq_lock);
+ sema_init(&bus->tx_seq_lock, 1);
+ init_waitqueue_head(&bus->ctrl_wait);
+ init_waitqueue_head(&bus->dcmd_resp_wait);
+
+ /* Set up the watchdog timer */
+ init_timer(&bus->timer);
+ bus->timer.data = (unsigned long)bus;
+ bus->timer.function = brcmf_sdio_watchdog;
+
+ /* Initialize watchdog thread */
+ init_completion(&bus->watchdog_wait);
+ bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,
+ bus, "brcmf_watchdog");
+ if (IS_ERR(bus->watchdog_tsk)) {
+ pr_warn("brcmf_watchdog thread failed to start\n");
+ bus->watchdog_tsk = NULL;
+ }
+ /* Initialize DPC thread */
+ atomic_set(&bus->dpc_tskcnt, 0);
+
+ /* Assign bus interface call back */
+ bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
+ bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
+ bus->sdiodev->bus_if->chip = bus->ci->chip;
+ bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
+
+ /* default sdio bus header length for tx packet */
+ bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
+
+ /* Attach to the common layer, reserve hdr space */
+ ret = brcmf_attach(bus->sdiodev->dev);
+ if (ret != 0) {
+ brcmf_err("brcmf_attach failed\n");
+ goto fail;
+ }
+
+ /* Query the F2 block size, set roundup accordingly */
+ bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+ bus->roundup = min(max_roundup, bus->blocksize);
+
+ /* Allocate buffers */
+ if (bus->sdiodev->bus_if->maxctl) {
+ bus->sdiodev->bus_if->maxctl += bus->roundup;
+ bus->rxblen =
+ roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
+ ALIGNMENT) + bus->head_align;
+ bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+ if (!(bus->rxbuf)) {
+ brcmf_err("rxbuf allocation failed\n");
+ goto fail;
+ }
+ }
+
+ sdio_claim_host(bus->sdiodev->func[1]);
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
+
+ bus->rxflow = false;
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ sdio_release_host(bus->sdiodev->func[1]);
+
+ /* ...and initialize clock/power states */
+ bus->clkstate = CLK_SDONLY;
+ bus->idletime = BRCMF_IDLE_INTERVAL;
+ bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+ /* SR state */
+ bus->sleeping = false;
+ bus->sr_enabled = false;
+
+ brcmf_sdio_debugfs_create(bus);
+ brcmf_dbg(INFO, "completed!!\n");
+
+ ret = brcmf_sdio_get_fwnames(bus->ci, sdiodev);
+ if (ret)
+ goto fail;
+
+ ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
+ sdiodev->fw_name, sdiodev->nvram_name,
+ brcmf_sdio_firmware_callback);
+ if (ret != 0) {
+ brcmf_err("async firmware request failed: %d\n", ret);
+ goto fail;
+ }
+
+ return bus;
+
+fail:
+ brcmf_sdio_remove(bus);
+ return NULL;
+}
+
+/* Detach and free everything */
+void brcmf_sdio_remove(struct brcmf_sdio *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus) {
+ /* De-register interrupt handler */
+ brcmf_sdiod_intr_unregister(bus->sdiodev);
+
+ brcmf_detach(bus->sdiodev->dev);
+
+ cancel_work_sync(&bus->datawork);
+ if (bus->brcmf_wq)
+ destroy_workqueue(bus->brcmf_wq);
+
+ if (bus->ci) {
+ if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+ /* Leave the device in state where it is
+ * 'quiet'. This is done by putting it in
+ * download_state which essentially resets
+ * all necessary cores.
+ */
+ msleep(20);
+ brcmf_chip_enter_download(bus->ci);
+ brcmf_sdio_clkctl(bus, CLK_NONE, false);
+ sdio_release_host(bus->sdiodev->func[1]);
+ }
+ brcmf_chip_detach(bus->ci);
+ }
+
+ kfree(bus->rxbuf);
+ kfree(bus->hdrbuf);
+ kfree(bus);
+ }
+
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
+
+void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
+{
+ /* Totally stop the timer */
+ if (!wdtick && bus->wd_timer_valid) {
+ del_timer_sync(&bus->timer);
+ bus->wd_timer_valid = false;
+ bus->save_ms = wdtick;
+ return;
+ }
+
+ /* don't start the wd until fw is loaded */
+ if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
+ return;
+
+ if (wdtick) {
+ if (bus->save_ms != BRCMF_WD_POLL_MS) {
+ if (bus->wd_timer_valid)
+ /* Stop timer and restart at new value */
+ del_timer_sync(&bus->timer);
+
+ /* Create timer again when watchdog period is
+ dynamically changed or in the first instance
+ */
+ bus->timer.expires =
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
+ add_timer(&bus->timer);
+
+ } else {
+ /* Re arm the timer, at last watchdog period */
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
+ }
+
+ bus->wd_timer_valid = true;
+ bus->save_ms = wdtick;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BRCMFMAC_SDIO_H
+#define BRCMFMAC_SDIO_H
+
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include "firmware.h"
+
+#define SDIO_FUNC_0 0
+#define SDIO_FUNC_1 1
+#define SDIO_FUNC_2 2
+
+#define SDIOD_FBR_SIZE 0x100
+
+/* io_en */
+#define SDIO_FUNC_ENABLE_1 0x02
+#define SDIO_FUNC_ENABLE_2 0x04
+
+/* io_rdys */
+#define SDIO_FUNC_READY_1 0x02
+#define SDIO_FUNC_READY_2 0x04
+
+/* intr_status */
+#define INTR_STATUS_FUNC1 0x2
+#define INTR_STATUS_FUNC2 0x4
+
+/* Maximum number of I/O funcs */
+#define SDIOD_MAX_IOFUNCS 7
+
+/* mask of register map */
+#define REG_F0_REG_MASK 0x7FF
+#define REG_F1_MISC_MASK 0x1FFFF
+
+/* as of sdiod rev 0, supports 3 functions */
+#define SBSDIO_NUM_FUNCTION 3
+
+/* function 0 vendor specific CCCR registers */
+#define SDIO_CCCR_BRCM_CARDCAP 0xf0
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04
+#define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08
+#define SDIO_CCCR_BRCM_CARDCTRL 0xf1
+#define SDIO_CCCR_BRCM_CARDCTRL_WLANRESET 0x02
+#define SDIO_CCCR_BRCM_SEPINT 0xf2
+
+#define SDIO_SEPINT_MASK 0x01
+#define SDIO_SEPINT_OE 0x02
+#define SDIO_SEPINT_ACT_HI 0x04
+
+/* function 1 miscellaneous registers */
+
+/* sprom command and status */
+#define SBSDIO_SPROM_CS 0x10000
+/* sprom info register */
+#define SBSDIO_SPROM_INFO 0x10001
+/* sprom indirect access data byte 0 */
+#define SBSDIO_SPROM_DATA_LOW 0x10002
+/* sprom indirect access data byte 1 */
+#define SBSDIO_SPROM_DATA_HIGH 0x10003
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_LOW 0x10004
+/* gpio select */
+#define SBSDIO_GPIO_SELECT 0x10005
+/* gpio output */
+#define SBSDIO_GPIO_OUT 0x10006
+/* gpio enable */
+#define SBSDIO_GPIO_EN 0x10007
+/* rev < 7, watermark for sdio device */
+#define SBSDIO_WATERMARK 0x10008
+/* control busy signal generation */
+#define SBSDIO_DEVICE_CTL 0x10009
+
+/* SB Address Window Low (b15) */
+#define SBSDIO_FUNC1_SBADDRLOW 0x1000A
+/* SB Address Window Mid (b23:b16) */
+#define SBSDIO_FUNC1_SBADDRMID 0x1000B
+/* SB Address Window High (b31:b24) */
+#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C
+/* Frame Control (frame term/abort) */
+#define SBSDIO_FUNC1_FRAMECTRL 0x1000D
+/* ChipClockCSR (ALP/HT ctl/status) */
+#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E
+/* SdioPullUp (on cmd, d0-d2) */
+#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F
+/* Write Frame Byte Count Low */
+#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019
+/* Write Frame Byte Count High */
+#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A
+/* Read Frame Byte Count Low */
+#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
+/* Read Frame Byte Count High */
+#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
+/* MesBusyCtl (rev 11) */
+#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D
+/* Sdio Core Rev 12 */
+#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1
+#define SBSDIO_FUNC1_SLEEPCSR 0x1001F
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1
+
+#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
+#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001F /* f1 misc register end */
+
+/* function 1 OCP space */
+
+/* sb offset addr is <= 15 bits, 32k */
+#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
+#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
+/* with b15, maps to 32-bit SB access */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
+
+/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
+
+#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
+#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
+#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
+/* Address bits from SBADDR regs */
+#define SBSDIO_SBWINDOW_MASK 0xffff8000
+
+#define SDIOH_READ 0 /* Read request */
+#define SDIOH_WRITE 1 /* Write request */
+
+#define SDIOH_DATA_FIX 0 /* Fixed addressing */
+#define SDIOH_DATA_INC 1 /* Incremental addressing */
+
+/* internal return code */
+#define SUCCESS 0
+#define ERROR 1
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#define BRCMF_SDALIGN (1 << 6)
+
+/* watchdog polling interval in ms */
+#define BRCMF_WD_POLL_MS 10
+
+struct brcmf_sdreg {
+ int func;
+ int offset;
+ int value;
+};
+
+struct brcmf_sdio;
+
+struct brcmf_sdio_dev {
+ struct sdio_func *func[SDIO_MAX_FUNCS];
+ u8 num_funcs; /* Supported funcs on client */
+ u32 sbwad; /* Save backplane window address */
+ struct brcmf_sdio *bus;
+ atomic_t suspend; /* suspend flag */
+ wait_queue_head_t request_word_wait;
+ wait_queue_head_t request_buffer_wait;
+ struct device *dev;
+ struct brcmf_bus *bus_if;
+ struct brcmfmac_sdio_platform_data *pdata;
+ bool oob_irq_requested;
+ bool irq_en; /* irq enable flags */
+ spinlock_t irq_en_lock;
+ bool irq_wake; /* irq wake enable flags */
+ bool sg_support;
+ uint max_request_size;
+ ushort max_segment_count;
+ uint max_segment_size;
+ uint txglomsz;
+ struct sg_table sgtable;
+ char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
+ char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
+ bool wowl_enabled;
+};
+
+/* sdio core registers */
+struct sdpcmd_regs {
+ u32 corecontrol; /* 0x00, rev8 */
+ u32 corestatus; /* rev8 */
+ u32 PAD[1];
+ u32 biststatus; /* rev8 */
+
+ /* PCMCIA access */
+ u16 pcmciamesportaladdr; /* 0x010, rev8 */
+ u16 PAD[1];
+ u16 pcmciamesportalmask; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciawrframebc; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciaunderflowtimer; /* rev8 */
+ u16 PAD[1];
+
+ /* interrupt */
+ u32 intstatus; /* 0x020, rev8 */
+ u32 hostintmask; /* rev8 */
+ u32 intmask; /* rev8 */
+ u32 sbintstatus; /* rev8 */
+ u32 sbintmask; /* rev8 */
+ u32 funcintmask; /* rev4 */
+ u32 PAD[2];
+ u32 tosbmailbox; /* 0x040, rev8 */
+ u32 tohostmailbox; /* rev8 */
+ u32 tosbmailboxdata; /* rev8 */
+ u32 tohostmailboxdata; /* rev8 */
+
+ /* synchronized access to registers in SDIO clock domain */
+ u32 sdioaccess; /* 0x050, rev8 */
+ u32 PAD[3];
+
+ /* PCMCIA frame control */
+ u8 pcmciaframectrl; /* 0x060, rev8 */
+ u8 PAD[3];
+ u8 pcmciawatermark; /* rev8 */
+ u8 PAD[155];
+
+ /* interrupt batching control */
+ u32 intrcvlazy; /* 0x100, rev8 */
+ u32 PAD[3];
+
+ /* counters */
+ u32 cmd52rd; /* 0x110, rev8 */
+ u32 cmd52wr; /* rev8 */
+ u32 cmd53rd; /* rev8 */
+ u32 cmd53wr; /* rev8 */
+ u32 abort; /* rev8 */
+ u32 datacrcerror; /* rev8 */
+ u32 rdoutofsync; /* rev8 */
+ u32 wroutofsync; /* rev8 */
+ u32 writebusy; /* rev8 */
+ u32 readwait; /* rev8 */
+ u32 readterm; /* rev8 */
+ u32 writeterm; /* rev8 */
+ u32 PAD[40];
+ u32 clockctlstatus; /* rev8 */
+ u32 PAD[7];
+
+ u32 PAD[128]; /* DMA engines */
+
+ /* SDIO/PCMCIA CIS region */
+ char cis[512]; /* 0x400-0x5ff, rev6 */
+
+ /* PCMCIA function control registers */
+ char pcmciafcr[256]; /* 0x600-6ff, rev6 */
+ u16 PAD[55];
+
+ /* PCMCIA backplane access */
+ u16 backplanecsr; /* 0x76E, rev6 */
+ u16 backplaneaddr0; /* rev6 */
+ u16 backplaneaddr1; /* rev6 */
+ u16 backplaneaddr2; /* rev6 */
+ u16 backplaneaddr3; /* rev6 */
+ u16 backplanedata0; /* rev6 */
+ u16 backplanedata1; /* rev6 */
+ u16 backplanedata2; /* rev6 */
+ u16 backplanedata3; /* rev6 */
+ u16 PAD[31];
+
+ /* sprom "size" & "blank" info */
+ u16 spromstatus; /* 0x7BE, rev2 */
+ u32 PAD[464];
+
+ u16 PAD[0x80];
+};
+
+/* Register/deregister interrupt handler. */
+int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
+int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
+
+/* sdio device register access interface */
+u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
+ int *ret);
+void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
+ int *ret);
+
+/* Buffer transfer to/from device (client) core via cmd53.
+ * fn: function number
+ * flags: backplane width, address increment, sync/async
+ * buf: pointer to memory data buffer
+ * nbytes: number of bytes to transfer to/from buf
+ * pkt: pointer to packet associated with buf (if any)
+ * complete: callback function for command completion (async only)
+ * handle: handle for completion callback (first arg in callback)
+ * Returns 0 or error code.
+ * NOTE: Async operation is not currently supported.
+ */
+int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
+ struct sk_buff_head *pktq);
+int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
+
+int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt);
+int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
+int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
+ struct sk_buff_head *pktq, uint totlen);
+
+/* Flags bits */
+
+/* Four-byte target (backplane) width (vs. two-byte) */
+#define SDIO_REQ_4BYTE 0x1
+/* Fixed address (FIFO) (vs. incrementing address) */
+#define SDIO_REQ_FIXED 0x2
+
+/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only).
+ * rw: read or write (0/1)
+ * addr: direct SDIO address
+ * buf: pointer to memory data buffer
+ * nbytes: number of bytes to transfer to/from buf
+ * Returns 0 or error code.
+ */
+int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
+ u8 *data, uint size);
+
+/* Issue an abort to the specified function */
+int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
+
+struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+void brcmf_sdio_remove(struct brcmf_sdio *bus);
+void brcmf_sdio_isr(struct brcmf_sdio *bus);
+
+void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
+void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
+
+#endif /* BRCMFMAC_SDIO_H */
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCM_SDH_H_
-#define _BRCM_SDH_H_
-
-#include <linux/skbuff.h>
-#include <linux/firmware.h>
-#include "firmware.h"
-
-#define SDIO_FUNC_0 0
-#define SDIO_FUNC_1 1
-#define SDIO_FUNC_2 2
-
-#define SDIOD_FBR_SIZE 0x100
-
-/* io_en */
-#define SDIO_FUNC_ENABLE_1 0x02
-#define SDIO_FUNC_ENABLE_2 0x04
-
-/* io_rdys */
-#define SDIO_FUNC_READY_1 0x02
-#define SDIO_FUNC_READY_2 0x04
-
-/* intr_status */
-#define INTR_STATUS_FUNC1 0x2
-#define INTR_STATUS_FUNC2 0x4
-
-/* Maximum number of I/O funcs */
-#define SDIOD_MAX_IOFUNCS 7
-
-/* mask of register map */
-#define REG_F0_REG_MASK 0x7FF
-#define REG_F1_MISC_MASK 0x1FFFF
-
-/* as of sdiod rev 0, supports 3 functions */
-#define SBSDIO_NUM_FUNCTION 3
-
-/* function 0 vendor specific CCCR registers */
-#define SDIO_CCCR_BRCM_CARDCAP 0xf0
-#define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02
-#define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04
-#define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08
-#define SDIO_CCCR_BRCM_CARDCTRL 0xf1
-#define SDIO_CCCR_BRCM_CARDCTRL_WLANRESET 0x02
-#define SDIO_CCCR_BRCM_SEPINT 0xf2
-
-#define SDIO_SEPINT_MASK 0x01
-#define SDIO_SEPINT_OE 0x02
-#define SDIO_SEPINT_ACT_HI 0x04
-
-/* function 1 miscellaneous registers */
-
-/* sprom command and status */
-#define SBSDIO_SPROM_CS 0x10000
-/* sprom info register */
-#define SBSDIO_SPROM_INFO 0x10001
-/* sprom indirect access data byte 0 */
-#define SBSDIO_SPROM_DATA_LOW 0x10002
-/* sprom indirect access data byte 1 */
-#define SBSDIO_SPROM_DATA_HIGH 0x10003
-/* sprom indirect access addr byte 0 */
-#define SBSDIO_SPROM_ADDR_LOW 0x10004
-/* gpio select */
-#define SBSDIO_GPIO_SELECT 0x10005
-/* gpio output */
-#define SBSDIO_GPIO_OUT 0x10006
-/* gpio enable */
-#define SBSDIO_GPIO_EN 0x10007
-/* rev < 7, watermark for sdio device */
-#define SBSDIO_WATERMARK 0x10008
-/* control busy signal generation */
-#define SBSDIO_DEVICE_CTL 0x10009
-
-/* SB Address Window Low (b15) */
-#define SBSDIO_FUNC1_SBADDRLOW 0x1000A
-/* SB Address Window Mid (b23:b16) */
-#define SBSDIO_FUNC1_SBADDRMID 0x1000B
-/* SB Address Window High (b31:b24) */
-#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C
-/* Frame Control (frame term/abort) */
-#define SBSDIO_FUNC1_FRAMECTRL 0x1000D
-/* ChipClockCSR (ALP/HT ctl/status) */
-#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E
-/* SdioPullUp (on cmd, d0-d2) */
-#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F
-/* Write Frame Byte Count Low */
-#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019
-/* Write Frame Byte Count High */
-#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A
-/* Read Frame Byte Count Low */
-#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
-/* Read Frame Byte Count High */
-#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
-/* MesBusyCtl (rev 11) */
-#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D
-/* Sdio Core Rev 12 */
-#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E
-#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1
-#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0
-#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2
-#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1
-#define SBSDIO_FUNC1_SLEEPCSR 0x1001F
-#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1
-#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0
-#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1
-#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2
-#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1
-
-#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
-#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001F /* f1 misc register end */
-
-/* function 1 OCP space */
-
-/* sb offset addr is <= 15 bits, 32k */
-#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
-#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
-/* with b15, maps to 32-bit SB access */
-#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
-
-/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
-
-#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
-#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
-#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
-/* Address bits from SBADDR regs */
-#define SBSDIO_SBWINDOW_MASK 0xffff8000
-
-#define SDIOH_READ 0 /* Read request */
-#define SDIOH_WRITE 1 /* Write request */
-
-#define SDIOH_DATA_FIX 0 /* Fixed addressing */
-#define SDIOH_DATA_INC 1 /* Incremental addressing */
-
-/* internal return code */
-#define SUCCESS 0
-#define ERROR 1
-
-/* Packet alignment for most efficient SDIO (can change based on platform) */
-#define BRCMF_SDALIGN (1 << 6)
-
-/* watchdog polling interval in ms */
-#define BRCMF_WD_POLL_MS 10
-
-struct brcmf_sdreg {
- int func;
- int offset;
- int value;
-};
-
-struct brcmf_sdio;
-
-struct brcmf_sdio_dev {
- struct sdio_func *func[SDIO_MAX_FUNCS];
- u8 num_funcs; /* Supported funcs on client */
- u32 sbwad; /* Save backplane window address */
- struct brcmf_sdio *bus;
- atomic_t suspend; /* suspend flag */
- wait_queue_head_t request_word_wait;
- wait_queue_head_t request_buffer_wait;
- struct device *dev;
- struct brcmf_bus *bus_if;
- struct brcmfmac_sdio_platform_data *pdata;
- bool oob_irq_requested;
- bool irq_en; /* irq enable flags */
- spinlock_t irq_en_lock;
- bool irq_wake; /* irq wake enable flags */
- bool sg_support;
- uint max_request_size;
- ushort max_segment_count;
- uint max_segment_size;
- uint txglomsz;
- struct sg_table sgtable;
- char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
- char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
-};
-
-/* sdio core registers */
-struct sdpcmd_regs {
- u32 corecontrol; /* 0x00, rev8 */
- u32 corestatus; /* rev8 */
- u32 PAD[1];
- u32 biststatus; /* rev8 */
-
- /* PCMCIA access */
- u16 pcmciamesportaladdr; /* 0x010, rev8 */
- u16 PAD[1];
- u16 pcmciamesportalmask; /* rev8 */
- u16 PAD[1];
- u16 pcmciawrframebc; /* rev8 */
- u16 PAD[1];
- u16 pcmciaunderflowtimer; /* rev8 */
- u16 PAD[1];
-
- /* interrupt */
- u32 intstatus; /* 0x020, rev8 */
- u32 hostintmask; /* rev8 */
- u32 intmask; /* rev8 */
- u32 sbintstatus; /* rev8 */
- u32 sbintmask; /* rev8 */
- u32 funcintmask; /* rev4 */
- u32 PAD[2];
- u32 tosbmailbox; /* 0x040, rev8 */
- u32 tohostmailbox; /* rev8 */
- u32 tosbmailboxdata; /* rev8 */
- u32 tohostmailboxdata; /* rev8 */
-
- /* synchronized access to registers in SDIO clock domain */
- u32 sdioaccess; /* 0x050, rev8 */
- u32 PAD[3];
-
- /* PCMCIA frame control */
- u8 pcmciaframectrl; /* 0x060, rev8 */
- u8 PAD[3];
- u8 pcmciawatermark; /* rev8 */
- u8 PAD[155];
-
- /* interrupt batching control */
- u32 intrcvlazy; /* 0x100, rev8 */
- u32 PAD[3];
-
- /* counters */
- u32 cmd52rd; /* 0x110, rev8 */
- u32 cmd52wr; /* rev8 */
- u32 cmd53rd; /* rev8 */
- u32 cmd53wr; /* rev8 */
- u32 abort; /* rev8 */
- u32 datacrcerror; /* rev8 */
- u32 rdoutofsync; /* rev8 */
- u32 wroutofsync; /* rev8 */
- u32 writebusy; /* rev8 */
- u32 readwait; /* rev8 */
- u32 readterm; /* rev8 */
- u32 writeterm; /* rev8 */
- u32 PAD[40];
- u32 clockctlstatus; /* rev8 */
- u32 PAD[7];
-
- u32 PAD[128]; /* DMA engines */
-
- /* SDIO/PCMCIA CIS region */
- char cis[512]; /* 0x400-0x5ff, rev6 */
-
- /* PCMCIA function control registers */
- char pcmciafcr[256]; /* 0x600-6ff, rev6 */
- u16 PAD[55];
-
- /* PCMCIA backplane access */
- u16 backplanecsr; /* 0x76E, rev6 */
- u16 backplaneaddr0; /* rev6 */
- u16 backplaneaddr1; /* rev6 */
- u16 backplaneaddr2; /* rev6 */
- u16 backplaneaddr3; /* rev6 */
- u16 backplanedata0; /* rev6 */
- u16 backplanedata1; /* rev6 */
- u16 backplanedata2; /* rev6 */
- u16 backplanedata3; /* rev6 */
- u16 PAD[31];
-
- /* sprom "size" & "blank" info */
- u16 spromstatus; /* 0x7BE, rev2 */
- u32 PAD[464];
-
- u16 PAD[0x80];
-};
-
-/* Register/deregister interrupt handler. */
-int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev);
-int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);
-
-/* sdio device register access interface */
-u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
-u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
-void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data,
- int *ret);
-void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data,
- int *ret);
-
-/* Buffer transfer to/from device (client) core via cmd53.
- * fn: function number
- * flags: backplane width, address increment, sync/async
- * buf: pointer to memory data buffer
- * nbytes: number of bytes to transfer to/from buf
- * pkt: pointer to packet associated with buf (if any)
- * complete: callback function for command completion (async only)
- * handle: handle for completion callback (first arg in callback)
- * Returns 0 or error code.
- * NOTE: Async operation is not currently supported.
- */
-int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev,
- struct sk_buff_head *pktq);
-int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
-
-int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt);
-int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes);
-int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
- struct sk_buff_head *pktq, uint totlen);
-
-/* Flags bits */
-
-/* Four-byte target (backplane) width (vs. two-byte) */
-#define SDIO_REQ_4BYTE 0x1
-/* Fixed address (FIFO) (vs. incrementing address) */
-#define SDIO_REQ_FIXED 0x2
-
-/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only).
- * rw: read or write (0/1)
- * addr: direct SDIO address
- * buf: pointer to memory data buffer
- * nbytes: number of bytes to transfer to/from buf
- * Returns 0 or error code.
- */
-int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
- u8 *data, uint size);
-
-/* Issue an abort to the specified function */
-int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
-
-struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
-void brcmf_sdio_remove(struct brcmf_sdio *bus);
-void brcmf_sdio_isr(struct brcmf_sdio *bus);
-
-void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
-
-#endif /* _BRCM_SDH_H_ */
#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
#include "tracepoint.h"
+
+void __brcmf_err(const char *func, const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ pr_err("%s: %pV", func, &vaf);
+ trace_brcmf_err(func, &vaf);
+ va_end(args);
+}
+
#endif
#include <brcmu_utils.h>
#include <brcm_hw_ids.h>
#include <brcmu_wifi.h>
-#include <dhd_bus.h>
-#include <dhd_dbg.h>
-
+#include "bus.h"
+#include "debug.h"
#include "firmware.h"
-#include "usb_rdl.h"
#include "usb.h"
+
#define IOCTL_RESP_TIMEOUT 2000
#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */
#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin"
#define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin"
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+#define TRX_MAX_OFFSET 3 /* Max number of file offsets */
+#define TRX_UNCOMP_IMAGE 0x20 /* Trx holds uncompressed img */
+#define TRX_RDL_CHUNK 1500 /* size of each dl transfer */
+#define TRX_OFFSETS_DLFWLEN_IDX 0
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE 0 /* returns the rdl_state_t struct */
+#define DL_CHECK_CRC 1 /* currently unused */
+#define DL_GO 2 /* execute downloaded image */
+#define DL_START 3 /* initialize dl state */
+#define DL_REBOOT 4 /* reboot the device in 2 seconds */
+#define DL_GETVER 5 /* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset
+ * event to occur in 2 seconds. It is the
+ * responsibility of the downloaded code to
+ * clear this event
+ */
+#define DL_EXEC 7 /* jump to a supplied address */
+#define DL_RESETCFG 8 /* To support single enum on dongle
+ * - Not used by bootloader
+ */
+#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup
+ * if resp unavailable
+ */
+
+/* states */
+#define DL_WAITING 0 /* waiting to rx first pkt */
+#define DL_READY 1 /* hdr was good, waiting for more of the
+ * compressed image
+ */
+#define DL_BAD_HDR 2 /* hdr was corrupted */
+#define DL_BAD_CRC 3 /* compressed image was corrupted */
+#define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */
+#define DL_START_FAIL 5 /* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM
+ * value
+ */
+#define DL_IMAGE_TOOBIG 7 /* firmware image too big */
+
+
+struct trx_header_le {
+ __le32 magic; /* "HDR0" */
+ __le32 len; /* Length of file including header */
+ __le32 crc32; /* CRC from flag_version to end of file */
+ __le32 flag_version; /* 0:15 flags, 16:31 version */
+ __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
+ * header
+ */
+};
+
+struct rdl_state_le {
+ __le32 state;
+ __le32 bytes;
+};
+
+struct bootrom_id_le {
+ __le32 chip; /* Chip id */
+ __le32 chiprev; /* Chip rev */
+ __le32 ramsize; /* Size of RAM */
+ __le32 remapbase; /* Current remap base address */
+ __le32 boardtype; /* Type of board */
+ __le32 boardrev; /* Board revision */
+};
+
struct brcmf_usb_image {
struct list_head list;
s8 *fwname;
u8 ifnum;
struct urb *bulk_urb; /* used for FW download */
+
+ bool wowl_enabled;
};
static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
return 0;
}
+static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
+{
+ if (devinfo->ctl_urb)
+ usb_kill_urb(devinfo->ctl_urb);
+ if (devinfo->bulk_urb)
+ usb_kill_urb(devinfo->bulk_urb);
+ brcmf_usb_free_q(&devinfo->tx_postq, true);
+ brcmf_usb_free_q(&devinfo->rx_postq, true);
+}
+
static void brcmf_usb_down(struct device *dev)
{
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
- if (devinfo->ctl_urb)
- usb_kill_urb(devinfo->ctl_urb);
-
- if (devinfo->bulk_urb)
- usb_kill_urb(devinfo->bulk_urb);
- brcmf_usb_free_q(&devinfo->tx_postq, true);
-
- brcmf_usb_free_q(&devinfo->rx_postq, true);
+ brcmf_cancel_all_urbs(devinfo);
}
static void
brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
- bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+ bulkchunk = kmalloc(TRX_RDL_CHUNK, GFP_ATOMIC);
if (bulkchunk == NULL) {
err = -ENOMEM;
goto fail;
/* Wait until the usb device reports it received all
* the bytes we sent */
if ((rdlbytes == sent) && (rdlbytes != dllen)) {
- if ((dllen-sent) < RDL_CHUNK)
+ if ((dllen-sent) < TRX_RDL_CHUNK)
sendlen = dllen-sent;
else
- sendlen = RDL_CHUNK;
+ sendlen = TRX_RDL_CHUNK;
/* simply avoid having to send a ZLP by ensuring we
* never have an even
kfree(devinfo->rx_reqs);
}
-#define TRX_MAGIC 0x30524448 /* "HDR0" */
-#define TRX_VERSION 1 /* Version 1 */
-#define TRX_MAX_LEN 0x3B0000 /* Max length */
-#define TRX_NO_HEADER 1 /* Do not write TRX header */
-#define TRX_MAX_OFFSET 3 /* Max number of individual files */
-#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed image */
-
-struct trx_header_le {
- __le32 magic; /* "HDR0" */
- __le32 len; /* Length of file including header */
- __le32 crc32; /* CRC from flag_version to end of file */
- __le32 flag_version; /* 0:15 flags, 16:31 version */
- __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
- * header */
-};
static int check_file(const u8 *headers)
{
return NULL;
}
+static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
+{
+ struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+ brcmf_dbg(USB, "Configuring WOWL, enabled=%d\n", enabled);
+ devinfo->wowl_enabled = enabled;
+ if (enabled)
+ device_set_wakeup_enable(devinfo->dev, true);
+ else
+ device_set_wakeup_enable(devinfo->dev, false);
+}
+
static struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx,
.stop = brcmf_usb_down,
.txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt,
+ .wowl_config = brcmf_usb_wowl_config,
};
static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
bus->ops = &brcmf_usb_bus_ops;
bus->proto_type = BRCMF_PROTO_BCDC;
bus->always_use_fws_queue = true;
+#ifdef CONFIG_PM
+ bus->wowl_supported = true;
+#endif
if (!brcmf_usb_dlneeded(devinfo)) {
ret = brcmf_usb_bus_setup(devinfo);
brcmf_dbg(USB, "Enter\n");
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
- brcmf_detach(&usb->dev);
+ if (devinfo->wowl_enabled)
+ brcmf_cancel_all_urbs(devinfo);
+ else
+ brcmf_detach(&usb->dev);
return 0;
}
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
brcmf_dbg(USB, "Enter\n");
- return brcmf_usb_bus_setup(devinfo);
+ if (!devinfo->wowl_enabled)
+ return brcmf_usb_bus_setup(devinfo);
+
+ devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
+ brcmf_usb_rx_fill_all(devinfo);
+ return 0;
}
static int brcmf_usb_reset_resume(struct usb_interface *intf)
+++ /dev/null
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _USB_RDL_H
-#define _USB_RDL_H
-
-/* Control messages: bRequest values */
-#define DL_GETSTATE 0 /* returns the rdl_state_t struct */
-#define DL_CHECK_CRC 1 /* currently unused */
-#define DL_GO 2 /* execute downloaded image */
-#define DL_START 3 /* initialize dl state */
-#define DL_REBOOT 4 /* reboot the device in 2 seconds */
-#define DL_GETVER 5 /* returns the bootrom_id_t struct */
-#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset
- * event to occur in 2 seconds. It is the
- * responsibility of the downloaded code to
- * clear this event
- */
-#define DL_EXEC 7 /* jump to a supplied address */
-#define DL_RESETCFG 8 /* To support single enum on dongle
- * - Not used by bootloader
- */
-#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup
- * if resp unavailable
- */
-
-/* states */
-#define DL_WAITING 0 /* waiting to rx first pkt */
-#define DL_READY 1 /* hdr was good, waiting for more of the
- * compressed image */
-#define DL_BAD_HDR 2 /* hdr was corrupted */
-#define DL_BAD_CRC 3 /* compressed image was corrupted */
-#define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */
-#define DL_START_FAIL 5 /* failed to initialize correctly */
-#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM
- * value */
-#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START
- * for rdl) */
-
-struct rdl_state_le {
- __le32 state;
- __le32 bytes;
-};
-
-struct bootrom_id_le {
- __le32 chip; /* Chip id */
- __le32 chiprev; /* Chip rev */
- __le32 ramsize; /* Size of RAM */
- __le32 remapbase; /* Current remap base address */
- __le32 boardtype; /* Type of board */
- __le32 boardrev; /* Board revision */
-};
-
-#define RDL_CHUNK 1500 /* size of each dl transfer */
-
-#define TRX_OFFSETS_DLFWLEN_IDX 0
-#define TRX_OFFSETS_JUMPTO_IDX 1
-#define TRX_OFFSETS_NVM_LEN_IDX 2
-
-#define TRX_OFFSETS_DLBASE_IDX 0
-
-#endif /* _USB_RDL_H */
#include <brcmu_wifi.h>
#include "fwil_types.h"
-#include "dhd.h"
+#include "core.h"
#include "p2p.h"
-#include "dhd_dbg.h"
-#include "wl_cfg80211.h"
+#include "debug.h"
+#include "cfg80211.h"
#include "vendor.h"
#include "fwil.h"
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
-
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <net/cfg80211.h>
-#include <net/netlink.h>
-
-#include <brcmu_utils.h>
-#include <defs.h>
-#include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
-#include "tracepoint.h"
-#include "fwil_types.h"
-#include "p2p.h"
-#include "btcoex.h"
-#include "wl_cfg80211.h"
-#include "feature.h"
-#include "fwil.h"
-#include "proto.h"
-#include "vendor.h"
-#include "dhd_bus.h"
-
-#define BRCMF_SCAN_IE_LEN_MAX 2048
-#define BRCMF_PNO_VERSION 2
-#define BRCMF_PNO_TIME 30
-#define BRCMF_PNO_REPEAT 4
-#define BRCMF_PNO_FREQ_EXPO_MAX 3
-#define BRCMF_PNO_MAX_PFN_COUNT 16
-#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6
-#define BRCMF_PNO_HIDDEN_BIT 2
-#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF
-#define BRCMF_PNO_SCAN_COMPLETE 1
-#define BRCMF_PNO_SCAN_INCOMPLETE 0
-
-#define BRCMF_IFACE_MAX_CNT 3
-
-#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
-#define WPA_OUI_TYPE 1
-#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
-#define WME_OUI_TYPE 2
-#define WPS_OUI_TYPE 4
-
-#define VS_IE_FIXED_HDR_LEN 6
-#define WPA_IE_VERSION_LEN 2
-#define WPA_IE_MIN_OUI_LEN 4
-#define WPA_IE_SUITE_COUNT_LEN 2
-
-#define WPA_CIPHER_NONE 0 /* None */
-#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */
-#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */
-#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */
-#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */
-
-#define RSN_AKM_NONE 0 /* None (IBSS) */
-#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
-#define RSN_AKM_PSK 2 /* Pre-shared Key */
-#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
-#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
-
-#define VNDR_IE_CMD_LEN 4 /* length of the set command
- * string :"add", "del" (+ NUL)
- */
-#define VNDR_IE_COUNT_OFFSET 4
-#define VNDR_IE_PKTFLAG_OFFSET 8
-#define VNDR_IE_VSIE_OFFSET 12
-#define VNDR_IE_HDR_SIZE 12
-#define VNDR_IE_PARSE_LIMIT 5
-
-#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
-#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
-
-#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
-#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
-#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
-
-#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
- (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
-
-static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
-{
- if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
- brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
- vif->sme_state);
- return false;
- }
- return true;
-}
-
-#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
-#define RATETAB_ENT(_rateid, _flags) \
- { \
- .bitrate = RATE_TO_BASE100KBPS(_rateid), \
- .hw_value = (_rateid), \
- .flags = (_flags), \
- }
-
-static struct ieee80211_rate __wl_rates[] = {
- RATETAB_ENT(BRCM_RATE_1M, 0),
- RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
- RATETAB_ENT(BRCM_RATE_6M, 0),
- RATETAB_ENT(BRCM_RATE_9M, 0),
- RATETAB_ENT(BRCM_RATE_12M, 0),
- RATETAB_ENT(BRCM_RATE_18M, 0),
- RATETAB_ENT(BRCM_RATE_24M, 0),
- RATETAB_ENT(BRCM_RATE_36M, 0),
- RATETAB_ENT(BRCM_RATE_48M, 0),
- RATETAB_ENT(BRCM_RATE_54M, 0),
-};
-
-#define wl_a_rates (__wl_rates + 4)
-#define wl_a_rates_size 8
-#define wl_g_rates (__wl_rates + 0)
-#define wl_g_rates_size 12
-
-/* Band templates duplicated per wiphy. The channel info
- * is filled in after querying the device.
- */
-static const struct ieee80211_supported_band __wl_band_2ghz = {
- .band = IEEE80211_BAND_2GHZ,
- .bitrates = wl_g_rates,
- .n_bitrates = wl_g_rates_size,
-};
-
-static const struct ieee80211_supported_band __wl_band_5ghz_a = {
- .band = IEEE80211_BAND_5GHZ,
- .bitrates = wl_a_rates,
- .n_bitrates = wl_a_rates_size,
-};
-
-/* This is to override regulatory domains defined in cfg80211 module (reg.c)
- * By default world regulatory domain defined in reg.c puts the flags
- * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
- * With respect to these flags, wpa_supplicant doesn't * start p2p
- * operations on 5GHz channels. All the changes in world regulatory
- * domain are to be done here.
- */
-static const struct ieee80211_regdomain brcmf_regdom = {
- .n_reg_rules = 4,
- .alpha2 = "99",
- .reg_rules = {
- /* IEEE 802.11b/g, channels 1..11 */
- REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
- /* If any */
- /* IEEE 802.11 channel 14 - Only JP enables
- * this and for 802.11b only
- */
- REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
- /* IEEE 802.11a, channel 36..64 */
- REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
- /* IEEE 802.11a, channel 100..165 */
- REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
-};
-
-static const u32 __wl_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
- WLAN_CIPHER_SUITE_AES_CMAC,
-};
-
-/* Vendor specific ie. id = 221, oui and type defines exact ie */
-struct brcmf_vs_tlv {
- u8 id;
- u8 len;
- u8 oui[3];
- u8 oui_type;
-};
-
-struct parsed_vndr_ie_info {
- u8 *ie_ptr;
- u32 ie_len; /* total length including id & length field */
- struct brcmf_vs_tlv vndrie;
-};
-
-struct parsed_vndr_ies {
- u32 count;
- struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
-};
-
-static int brcmf_roamoff;
-module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
-MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
-
-/* Quarter dBm units to mW
- * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
- * Table is offset so the last entry is largest mW value that fits in
- * a u16.
- */
-
-#define QDBM_OFFSET 153 /* Offset for first entry */
-#define QDBM_TABLE_LEN 40 /* Table size */
-
-/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
- * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
- */
-#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
-
-/* Largest mW value that will round down to the last table entry,
- * QDBM_OFFSET + QDBM_TABLE_LEN-1.
- * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
- * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
- */
-#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
-
-static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
-/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
-/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
-/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
-/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
-/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
-/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
-};
-
-static u16 brcmf_qdbm_to_mw(u8 qdbm)
-{
- uint factor = 1;
- int idx = qdbm - QDBM_OFFSET;
-
- if (idx >= QDBM_TABLE_LEN)
- /* clamp to max u16 mW value */
- return 0xFFFF;
-
- /* scale the qdBm index up to the range of the table 0-40
- * where an offset of 40 qdBm equals a factor of 10 mW.
- */
- while (idx < 0) {
- idx += 40;
- factor *= 10;
- }
-
- /* return the mW value scaled down to the correct factor of 10,
- * adding in factor/2 to get proper rounding.
- */
- return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
-}
-
-static u8 brcmf_mw_to_qdbm(u16 mw)
-{
- u8 qdbm;
- int offset;
- uint mw_uint = mw;
- uint boundary;
-
- /* handle boundary case */
- if (mw_uint <= 1)
- return 0;
-
- offset = QDBM_OFFSET;
-
- /* move mw into the range of the table */
- while (mw_uint < QDBM_TABLE_LOW_BOUND) {
- mw_uint *= 10;
- offset -= 40;
- }
-
- for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
- boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
- nqdBm_to_mW_map[qdbm]) / 2;
- if (mw_uint < boundary)
- break;
- }
-
- qdbm += (u8) offset;
-
- return qdbm;
-}
-
-static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
- struct cfg80211_chan_def *ch)
-{
- struct brcmu_chan ch_inf;
- s32 primary_offset;
-
- brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
- ch->chan->center_freq, ch->center_freq1, ch->width);
- ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
- primary_offset = ch->center_freq1 - ch->chan->center_freq;
- switch (ch->width) {
- case NL80211_CHAN_WIDTH_20:
- ch_inf.bw = BRCMU_CHAN_BW_20;
- WARN_ON(primary_offset != 0);
- break;
- case NL80211_CHAN_WIDTH_40:
- ch_inf.bw = BRCMU_CHAN_BW_40;
- if (primary_offset < 0)
- ch_inf.sb = BRCMU_CHAN_SB_U;
- else
- ch_inf.sb = BRCMU_CHAN_SB_L;
- break;
- case NL80211_CHAN_WIDTH_80:
- ch_inf.bw = BRCMU_CHAN_BW_80;
- if (primary_offset < 0) {
- if (primary_offset < -CH_10MHZ_APART)
- ch_inf.sb = BRCMU_CHAN_SB_UU;
- else
- ch_inf.sb = BRCMU_CHAN_SB_UL;
- } else {
- if (primary_offset > CH_10MHZ_APART)
- ch_inf.sb = BRCMU_CHAN_SB_LL;
- else
- ch_inf.sb = BRCMU_CHAN_SB_LU;
- }
- break;
- default:
- WARN_ON_ONCE(1);
- }
- switch (ch->chan->band) {
- case IEEE80211_BAND_2GHZ:
- ch_inf.band = BRCMU_CHAN_BAND_2G;
- break;
- case IEEE80211_BAND_5GHZ:
- ch_inf.band = BRCMU_CHAN_BAND_5G;
- break;
- default:
- WARN_ON_ONCE(1);
- }
- d11inf->encchspec(&ch_inf);
-
- return ch_inf.chspec;
-}
-
-u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
- struct ieee80211_channel *ch)
-{
- struct brcmu_chan ch_inf;
-
- ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
- ch_inf.bw = BRCMU_CHAN_BW_20;
- d11inf->encchspec(&ch_inf);
-
- return ch_inf.chspec;
-}
-
-/* Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
- */
-const struct brcmf_tlv *
-brcmf_parse_tlvs(const void *buf, int buflen, uint key)
-{
- const struct brcmf_tlv *elt = buf;
- int totlen = buflen;
-
- /* find tagged parameter */
- while (totlen >= TLV_HDR_LEN) {
- int len = elt->len;
-
- /* validate remaining totlen */
- if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
- return elt;
-
- elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
- totlen -= (len + TLV_HDR_LEN);
- }
-
- return NULL;
-}
-
-/* Is any of the tlvs the expected entry? If
- * not update the tlvs buffer pointer/length.
- */
-static bool
-brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
- const u8 *oui, u32 oui_len, u8 type)
-{
- /* If the contents match the OUI and the type */
- if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
- !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
- type == ie[TLV_BODY_OFF + oui_len]) {
- return true;
- }
-
- if (tlvs == NULL)
- return false;
- /* point to the next ie */
- ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
- /* calculate the length of the rest of the buffer */
- *tlvs_len -= (int)(ie - *tlvs);
- /* update the pointer to the start of the buffer */
- *tlvs = ie;
-
- return false;
-}
-
-static struct brcmf_vs_tlv *
-brcmf_find_wpaie(const u8 *parse, u32 len)
-{
- const struct brcmf_tlv *ie;
-
- while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
- if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
- WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
- return (struct brcmf_vs_tlv *)ie;
- }
- return NULL;
-}
-
-static struct brcmf_vs_tlv *
-brcmf_find_wpsie(const u8 *parse, u32 len)
-{
- const struct brcmf_tlv *ie;
-
- while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
- if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
- WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
- return (struct brcmf_vs_tlv *)ie;
- }
- return NULL;
-}
-
-
-static void convert_key_from_CPU(struct brcmf_wsec_key *key,
- struct brcmf_wsec_key_le *key_le)
-{
- key_le->index = cpu_to_le32(key->index);
- key_le->len = cpu_to_le32(key->len);
- key_le->algo = cpu_to_le32(key->algo);
- key_le->flags = cpu_to_le32(key->flags);
- key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
- key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
- key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
- memcpy(key_le->data, key->data, sizeof(key->data));
- memcpy(key_le->ea, key->ea, sizeof(key->ea));
-}
-
-static int
-send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
-{
- int err;
- struct brcmf_wsec_key_le key_le;
-
- convert_key_from_CPU(key, &key_le);
-
- brcmf_netdev_wait_pend8021x(ndev);
-
- err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
- sizeof(key_le));
-
- if (err)
- brcmf_err("wsec_key error (%d)\n", err);
- return err;
-}
-
-static s32
-brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
-{
- s32 err;
- u32 mode;
-
- if (enable)
- mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
- else
- mode = 0;
-
- /* Try to set and enable ARP offload feature, this may fail, then it */
- /* is simply not supported and err 0 will be returned */
- err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
- if (err) {
- brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
- mode, err);
- err = 0;
- } else {
- err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
- if (err) {
- brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
- enable, err);
- err = 0;
- } else
- brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
- enable, mode);
- }
-
- return err;
-}
-
-static void
-brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
-{
- struct brcmf_cfg80211_vif *vif;
- struct brcmf_if *ifp;
-
- vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
- ifp = vif->ifp;
-
- if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
- (wdev->iftype == NL80211_IFTYPE_AP) ||
- (wdev->iftype == NL80211_IFTYPE_P2P_GO))
- brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
- ADDR_DIRECT);
- else
- brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
- ADDR_INDIRECT);
-}
-
-static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
-{
- enum nl80211_iftype iftype;
-
- iftype = vif->wdev.iftype;
- return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
-}
-
-static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
-{
- return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
-}
-
-static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
- const char *name,
- enum nl80211_iftype type,
- u32 *flags,
- struct vif_params *params)
-{
- struct wireless_dev *wdev;
-
- brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_MESH_POINT:
- return ERR_PTR(-EOPNOTSUPP);
- case NL80211_IFTYPE_P2P_CLIENT:
- case NL80211_IFTYPE_P2P_GO:
- case NL80211_IFTYPE_P2P_DEVICE:
- wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params);
- if (!IS_ERR(wdev))
- brcmf_cfg80211_update_proto_addr_mode(wdev);
- return wdev;
- case NL80211_IFTYPE_UNSPECIFIED:
- default:
- return ERR_PTR(-EINVAL);
- }
-}
-
-static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
-{
- if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
- brcmf_set_mpc(ifp, mpc);
-}
-
-void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
-{
- s32 err = 0;
-
- if (check_vif_up(ifp->vif)) {
- err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
- if (err) {
- brcmf_err("fail to set mpc\n");
- return;
- }
- brcmf_dbg(INFO, "MPC : %d\n", mpc);
- }
-}
-
-s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp, bool aborted,
- bool fw_abort)
-{
- struct brcmf_scan_params_le params_le;
- struct cfg80211_scan_request *scan_request;
- s32 err = 0;
-
- brcmf_dbg(SCAN, "Enter\n");
-
- /* clear scan request, because the FW abort can cause a second call */
- /* to this functon and might cause a double cfg80211_scan_done */
- scan_request = cfg->scan_request;
- cfg->scan_request = NULL;
-
- if (timer_pending(&cfg->escan_timeout))
- del_timer_sync(&cfg->escan_timeout);
-
- if (fw_abort) {
- /* Do a scan abort to stop the driver's scan engine */
- brcmf_dbg(SCAN, "ABORT scan in firmware\n");
- memset(¶ms_le, 0, sizeof(params_le));
- memset(params_le.bssid, 0xFF, ETH_ALEN);
- params_le.bss_type = DOT11_BSSTYPE_ANY;
- params_le.scan_type = 0;
- params_le.channel_num = cpu_to_le32(1);
- params_le.nprobes = cpu_to_le32(1);
- params_le.active_time = cpu_to_le32(-1);
- params_le.passive_time = cpu_to_le32(-1);
- params_le.home_time = cpu_to_le32(-1);
- /* Scan is aborted by setting channel_list[0] to -1 */
- params_le.channel_list[0] = cpu_to_le16(-1);
- /* E-Scan (or anyother type) can be aborted by SCAN */
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
- ¶ms_le, sizeof(params_le));
- if (err)
- brcmf_err("Scan abort failed\n");
- }
-
- brcmf_scan_config_mpc(ifp, 1);
-
- /*
- * e-scan can be initiated by scheduled scan
- * which takes precedence.
- */
- if (cfg->sched_escan) {
- brcmf_dbg(SCAN, "scheduled scan completed\n");
- cfg->sched_escan = false;
- if (!aborted)
- cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
- } else if (scan_request) {
- brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
- aborted ? "Aborted" : "Done");
- cfg80211_scan_done(scan_request, aborted);
- }
- if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
- brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
-
- return err;
-}
-
-static
-int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct net_device *ndev = wdev->netdev;
-
- /* vif event pending in firmware */
- if (brcmf_cfg80211_vif_event_armed(cfg))
- return -EBUSY;
-
- if (ndev) {
- if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
- cfg->escan_info.ifp == netdev_priv(ndev))
- brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
- true, true);
-
- brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
- }
-
- switch (wdev->iftype) {
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_MESH_POINT:
- return -EOPNOTSUPP;
- case NL80211_IFTYPE_P2P_CLIENT:
- case NL80211_IFTYPE_P2P_GO:
- case NL80211_IFTYPE_P2P_DEVICE:
- return brcmf_p2p_del_vif(wiphy, wdev);
- case NL80211_IFTYPE_UNSPECIFIED:
- default:
- return -EINVAL;
- }
- return -EOPNOTSUPP;
-}
-
-static s32
-brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
- enum nl80211_iftype type, u32 *flags,
- struct vif_params *params)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_vif *vif = ifp->vif;
- s32 infra = 0;
- s32 ap = 0;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
-
- switch (type) {
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_WDS:
- brcmf_err("type (%d) : currently we do not support this type\n",
- type);
- return -EOPNOTSUPP;
- case NL80211_IFTYPE_ADHOC:
- infra = 0;
- break;
- case NL80211_IFTYPE_STATION:
- /* Ignore change for p2p IF. Unclear why supplicant does this */
- if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
- (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
- brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
- /* WAR: It is unexpected to get a change of VIF for P2P
- * IF, but it happens. The request can not be handled
- * but returning EPERM causes a crash. Returning 0
- * without setting ieee80211_ptr->iftype causes trace
- * (WARN_ON) but it works with wpa_supplicant
- */
- return 0;
- }
- infra = 1;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
- ap = 1;
- break;
- default:
- err = -EINVAL;
- goto done;
- }
-
- if (ap) {
- if (type == NL80211_IFTYPE_P2P_GO) {
- brcmf_dbg(INFO, "IF Type = P2P GO\n");
- err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
- }
- if (!err) {
- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
- brcmf_dbg(INFO, "IF Type = AP\n");
- }
- } else {
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
- if (err) {
- brcmf_err("WLC_SET_INFRA error (%d)\n", err);
- err = -EAGAIN;
- goto done;
- }
- brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
- "Adhoc" : "Infra");
- }
- ndev->ieee80211_ptr->iftype = type;
-
- brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
-
- return err;
-}
-
-static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
- struct brcmf_scan_params_le *params_le,
- struct cfg80211_scan_request *request)
-{
- u32 n_ssids;
- u32 n_channels;
- s32 i;
- s32 offset;
- u16 chanspec;
- char *ptr;
- struct brcmf_ssid_le ssid_le;
-
- memset(params_le->bssid, 0xFF, ETH_ALEN);
- params_le->bss_type = DOT11_BSSTYPE_ANY;
- params_le->scan_type = 0;
- params_le->channel_num = 0;
- params_le->nprobes = cpu_to_le32(-1);
- params_le->active_time = cpu_to_le32(-1);
- params_le->passive_time = cpu_to_le32(-1);
- params_le->home_time = cpu_to_le32(-1);
- memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le));
-
- /* if request is null exit so it will be all channel broadcast scan */
- if (!request)
- return;
-
- n_ssids = request->n_ssids;
- n_channels = request->n_channels;
- /* Copy channel array if applicable */
- brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
- n_channels);
- if (n_channels > 0) {
- for (i = 0; i < n_channels; i++) {
- chanspec = channel_to_chanspec(&cfg->d11inf,
- request->channels[i]);
- brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
- request->channels[i]->hw_value, chanspec);
- params_le->channel_list[i] = cpu_to_le16(chanspec);
- }
- } else {
- brcmf_dbg(SCAN, "Scanning all channels\n");
- }
- /* Copy ssid array if applicable */
- brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
- if (n_ssids > 0) {
- offset = offsetof(struct brcmf_scan_params_le, channel_list) +
- n_channels * sizeof(u16);
- offset = roundup(offset, sizeof(u32));
- ptr = (char *)params_le + offset;
- for (i = 0; i < n_ssids; i++) {
- memset(&ssid_le, 0, sizeof(ssid_le));
- ssid_le.SSID_len =
- cpu_to_le32(request->ssids[i].ssid_len);
- memcpy(ssid_le.SSID, request->ssids[i].ssid,
- request->ssids[i].ssid_len);
- if (!ssid_le.SSID_len)
- brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
- else
- brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
- i, ssid_le.SSID, ssid_le.SSID_len);
- memcpy(ptr, &ssid_le, sizeof(ssid_le));
- ptr += sizeof(ssid_le);
- }
- } else {
- brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
- if ((request->ssids) && request->ssids->ssid_len) {
- brcmf_dbg(SCAN, "SSID %s len=%d\n",
- params_le->ssid_le.SSID,
- request->ssids->ssid_len);
- params_le->ssid_le.SSID_len =
- cpu_to_le32(request->ssids->ssid_len);
- memcpy(¶ms_le->ssid_le.SSID, request->ssids->ssid,
- request->ssids->ssid_len);
- }
- }
- /* Adding mask to channel numbers */
- params_le->channel_num =
- cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
- (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
-}
-
-static s32
-brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
- struct cfg80211_scan_request *request, u16 action)
-{
- s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
- offsetof(struct brcmf_escan_params_le, params_le);
- struct brcmf_escan_params_le *params;
- s32 err = 0;
-
- brcmf_dbg(SCAN, "E-SCAN START\n");
-
- if (request != NULL) {
- /* Allocate space for populating ssids in struct */
- params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
-
- /* Allocate space for populating ssids in struct */
- params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
- }
-
- params = kzalloc(params_size, GFP_KERNEL);
- if (!params) {
- err = -ENOMEM;
- goto exit;
- }
- BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
- brcmf_escan_prep(cfg, ¶ms->params_le, request);
- params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
- params->action = cpu_to_le16(action);
- params->sync_id = cpu_to_le16(0x1234);
-
- err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
- if (err) {
- if (err == -EBUSY)
- brcmf_dbg(INFO, "system busy : escan canceled\n");
- else
- brcmf_err("error (%d)\n", err);
- }
-
- kfree(params);
-exit:
- return err;
-}
-
-static s32
-brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
- struct brcmf_if *ifp, struct cfg80211_scan_request *request)
-{
- s32 err;
- u32 passive_scan;
- struct brcmf_scan_results *results;
- struct escan_info *escan = &cfg->escan_info;
-
- brcmf_dbg(SCAN, "Enter\n");
- escan->ifp = ifp;
- escan->wiphy = wiphy;
- escan->escan_state = WL_ESCAN_STATE_SCANNING;
- passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
- passive_scan);
- if (err) {
- brcmf_err("error (%d)\n", err);
- return err;
- }
- brcmf_scan_config_mpc(ifp, 0);
- results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
- results->version = 0;
- results->count = 0;
- results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
-
- err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
- if (err)
- brcmf_scan_config_mpc(ifp, 1);
- return err;
-}
-
-static s32
-brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
- struct cfg80211_scan_request *request,
- struct cfg80211_ssid *this_ssid)
-{
- struct brcmf_if *ifp = vif->ifp;
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct cfg80211_ssid *ssids;
- struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
- u32 passive_scan;
- bool escan_req;
- bool spec_scan;
- s32 err;
- u32 SSID_len;
-
- brcmf_dbg(SCAN, "START ESCAN\n");
-
- if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
- return -EAGAIN;
- }
- if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
- brcmf_err("Scanning being aborted: status (%lu)\n",
- cfg->scan_status);
- return -EAGAIN;
- }
- if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
- brcmf_err("Scanning suppressed: status (%lu)\n",
- cfg->scan_status);
- return -EAGAIN;
- }
- if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
- brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
- return -EAGAIN;
- }
-
- /* If scan req comes for p2p0, send it over primary I/F */
- if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
- vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
-
- /* Arm scan timeout timer */
- mod_timer(&cfg->escan_timeout, jiffies +
- WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
-
- escan_req = false;
- if (request) {
- /* scan bss */
- ssids = request->ssids;
- escan_req = true;
- } else {
- /* scan in ibss */
- /* we don't do escan in ibss */
- ssids = this_ssid;
- }
-
- cfg->scan_request = request;
- set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- if (escan_req) {
- cfg->escan_info.run = brcmf_run_escan;
- err = brcmf_p2p_scan_prep(wiphy, request, vif);
- if (err)
- goto scan_out;
-
- err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
- if (err)
- goto scan_out;
- } else {
- brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
- ssids->ssid, ssids->ssid_len);
- memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
- SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
- sr->ssid_le.SSID_len = cpu_to_le32(0);
- spec_scan = false;
- if (SSID_len) {
- memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
- sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
- spec_scan = true;
- } else
- brcmf_dbg(SCAN, "Broadcast scan\n");
-
- passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
- passive_scan);
- if (err) {
- brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
- goto scan_out;
- }
- brcmf_scan_config_mpc(ifp, 0);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
- &sr->ssid_le, sizeof(sr->ssid_le));
- if (err) {
- if (err == -EBUSY)
- brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
- sr->ssid_le.SSID);
- else
- brcmf_err("WLC_SCAN error (%d)\n", err);
-
- brcmf_scan_config_mpc(ifp, 1);
- goto scan_out;
- }
- }
-
- return 0;
-
-scan_out:
- clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- if (timer_pending(&cfg->escan_timeout))
- del_timer_sync(&cfg->escan_timeout);
- cfg->scan_request = NULL;
- return err;
-}
-
-static s32
-brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
-{
- struct brcmf_cfg80211_vif *vif;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
- if (!check_vif_up(vif))
- return -EIO;
-
- err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
-
- if (err)
- brcmf_err("scan error (%d)\n", err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
-{
- s32 err = 0;
-
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
- rts_threshold);
- if (err)
- brcmf_err("Error (%d)\n", err);
-
- return err;
-}
-
-static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
-{
- s32 err = 0;
-
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
- frag_threshold);
- if (err)
- brcmf_err("Error (%d)\n", err);
-
- return err;
-}
-
-static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
-{
- s32 err = 0;
- u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
-
- err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
- if (err) {
- brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
- return err;
- }
- return err;
-}
-
-static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
- (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
- cfg->conf->rts_threshold = wiphy->rts_threshold;
- err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
- if (!err)
- goto done;
- }
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
- (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
- cfg->conf->frag_threshold = wiphy->frag_threshold;
- err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
- if (!err)
- goto done;
- }
- if (changed & WIPHY_PARAM_RETRY_LONG
- && (cfg->conf->retry_long != wiphy->retry_long)) {
- cfg->conf->retry_long = wiphy->retry_long;
- err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
- if (!err)
- goto done;
- }
- if (changed & WIPHY_PARAM_RETRY_SHORT
- && (cfg->conf->retry_short != wiphy->retry_short)) {
- cfg->conf->retry_short = wiphy->retry_short;
- err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
- if (!err)
- goto done;
- }
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
-{
- memset(prof, 0, sizeof(*prof));
-}
-
-static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
- brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
- err = brcmf_fil_cmd_data_set(vif->ifp,
- BRCMF_C_DISASSOC, NULL, 0);
- if (err) {
- brcmf_err("WLC_DISASSOC failed (%d)\n", err);
- }
- clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
- cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
-
- }
- clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
- clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
- brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
- brcmf_dbg(TRACE, "Exit\n");
-}
-
-static s32
-brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_ibss_params *params)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_join_params join_params;
- size_t join_params_size = 0;
- s32 err = 0;
- s32 wsec = 0;
- s32 bcnprd;
- u16 chanspec;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (params->ssid)
- brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
- else {
- brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
- return -EOPNOTSUPP;
- }
-
- set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
-
- if (params->bssid)
- brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
- else
- brcmf_dbg(CONN, "No BSSID specified\n");
-
- if (params->chandef.chan)
- brcmf_dbg(CONN, "channel: %d\n",
- params->chandef.chan->center_freq);
- else
- brcmf_dbg(CONN, "no channel specified\n");
-
- if (params->channel_fixed)
- brcmf_dbg(CONN, "fixed channel required\n");
- else
- brcmf_dbg(CONN, "no fixed channel required\n");
-
- if (params->ie && params->ie_len)
- brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
- else
- brcmf_dbg(CONN, "no ie specified\n");
-
- if (params->beacon_interval)
- brcmf_dbg(CONN, "beacon interval: %d\n",
- params->beacon_interval);
- else
- brcmf_dbg(CONN, "no beacon interval specified\n");
-
- if (params->basic_rates)
- brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
- else
- brcmf_dbg(CONN, "no basic rates specified\n");
-
- if (params->privacy)
- brcmf_dbg(CONN, "privacy required\n");
- else
- brcmf_dbg(CONN, "no privacy required\n");
-
- /* Configure Privacy for starter */
- if (params->privacy)
- wsec |= WEP_ENABLED;
-
- err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
- if (err) {
- brcmf_err("wsec failed (%d)\n", err);
- goto done;
- }
-
- /* Configure Beacon Interval for starter */
- if (params->beacon_interval)
- bcnprd = params->beacon_interval;
- else
- bcnprd = 100;
-
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
- if (err) {
- brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
- goto done;
- }
-
- /* Configure required join parameter */
- memset(&join_params, 0, sizeof(struct brcmf_join_params));
-
- /* SSID */
- profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
- memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
- memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
- join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
- join_params_size = sizeof(join_params.ssid_le);
-
- /* BSSID */
- if (params->bssid) {
- memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
- join_params_size = sizeof(join_params.ssid_le) +
- BRCMF_ASSOC_PARAMS_FIXED_SIZE;
- memcpy(profile->bssid, params->bssid, ETH_ALEN);
- } else {
- memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
- memset(profile->bssid, 0, ETH_ALEN);
- }
-
- /* Channel */
- if (params->chandef.chan) {
- u32 target_channel;
-
- cfg->channel =
- ieee80211_frequency_to_channel(
- params->chandef.chan->center_freq);
- if (params->channel_fixed) {
- /* adding chanspec */
- chanspec = chandef_to_chanspec(&cfg->d11inf,
- ¶ms->chandef);
- join_params.params_le.chanspec_list[0] =
- cpu_to_le16(chanspec);
- join_params.params_le.chanspec_num = cpu_to_le32(1);
- join_params_size += sizeof(join_params.params_le);
- }
-
- /* set channel for starter */
- target_channel = cfg->channel;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
- target_channel);
- if (err) {
- brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
- goto done;
- }
- } else
- cfg->channel = 0;
-
- cfg->ibss_starter = false;
-
-
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
- &join_params, join_params_size);
- if (err) {
- brcmf_err("WLC_SET_SSID failed (%d)\n", err);
- goto done;
- }
-
-done:
- if (err)
- clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- brcmf_link_down(ifp->vif);
-
- brcmf_dbg(TRACE, "Exit\n");
-
- return 0;
-}
-
-static s32 brcmf_set_wpa_version(struct net_device *ndev,
- struct cfg80211_connect_params *sme)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
- s32 val = 0;
- s32 err = 0;
-
- if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
- val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
- else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
- val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
- else
- val = WPA_AUTH_DISABLED;
- brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
- if (err) {
- brcmf_err("set wpa_auth failed (%d)\n", err);
- return err;
- }
- sec = &profile->sec;
- sec->wpa_versions = sme->crypto.wpa_versions;
- return err;
-}
-
-static s32 brcmf_set_auth_type(struct net_device *ndev,
- struct cfg80211_connect_params *sme)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
- s32 val = 0;
- s32 err = 0;
-
- switch (sme->auth_type) {
- case NL80211_AUTHTYPE_OPEN_SYSTEM:
- val = 0;
- brcmf_dbg(CONN, "open system\n");
- break;
- case NL80211_AUTHTYPE_SHARED_KEY:
- val = 1;
- brcmf_dbg(CONN, "shared key\n");
- break;
- case NL80211_AUTHTYPE_AUTOMATIC:
- val = 2;
- brcmf_dbg(CONN, "automatic\n");
- break;
- case NL80211_AUTHTYPE_NETWORK_EAP:
- brcmf_dbg(CONN, "network eap\n");
- default:
- val = 2;
- brcmf_err("invalid auth type (%d)\n", sme->auth_type);
- break;
- }
-
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
- if (err) {
- brcmf_err("set auth failed (%d)\n", err);
- return err;
- }
- sec = &profile->sec;
- sec->auth_type = sme->auth_type;
- return err;
-}
-
-static s32
-brcmf_set_wsec_mode(struct net_device *ndev,
- struct cfg80211_connect_params *sme, bool mfp)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
- s32 pval = 0;
- s32 gval = 0;
- s32 wsec;
- s32 err = 0;
-
- if (sme->crypto.n_ciphers_pairwise) {
- switch (sme->crypto.ciphers_pairwise[0]) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- pval = WEP_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- pval = TKIP_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- pval = AES_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- pval = AES_ENABLED;
- break;
- default:
- brcmf_err("invalid cipher pairwise (%d)\n",
- sme->crypto.ciphers_pairwise[0]);
- return -EINVAL;
- }
- }
- if (sme->crypto.cipher_group) {
- switch (sme->crypto.cipher_group) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- gval = WEP_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- gval = TKIP_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- gval = AES_ENABLED;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- gval = AES_ENABLED;
- break;
- default:
- brcmf_err("invalid cipher group (%d)\n",
- sme->crypto.cipher_group);
- return -EINVAL;
- }
- }
-
- brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
- /* In case of privacy, but no security and WPS then simulate */
- /* setting AES. WPS-2.0 allows no security */
- if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
- sme->privacy)
- pval = AES_ENABLED;
-
- if (mfp)
- wsec = pval | gval | MFP_CAPABLE;
- else
- wsec = pval | gval;
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
- if (err) {
- brcmf_err("error (%d)\n", err);
- return err;
- }
-
- sec = &profile->sec;
- sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
- sec->cipher_group = sme->crypto.cipher_group;
-
- return err;
-}
-
-static s32
-brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
- s32 val = 0;
- s32 err = 0;
-
- if (sme->crypto.n_akm_suites) {
- err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
- "wpa_auth", &val);
- if (err) {
- brcmf_err("could not get wpa_auth (%d)\n", err);
- return err;
- }
- if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
- switch (sme->crypto.akm_suites[0]) {
- case WLAN_AKM_SUITE_8021X:
- val = WPA_AUTH_UNSPECIFIED;
- break;
- case WLAN_AKM_SUITE_PSK:
- val = WPA_AUTH_PSK;
- break;
- default:
- brcmf_err("invalid cipher group (%d)\n",
- sme->crypto.cipher_group);
- return -EINVAL;
- }
- } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
- switch (sme->crypto.akm_suites[0]) {
- case WLAN_AKM_SUITE_8021X:
- val = WPA2_AUTH_UNSPECIFIED;
- break;
- case WLAN_AKM_SUITE_PSK:
- val = WPA2_AUTH_PSK;
- break;
- default:
- brcmf_err("invalid cipher group (%d)\n",
- sme->crypto.cipher_group);
- return -EINVAL;
- }
- }
-
- brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
- "wpa_auth", val);
- if (err) {
- brcmf_err("could not set wpa_auth (%d)\n", err);
- return err;
- }
- }
- sec = &profile->sec;
- sec->wpa_auth = sme->crypto.akm_suites[0];
-
- return err;
-}
-
-static s32
-brcmf_set_sharedkey(struct net_device *ndev,
- struct cfg80211_connect_params *sme)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_cfg80211_security *sec;
- struct brcmf_wsec_key key;
- s32 val;
- s32 err = 0;
-
- brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
-
- if (sme->key_len == 0)
- return 0;
-
- sec = &profile->sec;
- brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
- sec->wpa_versions, sec->cipher_pairwise);
-
- if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
- return 0;
-
- if (!(sec->cipher_pairwise &
- (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
- return 0;
-
- memset(&key, 0, sizeof(key));
- key.len = (u32) sme->key_len;
- key.index = (u32) sme->key_idx;
- if (key.len > sizeof(key.data)) {
- brcmf_err("Too long key length (%u)\n", key.len);
- return -EINVAL;
- }
- memcpy(key.data, sme->key, key.len);
- key.flags = BRCMF_PRIMARY_KEY;
- switch (sec->cipher_pairwise) {
- case WLAN_CIPHER_SUITE_WEP40:
- key.algo = CRYPTO_ALGO_WEP1;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- key.algo = CRYPTO_ALGO_WEP128;
- break;
- default:
- brcmf_err("Invalid algorithm (%d)\n",
- sme->crypto.ciphers_pairwise[0]);
- return -EINVAL;
- }
- /* Set the new key/index */
- brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
- key.len, key.index, key.algo);
- brcmf_dbg(CONN, "key \"%s\"\n", key.data);
- err = send_key_to_dongle(ndev, &key);
- if (err)
- return err;
-
- if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
- brcmf_dbg(CONN, "set auth_type to shared key\n");
- val = WL_AUTH_SHARED_KEY; /* shared key */
- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
- if (err)
- brcmf_err("set auth failed (%d)\n", err);
- }
- return err;
-}
-
-static
-enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
- enum nl80211_auth_type type)
-{
- if (type == NL80211_AUTHTYPE_AUTOMATIC &&
- brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
- brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
- type = NL80211_AUTHTYPE_OPEN_SYSTEM;
- }
- return type;
-}
-
-static s32
-brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_connect_params *sme)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct ieee80211_channel *chan = sme->channel;
- struct brcmf_join_params join_params;
- size_t join_params_size;
- const struct brcmf_tlv *rsn_ie;
- const struct brcmf_vs_tlv *wpa_ie;
- const void *ie;
- u32 ie_len;
- struct brcmf_ext_join_params_le *ext_join_params;
- u16 chanspec;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (!sme->ssid) {
- brcmf_err("Invalid ssid\n");
- return -EOPNOTSUPP;
- }
-
- if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
- /* A normal (non P2P) connection request setup. */
- ie = NULL;
- ie_len = 0;
- /* find the WPA_IE */
- wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
- if (wpa_ie) {
- ie = wpa_ie;
- ie_len = wpa_ie->len + TLV_HDR_LEN;
- } else {
- /* find the RSN_IE */
- rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
- sme->ie_len,
- WLAN_EID_RSN);
- if (rsn_ie) {
- ie = rsn_ie;
- ie_len = rsn_ie->len + TLV_HDR_LEN;
- }
- }
- brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
- }
-
- err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
- sme->ie, sme->ie_len);
- if (err)
- brcmf_err("Set Assoc REQ IE Failed\n");
- else
- brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
-
- set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
-
- if (chan) {
- cfg->channel =
- ieee80211_frequency_to_channel(chan->center_freq);
- chanspec = channel_to_chanspec(&cfg->d11inf, chan);
- brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
- cfg->channel, chan->center_freq, chanspec);
- } else {
- cfg->channel = 0;
- chanspec = 0;
- }
-
- brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
-
- err = brcmf_set_wpa_version(ndev, sme);
- if (err) {
- brcmf_err("wl_set_wpa_version failed (%d)\n", err);
- goto done;
- }
-
- sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
- err = brcmf_set_auth_type(ndev, sme);
- if (err) {
- brcmf_err("wl_set_auth_type failed (%d)\n", err);
- goto done;
- }
-
- err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
- if (err) {
- brcmf_err("wl_set_set_cipher failed (%d)\n", err);
- goto done;
- }
-
- err = brcmf_set_key_mgmt(ndev, sme);
- if (err) {
- brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
- goto done;
- }
-
- err = brcmf_set_sharedkey(ndev, sme);
- if (err) {
- brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
- goto done;
- }
-
- profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
- (u32)sme->ssid_len);
- memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
- if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
- profile->ssid.SSID[profile->ssid.SSID_len] = 0;
- brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
- profile->ssid.SSID_len);
- }
-
- /* Join with specific BSSID and cached SSID
- * If SSID is zero join based on BSSID only
- */
- join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
- offsetof(struct brcmf_assoc_params_le, chanspec_list);
- if (cfg->channel)
- join_params_size += sizeof(u16);
- ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
- if (ext_join_params == NULL) {
- err = -ENOMEM;
- goto done;
- }
- ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
- memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
- profile->ssid.SSID_len);
-
- /* Set up join scan parameters */
- ext_join_params->scan_le.scan_type = -1;
- ext_join_params->scan_le.home_time = cpu_to_le32(-1);
-
- if (sme->bssid)
- memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
- else
- memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
-
- if (cfg->channel) {
- ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
-
- ext_join_params->assoc_le.chanspec_list[0] =
- cpu_to_le16(chanspec);
- /* Increase dwell time to receive probe response or detect
- * beacon from target AP at a noisy air only during connect
- * command.
- */
- ext_join_params->scan_le.active_time =
- cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
- ext_join_params->scan_le.passive_time =
- cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
- /* To sync with presence period of VSDB GO send probe request
- * more frequently. Probe request will be stopped when it gets
- * probe response from target AP/GO.
- */
- ext_join_params->scan_le.nprobes =
- cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
- BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
- } else {
- ext_join_params->scan_le.active_time = cpu_to_le32(-1);
- ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
- ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
- }
-
- err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
- join_params_size);
- kfree(ext_join_params);
- if (!err)
- /* This is it. join command worked, we are done */
- goto done;
-
- /* join command failed, fallback to set ssid */
- memset(&join_params, 0, sizeof(join_params));
- join_params_size = sizeof(join_params.ssid_le);
-
- memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
- join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
-
- if (sme->bssid)
- memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
- else
- memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
-
- if (cfg->channel) {
- join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
- join_params.params_le.chanspec_num = cpu_to_le32(1);
- join_params_size += sizeof(join_params.params_le);
- }
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
- &join_params, join_params_size);
- if (err)
- brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
-
-done:
- if (err)
- clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
- u16 reason_code)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_scb_val_le scbval;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
- cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
-
- memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
- scbval.val = cpu_to_le32(reason_code);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
- &scbval, sizeof(scbval));
- if (err)
- brcmf_err("error (%d)\n", err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type, s32 mbm)
-{
-
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_if *ifp = netdev_priv(ndev);
- u16 txpwrmw;
- s32 err = 0;
- s32 disable = 0;
- s32 dbm = MBM_TO_DBM(mbm);
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- switch (type) {
- case NL80211_TX_POWER_AUTOMATIC:
- break;
- case NL80211_TX_POWER_LIMITED:
- case NL80211_TX_POWER_FIXED:
- if (dbm < 0) {
- brcmf_err("TX_POWER_FIXED - dbm is negative\n");
- err = -EINVAL;
- goto done;
- }
- break;
- }
- /* Make sure radio is off or on as far as software is concerned */
- disable = WL_RADIO_SW_DISABLE << 16;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
- if (err)
- brcmf_err("WLC_SET_RADIO error (%d)\n", err);
-
- if (dbm > 0xffff)
- txpwrmw = 0xffff;
- else
- txpwrmw = (u16) dbm;
- err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
- (s32)brcmf_mw_to_qdbm(txpwrmw));
- if (err)
- brcmf_err("qtxpower error (%d)\n", err);
- cfg->conf->tx_power = dbm;
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- s32 *dbm)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- s32 txpwrdbm;
- u8 result;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
- if (err) {
- brcmf_err("error (%d)\n", err);
- goto done;
- }
-
- result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
- *dbm = (s32) brcmf_qdbm_to_mw(result);
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool unicast, bool multicast)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- u32 index;
- u32 wsec;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
- if (err) {
- brcmf_err("WLC_GET_WSEC error (%d)\n", err);
- goto done;
- }
-
- if (wsec & WEP_ENABLED) {
- /* Just select a new current key */
- index = key_idx;
- err = brcmf_fil_cmd_int_set(ifp,
- BRCMF_C_SET_KEY_PRIMARY, index);
- if (err)
- brcmf_err("error (%d)\n", err);
- }
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, const u8 *mac_addr, struct key_params *params)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key key;
- s32 err = 0;
- u8 keybuf[8];
-
- memset(&key, 0, sizeof(key));
- key.index = (u32) key_idx;
- /* Instead of bcast for ea address for default wep keys,
- driver needs it to be Null */
- if (!is_multicast_ether_addr(mac_addr))
- memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
- key.len = (u32) params->key_len;
- /* check for key index change */
- if (key.len == 0) {
- /* key delete */
- err = send_key_to_dongle(ndev, &key);
- if (err)
- brcmf_err("key delete error (%d)\n", err);
- } else {
- if (key.len > sizeof(key.data)) {
- brcmf_err("Invalid key length (%d)\n", key.len);
- return -EINVAL;
- }
-
- brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
- memcpy(key.data, params->key, key.len);
-
- if (!brcmf_is_apmode(ifp->vif) &&
- (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
- brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
- memcpy(keybuf, &key.data[24], sizeof(keybuf));
- memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
- memcpy(&key.data[16], keybuf, sizeof(keybuf));
- }
-
- /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
- if (params->seq && params->seq_len == 6) {
- /* rx iv */
- u8 *ivptr;
- ivptr = (u8 *) params->seq;
- key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
- (ivptr[3] << 8) | ivptr[2];
- key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
- key.iv_initialized = true;
- }
-
- switch (params->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- key.algo = CRYPTO_ALGO_WEP1;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- key.algo = CRYPTO_ALGO_WEP128;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- key.algo = CRYPTO_ALGO_TKIP;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- key.algo = CRYPTO_ALGO_AES_CCM;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- key.algo = CRYPTO_ALGO_AES_CCM;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
- break;
- default:
- brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
- return -EINVAL;
- }
- err = send_key_to_dongle(ndev, &key);
- if (err)
- brcmf_err("wsec_key error (%d)\n", err);
- }
- return err;
-}
-
-static s32
-brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool pairwise, const u8 *mac_addr,
- struct key_params *params)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key key;
- s32 val;
- s32 wsec;
- s32 err = 0;
- u8 keybuf[8];
-
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (mac_addr &&
- (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
- (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
- brcmf_dbg(TRACE, "Exit");
- return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
- }
- memset(&key, 0, sizeof(key));
-
- key.len = (u32) params->key_len;
- key.index = (u32) key_idx;
-
- if (key.len > sizeof(key.data)) {
- brcmf_err("Too long key length (%u)\n", key.len);
- err = -EINVAL;
- goto done;
- }
- memcpy(key.data, params->key, key.len);
-
- key.flags = BRCMF_PRIMARY_KEY;
- switch (params->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- key.algo = CRYPTO_ALGO_WEP1;
- val = WEP_ENABLED;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- key.algo = CRYPTO_ALGO_WEP128;
- val = WEP_ENABLED;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- if (!brcmf_is_apmode(ifp->vif)) {
- brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
- memcpy(keybuf, &key.data[24], sizeof(keybuf));
- memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
- memcpy(&key.data[16], keybuf, sizeof(keybuf));
- }
- key.algo = CRYPTO_ALGO_TKIP;
- val = TKIP_ENABLED;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- key.algo = CRYPTO_ALGO_AES_CCM;
- val = AES_ENABLED;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- key.algo = CRYPTO_ALGO_AES_CCM;
- val = AES_ENABLED;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
- break;
- default:
- brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
- err = -EINVAL;
- goto done;
- }
-
- err = send_key_to_dongle(ndev, &key);
- if (err)
- goto done;
-
- err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
- if (err) {
- brcmf_err("get wsec error (%d)\n", err);
- goto done;
- }
- wsec |= val;
- err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
- if (err) {
- brcmf_err("set wsec error (%d)\n", err);
- goto done;
- }
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool pairwise, const u8 *mac_addr)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key key;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
- /* we ignore this key index in this case */
- brcmf_err("invalid key index (%d)\n", key_idx);
- return -EINVAL;
- }
-
- memset(&key, 0, sizeof(key));
-
- key.index = (u32) key_idx;
- key.flags = BRCMF_PRIMARY_KEY;
- key.algo = CRYPTO_ALGO_OFF;
-
- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-
- /* Set the new key/index */
- err = send_key_to_dongle(ndev, &key);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
- void (*callback) (void *cookie, struct key_params * params))
-{
- struct key_params params;
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_cfg80211_security *sec;
- s32 wsec;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CONN, "key index (%d)\n", key_idx);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- memset(¶ms, 0, sizeof(params));
-
- err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
- if (err) {
- brcmf_err("WLC_GET_WSEC error (%d)\n", err);
- /* Ignore this error, may happen during DISASSOC */
- err = -EAGAIN;
- goto done;
- }
- if (wsec & WEP_ENABLED) {
- sec = &profile->sec;
- if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
- params.cipher = WLAN_CIPHER_SUITE_WEP40;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
- } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
- params.cipher = WLAN_CIPHER_SUITE_WEP104;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
- }
- } else if (wsec & TKIP_ENABLED) {
- params.cipher = WLAN_CIPHER_SUITE_TKIP;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
- } else if (wsec & AES_ENABLED) {
- params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
- } else {
- brcmf_err("Invalid algo (0x%x)\n", wsec);
- err = -EINVAL;
- goto done;
- }
- callback(cookie, ¶ms);
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
- struct net_device *ndev, u8 key_idx)
-{
- brcmf_dbg(INFO, "Not supported\n");
-
- return -EOPNOTSUPP;
-}
-
-static s32
-brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
- const u8 *mac, struct station_info *sinfo)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_scb_val_le scb_val;
- int rssi;
- s32 rate;
- s32 err = 0;
- u8 *bssid = profile->bssid;
- struct brcmf_sta_info_le sta_info_le;
- u32 beacon_period;
- u32 dtim_period;
-
- brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- if (brcmf_is_apmode(ifp->vif)) {
- memcpy(&sta_info_le, mac, ETH_ALEN);
- err = brcmf_fil_iovar_data_get(ifp, "sta_info",
- &sta_info_le,
- sizeof(sta_info_le));
- if (err < 0) {
- brcmf_err("GET STA INFO failed, %d\n", err);
- goto done;
- }
- sinfo->filled = STATION_INFO_INACTIVE_TIME;
- sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
- if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
- sinfo->filled |= STATION_INFO_CONNECTED_TIME;
- sinfo->connected_time = le32_to_cpu(sta_info_le.in);
- }
- brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
- sinfo->inactive_time, sinfo->connected_time);
- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
- if (memcmp(mac, bssid, ETH_ALEN)) {
- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
- mac, bssid);
- err = -ENOENT;
- goto done;
- }
- /* Report the current tx rate */
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
- if (err) {
- brcmf_err("Could not get rate (%d)\n", err);
- goto done;
- } else {
- sinfo->filled |= STATION_INFO_TX_BITRATE;
- sinfo->txrate.legacy = rate * 5;
- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
- }
-
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state)) {
- memset(&scb_val, 0, sizeof(scb_val));
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
- &scb_val, sizeof(scb_val));
- if (err) {
- brcmf_err("Could not get rssi (%d)\n", err);
- goto done;
- } else {
- rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
- &beacon_period);
- if (err) {
- brcmf_err("Could not get beacon period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.beacon_interval =
- beacon_period;
- brcmf_dbg(CONN, "Beacon peroid %d\n",
- beacon_period);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
- &dtim_period);
- if (err) {
- brcmf_err("Could not get DTIM period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.dtim_period = dtim_period;
- brcmf_dbg(CONN, "DTIM peroid %d\n",
- dtim_period);
- }
- sinfo->filled |= STATION_INFO_BSS_PARAM;
- }
- } else
- err = -EPERM;
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
- bool enabled, s32 timeout)
-{
- s32 pm;
- s32 err = 0;
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /*
- * Powersave enable/disable request is coming from the
- * cfg80211 even before the interface is up. In that
- * scenario, driver will be storing the power save
- * preference in cfg struct to apply this to
- * FW later while initializing the dongle
- */
- cfg->pwr_save = enabled;
- if (!check_vif_up(ifp->vif)) {
-
- brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
- goto done;
- }
-
- pm = enabled ? PM_FAST : PM_OFF;
- /* Do not enable the power save after assoc if it is a p2p interface */
- if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
- brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
- pm = PM_OFF;
- }
- brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
-
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
- if (err) {
- if (err == -ENODEV)
- brcmf_err("net_device is not ready yet\n");
- else
- brcmf_err("error (%d)\n", err);
- }
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
- struct brcmf_bss_info_le *bi)
-{
- struct wiphy *wiphy = cfg_to_wiphy(cfg);
- struct ieee80211_channel *notify_channel;
- struct cfg80211_bss *bss;
- struct ieee80211_supported_band *band;
- struct brcmu_chan ch;
- u16 channel;
- u32 freq;
- u16 notify_capability;
- u16 notify_interval;
- u8 *notify_ie;
- size_t notify_ielen;
- s32 notify_signal;
-
- if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
- brcmf_err("Bss info is larger than buffer. Discarding\n");
- return 0;
- }
-
- if (!bi->ctl_ch) {
- ch.chspec = le16_to_cpu(bi->chanspec);
- cfg->d11inf.decchspec(&ch);
- bi->ctl_ch = ch.chnum;
- }
- channel = bi->ctl_ch;
-
- if (channel <= CH_MAX_2G_CHANNEL)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
- freq = ieee80211_channel_to_frequency(channel, band->band);
- notify_channel = ieee80211_get_channel(wiphy, freq);
-
- notify_capability = le16_to_cpu(bi->capability);
- notify_interval = le16_to_cpu(bi->beacon_period);
- notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
- notify_ielen = le32_to_cpu(bi->ie_length);
- notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
-
- brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
- brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
- brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
- brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
- brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
-
- bss = cfg80211_inform_bss(wiphy, notify_channel,
- CFG80211_BSS_FTYPE_UNKNOWN,
- (const u8 *)bi->BSSID,
- 0, notify_capability,
- notify_interval, notify_ie,
- notify_ielen, notify_signal,
- GFP_KERNEL);
-
- if (!bss)
- return -ENOMEM;
-
- cfg80211_put_bss(wiphy, bss);
-
- return 0;
-}
-
-static struct brcmf_bss_info_le *
-next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
-{
- if (bss == NULL)
- return list->bss_info_le;
- return (struct brcmf_bss_info_le *)((unsigned long)bss +
- le32_to_cpu(bss->length));
-}
-
-static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_scan_results *bss_list;
- struct brcmf_bss_info_le *bi = NULL; /* must be initialized */
- s32 err = 0;
- int i;
-
- bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
- if (bss_list->count != 0 &&
- bss_list->version != BRCMF_BSS_INFO_VERSION) {
- brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
- bss_list->version);
- return -EOPNOTSUPP;
- }
- brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
- for (i = 0; i < bss_list->count; i++) {
- bi = next_bss_le(bss_list, bi);
- err = brcmf_inform_single_bss(cfg, bi);
- if (err)
- break;
- }
- return err;
-}
-
-static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev, const u8 *bssid)
-{
- struct wiphy *wiphy = cfg_to_wiphy(cfg);
- struct ieee80211_channel *notify_channel;
- struct brcmf_bss_info_le *bi = NULL;
- struct ieee80211_supported_band *band;
- struct cfg80211_bss *bss;
- struct brcmu_chan ch;
- u8 *buf = NULL;
- s32 err = 0;
- u32 freq;
- u16 notify_capability;
- u16 notify_interval;
- u8 *notify_ie;
- size_t notify_ielen;
- s32 notify_signal;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (buf == NULL) {
- err = -ENOMEM;
- goto CleanUp;
- }
-
- *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
-
- err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
- buf, WL_BSS_INFO_MAX);
- if (err) {
- brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
- goto CleanUp;
- }
-
- bi = (struct brcmf_bss_info_le *)(buf + 4);
-
- ch.chspec = le16_to_cpu(bi->chanspec);
- cfg->d11inf.decchspec(&ch);
-
- if (ch.band == BRCMU_CHAN_BAND_2G)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
- freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
- notify_channel = ieee80211_get_channel(wiphy, freq);
-
- notify_capability = le16_to_cpu(bi->capability);
- notify_interval = le16_to_cpu(bi->beacon_period);
- notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
- notify_ielen = le32_to_cpu(bi->ie_length);
- notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
-
- brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
- brcmf_dbg(CONN, "capability: %X\n", notify_capability);
- brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
- brcmf_dbg(CONN, "signal: %d\n", notify_signal);
-
- bss = cfg80211_inform_bss(wiphy, notify_channel,
- CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
- notify_capability, notify_interval,
- notify_ie, notify_ielen, notify_signal,
- GFP_KERNEL);
-
- if (!bss) {
- err = -ENOMEM;
- goto CleanUp;
- }
-
- cfg80211_put_bss(wiphy, bss);
-
-CleanUp:
-
- kfree(buf);
-
- brcmf_dbg(TRACE, "Exit\n");
-
- return err;
-}
-
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp)
-{
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
- struct brcmf_bss_info_le *bi;
- struct brcmf_ssid *ssid;
- const struct brcmf_tlv *tim;
- u16 beacon_interval;
- u8 dtim_period;
- size_t ie_len;
- u8 *ie;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (brcmf_is_ibssmode(ifp->vif))
- return err;
-
- ssid = &profile->ssid;
-
- *(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
- cfg->extra_buf, WL_EXTRA_BUF_MAX);
- if (err) {
- brcmf_err("Could not get bss info %d\n", err);
- goto update_bss_info_out;
- }
-
- bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
- err = brcmf_inform_single_bss(cfg, bi);
- if (err)
- goto update_bss_info_out;
-
- ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
- ie_len = le32_to_cpu(bi->ie_length);
- beacon_interval = le16_to_cpu(bi->beacon_period);
-
- tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
- if (tim)
- dtim_period = tim->data[1];
- else {
- /*
- * active scan was done so we could not get dtim
- * information out of probe response.
- * so we speficially query dtim information to dongle.
- */
- u32 var;
- err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
- if (err) {
- brcmf_err("wl dtim_assoc failed (%d)\n", err);
- goto update_bss_info_out;
- }
- dtim_period = (u8)var;
- }
-
-update_bss_info_out:
- brcmf_dbg(TRACE, "Exit");
- return err;
-}
-
-void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
-{
- struct escan_info *escan = &cfg->escan_info;
-
- set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
- if (cfg->scan_request) {
- escan->escan_state = WL_ESCAN_STATE_IDLE;
- brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
- }
- clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
-}
-
-static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
-{
- struct brcmf_cfg80211_info *cfg =
- container_of(work, struct brcmf_cfg80211_info,
- escan_timeout_work);
-
- brcmf_inform_bss(cfg);
- brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
-}
-
-static void brcmf_escan_timeout(unsigned long data)
-{
- struct brcmf_cfg80211_info *cfg =
- (struct brcmf_cfg80211_info *)data;
-
- if (cfg->scan_request) {
- brcmf_err("timer expired\n");
- schedule_work(&cfg->escan_timeout_work);
- }
-}
-
-static s32
-brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
- struct brcmf_bss_info_le *bss,
- struct brcmf_bss_info_le *bss_info_le)
-{
- struct brcmu_chan ch_bss, ch_bss_info_le;
-
- ch_bss.chspec = le16_to_cpu(bss->chanspec);
- cfg->d11inf.decchspec(&ch_bss);
- ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
- cfg->d11inf.decchspec(&ch_bss_info_le);
-
- if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
- ch_bss.band == ch_bss_info_le.band &&
- bss_info_le->SSID_len == bss->SSID_len &&
- !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
- if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
- (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
- s16 bss_rssi = le16_to_cpu(bss->RSSI);
- s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
-
- /* preserve max RSSI if the measurements are
- * both on-channel or both off-channel
- */
- if (bss_info_rssi > bss_rssi)
- bss->RSSI = bss_info_le->RSSI;
- } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
- (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
- /* preserve the on-channel rssi measurement
- * if the new measurement is off channel
- */
- bss->RSSI = bss_info_le->RSSI;
- bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
- }
- return 1;
- }
- return 0;
-}
-
-static s32
-brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- s32 status;
- struct brcmf_escan_result_le *escan_result_le;
- struct brcmf_bss_info_le *bss_info_le;
- struct brcmf_bss_info_le *bss = NULL;
- u32 bi_length;
- struct brcmf_scan_results *list;
- u32 i;
- bool aborted;
-
- status = e->status;
-
- if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
- return -EPERM;
- }
-
- if (status == BRCMF_E_STATUS_PARTIAL) {
- brcmf_dbg(SCAN, "ESCAN Partial result\n");
- escan_result_le = (struct brcmf_escan_result_le *) data;
- if (!escan_result_le) {
- brcmf_err("Invalid escan result (NULL pointer)\n");
- goto exit;
- }
- if (le16_to_cpu(escan_result_le->bss_count) != 1) {
- brcmf_err("Invalid bss_count %d: ignoring\n",
- escan_result_le->bss_count);
- goto exit;
- }
- bss_info_le = &escan_result_le->bss_info_le;
-
- if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
- goto exit;
-
- if (!cfg->scan_request) {
- brcmf_dbg(SCAN, "result without cfg80211 request\n");
- goto exit;
- }
-
- bi_length = le32_to_cpu(bss_info_le->length);
- if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
- WL_ESCAN_RESULTS_FIXED_SIZE)) {
- brcmf_err("Invalid bss_info length %d: ignoring\n",
- bi_length);
- goto exit;
- }
-
- if (!(cfg_to_wiphy(cfg)->interface_modes &
- BIT(NL80211_IFTYPE_ADHOC))) {
- if (le16_to_cpu(bss_info_le->capability) &
- WLAN_CAPABILITY_IBSS) {
- brcmf_err("Ignoring IBSS result\n");
- goto exit;
- }
- }
-
- list = (struct brcmf_scan_results *)
- cfg->escan_info.escan_buf;
- if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
- brcmf_err("Buffer is too small: ignoring\n");
- goto exit;
- }
-
- for (i = 0; i < list->count; i++) {
- bss = bss ? (struct brcmf_bss_info_le *)
- ((unsigned char *)bss +
- le32_to_cpu(bss->length)) : list->bss_info_le;
- if (brcmf_compare_update_same_bss(cfg, bss,
- bss_info_le))
- goto exit;
- }
- memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
- bss_info_le, bi_length);
- list->version = le32_to_cpu(bss_info_le->version);
- list->buflen += bi_length;
- list->count++;
- } else {
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
- goto exit;
- if (cfg->scan_request) {
- brcmf_inform_bss(cfg);
- aborted = status != BRCMF_E_STATUS_SUCCESS;
- brcmf_notify_escan_complete(cfg, ifp, aborted, false);
- } else
- brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
- status);
- }
-exit:
- return 0;
-}
-
-static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
-{
- brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
- brcmf_cfg80211_escan_handler);
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
- /* Init scan_timeout timer */
- init_timer(&cfg->escan_timeout);
- cfg->escan_timeout.data = (unsigned long) cfg;
- cfg->escan_timeout.function = brcmf_escan_timeout;
- INIT_WORK(&cfg->escan_timeout_work,
- brcmf_cfg80211_escan_timeout_worker);
-}
-
-static __always_inline void brcmf_delay(u32 ms)
-{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
- msleep(ms);
- }
-}
-
-static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_if *ifp = netdev_priv(ndev);
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (cfg->wowl_enabled) {
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
- cfg->pre_wowl_pmmode);
- brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
- brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
- cfg->wowl_enabled = false;
- }
- return 0;
-}
-
-static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp,
- struct cfg80211_wowlan *wowl)
-{
- u32 wowl_config;
-
- brcmf_dbg(TRACE, "Suspend, wowl config.\n");
-
- brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
-
- wowl_config = 0;
- if (wowl->disconnect)
- wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
- /* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss
- * should be configured. This paramater is not supported by
- * wowlpf.
- */
- if (wowl->magic_pkt)
- wowl_config |= WL_WOWL_MAGIC;
- brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
- brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
- brcmf_bus_wowl_config(cfg->pub->bus_if, true);
- cfg->wowl_enabled = true;
-}
-
-static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
- struct cfg80211_wowlan *wowl)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_vif *vif;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* if the primary net_device is not READY there is nothing
- * we can do but pray resume goes smoothly.
- */
- if (!check_vif_up(ifp->vif))
- goto exit;
-
- /* end any scanning */
- if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
- brcmf_abort_scanning(cfg);
-
- if (wowl == NULL) {
- brcmf_bus_wowl_config(cfg->pub->bus_if, false);
- list_for_each_entry(vif, &cfg->vif_list, list) {
- if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
- continue;
- /* While going to suspend if associated with AP
- * disassociate from AP to save power while system is
- * in suspended state
- */
- brcmf_link_down(vif);
- /* Make sure WPA_Supplicant receives all the event
- * generated due to DISASSOC call to the fw to keep
- * the state fw and WPA_Supplicant state consistent
- */
- brcmf_delay(500);
- }
- /* Configure MPC */
- brcmf_set_mpc(ifp, 1);
-
- } else {
- /* Configure WOWL paramaters */
- brcmf_configure_wowl(cfg, ifp, wowl);
- }
-
-exit:
- brcmf_dbg(TRACE, "Exit\n");
- /* clear any scanning activity */
- cfg->scan_status = 0;
- return 0;
-}
-
-static __used s32
-brcmf_update_pmklist(struct net_device *ndev,
- struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
-{
- int i, j;
- int pmkid_len;
-
- pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
-
- brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
- for (i = 0; i < pmkid_len; i++) {
- brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
- &pmk_list->pmkids.pmkid[i].BSSID);
- for (j = 0; j < WLAN_PMKID_LEN; j++)
- brcmf_dbg(CONN, "%02x\n",
- pmk_list->pmkids.pmkid[i].PMKID[j]);
- }
-
- if (!err)
- brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
- (char *)pmk_list, sizeof(*pmk_list));
-
- return err;
-}
-
-static s32
-brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_pmksa *pmksa)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
- s32 err = 0;
- int i;
- int pmkid_len;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- pmkid_len = le32_to_cpu(pmkids->npmkid);
- for (i = 0; i < pmkid_len; i++)
- if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
- break;
- if (i < WL_NUM_PMKIDS_MAX) {
- memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
- memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
- if (i == pmkid_len) {
- pmkid_len++;
- pmkids->npmkid = cpu_to_le32(pmkid_len);
- }
- } else
- err = -EINVAL;
-
- brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
- pmkids->pmkid[pmkid_len].BSSID);
- for (i = 0; i < WLAN_PMKID_LEN; i++)
- brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
-
- err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_pmksa *pmksa)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct pmkid_list pmkid;
- s32 err = 0;
- int i, pmkid_len;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
- memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
-
- brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
- &pmkid.pmkid[0].BSSID);
- for (i = 0; i < WLAN_PMKID_LEN; i++)
- brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
-
- pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
- for (i = 0; i < pmkid_len; i++)
- if (!memcmp
- (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
- ETH_ALEN))
- break;
-
- if ((pmkid_len > 0)
- && (i < pmkid_len)) {
- memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
- sizeof(struct pmkid));
- for (; i < (pmkid_len - 1); i++) {
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
- &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
- ETH_ALEN);
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
- &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
- WLAN_PMKID_LEN);
- }
- cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
- } else
- err = -EINVAL;
-
- err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-
-}
-
-static s32
-brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
- err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-
-}
-
-/*
- * PFN result doesn't have all the info which are
- * required by the supplicant
- * (For e.g IEs) Do a target Escan so that sched scan results are reported
- * via wl_inform_single_bss in the required format. Escan does require the
- * scan request in the form of cfg80211_scan_request. For timebeing, create
- * cfg80211_scan_request one out of the received PNO event.
- */
-static s32
-brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
- struct cfg80211_scan_request *request = NULL;
- struct cfg80211_ssid *ssid = NULL;
- struct ieee80211_channel *channel = NULL;
- struct wiphy *wiphy = cfg_to_wiphy(cfg);
- int err = 0;
- int channel_req = 0;
- int band = 0;
- struct brcmf_pno_scanresults_le *pfn_result;
- u32 result_count;
- u32 status;
-
- brcmf_dbg(SCAN, "Enter\n");
-
- if (e->event_code == BRCMF_E_PFN_NET_LOST) {
- brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
- return 0;
- }
-
- pfn_result = (struct brcmf_pno_scanresults_le *)data;
- result_count = le32_to_cpu(pfn_result->count);
- status = le32_to_cpu(pfn_result->status);
-
- /*
- * PFN event is limited to fit 512 bytes so we may get
- * multiple NET_FOUND events. For now place a warning here.
- */
- WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
- brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
- if (result_count > 0) {
- int i;
-
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
- channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
- if (!request || !ssid || !channel) {
- err = -ENOMEM;
- goto out_err;
- }
-
- request->wiphy = wiphy;
- data += sizeof(struct brcmf_pno_scanresults_le);
- netinfo_start = (struct brcmf_pno_net_info_le *)data;
-
- for (i = 0; i < result_count; i++) {
- netinfo = &netinfo_start[i];
- if (!netinfo) {
- brcmf_err("Invalid netinfo ptr. index: %d\n",
- i);
- err = -EINVAL;
- goto out_err;
- }
-
- brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
- netinfo->SSID, netinfo->channel);
- memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
- ssid[i].ssid_len = netinfo->SSID_len;
- request->n_ssids++;
-
- channel_req = netinfo->channel;
- if (channel_req <= CH_MAX_2G_CHANNEL)
- band = NL80211_BAND_2GHZ;
- else
- band = NL80211_BAND_5GHZ;
- channel[i].center_freq =
- ieee80211_channel_to_frequency(channel_req,
- band);
- channel[i].band = band;
- channel[i].flags |= IEEE80211_CHAN_NO_HT40;
- request->channels[i] = &channel[i];
- request->n_channels++;
- }
-
- /* assign parsed ssid array */
- if (request->n_ssids)
- request->ssids = &ssid[0];
-
- if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- /* Abort any on-going scan */
- brcmf_abort_scanning(cfg);
- }
-
- set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- cfg->escan_info.run = brcmf_run_escan;
- err = brcmf_do_escan(cfg, wiphy, ifp, request);
- if (err) {
- clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- goto out_err;
- }
- cfg->sched_escan = true;
- cfg->scan_request = request;
- } else {
- brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
- goto out_err;
- }
-
- kfree(ssid);
- kfree(channel);
- kfree(request);
- return 0;
-
-out_err:
- kfree(ssid);
- kfree(channel);
- kfree(request);
- cfg80211_sched_scan_stopped(wiphy);
- return err;
-}
-
-static int brcmf_dev_pno_clean(struct net_device *ndev)
-{
- int ret;
-
- /* Disable pfn */
- ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
- if (ret == 0) {
- /* clear pfn */
- ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
- NULL, 0);
- }
- if (ret < 0)
- brcmf_err("failed code %d\n", ret);
-
- return ret;
-}
-
-static int brcmf_dev_pno_config(struct net_device *ndev)
-{
- struct brcmf_pno_param_le pfn_param;
-
- memset(&pfn_param, 0, sizeof(pfn_param));
- pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
-
- /* set extra pno params */
- pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
- pfn_param.repeat = BRCMF_PNO_REPEAT;
- pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
-
- /* set up pno scan fr */
- pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
-
- return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
- &pfn_param, sizeof(pfn_param));
-}
-
-static int
-brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
- struct net_device *ndev,
- struct cfg80211_sched_scan_request *request)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_pno_net_param_le pfn;
- int i;
- int ret = 0;
-
- brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
- request->n_match_sets, request->n_ssids);
- if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
- return -EAGAIN;
- }
- if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
- brcmf_err("Scanning suppressed: status (%lu)\n",
- cfg->scan_status);
- return -EAGAIN;
- }
-
- if (!request->n_ssids || !request->n_match_sets) {
- brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
- request->n_ssids);
- return -EINVAL;
- }
-
- if (request->n_ssids > 0) {
- for (i = 0; i < request->n_ssids; i++) {
- /* Active scan req for ssids */
- brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
- request->ssids[i].ssid);
-
- /*
- * match_set ssids is a supert set of n_ssid list,
- * so we need not add these set seperately.
- */
- }
- }
-
- if (request->n_match_sets > 0) {
- /* clean up everything */
- ret = brcmf_dev_pno_clean(ndev);
- if (ret < 0) {
- brcmf_err("failed error=%d\n", ret);
- return ret;
- }
-
- /* configure pno */
- ret = brcmf_dev_pno_config(ndev);
- if (ret < 0) {
- brcmf_err("PNO setup failed!! ret=%d\n", ret);
- return -EINVAL;
- }
-
- /* configure each match set */
- for (i = 0; i < request->n_match_sets; i++) {
- struct cfg80211_ssid *ssid;
- u32 ssid_len;
-
- ssid = &request->match_sets[i].ssid;
- ssid_len = ssid->ssid_len;
-
- if (!ssid_len) {
- brcmf_err("skip broadcast ssid\n");
- continue;
- }
- pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
- pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
- pfn.wsec = cpu_to_le32(0);
- pfn.infra = cpu_to_le32(1);
- pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
- pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
- memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
- ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
- sizeof(pfn));
- brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
- ret == 0 ? "set" : "failed", ssid->ssid);
- }
- /* Enable the PNO */
- if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
- brcmf_err("PNO enable failed!! ret=%d\n", ret);
- return -EINVAL;
- }
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
- struct net_device *ndev)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-
- brcmf_dbg(SCAN, "enter\n");
- brcmf_dev_pno_clean(ndev);
- if (cfg->sched_escan)
- brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
- return 0;
-}
-
-static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
-{
- s32 err;
-
- /* set auth */
- err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
- if (err < 0) {
- brcmf_err("auth error %d\n", err);
- return err;
- }
- /* set wsec */
- err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
- if (err < 0) {
- brcmf_err("wsec error %d\n", err);
- return err;
- }
- /* set upper-layer auth */
- err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
- if (err < 0) {
- brcmf_err("wpa_auth error %d\n", err);
- return err;
- }
-
- return 0;
-}
-
-static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
-{
- if (is_rsn_ie)
- return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);
-
- return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
-}
-
-static s32
-brcmf_configure_wpaie(struct net_device *ndev,
- const struct brcmf_vs_tlv *wpa_ie,
- bool is_rsn_ie)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- u32 auth = 0; /* d11 open authentication */
- u16 count;
- s32 err = 0;
- s32 len = 0;
- u32 i;
- u32 wsec;
- u32 pval = 0;
- u32 gval = 0;
- u32 wpa_auth = 0;
- u32 offset;
- u8 *data;
- u16 rsn_cap;
- u32 wme_bss_disable;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (wpa_ie == NULL)
- goto exit;
-
- len = wpa_ie->len + TLV_HDR_LEN;
- data = (u8 *)wpa_ie;
- offset = TLV_HDR_LEN;
- if (!is_rsn_ie)
- offset += VS_IE_FIXED_HDR_LEN;
- else
- offset += WPA_IE_VERSION_LEN;
-
- /* check for multicast cipher suite */
- if (offset + WPA_IE_MIN_OUI_LEN > len) {
- err = -EINVAL;
- brcmf_err("no multicast cipher suite\n");
- goto exit;
- }
-
- if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
- err = -EINVAL;
- brcmf_err("ivalid OUI\n");
- goto exit;
- }
- offset += TLV_OUI_LEN;
-
- /* pick up multicast cipher */
- switch (data[offset]) {
- case WPA_CIPHER_NONE:
- gval = 0;
- break;
- case WPA_CIPHER_WEP_40:
- case WPA_CIPHER_WEP_104:
- gval = WEP_ENABLED;
- break;
- case WPA_CIPHER_TKIP:
- gval = TKIP_ENABLED;
- break;
- case WPA_CIPHER_AES_CCM:
- gval = AES_ENABLED;
- break;
- default:
- err = -EINVAL;
- brcmf_err("Invalid multi cast cipher info\n");
- goto exit;
- }
-
- offset++;
- /* walk thru unicast cipher list and pick up what we recognize */
- count = data[offset] + (data[offset + 1] << 8);
- offset += WPA_IE_SUITE_COUNT_LEN;
- /* Check for unicast suite(s) */
- if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
- err = -EINVAL;
- brcmf_err("no unicast cipher suite\n");
- goto exit;
- }
- for (i = 0; i < count; i++) {
- if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
- err = -EINVAL;
- brcmf_err("ivalid OUI\n");
- goto exit;
- }
- offset += TLV_OUI_LEN;
- switch (data[offset]) {
- case WPA_CIPHER_NONE:
- break;
- case WPA_CIPHER_WEP_40:
- case WPA_CIPHER_WEP_104:
- pval |= WEP_ENABLED;
- break;
- case WPA_CIPHER_TKIP:
- pval |= TKIP_ENABLED;
- break;
- case WPA_CIPHER_AES_CCM:
- pval |= AES_ENABLED;
- break;
- default:
- brcmf_err("Ivalid unicast security info\n");
- }
- offset++;
- }
- /* walk thru auth management suite list and pick up what we recognize */
- count = data[offset] + (data[offset + 1] << 8);
- offset += WPA_IE_SUITE_COUNT_LEN;
- /* Check for auth key management suite(s) */
- if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
- err = -EINVAL;
- brcmf_err("no auth key mgmt suite\n");
- goto exit;
- }
- for (i = 0; i < count; i++) {
- if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
- err = -EINVAL;
- brcmf_err("ivalid OUI\n");
- goto exit;
- }
- offset += TLV_OUI_LEN;
- switch (data[offset]) {
- case RSN_AKM_NONE:
- brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
- wpa_auth |= WPA_AUTH_NONE;
- break;
- case RSN_AKM_UNSPECIFIED:
- brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
- is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
- (wpa_auth |= WPA_AUTH_UNSPECIFIED);
- break;
- case RSN_AKM_PSK:
- brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
- is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
- (wpa_auth |= WPA_AUTH_PSK);
- break;
- default:
- brcmf_err("Ivalid key mgmt info\n");
- }
- offset++;
- }
-
- if (is_rsn_ie) {
- wme_bss_disable = 1;
- if ((offset + RSN_CAP_LEN) <= len) {
- rsn_cap = data[offset] + (data[offset + 1] << 8);
- if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
- wme_bss_disable = 0;
- }
- /* set wme_bss_disable to sync RSN Capabilities */
- err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
- wme_bss_disable);
- if (err < 0) {
- brcmf_err("wme_bss_disable error %d\n", err);
- goto exit;
- }
- }
- /* FOR WPS , set SES_OW_ENABLED */
- wsec = (pval | gval | SES_OW_ENABLED);
-
- /* set auth */
- err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
- if (err < 0) {
- brcmf_err("auth error %d\n", err);
- goto exit;
- }
- /* set wsec */
- err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
- if (err < 0) {
- brcmf_err("wsec error %d\n", err);
- goto exit;
- }
- /* set upper-layer auth */
- err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
- if (err < 0) {
- brcmf_err("wpa_auth error %d\n", err);
- goto exit;
- }
-
-exit:
- return err;
-}
-
-static s32
-brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
- struct parsed_vndr_ies *vndr_ies)
-{
- struct brcmf_vs_tlv *vndrie;
- struct brcmf_tlv *ie;
- struct parsed_vndr_ie_info *parsed_info;
- s32 remaining_len;
-
- remaining_len = (s32)vndr_ie_len;
- memset(vndr_ies, 0, sizeof(*vndr_ies));
-
- ie = (struct brcmf_tlv *)vndr_ie_buf;
- while (ie) {
- if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
- goto next;
- vndrie = (struct brcmf_vs_tlv *)ie;
- /* len should be bigger than OUI length + one */
- if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
- brcmf_err("invalid vndr ie. length is too small %d\n",
- vndrie->len);
- goto next;
- }
- /* if wpa or wme ie, do not add ie */
- if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
- ((vndrie->oui_type == WPA_OUI_TYPE) ||
- (vndrie->oui_type == WME_OUI_TYPE))) {
- brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
- goto next;
- }
-
- parsed_info = &vndr_ies->ie_info[vndr_ies->count];
-
- /* save vndr ie information */
- parsed_info->ie_ptr = (char *)vndrie;
- parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
- memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));
-
- vndr_ies->count++;
-
- brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
- parsed_info->vndrie.oui[0],
- parsed_info->vndrie.oui[1],
- parsed_info->vndrie.oui[2],
- parsed_info->vndrie.oui_type);
-
- if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
- break;
-next:
- remaining_len -= (ie->len + TLV_HDR_LEN);
- if (remaining_len <= TLV_HDR_LEN)
- ie = NULL;
- else
- ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
- TLV_HDR_LEN);
- }
- return 0;
-}
-
-static u32
-brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
-{
-
- __le32 iecount_le;
- __le32 pktflag_le;
-
- strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
- iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
-
- iecount_le = cpu_to_le32(1);
- memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
-
- pktflag_le = cpu_to_le32(pktflag);
- memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
-
- memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
-
- return ie_len + VNDR_IE_HDR_SIZE;
-}
-
-s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
- const u8 *vndr_ie_buf, u32 vndr_ie_len)
-{
- struct brcmf_if *ifp;
- struct vif_saved_ie *saved_ie;
- s32 err = 0;
- u8 *iovar_ie_buf;
- u8 *curr_ie_buf;
- u8 *mgmt_ie_buf = NULL;
- int mgmt_ie_buf_len;
- u32 *mgmt_ie_len;
- u32 del_add_ie_buf_len = 0;
- u32 total_ie_buf_len = 0;
- u32 parsed_ie_buf_len = 0;
- struct parsed_vndr_ies old_vndr_ies;
- struct parsed_vndr_ies new_vndr_ies;
- struct parsed_vndr_ie_info *vndrie_info;
- s32 i;
- u8 *ptr;
- int remained_buf_len;
-
- if (!vif)
- return -ENODEV;
- ifp = vif->ifp;
- saved_ie = &vif->saved_ie;
-
- brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
- iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
- if (!iovar_ie_buf)
- return -ENOMEM;
- curr_ie_buf = iovar_ie_buf;
- switch (pktflag) {
- case BRCMF_VNDR_IE_PRBREQ_FLAG:
- mgmt_ie_buf = saved_ie->probe_req_ie;
- mgmt_ie_len = &saved_ie->probe_req_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
- break;
- case BRCMF_VNDR_IE_PRBRSP_FLAG:
- mgmt_ie_buf = saved_ie->probe_res_ie;
- mgmt_ie_len = &saved_ie->probe_res_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
- break;
- case BRCMF_VNDR_IE_BEACON_FLAG:
- mgmt_ie_buf = saved_ie->beacon_ie;
- mgmt_ie_len = &saved_ie->beacon_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
- break;
- case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
- mgmt_ie_buf = saved_ie->assoc_req_ie;
- mgmt_ie_len = &saved_ie->assoc_req_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
- break;
- default:
- err = -EPERM;
- brcmf_err("not suitable type\n");
- goto exit;
- }
-
- if (vndr_ie_len > mgmt_ie_buf_len) {
- err = -ENOMEM;
- brcmf_err("extra IE size too big\n");
- goto exit;
- }
-
- /* parse and save new vndr_ie in curr_ie_buff before comparing it */
- if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
- ptr = curr_ie_buf;
- brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
- for (i = 0; i < new_vndr_ies.count; i++) {
- vndrie_info = &new_vndr_ies.ie_info[i];
- memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
- vndrie_info->ie_len);
- parsed_ie_buf_len += vndrie_info->ie_len;
- }
- }
-
- if (mgmt_ie_buf && *mgmt_ie_len) {
- if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
- (memcmp(mgmt_ie_buf, curr_ie_buf,
- parsed_ie_buf_len) == 0)) {
- brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
- goto exit;
- }
-
- /* parse old vndr_ie */
- brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);
-
- /* make a command to delete old ie */
- for (i = 0; i < old_vndr_ies.count; i++) {
- vndrie_info = &old_vndr_ies.ie_info[i];
-
- brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
- vndrie_info->vndrie.id,
- vndrie_info->vndrie.len,
- vndrie_info->vndrie.oui[0],
- vndrie_info->vndrie.oui[1],
- vndrie_info->vndrie.oui[2]);
-
- del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
- vndrie_info->ie_ptr,
- vndrie_info->ie_len,
- "del");
- curr_ie_buf += del_add_ie_buf_len;
- total_ie_buf_len += del_add_ie_buf_len;
- }
- }
-
- *mgmt_ie_len = 0;
- /* Add if there is any extra IE */
- if (mgmt_ie_buf && parsed_ie_buf_len) {
- ptr = mgmt_ie_buf;
-
- remained_buf_len = mgmt_ie_buf_len;
-
- /* make a command to add new ie */
- for (i = 0; i < new_vndr_ies.count; i++) {
- vndrie_info = &new_vndr_ies.ie_info[i];
-
- /* verify remained buf size before copy data */
- if (remained_buf_len < (vndrie_info->vndrie.len +
- VNDR_IE_VSIE_OFFSET)) {
- brcmf_err("no space in mgmt_ie_buf: len left %d",
- remained_buf_len);
- break;
- }
- remained_buf_len -= (vndrie_info->ie_len +
- VNDR_IE_VSIE_OFFSET);
-
- brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
- vndrie_info->vndrie.id,
- vndrie_info->vndrie.len,
- vndrie_info->vndrie.oui[0],
- vndrie_info->vndrie.oui[1],
- vndrie_info->vndrie.oui[2]);
-
- del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
- vndrie_info->ie_ptr,
- vndrie_info->ie_len,
- "add");
-
- /* save the parsed IE in wl struct */
- memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
- vndrie_info->ie_len);
- *mgmt_ie_len += vndrie_info->ie_len;
-
- curr_ie_buf += del_add_ie_buf_len;
- total_ie_buf_len += del_add_ie_buf_len;
- }
- }
- if (total_ie_buf_len) {
- err = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
- total_ie_buf_len);
- if (err)
- brcmf_err("vndr ie set error : %d\n", err);
- }
-
-exit:
- kfree(iovar_ie_buf);
- return err;
-}
-
-s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
-{
- s32 pktflags[] = {
- BRCMF_VNDR_IE_PRBREQ_FLAG,
- BRCMF_VNDR_IE_PRBRSP_FLAG,
- BRCMF_VNDR_IE_BEACON_FLAG
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pktflags); i++)
- brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
-
- memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
- return 0;
-}
-
-static s32
-brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
- struct cfg80211_beacon_data *beacon)
-{
- s32 err;
-
- /* Set Beacon IEs to FW */
- err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
- beacon->tail, beacon->tail_len);
- if (err) {
- brcmf_err("Set Beacon IE Failed\n");
- return err;
- }
- brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
-
- /* Set Probe Response IEs to FW */
- err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
- beacon->proberesp_ies,
- beacon->proberesp_ies_len);
- if (err)
- brcmf_err("Set Probe Resp IE Failed\n");
- else
- brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
-
- return err;
-}
-
-static s32
-brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_ap_settings *settings)
-{
- s32 ie_offset;
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_if *ifp = netdev_priv(ndev);
- const struct brcmf_tlv *ssid_ie;
- struct brcmf_ssid_le ssid_le;
- s32 err = -EPERM;
- const struct brcmf_tlv *rsn_ie;
- const struct brcmf_vs_tlv *wpa_ie;
- struct brcmf_join_params join_params;
- enum nl80211_iftype dev_role;
- struct brcmf_fil_bss_enable_le bss_enable;
- u16 chanspec;
-
- brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
- settings->chandef.chan->hw_value,
- settings->chandef.center_freq1, settings->chandef.width,
- settings->beacon_interval, settings->dtim_period);
- brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
- settings->ssid, settings->ssid_len, settings->auth_type,
- settings->inactivity_timeout);
-
- dev_role = ifp->vif->wdev.iftype;
-
- memset(&ssid_le, 0, sizeof(ssid_le));
- if (settings->ssid == NULL || settings->ssid_len == 0) {
- ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
- ssid_ie = brcmf_parse_tlvs(
- (u8 *)&settings->beacon.head[ie_offset],
- settings->beacon.head_len - ie_offset,
- WLAN_EID_SSID);
- if (!ssid_ie)
- return -EINVAL;
-
- memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
- ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
- brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
- } else {
- memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
- ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
- }
-
- brcmf_set_mpc(ifp, 0);
- brcmf_configure_arp_offload(ifp, false);
-
- /* find the RSN_IE */
- rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
- settings->beacon.tail_len, WLAN_EID_RSN);
-
- /* find the WPA_IE */
- wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
- settings->beacon.tail_len);
-
- if ((wpa_ie != NULL || rsn_ie != NULL)) {
- brcmf_dbg(TRACE, "WPA(2) IE is found\n");
- if (wpa_ie != NULL) {
- /* WPA IE */
- err = brcmf_configure_wpaie(ndev, wpa_ie, false);
- if (err < 0)
- goto exit;
- } else {
- /* RSN IE */
- err = brcmf_configure_wpaie(ndev,
- (struct brcmf_vs_tlv *)rsn_ie, true);
- if (err < 0)
- goto exit;
- }
- } else {
- brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
- brcmf_configure_opensecurity(ifp);
- }
-
- brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
-
- chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
- err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
- if (err < 0) {
- brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err);
- goto exit;
- }
-
- if (settings->beacon_interval) {
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
- settings->beacon_interval);
- if (err < 0) {
- brcmf_err("Beacon Interval Set Error, %d\n", err);
- goto exit;
- }
- }
- if (settings->dtim_period) {
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
- settings->dtim_period);
- if (err < 0) {
- brcmf_err("DTIM Interval Set Error, %d\n", err);
- goto exit;
- }
- }
-
- if (dev_role == NL80211_IFTYPE_AP) {
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
- if (err < 0) {
- brcmf_err("BRCMF_C_DOWN error %d\n", err);
- goto exit;
- }
- brcmf_fil_iovar_int_set(ifp, "apsta", 0);
- }
-
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
- if (err < 0) {
- brcmf_err("SET INFRA error %d\n", err);
- goto exit;
- }
- if (dev_role == NL80211_IFTYPE_AP) {
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
- if (err < 0) {
- brcmf_err("setting AP mode failed %d\n", err);
- goto exit;
- }
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
- if (err < 0) {
- brcmf_err("BRCMF_C_UP error (%d)\n", err);
- goto exit;
- }
-
- memset(&join_params, 0, sizeof(join_params));
- /* join parameters starts with ssid */
- memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
- /* create softap */
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
- &join_params, sizeof(join_params));
- if (err < 0) {
- brcmf_err("SET SSID error (%d)\n", err);
- goto exit;
- }
- brcmf_dbg(TRACE, "AP mode configuration complete\n");
- } else {
- err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
- sizeof(ssid_le));
- if (err < 0) {
- brcmf_err("setting ssid failed %d\n", err);
- goto exit;
- }
- bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
- bss_enable.enable = cpu_to_le32(1);
- err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
- sizeof(bss_enable));
- if (err < 0) {
- brcmf_err("bss_enable config failed %d\n", err);
- goto exit;
- }
-
- brcmf_dbg(TRACE, "GO mode configuration complete\n");
- }
- clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
- set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
-
-exit:
- if (err) {
- brcmf_set_mpc(ifp, 1);
- brcmf_configure_arp_offload(ifp, true);
- }
- return err;
-}
-
-static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err;
- struct brcmf_fil_bss_enable_le bss_enable;
- struct brcmf_join_params join_params;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
- /* Due to most likely deauths outstanding we sleep */
- /* first to make sure they get processed by fw. */
- msleep(400);
-
- memset(&join_params, 0, sizeof(join_params));
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
- &join_params, sizeof(join_params));
- if (err < 0)
- brcmf_err("SET SSID error (%d)\n", err);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
- if (err < 0)
- brcmf_err("BRCMF_C_UP error %d\n", err);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
- if (err < 0)
- brcmf_err("setting AP mode failed %d\n", err);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
- if (err < 0)
- brcmf_err("setting INFRA mode failed %d\n", err);
- } else {
- bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
- bss_enable.enable = cpu_to_le32(0);
- err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
- sizeof(bss_enable));
- if (err < 0)
- brcmf_err("bss_enable config failed %d\n", err);
- }
- brcmf_set_mpc(ifp, 1);
- brcmf_configure_arp_offload(ifp, true);
- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
- clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
-
- return err;
-}
-
-static s32
-brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_beacon_data *info)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
-
- return err;
-}
-
-static int
-brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
- const u8 *mac)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_scb_val_le scbval;
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err;
-
- if (!mac)
- return -EFAULT;
-
- brcmf_dbg(TRACE, "Enter %pM\n", mac);
-
- if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
- ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- memcpy(&scbval.ea, mac, ETH_ALEN);
- scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
- &scbval, sizeof(scbval));
- if (err)
- brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
-
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-
-static void
-brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u16 frame_type, bool reg)
-{
- struct brcmf_cfg80211_vif *vif;
- u16 mgmt_type;
-
- brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
-
- mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
- vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
- if (reg)
- vif->mgmt_rx_reg |= BIT(mgmt_type);
- else
- vif->mgmt_rx_reg &= ~BIT(mgmt_type);
-}
-
-
-static int
-brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
- struct cfg80211_mgmt_tx_params *params, u64 *cookie)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct ieee80211_channel *chan = params->chan;
- const u8 *buf = params->buf;
- size_t len = params->len;
- const struct ieee80211_mgmt *mgmt;
- struct brcmf_cfg80211_vif *vif;
- s32 err = 0;
- s32 ie_offset;
- s32 ie_len;
- struct brcmf_fil_action_frame_le *action_frame;
- struct brcmf_fil_af_params_le *af_params;
- bool ack;
- s32 chan_nr;
- u32 freq;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- *cookie = 0;
-
- mgmt = (const struct ieee80211_mgmt *)buf;
-
- if (!ieee80211_is_mgmt(mgmt->frame_control)) {
- brcmf_err("Driver only allows MGMT packet type\n");
- return -EPERM;
- }
-
- vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
-
- if (ieee80211_is_probe_resp(mgmt->frame_control)) {
- /* Right now the only reason to get a probe response */
- /* is for p2p listen response or for p2p GO from */
- /* wpa_supplicant. Unfortunately the probe is send */
- /* on primary ndev, while dongle wants it on the p2p */
- /* vif. Since this is only reason for a probe */
- /* response to be sent, the vif is taken from cfg. */
- /* If ever desired to send proberesp for non p2p */
- /* response then data should be checked for */
- /* "DIRECT-". Note in future supplicant will take */
- /* dedicated p2p wdev to do this and then this 'hack'*/
- /* is not needed anymore. */
- ie_offset = DOT11_MGMT_HDR_LEN +
- DOT11_BCN_PRB_FIXED_LEN;
- ie_len = len - ie_offset;
- if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
- vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- err = brcmf_vif_set_mgmt_ie(vif,
- BRCMF_VNDR_IE_PRBRSP_FLAG,
- &buf[ie_offset],
- ie_len);
- cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
- GFP_KERNEL);
- } else if (ieee80211_is_action(mgmt->frame_control)) {
- af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
- if (af_params == NULL) {
- brcmf_err("unable to allocate frame\n");
- err = -ENOMEM;
- goto exit;
- }
- action_frame = &af_params->action_frame;
- /* Add the packet Id */
- action_frame->packet_id = cpu_to_le32(*cookie);
- /* Add BSSID */
- memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
- memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
- /* Add the length exepted for 802.11 header */
- action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
- /* Add the channel. Use the one specified as parameter if any or
- * the current one (got from the firmware) otherwise
- */
- if (chan)
- freq = chan->center_freq;
- else
- brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
- &freq);
- chan_nr = ieee80211_frequency_to_channel(freq);
- af_params->channel = cpu_to_le32(chan_nr);
-
- memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
- le16_to_cpu(action_frame->len));
-
- brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
- *cookie, le16_to_cpu(action_frame->len), freq);
-
- ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
- af_params);
-
- cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
- GFP_KERNEL);
- kfree(af_params);
- } else {
- brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
- brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
- }
-
-exit:
- return err;
-}
-
-
-static int
-brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u64 cookie)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_cfg80211_vif *vif;
- int err = 0;
-
- brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
-
- vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- if (vif == NULL) {
- brcmf_err("No p2p device available for probe response\n");
- err = -ENODEV;
- goto exit;
- }
- brcmf_p2p_cancel_remain_on_channel(vif->ifp);
-exit:
- return err;
-}
-
-static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- enum nl80211_crit_proto_id proto,
- u16 duration)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_cfg80211_vif *vif;
-
- vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
-
- /* only DHCP support for now */
- if (proto != NL80211_CRIT_PROTO_DHCP)
- return -EINVAL;
-
- /* suppress and abort scanning */
- set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
- brcmf_abort_scanning(cfg);
-
- return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
-}
-
-static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
- struct wireless_dev *wdev)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct brcmf_cfg80211_vif *vif;
-
- vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
-
- brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
- clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
-}
-
-static s32
-brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- switch (e->reason) {
- case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
- brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
- break;
- case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
- brcmf_dbg(TRACE, "TDLS Peer Connected\n");
- brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
- break;
- case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
- brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
- brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
- break;
- }
-
- return 0;
-}
-
-static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
-{
- int ret;
-
- switch (oper) {
- case NL80211_TDLS_DISCOVERY_REQ:
- ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
- break;
- case NL80211_TDLS_SETUP:
- ret = BRCMF_TDLS_MANUAL_EP_CREATE;
- break;
- case NL80211_TDLS_TEARDOWN:
- ret = BRCMF_TDLS_MANUAL_EP_DELETE;
- break;
- default:
- brcmf_err("unsupported operation: %d\n", oper);
- ret = -EOPNOTSUPP;
- }
- return ret;
-}
-
-static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
- struct net_device *ndev, const u8 *peer,
- enum nl80211_tdls_operation oper)
-{
- struct brcmf_if *ifp;
- struct brcmf_tdls_iovar_le info;
- int ret = 0;
-
- ret = brcmf_convert_nl80211_tdls_oper(oper);
- if (ret < 0)
- return ret;
-
- ifp = netdev_priv(ndev);
- memset(&info, 0, sizeof(info));
- info.mode = (u8)ret;
- if (peer)
- memcpy(info.ea, peer, ETH_ALEN);
-
- ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
- &info, sizeof(info));
- if (ret < 0)
- brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);
-
- return ret;
-}
-
-static struct cfg80211_ops wl_cfg80211_ops = {
- .add_virtual_intf = brcmf_cfg80211_add_iface,
- .del_virtual_intf = brcmf_cfg80211_del_iface,
- .change_virtual_intf = brcmf_cfg80211_change_iface,
- .scan = brcmf_cfg80211_scan,
- .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
- .join_ibss = brcmf_cfg80211_join_ibss,
- .leave_ibss = brcmf_cfg80211_leave_ibss,
- .get_station = brcmf_cfg80211_get_station,
- .set_tx_power = brcmf_cfg80211_set_tx_power,
- .get_tx_power = brcmf_cfg80211_get_tx_power,
- .add_key = brcmf_cfg80211_add_key,
- .del_key = brcmf_cfg80211_del_key,
- .get_key = brcmf_cfg80211_get_key,
- .set_default_key = brcmf_cfg80211_config_default_key,
- .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
- .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
- .connect = brcmf_cfg80211_connect,
- .disconnect = brcmf_cfg80211_disconnect,
- .suspend = brcmf_cfg80211_suspend,
- .resume = brcmf_cfg80211_resume,
- .set_pmksa = brcmf_cfg80211_set_pmksa,
- .del_pmksa = brcmf_cfg80211_del_pmksa,
- .flush_pmksa = brcmf_cfg80211_flush_pmksa,
- .start_ap = brcmf_cfg80211_start_ap,
- .stop_ap = brcmf_cfg80211_stop_ap,
- .change_beacon = brcmf_cfg80211_change_beacon,
- .del_station = brcmf_cfg80211_del_station,
- .sched_scan_start = brcmf_cfg80211_sched_scan_start,
- .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
- .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
- .mgmt_tx = brcmf_cfg80211_mgmt_tx,
- .remain_on_channel = brcmf_p2p_remain_on_channel,
- .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
- .start_p2p_device = brcmf_p2p_start_device,
- .stop_p2p_device = brcmf_p2p_stop_device,
- .crit_proto_start = brcmf_cfg80211_crit_proto_start,
- .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
- .tdls_oper = brcmf_cfg80211_tdls_oper,
-};
-
-struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
- enum nl80211_iftype type,
- bool pm_block)
-{
- struct brcmf_cfg80211_vif *vif;
-
- brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
- sizeof(*vif));
- vif = kzalloc(sizeof(*vif), GFP_KERNEL);
- if (!vif)
- return ERR_PTR(-ENOMEM);
-
- vif->wdev.wiphy = cfg->wiphy;
- vif->wdev.iftype = type;
-
- vif->pm_block = pm_block;
- vif->roam_off = -1;
-
- brcmf_init_prof(&vif->profile);
-
- list_add_tail(&vif->list, &cfg->vif_list);
- return vif;
-}
-
-void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
-{
- list_del(&vif->list);
- kfree(vif);
-}
-
-void brcmf_cfg80211_free_netdev(struct net_device *ndev)
-{
- struct brcmf_cfg80211_vif *vif;
- struct brcmf_if *ifp;
-
- ifp = netdev_priv(ndev);
- vif = ifp->vif;
-
- brcmf_free_vif(vif);
- free_netdev(ndev);
-}
-
-static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
-{
- u32 event = e->event_code;
- u32 status = e->status;
-
- if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
- brcmf_dbg(CONN, "Processing set ssid\n");
- return true;
- }
-
- return false;
-}
-
-static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
-{
- u32 event = e->event_code;
- u16 flags = e->flags;
-
- if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
- (event == BRCMF_E_DISASSOC_IND) ||
- ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
- brcmf_dbg(CONN, "Processing link down\n");
- return true;
- }
- return false;
-}
-
-static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
- const struct brcmf_event_msg *e)
-{
- u32 event = e->event_code;
- u32 status = e->status;
-
- if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
- brcmf_dbg(CONN, "Processing Link %s & no network found\n",
- e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
- return true;
- }
-
- if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
- brcmf_dbg(CONN, "Processing connecting & no network found\n");
- return true;
- }
-
- return false;
-}
-
-static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
-
- kfree(conn_info->req_ie);
- conn_info->req_ie = NULL;
- conn_info->req_ie_len = 0;
- kfree(conn_info->resp_ie);
- conn_info->resp_ie = NULL;
- conn_info->resp_ie_len = 0;
-}
-
-static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp)
-{
- struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
- struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
- u32 req_len;
- u32 resp_len;
- s32 err = 0;
-
- brcmf_clear_assoc_ies(cfg);
-
- err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
- cfg->extra_buf, WL_ASSOC_INFO_MAX);
- if (err) {
- brcmf_err("could not get assoc info (%d)\n", err);
- return err;
- }
- assoc_info =
- (struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
- req_len = le32_to_cpu(assoc_info->req_len);
- resp_len = le32_to_cpu(assoc_info->resp_len);
- if (req_len) {
- err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
- cfg->extra_buf,
- WL_ASSOC_INFO_MAX);
- if (err) {
- brcmf_err("could not get assoc req (%d)\n", err);
- return err;
- }
- conn_info->req_ie_len = req_len;
- conn_info->req_ie =
- kmemdup(cfg->extra_buf, conn_info->req_ie_len,
- GFP_KERNEL);
- } else {
- conn_info->req_ie_len = 0;
- conn_info->req_ie = NULL;
- }
- if (resp_len) {
- err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
- cfg->extra_buf,
- WL_ASSOC_INFO_MAX);
- if (err) {
- brcmf_err("could not get assoc resp (%d)\n", err);
- return err;
- }
- conn_info->resp_ie_len = resp_len;
- conn_info->resp_ie =
- kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
- GFP_KERNEL);
- } else {
- conn_info->resp_ie_len = 0;
- conn_info->resp_ie = NULL;
- }
- brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
- conn_info->req_ie_len, conn_info->resp_ie_len);
-
- return err;
-}
-
-static s32
-brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- const struct brcmf_event_msg *e)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
- struct wiphy *wiphy = cfg_to_wiphy(cfg);
- struct ieee80211_channel *notify_channel = NULL;
- struct ieee80211_supported_band *band;
- struct brcmf_bss_info_le *bi;
- struct brcmu_chan ch;
- u32 freq;
- s32 err = 0;
- u8 *buf;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- brcmf_get_assoc_ies(cfg, ifp);
- memcpy(profile->bssid, e->addr, ETH_ALEN);
- brcmf_update_bss_info(cfg, ifp);
-
- buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (buf == NULL) {
- err = -ENOMEM;
- goto done;
- }
-
- /* data sent to dongle has to be little endian */
- *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
- buf, WL_BSS_INFO_MAX);
-
- if (err)
- goto done;
-
- bi = (struct brcmf_bss_info_le *)(buf + 4);
- ch.chspec = le16_to_cpu(bi->chanspec);
- cfg->d11inf.decchspec(&ch);
-
- if (ch.band == BRCMU_CHAN_BAND_2G)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
- freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
- notify_channel = ieee80211_get_channel(wiphy, freq);
-
-done:
- kfree(buf);
- cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
- brcmf_dbg(CONN, "Report roaming result\n");
-
- set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
-static s32
-brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev, const struct brcmf_event_msg *e,
- bool completed)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
- &ifp->vif->sme_state)) {
- if (completed) {
- brcmf_get_assoc_ies(cfg, ifp);
- memcpy(profile->bssid, e->addr, ETH_ALEN);
- brcmf_update_bss_info(cfg, ifp);
- set_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state);
- }
- cfg80211_connect_result(ndev,
- (u8 *)profile->bssid,
- conn_info->req_ie,
- conn_info->req_ie_len,
- conn_info->resp_ie,
- conn_info->resp_ie_len,
- completed ? WLAN_STATUS_SUCCESS :
- WLAN_STATUS_AUTH_TIMEOUT,
- GFP_KERNEL);
- brcmf_dbg(CONN, "Report connect result - connection %s\n",
- completed ? "succeeded" : "failed");
- }
- brcmf_dbg(TRACE, "Exit\n");
- return 0;
-}
-
-static s32
-brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data)
-{
- static int generation;
- u32 event = e->event_code;
- u32 reason = e->reason;
- struct station_info sinfo;
-
- brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
- if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
- ndev != cfg_to_ndev(cfg)) {
- brcmf_dbg(CONN, "AP mode link down\n");
- complete(&cfg->vif_disabled);
- return 0;
- }
-
- if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
- (reason == BRCMF_E_STATUS_SUCCESS)) {
- memset(&sinfo, 0, sizeof(sinfo));
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
- if (!data) {
- brcmf_err("No IEs present in ASSOC/REASSOC_IND");
- return -EINVAL;
- }
- sinfo.assoc_req_ies = data;
- sinfo.assoc_req_ies_len = e->datalen;
- generation++;
- sinfo.generation = generation;
- cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
- } else if ((event == BRCMF_E_DISASSOC_IND) ||
- (event == BRCMF_E_DEAUTH_IND) ||
- (event == BRCMF_E_DEAUTH)) {
- cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
- }
- return 0;
-}
-
-static s32
-brcmf_notify_connect_status(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct net_device *ndev = ifp->ndev;
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct ieee80211_channel *chan;
- s32 err = 0;
-
- if ((e->event_code == BRCMF_E_DEAUTH) ||
- (e->event_code == BRCMF_E_DEAUTH_IND) ||
- (e->event_code == BRCMF_E_DISASSOC_IND) ||
- ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
- brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
- }
-
- if (brcmf_is_apmode(ifp->vif)) {
- err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
- } else if (brcmf_is_linkup(e)) {
- brcmf_dbg(CONN, "Linkup\n");
- if (brcmf_is_ibssmode(ifp->vif)) {
- chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
- memcpy(profile->bssid, e->addr, ETH_ALEN);
- wl_inform_ibss(cfg, ndev, e->addr);
- cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
- clear_bit(BRCMF_VIF_STATUS_CONNECTING,
- &ifp->vif->sme_state);
- set_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state);
- } else
- brcmf_bss_connect_done(cfg, ndev, e, true);
- } else if (brcmf_is_linkdown(e)) {
- brcmf_dbg(CONN, "Linkdown\n");
- if (!brcmf_is_ibssmode(ifp->vif)) {
- brcmf_bss_connect_done(cfg, ndev, e, false);
- }
- brcmf_link_down(ifp->vif);
- brcmf_init_prof(ndev_to_prof(ndev));
- if (ndev != cfg_to_ndev(cfg))
- complete(&cfg->vif_disabled);
- } else if (brcmf_is_nonetwork(cfg, e)) {
- if (brcmf_is_ibssmode(ifp->vif))
- clear_bit(BRCMF_VIF_STATUS_CONNECTING,
- &ifp->vif->sme_state);
- else
- brcmf_bss_connect_done(cfg, ndev, e, false);
- }
-
- return err;
-}
-
-static s32
-brcmf_notify_roaming_status(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- u32 event = e->event_code;
- u32 status = e->status;
-
- if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
- brcmf_bss_roaming_done(cfg, ifp->ndev, e);
- else
- brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
- }
-
- return 0;
-}
-
-static s32
-brcmf_notify_mic_status(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- u16 flags = e->flags;
- enum nl80211_key_type key_type;
-
- if (flags & BRCMF_EVENT_MSG_GROUP)
- key_type = NL80211_KEYTYPE_GROUP;
- else
- key_type = NL80211_KEYTYPE_PAIRWISE;
-
- cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
- NULL, GFP_KERNEL);
-
- return 0;
-}
-
-static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
- struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
- struct brcmf_cfg80211_vif *vif;
-
- brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
- ifevent->action, ifevent->flags, ifevent->ifidx,
- ifevent->bssidx);
-
- mutex_lock(&event->vif_event_lock);
- event->action = ifevent->action;
- vif = event->vif;
-
- switch (ifevent->action) {
- case BRCMF_E_IF_ADD:
- /* waiting process may have timed out */
- if (!cfg->vif_event.vif) {
- mutex_unlock(&event->vif_event_lock);
- return -EBADF;
- }
-
- ifp->vif = vif;
- vif->ifp = ifp;
- if (ifp->ndev) {
- vif->wdev.netdev = ifp->ndev;
- ifp->ndev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
- }
- mutex_unlock(&event->vif_event_lock);
- wake_up(&event->vif_wq);
- return 0;
-
- case BRCMF_E_IF_DEL:
- mutex_unlock(&event->vif_event_lock);
- /* event may not be upon user request */
- if (brcmf_cfg80211_vif_event_armed(cfg))
- wake_up(&event->vif_wq);
- return 0;
-
- case BRCMF_E_IF_CHANGE:
- mutex_unlock(&event->vif_event_lock);
- wake_up(&event->vif_wq);
- return 0;
-
- default:
- mutex_unlock(&event->vif_event_lock);
- break;
- }
- return -EINVAL;
-}
-
-static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
-{
- conf->frag_threshold = (u32)-1;
- conf->rts_threshold = (u32)-1;
- conf->retry_short = (u32)-1;
- conf->retry_long = (u32)-1;
- conf->tx_power = -1;
-}
-
-static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
-{
- brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
- brcmf_notify_roaming_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
- brcmf_notify_mic_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
- brcmf_notify_connect_status);
- brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
- brcmf_notify_sched_scan_results);
- brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
- brcmf_notify_vif_event);
- brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
- brcmf_p2p_notify_rx_mgmt_p2p_probereq);
- brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
- brcmf_p2p_notify_listen_complete);
- brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
- brcmf_p2p_notify_action_frame_rx);
- brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
- brcmf_p2p_notify_action_tx_complete);
- brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
- brcmf_p2p_notify_action_tx_complete);
-}
-
-static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
-{
- kfree(cfg->conf);
- cfg->conf = NULL;
- kfree(cfg->escan_ioctl_buf);
- cfg->escan_ioctl_buf = NULL;
- kfree(cfg->extra_buf);
- cfg->extra_buf = NULL;
- kfree(cfg->pmk_list);
- cfg->pmk_list = NULL;
-}
-
-static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
-{
- cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
- if (!cfg->conf)
- goto init_priv_mem_out;
- cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
- if (!cfg->escan_ioctl_buf)
- goto init_priv_mem_out;
- cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
- if (!cfg->extra_buf)
- goto init_priv_mem_out;
- cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
- if (!cfg->pmk_list)
- goto init_priv_mem_out;
-
- return 0;
-
-init_priv_mem_out:
- brcmf_deinit_priv_mem(cfg);
-
- return -ENOMEM;
-}
-
-static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
-{
- s32 err = 0;
-
- cfg->scan_request = NULL;
- cfg->pwr_save = true;
- cfg->active_scan = true; /* we do active scan per default */
- cfg->dongle_up = false; /* dongle is not up yet */
- err = brcmf_init_priv_mem(cfg);
- if (err)
- return err;
- brcmf_register_event_handlers(cfg);
- mutex_init(&cfg->usr_sync);
- brcmf_init_escan(cfg);
- brcmf_init_conf(cfg->conf);
- init_completion(&cfg->vif_disabled);
- return err;
-}
-
-static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
-{
- cfg->dongle_up = false; /* dongle down */
- brcmf_abort_scanning(cfg);
- brcmf_deinit_priv_mem(cfg);
-}
-
-static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
-{
- init_waitqueue_head(&event->vif_wq);
- mutex_init(&event->vif_event_lock);
-}
-
-static s32
-brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
-{
- s32 err = 0;
- __le32 roamtrigger[2];
- __le32 roam_delta[2];
-
- /*
- * Setup timeout if Beacons are lost and roam is
- * off to report link down
- */
- if (brcmf_roamoff) {
- err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
- if (err) {
- brcmf_err("bcn_timeout error (%d)\n", err);
- goto dongle_rom_out;
- }
- }
-
- /*
- * Enable/Disable built-in roaming to allow supplicant
- * to take care of roaming
- */
- brcmf_dbg(INFO, "Internal Roaming = %s\n",
- brcmf_roamoff ? "Off" : "On");
- err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
- if (err) {
- brcmf_err("roam_off error (%d)\n", err);
- goto dongle_rom_out;
- }
-
- roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
- roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
- (void *)roamtrigger, sizeof(roamtrigger));
- if (err) {
- brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
- goto dongle_rom_out;
- }
-
- roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
- roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
- (void *)roam_delta, sizeof(roam_delta));
- if (err) {
- brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
- goto dongle_rom_out;
- }
-
-dongle_rom_out:
- return err;
-}
-
-static s32
-brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
- s32 scan_unassoc_time, s32 scan_passive_time)
-{
- s32 err = 0;
-
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
- scan_assoc_time);
- if (err) {
- if (err == -EOPNOTSUPP)
- brcmf_dbg(INFO, "Scan assoc time is not supported\n");
- else
- brcmf_err("Scan assoc time error (%d)\n", err);
- goto dongle_scantime_out;
- }
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
- scan_unassoc_time);
- if (err) {
- if (err == -EOPNOTSUPP)
- brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
- else
- brcmf_err("Scan unassoc time error (%d)\n", err);
- goto dongle_scantime_out;
- }
-
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
- scan_passive_time);
- if (err) {
- if (err == -EOPNOTSUPP)
- brcmf_dbg(INFO, "Scan passive time is not supported\n");
- else
- brcmf_err("Scan passive time error (%d)\n", err);
- goto dongle_scantime_out;
- }
-
-dongle_scantime_out:
- return err;
-}
-
-/* Filter the list of channels received from firmware counting only
- * the 20MHz channels. The wiphy band data only needs those which get
- * flagged to indicate if they can take part in higher bandwidth.
- */
-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
- struct brcmf_chanspec_list *chlist,
- u32 chcnt[])
-{
- u32 total = le32_to_cpu(chlist->count);
- struct brcmu_chan ch;
- int i;
-
- for (i = 0; i < total; i++) {
- ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
- cfg->d11inf.decchspec(&ch);
-
- /* Firmware gives a ordered list. We skip non-20MHz
- * channels is 2G. For 5G we can abort upon reaching
- * a non-20MHz channel in the list.
- */
- if (ch.bw != BRCMU_CHAN_BW_20) {
- if (ch.band == BRCMU_CHAN_BAND_5G)
- break;
- else
- continue;
- }
-
- if (ch.band == BRCMU_CHAN_BAND_2G)
- chcnt[0] += 1;
- else if (ch.band == BRCMU_CHAN_BAND_5G)
- chcnt[1] += 1;
- }
-}
-
-static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
- struct brcmu_chan *ch)
-{
- u32 ht40_flag;
-
- ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
- if (ch->sb == BRCMU_CHAN_SB_U) {
- if (ht40_flag == IEEE80211_CHAN_NO_HT40)
- channel->flags &= ~IEEE80211_CHAN_NO_HT40;
- channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
- } else {
- /* It should be one of
- * IEEE80211_CHAN_NO_HT40 or
- * IEEE80211_CHAN_NO_HT40PLUS
- */
- channel->flags &= ~IEEE80211_CHAN_NO_HT40;
- if (ht40_flag == IEEE80211_CHAN_NO_HT40)
- channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
- }
-}
-
-static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
- u32 bw_cap[])
-{
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- struct ieee80211_supported_band *band;
- struct ieee80211_channel *channel;
- struct wiphy *wiphy;
- struct brcmf_chanspec_list *list;
- struct brcmu_chan ch;
- int err;
- u8 *pbuf;
- u32 i, j;
- u32 total;
- u32 chaninfo;
- u32 chcnt[2] = { 0, 0 };
- u32 index;
-
- pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
-
- if (pbuf == NULL)
- return -ENOMEM;
-
- list = (struct brcmf_chanspec_list *)pbuf;
-
- err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
- BRCMF_DCMD_MEDLEN);
- if (err) {
- brcmf_err("get chanspecs error (%d)\n", err);
- goto fail_pbuf;
- }
-
- brcmf_count_20mhz_channels(cfg, list, chcnt);
- wiphy = cfg_to_wiphy(cfg);
- if (chcnt[0]) {
- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->channels = kcalloc(chcnt[0], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_2GHZ] = band;
- }
- if (chcnt[1]) {
- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->channels = kcalloc(chcnt[1], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_5GHZ] = band;
- }
-
- total = le32_to_cpu(list->count);
- for (i = 0; i < total; i++) {
- ch.chspec = (u16)le32_to_cpu(list->element[i]);
- cfg->d11inf.decchspec(&ch);
-
- if (ch.band == BRCMU_CHAN_BAND_2G) {
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- } else if (ch.band == BRCMU_CHAN_BAND_5G) {
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
- } else {
- brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
- continue;
- }
- if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
- ch.bw == BRCMU_CHAN_BW_40)
- continue;
- if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
- ch.bw == BRCMU_CHAN_BW_80)
- continue;
-
- channel = band->channels;
- index = band->n_channels;
- for (j = 0; j < band->n_channels; j++) {
- if (channel[j].hw_value == ch.chnum) {
- index = j;
- break;
- }
- }
- channel[index].center_freq =
- ieee80211_channel_to_frequency(ch.chnum, band->band);
- channel[index].hw_value = ch.chnum;
-
- /* assuming the chanspecs order is HT20,
- * HT40 upper, HT40 lower, and VHT80.
- */
- if (ch.bw == BRCMU_CHAN_BW_80) {
- channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
- } else if (ch.bw == BRCMU_CHAN_BW_40) {
- brcmf_update_bw40_channel_flag(&channel[index], &ch);
- } else {
- /* disable other bandwidths for now as mentioned
- * order assure they are enabled for subsequent
- * chanspecs.
- */
- channel[index].flags = IEEE80211_CHAN_NO_HT40 |
- IEEE80211_CHAN_NO_80MHZ;
- ch.bw = BRCMU_CHAN_BW_20;
- cfg->d11inf.encchspec(&ch);
- chaninfo = ch.chspec;
- err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
- &chaninfo);
- if (!err) {
- if (chaninfo & WL_CHAN_RADAR)
- channel[index].flags |=
- (IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_NO_IR);
- if (chaninfo & WL_CHAN_PASSIVE)
- channel[index].flags |=
- IEEE80211_CHAN_NO_IR;
- }
- }
- if (index == band->n_channels)
- band->n_channels++;
- }
- kfree(pbuf);
- return 0;
-
-fail_band2g:
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
-fail_pbuf:
- kfree(pbuf);
- return err;
-}
-
-static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- struct ieee80211_supported_band *band;
- struct brcmf_fil_bwcap_le band_bwcap;
- struct brcmf_chanspec_list *list;
- u8 *pbuf;
- u32 val;
- int err;
- struct brcmu_chan ch;
- u32 num_chan;
- int i, j;
-
- /* verify support for bw_cap command */
- val = WLC_BAND_5G;
- err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);
-
- if (!err) {
- /* only set 2G bandwidth using bw_cap command */
- band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
- band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
- err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
- sizeof(band_bwcap));
- } else {
- brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
- val = WLC_N_BW_40ALL;
- err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
- }
-
- if (!err) {
- /* update channel info in 2G band */
- pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
-
- if (pbuf == NULL)
- return -ENOMEM;
-
- ch.band = BRCMU_CHAN_BAND_2G;
- ch.bw = BRCMU_CHAN_BW_40;
- ch.sb = BRCMU_CHAN_SB_NONE;
- ch.chnum = 0;
- cfg->d11inf.encchspec(&ch);
-
- /* pass encoded chanspec in query */
- *(__le16 *)pbuf = cpu_to_le16(ch.chspec);
-
- err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
- BRCMF_DCMD_MEDLEN);
- if (err) {
- brcmf_err("get chanspecs error (%d)\n", err);
- kfree(pbuf);
- return err;
- }
-
- band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
- list = (struct brcmf_chanspec_list *)pbuf;
- num_chan = le32_to_cpu(list->count);
- for (i = 0; i < num_chan; i++) {
- ch.chspec = (u16)le32_to_cpu(list->element[i]);
- cfg->d11inf.decchspec(&ch);
- if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
- continue;
- if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
- continue;
- for (j = 0; j < band->n_channels; j++) {
- if (band->channels[j].hw_value == ch.chnum)
- break;
- }
- if (WARN_ON(j == band->n_channels))
- continue;
-
- brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
- }
- kfree(pbuf);
- }
- return err;
-}
-
-static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
-{
- u32 band, mimo_bwcap;
- int err;
-
- band = WLC_BAND_2G;
- err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
- if (!err) {
- bw_cap[IEEE80211_BAND_2GHZ] = band;
- band = WLC_BAND_5G;
- err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
- if (!err) {
- bw_cap[IEEE80211_BAND_5GHZ] = band;
- return;
- }
- WARN_ON(1);
- return;
- }
- brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
- mimo_bwcap = 0;
- err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
- if (err)
- /* assume 20MHz if firmware does not give a clue */
- mimo_bwcap = WLC_N_BW_20ALL;
-
- switch (mimo_bwcap) {
- case WLC_N_BW_40ALL:
- bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
- /* fall-thru */
- case WLC_N_BW_20IN2G_40IN5G:
- bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
- /* fall-thru */
- case WLC_N_BW_20ALL:
- bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
- bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
- break;
- default:
- brcmf_err("invalid mimo_bw_cap value\n");
- }
-}
-
-static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
- u32 bw_cap[2], u32 nchain)
-{
- band->ht_cap.ht_supported = true;
- if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
- band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
- band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- }
- band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
- band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
- band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
- memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
- band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-}
-
-static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
-{
- u16 mcs_map;
- int i;
-
- for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
- mcs_map = (mcs_map << 2) | supp;
-
- return cpu_to_le16(mcs_map);
-}
-
-static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
- u32 bw_cap[2], u32 nchain)
-{
- __le16 mcs_map;
-
- /* not allowed in 2.4G band */
- if (band->band == IEEE80211_BAND_2GHZ)
- return;
-
- band->vht_cap.vht_supported = true;
- /* 80MHz is mandatory */
- band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
- if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
- band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
- band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
- }
- /* all support 256-QAM */
- mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
- band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
- band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
-}
-
-static int brcmf_setup_wiphybands(struct wiphy *wiphy)
-{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
- u32 nmode = 0;
- u32 vhtmode = 0;
- u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
- u32 rxchain;
- u32 nchain;
- int err;
- s32 i;
- struct ieee80211_supported_band *band;
-
- (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
- err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
- if (err) {
- brcmf_err("nmode error (%d)\n", err);
- } else {
- brcmf_get_bwcap(ifp, bw_cap);
- }
- brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
- nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
- bw_cap[IEEE80211_BAND_5GHZ]);
-
- err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
- if (err) {
- brcmf_err("rxchain error (%d)\n", err);
- nchain = 1;
- } else {
- for (nchain = 0; rxchain; nchain++)
- rxchain = rxchain & (rxchain - 1);
- }
- brcmf_dbg(INFO, "nchain=%d\n", nchain);
-
- err = brcmf_construct_chaninfo(cfg, bw_cap);
- if (err) {
- brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
- return err;
- }
-
- wiphy = cfg_to_wiphy(cfg);
- for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
- band = wiphy->bands[i];
- if (band == NULL)
- continue;
-
- if (nmode)
- brcmf_update_ht_cap(band, bw_cap, nchain);
- if (vhtmode)
- brcmf_update_vht_cap(band, bw_cap, nchain);
- }
-
- return 0;
-}
-
-static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
- {
- .max = 2,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
- {
- .max_interfaces = BRCMF_IFACE_MAX_CNT,
- .num_different_channels = 1,
- .n_limits = ARRAY_SIZE(brcmf_iface_limits),
- .limits = brcmf_iface_limits
- }
-};
-
-static const struct ieee80211_txrx_stypes
-brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
- [NL80211_IFTYPE_STATION] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_P2P_CLIENT] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- },
- [NL80211_IFTYPE_P2P_GO] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4) |
- BIT(IEEE80211_STYPE_AUTH >> 4) |
- BIT(IEEE80211_STYPE_DEAUTH >> 4) |
- BIT(IEEE80211_STYPE_ACTION >> 4)
- },
- [NL80211_IFTYPE_P2P_DEVICE] = {
- .tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
- }
-};
-
-static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
-{
- /* scheduled scan settings */
- wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
- wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-}
-
-
-#ifdef CONFIG_PM
-static const struct wiphy_wowlan_support brcmf_wowlan_support = {
- .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
-};
-#endif
-
-static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
-{
-#ifdef CONFIG_PM
- /* wowl settings */
- wiphy->wowlan = &brcmf_wowlan_support;
-#endif
-}
-
-static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
-{
- struct ieee80211_iface_combination ifc_combo;
- wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
- wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
- wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- /* need VSDB firmware feature for concurrent channels */
- ifc_combo = brcmf_iface_combos[0];
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
- ifc_combo.num_different_channels = 2;
- wiphy->iface_combinations = kmemdup(&ifc_combo,
- sizeof(ifc_combo),
- GFP_KERNEL);
- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- wiphy->cipher_suites = __wl_cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
- wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
- WIPHY_FLAG_OFFCHAN_TX |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_SUPPORTS_TDLS;
- if (!brcmf_roamoff)
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
- wiphy->mgmt_stypes = brcmf_txrx_stypes;
- wiphy->max_remain_on_channel_duration = 5000;
- brcmf_wiphy_pno_params(wiphy);
-
- /* vendor commands/events support */
- wiphy->vendor_commands = brcmf_vendor_cmds;
- wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
-
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
- brcmf_wiphy_wowl_params(wiphy);
-
- return brcmf_setup_wiphybands(wiphy);
-}
-
-static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
-{
- struct net_device *ndev;
- struct wireless_dev *wdev;
- struct brcmf_if *ifp;
- s32 power_mode;
- s32 err = 0;
-
- if (cfg->dongle_up)
- return err;
-
- ndev = cfg_to_ndev(cfg);
- wdev = ndev->ieee80211_ptr;
- ifp = netdev_priv(ndev);
-
- /* make sure RF is ready for work */
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
-
- brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
- WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
-
- power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
- if (err)
- goto default_conf_out;
- brcmf_dbg(INFO, "power save set to %s\n",
- (power_mode ? "enabled" : "disabled"));
-
- err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
- if (err)
- goto default_conf_out;
- err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
- NULL, NULL);
- if (err)
- goto default_conf_out;
-
- brcmf_configure_arp_offload(ifp, true);
-
- cfg->dongle_up = true;
-default_conf_out:
-
- return err;
-
-}
-
-static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
-{
- set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
-
- return brcmf_config_dongle(ifp->drvr->config);
-}
-
-static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
-
- /*
- * While going down, if associated with AP disassociate
- * from AP to save power
- */
- if (check_vif_up(ifp->vif)) {
- brcmf_link_down(ifp->vif);
-
- /* Make sure WPA_Supplicant receives all the event
- generated due to DISASSOC call to the fw to keep
- the state fw and WPA_Supplicant state consistent
- */
- brcmf_delay(500);
- }
-
- brcmf_abort_scanning(cfg);
- clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
-
- return 0;
-}
-
-s32 brcmf_cfg80211_up(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- s32 err = 0;
-
- mutex_lock(&cfg->usr_sync);
- err = __brcmf_cfg80211_up(ifp);
- mutex_unlock(&cfg->usr_sync);
-
- return err;
-}
-
-s32 brcmf_cfg80211_down(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- s32 err = 0;
-
- mutex_lock(&cfg->usr_sync);
- err = __brcmf_cfg80211_down(ifp);
- mutex_unlock(&cfg->usr_sync);
-
- return err;
-}
-
-enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
-{
- struct wireless_dev *wdev = &ifp->vif->wdev;
-
- return wdev->iftype;
-}
-
-bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
-{
- struct brcmf_cfg80211_vif *vif;
-
- list_for_each_entry(vif, &cfg->vif_list, list) {
- if (test_bit(state, &vif->sme_state))
- return true;
- }
- return false;
-}
-
-static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
- u8 action)
-{
- u8 evt_action;
-
- mutex_lock(&event->vif_event_lock);
- evt_action = event->action;
- mutex_unlock(&event->vif_event_lock);
- return evt_action == action;
-}
-
-void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
- struct brcmf_cfg80211_vif *vif)
-{
- struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
-
- mutex_lock(&event->vif_event_lock);
- event->vif = vif;
- event->action = 0;
- mutex_unlock(&event->vif_event_lock);
-}
-
-bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
- bool armed;
-
- mutex_lock(&event->vif_event_lock);
- armed = event->vif != NULL;
- mutex_unlock(&event->vif_event_lock);
-
- return armed;
-}
-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
- u8 action, ulong timeout)
-{
- struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
-
- return wait_event_timeout(event->vif_wq,
- vif_event_equals(event, action), timeout);
-}
-
-static void brcmf_free_wiphy(struct wiphy *wiphy)
-{
- kfree(wiphy->iface_combinations);
- if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
- }
- if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
- kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
- kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
- }
- wiphy_free(wiphy);
-}
-
-struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
- struct device *busdev)
-{
- struct net_device *ndev = drvr->iflist[0]->ndev;
- struct brcmf_cfg80211_info *cfg;
- struct wiphy *wiphy;
- struct brcmf_cfg80211_vif *vif;
- struct brcmf_if *ifp;
- s32 err = 0;
- s32 io_type;
- u16 *cap = NULL;
-
- if (!ndev) {
- brcmf_err("ndev is invalid\n");
- return NULL;
- }
-
- ifp = netdev_priv(ndev);
- wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
- if (!wiphy) {
- brcmf_err("Could not allocate wiphy device\n");
- return NULL;
- }
- set_wiphy_dev(wiphy, busdev);
-
- cfg = wiphy_priv(wiphy);
- cfg->wiphy = wiphy;
- cfg->pub = drvr;
- init_vif_event(&cfg->vif_event);
- INIT_LIST_HEAD(&cfg->vif_list);
-
- vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
- if (IS_ERR(vif))
- goto wiphy_out;
-
- vif->ifp = ifp;
- vif->wdev.netdev = ndev;
- ndev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
-
- err = wl_init_priv(cfg);
- if (err) {
- brcmf_err("Failed to init iwm_priv (%d)\n", err);
- brcmf_free_vif(vif);
- goto wiphy_out;
- }
- ifp->vif = vif;
-
- /* determine d11 io type before wiphy setup */
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
- if (err) {
- brcmf_err("Failed to get D11 version (%d)\n", err);
- goto priv_out;
- }
- cfg->d11inf.io_type = (u8)io_type;
- brcmu_d11_attach(&cfg->d11inf);
-
- err = brcmf_setup_wiphy(wiphy, ifp);
- if (err < 0)
- goto priv_out;
-
- brcmf_dbg(INFO, "Registering custom regulatory\n");
- wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
- wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
-
- /* firmware defaults to 40MHz disabled in 2G band. We signal
- * cfg80211 here that we do and have it decide we can enable
- * it. But first check if device does support 2G operation.
- */
- if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
- cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
- *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- }
- err = wiphy_register(wiphy);
- if (err < 0) {
- brcmf_err("Could not register wiphy device (%d)\n", err);
- goto priv_out;
- }
-
- /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
- * setup 40MHz in 2GHz band and enable OBSS scanning.
- */
- if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
- err = brcmf_enable_bw40_2g(cfg);
- if (!err)
- err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
- BRCMF_OBSS_COEX_AUTO);
- else
- *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- }
-
- err = brcmf_p2p_attach(cfg);
- if (err) {
- brcmf_err("P2P initilisation failed (%d)\n", err);
- goto wiphy_unreg_out;
- }
- err = brcmf_btcoex_attach(cfg);
- if (err) {
- brcmf_err("BT-coex initialisation failed (%d)\n", err);
- brcmf_p2p_detach(&cfg->p2p);
- goto wiphy_unreg_out;
- }
-
- err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
- if (err) {
- brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
- wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
- } else {
- brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
- brcmf_notify_tdls_peer_event);
- }
-
- return cfg;
-
-wiphy_unreg_out:
- wiphy_unregister(cfg->wiphy);
-priv_out:
- wl_deinit_priv(cfg);
- brcmf_free_vif(vif);
-wiphy_out:
- brcmf_free_wiphy(wiphy);
- return NULL;
-}
-
-void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
-{
- if (!cfg)
- return;
-
- WARN_ON(!list_empty(&cfg->vif_list));
- wiphy_unregister(cfg->wiphy);
- brcmf_btcoex_detach(cfg);
- brcmf_p2p_detach(&cfg->p2p);
- wl_deinit_priv(cfg);
- brcmf_free_wiphy(cfg->wiphy);
-}
+++ /dev/null
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _wl_cfg80211_h_
-#define _wl_cfg80211_h_
-
-/* for brcmu_d11inf */
-#include <brcmu_d11.h>
-
-#define WL_NUM_SCAN_MAX 10
-#define WL_NUM_PMKIDS_MAX MAXPMKID
-#define WL_TLV_INFO_MAX 1024
-#define WL_BSS_INFO_MAX 2048
-#define WL_ASSOC_INFO_MAX 512 /* assoc related fil max buf */
-#define WL_EXTRA_BUF_MAX 2048
-#define WL_ROAM_TRIGGER_LEVEL -75
-#define WL_ROAM_DELTA 20
-#define WL_BEACON_TIMEOUT 3
-
-#define WL_SCAN_CHANNEL_TIME 40
-#define WL_SCAN_UNASSOC_TIME 40
-#define WL_SCAN_PASSIVE_TIME 120
-
-#define WL_ESCAN_BUF_SIZE (1024 * 64)
-#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
-
-#define WL_ESCAN_ACTION_START 1
-#define WL_ESCAN_ACTION_CONTINUE 2
-#define WL_ESCAN_ACTION_ABORT 3
-
-#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
-#define IE_MAX_LEN 512
-
-/* IE TLV processing */
-#define TLV_LEN_OFF 1 /* length offset */
-#define TLV_HDR_LEN 2 /* header length */
-#define TLV_BODY_OFF 2 /* body offset */
-#define TLV_OUI_LEN 3 /* oui id length */
-
-/* 802.11 Mgmt Packet flags */
-#define BRCMF_VNDR_IE_BEACON_FLAG 0x1
-#define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2
-#define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4
-#define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8
-#define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10
-#define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20
-/* vendor IE in IW advertisement protocol ID field */
-#define BRCMF_VNDR_IE_IWAPID_FLAG 0x40
-/* allow custom IE id */
-#define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100
-
-/* P2P Action Frames flags (spec ordered) */
-#define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000
-#define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000
-#define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000
-#define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000
-#define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000
-#define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000
-#define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000
-#define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000
-#define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000
-
-#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
-
-
-/**
- * enum brcmf_scan_status - scan engine status
- *
- * @BRCMF_SCAN_STATUS_BUSY: scanning in progress on dongle.
- * @BRCMF_SCAN_STATUS_ABORT: scan being aborted on dongle.
- * @BRCMF_SCAN_STATUS_SUPPRESS: scanning is suppressed in driver.
- */
-enum brcmf_scan_status {
- BRCMF_SCAN_STATUS_BUSY,
- BRCMF_SCAN_STATUS_ABORT,
- BRCMF_SCAN_STATUS_SUPPRESS,
-};
-
-/* dongle configuration */
-struct brcmf_cfg80211_conf {
- u32 frag_threshold;
- u32 rts_threshold;
- u32 retry_short;
- u32 retry_long;
- s32 tx_power;
- struct ieee80211_channel channel;
-};
-
-/* basic structure of scan request */
-struct brcmf_cfg80211_scan_req {
- struct brcmf_ssid_le ssid_le;
-};
-
-/* basic structure of information element */
-struct brcmf_cfg80211_ie {
- u16 offset;
- u8 buf[WL_TLV_INFO_MAX];
-};
-
-/* security information with currently associated ap */
-struct brcmf_cfg80211_security {
- u32 wpa_versions;
- u32 auth_type;
- u32 cipher_pairwise;
- u32 cipher_group;
- u32 wpa_auth;
-};
-
-/**
- * struct brcmf_cfg80211_profile - profile information.
- *
- * @ssid: ssid of associated/associating ap.
- * @bssid: bssid of joined/joining ibss.
- * @sec: security information.
- */
-struct brcmf_cfg80211_profile {
- struct brcmf_ssid ssid;
- u8 bssid[ETH_ALEN];
- struct brcmf_cfg80211_security sec;
-};
-
-/**
- * enum brcmf_vif_status - bit indices for vif status.
- *
- * @BRCMF_VIF_STATUS_READY: ready for operation.
- * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
- * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
- * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
- * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
- * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
- */
-enum brcmf_vif_status {
- BRCMF_VIF_STATUS_READY,
- BRCMF_VIF_STATUS_CONNECTING,
- BRCMF_VIF_STATUS_CONNECTED,
- BRCMF_VIF_STATUS_DISCONNECTING,
- BRCMF_VIF_STATUS_AP_CREATING,
- BRCMF_VIF_STATUS_AP_CREATED
-};
-
-/**
- * struct vif_saved_ie - holds saved IEs for a virtual interface.
- *
- * @probe_req_ie: IE info for probe request.
- * @probe_res_ie: IE info for probe response.
- * @beacon_ie: IE info for beacon frame.
- * @probe_req_ie_len: IE info length for probe request.
- * @probe_res_ie_len: IE info length for probe response.
- * @beacon_ie_len: IE info length for beacon frame.
- */
-struct vif_saved_ie {
- u8 probe_req_ie[IE_MAX_LEN];
- u8 probe_res_ie[IE_MAX_LEN];
- u8 beacon_ie[IE_MAX_LEN];
- u8 assoc_req_ie[IE_MAX_LEN];
- u32 probe_req_ie_len;
- u32 probe_res_ie_len;
- u32 beacon_ie_len;
- u32 assoc_req_ie_len;
-};
-
-/**
- * struct brcmf_cfg80211_vif - virtual interface specific information.
- *
- * @ifp: lower layer interface pointer
- * @wdev: wireless device.
- * @profile: profile information.
- * @roam_off: roaming state.
- * @sme_state: SME state using enum brcmf_vif_status bits.
- * @pm_block: power-management blocked.
- * @list: linked list.
- * @mgmt_rx_reg: registered rx mgmt frame types.
- */
-struct brcmf_cfg80211_vif {
- struct brcmf_if *ifp;
- struct wireless_dev wdev;
- struct brcmf_cfg80211_profile profile;
- s32 roam_off;
- unsigned long sme_state;
- bool pm_block;
- struct vif_saved_ie saved_ie;
- struct list_head list;
- u16 mgmt_rx_reg;
-};
-
-/* association inform */
-struct brcmf_cfg80211_connect_info {
- u8 *req_ie;
- s32 req_ie_len;
- u8 *resp_ie;
- s32 resp_ie_len;
-};
-
-/* assoc ie length */
-struct brcmf_cfg80211_assoc_ielen_le {
- __le32 req_len;
- __le32 resp_len;
-};
-
-/* wpa2 pmk list */
-struct brcmf_cfg80211_pmk_list {
- struct pmkid_list pmkids;
- struct pmkid foo[MAXPMKID - 1];
-};
-
-/* dongle escan state */
-enum wl_escan_state {
- WL_ESCAN_STATE_IDLE,
- WL_ESCAN_STATE_SCANNING
-};
-
-struct escan_info {
- u32 escan_state;
- u8 escan_buf[WL_ESCAN_BUF_SIZE];
- struct wiphy *wiphy;
- struct brcmf_if *ifp;
- s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
- struct cfg80211_scan_request *request, u16 action);
-};
-
-/**
- * struct brcmf_pno_param_le - PNO scan configuration parameters
- *
- * @version: PNO parameters version.
- * @scan_freq: scan frequency.
- * @lost_network_timeout: #sec. to declare discovered network as lost.
- * @flags: Bit field to control features of PFN such as sort criteria auto
- * enable switch and background scan.
- * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort
- * criteria.
- * @bestn: number of best networks in each scan.
- * @mscan: number of scans recorded.
- * @repeat: minimum number of scan intervals before scan frequency changes
- * in adaptive scan.
- * @exp: exponent of 2 for maximum scan interval.
- * @slow_freq: slow scan period.
- */
-struct brcmf_pno_param_le {
- __le32 version;
- __le32 scan_freq;
- __le32 lost_network_timeout;
- __le16 flags;
- __le16 rssi_margin;
- u8 bestn;
- u8 mscan;
- u8 repeat;
- u8 exp;
- __le32 slow_freq;
-};
-
-/**
- * struct brcmf_pno_net_param_le - scan parameters per preferred network.
- *
- * @ssid: ssid name and its length.
- * @flags: bit2: hidden.
- * @infra: BSS vs IBSS.
- * @auth: Open vs Closed.
- * @wpa_auth: WPA type.
- * @wsec: wsec value.
- */
-struct brcmf_pno_net_param_le {
- struct brcmf_ssid_le ssid;
- __le32 flags;
- __le32 infra;
- __le32 auth;
- __le32 wpa_auth;
- __le32 wsec;
-};
-
-/**
- * struct brcmf_pno_net_info_le - information per found network.
- *
- * @bssid: BSS network identifier.
- * @channel: channel number only.
- * @SSID_len: length of ssid.
- * @SSID: ssid characters.
- * @RSSI: receive signal strength (in dBm).
- * @timestamp: age in seconds.
- */
-struct brcmf_pno_net_info_le {
- u8 bssid[ETH_ALEN];
- u8 channel;
- u8 SSID_len;
- u8 SSID[32];
- __le16 RSSI;
- __le16 timestamp;
-};
-
-/**
- * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event.
- *
- * @version: PNO version identifier.
- * @status: indicates completion status of PNO scan.
- * @count: amount of brcmf_pno_net_info_le entries appended.
- */
-struct brcmf_pno_scanresults_le {
- __le32 version;
- __le32 status;
- __le32 count;
-};
-
-/**
- * struct brcmf_cfg80211_vif_event - virtual interface event information.
- *
- * @vif_wq: waitqueue awaiting interface event from firmware.
- * @vif_event_lock: protects other members in this structure.
- * @vif_complete: completion for net attach.
- * @action: either add, change, or delete.
- * @vif: virtual interface object related to the event.
- */
-struct brcmf_cfg80211_vif_event {
- wait_queue_head_t vif_wq;
- struct mutex vif_event_lock;
- u8 action;
- struct brcmf_cfg80211_vif *vif;
-};
-
-/**
- * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
- *
- * @wiphy: wiphy object for cfg80211 interface.
- * @conf: dongle configuration.
- * @p2p: peer-to-peer specific information.
- * @btcoex: Bluetooth coexistence information.
- * @scan_request: cfg80211 scan request object.
- * @usr_sync: mainly for dongle up/down synchronization.
- * @bss_list: bss_list holding scanned ap information.
- * @scan_req_int: internal scan request object.
- * @bss_info: bss information for cfg80211 layer.
- * @ie: information element object for internal purpose.
- * @conn_info: association info.
- * @pmk_list: wpa2 pmk list.
- * @scan_status: scan activity on the dongle.
- * @pub: common driver information.
- * @channel: current channel.
- * @active_scan: current scan mode.
- * @sched_escan: e-scan for scheduled scan support running.
- * @ibss_starter: indicates this sta is ibss starter.
- * @pwr_save: indicate whether dongle to support power save mode.
- * @dongle_up: indicate whether dongle up or not.
- * @roam_on: on/off switch for dongle self-roaming.
- * @scan_tried: indicates if first scan attempted.
- * @dcmd_buf: dcmd buffer.
- * @extra_buf: mainly to grab assoc information.
- * @debugfsdir: debugfs folder for this device.
- * @escan_info: escan information.
- * @escan_timeout: Timer for catch scan timeout.
- * @escan_timeout_work: scan timeout worker.
- * @escan_ioctl_buf: dongle command buffer for escan commands.
- * @vif_list: linked list of vif instances.
- * @vif_cnt: number of vif instances.
- * @vif_event: vif event signalling.
- * @wowl_enabled; set during suspend, is wowl used.
- * @pre_wowl_pmmode: intermediate storage of pm mode during wowl.
- */
-struct brcmf_cfg80211_info {
- struct wiphy *wiphy;
- struct brcmf_cfg80211_conf *conf;
- struct brcmf_p2p_info p2p;
- struct brcmf_btcoex_info *btcoex;
- struct cfg80211_scan_request *scan_request;
- struct mutex usr_sync;
- struct brcmf_cfg80211_scan_req scan_req_int;
- struct wl_cfg80211_bss_info *bss_info;
- struct brcmf_cfg80211_ie ie;
- struct brcmf_cfg80211_connect_info conn_info;
- struct brcmf_cfg80211_pmk_list *pmk_list;
- unsigned long scan_status;
- struct brcmf_pub *pub;
- u32 channel;
- bool active_scan;
- bool sched_escan;
- bool ibss_starter;
- bool pwr_save;
- bool dongle_up;
- bool scan_tried;
- u8 *dcmd_buf;
- u8 *extra_buf;
- struct dentry *debugfsdir;
- struct escan_info escan_info;
- struct timer_list escan_timeout;
- struct work_struct escan_timeout_work;
- u8 *escan_ioctl_buf;
- struct list_head vif_list;
- struct brcmf_cfg80211_vif_event vif_event;
- struct completion vif_disabled;
- struct brcmu_d11inf d11inf;
- bool wowl_enabled;
- u32 pre_wowl_pmmode;
-};
-
-/**
- * struct brcmf_tlv - tag_ID/length/value_buffer tuple.
- *
- * @id: tag identifier.
- * @len: number of bytes in value buffer.
- * @data: value buffer.
- */
-struct brcmf_tlv {
- u8 id;
- u8 len;
- u8 data[1];
-};
-
-static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
-{
- return cfg->wiphy;
-}
-
-static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
-{
- return (struct brcmf_cfg80211_info *)(wiphy_priv(w));
-}
-
-static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
-{
- return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
-}
-
-static inline
-struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_cfg80211_vif *vif;
- vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
- return vif->wdev.netdev;
-}
-
-static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
-{
- return wdev_to_cfg(ndev->ieee80211_ptr);
-}
-
-static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd)
-{
- struct brcmf_if *ifp = netdev_priv(nd);
- return &ifp->vif->profile;
-}
-
-static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- return ifp->vif;
-}
-
-static inline struct
-brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
-{
- return &cfg->conn_info;
-}
-
-struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
- struct device *busdev);
-void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
-s32 brcmf_cfg80211_up(struct net_device *ndev);
-s32 brcmf_cfg80211_down(struct net_device *ndev);
-enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
-
-struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
- enum nl80211_iftype type,
- bool pm_block);
-void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
-
-s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
- const u8 *vndr_ie_buf, u32 vndr_ie_len);
-s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
-const struct brcmf_tlv *
-brcmf_parse_tlvs(const void *buf, int buflen, uint key);
-u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
- struct ieee80211_channel *ch);
-bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state);
-void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
- struct brcmf_cfg80211_vif *vif);
-bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
- u8 action, ulong timeout);
-s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct brcmf_if *ifp, bool aborted,
- bool fw_abort);
-void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
-void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
-void brcmf_cfg80211_free_netdev(struct net_device *ndev);
-
-#endif /* _wl_cfg80211_h_ */
}
static
-ssize_t brcms_debugfs_hardware_read(struct file *f, char __user *data,
- size_t count, loff_t *ppos)
+int brcms_debugfs_hardware_read(struct seq_file *s, void *data)
{
- char buf[128];
- int res;
- struct brcms_pub *drvr = f->private_data;
-
- /* only allow read from start */
- if (*ppos > 0)
- return 0;
-
- res = scnprintf(buf, sizeof(buf),
- "board vendor: %x\n"
- "board type: %x\n"
- "board revision: %x\n"
- "board flags: %x\n"
- "board flags2: %x\n"
- "firmware revision: %x\n",
- drvr->wlc->hw->d11core->bus->boardinfo.vendor,
- drvr->wlc->hw->d11core->bus->boardinfo.type,
- drvr->wlc->hw->boardrev,
- drvr->wlc->hw->boardflags,
- drvr->wlc->hw->boardflags2,
- drvr->wlc->ucode_rev
- );
-
- return simple_read_from_buffer(data, count, ppos, buf, res);
+ struct brcms_pub *drvr = s->private;
+
+ seq_printf(s, "board vendor: %x\n"
+ "board type: %x\n"
+ "board revision: %x\n"
+ "board flags: %x\n"
+ "board flags2: %x\n"
+ "firmware revision: %x\n",
+ drvr->wlc->hw->d11core->bus->boardinfo.vendor,
+ drvr->wlc->hw->d11core->bus->boardinfo.type,
+ drvr->wlc->hw->boardrev,
+ drvr->wlc->hw->boardflags,
+ drvr->wlc->hw->boardflags2,
+ drvr->wlc->ucode_rev);
+
+ return 0;
+}
+
+static int brcms_debugfs_macstat_read(struct seq_file *s, void *data)
+{
+ struct brcms_pub *drvr = s->private;
+ struct brcms_info *wl = drvr->ieee_hw->priv;
+ struct macstat stats;
+ int i;
+
+ spin_lock_bh(&wl->lock);
+ stats = *(drvr->wlc->core->macstat_snapshot);
+ spin_unlock_bh(&wl->lock);
+
+ seq_printf(s, "txallfrm: %d\n", stats.txallfrm);
+ seq_printf(s, "txrtsfrm: %d\n", stats.txrtsfrm);
+ seq_printf(s, "txctsfrm: %d\n", stats.txctsfrm);
+ seq_printf(s, "txackfrm: %d\n", stats.txackfrm);
+ seq_printf(s, "txdnlfrm: %d\n", stats.txdnlfrm);
+ seq_printf(s, "txbcnfrm: %d\n", stats.txbcnfrm);
+ seq_printf(s, "txfunfl[8]:");
+ for (i = 0; i < ARRAY_SIZE(stats.txfunfl); i++)
+ seq_printf(s, " %d", stats.txfunfl[i]);
+ seq_printf(s, "\ntxtplunfl: %d\n", stats.txtplunfl);
+ seq_printf(s, "txphyerr: %d\n", stats.txphyerr);
+ seq_printf(s, "pktengrxducast: %d\n", stats.pktengrxducast);
+ seq_printf(s, "pktengrxdmcast: %d\n", stats.pktengrxdmcast);
+ seq_printf(s, "rxfrmtoolong: %d\n", stats.rxfrmtoolong);
+ seq_printf(s, "rxfrmtooshrt: %d\n", stats.rxfrmtooshrt);
+ seq_printf(s, "rxinvmachdr: %d\n", stats.rxinvmachdr);
+ seq_printf(s, "rxbadfcs: %d\n", stats.rxbadfcs);
+ seq_printf(s, "rxbadplcp: %d\n", stats.rxbadplcp);
+ seq_printf(s, "rxcrsglitch: %d\n", stats.rxcrsglitch);
+ seq_printf(s, "rxstrt: %d\n", stats.rxstrt);
+ seq_printf(s, "rxdfrmucastmbss: %d\n", stats.rxdfrmucastmbss);
+ seq_printf(s, "rxmfrmucastmbss: %d\n", stats.rxmfrmucastmbss);
+ seq_printf(s, "rxcfrmucast: %d\n", stats.rxcfrmucast);
+ seq_printf(s, "rxrtsucast: %d\n", stats.rxrtsucast);
+ seq_printf(s, "rxctsucast: %d\n", stats.rxctsucast);
+ seq_printf(s, "rxackucast: %d\n", stats.rxackucast);
+ seq_printf(s, "rxdfrmocast: %d\n", stats.rxdfrmocast);
+ seq_printf(s, "rxmfrmocast: %d\n", stats.rxmfrmocast);
+ seq_printf(s, "rxcfrmocast: %d\n", stats.rxcfrmocast);
+ seq_printf(s, "rxrtsocast: %d\n", stats.rxrtsocast);
+ seq_printf(s, "rxctsocast: %d\n", stats.rxctsocast);
+ seq_printf(s, "rxdfrmmcast: %d\n", stats.rxdfrmmcast);
+ seq_printf(s, "rxmfrmmcast: %d\n", stats.rxmfrmmcast);
+ seq_printf(s, "rxcfrmmcast: %d\n", stats.rxcfrmmcast);
+ seq_printf(s, "rxbeaconmbss: %d\n", stats.rxbeaconmbss);
+ seq_printf(s, "rxdfrmucastobss: %d\n", stats.rxdfrmucastobss);
+ seq_printf(s, "rxbeaconobss: %d\n", stats.rxbeaconobss);
+ seq_printf(s, "rxrsptmout: %d\n", stats.rxrsptmout);
+ seq_printf(s, "bcntxcancl: %d\n", stats.bcntxcancl);
+ seq_printf(s, "rxf0ovfl: %d\n", stats.rxf0ovfl);
+ seq_printf(s, "rxf1ovfl: %d\n", stats.rxf1ovfl);
+ seq_printf(s, "rxf2ovfl: %d\n", stats.rxf2ovfl);
+ seq_printf(s, "txsfovfl: %d\n", stats.txsfovfl);
+ seq_printf(s, "pmqovfl: %d\n", stats.pmqovfl);
+ seq_printf(s, "rxcgprqfrm: %d\n", stats.rxcgprqfrm);
+ seq_printf(s, "rxcgprsqovfl: %d\n", stats.rxcgprsqovfl);
+ seq_printf(s, "txcgprsfail: %d\n", stats.txcgprsfail);
+ seq_printf(s, "txcgprssuc: %d\n", stats.txcgprssuc);
+ seq_printf(s, "prs_timeout: %d\n", stats.prs_timeout);
+ seq_printf(s, "rxnack: %d\n", stats.rxnack);
+ seq_printf(s, "frmscons: %d\n", stats.frmscons);
+ seq_printf(s, "txnack: %d\n", stats.txnack);
+ seq_printf(s, "txglitch_nack: %d\n", stats.txglitch_nack);
+ seq_printf(s, "txburst: %d\n", stats.txburst);
+ seq_printf(s, "bphy_rxcrsglitch: %d\n", stats.bphy_rxcrsglitch);
+ seq_printf(s, "phywatchdog: %d\n", stats.phywatchdog);
+ seq_printf(s, "bphy_badplcp: %d\n", stats.bphy_badplcp);
+ return 0;
+}
+
+struct brcms_debugfs_entry {
+ int (*read)(struct seq_file *seq, void *data);
+ struct brcms_pub *drvr;
+};
+
+static int brcms_debugfs_entry_open(struct inode *inode, struct file *f)
+{
+ struct brcms_debugfs_entry *entry = inode->i_private;
+
+ return single_open(f, entry->read, entry->drvr);
}
-static const struct file_operations brcms_debugfs_hardware_ops = {
+static const struct file_operations brcms_debugfs_def_ops = {
.owner = THIS_MODULE,
- .open = simple_open,
- .read = brcms_debugfs_hardware_read
+ .open = brcms_debugfs_entry_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek
};
+static int
+brcms_debugfs_add_entry(struct brcms_pub *drvr, const char *fn,
+ int (*read_fn)(struct seq_file *seq, void *data))
+{
+ struct device *dev = &drvr->wlc->hw->d11core->dev;
+ struct dentry *dentry = drvr->dbgfs_dir;
+ struct brcms_debugfs_entry *entry;
+
+ if (IS_ERR_OR_NULL(dentry))
+ return -ENOENT;
+
+ entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->read = read_fn;
+ entry->drvr = drvr;
+
+ dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+ &brcms_debugfs_def_ops);
+
+ return PTR_ERR_OR_ZERO(dentry);
+}
+
void brcms_debugfs_create_files(struct brcms_pub *drvr)
{
- struct dentry *dentry = drvr->dbgfs_dir;
+ if (IS_ERR_OR_NULL(drvr->dbgfs_dir))
+ return;
- if (!IS_ERR_OR_NULL(dentry))
- debugfs_create_file("hardware", S_IRUGO, dentry,
- drvr, &brcms_debugfs_hardware_ops);
+ brcms_debugfs_add_entry(drvr, "hardware", brcms_debugfs_hardware_read);
+ brcms_debugfs_add_entry(drvr, "macstat", brcms_debugfs_macstat_read);
}
#define __brcms_fn(fn) \
static void brcms_c_statsupd(struct brcms_c_info *wlc)
{
int i;
- struct macstat macstats;
+ struct macstat *macstats;
#ifdef DEBUG
u16 delta;
u16 rxf0ovfl;
if (!wlc->pub->up)
return;
+ macstats = wlc->core->macstat_snapshot;
+
#ifdef DEBUG
/* save last rx fifo 0 overflow count */
- rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
+ rxf0ovfl = macstats->rxf0ovfl;
/* save last tx fifo underflow count */
for (i = 0; i < NFIFO; i++)
- txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
+ txfunfl[i] = macstats->txfunfl[i];
#endif /* DEBUG */
/* Read mac stats from contiguous shared memory */
- brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
- sizeof(struct macstat), OBJADDR_SHM_SEL);
+ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, macstats,
+ sizeof(*macstats), OBJADDR_SHM_SEL);
#ifdef DEBUG
/* check for rx fifo 0 overflow */
- delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
+ delta = (u16)(macstats->rxf0ovfl - rxf0ovfl);
if (delta)
brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n",
wlc->pub->unit, delta);
/* check for tx fifo underflows */
for (i = 0; i < NFIFO; i++) {
- delta =
- (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
- txfunfl[i]);
+ delta = macstats->txfunfl[i] - txfunfl[i];
if (delta)
brcms_err(wlc->hw->d11core,
"wl%d: %u tx fifo %d underflows!\n",
if (!priv->cmdlog)
return 0;
for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
- (i != priv->cmdlog_pos) && (PAGE_SIZE - len);
+ (i != priv->cmdlog_pos) && (len < PAGE_SIZE);
i = (i + 1) % priv->cmdlog_len) {
len +=
snprintf(buf + len, PAGE_SIZE - len,
/* TPC Report - mandatory if spctrm mgmt required */
struct libipw_tpc_report tpc_report;
- /* IBSS DFS - mandatory if spctrm mgmt required and IBSS
- * NOTE: This is variable length and so must be allocated dynamically */
- struct libipw_ibss_dfs *ibss_dfs;
-
/* Channel Switch Announcement - optional if spctrm mgmt required */
struct libipw_csa csa;
/* make sure to set stats->len */
void libipw_rx_mgt(struct libipw_device *ieee, struct libipw_hdr_4addr *header,
struct libipw_rx_stats *stats);
-void libipw_network_reset(struct libipw_network *network);
/* libipw_geo.c */
const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee);
return 0;
}
-void libipw_network_reset(struct libipw_network *network)
-{
- if (!network)
- return;
-
- if (network->ibss_dfs) {
- kfree(network->ibss_dfs);
- network->ibss_dfs = NULL;
- }
-}
-
static inline void libipw_networks_free(struct libipw_device *ieee)
{
int i;
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- kfree(ieee->networks[i]->ibss_dfs);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++)
kfree(ieee->networks[i]);
- }
}
void libipw_networks_age(struct libipw_device *ieee,
break;
case WLAN_EID_IBSS_DFS:
- if (network->ibss_dfs)
- break;
- network->ibss_dfs = kmemdup(info_element->data,
- info_element->len,
- GFP_ATOMIC);
- if (!network->ibss_dfs)
- return 1;
network->flags |= NETWORK_HAS_IBSS_DFS;
break;
static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
*frame, struct libipw_rx_stats *stats)
{
- struct libipw_network network_resp = {
- .ibss_dfs = NULL,
- };
+ struct libipw_network network_resp = { };
struct libipw_network *network = &network_resp;
struct net_device *dev = ieee->dev;
int qos_active;
u8 old_param;
- libipw_network_reset(dst);
- dst->ibss_dfs = src->ibss_dfs;
-
/* We only update the statistics if they were created by receiving
* the network information on the actual channel the network is on.
*
*stats)
{
struct net_device *dev = ieee->dev;
- struct libipw_network network = {
- .ibss_dfs = NULL,
- };
+ struct libipw_network network = { };
struct libipw_network *target;
struct libipw_network *oldest = NULL;
#ifdef CONFIG_LIBIPW_DEBUG
LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
target->ssid_len, target->ssid,
target->bssid);
- libipw_network_reset(target);
} else {
/* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next,
"BEACON" : "PROBE RESPONSE");
#endif
memcpy(target, &network, sizeof(*target));
- network.ibss_dfs = NULL;
list_add_tail(&target->list, &ieee->network_list);
} else {
LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
is_beacon(beacon->header.frame_ctl) ?
"BEACON" : "PROBE RESPONSE");
update_network(target, &network);
- network.ibss_dfs = NULL;
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
void
-il4965_mac_channel_switch(struct ieee80211_hw *hw,
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch)
{
struct il_priv *il = hw->priv;
u8 buf_size);
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-void il4965_mac_channel_switch(struct ieee80211_hw *hw,
- struct ieee80211_channel_switch *ch_switch);
+void
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *ch_switch);
void il4965_led_enable(struct il_priv *il);
config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
+ select BACKPORT_WANT_DEV_COREDUMP
help
This is the driver that supports the MVM firmware which is
currently only available for 7260 and 3160 devices.
static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
{
- return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
- BT_UART_MSG_FRAME3SCOESCO_POS;
+ return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+ BT_UART_MSG_FRAME3SCOESCO_POS;
}
static void iwlagn_bt_traffic_change_work(struct work_struct *work)
}
static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
};
static const struct iwl_ht_params iwl8000_ht_params = {
+ .stbc = true,
.ldpc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
IWL_DEVICE_FAMILY_8000,
};
+static inline bool iwl_has_secure_boot(u32 hw_rev,
+ enum iwl_device_family family)
+{
+ /* return 1 only for family 8000 B0 */
+ if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC))
+ return 1;
+
+ return 0;
+}
+
/*
* LED mode
* IWL_LED_DEFAULT: use device default
* @nvm_hw_section_num: the ID of the HW NVM section
* @pwr_tx_backoffs: translation table between power limits and backoffs
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
+ * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
const char *default_nvm_file;
unsigned int max_rx_agg_size;
bool disable_dummy_notification;
+ unsigned int max_tx_agg_size;
};
/*
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
tlv_len);
drv->fw.mvm_fw = true;
- drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
break;
case IWL_UCODE_TLV_SECURE_SEC_INIT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
tlv_len);
drv->fw.mvm_fw = true;
- drv->fw.img[IWL_UCODE_INIT].is_secure = true;
break;
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
tlv_len);
drv->fw.mvm_fw = true;
- drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
break;
case IWL_UCODE_TLV_NUM_OF_CPU:
if (tlv_len != sizeof(u32))
struct fw_img {
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
- bool is_secure;
bool is_dual_cpus;
};
void (*ref)(struct iwl_trans *trans);
void (*unref)(struct iwl_trans *trans);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
-#endif
};
/**
trans->ops->unref(trans);
}
-#ifdef CONFIG_IWLWIFI_DEBUGFS
static inline struct iwl_trans_dump_data *
iwl_trans_dump_data(struct iwl_trans *trans)
{
return NULL;
return trans->ops->dump_data(trans);
}
-#endif
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd)
#include "mvm.h"
#include "iwl-debug.h"
-#define BT_ANTENNA_COUPLING_THRESHOLD (30)
-
const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
[BT_KILL_MSK_NEVER] = 0xffffffff,
},
};
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
- cpu_to_le32(0x2e402280),
- cpu_to_le32(0x7711a751),
-};
-
struct corunning_block_luts {
u8 range;
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
bt_cmd->max_kill = cpu_to_le32(5);
bt_cmd->bt4_antenna_isolation_thr =
- cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD);
+ cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS);
bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
sizeof(iwl_bt_prio_boost));
- memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
- sizeof(iwl_bt_mprio_lut));
+ bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
+ bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
send_cmd:
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
#undef EVENT_PRIO_ANT
-#define BT_ANTENNA_COUPLING_THRESHOLD (30)
-
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
{
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
},
};
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
- cpu_to_le32(0x2e402280),
- cpu_to_le32(0x7711a751),
-};
-
struct corunning_block_luts {
u8 range;
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
}
bt_cmd->max_kill = 5;
- bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
+ bt_cmd->bt4_antenna_isolation_thr =
+ IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS;
bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
bt_cmd->bt4_tx_rx_max_freq0 = 15;
memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
sizeof(iwl_bt_prio_boost));
- memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
- sizeof(iwl_bt_mprio_lut));
+ bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
+ bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
send_cmd:
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
#define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 0
#define IWL_MVM_BT_COEX_MPLUT 1
+#define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280
+#define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751
+#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
+#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0
#define IWL_MVM_QUOTA_THRESHOLD 8
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
+#define IWL_MVM_RS_DISABLE_MIMO 0
#endif /* __MVM_CONSTANTS_H */
return ret;
}
-struct iwl_d3_iter_data {
- struct iwl_mvm *mvm;
- struct ieee80211_vif *vif;
- bool error;
-};
-
-static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_d3_iter_data *data = _data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
- return;
-
- if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
- return;
-
- if (data->vif) {
- IWL_ERR(data->mvm, "More than one managed interface active!\n");
- data->error = true;
- return;
- }
-
- data->vif = vif;
-}
-
static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *ap_sta)
{
IWL_ERR(mvm, "failed to set non-QoS seqno\n");
}
+static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
+{
+ iwl_mvm_cancel_scan(mvm);
+
+ iwl_trans_stop_device(mvm->trans);
+
+ /*
+ * Set the HW restart bit -- this is mostly true as we're
+ * going to load new firmware and reprogram that, though
+ * the reprogramming is going to be manual to avoid adding
+ * all the MACs that aren't support.
+ * We don't have to clear up everything though because the
+ * reprogramming is manual. When we resume, we'll actually
+ * go through a proper restart sequence again to switch
+ * back to the runtime firmware image.
+ */
+ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+ /* We reprogram keys and shouldn't allocate new key indices */
+ memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
+ mvm->ptk_ivlen = 0;
+ mvm->ptk_icvlen = 0;
+ mvm->ptk_ivlen = 0;
+ mvm->ptk_icvlen = 0;
+
+ return iwl_mvm_load_d3_fw(mvm);
+}
+
static int
iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
const struct iwl_wowlan_config_cmd_v3 *cmd)
cmd_len, cmd);
}
-static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
- struct cfg80211_wowlan *wowlan,
- bool test)
+static int
+iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
+ struct cfg80211_wowlan *wowlan,
+ struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+ struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+ struct ieee80211_sta *ap_sta)
{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_d3_iter_data suspend_iter_data = {
- .mvm = mvm,
- };
- struct ieee80211_vif *vif;
- struct iwl_mvm_vif *mvmvif;
- struct ieee80211_sta *ap_sta;
- struct iwl_mvm_sta *mvm_ap_sta;
- struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
- struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
- struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
- struct iwl_d3_manager_config d3_cfg_cmd_data = {
- /*
- * Program the minimum sleep time to 10 seconds, as many
- * platforms have issues processing a wakeup signal while
- * still being in the process of suspending.
- */
- .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
- };
- struct iwl_host_cmd d3_cfg_cmd = {
- .id = D3_CONFIG_CMD,
- .flags = CMD_WANT_SKB,
- .data[0] = &d3_cfg_cmd_data,
- .len[0] = sizeof(d3_cfg_cmd_data),
- };
- struct wowlan_key_data key_data = {
- .use_rsc_tsc = false,
- .tkip = &tkip_cmd,
- .use_tkip = false,
- };
int ret;
- int len __maybe_unused;
-
- if (!wowlan) {
- /*
- * mac80211 shouldn't get here, but for D3 test
- * it doesn't warrant a warning
- */
- WARN_ON(!test);
- return -EINVAL;
- }
-
- key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
- if (!key_data.rsc_tsc)
- return -ENOMEM;
-
- mutex_lock(&mvm->mutex);
-
- /* see if there's only a single BSS vif and it's associated */
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_d3_iface_iterator, &suspend_iter_data);
-
- if (suspend_iter_data.error || !suspend_iter_data.vif) {
- ret = 1;
- goto out_noreset;
- }
-
- vif = suspend_iter_data.vif;
- mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- ap_sta = rcu_dereference_protected(
- mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
- lockdep_is_held(&mvm->mutex));
- if (IS_ERR_OR_NULL(ap_sta)) {
- ret = -EINVAL;
- goto out_noreset;
- }
-
- mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+ struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
- /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */
+ /* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */
- wowlan_config_cmd.common.is_11n_connection =
+ wowlan_config_cmd->common.is_11n_connection =
ap_sta->ht_cap.ht_supported;
/* Query the last used seqno and set it */
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
if (ret < 0)
- goto out_noreset;
- wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret);
+ return ret;
- iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common);
+ wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret);
+
+ iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common);
if (wowlan->disconnect)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
if (wowlan->magic_pkt)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
if (wowlan->gtk_rekey_failure)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
if (wowlan->eap_identity_req)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
if (wowlan->four_way_handshake)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
if (wowlan->n_patterns)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
if (wowlan->tcp) {
* Set the "link change" (really "link lost") flag as well
* since that implies losing the TCP connection.
*/
- wowlan_config_cmd.common.wakeup_filter |=
+ wowlan_config_cmd->common.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
}
- iwl_mvm_cancel_scan(mvm);
-
- iwl_trans_stop_device(mvm->trans);
-
- /*
- * Set the HW restart bit -- this is mostly true as we're
- * going to load new firmware and reprogram that, though
- * the reprogramming is going to be manual to avoid adding
- * all the MACs that aren't support.
- * We don't have to clear up everything though because the
- * reprogramming is manual. When we resume, we'll actually
- * go through a proper restart sequence again to switch
- * back to the runtime firmware image.
- */
- set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
-
- /* We reprogram keys and shouldn't allocate new key indices */
- memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
-
- mvm->ptk_ivlen = 0;
- mvm->ptk_icvlen = 0;
- mvm->ptk_ivlen = 0;
- mvm->ptk_icvlen = 0;
+ return 0;
+}
- ret = iwl_mvm_load_d3_fw(mvm);
- if (ret)
- goto out;
+static int
+iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
+ struct cfg80211_wowlan *wowlan,
+ struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+ struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+ struct ieee80211_sta *ap_sta)
+{
+ struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
+ struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
+ struct wowlan_key_data key_data = {
+ .use_rsc_tsc = false,
+ .tkip = &tkip_cmd,
+ .use_tkip = false,
+ };
+ int ret;
ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
if (ret)
- goto out;
+ return ret;
+
+ key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+ if (!key_data.rsc_tsc)
+ return -ENOMEM;
if (!iwlwifi_mod_params.sw_crypto) {
/*
}
}
- ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
+ ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd);
if (ret)
goto out;
goto out;
ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
- if (ret)
- goto out;
+
+out:
+ kfree(key_data.rsc_tsc);
+ return ret;
+}
+
+static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan,
+ bool test)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct ieee80211_vif *vif = NULL;
+ struct iwl_mvm_vif *mvmvif = NULL;
+ struct ieee80211_sta *ap_sta = NULL;
+ struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
+ struct iwl_d3_manager_config d3_cfg_cmd_data = {
+ /*
+ * Program the minimum sleep time to 10 seconds, as many
+ * platforms have issues processing a wakeup signal while
+ * still being in the process of suspending.
+ */
+ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
+ };
+ struct iwl_host_cmd d3_cfg_cmd = {
+ .id = D3_CONFIG_CMD,
+ .flags = CMD_WANT_SKB,
+ .data[0] = &d3_cfg_cmd_data,
+ .len[0] = sizeof(d3_cfg_cmd_data),
+ };
+ int ret;
+ int len __maybe_unused;
+
+ if (!wowlan) {
+ /*
+ * mac80211 shouldn't get here, but for D3 test
+ * it doesn't warrant a warning
+ */
+ WARN_ON(!test);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mvm->mutex);
+
+ vif = iwl_mvm_get_bss_vif(mvm);
+ if (IS_ERR_OR_NULL(vif)) {
+ ret = 1;
+ goto out_noreset;
+ }
+
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ /* if we're associated, this is wowlan */
+ if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+ ap_sta = rcu_dereference_protected(
+ mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+ lockdep_is_held(&mvm->mutex));
+ if (IS_ERR_OR_NULL(ap_sta)) {
+ ret = -EINVAL;
+ goto out_noreset;
+ }
+
+ ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+ vif, mvmvif, ap_sta);
+ if (ret)
+ goto out_noreset;
+
+ ret = iwl_mvm_switch_to_d3(mvm);
+ if (ret)
+ goto out;
+
+ ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+ vif, mvmvif, ap_sta);
+ if (ret)
+ goto out;
+ } else if (mvm->nd_config) {
+ ret = iwl_mvm_switch_to_d3(mvm);
+ if (ret)
+ goto out;
+
+ ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config,
+ mvm->nd_ies);
+ if (ret)
+ goto out;
+ } else {
+ ret = 1;
+ goto out_noreset;
+ }
ret = iwl_mvm_power_update_device(mvm);
if (ret)
if (ret < 0)
ieee80211_restart_hw(mvm->hw);
out_noreset:
- kfree(key_data.rsc_tsc);
-
mutex_unlock(&mvm->mutex);
return ret;
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
{
- struct iwl_d3_iter_data resume_iter_data = {
- .mvm = mvm,
- };
struct ieee80211_vif *vif = NULL;
int ret;
enum iwl_d3_status d3_status;
mutex_lock(&mvm->mutex);
/* get the BSS vif pointer again */
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_d3_iface_iterator, &resume_iter_data);
-
- if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
+ vif = iwl_mvm_get_bss_vif(mvm);
+ if (IS_ERR_OR_NULL(vif))
goto out_unlock;
- vif = resume_iter_data.vif;
-
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
if (ret)
goto out_unlock;
int remaining_time = 10;
mvm->d3_test_active = false;
+ rtnl_lock();
__iwl_mvm_resume(mvm, true);
+ rtnl_unlock();
iwl_abort_notification_waits(&mvm->notif_wait);
ieee80211_restart_hw(mvm->hw);
return ret;
}
-static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
-{
- struct iwl_mvm *mvm = inode->i_private;
- int ret;
-
- if (!mvm)
- return -EINVAL;
-
- mutex_lock(&mvm->mutex);
- if (!mvm->fw_error_dump) {
- ret = -ENODATA;
- goto out;
- }
-
- file->private_data = mvm->fw_error_dump;
- mvm->fw_error_dump = NULL;
- ret = 0;
-
-out:
- mutex_unlock(&mvm->mutex);
- return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
- ssize_t bytes_read = 0;
- ssize_t bytes_read_trans = 0;
-
- if (*ppos < dump_ptrs->op_mode_len)
- bytes_read +=
- simple_read_from_buffer(user_buf, count, ppos,
- dump_ptrs->op_mode_ptr,
- dump_ptrs->op_mode_len);
-
- if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
- return bytes_read;
-
- if (dump_ptrs->trans_ptr) {
- *ppos -= dump_ptrs->op_mode_len;
- bytes_read_trans =
- simple_read_from_buffer(user_buf + bytes_read,
- count - bytes_read, ppos,
- dump_ptrs->trans_ptr->data,
- dump_ptrs->trans_ptr->len);
- *ppos += dump_ptrs->op_mode_len;
-
- if (bytes_read_trans >= 0)
- bytes_read += bytes_read_trans;
- else if (!bytes_read)
- /* propagate the failure */
- return bytes_read_trans;
- }
-
- return bytes_read;
-
-}
-
-static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
- struct file *file)
-{
- struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-
- vfree(dump_ptrs->op_mode_ptr);
- vfree(dump_ptrs->trans_ptr);
- kfree(dump_ptrs);
-
- return 0;
-}
-
static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
return ret;
}
+
+#define MAX_NUM_ND_MATCHSETS 10
+
+static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ const char *seps = ",\n";
+ char *buf_ptr = buf;
+ char *value_str = NULL;
+ int ret, i;
+
+ /* TODO: don't free if write is being called several times in one go */
+ if (mvm->nd_config) {
+ kfree(mvm->nd_config->match_sets);
+ kfree(mvm->nd_config);
+ mvm->nd_config = NULL;
+ kfree(mvm->nd_ies);
+ mvm->nd_ies = NULL;
+ }
+
+ mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
+ if (!mvm->nd_ies)
+ return -ENOMEM;
+
+ mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
+ (11 * sizeof(struct ieee80211_channel *)),
+ GFP_KERNEL);
+ if (!mvm->nd_config) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ mvm->nd_config->n_channels = 11;
+ mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20;
+ mvm->nd_config->interval = 5;
+ mvm->nd_config->min_rssi_thold = -80;
+ for (i = 0; i < mvm->nd_config->n_channels; i++)
+ mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i];
+
+ mvm->nd_config->match_sets =
+ kcalloc(MAX_NUM_ND_MATCHSETS,
+ sizeof(*mvm->nd_config->match_sets),
+ GFP_KERNEL);
+ if (!mvm->nd_config->match_sets) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ while ((value_str = strsep(&buf_ptr, seps)) &&
+ strlen(value_str)) {
+ struct cfg80211_match_set *set;
+
+ if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets];
+ set->ssid.ssid_len = strlen(value_str);
+
+ if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len);
+
+ mvm->nd_config->n_match_sets++;
+ }
+
+ ret = count;
+
+ if (mvm->nd_config->n_match_sets)
+ goto out;
+
+out_free:
+ if (mvm->nd_config)
+ kfree(mvm->nd_config->match_sets);
+ kfree(mvm->nd_config);
+ mvm->nd_config = NULL;
+ kfree(mvm->nd_ies);
+ mvm->nd_ies = NULL;
+out:
+ return ret;
+}
+
+static ssize_t
+iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ size_t bufsz, ret;
+ char *buf;
+ int i, n_match_sets, pos = 0;
+
+ n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0;
+
+ bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1;
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < n_match_sets; i++) {
+ if (pos +
+ mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) {
+ ret = -EIO;
+ goto out;
+ }
+
+ memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid,
+ mvm->nd_config->match_sets[i].ssid.ssid_len);
+ pos += mvm->nd_config->match_sets[i].ssid.ssid_len;
+ buf[pos++] = '\n';
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+out:
+ kfree(buf);
+ return ret;
+}
#endif
#define PRINT_MVM_REF(ref) do { \
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
-static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
- .open = iwl_dbgfs_fw_error_dump_open,
- .read = iwl_dbgfs_fw_error_dump_read,
- .release = iwl_dbgfs_fw_error_dump_release,
-};
-
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
#endif
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
mvm->debugfs_dir, &mvm->d3_wake_sysassert))
goto err;
+ MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
#endif
if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
/*
* Get the mask of the queues used by the vif
*/
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
{
u32 qmask = 0, ac;
}
/* Mark the queues used by the vif */
- data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
+ data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
/* Mark MAC IDs as used by clearing the available bit, and
* (below) mark TSFs as used if their existing use is not
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
+#include <linux/devcoredump.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <net/tcp.h>
memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
}
-#ifdef CONFIG_IWLWIFI_DEBUGFS
+static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count,
+ const void *data, size_t datalen)
+{
+ const struct iwl_mvm_dump_ptrs *dump_ptrs = data;
+ ssize_t bytes_read;
+ ssize_t bytes_read_trans;
+
+ if (offset < dump_ptrs->op_mode_len) {
+ bytes_read = min_t(ssize_t, count,
+ dump_ptrs->op_mode_len - offset);
+ memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset,
+ bytes_read);
+ offset += bytes_read;
+ count -= bytes_read;
+
+ if (count == 0)
+ return bytes_read;
+ } else {
+ bytes_read = 0;
+ }
+
+ if (!dump_ptrs->trans_ptr)
+ return bytes_read;
+
+ offset -= dump_ptrs->op_mode_len;
+ bytes_read_trans = min_t(ssize_t, count,
+ dump_ptrs->trans_ptr->len - offset);
+ memcpy(buffer + bytes_read,
+ (u8 *)dump_ptrs->trans_ptr->data + offset,
+ bytes_read_trans);
+
+ return bytes_read + bytes_read_trans;
+}
+
+static void iwl_mvm_free_coredump(const void *data)
+{
+ const struct iwl_mvm_dump_ptrs *fw_error_dump = data;
+
+ vfree(fw_error_dump->op_mode_ptr);
+ vfree(fw_error_dump->trans_ptr);
+ kfree(fw_error_dump);
+}
+
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
- static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
lockdep_assert_held(&mvm->mutex);
- if (mvm->fw_error_dump)
- return;
-
- fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
+ fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
if (!fw_error_dump)
return;
if (fw_error_dump->trans_ptr)
file_len += fw_error_dump->trans_ptr->len;
dump_file->file_len = cpu_to_le32(file_len);
- mvm->fw_error_dump = fw_error_dump;
- /* notify the userspace about the error we had */
- kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
+ dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
+ GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
}
-#endif
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
return ret;
}
-static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
+static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
mutex_lock(&mvm->mutex);
mutex_unlock(&mvm->mutex);
}
+static void
+iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
+ enum ieee80211_reconfig_type reconfig_type)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ switch (reconfig_type) {
+ case IEEE80211_RECONFIG_TYPE_RESTART:
+ iwl_mvm_restart_complete(mvm);
+ break;
+ case IEEE80211_RECONFIG_TYPE_SUSPEND:
+ break;
+ }
+}
+
void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
{
lockdep_assert_held(&mvm->mutex);
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
- u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
+ u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
if (tfd_msk) {
mutex_lock(&mvm->mutex);
.cmd = cmd,
};
+ if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
+ return false;
+
memset(cmd, 0, sizeof(*cmd));
cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
cmd->max_macs = ARRAY_SIZE(cmd->macs);
mvm->scan_status = IWL_MVM_SCAN_SCHED;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
- ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
- if (ret)
- goto err;
- }
-
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+ ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
if (ret)
- goto err;
-
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
- else
- ret = iwl_mvm_sched_scan_start(mvm, req);
-
- if (!ret)
- goto out;
-err:
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
out:
mutex_unlock(&mvm->mutex);
return ret;
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
- if (WARN_ON_ONCE(!mvmsta))
- goto done;
+ if (WARN_ON_ONCE(!mvmsta)) {
+ mutex_unlock(&mvm->mutex);
+ return;
+ }
if (drop) {
if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
IWL_ERR(mvm, "flush request fail\n");
+ mutex_unlock(&mvm->mutex);
} else {
- iwl_trans_wait_tx_queue_empty(mvm->trans,
- mvmsta->tfd_queue_msk);
+ u32 tfd_queue_msk = mvmsta->tfd_queue_msk;
+ mutex_unlock(&mvm->mutex);
+
+ /* this can take a while, and we may need/want other operations
+ * to succeed while doing this, so do it without the mutex held
+ */
+ iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk);
}
-done:
- mutex_unlock(&mvm->mutex);
}
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.start = iwl_mvm_mac_start,
- .restart_complete = iwl_mvm_mac_restart_complete,
+ .reconfig_complete = iwl_mvm_mac_reconfig_complete,
.stop = iwl_mvm_mac_stop,
.add_interface = iwl_mvm_mac_add_interface,
.remove_interface = iwl_mvm_mac_remove_interface,
/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
struct work_struct fw_error_dump_wk;
- struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led;
#ifdef CONFIG_PM_SLEEP
struct wiphy_wowlan_support wowlan;
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
+
+ /* sched scan settings for net detect */
+ struct cfg80211_sched_scan_request *nd_config;
+ struct ieee80211_scan_ies *nd_ies;
#ifdef CONFIG_IWLWIFI_DEBUGFS
u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
bool d3_test_active;
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off, const u8 *bssid_override);
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req);
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
struct cfg80211_sched_scan_request *req);
+int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies);
int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
+
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
-#else
-static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
-#endif
#endif /* __IWL_MVM_H__ */
if (cfg->max_rx_agg_size)
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
+ if (cfg->max_tx_agg_size)
+ hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
+
op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
- if (mvm->fw_error_dump) {
- vfree(mvm->fw_error_dump->op_mode_ptr);
- vfree(mvm->fw_error_dump->trans_ptr);
- kfree(mvm->fw_error_dump);
- }
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
+ if (mvm->nd_config) {
+ kfree(mvm->nd_config->match_sets);
+ kfree(mvm->nd_config);
+ mvm->nd_config = NULL;
+ kfree(mvm->nd_ies);
+ mvm->nd_ies = NULL;
+ }
#endif
iwl_trans_op_mode_leave(mvm->trans);
static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix)
{
- IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
+ IWL_DEBUG_RATE(mvm,
+ "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n",
prefix, rs_pretty_lq_type(rate->type),
rate->index, rs_pretty_ant(rate->ant),
- rate->bw, rate->sgi, rate->ldpc);
+ rate->bw, rate->sgi, rate->ldpc, rate->stbc);
}
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
}
+ if (is_siso(rate) && rate->stbc) {
+ /* To enable STBC we need to set both a flag and ANT_AB */
+ ucode_rate |= RATE_MCS_ANT_AB_MSK;
+ ucode_rate |= RATE_MCS_VHT_STBC_MSK;
+ }
+
ucode_rate |= rate->bw;
if (rate->sgi)
ucode_rate |= RATE_MCS_SGI_MSK;
rate->sgi = true;
if (ucode_rate & RATE_MCS_LDPC_MSK)
rate->ldpc = true;
+ if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
+ rate->stbc = true;
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
if (nss == 1) {
rate->type = LQ_HT_SISO;
- WARN_ON_ONCE(num_of_ant != 1);
+ WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
} else if (nss == 2) {
rate->type = LQ_HT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2);
static inline bool rs_rate_match(struct rs_rate *a,
struct rs_rate *b)
{
- return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi);
+ bool ant_match;
+
+ if (a->stbc)
+ ant_match = (b->ant == ANT_A || b->ant == ANT_B);
+ else
+ ant_match = (a->ant == b->ant);
+
+ return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi)
+ && ant_match;
}
static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
done:
/* See if there's a better rate or modulation mode to try. */
- if (sta && sta->supp_rates[info->band])
+ if (sta->supp_rates[info->band])
rs_rate_scale_perform(mvm, sta, lq_sta, tid);
}
else
rate->type = LQ_LEGACY_G;
+ rate->bw = RATE_MCS_CHAN_WIDTH_20;
+ rate->ldpc = false;
rate_mask = lq_sta->active_legacy_rate;
} else if (column->mode == RS_SISO) {
rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
WARN_ON_ONCE("Bad column mode");
}
- rate->bw = rs_bw_from_sta_bw(sta);
- rate->ldpc = lq_sta->ldpc;
+ if (column->mode != RS_LEGACY) {
+ rate->bw = rs_bw_from_sta_bw(sta);
+ rate->ldpc = lq_sta->ldpc;
+ }
+
search_tbl->column = col_id;
rs_set_expected_tpt_table(lq_sta, search_tbl);
return action;
}
+static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct ieee80211_vif *vif = mvmsta->vif;
+ bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
+ !vif->bss_conf.ps);
+
+ /* Our chip supports Tx STBC and the peer is an HT/VHT STA which
+ * supports STBC of at least 1*SS
+ */
+ if (!lq_sta->stbc)
+ return false;
+
+ if (!mvm->ps_disabled && !sta_ps_disabled)
+ return false;
+
+ if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+ return false;
+
+ return true;
+}
+
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
int *weaker, int *stronger)
{
if (mvm->cfg->ht_params->ldpc &&
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+ (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
+ lq_sta->stbc = true;
} else {
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
lq_sta->is_vht = true;
if (mvm->cfg->ht_params->ldpc &&
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
+ lq_sta->stbc = true;
}
+ if (IWL_MVM_RS_DISABLE_MIMO)
+ lq_sta->active_mimo2_rate = 0;
+
lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
BITS_PER_LONG);
lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
BITS_PER_LONG);
IWL_DEBUG_RATE(mvm,
- "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
+ "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
lq_sta->active_legacy_rate,
lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate,
- lq_sta->is_vht, lq_sta->ldpc);
+ lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx,
* rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
*/
static void rs_build_rates_table(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
const struct rs_rate *initial_rate)
{
memcpy(&rate, initial_rate, sizeof(rate));
valid_tx_ant = mvm->fw->valid_tx_ant;
+ rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
if (is_siso(&rate)) {
num_rates = RS_INITIAL_SISO_NUM_RATES;
if (WARN_ON_ONCE(!sta || !initial_rate))
return;
- rs_build_rates_table(mvm, lq_sta, initial_rate);
+ rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
if (num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;
u32 bw;
bool sgi;
bool ldpc;
+ bool stbc;
};
u64 last_tx;
bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */
+ bool stbc; /* Tx STBC is supported by chip and Rx by STA */
enum ieee80211_band band;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
bool *global_bound = data;
- if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
+ mvmvif->phy_ctxt->id < MAX_PHYS)
*global_bound = true;
}
mvm->scan_status = IWL_MVM_SCAN_NONE;
ieee80211_scan_completed(mvm->hw,
status == IWL_SCAN_OFFLOAD_ABORTED);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}
mvm->last_ebs_successful = !ebs_status;
sizeof(scan_req), &scan_req);
}
+int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies)
+{
+ int ret;
+
+ if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
+ ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+ if (ret)
+ return ret;
+ ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
+ } else {
+ ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
+ if (ret)
+ return ret;
+ ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+ if (ret)
+ return ret;
+ ret = iwl_mvm_sched_scan_start(mvm, req);
+ }
+
+ return ret;
+}
+
static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
{
int ret;
/*
* Clear the scan status so the next scan requests will succeed. This
* also ensures the Rx handler doesn't do anything, as the scan was
- * stopped from above.
+ * stopped from above. Since the rx handler won't do anything now,
+ * we have to release the scan reference here.
*/
+ if (mvm->scan_status == IWL_MVM_SCAN_OS)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+
mvm->scan_status = IWL_MVM_SCAN_NONE;
if (notify) {
lockdep_assert_held(&mvm->mutex);
- qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+ qmask = iwl_mvm_mac_get_queues_mask(vif);
/*
* The firmware defines the TFD queue mask to only be relevant
*****************************************************************************/
#include "mvm.h"
-#include "iwl-config.h"
-#include "iwl-io.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
/* HT rate doesn't make sense for a non data frame */
WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
- "Got an HT rate for a non data frame 0x%x\n",
- info->control.rates[0].flags);
+ "Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n",
+ info->control.rates[0].flags,
+ info->control.rates[0].idx,
+ le16_to_cpu(fc));
rate_idx = info->control.rates[0].idx;
/* if the rate isn't a well known legacy rate, take the lowest one */
return idle;
}
+
+struct iwl_bss_iter_data {
+ struct ieee80211_vif *vif;
+ bool error;
+};
+
+static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_bss_iter_data *data = _data;
+
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ return;
+
+ if (data->vif) {
+ data->error = true;
+ return;
+ }
+
+ data->vif = vif;
+}
+
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
+{
+ struct iwl_bss_iter_data bss_iter_data = {};
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_bss_iface_iterator, &bss_iter_data);
+
+ if (bss_iter_data.error) {
+ IWL_ERR(mvm, "More than one managed interface active!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return bss_iter_data.vif;
+}
break;
}
- if (!page)
+ if (WARN_ON_ONCE(!page))
return;
trans_pcie->fw_mon_page = page;
int ret = 0;
int first_ucode_section;
- IWL_DEBUG_FW(trans,
- "working with %s image\n",
- image->is_secure ? "Secured" : "Non Secured");
IWL_DEBUG_FW(trans,
"working with %s CPU\n",
image->is_dual_cpus ? "Dual" : "Single");
/* configure the ucode to be ready to get the secured image */
- if (image->is_secure) {
+ if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
/* set secure boot inspector addresses */
iwl_write_prph(trans,
LMPM_SECURE_INSPECTOR_CODE_ADDR,
LMPM_SECURE_CPU2_HDR_MEM_SPACE);
/* load to FW the binary sections of CPU2 */
- if (image->is_secure)
+ if (iwl_has_secure_boot(trans->hw_rev,
+ trans->cfg->device_family))
ret = iwl_pcie_load_cpu_secured_sections(
trans, image, 2,
&first_ucode_section);
else
iwl_write32(trans, CSR_RESET, 0);
- if (image->is_secure) {
+ if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
/* wait for image verification to complete */
ret = iwl_poll_prph_bit(trans,
LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
return 0;
}
- iwl_pcie_set_pwr(trans, false);
-
- val = iwl_read32(trans, CSR_RESET);
- if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
- *status = IWL_D3_STATUS_RESET;
- return 0;
- }
-
/*
* Also enables interrupts - none will happen as the device doesn't
* know we're waking it up, only when the opmode actually tells it
return ret;
}
+ iwl_pcie_set_pwr(trans, false);
+
iwl_trans_pcie_tx_reset(trans);
ret = iwl_pcie_rx_init(trans);
return ret;
}
- *status = IWL_D3_STATUS_ALIVE;
+ val = iwl_read32(trans, CSR_RESET);
+ if (val & CSR_RESET_REG_FLAG_NEVO_RESET)
+ *status = IWL_D3_STATUS_RESET;
+ else
+ *status = IWL_D3_STATUS_ALIVE;
+
return 0;
}
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
return -ENOMEM;
}
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+ struct dentry *dir)
+{
+ return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
{
return dump_data;
}
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
- struct dentry *dir)
-{
- return 0;
-}
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
static const struct iwl_trans_ops trans_ops_pcie = {
.start_hw = iwl_trans_pcie_start_hw,
.release_nic_access = iwl_trans_pcie_release_nic_access,
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
-#ifdef CONFIG_IWLWIFI_DEBUGFS
.dump_data = iwl_trans_pcie_dump_data,
-#endif
};
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
struct mac_address addresses[2];
int channels, idx;
bool use_chanctx;
+ bool destroy_on_close;
+ struct work_struct destroy_work;
+ u32 portid;
struct ieee80211_channel *tmp_chan;
struct delayed_work roc_done;
/*
* Only radios in the same group can communicate together (the
* channel has to match too). Each bit represents a group. A
- * radio can be in more then one group.
+ * radio can be in more than one group.
*/
u64 group;
s64 bcn_delta;
/* absolute beacon transmission time. Used to cover up "tx" delay. */
u64 abs_bcn_ts;
+
+ /* Stats */
+ u64 tx_pkts;
+ u64 rx_pkts;
+ u64 tx_bytes;
+ u64 rx_bytes;
+ u64 tx_dropped;
+ u64 tx_failed;
};
.maxattr = HWSIM_ATTR_MAX,
};
+enum hwsim_multicast_groups {
+ HWSIM_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group hwsim_mcgrps[] = {
+ [HWSIM_MCGRP_CONFIG] = { .name = "config", },
+};
+
/* MAC80211_HWSIM netlink policy */
static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
[HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING },
+ [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
};
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
/* If the queue contains MAX_QUEUE skb's drop some */
if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
/* Droping until WARN_QUEUE level */
- while (skb_queue_len(&data->pending) >= WARN_QUEUE)
- skb_dequeue(&data->pending);
+ while (skb_queue_len(&data->pending) >= WARN_QUEUE) {
+ ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
+ data->tx_dropped++;
+ }
}
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
goto nla_put_failure;
+ if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq))
+ goto nla_put_failure;
+
/* We get the tx control (rate and retries) info*/
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
/* Enqueue the packet */
skb_queue_tail(&data->pending, my_skb);
+ data->tx_pkts++;
+ data->tx_bytes += my_skb->len;
return;
nla_put_failure:
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
+ ieee80211_free_txskb(hw, my_skb);
+ data->tx_failed++;
}
static bool hwsim_chans_compat(struct ieee80211_channel *c1,
rx_status.mactime = now + data2->tsf_offset;
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+ data2->rx_pkts++;
+ data2->rx_bytes += nskb->len;
ieee80211_rx_irqsafe(data2->hw, nskb);
}
spin_unlock(&hwsim_radio_lock);
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
/* NO wmediumd detected, perfect medium simulation */
+ data->tx_pkts++;
+ data->tx_bytes += skb->len;
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
if (ack && skb->len >= 16) {
hwsim_check_chanctx_magic(ctx);
}
+static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "tx_pkts_nic",
+ "tx_bytes_nic",
+ "rx_pkts_nic",
+ "rx_bytes_nic",
+ "d_tx_dropped",
+ "d_tx_failed",
+ "d_ps_mode",
+ "d_group",
+ "d_tx_power",
+};
+
+#define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats)
+
+static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u32 sset, u8 *data)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(data, *mac80211_hwsim_gstrings_stats,
+ sizeof(mac80211_hwsim_gstrings_stats));
+}
+
+static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return MAC80211_HWSIM_SSTATS_LEN;
+ return 0;
+}
+
+static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct mac80211_hwsim_data *ar = hw->priv;
+ int i = 0;
+
+ data[i++] = ar->tx_pkts;
+ data[i++] = ar->tx_bytes;
+ data[i++] = ar->rx_pkts;
+ data[i++] = ar->rx_bytes;
+ data[i++] = ar->tx_dropped;
+ data[i++] = ar->tx_failed;
+ data[i++] = ar->ps;
+ data[i++] = ar->group;
+ data[i++] = ar->power_level;
+
+ WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
+}
+
static const struct ieee80211_ops mac80211_hwsim_ops = {
.tx = mac80211_hwsim_tx,
.start = mac80211_hwsim_start,
.flush = mac80211_hwsim_flush,
.get_tsf = mac80211_hwsim_get_tsf,
.set_tsf = mac80211_hwsim_set_tsf,
+ .get_et_sset_count = mac80211_hwsim_get_et_sset_count,
+ .get_et_stats = mac80211_hwsim_get_et_stats,
+ .get_et_strings = mac80211_hwsim_get_et_strings,
};
static struct ieee80211_ops mac80211_hwsim_mchan_ops;
-static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
- const struct ieee80211_regdomain *regd,
- bool reg_strict, bool p2p_device,
- bool use_chanctx)
+struct hwsim_new_radio_params {
+ unsigned int channels;
+ const char *reg_alpha2;
+ const struct ieee80211_regdomain *regd;
+ bool reg_strict;
+ bool p2p_device;
+ bool use_chanctx;
+ bool destroy_on_close;
+ const char *hwname;
+ bool no_vif;
+};
+
+static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
+ struct genl_info *info)
+{
+ if (info)
+ genl_notify(&hwsim_genl_family, mcast_skb,
+ genl_info_net(info), info->snd_portid,
+ HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
+ else
+ genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
+ HWSIM_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static struct sk_buff *build_radio_msg(int cmd, int id,
+ struct hwsim_new_radio_params *param)
+{
+ struct sk_buff *skb;
+ void *data;
+ int ret;
+
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!skb)
+ return NULL;
+
+ data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd);
+ if (!data)
+ goto error;
+
+ ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+ if (ret < 0)
+ goto error;
+
+ if (param->channels) {
+ ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (param->reg_alpha2) {
+ ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
+ param->reg_alpha2);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (param->regd) {
+ int i;
+
+ for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
+ i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
+ ;
+
+ if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
+ ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
+ if (ret < 0)
+ goto error;
+ }
+ }
+
+ if (param->reg_strict) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (param->p2p_device) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (param->use_chanctx) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (param->hwname) {
+ ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
+ strlen(param->hwname), param->hwname);
+ if (ret < 0)
+ goto error;
+ }
+
+ genlmsg_end(skb, data);
+
+ return skb;
+
+error:
+ nlmsg_free(skb);
+ return NULL;
+}
+
+static void hswim_mcast_new_radio(int id, struct genl_info *info,
+ struct hwsim_new_radio_params *param)
+{
+ struct sk_buff *mcast_skb;
+
+ mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param);
+ if (!mcast_skb)
+ return;
+
+ hwsim_mcast_config_msg(mcast_skb, info);
+}
+
+static int mac80211_hwsim_new_radio(struct genl_info *info,
+ struct hwsim_new_radio_params *param)
{
int err;
u8 addr[ETH_ALEN];
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
int idx;
- if (WARN_ON(channels > 1 && !use_chanctx))
+ if (WARN_ON(param->channels > 1 && !param->use_chanctx))
return -EINVAL;
spin_lock_bh(&hwsim_radio_lock);
idx = hwsim_radio_idx++;
spin_unlock_bh(&hwsim_radio_lock);
- if (use_chanctx)
+ if (param->use_chanctx)
ops = &mac80211_hwsim_mchan_ops;
- hw = ieee80211_alloc_hw(sizeof(*data), ops);
+ hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname);
if (!hw) {
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
err = -ENOMEM;
hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses;
- data->channels = channels;
- data->use_chanctx = use_chanctx;
+ data->channels = param->channels;
+ data->use_chanctx = param->use_chanctx;
data->idx = idx;
+ data->destroy_on_close = param->destroy_on_close;
+ if (info)
+ data->portid = info->snd_portid;
if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
/* For channels > 1 DFS is not allowed */
hw->wiphy->n_iface_combinations = 1;
hw->wiphy->iface_combinations = &data->if_combination;
- if (p2p_device)
+ if (param->p2p_device)
data->if_combination = hwsim_if_comb_p2p_dev[0];
else
data->if_combination = hwsim_if_comb[0];
data->if_combination.num_different_channels = data->channels;
- } else if (p2p_device) {
+ } else if (param->p2p_device) {
hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
hw->wiphy->n_iface_combinations =
ARRAY_SIZE(hwsim_if_comb_p2p_dev);
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- if (p2p_device)
+ if (param->p2p_device)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->flags = IEEE80211_HW_MFP_CAPABLE |
sband->ht_cap.ht_supported = true;
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
sband->ht_cap.ampdu_factor = 0x3;
hw->max_rates = 4;
hw->max_rate_tries = 11;
- if (reg_strict)
+ if (param->reg_strict)
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
- if (regd) {
+ if (param->regd) {
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
- wiphy_apply_custom_regulatory(hw->wiphy, regd);
+ wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
/* give the regulatory workqueue a chance to run */
schedule_timeout_interruptible(1);
}
+ if (param->no_vif)
+ hw->flags |= IEEE80211_HW_NO_AUTO_VIF;
+
err = ieee80211_register_hw(hw);
if (err < 0) {
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
- if (reg_alpha2)
- regulatory_hint(hw->wiphy, reg_alpha2);
+ if (param->reg_alpha2)
+ regulatory_hint(hw->wiphy, param->reg_alpha2);
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
list_add_tail(&data->list, &hwsim_radios);
spin_unlock_bh(&hwsim_radio_lock);
+ if (idx > 0)
+ hswim_mcast_new_radio(idx, info, param);
+
return idx;
failed_hw:
return err;
}
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
+static void hwsim_mcast_del_radio(int id, const char *hwname,
+ struct genl_info *info)
+{
+ struct sk_buff *skb;
+ void *data;
+ int ret;
+
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+ HWSIM_CMD_DEL_RADIO);
+ if (!data)
+ goto error;
+
+ ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+ if (ret < 0)
+ goto error;
+
+ if (hwname) {
+ ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
+ hwname);
+ if (ret < 0)
+ goto error;
+ }
+
+ genlmsg_end(skb, data);
+
+ hwsim_mcast_config_msg(skb, info);
+
+ return;
+
+error:
+ nlmsg_free(skb);
+}
+
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
+ const char *hwname,
+ struct genl_info *info)
{
+ hwsim_mcast_del_radio(data->idx, hwname, info);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
- mac80211_hwsim_destroy_radio(data);
+ mac80211_hwsim_del_radio(data, NULL, NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
struct genl_info *info)
{
-
struct mac80211_hwsim_data *data2;
struct ieee80211_rx_status rx_status;
const u8 *dst;
/* A frame is received from user space */
memset(&rx_status, 0, sizeof(rx_status));
+ /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
+ * packets?
+ */
rx_status.freq = data2->channel->center_freq;
rx_status.band = data2->channel->band;
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ data2->rx_pkts++;
+ data2->rx_bytes += skb->len;
ieee80211_rx_irqsafe(data2->hw, skb);
return 0;
err:
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
- goto out;
out:
dev_kfree_skb(skb);
return -EINVAL;
return 0;
}
-static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
{
- unsigned int chans = channels;
- const char *alpha2 = NULL;
- const struct ieee80211_regdomain *regd = NULL;
- bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
- bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
- bool use_chanctx;
+ struct hwsim_new_radio_params param = { 0 };
+
+ param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+ param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+ param.channels = channels;
+ param.destroy_on_close =
+ info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
if (info->attrs[HWSIM_ATTR_CHANNELS])
- chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+ param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+
+ if (info->attrs[HWSIM_ATTR_NO_VIF])
+ param.no_vif = true;
+
+ if (info->attrs[HWSIM_ATTR_RADIO_NAME])
+ param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
- use_chanctx = true;
+ param.use_chanctx = true;
else
- use_chanctx = (chans > 1);
+ param.use_chanctx = (param.channels > 1);
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
- alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
+ param.reg_alpha2 =
+ nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
return -EINVAL;
- regd = hwsim_world_regdom_custom[idx];
+ param.regd = hwsim_world_regdom_custom[idx];
}
- return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
- p2p_device, use_chanctx);
+ return mac80211_hwsim_new_radio(info, ¶m);
}
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
{
struct mac80211_hwsim_data *data;
- int idx;
+ s64 idx = -1;
+ const char *hwname = NULL;
- if (!info->attrs[HWSIM_ATTR_RADIO_ID])
+ if (info->attrs[HWSIM_ATTR_RADIO_ID])
+ idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
+ else if (info->attrs[HWSIM_ATTR_RADIO_NAME])
+ hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
+ else
return -EINVAL;
- idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry(data, &hwsim_radios, list) {
- if (data->idx != idx)
- continue;
+ if (idx >= 0) {
+ if (data->idx != idx)
+ continue;
+ } else {
+ if (hwname &&
+ strcmp(hwname, wiphy_name(data->hw->wiphy)))
+ continue;
+ }
+
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
- mac80211_hwsim_destroy_radio(data);
+ mac80211_hwsim_del_radio(data, hwname, info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
.doit = hwsim_tx_info_frame_received_nl,
},
{
- .cmd = HWSIM_CMD_CREATE_RADIO,
+ .cmd = HWSIM_CMD_NEW_RADIO,
.policy = hwsim_genl_policy,
- .doit = hwsim_create_radio_nl,
+ .doit = hwsim_new_radio_nl,
.flags = GENL_ADMIN_PERM,
},
{
- .cmd = HWSIM_CMD_DESTROY_RADIO,
+ .cmd = HWSIM_CMD_DEL_RADIO,
.policy = hwsim_genl_policy,
- .doit = hwsim_destroy_radio_nl,
+ .doit = hwsim_del_radio_nl,
.flags = GENL_ADMIN_PERM,
},
};
+static void destroy_radio(struct work_struct *work)
+{
+ struct mac80211_hwsim_data *data =
+ container_of(work, struct mac80211_hwsim_data, destroy_work);
+
+ mac80211_hwsim_del_radio(data, NULL, NULL);
+}
+
+static void remove_user_radios(u32 portid)
+{
+ struct mac80211_hwsim_data *entry, *tmp;
+
+ spin_lock_bh(&hwsim_radio_lock);
+ list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+ if (entry->destroy_on_close && entry->portid == portid) {
+ list_del(&entry->list);
+ INIT_WORK(&entry->destroy_work, destroy_radio);
+ schedule_work(&entry->destroy_work);
+ }
+ }
+ spin_unlock_bh(&hwsim_radio_lock);
+}
+
static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
unsigned long state,
void *_notify)
if (state != NETLINK_URELEASE)
return NOTIFY_DONE;
+ remove_user_radios(notify->portid);
+
if (notify->portid == wmediumd_portid) {
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
" socket, switching to perfect channel medium\n");
printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
- rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
+ rc = genl_register_family_with_ops_groups(&hwsim_genl_family,
+ hwsim_ops,
+ hwsim_mcgrps);
if (rc)
goto failure;
goto out_unregister_driver;
}
+ err = hwsim_init_netlink();
+ if (err < 0)
+ goto out_unregister_driver;
+
for (i = 0; i < radios; i++) {
- const char *reg_alpha2 = NULL;
- const struct ieee80211_regdomain *regd = NULL;
- bool reg_strict = false;
+ struct hwsim_new_radio_params param = { 0 };
+
+ param.channels = channels;
switch (regtest) {
case HWSIM_REGTEST_DIFF_COUNTRY:
if (i < ARRAY_SIZE(hwsim_alpha2s))
- reg_alpha2 = hwsim_alpha2s[i];
+ param.reg_alpha2 = hwsim_alpha2s[i];
break;
case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
if (!i)
- reg_alpha2 = hwsim_alpha2s[0];
+ param.reg_alpha2 = hwsim_alpha2s[0];
break;
case HWSIM_REGTEST_STRICT_ALL:
- reg_strict = true;
+ param.reg_strict = true;
case HWSIM_REGTEST_DRIVER_REG_ALL:
- reg_alpha2 = hwsim_alpha2s[0];
+ param.reg_alpha2 = hwsim_alpha2s[0];
break;
case HWSIM_REGTEST_WORLD_ROAM:
if (i == 0)
- regd = &hwsim_world_regdom_custom_01;
+ param.regd = &hwsim_world_regdom_custom_01;
break;
case HWSIM_REGTEST_CUSTOM_WORLD:
- regd = &hwsim_world_regdom_custom_01;
+ param.regd = &hwsim_world_regdom_custom_01;
break;
case HWSIM_REGTEST_CUSTOM_WORLD_2:
if (i == 0)
- regd = &hwsim_world_regdom_custom_01;
+ param.regd = &hwsim_world_regdom_custom_01;
else if (i == 1)
- regd = &hwsim_world_regdom_custom_02;
+ param.regd = &hwsim_world_regdom_custom_02;
break;
case HWSIM_REGTEST_STRICT_FOLLOW:
if (i == 0) {
- reg_strict = true;
- reg_alpha2 = hwsim_alpha2s[0];
+ param.reg_strict = true;
+ param.reg_alpha2 = hwsim_alpha2s[0];
}
break;
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
if (i == 0) {
- reg_strict = true;
- reg_alpha2 = hwsim_alpha2s[0];
+ param.reg_strict = true;
+ param.reg_alpha2 = hwsim_alpha2s[0];
} else if (i == 1) {
- reg_alpha2 = hwsim_alpha2s[1];
+ param.reg_alpha2 = hwsim_alpha2s[1];
}
break;
case HWSIM_REGTEST_ALL:
switch (i) {
case 0:
- regd = &hwsim_world_regdom_custom_01;
+ param.regd = &hwsim_world_regdom_custom_01;
break;
case 1:
- regd = &hwsim_world_regdom_custom_02;
+ param.regd = &hwsim_world_regdom_custom_02;
break;
case 2:
- reg_alpha2 = hwsim_alpha2s[0];
+ param.reg_alpha2 = hwsim_alpha2s[0];
break;
case 3:
- reg_alpha2 = hwsim_alpha2s[1];
+ param.reg_alpha2 = hwsim_alpha2s[1];
break;
case 4:
- reg_strict = true;
- reg_alpha2 = hwsim_alpha2s[2];
+ param.reg_strict = true;
+ param.reg_alpha2 = hwsim_alpha2s[2];
break;
}
break;
break;
}
- err = mac80211_hwsim_create_radio(channels, reg_alpha2,
- regd, reg_strict,
- support_p2p_device,
- channels > 1);
+ param.p2p_device = support_p2p_device;
+ param.use_chanctx = channels > 1;
+
+ err = mac80211_hwsim_new_radio(NULL, ¶m);
if (err < 0)
goto out_free_radios;
}
}
rtnl_unlock();
- err = hwsim_init_netlink();
- if (err < 0)
- goto out_free_mon;
-
return 0;
out_free_mon:
* space, uses:
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER,
* %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE,
- * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
+ * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional)
* @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
* kernel, uses:
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
* %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
- * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters,
- * returns the radio ID (>= 0) or negative on errors
- * @HWSIM_CMD_DESTROY_RADIO: destroy a radio
+ * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters,
+ * returns the radio ID (>= 0) or negative on errors, if successful
+ * then multicast the result
+ * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
* @__HWSIM_CMD_MAX: enum limit
*/
enum {
HWSIM_CMD_REGISTER,
HWSIM_CMD_FRAME,
HWSIM_CMD_TX_INFO_FRAME,
- HWSIM_CMD_CREATE_RADIO,
- HWSIM_CMD_DESTROY_RADIO,
+ HWSIM_CMD_NEW_RADIO,
+ HWSIM_CMD_DEL_RADIO,
__HWSIM_CMD_MAX,
};
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
+#define HWSIM_CMD_CREATE_RADIO HWSIM_CMD_NEW_RADIO
+#define HWSIM_CMD_DESTROY_RADIO HWSIM_CMD_DEL_RADIO
+
/**
* enum hwsim_attrs - hwsim netlink attributes
*
* @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
* command to force use of channel contexts even when only a
* single channel is supported
+ * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO
+ * command to force radio removal when process that created the radio dies
+ * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666
+ * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio.
+ * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
* @__HWSIM_ATTR_MAX: enum limit
*/
HWSIM_ATTR_REG_STRICT_REG,
HWSIM_ATTR_SUPPORT_P2P_DEVICE,
HWSIM_ATTR_USE_CHANCTX,
+ HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
+ HWSIM_ATTR_RADIO_NAME,
+ HWSIM_ATTR_NO_VIF,
+ HWSIM_ATTR_FREQ,
__HWSIM_ATTR_MAX,
};
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
return mwifiex_dump_station_info(priv, sinfo);
}
+static int
+mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+ int idx, struct survey_info *survey)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_chan_stats *pchan_stats = priv->adapter->chan_stats;
+ enum ieee80211_band band;
+
+ dev_dbg(priv->adapter->dev, "dump_survey idx=%d\n", idx);
+
+ memset(survey, 0, sizeof(struct survey_info));
+
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ priv->media_connected && idx == 0) {
+ u8 curr_bss_band = priv->curr_bss_params.band;
+ u32 chan = priv->curr_bss_params.bss_descriptor.channel;
+
+ band = mwifiex_band_to_radio_type(curr_bss_band);
+ survey->channel = ieee80211_get_channel(wiphy,
+ ieee80211_channel_to_frequency(chan, band));
+
+ if (priv->bcn_nf_last) {
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = priv->bcn_nf_last;
+ }
+ return 0;
+ }
+
+ if (idx >= priv->adapter->num_in_chan_stats)
+ return -ENOENT;
+
+ if (!pchan_stats[idx].cca_scan_dur)
+ return 0;
+
+ band = pchan_stats[idx].bandcfg;
+ survey->channel = ieee80211_get_channel(wiphy,
+ ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band));
+ survey->filled = SURVEY_INFO_NOISE_DBM |
+ SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+ survey->noise = pchan_stats[idx].noise;
+ survey->channel_time = pchan_stats[idx].cca_scan_dur;
+ survey->channel_time_busy = pchan_stats[idx].cca_busy_dur;
+
+ return 0;
+}
+
/* Supported rates to be advertised to the cfg80211 */
static struct ieee80211_rate mwifiex_rates[] = {
{.bitrate = 10, .hw_value = 2, },
*/
static int
mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac)
+ struct station_del_parameters *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_sta_node *sta_node;
if (list_empty(&priv->sta_list) || !priv->bss_started)
return 0;
- if (!mac || is_broadcast_ether_addr(mac)) {
+ if (!params->mac || is_broadcast_ether_addr(params->mac)) {
wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
list_for_each_entry(sta_node, &priv->sta_list, list) {
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
mwifiex_uap_del_sta_data(priv, sta_node);
}
} else {
- wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac);
+ wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__,
+ params->mac);
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
- sta_node = mwifiex_get_sta_entry(priv, mac);
+ sta_node = mwifiex_get_sta_entry(priv, params->mac);
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
if (sta_node) {
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
.disconnect = mwifiex_cfg80211_disconnect,
.get_station = mwifiex_cfg80211_get_station,
.dump_station = mwifiex_cfg80211_dump_station,
+ .dump_survey = mwifiex_cfg80211_dump_survey,
.set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
.join_ibss = mwifiex_cfg80211_join_ibss,
.leave_ibss = mwifiex_cfg80211_leave_ibss,
.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
};
+int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter)
+{
+ u32 n_channels_bg, n_channels_a = 0;
+
+ n_channels_bg = mwifiex_band_2ghz.n_channels;
+
+ if (adapter->config_bands & BAND_A)
+ n_channels_a = mwifiex_band_5ghz.n_channels;
+
+ adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a);
+ adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) *
+ adapter->num_in_chan_stats);
+
+ if (!adapter->chan_stats)
+ return -ENOMEM;
+
+ return 0;
+}
+
/*
* This function registers the device with CFG802.11 subsystem.
*
u8 ar_tha[ETH_ALEN];
u8 ar_tip[4];
} __packed;
+
+struct mwifiex_chan_stats {
+ u8 chan_num;
+ u8 bandcfg;
+ u8 flags;
+ s8 noise;
+ u16 total_bss;
+ u16 cca_scan_dur;
+ u16 cca_busy_dur;
+} __packed;
#endif /* !_MWIFIEX_DECL_H_ */
#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194)
#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197)
#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
u8 reserved1;
};
+struct mwifiex_fw_chan_stats {
+ u8 chan_num;
+ u8 bandcfg;
+ u8 flags;
+ s8 noise;
+ __le16 total_bss;
+ __le16 cca_scan_dur;
+ __le16 cca_busy_dur;
+} __packed;
+
enum mwifiex_chan_scan_mode_bitmasks {
MWIFIEX_PASSIVE_SCAN = BIT(0),
MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
__le16 chan_gap;
} __packed;
+struct mwifiex_ietypes_chanstats {
+ struct mwifiex_ie_types_header header;
+ struct mwifiex_fw_chan_stats chanstats[0];
+} __packed;
+
struct mwifiex_ie_types_wildcard_ssid_params {
struct mwifiex_ie_types_header header;
u8 max_ssid_length;
}
}
+ vfree(adapter->chan_stats);
kfree(adapter);
return 0;
}
goto err_init_fw;
}
+ if (mwifiex_init_channel_scan_gap(adapter)) {
+ dev_err(adapter->dev, "could not init channel stats table\n");
+ goto err_init_fw;
+ }
+
rtnl_lock();
/* Create station interface by default */
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
u8 curr_mem_idx;
bool scan_chan_gap_enabled;
struct sk_buff_head rx_data_q;
+ struct mwifiex_chan_stats *chan_stats;
+ u32 num_in_chan_stats;
+ int survey_idx;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
-int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv);
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
void *buf);
{
struct mwifiex_adapter *adapter = priv->adapter;
+ adapter->survey_idx = 0;
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
if (!priv->scan_request) {
return 0;
}
+static void
+mwifiex_update_chan_statistics(struct mwifiex_private *priv,
+ struct mwifiex_ietypes_chanstats *tlv_stat)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 i, num_chan;
+ struct mwifiex_fw_chan_stats *fw_chan_stats;
+ struct mwifiex_chan_stats chan_stats;
+
+ fw_chan_stats = (void *)((u8 *)tlv_stat +
+ sizeof(struct mwifiex_ie_types_header));
+ num_chan = le16_to_cpu(tlv_stat->header.len) /
+ sizeof(struct mwifiex_chan_stats);
+
+ for (i = 0 ; i < num_chan; i++) {
+ chan_stats.chan_num = fw_chan_stats->chan_num;
+ chan_stats.bandcfg = fw_chan_stats->bandcfg;
+ chan_stats.flags = fw_chan_stats->flags;
+ chan_stats.noise = fw_chan_stats->noise;
+ chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss);
+ chan_stats.cca_scan_dur =
+ le16_to_cpu(fw_chan_stats->cca_scan_dur);
+ chan_stats.cca_busy_dur =
+ le16_to_cpu(fw_chan_stats->cca_busy_dur);
+ dev_dbg(adapter->dev,
+ "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+ chan_stats.chan_num,
+ chan_stats.noise,
+ chan_stats.total_bss,
+ chan_stats.cca_scan_dur,
+ chan_stats.cca_busy_dur);
+ memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
+ sizeof(struct mwifiex_chan_stats));
+ fw_chan_stats++;
+ }
+}
+
/* This function handles the command response of extended scan */
-int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
{
struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_scan_ext *ext_scan_resp;
+ struct mwifiex_ie_types_header *tlv;
+ struct mwifiex_ietypes_chanstats *tlv_stat;
+ u16 buf_left, type, len;
+
struct host_cmd_ds_command *cmd_ptr;
struct cmd_ctrl_node *cmd_node;
unsigned long cmd_flags, scan_flags;
dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
+ ext_scan_resp = &resp->params.ext_scan;
+
+ tlv = (void *)ext_scan_resp->tlv_buffer;
+ buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
+ - 1);
+
+ while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+ type = le16_to_cpu(tlv->type);
+ len = le16_to_cpu(tlv->len);
+
+ if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
+ dev_err(adapter->dev,
+ "error processing scan response TLVs");
+ break;
+ }
+
+ switch (type) {
+ case TLV_TYPE_CHANNEL_STATS:
+ tlv_stat = (void *)tlv;
+ mwifiex_update_chan_statistics(priv, tlv_stat);
+ break;
+ default:
+ break;
+ }
+
+ buf_left -= len + sizeof(struct mwifiex_ie_types_header);
+ tlv = (void *)((u8 *)tlv + len +
+ sizeof(struct mwifiex_ie_types_header));
+ }
+
spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
if (list_empty(&adapter->scan_pending_q)) {
adapter->curr_cmd->wait_q_enabled = false;
break;
case HostCmd_CMD_802_11_SCAN_EXT:
- ret = mwifiex_ret_802_11_scan_ext(priv);
+ ret = mwifiex_ret_802_11_scan_ext(priv, resp);
adapter->curr_cmd->wait_q_enabled = false;
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
__le16 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- ®, sizeof(reg), REGISTER_TIMEOUT);
+ ®, sizeof(reg));
*value = le16_to_cpu(reg);
}
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- value, length,
- REGISTER_TIMEOUT16(length));
+ value, length);
}
static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
__le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- ®, sizeof(reg), REGISTER_TIMEOUT);
+ ®, sizeof(reg));
}
static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- value, length,
- REGISTER_TIMEOUT16(length));
+ value, length);
}
static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
- const u16 buffer_length, const int timeout)
+ const u16 buffer_length)
{
int status = 0;
unsigned char *tb;
bsize = min_t(u16, CSR_CACHE_SIZE, len);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, off, tb,
- bsize, timeout);
+ bsize, REGISTER_TIMEOUT);
tb += bsize;
len -= bsize;
})
/*
- * For USB vendor requests we need to pass a timeout
- * time in ms, for this we use the REGISTER_TIMEOUT,
- * however when loading firmware a higher value is
- * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
+ * For USB vendor requests we need to pass a timeout time in ms, for this we
+ * use the REGISTER_TIMEOUT, however when loading firmware or read EEPROM
+ * a higher value is required. In that case we use the REGISTER_TIMEOUT_FIRMWARE
+ * and EEPROM_TIMEOUT.
*/
#define REGISTER_TIMEOUT 500
#define REGISTER_TIMEOUT_FIRMWARE 1000
-
-/**
- * REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access
- * @__datalen: Data length
- */
-#define REGISTER_TIMEOUT16(__datalen) \
- ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) )
-
-/**
- * REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access
- * @__datalen: Data length
- */
-#define REGISTER_TIMEOUT32(__datalen) \
- ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) )
+#define EEPROM_TIMEOUT 2000
/*
* Cache size
* @offset: Register offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
- * @timeout: Operation timeout
*
* This function will use a previously with kmalloc allocated cache
* to communicate with the device. The contents of the buffer pointer
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
- const u16 buffer_length, const int timeout);
+ const u16 buffer_length);
/**
* rt2x00usb_vendor_request_buff - Send register command to device (buffered)
{
return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
USB_VENDOR_REQUEST_IN, 0, 0,
- eeprom, length,
- REGISTER_TIMEOUT16(length));
+ eeprom, length, EEPROM_TIMEOUT);
}
/**
__le32 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- ®, sizeof(reg), REGISTER_TIMEOUT);
+ ®, sizeof(reg));
*value = le32_to_cpu(reg);
}
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- value, length,
- REGISTER_TIMEOUT32(length));
+ value, length);
}
/**
__le32 reg = cpu_to_le32(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- ®, sizeof(reg), REGISTER_TIMEOUT);
+ ®, sizeof(reg));
}
/**
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- (void *)value, length,
- REGISTER_TIMEOUT32(length));
+ (void *)value, length);
}
/**
"Invalid RateSection %d in Band 2.4G,Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
rate_section, path, txnum);
break;
- };
+ }
} else if (band == BAND_ON_5G) {
switch (rate_section) {
case OFDM:
"Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
rate_section, path, txnum);
break;
- };
+ }
} else {
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"Invalid Band %d in PHY_SetTxPowerByRateBase()\n", band);
"Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
rate_section, path, txnum);
break;
- };
+ }
} else if (band == BAND_ON_5G) {
switch (rate_section) {
case OFDM:
"Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
rate_section, path, txnum);
break;
- };
+ }
} else {
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"Invalid Band %d in PHY_GetTxPowerByRateBase()\n", band);
break;
default:
break;
- };
+ }
}
static void _rtl8821ae_iqk_rx_fill_iqc(struct ieee80211_hw *hw,
break;
default:
break;
- };
+ }
}
#define cal_num 10
}
static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch)
{
struct wl1271 *wl = hw->priv;
- struct wl12xx_vif *wlvif;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WLCORE_STATE_OFF)) {
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- continue;
-
+ if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
ieee80211_chswitch_done(vif, false);
- }
goto out;
} else if (unlikely(wl->state != WLCORE_STATE_ON)) {
goto out;
goto out;
/* TODO: change mac80211 to pass vif as param */
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- unsigned long delay_usec;
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- continue;
+ if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+ unsigned long delay_usec;
ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
if (ret)
/* indicate failure 5 seconds after channel switch time */
delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
- ch_switch->count;
+ ch_switch->count;
ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
- usecs_to_jiffies(delay_usec) +
- msecs_to_jiffies(5000));
+ usecs_to_jiffies(delay_usec) +
+ msecs_to_jiffies(5000));
}
out_sleep:
for (queue_index = 0; queue_index < num_queues; ++queue_index) {
queue = &vif->queues[queue_index];
- napi_disable(&queue->napi);
disable_irq(queue->tx_irq);
if (queue->tx_irq != queue->rx_irq)
disable_irq(queue->rx_irq);
+ napi_disable(&queue->napi);
del_timer_sync(&queue->credit_timeout);
}
}
static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT;
module_param(fatal_skb_slots, uint, 0444);
+/* The amount to copy out of the first guest Tx slot into the skb's
+ * linear area. If the first slot has more data, it will be mapped
+ * and put into the first frag.
+ *
+ * This is sized to avoid pulling headers from the frags for most
+ * TCP/IP packets.
+ */
+#define XEN_NETBACK_TX_COPY_LEN 128
+
+
static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
u8 status);
pending_tx_info[0]);
}
-/* This is a miniumum size for the linear area to avoid lots of
- * calls to __pskb_pull_tail() as we set up checksum offsets. The
- * value 128 was chosen as it covers all IPv4 and most likely
- * IPv6 headers.
- */
-#define PKT_PROT_LEN 128
-
static u16 frag_get_pending_idx(skb_frag_t *frag)
{
return (u16)frag->page_offset;
index = pending_index(queue->pending_cons);
pending_idx = queue->pending_ring[index];
- data_len = (txreq.size > PKT_PROT_LEN &&
+ data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN &&
ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
- PKT_PROT_LEN : txreq.size;
+ XEN_NETBACK_TX_COPY_LEN : txreq.size;
skb = xenvif_alloc_skb(data_len);
if (unlikely(skb == NULL)) {
unsigned int len;
BUG_ON(i >= MAX_SKB_FRAGS);
- page = alloc_page(GFP_ATOMIC|__GFP_COLD);
+ page = alloc_page(GFP_ATOMIC);
if (!page) {
int j;
skb->truesize += skb->data_len;
}
}
- if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) {
- int target = min_t(int, skb->len, PKT_PROT_LEN);
- __pskb_pull_tail(skb, target - skb_headlen(skb));
- }
-
skb->dev = queue->vif->dev;
skb->protocol = eth_type_trans(skb, skb->dev);
skb_reset_network_header(skb);
#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
-#define TX_MAX_TARGET min_t(int, NET_TX_RING_SIZE, 256)
+
+/* Minimum number of Rx slots (includes slot for GSO metadata). */
+#define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1)
/* Queue name is interface name with "-qNNN" appended */
#define QUEUE_NAME_SIZE (IFNAMSIZ + 6)
struct xen_netif_rx_front_ring rx;
int rx_ring_ref;
- /* Receive-ring batched refills. */
-#define RX_MIN_TARGET 8
-#define RX_DFL_MIN_TARGET 64
-#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
- unsigned rx_min_target, rx_max_target, rx_target;
- struct sk_buff_head rx_batch;
-
struct timer_list rx_refill_timer;
struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
static int netfront_tx_slot_available(struct netfront_queue *queue)
{
return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) <
- (TX_MAX_TARGET - MAX_SKB_FRAGS - 2);
+ (NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2);
}
static void xennet_maybe_wake_tx(struct netfront_queue *queue)
netif_tx_wake_queue(netdev_get_tx_queue(dev, queue->id));
}
-static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
+
+static struct sk_buff *xennet_alloc_one_rx_buffer(struct netfront_queue *queue)
{
- unsigned short id;
struct sk_buff *skb;
struct page *page;
- int i, batch_target, notify;
- RING_IDX req_prod = queue->rx.req_prod_pvt;
- grant_ref_t ref;
- unsigned long pfn;
- void *vaddr;
- struct xen_netif_rx_request *req;
- if (unlikely(!netif_carrier_ok(queue->info->netdev)))
- return;
+ skb = __netdev_alloc_skb(queue->info->netdev,
+ RX_COPY_THRESHOLD + NET_IP_ALIGN,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!skb))
+ return NULL;
- /*
- * Allocate skbuffs greedily, even though we batch updates to the
- * receive ring. This creates a less bursty demand on the memory
- * allocator, so should reduce the chance of failed allocation requests
- * both for ourself and for other kernel subsystems.
- */
- batch_target = queue->rx_target - (req_prod - queue->rx.rsp_cons);
- for (i = skb_queue_len(&queue->rx_batch); i < batch_target; i++) {
- skb = __netdev_alloc_skb(queue->info->netdev,
- RX_COPY_THRESHOLD + NET_IP_ALIGN,
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(!skb))
- goto no_skb;
-
- /* Align ip header to a 16 bytes boundary */
- skb_reserve(skb, NET_IP_ALIGN);
-
- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
- if (!page) {
- kfree_skb(skb);
-no_skb:
- /* Could not allocate any skbuffs. Try again later. */
- mod_timer(&queue->rx_refill_timer,
- jiffies + (HZ/10));
-
- /* Any skbuffs queued for refill? Force them out. */
- if (i != 0)
- goto refill;
- break;
- }
-
- skb_add_rx_frag(skb, 0, page, 0, 0, PAGE_SIZE);
- __skb_queue_tail(&queue->rx_batch, skb);
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+ if (!page) {
+ kfree_skb(skb);
+ return NULL;
}
+ skb_add_rx_frag(skb, 0, page, 0, 0, PAGE_SIZE);
+
+ /* Align ip header to a 16 bytes boundary */
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb->dev = queue->info->netdev;
+
+ return skb;
+}
+
- /* Is the batch large enough to be worthwhile? */
- if (i < (queue->rx_target/2)) {
- if (req_prod > queue->rx.sring->req_prod)
- goto push;
+static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
+{
+ RING_IDX req_prod = queue->rx.req_prod_pvt;
+ int notify;
+
+ if (unlikely(!netif_carrier_ok(queue->info->netdev)))
return;
- }
- /* Adjust our fill target if we risked running out of buffers. */
- if (((req_prod - queue->rx.sring->rsp_prod) < (queue->rx_target / 4)) &&
- ((queue->rx_target *= 2) > queue->rx_max_target))
- queue->rx_target = queue->rx_max_target;
+ for (req_prod = queue->rx.req_prod_pvt;
+ req_prod - queue->rx.rsp_cons < NET_RX_RING_SIZE;
+ req_prod++) {
+ struct sk_buff *skb;
+ unsigned short id;
+ grant_ref_t ref;
+ unsigned long pfn;
+ struct xen_netif_rx_request *req;
- refill:
- for (i = 0; ; i++) {
- skb = __skb_dequeue(&queue->rx_batch);
- if (skb == NULL)
+ skb = xennet_alloc_one_rx_buffer(queue);
+ if (!skb)
break;
- skb->dev = queue->info->netdev;
-
- id = xennet_rxidx(req_prod + i);
+ id = xennet_rxidx(req_prod);
BUG_ON(queue->rx_skbs[id]);
queue->rx_skbs[id] = skb;
queue->grant_rx_ref[id] = ref;
pfn = page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[0]));
- vaddr = page_address(skb_frag_page(&skb_shinfo(skb)->frags[0]));
- req = RING_GET_REQUEST(&queue->rx, req_prod + i);
+ req = RING_GET_REQUEST(&queue->rx, req_prod);
gnttab_grant_foreign_access_ref(ref,
queue->info->xbdev->otherend_id,
pfn_to_mfn(pfn),
req->gref = ref;
}
+ queue->rx.req_prod_pvt = req_prod;
+
+ /* Not enough requests? Try again later. */
+ if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN) {
+ mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10));
+ return;
+ }
+
wmb(); /* barrier so backend seens requests */
- /* Above is a suitable barrier to ensure backend will see requests. */
- queue->rx.req_prod_pvt = req_prod + i;
- push:
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->rx, notify);
if (notify)
notify_remote_via_irq(queue->rx_irq);
work_done -= handle_incoming_queue(queue, &rxq);
- /* If we get a callback with very few responses, reduce fill target. */
- /* NB. Note exponential increase, linear decrease. */
- if (((queue->rx.req_prod_pvt - queue->rx.sring->rsp_prod) >
- ((3*queue->rx_target) / 4)) &&
- (--queue->rx_target < queue->rx_min_target))
- queue->rx_target = queue->rx_min_target;
-
xennet_alloc_rx_buffers(queue);
if (work_done < budget) {
spin_lock_init(&queue->tx_lock);
spin_lock_init(&queue->rx_lock);
- skb_queue_head_init(&queue->rx_batch);
- queue->rx_target = RX_DFL_MIN_TARGET;
- queue->rx_min_target = RX_DFL_MIN_TARGET;
- queue->rx_max_target = RX_MAX_TARGET;
-
init_timer(&queue->rx_refill_timer);
queue->rx_refill_timer.data = (unsigned long)queue;
queue->rx_refill_timer.function = rx_refill_timeout;
}
/* A grant for every tx ring slot */
- if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+ if (gnttab_alloc_grant_references(NET_TX_RING_SIZE,
&queue->gref_tx_head) < 0) {
pr_alert("can't alloc tx grant refs\n");
err = -ENOMEM;
}
/* A grant for every rx ring slot */
- if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+ if (gnttab_alloc_grant_references(NET_RX_RING_SIZE,
&queue->gref_rx_head) < 0) {
pr_alert("can't alloc rx grant refs\n");
err = -ENOMEM;
};
#ifdef CONFIG_SYSFS
-static ssize_t show_rxbuf_min(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct net_device *netdev = to_net_dev(dev);
- struct netfront_info *info = netdev_priv(netdev);
- unsigned int num_queues = netdev->real_num_tx_queues;
-
- if (num_queues)
- return sprintf(buf, "%u\n", info->queues[0].rx_min_target);
- else
- return sprintf(buf, "%u\n", RX_MIN_TARGET);
-}
-
-static ssize_t store_rxbuf_min(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t show_rxbuf(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct net_device *netdev = to_net_dev(dev);
- struct netfront_info *np = netdev_priv(netdev);
- unsigned int num_queues = netdev->real_num_tx_queues;
- char *endp;
- unsigned long target;
- unsigned int i;
- struct netfront_queue *queue;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- target = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EBADMSG;
-
- if (target < RX_MIN_TARGET)
- target = RX_MIN_TARGET;
- if (target > RX_MAX_TARGET)
- target = RX_MAX_TARGET;
-
- for (i = 0; i < num_queues; ++i) {
- queue = &np->queues[i];
- spin_lock_bh(&queue->rx_lock);
- if (target > queue->rx_max_target)
- queue->rx_max_target = target;
- queue->rx_min_target = target;
- if (target > queue->rx_target)
- queue->rx_target = target;
-
- xennet_alloc_rx_buffers(queue);
-
- spin_unlock_bh(&queue->rx_lock);
- }
- return len;
-}
-
-static ssize_t show_rxbuf_max(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct net_device *netdev = to_net_dev(dev);
- struct netfront_info *info = netdev_priv(netdev);
- unsigned int num_queues = netdev->real_num_tx_queues;
-
- if (num_queues)
- return sprintf(buf, "%u\n", info->queues[0].rx_max_target);
- else
- return sprintf(buf, "%u\n", RX_MAX_TARGET);
+ return sprintf(buf, "%lu\n", NET_RX_RING_SIZE);
}
-static ssize_t store_rxbuf_max(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t store_rxbuf(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct net_device *netdev = to_net_dev(dev);
- struct netfront_info *np = netdev_priv(netdev);
- unsigned int num_queues = netdev->real_num_tx_queues;
char *endp;
unsigned long target;
- unsigned int i = 0;
- struct netfront_queue *queue = NULL;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (endp == buf)
return -EBADMSG;
- if (target < RX_MIN_TARGET)
- target = RX_MIN_TARGET;
- if (target > RX_MAX_TARGET)
- target = RX_MAX_TARGET;
-
- for (i = 0; i < num_queues; ++i) {
- queue = &np->queues[i];
- spin_lock_bh(&queue->rx_lock);
- if (target < queue->rx_min_target)
- queue->rx_min_target = target;
- queue->rx_max_target = target;
- if (target < queue->rx_target)
- queue->rx_target = target;
-
- xennet_alloc_rx_buffers(queue);
+ /* rxbuf_min and rxbuf_max are no longer configurable. */
- spin_unlock_bh(&queue->rx_lock);
- }
return len;
}
-static ssize_t show_rxbuf_cur(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct net_device *netdev = to_net_dev(dev);
- struct netfront_info *info = netdev_priv(netdev);
- unsigned int num_queues = netdev->real_num_tx_queues;
-
- if (num_queues)
- return sprintf(buf, "%u\n", info->queues[0].rx_target);
- else
- return sprintf(buf, "0\n");
-}
-
static struct device_attribute xennet_attrs[] = {
- __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
- __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
- __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf),
+ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf),
+ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL),
};
static int xennet_sysfs_addif(struct net_device *netdev)
config QETH
def_tristate y
prompt "Gigabit Ethernet device support"
- depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
+ depends on CCW && NETDEVICES && IP_MULTICAST && QDIO && ETHERNET
help
This driver supports the IBM System z OSA Express adapters
in QDIO mode (all media types), HiperSockets interfaces and z/VM
return -ENODEV;
}
- rc = sscanf(buf, "%u", &bs1);
- if (rc != 1)
+ rc = kstrtouint(buf, 0, &bs1);
+ if (rc)
goto einval;
if (bs1 > CTCM_BUFSIZE_LIMIT)
goto einval;
if (!priv)
return -ENODEV;
- rc = sscanf(buf, "%d", &value);
- if ((rc != 1) ||
+ rc = kstrtoint(buf, 0, &value);
+ if (rc ||
!((value == CTCM_PROTO_S390) ||
(value == CTCM_PROTO_LINUX) ||
(value == CTCM_PROTO_MPC) ||
lcs_portno_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lcs_card *card;
- int value, rc;
+ int rc;
+ s16 value;
card = dev_get_drvdata(dev);
if (!card)
return 0;
- rc = sscanf(buf, "%d", &value);
- if (rc != 1)
+ rc = kstrtos16(buf, 0, &value);
+ if (rc)
return -EINVAL;
/* TODO: sanity checks */
card->portno = value;
if (!card)
return 0;
- rc = sscanf(buf, "%u", &value);
- if (rc != 1)
+ rc = kstrtouint(buf, 0, &value);
+ if (rc)
return -EINVAL;
/* TODO: sanity checks */
card->lancmd_timeout = value;
#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
#define QETH_HDR_EXT_UDP 0x40 /*bit off for TCP*/
-static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
-{
- return (sbale->eflags & SBAL_EFLAGS_LAST_ENTRY);
-}
-
enum qeth_qdio_buffer_states {
/*
* inbound: read out by driver; owned by hardware in order to be filled
/*some helper functions*/
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
-static inline struct qeth_card *CARD_FROM_CDEV(struct ccw_device *cdev)
-{
- struct qeth_card *card = dev_get_drvdata(&((struct ccwgroup_device *)
- dev_get_drvdata(&cdev->dev))->dev);
- return card;
-}
-
static inline int qeth_get_micros(void)
{
return (int) (get_tod_clock() >> 12);
int qeth_realloc_buffer_pool(struct qeth_card *, int);
int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id);
void qeth_core_free_discipline(struct qeth_card *);
-void qeth_buffer_reclaim_work(struct work_struct *);
/* exports for qeth discipline device drivers */
extern struct qeth_card_list_struct qeth_core_card_list;
void qeth_print_status_message(struct qeth_card *);
int qeth_init_qdio_queues(struct qeth_card *);
int qeth_send_startlan(struct qeth_card *);
-int qeth_send_stoplan(struct qeth_card *);
int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
int (*reply_cb)
(struct qeth_card *, struct qeth_reply *, unsigned long),
int qeth_query_oat_command(struct qeth_card *, char __user *);
int qeth_query_switch_attributes(struct qeth_card *card,
struct qeth_switch_info *sw_info);
-int qeth_query_card_info(struct qeth_card *card,
- struct carrier_info *carrier_info);
int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
void *reply_param);
return 0;
}
+static struct qeth_card *CARD_FROM_CDEV(struct ccw_device *cdev)
+{
+ struct qeth_card *card = dev_get_drvdata(&((struct ccwgroup_device *)
+ dev_get_drvdata(&cdev->dev))->dev);
+ return card;
+}
+
static void qeth_setup_ccw(struct qeth_channel *channel, unsigned char *iob,
__u32 len)
{
}
}
+static void qeth_buffer_reclaim_work(struct work_struct *);
static int qeth_setup_card(struct qeth_card *card)
{
}
EXPORT_SYMBOL_GPL(qeth_check_qdio_errors);
-void qeth_buffer_reclaim_work(struct work_struct *work)
+static void qeth_buffer_reclaim_work(struct work_struct *work)
{
struct qeth_card *card = container_of(work, struct qeth_card,
buffer_reclaim_work.work);
qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
if (cmd->hdr.return_code) {
- QETH_CARD_TEXT_(card, 4, "prmrc%2.2x", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "prmrc%x", cmd->hdr.return_code);
setparms->data.mode = SET_PROMISC_MODE_OFF;
}
card->info.promisc_mode = setparms->data.mode;
snmp = &cmd->data.setadapterparms.data.snmp;
if (cmd->hdr.return_code) {
- QETH_CARD_TEXT_(card, 4, "scer1%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code);
return 0;
}
if (cmd->data.setadapterparms.hdr.return_code) {
cmd->hdr.return_code =
cmd->data.setadapterparms.hdr.return_code;
- QETH_CARD_TEXT_(card, 4, "scer2%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "scer2%x", cmd->hdr.return_code);
return 0;
}
data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data));
return 0;
}
-int qeth_query_card_info(struct qeth_card *card,
+static int qeth_query_card_info(struct qeth_card *card,
struct carrier_info *carrier_info)
{
struct qeth_cmd_buffer *iob;
return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb,
(void *)carrier_info);
}
-EXPORT_SYMBOL_GPL(qeth_query_card_info);
static inline int qeth_get_qdio_q_format(struct qeth_card *card)
{
return 0;
}
+static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
+{
+ return (sbale->eflags & SBAL_EFLAGS_LAST_ENTRY);
+}
+
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
struct qeth_qdio_buffer *qethbuffer,
struct qdio_buffer_element **__element, int *__offset,
QETH_CARD_TEXT(card, 2, "brstchng");
if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
- QETH_CARD_TEXT_(card, 2, "BPsz%.8d", qports->entry_length);
+ QETH_CARD_TEXT_(card, 2, "BPsz%04x", qports->entry_length);
return;
}
extrasize = sizeof(struct qeth_sbp_port_entry) * qports->num_entries;
};
-void qeth_l3_ipaddr4_to_string(const __u8 *, char *);
-int qeth_l3_string_to_ipaddr4(const char *, __u8 *);
-void qeth_l3_ipaddr6_to_string(const __u8 *, char *);
-int qeth_l3_string_to_ipaddr6(const char *, __u8 *);
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *);
int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *);
int qeth_l3_create_device_attributes(struct device *);
return 1;
}
-void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
+static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
{
sprintf(buf, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
}
-int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
+static int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
{
int count = 0, rc = 0;
unsigned int in[4];
return 0;
}
-void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
+static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
{
sprintf(buf, "%pI6", addr);
}
-int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
+static int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
{
const char *end, *end_tmp, *start;
__u16 *in;
rc = -EFAULT;
goto free_and_out;
}
- QETH_CARD_TEXT_(card, 4, "qacts");
+ QETH_CARD_TEXT(card, 4, "qacts");
}
free_and_out:
kfree(qinfo.udata);
/* Process Mbox response of VNP command */
rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
- if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+ if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n",
- FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+ FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
ret = -EINVAL;
goto out_free;
}
/* Process Mbox response of VNP command */
rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
- if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+ if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n",
- FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+ FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
ret = -EINVAL;
}
caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb);
CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1);
caps_cmd->op_to_write =
- htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ);
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
caps_cmd->cfvalid_to_len16 =
htonl(FW_CAPS_CONFIG_CMD_CFVALID |
FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
* And now tell the firmware to use the configuration we just loaded.
*/
caps_cmd->op_to_write =
- htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE);
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F);
caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd));
if (csio_mb_issue(hw, mbp)) {
}
rsp = (struct fw_fcoe_res_info_cmd *)(mbp->mb);
- retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+ retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
if (retval != FW_SUCCESS) {
csio_err(hw, "FW_FCOE_RES_INFO_CMD failed with ret x%x\n",
retval);
* MEM_EDC1 = 1
* MEM_MC = 2 -- T4
*/
- edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ edc_size = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A));
if (mtype != MEM_MC1)
memoffset = (mtype * (edc_size * 1024 * 1024));
else {
- mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
- MA_EXT_MEMORY_BAR));
+ mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR_A));
memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
}
csio_t4_dfs_create_ext_mem(struct csio_hw *hw)
{
u32 size;
- int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
- if (i & EXT_MEM_ENABLE) {
- size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+
+ if (i & EXT_MEM_ENABLE_F) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A);
csio_add_debugfs_mem(hw, "mc", MEM_MC,
- EXT_MEM_SIZE_GET(size));
+ EXT_MEM_SIZE_G(size));
}
}
* MEM_MC0 = 2 -- For T5
* MEM_MC1 = 3 -- For T5
*/
- edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ edc_size = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A));
if (mtype != MEM_MC1)
memoffset = (mtype * (edc_size * 1024 * 1024));
else {
- mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
- MA_EXT_MEMORY_BAR));
+ mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR_A));
memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
}
csio_t5_dfs_create_ext_mem(struct csio_hw *hw)
{
u32 size;
- int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
- if (i & EXT_MEM_ENABLE) {
- size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+
+ if (i & EXT_MEM_ENABLE_F) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A);
csio_add_debugfs_mem(hw, "mc0", MEM_MC0,
- EXT_MEM_SIZE_GET(size));
+ EXT_MEM_SIZE_G(size));
}
- if (i & EXT_MEM1_ENABLE) {
- size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR);
+ if (i & EXT_MEM1_ENABLE_F) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR_A);
csio_add_debugfs_mem(hw, "mc1", MEM_MC1,
- EXT_MEM_SIZE_GET(size));
+ EXT_MEM_SIZE_G(size));
}
}
if (IS_ERR_OR_NULL(hw->debugfs_root))
return -1;
- i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
- if (i & EDRAM0_ENABLE)
+ i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+ if (i & EDRAM0_ENABLE_F)
csio_add_debugfs_mem(hw, "edc0", MEM_EDC0, 5);
- if (i & EDRAM1_ENABLE)
+ if (i & EDRAM1_ENABLE_F)
csio_add_debugfs_mem(hw, "edc1", MEM_EDC1, 5);
hw->chip_ops->chip_dfs_create_ext_mem(hw);
enum fw_retval retval;
__be32 nport_id;
- retval = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+ retval = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
if (retval != FW_SUCCESS) {
csio_err(hw, "FCOE VNP read cmd returned error:0x%x\n", retval);
mempool_free(mbp, hw->mb_mempool);
(struct fw_fcoe_fcf_cmd *)(mbp->mb);
enum fw_retval retval;
- retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+ retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
if (retval != FW_SUCCESS) {
csio_ln_err(ln, "FCOE FCF cmd failed with ret x%x\n",
retval);
}
} else if (cpl_op == CPL_FW6_PLD) {
wr = (struct fw_wr_hdr *) (cmd + 4);
- if (FW_WR_OP_GET(be32_to_cpu(wr->hi))
+ if (FW_WR_OP_G(be32_to_cpu(wr->hi))
== FW_RDEV_WR) {
rdev_wr = (struct fw_rdev_wr *) (cmd + 4);
return;
} else {
csio_warn(hw, "unexpected WR op(0x%x) recv\n",
- FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+ FW_WR_OP_G(be32_to_cpu((wr->hi))));
CSIO_INC_STATS(hw, n_cpl_unexp);
}
} else if (cpl_op == CPL_FW6_MSG) {
wr = (struct fw_wr_hdr *) (cmd);
- if (FW_WR_OP_GET(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
+ if (FW_WR_OP_G(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
csio_ln_mgmt_wr_handler(hw, wr,
sizeof(struct fw_fcoe_els_ct_wr));
} else {
csio_warn(hw, "unexpected WR op(0x%x) recv\n",
- FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+ FW_WR_OP_G(be32_to_cpu((wr->hi))));
CSIO_INC_STATS(hw, n_cpl_unexp);
}
} else {
__be32 port_id;
wr = (struct fw_fcoe_els_ct_wr *)fw_wr;
- wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_FCOE_ELS_CT_WR) |
+ wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_FCOE_ELS_CT_WR) |
FW_FCOE_ELS_CT_WR_IMMDLEN(immd_len));
wr_len = DIV_ROUND_UP(wr_len, 16);
- wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(flow_id) |
- FW_WR_LEN16(wr_len));
+ wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(flow_id) |
+ FW_WR_LEN16_V(wr_len));
wr->els_ct_type = sub_op;
wr->ctl_pri = 0;
wr->cp_en_class = 0;
csio_wr_copy_to_wrp(pld->vaddr, &wrp, wr_off, im_len);
else {
/* Program DSGL to dma payload */
- dsgl.cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) |
+ dsgl.cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
ULPTX_MORE | ULPTX_NSGE(1));
dsgl.len0 = cpu_to_be32(pld_len);
dsgl.addr0 = cpu_to_be64(pld->paddr);
hdr = (struct fw_cmd_hdr *)(mbp->mb);
- return FW_CMD_RETVAL_GET(ntohl(hdr->lo));
+ return FW_CMD_RETVAL_G(ntohl(hdr->lo));
}
/*
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_write = htonl(FW_CMD_OP(FW_HELLO_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_HELLO_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->err_to_clearinit = htonl(
FW_HELLO_CMD_MASTERDIS(master == CSIO_MASTER_CANT) |
FW_HELLO_CMD_MASTERFORCE(master == CSIO_MASTER_MUST) |
struct fw_hello_cmd *rsp = (struct fw_hello_cmd *)(mbp->mb);
uint32_t value;
- *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+ *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
if (*retval == FW_SUCCESS) {
hw->fwrev = ntohl(rsp->fwrev);
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_write = htonl(FW_CMD_OP(FW_BYE_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_BYE_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
}
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_write = htonl(FW_CMD_OP(FW_RESET_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_RESET_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->val = htonl(reset);
cmdp->halt_pkd = htonl(halt);
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) |
- FW_CMD_REQUEST |
- (wr ? FW_CMD_WRITE : FW_CMD_READ) |
+ cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F |
+ (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F) |
FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
/* Write Params */
if (wr) {
uint32_t i;
__be32 *p = &rsp->param[0].val;
- *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+ *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
if (*retval == FW_SUCCESS)
for (i = 0; i < nparams; i++, p += 2)
* specified PCI-E Configuration Space register.
*/
ldst_cmd->op_to_addrspace =
- htonl(FW_CMD_OP(FW_LDST_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ htonl(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
ldst_cmd->cycles_to_len16 = htonl(FW_LEN16(struct fw_ldst_cmd));
ldst_cmd->u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, wr ? 0 : 1);
- cmdp->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST |
- (wr ? FW_CMD_WRITE : FW_CMD_READ));
- cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F));
+ cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
/* Read config */
if (!wr)
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) |
- FW_CMD_REQUEST |
- (wr ? FW_CMD_EXEC : FW_CMD_READ) |
+ cmdp->op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) |
+ FW_CMD_REQUEST_F |
+ (wr ? FW_CMD_EXEC_F : FW_CMD_READ_F) |
FW_PORT_CMD_PORTID(portid));
if (!wr) {
cmdp->action_to_len16 = htonl(
FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
return;
}
/* Set port */
cmdp->action_to_len16 = htonl(
FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
if (fc & PAUSE_RX)
lfc |= FW_PORT_CAP_FC_RX;
{
struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
- *retval = FW_CMD_RETVAL_GET(ntohl(rsp->action_to_len16));
+ *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
if (*retval == FW_SUCCESS)
*caps = ntohs(rsp->u.info.pcap);
CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
- cmdp->op_to_write = htonl(FW_CMD_OP(FW_INITIALIZE_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_INITIALIZE_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
}
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) |
- FW_CMD_REQUEST | FW_CMD_EXEC |
+ cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_IQ_CMD_PFN(iq_params->pfn) |
FW_IQ_CMD_VFN(iq_params->vfn));
cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->type_to_iqandstindex = htonl(
FW_IQ_CMD_VIID(iq_params->viid) |
if (!cascaded_req)
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_IQ_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE |
+ cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_IQ_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
FW_IQ_CMD_PFN(iq_params->pfn) |
FW_IQ_CMD_VFN(iq_params->vfn));
cmdp->alloc_to_len16 |= htonl(iq_start_stop |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->iqid |= htons(iq_params->iqid);
cmdp->fl0id |= htons(iq_params->fl0id);
cmdp->fl1id |= htons(iq_params->fl1id);
{
struct fw_iq_cmd *rsp = (struct fw_iq_cmd *)(mbp->mb);
- *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+ *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
if (*ret_val == FW_SUCCESS) {
iq_params->physiqid = ntohs(rsp->physiqid);
iq_params->iqid = ntohs(rsp->iqid);
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) |
- FW_CMD_REQUEST | FW_CMD_EXEC |
+ cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_IQ_CMD_PFN(iq_params->pfn) |
FW_IQ_CMD_VFN(iq_params->vfn));
cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_FREE |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iq_params->type));
cmdp->iqid = htons(iq_params->iqid);
struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) |
- FW_CMD_REQUEST | FW_CMD_EXEC |
+ cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
} /* csio_mb_eq_ofld_alloc */
if (!cascaded_req)
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE |
+ cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
cmdp->alloc_to_len16 |= htonl(eq_start_stop |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->eqid_pkd |= htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
{
struct fw_eq_ofld_cmd *rsp = (struct fw_eq_ofld_cmd *)(mbp->mb);
- *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+ *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
if (*ret_val == FW_SUCCESS) {
eq_ofld_params->eqid = FW_EQ_OFLD_CMD_EQID_GET(
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
- cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) |
- FW_CMD_REQUEST | FW_CMD_EXEC |
+ cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
} /* csio_mb_eq_ofld_free */
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
cmdp->op_to_portid = htonl((
- FW_CMD_OP(FW_FCOE_LINK_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_WRITE |
+ FW_CMD_OP_V(FW_FCOE_LINK_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F |
FW_FCOE_LINK_CMD_PORTID(port_id)));
cmdp->sub_opcode_fcfi = htonl(
FW_FCOE_LINK_CMD_SUB_OPCODE(sub_opcode) |
FW_FCOE_LINK_CMD_FCFI(fcfi));
cmdp->lstatus = link_status;
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
} /* csio_write_fcoe_link_cond_init_mb */
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
- cmdp->op_to_read = htonl((FW_CMD_OP(FW_FCOE_RES_INFO_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ));
+ cmdp->op_to_read = htonl((FW_CMD_OP_V(FW_FCOE_RES_INFO_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F));
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
} /* csio_fcoe_read_res_info_init_mb */
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
- cmdp->op_to_fcfi = htonl((FW_CMD_OP(FW_FCOE_VNP_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC |
+ cmdp->op_to_fcfi = htonl((FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F |
FW_FCOE_VNP_CMD_FCFI(fcfi)));
cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_ALLOC |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
(struct fw_fcoe_vnp_cmd *)(mbp->mb);
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
- cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_FCOE_VNP_CMD_FCFI(fcfi));
- cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
}
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
- cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_EXEC |
+ cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_EXEC_F |
FW_FCOE_VNP_CMD_FCFI(fcfi));
cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_FREE |
- FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
}
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
- cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_FCF_CMD) |
- FW_CMD_REQUEST |
- FW_CMD_READ |
+ cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_FCF_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
FW_FCOE_FCF_CMD_FCFI(fcfi));
- cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+ cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
} /* csio_fcoe_read_fcf_init_mb */
CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
mbp->mb_size = 64;
- cmdp->op_to_flowid = htonl(FW_CMD_OP(FW_FCOE_STATS_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
- cmdp->free_to_len16 = htonl(FW_CMD_LEN16(CSIO_MAX_MB_SIZE/16));
+ cmdp->op_to_flowid = htonl(FW_CMD_OP_V(FW_FCOE_STATS_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
+ cmdp->free_to_len16 = htonl(FW_CMD_LEN16_V(CSIO_MAX_MB_SIZE/16));
cmdp->u.ctl.nstats_port = FW_FCOE_STATS_CMD_NSTATS(portparams->nstats) |
FW_FCOE_STATS_CMD_PORT(portparams->portid);
uint8_t *src;
uint8_t *dst;
- *retval = FW_CMD_RETVAL_GET(ntohl(rsp->free_to_len16));
+ *retval = FW_CMD_RETVAL_G(ntohl(rsp->free_to_len16));
memset(&stats, 0, sizeof(struct fw_fcoe_port_stats));
hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
fw_hdr = (struct fw_cmd_hdr *)&hdr;
- switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
+ switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
case FW_DEBUG_CMD:
csio_mb_debug_cmd_handler(hw);
continue;
hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
fw_hdr = (struct fw_cmd_hdr *)&hdr;
- switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
+ switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
case FW_DEBUG_CMD:
csio_mb_debug_cmd_handler(hw);
return -EINVAL;
fw_hdr = (struct fw_cmd_hdr *)(mbp->mb);
csio_dbg(hw, "Mailbox num:%x op:0x%x timed out\n", hw->pfn,
- FW_CMD_OP_GET(ntohl(fw_hdr->hi)));
+ FW_CMD_OP_G(ntohl(fw_hdr->hi)));
mbm->mcurrent = NULL;
CSIO_INC_STATS(mbm, n_tmo);
- fw_hdr->lo = htonl(FW_CMD_RETVAL(FW_ETIMEDOUT));
+ fw_hdr->lo = htonl(FW_CMD_RETVAL_V(FW_ETIMEDOUT));
return mbp;
}
hdr = (struct fw_cmd_hdr *)(mbp->mb);
csio_dbg(hw, "Cancelling pending mailbox num %x op:%x\n",
- hw->pfn, FW_CMD_OP_GET(ntohl(hdr->hi)));
+ hw->pfn, FW_CMD_OP_G(ntohl(hdr->hi)));
CSIO_INC_STATS(mbm, n_cancel);
- hdr->lo = htonl(FW_CMD_RETVAL(FW_HOSTERROR));
+ hdr->lo = htonl(FW_CMD_RETVAL_V(FW_HOSTERROR));
}
}
struct csio_dma_buf *dma_buf;
uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
- wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_CMD_WR) |
+ wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_CMD_WR) |
FW_SCSI_CMD_WR_IMMDLEN(imm));
- wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
- FW_WR_LEN16(
+ wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+ FW_WR_LEN16_V(
DIV_ROUND_UP(size, 16)));
wr->cookie = (uintptr_t) req;
struct csio_dma_buf *dma_buf;
struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
- sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_MORE |
+ sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE |
ULPTX_NSGE(req->nsge));
/* Now add the data SGLs */
if (likely(!req->dcopy)) {
uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
- wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_READ_WR) |
+ wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_READ_WR) |
FW_SCSI_READ_WR_IMMDLEN(imm));
- wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
- FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+ wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(size, 16)));
wr->cookie = (uintptr_t)req;
wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
wr->tmo_val = (uint8_t)(req->tmo);
uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
- wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_WRITE_WR) |
+ wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_WRITE_WR) |
FW_SCSI_WRITE_WR_IMMDLEN(imm));
- wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
- FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+ wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+ FW_WR_LEN16_V(DIV_ROUND_UP(size, 16)));
wr->cookie = (uintptr_t)req;
wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
wr->tmo_val = (uint8_t)(req->tmo);
struct csio_rnode *rn = req->rnode;
struct fw_scsi_abrt_cls_wr *wr = (struct fw_scsi_abrt_cls_wr *)addr;
- wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_ABRT_CLS_WR));
- wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
- FW_WR_LEN16(
+ wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_ABRT_CLS_WR));
+ wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+ FW_WR_LEN16_V(
DIV_ROUND_UP(size, 16)));
wr->cookie = (uintptr_t) req;
/* WR status is at the same position as retval in a CMD header */
#define csio_wr_status(_wr) \
- (FW_CMD_RETVAL_GET(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
+ (FW_CMD_RETVAL_G(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
struct csio_hw;
unsigned int qid_atid = ((unsigned int)csk->atid) |
(((unsigned int)csk->rss_qid) << 14);
- opt0 = KEEP_ALIVE(1) |
- WND_SCALE(wscale) |
- MSS_IDX(csk->mss_idx) |
- L2T_IDX(((struct l2t_entry *)csk->l2t)->idx) |
- TX_CHAN(csk->tx_chan) |
- SMAC_SEL(csk->smac_idx) |
- ULP_MODE(ULP_MODE_ISCSI) |
- RCV_BUFSIZ(cxgb4i_rcv_win >> 10);
- opt2 = RX_CHANNEL(0) |
- RSS_QUEUE_VALID |
- (1 << 20) |
- RSS_QUEUE(csk->rss_qid);
+ opt0 = KEEP_ALIVE_F |
+ WND_SCALE_V(wscale) |
+ MSS_IDX_V(csk->mss_idx) |
+ L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) |
+ TX_CHAN_V(csk->tx_chan) |
+ SMAC_SEL_V(csk->smac_idx) |
+ ULP_MODE_V(ULP_MODE_ISCSI) |
+ RCV_BUFSIZ_V(cxgb4i_rcv_win >> 10);
+ opt2 = RX_CHANNEL_V(0) |
+ RSS_QUEUE_VALID_F |
+ (RX_FC_DISABLE_F) |
+ RSS_QUEUE_V(csk->rss_qid);
if (is_t4(lldi->adapter_type)) {
struct cpl_act_open_req *req =
req->params = cpu_to_be32(cxgb4_select_ntuple(
csk->cdev->ports[csk->port_id],
csk->l2t));
- opt2 |= 1 << 22;
+ opt2 |= RX_FC_VALID_F;
req->opt2 = cpu_to_be32(opt2);
log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
req->local_ip = csk->saddr.sin_addr.s_addr;
req->peer_ip = csk->daddr.sin_addr.s_addr;
req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be64(V_FILTER_TUPLE(
+ req->params = cpu_to_be64(FILTER_TUPLE_V(
cxgb4_select_ntuple(
csk->cdev->ports[csk->port_id],
csk->l2t)));
unsigned int qid_atid = ((unsigned int)csk->atid) |
(((unsigned int)csk->rss_qid) << 14);
- opt0 = KEEP_ALIVE(1) |
- WND_SCALE(wscale) |
- MSS_IDX(csk->mss_idx) |
- L2T_IDX(((struct l2t_entry *)csk->l2t)->idx) |
- TX_CHAN(csk->tx_chan) |
- SMAC_SEL(csk->smac_idx) |
- ULP_MODE(ULP_MODE_ISCSI) |
- RCV_BUFSIZ(cxgb4i_rcv_win >> 10);
+ opt0 = KEEP_ALIVE_F |
+ WND_SCALE_V(wscale) |
+ MSS_IDX_V(csk->mss_idx) |
+ L2T_IDX_V(((struct l2t_entry *)csk->l2t)->idx) |
+ TX_CHAN_V(csk->tx_chan) |
+ SMAC_SEL_V(csk->smac_idx) |
+ ULP_MODE_V(ULP_MODE_ISCSI) |
+ RCV_BUFSIZ_V(cxgb4i_rcv_win >> 10);
- opt2 = RX_CHANNEL(0) |
- RSS_QUEUE_VALID |
- RX_FC_DISABLE |
- RSS_QUEUE(csk->rss_qid);
+ opt2 = RX_CHANNEL_V(0) |
+ RSS_QUEUE_VALID_F |
+ RX_FC_DISABLE_F |
+ RSS_QUEUE_V(csk->rss_qid);
if (t4) {
struct cpl_act_open_req6 *req =
req->opt0 = cpu_to_be64(opt0);
- opt2 |= RX_FC_VALID;
+ opt2 |= RX_FC_VALID_F;
req->opt2 = cpu_to_be32(opt2);
req->params = cpu_to_be32(cxgb4_select_ntuple(
8);
req->opt0 = cpu_to_be64(opt0);
- opt2 |= T5_OPT_2_VALID;
+ opt2 |= T5_OPT_2_VALID_F;
req->opt2 = cpu_to_be32(opt2);
- req->params = cpu_to_be64(V_FILTER_TUPLE(cxgb4_select_ntuple(
+ req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple(
csk->cdev->ports[csk->port_id],
csk->l2t)));
}
INIT_TP_WR(req, csk->tid);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK,
csk->tid));
- req->credit_dack = cpu_to_be32(RX_CREDITS(credits) | RX_FORCE_ACK(1));
+ req->credit_dack = cpu_to_be32(RX_CREDITS_V(credits)
+ | RX_FORCE_ACK_F);
cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb);
return credits;
}
skb = alloc_wr(flowclen, 0, GFP_ATOMIC);
flowc = (struct fw_flowc_wr *)skb->head;
flowc->op_to_nparams =
- htonl(FW_WR_OP(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS(8));
+ htonl(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(8));
flowc->flowid_len16 =
- htonl(FW_WR_LEN16(DIV_ROUND_UP(72, 16)) |
- FW_WR_FLOWID(csk->tid));
+ htonl(FW_WR_LEN16_V(DIV_ROUND_UP(72, 16)) |
+ FW_WR_FLOWID_V(csk->tid));
flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
flowc->mnemval[0].val = htonl(csk->cdev->pfvf);
flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
{
struct fw_ofld_tx_data_wr *req;
unsigned int submode = cxgbi_skcb_ulp_mode(skb) & 3;
- unsigned int wr_ulp_mode = 0;
+ unsigned int wr_ulp_mode = 0, val;
req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, sizeof(*req));
if (is_ofld_imm(skb)) {
- req->op_to_immdlen = htonl(FW_WR_OP(FW_OFLD_TX_DATA_WR) |
- FW_WR_COMPL(1) |
- FW_WR_IMMDLEN(dlen));
- req->flowid_len16 = htonl(FW_WR_FLOWID(csk->tid) |
- FW_WR_LEN16(credits));
+ req->op_to_immdlen = htonl(FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+ FW_WR_COMPL_F |
+ FW_WR_IMMDLEN_V(dlen));
+ req->flowid_len16 = htonl(FW_WR_FLOWID_V(csk->tid) |
+ FW_WR_LEN16_V(credits));
} else {
req->op_to_immdlen =
- cpu_to_be32(FW_WR_OP(FW_OFLD_TX_DATA_WR) |
- FW_WR_COMPL(1) |
- FW_WR_IMMDLEN(0));
+ cpu_to_be32(FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+ FW_WR_COMPL_F |
+ FW_WR_IMMDLEN_V(0));
req->flowid_len16 =
- cpu_to_be32(FW_WR_FLOWID(csk->tid) |
- FW_WR_LEN16(credits));
+ cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
+ FW_WR_LEN16_V(credits));
}
if (submode)
- wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE(ULP2_MODE_ISCSI) |
- FW_OFLD_TX_DATA_WR_ULPSUBMODE(submode);
+ wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP2_MODE_ISCSI) |
+ FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
+ val = skb_peek(&csk->write_queue) ? 0 : 1;
req->tunnel_to_proxy = htonl(wr_ulp_mode |
- FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1));
+ FW_OFLD_TX_DATA_WR_SHOVE_V(val));
req->plen = htonl(len);
if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT))
cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT);
INIT_ULPTX_WR(req, wr_len, 0, 0);
if (is_t4(lldi->adapter_type))
- req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) |
- (ULP_MEMIO_ORDER(1)));
+ req->cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
+ (ULP_MEMIO_ORDER_F));
else
- req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) |
- (V_T5_ULP_MEMIO_IMM(1)));
- req->dlen = htonl(ULP_MEMIO_DATA_LEN(dlen >> 5));
- req->lock_addr = htonl(ULP_MEMIO_ADDR(pm_addr >> 5));
+ req->cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
+ (T5_ULP_MEMIO_IMM_F));
+ req->dlen = htonl(ULP_MEMIO_DATA_LEN_V(dlen >> 5));
+ req->lock_addr = htonl(ULP_MEMIO_ADDR_V(pm_addr >> 5));
req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16));
- idata->cmd_more = htonl(ULPTX_CMD(ULP_TX_SC_IMM));
+ idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
idata->len = htonl(dlen);
}
cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr);
cdev->itp = &cxgb4i_iscsi_transport;
- cdev->pfvf = FW_VIID_PFN_GET(cxgb4_port_viid(lldi->ports[0])) << 8;
+ cdev->pfvf = FW_VIID_PFN_G(cxgb4_port_viid(lldi->ports[0]))
+ << FW_VIID_PFN_S;
pr_info("cdev 0x%p,%s, pfvf %u.\n",
cdev, lldi->ports[0]->name, cdev->pfvf);
}
static int cfg80211_rtw_del_station(struct wiphy *wiphy,
- struct net_device *ndev, const u8 *mac)
+ struct net_device *ndev,
+ struct station_del_parameters *params)
{
+ const u8 *mac = params->mac;
int ret = 0;
struct list_head *phead, *plist, *ptmp;
u8 updated = 0;
struct page *page;
int err;
- page = __skb_alloc_page(gfp_flags | __GFP_NOMEMALLOC, NULL);
+ page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
if (!page)
return -ENOMEM;
if (page)
put_page(page);
if (req)
- pn_rx_submit(fp, req, GFP_ATOMIC | __GFP_COLD);
+ pn_rx_submit(fp, req, GFP_ATOMIC);
}
/*-------------------------------------------------------------------------*/
netif_carrier_on(dev);
for (i = 0; i < phonet_rxq_size; i++)
- pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC | __GFP_COLD);
+ pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
}
spin_unlock(&port->lock);
return 0;
#ifndef __ASM_GENERIC_HASH_H
#define __ASM_GENERIC_HASH_H
-struct fast_hash_ops;
-static inline void setup_arch_fast_hash(struct fast_hash_ops *ops)
+#include <linux/jhash.h>
+
+/**
+ * arch_fast_hash - Caclulates a hash over a given buffer that can have
+ * arbitrary size. This function will eventually use an
+ * architecture-optimized hashing implementation if
+ * available, and trades off distribution for speed.
+ *
+ * @data: buffer to hash
+ * @len: length of buffer in bytes
+ * @seed: start seed
+ *
+ * Returns 32bit hash.
+ */
+static inline u32 arch_fast_hash(const void *data, u32 len, u32 seed)
+{
+ return jhash(data, len, seed);
+}
+
+/**
+ * arch_fast_hash2 - Caclulates a hash over a given buffer that has a
+ * size that is of a multiple of 32bit words. This
+ * function will eventually use an architecture-
+ * optimized hashing implementation if available,
+ * and trades off distribution for speed.
+ *
+ * @data: buffer to hash (must be 32bit padded)
+ * @len: number of 32bit words
+ * @seed: start seed
+ *
+ * Returns 32bit hash.
+ */
+static inline u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
{
+ return jhash2(data, len, seed);
}
#endif /* __ASM_GENERIC_HASH_H */
u32 gpio_mask;
u32 gpio_val;
+ bool endian_check;
bool is_clk_25mhz;
bool tx_gain_buffalo;
+ bool disable_2ghz;
+ bool disable_5ghz;
int (*get_mac_revision)(void);
int (*external_reset)(void);
return (u32)val;
}
-struct fast_hash_ops {
- u32 (*hash)(const void *data, u32 len, u32 seed);
- u32 (*hash2)(const u32 *data, u32 len, u32 seed);
-};
-
-/**
- * arch_fast_hash - Caclulates a hash over a given buffer that can have
- * arbitrary size. This function will eventually use an
- * architecture-optimized hashing implementation if
- * available, and trades off distribution for speed.
- *
- * @data: buffer to hash
- * @len: length of buffer in bytes
- * @seed: start seed
- *
- * Returns 32bit hash.
- */
-extern u32 arch_fast_hash(const void *data, u32 len, u32 seed);
-
-/**
- * arch_fast_hash2 - Caclulates a hash over a given buffer that has a
- * size that is of a multiple of 32bit words. This
- * function will eventually use an architecture-
- * optimized hashing implementation if available,
- * and trades off distribution for speed.
- *
- * @data: buffer to hash (must be 32bit padded)
- * @len: number of 32bit words
- * @seed: start seed
- *
- * Returns 32bit hash.
- */
-extern u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed);
-
#endif /* _LINUX_HASH_H */
#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2
/*
- * Maximum length of AMPDU that the STA can receive.
+ * Maximum length of AMPDU that the STA can receive in high-throughput (HT).
* Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
*/
enum ieee80211_max_ampdu_length_exp {
IEEE80211_HT_MAX_AMPDU_64K = 3
};
+/*
+ * Maximum length of AMPDU that the STA can receive in VHT.
+ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+enum ieee80211_vht_max_ampdu_length_exp {
+ IEEE80211_VHT_MAX_AMPDU_8K = 0,
+ IEEE80211_VHT_MAX_AMPDU_16K = 1,
+ IEEE80211_VHT_MAX_AMPDU_32K = 2,
+ IEEE80211_VHT_MAX_AMPDU_64K = 3,
+ IEEE80211_VHT_MAX_AMPDU_128K = 4,
+ IEEE80211_VHT_MAX_AMPDU_256K = 5,
+ IEEE80211_VHT_MAX_AMPDU_512K = 6,
+ IEEE80211_VHT_MAX_AMPDU_1024K = 7
+};
+
#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
/* Minimum MPDU start spacing */
WLAN_TDLS_DISCOVERY_REQUEST = 10,
};
+/* Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2)
+
/* Interworking capabilities are set in 7th bit of 4th byte of the
* @WLAN_EID_EXT_CAPABILITY information element
*/
--- /dev/null
+/*
+ * IEEE802.15.4-2003 specification
+ *
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#ifndef LINUX_IEEE802154_H
+#define LINUX_IEEE802154_H
+
+#include <linux/types.h>
+
+#define IEEE802154_MTU 127
+#define IEEE802154_MIN_PSDU_LEN 5
+
+#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */
+#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */
+#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */
+#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */
+
+#define IEEE802154_FC_TYPE_SHIFT 0
+#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1)
+#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT)
+#define IEEE802154_FC_SET_TYPE(v, x) do { \
+ v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \
+ (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
+ } while (0)
+
+#define IEEE802154_FC_SECEN_SHIFT 3
+#define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT)
+#define IEEE802154_FC_FRPEND_SHIFT 4
+#define IEEE802154_FC_FRPEND (1 << IEEE802154_FC_FRPEND_SHIFT)
+#define IEEE802154_FC_ACK_REQ_SHIFT 5
+#define IEEE802154_FC_ACK_REQ (1 << IEEE802154_FC_ACK_REQ_SHIFT)
+#define IEEE802154_FC_INTRA_PAN_SHIFT 6
+#define IEEE802154_FC_INTRA_PAN (1 << IEEE802154_FC_INTRA_PAN_SHIFT)
+
+#define IEEE802154_FC_SAMODE_SHIFT 14
+#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT)
+#define IEEE802154_FC_DAMODE_SHIFT 10
+#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT)
+
+#define IEEE802154_FC_VERSION_SHIFT 12
+#define IEEE802154_FC_VERSION_MASK (3 << IEEE802154_FC_VERSION_SHIFT)
+#define IEEE802154_FC_VERSION(x) ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT)
+
+#define IEEE802154_FC_SAMODE(x) \
+ (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
+
+#define IEEE802154_FC_DAMODE(x) \
+ (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
+
+#define IEEE802154_SCF_SECLEVEL_MASK 7
+#define IEEE802154_SCF_SECLEVEL_SHIFT 0
+#define IEEE802154_SCF_SECLEVEL(x) (x & IEEE802154_SCF_SECLEVEL_MASK)
+#define IEEE802154_SCF_KEY_ID_MODE_SHIFT 3
+#define IEEE802154_SCF_KEY_ID_MODE_MASK (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+#define IEEE802154_SCF_KEY_ID_MODE(x) \
+ ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+
+#define IEEE802154_SCF_KEY_IMPLICIT 0
+#define IEEE802154_SCF_KEY_INDEX 1
+#define IEEE802154_SCF_KEY_SHORT_INDEX 2
+#define IEEE802154_SCF_KEY_HW_INDEX 3
+
+#define IEEE802154_SCF_SECLEVEL_NONE 0
+#define IEEE802154_SCF_SECLEVEL_MIC32 1
+#define IEEE802154_SCF_SECLEVEL_MIC64 2
+#define IEEE802154_SCF_SECLEVEL_MIC128 3
+#define IEEE802154_SCF_SECLEVEL_ENC 4
+#define IEEE802154_SCF_SECLEVEL_ENC_MIC32 5
+#define IEEE802154_SCF_SECLEVEL_ENC_MIC64 6
+#define IEEE802154_SCF_SECLEVEL_ENC_MIC128 7
+
+/* MAC footer size */
+#define IEEE802154_MFR_SIZE 2 /* 2 octets */
+
+/* MAC's Command Frames Identifiers */
+#define IEEE802154_CMD_ASSOCIATION_REQ 0x01
+#define IEEE802154_CMD_ASSOCIATION_RESP 0x02
+#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03
+#define IEEE802154_CMD_DATA_REQ 0x04
+#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05
+#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06
+#define IEEE802154_CMD_BEACON_REQ 0x07
+#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08
+#define IEEE802154_CMD_GTS_REQ 0x09
+
+/*
+ * The return values of MAC operations
+ */
+enum {
+ /*
+ * The requested operation was completed successfully.
+ * For a transmission request, this value indicates
+ * a successful transmission.
+ */
+ IEEE802154_SUCCESS = 0x0,
+
+ /* The beacon was lost following a synchronization request. */
+ IEEE802154_BEACON_LOSS = 0xe0,
+ /*
+ * A transmission could not take place due to activity on the
+ * channel, i.e., the CSMA-CA mechanism has failed.
+ */
+ IEEE802154_CHNL_ACCESS_FAIL = 0xe1,
+ /* The GTS request has been denied by the PAN coordinator. */
+ IEEE802154_DENINED = 0xe2,
+ /* The attempt to disable the transceiver has failed. */
+ IEEE802154_DISABLE_TRX_FAIL = 0xe3,
+ /*
+ * The received frame induces a failed security check according to
+ * the security suite.
+ */
+ IEEE802154_FAILED_SECURITY_CHECK = 0xe4,
+ /*
+ * The frame resulting from secure processing has a length that is
+ * greater than aMACMaxFrameSize.
+ */
+ IEEE802154_FRAME_TOO_LONG = 0xe5,
+ /*
+ * The requested GTS transmission failed because the specified GTS
+ * either did not have a transmit GTS direction or was not defined.
+ */
+ IEEE802154_INVALID_GTS = 0xe6,
+ /*
+ * A request to purge an MSDU from the transaction queue was made using
+ * an MSDU handle that was not found in the transaction table.
+ */
+ IEEE802154_INVALID_HANDLE = 0xe7,
+ /* A parameter in the primitive is out of the valid range.*/
+ IEEE802154_INVALID_PARAMETER = 0xe8,
+ /* No acknowledgment was received after aMaxFrameRetries. */
+ IEEE802154_NO_ACK = 0xe9,
+ /* A scan operation failed to find any network beacons.*/
+ IEEE802154_NO_BEACON = 0xea,
+ /* No response data were available following a request. */
+ IEEE802154_NO_DATA = 0xeb,
+ /* The operation failed because a short address was not allocated. */
+ IEEE802154_NO_SHORT_ADDRESS = 0xec,
+ /*
+ * A receiver enable request was unsuccessful because it could not be
+ * completed within the CAP.
+ */
+ IEEE802154_OUT_OF_CAP = 0xed,
+ /*
+ * A PAN identifier conflict has been detected and communicated to the
+ * PAN coordinator.
+ */
+ IEEE802154_PANID_CONFLICT = 0xee,
+ /* A coordinator realignment command has been received. */
+ IEEE802154_REALIGMENT = 0xef,
+ /* The transaction has expired and its information discarded. */
+ IEEE802154_TRANSACTION_EXPIRED = 0xf0,
+ /* There is no capacity to store the transaction. */
+ IEEE802154_TRANSACTION_OVERFLOW = 0xf1,
+ /*
+ * The transceiver was in the transmitter enabled state when the
+ * receiver was requested to be enabled.
+ */
+ IEEE802154_TX_ACTIVE = 0xf2,
+ /* The appropriate key is not available in the ACL. */
+ IEEE802154_UNAVAILABLE_KEY = 0xf3,
+ /*
+ * A SET/GET request was issued with the identifier of a PIB attribute
+ * that is not supported.
+ */
+ IEEE802154_UNSUPPORTED_ATTR = 0xf4,
+ /*
+ * A request to perform a scan operation failed because the MLME was
+ * in the process of performing a previously initiated scan operation.
+ */
+ IEEE802154_SCAN_IN_PROGRESS = 0xfc,
+};
+
+/**
+ * ieee802154_is_valid_psdu_len - check if psdu len is valid
+ * @len: psdu len with (MHR + payload + MFR)
+ */
+static inline bool ieee802154_is_valid_psdu_len(const u8 len)
+{
+ return (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU);
+}
+
+#endif /* LINUX_IEEE802154_H */
__s32 accept_ra_from_local;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
__s32 optimistic_dad;
+ __s32 use_optimistic;
#endif
#ifdef CONFIG_IPV6_MROUTE
__s32 mc_forwarding;
#define tcp_twsk_ipv6only(__sk) 0
#define inet_v6_ipv6only(__sk) 0
#endif /* IS_ENABLED(CONFIG_IPV6) */
-
-#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
- (((__sk)->sk_portpair == (__ports)) && \
- ((__sk)->sk_family == AF_INET6) && \
- ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr)) && \
- ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr)) && \
- (!(__sk)->sk_bound_dev_if || \
- ((__sk)->sk_bound_dev_if == (__dif))) && \
- net_eq(sock_net(__sk), (__net)))
-
#endif /* _IPV6_H */
#define MARVELL_PHY_ID_88E1318S 0x01410e90
#define MARVELL_PHY_ID_88E1116R 0x01410e40
#define MARVELL_PHY_ID_88E1510 0x01410dd0
+#define MARVELL_PHY_ID_88E3016 0x01410e60
/* struct phy_device dev_flags definitions */
#define MARVELL_PHY_M1145_FLAGS_RESISTANCE 0x00000001
MLX4_CMD_MAP_ICM_AUX = 0xffc,
MLX4_CMD_UNMAP_ICM_AUX = 0xffb,
MLX4_CMD_SET_ICM_SIZE = 0xffd,
+ MLX4_CMD_ACCESS_REG = 0x3b,
+
/*master notify fw on finish for slave's flr*/
MLX4_CMD_INFORM_FLR_DONE = 0x5b,
MLX4_CMD_GET_OP_REQ = 0x59,
MLX4_CMD_NATIVE
};
+/*
+ * MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP -
+ * Receive checksum value is reported in CQE also for non TCP/UDP packets.
+ *
+ * MLX4_RX_CSUM_MODE_L4 -
+ * L4_CSUM bit in CQE, which indicates whether or not L4 checksum
+ * was validated correctly, is supported.
+ *
+ * MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP -
+ * IP_OK CQE's field is supported also for non TCP/UDP IP packets.
+ *
+ * MLX4_RX_CSUM_MODE_MULTI_VLAN -
+ * Receive Checksum offload is supported for packets with more than 2 vlan headers.
+ */
+enum mlx4_rx_csum_mode {
+ MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP = 1UL << 0,
+ MLX4_RX_CSUM_MODE_L4 = 1UL << 1,
+ MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP = 1UL << 2,
+ MLX4_RX_CSUM_MODE_MULTI_VLAN = 1UL << 3
+};
+
+struct mlx4_config_dev_params {
+ u16 vxlan_udp_dport;
+ u8 rx_csum_flags_port_1;
+ u8 rx_csum_flags_port_2;
+};
+
struct mlx4_dev;
struct mlx4_cmd_mailbox {
int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting);
int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf);
int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state);
+int mlx4_config_dev_retrieval(struct mlx4_dev *dev,
+ struct mlx4_config_dev_params *params);
/*
* mlx4_get_slave_default_vlan -
* return true if VST ( default vlan)
enum {
MLX4_MAX_NUM_PF = 16,
- MLX4_MAX_NUM_VF = 64,
+ MLX4_MAX_NUM_VF = 126,
MLX4_MAX_NUM_VF_P_PORT = 64,
MLX4_MFUNC_MAX = 80,
MLX4_MAX_EQ_NUM = 1024,
MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS = 1LL << 10,
MLX4_DEV_CAP_FLAG2_MAD_DEMUX = 1LL << 11,
MLX4_DEV_CAP_FLAG2_CQE_STRIDE = 1LL << 12,
- MLX4_DEV_CAP_FLAG2_EQE_STRIDE = 1LL << 13
+ MLX4_DEV_CAP_FLAG2_EQE_STRIDE = 1LL << 13,
+ MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL = 1LL << 14,
+ MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP = 1LL << 15,
+ MLX4_DEV_CAP_FLAG2_CONFIG_DEV = 1LL << 16,
+ MLX4_DEV_CAP_FLAG2_SYS_EQS = 1LL << 17,
+ MLX4_DEV_CAP_FLAG2_80_VFS = 1LL << 18
};
enum {
#define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \
MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK)
+enum mlx4_module_id {
+ MLX4_MODULE_ID_SFP = 0x3,
+ MLX4_MODULE_ID_QSFP = 0xC,
+ MLX4_MODULE_ID_QSFP_PLUS = 0xD,
+ MLX4_MODULE_ID_QSFP28 = 0x11,
+};
+
static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor)
{
return (major << 32) | (minor << 16) | subminor;
int num_cqs;
int max_cqes;
int reserved_cqs;
+ int num_sys_eqs;
int num_eqs;
int reserved_eqs;
int num_comp_vectors;
u16 hca_core_clock;
u64 phys_port_id[MLX4_MAX_PORTS + 1];
int tunnel_offload_mode;
+ u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1];
};
struct mlx4_buf_list {
u64 si_guid;
};
+#define MAD_IFC_DATA_SZ 192
+/* MAD IFC Mailbox */
+struct mlx4_mad_ifc {
+ u8 base_version;
+ u8 mgmt_class;
+ u8 class_version;
+ u8 method;
+ __be16 status;
+ __be16 class_specific;
+ __be64 tid;
+ __be16 attr_id;
+ __be16 resv;
+ __be32 attr_mod;
+ __be64 mkey;
+ __be16 dr_slid;
+ __be16 dr_dlid;
+ u8 reserved[28];
+ u8 data[MAD_IFC_DATA_SZ];
+} __packed;
+
#define mlx4_foreach_port(port, dev, type) \
for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \
if ((type) == (dev)->caps.port_mask[(port)])
u64 iova, u64 size, int npages,
int page_shift, struct mlx4_mpt_entry *mpt_entry);
+int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
+ u16 offset, u16 size, u8 *data);
+
/* Returns true if running in low memory profile (kdump kernel) */
static inline bool mlx4_low_memory_profile(void)
{
return is_kdump_kernel();
}
+/* ACCESS REG commands */
+enum mlx4_access_reg_method {
+ MLX4_ACCESS_REG_QUERY = 0x1,
+ MLX4_ACCESS_REG_WRITE = 0x2,
+};
+
+/* ACCESS PTYS Reg command */
+enum mlx4_ptys_proto {
+ MLX4_PTYS_IB = 1<<0,
+ MLX4_PTYS_EN = 1<<2,
+};
+
+struct mlx4_ptys_reg {
+ u8 resrvd1;
+ u8 local_port;
+ u8 resrvd2;
+ u8 proto_mask;
+ __be32 resrvd3[2];
+ __be32 eth_proto_cap;
+ __be16 ib_width_cap;
+ __be16 ib_speed_cap;
+ __be32 resrvd4;
+ __be32 eth_proto_admin;
+ __be16 ib_width_admin;
+ __be16 ib_speed_admin;
+ __be32 resrvd5;
+ __be32 eth_proto_oper;
+ __be16 ib_width_oper;
+ __be16 ib_speed_oper;
+ __be32 resrvd6;
+ __be32 eth_proto_lp_adv;
+} __packed;
+
+int mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev,
+ enum mlx4_access_reg_method method,
+ struct mlx4_ptys_reg *ptys_reg);
+
#endif /* MLX4_DEVICE_H */
NETIF_F_GSO_SIT_BIT, /* ... SIT tunnel with TSO */
NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */
NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */
- NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */
+ NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */
/**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */
- NETIF_F_GSO_MPLS_BIT,
+ NETIF_F_GSO_TUNNEL_REMCSUM_BIT,
NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */
NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */
#define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT)
#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM)
-#define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS)
+#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
NETIF_F_GSO_IPIP | \
NETIF_F_GSO_SIT | \
NETIF_F_GSO_UDP_TUNNEL | \
- NETIF_F_GSO_UDP_TUNNEL_CSUM | \
- NETIF_F_GSO_MPLS)
+ NETIF_F_GSO_UDP_TUNNEL_CSUM)
#endif /* _LINUX_NETDEV_FEATURES_H */
struct net_device *dev;
struct sk_buff *gro_list;
struct sk_buff *skb;
+ struct hrtimer timer;
struct list_head dev_list;
struct hlist_node napi_hash_node;
unsigned int napi_id;
typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **pskb);
void __napi_schedule(struct napi_struct *n);
+void __napi_schedule_irqoff(struct napi_struct *n);
static inline bool napi_disable_pending(struct napi_struct *n)
{
__napi_schedule(n);
}
+/**
+ * napi_schedule_irqoff - schedule NAPI poll
+ * @n: napi context
+ *
+ * Variant of napi_schedule(), assuming hard irqs are masked.
+ */
+static inline void napi_schedule_irqoff(struct napi_struct *n)
+{
+ if (napi_schedule_prep(n))
+ __napi_schedule_irqoff(n);
+}
+
/* Try to reschedule poll. Called by dev->poll() after napi_complete(). */
static inline bool napi_reschedule(struct napi_struct *napi)
{
return false;
}
+void __napi_complete(struct napi_struct *n);
+void napi_complete_done(struct napi_struct *n, int work_done);
/**
* napi_complete - NAPI processing complete
* @n: napi context
*
* Mark NAPI processing as complete.
+ * Consider using napi_complete_done() instead.
*/
-void __napi_complete(struct napi_struct *n);
-void napi_complete(struct napi_struct *n);
+static inline void napi_complete(struct napi_struct *n)
+{
+ return napi_complete_done(n, 0);
+}
/**
* napi_by_id - lookup a NAPI by napi_id
* Stop NAPI from being scheduled on this context.
* Waits till any outstanding processing completes.
*/
-static inline void napi_disable(struct napi_struct *n)
-{
- might_sleep();
- set_bit(NAPI_STATE_DISABLE, &n->state);
- while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
- msleep(1);
- clear_bit(NAPI_STATE_DISABLE, &n->state);
-}
+void napi_disable(struct napi_struct *n);
/**
* napi_enable - enable NAPI scheduling
#endif
+ unsigned long gro_flush_timeout;
rx_handler_func_t __rcu *rx_handler;
void __rcu *rx_handler_data;
* Incoming packets are placed on per-cpu queues
*/
struct softnet_data {
- struct Qdisc *output_queue;
- struct Qdisc **output_queue_tailp;
struct list_head poll_list;
- struct sk_buff *completion_queue;
struct sk_buff_head process_queue;
/* stats */
unsigned int time_squeeze;
unsigned int cpu_collision;
unsigned int received_rps;
-
#ifdef CONFIG_RPS
struct softnet_data *rps_ipi_list;
+#endif
+#ifdef CONFIG_NET_FLOW_LIMIT
+ struct sd_flow_limit __rcu *flow_limit;
+#endif
+ struct Qdisc *output_queue;
+ struct Qdisc **output_queue_tailp;
+ struct sk_buff *completion_queue;
+#ifdef CONFIG_RPS
/* Elements below can be accessed between CPUs for RPS */
struct call_single_data csd ____cacheline_aligned_in_smp;
struct softnet_data *rps_ipi_next;
struct sk_buff_head input_pkt_queue;
struct napi_struct backlog;
-#ifdef CONFIG_NET_FLOW_LIMIT
- struct sd_flow_limit __rcu *flow_limit;
-#endif
};
static inline void input_queue_head_incr(struct softnet_data *sd)
}
#endif
-static inline int netif_copy_real_num_queues(struct net_device *to_dev,
- const struct net_device *from_dev)
-{
- int err;
-
- err = netif_set_real_num_tx_queues(to_dev,
- from_dev->real_num_tx_queues);
- if (err)
- return err;
-#ifdef CONFIG_SYSFS
- return netif_set_real_num_rx_queues(to_dev,
- from_dev->real_num_rx_queues);
-#else
- return 0;
-#endif
-}
-
#ifdef CONFIG_SYSFS
static inline unsigned int get_netdev_rx_queue_index(
struct netdev_rx_queue *queue)
BUILD_BUG_ON(SKB_GSO_SIT != (NETIF_F_GSO_SIT >> NETIF_F_GSO_SHIFT));
BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT));
BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT));
- BUILD_BUG_ON(SKB_GSO_MPLS != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT));
+ BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT));
return (features & feature) == feature;
}
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#ifndef NL802154_H
void mdio_bus_exit(void);
extern struct bus_type mdio_bus_type;
+
+/**
+ * module_phy_driver() - Helper macro for registering PHY drivers
+ * @__phy_drivers: array of PHY drivers to register
+ *
+ * Helper macro for PHY drivers which do not do anything special in module
+ * init/exit. Each module may only use this macro once, and calling it
+ * replaces module_init() and module_exit().
+ */
+#define phy_module_driver(__phy_drivers, __count) \
+static int __init phy_module_init(void) \
+{ \
+ return phy_drivers_register(__phy_drivers, __count); \
+} \
+module_init(phy_module_init); \
+static void __exit phy_module_exit(void) \
+{ \
+ phy_drivers_unregister(__phy_drivers, __count); \
+} \
+module_exit(phy_module_exit)
+
+#define module_phy_driver(__phy_drivers) \
+ phy_module_driver(__phy_drivers, ARRAY_SIZE(__phy_drivers))
+
#endif /* __PHY_H */
#ifndef __LINUX_PXA168_ETH_H
#define __LINUX_PXA168_ETH_H
+#include <linux/phy.h>
+
struct pxa168_eth_platform_data {
int port_number;
int phy_addr;
*/
int speed; /* 0, SPEED_10, SPEED_100 */
int duplex; /* DUPLEX_HALF or DUPLEX_FULL */
+ phy_interface_t intf;
/*
* Override default RX/TX queue sizes if nonzero.
size_t new_size);
bool (*shrink_decision)(const struct rhashtable *ht,
size_t new_size);
- int (*mutex_is_held)(void);
+#ifdef CONFIG_PROVE_LOCKING
+ int (*mutex_is_held)(void *parent);
+ void *parent;
+#endif
};
/**
u32 rhashtable_hashfn(const struct rhashtable *ht, const void *key, u32 len);
u32 rhashtable_obj_hashfn(const struct rhashtable *ht, void *ptr);
-void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node, gfp_t);
-bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node, gfp_t);
+void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node);
+bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node);
void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj,
- struct rhash_head __rcu **pprev, gfp_t flags);
+ struct rhash_head __rcu **pprev);
bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size);
bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size);
-int rhashtable_expand(struct rhashtable *ht, gfp_t flags);
-int rhashtable_shrink(struct rhashtable *ht, gfp_t flags);
+int rhashtable_expand(struct rhashtable *ht);
+int rhashtable_shrink(struct rhashtable *ht);
void *rhashtable_lookup(const struct rhashtable *ht, const void *key);
void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash,
#include <linux/time.h>
#include <linux/bug.h>
#include <linux/cache.h>
+#include <linux/rbtree.h>
+#include <linux/socket.h>
#include <linux/atomic.h>
#include <asm/types.h>
struct net_device;
struct scatterlist;
struct pipe_inode_info;
+struct iov_iter;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct nf_conntrack {
SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11,
- SKB_GSO_MPLS = 1 << 12,
-
+ SKB_GSO_TUNNEL_REMCSUM = 1 << 12,
};
#if BITS_PER_LONG > 32
* @next: Next buffer in list
* @prev: Previous buffer in list
* @tstamp: Time we arrived/left
+ * @rbnode: RB tree node, alternative to next/prev for netem/tcp
* @sk: Socket we are owned by
* @dev: Device we arrived on/are leaving by
* @cb: Control buffer. Free for use by every layer. Put private vars here
*/
struct sk_buff {
- /* These two members must be first. */
- struct sk_buff *next;
- struct sk_buff *prev;
-
union {
- ktime_t tstamp;
- struct skb_mstamp skb_mstamp;
+ struct {
+ /* These two members must be first. */
+ struct sk_buff *next;
+ struct sk_buff *prev;
+
+ union {
+ ktime_t tstamp;
+ struct skb_mstamp skb_mstamp;
+ };
+ };
+ struct rb_node rbnode; /* used in netem & tcp stack */
};
-
struct sock *sk;
struct net_device *dev;
#endif
__u8 ipvs_property:1;
__u8 inner_protocol_type:1;
- /* 4 or 6 bit hole */
+ __u8 remcsum_offload:1;
+ /* 3 or 5 bit hole */
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
}
/**
- * __skb_alloc_pages - allocate pages for ps-rx on a skb and preserve pfmemalloc data
- * @gfp_mask: alloc_pages_node mask. Set __GFP_NOMEMALLOC if not for network packet RX
- * @skb: skb to set pfmemalloc on if __GFP_MEMALLOC is used
- * @order: size of the allocation
+ * __dev_alloc_pages - allocate page for network Rx
+ * @gfp_mask: allocation priority. Set __GFP_NOMEMALLOC if not for network Rx
+ * @order: size of the allocation
*
- * Allocate a new page.
+ * Allocate a new page.
*
- * %NULL is returned if there is no free memory.
+ * %NULL is returned if there is no free memory.
*/
-static inline struct page *__skb_alloc_pages(gfp_t gfp_mask,
- struct sk_buff *skb,
- unsigned int order)
-{
- struct page *page;
-
- gfp_mask |= __GFP_COLD;
-
- if (!(gfp_mask & __GFP_NOMEMALLOC))
- gfp_mask |= __GFP_MEMALLOC;
+static inline struct page *__dev_alloc_pages(gfp_t gfp_mask,
+ unsigned int order)
+{
+ /* This piece of code contains several assumptions.
+ * 1. This is for device Rx, therefor a cold page is preferred.
+ * 2. The expectation is the user wants a compound page.
+ * 3. If requesting a order 0 page it will not be compound
+ * due to the check to see if order has a value in prep_new_page
+ * 4. __GFP_MEMALLOC is ignored if __GFP_NOMEMALLOC is set due to
+ * code in gfp_to_alloc_flags that should be enforcing this.
+ */
+ gfp_mask |= __GFP_COLD | __GFP_COMP | __GFP_MEMALLOC;
- page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, order);
- if (skb && page && page->pfmemalloc)
- skb->pfmemalloc = true;
+ return alloc_pages_node(NUMA_NO_NODE, gfp_mask, order);
+}
- return page;
+static inline struct page *dev_alloc_pages(unsigned int order)
+{
+ return __dev_alloc_pages(GFP_ATOMIC, order);
}
/**
- * __skb_alloc_page - allocate a page for ps-rx for a given skb and preserve pfmemalloc data
- * @gfp_mask: alloc_pages_node mask. Set __GFP_NOMEMALLOC if not for network packet RX
- * @skb: skb to set pfmemalloc on if __GFP_MEMALLOC is used
+ * __dev_alloc_page - allocate a page for network Rx
+ * @gfp_mask: allocation priority. Set __GFP_NOMEMALLOC if not for network Rx
*
- * Allocate a new page.
+ * Allocate a new page.
*
- * %NULL is returned if there is no free memory.
+ * %NULL is returned if there is no free memory.
*/
-static inline struct page *__skb_alloc_page(gfp_t gfp_mask,
- struct sk_buff *skb)
+static inline struct page *__dev_alloc_page(gfp_t gfp_mask)
{
- return __skb_alloc_pages(gfp_mask, skb, 0);
+ return __dev_alloc_pages(gfp_mask, 0);
+}
+
+static inline struct page *dev_alloc_page(void)
+{
+ return __dev_alloc_page(GFP_ATOMIC);
}
/**
struct poll_table_struct *wait);
int skb_copy_datagram_iovec(const struct sk_buff *from, int offset,
struct iovec *to, int size);
+static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
+ struct msghdr *msg, int size)
+{
+ return skb_copy_datagram_iovec(from, offset, msg->msg_iov, size);
+}
int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen,
struct iovec *iov);
int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
int len);
int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *frm,
int offset, size_t count);
-int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset,
- const struct iovec *to, int to_offset,
- int size);
+int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
+ struct iov_iter *to, int size);
void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
u16 urg_data; /* Saved octet of OOB data and control flags */
u8 ecn_flags; /* ECN status bits. */
- u8 reordering; /* Packet reordering metric. */
+ u8 keepalive_probes; /* num of allowed keep alive probes */
+ u32 reordering; /* Packet reordering metric. */
u32 snd_up; /* Urgent pointer */
- u8 keepalive_probes; /* num of allowed keep alive probes */
/*
* Options received (usually on last packet, some only on SYN packets).
*/
return skb->len + uncomp_header - ret;
}
-typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
-
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
- const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
- const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
- u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int
+lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
+ const u8 *saddr, const u8 saddr_type,
+ const u8 saddr_len, const u8 *daddr,
+ const u8 daddr_type, const u8 daddr_len,
+ u8 iphc0, u8 iphc1);
int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *_daddr,
const void *_saddr, unsigned int len);
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
__u16 le_conn_interval;
__u16 le_conn_latency;
__u16 le_supv_timeout;
+ __u8 le_adv_data[HCI_MAX_AD_LENGTH];
+ __u8 le_adv_data_len;
__s8 rssi;
__s8 tx_power;
__s8 max_tx_power;
HCI_CONN_STK_ENCRYPT,
HCI_CONN_AUTH_INITIATOR,
HCI_CONN_DROP,
+ HCI_CONN_PARAM_REMOVAL_PEND,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
void mgmt_discoverable_timeout(struct hci_dev *hdev);
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
bool persistent);
-void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u32 flags, u8 *name, u8 name_len,
- u8 *dev_class);
+void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
+ u32 flags, u8 *name, u8 name_len);
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 reason,
bool mgmt_connected);
--- /dev/null
+/*
+ * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ */
+
+#ifndef _NET_BOND_3AD_H
+#define _NET_BOND_3AD_H
+
+#include <asm/byteorder.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+
+/* General definitions */
+#define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW)
+#define AD_TIMER_INTERVAL 100 /*msec*/
+
+#define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02}
+
+#define AD_LACP_SLOW 0
+#define AD_LACP_FAST 1
+
+typedef struct mac_addr {
+ u8 mac_addr_value[ETH_ALEN];
+} __packed mac_addr_t;
+
+enum {
+ BOND_AD_STABLE = 0,
+ BOND_AD_BANDWIDTH = 1,
+ BOND_AD_COUNT = 2,
+};
+
+/* rx machine states(43.4.11 in the 802.3ad standard) */
+typedef enum {
+ AD_RX_DUMMY,
+ AD_RX_INITIALIZE, /* rx Machine */
+ AD_RX_PORT_DISABLED, /* rx Machine */
+ AD_RX_LACP_DISABLED, /* rx Machine */
+ AD_RX_EXPIRED, /* rx Machine */
+ AD_RX_DEFAULTED, /* rx Machine */
+ AD_RX_CURRENT /* rx Machine */
+} rx_states_t;
+
+/* periodic machine states(43.4.12 in the 802.3ad standard) */
+typedef enum {
+ AD_PERIODIC_DUMMY,
+ AD_NO_PERIODIC, /* periodic machine */
+ AD_FAST_PERIODIC, /* periodic machine */
+ AD_SLOW_PERIODIC, /* periodic machine */
+ AD_PERIODIC_TX /* periodic machine */
+} periodic_states_t;
+
+/* mux machine states(43.4.13 in the 802.3ad standard) */
+typedef enum {
+ AD_MUX_DUMMY,
+ AD_MUX_DETACHED, /* mux machine */
+ AD_MUX_WAITING, /* mux machine */
+ AD_MUX_ATTACHED, /* mux machine */
+ AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */
+} mux_states_t;
+
+/* tx machine states(43.4.15 in the 802.3ad standard) */
+typedef enum {
+ AD_TX_DUMMY,
+ AD_TRANSMIT /* tx Machine */
+} tx_states_t;
+
+/* rx indication types */
+typedef enum {
+ AD_TYPE_LACPDU = 1, /* type lacpdu */
+ AD_TYPE_MARKER /* type marker */
+} pdu_type_t;
+
+/* rx marker indication types */
+typedef enum {
+ AD_MARKER_INFORMATION_SUBTYPE = 1, /* marker imformation subtype */
+ AD_MARKER_RESPONSE_SUBTYPE /* marker response subtype */
+} bond_marker_subtype_t;
+
+/* timers types(43.4.9 in the 802.3ad standard) */
+typedef enum {
+ AD_CURRENT_WHILE_TIMER,
+ AD_ACTOR_CHURN_TIMER,
+ AD_PERIODIC_TIMER,
+ AD_PARTNER_CHURN_TIMER,
+ AD_WAIT_WHILE_TIMER
+} ad_timers_t;
+
+#pragma pack(1)
+
+/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
+typedef struct lacpdu {
+ u8 subtype; /* = LACP(= 0x01) */
+ u8 version_number;
+ u8 tlv_type_actor_info; /* = actor information(type/length/value) */
+ u8 actor_information_length; /* = 20 */
+ __be16 actor_system_priority;
+ struct mac_addr actor_system;
+ __be16 actor_key;
+ __be16 actor_port_priority;
+ __be16 actor_port;
+ u8 actor_state;
+ u8 reserved_3_1[3]; /* = 0 */
+ u8 tlv_type_partner_info; /* = partner information */
+ u8 partner_information_length; /* = 20 */
+ __be16 partner_system_priority;
+ struct mac_addr partner_system;
+ __be16 partner_key;
+ __be16 partner_port_priority;
+ __be16 partner_port;
+ u8 partner_state;
+ u8 reserved_3_2[3]; /* = 0 */
+ u8 tlv_type_collector_info; /* = collector information */
+ u8 collector_information_length;/* = 16 */
+ __be16 collector_max_delay;
+ u8 reserved_12[12];
+ u8 tlv_type_terminator; /* = terminator */
+ u8 terminator_length; /* = 0 */
+ u8 reserved_50[50]; /* = 0 */
+} __packed lacpdu_t;
+
+typedef struct lacpdu_header {
+ struct ethhdr hdr;
+ struct lacpdu lacpdu;
+} __packed lacpdu_header_t;
+
+/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
+typedef struct bond_marker {
+ u8 subtype; /* = 0x02 (marker PDU) */
+ u8 version_number; /* = 0x01 */
+ u8 tlv_type; /* = 0x01 (marker information) */
+ /* = 0x02 (marker response information) */
+ u8 marker_length; /* = 0x16 */
+ u16 requester_port; /* The number assigned to the port by the requester */
+ struct mac_addr requester_system; /* The requester's system id */
+ u32 requester_transaction_id; /* The transaction id allocated by the requester, */
+ u16 pad; /* = 0 */
+ u8 tlv_type_terminator; /* = 0x00 */
+ u8 terminator_length; /* = 0x00 */
+ u8 reserved_90[90]; /* = 0 */
+} __packed bond_marker_t;
+
+typedef struct bond_marker_header {
+ struct ethhdr hdr;
+ struct bond_marker marker;
+} __packed bond_marker_header_t;
+
+#pragma pack()
+
+struct slave;
+struct bonding;
+struct ad_info;
+struct port;
+
+#ifdef __ia64__
+#pragma pack(8)
+#endif
+
+/* aggregator structure(43.4.5 in the 802.3ad standard) */
+typedef struct aggregator {
+ struct mac_addr aggregator_mac_address;
+ u16 aggregator_identifier;
+ bool is_individual;
+ u16 actor_admin_aggregator_key;
+ u16 actor_oper_aggregator_key;
+ struct mac_addr partner_system;
+ u16 partner_system_priority;
+ u16 partner_oper_aggregator_key;
+ u16 receive_state; /* BOOLEAN */
+ u16 transmit_state; /* BOOLEAN */
+ struct port *lag_ports;
+ /* ****** PRIVATE PARAMETERS ****** */
+ struct slave *slave; /* pointer to the bond slave that this aggregator belongs to */
+ u16 is_active; /* BOOLEAN. Indicates if this aggregator is active */
+ u16 num_of_ports;
+} aggregator_t;
+
+struct port_params {
+ struct mac_addr system;
+ u16 system_priority;
+ u16 key;
+ u16 port_number;
+ u16 port_priority;
+ u16 port_state;
+};
+
+/* port structure(43.4.6 in the 802.3ad standard) */
+typedef struct port {
+ u16 actor_port_number;
+ u16 actor_port_priority;
+ struct mac_addr actor_system; /* This parameter is added here although it is not specified in the standard, just for simplification */
+ u16 actor_system_priority; /* This parameter is added here although it is not specified in the standard, just for simplification */
+ u16 actor_port_aggregator_identifier;
+ bool ntt;
+ u16 actor_admin_port_key;
+ u16 actor_oper_port_key;
+ u8 actor_admin_port_state;
+ u8 actor_oper_port_state;
+
+ struct port_params partner_admin;
+ struct port_params partner_oper;
+
+ bool is_enabled;
+
+ /* ****** PRIVATE PARAMETERS ****** */
+ u16 sm_vars; /* all state machines variables for this port */
+ rx_states_t sm_rx_state; /* state machine rx state */
+ u16 sm_rx_timer_counter; /* state machine rx timer counter */
+ periodic_states_t sm_periodic_state; /* state machine periodic state */
+ u16 sm_periodic_timer_counter; /* state machine periodic timer counter */
+ mux_states_t sm_mux_state; /* state machine mux state */
+ u16 sm_mux_timer_counter; /* state machine mux timer counter */
+ tx_states_t sm_tx_state; /* state machine tx state */
+ u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
+ struct slave *slave; /* pointer to the bond slave that this port belongs to */
+ struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
+ struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
+ u32 transaction_id; /* continuous number for identification of Marker PDU's; */
+ struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */
+} port_t;
+
+/* system structure */
+struct ad_system {
+ u16 sys_priority;
+ struct mac_addr sys_mac_addr;
+};
+
+#ifdef __ia64__
+#pragma pack()
+#endif
+
+/* ========== AD Exported structures to the main bonding code ========== */
+#define BOND_AD_INFO(bond) ((bond)->ad_info)
+#define SLAVE_AD_INFO(slave) ((slave)->ad_info)
+
+struct ad_bond_info {
+ struct ad_system system; /* 802.3ad system structure */
+ u32 agg_select_timer; /* Timer to select aggregator after all adapter's hand shakes */
+ u16 aggregator_identifier;
+};
+
+struct ad_slave_info {
+ struct aggregator aggregator; /* 802.3ad aggregator structure */
+ struct port port; /* 802.3ad port structure */
+ u16 id;
+};
+
+/* ========== AD Exported functions to the main bonding code ========== */
+void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
+void bond_3ad_bind_slave(struct slave *slave);
+void bond_3ad_unbind_slave(struct slave *slave);
+void bond_3ad_state_machine_handler(struct work_struct *);
+void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
+void bond_3ad_adapter_speed_changed(struct slave *slave);
+void bond_3ad_adapter_duplex_changed(struct slave *slave);
+void bond_3ad_handle_link_change(struct slave *slave, char link);
+int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
+int __bond_3ad_get_active_agg_info(struct bonding *bond,
+ struct ad_info *ad_info);
+int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave);
+int bond_3ad_set_carrier(struct bonding *bond);
+void bond_3ad_update_lacp_rate(struct bonding *bond);
+#endif /* _NET_BOND_3AD_H */
+
--- /dev/null
+/*
+ * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ */
+
+#ifndef _NET_BOND_ALB_H
+#define _NET_BOND_ALB_H
+
+#include <linux/if_ether.h>
+
+struct bonding;
+struct slave;
+
+#define BOND_ALB_INFO(bond) ((bond)->alb_info)
+#define SLAVE_TLB_INFO(slave) ((slave)->tlb_info)
+
+#define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */
+#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing.
+ * Used for division - never set
+ * to zero !!!
+ */
+#define BOND_ALB_DEFAULT_LP_INTERVAL 1
+#define BOND_ALB_LP_INTERVAL(bond) (bond->params.lp_interval) /* In seconds, periodic send of
+ * learning packets to the switch
+ */
+
+#define BOND_TLB_REBALANCE_TICKS (BOND_TLB_REBALANCE_INTERVAL \
+ * ALB_TIMER_TICKS_PER_SEC)
+
+#define BOND_ALB_LP_TICKS(bond) (BOND_ALB_LP_INTERVAL(bond) \
+ * ALB_TIMER_TICKS_PER_SEC)
+
+#define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table.
+ * Note that this value MUST NOT be smaller
+ * because the key hash table is BYTE wide !
+ */
+
+
+#define TLB_NULL_INDEX 0xffffffff
+
+/* rlb defs */
+#define RLB_HASH_TABLE_SIZE 256
+#define RLB_NULL_INDEX 0xffffffff
+#define RLB_UPDATE_DELAY (2*ALB_TIMER_TICKS_PER_SEC) /* 2 seconds */
+#define RLB_ARP_BURST_SIZE 2
+#define RLB_UPDATE_RETRY 3 /* 3-ticks - must be smaller than the rlb
+ * rebalance interval (5 min).
+ */
+/* RLB_PROMISC_TIMEOUT = 10 sec equals the time that the current slave is
+ * promiscuous after failover
+ */
+#define RLB_PROMISC_TIMEOUT (10*ALB_TIMER_TICKS_PER_SEC)
+
+
+struct tlb_client_info {
+ struct slave *tx_slave; /* A pointer to slave used for transmiting
+ * packets to a Client that the Hash function
+ * gave this entry index.
+ */
+ u32 tx_bytes; /* Each Client accumulates the BytesTx that
+ * were transmitted to it, and after each
+ * CallBack the LoadHistory is divided
+ * by the balance interval
+ */
+ u32 load_history; /* This field contains the amount of Bytes
+ * that were transmitted to this client by
+ * the server on the previous balance
+ * interval in Bps.
+ */
+ u32 next; /* The next Hash table entry index, assigned
+ * to use the same adapter for transmit.
+ */
+ u32 prev; /* The previous Hash table entry index,
+ * assigned to use the same
+ */
+};
+
+/* -------------------------------------------------------------------------
+ * struct rlb_client_info contains all info related to a specific rx client
+ * connection. This is the Clients Hash Table entry struct.
+ * Note that this is not a proper hash table; if a new client's IP address
+ * hash collides with an existing client entry, the old entry is replaced.
+ *
+ * There is a linked list (linked by the used_next and used_prev members)
+ * linking all the used entries of the hash table. This allows updating
+ * all the clients without walking over all the unused elements of the table.
+ *
+ * There are also linked lists of entries with identical hash(ip_src). These
+ * allow cleaning up the table from ip_src<->mac_src associations that have
+ * become outdated and would cause sending out invalid ARP updates to the
+ * network. These are linked by the (src_next and src_prev members).
+ * -------------------------------------------------------------------------
+ */
+struct rlb_client_info {
+ __be32 ip_src; /* the server IP address */
+ __be32 ip_dst; /* the client IP address */
+ u8 mac_src[ETH_ALEN]; /* the server MAC address */
+ u8 mac_dst[ETH_ALEN]; /* the client MAC address */
+
+ /* list of used hash table entries, starting at rx_hashtbl_used_head */
+ u32 used_next;
+ u32 used_prev;
+
+ /* ip_src based hashing */
+ u32 src_next; /* next entry with same hash(ip_src) */
+ u32 src_prev; /* prev entry with same hash(ip_src) */
+ u32 src_first; /* first entry with hash(ip_src) == this entry's index */
+
+ u8 assigned; /* checking whether this entry is assigned */
+ u8 ntt; /* flag - need to transmit client info */
+ struct slave *slave; /* the slave assigned to this client */
+ unsigned short vlan_id; /* VLAN tag associated with IP address */
+};
+
+struct tlb_slave_info {
+ u32 head; /* Index to the head of the bi-directional clients
+ * hash table entries list. The entries in the list
+ * are the entries that were assigned to use this
+ * slave for transmit.
+ */
+ u32 load; /* Each slave sums the loadHistory of all clients
+ * assigned to it
+ */
+};
+
+struct alb_bond_info {
+ struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */
+ u32 unbalanced_load;
+ int tx_rebalance_counter;
+ int lp_counter;
+ /* -------- rlb parameters -------- */
+ int rlb_enabled;
+ struct rlb_client_info *rx_hashtbl; /* Receive hash table */
+ u32 rx_hashtbl_used_head;
+ u8 rx_ntt; /* flag - need to transmit
+ * to all rx clients
+ */
+ struct slave *rx_slave;/* last slave to xmit from */
+ u8 primary_is_promisc; /* boolean */
+ u32 rlb_promisc_timeout_counter;/* counts primary
+ * promiscuity time
+ */
+ u32 rlb_update_delay_counter;
+ u32 rlb_update_retry_counter;/* counter of retries
+ * of client update
+ */
+ u8 rlb_rebalance; /* flag - indicates that the
+ * rx traffic should be
+ * rebalanced
+ */
+};
+
+int bond_alb_initialize(struct bonding *bond, int rlb_enabled);
+void bond_alb_deinitialize(struct bonding *bond);
+int bond_alb_init_slave(struct bonding *bond, struct slave *slave);
+void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
+void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
+void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
+int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
+int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
+void bond_alb_monitor(struct work_struct *);
+int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
+void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
+#endif /* _NET_BOND_ALB_H */
+
--- /dev/null
+/*
+ * drivers/net/bond/bond_options.h - bonding options
+ * Copyright (c) 2013 Nikolay Aleksandrov <nikolay@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _NET_BOND_OPTIONS_H
+#define _NET_BOND_OPTIONS_H
+
+#define BOND_OPT_MAX_NAMELEN 32
+#define BOND_OPT_VALID(opt) ((opt) < BOND_OPT_LAST)
+#define BOND_MODE_ALL_EX(x) (~(x))
+
+/* Option flags:
+ * BOND_OPTFLAG_NOSLAVES - check if the bond device is empty before setting
+ * BOND_OPTFLAG_IFDOWN - check if the bond device is down before setting
+ * BOND_OPTFLAG_RAWVAL - the option parses the value itself
+ */
+enum {
+ BOND_OPTFLAG_NOSLAVES = BIT(0),
+ BOND_OPTFLAG_IFDOWN = BIT(1),
+ BOND_OPTFLAG_RAWVAL = BIT(2)
+};
+
+/* Value type flags:
+ * BOND_VALFLAG_DEFAULT - mark the value as default
+ * BOND_VALFLAG_(MIN|MAX) - mark the value as min/max
+ */
+enum {
+ BOND_VALFLAG_DEFAULT = BIT(0),
+ BOND_VALFLAG_MIN = BIT(1),
+ BOND_VALFLAG_MAX = BIT(2)
+};
+
+/* Option IDs, their bit positions correspond to their IDs */
+enum {
+ BOND_OPT_MODE,
+ BOND_OPT_PACKETS_PER_SLAVE,
+ BOND_OPT_XMIT_HASH,
+ BOND_OPT_ARP_VALIDATE,
+ BOND_OPT_ARP_ALL_TARGETS,
+ BOND_OPT_FAIL_OVER_MAC,
+ BOND_OPT_ARP_INTERVAL,
+ BOND_OPT_ARP_TARGETS,
+ BOND_OPT_DOWNDELAY,
+ BOND_OPT_UPDELAY,
+ BOND_OPT_LACP_RATE,
+ BOND_OPT_MINLINKS,
+ BOND_OPT_AD_SELECT,
+ BOND_OPT_NUM_PEER_NOTIF,
+ BOND_OPT_MIIMON,
+ BOND_OPT_PRIMARY,
+ BOND_OPT_PRIMARY_RESELECT,
+ BOND_OPT_USE_CARRIER,
+ BOND_OPT_ACTIVE_SLAVE,
+ BOND_OPT_QUEUE_ID,
+ BOND_OPT_ALL_SLAVES_ACTIVE,
+ BOND_OPT_RESEND_IGMP,
+ BOND_OPT_LP_INTERVAL,
+ BOND_OPT_SLAVES,
+ BOND_OPT_TLB_DYNAMIC_LB,
+ BOND_OPT_LAST
+};
+
+/* This structure is used for storing option values and for passing option
+ * values when changing an option. The logic when used as an arg is as follows:
+ * - if string != NULL -> parse it, if the opt is RAW type then return it, else
+ * return the parse result
+ * - if string == NULL -> parse value
+ */
+struct bond_opt_value {
+ char *string;
+ u64 value;
+ u32 flags;
+};
+
+struct bonding;
+
+struct bond_option {
+ int id;
+ const char *name;
+ const char *desc;
+ u32 flags;
+
+ /* unsuppmodes is used to denote modes in which the option isn't
+ * supported.
+ */
+ unsigned long unsuppmodes;
+ /* supported values which this option can have, can be a subset of
+ * BOND_OPTVAL_RANGE's value range
+ */
+ const struct bond_opt_value *values;
+
+ int (*set)(struct bonding *bond, const struct bond_opt_value *val);
+};
+
+int __bond_opt_set(struct bonding *bond, unsigned int option,
+ struct bond_opt_value *val);
+int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
+
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+ struct bond_opt_value *val);
+const struct bond_option *bond_opt_get(unsigned int option);
+const struct bond_option *bond_opt_get_by_name(const char *name);
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
+
+/* This helper is used to initialize a bond_opt_value structure for parameter
+ * passing. There should be either a valid string or value, but not both.
+ * When value is ULLONG_MAX then string will be used.
+ */
+static inline void __bond_opt_init(struct bond_opt_value *optval,
+ char *string, u64 value)
+{
+ memset(optval, 0, sizeof(*optval));
+ optval->value = ULLONG_MAX;
+ if (value == ULLONG_MAX)
+ optval->string = string;
+ else
+ optval->value = value;
+}
+#define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
+#define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
+
+void bond_option_arp_ip_targets_clear(struct bonding *bond);
+
+#endif /* _NET_BOND_OPTIONS_H */
--- /dev/null
+/*
+ * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'.
+ *
+ * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Management, Inc.
+ *
+ * BUT, I'm the one who modified it for ethernet, so:
+ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef _NET_BONDING_H
+#define _NET_BONDING_H
+
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/if_bonding.h>
+#include <linux/cpumask.h>
+#include <linux/in6.h>
+#include <linux/netpoll.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/reciprocal_div.h>
+#include <linux/if_link.h>
+
+#include <net/bond_3ad.h>
+#include <net/bond_alb.h>
+#include <net/bond_options.h>
+
+#define DRV_VERSION "3.7.1"
+#define DRV_RELDATE "April 27, 2011"
+#define DRV_NAME "bonding"
+#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
+
+#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"
+
+#define BOND_MAX_ARP_TARGETS 16
+
+#define BOND_DEFAULT_MIIMON 100
+
+/*
+ * Less bad way to call ioctl from within the kernel; this needs to be
+ * done some other way to get the call out of interrupt context.
+ * Needs "ioctl" variable to be supplied by calling context.
+ */
+#define IOCTL(dev, arg, cmd) ({ \
+ int res = 0; \
+ mm_segment_t fs = get_fs(); \
+ set_fs(get_ds()); \
+ res = ioctl(dev, arg, cmd); \
+ set_fs(fs); \
+ res; })
+
+#define BOND_MODE(bond) ((bond)->params.mode)
+
+/* slave list primitives */
+#define bond_slave_list(bond) (&(bond)->dev->adj_list.lower)
+
+#define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
+
+/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
+#define bond_first_slave(bond) \
+ (bond_has_slaves(bond) ? \
+ netdev_adjacent_get_private(bond_slave_list(bond)->next) : \
+ NULL)
+#define bond_last_slave(bond) \
+ (bond_has_slaves(bond) ? \
+ netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \
+ NULL)
+
+/* Caller must have rcu_read_lock */
+#define bond_first_slave_rcu(bond) \
+ netdev_lower_get_first_private_rcu(bond->dev)
+
+#define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond))
+#define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond))
+
+/**
+ * bond_for_each_slave - iterate over all slaves
+ * @bond: the bond holding this list
+ * @pos: current slave
+ * @iter: list_head * iterator
+ *
+ * Caller must hold RTNL
+ */
+#define bond_for_each_slave(bond, pos, iter) \
+ netdev_for_each_lower_private((bond)->dev, pos, iter)
+
+/* Caller must have rcu_read_lock */
+#define bond_for_each_slave_rcu(bond, pos, iter) \
+ netdev_for_each_lower_private_rcu((bond)->dev, pos, iter)
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern atomic_t netpoll_block_tx;
+
+static inline void block_netpoll_tx(void)
+{
+ atomic_inc(&netpoll_block_tx);
+}
+
+static inline void unblock_netpoll_tx(void)
+{
+ atomic_dec(&netpoll_block_tx);
+}
+
+static inline int is_netpoll_tx_blocked(struct net_device *dev)
+{
+ if (unlikely(netpoll_tx_running(dev)))
+ return atomic_read(&netpoll_block_tx);
+ return 0;
+}
+#else
+#define block_netpoll_tx()
+#define unblock_netpoll_tx()
+#define is_netpoll_tx_blocked(dev) (0)
+#endif
+
+struct bond_params {
+ int mode;
+ int xmit_policy;
+ int miimon;
+ u8 num_peer_notif;
+ int arp_interval;
+ int arp_validate;
+ int arp_all_targets;
+ int use_carrier;
+ int fail_over_mac;
+ int updelay;
+ int downdelay;
+ int lacp_fast;
+ unsigned int min_links;
+ int ad_select;
+ char primary[IFNAMSIZ];
+ int primary_reselect;
+ __be32 arp_targets[BOND_MAX_ARP_TARGETS];
+ int tx_queues;
+ int all_slaves_active;
+ int resend_igmp;
+ int lp_interval;
+ int packets_per_slave;
+ int tlb_dynamic_lb;
+ struct reciprocal_value reciprocal_packets_per_slave;
+};
+
+struct bond_parm_tbl {
+ char *modename;
+ int mode;
+};
+
+struct slave {
+ struct net_device *dev; /* first - useful for panic debug */
+ struct bonding *bond; /* our master */
+ int delay;
+ /* all three in jiffies */
+ unsigned long last_link_up;
+ unsigned long last_rx;
+ unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
+ s8 link; /* one of BOND_LINK_XXXX */
+ s8 new_link;
+ u8 backup:1, /* indicates backup slave. Value corresponds with
+ BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
+ inactive:1, /* indicates inactive slave */
+ should_notify:1; /* indicateds whether the state changed */
+ u8 duplex;
+ u32 original_mtu;
+ u32 link_failure_count;
+ u32 speed;
+ u16 queue_id;
+ u8 perm_hwaddr[ETH_ALEN];
+ struct ad_slave_info *ad_info;
+ struct tlb_slave_info tlb_info;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ struct netpoll *np;
+#endif
+ struct kobject kobj;
+ struct rtnl_link_stats64 slave_stats;
+};
+
+struct bond_up_slave {
+ unsigned int count;
+ struct rcu_head rcu;
+ struct slave *arr[0];
+};
+
+/*
+ * Link pseudo-state only used internally by monitors
+ */
+#define BOND_LINK_NOCHANGE -1
+
+/*
+ * Here are the locking policies for the two bonding locks:
+ * Get rcu_read_lock when reading or RTNL when writing slave list.
+ */
+struct bonding {
+ struct net_device *dev; /* first - useful for panic debug */
+ struct slave __rcu *curr_active_slave;
+ struct slave __rcu *current_arp_slave;
+ struct slave __rcu *primary_slave;
+ struct bond_up_slave __rcu *slave_arr; /* Array of usable slaves */
+ bool force_primary;
+ s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
+ int (*recv_probe)(const struct sk_buff *, struct bonding *,
+ struct slave *);
+ /* mode_lock is used for mode-specific locking needs, currently used by:
+ * 3ad mode (4) - protect against running bond_3ad_unbind_slave() and
+ * bond_3ad_state_machine_handler() concurrently and also
+ * the access to the state machine shared variables.
+ * TLB mode (5) - to sync the use and modifications of its hash table
+ * ALB mode (6) - to sync the use and modifications of its hash table
+ */
+ spinlock_t mode_lock;
+ u8 send_peer_notif;
+ u8 igmp_retrans;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_entry;
+ char proc_file_name[IFNAMSIZ];
+#endif /* CONFIG_PROC_FS */
+ struct list_head bond_list;
+ u32 rr_tx_counter;
+ struct ad_bond_info ad_info;
+ struct alb_bond_info alb_info;
+ struct bond_params params;
+ struct workqueue_struct *wq;
+ struct delayed_work mii_work;
+ struct delayed_work arp_work;
+ struct delayed_work alb_work;
+ struct delayed_work ad_work;
+ struct delayed_work mcast_work;
+ struct delayed_work slave_arr_work;
+#ifdef CONFIG_DEBUG_FS
+ /* debugging support via debugfs */
+ struct dentry *debug_dir;
+#endif /* CONFIG_DEBUG_FS */
+ struct rtnl_link_stats64 bond_stats;
+};
+
+#define bond_slave_get_rcu(dev) \
+ ((struct slave *) rcu_dereference(dev->rx_handler_data))
+
+#define bond_slave_get_rtnl(dev) \
+ ((struct slave *) rtnl_dereference(dev->rx_handler_data))
+
+struct bond_vlan_tag {
+ __be16 vlan_proto;
+ unsigned short vlan_id;
+};
+
+/**
+ * Returns NULL if the net_device does not belong to any of the bond's slaves
+ *
+ * Caller must hold bond lock for read
+ */
+static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
+ struct net_device *slave_dev)
+{
+ return netdev_lower_dev_get_private(bond->dev, slave_dev);
+}
+
+static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
+{
+ return slave->bond;
+}
+
+static inline bool bond_should_override_tx_queue(struct bonding *bond)
+{
+ return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
+ BOND_MODE(bond) == BOND_MODE_ROUNDROBIN;
+}
+
+static inline bool bond_is_lb(const struct bonding *bond)
+{
+ return BOND_MODE(bond) == BOND_MODE_TLB ||
+ BOND_MODE(bond) == BOND_MODE_ALB;
+}
+
+static inline bool bond_is_nondyn_tlb(const struct bonding *bond)
+{
+ return (BOND_MODE(bond) == BOND_MODE_TLB) &&
+ (bond->params.tlb_dynamic_lb == 0);
+}
+
+static inline bool bond_mode_uses_xmit_hash(const struct bonding *bond)
+{
+ return (BOND_MODE(bond) == BOND_MODE_8023AD ||
+ BOND_MODE(bond) == BOND_MODE_XOR ||
+ bond_is_nondyn_tlb(bond));
+}
+
+static inline bool bond_mode_uses_arp(int mode)
+{
+ return mode != BOND_MODE_8023AD && mode != BOND_MODE_TLB &&
+ mode != BOND_MODE_ALB;
+}
+
+static inline bool bond_mode_uses_primary(int mode)
+{
+ return mode == BOND_MODE_ACTIVEBACKUP || mode == BOND_MODE_TLB ||
+ mode == BOND_MODE_ALB;
+}
+
+static inline bool bond_uses_primary(struct bonding *bond)
+{
+ return bond_mode_uses_primary(BOND_MODE(bond));
+}
+
+static inline bool bond_slave_is_up(struct slave *slave)
+{
+ return netif_running(slave->dev) && netif_carrier_ok(slave->dev);
+}
+
+static inline void bond_set_active_slave(struct slave *slave)
+{
+ if (slave->backup) {
+ slave->backup = 0;
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+ }
+}
+
+static inline void bond_set_backup_slave(struct slave *slave)
+{
+ if (!slave->backup) {
+ slave->backup = 1;
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+ }
+}
+
+static inline void bond_set_slave_state(struct slave *slave,
+ int slave_state, bool notify)
+{
+ if (slave->backup == slave_state)
+ return;
+
+ slave->backup = slave_state;
+ if (notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+ slave->should_notify = 0;
+ } else {
+ if (slave->should_notify)
+ slave->should_notify = 0;
+ else
+ slave->should_notify = 1;
+ }
+}
+
+static inline void bond_slave_state_change(struct bonding *bond)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter) {
+ if (tmp->link == BOND_LINK_UP)
+ bond_set_active_slave(tmp);
+ else if (tmp->link == BOND_LINK_DOWN)
+ bond_set_backup_slave(tmp);
+ }
+}
+
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter) {
+ if (tmp->should_notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC);
+ tmp->should_notify = 0;
+ }
+ }
+}
+
+static inline int bond_slave_state(struct slave *slave)
+{
+ return slave->backup;
+}
+
+static inline bool bond_is_active_slave(struct slave *slave)
+{
+ return !bond_slave_state(slave);
+}
+
+static inline bool bond_slave_can_tx(struct slave *slave)
+{
+ return bond_slave_is_up(slave) && slave->link == BOND_LINK_UP &&
+ bond_is_active_slave(slave);
+}
+
+#define BOND_PRI_RESELECT_ALWAYS 0
+#define BOND_PRI_RESELECT_BETTER 1
+#define BOND_PRI_RESELECT_FAILURE 2
+
+#define BOND_FOM_NONE 0
+#define BOND_FOM_ACTIVE 1
+#define BOND_FOM_FOLLOW 2
+
+#define BOND_ARP_TARGETS_ANY 0
+#define BOND_ARP_TARGETS_ALL 1
+
+#define BOND_ARP_VALIDATE_NONE 0
+#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
+#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
+#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
+ BOND_ARP_VALIDATE_BACKUP)
+#define BOND_ARP_FILTER (BOND_ARP_VALIDATE_ALL + 1)
+#define BOND_ARP_FILTER_ACTIVE (BOND_ARP_VALIDATE_ACTIVE | \
+ BOND_ARP_FILTER)
+#define BOND_ARP_FILTER_BACKUP (BOND_ARP_VALIDATE_BACKUP | \
+ BOND_ARP_FILTER)
+
+#define BOND_SLAVE_NOTIFY_NOW true
+#define BOND_SLAVE_NOTIFY_LATER false
+
+static inline int slave_do_arp_validate(struct bonding *bond,
+ struct slave *slave)
+{
+ return bond->params.arp_validate & (1 << bond_slave_state(slave));
+}
+
+static inline int slave_do_arp_validate_only(struct bonding *bond)
+{
+ return bond->params.arp_validate & BOND_ARP_FILTER;
+}
+
+static inline int bond_is_ip_target_ok(__be32 addr)
+{
+ return !ipv4_is_lbcast(addr) && !ipv4_is_zeronet(addr);
+}
+
+/* Get the oldest arp which we've received on this slave for bond's
+ * arp_targets.
+ */
+static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond,
+ struct slave *slave)
+{
+ int i = 1;
+ unsigned long ret = slave->target_last_arp_rx[0];
+
+ for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++)
+ if (time_before(slave->target_last_arp_rx[i], ret))
+ ret = slave->target_last_arp_rx[i];
+
+ return ret;
+}
+
+static inline unsigned long slave_last_rx(struct bonding *bond,
+ struct slave *slave)
+{
+ if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
+ return slave_oldest_target_arp_rx(bond, slave);
+
+ return slave->last_rx;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static inline void bond_netpoll_send_skb(const struct slave *slave,
+ struct sk_buff *skb)
+{
+ struct netpoll *np = slave->np;
+
+ if (np)
+ netpoll_send_skb(np, skb);
+}
+#else
+static inline void bond_netpoll_send_skb(const struct slave *slave,
+ struct sk_buff *skb)
+{
+}
+#endif
+
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+ bool notify)
+{
+ if (!bond_is_lb(slave->bond))
+ bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
+ if (!slave->bond->params.all_slaves_active)
+ slave->inactive = 1;
+}
+
+static inline void bond_set_slave_active_flags(struct slave *slave,
+ bool notify)
+{
+ bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
+ slave->inactive = 0;
+}
+
+static inline bool bond_is_slave_inactive(struct slave *slave)
+{
+ return slave->inactive;
+}
+
+static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local)
+{
+ struct in_device *in_dev;
+ __be32 addr = 0;
+
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
+
+ if (in_dev)
+ addr = inet_confirm_addr(dev_net(dev), in_dev, dst, local,
+ RT_SCOPE_HOST);
+ rcu_read_unlock();
+ return addr;
+}
+
+struct bond_net {
+ struct net *net; /* Associated network namespace */
+ struct list_head dev_list;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_dir;
+#endif
+ struct class_attribute class_attr_bonding_masters;
+};
+
+int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
+void bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
+int bond_create(struct net *net, const char *name);
+int bond_create_sysfs(struct bond_net *net);
+void bond_destroy_sysfs(struct bond_net *net);
+void bond_prepare_sysfs_group(struct bonding *bond);
+int bond_sysfs_slave_add(struct slave *slave);
+void bond_sysfs_slave_del(struct slave *slave);
+int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
+int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
+u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
+void bond_select_active_slave(struct bonding *bond);
+void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
+void bond_create_debugfs(void);
+void bond_destroy_debugfs(void);
+void bond_debug_register(struct bonding *bond);
+void bond_debug_unregister(struct bonding *bond);
+void bond_debug_reregister(struct bonding *bond);
+const char *bond_mode_name(int mode);
+void bond_setup(struct net_device *bond_dev);
+unsigned int bond_get_num_tx_queues(void);
+int bond_netlink_init(void);
+void bond_netlink_fini(void);
+struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
+const char *bond_slave_link_status(s8 link);
+struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
+ struct net_device *end_dev,
+ int level);
+int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave);
+void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay);
+
+#ifdef CONFIG_PROC_FS
+void bond_create_proc_entry(struct bonding *bond);
+void bond_remove_proc_entry(struct bonding *bond);
+void bond_create_proc_dir(struct bond_net *bn);
+void bond_destroy_proc_dir(struct bond_net *bn);
+#else
+static inline void bond_create_proc_entry(struct bonding *bond)
+{
+}
+
+static inline void bond_remove_proc_entry(struct bonding *bond)
+{
+}
+
+static inline void bond_create_proc_dir(struct bond_net *bn)
+{
+}
+
+static inline void bond_destroy_proc_dir(struct bond_net *bn)
+{
+}
+#endif
+
+static inline struct slave *bond_slave_has_mac(struct bonding *bond,
+ const u8 *mac)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter)
+ if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
+ return tmp;
+
+ return NULL;
+}
+
+/* Caller must hold rcu_read_lock() for read */
+static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond,
+ const u8 *mac)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave_rcu(bond, tmp, iter)
+ if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
+ return tmp;
+
+ return NULL;
+}
+
+/* Caller must hold rcu_read_lock() for read */
+static inline bool bond_slave_has_mac_rx(struct bonding *bond, const u8 *mac)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+ struct netdev_hw_addr *ha;
+
+ bond_for_each_slave_rcu(bond, tmp, iter)
+ if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
+ return true;
+
+ if (netdev_uc_empty(bond->dev))
+ return false;
+
+ netdev_for_each_uc_addr(ha, bond->dev)
+ if (ether_addr_equal_64bits(mac, ha->addr))
+ return true;
+
+ return false;
+}
+
+/* Check if the ip is present in arp ip list, or first free slot if ip == 0
+ * Returns -1 if not found, index if found
+ */
+static inline int bond_get_targets_ip(__be32 *targets, __be32 ip)
+{
+ int i;
+
+ for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
+ if (targets[i] == ip)
+ return i;
+ else if (targets[i] == 0)
+ break;
+
+ return -1;
+}
+
+/* exported from bond_main.c */
+extern int bond_net_id;
+extern const struct bond_parm_tbl bond_lacp_tbl[];
+extern const struct bond_parm_tbl xmit_hashtype_tbl[];
+extern const struct bond_parm_tbl arp_validate_tbl[];
+extern const struct bond_parm_tbl arp_all_targets_tbl[];
+extern const struct bond_parm_tbl fail_over_mac_tbl[];
+extern const struct bond_parm_tbl pri_reselect_tbl[];
+extern struct bond_parm_tbl ad_select_tbl[];
+
+/* exported from bond_netlink.c */
+extern struct rtnl_link_ops bond_link_ops;
+
+static inline void bond_tx_drop(struct net_device *dev, struct sk_buff *skb)
+{
+ atomic_long_inc(&dev->tx_dropped);
+ dev_kfree_skb_any(skb);
+}
+
+#endif /* _NET_BONDING_H */
/**
* struct vif_params - describes virtual interface parameters
* @use_4addr: use 4-address frames
- * @macaddr: address to use for this virtual interface. This will only
- * be used for non-netdevice interfaces. If this parameter is set
- * to zero address the driver may determine the address as needed.
+ * @macaddr: address to use for this virtual interface.
+ * If this parameter is set to zero address the driver may
+ * determine the address as needed.
+ * This feature is only fully supported by drivers that enable the
+ * %NL80211_FEATURE_MAC_ON_CREATE flag. Others may support creating
+ ** only p2p devices with specified MAC.
*/
struct vif_params {
int use_4addr;
bool opmode_notif_used;
};
+/**
+ * struct station_del_parameters - station deletion parameters
+ *
+ * Used to delete a station entry (or all stations).
+ *
+ * @mac: MAC address of the station to remove or NULL to remove all stations
+ * @subtype: Management frame subtype to use for indicating removal
+ * (10 = Disassociation, 12 = Deauthentication)
+ * @reason_code: Reason code for the Disassociation/Deauthentication frame
+ */
+struct station_del_parameters {
+ const u8 *mac;
+ u8 subtype;
+ u16 reason_code;
+};
+
/**
* enum cfg80211_station_type - the type of station being modified
* @CFG80211_STA_AP_CLIENT: client of an AP interface
u32 basic_rates;
};
+/**
+ * struct ocb_setup - 802.11p OCB mode setup configuration
+ * @chandef: defines the channel to use
+ *
+ * These parameters are fixed when connecting to the network
+ */
+struct ocb_setup {
+ struct cfg80211_chan_def chandef;
+};
+
/**
* struct ieee80211_txq_params - TX queue parameters
* @ac: AC identifier
* @stop_ap: Stop being an AP, including stopping beaconing.
*
* @add_station: Add a new station.
- * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ * @del_station: Remove a station
* @change_station: Modify a given station. Note that flags changes are not much
* validated in cfg80211, in particular the auth/assoc/authorized flags
* might come to the driver in invalid combinations -- make sure to check
* @change_mpath: change a given mesh path
* @get_mpath: get a mesh path for the given parameters
* @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @get_mpp: get a mesh proxy path for the given parameters
+ * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
* @join_mesh: join the mesh network with the specified parameters
* (invoked with the wireless_dev mutex held)
* @leave_mesh: leave the current mesh network
* with the peer followed by immediate teardown when the addition is later
* rejected)
* @del_tx_ts: remove an existing TX TS
+ *
+ * @join_ocb: join the OCB network with the specified parameters
+ * (invoked with the wireless_dev mutex held)
+ * @leave_ocb: leave the current OCB network
+ * (invoked with the wireless_dev mutex held)
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
const u8 *mac,
struct station_parameters *params);
int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac);
+ struct station_del_parameters *params);
int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac,
struct station_parameters *params);
int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *dst, u8 *next_hop,
struct mpath_info *pinfo);
+ int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *mpp, struct mpath_info *pinfo);
+ int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo);
int (*get_mesh_config)(struct wiphy *wiphy,
struct net_device *dev,
struct mesh_config *conf);
const struct mesh_setup *setup);
int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
+ int (*join_ocb)(struct wiphy *wiphy, struct net_device *dev,
+ struct ocb_setup *setup);
+ int (*leave_ocb)(struct wiphy *wiphy, struct net_device *dev);
+
int (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params);
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
* @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
* beaconing mode (AP, IBSS, Mesh, ...).
- * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
- * TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS
- * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
- * needs to be able to handle Block-Ack agreements and other things.
*/
enum wiphy_flags {
- WIPHY_FLAG_SUPPORTS_WMM_ADMISSION = BIT(0),
+ /* use hole at 0 */
/* use hole at 1 */
/* use hole at 2 */
WIPHY_FLAG_NETNS_OK = BIT(3),
return dev_name(&wiphy->dev);
}
+/**
+ * wiphy_new_nm - create a new wiphy for use with cfg80211
+ *
+ * @ops: The configuration operations for this device
+ * @sizeof_priv: The size of the private area to allocate
+ * @requested_name: Request a particular name.
+ * NULL is valid value, and means use the default phy%d naming.
+ *
+ * Create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * Return: A pointer to the new wiphy. This pointer must be
+ * assigned to each netdev's ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+ const char *requested_name);
+
/**
* wiphy_new - create a new wiphy for use with cfg80211
*
* Return: A pointer to the new wiphy. This pointer must be
* assigned to each netdev's ieee80211_ptr for proper operation.
*/
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
+static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
+ int sizeof_priv)
+{
+ return wiphy_new_nm(ops, sizeof_priv, NULL);
+}
/**
* wiphy_register - register a wiphy with cfg80211
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef __NET_CFG802154_H
+#define __NET_CFG802154_H
+
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/bug.h>
+
+/* According to the IEEE 802.15.4 stadard the upper most significant bits of
+ * the 32-bit channel bitmaps shall be used as an integer value to specify 32
+ * possible channel pages. The lower 27 bits of the channel bit map shall be
+ * used as a bit mask to specify channel numbers within a channel page.
+ */
+#define WPAN_NUM_CHANNELS 27
+#define WPAN_NUM_PAGES 32
+
+struct wpan_phy {
+ struct mutex pib_lock;
+
+ /*
+ * This is a PIB according to 802.15.4-2011.
+ * We do not provide timing-related variables, as they
+ * aren't used outside of driver
+ */
+ u8 current_channel;
+ u8 current_page;
+ u32 channels_supported[32];
+ s8 transmit_power;
+ u8 cca_mode;
+ u8 min_be;
+ u8 max_be;
+ u8 csma_retries;
+ s8 frame_retries;
+
+ bool lbt;
+ s32 cca_ed_level;
+
+ struct device dev;
+ int idx;
+
+ struct net_device *(*add_iface)(struct wpan_phy *phy,
+ const char *name, int type);
+ void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
+
+ char priv[0] __aligned(NETDEV_ALIGN);
+};
+
+#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
+
+struct wpan_phy *wpan_phy_alloc(size_t priv_size);
+static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
+{
+ phy->dev.parent = dev;
+}
+
+int wpan_phy_register(struct wpan_phy *phy);
+void wpan_phy_unregister(struct wpan_phy *phy);
+void wpan_phy_free(struct wpan_phy *phy);
+/* Same semantics as for class_for_each_device */
+int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), void *data);
+
+static inline void *wpan_phy_priv(struct wpan_phy *phy)
+{
+ BUG_ON(!phy);
+ return &phy->priv;
+}
+
+struct wpan_phy *wpan_phy_find(const char *str);
+
+static inline void wpan_phy_put(struct wpan_phy *phy)
+{
+ put_device(&phy->dev);
+}
+
+static inline const char *wpan_phy_name(struct wpan_phy *phy)
+{
+ return dev_name(&phy->dev);
+}
+
+#endif /* __NET_CFG802154_H */
struct device *host_dev;
int sw_addr;
+ /* set to size of eeprom if supported by the switch */
+ int eeprom_len;
+
/* Device tree node pointer for this specific switch chip
* used during switch setup in case additional properties
* and resources needs to be used
*/
struct device *master_dev;
+#ifdef CONFIG_NET_DSA_HWMON
+ /*
+ * Hardware monitoring information
+ */
+ char hwmon_name[IFNAMSIZ + 8];
+ struct device *hwmon_dev;
+#endif
+
/*
* Slave mii_bus and devices for the individual ports.
*/
struct ethtool_eee *e);
int (*get_eee)(struct dsa_switch *ds, int port,
struct ethtool_eee *e);
+
+#ifdef CONFIG_NET_DSA_HWMON
+ /* Hardware monitoring */
+ int (*get_temp)(struct dsa_switch *ds, int *temp);
+ int (*get_temp_limit)(struct dsa_switch *ds, int *temp);
+ int (*set_temp_limit)(struct dsa_switch *ds, int temp);
+ int (*get_temp_alarm)(struct dsa_switch *ds, bool *alarm);
+#endif
+
+ /* EEPROM access */
+ int (*get_eeprom_len)(struct dsa_switch *ds);
+ int (*get_eeprom)(struct dsa_switch *ds,
+ struct ethtool_eeprom *eeprom, u8 *data);
+ int (*set_eeprom)(struct dsa_switch *ds,
+ struct ethtool_eeprom *eeprom, u8 *data);
+
+ /*
+ * Register access.
+ */
+ int (*get_regs_len)(struct dsa_switch *ds, int port);
+ void (*get_regs)(struct dsa_switch *ds, int port,
+ struct ethtool_regs *regs, void *p);
};
void register_switch_driver(struct dsa_switch_driver *type);
--- /dev/null
+#ifndef __NET_FOU_H
+#define __NET_FOU_H
+
+#include <linux/skbuff.h>
+
+#include <net/flow.h>
+#include <net/gue.h>
+#include <net/ip_tunnels.h>
+#include <net/udp.h>
+
+size_t fou_encap_hlen(struct ip_tunnel_encap *e);
+static size_t gue_encap_hlen(struct ip_tunnel_encap *e);
+
+int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ u8 *protocol, struct flowi4 *fl4);
+int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ u8 *protocol, struct flowi4 *fl4);
+
+#endif
#ifndef __NET_GUE_H
#define __NET_GUE_H
+/* Definitions for the GUE header, standard and private flags, lengths
+ * of optional fields are below.
+ *
+ * Diagram of GUE header:
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Ver|C| Hlen | Proto/ctype | Standard flags |P|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * ~ Fields (optional) ~
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Private flags (optional, P bit is set) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * ~ Private fields (optional) ~
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * C bit indicates contol message when set, data message when unset.
+ * For a control message, proto/ctype is interpreted as a type of
+ * control message. For data messages, proto/ctype is the IP protocol
+ * of the next header.
+ *
+ * P bit indicates private flags field is present. The private flags
+ * may refer to options placed after this field.
+ */
+
struct guehdr {
union {
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 hlen:4,
- version:4;
+ __u8 hlen:5,
+ control:1,
+ version:2;
#elif defined (__BIG_ENDIAN_BITFIELD)
- __u8 version:4,
- hlen:4;
+ __u8 version:2,
+ control:1,
+ hlen:5;
#else
#error "Please fix <asm/byteorder.h>"
#endif
- __u8 next_hdr;
+ __u8 proto_ctype;
__u16 flags;
};
__u32 word;
};
};
+/* Standard flags in GUE header */
+
+#define GUE_FLAG_PRIV htons(1<<0) /* Private flags are in options */
+#define GUE_LEN_PRIV 4
+
+#define GUE_FLAGS_ALL (GUE_FLAG_PRIV)
+
+/* Private flags in the private option extension */
+
+#define GUE_PFLAG_REMCSUM htonl(1 << 31)
+#define GUE_PLEN_REMCSUM 4
+
+#define GUE_PFLAGS_ALL (GUE_PFLAG_REMCSUM)
+
+/* Functions to compute options length corresponding to flags.
+ * If we ever have a lot of flags this can be potentially be
+ * converted to a more optimized algorithm (table lookup
+ * for instance).
+ */
+static inline size_t guehdr_flags_len(__be16 flags)
+{
+ return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0);
+}
+
+static inline size_t guehdr_priv_flags_len(__be32 flags)
+{
+ return 0;
+}
+
+/* Validate standard and private flags. Returns non-zero (meaning invalid)
+ * if there is an unknown standard or private flags, or the options length for
+ * the flags exceeds the options length specific in hlen of the GUE header.
+ */
+static inline int validate_gue_flags(struct guehdr *guehdr,
+ size_t optlen)
+{
+ size_t len;
+ __be32 flags = guehdr->flags;
+
+ if (flags & ~GUE_FLAGS_ALL)
+ return 1;
+
+ len = guehdr_flags_len(flags);
+ if (len > optlen)
+ return 1;
+
+ if (flags & GUE_FLAG_PRIV) {
+ /* Private flags are last four bytes accounted in
+ * guehdr_flags_len
+ */
+ flags = *(__be32 *)((void *)&guehdr[1] + len - GUE_LEN_PRIV);
+
+ if (flags & ~GUE_PFLAGS_ALL)
+ return 1;
+
+ len += guehdr_priv_flags_len(flags);
+ if (len > optlen)
+ return 1;
+ }
+
+ return 0;
+}
+
#endif
+++ /dev/null
-/*
- * IEEE802.15.4-2003 specification
- *
- * Copyright (C) 2007, 2008 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Maxim Osipov <maxim.osipov@siemens.com>
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#ifndef NET_IEEE802154_H
-#define NET_IEEE802154_H
-
-#define IEEE802154_MTU 127
-
-#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */
-#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */
-#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */
-#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */
-
-#define IEEE802154_FC_TYPE_SHIFT 0
-#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1)
-#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT)
-#define IEEE802154_FC_SET_TYPE(v, x) do { \
- v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \
- (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
- } while (0)
-
-#define IEEE802154_FC_SECEN_SHIFT 3
-#define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT)
-#define IEEE802154_FC_FRPEND_SHIFT 4
-#define IEEE802154_FC_FRPEND (1 << IEEE802154_FC_FRPEND_SHIFT)
-#define IEEE802154_FC_ACK_REQ_SHIFT 5
-#define IEEE802154_FC_ACK_REQ (1 << IEEE802154_FC_ACK_REQ_SHIFT)
-#define IEEE802154_FC_INTRA_PAN_SHIFT 6
-#define IEEE802154_FC_INTRA_PAN (1 << IEEE802154_FC_INTRA_PAN_SHIFT)
-
-#define IEEE802154_FC_SAMODE_SHIFT 14
-#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT)
-#define IEEE802154_FC_DAMODE_SHIFT 10
-#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT)
-
-#define IEEE802154_FC_VERSION_SHIFT 12
-#define IEEE802154_FC_VERSION_MASK (3 << IEEE802154_FC_VERSION_SHIFT)
-#define IEEE802154_FC_VERSION(x) ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT)
-
-#define IEEE802154_FC_SAMODE(x) \
- (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
-
-#define IEEE802154_FC_DAMODE(x) \
- (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
-
-#define IEEE802154_SCF_SECLEVEL_MASK 7
-#define IEEE802154_SCF_SECLEVEL_SHIFT 0
-#define IEEE802154_SCF_SECLEVEL(x) (x & IEEE802154_SCF_SECLEVEL_MASK)
-#define IEEE802154_SCF_KEY_ID_MODE_SHIFT 3
-#define IEEE802154_SCF_KEY_ID_MODE_MASK (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT)
-#define IEEE802154_SCF_KEY_ID_MODE(x) \
- ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT)
-
-#define IEEE802154_SCF_KEY_IMPLICIT 0
-#define IEEE802154_SCF_KEY_INDEX 1
-#define IEEE802154_SCF_KEY_SHORT_INDEX 2
-#define IEEE802154_SCF_KEY_HW_INDEX 3
-
-#define IEEE802154_SCF_SECLEVEL_NONE 0
-#define IEEE802154_SCF_SECLEVEL_MIC32 1
-#define IEEE802154_SCF_SECLEVEL_MIC64 2
-#define IEEE802154_SCF_SECLEVEL_MIC128 3
-#define IEEE802154_SCF_SECLEVEL_ENC 4
-#define IEEE802154_SCF_SECLEVEL_ENC_MIC32 5
-#define IEEE802154_SCF_SECLEVEL_ENC_MIC64 6
-#define IEEE802154_SCF_SECLEVEL_ENC_MIC128 7
-
-/* MAC footer size */
-#define IEEE802154_MFR_SIZE 2 /* 2 octets */
-
-/* MAC's Command Frames Identifiers */
-#define IEEE802154_CMD_ASSOCIATION_REQ 0x01
-#define IEEE802154_CMD_ASSOCIATION_RESP 0x02
-#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03
-#define IEEE802154_CMD_DATA_REQ 0x04
-#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05
-#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06
-#define IEEE802154_CMD_BEACON_REQ 0x07
-#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08
-#define IEEE802154_CMD_GTS_REQ 0x09
-
-/*
- * The return values of MAC operations
- */
-enum {
- /*
- * The requested operation was completed successfully.
- * For a transmission request, this value indicates
- * a successful transmission.
- */
- IEEE802154_SUCCESS = 0x0,
-
- /* The beacon was lost following a synchronization request. */
- IEEE802154_BEACON_LOSS = 0xe0,
- /*
- * A transmission could not take place due to activity on the
- * channel, i.e., the CSMA-CA mechanism has failed.
- */
- IEEE802154_CHNL_ACCESS_FAIL = 0xe1,
- /* The GTS request has been denied by the PAN coordinator. */
- IEEE802154_DENINED = 0xe2,
- /* The attempt to disable the transceiver has failed. */
- IEEE802154_DISABLE_TRX_FAIL = 0xe3,
- /*
- * The received frame induces a failed security check according to
- * the security suite.
- */
- IEEE802154_FAILED_SECURITY_CHECK = 0xe4,
- /*
- * The frame resulting from secure processing has a length that is
- * greater than aMACMaxFrameSize.
- */
- IEEE802154_FRAME_TOO_LONG = 0xe5,
- /*
- * The requested GTS transmission failed because the specified GTS
- * either did not have a transmit GTS direction or was not defined.
- */
- IEEE802154_INVALID_GTS = 0xe6,
- /*
- * A request to purge an MSDU from the transaction queue was made using
- * an MSDU handle that was not found in the transaction table.
- */
- IEEE802154_INVALID_HANDLE = 0xe7,
- /* A parameter in the primitive is out of the valid range.*/
- IEEE802154_INVALID_PARAMETER = 0xe8,
- /* No acknowledgment was received after aMaxFrameRetries. */
- IEEE802154_NO_ACK = 0xe9,
- /* A scan operation failed to find any network beacons.*/
- IEEE802154_NO_BEACON = 0xea,
- /* No response data were available following a request. */
- IEEE802154_NO_DATA = 0xeb,
- /* The operation failed because a short address was not allocated. */
- IEEE802154_NO_SHORT_ADDRESS = 0xec,
- /*
- * A receiver enable request was unsuccessful because it could not be
- * completed within the CAP.
- */
- IEEE802154_OUT_OF_CAP = 0xed,
- /*
- * A PAN identifier conflict has been detected and communicated to the
- * PAN coordinator.
- */
- IEEE802154_PANID_CONFLICT = 0xee,
- /* A coordinator realignment command has been received. */
- IEEE802154_REALIGMENT = 0xef,
- /* The transaction has expired and its information discarded. */
- IEEE802154_TRANSACTION_EXPIRED = 0xf0,
- /* There is no capacity to store the transaction. */
- IEEE802154_TRANSACTION_OVERFLOW = 0xf1,
- /*
- * The transceiver was in the transmitter enabled state when the
- * receiver was requested to be enabled.
- */
- IEEE802154_TX_ACTIVE = 0xf2,
- /* The appropriate key is not available in the ACL. */
- IEEE802154_UNAVAILABLE_KEY = 0xf3,
- /*
- * A SET/GET request was issued with the identifier of a PIB attribute
- * that is not supported.
- */
- IEEE802154_UNSUPPORTED_ATTR = 0xf4,
- /*
- * A request to perform a scan operation failed because the MLME was
- * in the process of performing a previously initiated scan operation.
- */
- IEEE802154_SCAN_IN_PROGRESS = 0xfc,
-};
-
-
-#endif
-
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
* Maxim Gorbachyov <maxim.gorbachev@siemens.com>
#ifndef IEEE802154_NETDEVICE_H
#define IEEE802154_NETDEVICE_H
-#include <net/ieee802154.h>
#include <net/af_ieee802154.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+#include <linux/ieee802154.h>
struct ieee802154_sechdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
const struct in6_addr *daddr, const __be16 dport,
const int dif);
#endif /* IS_ENABLED(CONFIG_IPV6) */
+
+#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
+ (((__sk)->sk_portpair == (__ports)) && \
+ ((__sk)->sk_family == AF_INET6) && \
+ ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr)) && \
+ ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr)) && \
+ (!(__sk)->sk_bound_dev_if || \
+ ((__sk)->sk_bound_dev_if == (__dif))) && \
+ net_eq(sock_net(__sk), (__net)))
+
#endif /* _INET6_HASHTABLES_H */
void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst);
int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
const struct in6_addr *raddr);
-int ip6_tnl_xmit_ctl(struct ip6_tnl *t);
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
+ const struct in6_addr *raddr);
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
const struct in6_addr *raddr);
struct hlist_head tunnels[IP_TNL_HASH_SIZE];
};
+struct ip_tunnel_encap_ops {
+ size_t (*encap_hlen)(struct ip_tunnel_encap *e);
+ int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ u8 *protocol, struct flowi4 *fl4);
+};
+
+#define MAX_IPTUN_ENCAP_OPS 8
+
+extern const struct ip_tunnel_encap_ops __rcu *
+ iptun_encaps[MAX_IPTUN_ENCAP_OPS];
+
+int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *op,
+ unsigned int num);
+int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op,
+ unsigned int num);
+
#ifdef CONFIG_INET
int ip_tunnel_init(struct net_device *dev);
struct ipx_address ipx_source __packed;
};
+/* From af_ipx.c */
+extern int sysctl_ipx_pprop_broadcasting;
+
static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
{
return (struct ipxhdr *)skb_transport_header(skb);
#endif
#ifdef CONFIG_IRDA_DEBUG
-
-extern unsigned int irda_debug;
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#define IRDA_DEBUG_LEVEL 0
-
-#define IRDA_DEBUG(n, args...) \
-do { if (irda_debug >= (n)) \
- printk(KERN_DEBUG args); \
-} while (0)
#define IRDA_ASSERT(expr, func) \
do { if(!(expr)) { \
printk( "Assertion failed! %s:%s:%d %s\n", \
func } } while (0)
#define IRDA_ASSERT_LABEL(label) label
#else
-#define IRDA_DEBUG(n, args...) do { } while (0)
#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0)
#define IRDA_ASSERT_LABEL(label)
#endif /* CONFIG_IRDA_DEBUG */
-#define IRDA_WARNING(args...) do { if (net_ratelimit()) printk(KERN_WARNING args); } while (0)
-#define IRDA_MESSAGE(args...) do { if (net_ratelimit()) printk(KERN_INFO args); } while (0)
-#define IRDA_ERROR(args...) do { if (net_ratelimit()) printk(KERN_ERR args); } while (0)
-
/*
* Magic numbers used by Linux-IrDA. Random numbers which must be unique to
* give the best protection
if (!self || self->magic != LAP_MAGIC)
return;
- IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
+ pr_debug("next LAP state = %s\n", irlap_state[state]);
*/
self->state = state;
}
* @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed,
* note that this is only called when it changes after the channel
* context had been assigned.
+ * @BSS_CHANGED_OCB: OCB join status changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_P2P_PS = 1<<19,
BSS_CHANGED_BEACON_INFO = 1<<20,
BSS_CHANGED_BANDWIDTH = 1<<21,
+ BSS_CHANGED_OCB = 1<<22,
/* when adding here, make sure to change ieee80211_reconfig */
};
u8 ampdu_ack_len;
u8 ampdu_len;
u8 antenna;
- void *status_driver_data[21 / sizeof(void *)];
+ u16 tx_time;
+ void *status_driver_data[19 / sizeof(void *)];
} status;
struct {
struct ieee80211_tx_rate driver_rates[
* Function (TSF) timer when the frame containing the channel switch
* announcement was received. This is simply the rx.mactime parameter
* the driver passed into mac80211.
+ * @device_timestamp: arbitrary timestamp for the device, this is the
+ * rx.device_timestamp parameter the driver passed to mac80211.
* @block_tx: Indicates whether transmission must be blocked before the
* scheduled channel switch, as indicated by the AP.
* @chandef: the new channel to switch to
*/
struct ieee80211_channel_switch {
u64 timestamp;
+ u32 device_timestamp;
bool block_tx;
struct cfg80211_chan_def chandef;
u8 count;
* @smps_mode: current SMPS mode (off, static or dynamic)
* @rates: rate control selection table
* @tdls: indicates whether the STA is a TDLS peer
+ * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
+ * valid if the STA is a TDLS peer in the first place.
*/
struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS];
enum ieee80211_smps_mode smps_mode;
struct ieee80211_sta_rates __rcu *rates;
bool tdls;
+ bool tdls_initiator;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
* a virtual monitor interface when monitor interfaces are the only
* active interfaces.
*
+ * @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
+ * be created. It is expected user-space will create vifs as
+ * desired (and thus have them named as desired).
+ *
* @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
* queue mapping in order to use different queues (not just one per AC)
* for different virtual interfaces. See the doc section on HW queue
IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12,
IEEE80211_HW_MFP_CAPABLE = 1<<13,
IEEE80211_HW_WANT_MONITOR_VIF = 1<<14,
- /* free slots */
+ IEEE80211_HW_NO_AUTO_VIF = 1<<15,
+ /* free slot */
IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_ROC_TYPE_MGMT_TX,
};
+/**
+ * enum ieee80211_reconfig_complete_type - reconfig type
+ *
+ * This enum is used by the reconfig_complete() callback to indicate what
+ * reconfiguration type was completed.
+ *
+ * @IEEE80211_RECONFIG_TYPE_RESTART: hw restart type
+ * (also due to resume() callback returning 1)
+ * @IEEE80211_RECONFIG_TYPE_SUSPEND: suspend type (regardless
+ * of wowlan configuration)
+ */
+enum ieee80211_reconfig_type {
+ IEEE80211_RECONFIG_TYPE_RESTART,
+ IEEE80211_RECONFIG_TYPE_SUSPEND,
+};
+
/**
* struct ieee80211_ops - callbacks from mac80211 to the driver
*
* disabled/enabled via @bss_info_changed.
* @stop_ap: Stop operation on the AP interface.
*
- * @restart_complete: Called after a call to ieee80211_restart_hw(), when the
- * reconfiguration has completed. This can help the driver implement the
- * reconfiguration step. Also called when reconfiguring because the
- * driver's resume function returned 1, as this is just like an "inline"
- * hardware restart. This callback may sleep.
+ * @reconfig_complete: Called after a call to ieee80211_restart_hw() and
+ * during resume, when the reconfiguration has completed.
+ * This can help the driver implement the reconfiguration step (and
+ * indicate mac80211 is ready to receive frames).
+ * This callback may sleep.
*
* @ipv6_addr_change: IPv6 address assignment on the given interface changed.
* Currently, this is only called for managed or P2P client interfaces.
* transmitted and then call ieee80211_csa_finish().
* If the CSA count starts as zero or 1, this function will not be called,
* since there won't be any time to beacon before the switch anyway.
+ * @pre_channel_switch: This is an optional callback that is called
+ * before a channel switch procedure is started (ie. when a STA
+ * gets a CSA or an userspace initiated channel-switch), allowing
+ * the driver to prepare for the channel switch.
+ * @post_channel_switch: This is an optional callback that is called
+ * after a channel switch procedure is completed, allowing the
+ * driver to go back to a normal configuration.
*
* @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
* information in bss_conf is set up and the beacon can be retrieved. A
* @get_expected_throughput: extract the expected throughput towards the
* specified station. The returned value is expressed in Kbps. It returns 0
* if the RC algorithm does not have proper data to provide.
+ *
+ * @get_txpower: get current maximum tx power (in dBm) based on configuration
+ * and hardware limits.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int n_vifs,
enum ieee80211_chanctx_switch_mode mode);
- void (*restart_complete)(struct ieee80211_hw *hw);
+ void (*reconfig_complete)(struct ieee80211_hw *hw,
+ enum ieee80211_reconfig_type reconfig_type);
#if IS_ENABLED(CONFIG_IPV6)
void (*ipv6_addr_change)(struct ieee80211_hw *hw,
void (*channel_switch_beacon)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef);
+ int (*pre_channel_switch)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *ch_switch);
+
+ int (*post_channel_switch)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
+ int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ int *dbm);
};
/**
- * ieee80211_alloc_hw - Allocate a new hardware device
+ * ieee80211_alloc_hw_nm - Allocate a new hardware device
+ *
+ * This must be called once for each hardware device. The returned pointer
+ * must be used to refer to this device when calling other functions.
+ * mac80211 allocates a private data area for the driver pointed to by
+ * @priv in &struct ieee80211_hw, the size of this area is given as
+ * @priv_data_len.
+ *
+ * @priv_data_len: length of private data
+ * @ops: callbacks for this device
+ * @requested_name: Requested name for this device.
+ * NULL is valid value, and means use the default naming (phy%d)
+ *
+ * Return: A pointer to the new hardware device, or %NULL on error.
+ */
+struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
+ const struct ieee80211_ops *ops,
+ const char *requested_name);
+
+/**
+ * ieee80211_alloc_hw - Allocate a new hardware device
*
* This must be called once for each hardware device. The returned pointer
* must be used to refer to this device when calling other functions.
*
* Return: A pointer to the new hardware device, or %NULL on error.
*/
+static inline
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
- const struct ieee80211_ops *ops);
+ const struct ieee80211_ops *ops)
+{
+ return ieee80211_alloc_hw_nm(priv_data_len, ops, NULL);
+}
/**
* ieee80211_register_hw - Register hardware device
struct ieee80211_vif *vif),
void *data);
+/**
+ * ieee80211_iterate_stations_atomic - iterate stations
+ *
+ * This function iterates over all stations associated with a given
+ * hardware that are currently uploaded to the driver and calls the callback
+ * function for them.
+ * This function requires the iterator callback function to be atomic,
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data);
/**
* ieee80211_queue_work - add work onto the mac80211 workqueue
*
void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer,
enum nl80211_tdls_operation oper,
u16 reason_code, gfp_t gfp);
+
+/**
+ * ieee80211_ie_split - split an IE buffer according to ordering
+ *
+ * @ies: the IE buffer
+ * @ielen: the length of the IE buffer
+ * @ids: an array with element IDs that are allowed before
+ * the split
+ * @n_ids: the size of the element ID array
+ * @offset: offset where to start splitting in the buffer
+ *
+ * This function splits an IE buffer by updating the @offset
+ * variable to point to the location where the buffer should be
+ * split.
+ *
+ * It assumes that the given IE buffer is well-formed, this
+ * has to be guaranteed by the caller!
+ *
+ * It also assumes that the IEs in the buffer are ordered
+ * correctly, if not the result of using this function will not
+ * be ordered correctly either, i.e. it does no reordering.
+ *
+ * The function returns the offset where the next part of the
+ * buffer starts, which may be @ielen if the entire (remainder)
+ * of the buffer should be used.
+ */
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids, size_t offset);
#endif /* MAC80211_H */
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef NET_MAC802154_H
#define NET_MAC802154_H
*/
/* indicates that the Short Address changed */
-#define IEEE802515_AFILT_SADDR_CHANGED 0x00000001
+#define IEEE802154_AFILT_SADDR_CHANGED 0x00000001
/* indicates that the IEEE Address changed */
-#define IEEE802515_AFILT_IEEEADDR_CHANGED 0x00000002
+#define IEEE802154_AFILT_IEEEADDR_CHANGED 0x00000002
/* indicates that the PAN ID changed */
-#define IEEE802515_AFILT_PANID_CHANGED 0x00000004
+#define IEEE802154_AFILT_PANID_CHANGED 0x00000004
/* indicates that PAN Coordinator status changed */
-#define IEEE802515_AFILT_PANC_CHANGED 0x00000008
+#define IEEE802154_AFILT_PANC_CHANGED 0x00000008
struct ieee802154_hw_addr_filt {
__le16 pan_id; /* Each independent PAN selects a unique
u8 pan_coord;
};
-struct ieee802154_dev {
+struct ieee802154_hw {
/* filled by the driver */
int extra_tx_headroom;
u32 flags;
* however, so you are advised to review these flags carefully.
*/
-/* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */
-#define IEEE802154_HW_OMIT_CKSUM 0x00000001
+/* Indicates that xmitter will add FCS on it's own. */
+#define IEEE802154_HW_TX_OMIT_CKSUM 0x00000001
/* Indicates that receiver will autorespond with ACK frames. */
-#define IEEE802154_HW_AACK 0x00000002
+#define IEEE802154_HW_AACK 0x00000002
/* Indicates that transceiver will support transmit power setting. */
-#define IEEE802154_HW_TXPOWER 0x00000004
+#define IEEE802154_HW_TXPOWER 0x00000004
/* Indicates that transceiver will support listen before transmit. */
-#define IEEE802154_HW_LBT 0x00000008
+#define IEEE802154_HW_LBT 0x00000008
/* Indicates that transceiver will support cca mode setting. */
-#define IEEE802154_HW_CCA_MODE 0x00000010
+#define IEEE802154_HW_CCA_MODE 0x00000010
/* Indicates that transceiver will support cca ed level setting. */
-#define IEEE802154_HW_CCA_ED_LEVEL 0x00000020
+#define IEEE802154_HW_CCA_ED_LEVEL 0x00000020
/* Indicates that transceiver will support csma (max_be, min_be, csma retries)
* settings. */
-#define IEEE802154_HW_CSMA_PARAMS 0x00000040
+#define IEEE802154_HW_CSMA_PARAMS 0x00000040
/* Indicates that transceiver will support ARET frame retries setting. */
-#define IEEE802154_HW_FRAME_RETRIES 0x00000080
+#define IEEE802154_HW_FRAME_RETRIES 0x00000080
+/* Indicates that transceiver will support hardware address filter setting. */
+#define IEEE802154_HW_AFILT 0x00000100
+/* Indicates that transceiver will support promiscuous mode setting. */
+#define IEEE802154_HW_PROMISCUOUS 0x00000200
+/* Indicates that receiver omits FCS. */
+#define IEEE802154_HW_RX_OMIT_CKSUM 0x00000400
+/* Indicates that receiver will not filter frames with bad checksum. */
+#define IEEE802154_HW_RX_DROP_BAD_CKSUM 0x00000800
+
+/* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */
+#define IEEE802154_HW_OMIT_CKSUM (IEEE802154_HW_TX_OMIT_CKSUM | \
+ IEEE802154_HW_RX_OMIT_CKSUM)
/* This groups the most common CSMA support fields into one. */
#define IEEE802154_HW_CSMA (IEEE802154_HW_CCA_MODE | \
IEEE802154_HW_CCA_ED_LEVEL | \
- IEEE802154_HW_CSMA_PARAMS | \
+ IEEE802154_HW_CSMA_PARAMS)
+
+/* This groups the most common ARET support fields into one. */
+#define IEEE802154_HW_ARET (IEEE802154_HW_CSMA | \
IEEE802154_HW_FRAME_RETRIES)
/* struct ieee802154_ops - callbacks from mac802154 to the driver
* stop: Handler that 802.15.4 module calls for device cleanup.
* This function is called after the last interface is removed.
*
- * xmit: Handler that 802.15.4 module calls for each transmitted frame.
+ * xmit_sync:
+ * Handler that 802.15.4 module calls for each transmitted frame.
+ * skb cntains the buffer starting from the IEEE 802.15.4 header.
+ * The low-level driver should send the frame based on available
+ * configuration. This is called by a workqueue and useful for
+ * synchronous 802.15.4 drivers.
+ * This function should return zero or negative errno.
+ *
+ * WARNING:
+ * This will be deprecated soon. We don't accept synced xmit callbacks
+ * drivers anymore.
+ *
+ * xmit_async:
+ * Handler that 802.15.4 module calls for each transmitted frame.
* skb cntains the buffer starting from the IEEE 802.15.4 header.
* The low-level driver should send the frame based on available
* configuration.
- * This function should return zero or negative errno. Called with
- * pib_lock held.
+ * This function should return zero or negative errno.
*
* ed: Handler that 802.15.4 module calls for Energy Detection.
* This function should place the value for detected energy
* set_frame_retries
* Sets the retransmission attempt limit. Called with pib_lock held.
* Returns either zero, or negative errno.
+ *
+ * set_promiscuous_mode
+ * Enables or disable promiscuous mode.
*/
struct ieee802154_ops {
struct module *owner;
- int (*start)(struct ieee802154_dev *dev);
- void (*stop)(struct ieee802154_dev *dev);
- int (*xmit)(struct ieee802154_dev *dev,
- struct sk_buff *skb);
- int (*ed)(struct ieee802154_dev *dev, u8 *level);
- int (*set_channel)(struct ieee802154_dev *dev,
- int page,
- int channel);
- int (*set_hw_addr_filt)(struct ieee802154_dev *dev,
- struct ieee802154_hw_addr_filt *filt,
+ int (*start)(struct ieee802154_hw *hw);
+ void (*stop)(struct ieee802154_hw *hw);
+ int (*xmit_sync)(struct ieee802154_hw *hw,
+ struct sk_buff *skb);
+ int (*xmit_async)(struct ieee802154_hw *hw,
+ struct sk_buff *skb);
+ int (*ed)(struct ieee802154_hw *hw, u8 *level);
+ int (*set_channel)(struct ieee802154_hw *hw, u8 page,
+ u8 channel);
+ int (*set_hw_addr_filt)(struct ieee802154_hw *hw,
+ struct ieee802154_hw_addr_filt *filt,
unsigned long changed);
- int (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
- int (*set_txpower)(struct ieee802154_dev *dev, int db);
- int (*set_lbt)(struct ieee802154_dev *dev, bool on);
- int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
- int (*set_cca_ed_level)(struct ieee802154_dev *dev,
+ int (*set_txpower)(struct ieee802154_hw *hw, int db);
+ int (*set_lbt)(struct ieee802154_hw *hw, bool on);
+ int (*set_cca_mode)(struct ieee802154_hw *hw, u8 mode);
+ int (*set_cca_ed_level)(struct ieee802154_hw *hw,
s32 level);
- int (*set_csma_params)(struct ieee802154_dev *dev,
+ int (*set_csma_params)(struct ieee802154_hw *hw,
u8 min_be, u8 max_be, u8 retries);
- int (*set_frame_retries)(struct ieee802154_dev *dev,
+ int (*set_frame_retries)(struct ieee802154_hw *hw,
s8 retries);
+ int (*set_promiscuous_mode)(struct ieee802154_hw *hw,
+ const bool on);
};
-/* Basic interface to register ieee802154 device */
-struct ieee802154_dev *
-ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops);
-void ieee802154_free_device(struct ieee802154_dev *dev);
-int ieee802154_register_device(struct ieee802154_dev *dev);
-void ieee802154_unregister_device(struct ieee802154_dev *dev);
+/* Basic interface to register ieee802154 hwice */
+struct ieee802154_hw *
+ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops);
+void ieee802154_free_hw(struct ieee802154_hw *hw);
+int ieee802154_register_hw(struct ieee802154_hw *hw);
+void ieee802154_unregister_hw(struct ieee802154_hw *hw);
-void ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb,
+void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
+void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb,
u8 lqi);
+void ieee802154_wake_queue(struct ieee802154_hw *hw);
+void ieee802154_stop_queue(struct ieee802154_hw *hw);
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb);
+
#endif /* NET_MAC802154_H */
--- /dev/null
+/*
+ * Copyright (c) 2014 Nicira, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _NET_MPLS_H
+#define _NET_MPLS_H 1
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
+#define MPLS_HLEN 4
+
+static inline bool eth_p_mpls(__be16 eth_type)
+{
+ return eth_type == htons(ETH_P_MPLS_UC) ||
+ eth_type == htons(ETH_P_MPLS_MC);
+}
+
+/*
+ * For non-MPLS skbs this will correspond to the network header.
+ * For MPLS skbs it will be before the network_header as the MPLS
+ * label stack lies between the end of the mac header and the network
+ * header. That is, for MPLS skbs the end of the mac header
+ * is the top of the MPLS label stack.
+ */
+static inline unsigned char *skb_mpls_header(struct sk_buff *skb)
+{
+ return skb_mac_header(skb) + skb->mac_len;
+}
+#endif
struct net *net;
#endif
struct net_device *dev;
- struct neigh_parms *next;
+ struct list_head list;
int (*neigh_setup)(struct neighbour *);
void (*neigh_cleanup)(struct neighbour *);
struct neigh_table *tbl;
void (*proxy_redo)(struct sk_buff *skb);
char *id;
struct neigh_parms parms;
+ struct list_head parms_list;
int gc_interval;
int gc_thresh1;
int gc_thresh2;
struct pneigh_entry **phash_buckets;
};
+enum {
+ NEIGH_ARP_TABLE = 0,
+ NEIGH_ND_TABLE = 1,
+ NEIGH_DN_TABLE = 2,
+ NEIGH_NR_TABLES,
+};
+
static inline int neigh_parms_family(struct neigh_parms *p)
{
return p->tbl->family;
#define NEIGH_UPDATE_F_ISROUTER 0x40000000
#define NEIGH_UPDATE_F_ADMIN 0x80000000
-void neigh_table_init(struct neigh_table *tbl);
-int neigh_table_clear(struct neigh_table *tbl);
+void neigh_table_init(int index, struct neigh_table *tbl);
+int neigh_table_clear(int index, struct neigh_table *tbl);
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
struct net_device *dev);
struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
#define nla_for_each_nested(pos, nla, rem) \
nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem)
+/**
+ * nla_is_last - Test if attribute is last in stream
+ * @nla: attribute to test
+ * @rem: bytes remaining in stream
+ */
+static inline bool nla_is_last(const struct nlattr *nla, int rem)
+{
+ return nla->nla_len == rem;
+}
+
#endif
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#ifndef IEEE802154_NL_H
sctp_scope_t sctp_scope(const union sctp_addr *);
int sctp_in_scope(struct net *net, const union sctp_addr *addr, const sctp_scope_t scope);
int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
-int sctp_addr_is_valid(const union sctp_addr *addr);
int sctp_is_ep_boundall(struct sock *sk);
* @sk_rcvtimeo: %SO_RCVTIMEO setting
* @sk_sndtimeo: %SO_SNDTIMEO setting
* @sk_rxhash: flow hash received from netif layer
+ * @sk_incoming_cpu: record cpu processing incoming packets
* @sk_txhash: computed flow hash for use on transmit
* @sk_filter: socket filtering instructions
* @sk_protinfo: private area, net family specific, when not using slab
#ifdef CONFIG_RPS
__u32 sk_rxhash;
#endif
+ u16 sk_incoming_cpu;
+ /* 16bit hole
+ * Warned : sk_incoming_cpu can be set from softirq,
+ * Do not use this hole without fully understanding possible issues.
+ */
+
__u32 sk_txhash;
#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int sk_napi_id;
return sk->sk_backlog_rcv(sk, skb);
}
+static inline void sk_incoming_cpu_update(struct sock *sk)
+{
+ sk->sk_incoming_cpu = raw_smp_processor_id();
+}
+
static inline void sock_rps_record_flow_hash(__u32 hash)
{
#ifdef CONFIG_RPS
bool sk_capable(const struct sock *sk, int cap);
bool sk_net_capable(const struct sock *sk, int cap);
-/*
- * Enable debug/info messages
- */
-extern int net_msg_warn;
-#define NETDEBUG(fmt, args...) \
- do { if (net_msg_warn) printk(fmt,##args); } while (0)
-
-#define LIMIT_NETDEBUG(fmt, args...) \
- do { if (net_msg_warn && net_ratelimit()) printk(fmt,##args); } while(0)
-
extern __u32 sysctl_wmem_max;
extern __u32 sysctl_rmem_max;
#define MAX_TCP_HEADER (128 + MAX_HEADER)
#define MAX_TCP_OPTION_SPACE 40
-/*
+/*
* Never offer a window over 32767 without using window scaling. Some
- * poor stacks do signed 16bit maths!
+ * poor stacks do signed 16bit maths!
*/
#define MAX_TCP_WINDOW 32767U
/* After receiving this amount of duplicate ACKs fast retransmit starts. */
#define TCP_FASTRETRANS_THRESH 3
-/* Maximal reordering. */
-#define TCP_MAX_REORDERING 127
-
/* Maximal number of ACKs sent quickly to accelerate slow-start. */
#define TCP_MAX_QUICKACKS 16U
/*
* TCP option
*/
-
+
#define TCPOPT_NOP 1 /* Padding */
#define TCPOPT_EOL 0 /* End of options */
#define TCPOPT_MSS 2 /* Segment size negotiating */
extern int sysctl_tcp_max_orphans;
extern int sysctl_tcp_fack;
extern int sysctl_tcp_reordering;
+extern int sysctl_tcp_max_reordering;
extern int sysctl_tcp_dsack;
extern long sysctl_tcp_mem[3];
extern int sysctl_tcp_wmem[3];
u16 *mssp);
__u32 cookie_v4_init_sequence(struct sock *sk, const struct sk_buff *skb,
__u16 *mss);
-#endif
-
__u32 cookie_init_timestamp(struct request_sock *req);
-bool cookie_check_timestamp(struct tcp_options_received *opt, struct net *net,
- bool *ecn_ok);
+bool cookie_timestamp_decode(struct tcp_options_received *opt);
+bool cookie_ecn_ok(const struct tcp_options_received *opt,
+ const struct net *net, const struct dst_entry *dst);
/* From net/ipv6/syncookies.c */
int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th,
u32 cookie);
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
-#ifdef CONFIG_SYN_COOKIES
+
u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph,
const struct tcphdr *th, u16 *mssp);
__u32 cookie_v6_init_sequence(struct sock *sk, const struct sk_buff *skb,
space - (space>>sysctl_tcp_adv_win_scale);
}
-/* Note: caller must be prepared to deal with negative returns */
+/* Note: caller must be prepared to deal with negative returns */
static inline int tcp_space(const struct sock *sk)
{
return tcp_win_from_space(sk->sk_rcvbuf -
atomic_read(&sk->sk_rmem_alloc));
-}
+}
static inline int tcp_full_space(const struct sock *sk)
{
- return tcp_win_from_space(sk->sk_rcvbuf);
+ return tcp_win_from_space(sk->sk_rcvbuf);
}
static inline void tcp_openreq_init(struct request_sock *req,
* checksum. UDP-Lite (like IPv6) mandates checksums, hence packets
* with a zero checksum field are illegal. */
if (uh->check == 0) {
- LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: zeroed checksum field\n");
+ net_dbg_ratelimited("UDPLite: zeroed checksum field\n");
return 1;
}
/*
* Coverage length violates RFC 3828: log and discard silently.
*/
- LIMIT_NETDEBUG(KERN_DEBUG "UDPLite: bad csum coverage %d/%d\n",
- cscov, skb->len);
+ net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n",
+ cscov, skb->len);
return 1;
} else if (cscov < skb->len) {
+++ /dev/null
-/*
- * Copyright (C) 2007, 2008, 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- */
-
-#ifndef WPAN_PHY_H
-#define WPAN_PHY_H
-
-#include <linux/netdevice.h>
-#include <linux/mutex.h>
-#include <linux/bug.h>
-
-/* According to the IEEE 802.15.4 stadard the upper most significant bits of
- * the 32-bit channel bitmaps shall be used as an integer value to specify 32
- * possible channel pages. The lower 27 bits of the channel bit map shall be
- * used as a bit mask to specify channel numbers within a channel page.
- */
-#define WPAN_NUM_CHANNELS 27
-#define WPAN_NUM_PAGES 32
-
-struct wpan_phy {
- struct mutex pib_lock;
-
- /*
- * This is a PIB according to 802.15.4-2011.
- * We do not provide timing-related variables, as they
- * aren't used outside of driver
- */
- u8 current_channel;
- u8 current_page;
- u32 channels_supported[32];
- s8 transmit_power;
- u8 cca_mode;
- u8 min_be;
- u8 max_be;
- u8 csma_retries;
- s8 frame_retries;
-
- bool lbt;
- s32 cca_ed_level;
-
- struct device dev;
- int idx;
-
- struct net_device *(*add_iface)(struct wpan_phy *phy,
- const char *name, int type);
- void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
-
- int (*set_txpower)(struct wpan_phy *phy, int db);
- int (*set_lbt)(struct wpan_phy *phy, bool on);
- int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
- int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
- int (*set_csma_params)(struct wpan_phy *phy, u8 min_be, u8 max_be,
- u8 retries);
- int (*set_frame_retries)(struct wpan_phy *phy, s8 retries);
-
- char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
-};
-
-#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
-
-struct wpan_phy *wpan_phy_alloc(size_t priv_size);
-static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
-{
- phy->dev.parent = dev;
-}
-int wpan_phy_register(struct wpan_phy *phy);
-void wpan_phy_unregister(struct wpan_phy *phy);
-void wpan_phy_free(struct wpan_phy *phy);
-/* Same semantics as for class_for_each_device */
-int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), void *data);
-
-static inline void *wpan_phy_priv(struct wpan_phy *phy)
-{
- BUG_ON(!phy);
- return &phy->priv;
-}
-
-struct wpan_phy *wpan_phy_find(const char *str);
-
-static inline void wpan_phy_put(struct wpan_phy *phy)
-{
- put_device(&phy->dev);
-}
-
-static inline const char *wpan_phy_name(struct wpan_phy *phy)
-{
- return dev_name(&phy->dev);
-}
-#endif
#define SO_BPF_EXTENSIONS 48
+#define SO_INCOMING_CPU 49
+
#endif /* __ASM_GENERIC_SOCKET_H */
header-y += apm_bios.h
header-y += arcfb.h
header-y += atalk.h
-header-y += atm.h
-header-y += atm_eni.h
-header-y += atm_he.h
-header-y += atm_idt77105.h
-header-y += atm_nicstar.h
-header-y += atm_tcp.h
-header-y += atm_zatm.h
header-y += atmapi.h
header-y += atmarp.h
header-y += atmbr2684.h
header-y += atmclip.h
header-y += atmdev.h
+header-y += atm_eni.h
+header-y += atm.h
+header-y += atm_he.h
+header-y += atm_idt77105.h
header-y += atmioc.h
header-y += atmlec.h
header-y += atmmpc.h
+header-y += atm_nicstar.h
header-y += atmppp.h
header-y += atmsap.h
header-y += atmsvc.h
+header-y += atm_tcp.h
+header-y += atm_zatm.h
header-y += audit.h
-header-y += auto_fs.h
header-y += auto_fs4.h
+header-y += auto_fs.h
header-y += auxvec.h
header-y += ax25.h
header-y += b1lli.h
header-y += binfmts.h
header-y += blkpg.h
header-y += blktrace_api.h
-header-y += bpf.h
header-y += bpf_common.h
+header-y += bpf.h
header-y += bpqether.h
header-y += bsg.h
header-y += btrfs.h
header-y += cycx_cfm.h
header-y += dcbnl.h
header-y += dccp.h
-header-y += dlm.h
+header-y += dlmconstants.h
header-y += dlm_device.h
+header-y += dlm.h
header-y += dlm_netlink.h
header-y += dlm_plock.h
-header-y += dlmconstants.h
header-y += dm-ioctl.h
header-y += dm-log-userspace.h
header-y += dn.h
header-y += dqblk_xfs.h
header-y += edd.h
header-y += efs_fs_sb.h
+header-y += elfcore.h
header-y += elf-em.h
header-y += elf-fdpic.h
header-y += elf.h
-header-y += elfcore.h
header-y += errno.h
header-y += errqueue.h
header-y += ethtool.h
header-y += fuse.h
header-y += futex.h
header-y += gameport.h
-header-y += gen_stats.h
header-y += genetlink.h
+header-y += gen_stats.h
header-y += gfs2_ondisk.h
header-y += gigaset_dev.h
-header-y += hdlc.h
header-y += hdlcdrv.h
+header-y += hdlc.h
header-y += hdreg.h
-header-y += hid.h
header-y += hiddev.h
+header-y += hid.h
header-y += hidraw.h
header-y += hpet.h
header-y += hsr_netlink.h
header-y += i8k.h
header-y += icmp.h
header-y += icmpv6.h
-header-y += if.h
header-y += if_addr.h
header-y += if_addrlabel.h
header-y += if_alg.h
header-y += if_fc.h
header-y += if_fddi.h
header-y += if_frad.h
+header-y += if.h
header-y += if_hippi.h
header-y += if_infiniband.h
header-y += if_link.h
header-y += if_vlan.h
header-y += if_x25.h
header-y += igmp.h
-header-y += in.h
header-y += in6.h
-header-y += in_route.h
header-y += inet_diag.h
+header-y += in.h
header-y += inotify.h
header-y += input.h
+header-y += in_route.h
header-y += ioctl.h
-header-y += ip.h
header-y += ip6_tunnel.h
-header-y += ip_vs.h
header-y += ipc.h
+header-y += ip.h
header-y += ipmi.h
header-y += ipmi_msgdefs.h
header-y += ipsec.h
header-y += ipv6.h
header-y += ipv6_route.h
+header-y += ip_vs.h
header-y += ipx.h
header-y += irda.h
header-y += irqnr.h
-header-y += isdn.h
header-y += isdn_divertif.h
-header-y += isdn_ppp.h
+header-y += isdn.h
header-y += isdnif.h
+header-y += isdn_ppp.h
header-y += iso_fs.h
-header-y += ivtv.h
header-y += ivtvfb.h
+header-y += ivtv.h
header-y += ixjuser.h
header-y += jffs2.h
header-y += joystick.h
-header-y += kd.h
header-y += kdev_t.h
-header-y += kernel-page-flags.h
-header-y += kernel.h
+header-y += kd.h
header-y += kernelcapi.h
+header-y += kernel.h
+header-y += kernel-page-flags.h
header-y += kexec.h
header-y += keyboard.h
header-y += keyctl.h
header-y += kvm_para.h
endif
+header-y += hw_breakpoint.h
header-y += l2tp.h
header-y += libc-compat.h
header-y += limits.h
header-y += mmtimer.h
header-y += mpls.h
header-y += mqueue.h
-header-y += mroute.h
header-y += mroute6.h
+header-y += mroute.h
header-y += msdos_fs.h
header-y += msg.h
header-y += mtio.h
-header-y += n_r3964.h
header-y += nbd.h
-header-y += ncp.h
header-y += ncp_fs.h
+header-y += ncp.h
header-y += ncp_mount.h
header-y += ncp_no.h
header-y += neighbour.h
-header-y += net.h
-header-y += net_dropmon.h
-header-y += net_tstamp.h
header-y += netconf.h
header-y += netdevice.h
-header-y += netlink_diag.h
-header-y += netfilter.h
+header-y += net_dropmon.h
header-y += netfilter_arp.h
header-y += netfilter_bridge.h
header-y += netfilter_decnet.h
+header-y += netfilter.h
header-y += netfilter_ipv4.h
header-y += netfilter_ipv6.h
+header-y += net.h
+header-y += netlink_diag.h
header-y += netlink.h
header-y += netrom.h
+header-y += net_tstamp.h
header-y += nfc.h
-header-y += nfs.h
header-y += nfs2.h
header-y += nfs3.h
header-y += nfs4.h
header-y += nfs4_mount.h
+header-y += nfsacl.h
header-y += nfs_fs.h
+header-y += nfs.h
header-y += nfs_idmap.h
header-y += nfs_mount.h
-header-y += nfsacl.h
header-y += nl80211.h
+header-y += n_r3964.h
header-y += nubus.h
header-y += nvme.h
header-y += nvram.h
header-y += pg.h
header-y += phantom.h
header-y += phonet.h
+header-y += pktcdvd.h
header-y += pkt_cls.h
header-y += pkt_sched.h
-header-y += pktcdvd.h
header-y += pmu.h
header-y += poll.h
header-y += posix_types.h
header-y += ppdev.h
header-y += ppp-comp.h
-header-y += ppp-ioctl.h
header-y += ppp_defs.h
+header-y += ppp-ioctl.h
header-y += pps.h
header-y += prctl.h
header-y += psci.h
header-y += securebits.h
header-y += selinux_netlink.h
header-y += sem.h
-header-y += serial.h
header-y += serial_core.h
+header-y += serial.h
header-y += serial_reg.h
header-y += serio.h
header-y += shm.h
-header-y += signal.h
header-y += signalfd.h
+header-y += signal.h
header-y += smiapp.h
header-y += snmp.h
header-y += sock_diag.h
header-y += som.h
header-y += sonet.h
header-y += sonypi.h
-header-y += sound.h
header-y += soundcard.h
+header-y += sound.h
header-y += stat.h
header-y += stddef.h
header-y += string.h
header-y += times.h
header-y += timex.h
header-y += tiocl.h
-header-y += tipc.h
header-y += tipc_config.h
+header-y += tipc.h
header-y += toshiba.h
-header-y += tty.h
header-y += tty_flags.h
+header-y += tty.h
header-y += types.h
header-y += udf_fs_i.h
header-y += udp.h
header-y += x25.h
header-y += xattr.h
header-y += xfrm.h
-header-y += hw_breakpoint.h
header-y += zorro.h
header-y += zorro_ids.h
#define SUPPORTED_40000baseCR4_Full (1 << 24)
#define SUPPORTED_40000baseSR4_Full (1 << 25)
#define SUPPORTED_40000baseLR4_Full (1 << 26)
+#define SUPPORTED_56000baseKR4_Full (1 << 27)
+#define SUPPORTED_56000baseCR4_Full (1 << 28)
+#define SUPPORTED_56000baseSR4_Full (1 << 29)
+#define SUPPORTED_56000baseLR4_Full (1 << 30)
#define ADVERTISED_10baseT_Half (1 << 0)
#define ADVERTISED_10baseT_Full (1 << 1)
#define ADVERTISED_40000baseCR4_Full (1 << 24)
#define ADVERTISED_40000baseSR4_Full (1 << 25)
#define ADVERTISED_40000baseLR4_Full (1 << 26)
+#define ADVERTISED_56000baseKR4_Full (1 << 27)
+#define ADVERTISED_56000baseCR4_Full (1 << 28)
+#define ADVERTISED_56000baseSR4_Full (1 << 29)
+#define ADVERTISED_56000baseLR4_Full (1 << 30)
/* The following are all involved in forcing a particular link
* mode for the device for setting things. When getting the
* it was forced up into this mode or autonegotiated.
*/
-/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+/* The forced speed, 10Mb, 100Mb, gigabit, [2.5|10|20|40|56]GbE. */
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000
#define SPEED_2500 2500
#define SPEED_10000 10000
+#define SPEED_20000 20000
+#define SPEED_40000 40000
+#define SPEED_56000 56000
+
#define SPEED_UNKNOWN -1
/* Duplex, half or full. */
#define ETH_MODULE_SFF_8079_LEN 256
#define ETH_MODULE_SFF_8472 0x2
#define ETH_MODULE_SFF_8472_LEN 512
+#define ETH_MODULE_SFF_8636 0x3
+#define ETH_MODULE_SFF_8636_LEN 256
+#define ETH_MODULE_SFF_8436 0x4
+#define ETH_MODULE_SFF_8436_LEN 256
/* Reset flags */
/* The reset() operation must clear the flags for the components which
IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
IFLA_BRPORT_LEARNING, /* mac learning */
IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
+ IFLA_BRPORT_PROXYARP, /* proxy ARP */
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#define TUNNEL_ENCAP_FLAG_CSUM (1<<0)
#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1)
+#define TUNNEL_ENCAP_FLAG_REMCSUM (1<<2)
/* SIT-mode i_flags */
#define SIT_ISATAP 0x0001
DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
DEVCONF_SUPPRESS_FRAG_NDISC,
DEVCONF_ACCEPT_RA_FROM_LOCAL,
+ DEVCONF_USE_OPTIMISTIC,
DEVCONF_MAX
};
* the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all stations, on the interface identified
- * by %NL80211_ATTR_IFINDEX.
+ * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ * of disconnection indication should be sent to the station
+ * (Deauthentication or Disassociation frame and reason code for that
+ * frame).
*
* @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
* before removing a station entry entirely, or before disassociating
* or similar, cleanup will happen in the driver/device in this case.
*
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ * bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ * network is determined by the network interface.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
NL80211_CMD_ADD_TX_TS,
NL80211_CMD_DEL_TX_TS,
+ NL80211_CMD_GET_MPP,
+
+ NL80211_CMD_JOIN_OCB,
+ NL80211_CMD_LEAVE_OCB,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ * This mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
+ NL80211_IFTYPE_OCB,
/* keep last */
NUM_NL80211_IFTYPES,
* multiplexing powersave, ie. can turn off all but one chain
* and then wake the rest up as required after, for example,
* rts/cts handshake.
+ * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ * TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS
+ * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ * needs to be able to handle Block-Ack agreements and other things.
+ * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
+ * the vif's MAC address upon creation.
+ * See 'macaddr' field in the vif_params (cfg80211.h).
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23,
NL80211_FEATURE_STATIC_SMPS = 1 << 24,
NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25,
+ NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,
+ NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,
};
/**
* notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
* %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
* specified there.
+ * @OVS_PACKET_ATTR_EGRESS_TUN_KEY: Present for an %OVS_PACKET_CMD_ACTION
+ * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
+ * %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the
+ * output port is actually a tunnel port. Contains the output tunnel key
+ * extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes.
*
* These attributes follow the &struct ovs_header within the Generic Netlink
* payload for %OVS_PACKET_* commands.
OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */
+ OVS_PACKET_ATTR_EGRESS_TUN_KEY, /* Nested OVS_TUNNEL_KEY_ATTR_*
+ attributes. */
__OVS_PACKET_ATTR_MAX
};
OVS_KEY_ATTR_DP_HASH, /* u32 hash value. Value 0 indicates the hash
is not computed by the datapath. */
OVS_KEY_ATTR_RECIRC_ID, /* u32 recirc id */
+ OVS_KEY_ATTR_MPLS, /* array of struct ovs_key_mpls.
+ * The implementation may restrict
+ * the accepted length of the array. */
#ifdef __KERNEL__
OVS_KEY_ATTR_TUNNEL_INFO, /* struct ovs_tunnel_info */
OVS_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */
OVS_TUNNEL_KEY_ATTR_OAM, /* No argument. OAM frame. */
OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */
+ OVS_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */
+ OVS_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */
__OVS_TUNNEL_KEY_ATTR_MAX
};
__u8 eth_dst[ETH_ALEN];
};
+struct ovs_key_mpls {
+ __be32 mpls_lse;
+};
+
struct ovs_key_ipv4 {
__be32 ipv4_src;
__be32 ipv4_dst;
};
struct ovs_key_nd {
- __u32 nd_target[4];
- __u8 nd_sll[ETH_ALEN];
- __u8 nd_tll[ETH_ALEN];
+ __be32 nd_target[4];
+ __u8 nd_sll[ETH_ALEN];
+ __u8 nd_tll[ETH_ALEN];
};
/**
OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
OVS_FLOW_ATTR_MASK, /* Sequence of OVS_KEY_ATTR_* attributes. */
+ OVS_FLOW_ATTR_PROBE, /* Flow operation is a feature probe, error
+ * logging should be suppressed. */
__OVS_FLOW_ATTR_MAX
};
* message should be sent. Required.
* @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
* copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
+ * @OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: If present, u32 output port to get
+ * tunnel info.
*/
enum ovs_userspace_attr {
OVS_USERSPACE_ATTR_UNSPEC,
OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */
+ OVS_USERSPACE_ATTR_EGRESS_TUN_PORT, /* Optional, u32 output port
+ * to get tunnel info. */
__OVS_USERSPACE_ATTR_MAX
};
#define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
+/**
+ * struct ovs_action_push_mpls - %OVS_ACTION_ATTR_PUSH_MPLS action argument.
+ * @mpls_lse: MPLS label stack entry to push.
+ * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
+ *
+ * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
+ * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
+ */
+struct ovs_action_push_mpls {
+ __be32 mpls_lse;
+ __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
+};
+
/**
* struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
* @vlan_tpid: Tag protocol identifier (TPID) to push.
* @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
* @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
* the nested %OVS_SAMPLE_ATTR_* attributes.
+ * @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the
+ * top of the packets MPLS label stack. Set the ethertype of the
+ * encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to
+ * indicate the new packet contents.
+ * @OVS_ACTION_ATTR_POP_MPLS: Pop an MPLS label stack entry off of the
+ * packet's MPLS label stack. Set the encapsulating frame's ethertype to
+ * indicate the new packet contents. This could potentially still be
+ * %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
+ * is no MPLS label stack, as determined by ethertype, no action is taken.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
OVS_ACTION_ATTR_RECIRC, /* u32 recirc_id. */
OVS_ACTION_ATTR_HASH, /* struct ovs_action_hash. */
+ OVS_ACTION_ATTR_PUSH_MPLS, /* struct ovs_action_push_mpls. */
+ OVS_ACTION_ATTR_POP_MPLS, /* __be16 ethertype. */
+
__OVS_ACTION_ATTR_MAX
};
#define RTPROT_NTK 15 /* Netsukuku */
#define RTPROT_DHCP 16 /* DHCP client */
#define RTPROT_MROUTED 17 /* Multicast daemon */
+#define RTPROT_BABEL 42 /* Babel daemon */
/* rtm_scope
UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */
UDP_MIB_SNDBUFERRORS, /* SndbufErrors */
UDP_MIB_CSUMERRORS, /* InCsumErrors */
+ UDP_MIB_IGNOREDMULTI, /* IgnoredMulti */
__UDP_MIB_MAX
};
enum bpf_stack_slot_type {
STACK_INVALID, /* nothing was stored in this stack slot */
- STACK_SPILL, /* 1st byte of register spilled into stack */
- STACK_SPILL_PART, /* other 7 bytes of register spill */
+ STACK_SPILL, /* register spilled into stack */
STACK_MISC /* BPF program wrote some data into this slot */
};
-struct bpf_stack_slot {
- enum bpf_stack_slot_type stype;
- struct reg_state reg_st;
-};
+#define BPF_REG_SIZE 8 /* size of eBPF register in bytes */
/* state of the program:
* type of all registers and stack info
*/
struct verifier_state {
struct reg_state regs[MAX_BPF_REG];
- struct bpf_stack_slot stack[MAX_BPF_STACK];
+ u8 stack_slot_type[MAX_BPF_STACK];
+ struct reg_state spilled_regs[MAX_BPF_STACK / BPF_REG_SIZE];
};
/* linked list of verifier states used to prune search */
env->cur_state.regs[i].map_ptr->key_size,
env->cur_state.regs[i].map_ptr->value_size);
}
- for (i = 0; i < MAX_BPF_STACK; i++) {
- if (env->cur_state.stack[i].stype == STACK_SPILL)
+ for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) {
+ if (env->cur_state.stack_slot_type[i] == STACK_SPILL)
verbose(" fp%d=%s", -MAX_BPF_STACK + i,
- reg_type_str[env->cur_state.stack[i].reg_st.type]);
+ reg_type_str[env->cur_state.spilled_regs[i / BPF_REG_SIZE].type]);
}
verbose("\n");
}
static int check_stack_write(struct verifier_state *state, int off, int size,
int value_regno)
{
- struct bpf_stack_slot *slot;
int i;
+ /* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0,
+ * so it's aligned access and [off, off + size) are within stack limits
+ */
if (value_regno >= 0 &&
(state->regs[value_regno].type == PTR_TO_MAP_VALUE ||
state->regs[value_regno].type == PTR_TO_CTX)) {
/* register containing pointer is being spilled into stack */
- if (size != 8) {
+ if (size != BPF_REG_SIZE) {
verbose("invalid size of register spill\n");
return -EACCES;
}
- slot = &state->stack[MAX_BPF_STACK + off];
- slot->stype = STACK_SPILL;
/* save register state */
- slot->reg_st = state->regs[value_regno];
- for (i = 1; i < 8; i++) {
- slot = &state->stack[MAX_BPF_STACK + off + i];
- slot->stype = STACK_SPILL_PART;
- slot->reg_st.type = UNKNOWN_VALUE;
- slot->reg_st.map_ptr = NULL;
- }
- } else {
+ state->spilled_regs[(MAX_BPF_STACK + off) / BPF_REG_SIZE] =
+ state->regs[value_regno];
+ for (i = 0; i < BPF_REG_SIZE; i++)
+ state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_SPILL;
+ } else {
/* regular write of data into stack */
- for (i = 0; i < size; i++) {
- slot = &state->stack[MAX_BPF_STACK + off + i];
- slot->stype = STACK_MISC;
- slot->reg_st.type = UNKNOWN_VALUE;
- slot->reg_st.map_ptr = NULL;
- }
+ state->spilled_regs[(MAX_BPF_STACK + off) / BPF_REG_SIZE] =
+ (struct reg_state) {};
+
+ for (i = 0; i < size; i++)
+ state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_MISC;
}
return 0;
}
static int check_stack_read(struct verifier_state *state, int off, int size,
int value_regno)
{
+ u8 *slot_type;
int i;
- struct bpf_stack_slot *slot;
- slot = &state->stack[MAX_BPF_STACK + off];
+ slot_type = &state->stack_slot_type[MAX_BPF_STACK + off];
- if (slot->stype == STACK_SPILL) {
- if (size != 8) {
+ if (slot_type[0] == STACK_SPILL) {
+ if (size != BPF_REG_SIZE) {
verbose("invalid size of register spill\n");
return -EACCES;
}
- for (i = 1; i < 8; i++) {
- if (state->stack[MAX_BPF_STACK + off + i].stype !=
- STACK_SPILL_PART) {
+ for (i = 1; i < BPF_REG_SIZE; i++) {
+ if (slot_type[i] != STACK_SPILL) {
verbose("corrupted spill memory\n");
return -EACCES;
}
if (value_regno >= 0)
/* restore register state from stack */
- state->regs[value_regno] = slot->reg_st;
+ state->regs[value_regno] =
+ state->spilled_regs[(MAX_BPF_STACK + off) / BPF_REG_SIZE];
return 0;
} else {
for (i = 0; i < size; i++) {
- if (state->stack[MAX_BPF_STACK + off + i].stype !=
- STACK_MISC) {
+ if (slot_type[i] != STACK_MISC) {
verbose("invalid read from stack off %d+%d size %d\n",
off, i, size);
return -EACCES;
}
for (i = 0; i < access_size; i++) {
- if (state->stack[MAX_BPF_STACK + off + i].stype != STACK_MISC) {
+ if (state->stack_slot_type[MAX_BPF_STACK + off + i] != STACK_MISC) {
verbose("invalid indirect read from stack off %d+%d size %d\n",
off, i, access_size);
return -EACCES;
}
for (i = 0; i < MAX_BPF_STACK; i++) {
- if (memcmp(&old->stack[i], &cur->stack[i],
- sizeof(old->stack[0])) != 0) {
- if (old->stack[i].stype == STACK_INVALID)
- continue;
+ if (old->stack_slot_type[i] == STACK_INVALID)
+ continue;
+ if (old->stack_slot_type[i] != cur->stack_slot_type[i])
+ /* Ex: old explored (safe) state has STACK_SPILL in
+ * this stack slot, but current has has STACK_MISC ->
+ * this verifier states are not equivalent,
+ * return false to continue verification of this path
+ */
return false;
- }
+ if (i % BPF_REG_SIZE)
+ continue;
+ if (memcmp(&old->spilled_regs[i / BPF_REG_SIZE],
+ &cur->spilled_regs[i / BPF_REG_SIZE],
+ sizeof(old->spilled_regs[0])))
+ /* when explored and current stack slot types are
+ * the same, check that stored pointers types
+ * are the same as well.
+ * Ex: explored safe path could have stored
+ * (struct reg_state) {.type = PTR_TO_STACK, .imm = -8}
+ * but current path has stored:
+ * (struct reg_state) {.type = PTR_TO_STACK, .imm = -16}
+ * such verifier states are not equivalent.
+ * return false to continue verification of this path
+ */
+ return false;
+ else
+ continue;
}
return true;
}
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
- percpu-refcount.o percpu_ida.o hash.o rhashtable.o
+ percpu-refcount.o percpu_ida.o rhashtable.o
obj-y += string_helpers.o
obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
obj-y += kstrtox.o
+++ /dev/null
-/* General purpose hashing library
- *
- * That's a start of a kernel hashing library, which can be extended
- * with further algorithms in future. arch_fast_hash{2,}() will
- * eventually resolve to an architecture optimized implementation.
- *
- * Copyright 2013 Francesco Fusco <ffusco@redhat.com>
- * Copyright 2013 Daniel Borkmann <dborkman@redhat.com>
- * Copyright 2013 Thomas Graf <tgraf@redhat.com>
- * Licensed under the GNU General Public License, version 2.0 (GPLv2)
- */
-
-#include <linux/jhash.h>
-#include <linux/hash.h>
-#include <linux/cache.h>
-
-static struct fast_hash_ops arch_hash_ops __read_mostly = {
- .hash = jhash,
- .hash2 = jhash2,
-};
-
-u32 arch_fast_hash(const void *data, u32 len, u32 seed)
-{
- return arch_hash_ops.hash(data, len, seed);
-}
-EXPORT_SYMBOL_GPL(arch_fast_hash);
-
-u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
-{
- return arch_hash_ops.hash2(data, len, seed);
-}
-EXPORT_SYMBOL_GPL(arch_fast_hash2);
-
-static int __init hashlib_init(void)
-{
- setup_arch_fast_hash(&arch_hash_ops);
- return 0;
-}
-early_initcall(hashlib_init);
#ifdef CONFIG_PROVE_LOCKING
int lockdep_rht_mutex_is_held(const struct rhashtable *ht)
{
- return ht->p.mutex_is_held();
+ return ht->p.mutex_is_held(ht->p.parent);
}
EXPORT_SYMBOL_GPL(lockdep_rht_mutex_is_held);
#endif
return obj_hashfn(ht, rht_obj(ht, he), hsize);
}
-static struct bucket_table *bucket_table_alloc(size_t nbuckets, gfp_t flags)
+static struct bucket_table *bucket_table_alloc(size_t nbuckets)
{
struct bucket_table *tbl;
size_t size;
size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
- tbl = kzalloc(size, flags);
+ tbl = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (tbl == NULL)
tbl = vzalloc(size);
/**
* rhashtable_expand - Expand hash table while allowing concurrent lookups
* @ht: the hash table to expand
- * @flags: allocation flags
*
* A secondary bucket array is allocated and the hash entries are migrated
* while keeping them on both lists until the end of the RCU grace period.
* The caller must ensure that no concurrent table mutations take place.
* It is however valid to have concurrent lookups if they are RCU protected.
*/
-int rhashtable_expand(struct rhashtable *ht, gfp_t flags)
+int rhashtable_expand(struct rhashtable *ht)
{
struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht);
struct rhash_head *he;
if (ht->p.max_shift && ht->shift >= ht->p.max_shift)
return 0;
- new_tbl = bucket_table_alloc(old_tbl->size * 2, flags);
+ new_tbl = bucket_table_alloc(old_tbl->size * 2);
if (new_tbl == NULL)
return -ENOMEM;
/**
* rhashtable_shrink - Shrink hash table while allowing concurrent lookups
* @ht: the hash table to shrink
- * @flags: allocation flags
*
* This function may only be called in a context where it is safe to call
* synchronize_rcu(), e.g. not within a rcu_read_lock() section.
* The caller must ensure that no concurrent table mutations take place.
* It is however valid to have concurrent lookups if they are RCU protected.
*/
-int rhashtable_shrink(struct rhashtable *ht, gfp_t flags)
+int rhashtable_shrink(struct rhashtable *ht)
{
struct bucket_table *ntbl, *tbl = rht_dereference(ht->tbl, ht);
struct rhash_head __rcu **pprev;
if (ht->shift <= ht->p.min_shift)
return 0;
- ntbl = bucket_table_alloc(tbl->size / 2, flags);
+ ntbl = bucket_table_alloc(tbl->size / 2);
if (ntbl == NULL)
return -ENOMEM;
* rhashtable_insert - insert object into hash hash table
* @ht: hash table
* @obj: pointer to hash head inside object
- * @flags: allocation flags (table expansion)
*
* Will automatically grow the table via rhashtable_expand() if the the
* grow_decision function specified at rhashtable_init() returns true.
* The caller must ensure that no concurrent table mutations occur. It is
* however valid to have concurrent lookups if they are RCU protected.
*/
-void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
- gfp_t flags)
+void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj)
{
struct bucket_table *tbl = rht_dereference(ht->tbl, ht);
u32 hash;
ht->nelems++;
if (ht->p.grow_decision && ht->p.grow_decision(ht, tbl->size))
- rhashtable_expand(ht, flags);
+ rhashtable_expand(ht);
}
EXPORT_SYMBOL_GPL(rhashtable_insert);
* @ht: hash table
* @obj: pointer to hash head inside object
* @pprev: pointer to previous element
- * @flags: allocation flags (table expansion)
*
* Identical to rhashtable_remove() but caller is alreayd aware of the element
* in front of the element to be deleted. This is in particular useful for
* deletion when combined with walking or lookup.
*/
void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj,
- struct rhash_head __rcu **pprev, gfp_t flags)
+ struct rhash_head __rcu **pprev)
{
struct bucket_table *tbl = rht_dereference(ht->tbl, ht);
if (ht->p.shrink_decision &&
ht->p.shrink_decision(ht, tbl->size))
- rhashtable_shrink(ht, flags);
+ rhashtable_shrink(ht);
}
EXPORT_SYMBOL_GPL(rhashtable_remove_pprev);
* rhashtable_remove - remove object from hash table
* @ht: hash table
* @obj: pointer to hash head inside object
- * @flags: allocation flags (table expansion)
*
* Since the hash chain is single linked, the removal operation needs to
* walk the bucket chain upon removal. The removal operation is thus
* The caller must ensure that no concurrent table mutations occur. It is
* however valid to have concurrent lookups if they are RCU protected.
*/
-bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj,
- gfp_t flags)
+bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj)
{
struct bucket_table *tbl = rht_dereference(ht->tbl, ht);
struct rhash_head __rcu **pprev;
continue;
}
- rhashtable_remove_pprev(ht, he, pprev, flags);
+ rhashtable_remove_pprev(ht, he, pprev);
return true;
}
* .key_offset = offsetof(struct test_obj, key),
* .key_len = sizeof(int),
* .hashfn = arch_fast_hash,
+ * #ifdef CONFIG_PROVE_LOCKING
* .mutex_is_held = &my_mutex_is_held,
+ * #endif
* };
*
* Configuration Example 2: Variable length keys
* .head_offset = offsetof(struct test_obj, node),
* .hashfn = arch_fast_hash,
* .obj_hashfn = my_hash_fn,
+ * #ifdef CONFIG_PROVE_LOCKING
* .mutex_is_held = &my_mutex_is_held,
+ * #endif
* };
*/
int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
if (params->nelem_hint)
size = rounded_hashtable_size(params);
- tbl = bucket_table_alloc(size, GFP_KERNEL);
+ tbl = bucket_table_alloc(size);
if (tbl == NULL)
return -ENOMEM;
#define TEST_PTR ((void *) 0xdeadbeef)
#define TEST_NEXPANDS 4
-static int test_mutex_is_held(void)
+#ifdef CONFIG_PROVE_LOCKING
+static int test_mutex_is_held(void *parent)
{
return 1;
}
+#endif
struct test_obj {
void *ptr;
obj->ptr = TEST_PTR;
obj->value = i * 2;
- rhashtable_insert(ht, &obj->node, GFP_KERNEL);
+ rhashtable_insert(ht, &obj->node);
}
rcu_read_lock();
for (i = 0; i < TEST_NEXPANDS; i++) {
pr_info(" Table expansion iteration %u...\n", i);
- rhashtable_expand(ht, GFP_KERNEL);
+ rhashtable_expand(ht);
rcu_read_lock();
pr_info(" Verifying lookups...\n");
for (i = 0; i < TEST_NEXPANDS; i++) {
pr_info(" Table shrinkage iteration %u...\n", i);
- rhashtable_shrink(ht, GFP_KERNEL);
+ rhashtable_shrink(ht);
rcu_read_lock();
pr_info(" Verifying lookups...\n");
obj = rhashtable_lookup(ht, &key);
BUG_ON(!obj);
- rhashtable_remove(ht, &obj->node, GFP_KERNEL);
+ rhashtable_remove(ht, &obj->node);
kfree(obj);
}
.key_offset = offsetof(struct test_obj, value),
.key_len = sizeof(int),
.hashfn = arch_fast_hash,
+#ifdef CONFIG_PROVE_LOCKING
.mutex_is_held = &test_mutex_is_held,
+#endif
.grow_decision = rht_grow_above_75,
.shrink_decision = rht_shrink_below_30,
};
{ },
{ { 0, 1 } }
},
+ {
+ "nmap reduced",
+ .u.insns_int = {
+ BPF_MOV64_REG(R6, R1),
+ BPF_LD_ABS(BPF_H, 12),
+ BPF_JMP_IMM(BPF_JNE, R0, 0x806, 28),
+ BPF_LD_ABS(BPF_H, 12),
+ BPF_JMP_IMM(BPF_JNE, R0, 0x806, 26),
+ BPF_MOV32_IMM(R0, 18),
+ BPF_STX_MEM(BPF_W, R10, R0, -64),
+ BPF_LDX_MEM(BPF_W, R7, R10, -64),
+ BPF_LD_IND(BPF_W, R7, 14),
+ BPF_STX_MEM(BPF_W, R10, R0, -60),
+ BPF_MOV32_IMM(R0, 280971478),
+ BPF_STX_MEM(BPF_W, R10, R0, -56),
+ BPF_LDX_MEM(BPF_W, R7, R10, -56),
+ BPF_LDX_MEM(BPF_W, R0, R10, -60),
+ BPF_ALU32_REG(BPF_SUB, R0, R7),
+ BPF_JMP_IMM(BPF_JNE, R0, 0, 15),
+ BPF_LD_ABS(BPF_H, 12),
+ BPF_JMP_IMM(BPF_JNE, R0, 0x806, 13),
+ BPF_MOV32_IMM(R0, 22),
+ BPF_STX_MEM(BPF_W, R10, R0, -56),
+ BPF_LDX_MEM(BPF_W, R7, R10, -56),
+ BPF_LD_IND(BPF_H, R7, 14),
+ BPF_STX_MEM(BPF_W, R10, R0, -52),
+ BPF_MOV32_IMM(R0, 17366),
+ BPF_STX_MEM(BPF_W, R10, R0, -48),
+ BPF_LDX_MEM(BPF_W, R7, R10, -48),
+ BPF_LDX_MEM(BPF_W, R0, R10, -52),
+ BPF_ALU32_REG(BPF_SUB, R0, R7),
+ BPF_JMP_IMM(BPF_JNE, R0, 0, 2),
+ BPF_MOV32_IMM(R0, 256),
+ BPF_EXIT_INSN(),
+ BPF_MOV32_IMM(R0, 0),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x06, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x10, 0xbf, 0x48, 0xd6, 0x43, 0xd6},
+ { { 38, 256 } }
+ },
};
static struct net_device dev;
return 0;
}
-static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
- struct net_device *dev, skb_delivery_cb deliver_skb)
-{
- struct sk_buff *new;
- int stat;
-
- new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
- GFP_ATOMIC);
- kfree_skb(skb);
-
- if (!new)
- return -ENOMEM;
-
- skb_push(new, sizeof(struct ipv6hdr));
- skb_reset_network_header(new);
- skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
-
- new->protocol = htons(ETH_P_IPV6);
- new->pkt_type = PACKET_HOST;
- new->dev = dev;
-
- raw_dump_table(__func__, "raw skb data dump before receiving",
- new->data, new->len);
-
- stat = deliver_skb(new, dev);
-
- kfree_skb(new);
-
- return stat;
-}
-
/* Uncompress function for multicast destination address,
* when M bit is set.
*/
/* TTL uncompression values */
static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
- const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
- const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
- u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
+int
+lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
+ const u8 *saddr, const u8 saddr_type,
+ const u8 saddr_len, const u8 *daddr,
+ const u8 daddr_type, const u8 daddr_len,
+ u8 iphc0, u8 iphc1)
{
struct ipv6hdr hdr = {};
u8 tmp, num_context = 0;
/* UDP data uncompression */
if (iphc0 & LOWPAN_IPHC_NH_C) {
struct udphdr uh;
- struct sk_buff *new;
+ const int needed = sizeof(struct udphdr) + sizeof(hdr);
if (uncompress_udp_header(skb, &uh))
goto drop;
/* replace the compressed UDP head by the uncompressed UDP
* header
*/
- new = skb_copy_expand(skb, sizeof(struct udphdr),
- skb_tailroom(skb), GFP_ATOMIC);
- kfree_skb(skb);
-
- if (!new)
- return -ENOMEM;
-
- skb = new;
+ err = skb_cow(skb, needed);
+ if (unlikely(err)) {
+ kfree_skb(skb);
+ return err;
+ }
skb_push(skb, sizeof(struct udphdr));
skb_reset_transport_header(skb);
(u8 *)&uh, sizeof(uh));
hdr.nexthdr = UIP_PROTO_UDP;
+ } else {
+ err = skb_cow(skb, sizeof(hdr));
+ if (unlikely(err)) {
+ kfree_skb(skb);
+ return err;
+ }
}
hdr.payload_len = htons(skb->len);
hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
hdr.hop_limit, &hdr.daddr);
- raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
+ skb_push(skb, sizeof(hdr));
+ skb_reset_network_header(skb);
+ skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
- return skb_deliver(skb, &hdr, dev, deliver_skb);
+ raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
+ return 0;
drop:
kfree_skb(skb);
return -EINVAL;
}
-EXPORT_SYMBOL_GPL(lowpan_process_data);
+EXPORT_SYMBOL_GPL(lowpan_header_decompress);
static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
const struct in6_addr *ipaddr,
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
- err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, offset, msg, copied);
if (!err && msg->msg_name) {
DECLARE_SOCKADDR(struct sockaddr_at *, sat, msg->msg_name);
msg->msg_flags |= MSG_TRUNC;
}
- error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ error = skb_copy_datagram_msg(skb, 0, msg, copied);
if (error)
return error;
sock_recv_ts_and_drops(msg, sk, skb);
msg->msg_flags |= MSG_TRUNC;
}
- skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ skb_copy_datagram_msg(skb, 0, msg, copied);
if (msg->msg_name) {
ax25_digi digi;
* The list contains struct lowpan_dev elements.
*/
static LIST_HEAD(bt_6lowpan_devices);
-static DEFINE_RWLOCK(devices_lock);
+static DEFINE_SPINLOCK(devices_lock);
/* If psm is set to 0 (default value), then 6lowpan is disabled.
* Other values are used to indicate a Protocol Service Multiplexer
struct lowpan_peer {
struct list_head list;
+ struct rcu_head rcu;
struct l2cap_chan *chan;
/* peer addresses in various formats */
struct delayed_work notify_peers;
};
+static inline void peer_free(struct rcu_head *head)
+{
+ struct lowpan_peer *e = container_of(head, struct lowpan_peer, rcu);
+
+ kfree(e);
+}
+
static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
{
return netdev_priv(netdev);
static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
{
- list_add(&peer->list, &dev->peers);
+ list_add_rcu(&peer->list, &dev->peers);
atomic_inc(&dev->peer_count);
}
static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
{
- list_del(&peer->list);
+ list_del_rcu(&peer->list);
+ call_rcu(&peer->rcu, peer_free);
module_put(THIS_MODULE);
static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
bdaddr_t *ba, __u8 type)
{
- struct lowpan_peer *peer, *tmp;
+ struct lowpan_peer *peer;
BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
ba, type);
- list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(peer, &dev->peers, list) {
BT_DBG("dst addr %pMR dst type %d",
&peer->chan->dst, peer->chan->dst_type);
if (bacmp(&peer->chan->dst, ba))
continue;
- if (type == peer->chan->dst_type)
+ if (type == peer->chan->dst_type) {
+ rcu_read_unlock();
return peer;
+ }
}
+ rcu_read_unlock();
+
return NULL;
}
-static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev,
- struct l2cap_chan *chan)
+static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev,
+ struct l2cap_chan *chan)
{
- struct lowpan_peer *peer, *tmp;
+ struct lowpan_peer *peer;
- list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+ list_for_each_entry_rcu(peer, &dev->peers, list) {
if (peer->chan == chan)
return peer;
}
return NULL;
}
-static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
- struct l2cap_conn *conn)
+static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev,
+ struct l2cap_conn *conn)
{
- struct lowpan_peer *peer, *tmp;
+ struct lowpan_peer *peer;
- list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+ list_for_each_entry_rcu(peer, &dev->peers, list) {
if (peer->chan->conn == conn)
return peer;
}
struct in6_addr *daddr,
struct sk_buff *skb)
{
- struct lowpan_peer *peer, *tmp;
+ struct lowpan_peer *peer;
struct in6_addr *nexthop;
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
int count = atomic_read(&dev->peer_count);
* send the packet. If only one peer exists, then we can send the
* packet right away.
*/
- if (count == 1)
- return list_first_entry(&dev->peers, struct lowpan_peer,
- list);
+ if (count == 1) {
+ rcu_read_lock();
+ peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer,
+ list);
+ rcu_read_unlock();
+ return peer;
+ }
if (!rt) {
nexthop = &lowpan_cb(skb)->gw;
BT_DBG("gw %pI6c", nexthop);
- list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(peer, &dev->peers, list) {
BT_DBG("dst addr %pMR dst type %d ip %pI6c",
&peer->chan->dst, peer->chan->dst_type,
&peer->peer_addr);
- if (!ipv6_addr_cmp(&peer->peer_addr, nexthop))
+ if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) {
+ rcu_read_unlock();
return peer;
+ }
}
+ rcu_read_unlock();
+
return NULL;
}
static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
{
- struct lowpan_dev *entry, *tmp;
+ struct lowpan_dev *entry;
struct lowpan_peer *peer = NULL;
- unsigned long flags;
- read_lock_irqsave(&devices_lock, flags);
+ rcu_read_lock();
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
- peer = peer_lookup_conn(entry, conn);
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+ peer = __peer_lookup_conn(entry, conn);
if (peer)
break;
}
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_unlock();
return peer;
}
static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
{
- struct lowpan_dev *entry, *tmp;
+ struct lowpan_dev *entry;
struct lowpan_dev *dev = NULL;
- unsigned long flags;
- read_lock_irqsave(&devices_lock, flags);
+ rcu_read_lock();
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
if (conn->hcon->hdev == entry->hdev) {
dev = entry;
break;
}
}
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_unlock();
return dev;
}
static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *skb_cp;
- int ret;
skb_cp = skb_copy(skb, GFP_ATOMIC);
if (!skb_cp)
- return -ENOMEM;
-
- ret = netif_rx(skb_cp);
- if (ret < 0) {
- BT_DBG("receive skb %d", ret);
return NET_RX_DROP;
- }
- return ret;
+ return netif_rx(skb_cp);
}
-static int process_data(struct sk_buff *skb, struct net_device *netdev,
- struct l2cap_chan *chan)
+static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
+ struct l2cap_chan *chan)
{
const u8 *saddr, *daddr;
u8 iphc0, iphc1;
struct lowpan_dev *dev;
struct lowpan_peer *peer;
- unsigned long flags;
dev = lowpan_dev(netdev);
- read_lock_irqsave(&devices_lock, flags);
- peer = peer_lookup_chan(dev, chan);
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_lock();
+ peer = __peer_lookup_chan(dev, chan);
+ rcu_read_unlock();
if (!peer)
goto drop;
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
- return lowpan_process_data(skb, netdev,
- saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
- daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
- iphc0, iphc1, give_skb_to_upper);
+ return lowpan_header_decompress(skb, netdev,
+ saddr, IEEE802154_ADDR_LONG,
+ EUI64_ADDR_LEN, daddr,
+ IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+ iphc0, iphc1);
drop:
kfree_skb(skb);
if (dev->type != ARPHRD_6LOWPAN)
goto drop;
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb)
+ goto drop;
+
/* check that it's our buffer */
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
/* Copy the packet so that the IPv6 header is
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
- kfree_skb(local_skb);
- kfree_skb(skb);
+ consume_skb(local_skb);
+ consume_skb(skb);
} else {
switch (skb->data[0] & 0xe0) {
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
if (!local_skb)
goto drop;
- ret = process_data(local_skb, dev, chan);
- if (ret != NET_RX_SUCCESS)
+ ret = iphc_decompress(local_skb, dev, chan);
+ if (ret < 0)
goto drop;
+ local_skb->protocol = htons(ETH_P_IPV6);
+ local_skb->pkt_type = PACKET_HOST;
+ local_skb->dev = dev;
+
+ if (give_skb_to_upper(local_skb, dev)
+ != NET_RX_SUCCESS) {
+ kfree_skb(local_skb);
+ goto drop;
+ }
+
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
- kfree_skb(skb);
+ consume_skb(local_skb);
+ consume_skb(skb);
break;
default:
break;
if (ipv6_addr_is_multicast(&ipv6_daddr)) {
lowpan_cb(skb)->chan = NULL;
} else {
- unsigned long flags;
u8 addr_type;
/* Get destination BT device from skb.
BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
addr_type, &ipv6_daddr);
- read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_ba(dev, &addr, addr_type);
- read_unlock_irqrestore(&devices_lock, flags);
-
if (!peer) {
/* The packet might be sent to 6lowpan interface
* because of routing (either via default route
* or user set route) so get peer according to
* the destination address.
*/
- read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
- read_unlock_irqrestore(&devices_lock, flags);
if (!peer) {
BT_DBG("no such peer %pMR found", &addr);
return -ENOENT;
static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
{
struct sk_buff *local_skb;
- struct lowpan_dev *entry, *tmp;
- unsigned long flags;
+ struct lowpan_dev *entry;
int err = 0;
- read_lock_irqsave(&devices_lock, flags);
+ rcu_read_lock();
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
- struct lowpan_peer *pentry, *ptmp;
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+ struct lowpan_peer *pentry;
struct lowpan_dev *dev;
if (entry->netdev != netdev)
dev = lowpan_dev(entry->netdev);
- list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+ list_for_each_entry_rcu(pentry, &dev->peers, list) {
int ret;
local_skb = skb_clone(skb, GFP_ATOMIC);
}
}
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_unlock();
return err;
}
return err < 0 ? NET_XMIT_DROP : err;
}
+static struct lock_class_key bt_tx_busylock;
+static struct lock_class_key bt_netdev_xmit_lock_key;
+
+static void bt_set_lockdep_class_one(struct net_device *dev,
+ struct netdev_queue *txq,
+ void *_unused)
+{
+ lockdep_set_class(&txq->_xmit_lock, &bt_netdev_xmit_lock_key);
+}
+
+static int bt_dev_init(struct net_device *dev)
+{
+ netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL);
+ dev->qdisc_tx_busylock = &bt_tx_busylock;
+
+ return 0;
+}
+
static const struct net_device_ops netdev_ops = {
+ .ndo_init = bt_dev_init,
.ndo_start_xmit = bt_xmit,
};
struct lowpan_dev *dev)
{
struct lowpan_peer *peer;
- unsigned long flags;
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
if (!peer)
*/
set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
- write_lock_irqsave(&devices_lock, flags);
+ spin_lock(&devices_lock);
INIT_LIST_HEAD(&peer->list);
peer_add(dev, peer);
- write_unlock_irqrestore(&devices_lock, flags);
+ spin_unlock(&devices_lock);
/* Notifying peers about us needs to be done without locks held */
INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
{
struct net_device *netdev;
int err = 0;
- unsigned long flags;
netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE,
NET_NAME_UNKNOWN, netdev_setup);
(*dev)->hdev = chan->conn->hcon->hdev;
INIT_LIST_HEAD(&(*dev)->peers);
- write_lock_irqsave(&devices_lock, flags);
+ spin_lock(&devices_lock);
INIT_LIST_HEAD(&(*dev)->list);
- list_add(&(*dev)->list, &bt_6lowpan_devices);
- write_unlock_irqrestore(&devices_lock, flags);
+ list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
+ spin_unlock(&devices_lock);
return 0;
static void chan_close_cb(struct l2cap_chan *chan)
{
- struct lowpan_dev *entry, *tmp;
+ struct lowpan_dev *entry;
struct lowpan_dev *dev = NULL;
struct lowpan_peer *peer;
int err = -ENOENT;
- unsigned long flags;
bool last = false, removed = true;
BT_DBG("chan %p conn %p", chan, chan->conn);
removed = false;
}
- write_lock_irqsave(&devices_lock, flags);
+ spin_lock(&devices_lock);
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
dev = lowpan_dev(entry->netdev);
- peer = peer_lookup_chan(dev, chan);
+ peer = __peer_lookup_chan(dev, chan);
if (peer) {
last = peer_del(dev, peer);
err = 0;
atomic_read(&chan->kref.refcount));
l2cap_chan_put(chan);
- kfree(peer);
break;
}
}
if (!err && last && dev && !atomic_read(&dev->peer_count)) {
- write_unlock_irqrestore(&devices_lock, flags);
+ spin_unlock(&devices_lock);
cancel_delayed_work_sync(&dev->notify_peers);
schedule_work(&entry->delete_netdev);
}
} else {
- write_unlock_irqrestore(&devices_lock, flags);
+ spin_unlock(&devices_lock);
}
return;
static void disconnect_all_peers(void)
{
- struct lowpan_dev *entry, *tmp_dev;
+ struct lowpan_dev *entry;
struct lowpan_peer *peer, *tmp_peer, *new_peer;
struct list_head peers;
- unsigned long flags;
INIT_LIST_HEAD(&peers);
* with the same list at the same time.
*/
- read_lock_irqsave(&devices_lock, flags);
+ rcu_read_lock();
- list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
- list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) {
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+ list_for_each_entry_rcu(peer, &entry->peers, list) {
new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
if (!new_peer)
break;
}
}
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_unlock();
+ spin_lock(&devices_lock);
list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
l2cap_chan_close(peer->chan, ENOENT);
- kfree(peer);
+
+ list_del_rcu(&peer->list);
+ call_rcu(&peer->rcu, peer_free);
+
+ module_put(THIS_MODULE);
}
+ spin_unlock(&devices_lock);
}
-static int lowpan_psm_set(void *data, u64 val)
-{
+struct set_psm {
+ struct work_struct work;
u16 psm;
+};
+
+static void do_psm_set(struct work_struct *work)
+{
+ struct set_psm *set_psm = container_of(work, struct set_psm, work);
- psm = val;
- if (psm == 0 || psm_6lowpan != psm)
+ if (set_psm->psm == 0 || psm_6lowpan != set_psm->psm)
/* Disconnect existing connections if 6lowpan is
* disabled (psm = 0), or if psm changes.
*/
disconnect_all_peers();
- psm_6lowpan = psm;
+ psm_6lowpan = set_psm->psm;
if (listen_chan) {
l2cap_chan_close(listen_chan, 0);
listen_chan = bt_6lowpan_listen();
+ kfree(set_psm);
+}
+
+static int lowpan_psm_set(void *data, u64 val)
+{
+ struct set_psm *set_psm;
+
+ set_psm = kzalloc(sizeof(*set_psm), GFP_KERNEL);
+ if (!set_psm)
+ return -ENOMEM;
+
+ set_psm->psm = val;
+ INIT_WORK(&set_psm->work, do_psm_set);
+
+ schedule_work(&set_psm->work);
+
return 0;
}
static int lowpan_control_show(struct seq_file *f, void *ptr)
{
- struct lowpan_dev *entry, *tmp_dev;
- struct lowpan_peer *peer, *tmp_peer;
- unsigned long flags;
+ struct lowpan_dev *entry;
+ struct lowpan_peer *peer;
- read_lock_irqsave(&devices_lock, flags);
+ spin_lock(&devices_lock);
- list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
- list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list)
+ list_for_each_entry(entry, &bt_6lowpan_devices, list) {
+ list_for_each_entry(peer, &entry->peers, list)
seq_printf(f, "%pMR (type %u)\n",
&peer->chan->dst, peer->chan->dst_type);
}
- read_unlock_irqrestore(&devices_lock, flags);
+ spin_unlock(&devices_lock);
return 0;
}
{
struct lowpan_dev *entry, *tmp, *new_dev;
struct list_head devices;
- unsigned long flags;
INIT_LIST_HEAD(&devices);
* devices list.
*/
- read_lock_irqsave(&devices_lock, flags);
+ rcu_read_lock();
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC);
if (!new_dev)
break;
new_dev->netdev = entry->netdev;
INIT_LIST_HEAD(&new_dev->list);
- list_add(&new_dev->list, &devices);
+ list_add_rcu(&new_dev->list, &devices);
}
- read_unlock_irqrestore(&devices_lock, flags);
+ rcu_read_unlock();
list_for_each_entry_safe(entry, tmp, &devices, list) {
ifdown(entry->netdev);
unsigned long event, void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
- struct lowpan_dev *entry, *tmp;
- unsigned long flags;
+ struct lowpan_dev *entry;
if (netdev->type != ARPHRD_6LOWPAN)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UNREGISTER:
- write_lock_irqsave(&devices_lock, flags);
- list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
- list) {
+ spin_lock(&devices_lock);
+ list_for_each_entry(entry, &bt_6lowpan_devices, list) {
if (entry->netdev == netdev) {
BT_DBG("Unregistered netdev %s %p",
netdev->name, netdev);
break;
}
}
- write_unlock_irqrestore(&devices_lock, flags);
+ spin_unlock(&devices_lock);
break;
}
}
skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err == 0) {
sock_recv_ts_and_drops(msg, sk, skb);
}
chunk = min_t(unsigned int, skb->len, size);
- if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
+ if (skb_copy_datagram_msg(skb, 0, msg, chunk)) {
skb_queue_head(&sk->sk_receive_queue, skb);
if (!copied)
copied = -EFAULT;
*/
if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) {
struct hci_dev *hdev = conn->hdev;
- struct hci_cp_read_clock_offset cp;
+ struct hci_cp_read_clock_offset clkoff_cp;
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp);
+ clkoff_cp.handle = cpu_to_le16(conn->handle);
+ hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(clkoff_cp),
+ &clkoff_cp);
}
conn->state = BT_DISCONN;
* happen with broken hardware or if low duty cycle was used
* (which doesn't have a timeout of its own).
*/
- if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
+ if (conn->role == HCI_ROLE_SLAVE) {
u8 enable = 0x00;
hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
&enable);
/* Unacked frames */
hdev->acl_cnt += conn->sent;
} else if (conn->type == LE_LINK) {
- cancel_delayed_work_sync(&conn->le_conn_timeout);
+ cancel_delayed_work(&conn->le_conn_timeout);
if (hdev->le_pkts)
hdev->le_cnt += conn->sent;
hci_conn_del_sysfs(conn);
+ if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
+ hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
+
hci_dev_put(hdev);
hci_conn_put(conn);
BT_DBG("length %u", skb_queue_len(&req->cmd_q));
- /* If an error occured during request building, remove all HCI
+ /* If an error occurred during request building, remove all HCI
* commands queued on the HCI request queue.
*/
if (req->err) {
return -ENOMEM;
}
- /* Stand-alone HCI commands must be flaged as
+ /* Stand-alone HCI commands must be flagged as
* single-command requests.
*/
bt_cb(skb)->req.start = true;
BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
- /* If an error occured during request building, there is no point in
+ /* If an error occurred during request building, there is no point in
* queueing the HCI command. We can simply return.
*/
if (req->err)
skb_shinfo(skb)->frag_list = NULL;
- /* Queue all fragments atomically */
- spin_lock(&queue->lock);
+ /* Queue all fragments atomically. We need to use spin_lock_bh
+ * here because of 6LoWPAN links, as there this function is
+ * called from softirq and using normal spin lock could cause
+ * deadlocks.
+ */
+ spin_lock_bh(&queue->lock);
__skb_queue_tail(queue, skb);
__skb_queue_tail(queue, skb);
} while (list);
- spin_unlock(&queue->lock);
+ spin_unlock_bh(&queue->lock);
}
}
hdev->le_scan_type = LE_SCAN_PASSIVE;
hdev->ssp_debug_mode = 0;
+
+ hci_bdaddr_list_clear(&hdev->le_white_list);
}
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock(hdev);
- /* If we're doing connection initation as peripheral. Set a
+ /* If we're doing connection initiation as peripheral. Set a
* timeout in case something goes wrong.
*/
if (*sent) {
struct inquiry_entry *e;
if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
- name_len, conn->dev_class);
+ mgmt_device_connected(hdev, conn, 0, name, name_len);
if (discov->state == DISCOVERY_STOPPED)
return;
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
+ mgmt_device_connected(hdev, conn, 0, NULL, 0);
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
+ mgmt_device_connected(hdev, conn, 0, NULL, 0);
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
}
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0, NULL);
+ mgmt_device_connected(hdev, conn, 0, NULL, 0);
conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle);
}
/* This function requires the caller holds hdev->lock */
-static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
- u8 addr_type, u8 adv_type)
+static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
+ bdaddr_t *addr,
+ u8 addr_type, u8 adv_type)
{
struct hci_conn *conn;
struct hci_conn_params *params;
/* If the event is not connectable don't proceed further */
if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
- return;
+ return NULL;
/* Ignore if the device is blocked */
if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type))
- return;
+ return NULL;
/* Most controller will fail if we try to create new connections
* while we have an existing one in slave role.
*/
if (hdev->conn_hash.le_num_slave > 0)
- return;
+ return NULL;
/* If we're not connectable only connect devices that we have in
* our pend_le_conns list.
params = hci_pend_le_action_lookup(&hdev->pend_le_conns,
addr, addr_type);
if (!params)
- return;
+ return NULL;
switch (params->auto_connect) {
case HCI_AUTO_CONN_DIRECT:
* incoming connections from slave devices.
*/
if (adv_type != LE_ADV_DIRECT_IND)
- return;
+ return NULL;
break;
case HCI_AUTO_CONN_ALWAYS:
/* Devices advertising with ADV_IND or ADV_DIRECT_IND
*/
break;
default:
- return;
+ return NULL;
}
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
* count consistent once the connection is established.
*/
params->conn = hci_conn_get(conn);
- return;
+ return conn;
}
switch (PTR_ERR(conn)) {
break;
default:
BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+ return NULL;
}
+
+ return NULL;
}
static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
{
struct discovery_state *d = &hdev->discovery;
struct smp_irk *irk;
+ struct hci_conn *conn;
bool match;
u32 flags;
}
/* Check if we have been requested to connect to this device */
- check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+ conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+ if (conn && type == LE_ADV_IND) {
+ /* Store report for later inclusion by
+ * mgmt_device_connected
+ */
+ memcpy(conn->le_adv_data, data, len);
+ conn->le_adv_data_len = len;
+ }
/* Passive scanning shouldn't trigger any device found events,
* except for devices marked as CONN_REPORT for which we do send
}
skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
switch (hci_pi(sk)->channel) {
case HCI_CHANNEL_RAW:
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
} else {
- /* Stand-alone HCI commands must be flaged as
+ /* Stand-alone HCI commands must be flagged as
* single-command requests.
*/
bt_cb(skb)->req.start = true;
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
- mgmt_device_connected(hdev, &hcon->dst, hcon->type,
- hcon->dst_type, 0, NULL, 0,
- hcon->dev_class);
+ mgmt_device_connected(hdev, hcon, 0, NULL, 0);
hci_dev_unlock(hdev);
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
chan->num_conf_req++;
}
- /* Got Conf Rsp PENDING from remote side and asume we sent
+ /* Got Conf Rsp PENDING from remote side and assume we sent
Conf Rsp PENDING in the code above */
if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
if (credits > max_credits) {
BT_ERR("LE credits overflow");
l2cap_send_disconn_req(chan, ECONNRESET);
+ l2cap_chan_unlock(chan);
/* Return 0 so that we don't trigger an unnecessary
* command reject packet.
}
if (cp->addr.type == BDADDR_BREDR) {
+ /* If disconnection is requested, then look up the
+ * connection. If the remote device is connected, it
+ * will be later used to terminate the link.
+ *
+ * Setting it to NULL explicitly will cause no
+ * termination of the link.
+ */
+ if (cp->disconnect)
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+ &cp->addr.bdaddr);
+ else
+ conn = NULL;
+
err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
} else {
u8 addr_type;
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+ &cp->addr.bdaddr);
+ if (conn) {
+ /* Defer clearing up the connection parameters
+ * until closing to give a chance of keeping
+ * them if a repairing happens.
+ */
+ set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
+
+ /* If disconnection is not requested, then
+ * clear the connection variable so that the
+ * link is not terminated.
+ */
+ if (!cp->disconnect)
+ conn = NULL;
+ }
+
if (cp->addr.type == BDADDR_LE_PUBLIC)
addr_type = ADDR_LE_DEV_PUBLIC;
else
hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
- hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
-
err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
}
goto unlock;
}
- if (cp->disconnect) {
- if (cp->addr.type == BDADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
- &cp->addr.bdaddr);
- else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
- &cp->addr.bdaddr);
- } else {
- conn = NULL;
- }
-
+ /* If the connection variable is set, then termination of the
+ * link is requested.
+ */
if (!conn) {
err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
&rp, sizeof(rp));
hci_conn_put(conn);
mgmt_pending_remove(cmd);
+
+ /* The device is paired so there is no need to remove
+ * its connection parameters anymore.
+ */
+ clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
}
void mgmt_smp_complete(struct hci_conn *conn, bool complete)
return eir_len;
}
-void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
- u8 addr_type, u32 flags, u8 *name, u8 name_len,
- u8 *dev_class)
+void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
+ u32 flags, u8 *name, u8 name_len)
{
char buf[512];
struct mgmt_ev_device_connected *ev = (void *) buf;
u16 eir_len = 0;
- bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_bdaddr(link_type, addr_type);
+ bacpy(&ev->addr.bdaddr, &conn->dst);
+ ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
ev->flags = __cpu_to_le32(flags);
- if (name_len > 0)
- eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
- name, name_len);
+ /* We must ensure that the EIR Data fields are ordered and
+ * unique. Keep it simple for now and avoid the problem by not
+ * adding any BR/EDR data to the LE adv.
+ */
+ if (conn->le_adv_data_len > 0) {
+ memcpy(&ev->eir[eir_len],
+ conn->le_adv_data, conn->le_adv_data_len);
+ eir_len = conn->le_adv_data_len;
+ } else {
+ if (name_len > 0)
+ eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
+ name, name_len);
- if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
- eir_len = eir_append_data(ev->eir, eir_len,
- EIR_CLASS_OF_DEV, dev_class, 3);
+ if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
+ eir_len = eir_append_data(ev->eir, eir_len,
+ EIR_CLASS_OF_DEV,
+ conn->dev_class, 3);
+ }
ev->eir_len = cpu_to_le16(eir_len);
#define __get_type(b) ((b & 0xef))
#define __test_ea(b) ((b & 0x01))
-#define __test_cr(b) ((b & 0x02))
-#define __test_pf(b) ((b & 0x10))
+#define __test_cr(b) (!!(b & 0x02))
+#define __test_pf(b) (!!(b & 0x10))
#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
hdr->len = __len8(sizeof(*mcc) + 1);
mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(cr, RFCOMM_NSC);
+ mcc->type = __mcc_type(0, RFCOMM_NSC);
mcc->len = __len8(1);
/* Type that we didn't like */
return 0;
}
-static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7],
- u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra,
- u8 res[16])
+static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16],
+ u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat,
+ bdaddr_t *ra, u8 res[16])
{
- struct hci_dev *hdev = smp->conn->hcon->hdev;
u8 p1[16], p2[16];
int err;
- BT_DBG("%s", hdev->name);
-
memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
/* res = e(k, res) */
- err = smp_e(smp->tfm_aes, k, res);
+ err = smp_e(tfm_aes, k, res);
if (err) {
BT_ERR("Encrypt data error");
return err;
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
/* res = e(k, res) */
- err = smp_e(smp->tfm_aes, k, res);
+ err = smp_e(tfm_aes, k, res);
if (err)
BT_ERR("Encrypt data error");
return err;
}
-static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
- u8 _r[16])
+static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16],
+ u8 r2[16], u8 _r[16])
{
- struct hci_dev *hdev = smp->conn->hcon->hdev;
int err;
- BT_DBG("%s", hdev->name);
-
/* Just least significant octets from r1 and r2 are considered */
memcpy(_r, r2, 8);
memcpy(_r + 8, r1, 8);
- err = smp_e(smp->tfm_aes, k, _r);
+ err = smp_e(tfm_aes, k, _r);
if (err)
BT_ERR("Encrypt data error");
BT_DBG("conn %p", conn);
- ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp,
+ ret = smp_c1(smp->tfm_aes, smp->tk, smp->prnd, smp->preq, smp->prsp,
conn->hcon->init_addr_type, &conn->hcon->init_addr,
conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
cp.confirm_val);
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
- ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+ ret = smp_c1(smp->tfm_aes, smp->tk, smp->rrnd, smp->preq, smp->prsp,
hcon->init_addr_type, &hcon->init_addr,
hcon->resp_addr_type, &hcon->resp_addr, confirm);
if (ret)
__le64 rand = 0;
__le16 ediv = 0;
- smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk);
+ smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk);
memset(stk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
smp->prnd);
- smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk);
+ smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk);
memset(stk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
if (sec_level > conn->hcon->pending_sec_level)
conn->hcon->pending_sec_level = sec_level;
- /* If we need MITM check that it can be acheived */
+ /* If we need MITM check that it can be achieved */
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
u8 method;
auth = rsp->auth_req & AUTH_REQ_MASK;
- /* If we need MITM check that it can be acheived */
+ /* If we need MITM check that it can be achieved */
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
u8 method;
/* Do not flood unicast traffic to ports that turn it off */
if (unicast && !(p->flags & BR_FLOOD))
continue;
+
+ /* Do not flood to ports that enable proxy ARP */
+ if (p->flags & BR_PROXYARP)
+ continue;
+
prev = maybe_deliver(prev, p, skb, __packet_hook);
if (IS_ERR(prev))
goto out;
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/netfilter_bridge.h>
+#include <linux/neighbour.h>
+#include <net/arp.h>
#include <linux/export.h>
#include <linux/rculist.h>
#include "br_private.h"
netif_receive_skb);
}
+static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
+ u16 vid)
+{
+ struct net_device *dev = br->dev;
+ struct neighbour *n;
+ struct arphdr *parp;
+ u8 *arpptr, *sha;
+ __be32 sip, tip;
+
+ if (dev->flags & IFF_NOARP)
+ return;
+
+ if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
+ dev->stats.tx_dropped++;
+ return;
+ }
+ parp = arp_hdr(skb);
+
+ if (parp->ar_pro != htons(ETH_P_IP) ||
+ parp->ar_op != htons(ARPOP_REQUEST) ||
+ parp->ar_hln != dev->addr_len ||
+ parp->ar_pln != 4)
+ return;
+
+ arpptr = (u8 *)parp + sizeof(struct arphdr);
+ sha = arpptr;
+ arpptr += dev->addr_len; /* sha */
+ memcpy(&sip, arpptr, sizeof(sip));
+ arpptr += sizeof(sip);
+ arpptr += dev->addr_len; /* tha */
+ memcpy(&tip, arpptr, sizeof(tip));
+
+ if (ipv4_is_loopback(tip) ||
+ ipv4_is_multicast(tip))
+ return;
+
+ n = neigh_lookup(&arp_tbl, &tip, dev);
+ if (n) {
+ struct net_bridge_fdb_entry *f;
+
+ if (!(n->nud_state & NUD_VALID)) {
+ neigh_release(n);
+ return;
+ }
+
+ f = __br_fdb_get(br, n->ha, vid);
+ if (f)
+ arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
+ sha, n->ha, sha);
+
+ neigh_release(n);
+ }
+}
+
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct sk_buff *skb)
{
dst = NULL;
if (is_broadcast_ether_addr(dest)) {
+ if (p->flags & BR_PROXYARP &&
+ skb->protocol == htons(ETH_P_ARP))
+ br_do_proxy_arp(skb, br, vid);
+
skb2 = skb;
unicast = false;
} else if (is_multicast_ether_addr(dest)) {
nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
- nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)))
+ nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) ||
+ nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)))
return -EMSGSIZE;
return 0;
br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
+ br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
if (tb[IFLA_BRPORT_COST]) {
err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
#define BR_FLOOD 0x00000040
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
#define BR_PROMISC 0x00000080
+#define BR_PROXYARP 0x00000100
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
struct bridge_mcast_own_query ip4_own_query;
BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
BRPORT_ATTR_FLAG(learning, BR_LEARNING);
BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
+BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
&brport_attr_multicast_router,
&brport_attr_multicast_fast_leave,
#endif
+ &brport_attr_proxyarp,
NULL
};
copylen = len;
}
- ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, copylen);
+ ret = skb_copy_datagram_msg(skb, 0, m, copylen);
if (ret)
goto out_free;
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
+#include <linux/uio.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
EXPORT_SYMBOL(skb_copy_datagram_iovec);
/**
- * skb_copy_datagram_const_iovec - Copy a datagram to an iovec.
+ * skb_copy_datagram_iter - Copy a datagram to an iovec iterator.
* @skb: buffer to copy
* @offset: offset in the buffer to start copying from
- * @to: io vector to copy to
- * @to_offset: offset in the io vector to start copying to
+ * @to: iovec iterator to copy to
* @len: amount of data to copy from buffer to iovec
- *
- * Returns 0 or -EFAULT.
- * Note: the iovec is not modified during the copy.
*/
-int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset,
- const struct iovec *to, int to_offset,
- int len)
+int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
+ struct iov_iter *to, int len)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
+ trace_skb_copy_datagram_iovec(skb, len);
+
/* Copy header. */
if (copy > 0) {
if (copy > len)
copy = len;
- if (memcpy_toiovecend(to, skb->data + offset, to_offset, copy))
- goto fault;
+ if (copy_to_iter(skb->data + offset, copy, to) != copy)
+ goto short_copy;
if ((len -= copy) == 0)
return 0;
offset += copy;
- to_offset += copy;
}
/* Copy paged appendix. Hmm... why does this look so complicated? */
end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
- int err;
- u8 *vaddr;
- struct page *page = skb_frag_page(frag);
-
if (copy > len)
copy = len;
- vaddr = kmap(page);
- err = memcpy_toiovecend(to, vaddr + frag->page_offset +
- offset - start, to_offset, copy);
- kunmap(page);
- if (err)
- goto fault;
+ if (copy_page_to_iter(skb_frag_page(frag),
+ frag->page_offset + offset -
+ start, copy, to) != copy)
+ goto short_copy;
if (!(len -= copy))
return 0;
offset += copy;
- to_offset += copy;
}
start = end;
}
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_copy_datagram_const_iovec(frag_iter,
- offset - start,
- to, to_offset,
- copy))
+ if (skb_copy_datagram_iter(frag_iter, offset - start,
+ to, copy))
goto fault;
if ((len -= copy) == 0)
return 0;
offset += copy;
- to_offset += copy;
}
start = end;
}
if (!len)
return 0;
+ /* This is not really a user copy fault, but rather someone
+ * gave us a bogus length on the skb. We should probably
+ * print a warning here as it may indicate a kernel bug.
+ */
+
fault:
return -EFAULT;
+
+short_copy:
+ if (iov_iter_count(to))
+ goto fault;
+
+ return 0;
}
-EXPORT_SYMBOL(skb_copy_datagram_const_iovec);
+EXPORT_SYMBOL(skb_copy_datagram_iter);
/**
* skb_copy_datagram_from_iovec - Copy a datagram from an iovec.
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <net/ip.h>
+#include <net/mpls.h>
#include <linux/ipv6.h>
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/vmalloc.h>
#include <linux/if_macvlan.h>
#include <linux/errqueue.h>
+#include <linux/hrtimer.h>
#include "net-sysfs.h"
*/
void dev_disable_lro(struct net_device *dev)
{
- /*
- * If we're trying to disable lro on a vlan device
- * use the underlying physical device instead
- */
- if (is_vlan_dev(dev))
- dev = vlan_dev_real_dev(dev);
-
- /* the same for macvlan devices */
- if (netif_is_macvlan(dev))
- dev = macvlan_dev_real_dev(dev);
+ struct net_device *lower_dev;
+ struct list_head *iter;
dev->wanted_features &= ~NETIF_F_LRO;
netdev_update_features(dev);
if (unlikely(dev->features & NETIF_F_LRO))
netdev_WARN(dev, "failed to disable LRO!\n");
+
+ netdev_for_each_lower_dev(dev, lower_dev, iter)
+ dev_disable_lro(lower_dev);
}
EXPORT_SYMBOL(dev_disable_lro);
netdev_features_t features,
__be16 type)
{
- if (type == htons(ETH_P_MPLS_UC) || type == htons(ETH_P_MPLS_MC))
+ if (eth_p_mpls(type))
features &= skb->dev->mpls_features;
return features;
local_irq_enable();
}
+static bool sd_has_rps_ipi_waiting(struct softnet_data *sd)
+{
+#ifdef CONFIG_RPS
+ return sd->rps_ipi_list != NULL;
+#else
+ return false;
+#endif
+}
+
static int process_backlog(struct napi_struct *napi, int quota)
{
int work = 0;
struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
-#ifdef CONFIG_RPS
/* Check if we have pending ipi, its better to send them now,
* not waiting net_rx_action() end.
*/
- if (sd->rps_ipi_list) {
+ if (sd_has_rps_ipi_waiting(sd)) {
local_irq_disable();
net_rps_action_and_irq_enable(sd);
}
-#endif
+
napi->weight = weight_p;
local_irq_disable();
while (1) {
* We can use a plain write instead of clear_bit(),
* and we dont need an smp_mb() memory barrier.
*/
- list_del(&napi->poll_list);
napi->state = 0;
rps_unlock(sd);
* __napi_schedule - schedule for receive
* @n: entry to schedule
*
- * The entry's receive function will be scheduled to run
+ * The entry's receive function will be scheduled to run.
+ * Consider using __napi_schedule_irqoff() if hard irqs are masked.
*/
void __napi_schedule(struct napi_struct *n)
{
}
EXPORT_SYMBOL(__napi_schedule);
+/**
+ * __napi_schedule_irqoff - schedule for receive
+ * @n: entry to schedule
+ *
+ * Variant of __napi_schedule() assuming hard irqs are masked
+ */
+void __napi_schedule_irqoff(struct napi_struct *n)
+{
+ ____napi_schedule(this_cpu_ptr(&softnet_data), n);
+}
+EXPORT_SYMBOL(__napi_schedule_irqoff);
+
void __napi_complete(struct napi_struct *n)
{
BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
- BUG_ON(n->gro_list);
- list_del(&n->poll_list);
+ list_del_init(&n->poll_list);
smp_mb__before_atomic();
clear_bit(NAPI_STATE_SCHED, &n->state);
}
EXPORT_SYMBOL(__napi_complete);
-void napi_complete(struct napi_struct *n)
+void napi_complete_done(struct napi_struct *n, int work_done)
{
unsigned long flags;
if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
return;
- napi_gro_flush(n, false);
- local_irq_save(flags);
- __napi_complete(n);
- local_irq_restore(flags);
+ if (n->gro_list) {
+ unsigned long timeout = 0;
+
+ if (work_done)
+ timeout = n->dev->gro_flush_timeout;
+
+ if (timeout)
+ hrtimer_start(&n->timer, ns_to_ktime(timeout),
+ HRTIMER_MODE_REL_PINNED);
+ else
+ napi_gro_flush(n, false);
+ }
+ if (likely(list_empty(&n->poll_list))) {
+ WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state));
+ } else {
+ /* If n->poll_list is not empty, we need to mask irqs */
+ local_irq_save(flags);
+ __napi_complete(n);
+ local_irq_restore(flags);
+ }
}
-EXPORT_SYMBOL(napi_complete);
+EXPORT_SYMBOL(napi_complete_done);
/* must be called under rcu_read_lock(), as we dont take a reference */
struct napi_struct *napi_by_id(unsigned int napi_id)
}
EXPORT_SYMBOL_GPL(napi_hash_del);
+static enum hrtimer_restart napi_watchdog(struct hrtimer *timer)
+{
+ struct napi_struct *napi;
+
+ napi = container_of(timer, struct napi_struct, timer);
+ if (napi->gro_list)
+ napi_schedule(napi);
+
+ return HRTIMER_NORESTART;
+}
+
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
INIT_LIST_HEAD(&napi->poll_list);
+ hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+ napi->timer.function = napi_watchdog;
napi->gro_count = 0;
napi->gro_list = NULL;
napi->skb = NULL;
}
EXPORT_SYMBOL(netif_napi_add);
+void napi_disable(struct napi_struct *n)
+{
+ might_sleep();
+ set_bit(NAPI_STATE_DISABLE, &n->state);
+
+ while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
+ msleep(1);
+
+ hrtimer_cancel(&n->timer);
+
+ clear_bit(NAPI_STATE_DISABLE, &n->state);
+}
+EXPORT_SYMBOL(napi_disable);
+
void netif_napi_del(struct napi_struct *napi)
{
list_del_init(&napi->dev_list);
struct softnet_data *sd = this_cpu_ptr(&softnet_data);
unsigned long time_limit = jiffies + 2;
int budget = netdev_budget;
+ LIST_HEAD(list);
+ LIST_HEAD(repoll);
void *have;
local_irq_disable();
+ list_splice_init(&sd->poll_list, &list);
+ local_irq_enable();
- while (!list_empty(&sd->poll_list)) {
+ while (!list_empty(&list)) {
struct napi_struct *n;
int work, weight;
- /* If softirq window is exhuasted then punt.
+ /* If softirq window is exhausted then punt.
* Allow this to run for 2 jiffies since which will allow
* an average latency of 1.5/HZ.
*/
if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))
goto softnet_break;
- local_irq_enable();
- /* Even though interrupts have been re-enabled, this
- * access is safe because interrupts can only add new
- * entries to the tail of this list, and only ->poll()
- * calls can remove this head entry from the list.
- */
- n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list);
+ n = list_first_entry(&list, struct napi_struct, poll_list);
+ list_del_init(&n->poll_list);
have = netpoll_poll_lock(n);
budget -= work;
- local_irq_disable();
-
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
* still "owns" the NAPI instance and therefore can
*/
if (unlikely(work == weight)) {
if (unlikely(napi_disable_pending(n))) {
- local_irq_enable();
napi_complete(n);
- local_irq_disable();
} else {
if (n->gro_list) {
/* flush too old packets
* If HZ < 1000, flush all packets.
*/
- local_irq_enable();
napi_gro_flush(n, HZ >= 1000);
- local_irq_disable();
}
- list_move_tail(&n->poll_list, &sd->poll_list);
+ list_add_tail(&n->poll_list, &repoll);
}
}
netpoll_poll_unlock(have);
}
+
+ if (!sd_has_rps_ipi_waiting(sd) &&
+ list_empty(&list) &&
+ list_empty(&repoll))
+ return;
out:
+ local_irq_disable();
+
+ list_splice_tail_init(&sd->poll_list, &list);
+ list_splice_tail(&repoll, &list);
+ list_splice(&list, &sd->poll_list);
+ if (!list_empty(&sd->poll_list))
+ __raise_softirq_irqoff(NET_RX_SOFTIRQ);
+
net_rps_action_and_irq_enable(sd);
return;
softnet_break:
sd->time_squeeze++;
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
goto out;
}
[NETIF_F_GSO_IPIP_BIT] = "tx-ipip-segmentation",
[NETIF_F_GSO_SIT_BIT] = "tx-sit-segmentation",
[NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
- [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation",
[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp",
static void neigh_update_notify(struct neighbour *neigh);
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
-static struct neigh_table *neigh_tables;
#ifdef CONFIG_PROC_FS
static const struct file_operations neigh_stat_seq_fops;
#endif
the most complicated procedure, which we allow is dev->hard_header.
It is supposed, that dev->hard_header is simplistic and does
not make callbacks to neighbour tables.
-
- The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
- list of neighbour tables. This list is used only in process context,
*/
-static DEFINE_RWLOCK(neigh_tbl_lock);
-
static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
{
kfree_skb(skb);
if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
struct neigh_parms *p;
tbl->last_rand = jiffies;
- for (p = &tbl->parms; p; p = p->next)
+ list_for_each_entry(p, &tbl->parms_list, list)
p->reachable_time =
neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
}
{
struct neigh_parms *p;
- for (p = &tbl->parms; p; p = p->next) {
+ list_for_each_entry(p, &tbl->parms_list, list) {
if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
(!p->dev && !ifindex && net_eq(net, &init_net)))
return p;
}
write_lock_bh(&tbl->lock);
- p->next = tbl->parms.next;
- tbl->parms.next = p;
+ list_add(&p->list, &tbl->parms.list);
write_unlock_bh(&tbl->lock);
neigh_parms_data_state_cleanall(p);
void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
{
- struct neigh_parms **p;
-
if (!parms || parms == &tbl->parms)
return;
write_lock_bh(&tbl->lock);
- for (p = &tbl->parms.next; *p; p = &(*p)->next) {
- if (*p == parms) {
- *p = parms->next;
- parms->dead = 1;
- write_unlock_bh(&tbl->lock);
- if (parms->dev)
- dev_put(parms->dev);
- call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
- return;
- }
- }
+ list_del(&parms->list);
+ parms->dead = 1;
write_unlock_bh(&tbl->lock);
- neigh_dbg(1, "%s: not found\n", __func__);
+ if (parms->dev)
+ dev_put(parms->dev);
+ call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
}
EXPORT_SYMBOL(neigh_parms_release);
static struct lock_class_key neigh_table_proxy_queue_class;
-static void neigh_table_init_no_netlink(struct neigh_table *tbl)
+static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
+
+void neigh_table_init(int index, struct neigh_table *tbl)
{
unsigned long now = jiffies;
unsigned long phsize;
+ INIT_LIST_HEAD(&tbl->parms_list);
+ list_add(&tbl->parms.list, &tbl->parms_list);
write_pnet(&tbl->parms.net, &init_net);
atomic_set(&tbl->parms.refcnt, 1);
tbl->parms.reachable_time =
tbl->last_flush = now;
tbl->last_rand = now + tbl->parms.reachable_time * 20;
-}
-
-void neigh_table_init(struct neigh_table *tbl)
-{
- struct neigh_table *tmp;
-
- neigh_table_init_no_netlink(tbl);
- write_lock(&neigh_tbl_lock);
- for (tmp = neigh_tables; tmp; tmp = tmp->next) {
- if (tmp->family == tbl->family)
- break;
- }
- tbl->next = neigh_tables;
- neigh_tables = tbl;
- write_unlock(&neigh_tbl_lock);
- if (unlikely(tmp)) {
- pr_err("Registering multiple tables for family %d\n",
- tbl->family);
- dump_stack();
- }
+ neigh_tables[index] = tbl;
}
EXPORT_SYMBOL(neigh_table_init);
-int neigh_table_clear(struct neigh_table *tbl)
+int neigh_table_clear(int index, struct neigh_table *tbl)
{
- struct neigh_table **tp;
-
+ neigh_tables[index] = NULL;
/* It is not clean... Fix it to unload IPv6 module safely */
cancel_delayed_work_sync(&tbl->gc_work);
del_timer_sync(&tbl->proxy_timer);
neigh_ifdown(tbl, NULL);
if (atomic_read(&tbl->entries))
pr_crit("neighbour leakage\n");
- write_lock(&neigh_tbl_lock);
- for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
- if (*tp == tbl) {
- *tp = tbl->next;
- break;
- }
- }
- write_unlock(&neigh_tbl_lock);
call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
neigh_hash_free_rcu);
}
EXPORT_SYMBOL(neigh_table_clear);
+static struct neigh_table *neigh_find_table(int family)
+{
+ struct neigh_table *tbl = NULL;
+
+ switch (family) {
+ case AF_INET:
+ tbl = neigh_tables[NEIGH_ARP_TABLE];
+ break;
+ case AF_INET6:
+ tbl = neigh_tables[NEIGH_ND_TABLE];
+ break;
+ case AF_DECnet:
+ tbl = neigh_tables[NEIGH_DN_TABLE];
+ break;
+ }
+
+ return tbl;
+}
+
static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
struct nlattr *dst_attr;
struct neigh_table *tbl;
+ struct neighbour *neigh;
struct net_device *dev = NULL;
int err = -EINVAL;
}
}
- read_lock(&neigh_tbl_lock);
- for (tbl = neigh_tables; tbl; tbl = tbl->next) {
- struct neighbour *neigh;
+ tbl = neigh_find_table(ndm->ndm_family);
+ if (tbl == NULL)
+ return -EAFNOSUPPORT;
- if (tbl->family != ndm->ndm_family)
- continue;
- read_unlock(&neigh_tbl_lock);
-
- if (nla_len(dst_attr) < tbl->key_len)
- goto out;
-
- if (ndm->ndm_flags & NTF_PROXY) {
- err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
- goto out;
- }
+ if (nla_len(dst_attr) < tbl->key_len)
+ goto out;
- if (dev == NULL)
- goto out;
+ if (ndm->ndm_flags & NTF_PROXY) {
+ err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
+ goto out;
+ }
- neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
- if (neigh == NULL) {
- err = -ENOENT;
- goto out;
- }
+ if (dev == NULL)
+ goto out;
- err = neigh_update(neigh, NULL, NUD_FAILED,
- NEIGH_UPDATE_F_OVERRIDE |
- NEIGH_UPDATE_F_ADMIN);
- neigh_release(neigh);
+ neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
+ if (neigh == NULL) {
+ err = -ENOENT;
goto out;
}
- read_unlock(&neigh_tbl_lock);
- err = -EAFNOSUPPORT;
+
+ err = neigh_update(neigh, NULL, NUD_FAILED,
+ NEIGH_UPDATE_F_OVERRIDE |
+ NEIGH_UPDATE_F_ADMIN);
+ neigh_release(neigh);
out:
return err;
static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
+ int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
struct nlattr *tb[NDA_MAX+1];
struct neigh_table *tbl;
struct net_device *dev = NULL;
+ struct neighbour *neigh;
+ void *dst, *lladdr;
int err;
ASSERT_RTNL();
goto out;
}
- read_lock(&neigh_tbl_lock);
- for (tbl = neigh_tables; tbl; tbl = tbl->next) {
- int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
- struct neighbour *neigh;
- void *dst, *lladdr;
+ tbl = neigh_find_table(ndm->ndm_family);
+ if (tbl == NULL)
+ return -EAFNOSUPPORT;
- if (tbl->family != ndm->ndm_family)
- continue;
- read_unlock(&neigh_tbl_lock);
+ if (nla_len(tb[NDA_DST]) < tbl->key_len)
+ goto out;
+ dst = nla_data(tb[NDA_DST]);
+ lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
- if (nla_len(tb[NDA_DST]) < tbl->key_len)
- goto out;
- dst = nla_data(tb[NDA_DST]);
- lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
+ if (ndm->ndm_flags & NTF_PROXY) {
+ struct pneigh_entry *pn;
- if (ndm->ndm_flags & NTF_PROXY) {
- struct pneigh_entry *pn;
+ err = -ENOBUFS;
+ pn = pneigh_lookup(tbl, net, dst, dev, 1);
+ if (pn) {
+ pn->flags = ndm->ndm_flags;
+ err = 0;
+ }
+ goto out;
+ }
- err = -ENOBUFS;
- pn = pneigh_lookup(tbl, net, dst, dev, 1);
- if (pn) {
- pn->flags = ndm->ndm_flags;
- err = 0;
- }
+ if (dev == NULL)
+ goto out;
+
+ neigh = neigh_lookup(tbl, dst, dev);
+ if (neigh == NULL) {
+ if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
+ err = -ENOENT;
goto out;
}
- if (dev == NULL)
+ neigh = __neigh_lookup_errno(tbl, dst, dev);
+ if (IS_ERR(neigh)) {
+ err = PTR_ERR(neigh);
+ goto out;
+ }
+ } else {
+ if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ err = -EEXIST;
+ neigh_release(neigh);
goto out;
-
- neigh = neigh_lookup(tbl, dst, dev);
- if (neigh == NULL) {
- if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
- err = -ENOENT;
- goto out;
- }
-
- neigh = __neigh_lookup_errno(tbl, dst, dev);
- if (IS_ERR(neigh)) {
- err = PTR_ERR(neigh);
- goto out;
- }
- } else {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
- err = -EEXIST;
- neigh_release(neigh);
- goto out;
- }
-
- if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
- flags &= ~NEIGH_UPDATE_F_OVERRIDE;
}
- if (ndm->ndm_flags & NTF_USE) {
- neigh_event_send(neigh, NULL);
- err = 0;
- } else
- err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
- neigh_release(neigh);
- goto out;
+ if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
+ flags &= ~NEIGH_UPDATE_F_OVERRIDE;
}
- read_unlock(&neigh_tbl_lock);
- err = -EAFNOSUPPORT;
+ if (ndm->ndm_flags & NTF_USE) {
+ neigh_event_send(neigh, NULL);
+ err = 0;
+ } else
+ err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
+ neigh_release(neigh);
+
out:
return err;
}
struct neigh_table *tbl;
struct ndtmsg *ndtmsg;
struct nlattr *tb[NDTA_MAX+1];
- int err;
+ bool found = false;
+ int err, tidx;
err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
nl_neightbl_policy);
}
ndtmsg = nlmsg_data(nlh);
- read_lock(&neigh_tbl_lock);
- for (tbl = neigh_tables; tbl; tbl = tbl->next) {
+
+ for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
+ tbl = neigh_tables[tidx];
+ if (!tbl)
+ continue;
if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
continue;
-
- if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
+ if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
+ found = true;
break;
+ }
}
- if (tbl == NULL) {
- err = -ENOENT;
- goto errout_locked;
- }
+ if (!found)
+ return -ENOENT;
/*
* We acquire tbl->lock to be nice to the periodic timers and
errout_tbl_lock:
write_unlock_bh(&tbl->lock);
-errout_locked:
- read_unlock(&neigh_tbl_lock);
errout:
return err;
}
family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
- read_lock(&neigh_tbl_lock);
- for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
+ for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
struct neigh_parms *p;
+ tbl = neigh_tables[tidx];
+ if (!tbl)
+ continue;
+
if (tidx < tbl_skip || (family && tbl->family != family))
continue;
NLM_F_MULTI) <= 0)
break;
- for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
+ nidx = 0;
+ p = list_next_entry(&tbl->parms, list);
+ list_for_each_entry_from(p, &tbl->parms_list, list) {
if (!net_eq(neigh_parms_net(p), net))
continue;
neigh_skip = 0;
}
out:
- read_unlock(&neigh_tbl_lock);
cb->args[0] = tidx;
cb->args[1] = nidx;
int proxy = 0;
int err;
- read_lock(&neigh_tbl_lock);
family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
/* check for full ndmsg structure presence, family member is
s_t = cb->args[0];
- for (tbl = neigh_tables, t = 0; tbl;
- tbl = tbl->next, t++) {
+ for (t = 0; t < NEIGH_NR_TABLES; t++) {
+ tbl = neigh_tables[t];
+
+ if (!tbl)
+ continue;
if (t < s_t || (family && tbl->family != family))
continue;
if (t > s_t)
if (err < 0)
break;
}
- read_unlock(&neigh_tbl_lock);
cb->args[0] = t;
return skb->len;
}
NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong);
+static int change_gro_flush_timeout(struct net_device *dev, unsigned long val)
+{
+ dev->gro_flush_timeout = val;
+ return 0;
+}
+
+static ssize_t gro_flush_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ return netdev_store(dev, attr, buf, len, change_gro_flush_timeout);
+}
+NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong);
+
static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len)
{
&dev_attr_mtu.attr,
&dev_attr_flags.attr,
&dev_attr_tx_queue_len.attr,
+ &dev_attr_gro_flush_timeout.attr,
&dev_attr_phys_port_id.attr,
NULL,
};
if (nskb->len == len + doffset)
goto perform_csum_check;
- if (!sg) {
+ if (!sg && !nskb->remcsum_offload) {
nskb->ip_summed = CHECKSUM_NONE;
nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
skb_put(nskb, len),
nskb->truesize += nskb->data_len;
perform_csum_check:
- if (!csum) {
+ if (!csum && !nskb->remcsum_offload) {
nskb->csum = skb_checksum(nskb, doffset,
nskb->len - doffset, 0);
nskb->ip_summed = CHECKSUM_NONE;
* (see validate_xmit_skb_list() for example)
*/
segs->prev = tail;
+
+ /* Following permits correct backpressure, for protocols
+ * using skb_set_owner_w().
+ * Idea is to tranfert ownership from head_skb to last segment.
+ */
+ if (head_skb->destructor == sock_wfree) {
+ swap(tail->truesize, head_skb->truesize);
+ swap(tail->destructor, head_skb->destructor);
+ swap(tail->sk, head_skb->sk);
+ }
return segs;
err:
v.val = sk->sk_max_pacing_rate;
break;
+ case SO_INCOMING_CPU:
+ v.val = sk->sk_incoming_cpu;
+ break;
+
default:
return -ENOPROTOOPT;
}
newsk->sk_err = 0;
newsk->sk_priority = 0;
+ newsk->sk_incoming_cpu = raw_smp_processor_id();
/*
* Before updating sk_refcnt, we must commit prior changes to memory
* (Documentation/RCU/rculist_nulls.txt for details)
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free_skb;
static int one = 1;
static int ushort_max = USHRT_MAX;
+static int net_msg_warn; /* Unused, but still a sysctl */
+
#ifdef CONFIG_RPS
static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
#include <asm/byteorder.h>
#include <asm/uaccess.h>
-int net_msg_warn __read_mostly = 1;
-EXPORT_SYMBOL(net_msg_warn);
-
DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
/*
* All net warning printk()s should be guarded by this function.
/*
* DCCP - specific warning and debugging macros.
*/
-#define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \
- __func__, ##a)
+#define DCCP_WARN(fmt, ...) \
+ net_warn_ratelimited("%s: " fmt, __func__, ##__VA_ARGS__)
#define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d/%s()\n", ##a, \
__FILE__, __LINE__, __func__)
#define DCCP_BUG(a...) do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0)
else if (len < skb->len)
msg->msg_flags |= MSG_TRUNC;
- if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
+ if (skb_copy_datagram_msg(skb, 0, msg, len)) {
/* Exception. Bailout! */
len = -EFAULT;
break;
void __init dn_neigh_init(void)
{
- neigh_table_init(&dn_neigh_table);
+ neigh_table_init(NEIGH_DN_TABLE, &dn_neigh_table);
proc_create("decnet_neigh", S_IRUGO, init_net.proc_net,
&dn_neigh_seq_fops);
}
void __exit dn_neigh_cleanup(void)
{
remove_proc_entry("decnet_neigh", init_net.proc_net);
- neigh_table_clear(&dn_neigh_table);
+ neigh_table_clear(NEIGH_DN_TABLE, &dn_neigh_table);
}
if NET_DSA
+config NET_DSA_HWMON
+ bool "Distributed Switch Architecture HWMON support"
+ default y
+ depends on HWMON && !(NET_DSA=y && HWMON=m)
+ ---help---
+ Say Y if you want to expose thermal sensor data on switches supported
+ by the Distributed Switch Architecture.
+
+ Some of those switches contain thermal sensors. This data is available
+ via the hwmon sysfs interface and exposes the onboard sensors.
+
# tagging formats
config NET_DSA_TAG_BRCM
bool
* (at your option) any later version.
*/
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
+#include <linux/sysfs.h>
#include "dsa_priv.h"
char dsa_driver_version[] = "0.1";
return ret;
}
+/* hwmon support ************************************************************/
+
+#ifdef CONFIG_NET_DSA_HWMON
+
+static ssize_t temp1_input_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+ int temp, ret;
+
+ ret = ds->drv->get_temp(ds, &temp);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp * 1000);
+}
+static DEVICE_ATTR_RO(temp1_input);
+
+static ssize_t temp1_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+ int temp, ret;
+
+ ret = ds->drv->get_temp_limit(ds, &temp);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t temp1_max_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+ int temp, ret;
+
+ ret = kstrtoint(buf, 0, &temp);
+ if (ret < 0)
+ return ret;
+
+ ret = ds->drv->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR(temp1_max, S_IRUGO, temp1_max_show, temp1_max_store);
+
+static ssize_t temp1_max_alarm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+ bool alarm;
+ int ret;
+
+ ret = ds->drv->get_temp_alarm(ds, &alarm);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", alarm);
+}
+static DEVICE_ATTR_RO(temp1_max_alarm);
+
+static struct attribute *dsa_hwmon_attrs[] = {
+ &dev_attr_temp1_input.attr, /* 0 */
+ &dev_attr_temp1_max.attr, /* 1 */
+ &dev_attr_temp1_max_alarm.attr, /* 2 */
+ NULL
+};
+
+static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct dsa_switch *ds = dev_get_drvdata(dev);
+ struct dsa_switch_driver *drv = ds->drv;
+ umode_t mode = attr->mode;
+
+ if (index == 1) {
+ if (!drv->get_temp_limit)
+ mode = 0;
+ else if (drv->set_temp_limit)
+ mode |= S_IWUSR;
+ } else if (index == 2 && !drv->get_temp_alarm) {
+ mode = 0;
+ }
+ return mode;
+}
+
+static const struct attribute_group dsa_hwmon_group = {
+ .attrs = dsa_hwmon_attrs,
+ .is_visible = dsa_hwmon_attrs_visible,
+};
+__ATTRIBUTE_GROUPS(dsa_hwmon);
+
+#endif /* CONFIG_NET_DSA_HWMON */
/* basic switch operations **************************************************/
static struct dsa_switch *
*/
drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
if (drv == NULL) {
- printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
- dst->master_netdev->name, index);
+ netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n",
+ index);
return ERR_PTR(-EINVAL);
}
- printk(KERN_INFO "%s[%d]: detected a %s switch\n",
- dst->master_netdev->name, index, name);
+ netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n",
+ index, name);
/*
if (!strcmp(name, "cpu")) {
if (dst->cpu_switch != -1) {
- printk(KERN_ERR "multiple cpu ports?!\n");
+ netdev_err(dst->master_netdev,
+ "multiple cpu ports?!\n");
ret = -EINVAL;
goto out;
}
slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
if (slave_dev == NULL) {
- printk(KERN_ERR "%s[%d]: can't create dsa "
- "slave device for port %d(%s)\n",
- dst->master_netdev->name,
- index, i, pd->port_names[i]);
+ netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
+ index, i, pd->port_names[i]);
continue;
}
ds->ports[i] = slave_dev;
}
+#ifdef CONFIG_NET_DSA_HWMON
+ /* If the switch provides a temperature sensor,
+ * register with hardware monitoring subsystem.
+ * Treat registration error as non-fatal and ignore it.
+ */
+ if (drv->get_temp) {
+ const char *netname = netdev_name(dst->master_netdev);
+ char hname[IFNAMSIZ + 1];
+ int i, j;
+
+ /* Create valid hwmon 'name' attribute */
+ for (i = j = 0; i < IFNAMSIZ && netname[i]; i++) {
+ if (isalnum(netname[i]))
+ hname[j++] = netname[i];
+ }
+ hname[j] = '\0';
+ scnprintf(ds->hwmon_name, sizeof(ds->hwmon_name), "%s_dsa%d",
+ hname, index);
+ ds->hwmon_dev = hwmon_device_register_with_groups(NULL,
+ ds->hwmon_name, ds, dsa_hwmon_groups);
+ if (IS_ERR(ds->hwmon_dev))
+ ds->hwmon_dev = NULL;
+ }
+#endif /* CONFIG_NET_DSA_HWMON */
+
return ds;
out_free:
static void dsa_switch_destroy(struct dsa_switch *ds)
{
+#ifdef CONFIG_NET_DSA_HWMON
+ if (ds->hwmon_dev)
+ hwmon_device_unregister(ds->hwmon_dev);
+#endif
}
#ifdef CONFIG_PM_SLEEP
const char *port_name;
int chip_index, port_index;
const unsigned int *sw_addr, *port_reg;
+ u32 eeprom_len;
int ret;
mdio = of_parse_phandle(np, "dsa,mii-bus", 0);
if (cd->sw_addr > PHY_MAX_ADDR)
continue;
+ if (!of_property_read_u32(np, "eeprom-length", &eeprom_len))
+ cd->eeprom_len = eeprom_len;
+
for_each_available_child_of_node(child, port) {
port_reg = of_get_property(port, "reg", NULL);
if (!port_reg)
static int dsa_probe(struct platform_device *pdev)
{
- static int dsa_version_printed;
struct dsa_platform_data *pd = pdev->dev.platform_data;
struct net_device *dev;
struct dsa_switch_tree *dst;
int i, ret;
- if (!dsa_version_printed++)
- printk(KERN_NOTICE "Distributed Switch Architecture "
- "driver version %s\n", dsa_driver_version);
+ pr_notice_once("Distributed Switch Architecture driver version %s\n",
+ dsa_driver_version);
if (pdev->dev.of_node) {
ret = dsa_of_probe(pdev);
ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev);
if (IS_ERR(ds)) {
- printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
- "instance (error %ld)\n", dev->name, i,
- PTR_ERR(ds));
+ netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n",
+ i, PTR_ERR(ds));
continue;
}
strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info));
}
+static int dsa_slave_get_regs_len(struct net_device *dev)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->drv->get_regs_len)
+ return ds->drv->get_regs_len(ds, p->port);
+
+ return -EOPNOTSUPP;
+}
+
+static void
+dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->drv->get_regs)
+ ds->drv->get_regs(ds, p->port, regs, _p);
+}
+
static int dsa_slave_nway_reset(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
return -EOPNOTSUPP;
}
+static int dsa_slave_get_eeprom_len(struct net_device *dev)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->pd->eeprom_len)
+ return ds->pd->eeprom_len;
+
+ if (ds->drv->get_eeprom_len)
+ return ds->drv->get_eeprom_len(ds);
+
+ return 0;
+}
+
+static int dsa_slave_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->drv->get_eeprom)
+ return ds->drv->get_eeprom(ds, eeprom, data);
+
+ return -EOPNOTSUPP;
+}
+
+static int dsa_slave_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct dsa_slave_priv *p = netdev_priv(dev);
+ struct dsa_switch *ds = p->parent;
+
+ if (ds->drv->set_eeprom)
+ return ds->drv->set_eeprom(ds, eeprom, data);
+
+ return -EOPNOTSUPP;
+}
+
static void dsa_slave_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *data)
{
.get_settings = dsa_slave_get_settings,
.set_settings = dsa_slave_set_settings,
.get_drvinfo = dsa_slave_get_drvinfo,
+ .get_regs_len = dsa_slave_get_regs_len,
+ .get_regs = dsa_slave_get_regs,
.nway_reset = dsa_slave_nway_reset,
.get_link = dsa_slave_get_link,
+ .get_eeprom_len = dsa_slave_get_eeprom_len,
+ .get_eeprom = dsa_slave_get_eeprom,
+ .set_eeprom = dsa_slave_set_eeprom,
.get_strings = dsa_slave_get_strings,
.get_ethtool_stats = dsa_slave_get_ethtool_stats,
.get_sset_count = dsa_slave_get_sset_count,
*/
ret = of_phy_register_fixed_link(port_dn);
if (ret) {
- pr_err("failed to register fixed PHY\n");
+ netdev_err(slave_dev, "failed to register fixed PHY\n");
return;
}
phy_is_fixed = true;
phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
p->phy_interface);
} else {
- pr_info("attached PHY at address %d [%s]\n",
- p->phy->addr, p->phy->drv->name);
+ netdev_info(slave_dev, "attached PHY at address %d [%s]\n",
+ p->phy->addr, p->phy->drv->name);
}
}
ret = register_netdev(slave_dev);
if (ret) {
- printk(KERN_ERR "%s: error %d registering interface %s\n",
- master->name, ret, slave_dev->name);
+ netdev_err(master, "error %d registering interface %s\n",
+ ret, slave_dev->name);
free_netdev(slave_dev);
return NULL;
}
dsa_header[3] = 0x00;
}
- skb->protocol = htons(ETH_P_DSA);
-
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
edsa_header[7] = 0x00;
}
- skb->protocol = htons(ETH_P_EDSA);
-
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
trailer[2] = 0x10;
trailer[3] = 0x00;
- nskb->protocol = htons(ETH_P_TRAILER);
-
nskb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(nskb);
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
+#include <linux/ieee802154.h>
#include <net/af_ieee802154.h>
-#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
#include <net/6lowpan.h>
#include <net/ipv6.h>
#include "reassembly.h"
static LIST_HEAD(lowpan_devices);
+static int lowpan_open_count;
/* private device info */
struct lowpan_dev_info {
struct net_device *real_dev; /* real WPAN device ptr */
struct mutex dev_list_mtx; /* mutex for list ops */
- __be16 fragment_tag;
+ u16 fragment_tag;
};
struct lowpan_dev_record {
struct sk_buff *skb_cp;
int stat = NET_RX_SUCCESS;
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->pkt_type = PACKET_HOST;
+
rcu_read_lock();
list_for_each_entry_rcu(entry, &lowpan_devices, list)
if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
skb_cp = skb_copy(skb, GFP_ATOMIC);
if (!skb_cp) {
- stat = -ENOMEM;
- break;
+ kfree_skb(skb);
+ rcu_read_unlock();
+ return NET_RX_DROP;
}
skb_cp->dev = entry->ldev;
stat = netif_rx(skb_cp);
+ if (stat == NET_RX_DROP)
+ break;
}
rcu_read_unlock();
+ consume_skb(skb);
+
return stat;
}
-static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
+static int
+iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
{
u8 iphc0, iphc1;
struct ieee802154_addr_sa sa, da;
else
dap = &da.hwaddr;
- return lowpan_process_data(skb, skb->dev, sap, sa.addr_type,
- IEEE802154_ADDR_LEN, dap, da.addr_type,
- IEEE802154_ADDR_LEN, iphc0, iphc1,
- lowpan_give_skb_to_devices);
+ return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
+ IEEE802154_ADDR_LEN, dap, da.addr_type,
+ IEEE802154_ADDR_LEN, iphc0, iphc1);
drop:
kfree_skb(skb);
&master_hdr->source, size);
if (rc < 0) {
kfree_skb(frag);
- return ERR_PTR(-rc);
+ return ERR_PTR(rc);
}
} else {
frag = ERR_PTR(-ENOMEM);
dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
skb->mac_len;
- frag_tag = lowpan_dev_info(dev)->fragment_tag++;
+ frag_tag = htons(lowpan_dev_info(dev)->fragment_tag);
+ lowpan_dev_info(dev)->fragment_tag++;
frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
frag_hdr[1] = dgram_size & 0xff;
frag_len + skb_network_header_len(skb));
if (rc) {
pr_debug("%s unable to send FRAG1 packet (tag: %d)",
- __func__, frag_tag);
+ __func__, ntohs(frag_tag));
goto err;
}
frag_len);
if (rc) {
pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
- __func__, frag_tag, skb_offset);
+ __func__, ntohs(frag_tag), skb_offset);
goto err;
}
} while (skb_unprocessed > frag_cap);
if (!netif_running(dev))
goto drop_skb;
+ if (skb->pkt_type == PACKET_OTHERHOST)
+ goto drop_skb;
+
if (dev->type != ARPHRD_IEEE802154)
goto drop_skb;
/* check that it's our buffer */
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
- skb->protocol = htons(ETH_P_IPV6);
- skb->pkt_type = PACKET_HOST;
-
/* Pull off the 1-byte of 6lowpan header. */
skb_pull(skb, 1);
-
- ret = lowpan_give_skb_to_devices(skb, NULL);
- if (ret == NET_RX_DROP)
- goto drop;
+ return lowpan_give_skb_to_devices(skb, NULL);
} else {
switch (skb->data[0] & 0xe0) {
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
- ret = process_data(skb, &hdr);
- if (ret == NET_RX_DROP)
+ ret = iphc_decompress(skb, &hdr);
+ if (ret < 0)
goto drop;
- break;
+
+ return lowpan_give_skb_to_devices(skb, NULL);
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
if (ret == 1) {
- ret = process_data(skb, &hdr);
- if (ret == NET_RX_DROP)
+ ret = iphc_decompress(skb, &hdr);
+ if (ret < 0)
goto drop;
+
+ return lowpan_give_skb_to_devices(skb, NULL);
+ } else if (ret == -1) {
+ return NET_RX_DROP;
+ } else {
+ return NET_RX_SUCCESS;
}
- break;
case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
if (ret == 1) {
- ret = process_data(skb, &hdr);
- if (ret == NET_RX_DROP)
+ ret = iphc_decompress(skb, &hdr);
+ if (ret < 0)
goto drop;
+
+ return lowpan_give_skb_to_devices(skb, NULL);
+ } else if (ret == -1) {
+ return NET_RX_DROP;
+ } else {
+ return NET_RX_SUCCESS;
}
- break;
default:
break;
}
}
- return NET_RX_SUCCESS;
drop_skb:
kfree_skb(skb);
drop:
return NET_RX_DROP;
}
+static struct packet_type lowpan_packet_type = {
+ .type = htons(ETH_P_IEEE802154),
+ .func = lowpan_rcv,
+};
+
static int lowpan_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct net_device *real_dev;
struct lowpan_dev_record *entry;
+ int ret;
+
+ ASSERT_RTNL();
pr_debug("adding new link\n");
list_add_tail(&entry->list, &lowpan_devices);
mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
- register_netdevice(dev);
+ ret = register_netdevice(dev);
+ if (ret >= 0) {
+ if (!lowpan_open_count)
+ dev_add_pack(&lowpan_packet_type);
+ lowpan_open_count++;
+ }
- return 0;
+ return ret;
}
static void lowpan_dellink(struct net_device *dev, struct list_head *head)
ASSERT_RTNL();
+ lowpan_open_count--;
+ if (!lowpan_open_count)
+ dev_remove_pack(&lowpan_packet_type);
+
mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
if (entry->ldev == dev) {
.notifier_call = lowpan_device_event,
};
-static struct packet_type lowpan_packet_type = {
- .type = htons(ETH_P_IEEE802154),
- .func = lowpan_rcv,
-};
-
static int __init lowpan_init_module(void)
{
int err = 0;
if (err < 0)
goto out_frag;
- dev_add_pack(&lowpan_packet_type);
-
err = register_netdevice_notifier(&lowpan_dev_notifier);
if (err < 0)
goto out_pack;
return 0;
out_pack:
- dev_remove_pack(&lowpan_packet_type);
lowpan_netlink_fini();
out_frag:
lowpan_net_frag_exit();
{
lowpan_netlink_fini();
- dev_remove_pack(&lowpan_packet_type);
-
lowpan_net_frag_exit();
unregister_netdevice_notifier(&lowpan_dev_notifier);
obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o
ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o
-ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \
- header_ops.o
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \
+ header_ops.o sysfs.o
af_802154-y := af_ieee802154.o raw.o dgram.o
ccflags-y += -D__CHECK_ENDIAN__
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Maxim Gorbachyov <maxim.gorbachev@siemens.com>
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <net/cfg802154.h>
+
+#include "ieee802154.h"
+#include "sysfs.h"
+
+static DEFINE_MUTEX(wpan_phy_mutex);
+static int wpan_phy_idx;
+
+static int wpan_phy_match(struct device *dev, const void *data)
+{
+ return !strcmp(dev_name(dev), (const char *)data);
+}
+
+struct wpan_phy *wpan_phy_find(const char *str)
+{
+ struct device *dev;
+
+ if (WARN_ON(!str))
+ return NULL;
+
+ dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match);
+ if (!dev)
+ return NULL;
+
+ return container_of(dev, struct wpan_phy, dev);
+}
+EXPORT_SYMBOL(wpan_phy_find);
+
+struct wpan_phy_iter_data {
+ int (*fn)(struct wpan_phy *phy, void *data);
+ void *data;
+};
+
+static int wpan_phy_iter(struct device *dev, void *_data)
+{
+ struct wpan_phy_iter_data *wpid = _data;
+ struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
+
+ return wpid->fn(phy, wpid->data);
+}
+
+int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data),
+ void *data)
+{
+ struct wpan_phy_iter_data wpid = {
+ .fn = fn,
+ .data = data,
+ };
+
+ return class_for_each_device(&wpan_phy_class, NULL,
+ &wpid, wpan_phy_iter);
+}
+EXPORT_SYMBOL(wpan_phy_for_each);
+
+static int wpan_phy_idx_valid(int idx)
+{
+ return idx >= 0;
+}
+
+struct wpan_phy *wpan_phy_alloc(size_t priv_size)
+{
+ struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size,
+ GFP_KERNEL);
+
+ if (!phy)
+ goto out;
+ mutex_lock(&wpan_phy_mutex);
+ phy->idx = wpan_phy_idx++;
+ if (unlikely(!wpan_phy_idx_valid(phy->idx))) {
+ wpan_phy_idx--;
+ mutex_unlock(&wpan_phy_mutex);
+ kfree(phy);
+ goto out;
+ }
+ mutex_unlock(&wpan_phy_mutex);
+
+ mutex_init(&phy->pib_lock);
+
+ device_initialize(&phy->dev);
+ dev_set_name(&phy->dev, "wpan-phy%d", phy->idx);
+
+ phy->dev.class = &wpan_phy_class;
+
+ phy->current_channel = -1; /* not initialised */
+ phy->current_page = 0; /* for compatibility */
+
+ return phy;
+
+out:
+ return NULL;
+}
+EXPORT_SYMBOL(wpan_phy_alloc);
+
+int wpan_phy_register(struct wpan_phy *phy)
+{
+ return device_add(&phy->dev);
+}
+EXPORT_SYMBOL(wpan_phy_register);
+
+void wpan_phy_unregister(struct wpan_phy *phy)
+{
+ device_del(&phy->dev);
+}
+EXPORT_SYMBOL(wpan_phy_unregister);
+
+void wpan_phy_free(struct wpan_phy *phy)
+{
+ put_device(&phy->dev);
+}
+EXPORT_SYMBOL(wpan_phy_free);
+
+static int __init wpan_phy_class_init(void)
+{
+ int rc;
+
+ rc = wpan_phy_sysfs_init();
+ if (rc)
+ goto err;
+
+ rc = ieee802154_nl_init();
+ if (rc)
+ goto err_nl;
+
+ return 0;
+err_nl:
+ wpan_phy_sysfs_exit();
+err:
+ return rc;
+}
+subsys_initcall(wpan_phy_class_init);
+
+static void __exit wpan_phy_class_exit(void)
+{
+ ieee802154_nl_exit();
+ wpan_phy_sysfs_exit();
+}
+module_exit(wpan_phy_class_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("IEEE 802.15.4 configuration interface");
+MODULE_AUTHOR("Dmitry Eremin-Solenikov");
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
#include <linux/if_arp.h>
#include <linux/list.h>
#include <linux/slab.h>
+#include <linux/ieee802154.h>
#include <net/sock.h>
#include <net/af_ieee802154.h>
-#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
#include <asm/ioctls.h>
}
/* FIXME: skip headers if necessary ?! */
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
* Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
*/
+#include <linux/ieee802154.h>
+
#include <net/mac802154.h>
-#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
static int
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#ifndef IEEE_802154_LOCAL_H
#define IEEE_802154_LOCAL_H
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
+#include <linux/ieee802154.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/sock.h>
#include <linux/export.h>
#include <net/af_ieee802154.h>
#include <net/nl802154.h>
-#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
#include "ieee802154.h"
phy = ops->get_phy(dev);
- if ((!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
- (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
- (!phy->set_cca_ed_level &&
- info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) ||
- (!phy->set_csma_params &&
- (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
- info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
- info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])) ||
- (!phy->set_frame_retries &&
- info->attrs[IEEE802154_ATTR_FRAME_RETRIES])) {
- rc = -EOPNOTSUPP;
- goto out_phy;
- }
-
ops->get_mac_params(dev, ¶ms);
if (info->attrs[IEEE802154_ATTR_TXPOWER])
wpan_phy_put(phy);
dev_put(dev);
- return rc;
-out_phy:
- wpan_phy_put(phy);
+ return 0;
+
out:
dev_put(dev);
return rc;
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
#include <linux/if_arp.h>
#include <net/netlink.h>
#include <net/genetlink.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
#include <net/af_ieee802154.h>
#include <net/ieee802154_netdev.h>
#include <net/rtnetlink.h> /* for rtnl_{un,}lock */
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <linux/kernel.h>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
static const char lowpan_frags_cache_name[] = "lowpan-frags";
struct lowpan_frag_info {
- __be16 d_tag;
+ u16 d_tag;
u16 d_size;
u8 d_offset;
};
static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
struct sk_buff *prev, struct net_device *dev);
-static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size,
+static unsigned int lowpan_hash_frag(u16 tag, u16 d_size,
const struct ieee802154_addr *saddr,
const struct ieee802154_addr *daddr)
{
{
bool fail;
u8 pattern = 0, low = 0;
+ __be16 d_tag = 0;
fail = lowpan_fetch_skb(skb, &pattern, 1);
fail |= lowpan_fetch_skb(skb, &low, 1);
frag_info->d_size = (pattern & 7) << 8 | low;
- fail |= lowpan_fetch_skb(skb, &frag_info->d_tag, 2);
+ fail |= lowpan_fetch_skb(skb, &d_tag, 2);
+ frag_info->d_tag = ntohs(d_tag);
if (frag_type == LOWPAN_DISPATCH_FRAGN) {
fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1);
#include <net/inet_frag.h>
struct lowpan_create_arg {
- __be16 tag;
+ u16 tag;
u16 d_size;
const struct ieee802154_addr *src;
const struct ieee802154_addr *dst;
struct lowpan_frag_queue {
struct inet_frag_queue q;
- __be16 tag;
+ u16 tag;
u16 d_size;
struct ieee802154_addr saddr;
struct ieee802154_addr daddr;
--- /dev/null
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ *
+ * Based on: net/wireless/sysfs.c
+ */
+
+#include <linux/device.h>
+
+#include <net/cfg802154.h>
+
+#define MASTER_SHOW_COMPLEX(name, format_string, args...) \
+static ssize_t name ## _show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \
+ int ret; \
+ \
+ mutex_lock(&phy->pib_lock); \
+ ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \
+ mutex_unlock(&phy->pib_lock); \
+ return ret; \
+} \
+static DEVICE_ATTR_RO(name)
+
+#define MASTER_SHOW(field, format_string) \
+ MASTER_SHOW_COMPLEX(field, format_string, phy->field)
+
+MASTER_SHOW(current_channel, "%d");
+MASTER_SHOW(current_page, "%d");
+MASTER_SHOW(transmit_power, "%d +- 1 dB");
+MASTER_SHOW(cca_mode, "%d");
+
+static ssize_t channels_supported_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
+ int ret;
+ int i, len = 0;
+
+ mutex_lock(&phy->pib_lock);
+ for (i = 0; i < 32; i++) {
+ ret = snprintf(buf + len, PAGE_SIZE - len,
+ "%#09x\n", phy->channels_supported[i]);
+ if (ret < 0)
+ break;
+ len += ret;
+ }
+ mutex_unlock(&phy->pib_lock);
+ return len;
+}
+static DEVICE_ATTR_RO(channels_supported);
+
+static void wpan_phy_release(struct device *d)
+{
+ struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
+
+ kfree(phy);
+}
+
+static struct attribute *pmib_attrs[] = {
+ &dev_attr_current_channel.attr,
+ &dev_attr_current_page.attr,
+ &dev_attr_channels_supported.attr,
+ &dev_attr_transmit_power.attr,
+ &dev_attr_cca_mode.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(pmib);
+
+struct class wpan_phy_class = {
+ .name = "ieee802154",
+ .dev_release = wpan_phy_release,
+ .dev_groups = pmib_groups,
+};
+
+int wpan_phy_sysfs_init(void)
+{
+ return class_register(&wpan_phy_class);
+}
+
+void wpan_phy_sysfs_exit(void)
+{
+ class_unregister(&wpan_phy_class);
+}
--- /dev/null
+#ifndef __IEEE802154_SYSFS_H
+#define __IEEE802154_SYSFS_H
+
+int wpan_phy_sysfs_init(void);
+void wpan_phy_sysfs_exit(void);
+
+extern struct class wpan_phy_class;
+
+#endif /* __IEEE802154_SYSFS_H */
+++ /dev/null
-/*
- * Copyright (C) 2007, 2008, 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include <net/wpan-phy.h>
-
-#include "ieee802154.h"
-
-#define MASTER_SHOW_COMPLEX(name, format_string, args...) \
-static ssize_t name ## _show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \
- int ret; \
- \
- mutex_lock(&phy->pib_lock); \
- ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \
- mutex_unlock(&phy->pib_lock); \
- return ret; \
-} \
-static DEVICE_ATTR_RO(name);
-
-#define MASTER_SHOW(field, format_string) \
- MASTER_SHOW_COMPLEX(field, format_string, phy->field)
-
-MASTER_SHOW(current_channel, "%d");
-MASTER_SHOW(current_page, "%d");
-MASTER_SHOW(transmit_power, "%d +- 1 dB");
-MASTER_SHOW(cca_mode, "%d");
-
-static ssize_t channels_supported_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
- int ret;
- int i, len = 0;
-
- mutex_lock(&phy->pib_lock);
- for (i = 0; i < 32; i++) {
- ret = snprintf(buf + len, PAGE_SIZE - len,
- "%#09x\n", phy->channels_supported[i]);
- if (ret < 0)
- break;
- len += ret;
- }
- mutex_unlock(&phy->pib_lock);
- return len;
-}
-static DEVICE_ATTR_RO(channels_supported);
-
-static struct attribute *pmib_attrs[] = {
- &dev_attr_current_channel.attr,
- &dev_attr_current_page.attr,
- &dev_attr_channels_supported.attr,
- &dev_attr_transmit_power.attr,
- &dev_attr_cca_mode.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(pmib);
-
-static void wpan_phy_release(struct device *d)
-{
- struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
-
- kfree(phy);
-}
-
-static struct class wpan_phy_class = {
- .name = "ieee802154",
- .dev_release = wpan_phy_release,
- .dev_groups = pmib_groups,
-};
-
-static DEFINE_MUTEX(wpan_phy_mutex);
-static int wpan_phy_idx;
-
-static int wpan_phy_match(struct device *dev, const void *data)
-{
- return !strcmp(dev_name(dev), (const char *)data);
-}
-
-struct wpan_phy *wpan_phy_find(const char *str)
-{
- struct device *dev;
-
- if (WARN_ON(!str))
- return NULL;
-
- dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match);
- if (!dev)
- return NULL;
-
- return container_of(dev, struct wpan_phy, dev);
-}
-EXPORT_SYMBOL(wpan_phy_find);
-
-struct wpan_phy_iter_data {
- int (*fn)(struct wpan_phy *phy, void *data);
- void *data;
-};
-
-static int wpan_phy_iter(struct device *dev, void *_data)
-{
- struct wpan_phy_iter_data *wpid = _data;
- struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
-
- return wpid->fn(phy, wpid->data);
-}
-
-int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data),
- void *data)
-{
- struct wpan_phy_iter_data wpid = {
- .fn = fn,
- .data = data,
- };
-
- return class_for_each_device(&wpan_phy_class, NULL,
- &wpid, wpan_phy_iter);
-}
-EXPORT_SYMBOL(wpan_phy_for_each);
-
-static int wpan_phy_idx_valid(int idx)
-{
- return idx >= 0;
-}
-
-struct wpan_phy *wpan_phy_alloc(size_t priv_size)
-{
- struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size,
- GFP_KERNEL);
-
- if (!phy)
- goto out;
- mutex_lock(&wpan_phy_mutex);
- phy->idx = wpan_phy_idx++;
- if (unlikely(!wpan_phy_idx_valid(phy->idx))) {
- wpan_phy_idx--;
- mutex_unlock(&wpan_phy_mutex);
- kfree(phy);
- goto out;
- }
- mutex_unlock(&wpan_phy_mutex);
-
- mutex_init(&phy->pib_lock);
-
- device_initialize(&phy->dev);
- dev_set_name(&phy->dev, "wpan-phy%d", phy->idx);
-
- phy->dev.class = &wpan_phy_class;
-
- phy->current_channel = -1; /* not initialised */
- phy->current_page = 0; /* for compatibility */
-
- return phy;
-
-out:
- return NULL;
-}
-EXPORT_SYMBOL(wpan_phy_alloc);
-
-int wpan_phy_register(struct wpan_phy *phy)
-{
- return device_add(&phy->dev);
-}
-EXPORT_SYMBOL(wpan_phy_register);
-
-void wpan_phy_unregister(struct wpan_phy *phy)
-{
- device_del(&phy->dev);
-}
-EXPORT_SYMBOL(wpan_phy_unregister);
-
-void wpan_phy_free(struct wpan_phy *phy)
-{
- put_device(&phy->dev);
-}
-EXPORT_SYMBOL(wpan_phy_free);
-
-static int __init wpan_phy_class_init(void)
-{
- int rc;
-
- rc = class_register(&wpan_phy_class);
- if (rc)
- goto err;
-
- rc = ieee802154_nl_init();
- if (rc)
- goto err_nl;
-
- return 0;
-err_nl:
- class_unregister(&wpan_phy_class);
-err:
- return rc;
-}
-subsys_initcall(wpan_phy_class_init);
-
-static void __exit wpan_phy_class_exit(void)
-{
- ieee802154_nl_exit();
- class_unregister(&wpan_phy_class);
-}
-module_exit(wpan_phy_class_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("IEEE 802.15.4 configuration interface");
-MODULE_AUTHOR("Dmitry Eremin-Solenikov");
-
network mechanisms and optimizations for UDP (such as ECMP
and RSS) can be leveraged to provide better service.
+config NET_FOU_IP_TUNNELS
+ bool "IP: FOU encapsulation of IP tunnels"
+ depends on NET_IPIP || NET_IPGRE || IPV6_SIT
+ select NET_FOU
+ ---help---
+ Allow configuration of FOU or GUE encapsulation for IP tunnels.
+ When this option is enabled IP tunnels can be configured to use
+ FOU or GUE encapsulation.
+
config GENEVE
tristate "Generic Network Virtualization Encapsulation (Geneve)"
depends on INET
SKB_GSO_TCPV6 |
SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM |
- SKB_GSO_MPLS |
+ SKB_GSO_TUNNEL_REMCSUM |
0)))
goto out;
void __init arp_init(void)
{
- neigh_table_init(&arp_tbl);
+ neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl);
dev_add_pack(&arp_packet_type);
arp_proc_init();
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <linux/atomic.h>
-#include <asm/bug.h>
+#include <linux/bug.h>
#include <asm/unaligned.h>
/* List of available DOI definitions */
u32 size;
struct list_head list;
};
+
struct cipso_v4_map_cache_entry {
u32 hash;
unsigned char *key;
u32 activity;
struct list_head list;
};
-static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
+
+static struct cipso_v4_map_cache_bkt *cipso_v4_cache;
/* Restricted bitmap (tag #1) flags */
int cipso_v4_rbm_optfmt = 0;
/**
* cipso_v4_doi_free - Frees a DOI definition
- * @entry: the entry's RCU field
+ * @doi_def: the DOI definition
*
* Description:
* This function frees all of the memory associated with a DOI definition.
if (elen <= 0)
goto out;
- if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ err = skb_cow_data(skb, 0, &trailer);
+ if (err < 0)
goto out;
+
nfrags = err;
assoclen = sizeof(*esph);
BUG_ON(!aalg_desc);
err = -EINVAL;
- if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+ if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
- NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
- x->aalg->alg_name,
- crypto_aead_authsize(aead),
- aalg_desc->uinfo.auth.icv_fullbits/8);
+ pr_info("ESP: %s digestsize %u != %hu\n",
+ x->aalg->alg_name,
+ crypto_aead_authsize(aead),
+ aalg_desc->uinfo.auth.icv_fullbits / 8);
goto free_key;
}
return sk->sk_user_data;
}
-static int fou_udp_encap_recv_deliver(struct sk_buff *skb,
- u8 protocol, size_t len)
+static void fou_recv_pull(struct sk_buff *skb, size_t len)
{
struct iphdr *iph = ip_hdr(skb);
/* Remove 'len' bytes from the packet (UDP header and
- * FOU header if present), modify the protocol to the one
- * we found, and then call rcv_encap.
+ * FOU header if present).
*/
iph->tot_len = htons(ntohs(iph->tot_len) - len);
__skb_pull(skb, len);
skb_postpull_rcsum(skb, udp_hdr(skb), len);
skb_reset_transport_header(skb);
-
- return -protocol;
}
static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
if (!fou)
return 1;
- return fou_udp_encap_recv_deliver(skb, fou->protocol,
- sizeof(struct udphdr));
+ fou_recv_pull(skb, sizeof(struct udphdr));
+
+ return -fou->protocol;
+}
+
+static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr,
+ void *data, int hdrlen, u8 ipproto)
+{
+ __be16 *pd = data;
+ u16 start = ntohs(pd[0]);
+ u16 offset = ntohs(pd[1]);
+ u16 poffset = 0;
+ u16 plen;
+ __wsum csum, delta;
+ __sum16 *psum;
+
+ if (skb->remcsum_offload) {
+ /* Already processed in GRO path */
+ skb->remcsum_offload = 0;
+ return guehdr;
+ }
+
+ if (start > skb->len - hdrlen ||
+ offset > skb->len - hdrlen - sizeof(u16))
+ return NULL;
+
+ if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE))
+ __skb_checksum_complete(skb);
+
+ plen = hdrlen + offset + sizeof(u16);
+ if (!pskb_may_pull(skb, plen))
+ return NULL;
+ guehdr = (struct guehdr *)&udp_hdr(skb)[1];
+
+ if (ipproto == IPPROTO_IP && sizeof(struct iphdr) < plen) {
+ struct iphdr *ip = (struct iphdr *)(skb->data + hdrlen);
+
+ /* If next header happens to be IP we can skip that for the
+ * checksum calculation since the IP header checksum is zero
+ * if correct.
+ */
+ poffset = ip->ihl * 4;
+ }
+
+ csum = csum_sub(skb->csum, skb_checksum(skb, poffset + hdrlen,
+ start - poffset - hdrlen, 0));
+
+ /* Set derived checksum in packet */
+ psum = (__sum16 *)(skb->data + hdrlen + offset);
+ delta = csum_sub(csum_fold(csum), *psum);
+ *psum = csum_fold(csum);
+
+ /* Adjust skb->csum since we changed the packet */
+ skb->csum = csum_add(skb->csum, delta);
+
+ return guehdr;
+}
+
+static int gue_control_message(struct sk_buff *skb, struct guehdr *guehdr)
+{
+ /* No support yet */
+ kfree_skb(skb);
+ return 0;
}
static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
{
struct fou *fou = fou_from_sock(sk);
- size_t len;
+ size_t len, optlen, hdrlen;
struct guehdr *guehdr;
- struct udphdr *uh;
+ void *data;
+ u16 doffset = 0;
if (!fou)
return 1;
if (!pskb_may_pull(skb, len))
goto drop;
- uh = udp_hdr(skb);
- guehdr = (struct guehdr *)&uh[1];
+ guehdr = (struct guehdr *)&udp_hdr(skb)[1];
+
+ optlen = guehdr->hlen << 2;
+ len += optlen;
- len += guehdr->hlen << 2;
if (!pskb_may_pull(skb, len))
goto drop;
- uh = udp_hdr(skb);
- guehdr = (struct guehdr *)&uh[1];
+ /* guehdr may change after pull */
+ guehdr = (struct guehdr *)&udp_hdr(skb)[1];
- if (guehdr->version != 0)
- goto drop;
+ hdrlen = sizeof(struct guehdr) + optlen;
- if (guehdr->flags) {
- /* No support yet */
+ if (guehdr->version != 0 || validate_gue_flags(guehdr, optlen))
goto drop;
+
+ hdrlen = sizeof(struct guehdr) + optlen;
+
+ ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len);
+
+ /* Pull UDP header now, skb->data points to guehdr */
+ __skb_pull(skb, sizeof(struct udphdr));
+
+ /* Pull csum through the guehdr now . This can be used if
+ * there is a remote checksum offload.
+ */
+ skb_postpull_rcsum(skb, udp_hdr(skb), len);
+
+ data = &guehdr[1];
+
+ if (guehdr->flags & GUE_FLAG_PRIV) {
+ __be32 flags = *(__be32 *)(data + doffset);
+
+ doffset += GUE_LEN_PRIV;
+
+ if (flags & GUE_PFLAG_REMCSUM) {
+ guehdr = gue_remcsum(skb, guehdr, data + doffset,
+ hdrlen, guehdr->proto_ctype);
+ if (!guehdr)
+ goto drop;
+
+ data = &guehdr[1];
+
+ doffset += GUE_PLEN_REMCSUM;
+ }
}
- return fou_udp_encap_recv_deliver(skb, guehdr->next_hdr, len);
+ if (unlikely(guehdr->control))
+ return gue_control_message(skb, guehdr);
+
+ __skb_pull(skb, hdrlen);
+ skb_reset_transport_header(skb);
+
+ return -guehdr->proto_ctype;
+
drop:
kfree_skb(skb);
return 0;
return err;
}
+static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off,
+ struct guehdr *guehdr, void *data,
+ size_t hdrlen, u8 ipproto)
+{
+ __be16 *pd = data;
+ u16 start = ntohs(pd[0]);
+ u16 offset = ntohs(pd[1]);
+ u16 poffset = 0;
+ u16 plen;
+ void *ptr;
+ __wsum csum, delta;
+ __sum16 *psum;
+
+ if (skb->remcsum_offload)
+ return guehdr;
+
+ if (start > skb_gro_len(skb) - hdrlen ||
+ offset > skb_gro_len(skb) - hdrlen - sizeof(u16) ||
+ !NAPI_GRO_CB(skb)->csum_valid || skb->remcsum_offload)
+ return NULL;
+
+ plen = hdrlen + offset + sizeof(u16);
+
+ /* Pull checksum that will be written */
+ if (skb_gro_header_hard(skb, off + plen)) {
+ guehdr = skb_gro_header_slow(skb, off + plen, off);
+ if (!guehdr)
+ return NULL;
+ }
+
+ ptr = (void *)guehdr + hdrlen;
+
+ if (ipproto == IPPROTO_IP &&
+ (hdrlen + sizeof(struct iphdr) < plen)) {
+ struct iphdr *ip = (struct iphdr *)(ptr + hdrlen);
+
+ /* If next header happens to be IP we can skip
+ * that for the checksum calculation since the
+ * IP header checksum is zero if correct.
+ */
+ poffset = ip->ihl * 4;
+ }
+
+ csum = csum_sub(NAPI_GRO_CB(skb)->csum,
+ csum_partial(ptr + poffset, start - poffset, 0));
+
+ /* Set derived checksum in packet */
+ psum = (__sum16 *)(ptr + offset);
+ delta = csum_sub(csum_fold(csum), *psum);
+ *psum = csum_fold(csum);
+
+ /* Adjust skb->csum since we changed the packet */
+ skb->csum = csum_add(skb->csum, delta);
+ NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta);
+
+ skb->remcsum_offload = 1;
+
+ return guehdr;
+}
+
static struct sk_buff **gue_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
const struct net_offload *ops;
struct sk_buff **pp = NULL;
struct sk_buff *p;
- u8 proto;
struct guehdr *guehdr;
- unsigned int hlen, guehlen;
- unsigned int off;
+ size_t len, optlen, hdrlen, off;
+ void *data;
+ u16 doffset = 0;
int flush = 1;
off = skb_gro_offset(skb);
- hlen = off + sizeof(*guehdr);
+ len = off + sizeof(*guehdr);
+
guehdr = skb_gro_header_fast(skb, off);
- if (skb_gro_header_hard(skb, hlen)) {
- guehdr = skb_gro_header_slow(skb, hlen, off);
+ if (skb_gro_header_hard(skb, len)) {
+ guehdr = skb_gro_header_slow(skb, len, off);
if (unlikely(!guehdr))
goto out;
}
- proto = guehdr->next_hdr;
+ optlen = guehdr->hlen << 2;
+ len += optlen;
- rcu_read_lock();
- offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
- ops = rcu_dereference(offloads[proto]);
- if (WARN_ON(!ops || !ops->callbacks.gro_receive))
- goto out_unlock;
+ if (skb_gro_header_hard(skb, len)) {
+ guehdr = skb_gro_header_slow(skb, len, off);
+ if (unlikely(!guehdr))
+ goto out;
+ }
- guehlen = sizeof(*guehdr) + (guehdr->hlen << 2);
+ if (unlikely(guehdr->control) || guehdr->version != 0 ||
+ validate_gue_flags(guehdr, optlen))
+ goto out;
- hlen = off + guehlen;
- if (skb_gro_header_hard(skb, hlen)) {
- guehdr = skb_gro_header_slow(skb, hlen, off);
- if (unlikely(!guehdr))
- goto out_unlock;
+ hdrlen = sizeof(*guehdr) + optlen;
+
+ /* Adjust NAPI_GRO_CB(skb)->csum to account for guehdr,
+ * this is needed if there is a remote checkcsum offload.
+ */
+ skb_gro_postpull_rcsum(skb, guehdr, hdrlen);
+
+ data = &guehdr[1];
+
+ if (guehdr->flags & GUE_FLAG_PRIV) {
+ __be32 flags = *(__be32 *)(data + doffset);
+
+ doffset += GUE_LEN_PRIV;
+
+ if (flags & GUE_PFLAG_REMCSUM) {
+ guehdr = gue_gro_remcsum(skb, off, guehdr,
+ data + doffset, hdrlen,
+ guehdr->proto_ctype);
+ if (!guehdr)
+ goto out;
+
+ data = &guehdr[1];
+
+ doffset += GUE_PLEN_REMCSUM;
+ }
}
+ skb_gro_pull(skb, hdrlen);
+
flush = 0;
for (p = *head; p; p = p->next) {
guehdr2 = (struct guehdr *)(p->data + off);
/* Compare base GUE header to be equal (covers
- * hlen, version, next_hdr, and flags.
+ * hlen, version, proto_ctype, and flags.
*/
if (guehdr->word != guehdr2->word) {
NAPI_GRO_CB(p)->same_flow = 0;
}
}
- skb_gro_pull(skb, guehlen);
-
- /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
- skb_gro_postpull_rcsum(skb, guehdr, guehlen);
+ rcu_read_lock();
+ offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
+ ops = rcu_dereference(offloads[guehdr->proto_ctype]);
+ if (WARN_ON(!ops || !ops->callbacks.gro_receive))
+ goto out_unlock;
pp = ops->callbacks.gro_receive(head, skb);
u8 proto;
int err = -ENOENT;
- proto = guehdr->next_hdr;
+ proto = guehdr->proto_ctype;
guehlen = sizeof(*guehdr) + (guehdr->hlen << 2);
},
};
+size_t fou_encap_hlen(struct ip_tunnel_encap *e)
+{
+ return sizeof(struct udphdr);
+}
+EXPORT_SYMBOL(fou_encap_hlen);
+
+size_t gue_encap_hlen(struct ip_tunnel_encap *e)
+{
+ size_t len;
+ bool need_priv = false;
+
+ len = sizeof(struct udphdr) + sizeof(struct guehdr);
+
+ if (e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) {
+ len += GUE_PLEN_REMCSUM;
+ need_priv = true;
+ }
+
+ len += need_priv ? GUE_LEN_PRIV : 0;
+
+ return len;
+}
+EXPORT_SYMBOL(gue_encap_hlen);
+
+static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ struct flowi4 *fl4, u8 *protocol, __be16 sport)
+{
+ struct udphdr *uh;
+
+ skb_push(skb, sizeof(struct udphdr));
+ skb_reset_transport_header(skb);
+
+ uh = udp_hdr(skb);
+
+ uh->dest = e->dport;
+ uh->source = sport;
+ uh->len = htons(skb->len);
+ uh->check = 0;
+ udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
+ fl4->saddr, fl4->daddr, skb->len);
+
+ *protocol = IPPROTO_UDP;
+}
+
+int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ u8 *protocol, struct flowi4 *fl4)
+{
+ bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM);
+ int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
+ __be16 sport;
+
+ skb = iptunnel_handle_offloads(skb, csum, type);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev),
+ skb, 0, 0, false);
+ fou_build_udp(skb, e, fl4, protocol, sport);
+
+ return 0;
+}
+EXPORT_SYMBOL(fou_build_header);
+
+int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
+ u8 *protocol, struct flowi4 *fl4)
+{
+ bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM);
+ int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
+ struct guehdr *guehdr;
+ size_t hdrlen, optlen = 0;
+ __be16 sport;
+ void *data;
+ bool need_priv = false;
+
+ if ((e->flags & TUNNEL_ENCAP_FLAG_REMCSUM) &&
+ skb->ip_summed == CHECKSUM_PARTIAL) {
+ csum = false;
+ optlen += GUE_PLEN_REMCSUM;
+ type |= SKB_GSO_TUNNEL_REMCSUM;
+ need_priv = true;
+ }
+
+ optlen += need_priv ? GUE_LEN_PRIV : 0;
+
+ skb = iptunnel_handle_offloads(skb, csum, type);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* Get source port (based on flow hash) before skb_push */
+ sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev),
+ skb, 0, 0, false);
+
+ hdrlen = sizeof(struct guehdr) + optlen;
+
+ skb_push(skb, hdrlen);
+
+ guehdr = (struct guehdr *)skb->data;
+
+ guehdr->control = 0;
+ guehdr->version = 0;
+ guehdr->hlen = optlen >> 2;
+ guehdr->flags = 0;
+ guehdr->proto_ctype = *protocol;
+
+ data = &guehdr[1];
+
+ if (need_priv) {
+ __be32 *flags = data;
+
+ guehdr->flags |= GUE_FLAG_PRIV;
+ *flags = 0;
+ data += GUE_LEN_PRIV;
+
+ if (type & SKB_GSO_TUNNEL_REMCSUM) {
+ u16 csum_start = skb_checksum_start_offset(skb);
+ __be16 *pd = data;
+
+ if (csum_start < hdrlen)
+ return -EINVAL;
+
+ csum_start -= hdrlen;
+ pd[0] = htons(csum_start);
+ pd[1] = htons(csum_start + skb->csum_offset);
+
+ if (!skb_is_gso(skb)) {
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->encapsulation = 0;
+ }
+
+ *flags |= GUE_PFLAG_REMCSUM;
+ data += GUE_PLEN_REMCSUM;
+ }
+
+ }
+
+ fou_build_udp(skb, e, fl4, protocol, sport);
+
+ return 0;
+}
+EXPORT_SYMBOL(gue_build_header);
+
+#ifdef CONFIG_NET_FOU_IP_TUNNELS
+
+static const struct ip_tunnel_encap_ops __read_mostly fou_iptun_ops = {
+ .encap_hlen = fou_encap_hlen,
+ .build_header = fou_build_header,
+};
+
+static const struct ip_tunnel_encap_ops __read_mostly gue_iptun_ops = {
+ .encap_hlen = gue_encap_hlen,
+ .build_header = gue_build_header,
+};
+
+static int ip_tunnel_encap_add_fou_ops(void)
+{
+ int ret;
+
+ ret = ip_tunnel_encap_add_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
+ if (ret < 0) {
+ pr_err("can't add fou ops\n");
+ return ret;
+ }
+
+ ret = ip_tunnel_encap_add_ops(&gue_iptun_ops, TUNNEL_ENCAP_GUE);
+ if (ret < 0) {
+ pr_err("can't add gue ops\n");
+ ip_tunnel_encap_del_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ip_tunnel_encap_del_fou_ops(void)
+{
+ ip_tunnel_encap_del_ops(&fou_iptun_ops, TUNNEL_ENCAP_FOU);
+ ip_tunnel_encap_del_ops(&gue_iptun_ops, TUNNEL_ENCAP_GUE);
+}
+
+#else
+
+static int ip_tunnel_encap_add_fou_ops(void)
+{
+ return 0;
+}
+
+static void ip_tunnel_encap_del_fou_ops(void)
+{
+}
+
+#endif
+
static int __init fou_init(void)
{
int ret;
ret = genl_register_family_with_ops(&fou_nl_family,
fou_nl_ops);
+ if (ret < 0)
+ goto exit;
+
+ ret = ip_tunnel_encap_add_fou_ops();
+ if (ret < 0)
+ genl_unregister_family(&fou_nl_family);
+
+exit:
return ret;
}
{
struct fou *fou, *next;
+ ip_tunnel_encap_del_fou_ops();
+
genl_unregister_family(&fou_nl_family);
/* Close all the FOU sockets */
memcpy(geneveh->options, options, options_len);
}
-/* Transmit a fully formated Geneve frame.
+/* Transmit a fully formatted Geneve frame.
*
* When calling this function. The skb->data should point
* to the geneve header which is fully formed.
*/
switch (net->ipv4.sysctl_ip_no_pmtu_disc) {
default:
- LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"),
- &iph->daddr);
+ net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n",
+ &iph->daddr);
break;
case 2:
goto out;
}
break;
case ICMP_SR_FAILED:
- LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: Source Route Failed\n"),
- &iph->daddr);
+ net_dbg_ratelimited("%pI4: Source Route Failed\n",
+ &iph->daddr);
break;
default:
break;
#ifdef CONFIG_IP_MULTICAST
/* Parameter names and values are taken from igmp-v2-06 draft */
-#define IGMP_V1_Router_Present_Timeout (400*HZ)
-#define IGMP_V2_Router_Present_Timeout (400*HZ)
-#define IGMP_V2_Unsolicited_Report_Interval (10*HZ)
-#define IGMP_V3_Unsolicited_Report_Interval (1*HZ)
-#define IGMP_Query_Response_Interval (10*HZ)
-#define IGMP_Query_Robustness_Variable 2
+#define IGMP_V1_ROUTER_PRESENT_TIMEOUT (400*HZ)
+#define IGMP_V2_ROUTER_PRESENT_TIMEOUT (400*HZ)
+#define IGMP_V2_UNSOLICITED_REPORT_INTERVAL (10*HZ)
+#define IGMP_V3_UNSOLICITED_REPORT_INTERVAL (1*HZ)
+#define IGMP_QUERY_RESPONSE_INTERVAL (10*HZ)
+#define IGMP_QUERY_ROBUSTNESS_VARIABLE 2
-#define IGMP_Initial_Report_Delay (1)
+#define IGMP_INITIAL_REPORT_DELAY (1)
-/* IGMP_Initial_Report_Delay is not from IGMP specs!
+/* IGMP_INITIAL_REPORT_DELAY is not from IGMP specs!
* IGMP specs require to report membership immediately after
* joining a group, but we delay the first report by a
* small interval. It seems more natural and still does not
return scount;
}
-#define igmp_skb_size(skb) (*(unsigned int *)((skb)->cb))
-
-static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
+static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
{
struct sk_buff *skb;
struct rtable *rt;
struct flowi4 fl4;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
+ unsigned int size = mtu;
while (1) {
skb = alloc_skb(size + hlen + tlen,
return NULL;
}
skb->priority = TC_PRIO_CONTROL;
- igmp_skb_size(skb) = size;
rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
0, 0,
skb_dst_set(skb, &rt->dst);
skb->dev = dev;
+ skb->reserved_tailroom = skb_end_offset(skb) -
+ min(mtu, skb_end_offset(skb));
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
return skb;
}
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? igmp_skb_size(skb) - (skb)->len : \
- skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
int type, int gdeleted, int sdeleted)
if (ih->code == 0) {
/* Alas, old v1 router presents here. */
- max_delay = IGMP_Query_Response_Interval;
+ max_delay = IGMP_QUERY_RESPONSE_INTERVAL;
in_dev->mr_v1_seen = jiffies +
- IGMP_V1_Router_Present_Timeout;
+ IGMP_V1_ROUTER_PRESENT_TIMEOUT;
group = 0;
} else {
/* v2 router present */
max_delay = ih->code*(HZ/IGMP_TIMER_SCALE);
in_dev->mr_v2_seen = jiffies +
- IGMP_V2_Router_Present_Timeout;
+ IGMP_V2_ROUTER_PRESENT_TIMEOUT;
}
/* cancel the interface change timer */
in_dev->mr_ifc_count = 0;
return true; /* ignore bogus packet; freed by caller */
} else if (IGMP_V1_SEEN(in_dev)) {
/* This is a v3 query with v1 queriers present */
- max_delay = IGMP_Query_Response_Interval;
+ max_delay = IGMP_QUERY_RESPONSE_INTERVAL;
group = 0;
} else if (IGMP_V2_SEEN(in_dev)) {
/* this is a v3 query with v2 queriers present;
return;
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
spin_lock_bh(&im->lock);
- igmp_start_timer(im, IGMP_Initial_Report_Delay);
+ igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
spin_unlock_bh(&im->lock);
return;
}
int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS;
int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;
#ifdef CONFIG_IP_MULTICAST
-int sysctl_igmp_qrv __read_mostly = IGMP_Query_Robustness_Variable;
+int sysctl_igmp_qrv __read_mostly = IGMP_QUERY_ROBUSTNESS_VARIABLE;
#endif
static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
if (v == SEQ_START_TOKEN) {
- seq_printf(seq,
- "%3s %6s "
- "%10s %10s %6s %6s\n", "Idx",
- "Device", "MCA",
- "SRC", "INC", "EXC");
+ seq_puts(seq, "Idx Device MCA SRC INC EXC\n");
} else {
seq_printf(seq,
"%3d %6.6s 0x%08x "
". Dropping fragment.\n";
if (PTR_ERR(q) == -ENOBUFS)
- LIMIT_NETDEBUG(KERN_WARNING "%s%s", prefix, msg);
+ net_dbg_ratelimited("%s%s", prefix, msg);
}
EXPORT_SYMBOL(inet_frag_maybe_warn_overflow);
struct inet_peer *peer;
};
-static inline u8 ip4_frag_ecn(u8 tos)
+static u8 ip4_frag_ecn(u8 tos)
{
return 1 << (tos & INET_ECN_MASK);
}
inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, 1) : NULL;
}
-static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
+static void ip4_frag_free(struct inet_frag_queue *q)
{
struct ipq *qp;
/* Destruction primitives. */
-static __inline__ void ipq_put(struct ipq *ipq)
+static void ipq_put(struct ipq *ipq)
{
inet_frag_put(&ipq->q, &ip4_frags);
}
/* Find the correct entry in the "incomplete datagrams" queue for
* this IP datagram, and create new one, if nothing is found.
*/
-static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
+static struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
{
struct inet_frag_queue *q;
struct ip4_create_arg arg;
}
/* Is the fragment too far ahead to be part of ipq? */
-static inline int ip_frag_too_far(struct ipq *qp)
+static int ip_frag_too_far(struct ipq *qp)
{
struct inet_peer *peer = qp->peer;
unsigned int max = sysctl_ipfrag_max_dist;
return 0;
out_nomem:
- LIMIT_NETDEBUG(KERN_ERR pr_fmt("queue_glue: no memory for gluing queue %p\n"),
- qp);
+ net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp);
err = -ENOMEM;
goto out_fail;
out_oversize:
register_net_sysctl(&init_net, "net/ipv4", ip4_frags_ctl_table);
}
#else
-static inline int ip4_frags_ns_ctl_register(struct net *net)
+static int ip4_frags_ns_ctl_register(struct net *net)
{
return 0;
}
-static inline void ip4_frags_ns_ctl_unregister(struct net *net)
+static void ip4_frags_ns_ctl_unregister(struct net *net)
{
}
-static inline void __init ip4_frags_ctl_register(void)
+static void __init ip4_frags_ctl_register(void)
{
}
#endif
nla_put_u16(skb, IFLA_GRE_ENCAP_DPORT,
t->encap.dport) ||
nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
- t->encap.dport))
+ t->encap.flags))
goto nla_put_failure;
return 0;
if (len < left) {
len &= ~7;
}
- /*
- * Allocate buffer.
- */
- if ((skb2 = alloc_skb(len+hlen+ll_rs, GFP_ATOMIC)) == NULL) {
- NETDEBUG(KERN_INFO "IP: frag: no memory for new fragment!\n");
+ /* Allocate buffer */
+ skb2 = alloc_skb(len + hlen + ll_rs, GFP_ATOMIC);
+ if (!skb2) {
err = -ENOMEM;
goto fail;
}
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free_skb;
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
#include <net/udp.h>
-#include <net/gue.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
static int ip_encap_hlen(struct ip_tunnel_encap *e)
{
- switch (e->type) {
- case TUNNEL_ENCAP_NONE:
+ const struct ip_tunnel_encap_ops *ops;
+ int hlen = -EINVAL;
+
+ if (e->type == TUNNEL_ENCAP_NONE)
return 0;
- case TUNNEL_ENCAP_FOU:
- return sizeof(struct udphdr);
- case TUNNEL_ENCAP_GUE:
- return sizeof(struct udphdr) + sizeof(struct guehdr);
- default:
+
+ if (e->type >= MAX_IPTUN_ENCAP_OPS)
return -EINVAL;
- }
+
+ rcu_read_lock();
+ ops = rcu_dereference(iptun_encaps[e->type]);
+ if (likely(ops && ops->encap_hlen))
+ hlen = ops->encap_hlen(e);
+ rcu_read_unlock();
+
+ return hlen;
}
+const struct ip_tunnel_encap_ops __rcu *
+ iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
+
+int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops,
+ unsigned int num)
+{
+ return !cmpxchg((const struct ip_tunnel_encap_ops **)
+ &iptun_encaps[num],
+ NULL, ops) ? 0 : -1;
+}
+EXPORT_SYMBOL(ip_tunnel_encap_add_ops);
+
+int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops,
+ unsigned int num)
+{
+ int ret;
+
+ ret = (cmpxchg((const struct ip_tunnel_encap_ops **)
+ &iptun_encaps[num],
+ ops, NULL) == ops) ? 0 : -1;
+
+ synchronize_net();
+
+ return ret;
+}
+EXPORT_SYMBOL(ip_tunnel_encap_del_ops);
+
int ip_tunnel_encap_setup(struct ip_tunnel *t,
struct ip_tunnel_encap *ipencap)
{
}
EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
-static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
- size_t hdr_len, u8 *protocol, struct flowi4 *fl4)
-{
- struct udphdr *uh;
- __be16 sport;
- bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM);
- int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
-
- skb = iptunnel_handle_offloads(skb, csum, type);
-
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- /* Get length and hash before making space in skb */
-
- sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev),
- skb, 0, 0, false);
-
- skb_push(skb, hdr_len);
-
- skb_reset_transport_header(skb);
- uh = udp_hdr(skb);
-
- if (e->type == TUNNEL_ENCAP_GUE) {
- struct guehdr *guehdr = (struct guehdr *)&uh[1];
-
- guehdr->version = 0;
- guehdr->hlen = 0;
- guehdr->flags = 0;
- guehdr->next_hdr = *protocol;
- }
-
- uh->dest = e->dport;
- uh->source = sport;
- uh->len = htons(skb->len);
- uh->check = 0;
- udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
- fl4->saddr, fl4->daddr, skb->len);
-
- *protocol = IPPROTO_UDP;
-
- return 0;
-}
-
int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
u8 *protocol, struct flowi4 *fl4)
{
- switch (t->encap.type) {
- case TUNNEL_ENCAP_NONE:
+ const struct ip_tunnel_encap_ops *ops;
+ int ret = -EINVAL;
+
+ if (t->encap.type == TUNNEL_ENCAP_NONE)
return 0;
- case TUNNEL_ENCAP_FOU:
- case TUNNEL_ENCAP_GUE:
- return fou_build_header(skb, &t->encap, t->encap_hlen,
- protocol, fl4);
- default:
- return -EINVAL;
- }
+
+ rcu_read_lock();
+ ops = rcu_dereference(iptun_encaps[t->encap.type]);
+ if (likely(ops && ops->build_header))
+ ret = ops->build_header(skb, &t->encap, protocol, fl4);
+ rcu_read_unlock();
+
+ return ret;
}
EXPORT_SYMBOL(ip_tunnel_encap);
*/
int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */
-static int ic_enable __initdata = 0; /* IP config enabled? */
+static int ic_enable __initdata; /* IP config enabled? */
/* Protocol choice */
int ic_proto_enabled __initdata = 0
#endif
;
-static int ic_host_name_set __initdata = 0; /* Host name set by us? */
+static int ic_host_name_set __initdata; /* Host name set by us? */
__be32 ic_myaddr = NONE; /* My IP address */
static __be32 ic_netmask = NONE; /* Netmask for local subnet */
static char user_dev_name[IFNAMSIZ] __initdata = { 0, };
/* Protocols supported by available interfaces */
-static int ic_proto_have_if __initdata = 0;
+static int ic_proto_have_if __initdata;
/* MTU for boot device */
-static int ic_dev_mtu __initdata = 0;
+static int ic_dev_mtu __initdata;
#ifdef IPCONFIG_DYNAMIC
static DEFINE_SPINLOCK(ic_recv_lock);
-static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */
+static volatile int ic_got_reply __initdata; /* Proto(s) that replied */
#endif
#ifdef IPCONFIG_DHCP
-static int ic_dhcp_msgtype __initdata = 0; /* DHCP msg type received */
+static int ic_dhcp_msgtype __initdata; /* DHCP msg type received */
#endif
__be32 xid;
};
-static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
-static struct net_device *ic_dev __initdata = NULL; /* Selected device */
+static struct ic_device *ic_first_dev __initdata; /* List of open device */
+static struct net_device *ic_dev __initdata; /* Selected device */
static bool __init ic_is_init_dev(struct net_device *dev)
{
struct arphdr *rarp;
unsigned char *rarp_ptr;
__be32 sip, tip;
- unsigned char *sha, *tha; /* s for "source", t for "target" */
+ unsigned char *tha; /* t for "target" */
struct ic_device *d;
if (!net_eq(dev_net(dev), &init_net))
goto drop_unlock; /* should never happen */
/* Extract variable-width fields */
- sha = rarp_ptr;
rarp_ptr += dev->addr_len;
memcpy(&sip, rarp_ptr, 4);
rarp_ptr += 4;
nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT,
tunnel->encap.dport) ||
nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
- tunnel->encap.dport))
+ tunnel->encap.flags))
goto nla_put_failure;
return 0;
}
/* Don't bother checking the checksum */
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS),
SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS),
SNMP_MIB_ITEM("InCsumErrors", UDP_MIB_CSUMERRORS),
+ SNMP_MIB_ITEM("IgnoredMulti", UDP_MIB_IGNOREDMULTI),
SNMP_MIB_SENTINEL
};
int j;
if (count) {
- seq_printf(seq, "\nIcmpMsg:");
+ seq_puts(seq, "\nIcmpMsg:");
for (j = 0; j < count; ++j)
seq_printf(seq, " %sType%u",
type[j] & 0x100 ? "Out" : "In",
type[j] & 0xff);
- seq_printf(seq, "\nIcmpMsg:");
+ seq_puts(seq, "\nIcmpMsg:");
for (j = 0; j < count; ++j)
seq_printf(seq, " %lu", vals[j]);
}
seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
for (i = 0; icmpmibmap[i].name != NULL; i++)
seq_printf(seq, " In%s", icmpmibmap[i].name);
- seq_printf(seq, " OutMsgs OutErrors");
+ seq_puts(seq, " OutMsgs OutErrors");
for (i = 0; icmpmibmap[i].name != NULL; i++)
seq_printf(seq, " Out%s", icmpmibmap[i].name);
seq_printf(seq, "\nIcmp: %lu %lu %lu",
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/compat.h>
+#include <linux/uio.h>
+
+struct raw_frag_vec {
+ struct iovec *iov;
+ union {
+ struct icmphdr icmph;
+ char c[1];
+ } hdr;
+ int hlen;
+};
static struct raw_hashinfo raw_v4_hashinfo = {
.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
return err;
}
-static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg)
+static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
{
- struct iovec *iov;
- u8 __user *type = NULL;
- u8 __user *code = NULL;
- int probed = 0;
- unsigned int i;
+ int err;
- if (!msg->msg_iov)
+ if (fl4->flowi4_proto != IPPROTO_ICMP)
return 0;
- for (i = 0; i < msg->msg_iovlen; i++) {
- iov = &msg->msg_iov[i];
- if (!iov)
- continue;
-
- switch (fl4->flowi4_proto) {
- case IPPROTO_ICMP:
- /* check if one-byte field is readable or not. */
- if (iov->iov_base && iov->iov_len < 1)
- break;
-
- if (!type) {
- type = iov->iov_base;
- /* check if code field is readable or not. */
- if (iov->iov_len > 1)
- code = type + 1;
- } else if (!code)
- code = iov->iov_base;
-
- if (type && code) {
- if (get_user(fl4->fl4_icmp_type, type) ||
- get_user(fl4->fl4_icmp_code, code))
- return -EFAULT;
- probed = 1;
- }
- break;
- default:
- probed = 1;
- break;
- }
- if (probed)
- break;
- }
+ /* We only need the first two bytes. */
+ rfv->hlen = 2;
+
+ err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen);
+ if (err)
+ return err;
+
+ fl4->fl4_icmp_type = rfv->hdr.icmph.type;
+ fl4->fl4_icmp_code = rfv->hdr.icmph.code;
+
return 0;
}
+static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
+ struct sk_buff *skb)
+{
+ struct raw_frag_vec *rfv = from;
+
+ if (offset < rfv->hlen) {
+ int copy = min(rfv->hlen - offset, len);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ memcpy(to, rfv->hdr.c + offset, copy);
+ else
+ skb->csum = csum_block_add(
+ skb->csum,
+ csum_partial_copy_nocheck(rfv->hdr.c + offset,
+ to, copy, 0),
+ odd);
+
+ odd = 0;
+ offset += copy;
+ to += copy;
+ len -= copy;
+
+ if (!len)
+ return 0;
+ }
+
+ offset -= rfv->hlen;
+
+ return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb);
+}
+
static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len)
{
u8 tos;
int err;
struct ip_options_data opt_copy;
+ struct raw_frag_vec rfv;
err = -EMSGSIZE;
if (len > 0xFFFF)
daddr, saddr, 0, 0);
if (!inet->hdrincl) {
- err = raw_probe_proto_opt(&fl4, msg);
+ rfv.iov = msg->msg_iov;
+ rfv.hlen = 0;
+
+ err = raw_probe_proto_opt(&rfv, &fl4);
if (err)
goto done;
}
if (!ipc.addr)
ipc.addr = fl4.daddr;
lock_sock(sk);
- err = ip_append_data(sk, &fl4, ip_generic_getfrag,
- msg->msg_iov, len, 0,
+ err = ip_append_data(sk, &fl4, raw_getfrag,
+ &rfv, len, 0,
&ipc, &rt, msg->msg_flags);
if (err)
ip_flush_pending_frames(sk);
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
#include <net/tcp.h>
#include <net/route.h>
-/* Timestamps: lowest bits store TCP options */
-#define TSBITS 6
-#define TSMASK (((__u32)1 << TSBITS) - 1)
-
extern int sysctl_tcp_syncookies;
static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+/* TCP Timestamp: 6 lowest bits of timestamp sent in the cookie SYN-ACK
+ * stores TCP options:
+ *
+ * MSB LSB
+ * | 31 ... 6 | 5 | 4 | 3 2 1 0 |
+ * | Timestamp | ECN | SACK | WScale |
+ *
+ * When we receive a valid cookie-ACK, we look at the echoed tsval (if
+ * any) to figure out which TCP options we should use for the rebuilt
+ * connection.
+ *
+ * A WScale setting of '0xf' (which is an invalid scaling value)
+ * means that original syn did not include the TCP window scaling option.
+ */
+#define TS_OPT_WSCALE_MASK 0xf
+#define TS_OPT_SACK BIT(4)
+#define TS_OPT_ECN BIT(5)
+/* There is no TS_OPT_TIMESTAMP:
+ * if ACK contains timestamp option, we already know it was
+ * requested/supported by the syn/synack exchange.
+ */
+#define TSBITS 6
+#define TSMASK (((__u32)1 << TSBITS) - 1)
+
static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
ipv4_cookie_scratch);
ireq = inet_rsk(req);
- options = ireq->wscale_ok ? ireq->snd_wscale : 0xf;
- options |= ireq->sack_ok << 4;
- options |= ireq->ecn_ok << 5;
+ options = ireq->wscale_ok ? ireq->snd_wscale : TS_OPT_WSCALE_MASK;
+ if (ireq->sack_ok)
+ options |= TS_OPT_SACK;
+ if (ireq->ecn_ok)
+ options |= TS_OPT_ECN;
ts = ts_now & ~TSMASK;
ts |= options;
* additional tcp options in the timestamp.
* This extracts these options from the timestamp echo.
*
- * The lowest 4 bits store snd_wscale.
- * next 2 bits indicate SACK and ECN support.
- *
- * return false if we decode an option that should not be.
+ * return false if we decode a tcp option that is disabled
+ * on the host.
*/
-bool cookie_check_timestamp(struct tcp_options_received *tcp_opt,
- struct net *net, bool *ecn_ok)
+bool cookie_timestamp_decode(struct tcp_options_received *tcp_opt)
{
/* echoed timestamp, lowest bits contain options */
- u32 options = tcp_opt->rcv_tsecr & TSMASK;
+ u32 options = tcp_opt->rcv_tsecr;
if (!tcp_opt->saw_tstamp) {
tcp_clear_options(tcp_opt);
if (!sysctl_tcp_timestamps)
return false;
- tcp_opt->sack_ok = (options & (1 << 4)) ? TCP_SACK_SEEN : 0;
- *ecn_ok = (options >> 5) & 1;
- if (*ecn_ok && !net->ipv4.sysctl_tcp_ecn)
- return false;
+ tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0;
if (tcp_opt->sack_ok && !sysctl_tcp_sack)
return false;
- if ((options & 0xf) == 0xf)
+ if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK)
return true; /* no window scaling */
tcp_opt->wscale_ok = 1;
- tcp_opt->snd_wscale = options & 0xf;
+ tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK;
+
return sysctl_tcp_window_scaling != 0;
}
-EXPORT_SYMBOL(cookie_check_timestamp);
+EXPORT_SYMBOL(cookie_timestamp_decode);
+
+bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt,
+ const struct net *net, const struct dst_entry *dst)
+{
+ bool ecn_ok = tcp_opt->rcv_tsecr & TS_OPT_ECN;
+
+ if (!ecn_ok)
+ return false;
+
+ if (net->ipv4.sysctl_tcp_ecn)
+ return true;
+
+ return dst_feature(dst, RTAX_FEATURE_ECN);
+}
+EXPORT_SYMBOL(cookie_ecn_ok);
struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
{
int mss;
struct rtable *rt;
__u8 rcv_wscale;
- bool ecn_ok = false;
struct flowi4 fl4;
if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
- if (tcp_synq_no_recent_overflow(sk) ||
- (mss = __cookie_v4_check(ip_hdr(skb), th, cookie)) == 0) {
+ if (tcp_synq_no_recent_overflow(sk))
+ goto out;
+
+ mss = __cookie_v4_check(ip_hdr(skb), th, cookie);
+ if (mss == 0) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED);
goto out;
}
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, 0, NULL);
- if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
+ if (!cookie_timestamp_decode(&tcp_opt))
goto out;
ret = NULL;
ireq->ir_loc_addr = ip_hdr(skb)->daddr;
ireq->ir_rmt_addr = ip_hdr(skb)->saddr;
ireq->ir_mark = inet_request_mark(sk, skb);
- ireq->ecn_ok = ecn_ok;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
dst_metric(&rt->dst, RTAX_INITRWND));
ireq->rcv_wscale = rcv_wscale;
+ ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst);
ret = get_cookie_sock(sk, skb, req, &rt->dst);
/* ip_queue_xmit() depends on our flow being setup
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "tcp_max_reordering",
+ .data = &sysctl_tcp_max_reordering,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
{
.procname = "tcp_dsack",
.data = &sysctl_tcp_dsack,
/* XXX -- need to support SO_PEEK_OFF */
skb_queue_walk(&sk->sk_write_queue, skb) {
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, skb->len);
+ err = skb_copy_datagram_msg(skb, 0, msg, skb->len);
if (err)
break;
}
if (!(flags & MSG_TRUNC)) {
- err = skb_copy_datagram_iovec(skb, offset,
- msg->msg_iov, used);
+ err = skb_copy_datagram_msg(skb, offset, msg, used);
if (err) {
/* Exception. Bailout! */
if (!copied)
/*
- * Plugable TCP congestion control support and newReno
+ * Pluggable TCP congestion control support and newReno
* congestion control.
* Based on ideas from I/O scheduler support and Web100.
*
int sysctl_tcp_sack __read_mostly = 1;
int sysctl_tcp_fack __read_mostly = 1;
int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
+int sysctl_tcp_max_reordering __read_mostly = 300;
EXPORT_SYMBOL(sysctl_tcp_reordering);
int sysctl_tcp_dsack __read_mostly = 1;
int sysctl_tcp_app_win __read_mostly = 31;
if (metric > tp->reordering) {
int mib_idx;
- tp->reordering = min(TCP_MAX_REORDERING, metric);
+ tp->reordering = min(sysctl_tcp_max_reordering, metric);
/* This exciting event is worth to be remembered. 8) */
if (ts)
/* step 3: check security and precedence [ignored] */
/* step 4: Check for a SYN
- * RFC 5691 4.2 : Send a challenge ack
+ * RFC 5961 4.2 : Send a challenge ack
*/
if (th->syn) {
syn_challenge:
struct inet_request_sock *ireq = inet_rsk(req);
if (family == AF_INET)
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"),
- &ireq->ir_rmt_addr, port);
+ net_dbg_ratelimited("drop open request from %pI4/%u\n",
+ &ireq->ir_rmt_addr, port);
#if IS_ENABLED(CONFIG_IPV6)
else if (family == AF_INET6)
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"),
- &ireq->ir_v6_rmt_addr, port);
+ net_dbg_ratelimited("drop open request from %pI6/%u\n",
+ &ireq->ir_v6_rmt_addr, port);
#endif
}
* If we receive a SYN packet with these bits set, it means a
* network is playing bad games with TOS bits. In order to
* avoid possible false congestion notifications, we disable
- * TCP ECN negociation.
+ * TCP ECN negotiation.
*
* Exception: tcp_ca wants ECN. This is required for DCTCP
* congestion control; it requires setting ECT on all packets,
*/
static void tcp_ecn_create_request(struct request_sock *req,
const struct sk_buff *skb,
- const struct sock *listen_sk)
+ const struct sock *listen_sk,
+ const struct dst_entry *dst)
{
const struct tcphdr *th = tcp_hdr(skb);
const struct net *net = sock_net(listen_sk);
bool th_ecn = th->ece && th->cwr;
- bool ect, need_ecn;
+ bool ect, need_ecn, ecn_ok;
if (!th_ecn)
return;
ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield);
need_ecn = tcp_ca_needs_ecn(listen_sk);
+ ecn_ok = net->ipv4.sysctl_tcp_ecn || dst_feature(dst, RTAX_FEATURE_ECN);
- if (!ect && !need_ecn && net->ipv4.sysctl_tcp_ecn)
+ if (!ect && !need_ecn && ecn_ok)
inet_rsk(req)->ecn_ok = 1;
else if (ect && need_ecn)
inet_rsk(req)->ecn_ok = 1;
if (security_inet_conn_request(sk, skb, req))
goto drop_and_free;
- if (!want_cookie || tmp_opt.tstamp_ok)
- tcp_ecn_create_request(req, skb, sk);
-
- if (want_cookie) {
- isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
- req->cookie_ts = tmp_opt.tstamp_ok;
- } else if (!isn) {
+ if (!want_cookie && !isn) {
/* VJ's idea. We save last timestamp seen
* from the destination in peer table, when entering
* state TIME-WAIT, and check against it before
goto drop_and_free;
}
+ tcp_ecn_create_request(req, skb, sk, dst);
+
+ if (want_cookie) {
+ isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
+ req->cookie_ts = tmp_opt.tstamp_ok;
+ if (!tmp_opt.tstamp_ok)
+ inet_rsk(req)->ecn_ok = 0;
+ }
+
tcp_rsk(req)->snt_isn = isn;
tcp_openreq_init_rwin(req, sk, dst);
fastopen = !want_cookie &&
struct dst_entry *dst = sk->sk_rx_dst;
sock_rps_save_rxhash(sk, skb);
+ sk_mark_napi_id(sk, skb);
if (dst) {
if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
dst->ops->check(dst, 0) == NULL) {
if (nsk != sk) {
sock_rps_save_rxhash(nsk, skb);
+ sk_mark_napi_id(sk, skb);
if (tcp_child_process(sk, nsk, skb)) {
rsk = nsk;
goto reset;
if (sk_filter(sk, skb))
goto discard_and_relse;
- sk_mark_napi_id(sk, skb);
+ sk_incoming_cpu_update(sk);
skb->dev = NULL;
bh_lock_sock_nested(sk);
SKB_GSO_GRE_CSUM |
SKB_GSO_IPIP |
SKB_GSO_SIT |
- SKB_GSO_MPLS |
SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM |
+ SKB_GSO_TUNNEL_REMCSUM |
0) ||
!(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
goto out;
static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
+ bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
+ tcp_ca_needs_ecn(sk);
+
+ if (!use_ecn) {
+ const struct dst_entry *dst = __sk_dst_get(sk);
+
+ if (dst && dst_feature(dst, RTAX_FEATURE_ECN))
+ use_ecn = true;
+ }
tp->ecn_flags = 0;
- if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
- tcp_ca_needs_ecn(sk)) {
+
+ if (use_ecn) {
TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
tp->ecn_flags = TCP_ECN_OK;
if (tcp_ca_needs_ecn(sk))
static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp,
const struct sk_buff *skb)
{
- u32 in_flight, cwnd;
+ u32 in_flight, cwnd, halfcwnd;
/* Don't be strict about the congestion window for the final FIN. */
if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) &&
in_flight = tcp_packets_in_flight(tp);
cwnd = tp->snd_cwnd;
- if (in_flight < cwnd)
- return (cwnd - in_flight);
+ if (in_flight >= cwnd)
+ return 0;
- return 0;
+ /* For better scheduling, ensure we have at least
+ * 2 GSO packets in flight.
+ */
+ halfcwnd = max(cwnd >> 1, 1U);
+ return min(halfcwnd, cwnd - in_flight);
}
/* Initialize TSO state of a skb.
*/
struct inet_sock *inet = inet_sk(sk);
if (sk->sk_family == AF_INET) {
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"),
- &inet->inet_daddr,
- ntohs(inet->inet_dport), inet->inet_num,
- tp->snd_una, tp->snd_nxt);
+ net_dbg_ratelimited("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
+ &inet->inet_daddr,
+ ntohs(inet->inet_dport),
+ inet->inet_num,
+ tp->snd_una, tp->snd_nxt);
}
#if IS_ENABLED(CONFIG_IPV6)
else if (sk->sk_family == AF_INET6) {
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n"),
- &sk->sk_v6_daddr,
- ntohs(inet->inet_dport), inet->inet_num,
- tp->snd_una, tp->snd_nxt);
+ net_dbg_ratelimited("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
+ &sk->sk_v6_daddr,
+ ntohs(inet->inet_dport),
+ inet->inet_num,
+ tp->snd_una, tp->snd_nxt);
}
#endif
if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) {
struct hlist_nulls_node *node;
kuid_t uid = sock_i_uid(sk);
- sk_nulls_for_each(sk2, node, &hslot->head)
+ sk_nulls_for_each(sk2, node, &hslot->head) {
if (net_eq(sock_net(sk2), net) &&
sk2 != sk &&
(bitmap || udp_sk(sk2)->udp_port_hash == num) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
(!sk2->sk_reuseport || !sk->sk_reuseport ||
- !uid_eq(uid, sock_i_uid(sk2))) &&
- (*saddr_comp)(sk, sk2)) {
- if (bitmap)
- __set_bit(udp_sk(sk2)->udp_port_hash >> log,
- bitmap);
- else
+ !uid_eq(uid, sock_i_uid(sk2))) &&
+ saddr_comp(sk, sk2)) {
+ if (!bitmap)
return 1;
+ __set_bit(udp_sk(sk2)->udp_port_hash >> log, bitmap);
}
+ }
return 0;
}
* can insert/delete a socket with local_port == num
*/
static int udp_lib_lport_inuse2(struct net *net, __u16 num,
- struct udp_hslot *hslot2,
- struct sock *sk,
- int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2))
+ struct udp_hslot *hslot2,
+ struct sock *sk,
+ int (*saddr_comp)(const struct sock *sk1,
+ const struct sock *sk2))
{
struct sock *sk2;
struct hlist_nulls_node *node;
int res = 0;
spin_lock(&hslot2->lock);
- udp_portaddr_for_each_entry(sk2, node, &hslot2->head)
+ udp_portaddr_for_each_entry(sk2, node, &hslot2->head) {
if (net_eq(sock_net(sk2), net) &&
sk2 != sk &&
(udp_sk(sk2)->udp_port_hash == num) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
(!sk2->sk_reuseport || !sk->sk_reuseport ||
- !uid_eq(uid, sock_i_uid(sk2))) &&
- (*saddr_comp)(sk, sk2)) {
+ !uid_eq(uid, sock_i_uid(sk2))) &&
+ saddr_comp(sk, sk2)) {
res = 1;
break;
}
+ }
spin_unlock(&hslot2->lock);
return res;
}
* with NULL address
*/
int udp_lib_get_port(struct sock *sk, unsigned short snum,
- int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2),
+ int (*saddr_comp)(const struct sock *sk1,
+ const struct sock *sk2),
unsigned int hash2_nulladdr)
{
struct udp_hslot *hslot, *hslot2;
/* ... which is an evident application bug. --ANK */
release_sock(sk);
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("cork app bug 2\n"));
+ net_dbg_ratelimited("cork app bug 2\n");
err = -EINVAL;
goto out;
}
if (unlikely(!up->pending)) {
release_sock(sk);
- LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("udp cork app bug 3\n"));
+ net_dbg_ratelimited("udp cork app bug 3\n");
return -EINVAL;
}
}
if (skb_csum_unnecessary(skb))
- err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
- msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
+ msg, copied);
else {
err = skb_copy_and_csum_datagram_iovec(skb,
sizeof(struct udphdr),
if (inet_sk(sk)->inet_daddr) {
sock_rps_save_rxhash(sk, skb);
sk_mark_napi_id(sk, skb);
+ sk_incoming_cpu_update(sk);
}
rc = sock_queue_rcv_skb(sk, skb);
* provided by the application."
*/
if (up->pcrlen == 0) { /* full coverage was set */
- LIMIT_NETDEBUG(KERN_WARNING "UDPLite: partial coverage %d while full coverage %d requested\n",
- UDP_SKB_CB(skb)->cscov, skb->len);
+ net_dbg_ratelimited("UDPLite: partial coverage %d while full coverage %d requested\n",
+ UDP_SKB_CB(skb)->cscov, skb->len);
goto drop;
}
/* The next case involves violating the min. coverage requested
* Therefore the above ...()->partial_cov statement is essential.
*/
if (UDP_SKB_CB(skb)->cscov < up->pcrlen) {
- LIMIT_NETDEBUG(KERN_WARNING "UDPLite: coverage %d too small, need min %d\n",
- UDP_SKB_CB(skb)->cscov, up->pcrlen);
+ net_dbg_ratelimited("UDPLite: coverage %d too small, need min %d\n",
+ UDP_SKB_CB(skb)->cscov, up->pcrlen);
goto drop;
}
}
static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
struct udphdr *uh,
__be32 saddr, __be32 daddr,
- struct udp_table *udptable)
+ struct udp_table *udptable,
+ int proto)
{
struct sock *sk, *stack[256 / sizeof(struct sock *)];
struct hlist_nulls_node *node;
int dif = skb->dev->ifindex;
unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
+ bool inner_flushed = false;
if (use_hash2) {
hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
dif, hnum)) {
if (unlikely(count == ARRAY_SIZE(stack))) {
flush_stack(stack, count, skb, ~0);
+ inner_flushed = true;
count = 0;
}
stack[count++] = sk;
if (count) {
flush_stack(stack, count, skb, count - 1);
} else {
- kfree_skb(skb);
+ if (!inner_flushed)
+ UDP_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
+ proto == IPPROTO_UDPLITE);
+ consume_skb(skb);
}
return 0;
}
if (ret > 0)
return -ret;
return 0;
- } else {
- if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
- return __udp4_lib_mcast_deliver(net, skb, uh,
- saddr, daddr, udptable);
-
- sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
}
+ if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
+ return __udp4_lib_mcast_deliver(net, skb, uh,
+ saddr, daddr, udptable, proto);
+
+ sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
if (sk != NULL) {
int ret;
return 0;
short_packet:
- LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n",
- proto == IPPROTO_UDPLITE ? "Lite" : "",
- &saddr, ntohs(uh->source),
- ulen, skb->len,
- &daddr, ntohs(uh->dest));
+ net_dbg_ratelimited("UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n",
+ proto == IPPROTO_UDPLITE ? "Lite" : "",
+ &saddr, ntohs(uh->source),
+ ulen, skb->len,
+ &daddr, ntohs(uh->dest));
goto drop;
csum_error:
* RFC1122: OK. Discards the bad packet silently (as far as
* the network is concerned, anyway) as per 4.1.3.4 (MUST).
*/
- LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n",
- proto == IPPROTO_UDPLITE ? "Lite" : "",
- &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest),
- ulen);
+ net_dbg_ratelimited("UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n",
+ proto == IPPROTO_UDPLITE ? "Lite" : "",
+ &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest),
+ ulen);
UDP_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE);
drop:
UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
} else {
up->corkflag = 0;
lock_sock(sk);
- (*push_pending_frames)(sk);
+ push_pending_frames(sk);
release_sock(sk);
}
break;
netdev_features_t features,
struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
netdev_features_t features),
- __be16 new_protocol)
+ __be16 new_protocol, bool is_ipv6)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
u16 mac_offset = skb->mac_header;
netdev_features_t enc_features;
int udp_offset, outer_hlen;
unsigned int oldlen;
- bool need_csum;
+ bool need_csum = !!(skb_shinfo(skb)->gso_type &
+ SKB_GSO_UDP_TUNNEL_CSUM);
+ bool remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM);
+ bool offload_csum = false, dont_encap = (need_csum || remcsum);
oldlen = (u16)~skb->len;
skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = skb_inner_network_offset(skb);
skb->protocol = new_protocol;
+ skb->encap_hdr_csum = need_csum;
+ skb->remcsum_offload = remcsum;
- need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
- if (need_csum)
- skb->encap_hdr_csum = 1;
+ /* Try to offload checksum if possible */
+ offload_csum = !!(need_csum &&
+ (skb->dev->features &
+ (is_ipv6 ? NETIF_F_V6_CSUM : NETIF_F_V4_CSUM)));
/* segment inner packet. */
enc_features = skb->dev->hw_enc_features & features;
do {
struct udphdr *uh;
int len;
-
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
+ __be32 delta;
+
+ if (dont_encap) {
+ skb->encapsulation = 0;
+ skb->ip_summed = CHECKSUM_NONE;
+ } else {
+ /* Only set up inner headers if we might be offloading
+ * inner checksum.
+ */
+ skb_reset_inner_headers(skb);
+ skb->encapsulation = 1;
+ }
skb->mac_len = mac_len;
+ skb->protocol = protocol;
skb_push(skb, outer_hlen);
skb_reset_mac_header(skb);
uh = udp_hdr(skb);
uh->len = htons(len);
- if (need_csum) {
- __be32 delta = htonl(oldlen + len);
+ if (!need_csum)
+ continue;
- uh->check = ~csum_fold((__force __wsum)
- ((__force u32)uh->check +
- (__force u32)delta));
+ delta = htonl(oldlen + len);
+
+ uh->check = ~csum_fold((__force __wsum)
+ ((__force u32)uh->check +
+ (__force u32)delta));
+ if (offload_csum) {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ } else if (remcsum) {
+ /* Need to calculate checksum from scratch,
+ * inner checksums are never when doing
+ * remote_checksum_offload.
+ */
+
+ skb->csum = skb_checksum(skb, udp_offset,
+ skb->len - udp_offset,
+ 0);
+ uh->check = csum_fold(skb->csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ } else {
uh->check = gso_make_checksum(skb, ~uh->check);
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
}
-
- skb->protocol = protocol;
} while ((skb = skb->next));
out:
return segs;
}
segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment,
- protocol);
+ protocol, is_ipv6);
out_unlock:
rcu_read_unlock();
if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM |
+ SKB_GSO_TUNNEL_REMCSUM |
SKB_GSO_IPIP |
- SKB_GSO_GRE | SKB_GSO_GRE_CSUM |
- SKB_GSO_MPLS) ||
+ SKB_GSO_GRE | SKB_GSO_GRE_CSUM) ||
!(type & (SKB_GSO_UDP))))
goto out;
IPV6_SADDR_RULE_PRIVACY,
IPV6_SADDR_RULE_ORCHID,
IPV6_SADDR_RULE_PREFIX,
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ IPV6_SADDR_RULE_NOT_OPTIMISTIC,
+#endif
IPV6_SADDR_RULE_MAX
};
return 0;
}
+static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev)
+{
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic;
+#else
+ return false;
+#endif
+}
+
static int ipv6_get_saddr_eval(struct net *net,
struct ipv6_saddr_score *score,
struct ipv6_saddr_dst *dst,
score->scopedist = ret;
break;
case IPV6_SADDR_RULE_PREFERRED:
+ {
/* Rule 3: Avoid deprecated and optimistic addresses */
+ u8 avoid = IFA_F_DEPRECATED;
+
+ if (!ipv6_use_optimistic_addr(score->ifa->idev))
+ avoid |= IFA_F_OPTIMISTIC;
ret = ipv6_saddr_preferred(score->addr_type) ||
- !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC));
+ !(score->ifa->flags & avoid);
break;
+ }
#ifdef CONFIG_IPV6_MIP6
case IPV6_SADDR_RULE_HOA:
{
ret = score->ifa->prefix_len;
score->matchlen = ret;
break;
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ case IPV6_SADDR_RULE_NOT_OPTIMISTIC:
+ /* Optimistic addresses still have lower precedence than other
+ * preferred addresses.
+ */
+ ret = !(score->ifa->flags & IFA_F_OPTIMISTIC);
+ break;
+#endif
default:
ret = 0;
}
if (unlikely(score->addr_type == IPV6_ADDR_ANY ||
score->addr_type & IPV6_ADDR_MULTICAST)) {
- LIMIT_NETDEBUG(KERN_DEBUG
- "ADDRCONF: unspecified / multicast address "
- "assigned as unicast address on %s",
- dev->name);
+ net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s",
+ dev->name);
continue;
}
else
stored_lft = 0;
if (!update_lft && !create && stored_lft) {
- const u32 minimum_lft = min(
- stored_lft, (u32)MIN_VALID_LIFETIME);
+ const u32 minimum_lft = min_t(u32,
+ stored_lft, MIN_VALID_LIFETIME);
valid_lft = max(valid_lft, minimum_lft);
/* RFC4862 Section 5.5.3e:
* Optimistic nodes can start receiving
* Frames right away
*/
- if (ifp->flags & IFA_F_OPTIMISTIC)
+ if (ifp->flags & IFA_F_OPTIMISTIC) {
ip6_ins_rt(ifp->rt);
+ if (ipv6_use_optimistic_addr(idev)) {
+ /* Because optimistic nodes can use this address,
+ * notify listeners. If DAD fails, RTM_DELADDR is sent.
+ */
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ }
+ }
addrconf_dad_kick(ifp);
out:
array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
+ array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic;
#endif
#ifdef CONFIG_IPV6_MROUTE
array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
.proc_handler = proc_dointvec,
},
+ {
+ .procname = "use_optimistic",
+ .data = &ipv6_devconf.use_optimistic,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+
+ },
#endif
#ifdef CONFIG_IPV6_MROUTE
{
ipv6_rearrange_destopt(iph, exthdr.opth);
case NEXTHDR_HOP:
if (!zero_out_mutable_opts(exthdr.opth)) {
- LIMIT_NETDEBUG(
- KERN_WARNING "overrun %sopts\n",
- nexthdr == NEXTHDR_HOP ?
- "hop" : "dest");
+ net_dbg_ratelimited("overrun %sopts\n",
+ nexthdr == NEXTHDR_HOP ?
+ "hop" : "dest");
return -EINVAL;
}
break;
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free_skb;
msg->msg_flags |= MSG_TRUNC;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free_skb;
break;
}
default:
- LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
- cmsg->cmsg_type);
+ net_dbg_ratelimited("invalid cmsg type: %d\n",
+ cmsg->cmsg_type);
err = -EINVAL;
goto exit_f;
}
err = -EINVAL;
padlen = nexthdr[0];
if (padlen + 2 + alen >= elen) {
- LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
- "padlen=%d, elen=%d\n", padlen + 2, elen - alen);
+ net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n",
+ padlen + 2, elen - alen);
goto out;
}
BUG_ON(!aalg_desc);
err = -EINVAL;
- if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+ if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
- NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
- x->aalg->alg_name,
- crypto_aead_authsize(aead),
- aalg_desc->uinfo.auth.icv_fullbits/8);
+ pr_info("ESP: %s digestsize %u != %hu\n",
+ x->aalg->alg_name,
+ crypto_aead_authsize(aead),
+ aalg_desc->uinfo.auth.icv_fullbits / 8);
goto free_key;
}
#include <net/xfrm.h>
#endif
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
/*
* Parsing tlv encoded headers.
int ret;
if (opt->dsthao) {
- LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
+ net_dbg_ratelimited("hao duplicated\n");
goto discard;
}
opt->dsthao = opt->dst1;
hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
if (hao->length != 16) {
- LIMIT_NETDEBUG(
- KERN_DEBUG "hao invalid option length = %d\n", hao->length);
+ net_dbg_ratelimited("hao invalid option length = %d\n",
+ hao->length);
goto discard;
}
if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
- LIMIT_NETDEBUG(
- KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
+ net_dbg_ratelimited("hao is not an unicast addr: %pI6\n",
+ &hao->addr);
goto discard;
}
memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra));
return true;
}
- LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
- nh[optoff + 1]);
+ net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n",
+ nh[optoff + 1]);
kfree_skb(skb);
return false;
}
u32 pkt_len;
if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
- LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
- nh[optoff+1]);
+ net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
+ nh[optoff+1]);
IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
IPSTATS_MIB_INHDRERRORS);
goto drop;
* anycast.
*/
if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n");
+ net_dbg_ratelimited("icmp6_send: acast source\n");
dst_release(dst);
return ERR_PTR(-EINVAL);
}
* and anycast addresses will be checked later.
*/
if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n");
+ net_dbg_ratelimited("icmp6_send: addr_any/mcast source\n");
return;
}
* Never answer to a ICMP packet.
*/
if (is_ineligible(skb)) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n");
+ net_dbg_ratelimited("icmp6_send: no reply to icmp error\n");
return;
}
len = skb->len - msg.offset;
len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
if (len < 0) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
+ net_dbg_ratelimited("icmp: len problem\n");
goto out_dst_release;
}
daddr = &ipv6_hdr(skb)->daddr;
if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
- LIMIT_NETDEBUG(KERN_DEBUG
- "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
- saddr, daddr);
+ net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n",
+ saddr, daddr);
goto csum_error;
}
if (type & ICMPV6_INFOMSG_MASK)
break;
- LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n");
+ net_dbg_ratelimited("icmpv6: msg of unknown type\n");
/*
* error of unknown type.
return table;
}
#endif
-
static int ip6fl_seq_show(struct seq_file *seq, void *v)
{
struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
- if (v == SEQ_START_TOKEN)
- seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n",
- "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
- else {
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, "Label S Owner Users Linger Expires Dst Opt\n");
+ } else {
struct ip6_flowlabel *fl = v;
seq_printf(seq,
"%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
struct net_device_stats *stats = &t->dev->stats;
int ret;
- if (!ip6_tnl_xmit_ctl(t))
+ if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
goto tx_err;
switch (skb->protocol) {
SKB_GSO_SIT |
SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM |
- SKB_GSO_MPLS |
+ SKB_GSO_TUNNEL_REMCSUM |
SKB_GSO_TCPV6 |
0)))
goto out;
if (len < left) {
len &= ~7;
}
- /*
- * Allocate buffer.
- */
- if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
- hroom + troom, GFP_ATOMIC)) == NULL) {
- NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
+ /* Allocate buffer */
+ frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
+ hroom + troom, GFP_ATOMIC);
+ if (!frag) {
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
unsigned int hash = HASH(remote, local);
struct ip6_tnl *t;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ struct in6_addr any;
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
(t->dev->flags & IFF_UP))
return t;
}
+
+ memset(&any, 0, sizeof(any));
+ hash = HASH(&any, local);
+ for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ if (ipv6_addr_equal(local, &t->parms.laddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+
+ hash = HASH(remote, &any);
+ for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+
t = rcu_dereference(ip6n->tnls_wc[0]);
if (t && (t->dev->flags & IFF_UP))
return t;
int rel_msg = 0;
u8 rel_type = ICMPV6_DEST_UNREACH;
u8 rel_code = ICMPV6_ADDR_UNREACH;
+ u8 tproto;
__u32 rel_info = 0;
__u16 len;
int err = -ENOENT;
&ipv6h->saddr)) == NULL)
goto out;
- if (t->parms.proto != ipproto && t->parms.proto != 0)
+ tproto = ACCESS_ONCE(t->parms.proto);
+ if (tproto != ipproto && tproto != 0)
goto out;
err = 0;
{
struct ip6_tnl *t;
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ u8 tproto;
int err;
rcu_read_lock();
&ipv6h->daddr)) != NULL) {
struct pcpu_sw_netstats *tstats;
- if (t->parms.proto != ipproto && t->parms.proto != 0) {
+ tproto = ACCESS_ONCE(t->parms.proto);
+ if (tproto != ipproto && tproto != 0) {
rcu_read_unlock();
goto discard;
}
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
}
-int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
+ const struct in6_addr *laddr,
+ const struct in6_addr *raddr)
{
struct __ip6_tnl_parm *p = &t->parms;
int ret = 0;
struct net *net = t->net;
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
+ if ((p->flags & IP6_TNL_F_CAP_XMIT) ||
+ ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
+ (ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_XMIT))) {
struct net_device *ldev = NULL;
rcu_read_lock();
if (p->link)
ldev = dev_get_by_index_rcu(net, p->link);
- if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0)))
+ if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0)))
pr_warn("%s xmit: Local address not yet configured!\n",
p->name);
- else if (!ipv6_addr_is_multicast(&p->raddr) &&
- unlikely(ipv6_chk_addr(net, &p->raddr, NULL, 0)))
+ else if (!ipv6_addr_is_multicast(raddr) &&
+ unlikely(ipv6_chk_addr(net, raddr, NULL, 0)))
pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
p->name);
else
u8 proto;
int err = -1;
- if (!fl6->flowi6_mark)
+ /* NBMA tunnel */
+ if (ipv6_addr_any(&t->parms.raddr)) {
+ struct in6_addr *addr6;
+ struct neighbour *neigh;
+ int addr_type;
+
+ if (!skb_dst(skb))
+ goto tx_err_link_failure;
+
+ neigh = dst_neigh_lookup(skb_dst(skb),
+ &ipv6_hdr(skb)->daddr);
+ if (!neigh)
+ goto tx_err_link_failure;
+
+ addr6 = (struct in6_addr *)&neigh->primary_key;
+ addr_type = ipv6_addr_type(addr6);
+
+ if (addr_type == IPV6_ADDR_ANY)
+ addr6 = &ipv6_hdr(skb)->daddr;
+
+ memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
+ neigh_release(neigh);
+ } else if (!fl6->flowi6_mark)
dst = ip6_tnl_dst_check(t);
+
+ if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
+ goto tx_err_link_failure;
+
if (!dst) {
ndst = ip6_route_output(net, NULL, fl6);
struct flowi6 fl6;
__u8 dsfield;
__u32 mtu;
+ u8 tproto;
int err;
- if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
- !ip6_tnl_xmit_ctl(t))
+ tproto = ACCESS_ONCE(t->parms.proto);
+ if (tproto != IPPROTO_IPIP && tproto != 0)
return -1;
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
struct flowi6 fl6;
__u8 dsfield;
__u32 mtu;
+ u8 tproto;
int err;
- if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
- !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
+ tproto = ACCESS_ONCE(t->parms.proto);
+ if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
+ ip6_tnl_addr_conflict(t, ipv6h))
return -1;
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
return err;
}
+static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+{
+ /* for default tnl0 device allow to change only the proto */
+ t->parms.proto = p->proto;
+ netdev_state_change(t->dev);
+ return 0;
+}
+
static void
ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
{
break;
ip6_tnl_parm_from_user(&p1, &p);
t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
- if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
+ if (cmd == SIOCCHGTUNNEL) {
if (t != NULL) {
if (t->dev != dev) {
err = -EEXIST;
}
} else
t = netdev_priv(dev);
-
- err = ip6_tnl_update(t, &p1);
+ if (dev == ip6n->fb_tnl_dev)
+ err = ip6_tnl0_update(t, &p1);
+ else
+ err = ip6_tnl_update(t, &p1);
}
if (t) {
err = 0;
struct net_device_stats *stats = &t->dev->stats;
struct dst_entry *dst = skb_dst(skb);
struct net_device *tdev;
+ struct xfrm_state *x;
int err = -1;
if (!dst)
goto tx_err_link_failure;
}
- if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
+ x = dst->xfrm;
+ if (!vti6_state_check(x, &t->parms.raddr, &t->parms.laddr))
+ goto tx_err_link_failure;
+
+ if (!ip6_tnl_xmit_ctl(t, (const struct in6_addr *)&x->props.saddr,
+ (const struct in6_addr *)&x->id.daddr))
goto tx_err_link_failure;
tdev = dst->dev;
ipv6h = ipv6_hdr(skb);
if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
- !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
+ vti6_addr_conflict(t, ipv6h))
goto tx_err;
xfrm_decode_session(skb, &fl, AF_INET6);
if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
struct mfc6_cache *cache_proxy;
- /* For an (*,G) entry, we only check that the incomming
+ /* For an (*,G) entry, we only check that the incoming
* interface is part of the static tree.
*/
cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
hdr->daddr = *daddr;
}
-static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
+static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
{
struct net_device *dev = idev->dev;
struct net *net = dev_net(dev);
const struct in6_addr *saddr;
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
+ unsigned int size = mtu + hlen + tlen;
int err;
u8 ra[8] = { IPPROTO_ICMPV6, 0,
IPV6_TLV_ROUTERALERT, 2, 0, 0,
IPV6_TLV_PADN, 0 };
/* we assume size > sizeof(ra) here */
- size += hlen + tlen;
/* limit our allocations to order-0 page */
size = min_t(int, size, SKB_MAX_ORDER(0, 0));
skb = sock_alloc_send_skb(sk, size, 1, &err);
return NULL;
skb->priority = TC_PRIO_CONTROL;
+ skb->reserved_tailroom = skb_end_offset(skb) -
+ min(mtu, skb_end_offset(skb));
skb_reserve(skb, hlen);
if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
return skb;
}
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
- skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
int type, int gdeleted, int sdeleted, int crsend)
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
if (v == SEQ_START_TOKEN) {
- seq_printf(seq,
- "%3s %6s "
- "%32s %32s %6s %6s\n", "Idx",
- "Device", "Multicast Address",
- "Source Address", "INC", "EXC");
+ seq_puts(seq, "Idx Device Multicast Address Source Address INC EXC\n");
} else {
seq_printf(seq,
"%3d %6.6s %pi6 %pi6 %6lu %6lu\n",
return -1;
if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
- LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
- mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
+ net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d\n",
+ mh->ip6mh_hdrlen,
+ mip6_mh_len(mh->ip6mh_type));
mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) +
skb_network_header_len(skb));
return -1;
}
if (mh->ip6mh_proto != IPPROTO_NONE) {
- LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
- mh->ip6mh_proto);
+ net_dbg_ratelimited("mip6: MH invalid payload proto = %d\n",
+ mh->ip6mh_proto);
mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) +
skb_network_header_len(skb));
return -1;
* XXX: packet if HAO exists.
*/
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
- LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n");
+ net_dbg_ratelimited("mip6: hao exists already, override\n");
return offset;
}
/*
* Initialize the neighbour table
*/
- neigh_table_init(&nd_tbl);
+ neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
#ifdef CONFIG_SYSCTL
err = neigh_sysctl_register(NULL, &nd_tbl.parms,
#ifdef CONFIG_SYSCTL
neigh_sysctl_unregister(&nd_tbl.parms);
#endif
- neigh_table_clear(&nd_tbl);
+ neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
unregister_pernet_subsys(&ndisc_net_ops);
}
err = dst->error;
if (err) {
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
- LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
+ net_dbg_ratelimited("ip6_route_me_harder: No more route\n");
dst_release(dst);
return err;
}
SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS),
SNMP_MIB_ITEM("Udp6InCsumErrors", UDP_MIB_CSUMERRORS),
+ SNMP_MIB_ITEM("Udp6IgnoredMulti", UDP_MIB_IGNOREDMULTI),
SNMP_MIB_SENTINEL
};
}
if (skb_csum_unnecessary(skb)) {
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
} else if (msg->msg_flags&MSG_TRUNC) {
if (__skb_checksum_complete(skb))
goto csum_copy_err;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
} else {
err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov);
if (err == -EINVAL)
if (!rp->checksum)
goto send;
- if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
+ skb = skb_peek(&sk->sk_write_queue);
+ if (!skb)
goto out;
offset = rp->offset;
#define FRAG6_CB(skb) ((struct ip6frag_skb_cb *)((skb)->cb))
-static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
+static u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
{
return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
}
ip6_expire_frag_queue(net, fq, &ip6_frags);
}
-static __inline__ struct frag_queue *
+static struct frag_queue *
fq_find(struct net *net, __be32 id, const struct in6_addr *src,
const struct in6_addr *dst, u8 ecn)
{
unregister_net_sysctl_table(ip6_ctl_header);
}
#else
-static inline int ip6_frags_ns_sysctl_register(struct net *net)
+static int ip6_frags_ns_sysctl_register(struct net *net)
{
return 0;
}
-static inline void ip6_frags_ns_sysctl_unregister(struct net *net)
+static void ip6_frags_ns_sysctl_unregister(struct net *net)
{
}
-static inline int ip6_frags_sysctl_register(void)
+static int ip6_frags_sysctl_register(void)
{
return 0;
}
-static inline void ip6_frags_sysctl_unregister(void)
+static void ip6_frags_sysctl_unregister(void)
{
}
#endif
}
#endif
-#define BACKTRACK(__net, saddr) \
-do { \
- if (rt == __net->ipv6.ip6_null_entry) { \
- struct fib6_node *pn; \
- while (1) { \
- if (fn->fn_flags & RTN_TL_ROOT) \
- goto out; \
- pn = fn->parent; \
- if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
- fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
- else \
- fn = pn; \
- if (fn->fn_flags & RTN_RTINFO) \
- goto restart; \
- } \
- } \
-} while (0)
+static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
+ struct in6_addr *saddr)
+{
+ struct fib6_node *pn;
+ while (1) {
+ if (fn->fn_flags & RTN_TL_ROOT)
+ return NULL;
+ pn = fn->parent;
+ if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
+ fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
+ else
+ fn = pn;
+ if (fn->fn_flags & RTN_RTINFO)
+ return fn;
+ }
+}
static struct rt6_info *ip6_pol_route_lookup(struct net *net,
struct fib6_table *table,
rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
- BACKTRACK(net, &fl6->saddr);
-out:
+ if (rt == net->ipv6.ip6_null_entry) {
+ fn = fib6_backtrack(fn, &fl6->saddr);
+ if (fn)
+ goto restart;
+ }
dst_use(&rt->dst, jiffies);
read_unlock_bh(&table->tb6_lock);
return rt;
static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
struct flowi6 *fl6, int flags)
{
- struct fib6_node *fn;
+ struct fib6_node *fn, *saved_fn;
struct rt6_info *rt, *nrt;
int strict = 0;
int attempts = 3;
int err;
- int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
strict |= flags & RT6_LOOKUP_F_IFACE;
+ if (net->ipv6.devconf_all->forwarding == 0)
+ strict |= RT6_LOOKUP_F_REACHABLE;
-relookup:
+redo_fib6_lookup_lock:
read_lock_bh(&table->tb6_lock);
-restart_2:
fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
+ saved_fn = fn;
-restart:
- rt = rt6_select(fn, oif, strict | reachable);
+redo_rt6_select:
+ rt = rt6_select(fn, oif, strict);
if (rt->rt6i_nsiblings)
- rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
- BACKTRACK(net, &fl6->saddr);
- if (rt == net->ipv6.ip6_null_entry ||
- rt->rt6i_flags & RTF_CACHE)
- goto out;
+ rt = rt6_multipath_select(rt, fl6, oif, strict);
+ if (rt == net->ipv6.ip6_null_entry) {
+ fn = fib6_backtrack(fn, &fl6->saddr);
+ if (fn)
+ goto redo_rt6_select;
+ else if (strict & RT6_LOOKUP_F_REACHABLE) {
+ /* also consider unreachable route */
+ strict &= ~RT6_LOOKUP_F_REACHABLE;
+ fn = saved_fn;
+ goto redo_rt6_select;
+ } else {
+ dst_hold(&rt->dst);
+ read_unlock_bh(&table->tb6_lock);
+ goto out2;
+ }
+ }
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
+ if (rt->rt6i_flags & RTF_CACHE)
+ goto out2;
+
if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
else if (!(rt->dst.flags & DST_HOST))
* released someone could insert this route. Relookup.
*/
ip6_rt_put(rt);
- goto relookup;
+ goto redo_fib6_lookup_lock;
-out:
- if (reachable) {
- reachable = 0;
- goto restart_2;
- }
- dst_hold(&rt->dst);
- read_unlock_bh(&table->tb6_lock);
out2:
rt->dst.lastuse = jiffies;
rt->dst.__use++;
rt = net->ipv6.ip6_null_entry;
else if (rt->dst.error) {
rt = net->ipv6.ip6_null_entry;
- goto out;
+ } else if (rt == net->ipv6.ip6_null_entry) {
+ fn = fib6_backtrack(fn, &fl6->saddr);
+ if (fn)
+ goto restart;
}
- BACKTRACK(net, &fl6->saddr);
-out:
+
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT,
tunnel->encap.dport) ||
nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
- tunnel->encap.dport))
+ tunnel->encap.flags))
goto nla_put_failure;
return 0;
int mss;
struct dst_entry *dst;
__u8 rcv_wscale;
- bool ecn_ok = false;
if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
- if (tcp_synq_no_recent_overflow(sk) ||
- (mss = __cookie_v6_check(ipv6_hdr(skb), th, cookie)) == 0) {
+ if (tcp_synq_no_recent_overflow(sk))
+ goto out;
+
+ mss = __cookie_v6_check(ipv6_hdr(skb), th, cookie);
+ if (mss == 0) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED);
goto out;
}
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, 0, NULL);
- if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
+ if (!cookie_timestamp_decode(&tcp_opt))
goto out;
ret = NULL;
req->expires = 0UL;
req->num_retrans = 0;
- ireq->ecn_ok = ecn_ok;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
dst_metric(dst, RTAX_INITRWND));
ireq->rcv_wscale = rcv_wscale;
+ ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst);
ret = get_cookie_sock(sk, skb, req, dst);
out:
reqsk_free(req);
return NULL;
}
-
struct dst_entry *dst = sk->sk_rx_dst;
sock_rps_save_rxhash(sk, skb);
+ sk_mark_napi_id(sk, skb);
if (dst) {
if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
*/
if (nsk != sk) {
sock_rps_save_rxhash(nsk, skb);
+ sk_mark_napi_id(sk, skb);
if (tcp_child_process(sk, nsk, skb))
goto reset;
if (opt_skb)
if (sk_filter(sk, skb))
goto discard_and_relse;
- sk_mark_napi_id(sk, skb);
+ sk_incoming_cpu_update(sk);
skb->dev = NULL;
bh_lock_sock_nested(sk);
}
if (skb_csum_unnecessary(skb))
- err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
- msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
+ msg, copied);
else {
err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
if (err == -EINVAL)
if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
sock_rps_save_rxhash(sk, skb);
sk_mark_napi_id(sk, skb);
+ sk_incoming_cpu_update(sk);
}
rc = sock_queue_rcv_skb(sk, skb);
if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) {
if (up->pcrlen == 0) { /* full coverage was set */
- LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage"
- " %d while full coverage %d requested\n",
- UDP_SKB_CB(skb)->cscov, skb->len);
+ net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n",
+ UDP_SKB_CB(skb)->cscov, skb->len);
goto drop;
}
if (UDP_SKB_CB(skb)->cscov < up->pcrlen) {
- LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d "
- "too small, need min %d\n",
- UDP_SKB_CB(skb)->cscov, up->pcrlen);
+ net_dbg_ratelimited("UDPLITE6: coverage %d too small, need min %d\n",
+ UDP_SKB_CB(skb)->cscov, up->pcrlen);
goto drop;
}
}
/* RFC 2460 section 8.1 says that we SHOULD log
* this error. Well, it is reasonable.
*/
- LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
- &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
- &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
+ net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
+ &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
+ &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
}
/*
*/
static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
const struct in6_addr *saddr, const struct in6_addr *daddr,
- struct udp_table *udptable)
+ struct udp_table *udptable, int proto)
{
struct sock *sk, *stack[256 / sizeof(struct sock *)];
const struct udphdr *uh = udp_hdr(skb);
int dif = inet6_iif(skb);
unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
+ bool inner_flushed = false;
if (use_hash2) {
hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) &
(uh->check || udp_sk(sk)->no_check6_rx)) {
if (unlikely(count == ARRAY_SIZE(stack))) {
flush_stack(stack, count, skb, ~0);
+ inner_flushed = true;
count = 0;
}
stack[count++] = sk;
if (count) {
flush_stack(stack, count, skb, count - 1);
} else {
- kfree_skb(skb);
+ if (!inner_flushed)
+ UDP_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
+ proto == IPPROTO_UDPLITE);
+ consume_skb(skb);
}
return 0;
}
*/
if (ipv6_addr_is_multicast(daddr))
return __udp6_lib_mcast_deliver(net, skb,
- saddr, daddr, udptable);
+ saddr, daddr, udptable, proto);
/* Unicast */
return 0;
short_packet:
- LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n",
- proto == IPPROTO_UDPLITE ? "-Lite" : "",
- saddr,
- ntohs(uh->source),
- ulen,
- skb->len,
- daddr,
- ntohs(uh->dest));
+ net_dbg_ratelimited("UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n",
+ proto == IPPROTO_UDPLITE ? "-Lite" : "",
+ saddr, ntohs(uh->source),
+ ulen, skb->len,
+ daddr, ntohs(uh->dest));
goto discard;
csum_error:
UDP6_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE);
/* ... which is an evident application bug. --ANK */
release_sock(sk);
- LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n");
+ net_dbg_ratelimited("udp cork app bug 2\n");
err = -EINVAL;
goto out;
}
SKB_GSO_DODGY |
SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM |
+ SKB_GSO_TUNNEL_REMCSUM |
SKB_GSO_GRE |
SKB_GSO_GRE_CSUM |
SKB_GSO_IPIP |
- SKB_GSO_SIT |
- SKB_GSO_MPLS) ||
+ SKB_GSO_SIT) ||
!(type & (SKB_GSO_UDP))))
goto out;
spin_unlock_bh(&ipx_interfaces_lock);
}
-static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
+static void __ipxitf_put(struct ipx_interface *intrfc)
{
if (atomic_dec_and_test(&intrfc->refcnt))
__ipxitf_down(intrfc);
msg->msg_flags |= MSG_TRUNC;
}
- rc = skb_copy_datagram_iovec(skb, sizeof(struct ipxhdr), msg->msg_iov,
- copied);
+ rc = skb_copy_datagram_msg(skb, sizeof(struct ipxhdr), msg, copied);
if (rc)
goto out_free;
if (skb->tstamp.tv64)
}
i = list_entry(v, struct ipx_interface, node);
- seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum));
+ seq_printf(seq, "%08X ", ntohl(i->if_netnum));
seq_printf(seq, "%02X%02X%02X%02X%02X%02X ",
i->if_node[0], i->if_node[1], i->if_node[2],
i->if_node[3], i->if_node[4], i->if_node[5]);
rt = list_entry(v, struct ipx_route, node);
- seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net));
+ seq_printf(seq, "%08X ", ntohl(rt->ir_net));
if (rt->ir_routed)
- seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n",
- (long unsigned int)ntohl(rt->ir_intrfc->if_netnum),
+ seq_printf(seq, "%08X %02X%02X%02X%02X%02X%02X\n",
+ ntohl(rt->ir_intrfc->if_netnum),
rt->ir_router_node[0], rt->ir_router_node[1],
rt->ir_router_node[2], rt->ir_router_node[3],
rt->ir_router_node[4], rt->ir_router_node[5]);
s = v;
ipxs = ipx_sk(s);
#ifdef CONFIG_IPX_INTERN
- seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
- (unsigned long)ntohl(ipxs->intrfc->if_netnum),
+ seq_printf(seq, "%08X:%02X%02X%02X%02X%02X%02X:%04X ",
+ ntohl(ipxs->intrfc->if_netnum),
ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3],
ipxs->node[4], ipxs->node[5], ntohs(ipxs->port));
#else
- seq_printf(seq, "%08lX:%04X ", (unsigned long) ntohl(ipxs->intrfc->if_netnum),
+ seq_printf(seq, "%08X:%04X ", ntohl(ipxs->intrfc->if_netnum),
ntohs(ipxs->port));
#endif /* CONFIG_IPX_INTERN */
if (s->sk_state != TCP_ESTABLISHED)
seq_printf(seq, "%-28s", "Not_Connected");
else {
- seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
- (unsigned long)ntohl(ipxs->dest_addr.net),
+ seq_printf(seq, "%08X:%02X%02X%02X%02X%02X%02X:%04X ",
+ ntohl(ipxs->dest_addr.net),
ipxs->dest_addr.node[0], ipxs->dest_addr.node[1],
ipxs->dest_addr.node[2], ipxs->dest_addr.node[3],
ipxs->dest_addr.node[4], ipxs->dest_addr.node[5],
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <net/net_namespace.h>
+#include <net/ipx.h>
#ifndef CONFIG_SYSCTL
#error This file should not be compiled without CONFIG_SYSCTL defined
#endif
-/* From af_ipx.c */
-extern int sysctl_ipx_pprop_broadcasting;
-
static struct ctl_table ipx_table[] = {
{
.procname = "ipx_pprop_broadcasting",
struct sock *sk;
int err;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
self = instance;
sk = instance;
err = sock_queue_rcv_skb(sk, skb);
if (err) {
- IRDA_DEBUG(1, "%s(), error: no more mem!\n", __func__);
+ pr_debug("%s(), error: no more mem!\n", __func__);
self->rx_flow = FLOW_STOP;
/* When we return error, TTP will need to requeue the skb */
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
/* Don't care about it, but let's not leak it */
if(skb)
sk = instance;
if (sk == NULL) {
- IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n",
- __func__, self);
+ pr_debug("%s(%p) : BUG : sk is NULL\n",
+ __func__, self);
return;
}
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
sk = instance;
if (sk == NULL) {
switch (sk->sk_type) {
case SOCK_STREAM:
if (max_sdu_size != 0) {
- IRDA_ERROR("%s: max_sdu_size must be 0\n",
- __func__);
+ net_err_ratelimited("%s: max_sdu_size must be 0\n",
+ __func__);
return;
}
self->max_data_size = irttp_get_max_seg_size(self->tsap);
break;
case SOCK_SEQPACKET:
if (max_sdu_size == 0) {
- IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
- __func__);
+ net_err_ratelimited("%s: max_sdu_size cannot be 0\n",
+ __func__);
return;
}
self->max_data_size = max_sdu_size;
self->max_data_size = irttp_get_max_seg_size(self->tsap);
}
- IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
- self->max_data_size);
+ pr_debug("%s(), max_data_size=%d\n", __func__,
+ self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
self = instance;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
sk = instance;
if (sk == NULL) {
switch (sk->sk_type) {
case SOCK_STREAM:
if (max_sdu_size != 0) {
- IRDA_ERROR("%s: max_sdu_size must be 0\n",
- __func__);
+ net_err_ratelimited("%s: max_sdu_size must be 0\n",
+ __func__);
kfree_skb(skb);
return;
}
break;
case SOCK_SEQPACKET:
if (max_sdu_size == 0) {
- IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
- __func__);
+ net_err_ratelimited("%s: max_sdu_size cannot be 0\n",
+ __func__);
kfree_skb(skb);
return;
}
self->max_data_size = irttp_get_max_seg_size(self->tsap);
}
- IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
- self->max_data_size);
+ pr_debug("%s(), max_data_size=%d\n", __func__,
+ self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
{
struct sk_buff *skb;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL);
if (skb == NULL) {
- IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
- __func__);
+ pr_debug("%s() Unable to allocate sk_buff!\n",
+ __func__);
return;
}
struct irda_sock *self;
struct sock *sk;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
self = instance;
sk = instance;
BUG_ON(sk == NULL);
switch (flow) {
case FLOW_STOP:
- IRDA_DEBUG(1, "%s(), IrTTP wants us to slow down\n",
- __func__);
+ pr_debug("%s(), IrTTP wants us to slow down\n",
+ __func__);
self->tx_flow = flow;
break;
case FLOW_START:
self->tx_flow = flow;
- IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n",
- __func__);
+ pr_debug("%s(), IrTTP wants us to start again\n",
+ __func__);
wake_up_interruptible(sk_sleep(sk));
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __func__);
+ pr_debug("%s(), Unknown flow command!\n", __func__);
/* Unknown flow command, better stop */
self->tx_flow = flow;
break;
self = priv;
if (!self) {
- IRDA_WARNING("%s: lost myself!\n", __func__);
+ net_warn_ratelimited("%s: lost myself!\n", __func__);
return;
}
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
/* We probably don't need to make any more queries */
iriap_close(self->iriap);
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __func__,
- result);
+ pr_debug("%s(), IAS query failed! (%d)\n", __func__,
+ result);
self->errno = result; /* We really need it later */
{
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
self = priv;
if (!self) {
- IRDA_WARNING("%s: lost myself!\n", __func__);
+ net_warn_ratelimited("%s: lost myself!\n", __func__);
return;
}
{
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
self = (struct irda_sock *) priv;
BUG_ON(self == NULL);
notify_t notify;
if (self->tsap) {
- IRDA_DEBUG(0, "%s: busy!\n", __func__);
+ pr_debug("%s: busy!\n", __func__);
return -EBUSY;
}
self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT,
¬ify);
if (self->tsap == NULL) {
- IRDA_DEBUG(0, "%s(), Unable to allocate TSAP!\n",
- __func__);
+ pr_debug("%s(), Unable to allocate TSAP!\n",
+ __func__);
return -ENOMEM;
}
/* Remember which TSAP selector we actually got */
notify_t notify;
if (self->lsap) {
- IRDA_WARNING("%s(), busy!\n", __func__);
+ net_warn_ratelimited("%s(), busy!\n", __func__);
return -EBUSY;
}
self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, pid);
if (self->lsap == NULL) {
- IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __func__);
+ pr_debug("%s(), Unable to allocate LSAP!\n", __func__);
return -ENOMEM;
}
*/
static int irda_find_lsap_sel(struct irda_sock *self, char *name)
{
- IRDA_DEBUG(2, "%s(%p, %s)\n", __func__, self, name);
+ pr_debug("%s(%p, %s)\n", __func__, self, name);
if (self->iriap) {
- IRDA_WARNING("%s(): busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s(): busy with a previous query\n",
+ __func__);
return -EBUSY;
}
/* Get the remote TSAP selector */
switch (self->ias_result->type) {
case IAS_INTEGER:
- IRDA_DEBUG(4, "%s() int=%d\n",
- __func__, self->ias_result->t.integer);
+ pr_debug("%s() int=%d\n",
+ __func__, self->ias_result->t.integer);
if (self->ias_result->t.integer != -1)
self->dtsap_sel = self->ias_result->t.integer;
break;
default:
self->dtsap_sel = 0;
- IRDA_DEBUG(0, "%s(), bad type!\n", __func__);
+ pr_debug("%s(), bad type!\n", __func__);
break;
}
if (self->ias_result)
__u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */
__u8 dtsap_sel = 0x0; /* TSAP associated with it */
- IRDA_DEBUG(2, "%s(), name=%s\n", __func__, name);
+ pr_debug("%s(), name=%s\n", __func__, name);
/* Ask lmp for the current discovery log
* Note : we have to use irlmp_get_discoveries(), as opposed
/* Try the address in the log */
self->daddr = discoveries[i].daddr;
self->saddr = 0x0;
- IRDA_DEBUG(1, "%s(), trying daddr = %08x\n",
- __func__, self->daddr);
+ pr_debug("%s(), trying daddr = %08x\n",
+ __func__, self->daddr);
/* Query remote LM-IAS for this service */
err = irda_find_lsap_sel(self, name);
case 0:
/* We found the requested service */
if(daddr != DEV_ADDR_ANY) {
- IRDA_DEBUG(1, "%s(), discovered service ''%s'' in two different devices !!!\n",
- __func__, name);
+ pr_debug("%s(), discovered service ''%s'' in two different devices !!!\n",
+ __func__, name);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
return -ENOTUNIQ;
break;
default:
/* Something bad did happen :-( */
- IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __func__);
+ pr_debug("%s(), unexpected IAS query failure\n",
+ __func__);
self->daddr = DEV_ADDR_ANY;
kfree(discoveries);
return -EHOSTUNREACH;
/* Check out what we found */
if(daddr == DEV_ADDR_ANY) {
- IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n",
- __func__, name);
+ pr_debug("%s(), cannot discover service ''%s'' in any device !!!\n",
+ __func__, name);
self->daddr = DEV_ADDR_ANY;
return -EADDRNOTAVAIL;
}
self->saddr = 0x0;
self->dtsap_sel = dtsap_sel;
- IRDA_DEBUG(1, "%s(), discovered requested service ''%s'' at address %08x\n",
- __func__, name, self->daddr);
+ pr_debug("%s(), discovered requested service ''%s'' at address %08x\n",
+ __func__, name, self->daddr);
return 0;
}
saddr.sir_addr = self->saddr;
}
- IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
- IRDA_DEBUG(1, "%s(), addr = %08x\n", __func__, saddr.sir_addr);
+ pr_debug("%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
+ pr_debug("%s(), addr = %08x\n", __func__, saddr.sir_addr);
/* uaddr_len come to us uninitialised */
*uaddr_len = sizeof (struct sockaddr_irda);
struct sock *sk = sock->sk;
int err = -EOPNOTSUPP;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
lock_sock(sk);
if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
struct irda_sock *self = irda_sk(sk);
int err;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL;
self->pid = addr->sir_lsap_sel;
err = -EOPNOTSUPP;
if (self->pid & 0x80) {
- IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
+ pr_debug("%s(), extension in PID not supp!\n",
+ __func__);
goto out;
}
err = irda_open_lsap(self, self->pid);
struct sk_buff *skb;
int err;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0);
if (err)
return err;
new->tsap = irttp_dup(self->tsap, new);
err = -EPERM; /* value does not seem to make sense. -arnd */
if (!new->tsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
+ pr_debug("%s(), dup failed!\n", __func__);
kfree_skb(skb);
goto out;
}
struct irda_sock *self = irda_sk(sk);
int err;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
lock_sock(sk);
/* Don't allow connect for Ultra sockets */
/* Try to find one suitable */
err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
if (err) {
- IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __func__);
+ pr_debug("%s(), auto-connect failed!\n", __func__);
goto out;
}
} else {
/* Use the one provided by the user */
self->daddr = addr->sir_addr;
- IRDA_DEBUG(1, "%s(), daddr = %08x\n", __func__, self->daddr);
+ pr_debug("%s(), daddr = %08x\n", __func__, self->daddr);
/* If we don't have a valid service name, we assume the
* user want to connect on a specific LSAP. Prevent
/* Query remote LM-IAS using service name */
err = irda_find_lsap_sel(self, addr->sir_name);
if (err) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
+ pr_debug("%s(), connect failed!\n", __func__);
goto out;
}
} else {
self->saddr, self->daddr, NULL,
self->max_sdu_size_rx, NULL);
if (err) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
+ pr_debug("%s(), connect failed!\n", __func__);
goto out;
}
struct sock *sk;
struct irda_sock *self;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
if (net != &init_net)
return -EAFNOSUPPORT;
return -ENOMEM;
self = irda_sk(sk);
- IRDA_DEBUG(2, "%s() : self is %p\n", __func__, self);
+ pr_debug("%s() : self is %p\n", __func__, self);
init_waitqueue_head(&self->query_wait);
*/
static void irda_destroy_socket(struct irda_sock *self)
{
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
/* Unregister with IrLMP */
irlmp_unregister_client(self->ckey);
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
if (sk == NULL)
return 0;
struct sk_buff *skb;
int err = -EPIPE;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
+ pr_debug("%s(), len=%zd\n", __func__, len);
/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
/* Check that we don't send out too big frames */
if (len > self->max_data_size) {
- IRDA_DEBUG(2, "%s(), Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
+ pr_debug("%s(), Chopping frame from %zd to %d bytes!\n",
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
*/
err = irttp_data_request(self->tsap, skb);
if (err) {
- IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
+ pr_debug("%s(), err=%d\n", __func__, err);
goto out_err;
}
size_t copied;
int err;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
if (!skb)
copied = skb->len;
if (copied > size) {
- IRDA_DEBUG(2, "%s(), Received truncated frame (%zd < %zd)!\n",
- __func__, copied, size);
+ pr_debug("%s(), Received truncated frame (%zd < %zd)!\n",
+ __func__, copied, size);
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
- skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ skb_copy_datagram_msg(skb, 0, msg, copied);
skb_free_datagram(sk, skb);
*/
if (self->rx_flow == FLOW_STOP) {
if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
+ pr_debug("%s(), Starting IrTTP\n", __func__);
self->rx_flow = FLOW_START;
irttp_flow_request(self->tsap, FLOW_START);
}
int target, err;
long timeo;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
if ((err = sock_error(sk)) < 0)
return err;
/* put the skb back if we didn't use it up.. */
if (skb->len) {
- IRDA_DEBUG(1, "%s(), back on q!\n",
- __func__);
+ pr_debug("%s(), back on q!\n",
+ __func__);
skb_queue_head(&sk->sk_receive_queue, skb);
break;
}
kfree_skb(skb);
} else {
- IRDA_DEBUG(0, "%s() questionable!?\n", __func__);
+ pr_debug("%s() questionable!?\n", __func__);
/* put message back and return */
skb_queue_head(&sk->sk_receive_queue, skb);
*/
if (self->rx_flow == FLOW_STOP) {
if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
+ pr_debug("%s(), Starting IrTTP\n", __func__);
self->rx_flow = FLOW_START;
irttp_flow_request(self->tsap, FLOW_START);
}
struct sk_buff *skb;
int err;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
+ pr_debug("%s(), len=%zd\n", __func__, len);
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
return -EINVAL;
* service, so we have no fragmentation and no coalescence
*/
if (len > self->max_data_size) {
- IRDA_DEBUG(0, "%s(), Warning to much data! "
- "Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
+ pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n",
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
skb_reserve(skb, self->max_header_size);
skb_reset_transport_header(skb);
- IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
+ pr_debug("%s(), appending user data\n", __func__);
skb_put(skb, len);
err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
if (err) {
*/
err = irttp_udata_request(self->tsap, skb);
if (err) {
- IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
+ pr_debug("%s(), err=%d\n", __func__, err);
goto out;
}
struct sk_buff *skb;
int err;
- IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
+ pr_debug("%s(), len=%zd\n", __func__, len);
err = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
pid = addr->sir_lsap_sel;
if (pid & 0x80) {
- IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
+ pr_debug("%s(), extension in PID not supp!\n",
+ __func__);
err = -EOPNOTSUPP;
goto out;
}
* port. Jean II */
if ((self->lsap == NULL) ||
(sk->sk_state != TCP_ESTABLISHED)) {
- IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n",
- __func__);
+ pr_debug("%s(), socket not bound to Ultra PID.\n",
+ __func__);
err = -ENOTCONN;
goto out;
}
* service, so we have no fragmentation and no coalescence
*/
if (len > self->max_data_size) {
- IRDA_DEBUG(0, "%s(), Warning to much data! "
- "Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
+ pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n",
+ __func__, len, self->max_data_size);
len = self->max_data_size;
}
skb_reserve(skb, self->max_header_size);
skb_reset_transport_header(skb);
- IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
+ pr_debug("%s(), appending user data\n", __func__);
skb_put(skb, len);
err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
if (err) {
err = irlmp_connless_data_request((bound ? self->lsap : NULL),
skb, pid);
if (err)
- IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
+ pr_debug("%s(), err=%d\n", __func__, err);
out:
release_sock(sk);
return err ? : len;
struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk);
- IRDA_DEBUG(1, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
lock_sock(sk);
struct irda_sock *self = irda_sk(sk);
unsigned int mask;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
poll_wait(file, sk_sleep(sk), wait);
mask = 0;
if (sk->sk_err)
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN) {
- IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
+ pr_debug("%s(), POLLHUP\n", __func__);
mask |= POLLHUP;
}
/* Readable? */
if (!skb_queue_empty(&sk->sk_receive_queue)) {
- IRDA_DEBUG(4, "Socket is readable\n");
+ pr_debug("Socket is readable\n");
mask |= POLLIN | POLLRDNORM;
}
switch (sk->sk_type) {
case SOCK_STREAM:
if (sk->sk_state == TCP_CLOSE) {
- IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
+ pr_debug("%s(), POLLHUP\n", __func__);
mask |= POLLHUP;
}
struct sock *sk = sock->sk;
int err;
- IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);
+ pr_debug("%s(), cmd=%#x\n", __func__, cmd);
err = -EINVAL;
switch (cmd) {
case SIOCSIFMETRIC:
break;
default:
- IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
+ pr_debug("%s(), doing device ioctl!\n", __func__);
err = -ENOIOCTLCMD;
}
struct ias_attrib * ias_attr; /* Attribute in IAS object */
int opt, free_ias = 0, err = 0;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
/* Check is the user space own the object */
if(ias_attr->value->owner != IAS_USER_ATTR) {
- IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
+ pr_debug("%s(), attempting to delete a kernel attribute\n",
+ __func__);
kfree(ias_opt);
err = -EPERM;
goto out;
/* Only possible for a seqpacket service (TTP with SAR) */
if (sk->sk_type != SOCK_SEQPACKET) {
- IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n",
- __func__, opt);
+ pr_debug("%s(), setting max_sdu_size = %d\n",
+ __func__, opt);
self->max_sdu_size_rx = opt;
} else {
- IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
- __func__);
+ net_warn_ratelimited("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
+ __func__);
err = -ENOPROTOOPT;
goto out;
}
int err = 0;
int offset, total;
- IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
+ pr_debug("%s(%p)\n", __func__, self);
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
/* Check that we can proceed with IAP */
if (self->iriap) {
- IRDA_WARNING("%s: busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s: busy with a previous query\n",
+ __func__);
kfree(ias_opt);
err = -EBUSY;
goto out;
/* Wait until a node is discovered */
if (!self->cachedaddr) {
- IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__);
+ pr_debug("%s(), nothing discovered yet, going to sleep...\n",
+ __func__);
/* Set watchdog timer to expire in <val> ms. */
self->errno = 0;
/* If watchdog is still activated, kill it! */
del_timer(&(self->watchdog));
- IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__);
+ pr_debug("%s(), ...waking up !\n", __func__);
if (err != 0)
goto out;
}
else
- IRDA_DEBUG(1, "%s(), found immediately !\n",
- __func__);
+ pr_debug("%s(), found immediately !\n",
+ __func__);
/* Tell IrLMP that we have been notified */
irlmp_update_client(self->ckey, self->mask.word,
{
discovery_t *discovery;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/*
* If log is missing this means that IrLAP was unable to perform the
* discovery, so restart discovery again with just the half timeout
int i = 0; /* How many we expired */
IRDA_ASSERT(log != NULL, return;);
- IRDA_DEBUG(4, "%s()\n", __func__);
-
spin_lock_irqsave(&log->hb_spinlock, flags);
discovery = (discovery_t *) hashbin_get_first(log);
discovery = (discovery_t *) hashbin_get_first(log);
while (discovery != NULL) {
- IRDA_DEBUG(0, "Discovery:\n");
- IRDA_DEBUG(0, " daddr=%08x\n", discovery->data.daddr);
- IRDA_DEBUG(0, " saddr=%08x\n", discovery->data.saddr);
- IRDA_DEBUG(0, " nickname=%s\n", discovery->data.info);
+ pr_debug("Discovery:\n");
+ pr_debug(" daddr=%08x\n", discovery->data.daddr);
+ pr_debug(" saddr=%08x\n", discovery->data.saddr);
+ pr_debug(" nickname=%s\n", discovery->data.info);
discovery = (discovery_t *) hashbin_get_next(log);
}
{
ircomm = hashbin_new(HB_LOCK);
if (ircomm == NULL) {
- IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
+ net_err_ratelimited("%s(), can't allocate hashbin!\n",
+ __func__);
return -ENOMEM;
}
}
#endif /* CONFIG_PROC_FS */
- IRDA_MESSAGE("IrCOMM protocol (Dag Brattli)\n");
+ net_info_ratelimited("IrCOMM protocol (Dag Brattli)\n");
return 0;
}
static void __exit ircomm_cleanup(void)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
#ifdef CONFIG_PROC_FS
struct ircomm_cb *self = NULL;
int ret;
- IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __func__ ,
- service_type);
+ pr_debug("%s(), service_type=0x%02x\n", __func__ ,
+ service_type);
IRDA_ASSERT(ircomm != NULL, return NULL;);
*/
static int __ircomm_close(struct ircomm_cb *self)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Disconnect link if any */
ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
IRDA_ASSERT(self != NULL, return -EIO;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
entry = hashbin_remove(ircomm, self->line, NULL);
IRDA_ASSERT(entry == self, return -1;);
struct ircomm_info info;
int ret;
- IRDA_DEBUG(2 , "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
struct ircomm_info *info)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/*
* If there are any data hiding in the control channel, we must
* deliver it first. The side effect is that the control channel
info->qos, info->max_data_size,
info->max_header_size, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
+ pr_debug("%s(), missing handler\n", __func__);
}
}
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
return ret;
void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
struct ircomm_info *info)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
if (self->notify.connect_confirm )
self->notify.connect_confirm(self->notify.instance,
self, info->qos,
info->max_data_size,
info->max_header_size, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
+ pr_debug("%s(), missing handler\n", __func__);
}
}
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -EFAULT;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
IRDA_ASSERT(skb != NULL, return -EFAULT;);
*/
void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(skb->len > 0, return;);
if (self->notify.data_indication)
self->notify.data_indication(self->notify.instance, self, skb);
else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
+ pr_debug("%s(), missing handler\n", __func__);
}
}
* fine
*/
if (unlikely(skb->len < (clen + 1))) {
- IRDA_DEBUG(2, "%s() throwing away illegal frame\n",
- __func__ );
+ pr_debug("%s() throwing away illegal frame\n",
+ __func__);
return;
}
if (skb->len)
ircomm_data_indication(self, skb);
else {
- IRDA_DEBUG(4, "%s(), data was control info only!\n",
- __func__ );
+ pr_debug("%s(), data was control info only!\n",
+ __func__);
}
}
{
int ret;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -EFAULT;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
IRDA_ASSERT(skb != NULL, return -EFAULT;);
static void ircomm_control_indication(struct ircomm_cb *self,
struct sk_buff *skb, int clen)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Use udata for delivering data on the control channel */
if (self->notify.udata_indication) {
struct sk_buff *ctrl_skb;
* see ircomm_tty_control_indication(). */
dev_kfree_skb(ctrl_skb);
} else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
+ pr_debug("%s(), missing handler\n", __func__);
}
}
struct ircomm_info info;
int ret;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
struct ircomm_info *info)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(info != NULL, return;);
if (self->notify.disconnect_indication) {
self->notify.disconnect_indication(self->notify.instance, self,
info->reason, skb);
} else {
- IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
+ pr_debug("%s(), missing handler\n", __func__);
}
}
*/
void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
"IRCOMM_CONN",
};
-#ifdef CONFIG_IRDA_DEBUG
-static const char *const ircomm_event[] = {
+static const char *const ircomm_event[] __maybe_unused = {
"IRCOMM_CONNECT_REQUEST",
"IRCOMM_CONNECT_RESPONSE",
"IRCOMM_TTP_CONNECT_INDICATION",
"IRCOMM_CONTROL_REQUEST",
"IRCOMM_CONTROL_INDICATION",
};
-#endif /* CONFIG_IRDA_DEBUG */
static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb, struct ircomm_info *info) =
ircomm_connect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(4, "%s(), unknown event: %s\n", __func__ ,
- ircomm_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_event[event]);
ret = -EINVAL;
}
return ret;
ircomm_disconnect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event: %s\n", __func__ ,
- ircomm_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_event[event]);
ret = -EINVAL;
}
return ret;
ircomm_disconnect_indication(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
- ircomm_event[event]);
+ pr_debug("%s(), unknown event = %s\n", __func__ ,
+ ircomm_event[event]);
ret = -EINVAL;
}
return ret;
ret = self->issue.disconnect_request(self, skb, info);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
- ircomm_event[event]);
+ pr_debug("%s(), unknown event = %s\n", __func__ ,
+ ircomm_event[event]);
ret = -EINVAL;
}
return ret;
int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb, struct ircomm_info *info)
{
- IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_state[self->state], ircomm_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_state[self->state], ircomm_event[event]);
return (*state[self->state])(self, event, skb, info);
}
{
self->state = state;
- IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __func__ ,
- ircomm_state[self->state], self->service_type);
+ pr_debug("%s: next state=%s, service type=%d\n", __func__ ,
+ ircomm_state[self->state], self->service_type);
}
{
int ret = 0;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
{
struct sk_buff *tx_skb;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
/* Any userdata supplied? */
if (userdata == NULL) {
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
struct sk_buff *tx_skb;
int ret;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
if (!userdata) {
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
cb = (struct irda_skb_cb *) skb->cb;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
line = cb->line;
self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
if (!self) {
- IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ );
+ pr_debug("%s(), didn't find myself\n", __func__);
return;
}
self->pkt_count--;
if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
- IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ );
+ pr_debug("%s(), asking TTY to start again!\n", __func__);
self->flow_status = FLOW_START;
if (self->notify.flow_indication)
self->notify.flow_indication(self->notify.instance,
cb->line = self->line;
- IRDA_DEBUG(4, "%s(), sending frame\n", __func__ );
+ pr_debug("%s(), sending frame\n", __func__);
/* Don't forget to refcount it - see ircomm_tty_do_softint() */
skb_get(skb);
skb->destructor = ircomm_lmp_flow_control;
if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
- IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ );
+ pr_debug("%s(), asking TTY to slow down!\n", __func__);
self->flow_status = FLOW_STOP;
if (self->notify.flow_indication)
self->notify.flow_indication(self->notify.instance,
}
ret = irlmp_data_request(self->lsap, skb);
if (ret) {
- IRDA_ERROR("%s(), failed\n", __func__);
+ net_err_ratelimited("%s(), failed\n", __func__);
/* irlmp_data_request already free the packet */
}
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
struct ircomm_cb *self = (struct ircomm_cb *)instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
{
notify_t notify;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
/* Register callbacks */
irda_notify_init(¬ify);
notify.data_indication = ircomm_lmp_data_indication;
self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0);
if (!self->lsap) {
- IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ );
+ pr_debug("%sfailed to allocate tsap\n", __func__);
return -1;
}
self->slsap_sel = self->lsap->slsap_sel;
struct sk_buff *skb;
int count;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
count = irda_param_insert(self, pi, skb_tail_pointer(skb),
skb_tailroom(skb), &ircomm_param_info);
if (count < 0) {
- IRDA_WARNING("%s(), no room for parameter!\n", __func__);
+ net_warn_ratelimited("%s(), no room for parameter!\n",
+ __func__);
spin_unlock_irqrestore(&self->spinlock, flags);
return -1;
}
spin_unlock_irqrestore(&self->spinlock, flags);
- IRDA_DEBUG(2, "%s(), skb->len=%d\n", __func__ , skb->len);
+ pr_debug("%s(), skb->len=%d\n", __func__ , skb->len);
if (flush) {
/* ircomm_tty_do_softint will take care of the rest */
/* Find all common service types */
service_type &= self->service_type;
if (!service_type) {
- IRDA_DEBUG(2,
- "%s(), No common service type to use!\n", __func__ );
+ pr_debug("%s(), No common service type to use!\n", __func__);
return -1;
}
- IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ ,
- service_type);
+ pr_debug("%s(), services in common=%02x\n", __func__ ,
+ service_type);
/*
* Now choose a preferred service type of those available
else if (service_type & IRCOMM_3_WIRE_RAW)
self->settings.service_type = IRCOMM_3_WIRE_RAW;
- IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __func__ ,
- self->settings.service_type);
+ pr_debug("%s(), resulting service type=0x%02x\n", __func__ ,
+ self->settings.service_type);
/*
* Now the line is ready for some communication. Check if we are a
else {
self->settings.port_type = (__u8) param->pv.i;
- IRDA_DEBUG(0, "%s(), port type=%d\n", __func__ ,
- self->settings.port_type);
+ pr_debug("%s(), port type=%d\n", __func__ ,
+ self->settings.port_type);
}
return 0;
}
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get) {
- IRDA_DEBUG(0, "%s(), not imp!\n", __func__ );
+ pr_debug("%s(), not imp!\n", __func__);
} else {
- IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , param->pv.c);
+ pr_debug("%s(), port-name=%s\n", __func__ , param->pv.c);
strncpy(self->settings.port_name, param->pv.c, 32);
}
else
self->settings.data_rate = param->pv.i;
- IRDA_DEBUG(2, "%s(), data rate = %d\n", __func__ , param->pv.i);
+ pr_debug("%s(), data rate = %d\n", __func__ , param->pv.i);
return 0;
}
else
self->settings.flow_control = (__u8) param->pv.i;
- IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __func__ , (__u8) param->pv.i);
+ pr_debug("%s(), flow control = 0x%02x\n", __func__ , (__u8)param->pv.i);
return 0;
}
self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
}
- IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
- param->pv.i & 0xff, param->pv.i >> 8);
+ pr_debug("%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
+ param->pv.i & 0xff, param->pv.i >> 8);
return 0;
}
self->settings.enqack[1] = (__u16) param->pv.i >> 8;
}
- IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
- param->pv.i & 0xff, param->pv.i >> 8);
+ pr_debug("%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
+ param->pv.i & 0xff, param->pv.i >> 8);
return 0;
}
static int ircomm_param_line_status(void *instance, irda_param_t *param,
int get)
{
- IRDA_DEBUG(2, "%s(), not impl.\n", __func__ );
+ pr_debug("%s(), not impl.\n", __func__);
return 0;
}
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
__u8 dce;
- IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __func__ , (__u8) param->pv.i);
+ pr_debug("%s(), dce = 0x%02x\n", __func__ , (__u8)param->pv.i);
dce = (__u8) param->pv.i;
/* Check if any of the settings have changed */
if (dce & 0x0f) {
if (dce & IRCOMM_DELTA_CTS) {
- IRDA_DEBUG(2, "%s(), CTS\n", __func__ );
+ pr_debug("%s(), CTS\n", __func__);
}
}
{
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
/* Register callbacks */
irda_notify_init(¬ify);
notify.data_indication = ircomm_ttp_data_indication;
self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
¬ify);
if (!self->tsap) {
- IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ );
+ pr_debug("%sfailed to allocate tsap\n", __func__);
return -1;
}
self->slsap_sel = self->tsap->stsap_sel;
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
/* Don't forget to refcount it - should be NULL anyway */
if(userdata)
skb_get(userdata);
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen);
+ pr_debug("%s(), clen=%d\n", __func__ , clen);
/*
* Insert clen field, currently we either send data only, or control
ret = irttp_data_request(self->tsap, skb);
if (ret) {
- IRDA_ERROR("%s(), failed\n", __func__);
+ net_err_ratelimited("%s(), failed\n", __func__);
/* irttp_data_request already free the packet */
}
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) {
- IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
- __func__);
+ net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
+ __func__);
goto out;
}
struct ircomm_cb *self = (struct ircomm_cb *)instance;
struct ircomm_info info;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) {
- IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
- __func__);
+ net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
+ __func__);
goto out;
}
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
{
struct ircomm_cb *self = (struct ircomm_cb *) instance;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
return -ENOMEM;
ircomm_tty = hashbin_new(HB_LOCK);
if (ircomm_tty == NULL) {
- IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
+ net_err_ratelimited("%s(), can't allocate hashbin!\n",
+ __func__);
put_tty_driver(driver);
return -ENOMEM;
}
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &ops);
if (tty_register_driver(driver)) {
- IRDA_ERROR("%s(): Couldn't register serial driver\n",
- __func__);
+ net_err_ratelimited("%s(): Couldn't register serial driver\n",
+ __func__);
put_tty_driver(driver);
return -1;
}
static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
ret = tty_unregister_driver(driver);
if (ret) {
- IRDA_ERROR("%s(), failed to unregister driver\n",
- __func__);
+ net_err_ratelimited("%s(), failed to unregister driver\n",
+ __func__);
return;
}
notify_t notify;
int ret = -ENODEV;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if already open */
if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
- IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
+ pr_debug("%s(), already open so break out!\n", __func__);
return 0;
}
/* Connect IrCOMM link with remote device */
ret = ircomm_tty_attach_cable(self);
if (ret < 0) {
- IRDA_ERROR("%s(), error attaching cable!\n", __func__);
+ net_err_ratelimited("%s(), error attaching cable!\n", __func__);
goto err;
}
int do_clocal = 0;
unsigned long flags;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
- IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
+ pr_debug("%s(), O_NONBLOCK requested!\n", __func__);
return 0;
}
if (tty->termios.c_cflag & CLOCAL) {
- IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
+ pr_debug("%s(), doing CLOCAL!\n", __func__);
do_clocal = 1;
}
retval = 0;
add_wait_queue(&port->open_wait, &wait);
- IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
+ pr_debug("%s(%d):block_til_ready before block on %s open_count=%d\n",
+ __FILE__, __LINE__, tty->driver->name, port->count);
spin_lock_irqsave(&port->lock, flags);
port->count--;
break;
}
- IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
+ pr_debug("%s(%d):block_til_ready blocking on %s open_count=%d\n",
+ __FILE__, __LINE__, tty->driver->name, port->count);
schedule();
}
port->blocked_open--;
spin_unlock_irqrestore(&port->lock, flags);
- IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
+ pr_debug("%s(%d):block_til_ready after blocking on %s open_count=%d\n",
+ __FILE__, __LINE__, tty->driver->name, port->count);
if (!retval)
port->flags |= ASYNC_NORMAL_ACTIVE;
if (!self) {
/* No, so make new instance */
self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
- if (self == NULL) {
- IRDA_ERROR("%s(), kmalloc failed!\n", __func__);
+ if (self == NULL)
return -ENOMEM;
- }
tty_port_init(&self->port);
self->port.ops = &ircomm_port_ops;
unsigned long flags;
int ret;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* ++ is not atomic, so this should be protected - Jean II */
spin_lock_irqsave(&self->port.lock, flags);
self->port.count++;
spin_unlock_irqrestore(&self->port.lock, flags);
tty_port_tty_set(&self->port, tty);
- IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
- self->line, self->port.count);
+ pr_debug("%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
+ self->line, self->port.count);
/* Not really used by us, but lets do it anyway */
self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if (wait_event_interruptible(self->port.close_wait,
!test_bit(ASYNCB_CLOSING, &self->port.flags))) {
- IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
- __func__);
+ net_warn_ratelimited("%s - got signal while blocking on ASYNC_CLOSING!\n",
+ __func__);
return -ERESTARTSYS;
}
self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */
- IRDA_DEBUG(2, "%s(), IrCOMM device\n", __func__ );
+ pr_debug("%s(), IrCOMM device\n", __func__);
} else {
- IRDA_DEBUG(2, "%s(), IrLPT device\n", __func__ );
+ pr_debug("%s(), IrLPT device\n", __func__);
self->service_type = IRCOMM_3_WIRE_RAW;
self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
}
ret = ircomm_tty_block_til_ready(self, tty, filp);
if (ret) {
- IRDA_DEBUG(2,
- "%s(), returning after block_til_ready with %d\n", __func__ ,
- ret);
+ pr_debug("%s(), returning after block_til_ready with %d\n",
+ __func__, ret);
return ret;
}
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
struct tty_port *port = &self->port;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
unsigned long flags;
struct sk_buff *skb, *ctrl_skb;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
int len = 0;
int size;
- IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __func__ , count,
- tty->hw_stopped);
+ pr_debug("%s(), count=%d, hw_stopped=%d\n", __func__ , count,
+ tty->hw_stopped);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
* we don't mess up the original "safe skb" (see tx_data_size).
* Jean II */
if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
- IRDA_DEBUG(1, "%s() : not initialised\n", __func__);
+ pr_debug("%s() : not initialised\n", __func__);
#ifdef IRCOMM_NO_TX_BEFORE_INIT
/* We didn't consume anything, TTY will retry */
return 0;
ret = self->max_data_size;
spin_unlock_irqrestore(&self->spinlock, flags);
}
- IRDA_DEBUG(2, "%s(), ret=%d\n", __func__ , ret);
+ pr_debug("%s(), ret=%d\n", __func__ , ret);
return ret;
}
unsigned long orig_jiffies, poll_time;
unsigned long flags;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
- IRDA_DEBUG(1, "%s(), FLOW_START\n", __func__ );
+ pr_debug("%s(), FLOW_START\n", __func__);
}
ircomm_flow_request(self->ircomm, FLOW_START);
}
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
return;
struct tty_port *port = &self->port;
unsigned long flags;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
*/
static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
{
- IRDA_DEBUG(0, "%s(), not impl\n", __func__ );
+ pr_debug("%s(), not impl\n", __func__);
}
/*
struct tty_struct *tty;
int status;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
/*wake_up_interruptible(&self->delta_msr_wait);*/
}
if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
- IRDA_DEBUG(2,
- "%s(), ircomm%d CD now %s...\n", __func__ , self->line,
- (status & IRCOMM_CD) ? "on" : "off");
+ pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line,
+ (status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
wake_up_interruptible(&self->port.open_wait);
} else {
- IRDA_DEBUG(2,
- "%s(), Doing serial hangup..\n", __func__ );
+ pr_debug("%s(), Doing serial hangup..\n", __func__);
if (tty)
tty_hangup(tty);
if (tty && tty_port_cts_enabled(&self->port)) {
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
- IRDA_DEBUG(2,
- "%s(), CTS tx start...\n", __func__ );
+ pr_debug("%s(), CTS tx start...\n", __func__);
tty->hw_stopped = 0;
/* Wake up processes blocked on open */
}
} else {
if (!(status & IRCOMM_CTS)) {
- IRDA_DEBUG(2,
- "%s(), CTS tx stop...\n", __func__ );
+ pr_debug("%s(), CTS tx stop...\n", __func__);
tty->hw_stopped = 1;
}
}
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
struct tty_struct *tty;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
tty = tty_port_tty_get(&self->port);
if (!tty) {
- IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
+ pr_debug("%s(), no tty!\n", __func__);
return 0;
}
* params, we can just as well declare the hardware for running.
*/
if (tty->hw_stopped && (self->flow == FLOW_START)) {
- IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
+ pr_debug("%s(), polling for line settings!\n", __func__);
ircomm_param_request(self, IRCOMM_POLL, TRUE);
/* We can just as well declare the hardware for running */
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
int clen;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
switch (cmd) {
case FLOW_START:
- IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
+ pr_debug("%s(), hw start!\n", __func__);
if (tty)
tty->hw_stopped = 0;
break;
default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
- IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
+ pr_debug("%s(), hw stopped!\n", __func__);
if (tty)
tty->hw_stopped = 1;
break;
"*** ERROR *** ",
};
-#ifdef CONFIG_IRDA_DEBUG
-static const char *const ircomm_tty_event[] = {
+static const char *const ircomm_tty_event[] __maybe_unused = {
"IRCOMM_TTY_ATTACH_CABLE",
"IRCOMM_TTY_DETACH_CABLE",
"IRCOMM_TTY_DATA_REQUEST",
"IRCOMM_TTY_GOT_LSAPSEL",
"*** ERROR ****",
};
-#endif /* CONFIG_IRDA_DEBUG */
static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
struct sk_buff *skb, struct ircomm_tty_info *info) =
{
struct tty_struct *tty;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
/* Check if somebody has already connected to us */
if (ircomm_is_connected(self->ircomm)) {
- IRDA_DEBUG(0, "%s(), already connected!\n", __func__ );
+ pr_debug("%s(), already connected!\n", __func__);
return 0;
}
*/
void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
__u8 oct_seq[6];
__u16 hints;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
* Set default values, but only if the application for some reason
* haven't set them already
*/
- IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ ,
- self->settings.data_rate);
+ pr_debug("%s(), data-rate = %d\n", __func__ ,
+ self->settings.data_rate);
if (!self->settings.data_rate)
self->settings.data_rate = 9600;
- IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ ,
- self->settings.data_format);
+ pr_debug("%s(), data-format = %d\n", __func__ ,
+ self->settings.data_format);
if (!self->settings.data_format)
self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
- IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ ,
- self->settings.flow_control);
+ pr_debug("%s(), flow-control = %d\n", __func__ ,
+ self->settings.flow_control);
/*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
/* Do not set delta values for the initial parameters */
struct ircomm_tty_cb *self;
struct ircomm_tty_info info;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Important note :
* We need to drop all passive discoveries.
* The LSAP management of IrComm is deficient and doesn't deal
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
struct tty_struct *tty;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ );
+ pr_debug("%s(), got NULL value!\n", __func__);
return;
}
switch (value->type) {
case IAS_OCT_SEQ:
- IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ );
+ pr_debug("%s(), got octet sequence\n", __func__);
irda_param_extract_all(self, value->t.oct_seq, value->len,
&ircomm_param_info);
break;
case IAS_INTEGER:
/* Got LSAP selector */
- IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ ,
- value->t.integer);
+ pr_debug("%s(), got lsapsel = %d\n", __func__ ,
+ value->t.integer);
if (value->t.integer == -1) {
- IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ );
+ pr_debug("%s(), invalid value!\n", __func__);
} else
self->dlsap_sel = value->t.integer;
ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
break;
case IAS_MISSING:
- IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ );
+ pr_debug("%s(), got IAS_MISSING\n", __func__);
break;
default:
- IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ );
+ pr_debug("%s(), got unknown type!\n", __func__);
break;
}
irias_delete_value(value);
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
int clen;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
{
struct tty_struct *tty;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
*/
if (tty_port_cts_enabled(&self->port) &&
((self->settings.dce & IRCOMM_CTS) == 0)) {
- IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
+ pr_debug("%s(), waiting for CTS ...\n", __func__);
goto put;
} else {
- IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
+ pr_debug("%s(), starting hardware!\n", __func__);
tty->hw_stopped = 0;
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
return (*state[self->state])(self, event, skb, info);
}
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
- IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ ,
- ircomm_tty_state[self->state], self->service_type);
+ pr_debug("%s: next state=%s, service type=%d\n", __func__ ,
+ ircomm_tty_state[self->state], self->service_type);
*/
self->state = state;
}
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_ATTACH_CABLE:
/* Try to discover any remote devices */
self->saddr = info->saddr;
if (self->iriap) {
- IRDA_WARNING("%s(), busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s(), busy with a previous query\n",
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_DISCOVERY_INDICATION:
self->saddr = info->saddr;
if (self->iriap) {
- IRDA_WARNING("%s(), busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s(), busy with a previous query\n",
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_GOT_PARAMETERS:
if (self->iriap) {
- IRDA_WARNING("%s(), busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s(), busy with a previous query\n",
+ __func__);
return -EBUSY;
}
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_GOT_LSAPSEL:
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
{
int ret = 0;
- IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
+ pr_debug("%s: state=%s, event=%s\n", __func__ ,
+ ircomm_tty_state[self->state], ircomm_tty_event[event]);
switch (event) {
case IRCOMM_TTY_CONNECT_CONFIRM:
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self);
} else {
- IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
+ pr_debug("%s(), hanging up!\n", __func__);
tty_port_tty_hangup(&self->port, false);
}
break;
default:
- IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
+ pr_debug("%s(), unknown event: %s\n", __func__ ,
+ ircomm_tty_event[event]);
ret = -EINVAL;
}
return ret;
unsigned int cflag, cval;
int baud;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (!self->ircomm)
return;
self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
/* This got me. Bummer. Jean II */
if (self->service_type == IRCOMM_3_WIRE_RAW)
- IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
+ net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n",
+ __func__);
} else {
self->port.flags &= ~ASYNC_CTS_FLOW;
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int cflag = tty->termios.c_cflag;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(tty->termios.c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag)))
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int result;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
if (!retinfo)
return -EFAULT;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
memset(&info, 0, sizeof(info));
info.line = self->line;
info.flags = self->port.flags;
struct serial_struct new_serial;
struct ircomm_tty_cb old_state, *state;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
int ret = 0;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg);
break;
case TIOCMIWAIT:
- IRDA_DEBUG(0, "(), TIOCMIWAIT, not impl!\n");
+ pr_debug("(), TIOCMIWAIT, not impl!\n");
break;
case TIOCGICOUNT:
- IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __func__ );
+ pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__);
#if 0
save_flags(flags); cli();
cnow = driver->icount;
{
dongles = hashbin_new(HB_NOLOCK);
if (dongles == NULL) {
- IRDA_WARNING("IrDA: Can't allocate dongles hashbin!\n");
+ net_warn_ratelimited("IrDA: Can't allocate dongles hashbin!\n");
return -ENOMEM;
}
spin_lock_init(&dongles->hb_spinlock);
tasks = hashbin_new(HB_LOCK);
if (tasks == NULL) {
- IRDA_WARNING("IrDA: Can't allocate tasks hashbin!\n");
+ net_warn_ratelimited("IrDA: Can't allocate tasks hashbin!\n");
hashbin_delete(dongles, NULL);
return -ENOMEM;
}
static void leftover_dongle(void *arg)
{
struct dongle_reg *reg = arg;
- IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
- reg->type);
+ net_warn_ratelimited("IrDA: Dongle type %x not unregistered\n",
+ reg->type);
}
void irda_device_cleanup(void)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
hashbin_delete(dongles, leftover_dongle);
{
struct irlap_cb *self;
- IRDA_DEBUG(4, "%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
+ pr_debug("%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
self = (struct irlap_cb *) dev->atalk_ptr;
irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT);
else
irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT);
- IRDA_DEBUG( 4, "Media busy!\n");
+ pr_debug("Media busy!\n");
} else {
self->media_busy = FALSE;
irlap_stop_mbusy_timer(self);
struct if_irda_req req;
int ret;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
if (!dev->netdev_ops->ndo_do_ioctl) {
- IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
- __func__);
+ net_err_ratelimited("%s: do_ioctl not impl. by device driver\n",
+ __func__);
return -1;
}
int count = 0;
int timeout;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(task != NULL, return -1;);
IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
do {
timeout = task->function(task);
if (count++ > 100) {
- IRDA_ERROR("%s: error in task handler!\n",
- __func__);
+ net_err_ratelimited("%s: error in task handler!\n",
+ __func__);
irda_task_delete(task);
return TRUE;
}
} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
if (timeout < 0) {
- IRDA_ERROR("%s: Error executing task!\n", __func__);
+ net_err_ratelimited("%s: Error executing task!\n", __func__);
irda_task_delete(task);
return TRUE;
}
irda_task_timer_expired);
finished = FALSE;
} else {
- IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n",
- __func__);
+ pr_debug("%s(), not finished, and no timeout!\n",
+ __func__);
finished = FALSE;
}
{
struct irda_task *task;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
task = data;
irda_task_kick(task);
#include <net/irda/iriap_event.h>
#include <net/irda/iriap.h>
-#ifdef CONFIG_IRDA_DEBUG
/* FIXME: This one should go in irlmp.c */
-static const char *const ias_charset_types[] = {
+static const char *const ias_charset_types[] __maybe_unused = {
"CS_ASCII",
"CS_ISO_8859_1",
"CS_ISO_8859_2",
"CS_ISO_8859_9",
"CS_UNICODE"
};
-#endif /* CONFIG_IRDA_DEBUG */
static hashbin_t *iriap = NULL;
static void *service_handle;
/* Object repository - defined in irias_object.c */
irias_objects = hashbin_new(HB_LOCK);
if (!irias_objects) {
- IRDA_WARNING("%s: Can't allocate irias_objects hashbin!\n",
- __func__);
+ net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n",
+ __func__);
hashbin_delete(iriap, NULL);
return -ENOMEM;
}
*/
server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!server) {
- IRDA_DEBUG(0, "%s(), unable to open server\n", __func__);
+ pr_debug("%s(), unable to open server\n", __func__);
return -1;
}
iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
{
struct iriap_cb *self;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
self = kzalloc(sizeof(*self), GFP_ATOMIC);
- if (!self) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ if (!self)
return NULL;
- }
/*
* Initialize instance
*/
static void __iriap_close(struct iriap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
{
struct iriap_cb *entry;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
{
notify_t notify;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
irda_notify_init(¬ify);
notify.connect_confirm = iriap_connect_confirm;
notify.connect_indication = iriap_connect_indication;
self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0);
if (self->lsap == NULL) {
- IRDA_ERROR("%s: Unable to allocated LSAP!\n", __func__);
+ net_err_ratelimited("%s: Unable to allocated LSAP!\n",
+ __func__);
return -1;
}
self->slsap_sel = self->lsap->slsap_sel;
{
struct iriap_cb *self;
- IRDA_DEBUG(4, "%s(), reason=%s [%d]\n", __func__,
- irlmp_reason_str(reason), reason);
+ pr_debug("%s(), reason=%s [%d]\n", __func__,
+ irlmp_reason_str(reason), reason);
self = instance;
dev_kfree_skb(skb);
if (self->mode == IAS_CLIENT) {
- IRDA_DEBUG(4, "%s(), disconnect as client\n", __func__);
+ pr_debug("%s(), disconnect as client\n", __func__);
iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION,
if (self->confirm)
self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
} else {
- IRDA_DEBUG(4, "%s(), disconnect as server\n", __func__);
+ pr_debug("%s(), disconnect as server\n", __func__);
iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
NULL);
iriap_close(self);
{
struct sk_buff *tx_skb;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (tx_skb == NULL) {
- IRDA_DEBUG(0,
- "%s(), Could not allocate an sk_buff of length %d\n",
- __func__, LMP_MAX_HEADER);
+ pr_debug("%s(), Could not allocate an sk_buff of length %d\n",
+ __func__, LMP_MAX_HEADER);
return;
}
len = get_unaligned_be16(fp + n);
n += 2;
- IRDA_DEBUG(4, "%s(), len=%d\n", __func__, len);
+ pr_debug("%s(), len=%d\n", __func__, len);
/* Get object ID, MSB first */
obj_id = get_unaligned_be16(fp + n);
n += 2;
type = fp[n++];
- IRDA_DEBUG(4, "%s(), Value type = %d\n", __func__, type);
+ pr_debug("%s(), Value type = %d\n", __func__, type);
switch (type) {
case IAS_INTEGER:
value = irias_new_integer_value(tmp_cpu32);
/* Legal values restricted to 0x01-0x6f, page 15 irttp */
- IRDA_DEBUG(4, "%s(), lsap=%d\n", __func__, value->t.integer);
+ pr_debug("%s(), lsap=%d\n", __func__, value->t.integer);
break;
case IAS_STRING:
charset = fp[n++];
/* case CS_ISO_8859_9: */
/* case CS_UNICODE: */
default:
- IRDA_DEBUG(0, "%s(), charset [%d] %s, not supported\n",
- __func__, charset,
- charset < ARRAY_SIZE(ias_charset_types) ?
- ias_charset_types[charset] :
- "(unknown)");
+ pr_debug("%s(), charset [%d] %s, not supported\n",
+ __func__, charset,
+ charset < ARRAY_SIZE(ias_charset_types) ?
+ ias_charset_types[charset] :
+ "(unknown)");
/* Aborting, close connection! */
iriap_disconnect_request(self);
/* break; */
}
value_len = fp[n++];
- IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len);
+ pr_debug("%s(), strlen=%d\n", __func__, value_len);
/* Make sure the string is null-terminated */
if (n + value_len < skb->len)
fp[n + value_len] = 0x00;
- IRDA_DEBUG(4, "Got string %s\n", fp+n);
+ pr_debug("Got string %s\n", fp+n);
/* Will truncate to IAS_MAX_STRING bytes */
value = irias_new_string_value(fp+n);
if (self->confirm)
self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
else {
- IRDA_DEBUG(0, "%s(), missing handler!\n", __func__);
+ pr_debug("%s(), missing handler!\n", __func__);
irias_delete_value(value);
}
}
__be16 tmp_be16;
__u8 *fp;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
IRDA_ASSERT(value != NULL, return;);
memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
break;
case IAS_MISSING:
- IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __func__);
+ pr_debug("%s: sending IAS_MISSING\n", __func__);
skb_put(tx_skb, 1);
fp[n++] = value->type;
break;
default:
- IRDA_DEBUG(0, "%s(), type not implemented!\n", __func__);
+ pr_debug("%s(), type not implemented!\n", __func__);
break;
}
iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
__u8 *fp;
int n;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
memcpy(attr, fp+n, attr_len); n+=attr_len;
attr[attr_len] = '\0';
- IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
+ pr_debug("LM-IAS: Looking up %s: %s\n", name, attr);
obj = irias_find_object(name);
if (obj == NULL) {
- IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name);
+ pr_debug("LM-IAS: Object %s not found\n", name);
iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
&irias_missing);
return;
}
- IRDA_DEBUG(4, "LM-IAS: found %s, id=%d\n", obj->name, obj->id);
+ pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id);
attrib = irias_find_attrib(obj, attr);
if (attrib == NULL) {
- IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr);
+ pr_debug("LM-IAS: Attribute %s not found\n", attr);
iriap_getvaluebyclass_response(self, obj->id,
IAS_ATTRIB_UNKNOWN,
&irias_missing);
struct sk_buff *tx_skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
self->saddr, self->daddr,
NULL, NULL);
if (ret < 0) {
- IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
+ pr_debug("%s(), connect failed!\n", __func__);
self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
}
}
{
struct iriap_cb *self, *new;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(skb != NULL, return;);
/* Start new server */
new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!new) {
- IRDA_DEBUG(0, "%s(), open failed\n", __func__);
+ pr_debug("%s(), open failed\n", __func__);
goto out;
}
/* Now attach up the new "socket" */
new->lsap = irlmp_dup(self->lsap, new);
if (!new->lsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
+ pr_debug("%s(), dup failed!\n", __func__);
goto out;
}
__u8 *frame;
__u8 opcode;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(skb != NULL, return 0;);
if (self->mode == IAS_SERVER) {
/* Call server */
- IRDA_DEBUG(4, "%s(), Calling server!\n", __func__);
+ pr_debug("%s(), Calling server!\n", __func__);
iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
goto out;
}
opcode = frame[0];
if (~opcode & IAP_LST) {
- IRDA_WARNING("%s:, IrIAS multiframe commands or "
- "results is not implemented yet!\n",
- __func__);
+ net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n",
+ __func__);
goto out;
}
/* Check for ack frames since they don't contain any data */
if (opcode & IAP_ACK) {
- IRDA_DEBUG(0, "%s() Got ack frame!\n", __func__);
+ pr_debug("%s() Got ack frame!\n", __func__);
goto out;
}
switch (opcode) {
case GET_INFO_BASE:
- IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n");
+ pr_debug("IrLMP GetInfoBaseDetails not implemented!\n");
break;
case GET_VALUE_BY_CLASS:
iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
iriap_getvaluebyclass_confirm(self, skb);
break;
case IAS_CLASS_UNKNOWN:
- IRDA_DEBUG(1, "%s(), No such class!\n", __func__);
+ pr_debug("%s(), No such class!\n", __func__);
/* Finished, close connection! */
iriap_disconnect_request(self);
self->priv);
break;
case IAS_ATTRIB_UNKNOWN:
- IRDA_DEBUG(1, "%s(), No such attribute!\n", __func__);
+ pr_debug("%s(), No such attribute!\n", __func__);
/* Finished, close connection! */
iriap_disconnect_request(self);
}
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __func__,
- opcode);
+ pr_debug("%s(), Unknown op-code: %02x\n", __func__,
+ opcode);
break;
}
__u8 *fp;
__u8 opcode;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
opcode = fp[0];
if (~opcode & 0x80) {
- IRDA_WARNING("%s: IrIAS multiframe commands or results "
- "is not implemented yet!\n", __func__);
+ net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n",
+ __func__);
return;
}
opcode &= 0x7f; /* Mask away LST bit */
switch (opcode) {
case GET_INFO_BASE:
- IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n",
- __func__);
+ net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n",
+ __func__);
break;
case GET_VALUE_BY_CLASS:
iriap_getvaluebyclass_indication(self, skb);
case IAP_LM_DISCONNECT_INDICATION:
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
+ pr_debug("%s(), Unknown event %d\n", __func__, event);
break;
}
}
iriap_next_client_state(self, S_DISCONNECT);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
+ pr_debug("%s(), Unknown event %d\n", __func__, event);
break;
}
}
iriap_next_client_state(self, S_DISCONNECT);
break;
default:
- IRDA_DEBUG(0, "state_s_call: Unknown event %d\n", event);
+ pr_debug("state_s_call: Unknown event %d\n", event);
break;
}
}
iriap_next_call_state(self, S_OUTSTANDING);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
+ pr_debug("%s(), Unknown event %d\n", __func__, event);
break;
}
}
static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
/*
iriap_next_call_state(self, S_WAIT_FOR_CALL);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
+ pr_debug("%s(), Unknown event %d\n", __func__, event);
break;
}
}
static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
/*
static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
/**************************************************************************
switch (event) {
case IAP_LM_CONNECT_INDICATION:
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (tx_skb == NULL) {
- IRDA_WARNING("%s: unable to malloc!\n", __func__);
+ if (tx_skb == NULL)
return;
- }
/* Reserve space for MUX_CONTROL and LAP header */
skb_reserve(tx_skb, LMP_MAX_HEADER);
iriap_next_r_connect_state(self, R_RECEIVING);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event %d\n", __func__, event);
+ pr_debug("%s(), unknown event %d\n", __func__, event);
break;
}
}
static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
switch (event) {
case IAP_LM_DISCONNECT_INDICATION:
/* Abort call */
iriap_next_r_connect_state(self, R_WAITING);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
+ pr_debug("%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
+ pr_debug("%s(), Not implemented\n", __func__);
}
/*
static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
switch (event) {
case IAP_RECV_F_LST:
iriap_next_r_connect_state(self, R_EXECUTE);
iriap_call_indication(self, skb);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
+ pr_debug("%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
irlmp_data_request(self->lsap, skb);
break;
default:
- IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
+ pr_debug("%s(), unknown event!\n", __func__);
break;
}
}
static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(0, "%s(), event=%d\n", __func__, event);
+ pr_debug("%s(), event=%d\n", __func__, event);
switch (event) {
case IAP_RECV_F_LST:
{
struct ias_object *obj;
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC);
if (obj == NULL) {
- IRDA_WARNING("%s(), Unable to allocate object!\n",
- __func__);
+ net_warn_ratelimited("%s(), Unable to allocate object!\n",
+ __func__);
return NULL;
}
obj->magic = IAS_OBJECT_MAGIC;
obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
if (!obj->name) {
- IRDA_WARNING("%s(), Unable to allocate name!\n",
- __func__);
+ net_warn_ratelimited("%s(), Unable to allocate name!\n",
+ __func__);
kfree(obj);
return NULL;
}
obj->attribs = hashbin_new(HB_LOCK);
if (obj->attribs == NULL) {
- IRDA_WARNING("%s(), Unable to allocate attribs!\n",
- __func__);
+ net_warn_ratelimited("%s(), Unable to allocate attribs!\n",
+ __func__);
kfree(obj->name);
kfree(obj);
return NULL;
/* Remove from list */
node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
if (!node)
- IRDA_DEBUG( 0, "%s(), object already removed!\n",
- __func__);
+ pr_debug("%s(), object already removed!\n",
+ __func__);
/* Destroy */
__irias_delete_object(obj);
/* Find object */
obj = hashbin_lock_find(irias_objects, 0, obj_name);
if (obj == NULL) {
- IRDA_WARNING("%s: Unable to find object: %s\n", __func__,
- obj_name);
+ net_warn_ratelimited("%s: Unable to find object: %s\n",
+ __func__, obj_name);
return -1;
}
/* Find attribute */
attrib = hashbin_find(obj->attribs, 0, attrib_name);
if (attrib == NULL) {
- IRDA_WARNING("%s: Unable to find attribute: %s\n",
- __func__, attrib_name);
+ net_warn_ratelimited("%s: Unable to find attribute: %s\n",
+ __func__, attrib_name);
spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
return -1;
}
if ( attrib->value->type != new_value->type) {
- IRDA_DEBUG( 0, "%s(), changing value type not allowed!\n",
- __func__);
+ pr_debug("%s(), changing value type not allowed!\n",
+ __func__);
spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
return -1;
}
attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
return;
}
/* Insert value */
attrib->value = irias_new_integer_value(value);
if (!attrib->name || !attrib->value) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
return;
}
attrib->value = irias_new_octseq_value( octets, len);
if (!attrib->name || !attrib->value) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC);
if (attrib == NULL) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
return;
}
attrib->value = irias_new_string_value(value);
if (!attrib->name || !attrib->value) {
- IRDA_WARNING("%s: Unable to allocate attribute!\n",
- __func__);
+ net_warn_ratelimited("%s: Unable to allocate attribute!\n",
+ __func__);
if (attrib->value)
irias_delete_value(attrib->value);
kfree(attrib->name);
struct ias_value *value;
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ if (value == NULL)
return NULL;
- }
value->type = IAS_INTEGER;
value->len = 4;
struct ias_value *value;
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ if (value == NULL)
return NULL;
- }
value->type = IAS_STRING;
value->charset = CS_ASCII;
value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
if (!value->t.string) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__);
kfree(value);
return NULL;
}
struct ias_value *value;
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ if (value == NULL)
return NULL;
- }
value->type = IAS_OCT_SEQ;
/* Check length */
value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC);
if (value->t.oct_seq == NULL){
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__);
kfree(value);
return NULL;
}
struct ias_value *value;
value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
+ if (value == NULL)
return NULL;
- }
value->type = IAS_MISSING;
*/
void irias_delete_value(struct ias_value *value)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(value != NULL, return;);
switch (value->type) {
kfree(value->t.oct_seq);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown value type!\n", __func__);
+ pr_debug("%s(), Unknown value type!\n", __func__);
break;
}
kfree(value);
{
struct irlan_cb *self = (struct irlan_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
irlan_client_kick_timer_expired);
}
*/
void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
{
- IRDA_DEBUG(1, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
if ((self->client.state != IRLAN_IDLE) ||
(self->provider.access_type == ACCESS_DIRECT))
{
- IRDA_DEBUG(0, "%s(), already awake!\n", __func__ );
+ pr_debug("%s(), already awake!\n", __func__);
return;
}
self->daddr = daddr;
if (self->disconnect_reason == LM_USER_REQUEST) {
- IRDA_DEBUG(0, "%s(), still stopped by user\n", __func__ );
+ pr_debug("%s(), still stopped by user\n", __func__);
return;
}
struct irlan_cb *self;
__u32 saddr, daddr;
- IRDA_DEBUG(1, "%s()\n", __func__ );
-
IRDA_ASSERT(discovery != NULL, return;);
/*
if (self) {
IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
- IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __func__ ,
- daddr);
+ pr_debug("%s(), Found instance (%08x)!\n", __func__ ,
+ daddr);
irlan_client_wakeup(self, saddr, daddr);
}
{
struct irlan_cb *self;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
self = instance;
IRDA_ASSERT(self != NULL, return -1;);
irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
/* Ready for a new command */
- IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __func__ );
+ pr_debug("%s(), clearing tx_busy\n", __func__);
self->client.tx_busy = FALSE;
/* Check if we have some queued commands waiting to be sent */
struct tsap_cb *tsap;
struct sk_buff *skb;
- IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
+ pr_debug("%s(), reason=%d\n", __func__ , reason);
self = instance;
tsap = sap;
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
+ pr_debug("%s(), Got no tsap!\n", __func__);
return;
}
self->client.tsap_ctrl = tsap;
{
struct irlan_cb *self;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
self = instance;
IRDA_ASSERT(self != NULL, return;);
printk(KERN_INFO "Success\n");
break;
case 1:
- IRDA_WARNING("IrLAN: Insufficient resources\n");
+ net_warn_ratelimited("IrLAN: Insufficient resources\n");
break;
case 2:
- IRDA_WARNING("IrLAN: Invalid command format\n");
+ net_warn_ratelimited("IrLAN: Invalid command format\n");
break;
case 3:
- IRDA_WARNING("IrLAN: Command not supported\n");
+ net_warn_ratelimited("IrLAN: Command not supported\n");
break;
case 4:
- IRDA_WARNING("IrLAN: Parameter not supported\n");
+ net_warn_ratelimited("IrLAN: Parameter not supported\n");
break;
case 5:
- IRDA_WARNING("IrLAN: Value not supported\n");
+ net_warn_ratelimited("IrLAN: Value not supported\n");
break;
case 6:
- IRDA_WARNING("IrLAN: Not open\n");
+ net_warn_ratelimited("IrLAN: Not open\n");
break;
case 7:
- IRDA_WARNING("IrLAN: Authentication required\n");
+ net_warn_ratelimited("IrLAN: Authentication required\n");
break;
case 8:
- IRDA_WARNING("IrLAN: Invalid password\n");
+ net_warn_ratelimited("IrLAN: Invalid password\n");
break;
case 9:
- IRDA_WARNING("IrLAN: Protocol error\n");
+ net_warn_ratelimited("IrLAN: Protocol error\n");
break;
case 255:
- IRDA_WARNING("IrLAN: Asynchronous status\n");
+ net_warn_ratelimited("IrLAN: Asynchronous status\n");
break;
}
}
IRDA_ASSERT(skb != NULL, return;);
- IRDA_DEBUG(4, "%s() skb->len=%d\n", __func__ , (int) skb->len);
+ pr_debug("%s() skb->len=%d\n", __func__ , (int)skb->len);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
if (!skb) {
- IRDA_ERROR("%s(), Got NULL skb!\n", __func__);
+ net_err_ratelimited("%s(), Got NULL skb!\n", __func__);
return;
}
frame = skb->data;
/* How many parameters? */
count = frame[1];
- IRDA_DEBUG(4, "%s(), got %d parameters\n", __func__ , count);
+ pr_debug("%s(), got %d parameters\n", __func__ , count);
ptr = frame+2;
for (i=0; i<count;i++) {
ret = irlan_extract_param(ptr, name, value, &val_len);
if (ret < 0) {
- IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
+ pr_debug("%s(), IrLAN, Error!\n", __func__);
break;
}
ptr += ret;
__u8 *bytes;
int i;
- IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param);
+ pr_debug("%s(), parm=%s\n", __func__ , param);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
else if (strcmp(value, "HOSTED") == 0)
self->client.access_type = ACCESS_HOSTED;
else {
- IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
+ pr_debug("%s(), unknown access type!\n", __func__);
}
}
/* IRLAN version */
if (strcmp(param, "IRLAN_VER") == 0) {
- IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
- (__u8) value[1]);
+ pr_debug("IrLAN version %d.%d\n", (__u8)value[0],
+ (__u8)value[1]);
self->version[0] = value[0];
self->version[1] = value[1];
/* Which remote TSAP to use for data channel */
if (strcmp(param, "DATA_CHAN") == 0) {
self->dtsap_sel_data = value[0];
- IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
+ pr_debug("Data TSAP = %02x\n", self->dtsap_sel_data);
return;
}
if (strcmp(param, "CON_ARB") == 0) {
memcpy(&tmp_cpu, value, 2); /* Align value */
le16_to_cpus(&tmp_cpu); /* Convert to host order */
self->client.recv_arb_val = tmp_cpu;
- IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __func__ ,
- self->client.recv_arb_val);
+ pr_debug("%s(), receive arb val=%d\n", __func__ ,
+ self->client.recv_arb_val);
}
if (strcmp(param, "MAX_FRAME") == 0) {
memcpy(&tmp_cpu, value, 2); /* Align value */
le16_to_cpus(&tmp_cpu); /* Convert to host order */
self->client.max_frame = tmp_cpu;
- IRDA_DEBUG(4, "%s(), max frame=%d\n", __func__ ,
- self->client.max_frame);
+ pr_debug("%s(), max frame=%d\n", __func__ ,
+ self->client.max_frame);
}
/* RECONNECT_KEY, in case the link goes down! */
if (strcmp(param, "RECONNECT_KEY") == 0) {
- IRDA_DEBUG(4, "Got reconnect key: ");
+ pr_debug("Got reconnect key: ");
/* for (i = 0; i < val_len; i++) */
/* printk("%02x", value[i]); */
memcpy(self->client.reconnect_key, value, val_len);
self->client.key_len = val_len;
- IRDA_DEBUG(4, "\n");
+ pr_debug("\n");
}
/* FILTER_ENTRY, have we got an ethernet address? */
if (strcmp(param, "FILTER_ENTRY") == 0) {
bytes = value;
- IRDA_DEBUG(4, "Ethernet address = %pM\n", bytes);
+ pr_debug("Ethernet address = %pM\n", bytes);
for (i = 0; i < 6; i++)
self->dev->dev_addr[i] = bytes[i];
}
{
struct irlan_cb *self;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(priv != NULL, return;);
self = priv;
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(2, "%s(), got NULL value!\n", __func__ );
+ pr_debug("%s(), got NULL value!\n", __func__);
irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
NULL);
return;
irias_delete_value(value);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown type!\n", __func__ );
+ pr_debug("%s(), unknown type!\n", __func__);
break;
}
irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
switch (event) {
case IRLAN_DISCOVERY_INDICATION:
if (self->client.iriap) {
- IRDA_WARNING("%s(), busy with a previous query\n",
- __func__);
+ net_warn_ratelimited("%s(), busy with a previous query\n",
+ __func__);
return -EBUSY;
}
"IrLAN", "IrDA:TinyTP:LsapSel");
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_client_state(self, IRLAN_CONN);
break;
case IRLAN_IAS_PROVIDER_NOT_AVAIL:
- IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__ );
+ pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__);
irlan_next_client_state(self, IRLAN_IDLE);
/* Give the client a kick! */
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch (event) {
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch (event) {
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
struct qos_info qos;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_client_state(self, IRLAN_DATA);
break;
default:
- IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
+ pr_debug("%s(), unknown access type!\n", __func__);
break;
}
break;
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
struct qos_info qos;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
} else if (self->client.recv_arb_val >
self->provider.send_arb_val)
{
- IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__ );
+ pr_debug("%s(), lost the battle :-(\n", __func__);
}
break;
case IRLAN_DATA_CONNECT_INDICATION:
irlan_next_client_state(self, IRLAN_IDLE);
break;
case IRLAN_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
+ pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_client_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (skb)
dev_kfree_skb(skb);
static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (skb)
dev_kfree_skb(skb);
struct irlan_cb *new;
__u16 hints;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
#ifdef CONFIG_PROC_FS
{ struct proc_dir_entry *proc;
proc = proc_create("irlan", 0, proc_irda, &irlan_fops);
}
#endif /* CONFIG_PROC_FS */
- IRDA_DEBUG(4, "%s()\n", __func__ );
hints = irlmp_service_to_hint(S_LAN);
/* Register with IrLMP as a client */
{
struct irlan_cb *self, *next;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
irlmp_unregister_client(ckey);
irlmp_unregister_service(skey);
struct net_device *dev;
struct irlan_cb *self;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Create network device with irlan */
dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
if (!dev)
irlan_next_provider_state(self, IRLAN_IDLE);
if (register_netdev(dev)) {
- IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
- __func__ );
+ pr_debug("%s(), register_netdev() failed!\n",
+ __func__);
self = NULL;
free_netdev(dev);
} else {
*/
static void __irlan_close(struct irlan_cb *self)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
ASSERT_RTNL();
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
self = instance;
tsap = sap;
self->max_sdu_size = max_sdu_size;
self->max_header_size = max_header_size;
- IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
+ pr_debug("%s: We are now connected!\n", __func__);
del_timer(&self->watchdog_timer);
/* TODO: we could set the MTU depending on the max_sdu_size */
- IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
+ pr_debug("%s: We are now connected!\n", __func__);
del_timer(&self->watchdog_timer);
/*
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(0, "%s(), reason=%d\n", __func__ , reason);
+ pr_debug("%s(), reason=%d\n", __func__ , reason);
self = instance;
tsap = sap;
IRDA_ASSERT(tsap == self->tsap_data, return;);
- IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
+ pr_debug("IrLAN, data channel disconnected by peer!\n");
/* Save reason so we know if we should try to reconnect or not */
self->disconnect_reason = reason;
switch (reason) {
case LM_USER_REQUEST: /* User request */
- IRDA_DEBUG(2, "%s(), User requested\n", __func__ );
+ pr_debug("%s(), User requested\n", __func__);
break;
case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
- IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __func__ );
+ pr_debug("%s(), Unexpected IrLAP disconnect\n", __func__);
break;
case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
- IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __func__ );
+ pr_debug("%s(), IrLAP connect failed\n", __func__);
break;
case LM_LAP_RESET: /* IrLAP reset */
- IRDA_DEBUG(2, "%s(), IrLAP reset\n", __func__ );
+ pr_debug("%s(), IrLAP reset\n", __func__);
break;
case LM_INIT_DISCONNECT:
- IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __func__ );
+ pr_debug("%s(), IrLMP connect failed\n", __func__);
break;
default:
- IRDA_ERROR("%s(), Unknown disconnect reason\n", __func__);
+ net_err_ratelimited("%s(), Unknown disconnect reason\n",
+ __func__);
break;
}
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
+ pr_debug("%s(), Got no tsap!\n", __func__);
return;
}
self->tsap_data = tsap;
void irlan_close_tsaps(struct irlan_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
{
struct sk_buff *skb;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
if (irda_lock(&self->client.tx_busy) == FALSE)
return -EBUSY;
dev_kfree_skb(skb);
return -1;
}
- IRDA_DEBUG(2, "%s(), sending ...\n", __func__ );
+ pr_debug("%s(), sending ...\n", __func__);
return irttp_data_request(self->client.tsap_ctrl, skb);
}
*/
static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
/* Queue command */
skb_queue_tail(&self->client.txq, skb);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
int n=0;
if (skb == NULL) {
- IRDA_DEBUG(2, "%s(), Got NULL skb\n", __func__ );
+ pr_debug("%s(), Got NULL skb\n", __func__);
return 0;
}
IRDA_ASSERT(value_len > 0, return 0;);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ );
+ pr_debug("%s(), Unknown parameter type!\n", __func__);
return 0;
}
/* Make space for data */
if (skb_tailroom(skb) < (param_len+value_len+3)) {
- IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __func__ );
+ pr_debug("%s(), No more space at end of skb\n", __func__);
return 0;
}
skb_put(skb, param_len+value_len+3);
__u16 val_len;
int n=0;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
/* get length of parameter name (1 byte) */
name_len = buf[n++];
if (name_len > 254) {
- IRDA_DEBUG(2, "%s(), name_len > 254\n", __func__ );
+ pr_debug("%s(), name_len > 254\n", __func__);
return -RSP_INVALID_COMMAND_FORMAT;
}
le16_to_cpus(&val_len); n+=2;
if (val_len >= 1016) {
- IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ );
+ pr_debug("%s(), parameter length to long\n", __func__);
return -RSP_INVALID_COMMAND_FORMAT;
}
*len = val_len;
value[val_len] = '\0';
n+=val_len;
- IRDA_DEBUG(4, "Parameter: %s ", name);
- IRDA_DEBUG(4, "Value: %s\n", value);
+ pr_debug("Parameter: %s ", name);
+ pr_debug("Value: %s\n", value);
return n;
}
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Ready to play! */
netif_stop_queue(dev); /* Wait until data link is ready */
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Stop device */
netif_stop_queue(dev);
return 0;
}
if (skb->len < ETH_HLEN) {
- IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
- __func__, skb->len);
+ pr_debug("%s() : IrLAN frame too short (%d)\n",
+ __func__, skb->len);
dev->stats.rx_dropped++;
dev_kfree_skb(skb);
return 0;
IRDA_ASSERT(dev != NULL, return;);
- IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__,
- flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
- netif_running(dev));
+ pr_debug("%s() : flow %s ; running %d\n", __func__,
+ flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
+ netif_running(dev));
switch (flow) {
case FLOW_STOP:
{
struct irlan_cb *self = netdev_priv(dev);
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Check if data channel has been connected yet */
if (self->client.state != IRLAN_DATA) {
- IRDA_DEBUG(1, "%s(), delaying!\n", __func__);
+ pr_debug("%s(), delaying!\n", __func__);
return;
}
if (dev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */
- IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n");
+ net_warn_ratelimited("Promiscuous mode not implemented by IrLAN!\n");
} else if ((dev->flags & IFF_ALLMULTI) ||
netdev_mc_count(dev) > HW_MAX_ADDRS) {
/* Disable promiscuous mode, use normal mode. */
- IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__);
+ pr_debug("%s(), Setting multicast filter\n", __func__);
/* hardware_set_filter(NULL); */
irlan_set_multicast_filter(self, TRUE);
} else if (!netdev_mc_empty(dev)) {
- IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__);
+ pr_debug("%s(), Setting multicast filter\n", __func__);
/* Walk the address list, and load the filter */
/* hardware_set_filter(dev->mc_list); */
irlan_set_multicast_filter(self, TRUE);
} else {
- IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__);
+ pr_debug("%s(), Clearing multicast filter\n", __func__);
irlan_set_multicast_filter(self, FALSE);
}
void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
{
- IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
+ pr_debug("%s(), %s\n", __func__ , irlan_state[state]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state)
{
- IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
+ pr_debug("%s(), %s\n", __func__ , irlan_state[state]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
if ((self->provider.filter_type == IRLAN_DIRECTED) &&
(self->provider.filter_operation == DYNAMIC))
{
- IRDA_DEBUG(0, "Giving peer a dynamic Ethernet address\n");
+ pr_debug("Giving peer a dynamic Ethernet address\n");
self->provider.mac_address[0] = 0x40;
self->provider.mac_address[1] = 0x00;
self->provider.mac_address[2] = 0x00;
if ((self->provider.filter_type == IRLAN_DIRECTED) &&
(self->provider.filter_mode == FILTER))
{
- IRDA_DEBUG(0, "Directed filter on\n");
+ pr_debug("Directed filter on\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_DIRECTED) &&
(self->provider.filter_mode == NONE))
{
- IRDA_DEBUG(0, "Directed filter off\n");
+ pr_debug("Directed filter off\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_BROADCAST) &&
(self->provider.filter_mode == FILTER))
{
- IRDA_DEBUG(0, "Broadcast filter on\n");
+ pr_debug("Broadcast filter on\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_BROADCAST) &&
(self->provider.filter_mode == NONE))
{
- IRDA_DEBUG(0, "Broadcast filter off\n");
+ pr_debug("Broadcast filter off\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_MULTICAST) &&
(self->provider.filter_mode == FILTER))
{
- IRDA_DEBUG(0, "Multicast filter on\n");
+ pr_debug("Multicast filter on\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_MULTICAST) &&
(self->provider.filter_mode == NONE))
{
- IRDA_DEBUG(0, "Multicast filter off\n");
+ pr_debug("Multicast filter off\n");
skb->data[0] = 0x00; /* Success */
skb->data[1] = 0x00;
return;
if ((self->provider.filter_type == IRLAN_MULTICAST) &&
(self->provider.filter_operation == GET))
{
- IRDA_DEBUG(0, "Multicast filter get\n");
+ pr_debug("Multicast filter get\n");
skb->data[0] = 0x00; /* Success? */
skb->data[1] = 0x02;
irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
skb->data[0] = 0x00; /* Command not supported */
skb->data[1] = 0x00;
- IRDA_DEBUG(0, "Not implemented!\n");
+ pr_debug("Not implemented!\n");
}
/*
*/
void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- IRDA_DEBUG(4, "%s, %s\n", param, value);
+ pr_debug("%s, %s\n", param, value);
/*
* This is experimental!! DB.
*/
if (strcmp(param, "MODE") == 0) {
- IRDA_DEBUG(0, "%s()\n", __func__ );
self->use_udata = TRUE;
return;
}
struct irlan_cb *self;
__u8 code;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
self = instance;
IRDA_ASSERT(self != NULL, return -1;);
code = skb->data[0];
switch(code) {
case CMD_GET_PROVIDER_INFO:
- IRDA_DEBUG(4, "Got GET_PROVIDER_INFO command!\n");
+ pr_debug("Got GET_PROVIDER_INFO command!\n");
irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb);
break;
case CMD_GET_MEDIA_CHAR:
- IRDA_DEBUG(4, "Got GET_MEDIA_CHAR command!\n");
+ pr_debug("Got GET_MEDIA_CHAR command!\n");
irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb);
break;
case CMD_OPEN_DATA_CHANNEL:
- IRDA_DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n");
+ pr_debug("Got OPEN_DATA_CHANNEL command!\n");
irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb);
break;
case CMD_FILTER_OPERATION:
- IRDA_DEBUG(4, "Got FILTER_OPERATION command!\n");
+ pr_debug("Got FILTER_OPERATION command!\n");
irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
break;
case CMD_RECONNECT_DATA_CHAN:
- IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __func__ );
- IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
+ pr_debug("%s(), Got RECONNECT_DATA_CHAN command\n", __func__);
+ pr_debug("%s(), NOT IMPLEMENTED\n", __func__);
break;
case CMD_CLOSE_DATA_CHAN:
- IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
- IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
+ pr_debug("Got CLOSE_DATA_CHAN command!\n");
+ pr_debug("%s(), NOT IMPLEMENTED\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
+ pr_debug("%s(), Unknown command!\n", __func__);
break;
}
return 0;
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(0, "%s()\n", __func__ );
-
self = instance;
tsap = sap;
struct irlan_cb *self;
struct tsap_cb *tsap;
- IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
+ pr_debug("%s(), reason=%d\n", __func__ , reason);
self = instance;
tsap = sap;
IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
- IRDA_DEBUG(4, "%s(), skb->len=%d\n", __func__ , (int)skb->len);
+ pr_debug("%s(), skb->len=%d\n", __func__ , (int)skb->len);
IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
/* How many parameters? */
count = frame[1];
- IRDA_DEBUG(4, "Got %d parameters\n", count);
+ pr_debug("Got %d parameters\n", count);
ptr = frame+2;
for (i=0; i<count;i++) {
ret = irlan_extract_param(ptr, name, value, &val_len);
if (ret < 0) {
- IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
+ pr_debug("%s(), IrLAN, Error!\n", __func__);
break;
}
ptr+=ret;
{
struct sk_buff *skb;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
irlan_insert_string_param(skb, "MEDIA", "802.5");
break;
default:
- IRDA_DEBUG(2, "%s(), unknown media type!\n", __func__ );
+ pr_debug("%s(), unknown media type!\n", __func__);
break;
}
irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown access type\n", __func__ );
+ pr_debug("%s(), Unknown access type\n", __func__);
break;
}
irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
irlan_filter_request(self, skb);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
+ pr_debug("%s(), Unknown command!\n", __func__);
break;
}
struct tsap_cb *tsap;
notify_t notify;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify);
if (!tsap) {
- IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
+ pr_debug("%s(), Got no tsap!\n", __func__);
return -1;
}
self->provider.tsap_ctrl = tsap;
static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_provider_state( self, IRLAN_INFO);
break;
default:
- IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
switch(event) {
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__ );
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
irlan_next_provider_state(self, IRLAN_IDLE);
break;
default:
- IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
+ pr_debug("%s(), Unknown event %d\n", __func__ , event);
break;
}
if (skb)
static void irlap_init_qos_capabilities(struct irlap_cb *self,
struct qos_info *qos_user);
-#ifdef CONFIG_IRDA_DEBUG
-static const char *const lap_reasons[] = {
+static const char *const lap_reasons[] __maybe_unused = {
"ERROR, NOT USED",
"LAP_DISC_INDICATION",
"LAP_NO_RESPONSE",
"LAP_PRIMARY_CONFLICT",
"ERROR, NOT USED",
};
-#endif /* CONFIG_IRDA_DEBUG */
int __init irlap_init(void)
{
/* Allocate master array */
irlap = hashbin_new(HB_LOCK);
if (irlap == NULL) {
- IRDA_ERROR("%s: can't allocate irlap hashbin!\n",
- __func__);
+ net_err_ratelimited("%s: can't allocate irlap hashbin!\n",
+ __func__);
return -ENOMEM;
}
{
struct irlap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* Initialize the irlap structure. */
self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL);
if (self == NULL)
{
struct irlap_cb *lap;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
/* Be sure that we manage to remove ourself from the hash */
lap = hashbin_remove(irlap, self->saddr, NULL);
if (!lap) {
- IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __func__);
+ pr_debug("%s(), Didn't find myself!\n", __func__);
return;
}
__irlap_close(lap);
*/
void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
}
void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
struct qos_info *qos_user, int sniff)
{
- IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __func__, daddr);
+ pr_debug("%s(), daddr=0x%08x\n", __func__, daddr);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
return;);
skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
return;);
skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
#ifdef CONFIG_IRDA_ULTRA
void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
*/
void irlap_disconnect_request(struct irlap_cb *self)
{
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
break;
default:
- IRDA_DEBUG(2, "%s(), disconnect pending!\n", __func__);
+ pr_debug("%s(), disconnect pending!\n", __func__);
self->disconnect_pending = TRUE;
break;
}
*/
void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
{
- IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, lap_reasons[reason]);
+ pr_debug("%s(), reason=%s\n", __func__, lap_reasons[reason]);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
switch (reason) {
case LAP_RESET_INDICATION:
- IRDA_DEBUG(1, "%s(), Sending reset request!\n", __func__);
+ pr_debug("%s(), Sending reset request!\n", __func__);
irlap_do_event(self, RESET_REQUEST, NULL, NULL);
break;
case LAP_NO_RESPONSE: /* FALLTHROUGH */
reason, NULL);
break;
default:
- IRDA_ERROR("%s: Unknown reason %d\n", __func__, reason);
+ net_err_ratelimited("%s: Unknown reason %d\n",
+ __func__, reason);
}
}
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(discovery != NULL, return;);
- IRDA_DEBUG(4, "%s(), nslots = %d\n", __func__, discovery->nslots);
+ pr_debug("%s(), nslots = %d\n", __func__, discovery->nslots);
IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
(discovery->nslots == 8) || (discovery->nslots == 16),
/* Discovery is only possible in NDM mode */
if (self->state != LAP_NDM) {
- IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n",
- __func__);
+ pr_debug("%s(), discovery only possible in NDM mode\n",
+ __func__);
irlap_discovery_confirm(self, NULL);
/* Note : in theory, if we are not in NDM, we could postpone
* the discovery like we do for connection request.
self->discovery_log = hashbin_new(HB_NOLOCK);
if (self->discovery_log == NULL) {
- IRDA_WARNING("%s(), Unable to allocate discovery log!\n",
- __func__);
+ net_warn_ratelimited("%s(), Unable to allocate discovery log!\n",
+ __func__);
return;
}
*/
void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(discovery != NULL, return;);
{
switch (quality_of_link) {
case STATUS_NO_ACTIVITY:
- IRDA_MESSAGE("IrLAP, no activity on link!\n");
+ net_info_ratelimited("IrLAP, no activity on link!\n");
break;
case STATUS_NOISY:
- IRDA_MESSAGE("IrLAP, noisy link!\n");
+ net_info_ratelimited("IrLAP, noisy link!\n");
break;
default:
break;
*/
void irlap_reset_indication(struct irlap_cb *self)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_reset_confirm(void)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
}
/*
{
/* nr as expected? */
if (nr == self->vs) {
- IRDA_DEBUG(4, "%s(), expected!\n", __func__);
+ pr_debug("%s(), expected!\n", __func__);
return NR_EXPECTED;
}
*/
void irlap_initiate_connection_state(struct irlap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
{
struct sk_buff *skb;
- IRDA_DEBUG(0, "%s(), setting speed to %d\n", __func__, speed);
+ pr_debug("%s(), setting speed to %d\n", __func__, speed);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
* user may not have set all of them.
*/
if (qos_user) {
- IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __func__);
+ pr_debug("%s(), Found user specified QoS!\n", __func__);
if (qos_user->baud_rate.bits)
self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
*/
void irlap_apply_default_connection_parameters(struct irlap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
*/
void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
self->N1 = sysctl_warn_noreply_time * 1000 /
self->qos_rx.max_turn_time.value;
- IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
+ pr_debug("Setting N1 = %d\n", self->N1);
/* Set N2 to match our own disconnect time */
self->N2 = self->qos_tx.link_disc_time.value * 1000 /
self->qos_rx.max_turn_time.value;
- IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
+ pr_debug("Setting N2 = %d\n", self->N2);
}
#ifdef CONFIG_PROC_FS
static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event,
struct sk_buff *, struct irlap_info *);
-#ifdef CONFIG_IRDA_DEBUG
-static const char *const irlap_event[] = {
+static const char *const irlap_event[] __maybe_unused = {
"DISCOVERY_REQUEST",
"CONNECT_REQUEST",
"CONNECT_RESPONSE",
"BACKOFF_TIMER_EXPIRED",
"MEDIA_BUSY_TIMER_EXPIRED",
};
-#endif /* CONFIG_IRDA_DEBUG */
const char *const irlap_state[] = {
"LAP_NDM",
} else
self->fast_RR = FALSE;
- IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies);
+ pr_debug("%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies);
#endif /* CONFIG_IRDA_FAST_RR */
if (timeout == 0)
if (!self || self->magic != LAP_MAGIC)
return;
- IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __func__,
- irlap_event[event], irlap_state[self->state]);
+ pr_debug("%s(), event = %s, state = %s\n", __func__,
+ irlap_event[event], irlap_state[self->state]);
ret = (*state[self->state])(self, event, skb, info);
* try to disconnect link if we send any data frames, since
* that will change the state away form XMIT
*/
- IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
- skb_queue_len(&self->txq));
+ pr_debug("%s() : queue len = %d\n", __func__,
+ skb_queue_len(&self->txq));
if (!skb_queue_empty(&self->txq)) {
/* Prevent race conditions with irlap_data_request() */
/* Note : this will never happen, because we test
* media busy in irlap_connect_request() and
* postpone the event... - Jean II */
- IRDA_DEBUG(0, "%s(), CONNECT_REQUEST: media busy!\n",
- __func__);
+ pr_debug("%s(), CONNECT_REQUEST: media busy!\n",
+ __func__);
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
irlap_connect_indication(self, skb);
} else {
- IRDA_DEBUG(0, "%s(), SNRM frame does not "
- "contain an I field!\n", __func__);
+ pr_debug("%s(), SNRM frame does not contain an I field!\n",
+ __func__);
}
break;
case DISCOVERY_REQUEST:
IRDA_ASSERT(info != NULL, return -1;);
if (self->media_busy) {
- IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n",
- __func__);
+ pr_debug("%s(), DISCOVERY_REQUEST: media busy!\n",
+ __func__);
/* irlap->log.condition = MEDIA_BUSY; */
/* This will make IrLMP try again */
* those cases...
* Jean II
*/
- IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __func__);
+ pr_debug("%s(), Receiving final discovery request, missed the discovery slots :-(\n",
+ __func__);
/* Last discovery request -> in the log */
irlap_discovery_indication(self, info->discovery);
case RECV_UI_FRAME:
/* Only accept broadcast frames in NDM mode */
if (info->caddr != CBROADCAST) {
- IRDA_DEBUG(0, "%s(), not a broadcast frame!\n",
- __func__);
+ pr_debug("%s(), not a broadcast frame!\n",
+ __func__);
} else
irlap_unitdata_indication(self, skb);
break;
irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
break;
case RECV_TEST_RSP:
- IRDA_DEBUG(0, "%s() not implemented!\n", __func__);
+ pr_debug("%s() not implemented!\n", __func__);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n", __func__,
+ irlap_event[event]);
ret = -1;
break;
IRDA_ASSERT(info != NULL, return -1;);
IRDA_ASSERT(info->discovery != NULL, return -1;);
- IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
- info->discovery->data.daddr);
+ pr_debug("%s(), daddr=%08x\n", __func__,
+ info->discovery->data.daddr);
if (!self->discovery_log) {
- IRDA_WARNING("%s: discovery log is gone! "
- "maybe the discovery timeout has been set"
- " too short?\n", __func__);
+ net_warn_ratelimited("%s: discovery log is gone! maybe the discovery timeout has been set too short?\n",
+ __func__);
break;
}
hashbin_insert(self->discovery_log,
IRDA_ASSERT(info != NULL, return -1;);
- IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __func__, info->s);
+ pr_debug("%s(), Receiving discovery request (s = %d) while performing discovery :-(\n",
+ __func__, info->s);
/* Last discovery request ? */
if (info->s == 0xff)
* timing requirements.
*/
if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
- IRDA_DEBUG(2, "%s(), device is slow to answer, "
- "waiting some more!\n", __func__);
+ pr_debug("%s(), device is slow to answer, waiting some more!\n",
+ __func__);
irlap_start_slot_timer(self, msecs_to_jiffies(10));
self->add_wait = TRUE;
return ret;
}
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n", __func__,
+ irlap_event[event]);
ret = -1;
break;
discovery_t *discovery_rsp;
int ret=0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
case QUERY_TIMER_EXPIRED:
- IRDA_DEBUG(0, "%s(), QUERY_TIMER_EXPIRED <%ld>\n",
- __func__, jiffies);
+ pr_debug("%s(), QUERY_TIMER_EXPIRED <%ld>\n",
+ __func__, jiffies);
irlap_next_state(self, LAP_NDM);
break;
case RECV_DISCOVERY_XID_CMD:
}
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, %s\n", __func__,
+ event, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
+ pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
break;
case RECV_DISCOVERY_XID_CMD:
- IRDA_DEBUG(3, "%s(), event RECV_DISCOVER_XID_CMD!\n",
- __func__);
+ pr_debug("%s(), event RECV_DISCOVER_XID_CMD!\n",
+ __func__);
irlap_next_state(self, LAP_NDM);
break;
case DISCONNECT_REQUEST:
- IRDA_DEBUG(0, "%s(), Disconnect request!\n", __func__);
+ pr_debug("%s(), Disconnect request!\n", __func__);
irlap_send_dm_frame(self);
irlap_next_state( self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, %s\n", __func__,
+ event, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
self->retry_count++;
break;
case RECV_SNRM_CMD:
- IRDA_DEBUG(4, "%s(), SNRM battle!\n", __func__);
+ pr_debug("%s(), SNRM battle!\n", __func__);
IRDA_ASSERT(skb != NULL, return 0;);
IRDA_ASSERT(info != NULL, return 0;);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, %s\n", __func__,
+ event, irlap_event[event]);
ret = -1;
break;
static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info)
{
- IRDA_DEBUG( 0, "%s(), Unknown event\n", __func__);
+ pr_debug("%s(), Unknown event\n", __func__);
return -1;
}
* speed and turn-around-time.
*/
if((!nextfit) && (skb->len > self->bytes_left)) {
- IRDA_DEBUG(0, "%s(), Not allowed to transmit"
- " more bytes!\n", __func__);
+ pr_debug("%s(), Not allowed to transmit more bytes!\n",
+ __func__);
/* Requeue the skb */
skb_queue_head(&self->txq, skb_get(skb));
/*
self->fast_RR = FALSE;
#endif /* CONFIG_IRDA_FAST_RR */
} else {
- IRDA_DEBUG(4, "%s(), Unable to send! remote busy?\n",
- __func__);
+ pr_debug("%s(), Unable to send! remote busy?\n",
+ __func__);
skb_queue_head(&self->txq, skb_get(skb));
/*
}
break;
case POLL_TIMER_EXPIRED:
- IRDA_DEBUG(3, "%s(), POLL_TIMER_EXPIRED <%ld>\n",
- __func__, jiffies);
+ pr_debug("%s(), POLL_TIMER_EXPIRED <%ld>\n",
+ __func__, jiffies);
irlap_send_rr_frame(self, CMD_FRAME);
/* Return to NRM properly - Jean II */
self->window = self->window_size;
* when we return... - Jean II */
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n",
+ __func__, irlap_event[event]);
ret = -EINVAL;
break;
{
int ret = 0;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
}
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d\n", __func__, event);
+ pr_debug("%s(), Unknown event %d\n", __func__, event);
ret = -1;
break;
/* Keep state */
irlap_next_state(self, LAP_NRM_P);
} else {
- IRDA_DEBUG(4,
- "%s(), missing or duplicate frame!\n",
- __func__);
+ pr_debug("%s(), missing or duplicate frame!\n",
+ __func__);
/* Update Nr received */
irlap_update_nr_received(self, info->nr);
if ((ns_status == NS_UNEXPECTED) &&
(nr_status == NR_UNEXPECTED))
{
- IRDA_DEBUG(4, "%s(), unexpected nr and ns!\n",
- __func__);
+ pr_debug("%s(), unexpected nr and ns!\n",
+ __func__);
if (info->pf) {
/* Resend rejected frames */
irlap_resend_rejected_frames(self, CMD_FRAME);
}
break;
}
- IRDA_DEBUG(1, "%s(), Not implemented!\n", __func__);
- IRDA_DEBUG(1, "%s(), event=%s, ns_status=%d, nr_status=%d\n",
- __func__, irlap_event[event], ns_status, nr_status);
+ pr_debug("%s(), Not implemented!\n", __func__);
+ pr_debug("%s(), event=%s, ns_status=%d, nr_status=%d\n",
+ __func__, irlap_event[event], ns_status, nr_status);
break;
case RECV_UI_FRAME:
/* Poll bit cleared? */
del_timer(&self->final_timer);
irlap_data_indication(self, skb, TRUE);
irlap_next_state(self, LAP_XMIT_P);
- IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __func__, irlap_state[self->state]);
+ pr_debug("%s: RECV_UI_FRAME: next state %s\n",
+ __func__, irlap_state[self->state]);
irlap_start_poll_timer(self, self->poll_timeout);
}
break;
/* Update Nr received */
irlap_update_nr_received(self, info->nr);
- IRDA_DEBUG(4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, "
- "vs=%d, vr=%d\n",
- self->retry_count, info->nr, self->va,
- self->vs, self->vr);
+ pr_debug("RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
+ self->retry_count, info->nr, self->va,
+ self->vs, self->vr);
/* Resend rejected frames */
irlap_resend_rejected_frames(self, CMD_FRAME);
irlap_next_state(self, LAP_NRM_P);
} else if (ret == NR_INVALID) {
- IRDA_DEBUG(1, "%s(), Received RR with "
- "invalid nr !\n", __func__);
+ pr_debug("%s(), Received RR with invalid nr !\n",
+ __func__);
irlap_next_state(self, LAP_RESET_WAIT);
* we only do this once for each frame.
*/
if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
- IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
- "frame! Waiting a little bit more!\n");
+ pr_debug("FINAL_TIMER_EXPIRED when receiving a frame! Waiting a little bit more!\n");
irlap_start_final_timer(self, msecs_to_jiffies(300));
/*
if (self->retry_count < self->N2) {
if (skb_peek(&self->wx_list) == NULL) {
/* Retry sending the pf bit to the secondary */
- IRDA_DEBUG(4, "nrm_p: resending rr");
+ pr_debug("nrm_p: resending rr");
irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_send_rr_frame(self, CMD_FRAME);
} else {
- IRDA_DEBUG(4, "nrm_p: resend frames");
+ pr_debug("nrm_p: resend frames");
irlap_resend_rejected_frames(self, CMD_FRAME);
}
irlap_start_final_timer(self, self->final_timeout);
self->retry_count++;
- IRDA_DEBUG(4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
- " retry_count=%d\n", self->retry_count);
+ pr_debug("irlap_state_nrm_p: FINAL_TIMER_EXPIRED: retry_count=%d\n",
+ self->retry_count);
/* Early warning event. I'm using a pretty liberal
* interpretation of the spec and generate an event
irlap_start_final_timer(self, 2 * self->final_timeout);
break;
case RECV_RD_RSP:
- IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __func__);
+ pr_debug("%s(), RECV_RD_RSP\n", __func__);
irlap_flush_all_queues(self);
irlap_next_state(self, LAP_XMIT_P);
irlap_disconnect_request(self);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n",
+ __func__, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
+ pr_debug("%s(), event = %s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
irlap_next_state( self, LAP_PCLOSE);
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n", __func__,
+ irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
+ pr_debug("%s(), event = %s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
* state
*/
if (!info) {
- IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __func__);
+ pr_debug("%s(), RECV_SNRM_CMD\n", __func__);
irlap_initiate_connection_state(self);
irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_send_ua_response_frame(self, &self->qos_rx);
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NDM);
} else {
- IRDA_DEBUG(0,
- "%s(), SNRM frame contained an I field!\n",
- __func__);
+ pr_debug("%s(), SNRM frame contained an I field!\n",
+ __func__);
}
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n",
+ __func__, irlap_event[event]);
ret = -1;
break;
{
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[event]);
+ pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
* speed and turn-around-time.
*/
if((!nextfit) && (skb->len > self->bytes_left)) {
- IRDA_DEBUG(0, "%s(), Not allowed to transmit"
- " more bytes!\n", __func__);
+ pr_debug("%s(), Not allowed to transmit more bytes!\n",
+ __func__);
/* Requeue the skb */
skb_queue_head(&self->txq, skb_get(skb));
ret = -EPROTO;
}
} else {
- IRDA_DEBUG(2, "%s(), Unable to send!\n", __func__);
+ pr_debug("%s(), Unable to send!\n", __func__);
skb_queue_head(&self->txq, skb_get(skb));
ret = -EPROTO;
}
* when we return... - Jean II */
break;
default:
- IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
+ pr_debug("%s(), Unknown event %s\n", __func__,
+ irlap_event[event]);
ret = -EINVAL;
break;
int nr_status;
int ret = 0;
- IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
+ pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
case RECV_I_CMD: /* Optimize for the common case */
/* FIXME: must check for remote_busy below */
- IRDA_DEBUG(4, "%s(), event=%s nr=%d, vs=%d, ns=%d, "
- "vr=%d, pf=%d\n", __func__,
- irlap_event[event], info->nr,
- self->vs, info->ns, self->vr, info->pf);
+ pr_debug("%s(), event=%s nr=%d, vs=%d, ns=%d, vr=%d, pf=%d\n",
+ __func__, irlap_event[event], info->nr,
+ self->vs, info->ns, self->vr, info->pf);
self->retry_count = 0;
if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
{
if (info->pf) {
- IRDA_DEBUG(4, "RECV_I_RSP: frame(s) lost\n");
+ pr_debug("RECV_I_RSP: frame(s) lost\n");
self->vr = (self->vr + 1) % 8;
}
if (ret == NR_INVALID) {
- IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n");
+ pr_debug("NRM_S, NR_INVALID not implemented!\n");
}
if (ret == NS_INVALID) {
- IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n");
+ pr_debug("NRM_S, NS_INVALID not implemented!\n");
}
break;
case RECV_UI_FRAME:
/* Keep state */
irlap_next_state(self, LAP_NRM_S);
} else {
- IRDA_DEBUG(1, "%s(), invalid nr not implemented!\n",
- __func__);
+ pr_debug("%s(), invalid nr not implemented!\n",
+ __func__);
}
break;
case RECV_SNRM_CMD:
/* SNRM frame is not allowed to contain an I-field */
if (!info) {
del_timer(&self->wd_timer);
- IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __func__);
+ pr_debug("%s(), received SNRM cmd\n", __func__);
irlap_next_state(self, LAP_RESET_CHECK);
irlap_reset_indication(self);
} else {
- IRDA_DEBUG(0,
- "%s(), SNRM frame contained an I-field!\n",
- __func__);
+ pr_debug("%s(), SNRM frame contained an I-field!\n",
+ __func__);
}
break;
* which explain why we use (self->N2 / 2) here !!!
* Jean II
*/
- IRDA_DEBUG(1, "%s(), retry_count = %d\n", __func__,
- self->retry_count);
+ pr_debug("%s(), retry_count = %d\n", __func__,
+ self->retry_count);
if (self->retry_count < (self->N2 / 2)) {
/* No retry, just wait for primary */
irlap_send_test_frame(self, self->caddr, info->daddr, skb);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
+ event, irlap_event[event]);
ret = -EINVAL;
break;
static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
break; /* stay in SCLOSE */
}
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
+ event, irlap_event[event]);
break;
}
{
int ret = 0;
- IRDA_DEBUG(1, "%s(), event=%s\n", __func__, irlap_event[event]);
+ pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
IRDA_ASSERT(self != NULL, return -ENODEV;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
irlap_next_state(self, LAP_SCLOSE);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
+ pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
+ event, irlap_event[event]);
ret = -EINVAL;
break;
irlap_insert_info(self, skb);
if (unlikely(self->mode & IRDA_MODE_MONITOR)) {
- IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __func__,
- self->netdev->name);
+ pr_debug("%s(): %s is in monitor mode\n", __func__,
+ self->netdev->name);
dev_kfree_skb(skb);
return;
}
/* Check if the new connection address is valid */
if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
- IRDA_DEBUG(3, "%s(), invalid connection address!\n",
- __func__);
+ pr_debug("%s(), invalid connection address!\n",
+ __func__);
return;
}
/* Only accept if addressed directly to us */
if (info->saddr != self->saddr) {
- IRDA_DEBUG(2, "%s(), not addressed to us!\n",
- __func__);
+ pr_debug("%s(), not addressed to us!\n",
+ __func__);
return;
}
irlap_do_event(self, RECV_SNRM_CMD, skb, info);
struct ua_frame *frame;
int ret;
- IRDA_DEBUG(2, "%s() <%ld>\n", __func__, jiffies);
+ pr_debug("%s() <%ld>\n", __func__, jiffies);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
struct sk_buff *tx_skb = NULL;
struct disc_frame *frame;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
__u32 bcast = BROADCAST;
__u8 *info;
- IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __func__,
- s, S, command);
+ pr_debug("%s(), s=%d, S=%d, command=%d\n", __func__,
+ s, S, command);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
__u8 *discovery_info;
char *text;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- IRDA_ERROR("%s: frame too short!\n", __func__);
+ net_err_ratelimited("%s: frame too short!\n", __func__);
return;
}
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
- __func__);
+ pr_debug("%s(), frame is not addressed to us!\n",
+ __func__);
return;
}
if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
- IRDA_WARNING("%s: kmalloc failed!\n", __func__);
+ net_warn_ratelimited("%s: kmalloc failed!\n", __func__);
return;
}
discovery->data.saddr = self->saddr;
discovery->timestamp = jiffies;
- IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
- discovery->data.daddr);
+ pr_debug("%s(), daddr=%08x\n", __func__,
+ discovery->data.daddr);
discovery_info = skb_pull(skb, sizeof(struct xid_frame));
/* Get info returned from peer */
discovery->data.hints[0] = discovery_info[0];
if (discovery_info[0] & HINT_EXTENSION) {
- IRDA_DEBUG(4, "EXTENSION\n");
+ pr_debug("EXTENSION\n");
discovery->data.hints[1] = discovery_info[1];
discovery->data.charset = discovery_info[2];
text = (char *) &discovery_info[3];
char *text;
if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- IRDA_ERROR("%s: frame too short!\n", __func__);
+ net_err_ratelimited("%s: frame too short!\n", __func__);
return;
}
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
- __func__);
+ pr_debug("%s(), frame is not addressed to us!\n",
+ __func__);
return;
}
/* Check if things are sane at this point... */
if((discovery_info == NULL) ||
!pskb_may_pull(skb, 3)) {
- IRDA_ERROR("%s: discovery frame too short!\n",
- __func__);
+ net_err_ratelimited("%s: discovery frame too short!\n",
+ __func__);
return;
}
* We now have some discovery info to deliver!
*/
discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC);
- if (!discovery) {
- IRDA_WARNING("%s: unable to malloc!\n", __func__);
+ if (!discovery)
return;
- }
discovery->data.daddr = info->daddr;
discovery->data.saddr = self->saddr;
{
info->nr = skb->data[1] >> 5;
- IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __func__, info->nr, jiffies);
+ pr_debug("%s(), nr=%d, %ld\n", __func__, info->nr, jiffies);
if (command)
irlap_do_event(self, RECV_RNR_CMD, skb, info);
static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(0, "%s()\n", __func__);
-
info->nr = skb->data[1] >> 5;
/* Check if this is a command or a response frame */
static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(0, "%s()\n", __func__);
-
info->nr = skb->data[1] >> 5;
/* Check if this is a command or a response frame */
static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info, int command)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/* Check if this is a command or a response frame */
if (command)
irlap_do_event(self, RECV_DISC_CMD, skb, info);
irlap_send_i_frame( self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
+ pr_debug("%s(), sending unreliable frame\n", __func__);
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
self->window -= 1;
}
irlap_next_state(self, LAP_NRM_P);
irlap_send_i_frame(self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
+ pr_debug("%s(), sending unreliable frame\n", __func__);
if (self->ack_required) {
irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
* See max_line_capacities[][] in qos.c for details. Jean II */
transmission_time -= (self->final_timeout * self->bytes_left
/ self->line_capacity);
- IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __func__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time);
+ pr_debug("%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n",
+ __func__, self->final_timeout, self->bytes_left,
+ self->line_capacity, transmission_time);
/* We are allowed to transmit a maximum number of bytes again. */
self->bytes_left = self->line_capacity;
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
if (!tx_skb) {
- IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
+ pr_debug("%s(), unable to copy\n", __func__);
return;
}
*/
while (!skb_queue_empty(&self->txq)) {
- IRDA_DEBUG(0, "%s(), sending additional frames!\n", __func__);
+ pr_debug("%s(), sending additional frames!\n", __func__);
if (self->window > 0) {
skb = skb_dequeue( &self->txq);
IRDA_ASSERT(skb != NULL, return;);
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
if (!tx_skb) {
- IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
+ pr_debug("%s(), unable to copy\n", __func__);
return;
}
void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
__u8 caddr, int command)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info)
{
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
info->pf = skb->data[1] & PF_BIT; /* Final bit */
irlap_do_event(self, RECV_UI_FRAME, skb, info);
__u8 *frame;
int w, x, y, z;
- IRDA_DEBUG(0, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(info != NULL, return;);
if (!pskb_may_pull(skb, 4)) {
- IRDA_ERROR("%s: frame too short!\n", __func__);
+ net_err_ratelimited("%s: frame too short!\n", __func__);
return;
}
z = frame[3] & 0x08;
if (w) {
- IRDA_DEBUG(0, "Rejected control field is undefined or not "
- "implemented.\n");
+ pr_debug("Rejected control field is undefined or not implemented\n");
}
if (x) {
- IRDA_DEBUG(0, "Rejected control field was invalid because it "
- "contained a non permitted I field.\n");
+ pr_debug("Rejected control field was invalid because it contained a non permitted I field\n");
}
if (y) {
- IRDA_DEBUG(0, "Received I field exceeded the maximum negotiated "
- "for the existing connection or exceeded the maximum "
- "this station supports if no connection exists.\n");
+ pr_debug("Received I field exceeded the maximum negotiated for the existing connection or exceeded the maximum this station supports if no connection exists\n");
}
if (z) {
- IRDA_DEBUG(0, "Rejected control field control field contained an "
- "invalid Nr count.\n");
+ pr_debug("Rejected control field control field contained an invalid Nr count\n");
}
irlap_do_event(self, RECV_FRMR_RSP, skb, info);
}
{
struct test_frame *frame;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
if (!pskb_may_pull(skb, sizeof(*frame))) {
- IRDA_ERROR("%s: frame too short!\n", __func__);
+ net_err_ratelimited("%s: frame too short!\n", __func__);
return;
}
frame = (struct test_frame *) skb->data;
/* Broadcast frames must carry saddr and daddr fields */
if (info->caddr == CBROADCAST) {
if (skb->len < sizeof(struct test_frame)) {
- IRDA_DEBUG(0, "%s() test frame too short!\n",
- __func__);
+ pr_debug("%s() test frame too short!\n",
+ __func__);
return;
}
* share and non linear skbs. This should never happen, so
* we don't need to be clever about it. Jean II */
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- IRDA_ERROR("%s: can't clone shared skb!\n", __func__);
+ net_err_ratelimited("%s: can't clone shared skb!\n", __func__);
goto err;
}
/* Check if frame is large enough for parsing */
if (!pskb_may_pull(skb, 2)) {
- IRDA_ERROR("%s: frame too short!\n", __func__);
+ net_err_ratelimited("%s: frame too short!\n", __func__);
goto err;
}
/* First we check if this frame has a valid connection address */
if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
- IRDA_DEBUG(0, "%s(), wrong connection address!\n",
- __func__);
+ pr_debug("%s(), wrong connection address!\n",
+ __func__);
goto out;
}
/*
irlap_recv_srej_frame(self, skb, &info, command);
break;
default:
- IRDA_WARNING("%s: Unknown S-frame %02x received!\n",
- __func__, info.control);
+ net_warn_ratelimited("%s: Unknown S-frame %02x received!\n",
+ __func__, info.control);
break;
}
goto out;
irlap_recv_ui_frame(self, skb, &info);
break;
default:
- IRDA_WARNING("%s: Unknown frame %02x received!\n",
- __func__, info.control);
+ net_warn_ratelimited("%s: Unknown frame %02x received!\n",
+ __func__, info.control);
break;
}
out:
*/
int __init irlmp_init(void)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
/* Initialize the irlmp structure. */
irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
if (irlmp == NULL)
/* Allocate new instance of a LSAP connection */
self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
- if (self == NULL) {
- IRDA_ERROR("%s: can't allocate memory\n", __func__);
+ if (self == NULL)
return NULL;
- }
self->magic = LMP_LSAP_MAGIC;
self->slsap_sel = slsap_sel;
*/
static void __irlmp_close_lsap(struct lsap_cb *self)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
NULL);
}
if (!lsap) {
- IRDA_DEBUG(0,
- "%s(), Looks like somebody has removed me already!\n",
- __func__);
+ pr_debug("%s(), Looks like somebody has removed me already!\n",
+ __func__);
return;
}
__irlmp_close_lsap(self);
* Allocate new instance of a LSAP connection
*/
lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL);
- if (lap == NULL) {
- IRDA_ERROR("%s: unable to kmalloc\n", __func__);
+ if (lap == NULL)
return;
- }
lap->irlap = irlap;
lap->magic = LMP_LAP_MAGIC;
#endif
lap->lsaps = hashbin_new(HB_LOCK);
if (lap->lsaps == NULL) {
- IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __func__);
+ net_warn_ratelimited("%s(), unable to kmalloc lsaps\n",
+ __func__);
kfree(lap);
return;
}
{
struct lap_cb *link;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* We must remove ourselves from the hashbin *first*. This ensure
* that no more LSAPs will be open on this link and no discovery
* will be triggered anymore. Jean II */
IRDA_ASSERT(self != NULL, return -EBADR;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
- IRDA_DEBUG(2,
- "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
- __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
+ pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
+ __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
if (test_bit(0, &self->connected)) {
ret = -EISCONN;
if (daddr != DEV_ADDR_ANY)
discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
else {
- IRDA_DEBUG(2, "%s(), no daddr\n", __func__);
+ pr_debug("%s(), no daddr\n", __func__);
discovery = (discovery_t *)
hashbin_get_first(irlmp->cachelog);
}
}
lap = hashbin_lock_find(irlmp->links, saddr, NULL);
if (lap == NULL) {
- IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __func__);
+ pr_debug("%s(), Unable to find a usable link!\n", __func__);
ret = -EHOSTUNREACH;
goto err;
}
* disconnected yet (waiting for timeout in LAP).
* Maybe we could give LAP a bit of help in this case.
*/
- IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__);
+ pr_debug("%s(), sorry, but I'm waiting for LAP to timeout!\n",
+ __func__);
ret = -EAGAIN;
goto err;
}
/* LAP is already connected to a different node, and LAP
* can only talk to one node at a time */
- IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __func__);
+ pr_debug("%s(), sorry, but link is busy!\n", __func__);
ret = -EBUSY;
goto err;
}
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(self->lap != NULL, return;);
- IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
+ pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Note : self->lap is set in irlmp_link_data_indication(),
* (case CONNECT_CMD:) because we have no way to set it here.
/* We set the connected bit and move the lsap to the connected list
* in the state machine itself. Jean II */
- IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
+ pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Make room for MUX control header (3 bytes) */
IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
int lap_header_size;
int max_seg_size;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(skb != NULL, return;);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
max_header_size = LMP_HEADER + lap_header_size;
- IRDA_DEBUG(2, "%s(), max_header_size=%d\n",
- __func__, max_header_size);
+ pr_debug("%s(), max_header_size=%d\n",
+ __func__, max_header_size);
/* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER);
struct lsap_cb *new;
unsigned long flags;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
/* Only allowed to duplicate unconnected LSAP's, and only LSAPs
* that have received a connect indication. Jean II */
if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||
(orig->lap == NULL)) {
- IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n",
- __func__);
+ pr_debug("%s(), invalid LSAP (wrong state)\n",
+ __func__);
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
flags);
return NULL;
/* Allocate a new instance */
new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);
if (!new) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
+ pr_debug("%s(), unable to kmalloc\n", __func__);
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
flags);
return NULL;
* and us that might mess up the hashbins below. This fixes it.
* Jean II */
if (! test_and_clear_bit(0, &self->connected)) {
- IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
+ pr_debug("%s(), already disconnected!\n", __func__);
dev_kfree_skb(userdata);
return -1;
}
{
struct lsap_cb *lsap;
- IRDA_DEBUG(1, "%s(), reason=%s [%d]\n", __func__,
- irlmp_reason_str(reason), reason);
+ pr_debug("%s(), reason=%s [%d]\n", __func__,
+ irlmp_reason_str(reason), reason);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
+ pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
+ __func__, self->slsap_sel, self->dlsap_sel);
/* Already disconnected ?
* There is a race condition between irlmp_disconnect_request()
* and us that might mess up the hashbins below. This fixes it.
* Jean II */
if (! test_and_clear_bit(0, &self->connected)) {
- IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
+ pr_debug("%s(), already disconnected!\n", __func__);
return;
}
self->notify.disconnect_indication(self->notify.instance,
self, reason, skb);
} else {
- IRDA_DEBUG(0, "%s(), no handler\n", __func__);
+ pr_debug("%s(), no handler\n", __func__);
}
}
/* Make sure the value is sane */
if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
- IRDA_WARNING("%s: invalid value for number of slots!\n",
- __func__);
+ net_warn_ratelimited("%s: invalid value for number of slots!\n",
+ __func__);
nslots = sysctl_discovery_slots = 8;
}
int number; /* Number of nodes in the log */
int i;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
/* Check if client wants or not partial/selective log (optimisation) */
if (!client->disco_callback)
return;
irlmp_client_t *client;
irlmp_client_t *client_next;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(log != NULL, return;);
if (!(HASHBIN_GET_SIZE(log)))
irlmp_client_t *client_next;
int i;
- IRDA_DEBUG(3, "%s()\n", __func__);
-
IRDA_ASSERT(expiries != NULL, return;);
/* For each client - notify callback may touch client list */
*/
discovery_t *irlmp_get_discovery_response(void)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(irlmp != NULL, return NULL;);
put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints);
{
int ret;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(userdata != NULL, return -1;);
/* Make room for MUX header */
*/
void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
struct sk_buff *clone_skb;
struct lap_cb *lap;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(userdata != NULL, return -1;);
/* Make room for MUX and PID header */
#ifdef CONFIG_IRDA_ULTRA
void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
curr->notify.status_indication(curr->notify.instance,
link, lock);
else
- IRDA_DEBUG(2, "%s(), no handler\n", __func__);
+ pr_debug("%s(), no handler\n", __func__);
curr = next;
}
/* Get the number of lsap. That's the only safe way to know
* that we have looped around... - Jean II */
lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
- IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __func__, lsap_todo);
+ pr_debug("%s() : %d lsaps to scan\n", __func__, lsap_todo);
/* Poll lsap in order until the queue is full or until we
* tried them all.
/* Uh-oh... Paranoia */
if(curr == NULL)
break;
- IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
+ pr_debug("%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n",
+ __func__, curr, next, self->flow_next, lsap_todo,
+ IRLAP_GET_TX_QUEUE_LEN(self->irlap));
/* Inform lsap user that it can send one more packet. */
if (curr->notify.flow_indication != NULL)
curr->notify.flow_indication(curr->notify.instance,
curr, flow);
else
- IRDA_DEBUG(1, "%s(), no handler\n", __func__);
+ pr_debug("%s(), no handler\n", __func__);
}
}
* since we currently only support 2 hint bytes
*/
service = kmalloc(16, GFP_ATOMIC);
- if (!service) {
- IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
+ if (!service)
return NULL;
- }
if (!hint[0]) {
- IRDA_DEBUG(1, "<None>\n");
+ pr_debug("<None>\n");
kfree(service);
return NULL;
}
if (hint[0] & HINT_PNP)
- IRDA_DEBUG(1, "PnP Compatible ");
+ pr_debug("PnP Compatible ");
if (hint[0] & HINT_PDA)
- IRDA_DEBUG(1, "PDA/Palmtop ");
+ pr_debug("PDA/Palmtop ");
if (hint[0] & HINT_COMPUTER)
- IRDA_DEBUG(1, "Computer ");
+ pr_debug("Computer ");
if (hint[0] & HINT_PRINTER) {
- IRDA_DEBUG(1, "Printer ");
+ pr_debug("Printer ");
service[i++] = S_PRINTER;
}
if (hint[0] & HINT_MODEM)
- IRDA_DEBUG(1, "Modem ");
+ pr_debug("Modem ");
if (hint[0] & HINT_FAX)
- IRDA_DEBUG(1, "Fax ");
+ pr_debug("Fax ");
if (hint[0] & HINT_LAN) {
- IRDA_DEBUG(1, "LAN Access ");
+ pr_debug("LAN Access ");
service[i++] = S_LAN;
}
/*
*/
if (hint[0] & HINT_EXTENSION) {
if (hint[1] & HINT_TELEPHONY) {
- IRDA_DEBUG(1, "Telephony ");
+ pr_debug("Telephony ");
service[i++] = S_TELEPHONY;
}
if (hint[1] & HINT_FILE_SERVER)
- IRDA_DEBUG(1, "File Server ");
+ pr_debug("File Server ");
if (hint[1] & HINT_COMM) {
- IRDA_DEBUG(1, "IrCOMM ");
+ pr_debug("IrCOMM ");
service[i++] = S_COMM;
}
if (hint[1] & HINT_OBEX) {
- IRDA_DEBUG(1, "IrOBEX ");
+ pr_debug("IrOBEX ");
service[i++] = S_OBEX;
}
}
- IRDA_DEBUG(1, "\n");
+ pr_debug("\n");
/* So that client can be notified about any discovery */
service[i++] = S_ANY;
{
irlmp_service_t *service;
- IRDA_DEBUG(4, "%s(), hints = %04x\n", __func__, hints);
+ pr_debug("%s(), hints = %04x\n", __func__, hints);
/* Make a new registration */
service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
- if (!service) {
- IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
+ if (!service)
return NULL;
- }
+
service->hints.word = hints;
hashbin_insert(irlmp->services, (irda_queue_t *) service,
(long) service, NULL);
irlmp_service_t *service;
unsigned long flags;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
if (!handle)
return -1;
/* Caller may call with invalid handle (it's legal) - Jean II */
service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
if (!service) {
- IRDA_DEBUG(1, "%s(), Unknown service!\n", __func__);
+ pr_debug("%s(), Unknown service!\n", __func__);
return -1;
}
{
irlmp_client_t *client;
- IRDA_DEBUG(1, "%s()\n", __func__);
IRDA_ASSERT(irlmp != NULL, return NULL;);
/* Make a new registration */
client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
- if (!client) {
- IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __func__);
+ if (!client)
return NULL;
- }
/* Register the details */
client->hint_mask.word = hint_mask;
client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
if (!client) {
- IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
+ pr_debug("%s(), Unknown client!\n", __func__);
return -1;
}
{
struct irlmp_client *client;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
if (!handle)
return -1;
/* Caller may call with invalid handle (it's legal) - Jean II */
client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
if (!client) {
- IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
+ pr_debug("%s(), Unknown client!\n", __func__);
return -1;
}
- IRDA_DEBUG(4, "%s(), removing client!\n", __func__);
+ pr_debug("%s(), removing client!\n", __func__);
hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
kfree(client);
IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
- IRDA_DEBUG(4, "%s()\n", __func__);
-
#ifdef CONFIG_IRDA_ULTRA
/* Accept all bindings to the connectionless LSAP */
if (slsap_sel == LSAP_CONNLESS)
goto errlsap;);
if ((self->slsap_sel == slsap_sel)) {
- IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n",
- self->slsap_sel);
+ pr_debug("Source LSAP selector=%02x in use\n",
+ self->slsap_sel);
goto errlsap;
}
self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
while (self != NULL) {
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;);
if ((self->slsap_sel == slsap_sel)) {
- IRDA_DEBUG(4, "Source LSAP selector=%02x in use (unconnected)\n",
- self->slsap_sel);
+ pr_debug("Source LSAP selector=%02x in use (unconnected)\n",
+ self->slsap_sel);
goto erruncon;
}
self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
/* Make sure we terminate the loop */
if (wrapped++) {
- IRDA_ERROR("%s: no more free LSAPs !\n",
- __func__);
+ net_err_ratelimited("%s: no more free LSAPs !\n",
+ __func__);
return 0;
}
}
/* Got it ! */
lsap_sel = irlmp->last_lsap_sel;
- IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n",
- __func__, lsap_sel);
+ pr_debug("%s(), found free lsap_sel=%02x\n",
+ __func__, lsap_sel);
return lsap_sel;
}
switch (lap_reason) {
case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
- IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __func__);
+ pr_debug("%s(), LAP_DISC_INDICATION\n", __func__);
reason = LM_USER_REQUEST;
break;
case LAP_NO_RESPONSE: /* To many retransmits without response */
- IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __func__);
+ pr_debug("%s(), LAP_NO_RESPONSE\n", __func__);
reason = LM_LAP_DISCONNECT;
break;
case LAP_RESET_INDICATION:
- IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __func__);
+ pr_debug("%s(), LAP_RESET_INDICATION\n", __func__);
reason = LM_LAP_RESET;
break;
case LAP_FOUND_NONE:
case LAP_MEDIA_BUSY:
case LAP_PRIMARY_CONFLICT:
- IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__);
+ pr_debug("%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n",
+ __func__);
reason = LM_CONNECT_FAILURE;
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown IrLAP disconnect reason %d!\n",
- __func__, lap_reason);
+ pr_debug("%s(), Unknown IrLAP disconnect reason %d!\n",
+ __func__, lap_reason);
reason = LM_LAP_DISCONNECT;
break;
}
"LSAP_SETUP_PEND",
};
-#ifdef CONFIG_IRDA_DEBUG
-static const char *const irlmp_event[] = {
+static const char *const irlmp_event[] __maybe_unused = {
"LM_CONNECT_REQUEST",
"LM_CONNECT_CONFIRM",
"LM_CONNECT_RESPONSE",
"LM_LAP_DISCOVERY_CONFIRM",
"LM_LAP_IDLE_TIMEOUT",
};
-#endif /* CONFIG_IRDA_DEBUG */
/* LAP Connection control proto declarations */
static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT,
IRLMP_STATE state)
{
/*
- IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
+ pr_debug("%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
*/
self->lap_state = state;
}
{
/*
IRDA_ASSERT(self != NULL, return;);
- IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
+ pr_debug("%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
*/
self->lsap_state = state;
}
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
- __func__, irlmp_event[event], irlsap_state[ self->lsap_state]);
+ pr_debug("%s(), EVENT = %s, STATE = %s\n",
+ __func__, irlmp_event[event], irlsap_state[self->lsap_state]);
return (*lsap_state[self->lsap_state]) (self, event, skb);
}
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__,
- irlmp_event[event],
- irlmp_state[self->lap_state]);
+ pr_debug("%s(), EVENT = %s, STATE = %s\n", __func__,
+ irlmp_event[event],
+ irlmp_state[self->lap_state]);
(*lap_state[self->lap_state]) (self, event, skb);
}
void irlmp_discovery_timer_expired(void *data)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* We always cleanup the log (active & passive discovery) */
irlmp_do_expiry();
{
struct lsap_cb *self = (struct lsap_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
{
struct lap_cb *self = (struct lap_cb *) data;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
IRDA_ASSERT(self->irlap != NULL, return;);
switch (event) {
irlap_connect_response(self->irlap, skb);
break;
case LM_LAP_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__);
+ pr_debug("%s() LS_CONNECT_REQUEST\n", __func__);
irlmp_next_lap_state(self, LAP_U_CONNECT);
irlap_connect_request(self->irlap, self->daddr, NULL, 0);
break;
case LM_LAP_DISCONNECT_INDICATION:
- IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
- __func__);
+ pr_debug("%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
+ __func__);
irlmp_next_lap_state(self, LAP_STANDBY);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s\n",
- __func__, irlmp_event[event]);
+ pr_debug("%s(), Unknown event %s\n",
+ __func__, irlmp_event[event]);
break;
}
}
static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]);
+ pr_debug("%s(), event=%s\n", __func__, irlmp_event[event]);
switch (event) {
case LM_LAP_CONNECT_INDICATION:
* the lsaps may already have gone. This avoid getting stuck
* forever in LAP_ACTIVE state - Jean II */
if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
+ pr_debug("%s() NO LSAPs !\n", __func__);
irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
}
break;
* the lsaps may already have gone. This avoid getting stuck
* forever in LAP_ACTIVE state - Jean II */
if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__);
+ pr_debug("%s() NO LSAPs !\n", __func__);
irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
}
break;
case LM_LAP_DISCONNECT_INDICATION:
- IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__);
+ pr_debug("%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__);
irlmp_next_lap_state(self, LAP_STANDBY);
/* Send disconnect event to all LSAPs using this link */
LM_LAP_DISCONNECT_INDICATION);
break;
case LM_LAP_DISCONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__);
+ pr_debug("%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__);
/* One of the LSAP did timeout or was closed, if it was
* the last one, try to get out of here - Jean II */
}
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s\n",
+ pr_debug("%s(), Unknown event %s\n",
__func__, irlmp_event[event]);
break;
}
static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
switch (event) {
case LM_LAP_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__);
+ pr_debug("%s(), LS_CONNECT_REQUEST\n", __func__);
/*
* IrLAP may have a pending disconnect. We tried to close
irlmp_do_expiry();
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s\n",
+ pr_debug("%s(), Unknown event %s\n",
__func__, irlmp_event[event]);
break;
}
{
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
break;
#endif /* CONFIG_IRDA_ULTRA */
case LM_CONNECT_REQUEST:
- IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__);
+ pr_debug("%s(), LM_CONNECT_REQUEST\n", __func__);
if (self->conn_skb) {
- IRDA_WARNING("%s: busy with another request!\n",
- __func__);
+ net_warn_ratelimited("%s: busy with another request!\n",
+ __func__);
return -EBUSY;
}
/* Don't forget to refcount it (see irlmp_connect_request()) */
break;
case LM_CONNECT_INDICATION:
if (self->conn_skb) {
- IRDA_WARNING("%s: busy with another request!\n",
- __func__);
+ net_warn_ratelimited("%s: busy with another request!\n",
+ __func__);
return -EBUSY;
}
/* Don't forget to refcount it (see irlap_driver_rcv()) */
irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
struct lsap_cb *lsap;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
case LM_WATCHDOG_TIMEOUT:
/* May happen, who knows...
* Jean II */
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
+ pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
/* Disconnect, get out... - Jean II */
self->lap = NULL;
default:
/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
* are *not* yet bound to the IrLAP link. Jean II */
- IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
struct sk_buff *tx_skb;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
/* Keep state */
break;
case LM_CONNECT_RESPONSE:
- IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
- "no indication issued yet\n", __func__);
+ pr_debug("%s(), LM_CONNECT_RESPONSE, no indication issued yet\n",
+ __func__);
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
- IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
- "not yet bound to IrLAP connection\n", __func__);
+ pr_debug("%s(), LM_DISCONNECT_REQUEST, not yet bound to IrLAP connection\n",
+ __func__);
/* Keep state */
break;
case LM_LAP_CONNECT_CONFIRM:
- IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __func__);
+ pr_debug("%s(), LS_CONNECT_CONFIRM\n", __func__);
irlmp_next_lsap_state(self, LSAP_CONNECT);
tx_skb = self->conn_skb;
/* Will happen in some rare cases because of a race condition.
* Just make sure we don't stay there forever...
* Jean II */
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
+ pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
/* Go back to disconnected mode, keep the socket waiting */
self->lap = NULL;
default:
/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
* are *not* yet bound to the IrLAP link. Jean II */
- IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
LM_REASON reason;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
IRDA_ASSERT(self->lap != NULL, return -1;);
irlmp_udata_indication(self, skb);
break;
case LM_CONNECT_REQUEST:
- IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
- "error, LSAP already connected\n", __func__);
+ pr_debug("%s(), LM_CONNECT_REQUEST, error, LSAP already connected\n",
+ __func__);
/* Keep state */
break;
case LM_CONNECT_RESPONSE:
- IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
- "error, LSAP already connected\n", __func__);
+ pr_debug("%s(), LM_CONNECT_RESPONSE, error, LSAP already connected\n",
+ __func__);
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
/* Try to close the LAP connection if its still there */
if (self->lap) {
- IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",
- __func__);
+ pr_debug("%s(), trying to close IrLAP\n",
+ __func__);
irlmp_do_lap_event(self->lap,
LM_LAP_DISCONNECT_REQUEST,
NULL);
reason = skb->data[3];
/* Try to close the LAP connection */
- IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
+ pr_debug("%s(), trying to close IrLAP\n", __func__);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, reason, skb);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s()\n", __func__);
-
switch (event) {
case LM_CONNECT_CONFIRM:
irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
reason = skb->data[3];
/* Try to close the LAP connection */
- IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
+ pr_debug("%s(), trying to close IrLAP\n", __func__);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, reason, skb);
irlmp_disconnect_indication(self, reason, skb);
break;
case LM_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
+ pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
IRDA_ASSERT(self->lap != NULL, return -1;);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
LM_REASON reason;
int ret = 0;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(irlmp != NULL, return -1;);
irlmp_next_lsap_state(self, LSAP_SETUP);
break;
case LM_WATCHDOG_TIMEOUT:
- IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __func__);
+ pr_debug("%s() : WATCHDOG_TIMEOUT !\n", __func__);
IRDA_ASSERT(self->lap != NULL, return -1;);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
irlmp_disconnect_indication(self, reason, NULL);
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
+ pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
+ __func__, irlmp_event[event], self->slsap_sel);
break;
}
return ret;
skb->data[1] = slsap;
if (expedited) {
- IRDA_DEBUG(4, "%s(), sending expedited data\n", __func__);
+ pr_debug("%s(), sending expedited data\n", __func__);
irlap_data_request(self->irlap, skb, TRUE);
} else
irlap_data_request(self->irlap, skb, FALSE);
{
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
__u8 dlsap_sel; /* Destination LSAP address */
__u8 *fp;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
IRDA_ASSERT(skb->len > 2, return;);
* it in a different way than other established connections.
*/
if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
- IRDA_DEBUG(3, "%s(), incoming connection, "
- "source LSAP=%d, dest LSAP=%d\n",
- __func__, slsap_sel, dlsap_sel);
+ pr_debug("%s(), incoming connection, source LSAP=%d, dest LSAP=%d\n",
+ __func__, slsap_sel, dlsap_sel);
/* Try to find LSAP among the unconnected LSAPs */
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
/* Maybe LSAP was already connected, so try one more time */
if (!lsap) {
- IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __func__);
+ pr_debug("%s(), incoming connection for LSAP already connected\n",
+ __func__);
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
self->lsaps);
}
self->lsaps);
if (lsap == NULL) {
- IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
- IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
- __func__, slsap_sel, dlsap_sel);
+ pr_debug("IrLMP, Sorry, no LSAP for received frame!\n");
+ pr_debug("%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
+ __func__, slsap_sel, dlsap_sel);
if (fp[0] & CONTROL_BIT) {
- IRDA_DEBUG(2, "%s(), received control frame %02x\n",
- __func__, fp[2]);
+ pr_debug("%s(), received control frame %02x\n",
+ __func__, fp[2]);
} else {
- IRDA_DEBUG(2, "%s(), received data frame\n", __func__);
+ pr_debug("%s(), received data frame\n", __func__);
}
return;
}
irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
break;
case DISCONNECT:
- IRDA_DEBUG(4, "%s(), Disconnect indication!\n",
- __func__);
+ pr_debug("%s(), Disconnect indication!\n",
+ __func__);
irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
skb);
break;
case ACCESSMODE_CMD:
- IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
+ pr_debug("Access mode cmd not implemented!\n");
break;
case ACCESSMODE_CNF:
- IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
+ pr_debug("Access mode cnf not implemented!\n");
break;
default:
- IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
- __func__, fp[2]);
+ pr_debug("%s(), Unknown control frame %02x\n",
+ __func__, fp[2]);
break;
}
} else if (unreliable) {
__u8 *fp;
unsigned long flags;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
IRDA_ASSERT(skb->len > 2, return;);
pid = fp[2];
if (pid & 0x80) {
- IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
- __func__);
+ pr_debug("%s(), extension in PID not supp!\n",
+ __func__);
return;
}
/* Check if frame is addressed to the connectionless LSAP */
if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
- IRDA_DEBUG(0, "%s(), dropping frame!\n", __func__);
+ pr_debug("%s(), dropping frame!\n", __func__);
return;
}
if (lsap)
irlmp_connless_data_indication(lsap, skb);
else {
- IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __func__);
+ pr_debug("%s(), found no matching LSAP!\n", __func__);
}
}
#endif /* CONFIG_IRDA_ULTRA */
LAP_REASON reason,
struct sk_buff *skb)
{
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(lap != NULL, return;);
IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
__u32 daddr, struct qos_info *qos,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* Copy QoS settings for this session */
self->qos = qos;
void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
IRDA_ASSERT(qos != NULL, return;);
*/
void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
{
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
#include <net/irda/irttp.h> /* irttp_init */
#include <net/irda/irda_device.h> /* irda_device_init */
-/*
- * Module parameters
- */
-#ifdef CONFIG_IRDA_DEBUG
-unsigned int irda_debug = IRDA_DEBUG_LEVEL;
-module_param_named(debug, irda_debug, uint, 0);
-MODULE_PARM_DESC(debug, "IRDA debugging level");
-EXPORT_SYMBOL(irda_debug);
-#endif
-
/* Packet type handler.
* Tell the kernel how IrDA packets should be handled.
*/
{
int ret = 0;
- IRDA_DEBUG(0, "%s()\n", __func__);
-
/* Lower layer of the stack */
irlmp_init();
irlap_init();
ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
- IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname);
+ pr_debug("%s(): Looking for %s\n", __func__, ifname);
return dev_get_by_name(net, ifname);
}
mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
- IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode);
+ pr_debug("%s(): Switching to mode: %d\n", __func__, mode);
dev = ifname_to_netdev(&init_net, info);
if (!dev)
static void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
{
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
/*
* Check if queue is empty.
*/
{
irda_queue_t *ret;
- IRDA_DEBUG( 4, "dequeue_first()\n");
+ pr_debug("dequeue_first()\n");
/*
* Set return value
{
irda_queue_t *ret;
- IRDA_DEBUG( 4, "dequeue_general()\n");
+ pr_debug("dequeue_general()\n");
/*
* Set return value
unsigned long flags = 0;
int bin;
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
IRDA_ASSERT( hashbin != NULL, return;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;);
unsigned long flags = 0;
irda_queue_t* entry;
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
IRDA_ASSERT( hashbin != NULL, return NULL;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
int bin;
long hashv;
- IRDA_DEBUG( 4, "%s()\n", __func__);
-
IRDA_ASSERT( hashbin != NULL, return NULL;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
IRDA_ASSERT( entry != NULL, return NULL;);
int bin;
irda_queue_t* entry;
- IRDA_DEBUG( 4, "hashbin_find()\n");
+ pr_debug("hashbin_find()\n");
IRDA_ASSERT( hashbin != NULL, return NULL;);
IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
.mode = 0644,
.proc_handler = do_devname,
},
-#ifdef CONFIG_IRDA_DEBUG
- {
- .procname = "debug",
- .data = &irda_debug,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
-#endif
#ifdef CONFIG_IRDA_FAST_RR
{
.procname = "fast_poll_increase",
irttp->tsaps = hashbin_new(HB_LOCK);
if (!irttp->tsaps) {
- IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n",
- __func__);
+ net_err_ratelimited("%s: can't allocate IrTTP hashbin!\n",
+ __func__);
kfree(irttp);
return -ENOMEM;
}
if (!self || self->magic != TTP_TSAP_MAGIC)
return;
- IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
+ pr_debug("%s(instance=%p)\n", __func__, self);
/* Try to make some progress, especially on Tx side - Jean II */
irttp_run_rx_queue(self);
{
struct sk_buff *skb;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
IRDA_ASSERT(self != NULL, return NULL;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
- IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __func__,
- self->rx_sdu_size);
+ pr_debug("%s(), self->rx_sdu_size=%d\n", __func__,
+ self->rx_sdu_size);
skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
if (!skb)
dev_kfree_skb(frag);
}
- IRDA_DEBUG(2,
- "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
- __func__, n, self->rx_sdu_size, self->rx_max_sdu_size);
+ pr_debug("%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
+ __func__, n, self->rx_sdu_size, self->rx_max_sdu_size);
/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
* by summing the size of all fragments, so we should always
* have n == self->rx_sdu_size, except in cases where we
struct sk_buff *frag;
__u8 *frame;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
IRDA_ASSERT(skb != NULL, return;);
* Split frame into a number of segments
*/
while (skb->len > self->max_seg_size) {
- IRDA_DEBUG(2, "%s(), fragmenting ...\n", __func__);
+ pr_debug("%s(), fragmenting ...\n", __func__);
/* Make new segment */
frag = alloc_skb(self->max_seg_size+self->max_header_size,
skb_queue_tail(&self->tx_queue, frag);
}
/* Queue what is left of the original skb */
- IRDA_DEBUG(2, "%s(), queuing last segment\n", __func__);
+ pr_debug("%s(), queuing last segment\n", __func__);
frame = skb_push(skb, TTP_HEADER);
frame[0] = 0x00; /* Clear more bit */
else
self->tx_max_sdu_size = param->pv.i;
- IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __func__, param->pv.i);
+ pr_debug("%s(), MaxSduSize=%d\n", __func__, param->pv.i);
return 0;
}
* JeanII */
if ((stsap_sel != LSAP_ANY) &&
((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {
- IRDA_DEBUG(0, "%s(), invalid tsap!\n", __func__);
+ pr_debug("%s(), invalid tsap!\n", __func__);
return NULL;
}
self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
- if (self == NULL) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __func__);
+ if (self == NULL)
return NULL;
- }
/* Initialize internal objects */
irttp_init_tsap(self);
*/
lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
if (lsap == NULL) {
- IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__);
+ pr_debug("%s: unable to allocate LSAP!!\n", __func__);
__irttp_close_tsap(self);
return NULL;
}
* the stsap_sel we have might not be valid anymore
*/
self->stsap_sel = lsap->slsap_sel;
- IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __func__, self->stsap_sel);
+ pr_debug("%s(), stsap_sel=%02x\n", __func__, self->stsap_sel);
self->notify = *notify;
self->lsap = lsap;
{
struct tsap_cb *tsap;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
if (self->connected) {
/* Check if disconnect is not pending */
if (!test_bit(0, &self->disconnect_pend)) {
- IRDA_WARNING("%s: TSAP still connected!\n",
- __func__);
+ net_warn_ratelimited("%s: TSAP still connected!\n",
+ __func__);
irttp_disconnect_request(self, NULL, P_NORMAL);
}
self->close_pend = TRUE;
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(4, "%s()\n", __func__);
-
/* Take shortcut on zero byte packets */
if (skb->len == 0) {
ret = 0;
/* Check that nothing bad happens */
if (!self->connected) {
- IRDA_WARNING("%s(), Not connected\n", __func__);
+ net_warn_ratelimited("%s(), Not connected\n", __func__);
ret = -ENOTCONN;
goto err;
}
if (skb->len > self->max_seg_size) {
- IRDA_ERROR("%s(), UData is too large for IrLAP!\n", __func__);
+ net_err_ratelimited("%s(), UData is too large for IrLAP!\n",
+ __func__);
ret = -EMSGSIZE;
goto err;
}
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
- skb_queue_len(&self->tx_queue));
+ pr_debug("%s() : queue len = %d\n", __func__,
+ skb_queue_len(&self->tx_queue));
/* Take shortcut on zero byte packets */
if (skb->len == 0) {
/* Check that nothing bad happens */
if (!self->connected) {
- IRDA_WARNING("%s: Not connected\n", __func__);
+ net_warn_ratelimited("%s: Not connected\n", __func__);
ret = -ENOTCONN;
goto err;
}
* inside an IrLAP frame
*/
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
- IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n",
- __func__);
+ net_err_ratelimited("%s: SAR disabled, and data is too large for IrLAP!\n",
+ __func__);
ret = -EMSGSIZE;
goto err;
}
if ((self->tx_max_sdu_size != 0) &&
(self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&
(skb->len > self->tx_max_sdu_size)) {
- IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
- __func__);
+ net_err_ratelimited("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
+ __func__);
ret = -EMSGSIZE;
goto err;
}
unsigned long flags;
int n;
- IRDA_DEBUG(2, "%s() : send_credit = %d, queue_len = %d\n",
- __func__,
- self->send_credit, skb_queue_len(&self->tx_queue));
+ pr_debug("%s() : send_credit = %d, queue_len = %d\n",
+ __func__,
+ self->send_credit, skb_queue_len(&self->tx_queue));
/* Get exclusive access to the tx queue, otherwise don't touch it */
if (irda_lock(&self->tx_queue_lock) == FALSE)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n",
- __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
+ pr_debug("%s() send=%d,avail=%d,remote=%d\n",
+ __func__,
+ self->send_credit, self->avail_credit, self->remote_credit);
/* Give credit to peer */
tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC);
struct tsap_cb *self;
int err;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(self != NULL, return -1;);
{
struct tsap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(self != NULL, return;);
self->notify.status_indication(self->notify.instance,
link, lock);
else
- IRDA_DEBUG(2, "%s(), no handler\n", __func__);
+ pr_debug("%s(), no handler\n", __func__);
}
/*
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
+ pr_debug("%s(instance=%p)\n", __func__, self);
/* We are "polled" directly from LAP, and the LAP want to fill
* its Tx window. We want to do our best to send it data, so that
*/
void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
{
- IRDA_DEBUG(1, "%s()\n", __func__);
-
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
switch (flow) {
case FLOW_STOP:
- IRDA_DEBUG(1, "%s(), flow stop\n", __func__);
+ pr_debug("%s(), flow stop\n", __func__);
self->rx_sdu_busy = TRUE;
break;
case FLOW_START:
- IRDA_DEBUG(1, "%s(), flow start\n", __func__);
+ pr_debug("%s(), flow start\n", __func__);
self->rx_sdu_busy = FALSE;
/* Client say he can accept more data, try to free our
break;
default:
- IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __func__);
+ pr_debug("%s(), Unknown flow command!\n", __func__);
}
}
EXPORT_SYMBOL(irttp_flow_request);
__u8 *frame;
__u8 n;
- IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __func__, max_sdu_size);
+ pr_debug("%s(), max_sdu_size=%d\n", __func__, max_sdu_size);
IRDA_ASSERT(self != NULL, return -EBADR;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
__u8 plen;
__u8 n;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(self != NULL, return;);
* negotiated QoS for the link.
*/
if (qos) {
- IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n",
- qos->baud_rate.bits);
- IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n",
- qos->baud_rate.value);
+ pr_debug("IrTTP, Negotiated BAUD_RATE: %02x\n",
+ qos->baud_rate.bits);
+ pr_debug("IrTTP, Negotiated BAUD_RATE: %d bps.\n",
+ qos->baud_rate.value);
}
n = skb->data[0] & 0x7f;
- IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __func__, n);
+ pr_debug("%s(), Initial send_credit=%d\n", __func__, n);
self->send_credit = n;
self->tx_max_sdu_size = 0;
/* Any errors in the parameter list? */
if (ret < 0) {
- IRDA_WARNING("%s: error extracting parameters\n",
- __func__);
+ net_warn_ratelimited("%s: error extracting parameters\n",
+ __func__);
dev_kfree_skb(skb);
/* Do not accept this connection attempt */
skb_pull(skb, IRDA_MIN(skb->len, plen+1));
}
- IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
+ pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__,
+ self->send_credit, self->avail_credit, self->remote_credit);
- IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __func__,
- self->tx_max_sdu_size);
+ pr_debug("%s(), MaxSduSize=%d\n", __func__,
+ self->tx_max_sdu_size);
if (self->notify.connect_confirm) {
self->notify.connect_confirm(self->notify.instance, self, qos,
self->max_seg_size = max_seg_size - TTP_HEADER;
self->max_header_size = max_header_size+TTP_HEADER;
- IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __func__, self->stsap_sel);
+ pr_debug("%s(), TSAP sel=%02x\n", __func__, self->stsap_sel);
/* Need to update dtsap_sel if its equal to LSAP_ANY */
self->dtsap_sel = lsap->dlsap_sel;
/* Any errors in the parameter list? */
if (ret < 0) {
- IRDA_WARNING("%s: error extracting parameters\n",
- __func__);
+ net_warn_ratelimited("%s: error extracting parameters\n",
+ __func__);
dev_kfree_skb(skb);
/* Do not accept this connection attempt */
IRDA_ASSERT(self != NULL, return -1;);
IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __func__,
- self->stsap_sel);
+ pr_debug("%s(), Source TSAP selector=%02x\n", __func__,
+ self->stsap_sel);
/* Any userdata supplied? */
if (userdata == NULL) {
struct tsap_cb *new;
unsigned long flags;
- IRDA_DEBUG(1, "%s()\n", __func__);
-
/* Protect our access to the old tsap instance */
spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
/* Find the old instance */
if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) {
- IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __func__);
+ pr_debug("%s(), unable to find TSAP\n", __func__);
spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
return NULL;
}
/* Allocate a new instance */
new = kmemdup(orig, sizeof(struct tsap_cb), GFP_ATOMIC);
if (!new) {
- IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
+ pr_debug("%s(), unable to kmalloc\n", __func__);
spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
return NULL;
}
/* Try to dup the LSAP (may fail if we were too slow) */
new->lsap = irlmp_dup(orig->lsap, new);
if (!new->lsap) {
- IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
+ pr_debug("%s(), dup failed!\n", __func__);
kfree(new);
return NULL;
}
/* Already disconnected? */
if (!self->connected) {
- IRDA_DEBUG(4, "%s(), already disconnected!\n", __func__);
+ pr_debug("%s(), already disconnected!\n", __func__);
if (userdata)
dev_kfree_skb(userdata);
return -1;
* for following a disconnect_indication() (i.e. net_bh).
* Jean II */
if (test_and_set_bit(0, &self->disconnect_pend)) {
- IRDA_DEBUG(0, "%s(), disconnect already pending\n",
- __func__);
+ pr_debug("%s(), disconnect already pending\n",
+ __func__);
if (userdata)
dev_kfree_skb(userdata);
* disconnecting right now since the data will
* not have any usable connection to be sent on
*/
- IRDA_DEBUG(1, "%s(): High priority!!()\n", __func__);
+ pr_debug("%s(): High priority!!()\n", __func__);
irttp_flush_queues(self);
} else if (priority == P_NORMAL) {
/*
* be sent at the LMP level (so even if the peer has its Tx queue
* full of data). - Jean II */
- IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __func__);
+ pr_debug("%s(), Disconnecting ...\n", __func__);
self->connected = FALSE;
if (!userdata) {
{
struct tsap_cb *self;
- IRDA_DEBUG(4, "%s()\n", __func__);
-
self = instance;
IRDA_ASSERT(self != NULL, return;);
* give an error back
*/
if (err) {
- IRDA_DEBUG(0, "%s() requeueing skb!\n", __func__);
+ pr_debug("%s() requeueing skb!\n", __func__);
/* Make sure we take a break */
self->rx_sdu_busy = TRUE;
struct sk_buff *skb;
int more = 0;
- IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
+ pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__,
+ self->send_credit, self->avail_credit, self->remote_credit);
/* Get exclusive access to the rx queue, otherwise don't touch it */
if (irda_lock(&self->rx_queue_lock) == FALSE)
* limits of the maximum size of the rx_sdu
*/
if (self->rx_sdu_size <= self->rx_max_sdu_size) {
- IRDA_DEBUG(4, "%s(), queueing frag\n",
- __func__);
+ pr_debug("%s(), queueing frag\n",
+ __func__);
skb_queue_tail(&self->rx_fragments, skb);
} else {
/* Free the part of the SDU that is too big */
/* Now we can deliver the reassembled skb */
irttp_do_data_indication(self, skb);
} else {
- IRDA_DEBUG(1, "%s(), Truncated frame\n", __func__);
+ pr_debug("%s(), Truncated frame\n", __func__);
/* Free the part of the SDU that is too big */
dev_kfree_skb(skb);
*/
if (p.pl == 0) {
if (p.pv.i < 0xff) {
- IRDA_DEBUG(2, "%s(), using 1 byte\n", __func__);
+ pr_debug("%s(), using 1 byte\n", __func__);
p.pl = 1;
} else if (p.pv.i < 0xffff) {
- IRDA_DEBUG(2, "%s(), using 2 bytes\n", __func__);
+ pr_debug("%s(), using 2 bytes\n", __func__);
p.pl = 2;
} else {
- IRDA_DEBUG(2, "%s(), using 4 bytes\n", __func__);
+ pr_debug("%s(), using 4 bytes\n", __func__);
p.pl = 4; /* Default length */
}
}
/* Check if buffer is long enough for insertion */
if (len < (2+p.pl)) {
- IRDA_WARNING("%s: buffer too short for insertion!\n",
- __func__);
+ net_warn_ratelimited("%s: buffer too short for insertion!\n",
+ __func__);
return -1;
}
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
- p.pi, p.pl, p.pv.i);
+ pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
+ p.pi, p.pl, p.pv.i);
switch (p.pl) {
case 1:
n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i);
break;
default:
- IRDA_WARNING("%s: length %d not supported\n",
- __func__, p.pl);
+ net_warn_ratelimited("%s: length %d not supported\n",
+ __func__, p.pl);
/* Skip parameter */
return -1;
}
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
- IRDA_WARNING("%s: buffer too short for parsing! "
- "Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
+ net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
+ __func__, p.pl, len);
return -1;
}
* PV_INTEGER means that the handler is flexible.
*/
if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
- IRDA_ERROR("%s: invalid parameter length! "
- "Expected %d bytes, but value had %d bytes!\n",
- __func__, type & PV_MASK, p.pl);
+ net_err_ratelimited("%s: invalid parameter length! Expected %d bytes, but value had %d bytes!\n",
+ __func__, type & PV_MASK, p.pl);
/* Most parameters are bit/byte fields or little endian,
* so it's ok to only extract a subset of it (the subset
le32_to_cpus(&p.pv.i);
break;
default:
- IRDA_WARNING("%s: length %d not supported\n",
- __func__, p.pl);
+ net_warn_ratelimited("%s: length %d not supported\n",
+ __func__, p.pl);
/* Skip parameter */
return p.pl+2;
}
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
- p.pi, p.pl, p.pv.i);
+ pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
+ p.pi, p.pl, p.pv.i);
/* Call handler for this parameter */
err = (*func)(self, &p, PV_PUT);
if (err < 0)
irda_param_t p;
int err;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract length of value */
if (p.pl > 32)
p.pl = 32;
- IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__,
- p.pi, p.pl);
+ pr_debug("%s(), pi=%#x, pl=%d\n", __func__,
+ p.pi, p.pl);
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
- IRDA_WARNING("%s: buffer too short for parsing! "
- "Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
+ net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
+ __func__, p.pl, len);
return -1;
}
* checked that the buffer is long enough */
strncpy(str, buf+2, p.pl);
- IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __func__,
- (__u8) str[0], (__u8) str[1]);
+ pr_debug("%s(), str=0x%02x 0x%02x\n",
+ __func__, (__u8)str[0], (__u8)str[1]);
/* Null terminate string */
str[p.pl] = '\0';
/* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) {
- IRDA_WARNING("%s: buffer too short for parsing! "
- "Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
+ net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
+ __func__, p.pl, len);
return -1;
}
- IRDA_DEBUG(0, "%s(), not impl\n", __func__);
+ pr_debug("%s(), not impl\n", __func__);
return p.pl+2; /* Extracted pl+2 bytes */
}
if ((pi_major > info->len-1) ||
(pi_minor > info->tables[pi_major].len-1))
{
- IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
- __func__, pi);
+ pr_debug("%s(), no handler for parameter=0x%02x\n",
+ __func__, pi);
/* Skip this parameter */
return -1;
/* Check if handler has been implemented */
if (!pi_minor_info->func) {
- IRDA_MESSAGE("%s: no handler for pi=%#x\n", __func__, pi);
+ net_info_ratelimited("%s: no handler for pi=%#x\n",
+ __func__, pi);
/* Skip this parameter */
return -1;
}
if ((pi_major > info->len-1) ||
(pi_minor > info->tables[pi_major].len-1))
{
- IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
- __func__, buf[0]);
+ pr_debug("%s(), no handler for parameter=0x%02x\n",
+ __func__, buf[0]);
/* Skip this parameter */
return 2 + buf[n + 1]; /* Continue */
/* Find expected data type for this parameter identifier (pi)*/
type = pi_minor_info->type;
- IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __func__,
- pi_major, pi_minor, type);
+ pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__,
+ pi_major, pi_minor, type);
/* Check if handler has been implemented */
if (!pi_minor_info->func) {
- IRDA_MESSAGE("%s: no handler for pi=%#x\n",
- __func__, buf[n]);
+ net_info_ratelimited("%s: no handler for pi=%#x\n",
+ __func__, buf[n]);
/* Skip this parameter */
return 2 + buf[n + 1]; /* Continue */
}
* able to check precisely what's going on. If a end user sees this,
* it's very likely the peer. - Jean II */
if (word == 0) {
- IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
- __func__);
+ net_warn_ratelimited("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
+ __func__);
/* The only safe choice (we don't know the array size) */
word = 0x1;
}
__u32 line_capacity;
int index;
- IRDA_DEBUG(2, "%s()\n", __func__);
-
/*
* Make sure the mintt is sensible.
* Main culprit : Ericsson T39. - Jean II
if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
int i;
- IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
- __func__, sysctl_min_tx_turn_time);
+ net_warn_ratelimited("%s(), Detected buggy peer, adjust mtt to %dus!\n",
+ __func__, sysctl_min_tx_turn_time);
/* We don't really need bits, but easier this way */
i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
if ((qos->baud_rate.value < 115200) &&
(qos->max_turn_time.value < 500))
{
- IRDA_DEBUG(0,
- "%s(), adjusting max turn time from %d to 500 ms\n",
- __func__, qos->max_turn_time.value);
+ pr_debug("%s(), adjusting max turn time from %d to 500 ms\n",
+ __func__, qos->max_turn_time.value);
qos->max_turn_time.value = 500;
}
#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
while ((qos->data_size.value > line_capacity) && (index > 0)) {
qos->data_size.value = data_sizes[index--];
- IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
- __func__, qos->data_size.value);
+ pr_debug("%s(), reducing data size to %d\n",
+ __func__, qos->data_size.value);
}
#else /* Use method described in section 6.6.11 of IrLAP */
while (irlap_requested_line_capacity(qos) > line_capacity) {
/* Must be able to send at least one frame */
if (qos->window_size.value > 1) {
qos->window_size.value--;
- IRDA_DEBUG(2, "%s(), reducing window size to %d\n",
- __func__, qos->window_size.value);
+ pr_debug("%s(), reducing window size to %d\n",
+ __func__, qos->window_size.value);
} else if (index > 1) {
qos->data_size.value = data_sizes[index--];
- IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
- __func__, qos->data_size.value);
+ pr_debug("%s(), reducing data size to %d\n",
+ __func__, qos->data_size.value);
} else {
- IRDA_WARNING("%s(), nothing more we can do!\n",
- __func__);
+ net_warn_ratelimited("%s(), nothing more we can do!\n",
+ __func__);
}
}
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
irlap_adjust_qos_settings(&self->qos_tx);
- IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
- self->qos_tx.baud_rate.value);
- IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
- self->qos_tx.data_size.value);
- IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
- self->qos_tx.window_size.value);
- IRDA_DEBUG(2, "Setting XBOFS to %d\n",
- self->qos_tx.additional_bofs.value);
- IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
- self->qos_tx.max_turn_time.value);
- IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
- self->qos_tx.min_turn_time.value);
- IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
- self->qos_tx.link_disc_time.value);
+ pr_debug("Setting BAUD_RATE to %d bps.\n",
+ self->qos_tx.baud_rate.value);
+ pr_debug("Setting DATA_SIZE to %d bytes\n",
+ self->qos_tx.data_size.value);
+ pr_debug("Setting WINDOW_SIZE to %d\n",
+ self->qos_tx.window_size.value);
+ pr_debug("Setting XBOFS to %d\n",
+ self->qos_tx.additional_bofs.value);
+ pr_debug("Setting MAX_TURN_TIME to %d ms.\n",
+ self->qos_tx.max_turn_time.value);
+ pr_debug("Setting MIN_TURN_TIME to %d usecs.\n",
+ self->qos_tx.min_turn_time.value);
+ pr_debug("Setting LINK_DISC to %d secs.\n",
+ self->qos_tx.link_disc_time.value);
return ret;
}
if (get) {
param->pv.i = self->qos_rx.baud_rate.bits;
- IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n",
- __func__, param->pv.i);
+ pr_debug("%s(), baud rate = 0x%02x\n",
+ __func__, param->pv.i);
} else {
/*
* Stations must agree on baud rate, so calculate
* intersection
*/
- IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", (__u16) param->pv.i);
+ pr_debug("Requested BAUD_RATE: 0x%04x\n", (__u16)param->pv.i);
final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits;
- IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
+ pr_debug("Final BAUD_RATE: 0x%04x\n", final);
self->qos_tx.baud_rate.bits = final;
self->qos_rx.baud_rate.bits = final;
}
* Stations must agree on link disconnect/threshold
* time.
*/
- IRDA_DEBUG(2, "LINK_DISC: %02x\n", (__u8) param->pv.i);
+ pr_debug("LINK_DISC: %02x\n", (__u8)param->pv.i);
final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits;
- IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
+ pr_debug("Final LINK_DISC: %02x\n", final);
self->qos_tx.link_disc_time.bits = final;
self->qos_rx.link_disc_time.bits = final;
}
__u32 line_capacity;
int i,j;
- IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n",
- __func__, speed, max_turn_time);
+ pr_debug("%s(), speed=%d, max_turn_time=%d\n",
+ __func__, speed, max_turn_time);
i = value_index(speed, baud_rates, 10);
j = value_index(max_turn_time, max_turn_times, 4);
line_capacity = max_line_capacities[i][j];
- IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n",
- __func__, line_capacity);
+ pr_debug("%s(), line capacity=%d bytes\n",
+ __func__, line_capacity);
return line_capacity;
}
irlap_min_turn_time_in_bytes(qos->baud_rate.value,
qos->min_turn_time.value);
- IRDA_DEBUG(2, "%s(), requested line capacity=%d\n",
- __func__, line_capacity);
+ pr_debug("%s(), requested line capacity=%d\n",
+ __func__, line_capacity);
return line_capacity;
}
* Nothing to worry about, but we set the default number of
* BOF's
*/
- IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __func__);
+ pr_debug("%s(), wrong magic in skb!\n", __func__);
xbofs = 10;
} else
xbofs = cb->xbofs + cb->xbofs_delay;
- IRDA_DEBUG(4, "%s(), xbofs=%d\n", __func__, xbofs);
+ pr_debug("%s(), xbofs=%d\n", __func__, xbofs);
/* Check that we never use more than 115 + 48 xbofs */
if (xbofs > 163) {
- IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __func__,
- xbofs);
+ pr_debug("%s(), too many xbofs (%d)\n", __func__,
+ xbofs);
xbofs = 163;
}
* transmitted after this point is 5.
*/
if(n >= (buffsize-5)) {
- IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n",
- __func__, n);
+ net_err_ratelimited("%s(), tx buffer overflow (n=%d)\n",
+ __func__, n);
return n;
}
case INSIDE_FRAME:
/* Not supposed to happen, the previous frame is not
* finished - Jean II */
- IRDA_DEBUG(1, "%s(), Discarding incomplete frame\n",
- __func__);
+ pr_debug("%s(), Discarding incomplete frame\n",
+ __func__);
stats->rx_errors++;
stats->rx_missed_errors++;
irda_device_set_media_busy(dev, TRUE);
/* Wrong CRC, discard frame! */
irda_device_set_media_busy(dev, TRUE);
- IRDA_DEBUG(1, "%s(), crc error\n", __func__);
+ pr_debug("%s(), crc error\n", __func__);
stats->rx_errors++;
stats->rx_crc_errors++;
}
break;
case LINK_ESCAPE:
- IRDA_WARNING("%s: state not defined\n", __func__);
+ net_warn_ratelimited("%s: state not defined\n", __func__);
break;
case BEGIN_FRAME:
rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
#endif
} else {
- IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
- __func__);
+ pr_debug("%s(), Rx buffer overflow, aborting\n",
+ __func__);
rx_buff->state = OUTSIDE_FRAME;
}
break;
#endif
rx_buff->state = INSIDE_FRAME;
} else {
- IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
- __func__);
+ pr_debug("%s(), Rx buffer overflow, aborting\n",
+ __func__);
rx_buff->state = OUTSIDE_FRAME;
}
break;
sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
cskb = skb;
- if (skb_copy_datagram_iovec(cskb, offset, msg->msg_iov, copied)) {
+ if (skb_copy_datagram_msg(cskb, offset, msg, copied)) {
if (!(flags & MSG_PEEK))
skb_queue_head(&sk->sk_receive_queue, skb);
return -EFAULT;
}
skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
copied = len;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto done;
else if (len < skb->len)
msg->msg_flags |= MSG_TRUNC;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+ err = skb_copy_datagram_msg(skb, 0, msg, len);
if (likely(err == 0))
err = len;
lapb_put(lapb);
}
}
+EXPORT_SYMBOL(lapb_register);
/*
* Add a socket to the bound sockets list.
write_unlock_bh(&lapb_list_lock);
return rc;
}
+EXPORT_SYMBOL(lapb_unregister);
int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
{
out:
return rc;
}
+EXPORT_SYMBOL(lapb_getparms);
int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
{
out:
return rc;
}
+EXPORT_SYMBOL(lapb_setparms);
int lapb_connect_request(struct net_device *dev)
{
out:
return rc;
}
+EXPORT_SYMBOL(lapb_connect_request);
int lapb_disconnect_request(struct net_device *dev)
{
out:
return rc;
}
+EXPORT_SYMBOL(lapb_disconnect_request);
int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
{
out:
return rc;
}
+EXPORT_SYMBOL(lapb_data_request);
int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
{
return rc;
}
+EXPORT_SYMBOL(lapb_data_received);
void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
{
return used;
}
-EXPORT_SYMBOL(lapb_register);
-EXPORT_SYMBOL(lapb_unregister);
-EXPORT_SYMBOL(lapb_getparms);
-EXPORT_SYMBOL(lapb_setparms);
-EXPORT_SYMBOL(lapb_connect_request);
-EXPORT_SYMBOL(lapb_disconnect_request);
-EXPORT_SYMBOL(lapb_data_request);
-EXPORT_SYMBOL(lapb_data_received);
-
static int __init lapb_init(void)
{
return 0;
used = len;
if (!(flags & MSG_TRUNC)) {
- int rc = skb_copy_datagram_iovec(skb, offset,
- msg->msg_iov, used);
+ int rc = skb_copy_datagram_msg(skb, offset, msg, used);
if (rc) {
/* Exception. Bailout! */
if (!copied)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
#include <net/llc_if.h>
#include <net/llc_sap.h>
#include <net/llc_s_ev.h>
---help---
This option enables the 'minstrel_ht' TX rate control algorithm
+config MAC80211_RC_MINSTREL_VHT
+ bool "Minstrel 802.11ac support" if EXPERT
+ depends on MAC80211_RC_MINSTREL_HT
+ default n
+ ---help---
+ This option enables VHT in the 'minstrel_ht' TX rate control algorithm
+
choice
prompt "Default rate control algorithm"
depends on MAC80211_HAS_RC
Do not select this option.
+config MAC80211_OCB_DEBUG
+ bool "Verbose OCB debugging"
+ depends on MAC80211_DEBUG_MENU
+ ---help---
+ Selecting this option causes mac80211 to print out
+ very verbose OCB debugging messages. It should not
+ be selected on production systems as those messages
+ are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_IBSS_DEBUG
bool "Verbose IBSS debugging"
depends on MAC80211_DEBUG_MENU
event.o \
chan.o \
trace.o mlme.o \
- tdls.o
+ tdls.o \
+ ocb.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
}
-static inline int ieee80211_ac_from_tid(int tid)
-{
- return ieee802_1d_to_ac[tid & 7];
-}
-
/*
* When multiple aggregation sessions on multiple stations
* are being created/destroyed simultaneously, we need to
#include "cfg.h"
#include "rate.h"
#include "mesh.h"
+#include "wme.h"
static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
const char *name,
* receive the key. When wpa_supplicant has roamed
* using FT, it attempts to set the key before
* association has completed, this rejects that attempt
- * so it will set the key again after assocation.
+ * so it will set the key again after association.
*
* TODO: accept the key if we have a station entry and
* add it to the device after the station.
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_OCB:
/* shouldn't happen */
WARN_ON_ONCE(1);
break;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac)
+ struct station_del_parameters *params)
{
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (mac)
- return sta_info_destroy_addr_bss(sdata, mac);
+ if (params->mac)
+ return sta_info_destroy_addr_bss(sdata, params->mac);
sta_info_flush(sdata);
return 0;
return 0;
}
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ memset(pinfo, 0, sizeof(*pinfo));
+ memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+ pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
+ mpath = mpp_path_lookup(sdata, dst);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpp_set_pinfo(mpath, mpp, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
+ mpath = mpp_path_lookup_by_idx(sdata, idx);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpp_set_pinfo(mpath, mpp, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
static int ieee80211_get_mesh_config(struct wiphy *wiphy,
struct net_device *dev,
struct mesh_config *conf)
return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
}
+static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev,
+ struct ocb_setup *setup)
+{
+ return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup);
+}
+
+static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev)
+{
+ return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev));
+}
+
static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
int rate[IEEE80211_NUM_BANDS])
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ if (local->ops->get_txpower)
+ return drv_get_txpower(local, sdata, dbm);
+
if (!local->use_chanctx)
*dbm = local->hw.conf.power_level;
else
if (sdata->reserved_ready)
return 0;
- err = ieee80211_vif_use_reserved_context(sdata);
- if (err)
- return err;
-
- return 0;
+ return ieee80211_vif_use_reserved_context(sdata);
}
if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
return err;
ieee80211_bss_info_change_notify(sdata, changed);
- cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
sdata->csa_block_tx = false;
}
+ err = drv_post_channel_switch(sdata);
+ if (err)
+ return err;
+
+ cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
return 0;
}
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_channel_switch ch_switch;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *chanctx;
- int err, changed = 0;
+ u32 changed = 0;
+ int err;
sdata_assert_lock(sdata);
lockdep_assert_held(&local->mtx);
goto out;
}
+ err = drv_pre_channel_switch(sdata, &ch_switch);
+ if (err)
+ goto out;
+
err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef,
chanctx->mode,
params->radar_required);
goto out;
}
+ ch_switch.timestamp = 0;
+ ch_switch.device_timestamp = 0;
+ ch_switch.block_tx = params->block_tx;
+ ch_switch.chandef = params->chandef;
+ ch_switch.count = params->count;
+
err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err) {
ieee80211_vif_unreserve_chanctx(sdata);
return ret;
}
+static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+ u8 tsid, const u8 *peer, u8 up,
+ u16 admitted_time)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ int ac = ieee802_1d_to_ac[up];
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ if (!(sdata->wmm_acm & BIT(up)))
+ return -EINVAL;
+
+ if (ifmgd->tx_tspec[ac].admitted_time)
+ return -EBUSY;
+
+ if (admitted_time) {
+ ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time;
+ ifmgd->tx_tspec[ac].tsid = tsid;
+ ifmgd->tx_tspec[ac].up = up;
+ }
+
+ return 0;
+}
+
+static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+ u8 tsid, const u8 *peer)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ int ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+
+ /* skip unused entries */
+ if (!tx_tspec->admitted_time)
+ continue;
+
+ if (tx_tspec->tsid != tsid)
+ continue;
+
+ /* due to this new packets will be reassigned to non-ACM ACs */
+ tx_tspec->up = -1;
+
+ /* Make sure that all packets have been sent to avoid to
+ * restore the QoS params on packets that are still on the
+ * queues.
+ */
+ synchronize_net();
+ ieee80211_flush_queues(local, sdata);
+
+ /* restore the normal QoS parameters
+ * (unconditionally to avoid races)
+ */
+ tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
+ tx_tspec->downgraded = false;
+ ieee80211_sta_handle_tspec_ac_params(sdata);
+
+ /* finally clear all the data */
+ memset(tx_tspec, 0, sizeof(*tx_tspec));
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
.change_mpath = ieee80211_change_mpath,
.get_mpath = ieee80211_get_mpath,
.dump_mpath = ieee80211_dump_mpath,
+ .get_mpp = ieee80211_get_mpp,
+ .dump_mpp = ieee80211_dump_mpp,
.update_mesh_config = ieee80211_update_mesh_config,
.get_mesh_config = ieee80211_get_mesh_config,
.join_mesh = ieee80211_join_mesh,
.leave_mesh = ieee80211_leave_mesh,
#endif
+ .join_ocb = ieee80211_join_ocb,
+ .leave_ocb = ieee80211_leave_ocb,
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
.set_monitor_channel = ieee80211_set_monitor_channel,
.channel_switch = ieee80211_channel_switch,
.set_qos_map = ieee80211_set_qos_map,
.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
+ .add_tx_ts = ieee80211_add_tx_ts,
+ .del_tx_ts = ieee80211_del_tx_ts,
};
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_OCB:
width = vif->bss_conf.chandef.width;
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_OCB:
break;
default:
WARN_ON_ONCE(1);
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_OCB:
ieee80211_queue_work(&sdata->local->hw,
&sdata->csa_finalize_work);
break;
}
break;
case IEEE80211_CHANCTX_WILL_BE_REPLACED:
- /* TODO: Perhaps the bandwith change could be treated as a
+ /* TODO: Perhaps the bandwidth change could be treated as a
* reservation itself? */
ret = -EBUSY;
goto out;
#define __MAC80211_DEBUG_H
#include <net/cfg80211.h>
+#ifdef CONFIG_MAC80211_OCB_DEBUG
+#define MAC80211_OCB_DEBUG 1
+#else
+#define MAC80211_OCB_DEBUG 0
+#endif
+
#ifdef CONFIG_MAC80211_IBSS_DEBUG
#define MAC80211_IBSS_DEBUG 1
#else
_sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \
sdata, fmt, ##__VA_ARGS__)
+#define ocb_dbg(sdata, fmt, ...) \
+ _sdata_dbg(MAC80211_OCB_DEBUG, \
+ sdata, fmt, ##__VA_ARGS__)
+
#define ibss_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_IBSS_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
lockdep_assert_held(&sdata->local->key_mtx);
- if (sdata->debugfs.default_unicast_key) {
- debugfs_remove(sdata->debugfs.default_unicast_key);
- sdata->debugfs.default_unicast_key = NULL;
- }
+ debugfs_remove(sdata->debugfs.default_unicast_key);
+ sdata->debugfs.default_unicast_key = NULL;
if (sdata->default_unicast_key) {
key = key_mtx_dereference(sdata->local,
sdata->vif.debugfs_dir, buf);
}
- if (sdata->debugfs.default_multicast_key) {
- debugfs_remove(sdata->debugfs.default_multicast_key);
- sdata->debugfs.default_multicast_key = NULL;
- }
+ debugfs_remove(sdata->debugfs.default_multicast_key);
+ sdata->debugfs.default_multicast_key = NULL;
if (sdata->default_multicast_key) {
key = key_mtx_dereference(sdata->local,
BSS_CHANGED_BEACON_ENABLED) &&
sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_OCB))
return;
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
if (!check_sdata_in_driver(sdata))
return -EIO;
+ if (WARN_ONCE(params->cw_min == 0 ||
+ params->cw_min > params->cw_max,
+ "%s: invalid CW_min/CW_max: %d/%d\n",
+ sdata->name, params->cw_min, params->cw_max))
+ return -EINVAL;
+
trace_drv_conf_tx(local, sdata, ac, params);
if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, &sdata->vif,
}
static inline void drv_channel_switch(struct ieee80211_local *local,
- struct ieee80211_channel_switch *ch_switch)
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_switch *ch_switch)
{
might_sleep();
- trace_drv_channel_switch(local, ch_switch);
- local->ops->channel_switch(&local->hw, ch_switch);
+ trace_drv_channel_switch(local, sdata, ch_switch);
+ local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
trace_drv_return_void(local);
}
trace_drv_return_void(local);
}
-static inline void drv_restart_complete(struct ieee80211_local *local)
+static inline void
+drv_reconfig_complete(struct ieee80211_local *local,
+ enum ieee80211_reconfig_type reconfig_type)
{
might_sleep();
- trace_drv_restart_complete(local);
- if (local->ops->restart_complete)
- local->ops->restart_complete(&local->hw);
+ trace_drv_reconfig_complete(local, reconfig_type);
+ if (local->ops->reconfig_complete)
+ local->ops->reconfig_complete(&local->hw, reconfig_type);
trace_drv_return_void(local);
}
}
}
+static inline int
+drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret = 0;
+
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ trace_drv_pre_channel_switch(local, sdata, ch_switch);
+ if (local->ops->pre_channel_switch)
+ ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif,
+ ch_switch);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+static inline int
+drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret = 0;
+
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ trace_drv_post_channel_switch(local, sdata);
+ if (local->ops->post_channel_switch)
+ ret = local->ops->post_channel_switch(&local->hw, &sdata->vif);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
static inline int drv_join_ibss(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
return ret;
}
+static inline int drv_get_txpower(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata, int *dbm)
+{
+ int ret;
+
+ if (!local->ops->get_txpower)
+ return -EOPNOTSUPP;
+
+ ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm);
+ trace_drv_get_txpower(local, sdata, *dbm, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
*
* These are bss flags that are attached to a bss in the
* @valid_data field of &struct ieee80211_bss. They show which parts
- * of the data structure were recieved as a result of an un-corrupted
+ * of the data structure were received as a result of an un-corrupted
* beacon/probe response.
*/
enum ieee80211_bss_valid_data_flags {
u8 ie[];
};
+struct ieee80211_sta_tx_tspec {
+ /* timestamp of the first packet in the time slice */
+ unsigned long time_slice_start;
+
+ u32 admitted_time; /* in usecs, unlike over the air */
+ u8 tsid;
+ s8 up; /* signed to be able to invalidate with -1 during teardown */
+
+ /* consumed TX time in microseconds in the time slice */
+ u32 consumed_tx_time;
+ enum {
+ TX_TSPEC_ACTION_NONE = 0,
+ TX_TSPEC_ACTION_DOWNGRADE,
+ TX_TSPEC_ACTION_STOP_DOWNGRADE,
+ } action;
+ bool downgraded;
+};
+
struct ieee80211_if_managed {
struct timer_list timer;
struct timer_list conn_mon_timer;
unsigned int flags;
+ bool csa_waiting_bcn;
+
bool beacon_crc_valid;
u32 beacon_crc;
u8 tdls_peer[ETH_ALEN] __aligned(2);
struct delayed_work tdls_peer_del_work;
+
+ /* WMM-AC TSPEC support */
+ struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
+ /* Use a separate work struct so that we can do something here
+ * while the sdata->work is flushing the queues, for example.
+ * otherwise, in scenarios where we hardly get any traffic out
+ * on the BE queue, but there's a lot of VO traffic, we might
+ * get stuck in a downgraded situation and flush takes forever.
+ */
+ struct delayed_work tx_tspec_wk;
};
struct ieee80211_if_ibss {
} state;
};
+/**
+ * struct ieee80211_if_ocb - OCB mode state
+ *
+ * @housekeeping_timer: timer for periodic invocation of a housekeeping task
+ * @wrkq_flags: OCB deferred task action
+ * @incomplete_lock: delayed STA insertion lock
+ * @incomplete_stations: list of STAs waiting for delayed insertion
+ * @joined: indication if the interface is connected to an OCB network
+ */
+struct ieee80211_if_ocb {
+ struct timer_list housekeeping_timer;
+ unsigned long wrkq_flags;
+
+ spinlock_t incomplete_lock;
+ struct list_head incomplete_stations;
+
+ bool joined;
+};
+
/**
* struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface
*
struct ieee80211_if_managed mgd;
struct ieee80211_if_ibss ibss;
struct ieee80211_if_mesh mesh;
+ struct ieee80211_if_ocb ocb;
u32 mntr_flags;
} u;
/* virtual monitor interface */
struct ieee80211_sub_if_data __rcu *monitor_sdata;
struct cfg80211_chan_def monitor_chandef;
+
+ /* extended capabilities provided by mac80211 */
+ u8 ext_capa[8];
};
static inline struct ieee80211_sub_if_data *
__le16 fc, bool acked);
void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata);
/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
+/* OCB code */
+void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid, const u8 *addr, u32 supp_rates);
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata);
+int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
+ struct ocb_setup *setup);
+int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata);
+
/* mesh code */
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
return true;
}
+extern const int ieee802_1d_to_ac[8];
+
+static inline int ieee80211_ac_from_tid(int tid)
+{
+ return ieee802_1d_to_ac[tid & 7];
+}
+
void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
void ieee80211_dynamic_ps_timer(unsigned long data);
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr);
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_hdr *hdr, bool ack);
+ struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
unsigned long queues,
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
- const u8 *ids, int n_ids, size_t offset);
+size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids,
+ const u8 *after_ric, int n_after_ric,
+ size_t offset);
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap);
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(nsdata, &local->interfaces, list) {
if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
+ /*
+ * Only OCB and monitor mode may coexist
+ */
+ if ((sdata->vif.type == NL80211_IFTYPE_OCB &&
+ nsdata->vif.type != NL80211_IFTYPE_MONITOR) ||
+ (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ nsdata->vif.type == NL80211_IFTYPE_OCB))
+ return -EBUSY;
+
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_DEVICE:
+ case NL80211_IFTYPE_OCB:
/* no special treatment */
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_OCB:
netif_carrier_off(dev);
break;
case NL80211_IFTYPE_WDS:
sdata_lock(sdata);
mutex_lock(&local->mtx);
sdata->vif.csa_active = false;
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ sdata->u.mgd.csa_waiting_bcn = false;
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
break;
ieee80211_mesh_work(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ ieee80211_ocb_work(sdata);
+ break;
default:
break;
}
static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type)
{
+ static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff};
+
/* clear type-dependent union */
memset(&sdata->u, 0, sizeof(sdata->u));
sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
ieee80211_sta_setup_sdata(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ sdata->vif.bss_conf.bssid = bssid_wildcard;
+ ieee80211_ocb_setup_sdata(sdata);
+ break;
case NL80211_IFTYPE_ADHOC:
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
ieee80211_ibss_setup_sdata(sdata);
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_OCB:
/*
* Could maybe also all others here?
* Just not sure how that interacts
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_OCB:
/*
* Could probably support everything
* but WDS here (WDS do_open can fail
}
ieee80211_assign_perm_addr(local, ndev->perm_addr, type);
- memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+ if (params && is_valid_ether_addr(params->macaddr))
+ memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN);
+ else
+ memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
/* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */
might_sleep();
- if (key->flags & KEY_FLAG_TAINTED)
+ if (key->flags & KEY_FLAG_TAINTED) {
+ /* If we get here, it's during resume and the key is
+ * tainted so shouldn't be used/programmed any more.
+ * However, its flags may still indicate that it was
+ * programmed into the device (since we're in resume)
+ * so clear that flag now to avoid trying to remove
+ * it again later.
+ */
+ key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
return -EINVAL;
+ }
if (!key->local->ops->set_key)
goto out_unsupported;
},
};
-static const u8 extended_capabilities[] = {
- 0, 0, 0, 0, 0, 0, 0,
- WLAN_EXT_CAPA8_OPMODE_NOTIF,
-};
-
-struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
- const struct ieee80211_ops *ops)
+struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
+ const struct ieee80211_ops *ops,
+ const char *requested_name)
{
struct ieee80211_local *local;
int priv_size, i;
*/
priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
- wiphy = wiphy_new(&mac80211_config_ops, priv_size);
+ wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name);
if (!wiphy)
return NULL;
WIPHY_FLAG_REPORTS_OBSS |
WIPHY_FLAG_OFFCHAN_TX;
- wiphy->extended_capabilities = extended_capabilities;
- wiphy->extended_capabilities_mask = extended_capabilities;
- wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
-
if (ops->remain_on_channel)
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
NL80211_FEATURE_SAE |
NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER |
+ NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM;
if (!ops->hw_scan)
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
+ local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF;
+
+ wiphy->extended_capabilities = local->ext_capa;
+ wiphy->extended_capabilities_mask = local->ext_capa;
+ wiphy->extended_capabilities_len =
+ ARRAY_SIZE(local->ext_capa);
+
INIT_LIST_HEAD(&local->interfaces);
__hw_addr_init(&local->mc_list);
return &local->hw;
}
-EXPORT_SYMBOL(ieee80211_alloc_hw);
+EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
{
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
return -EINVAL;
- /* DFS currently not supported with channel context drivers */
+ /* DFS is not supported with multi-channel combinations yet */
for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *comb;
comb = &local->hw.wiphy->iface_combinations[i];
- if (comb->radar_detect_widths)
+ if (comb->radar_detect_widths &&
+ comb->num_different_channels > 1)
return -EINVAL;
}
}
if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+ /* mac80211 supports eCSA, if the driver supports STA CSA at all */
+ if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)
+ local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
+
local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
result = wiphy_register(local->hw.wiphy);
}
/* add one default STA interface if supported */
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
+ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
+ !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) {
result = ieee80211_if_add(local, "wlan%d", NULL,
NL80211_IFTYPE_STATION, NULL);
if (result)
const u8 *dst, const u8 *mpp);
struct mesh_path *
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
extern int mesh_paths_generation;
+extern int mpp_paths_generation;
#ifdef CONFIG_MAC80211_MESH
static inline
static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
int mesh_paths_generation;
+int mpp_paths_generation;
/* This lock will have the grow table function as writer and add / delete nodes
* as readers. RCU provides sufficient protection only when reading the table
return NULL;
}
+/**
+ * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the proxy path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
+{
+ struct mesh_table *tbl = rcu_dereference(mpp_paths);
+ struct mpath_node *node;
+ int i;
+ int j = 0;
+
+ for_each_mesh_entry(tbl, node, i) {
+ if (sdata && node->mpath->sdata != sdata)
+ continue;
+ if (j++ == idx)
+ return node->mpath;
+ }
+
+ return NULL;
+}
+
/**
* mesh_path_add_gate - add the given mpath to a mesh gate to our path table
* @mpath: gate path to add to table
spin_unlock(&tbl->hashwlock[hash_idx]);
read_unlock_bh(&pathtbl_resize_lock);
+
+ mpp_paths_generation++;
+
if (grow) {
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
WLAN_EID_QOS_CAPA,
WLAN_EID_RRM_ENABLED_CAPABILITIES,
WLAN_EID_MOBILITY_DOMAIN,
+ WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */
+ WLAN_EID_RIC_DATA, /* reassoc only */
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
};
- noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
- before_ht, ARRAY_SIZE(before_ht),
- offset);
+ static const u8 after_ric[] = {
+ WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+ WLAN_EID_HT_CAPABILITY,
+ WLAN_EID_BSS_COEX_2040,
+ WLAN_EID_EXT_CAPABILITY,
+ WLAN_EID_QOS_TRAFFIC_CAPA,
+ WLAN_EID_TIM_BCAST_REQ,
+ WLAN_EID_INTERWORKING,
+ /* 60GHz doesn't happen right now */
+ WLAN_EID_VHT_CAPABILITY,
+ WLAN_EID_OPMODE_NOTIF,
+ };
+
+ noffset = ieee80211_ie_split_ric(assoc_data->ie,
+ assoc_data->ie_len,
+ before_ht,
+ ARRAY_SIZE(before_ht),
+ after_ric,
+ ARRAY_SIZE(after_ric),
+ offset);
pos = skb_put(skb, noffset - offset);
memcpy(pos, assoc_data->ie + offset, noffset - offset);
offset = noffset;
WLAN_EID_TIM_BCAST_REQ,
WLAN_EID_INTERWORKING,
};
+
+ /* RIC already taken above, so no need to handle here anymore */
noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
before_vht, ARRAY_SIZE(before_vht),
offset);
/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->csa_chandef.chan;
- sdata->vif.csa_active = false;
-
- /* XXX: wait for a beacon first? */
- if (sdata->csa_block_tx) {
- ieee80211_wake_vif_queues(local, sdata,
- IEEE80211_QUEUE_STOP_REASON_CSA);
- sdata->csa_block_tx = false;
- }
+ ifmgd->csa_waiting_bcn = true;
ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
sdata_unlock(sdata);
}
+static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ int ret;
+
+ sdata_assert_lock(sdata);
+
+ WARN_ON(!sdata->vif.csa_active);
+
+ if (sdata->csa_block_tx) {
+ ieee80211_wake_vif_queues(local, sdata,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+ sdata->csa_block_tx = false;
+ }
+
+ sdata->vif.csa_active = false;
+ ifmgd->csa_waiting_bcn = false;
+
+ ret = drv_post_channel_switch(sdata);
+ if (ret) {
+ sdata_info(sdata,
+ "driver post channel switch failed, disconnecting\n");
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ return;
+ }
+}
+
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- u64 timestamp, struct ieee802_11_elems *elems,
+ u64 timestamp, u32 device_timestamp,
+ struct ieee802_11_elems *elems,
bool beacon)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *chanctx;
enum ieee80211_band current_band;
struct ieee80211_csa_ie csa_ie;
+ struct ieee80211_channel_switch ch_switch;
int res;
sdata_assert_lock(sdata);
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
- if (local->use_chanctx) {
- u32 num_chanctx = 0;
- list_for_each_entry(chanctx, &local->chanctx_list, list)
- num_chanctx++;
+ if (local->use_chanctx &&
+ !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+ sdata_info(sdata,
+ "driver doesn't support chan-switch with channel contexts\n");
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ mutex_unlock(&local->chanctx_mtx);
+ mutex_unlock(&local->mtx);
+ return;
+ }
- if (num_chanctx > 1 ||
- !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
- sdata_info(sdata,
- "not handling chan-switch with channel contexts\n");
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
- mutex_unlock(&local->mtx);
- return;
- }
+ ch_switch.timestamp = timestamp;
+ ch_switch.device_timestamp = device_timestamp;
+ ch_switch.block_tx = csa_ie.mode;
+ ch_switch.chandef = csa_ie.chandef;
+ ch_switch.count = csa_ie.count;
+
+ if (drv_pre_channel_switch(sdata, &ch_switch)) {
+ sdata_info(sdata,
+ "preparing for channel switch failed, disconnecting\n");
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ mutex_unlock(&local->chanctx_mtx);
+ mutex_unlock(&local->mtx);
+ return;
}
res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
if (local->ops->channel_switch) {
/* use driver's channel switch callback */
- struct ieee80211_channel_switch ch_switch = {
- .timestamp = timestamp,
- .block_tx = csa_ie.mode,
- .chandef = csa_ie.chandef,
- .count = csa_ie.count,
- };
-
- drv_channel_switch(local, &ch_switch);
+ drv_channel_switch(local, sdata, &ch_switch);
return;
}
mutex_unlock(&sdata->local->mtx);
}
+static bool
+__ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ bool ret;
+ int ac;
+
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ return false;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+ int non_acm_ac;
+ unsigned long now = jiffies;
+
+ if (tx_tspec->action == TX_TSPEC_ACTION_NONE &&
+ tx_tspec->admitted_time &&
+ time_after(now, tx_tspec->time_slice_start + HZ)) {
+ tx_tspec->consumed_tx_time = 0;
+ tx_tspec->time_slice_start = now;
+
+ if (tx_tspec->downgraded)
+ tx_tspec->action =
+ TX_TSPEC_ACTION_STOP_DOWNGRADE;
+ }
+
+ switch (tx_tspec->action) {
+ case TX_TSPEC_ACTION_STOP_DOWNGRADE:
+ /* take the original parameters */
+ if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
+ sdata_err(sdata,
+ "failed to set TX queue parameters for queue %d\n",
+ ac);
+ tx_tspec->action = TX_TSPEC_ACTION_NONE;
+ tx_tspec->downgraded = false;
+ ret = true;
+ break;
+ case TX_TSPEC_ACTION_DOWNGRADE:
+ if (time_after(now, tx_tspec->time_slice_start + HZ)) {
+ tx_tspec->action = TX_TSPEC_ACTION_NONE;
+ ret = true;
+ break;
+ }
+ /* downgrade next lower non-ACM AC */
+ for (non_acm_ac = ac + 1;
+ non_acm_ac < IEEE80211_NUM_ACS;
+ non_acm_ac++)
+ if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac)))
+ break;
+ /* The loop will result in using BK even if it requires
+ * admission control, such configuration makes no sense
+ * and we have to transmit somehow - the AC selection
+ * does the same thing.
+ */
+ if (drv_conf_tx(local, sdata, ac,
+ &sdata->tx_conf[non_acm_ac]))
+ sdata_err(sdata,
+ "failed to set TX queue parameters for queue %d\n",
+ ac);
+ tx_tspec->action = TX_TSPEC_ACTION_NONE;
+ ret = true;
+ schedule_delayed_work(&ifmgd->tx_tspec_wk,
+ tx_tspec->time_slice_start + HZ - now + 1);
+ break;
+ case TX_TSPEC_ACTION_NONE:
+ /* nothing now */
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
+{
+ if (__ieee80211_sta_handle_tspec_ac_params(sdata))
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+}
+
+static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.tx_tspec_wk.work);
+ ieee80211_sta_handle_tspec_ac_params(sdata);
+}
+
/* MLME */
static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
params.uapsd = uapsd;
mlme_dbg(sdata,
- "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+ "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
queue, aci, acm,
params.aifs, params.cw_min, params.cw_max,
- params.txop, params.uapsd);
+ params.txop, params.uapsd,
+ ifmgd->tx_tspec[queue].downgraded);
sdata->tx_conf[queue] = params;
- if (drv_conf_tx(local, sdata, queue, ¶ms))
+ if (!ifmgd->tx_tspec[queue].downgraded &&
+ drv_conf_tx(local, sdata, queue, ¶ms))
sdata_err(sdata,
"failed to set TX queue parameters for queue %d\n",
queue);
ieee80211_vif_release_channel(sdata);
sdata->vif.csa_active = false;
+ ifmgd->csa_waiting_bcn = false;
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
}
mutex_unlock(&local->mtx);
+ /* existing TX TSPEC sessions no longer exist */
+ memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
+ cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
+
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
}
mutex_unlock(&local->mtx);
}
+static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr,
+ u16 tx_time)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ int ac = ieee80211_ac_from_tid(tid);
+ struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+ unsigned long now = jiffies;
+
+ if (likely(!tx_tspec->admitted_time))
+ return;
+
+ if (time_after(now, tx_tspec->time_slice_start + HZ)) {
+ tx_tspec->consumed_tx_time = 0;
+ tx_tspec->time_slice_start = now;
+
+ if (tx_tspec->downgraded) {
+ tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
+ schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
+ }
+ }
+
+ if (tx_tspec->downgraded)
+ return;
+
+ tx_tspec->consumed_tx_time += tx_time;
+
+ if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) {
+ tx_tspec->downgraded = true;
+ tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE;
+ schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
+ }
+}
+
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_hdr *hdr, bool ack)
+ struct ieee80211_hdr *hdr, bool ack, u16 tx_time)
{
+ ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
+
if (!ieee80211_is_data(hdr->frame_control))
return;
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
run_again(sdata, ifmgd->probe_timeout);
- if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
- ieee80211_flush_queues(sdata->local, sdata);
}
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
true, frame_buf);
mutex_lock(&local->mtx);
sdata->vif.csa_active = false;
+ ifmgd->csa_waiting_bcn = false;
if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA);
}
}
+ if (ifmgd->csa_waiting_bcn)
+ ieee80211_chswitch_post_beacon(sdata);
+
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
return;
ifmgd->beacon_crc = ncrc;
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+ rx_status->device_timestamp,
&elems, true);
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
break;
ieee80211_sta_process_chanswitch(sdata,
- rx_status->mactime,
- &elems, false);
+ rx_status->mactime,
+ rx_status->device_timestamp,
+ &elems, false);
} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
ies_len = skb->len -
offsetof(struct ieee80211_mgmt,
&mgmt->u.action.u.ext_chan_switch.data;
ieee80211_sta_process_chanswitch(sdata,
- rx_status->mactime,
- &elems, false);
+ rx_status->mactime,
+ rx_status->device_timestamp,
+ &elems, false);
}
break;
}
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
if (local->quiescing)
return;
- if (sdata->vif.csa_active)
+ if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
sdata->u.mgd.connection_loss = false;
if (local->quiescing)
return;
- if (sdata->vif.csa_active)
+ if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
(unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
(unsigned long) sdata);
+ INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
+ ieee80211_sta_handle_tspec_ac_params_wk);
ifmgd->flags = 0;
ifmgd->powersave = sdata->wdev.ps;
--- /dev/null
+/*
+ * OCB mode implementation
+ *
+ * Copyright: (c) 2014 Czech Technical University in Prague
+ * (c) 2014 Volkswagen Group Research
+ * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "driver-ops.h"
+#include "rate.h"
+
+#define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (60 * HZ)
+#define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (240 * HZ)
+#define IEEE80211_OCB_MAX_STA_ENTRIES 128
+
+/**
+ * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks
+ * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks
+ *
+ * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb
+ */
+enum ocb_deferred_task_flags {
+ OCB_WORK_HOUSEKEEPING,
+};
+
+void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
+ const u8 *bssid, const u8 *addr,
+ u32 supp_rates)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_supported_band *sband;
+ enum nl80211_bss_scan_width scan_width;
+ struct sta_info *sta;
+ int band;
+
+ /* XXX: Consider removing the least recently used entry and
+ * allow new one to be added.
+ */
+ if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) {
+ net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n",
+ sdata->name, addr);
+ return;
+ }
+
+ ocb_dbg(sdata, "Adding new OCB station %pM\n", addr);
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (WARN_ON_ONCE(!chanctx_conf)) {
+ rcu_read_unlock();
+ return;
+ }
+ band = chanctx_conf->def.chan->band;
+ scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
+ rcu_read_unlock();
+
+ sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+ if (!sta)
+ return;
+
+ sta->last_rx = jiffies;
+
+ /* Add only mandatory rates for now */
+ sband = local->hw.wiphy->bands[band];
+ sta->sta.supp_rates[band] =
+ ieee80211_mandatory_rates(sband, scan_width);
+
+ spin_lock(&ifocb->incomplete_lock);
+ list_add(&sta->list, &ifocb->incomplete_stations);
+ spin_unlock(&ifocb->incomplete_lock);
+ ieee80211_queue_work(&local->hw, &sdata->work);
+}
+
+static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
+ __acquires(RCU)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u8 addr[ETH_ALEN];
+
+ memcpy(addr, sta->sta.addr, ETH_ALEN);
+
+ ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n",
+ addr, sdata->name);
+
+ sta_info_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+ sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+
+ rate_control_rate_init(sta);
+
+ /* If it fails, maybe we raced another insertion? */
+ if (sta_info_insert_rcu(sta))
+ return sta_info_get(sdata, addr);
+ return sta;
+}
+
+static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+ ocb_dbg(sdata, "Running ocb housekeeping\n");
+
+ ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT);
+
+ mod_timer(&ifocb->housekeeping_timer,
+ round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL));
+}
+
+void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+ struct sta_info *sta;
+
+ if (ifocb->joined != true)
+ return;
+
+ sdata_lock(sdata);
+
+ spin_lock_bh(&ifocb->incomplete_lock);
+ while (!list_empty(&ifocb->incomplete_stations)) {
+ sta = list_first_entry(&ifocb->incomplete_stations,
+ struct sta_info, list);
+ list_del(&sta->list);
+ spin_unlock_bh(&ifocb->incomplete_lock);
+
+ ieee80211_ocb_finish_sta(sta);
+ rcu_read_unlock();
+ spin_lock_bh(&ifocb->incomplete_lock);
+ }
+ spin_unlock_bh(&ifocb->incomplete_lock);
+
+ if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags))
+ ieee80211_ocb_housekeeping(sdata);
+
+ sdata_unlock(sdata);
+}
+
+static void ieee80211_ocb_housekeeping_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata = (void *)data;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+ set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
+
+ ieee80211_queue_work(&local->hw, &sdata->work);
+}
+
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+ setup_timer(&ifocb->housekeeping_timer,
+ ieee80211_ocb_housekeeping_timer,
+ (unsigned long)sdata);
+ INIT_LIST_HEAD(&ifocb->incomplete_stations);
+ spin_lock_init(&ifocb->incomplete_lock);
+}
+
+int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
+ struct ocb_setup *setup)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+ u32 changed = BSS_CHANGED_OCB;
+ int err;
+
+ if (ifocb->joined == true)
+ return -EINVAL;
+
+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+ sdata->smps_mode = IEEE80211_SMPS_OFF;
+ sdata->needed_rx_chains = sdata->local->rx_chains;
+
+ mutex_lock(&sdata->local->mtx);
+ err = ieee80211_vif_use_channel(sdata, &setup->chandef,
+ IEEE80211_CHANCTX_SHARED);
+ mutex_unlock(&sdata->local->mtx);
+ if (err)
+ return err;
+
+ ieee80211_bss_info_change_notify(sdata, changed);
+
+ ifocb->joined = true;
+
+ set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
+ ieee80211_queue_work(&local->hw, &sdata->work);
+
+ netif_carrier_on(sdata->dev);
+ return 0;
+}
+
+int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ ifocb->joined = false;
+ sta_info_flush(sdata);
+
+ spin_lock_bh(&ifocb->incomplete_lock);
+ while (!list_empty(&ifocb->incomplete_stations)) {
+ sta = list_first_entry(&ifocb->incomplete_stations,
+ struct sta_info, list);
+ list_del(&sta->list);
+ spin_unlock_bh(&ifocb->incomplete_lock);
+
+ sta_info_free(local, sta);
+ spin_lock_bh(&ifocb->incomplete_lock);
+ }
+ spin_unlock_bh(&ifocb->incomplete_lock);
+
+ netif_carrier_off(sdata->dev);
+ clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB);
+
+ mutex_lock(&sdata->local->mtx);
+ ieee80211_vif_release_channel(sdata);
+ mutex_unlock(&sdata->local->mtx);
+
+ skb_queue_purge(&sdata->skb_queue);
+
+ del_timer_sync(&sdata->u.ocb.housekeeping_timer);
+ /* If the timer fired while we waited for it, it will have
+ * requeued the work. Now the work will be running again
+ * but will not rearm the timer again because it checks
+ * whether we are connected to the network or not -- at this
+ * point we shouldn't be anymore.
+ */
+
+ return 0;
+}
* (1) if any success probabilitiy >= 95%, out of those rates
* choose the maximum throughput rate as max_prob_rate
* (2) if all success probabilities < 95%, the rate with
- * highest success probability is choosen as max_prob_rate */
+ * highest success probability is chosen as max_prob_rate */
if (mrs->probability >= MINSTREL_FRAC(95, 100)) {
if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp)
tmp_prob_rate = i;
#include <linux/skbuff.h>
#include <linux/debugfs.h>
#include <linux/random.h>
+#include <linux/moduleparam.h>
#include <linux/ieee80211.h>
#include <net/mac80211.h>
#include "rate.h"
/* Transmit duration for the raw data part of an average sized packet */
#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+#define BW_20 0
+#define BW_40 1
+#define BW_80 2
+
/*
* Define group sort order: HT40 -> SGI -> #streams
*/
#define GROUP_IDX(_streams, _sgi, _ht40) \
+ MINSTREL_HT_GROUP_0 + \
MINSTREL_MAX_STREAMS * 2 * _ht40 + \
- MINSTREL_MAX_STREAMS * _sgi + \
+ MINSTREL_MAX_STREAMS * _sgi + \
_streams - 1
/* MCS rate information for an MCS group */
[GROUP_IDX(_streams, _sgi, _ht40)] = { \
.streams = _streams, \
.flags = \
+ IEEE80211_TX_RC_MCS | \
(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
(_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
.duration = { \
} \
}
+#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
+ (MINSTREL_VHT_GROUP_0 + \
+ MINSTREL_MAX_STREAMS * 2 * (_bw) + \
+ MINSTREL_MAX_STREAMS * (_sgi) + \
+ (_streams) - 1)
+
+#define BW2VBPS(_bw, r3, r2, r1) \
+ (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
+
+#define VHT_GROUP(_streams, _sgi, _bw) \
+ [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
+ .streams = _streams, \
+ .flags = \
+ IEEE80211_TX_RC_VHT_MCS | \
+ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
+ (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH : \
+ _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
+ .duration = { \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 117, 54, 26)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 234, 108, 52)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 351, 162, 78)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 468, 216, 104)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 702, 324, 156)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 936, 432, 208)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 1053, 486, 234)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 1170, 540, 260)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 1404, 648, 312)), \
+ MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 1560, 720, 346)) \
+ } \
+}
+
#define CCK_DURATION(_bitrate, _short, _len) \
(1000 * (10 /* SIFS */ + \
(_short ? 72 + 24 : 144 + 48) + \
CCK_ACK_DURATION(55, _short), \
CCK_ACK_DURATION(110, _short)
-#define CCK_GROUP \
- [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \
- .streams = 0, \
- .duration = { \
- CCK_DURATION_LIST(false), \
- CCK_DURATION_LIST(true) \
- } \
+#define CCK_GROUP \
+ [MINSTREL_CCK_GROUP] = { \
+ .streams = 0, \
+ .flags = 0, \
+ .duration = { \
+ CCK_DURATION_LIST(false), \
+ CCK_DURATION_LIST(true) \
+ } \
}
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+static bool minstrel_vht_only = true;
+module_param(minstrel_vht_only, bool, 0644);
+MODULE_PARM_DESC(minstrel_vht_only,
+ "Use only VHT rates when VHT is supported by sta.");
+#endif
+
/*
* To enable sufficiently targeted rate sampling, MCS rates are divided into
* groups, based on the number of streams and flags (HT40, SGI) that they
* use.
*
* Sortorder has to be fixed for GROUP_IDX macro to be applicable:
- * HT40 -> SGI -> #streams
+ * BW -> SGI -> #streams
*/
const struct mcs_group minstrel_mcs_groups[] = {
- MCS_GROUP(1, 0, 0),
- MCS_GROUP(2, 0, 0),
+ MCS_GROUP(1, 0, BW_20),
+ MCS_GROUP(2, 0, BW_20),
#if MINSTREL_MAX_STREAMS >= 3
- MCS_GROUP(3, 0, 0),
+ MCS_GROUP(3, 0, BW_20),
#endif
- MCS_GROUP(1, 1, 0),
- MCS_GROUP(2, 1, 0),
+ MCS_GROUP(1, 1, BW_20),
+ MCS_GROUP(2, 1, BW_20),
#if MINSTREL_MAX_STREAMS >= 3
- MCS_GROUP(3, 1, 0),
+ MCS_GROUP(3, 1, BW_20),
#endif
- MCS_GROUP(1, 0, 1),
- MCS_GROUP(2, 0, 1),
+ MCS_GROUP(1, 0, BW_40),
+ MCS_GROUP(2, 0, BW_40),
#if MINSTREL_MAX_STREAMS >= 3
- MCS_GROUP(3, 0, 1),
+ MCS_GROUP(3, 0, BW_40),
#endif
- MCS_GROUP(1, 1, 1),
- MCS_GROUP(2, 1, 1),
+ MCS_GROUP(1, 1, BW_40),
+ MCS_GROUP(2, 1, BW_40),
#if MINSTREL_MAX_STREAMS >= 3
- MCS_GROUP(3, 1, 1),
+ MCS_GROUP(3, 1, BW_40),
#endif
- /* must be last */
- CCK_GROUP
-};
+ CCK_GROUP,
-#define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1)
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+ VHT_GROUP(1, 0, BW_20),
+ VHT_GROUP(2, 0, BW_20),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 0, BW_20),
+#endif
+
+ VHT_GROUP(1, 1, BW_20),
+ VHT_GROUP(2, 1, BW_20),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 1, BW_20),
+#endif
+
+ VHT_GROUP(1, 0, BW_40),
+ VHT_GROUP(2, 0, BW_40),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 0, BW_40),
+#endif
+
+ VHT_GROUP(1, 1, BW_40),
+ VHT_GROUP(2, 1, BW_40),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 1, BW_40),
+#endif
+
+ VHT_GROUP(1, 0, BW_80),
+ VHT_GROUP(2, 0, BW_80),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 0, BW_80),
+#endif
+
+ VHT_GROUP(1, 1, BW_80),
+ VHT_GROUP(2, 1, BW_80),
+#if MINSTREL_MAX_STREAMS >= 3
+ VHT_GROUP(3, 1, BW_80),
+#endif
+#endif
+};
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
static void
minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
+/*
+ * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer)
+ * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1
+ *
+ * Returns the valid mcs map for struct minstrel_mcs_group_data.supported
+ */
+static u16
+minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map)
+{
+ u16 mask = 0;
+
+ if (bw == BW_20) {
+ if (nss != 3 && nss != 6)
+ mask = BIT(9);
+ } else if (bw == BW_80) {
+ if (nss == 3 || nss == 7)
+ mask = BIT(6);
+ else if (nss == 6)
+ mask = BIT(9);
+ } else {
+ WARN_ON(bw != BW_40);
+ }
+
+ switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) {
+ case IEEE80211_VHT_MCS_SUPPORT_0_7:
+ mask |= 0x300;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8:
+ mask |= 0x200;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9:
+ break;
+ default:
+ mask = 0x3ff;
+ }
+
+ return 0x3ff & ~mask;
+}
+
/*
* Look up an MCS group index based on mac80211 rate information
*/
static int
minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
{
- return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
+ return GROUP_IDX((rate->idx / 8) + 1,
!!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
!!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
}
+static int
+minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+ return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate),
+ !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
+ !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +
+ 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH));
+}
+
static struct minstrel_rate_stats *
minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_tx_rate *rate)
if (rate->flags & IEEE80211_TX_RC_MCS) {
group = minstrel_ht_get_group_idx(rate);
idx = rate->idx % 8;
+ } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+ group = minstrel_vht_get_group_idx(rate);
+ idx = ieee80211_rate_get_vht_mcs(rate);
} else {
group = MINSTREL_CCK_GROUP;
* MCS groups, CCK rates do not provide aggregation and are therefore at last.
*/
static void
-minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index,
- u8 *tp_list)
+minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
+ u16 *tp_list)
{
int cur_group, cur_idx, cur_thr, cur_prob;
int tmp_group, tmp_idx, tmp_thr, tmp_prob;
* Find and set the topmost probability rate per sta and per group
*/
static void
-minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index)
+minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
{
struct minstrel_mcs_group_data *mg;
struct minstrel_rate_stats *mr;
*/
static void
minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
- u8 tmp_mcs_tp_rate[MAX_THR_RATES],
- u8 tmp_cck_tp_rate[MAX_THR_RATES])
+ u16 tmp_mcs_tp_rate[MAX_THR_RATES],
+ u16 tmp_cck_tp_rate[MAX_THR_RATES])
{
unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp;
int i;
struct minstrel_mcs_group_data *mg;
struct minstrel_rate_stats *mr;
int group, i, j;
- u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
- u8 tmp_cck_tp_rate[MAX_THR_RATES], index;
+ u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
+ u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
if (mi->ampdu_packets > 0) {
mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
if (!rate->count)
return false;
- if (rate->flags & IEEE80211_TX_RC_MCS)
+ if (rate->flags & IEEE80211_TX_RC_MCS ||
+ rate->flags & IEEE80211_TX_RC_VHT_MCS)
return true;
return rate->idx == mp->cck_rates[0] ||
}
static void
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary)
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
{
int group, orig_group;
const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
struct minstrel_rate_stats *mr;
u8 idx;
- u16 flags;
+ u16 flags = group->flags;
mr = minstrel_get_ratestats(mi, index);
if (!mr->retry_updated)
ratetbl->rate[offset].count_rts = mr->retry_count_rtscts;
}
- if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+ if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP)
idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
- flags = 0;
- } else {
+ else if (flags & IEEE80211_TX_RC_VHT_MCS)
+ idx = ((group->streams - 1) << 4) |
+ ((index % MCS_GROUP_RATES) & 0xF);
+ else
idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
- flags = IEEE80211_TX_RC_MCS | group->flags;
- }
if (offset > 0) {
ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
rate->idx = mp->cck_rates[idx];
- rate->flags = 0;
- return;
+ } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) {
+ ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES,
+ sample_group->streams);
+ } else {
+ rate->idx = sample_idx % MCS_GROUP_RATES +
+ (sample_group->streams - 1) * 8;
}
- rate->idx = sample_idx % MCS_GROUP_RATES +
- (sample_group->streams - 1) * 8;
- rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
+ rate->flags = sample_group->flags;
}
static void
struct minstrel_ht_sta *mi = &msp->ht;
struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
u16 sta_cap = sta->ht_cap.cap;
+ struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ int use_vht;
int n_supported = 0;
int ack_dur;
int stbc;
if (!sta->ht_cap.ht_supported)
goto use_legacy;
- BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
- MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB);
+
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+ if (vht_cap->vht_supported)
+ use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0);
+ else
+#endif
+ use_vht = 0;
msp->is_ht = true;
memset(mi, 0, sizeof(*mi));
}
mi->sample_tries = 4;
- stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
- IEEE80211_HT_CAP_RX_STBC_SHIFT;
- mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+ /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */
+ if (!use_vht) {
+ stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
- if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
- mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+ if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+ mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+ }
for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+ u32 gflags = minstrel_mcs_groups[i].flags;
+ int bw, nss;
+
mi->groups[i].supported = 0;
if (i == MINSTREL_CCK_GROUP) {
minstrel_ht_update_cck(mp, mi, sband, sta);
continue;
}
- if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
- if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+ if (gflags & IEEE80211_TX_RC_SHORT_GI) {
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
continue;
} else {
}
}
- if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
sta->bandwidth < IEEE80211_STA_RX_BW_40)
continue;
+ nss = minstrel_mcs_groups[i].streams;
+
/* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
- if (sta->smps_mode == IEEE80211_SMPS_STATIC &&
- minstrel_mcs_groups[i].streams > 1)
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1)
+ continue;
+
+ /* HT rate */
+ if (gflags & IEEE80211_TX_RC_MCS) {
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+ if (use_vht && minstrel_vht_only)
+ continue;
+#endif
+ mi->groups[i].supported = mcs->rx_mask[nss - 1];
+ if (mi->groups[i].supported)
+ n_supported++;
continue;
+ }
+
+ /* VHT rate */
+ if (!vht_cap->vht_supported ||
+ WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) ||
+ WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH))
+ continue;
+
+ if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) {
+ if (sta->bandwidth < IEEE80211_STA_RX_BW_80 ||
+ ((gflags & IEEE80211_TX_RC_SHORT_GI) &&
+ !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) {
+ continue;
+ }
+ }
+
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ bw = BW_40;
+ else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ bw = BW_80;
+ else
+ bw = BW_20;
- mi->groups[i].supported =
- mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+ mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss,
+ vht_cap->vht_mcs.tx_mcs_map);
if (mi->groups[i].supported)
n_supported++;
* The number of streams can be changed to 2 to reduce code
* size and memory footprint.
*/
-#define MINSTREL_MAX_STREAMS 3
-#define MINSTREL_STREAM_GROUPS 4
+#define MINSTREL_MAX_STREAMS 3
+#define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+#define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */
+#else
+#define MINSTREL_VHT_STREAM_GROUPS 0
+#endif
-#define MCS_GROUP_RATES 8
+#define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \
+ MINSTREL_HT_STREAM_GROUPS)
+#define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \
+ MINSTREL_VHT_STREAM_GROUPS)
+#define MINSTREL_CCK_GROUPS_NB 1
+#define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \
+ MINSTREL_VHT_GROUPS_NB + \
+ MINSTREL_CCK_GROUPS_NB)
+
+#define MINSTREL_HT_GROUP_0 0
+#define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB)
+#define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1)
+
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+#define MCS_GROUP_RATES 10
+#else
+#define MCS_GROUP_RATES 8
+#endif
struct mcs_group {
u32 flags;
u8 column;
/* bitfield of supported MCS rates of this group */
- u8 supported;
+ u16 supported;
/* sorted rate set within a MCS group*/
- u8 max_group_tp_rate[MAX_THR_RATES];
- u8 max_group_prob_rate;
+ u16 max_group_tp_rate[MAX_THR_RATES];
+ u16 max_group_prob_rate;
/* MCS rate statistics */
struct minstrel_rate_stats rates[MCS_GROUP_RATES];
unsigned int avg_ampdu_len;
/* overall sorted rate set */
- u8 max_tp_rate[MAX_THR_RATES];
- u8 max_prob_rate;
+ u16 max_tp_rate[MAX_THR_RATES];
+ u16 max_prob_rate;
/* time of last status update */
unsigned long stats_update;
u8 cck_supported_short;
/* MCS rate group info and statistics */
- struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1];
+ struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB];
};
struct minstrel_ht_sta_priv {
static char *
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{
- unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
const struct mcs_group *mg;
unsigned int j, tp, prob, eprob;
char htmode = '2';
char gimode = 'L';
+ u32 gflags;
if (!mi->groups[i].supported)
return p;
mg = &minstrel_mcs_groups[i];
- if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ gflags = mg->flags;
+
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
htmode = '4';
- if (mg->flags & IEEE80211_TX_RC_SHORT_GI)
+ else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ htmode = '8';
+ if (gflags & IEEE80211_TX_RC_SHORT_GI)
gimode = 'S';
for (j = 0; j < MCS_GROUP_RATES; j++) {
if (!(mi->groups[i].supported & BIT(j)))
continue;
- if (i == max_mcs)
- p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S');
+ if (gflags & IEEE80211_TX_RC_MCS)
+ p += sprintf(p, " HT%c0/%cGI ", htmode, gimode);
+ else if (gflags & IEEE80211_TX_RC_VHT_MCS)
+ p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode);
else
- p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+ p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S');
*(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
*(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
*(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' ';
*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
- if (i == max_mcs) {
- int r = bitrates[j % 4];
- p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
+ if (gflags & IEEE80211_TX_RC_MCS) {
+ p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j);
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
+ p += sprintf(p, " MCS%-1u/%1u", j, mg->streams);
} else {
- p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
+ int r = bitrates[j % 4];
+
+ p += sprintf(p, " %2u.%1uM ", r / 10, r % 10);
}
tp = mr->cur_tp / 10;
struct minstrel_ht_sta *mi = &msp->ht;
struct minstrel_debugfs_info *ms;
unsigned int i;
- unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
char *p;
int ret;
return ret;
}
- ms = kmalloc(8192, GFP_KERNEL);
+ ms = kmalloc(32768, GFP_KERNEL);
if (!ms)
return -ENOMEM;
file->private_data = ms;
p = ms->buf;
- p += sprintf(p, "type rate tpt eprob *prob "
+ p += sprintf(p, " type rate tpt eprob *prob "
"ret *ok(*cum) ok( cum)\n");
-
- p = minstrel_ht_stats_dump(mi, max_mcs, p);
- for (i = 0; i < max_mcs; i++)
+ p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
+ for (i = 0; i < MINSTREL_CCK_GROUP; i++)
+ p = minstrel_ht_stats_dump(mi, i, p);
+ for (i++; i < ARRAY_SIZE(mi->groups); i++)
p = minstrel_ht_stats_dump(mi, i, p);
p += sprintf(p, "\nTotal packet count:: ideal %d "
MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
ms->len = p - ms->buf;
- WARN_ON(ms->len + sizeof(*ms) > 8192);
+ WARN_ON(ms->len + sizeof(*ms) > 32768);
return nonseekable_open(inode, file);
}
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
+ rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
/*
* accept port control frames from the AP even when it's not
sta->last_rx_rate_vht_nss = status->vht_nss;
}
}
+ } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
+ u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+ NL80211_IFTYPE_OCB);
+ /* OCB uses wild-card BSSID */
+ if (is_broadcast_ether_addr(bssid))
+ sta->last_rx = jiffies;
} else if (!is_multicast_ether_addr(hdr->addr1)) {
/*
* Mesh beacons will update last_rx when if they are found to
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_OCB &&
sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
BIT(rate_idx));
}
break;
+ case NL80211_IFTYPE_OCB:
+ if (!bssid)
+ return false;
+ if (ieee80211_is_beacon(hdr->frame_control)) {
+ return false;
+ } else if (!is_broadcast_ether_addr(bssid)) {
+ ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n");
+ return false;
+ } else if (!multicast &&
+ !ether_addr_equal(sdata->dev->dev_addr,
+ hdr->addr1)) {
+ /* if we are in promisc mode we also accept
+ * packets not destined for us
+ */
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ return false;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ } else if (!rx->sta) {
+ int rate_idx;
+ if (status->flag & RX_FLAG_HT)
+ rate_idx = 0; /* TODO: HT rates */
+ else
+ rate_idx = status->rate_idx;
+ ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
+ BIT(rate_idx));
+ }
+ break;
case NL80211_IFTYPE_MESH_POINT:
if (!multicast &&
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
/* make the station visible */
sta_info_hash_add(local, sta);
- list_add_rcu(&sta->list, &local->sta_list);
+ list_add_tail_rcu(&sta->list, &local->sta_list);
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
break;
case 0:
/* XXX: what is a good value? */
- n_frames = 8;
+ n_frames = 128;
break;
}
if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
- ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked);
+ ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
+ acked, info->status.tx_time);
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
if (info->flags & IEEE80211_TX_STAT_ACK) {
/* infer the initiator if we can, to support old userspace */
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
- if (sta)
+ if (sta) {
set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
+ sta->sta.tdls_initiator = false;
+ }
/* fall-through */
case WLAN_TDLS_SETUP_CONFIRM:
case WLAN_TDLS_DISCOVERY_REQUEST:
* Make the last packet sent take effect for the initiator
* value.
*/
- if (sta)
+ if (sta) {
clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
+ sta->sta.tdls_initiator = true;
+ }
/* fall-through */
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
initiator = false;
TRACE_EVENT(drv_channel_switch,
TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_switch *ch_switch),
- TP_ARGS(local, ch_switch),
+ TP_ARGS(local, sdata, ch_switch),
TP_STRUCT__entry(
LOCAL_ENTRY
+ VIF_ENTRY
CHANDEF_ENTRY
__field(u64, timestamp)
+ __field(u32, device_timestamp)
__field(bool, block_tx)
__field(u8, count)
),
TP_fast_assign(
LOCAL_ASSIGN;
+ VIF_ASSIGN;
CHANDEF_ASSIGN(&ch_switch->chandef)
__entry->timestamp = ch_switch->timestamp;
+ __entry->device_timestamp = ch_switch->device_timestamp;
__entry->block_tx = ch_switch->block_tx;
__entry->count = ch_switch->count;
),
TP_printk(
- LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
- LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
+ LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
)
);
TP_ARGS(local, sdata)
);
-DEFINE_EVENT(local_only_evt, drv_restart_complete,
- TP_PROTO(struct ieee80211_local *local),
- TP_ARGS(local)
+TRACE_EVENT(drv_reconfig_complete,
+ TP_PROTO(struct ieee80211_local *local,
+ enum ieee80211_reconfig_type reconfig_type),
+ TP_ARGS(local, reconfig_type),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u8, reconfig_type)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->reconfig_type = reconfig_type;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " reconfig_type:%d",
+ LOCAL_PR_ARG, __entry->reconfig_type
+ )
+
);
#if IS_ENABLED(CONFIG_IPV6)
)
);
+TRACE_EVENT(drv_pre_channel_switch,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_switch *ch_switch),
+
+ TP_ARGS(local, sdata, ch_switch),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ CHANDEF_ENTRY
+ __field(u64, timestamp)
+ __field(bool, block_tx)
+ __field(u8, count)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ CHANDEF_ASSIGN(&ch_switch->chandef)
+ __entry->timestamp = ch_switch->timestamp;
+ __entry->block_tx = ch_switch->block_tx;
+ __entry->count = ch_switch->count;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to "
+ CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu",
+ LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count,
+ __entry->block_tx, __entry->timestamp
+ )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_get_txpower,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int dbm, int ret),
+
+ TP_ARGS(local, sdata, dbm, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(int, dbm)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->dbm = dbm;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret
+ )
+);
+
#ifdef CONFIG_MAC80211_MESSAGE_TRACING
#undef TRACE_SYSTEM
*/
return TX_DROP;
+ if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
+ return TX_CONTINUE;
+
if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
return TX_CONTINUE;
goto fail_rcu;
band = chanctx_conf->def.chan->band;
break;
+ case NL80211_IFTYPE_OCB:
+ /* DA SA BSSID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ eth_broadcast_addr(hdr.addr3);
+ hdrlen = 24;
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf)
+ goto fail_rcu;
+ band = chanctx_conf->def.chan->band;
+ break;
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
* EAPOL frames from the local station.
*/
if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
+ (sdata->vif.type != NL80211_IFTYPE_OCB) &&
!multicast && !authorized &&
(cpu_to_be16(ethertype) != sdata->control_port_protocol ||
!ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
+static void __iterate_stations(struct ieee80211_local *local,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data)
+{
+ struct sta_info *sta;
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (!sta->uploaded)
+ continue;
+
+ iterator(data, &sta->sta);
+ }
+}
+
+void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ rcu_read_lock();
+ __iterate_stations(local, iterator, data);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
+
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_chanctx_conf *chanctx_conf;
int ac;
bool use_11b, enable_qos;
+ bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */
int aCWmin, aCWmax;
if (!local->ops->conf_tx)
*/
enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
+ is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
+
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
if (use_11b)
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
- qparam.aifs = 7;
+ if (is_ocb)
+ qparam.aifs = 9;
+ else
+ qparam.aifs = 7;
break;
/* never happens but let's not leave undefined */
default:
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
- qparam.aifs = 3;
+ if (is_ocb)
+ qparam.aifs = 6;
+ else
+ qparam.aifs = 3;
break;
case IEEE80211_AC_VI:
qparam.cw_max = aCWmin;
qparam.cw_min = (aCWmin + 1) / 2 - 1;
- if (use_11b)
+ if (is_ocb)
+ qparam.txop = 0;
+ else if (use_11b)
qparam.txop = 6016/32;
else
qparam.txop = 3008/32;
- qparam.aifs = 2;
+
+ if (is_ocb)
+ qparam.aifs = 3;
+ else
+ qparam.aifs = 2;
break;
case IEEE80211_AC_VO:
qparam.cw_max = (aCWmin + 1) / 2 - 1;
qparam.cw_min = (aCWmin + 1) / 4 - 1;
- if (use_11b)
+ if (is_ocb)
+ qparam.txop = 0;
+ else if (use_11b)
qparam.txop = 3264/32;
else
qparam.txop = 1504/32;
ieee80211_bss_info_change_notify(sdata, changed);
sdata_unlock(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ changed |= BSS_CHANGED_OCB;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ break;
case NL80211_IFTYPE_ADHOC:
changed |= BSS_CHANGED_IBSS;
/* fall through */
* We may want to change that later, however.
*/
if (!local->suspended || reconfig_due_to_wowlan)
- drv_restart_complete(local);
+ drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
if (!local->suspended)
return 0;
mb();
local->resuming = false;
+ if (!reconfig_due_to_wowlan)
+ drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
+
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
return false;
}
-/**
- * ieee80211_ie_split - split an IE buffer according to ordering
- *
- * @ies: the IE buffer
- * @ielen: the length of the IE buffer
- * @ids: an array with element IDs that are allowed before
- * the split
- * @n_ids: the size of the element ID array
- * @offset: offset where to start splitting in the buffer
- *
- * This function splits an IE buffer by updating the @offset
- * variable to point to the location where the buffer should be
- * split.
- *
- * It assumes that the given IE buffer is well-formed, this
- * has to be guaranteed by the caller!
- *
- * It also assumes that the IEs in the buffer are ordered
- * correctly, if not the result of using this function will not
- * be ordered correctly either, i.e. it does no reordering.
- *
- * The function returns the offset where the next part of the
- * buffer starts, which may be @ielen if the entire (remainder)
- * of the buffer should be used.
- */
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
- const u8 *ids, int n_ids, size_t offset)
+size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids,
+ const u8 *after_ric, int n_after_ric,
+ size_t offset)
{
size_t pos = offset;
- while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
- pos += 2 + ies[pos + 1];
+ while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
+ if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
+ pos += 2 + ies[pos + 1];
+
+ while (pos < ielen &&
+ !ieee80211_id_in_list(after_ric, n_after_ric,
+ ies[pos]))
+ pos += 2 + ies[pos + 1];
+ } else {
+ pos += 2 + ies[pos + 1];
+ }
+ }
return pos;
}
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids, size_t offset)
+{
+ return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset);
+}
+EXPORT_SYMBOL(ieee80211_ie_split);
+
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
{
size_t pos = offset;
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, radar_detected_work);
struct cfg80211_chan_def chandef = local->hw.conf.chandef;
+ struct ieee80211_chanctx *ctx;
+ int num_chanctx = 0;
+
+ mutex_lock(&local->chanctx_mtx);
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
+ continue;
+
+ num_chanctx++;
+ chandef = ctx->conf.def;
+ }
+ mutex_unlock(&local->chanctx_mtx);
ieee80211_dfs_cac_cancel(local);
- if (local->use_chanctx)
- /* currently not handled */
+ if (num_chanctx > 1)
+ /* XXX: multi-channel is not supported yet */
WARN_ON(1);
else
cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
return newhdr + hdrlen;
- skb_set_network_header(skb, skb_network_offset(skb) +
- IEEE80211_WEP_IV_LEN);
ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
return newhdr + hdrlen;
}
}
static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+ struct sta_info *sta, struct sk_buff *skb)
{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
/* in case we are a client verify acm is not set for this ac */
- while (unlikely(sdata->wmm_acm & BIT(skb->priority))) {
+ while (sdata->wmm_acm & BIT(skb->priority)) {
+ int ac = ieee802_1d_to_ac[skb->priority];
+
+ if (ifmgd->tx_tspec[ac].admitted_time &&
+ skb->priority == ifmgd->tx_tspec[ac].up)
+ return ac;
+
if (wme_downgrade_ac(skb)) {
/*
* This should not really happen. The AP has marked all
p = ieee80211_get_qos_ctl(hdr);
skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
- return ieee80211_downgrade_queue(sdata, skb);
+ return ieee80211_downgrade_queue(sdata, NULL, skb);
}
/* Indicate which queue to use. */
const u8 *ra = NULL;
bool qos = false;
struct mac80211_qos_map *qos_map;
+ u16 ret;
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
skb->priority = 0; /* required for correct WPA/11i MIC */
case NL80211_IFTYPE_ADHOC:
ra = skb->data;
break;
+ case NL80211_IFTYPE_OCB:
+ /* all stations are required to support WME */
+ qos = true;
+ break;
default:
break;
}
if (sta)
qos = sta->sta.wme;
}
- rcu_read_unlock();
if (!qos) {
skb->priority = 0; /* required for correct WPA/11i MIC */
- return IEEE80211_AC_BE;
+ ret = IEEE80211_AC_BE;
+ goto out;
}
if (skb->protocol == sdata->control_port_protocol) {
skb->priority = 7;
- return ieee80211_downgrade_queue(sdata, skb);
+ goto downgrade;
}
/* use the data classifier to determine what 802.1d tag the
* data frame has */
- rcu_read_lock();
qos_map = rcu_dereference(sdata->qos_map);
skb->priority = cfg80211_classify8021d(skb, qos_map ?
&qos_map->qos_map : NULL);
- rcu_read_unlock();
- return ieee80211_downgrade_queue(sdata, skb);
+ downgrade:
+ ret = ieee80211_downgrade_queue(sdata, sta, skb);
+ out:
+ rcu_read_unlock();
+ return ret;
}
/**
#include <linux/netdevice.h>
#include "ieee80211_i.h"
-extern const int ieee802_1d_to_ac[8];
-
u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_hdr *hdr);
pos = skb_push(skb, IEEE80211_TKIP_IV_LEN);
memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen);
- skb_set_network_header(skb, skb_network_offset(skb) +
- IEEE80211_TKIP_IV_LEN);
pos += hdrlen;
/* the HW only needs room for the IV, but not the actual IV */
pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN);
memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen);
- skb_set_network_header(skb, skb_network_offset(skb) +
- IEEE80211_CCMP_HDR_LEN);
/* the HW only needs room for the IV, but not the actual IV */
if (info->control.hw_key &&
pos = skb_push(skb, cs->hdr_len);
memmove(pos, pos + cs->hdr_len, hdrlen);
- skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
return TX_CONTINUE;
}
been tested yet!
If you plan to use HardMAC IEEE 802.15.4 devices, you can
- say N here. Alternatievly you can say M to compile it as
+ say N here. Alternatively you can say M to compile it as
module.
obj-$(CONFIG_MAC802154) += mac802154.o
-mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o \
- monitor.o wpan.o llsec.o
+mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \
+ iface.o llsec.o util.o
ccflags-y += -D__CHECK_ENDIAN__
--- /dev/null
+#ifndef __MAC802154_DRVIER_OPS
+#define __MAC802154_DRIVER_OPS
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
+#include <net/mac802154.h>
+
+#include "ieee802154_i.h"
+
+static inline int
+drv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb)
+{
+ return local->ops->xmit_async(&local->hw, skb);
+}
+
+static inline int
+drv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb)
+{
+ /* don't allow other operations while sync xmit */
+ ASSERT_RTNL();
+
+ might_sleep();
+
+ return local->ops->xmit_sync(&local->hw, skb);
+}
+
+static inline int drv_start(struct ieee802154_local *local)
+{
+ might_sleep();
+
+ local->started = true;
+ smp_mb();
+
+ return local->ops->start(&local->hw);
+}
+
+static inline void drv_stop(struct ieee802154_local *local)
+{
+ might_sleep();
+
+ local->ops->stop(&local->hw);
+
+ /* sync away all work on the tasklet before clearing started */
+ tasklet_disable(&local->tasklet);
+ tasklet_enable(&local->tasklet);
+
+ barrier();
+
+ local->started = false;
+}
+
+static inline int drv_set_channel(struct ieee802154_local *local,
+ const u8 page, const u8 channel)
+{
+ might_sleep();
+
+ return local->ops->set_channel(&local->hw, page, channel);
+}
+
+static inline int drv_set_tx_power(struct ieee802154_local *local,
+ const s8 dbm)
+{
+ might_sleep();
+
+ if (!local->ops->set_txpower) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_txpower(&local->hw, dbm);
+}
+
+static inline int drv_set_cca_mode(struct ieee802154_local *local,
+ const u8 cca_mode)
+{
+ might_sleep();
+
+ if (!local->ops->set_cca_mode) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_cca_mode(&local->hw, cca_mode);
+}
+
+static inline int drv_set_lbt_mode(struct ieee802154_local *local,
+ const bool mode)
+{
+ might_sleep();
+
+ if (!local->ops->set_lbt) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_lbt(&local->hw, mode);
+}
+
+static inline int drv_set_cca_ed_level(struct ieee802154_local *local,
+ const s32 ed_level)
+{
+ might_sleep();
+
+ if (!local->ops->set_cca_ed_level) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_cca_ed_level(&local->hw, ed_level);
+}
+
+static inline int drv_set_pan_id(struct ieee802154_local *local,
+ const __le16 pan_id)
+{
+ struct ieee802154_hw_addr_filt filt;
+
+ might_sleep();
+
+ if (!local->ops->set_hw_addr_filt) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ filt.pan_id = pan_id;
+
+ return local->ops->set_hw_addr_filt(&local->hw, &filt,
+ IEEE802154_AFILT_PANID_CHANGED);
+}
+
+static inline int drv_set_extended_addr(struct ieee802154_local *local,
+ const __le64 extended_addr)
+{
+ struct ieee802154_hw_addr_filt filt;
+
+ might_sleep();
+
+ if (!local->ops->set_hw_addr_filt) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ filt.ieee_addr = extended_addr;
+
+ return local->ops->set_hw_addr_filt(&local->hw, &filt,
+ IEEE802154_AFILT_IEEEADDR_CHANGED);
+}
+
+static inline int drv_set_short_addr(struct ieee802154_local *local,
+ const __le16 short_addr)
+{
+ struct ieee802154_hw_addr_filt filt;
+
+ might_sleep();
+
+ if (!local->ops->set_hw_addr_filt) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ filt.short_addr = short_addr;
+
+ return local->ops->set_hw_addr_filt(&local->hw, &filt,
+ IEEE802154_AFILT_SADDR_CHANGED);
+}
+
+static inline int drv_set_pan_coord(struct ieee802154_local *local,
+ const bool is_coord)
+{
+ struct ieee802154_hw_addr_filt filt;
+
+ might_sleep();
+
+ if (!local->ops->set_hw_addr_filt) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ filt.pan_coord = is_coord;
+
+ return local->ops->set_hw_addr_filt(&local->hw, &filt,
+ IEEE802154_AFILT_PANC_CHANGED);
+}
+
+static inline int drv_set_csma_params(struct ieee802154_local *local,
+ u8 min_be, u8 max_be,
+ u8 max_csma_backoffs)
+{
+ might_sleep();
+
+ if (!local->ops->set_csma_params) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_csma_params(&local->hw, min_be, max_be,
+ max_csma_backoffs);
+}
+
+static inline int drv_set_max_frame_retries(struct ieee802154_local *local,
+ s8 max_frame_retries)
+{
+ might_sleep();
+
+ if (!local->ops->set_frame_retries) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_frame_retries(&local->hw, max_frame_retries);
+}
+
+static inline int drv_set_promiscuous_mode(struct ieee802154_local *local,
+ const bool on)
+{
+ might_sleep();
+
+ if (!local->ops->set_promiscuous_mode) {
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ return local->ops->set_promiscuous_mode(&local->hw, on);
+}
+
+#endif /* __MAC802154_DRVIER_OPS */
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Siemens AG
- *
- * Written by:
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- *
- * Based on the code from 'linux-zigbee.sourceforge.net' project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-
-#include <net/netlink.h>
-#include <linux/nl802154.h>
-#include <net/mac802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/route.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
-
-int mac802154_slave_open(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct mac802154_sub_if_data *subif;
- struct mac802154_priv *ipriv = priv->hw;
- int res = 0;
-
- ASSERT_RTNL();
-
- if (priv->type == IEEE802154_DEV_WPAN) {
- mutex_lock(&priv->hw->slaves_mtx);
- list_for_each_entry(subif, &priv->hw->slaves, list) {
- if (subif != priv && subif->type == priv->type &&
- subif->running) {
- mutex_unlock(&priv->hw->slaves_mtx);
- return -EBUSY;
- }
- }
- mutex_unlock(&priv->hw->slaves_mtx);
- }
-
- mutex_lock(&priv->hw->slaves_mtx);
- priv->running = true;
- mutex_unlock(&priv->hw->slaves_mtx);
-
- if (ipriv->open_count++ == 0) {
- res = ipriv->ops->start(&ipriv->hw);
- WARN_ON(res);
- if (res)
- goto err;
- }
-
- if (ipriv->ops->ieee_addr) {
- __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr);
-
- res = ipriv->ops->ieee_addr(&ipriv->hw, addr);
- WARN_ON(res);
- if (res)
- goto err;
- mac802154_dev_set_ieee_addr(dev);
- }
-
- netif_start_queue(dev);
- return 0;
-err:
- priv->hw->open_count--;
-
- return res;
-}
-
-int mac802154_slave_close(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct mac802154_priv *ipriv = priv->hw;
-
- ASSERT_RTNL();
-
- netif_stop_queue(dev);
-
- mutex_lock(&priv->hw->slaves_mtx);
- priv->running = false;
- mutex_unlock(&priv->hw->slaves_mtx);
-
- if (!--ipriv->open_count)
- ipriv->ops->stop(&ipriv->hw);
-
- return 0;
-}
-
-static int
-mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv;
- struct mac802154_priv *ipriv;
- int err;
-
- ipriv = wpan_phy_priv(phy);
-
- priv = netdev_priv(dev);
- priv->dev = dev;
- priv->hw = ipriv;
-
- dev->needed_headroom = ipriv->hw.extra_tx_headroom;
-
- SET_NETDEV_DEV(dev, &ipriv->phy->dev);
-
- mutex_lock(&ipriv->slaves_mtx);
- if (!ipriv->running) {
- mutex_unlock(&ipriv->slaves_mtx);
- return -ENODEV;
- }
- mutex_unlock(&ipriv->slaves_mtx);
-
- err = register_netdev(dev);
- if (err < 0)
- return err;
-
- rtnl_lock();
- mutex_lock(&ipriv->slaves_mtx);
- list_add_tail_rcu(&priv->list, &ipriv->slaves);
- mutex_unlock(&ipriv->slaves_mtx);
- rtnl_unlock();
-
- return 0;
-}
-
-static void
-mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
-{
- struct mac802154_sub_if_data *sdata;
-
- ASSERT_RTNL();
-
- sdata = netdev_priv(dev);
-
- BUG_ON(sdata->hw->phy != phy);
-
- mutex_lock(&sdata->hw->slaves_mtx);
- list_del_rcu(&sdata->list);
- mutex_unlock(&sdata->hw->slaves_mtx);
-
- synchronize_rcu();
- unregister_netdevice(sdata->dev);
-}
-
-static struct net_device *
-mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
-{
- struct net_device *dev;
- int err = -ENOMEM;
-
- switch (type) {
- case IEEE802154_DEV_MONITOR:
- dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
- name, NET_NAME_UNKNOWN,
- mac802154_monitor_setup);
- break;
- case IEEE802154_DEV_WPAN:
- dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
- name, NET_NAME_UNKNOWN,
- mac802154_wpan_setup);
- break;
- default:
- dev = NULL;
- err = -EINVAL;
- break;
- }
- if (!dev)
- goto err;
-
- err = mac802154_netdev_register(phy, dev);
- if (err)
- goto err_free;
-
- dev_hold(dev); /* we return an incremented device refcount */
- return dev;
-
-err_free:
- free_netdev(dev);
-err:
- return ERR_PTR(err);
-}
-
-static int mac802154_set_txpower(struct wpan_phy *phy, int db)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_txpower(&priv->hw, db);
-}
-
-static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_lbt(&priv->hw, on);
-}
-
-static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_cca_mode(&priv->hw, mode);
-}
-
-static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_cca_ed_level(&priv->hw, level);
-}
-
-static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
- u8 max_be, u8 retries)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries);
-}
-
-static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
-{
- struct mac802154_priv *priv = wpan_phy_priv(phy);
-
- return priv->ops->set_frame_retries(&priv->hw, retries);
-}
-
-struct ieee802154_dev *
-ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
-{
- struct wpan_phy *phy;
- struct mac802154_priv *priv;
- size_t priv_size;
-
- if (!ops || !ops->xmit || !ops->ed || !ops->start ||
- !ops->stop || !ops->set_channel) {
- pr_err("undefined IEEE802.15.4 device operations\n");
- return NULL;
- }
-
- /* Ensure 32-byte alignment of our private data and hw private data.
- * We use the wpan_phy priv data for both our mac802154_priv and for
- * the driver's private data
- *
- * in memory it'll be like this:
- *
- * +-----------------------+
- * | struct wpan_phy |
- * +-----------------------+
- * | struct mac802154_priv |
- * +-----------------------+
- * | driver's private data |
- * +-----------------------+
- *
- * Due to ieee802154 layer isn't aware of driver and MAC structures,
- * so lets allign them here.
- */
-
- priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_data_len;
-
- phy = wpan_phy_alloc(priv_size);
- if (!phy) {
- pr_err("failure to allocate master IEEE802.15.4 device\n");
- return NULL;
- }
-
- priv = wpan_phy_priv(phy);
- priv->phy = phy;
- priv->hw.phy = priv->phy;
- priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN);
- priv->ops = ops;
-
- INIT_LIST_HEAD(&priv->slaves);
- mutex_init(&priv->slaves_mtx);
-
- return &priv->hw;
-}
-EXPORT_SYMBOL(ieee802154_alloc_device);
-
-void ieee802154_free_device(struct ieee802154_dev *hw)
-{
- struct mac802154_priv *priv = mac802154_to_priv(hw);
-
- BUG_ON(!list_empty(&priv->slaves));
-
- mutex_destroy(&priv->slaves_mtx);
-
- wpan_phy_free(priv->phy);
-}
-EXPORT_SYMBOL(ieee802154_free_device);
-
-int ieee802154_register_device(struct ieee802154_dev *dev)
-{
- struct mac802154_priv *priv = mac802154_to_priv(dev);
- int rc = -ENOSYS;
-
- if (dev->flags & IEEE802154_HW_TXPOWER) {
- if (!priv->ops->set_txpower)
- goto out;
-
- priv->phy->set_txpower = mac802154_set_txpower;
- }
-
- if (dev->flags & IEEE802154_HW_LBT) {
- if (!priv->ops->set_lbt)
- goto out;
-
- priv->phy->set_lbt = mac802154_set_lbt;
- }
-
- if (dev->flags & IEEE802154_HW_CCA_MODE) {
- if (!priv->ops->set_cca_mode)
- goto out;
-
- priv->phy->set_cca_mode = mac802154_set_cca_mode;
- }
-
- if (dev->flags & IEEE802154_HW_CCA_ED_LEVEL) {
- if (!priv->ops->set_cca_ed_level)
- goto out;
-
- priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
- }
-
- if (dev->flags & IEEE802154_HW_CSMA_PARAMS) {
- if (!priv->ops->set_csma_params)
- goto out;
-
- priv->phy->set_csma_params = mac802154_set_csma_params;
- }
-
- if (dev->flags & IEEE802154_HW_FRAME_RETRIES) {
- if (!priv->ops->set_frame_retries)
- goto out;
-
- priv->phy->set_frame_retries = mac802154_set_frame_retries;
- }
-
- priv->dev_workqueue =
- create_singlethread_workqueue(wpan_phy_name(priv->phy));
- if (!priv->dev_workqueue) {
- rc = -ENOMEM;
- goto out;
- }
-
- wpan_phy_set_dev(priv->phy, priv->hw.parent);
-
- priv->phy->add_iface = mac802154_add_iface;
- priv->phy->del_iface = mac802154_del_iface;
-
- rc = wpan_phy_register(priv->phy);
- if (rc < 0)
- goto out_wq;
-
- rtnl_lock();
-
- mutex_lock(&priv->slaves_mtx);
- priv->running = MAC802154_DEVICE_RUN;
- mutex_unlock(&priv->slaves_mtx);
-
- rtnl_unlock();
-
- return 0;
-
-out_wq:
- destroy_workqueue(priv->dev_workqueue);
-out:
- return rc;
-}
-EXPORT_SYMBOL(ieee802154_register_device);
-
-void ieee802154_unregister_device(struct ieee802154_dev *dev)
-{
- struct mac802154_priv *priv = mac802154_to_priv(dev);
- struct mac802154_sub_if_data *sdata, *next;
-
- flush_workqueue(priv->dev_workqueue);
- destroy_workqueue(priv->dev_workqueue);
-
- rtnl_lock();
-
- mutex_lock(&priv->slaves_mtx);
- priv->running = MAC802154_DEVICE_STOPPED;
- mutex_unlock(&priv->slaves_mtx);
-
- list_for_each_entry_safe(sdata, next, &priv->slaves, list) {
- mutex_lock(&sdata->hw->slaves_mtx);
- list_del(&sdata->list);
- mutex_unlock(&sdata->hw->slaves_mtx);
-
- unregister_netdevice(sdata->dev);
- }
-
- rtnl_unlock();
-
- wpan_phy_unregister(priv->phy);
-}
-EXPORT_SYMBOL(ieee802154_unregister_device);
-
-MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
-MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+#ifndef __IEEE802154_I_H
+#define __IEEE802154_I_H
+
+#include <linux/mutex.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+
+#include "llsec.h"
+
+/* mac802154 device private data */
+struct ieee802154_local {
+ struct ieee802154_hw hw;
+ const struct ieee802154_ops *ops;
+
+ /* ieee802154 phy */
+ struct wpan_phy *phy;
+
+ int open_count;
+
+ /* As in mac80211 slaves list is modified:
+ * 1) under the RTNL
+ * 2) protected by slaves_mtx;
+ * 3) in an RCU manner
+ *
+ * So atomic readers can use any of this protection methods.
+ */
+ struct list_head interfaces;
+ struct mutex iflist_mtx;
+
+ /* This one is used for scanning and other jobs not to be interfered
+ * with serial driver.
+ */
+ struct workqueue_struct *workqueue;
+
+ bool started;
+
+ struct tasklet_struct tasklet;
+ struct sk_buff_head skb_queue;
+};
+
+enum {
+ IEEE802154_RX_MSG = 1,
+};
+
+enum ieee802154_sdata_state_bits {
+ SDATA_STATE_RUNNING,
+};
+
+/* Slave interface definition.
+ *
+ * Slaves represent typical network interfaces available from userspace.
+ * Each ieee802154 device/transceiver may have several slaves and able
+ * to be associated with several networks at the same time.
+ */
+struct ieee802154_sub_if_data {
+ struct list_head list; /* the ieee802154_priv->slaves list */
+
+ struct ieee802154_local *local;
+ struct net_device *dev;
+
+ int type;
+ unsigned long state;
+
+ spinlock_t mib_lock;
+
+ __le16 pan_id;
+ __le16 short_addr;
+ __le64 extended_addr;
+ bool promisuous_mode;
+
+ struct ieee802154_mac_params mac_params;
+
+ /* MAC BSN field */
+ u8 bsn;
+ /* MAC DSN field */
+ u8 dsn;
+
+ /* protects sec from concurrent access by netlink. access by
+ * encrypt/decrypt/header_create safe without additional protection.
+ */
+ struct mutex sec_mtx;
+
+ struct mac802154_llsec sec;
+};
+
+#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
+
+static inline struct ieee802154_local *
+hw_to_local(struct ieee802154_hw *hw)
+{
+ return container_of(hw, struct ieee802154_local, hw);
+}
+
+static inline struct ieee802154_sub_if_data *
+IEEE802154_DEV_TO_SUB_IF(const struct net_device *dev)
+{
+ return netdev_priv(dev);
+}
+
+static inline bool
+ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
+{
+ return test_bit(SDATA_STATE_RUNNING, &sdata->state);
+}
+
+extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
+extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
+
+void mac802154_monitor_setup(struct net_device *dev);
+netdev_tx_t
+ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+void mac802154_wpan_setup(struct net_device *dev);
+netdev_tx_t
+ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* MIB callbacks */
+void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
+__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
+void mac802154_dev_set_ieee_addr(struct net_device *dev);
+__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
+void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
+void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
+u8 mac802154_dev_get_dsn(const struct net_device *dev);
+
+int mac802154_get_params(struct net_device *dev,
+ struct ieee802154_llsec_params *params);
+int mac802154_set_params(struct net_device *dev,
+ const struct ieee802154_llsec_params *params,
+ int changed);
+
+int mac802154_add_key(struct net_device *dev,
+ const struct ieee802154_llsec_key_id *id,
+ const struct ieee802154_llsec_key *key);
+int mac802154_del_key(struct net_device *dev,
+ const struct ieee802154_llsec_key_id *id);
+
+int mac802154_add_dev(struct net_device *dev,
+ const struct ieee802154_llsec_device *llsec_dev);
+int mac802154_del_dev(struct net_device *dev, __le64 dev_addr);
+
+int mac802154_add_devkey(struct net_device *dev,
+ __le64 device_addr,
+ const struct ieee802154_llsec_device_key *key);
+int mac802154_del_devkey(struct net_device *dev,
+ __le64 device_addr,
+ const struct ieee802154_llsec_device_key *key);
+
+int mac802154_add_seclevel(struct net_device *dev,
+ const struct ieee802154_llsec_seclevel *sl);
+int mac802154_del_seclevel(struct net_device *dev,
+ const struct ieee802154_llsec_seclevel *sl);
+
+void mac802154_lock_table(struct net_device *dev);
+void mac802154_get_table(struct net_device *dev,
+ struct ieee802154_llsec_table **t);
+void mac802154_unlock_table(struct net_device *dev);
+
+#endif /* __IEEE802154_I_H */
--- /dev/null
+/*
+ * Copyright 2007-2012 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Sergey Lapin <slapin@ossfans.org>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/ieee802154.h>
+
+#include <net/rtnetlink.h>
+#include <linux/nl802154.h>
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/cfg802154.h>
+
+#include "ieee802154_i.h"
+#include "driver-ops.h"
+
+static int mac802154_wpan_update_llsec(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
+ int rc = 0;
+
+ if (ops->llsec) {
+ struct ieee802154_llsec_params params;
+ int changed = 0;
+
+ params.pan_id = sdata->pan_id;
+ changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
+
+ params.hwaddr = sdata->extended_addr;
+ changed |= IEEE802154_LLSEC_PARAM_HWADDR;
+
+ rc = ops->llsec->set_params(dev, ¶ms, changed);
+ }
+
+ return rc;
+}
+
+static int
+mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct sockaddr_ieee802154 *sa =
+ (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+ int err = -ENOIOCTLCMD;
+
+ spin_lock_bh(&sdata->mib_lock);
+
+ switch (cmd) {
+ case SIOCGIFADDR:
+ {
+ u16 pan_id, short_addr;
+
+ pan_id = le16_to_cpu(sdata->pan_id);
+ short_addr = le16_to_cpu(sdata->short_addr);
+ if (pan_id == IEEE802154_PANID_BROADCAST ||
+ short_addr == IEEE802154_ADDR_BROADCAST) {
+ err = -EADDRNOTAVAIL;
+ break;
+ }
+
+ sa->family = AF_IEEE802154;
+ sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+ sa->addr.pan_id = pan_id;
+ sa->addr.short_addr = short_addr;
+
+ err = 0;
+ break;
+ }
+ case SIOCSIFADDR:
+ dev_warn(&dev->dev,
+ "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
+ if (sa->family != AF_IEEE802154 ||
+ sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
+ sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
+ sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
+ sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
+ err = -EINVAL;
+ break;
+ }
+
+ sdata->pan_id = cpu_to_le16(sa->addr.pan_id);
+ sdata->short_addr = cpu_to_le16(sa->addr.short_addr);
+
+ err = mac802154_wpan_update_llsec(dev);
+ break;
+ }
+
+ spin_unlock_bh(&sdata->mib_lock);
+ return err;
+}
+
+static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* FIXME: validate addr */
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ mac802154_dev_set_ieee_addr(dev);
+ return mac802154_wpan_update_llsec(dev);
+}
+
+int mac802154_set_mac_params(struct net_device *dev,
+ const struct ieee802154_mac_params *params)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ sdata->mac_params = *params;
+ mutex_unlock(&sdata->local->iflist_mtx);
+
+ return 0;
+}
+
+void mac802154_get_mac_params(struct net_device *dev,
+ struct ieee802154_mac_params *params)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ *params = sdata->mac_params;
+ mutex_unlock(&sdata->local->iflist_mtx);
+}
+
+static int mac802154_slave_open(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_sub_if_data *subif;
+ struct ieee802154_local *local = sdata->local;
+ int res = 0;
+
+ ASSERT_RTNL();
+
+ if (sdata->type == IEEE802154_DEV_WPAN) {
+ mutex_lock(&sdata->local->iflist_mtx);
+ list_for_each_entry(subif, &sdata->local->interfaces, list) {
+ if (subif != sdata && subif->type == sdata->type &&
+ ieee802154_sdata_running(subif)) {
+ mutex_unlock(&sdata->local->iflist_mtx);
+ return -EBUSY;
+ }
+ }
+ mutex_unlock(&sdata->local->iflist_mtx);
+ }
+
+ set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+ if (!local->open_count) {
+ res = drv_start(local);
+ WARN_ON(res);
+ if (res)
+ goto err;
+ }
+
+ local->open_count++;
+ netif_start_queue(dev);
+ return 0;
+err:
+ /* might already be clear but that doesn't matter */
+ clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+ return res;
+}
+
+static int mac802154_wpan_open(struct net_device *dev)
+{
+ int rc;
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_local *local = sdata->local;
+ struct wpan_phy *phy = sdata->local->phy;
+
+ rc = mac802154_slave_open(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&phy->pib_lock);
+
+ if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
+ rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_TXPOWER) {
+ rc = drv_set_tx_power(local, sdata->mac_params.transmit_power);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_LBT) {
+ rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
+ rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) {
+ rc = drv_set_cca_ed_level(local,
+ sdata->mac_params.cca_ed_level);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
+ rc = drv_set_csma_params(local, sdata->mac_params.min_be,
+ sdata->mac_params.max_be,
+ sdata->mac_params.csma_retries);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
+ rc = drv_set_max_frame_retries(local,
+ sdata->mac_params.frame_retries);
+ if (rc < 0)
+ goto out;
+ }
+
+ mutex_unlock(&phy->pib_lock);
+ return 0;
+
+out:
+ mutex_unlock(&phy->pib_lock);
+ return rc;
+}
+
+static int mac802154_slave_close(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_local *local = sdata->local;
+
+ ASSERT_RTNL();
+
+ netif_stop_queue(dev);
+ local->open_count--;
+
+ clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+ if (!local->open_count)
+ drv_stop(local);
+
+ return 0;
+}
+
+static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
+ struct ieee802154_hdr *hdr,
+ const struct ieee802154_mac_cb *cb)
+{
+ struct ieee802154_llsec_params params;
+ u8 level;
+
+ mac802154_llsec_get_params(&sdata->sec, ¶ms);
+
+ if (!params.enabled && cb->secen_override && cb->secen)
+ return -EINVAL;
+ if (!params.enabled ||
+ (cb->secen_override && !cb->secen) ||
+ !params.out_level)
+ return 0;
+ if (cb->seclevel_override && !cb->seclevel)
+ return -EINVAL;
+
+ level = cb->seclevel_override ? cb->seclevel : params.out_level;
+
+ hdr->fc.security_enabled = 1;
+ hdr->sec.level = level;
+ hdr->sec.key_id_mode = params.out_key.mode;
+ if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
+ hdr->sec.short_src = params.out_key.short_source;
+ else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
+ hdr->sec.extended_src = params.out_key.extended_source;
+ hdr->sec.key_id = params.out_key.id;
+
+ return 0;
+}
+
+static int mac802154_header_create(struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned short type,
+ const void *daddr,
+ const void *saddr,
+ unsigned len)
+{
+ struct ieee802154_hdr hdr;
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_mac_cb *cb = mac_cb(skb);
+ int hlen;
+
+ if (!daddr)
+ return -EINVAL;
+
+ memset(&hdr.fc, 0, sizeof(hdr.fc));
+ hdr.fc.type = cb->type;
+ hdr.fc.security_enabled = cb->secen;
+ hdr.fc.ack_request = cb->ackreq;
+ hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+
+ if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
+ return -EINVAL;
+
+ if (!saddr) {
+ spin_lock_bh(&sdata->mib_lock);
+
+ if (sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
+ sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+ sdata->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+ hdr.source.mode = IEEE802154_ADDR_LONG;
+ hdr.source.extended_addr = sdata->extended_addr;
+ } else {
+ hdr.source.mode = IEEE802154_ADDR_SHORT;
+ hdr.source.short_addr = sdata->short_addr;
+ }
+
+ hdr.source.pan_id = sdata->pan_id;
+
+ spin_unlock_bh(&sdata->mib_lock);
+ } else {
+ hdr.source = *(const struct ieee802154_addr *)saddr;
+ }
+
+ hdr.dest = *(const struct ieee802154_addr *)daddr;
+
+ hlen = ieee802154_hdr_push(skb, &hdr);
+ if (hlen < 0)
+ return -EINVAL;
+
+ skb_reset_mac_header(skb);
+ skb->mac_len = hlen;
+
+ if (len > ieee802154_max_payload(&hdr))
+ return -EMSGSIZE;
+
+ return hlen;
+}
+
+static int
+mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+ struct ieee802154_hdr hdr;
+ struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
+
+ if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+ pr_debug("malformed packet\n");
+ return 0;
+ }
+
+ *addr = hdr.source;
+ return sizeof(*addr);
+}
+
+static struct header_ops mac802154_header_ops = {
+ .create = mac802154_header_create,
+ .parse = mac802154_header_parse,
+};
+
+static const struct net_device_ops mac802154_wpan_ops = {
+ .ndo_open = mac802154_wpan_open,
+ .ndo_stop = mac802154_slave_close,
+ .ndo_start_xmit = ieee802154_subif_start_xmit,
+ .ndo_do_ioctl = mac802154_wpan_ioctl,
+ .ndo_set_mac_address = mac802154_wpan_mac_addr,
+};
+
+static const struct net_device_ops mac802154_monitor_ops = {
+ .ndo_open = mac802154_wpan_open,
+ .ndo_stop = mac802154_slave_close,
+ .ndo_start_xmit = ieee802154_monitor_start_xmit,
+};
+
+static void mac802154_wpan_free(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ mac802154_llsec_destroy(&sdata->sec);
+
+ free_netdev(dev);
+}
+
+void mac802154_wpan_setup(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata;
+
+ dev->addr_len = IEEE802154_ADDR_LEN;
+ memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+
+ dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
+ dev->header_ops = &mac802154_header_ops;
+ dev->needed_tailroom = 2 + 16; /* FCS + MIC */
+ dev->mtu = IEEE802154_MTU;
+ dev->tx_queue_len = 300;
+ dev->type = ARPHRD_IEEE802154;
+ dev->flags = IFF_NOARP | IFF_BROADCAST;
+
+ dev->destructor = mac802154_wpan_free;
+ dev->netdev_ops = &mac802154_wpan_ops;
+ dev->ml_priv = &mac802154_mlme_wpan;
+
+ sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ sdata->type = IEEE802154_DEV_WPAN;
+
+ spin_lock_init(&sdata->mib_lock);
+ mutex_init(&sdata->sec_mtx);
+
+ get_random_bytes(&sdata->bsn, 1);
+ get_random_bytes(&sdata->dsn, 1);
+
+ /* defaults per 802.15.4-2011 */
+ sdata->mac_params.min_be = 3;
+ sdata->mac_params.max_be = 5;
+ sdata->mac_params.csma_retries = 4;
+ /* for compatibility, actual default is 3 */
+ sdata->mac_params.frame_retries = -1;
+
+ sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+ sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+
+ sdata->promisuous_mode = false;
+
+ mac802154_llsec_init(&sdata->sec);
+}
+
+void mac802154_monitor_setup(struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata;
+
+ dev->needed_tailroom = 2; /* room for FCS */
+ dev->mtu = IEEE802154_MTU;
+ dev->tx_queue_len = 10;
+ dev->type = ARPHRD_IEEE802154_MONITOR;
+ dev->flags = IFF_NOARP | IFF_BROADCAST;
+
+ dev->destructor = free_netdev;
+ dev->netdev_ops = &mac802154_monitor_ops;
+ dev->ml_priv = &mac802154_mlme_reduced;
+
+ sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ sdata->type = IEEE802154_DEV_MONITOR;
+
+ sdata->promisuous_mode = true;
+}
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/completion.h>
-#include <net/ieee802154.h>
+#include <linux/ieee802154.h>
#include <crypto/algapi.h>
-#include "mac802154.h"
+#include "ieee802154_i.h"
#include "llsec.h"
static void llsec_key_put(struct mac802154_llsec_key *key);
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-#ifndef MAC802154_H
-#define MAC802154_H
-
-#include <linux/mutex.h>
-#include <net/mac802154.h>
-#include <net/ieee802154_netdev.h>
-
-#include "llsec.h"
-
-/* mac802154 device private data */
-struct mac802154_priv {
- struct ieee802154_dev hw;
- struct ieee802154_ops *ops;
-
- /* ieee802154 phy */
- struct wpan_phy *phy;
-
- int open_count;
-
- /* As in mac80211 slaves list is modified:
- * 1) under the RTNL
- * 2) protected by slaves_mtx;
- * 3) in an RCU manner
- *
- * So atomic readers can use any of this protection methods.
- */
- struct list_head slaves;
- struct mutex slaves_mtx;
-
- /* This one is used for scanning and other jobs not to be interfered
- * with serial driver.
- */
- struct workqueue_struct *dev_workqueue;
-
- /* SoftMAC device is registered and running. One can add subinterfaces.
- * This flag should be modified under slaves_mtx and RTNL, so you can
- * read them using any of protection methods.
- */
- bool running;
-};
-
-#define MAC802154_DEVICE_STOPPED 0x00
-#define MAC802154_DEVICE_RUN 0x01
-
-/* Slave interface definition.
- *
- * Slaves represent typical network interfaces available from userspace.
- * Each ieee802154 device/transceiver may have several slaves and able
- * to be associated with several networks at the same time.
- */
-struct mac802154_sub_if_data {
- struct list_head list; /* the ieee802154_priv->slaves list */
-
- struct mac802154_priv *hw;
- struct net_device *dev;
-
- int type;
- bool running;
-
- spinlock_t mib_lock;
-
- __le16 pan_id;
- __le16 short_addr;
- __le64 extended_addr;
-
- u8 chan;
- u8 page;
-
- struct ieee802154_mac_params mac_params;
-
- /* MAC BSN field */
- u8 bsn;
- /* MAC DSN field */
- u8 dsn;
-
- /* protects sec from concurrent access by netlink. access by
- * encrypt/decrypt/header_create safe without additional protection.
- */
- struct mutex sec_mtx;
-
- struct mac802154_llsec sec;
-};
-
-#define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw)
-
-#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
-
-extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
-extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
-
-int mac802154_slave_open(struct net_device *dev);
-int mac802154_slave_close(struct net_device *dev);
-
-void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb);
-void mac802154_monitor_setup(struct net_device *dev);
-
-void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb);
-void mac802154_wpan_setup(struct net_device *dev);
-
-netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
- u8 page, u8 chan);
-
-/* MIB callbacks */
-void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
-__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
-void mac802154_dev_set_ieee_addr(struct net_device *dev);
-__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
-void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
-void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
-u8 mac802154_dev_get_dsn(const struct net_device *dev);
-
-int mac802154_set_mac_params(struct net_device *dev,
- const struct ieee802154_mac_params *params);
-void mac802154_get_mac_params(struct net_device *dev,
- struct ieee802154_mac_params *params);
-
-int mac802154_get_params(struct net_device *dev,
- struct ieee802154_llsec_params *params);
-int mac802154_set_params(struct net_device *dev,
- const struct ieee802154_llsec_params *params,
- int changed);
-
-int mac802154_add_key(struct net_device *dev,
- const struct ieee802154_llsec_key_id *id,
- const struct ieee802154_llsec_key *key);
-int mac802154_del_key(struct net_device *dev,
- const struct ieee802154_llsec_key_id *id);
-
-int mac802154_add_dev(struct net_device *dev,
- const struct ieee802154_llsec_device *llsec_dev);
-int mac802154_del_dev(struct net_device *dev, __le64 dev_addr);
-
-int mac802154_add_devkey(struct net_device *dev,
- __le64 device_addr,
- const struct ieee802154_llsec_device_key *key);
-int mac802154_del_devkey(struct net_device *dev,
- __le64 device_addr,
- const struct ieee802154_llsec_device_key *key);
-
-int mac802154_add_seclevel(struct net_device *dev,
- const struct ieee802154_llsec_seclevel *sl);
-int mac802154_del_seclevel(struct net_device *dev,
- const struct ieee802154_llsec_seclevel *sl);
-
-void mac802154_lock_table(struct net_device *dev);
-void mac802154_get_table(struct net_device *dev,
- struct ieee802154_llsec_table **t);
-void mac802154_unlock_table(struct net_device *dev);
-
-#endif /* MAC802154_H */
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Sergey Lapin <slapin@ossfans.org>
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
+#include <linux/ieee802154.h>
-#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
#include <net/mac802154.h>
#include <net/nl802154.h>
-#include "mac802154.h"
+#include "ieee802154_i.h"
static int mac802154_mlme_start_req(struct net_device *dev,
struct ieee802154_addr *addr,
static struct wpan_phy *mac802154_get_phy(const struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- return to_phy(get_device(&priv->hw->phy->dev));
+ return to_phy(get_device(&sdata->local->phy->dev));
+}
+
+static int mac802154_set_mac_params(struct net_device *dev,
+ const struct ieee802154_mac_params *params)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ sdata->mac_params = *params;
+ mutex_unlock(&sdata->local->iflist_mtx);
+
+ return 0;
+}
+
+static void mac802154_get_mac_params(struct net_device *dev,
+ struct ieee802154_mac_params *params)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ *params = sdata->mac_params;
+ mutex_unlock(&sdata->local->iflist_mtx);
}
static struct ieee802154_llsec_ops mac802154_llsec_ops = {
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Siemens AG
+ *
+ * Written by:
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ *
+ * Based on the code from 'linux-zigbee.sourceforge.net' project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include <net/netlink.h>
+#include <linux/nl802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/route.h>
+#include <net/cfg802154.h>
+
+#include "ieee802154_i.h"
+
+static int
+mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_local *local;
+ int err;
+
+ local = wpan_phy_priv(phy);
+
+ sdata->dev = dev;
+ sdata->local = local;
+
+ dev->needed_headroom = local->hw.extra_tx_headroom;
+
+ SET_NETDEV_DEV(dev, &local->phy->dev);
+
+ err = register_netdev(dev);
+ if (err < 0)
+ return err;
+
+ rtnl_lock();
+ mutex_lock(&local->iflist_mtx);
+ list_add_tail_rcu(&sdata->list, &local->interfaces);
+ mutex_unlock(&local->iflist_mtx);
+ rtnl_unlock();
+
+ return 0;
+}
+
+static void
+mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ ASSERT_RTNL();
+
+ BUG_ON(sdata->local->phy != phy);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ list_del_rcu(&sdata->list);
+ mutex_unlock(&sdata->local->iflist_mtx);
+
+ synchronize_rcu();
+ unregister_netdevice(sdata->dev);
+}
+
+static struct net_device *
+mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
+{
+ struct net_device *dev;
+ int err = -ENOMEM;
+
+ switch (type) {
+ case IEEE802154_DEV_MONITOR:
+ dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+ name, NET_NAME_UNKNOWN,
+ mac802154_monitor_setup);
+ break;
+ case IEEE802154_DEV_WPAN:
+ dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+ name, NET_NAME_UNKNOWN,
+ mac802154_wpan_setup);
+ break;
+ default:
+ dev = NULL;
+ err = -EINVAL;
+ break;
+ }
+ if (!dev)
+ goto err;
+
+ err = mac802154_netdev_register(phy, dev);
+ if (err)
+ goto err_free;
+
+ dev_hold(dev); /* we return an incremented device refcount */
+ return dev;
+
+err_free:
+ free_netdev(dev);
+err:
+ return ERR_PTR(err);
+}
+
+static void ieee802154_tasklet_handler(unsigned long data)
+{
+ struct ieee802154_local *local = (struct ieee802154_local *)data;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&local->skb_queue))) {
+ switch (skb->pkt_type) {
+ case IEEE802154_RX_MSG:
+ /* Clear skb->pkt_type in order to not confuse kernel
+ * netstack.
+ */
+ skb->pkt_type = 0;
+ ieee802154_rx(&local->hw, skb);
+ break;
+ default:
+ WARN(1, "mac802154: Packet is of unknown type %d\n",
+ skb->pkt_type);
+ kfree_skb(skb);
+ break;
+ }
+ }
+}
+
+struct ieee802154_hw *
+ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
+{
+ struct wpan_phy *phy;
+ struct ieee802154_local *local;
+ size_t priv_size;
+
+ if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
+ !ops->start || !ops->stop || !ops->set_channel) {
+ pr_err("undefined IEEE802.15.4 device operations\n");
+ return NULL;
+ }
+
+ /* Ensure 32-byte alignment of our private data and hw private data.
+ * We use the wpan_phy priv data for both our ieee802154_local and for
+ * the driver's private data
+ *
+ * in memory it'll be like this:
+ *
+ * +-------------------------+
+ * | struct wpan_phy |
+ * +-------------------------+
+ * | struct ieee802154_local |
+ * +-------------------------+
+ * | driver's private data |
+ * +-------------------------+
+ *
+ * Due to ieee802154 layer isn't aware of driver and MAC structures,
+ * so lets align them here.
+ */
+
+ priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
+
+ phy = wpan_phy_alloc(priv_size);
+ if (!phy) {
+ pr_err("failure to allocate master IEEE802.15.4 device\n");
+ return NULL;
+ }
+
+ local = wpan_phy_priv(phy);
+ local->phy = phy;
+ local->hw.phy = local->phy;
+ local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
+ local->ops = ops;
+
+ INIT_LIST_HEAD(&local->interfaces);
+ mutex_init(&local->iflist_mtx);
+
+ tasklet_init(&local->tasklet,
+ ieee802154_tasklet_handler,
+ (unsigned long)local);
+
+ skb_queue_head_init(&local->skb_queue);
+
+ return &local->hw;
+}
+EXPORT_SYMBOL(ieee802154_alloc_hw);
+
+void ieee802154_free_hw(struct ieee802154_hw *hw)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ BUG_ON(!list_empty(&local->interfaces));
+
+ mutex_destroy(&local->iflist_mtx);
+
+ wpan_phy_free(local->phy);
+}
+EXPORT_SYMBOL(ieee802154_free_hw);
+
+int ieee802154_register_hw(struct ieee802154_hw *hw)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+ int rc = -ENOSYS;
+
+ local->workqueue =
+ create_singlethread_workqueue(wpan_phy_name(local->phy));
+ if (!local->workqueue) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ wpan_phy_set_dev(local->phy, local->hw.parent);
+
+ local->phy->add_iface = mac802154_add_iface;
+ local->phy->del_iface = mac802154_del_iface;
+
+ rc = wpan_phy_register(local->phy);
+ if (rc < 0)
+ goto out_wq;
+
+ return 0;
+
+out_wq:
+ destroy_workqueue(local->workqueue);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(ieee802154_register_hw);
+
+void ieee802154_unregister_hw(struct ieee802154_hw *hw)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+ struct ieee802154_sub_if_data *sdata, *next;
+
+ tasklet_kill(&local->tasklet);
+ flush_workqueue(local->workqueue);
+ destroy_workqueue(local->workqueue);
+
+ rtnl_lock();
+
+ list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
+ mutex_lock(&sdata->local->iflist_mtx);
+ list_del(&sdata->list);
+ mutex_unlock(&sdata->local->iflist_mtx);
+
+ unregister_netdevice(sdata->dev);
+ }
+
+ rtnl_unlock();
+
+ wpan_phy_unregister(local->phy);
+}
+EXPORT_SYMBOL(ieee802154_unregister_hw);
+
+MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
+MODULE_LICENSE("GPL v2");
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* Sergey Lapin <slapin@ossfans.org>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
+#include <net/cfg802154.h>
-struct phy_chan_notify_work {
- struct work_struct work;
- struct net_device *dev;
-};
+#include "ieee802154_i.h"
+#include "driver-ops.h"
struct hw_addr_filt_notify_work {
struct work_struct work;
unsigned long changed;
};
-static struct mac802154_priv *mac802154_slave_get_priv(struct net_device *dev)
+static struct ieee802154_local *mac802154_slave_get_priv(struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- return priv->hw;
+ return sdata->local;
}
static void hw_addr_notify(struct work_struct *work)
{
struct hw_addr_filt_notify_work *nw = container_of(work,
struct hw_addr_filt_notify_work, work);
- struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev);
+ struct ieee802154_local *local = mac802154_slave_get_priv(nw->dev);
int res;
- res = hw->ops->set_hw_addr_filt(&hw->hw,
- &hw->hw.hw_filt,
- nw->changed);
+ res = local->ops->set_hw_addr_filt(&local->hw, &local->hw.hw_filt,
+ nw->changed);
if (res)
pr_debug("failed changed mask %lx\n", nw->changed);
static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct hw_addr_filt_notify_work *work;
work = kzalloc(sizeof(*work), GFP_ATOMIC);
INIT_WORK(&work->work, hw_addr_notify);
work->dev = dev;
work->changed = changed;
- queue_work(priv->hw->dev_workqueue, &work->work);
+ queue_work(sdata->local->workqueue, &work->work);
}
void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- spin_lock_bh(&priv->mib_lock);
- priv->short_addr = val;
- spin_unlock_bh(&priv->mib_lock);
+ spin_lock_bh(&sdata->mib_lock);
+ sdata->short_addr = val;
+ spin_unlock_bh(&sdata->mib_lock);
- if ((priv->hw->ops->set_hw_addr_filt) &&
- (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) {
- priv->hw->hw.hw_filt.short_addr = priv->short_addr;
- set_hw_addr_filt(dev, IEEE802515_AFILT_SADDR_CHANGED);
+ if ((sdata->local->ops->set_hw_addr_filt) &&
+ (sdata->local->hw.hw_filt.short_addr != sdata->short_addr)) {
+ sdata->local->hw.hw_filt.short_addr = sdata->short_addr;
+ set_hw_addr_filt(dev, IEEE802154_AFILT_SADDR_CHANGED);
}
}
__le16 mac802154_dev_get_short_addr(const struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
__le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- spin_lock_bh(&priv->mib_lock);
- ret = priv->short_addr;
- spin_unlock_bh(&priv->mib_lock);
+ spin_lock_bh(&sdata->mib_lock);
+ ret = sdata->short_addr;
+ spin_unlock_bh(&sdata->mib_lock);
return ret;
}
void mac802154_dev_set_ieee_addr(struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct mac802154_priv *mac = priv->hw;
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_local *local = sdata->local;
- priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+ sdata->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
- if (mac->ops->set_hw_addr_filt &&
- mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
- mac->hw.hw_filt.ieee_addr = priv->extended_addr;
- set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED);
+ if (local->ops->set_hw_addr_filt &&
+ local->hw.hw_filt.ieee_addr != sdata->extended_addr) {
+ local->hw.hw_filt.ieee_addr = sdata->extended_addr;
+ set_hw_addr_filt(dev, IEEE802154_AFILT_IEEEADDR_CHANGED);
}
}
__le16 mac802154_dev_get_pan_id(const struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
__le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- spin_lock_bh(&priv->mib_lock);
- ret = priv->pan_id;
- spin_unlock_bh(&priv->mib_lock);
+ spin_lock_bh(&sdata->mib_lock);
+ ret = sdata->pan_id;
+ spin_unlock_bh(&sdata->mib_lock);
return ret;
}
void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- spin_lock_bh(&priv->mib_lock);
- priv->pan_id = val;
- spin_unlock_bh(&priv->mib_lock);
+ spin_lock_bh(&sdata->mib_lock);
+ sdata->pan_id = val;
+ spin_unlock_bh(&sdata->mib_lock);
- if ((priv->hw->ops->set_hw_addr_filt) &&
- (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) {
- priv->hw->hw.hw_filt.pan_id = priv->pan_id;
- set_hw_addr_filt(dev, IEEE802515_AFILT_PANID_CHANGED);
+ if ((sdata->local->ops->set_hw_addr_filt) &&
+ (sdata->local->hw.hw_filt.pan_id != sdata->pan_id)) {
+ sdata->local->hw.hw_filt.pan_id = sdata->pan_id;
+ set_hw_addr_filt(dev, IEEE802154_AFILT_PANID_CHANGED);
}
}
u8 mac802154_dev_get_dsn(const struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- return priv->dsn++;
-}
-
-static void phy_chan_notify(struct work_struct *work)
-{
- struct phy_chan_notify_work *nw = container_of(work,
- struct phy_chan_notify_work, work);
- struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev);
- struct mac802154_sub_if_data *priv = netdev_priv(nw->dev);
- int res;
-
- mutex_lock(&priv->hw->phy->pib_lock);
- res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan);
- if (res) {
- pr_debug("set_channel failed\n");
- } else {
- priv->hw->phy->current_channel = priv->chan;
- priv->hw->phy->current_page = priv->page;
- }
- mutex_unlock(&priv->hw->phy->pib_lock);
-
- kfree(nw);
+ return sdata->dsn++;
}
void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct phy_chan_notify_work *work;
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ struct ieee802154_local *local = sdata->local;
+ int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- spin_lock_bh(&priv->mib_lock);
- priv->page = page;
- priv->chan = chan;
- spin_unlock_bh(&priv->mib_lock);
-
- mutex_lock(&priv->hw->phy->pib_lock);
- if (priv->hw->phy->current_channel != priv->chan ||
- priv->hw->phy->current_page != priv->page) {
- mutex_unlock(&priv->hw->phy->pib_lock);
-
- work = kzalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
- return;
-
- INIT_WORK(&work->work, phy_chan_notify);
- work->dev = dev;
- queue_work(priv->hw->dev_workqueue, &work->work);
+ res = drv_set_channel(local, page, chan);
+ if (res) {
+ pr_debug("set_channel failed\n");
} else {
- mutex_unlock(&priv->hw->phy->pib_lock);
+ mutex_lock(&local->phy->pib_lock);
+ local->phy->current_channel = chan;
+ local->phy->current_page = page;
+ mutex_unlock(&local->phy->pib_lock);
}
}
int mac802154_get_params(struct net_device *dev,
struct ieee802154_llsec_params *params)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_get_params(&priv->sec, params);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_get_params(&sdata->sec, params);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
const struct ieee802154_llsec_params *params,
int changed)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_set_params(&priv->sec, params, changed);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_set_params(&sdata->sec, params, changed);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
const struct ieee802154_llsec_key_id *id,
const struct ieee802154_llsec_key *key)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_key_add(&priv->sec, id, key);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_key_add(&sdata->sec, id, key);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
int mac802154_del_key(struct net_device *dev,
const struct ieee802154_llsec_key_id *id)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_key_del(&priv->sec, id);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_key_del(&sdata->sec, id);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
int mac802154_add_dev(struct net_device *dev,
const struct ieee802154_llsec_device *llsec_dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_dev_add(&priv->sec, llsec_dev);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_dev_add(&sdata->sec, llsec_dev);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
int mac802154_del_dev(struct net_device *dev, __le64 dev_addr)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_dev_del(&priv->sec, dev_addr);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_dev_del(&sdata->sec, dev_addr);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
__le64 device_addr,
const struct ieee802154_llsec_device_key *key)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_devkey_add(&priv->sec, device_addr, key);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_devkey_add(&sdata->sec, device_addr, key);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
__le64 device_addr,
const struct ieee802154_llsec_device_key *key)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_devkey_del(&priv->sec, device_addr, key);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_devkey_del(&sdata->sec, device_addr, key);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
int mac802154_add_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_seclevel_add(&priv->sec, sl);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_seclevel_add(&sdata->sec, sl);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
int mac802154_del_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
- res = mac802154_llsec_seclevel_del(&priv->sec, sl);
- mutex_unlock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
+ res = mac802154_llsec_seclevel_del(&sdata->sec, sl);
+ mutex_unlock(&sdata->sec_mtx);
return res;
}
void mac802154_lock_table(struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_lock(&priv->sec_mtx);
+ mutex_lock(&sdata->sec_mtx);
}
void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- *t = &priv->sec.table;
+ *t = &sdata->sec.table;
}
void mac802154_unlock_table(struct net_device *dev)
{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
- mutex_unlock(&priv->sec_mtx);
+ mutex_unlock(&sdata->sec_mtx);
}
+++ /dev/null
-/*
- * Copyright 2007, 2008, 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Sergey Lapin <slapin@ossfans.org>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/crc-ccitt.h>
-
-#include <net/ieee802154.h>
-#include <net/mac802154.h>
-#include <net/netlink.h>
-#include <net/wpan-phy.h>
-#include <linux/nl802154.h>
-
-#include "mac802154.h"
-
-static netdev_tx_t mac802154_monitor_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv;
- u8 chan, page;
-
- priv = netdev_priv(dev);
-
- /* FIXME: locking */
- chan = priv->hw->phy->current_channel;
- page = priv->hw->phy->current_page;
-
- if (chan == MAC802154_CHAN_NONE) /* not initialized */
- return NETDEV_TX_OK;
-
- if (WARN_ON(page >= WPAN_NUM_PAGES) ||
- WARN_ON(chan >= WPAN_NUM_CHANNELS))
- return NETDEV_TX_OK;
-
- skb->skb_iif = dev->ifindex;
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
-
- return mac802154_tx(priv->hw, skb, page, chan);
-}
-
-
-void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb)
-{
- struct sk_buff *skb2;
- struct mac802154_sub_if_data *sdata;
- u16 crc = crc_ccitt(0, skb->data, skb->len);
- u8 *data;
-
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &priv->slaves, list) {
- if (sdata->type != IEEE802154_DEV_MONITOR ||
- !netif_running(sdata->dev))
- continue;
-
- skb2 = skb_clone(skb, GFP_ATOMIC);
- skb2->dev = sdata->dev;
- skb2->pkt_type = PACKET_HOST;
- data = skb_put(skb2, 2);
- data[0] = crc & 0xff;
- data[1] = crc >> 8;
-
- netif_rx_ni(skb2);
- }
- rcu_read_unlock();
-}
-
-static const struct net_device_ops mac802154_monitor_ops = {
- .ndo_open = mac802154_slave_open,
- .ndo_stop = mac802154_slave_close,
- .ndo_start_xmit = mac802154_monitor_xmit,
-};
-
-void mac802154_monitor_setup(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv;
-
- dev->addr_len = 0;
- dev->hard_header_len = 0;
- dev->needed_tailroom = 2; /* room for FCS */
- dev->mtu = IEEE802154_MTU;
- dev->tx_queue_len = 10;
- dev->type = ARPHRD_IEEE802154_MONITOR;
- dev->flags = IFF_NOARP | IFF_BROADCAST;
- dev->watchdog_timeo = 0;
-
- dev->destructor = free_netdev;
- dev->netdev_ops = &mac802154_monitor_ops;
- dev->ml_priv = &mac802154_mlme_reduced;
-
- priv = netdev_priv(dev);
- priv->type = IEEE802154_DEV_MONITOR;
-
- priv->chan = MAC802154_CHAN_NONE; /* not initialized */
- priv->page = 0;
-}
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
* Maxim Gorbachyov <maxim.gorbachev@siemens.com>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/workqueue.h>
#include <linux/netdevice.h>
#include <linux/crc-ccitt.h>
+#include <asm/unaligned.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
+#include <net/rtnetlink.h>
+#include <linux/nl802154.h>
-#include "mac802154.h"
+#include "ieee802154_i.h"
-/* The IEEE 802.15.4 standard defines 4 MAC packet types:
- * - beacon frame
- * - MAC command frame
- * - acknowledgement frame
- * - data frame
- *
- * and only the data frame should be pushed to the upper layers, other types
- * are just internal MAC layer management information. So only data packets
- * are going to be sent to the networking queue, all other will be processed
- * right here by using the device workqueue.
- */
-struct rx_work {
- struct sk_buff *skb;
- struct work_struct work;
- struct ieee802154_dev *dev;
- u8 lqi;
-};
+static int ieee802154_deliver_skb(struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->protocol = htons(ETH_P_IEEE802154);
-static void
-mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi)
+ return netif_receive_skb(skb);
+}
+
+static int
+ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
+ struct sk_buff *skb, const struct ieee802154_hdr *hdr)
{
- struct mac802154_priv *priv = mac802154_to_priv(hw);
+ __le16 span, sshort;
+ int rc;
- mac_cb(skb)->lqi = lqi;
- skb->protocol = htons(ETH_P_IEEE802154);
- skb_reset_mac_header(skb);
+ pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
- if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
- u16 crc;
+ spin_lock_bh(&sdata->mib_lock);
- if (skb->len < 2) {
- pr_debug("got invalid frame\n");
- goto fail;
- }
- crc = crc_ccitt(0, skb->data, skb->len);
- if (crc) {
- pr_debug("CRC mismatch\n");
- goto fail;
- }
- skb_trim(skb, skb->len - 2); /* CRC */
+ span = sdata->pan_id;
+ sshort = sdata->short_addr;
+
+ switch (mac_cb(skb)->dest.mode) {
+ case IEEE802154_ADDR_NONE:
+ if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
+ /* FIXME: check if we are PAN coordinator */
+ skb->pkt_type = PACKET_OTHERHOST;
+ else
+ /* ACK comes with both addresses empty */
+ skb->pkt_type = PACKET_HOST;
+ break;
+ case IEEE802154_ADDR_LONG:
+ if (mac_cb(skb)->dest.pan_id != span &&
+ mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
+ skb->pkt_type = PACKET_OTHERHOST;
+ else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
+ skb->pkt_type = PACKET_HOST;
+ else
+ skb->pkt_type = PACKET_OTHERHOST;
+ break;
+ case IEEE802154_ADDR_SHORT:
+ if (mac_cb(skb)->dest.pan_id != span &&
+ mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
+ skb->pkt_type = PACKET_OTHERHOST;
+ else if (mac_cb(skb)->dest.short_addr == sshort)
+ skb->pkt_type = PACKET_HOST;
+ else if (mac_cb(skb)->dest.short_addr ==
+ cpu_to_le16(IEEE802154_ADDR_BROADCAST))
+ skb->pkt_type = PACKET_BROADCAST;
+ else
+ skb->pkt_type = PACKET_OTHERHOST;
+ break;
+ default:
+ spin_unlock_bh(&sdata->mib_lock);
+ pr_debug("invalid dest mode\n");
+ kfree_skb(skb);
+ return NET_RX_DROP;
}
- mac802154_monitors_rx(priv, skb);
- mac802154_wpans_rx(priv, skb);
+ spin_unlock_bh(&sdata->mib_lock);
- return;
+ skb->dev = sdata->dev;
+
+ rc = mac802154_llsec_decrypt(&sdata->sec, skb);
+ if (rc) {
+ pr_debug("decryption failed: %i\n", rc);
+ goto fail;
+ }
+
+ sdata->dev->stats.rx_packets++;
+ sdata->dev->stats.rx_bytes += skb->len;
+
+ switch (mac_cb(skb)->type) {
+ case IEEE802154_FC_TYPE_DATA:
+ return ieee802154_deliver_skb(skb);
+ default:
+ pr_warn("ieee802154: bad frame received (type = %d)\n",
+ mac_cb(skb)->type);
+ goto fail;
+ }
fail:
kfree_skb(skb);
+ return NET_RX_DROP;
}
-static void mac802154_rx_worker(struct work_struct *work)
+static void
+ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
{
- struct rx_work *rw = container_of(work, struct rx_work, work);
+ if (addr->mode == IEEE802154_ADDR_NONE)
+ pr_debug("%s not present\n", name);
+
+ pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+ if (addr->mode == IEEE802154_ADDR_SHORT) {
+ pr_debug("%s is short: %04x\n", name,
+ le16_to_cpu(addr->short_addr));
+ } else {
+ u64 hw = swab64((__force u64)addr->extended_addr);
- mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
- kfree(rw);
+ pr_debug("%s is hardware: %8phC\n", name, &hw);
+ }
}
-void
-ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+static int
+ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
- struct mac802154_priv *priv = mac802154_to_priv(dev);
- struct rx_work *work;
+ int hlen;
+ struct ieee802154_mac_cb *cb = mac_cb_init(skb);
- if (!skb)
- return;
+ skb_reset_mac_header(skb);
+
+ hlen = ieee802154_hdr_pull(skb, hdr);
+ if (hlen < 0)
+ return -EINVAL;
+
+ skb->mac_len = hlen;
+
+ pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
+ hdr->seq);
+
+ cb->type = hdr->fc.type;
+ cb->ackreq = hdr->fc.ack_request;
+ cb->secen = hdr->fc.security_enabled;
+
+ ieee802154_print_addr("destination", &hdr->dest);
+ ieee802154_print_addr("source", &hdr->source);
+
+ cb->source = hdr->source;
+ cb->dest = hdr->dest;
+
+ if (hdr->fc.security_enabled) {
+ u64 key;
+
+ pr_debug("seclevel %i\n", hdr->sec.level);
+
+ switch (hdr->sec.key_id_mode) {
+ case IEEE802154_SCF_KEY_IMPLICIT:
+ pr_debug("implicit key\n");
+ break;
+
+ case IEEE802154_SCF_KEY_INDEX:
+ pr_debug("key %02x\n", hdr->sec.key_id);
+ break;
+
+ case IEEE802154_SCF_KEY_SHORT_INDEX:
+ pr_debug("key %04x:%04x %02x\n",
+ le32_to_cpu(hdr->sec.short_src) >> 16,
+ le32_to_cpu(hdr->sec.short_src) & 0xffff,
+ hdr->sec.key_id);
+ break;
+
+ case IEEE802154_SCF_KEY_HW_INDEX:
+ key = swab64((__force u64)hdr->sec.extended_src);
+ pr_debug("key source %8phC %02x\n", &key,
+ hdr->sec.key_id);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void
+__ieee802154_rx_handle_packet(struct ieee802154_local *local,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct ieee802154_sub_if_data *sdata;
+ struct ieee802154_hdr hdr;
- work = kzalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
+ ret = ieee802154_parse_frame_start(skb, &hdr);
+ if (ret) {
+ pr_debug("got invalid frame\n");
+ kfree_skb(skb);
return;
+ }
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->type != IEEE802154_DEV_WPAN ||
+ !netif_running(sdata->dev))
+ continue;
+
+ ieee802154_subif_frame(sdata, skb, &hdr);
+ skb = NULL;
+ break;
+ }
+
+ if (skb)
+ kfree_skb(skb);
+}
+
+static void
+ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
+{
+ struct sk_buff *skb2;
+ struct ieee802154_sub_if_data *sdata;
+
+ skb_reset_mac_header(skb);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_IEEE802154);
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->type != IEEE802154_DEV_MONITOR)
+ continue;
+
+ if (!ieee802154_sdata_running(sdata))
+ continue;
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ skb2->dev = sdata->dev;
+ ieee802154_deliver_skb(skb2);
+
+ sdata->dev->stats.rx_packets++;
+ sdata->dev->stats.rx_bytes += skb->len;
+ }
+ }
+}
+
+void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+ u16 crc;
- INIT_WORK(&work->work, mac802154_rx_worker);
- work->skb = skb;
- work->dev = dev;
- work->lqi = lqi;
+ WARN_ON_ONCE(softirq_count() == 0);
- queue_work(priv->dev_workqueue, &work->work);
+ /* TODO: When a transceiver omits the checksum here, we
+ * add an own calculated one. This is currently an ugly
+ * solution because the monitor needs a crc here.
+ */
+ if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
+ crc = crc_ccitt(0, skb->data, skb->len);
+ put_unaligned_le16(crc, skb_put(skb, 2));
+ }
+
+ rcu_read_lock();
+
+ ieee802154_monitors_rx(local, skb);
+
+ /* Check if transceiver doesn't validate the checksum.
+ * If not we validate the checksum here.
+ */
+ if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) {
+ crc = crc_ccitt(0, skb->data, skb->len);
+ if (crc) {
+ rcu_read_unlock();
+ kfree_skb(skb);
+ return;
+ }
+ }
+ /* remove crc */
+ skb_trim(skb, skb->len - 2);
+
+ __ieee802154_rx_handle_packet(local, skb);
+
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_rx);
+
+void
+ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ mac_cb(skb)->lqi = lqi;
+ skb->pkt_type = IEEE802154_RX_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
}
EXPORT_SYMBOL(ieee802154_rx_irqsafe);
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Written by:
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
* Sergey Lapin <slapin@ossfans.org>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/crc-ccitt.h>
+#include <asm/unaligned.h>
+#include <net/rtnetlink.h>
#include <net/ieee802154_netdev.h>
#include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
-#include "mac802154.h"
+#include "ieee802154_i.h"
+#include "driver-ops.h"
/* IEEE 802.15.4 transceivers can sleep during the xmit session, so process
* packets through the workqueue.
*/
-struct xmit_work {
+struct ieee802154_xmit_cb {
struct sk_buff *skb;
struct work_struct work;
- struct mac802154_priv *priv;
- u8 chan;
- u8 page;
+ struct ieee802154_local *local;
};
-static void mac802154_xmit_worker(struct work_struct *work)
+static struct ieee802154_xmit_cb ieee802154_xmit_cb;
+
+static void ieee802154_xmit_worker(struct work_struct *work)
{
- struct xmit_work *xw = container_of(work, struct xmit_work, work);
- struct mac802154_sub_if_data *sdata;
+ struct ieee802154_xmit_cb *cb =
+ container_of(work, struct ieee802154_xmit_cb, work);
+ struct ieee802154_local *local = cb->local;
+ struct sk_buff *skb = cb->skb;
+ struct net_device *dev = skb->dev;
int res;
- mutex_lock(&xw->priv->phy->pib_lock);
- if (xw->priv->phy->current_channel != xw->chan ||
- xw->priv->phy->current_page != xw->page) {
- res = xw->priv->ops->set_channel(&xw->priv->hw,
- xw->page,
- xw->chan);
- if (res) {
- pr_debug("set_channel failed\n");
- goto out;
- }
+ rtnl_lock();
- xw->priv->phy->current_channel = xw->chan;
- xw->priv->phy->current_page = xw->page;
- }
+ /* check if ifdown occurred while schedule */
+ if (!netif_running(dev))
+ goto err_tx;
- res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb);
+ res = drv_xmit_sync(local, skb);
if (res)
- pr_debug("transmission failed\n");
+ goto err_tx;
-out:
- mutex_unlock(&xw->priv->phy->pib_lock);
+ ieee802154_xmit_complete(&local->hw, skb);
- /* Restart the netif queue on each sub_if_data object. */
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &xw->priv->slaves, list)
- netif_wake_queue(sdata->dev);
- rcu_read_unlock();
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
- dev_kfree_skb(xw->skb);
+ rtnl_unlock();
- kfree(xw);
+ return;
+
+err_tx:
+ /* Restart the netif queue on each sub_if_data object. */
+ ieee802154_wake_queue(&local->hw);
+ rtnl_unlock();
+ kfree_skb(skb);
+ netdev_dbg(dev, "transmission failed\n");
}
-netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
- u8 page, u8 chan)
+static netdev_tx_t
+ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
{
- struct xmit_work *work;
- struct mac802154_sub_if_data *sdata;
-
- if (!(priv->phy->channels_supported[page] & (1 << chan))) {
- WARN_ON(1);
- goto err_tx;
- }
-
- mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
+ struct net_device *dev = skb->dev;
+ int ret;
- if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
+ if (!(local->hw.flags & IEEE802154_HW_TX_OMIT_CKSUM)) {
u16 crc = crc_ccitt(0, skb->data, skb->len);
- u8 *data = skb_put(skb, 2);
- data[0] = crc & 0xff;
- data[1] = crc >> 8;
+ put_unaligned_le16(crc, skb_put(skb, 2));
}
- if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
+ if (skb_cow_head(skb, local->hw.extra_tx_headroom))
goto err_tx;
- work = kzalloc(sizeof(*work), GFP_ATOMIC);
- if (!work) {
- kfree_skb(skb);
- return NETDEV_TX_BUSY;
- }
-
/* Stop the netif queue on each sub_if_data object. */
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &priv->slaves, list)
- netif_stop_queue(sdata->dev);
- rcu_read_unlock();
+ ieee802154_stop_queue(&local->hw);
+
+ /* async is priority, otherwise sync is fallback */
+ if (local->ops->xmit_async) {
+ ret = drv_xmit_async(local, skb);
+ if (ret) {
+ ieee802154_wake_queue(&local->hw);
+ goto err_tx;
+ }
- INIT_WORK(&work->work, mac802154_xmit_worker);
- work->skb = skb;
- work->priv = priv;
- work->page = page;
- work->chan = chan;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ } else {
+ INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker);
+ ieee802154_xmit_cb.skb = skb;
+ ieee802154_xmit_cb.local = local;
- queue_work(priv->dev_workqueue, &work->work);
+ queue_work(local->workqueue, &ieee802154_xmit_cb.work);
+ }
return NETDEV_TX_OK;
kfree_skb(skb);
return NETDEV_TX_OK;
}
+
+netdev_tx_t
+ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+ skb->skb_iif = dev->ifindex;
+
+ return ieee802154_tx(sdata->local, skb);
+}
+
+netdev_tx_t
+ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ int rc;
+
+ rc = mac802154_llsec_encrypt(&sdata->sec, skb);
+ if (rc) {
+ netdev_warn(dev, "encryption failed: %i\n", rc);
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ skb->skb_iif = dev->ifindex;
+
+ return ieee802154_tx(sdata->local, skb);
+}
--- /dev/null
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ *
+ * Based on: net/mac80211/util.c
+ */
+
+#include "ieee802154_i.h"
+
+void ieee802154_wake_queue(struct ieee802154_hw *hw)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+ struct ieee802154_sub_if_data *sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!sdata->dev)
+ continue;
+
+ netif_wake_queue(sdata->dev);
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_wake_queue);
+
+void ieee802154_stop_queue(struct ieee802154_hw *hw)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+ struct ieee802154_sub_if_data *sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!sdata->dev)
+ continue;
+
+ netif_stop_queue(sdata->dev);
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_stop_queue);
+
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+ ieee802154_wake_queue(hw);
+ consume_skb(skb);
+}
+EXPORT_SYMBOL(ieee802154_xmit_complete);
+++ /dev/null
-/*
- * Copyright 2007-2012 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Sergey Lapin <slapin@ossfans.org>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#include <linux/netdevice.h>
-#include <linux/module.h>
-#include <linux/if_arp.h>
-
-#include <net/rtnetlink.h>
-#include <linux/nl802154.h>
-#include <net/af_ieee802154.h>
-#include <net/mac802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ieee802154.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
-
-static int mac802154_wpan_update_llsec(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
- int rc = 0;
-
- if (ops->llsec) {
- struct ieee802154_llsec_params params;
- int changed = 0;
-
- params.pan_id = priv->pan_id;
- changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
-
- params.hwaddr = priv->extended_addr;
- changed |= IEEE802154_LLSEC_PARAM_HWADDR;
-
- rc = ops->llsec->set_params(dev, ¶ms, changed);
- }
-
- return rc;
-}
-
-static int
-mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct sockaddr_ieee802154 *sa =
- (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
- int err = -ENOIOCTLCMD;
-
- spin_lock_bh(&priv->mib_lock);
-
- switch (cmd) {
- case SIOCGIFADDR:
- {
- u16 pan_id, short_addr;
-
- pan_id = le16_to_cpu(priv->pan_id);
- short_addr = le16_to_cpu(priv->short_addr);
- if (pan_id == IEEE802154_PANID_BROADCAST ||
- short_addr == IEEE802154_ADDR_BROADCAST) {
- err = -EADDRNOTAVAIL;
- break;
- }
-
- sa->family = AF_IEEE802154;
- sa->addr.addr_type = IEEE802154_ADDR_SHORT;
- sa->addr.pan_id = pan_id;
- sa->addr.short_addr = short_addr;
-
- err = 0;
- break;
- }
- case SIOCSIFADDR:
- dev_warn(&dev->dev,
- "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
- if (sa->family != AF_IEEE802154 ||
- sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
- sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
- sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
- sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
- err = -EINVAL;
- break;
- }
-
- priv->pan_id = cpu_to_le16(sa->addr.pan_id);
- priv->short_addr = cpu_to_le16(sa->addr.short_addr);
-
- err = mac802154_wpan_update_llsec(dev);
- break;
- }
-
- spin_unlock_bh(&priv->mib_lock);
- return err;
-}
-
-static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
-
- if (netif_running(dev))
- return -EBUSY;
-
- /* FIXME: validate addr */
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- mac802154_dev_set_ieee_addr(dev);
- return mac802154_wpan_update_llsec(dev);
-}
-
-int mac802154_set_mac_params(struct net_device *dev,
- const struct ieee802154_mac_params *params)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
- mutex_lock(&priv->hw->slaves_mtx);
- priv->mac_params = *params;
- mutex_unlock(&priv->hw->slaves_mtx);
-
- return 0;
-}
-
-void mac802154_get_mac_params(struct net_device *dev,
- struct ieee802154_mac_params *params)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
- mutex_lock(&priv->hw->slaves_mtx);
- *params = priv->mac_params;
- mutex_unlock(&priv->hw->slaves_mtx);
-}
-
-static int mac802154_wpan_open(struct net_device *dev)
-{
- int rc;
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct wpan_phy *phy = priv->hw->phy;
-
- rc = mac802154_slave_open(dev);
- if (rc < 0)
- return rc;
-
- mutex_lock(&phy->pib_lock);
-
- if (phy->set_txpower) {
- rc = phy->set_txpower(phy, priv->mac_params.transmit_power);
- if (rc < 0)
- goto out;
- }
-
- if (phy->set_lbt) {
- rc = phy->set_lbt(phy, priv->mac_params.lbt);
- if (rc < 0)
- goto out;
- }
-
- if (phy->set_cca_mode) {
- rc = phy->set_cca_mode(phy, priv->mac_params.cca_mode);
- if (rc < 0)
- goto out;
- }
-
- if (phy->set_cca_ed_level) {
- rc = phy->set_cca_ed_level(phy, priv->mac_params.cca_ed_level);
- if (rc < 0)
- goto out;
- }
-
- if (phy->set_csma_params) {
- rc = phy->set_csma_params(phy, priv->mac_params.min_be,
- priv->mac_params.max_be,
- priv->mac_params.csma_retries);
- if (rc < 0)
- goto out;
- }
-
- if (phy->set_frame_retries) {
- rc = phy->set_frame_retries(phy,
- priv->mac_params.frame_retries);
- if (rc < 0)
- goto out;
- }
-
- mutex_unlock(&phy->pib_lock);
- return 0;
-
-out:
- mutex_unlock(&phy->pib_lock);
- return rc;
-}
-
-static int mac802154_set_header_security(struct mac802154_sub_if_data *priv,
- struct ieee802154_hdr *hdr,
- const struct ieee802154_mac_cb *cb)
-{
- struct ieee802154_llsec_params params;
- u8 level;
-
- mac802154_llsec_get_params(&priv->sec, ¶ms);
-
- if (!params.enabled && cb->secen_override && cb->secen)
- return -EINVAL;
- if (!params.enabled ||
- (cb->secen_override && !cb->secen) ||
- !params.out_level)
- return 0;
- if (cb->seclevel_override && !cb->seclevel)
- return -EINVAL;
-
- level = cb->seclevel_override ? cb->seclevel : params.out_level;
-
- hdr->fc.security_enabled = 1;
- hdr->sec.level = level;
- hdr->sec.key_id_mode = params.out_key.mode;
- if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
- hdr->sec.short_src = params.out_key.short_source;
- else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
- hdr->sec.extended_src = params.out_key.extended_source;
- hdr->sec.key_id = params.out_key.id;
-
- return 0;
-}
-
-static int mac802154_header_create(struct sk_buff *skb,
- struct net_device *dev,
- unsigned short type,
- const void *daddr,
- const void *saddr,
- unsigned len)
-{
- struct ieee802154_hdr hdr;
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
- struct ieee802154_mac_cb *cb = mac_cb(skb);
- int hlen;
-
- if (!daddr)
- return -EINVAL;
-
- memset(&hdr.fc, 0, sizeof(hdr.fc));
- hdr.fc.type = cb->type;
- hdr.fc.security_enabled = cb->secen;
- hdr.fc.ack_request = cb->ackreq;
- hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
-
- if (mac802154_set_header_security(priv, &hdr, cb) < 0)
- return -EINVAL;
-
- if (!saddr) {
- spin_lock_bh(&priv->mib_lock);
-
- if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
- priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
- priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
- hdr.source.mode = IEEE802154_ADDR_LONG;
- hdr.source.extended_addr = priv->extended_addr;
- } else {
- hdr.source.mode = IEEE802154_ADDR_SHORT;
- hdr.source.short_addr = priv->short_addr;
- }
-
- hdr.source.pan_id = priv->pan_id;
-
- spin_unlock_bh(&priv->mib_lock);
- } else {
- hdr.source = *(const struct ieee802154_addr *)saddr;
- }
-
- hdr.dest = *(const struct ieee802154_addr *)daddr;
-
- hlen = ieee802154_hdr_push(skb, &hdr);
- if (hlen < 0)
- return -EINVAL;
-
- skb_reset_mac_header(skb);
- skb->mac_len = hlen;
-
- if (len > ieee802154_max_payload(&hdr))
- return -EMSGSIZE;
-
- return hlen;
-}
-
-static int
-mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
-{
- struct ieee802154_hdr hdr;
- struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
-
- if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
- pr_debug("malformed packet\n");
- return 0;
- }
-
- *addr = hdr.source;
- return sizeof(*addr);
-}
-
-static netdev_tx_t
-mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv;
- u8 chan, page;
- int rc;
-
- priv = netdev_priv(dev);
-
- spin_lock_bh(&priv->mib_lock);
- chan = priv->chan;
- page = priv->page;
- spin_unlock_bh(&priv->mib_lock);
-
- if (chan == MAC802154_CHAN_NONE ||
- page >= WPAN_NUM_PAGES ||
- chan >= WPAN_NUM_CHANNELS) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- rc = mac802154_llsec_encrypt(&priv->sec, skb);
- if (rc) {
- pr_warn("encryption failed: %i\n", rc);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- skb->skb_iif = dev->ifindex;
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
-
- return mac802154_tx(priv->hw, skb, page, chan);
-}
-
-static struct header_ops mac802154_header_ops = {
- .create = mac802154_header_create,
- .parse = mac802154_header_parse,
-};
-
-static const struct net_device_ops mac802154_wpan_ops = {
- .ndo_open = mac802154_wpan_open,
- .ndo_stop = mac802154_slave_close,
- .ndo_start_xmit = mac802154_wpan_xmit,
- .ndo_do_ioctl = mac802154_wpan_ioctl,
- .ndo_set_mac_address = mac802154_wpan_mac_addr,
-};
-
-static void mac802154_wpan_free(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
- mac802154_llsec_destroy(&priv->sec);
-
- free_netdev(dev);
-}
-
-void mac802154_wpan_setup(struct net_device *dev)
-{
- struct mac802154_sub_if_data *priv;
-
- dev->addr_len = IEEE802154_ADDR_LEN;
- memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
-
- dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
- dev->header_ops = &mac802154_header_ops;
- dev->needed_tailroom = 2 + 16; /* FCS + MIC */
- dev->mtu = IEEE802154_MTU;
- dev->tx_queue_len = 300;
- dev->type = ARPHRD_IEEE802154;
- dev->flags = IFF_NOARP | IFF_BROADCAST;
- dev->watchdog_timeo = 0;
-
- dev->destructor = mac802154_wpan_free;
- dev->netdev_ops = &mac802154_wpan_ops;
- dev->ml_priv = &mac802154_mlme_wpan;
-
- priv = netdev_priv(dev);
- priv->type = IEEE802154_DEV_WPAN;
-
- priv->chan = MAC802154_CHAN_NONE;
- priv->page = 0;
-
- spin_lock_init(&priv->mib_lock);
- mutex_init(&priv->sec_mtx);
-
- get_random_bytes(&priv->bsn, 1);
- get_random_bytes(&priv->dsn, 1);
-
- /* defaults per 802.15.4-2011 */
- priv->mac_params.min_be = 3;
- priv->mac_params.max_be = 5;
- priv->mac_params.csma_retries = 4;
- priv->mac_params.frame_retries = -1; /* for compatibility, actual default is 3 */
-
- priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
- priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
-
- mac802154_llsec_init(&priv->sec);
-}
-
-static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
-{
- return netif_rx_ni(skb);
-}
-
-static int
-mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
- const struct ieee802154_hdr *hdr)
-{
- __le16 span, sshort;
- int rc;
-
- pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
-
- spin_lock_bh(&sdata->mib_lock);
-
- span = sdata->pan_id;
- sshort = sdata->short_addr;
-
- switch (mac_cb(skb)->dest.mode) {
- case IEEE802154_ADDR_NONE:
- if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
- /* FIXME: check if we are PAN coordinator */
- skb->pkt_type = PACKET_OTHERHOST;
- else
- /* ACK comes with both addresses empty */
- skb->pkt_type = PACKET_HOST;
- break;
- case IEEE802154_ADDR_LONG:
- if (mac_cb(skb)->dest.pan_id != span &&
- mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
- skb->pkt_type = PACKET_OTHERHOST;
- else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
- skb->pkt_type = PACKET_HOST;
- else
- skb->pkt_type = PACKET_OTHERHOST;
- break;
- case IEEE802154_ADDR_SHORT:
- if (mac_cb(skb)->dest.pan_id != span &&
- mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
- skb->pkt_type = PACKET_OTHERHOST;
- else if (mac_cb(skb)->dest.short_addr == sshort)
- skb->pkt_type = PACKET_HOST;
- else if (mac_cb(skb)->dest.short_addr ==
- cpu_to_le16(IEEE802154_ADDR_BROADCAST))
- skb->pkt_type = PACKET_BROADCAST;
- else
- skb->pkt_type = PACKET_OTHERHOST;
- break;
- default:
- spin_unlock_bh(&sdata->mib_lock);
- pr_debug("invalid dest mode\n");
- kfree_skb(skb);
- return NET_RX_DROP;
- }
-
- spin_unlock_bh(&sdata->mib_lock);
-
- skb->dev = sdata->dev;
-
- rc = mac802154_llsec_decrypt(&sdata->sec, skb);
- if (rc) {
- pr_debug("decryption failed: %i\n", rc);
- goto fail;
- }
-
- sdata->dev->stats.rx_packets++;
- sdata->dev->stats.rx_bytes += skb->len;
-
- switch (mac_cb(skb)->type) {
- case IEEE802154_FC_TYPE_DATA:
- return mac802154_process_data(sdata->dev, skb);
- default:
- pr_warn("ieee802154: bad frame received (type = %d)\n",
- mac_cb(skb)->type);
- goto fail;
- }
-
-fail:
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-static void mac802154_print_addr(const char *name,
- const struct ieee802154_addr *addr)
-{
- if (addr->mode == IEEE802154_ADDR_NONE)
- pr_debug("%s not present\n", name);
-
- pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
- if (addr->mode == IEEE802154_ADDR_SHORT) {
- pr_debug("%s is short: %04x\n", name,
- le16_to_cpu(addr->short_addr));
- } else {
- u64 hw = swab64((__force u64) addr->extended_addr);
-
- pr_debug("%s is hardware: %8phC\n", name, &hw);
- }
-}
-
-static int mac802154_parse_frame_start(struct sk_buff *skb,
- struct ieee802154_hdr *hdr)
-{
- int hlen;
- struct ieee802154_mac_cb *cb = mac_cb_init(skb);
-
- hlen = ieee802154_hdr_pull(skb, hdr);
- if (hlen < 0)
- return -EINVAL;
-
- skb->mac_len = hlen;
-
- pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
- hdr->seq);
-
- cb->type = hdr->fc.type;
- cb->ackreq = hdr->fc.ack_request;
- cb->secen = hdr->fc.security_enabled;
-
- mac802154_print_addr("destination", &hdr->dest);
- mac802154_print_addr("source", &hdr->source);
-
- cb->source = hdr->source;
- cb->dest = hdr->dest;
-
- if (hdr->fc.security_enabled) {
- u64 key;
-
- pr_debug("seclevel %i\n", hdr->sec.level);
-
- switch (hdr->sec.key_id_mode) {
- case IEEE802154_SCF_KEY_IMPLICIT:
- pr_debug("implicit key\n");
- break;
-
- case IEEE802154_SCF_KEY_INDEX:
- pr_debug("key %02x\n", hdr->sec.key_id);
- break;
-
- case IEEE802154_SCF_KEY_SHORT_INDEX:
- pr_debug("key %04x:%04x %02x\n",
- le32_to_cpu(hdr->sec.short_src) >> 16,
- le32_to_cpu(hdr->sec.short_src) & 0xffff,
- hdr->sec.key_id);
- break;
-
- case IEEE802154_SCF_KEY_HW_INDEX:
- key = swab64((__force u64) hdr->sec.extended_src);
- pr_debug("key source %8phC %02x\n", &key,
- hdr->sec.key_id);
- break;
- }
- }
-
- return 0;
-}
-
-void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
-{
- int ret;
- struct mac802154_sub_if_data *sdata;
- struct ieee802154_hdr hdr;
-
- ret = mac802154_parse_frame_start(skb, &hdr);
- if (ret) {
- pr_debug("got invalid frame\n");
- kfree_skb(skb);
- return;
- }
-
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &priv->slaves, list) {
- if (sdata->type != IEEE802154_DEV_WPAN ||
- !netif_running(sdata->dev))
- continue;
-
- mac802154_subif_frame(sdata, skb, &hdr);
- skb = NULL;
- break;
- }
- rcu_read_unlock();
-
- if (skb)
- kfree_skb(skb);
-}
SKB_GSO_TCP_ECN |
SKB_GSO_GRE |
SKB_GSO_GRE_CSUM |
- SKB_GSO_IPIP |
- SKB_GSO_MPLS)))
+ SKB_GSO_IPIP)))
goto out;
/* Setup inner SKB. */
if (set->flags & NFT_SET_MAP)
nft_data_copy(he->data, &elem->data);
- rhashtable_insert(priv, &he->node, GFP_KERNEL);
+ rhashtable_insert(priv, &he->node);
return 0;
}
pprev = elem->cookie;
he = rht_dereference((*pprev), priv);
- rhashtable_remove_pprev(priv, he, pprev, GFP_KERNEL);
+ rhashtable_remove_pprev(priv, he, pprev);
synchronize_rcu();
kfree(he);
return sizeof(struct rhashtable);
}
-static int lockdep_nfnl_lock_is_held(void)
+#ifdef CONFIG_PROVE_LOCKING
+static int lockdep_nfnl_lock_is_held(void *parent)
{
return lockdep_nfnl_is_held(NFNL_SUBSYS_NFTABLES);
}
+#endif
static int nft_hash_init(const struct nft_set *set,
const struct nft_set_desc *desc,
.hashfn = jhash,
.grow_decision = rht_grow_above_75,
.shrink_decision = rht_shrink_below_30,
+#ifdef CONFIG_PROVE_LOCKING
.mutex_is_held = lockdep_nfnl_lock_is_held,
+#endif
};
return rhashtable_init(priv, ¶ms);
DEFINE_MUTEX(nl_sk_hash_lock);
EXPORT_SYMBOL_GPL(nl_sk_hash_lock);
-static int lockdep_nl_sk_hash_is_held(void)
+#ifdef CONFIG_PROVE_LOCKING
+static int lockdep_nl_sk_hash_is_held(void *parent)
{
-#ifdef CONFIG_LOCKDEP
if (debug_locks)
return lockdep_is_held(&nl_sk_hash_lock) || lockdep_is_held(&nl_table_lock);
-#endif
return 1;
}
+#endif
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
nlk_sk(sk)->portid = portid;
sock_hold(sk);
- rhashtable_insert(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL);
+ rhashtable_insert(&table->hash, &nlk_sk(sk)->node);
err = 0;
err:
mutex_unlock(&nl_sk_hash_lock);
mutex_lock(&nl_sk_hash_lock);
table = &nl_table[sk->sk_protocol];
- if (rhashtable_remove(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL)) {
+ if (rhashtable_remove(&table->hash, &nlk_sk(sk)->node)) {
WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
}
skb_reset_transport_header(data_skb);
- err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(data_skb, 0, msg, copied);
if (msg->msg_name) {
DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
.max_shift = 16, /* 64K */
.grow_decision = rht_grow_above_75,
.shrink_decision = rht_shrink_below_30,
+#ifdef CONFIG_PROVE_LOCKING
.mutex_is_held = lockdep_nl_sk_hash_is_held,
+#endif
};
if (err != 0)
msg->msg_flags |= MSG_TRUNC;
}
- er = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ er = skb_copy_datagram_msg(skb, 0, msg, copied);
if (er < 0) {
skb_free_datagram(sk, skb);
release_sock(sk);
copied = min_t(unsigned int, rlen, len);
cskb = skb;
- if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
+ if (skb_copy_datagram_msg(cskb, 0, msg, copied)) {
if (!(flags & MSG_PEEK))
skb_queue_head(&sk->sk_receive_queue, skb);
return -EFAULT;
copied = len;
}
- rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ rc = skb_copy_datagram_msg(skb, 0, msg, copied);
skb_free_datagram(sk, skb);
If unsure, say N.
config OPENVSWITCH_GRE
- bool "Open vSwitch GRE tunneling support"
+ tristate "Open vSwitch GRE tunneling support"
+ select NET_MPLS_GSO
depends on INET
depends on OPENVSWITCH
- depends on NET_IPGRE_DEMUX && !(OPENVSWITCH=y && NET_IPGRE_DEMUX=m)
- default y
+ depends on NET_IPGRE_DEMUX
+ default OPENVSWITCH
---help---
If you say Y here, then the Open vSwitch will be able create GRE
vport.
If unsure, say Y.
config OPENVSWITCH_VXLAN
- bool "Open vSwitch VXLAN tunneling support"
+ tristate "Open vSwitch VXLAN tunneling support"
depends on INET
depends on OPENVSWITCH
- depends on VXLAN && !(OPENVSWITCH=y && VXLAN=m)
- default y
+ depends on VXLAN
+ default OPENVSWITCH
---help---
If you say Y here, then the Open vSwitch will be able create vxlan vport.
If unsure, say Y.
config OPENVSWITCH_GENEVE
- bool "Open vSwitch Geneve tunneling support"
+ tristate "Open vSwitch Geneve tunneling support"
depends on INET
depends on OPENVSWITCH
- depends on GENEVE && !(OPENVSWITCH=y && GENEVE=m)
- default y
+ depends on GENEVE
+ default OPENVSWITCH
---help---
If you say Y here, then the Open vSwitch will be able create geneve vport.
vport-internal_dev.o \
vport-netdev.o
-ifneq ($(CONFIG_OPENVSWITCH_GENEVE),)
-openvswitch-y += vport-geneve.o
-endif
-
-ifneq ($(CONFIG_OPENVSWITCH_VXLAN),)
-openvswitch-y += vport-vxlan.o
-endif
-
-ifneq ($(CONFIG_OPENVSWITCH_GRE),)
-openvswitch-y += vport-gre.o
-endif
+obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o
+obj-$(CONFIG_OPENVSWITCH_VXLAN) += vport-vxlan.o
+obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o
#include <linux/in6.h>
#include <linux/if_arp.h>
#include <linux/if_vlan.h>
+
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/checksum.h>
#include <net/dsfield.h>
+#include <net/mpls.h>
#include <net/sctp/checksum.h>
#include "datapath.h"
fifo->tail = 0;
}
-static bool action_fifo_is_empty(struct action_fifo *fifo)
+static bool action_fifo_is_empty(const struct action_fifo *fifo)
{
return (fifo->head == fifo->tail);
}
/* Return true if fifo is not full */
static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
- struct sw_flow_key *key,
+ const struct sw_flow_key *key,
const struct nlattr *attr)
{
struct action_fifo *fifo;
return da;
}
+static void invalidate_flow_key(struct sw_flow_key *key)
+{
+ key->eth.type = htons(0);
+}
+
+static bool is_flow_key_valid(const struct sw_flow_key *key)
+{
+ return !!key->eth.type;
+}
+
static int make_writable(struct sk_buff *skb, int write_len)
{
if (!pskb_may_pull(skb, write_len))
return pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
}
+static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_action_push_mpls *mpls)
+{
+ __be32 *new_mpls_lse;
+ struct ethhdr *hdr;
+
+ /* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */
+ if (skb->encapsulation)
+ return -ENOTSUPP;
+
+ if (skb_cow_head(skb, MPLS_HLEN) < 0)
+ return -ENOMEM;
+
+ skb_push(skb, MPLS_HLEN);
+ memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb),
+ skb->mac_len);
+ skb_reset_mac_header(skb);
+
+ new_mpls_lse = (__be32 *)skb_mpls_header(skb);
+ *new_mpls_lse = mpls->mpls_lse;
+
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_add(skb->csum, csum_partial(new_mpls_lse,
+ MPLS_HLEN, 0));
+
+ hdr = eth_hdr(skb);
+ hdr->h_proto = mpls->mpls_ethertype;
+
+ skb_set_inner_protocol(skb, skb->protocol);
+ skb->protocol = mpls->mpls_ethertype;
+
+ invalidate_flow_key(key);
+ return 0;
+}
+
+static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
+ const __be16 ethertype)
+{
+ struct ethhdr *hdr;
+ int err;
+
+ err = make_writable(skb, skb->mac_len + MPLS_HLEN);
+ if (unlikely(err))
+ return err;
+
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_sub(skb->csum,
+ csum_partial(skb_mpls_header(skb),
+ MPLS_HLEN, 0));
+
+ memmove(skb_mac_header(skb) + MPLS_HLEN, skb_mac_header(skb),
+ skb->mac_len);
+
+ __skb_pull(skb, MPLS_HLEN);
+ skb_reset_mac_header(skb);
+
+ /* skb_mpls_header() is used to locate the ethertype
+ * field correctly in the presence of VLAN tags.
+ */
+ hdr = (struct ethhdr *)(skb_mpls_header(skb) - ETH_HLEN);
+ hdr->h_proto = ethertype;
+ if (eth_p_mpls(skb->protocol))
+ skb->protocol = ethertype;
+
+ invalidate_flow_key(key);
+ return 0;
+}
+
+static int set_mpls(struct sk_buff *skb, struct sw_flow_key *key,
+ const __be32 *mpls_lse)
+{
+ __be32 *stack;
+ int err;
+
+ err = make_writable(skb, skb->mac_len + MPLS_HLEN);
+ if (unlikely(err))
+ return err;
+
+ stack = (__be32 *)skb_mpls_header(skb);
+ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ __be32 diff[] = { ~(*stack), *mpls_lse };
+ skb->csum = ~csum_partial((char *)diff, sizeof(diff),
+ ~skb->csum);
+ }
+
+ *stack = *mpls_lse;
+ key->mpls.top_lse = *mpls_lse;
+ return 0;
+}
+
/* remove VLAN header from packet and update csum accordingly. */
static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
{
vlan_set_encap_proto(skb, vhdr);
skb->mac_header += VLAN_HLEN;
+
if (skb_network_offset(skb) < ETH_HLEN)
skb_set_network_header(skb, ETH_HLEN);
- skb_reset_mac_len(skb);
+ /* Update mac_len for subsequent MPLS actions */
+ skb_reset_mac_len(skb);
return 0;
}
-static int pop_vlan(struct sk_buff *skb)
+static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
{
__be16 tci;
int err;
}
/* move next vlan tag to hw accel tag */
if (likely(skb->protocol != htons(ETH_P_8021Q) ||
- skb->len < VLAN_ETH_HLEN))
+ skb->len < VLAN_ETH_HLEN)) {
+ key->eth.tci = 0;
return 0;
+ }
+ invalidate_flow_key(key);
err = __pop_vlan_tci(skb, &tci);
if (unlikely(err))
return err;
return 0;
}
-static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vlan)
+static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_action_push_vlan *vlan)
{
if (unlikely(vlan_tx_tag_present(skb))) {
u16 current_tag;
if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag))
return -ENOMEM;
+ /* Update mac_len for subsequent MPLS actions */
+ skb->mac_len += VLAN_HLEN;
if (skb->ip_summed == CHECKSUM_COMPLETE)
skb->csum = csum_add(skb->csum, csum_partial(skb->data
+ (2 * ETH_ALEN), VLAN_HLEN, 0));
+ invalidate_flow_key(key);
+ } else {
+ key->eth.tci = vlan->vlan_tci;
}
__vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
return 0;
}
-static int set_eth_addr(struct sk_buff *skb,
+static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_key_ethernet *eth_key)
{
int err;
ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
+ ether_addr_copy(key->eth.src, eth_key->eth_src);
+ ether_addr_copy(key->eth.dst, eth_key->eth_dst);
return 0;
}
static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
- __be32 *addr, __be32 new_addr)
+ __be32 *addr, __be32 new_addr)
{
int transport_len = skb->len - skb_transport_offset(skb);
nh->ttl = new_ttl;
}
-static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
+static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_key_ipv4 *ipv4_key)
{
struct iphdr *nh;
int err;
nh = ip_hdr(skb);
- if (ipv4_key->ipv4_src != nh->saddr)
+ if (ipv4_key->ipv4_src != nh->saddr) {
set_ip_addr(skb, nh, &nh->saddr, ipv4_key->ipv4_src);
+ key->ipv4.addr.src = ipv4_key->ipv4_src;
+ }
- if (ipv4_key->ipv4_dst != nh->daddr)
+ if (ipv4_key->ipv4_dst != nh->daddr) {
set_ip_addr(skb, nh, &nh->daddr, ipv4_key->ipv4_dst);
+ key->ipv4.addr.dst = ipv4_key->ipv4_dst;
+ }
- if (ipv4_key->ipv4_tos != nh->tos)
+ if (ipv4_key->ipv4_tos != nh->tos) {
ipv4_change_dsfield(nh, 0, ipv4_key->ipv4_tos);
+ key->ip.tos = nh->tos;
+ }
- if (ipv4_key->ipv4_ttl != nh->ttl)
+ if (ipv4_key->ipv4_ttl != nh->ttl) {
set_ip_ttl(skb, nh, ipv4_key->ipv4_ttl);
+ key->ip.ttl = ipv4_key->ipv4_ttl;
+ }
return 0;
}
-static int set_ipv6(struct sk_buff *skb, const struct ovs_key_ipv6 *ipv6_key)
+static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_key_ipv6 *ipv6_key)
{
struct ipv6hdr *nh;
int err;
saddr = (__be32 *)&nh->saddr;
daddr = (__be32 *)&nh->daddr;
- if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src)))
+ if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src))) {
set_ipv6_addr(skb, ipv6_key->ipv6_proto, saddr,
ipv6_key->ipv6_src, true);
+ memcpy(&key->ipv6.addr.src, ipv6_key->ipv6_src,
+ sizeof(ipv6_key->ipv6_src));
+ }
if (memcmp(ipv6_key->ipv6_dst, daddr, sizeof(ipv6_key->ipv6_dst))) {
unsigned int offset = 0;
set_ipv6_addr(skb, ipv6_key->ipv6_proto, daddr,
ipv6_key->ipv6_dst, recalc_csum);
+ memcpy(&key->ipv6.addr.dst, ipv6_key->ipv6_dst,
+ sizeof(ipv6_key->ipv6_dst));
}
set_ipv6_tc(nh, ipv6_key->ipv6_tclass);
+ key->ip.tos = ipv6_get_dsfield(nh);
+
set_ipv6_fl(nh, ntohl(ipv6_key->ipv6_label));
- nh->hop_limit = ipv6_key->ipv6_hlimit;
+ key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
+ nh->hop_limit = ipv6_key->ipv6_hlimit;
+ key->ip.ttl = ipv6_key->ipv6_hlimit;
return 0;
}
}
}
-static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key)
+static int set_udp(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_key_udp *udp_port_key)
{
struct udphdr *uh;
int err;
return err;
uh = udp_hdr(skb);
- if (udp_port_key->udp_src != uh->source)
+ if (udp_port_key->udp_src != uh->source) {
set_udp_port(skb, &uh->source, udp_port_key->udp_src);
+ key->tp.src = udp_port_key->udp_src;
+ }
- if (udp_port_key->udp_dst != uh->dest)
+ if (udp_port_key->udp_dst != uh->dest) {
set_udp_port(skb, &uh->dest, udp_port_key->udp_dst);
+ key->tp.dst = udp_port_key->udp_dst;
+ }
return 0;
}
-static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key)
+static int set_tcp(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_key_tcp *tcp_port_key)
{
struct tcphdr *th;
int err;
return err;
th = tcp_hdr(skb);
- if (tcp_port_key->tcp_src != th->source)
+ if (tcp_port_key->tcp_src != th->source) {
set_tp_port(skb, &th->source, tcp_port_key->tcp_src, &th->check);
+ key->tp.src = tcp_port_key->tcp_src;
+ }
- if (tcp_port_key->tcp_dst != th->dest)
+ if (tcp_port_key->tcp_dst != th->dest) {
set_tp_port(skb, &th->dest, tcp_port_key->tcp_dst, &th->check);
+ key->tp.dst = tcp_port_key->tcp_dst;
+ }
return 0;
}
-static int set_sctp(struct sk_buff *skb,
- const struct ovs_key_sctp *sctp_port_key)
+static int set_sctp(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct ovs_key_sctp *sctp_port_key)
{
struct sctphdr *sh;
int err;
sh->checksum = old_csum ^ old_correct_csum ^ new_csum;
skb_clear_hash(skb);
+ key->tp.src = sctp_port_key->sctp_src;
+ key->tp.dst = sctp_port_key->sctp_dst;
}
return 0;
}
-static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
+static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
{
- struct vport *vport;
-
- if (unlikely(!skb))
- return -ENOMEM;
+ struct vport *vport = ovs_vport_rcu(dp, out_port);
- vport = ovs_vport_rcu(dp, out_port);
- if (unlikely(!vport)) {
+ if (likely(vport))
+ ovs_vport_send(vport, skb);
+ else
kfree_skb(skb);
- return -ENODEV;
- }
-
- ovs_vport_send(vport, skb);
- return 0;
}
static int output_userspace(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key, const struct nlattr *attr)
{
+ struct ovs_tunnel_info info;
struct dp_upcall_info upcall;
const struct nlattr *a;
int rem;
upcall.cmd = OVS_PACKET_CMD_ACTION;
- upcall.key = key;
upcall.userdata = NULL;
upcall.portid = 0;
+ upcall.egress_tun_info = NULL;
for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
a = nla_next(a, &rem)) {
case OVS_USERSPACE_ATTR_PID:
upcall.portid = nla_get_u32(a);
break;
+
+ case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: {
+ /* Get out tunnel info. */
+ struct vport *vport;
+
+ vport = ovs_vport_rcu(dp, nla_get_u32(a));
+ if (vport) {
+ int err;
+
+ err = ovs_vport_get_egress_tun_info(vport, skb,
+ &info);
+ if (!err)
+ upcall.egress_tun_info = &info;
+ }
+ break;
}
- }
- return ovs_dp_upcall(dp, skb, &upcall);
-}
+ } /* End of switch. */
+ }
-static bool last_action(const struct nlattr *a, int rem)
-{
- return a->nla_len == rem;
+ return ovs_dp_upcall(dp, skb, key, &upcall);
}
static int sample(struct datapath *dp, struct sk_buff *skb,
* user space. This skb will be consumed by its caller.
*/
if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE &&
- last_action(a, rem)))
+ nla_is_last(a, rem)))
return output_userspace(dp, skb, key, a);
skb = skb_clone(skb, GFP_ATOMIC);
key->ovs_flow_hash = hash;
}
-static int execute_set_action(struct sk_buff *skb,
- const struct nlattr *nested_attr)
+static int execute_set_action(struct sk_buff *skb, struct sw_flow_key *key,
+ const struct nlattr *nested_attr)
{
int err = 0;
switch (nla_type(nested_attr)) {
case OVS_KEY_ATTR_PRIORITY:
skb->priority = nla_get_u32(nested_attr);
+ key->phy.priority = skb->priority;
break;
case OVS_KEY_ATTR_SKB_MARK:
skb->mark = nla_get_u32(nested_attr);
+ key->phy.skb_mark = skb->mark;
break;
case OVS_KEY_ATTR_TUNNEL_INFO:
break;
case OVS_KEY_ATTR_ETHERNET:
- err = set_eth_addr(skb, nla_data(nested_attr));
+ err = set_eth_addr(skb, key, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_IPV4:
- err = set_ipv4(skb, nla_data(nested_attr));
+ err = set_ipv4(skb, key, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_IPV6:
- err = set_ipv6(skb, nla_data(nested_attr));
+ err = set_ipv6(skb, key, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_TCP:
- err = set_tcp(skb, nla_data(nested_attr));
+ err = set_tcp(skb, key, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_UDP:
- err = set_udp(skb, nla_data(nested_attr));
+ err = set_udp(skb, key, nla_data(nested_attr));
break;
case OVS_KEY_ATTR_SCTP:
- err = set_sctp(skb, nla_data(nested_attr));
+ err = set_sctp(skb, key, nla_data(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_MPLS:
+ err = set_mpls(skb, key, nla_data(nested_attr));
break;
}
const struct nlattr *a, int rem)
{
struct deferred_action *da;
- int err;
- err = ovs_flow_key_update(skb, key);
- if (err)
- return err;
+ if (!is_flow_key_valid(key)) {
+ int err;
- if (!last_action(a, rem)) {
+ err = ovs_flow_key_update(skb, key);
+ if (err)
+ return err;
+ }
+ BUG_ON(!is_flow_key_valid(key));
+
+ if (!nla_is_last(a, rem)) {
/* Recirc action is the not the last action
* of the action list, need to clone the skb.
*/
/* Every output action needs a separate clone of 'skb', but the common
* case is just a single output action, so that doing a clone and
* then freeing the original skbuff is wasteful. So the following code
- * is slightly obscure just to avoid that. */
+ * is slightly obscure just to avoid that.
+ */
int prev_port = -1;
const struct nlattr *a;
int rem;
a = nla_next(a, &rem)) {
int err = 0;
- if (prev_port != -1) {
- do_output(dp, skb_clone(skb, GFP_ATOMIC), prev_port);
+ if (unlikely(prev_port != -1)) {
+ struct sk_buff *out_skb = skb_clone(skb, GFP_ATOMIC);
+
+ if (out_skb)
+ do_output(dp, out_skb, prev_port);
+
prev_port = -1;
}
execute_hash(skb, key, a);
break;
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ err = push_mpls(skb, key, nla_data(a));
+ break;
+
+ case OVS_ACTION_ATTR_POP_MPLS:
+ err = pop_mpls(skb, key, nla_get_be16(a));
+ break;
+
case OVS_ACTION_ATTR_PUSH_VLAN:
- err = push_vlan(skb, nla_data(a));
+ err = push_vlan(skb, key, nla_data(a));
if (unlikely(err)) /* skb already freed. */
return err;
break;
case OVS_ACTION_ATTR_POP_VLAN:
- err = pop_vlan(skb);
+ err = pop_vlan(skb, key);
break;
case OVS_ACTION_ATTR_RECIRC:
err = execute_recirc(dp, skb, key, a, rem);
- if (last_action(a, rem)) {
+ if (nla_is_last(a, rem)) {
/* If this is the last action, the skb has
* been consumed or freed.
* Return immediately.
break;
case OVS_ACTION_ATTR_SET:
- err = execute_set_action(skb, nla_data(a));
+ err = execute_set_action(skb, key, nla_data(a));
break;
case OVS_ACTION_ATTR_SAMPLE:
/* Execute a list of actions against 'skb'. */
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_actions *acts,
struct sw_flow_key *key)
{
int level = this_cpu_read(exec_actions_level);
- struct sw_flow_actions *acts;
int err;
- acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
-
this_cpu_inc(exec_actions_level);
OVS_CB(skb)->egress_tun_info = NULL;
err = do_execute_actions(dp, skb, key,
#include "vport-netdev.h"
int ovs_net_id __read_mostly;
+EXPORT_SYMBOL_GPL(ovs_net_id);
static struct genl_family dp_packet_genl_family;
static struct genl_family dp_flow_genl_family;
else
return 1;
}
+EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held);
#endif
static struct vport *new_vport(const struct vport_parms *);
static int queue_gso_packets(struct datapath *dp, struct sk_buff *,
+ const struct sw_flow_key *,
const struct dp_upcall_info *);
static int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
+ const struct sw_flow_key *,
const struct dp_upcall_info *);
-/* Must be called with rcu_read_lock or ovs_mutex. */
-static struct datapath *get_dp(struct net *net, int dp_ifindex)
+/* Must be called with rcu_read_lock. */
+static struct datapath *get_dp_rcu(struct net *net, int dp_ifindex)
{
- struct datapath *dp = NULL;
- struct net_device *dev;
+ struct net_device *dev = dev_get_by_index_rcu(net, dp_ifindex);
- rcu_read_lock();
- dev = dev_get_by_index_rcu(net, dp_ifindex);
if (dev) {
struct vport *vport = ovs_internal_dev_get_vport(dev);
if (vport)
- dp = vport->dp;
+ return vport->dp;
}
+
+ return NULL;
+}
+
+/* The caller must hold either ovs_mutex or rcu_read_lock to keep the
+ * returned dp pointer valid.
+ */
+static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
+{
+ struct datapath *dp;
+
+ WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_ovsl_is_held());
+ rcu_read_lock();
+ dp = get_dp_rcu(net, dp_ifindex);
rcu_read_unlock();
return dp;
return vport->ops->get_name(vport);
}
-static int get_dpifindex(struct datapath *dp)
+static int get_dpifindex(const struct datapath *dp)
{
struct vport *local;
int ifindex;
{
struct datapath *dp = container_of(rcu, struct datapath, rcu);
+ ovs_flow_tbl_destroy(&dp->table);
free_percpu(dp->stats_percpu);
release_net(ovs_dp_get_net(dp));
kfree(dp->ports);
const struct vport *p = OVS_CB(skb)->input_vport;
struct datapath *dp = p->dp;
struct sw_flow *flow;
+ struct sw_flow_actions *sf_acts;
struct dp_stats_percpu *stats;
u64 *stats_counter;
u32 n_mask_hit;
int error;
upcall.cmd = OVS_PACKET_CMD_MISS;
- upcall.key = key;
upcall.userdata = NULL;
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
- error = ovs_dp_upcall(dp, skb, &upcall);
+ upcall.egress_tun_info = NULL;
+ error = ovs_dp_upcall(dp, skb, key, &upcall);
if (unlikely(error))
kfree_skb(skb);
else
goto out;
}
- OVS_CB(skb)->flow = flow;
+ ovs_flow_stats_update(flow, key->tp.flags, skb);
+ sf_acts = rcu_dereference(flow->sf_acts);
+ ovs_execute_actions(dp, skb, sf_acts, key);
- ovs_flow_stats_update(OVS_CB(skb)->flow, key->tp.flags, skb);
- ovs_execute_actions(dp, skb, key);
stats_counter = &stats->n_hit;
out:
}
int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
const struct dp_upcall_info *upcall_info)
{
struct dp_stats_percpu *stats;
}
if (!skb_is_gso(skb))
- err = queue_userspace_packet(dp, skb, upcall_info);
+ err = queue_userspace_packet(dp, skb, key, upcall_info);
else
- err = queue_gso_packets(dp, skb, upcall_info);
+ err = queue_gso_packets(dp, skb, key, upcall_info);
if (err)
goto err;
}
static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
const struct dp_upcall_info *upcall_info)
{
unsigned short gso_type = skb_shinfo(skb)->gso_type;
- struct dp_upcall_info later_info;
struct sw_flow_key later_key;
struct sk_buff *segs, *nskb;
+ struct ovs_skb_cb ovs_cb;
int err;
+ ovs_cb = *OVS_CB(skb);
segs = __skb_gso_segment(skb, NETIF_F_SG, false);
+ *OVS_CB(skb) = ovs_cb;
if (IS_ERR(segs))
return PTR_ERR(segs);
if (segs == NULL)
return -EINVAL;
+ if (gso_type & SKB_GSO_UDP) {
+ /* The initial flow key extracted by ovs_flow_key_extract()
+ * in this case is for a first fragment, so we need to
+ * properly mark later fragments.
+ */
+ later_key = *key;
+ later_key.ip.frag = OVS_FRAG_TYPE_LATER;
+ }
+
/* Queue all of the segments. */
skb = segs;
do {
- err = queue_userspace_packet(dp, skb, upcall_info);
+ *OVS_CB(skb) = ovs_cb;
+ if (gso_type & SKB_GSO_UDP && skb != segs)
+ key = &later_key;
+
+ err = queue_userspace_packet(dp, skb, key, upcall_info);
if (err)
break;
- if (skb == segs && gso_type & SKB_GSO_UDP) {
- /* The initial flow key extracted by ovs_flow_extract()
- * in this case is for a first fragment, so we need to
- * properly mark later fragments.
- */
- later_key = *upcall_info->key;
- later_key.ip.frag = OVS_FRAG_TYPE_LATER;
-
- later_info = *upcall_info;
- later_info.key = &later_key;
- upcall_info = &later_info;
- }
} while ((skb = skb->next));
/* Free all of the segments. */
return err;
}
-static size_t key_attr_size(void)
-{
- return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
- + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
- + nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
- + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
- + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
- + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
- + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
- + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
- + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
- + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
- + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
- + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
- + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
- + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
- + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
- + nla_total_size(4) /* OVS_KEY_ATTR_8021Q */
- + nla_total_size(0) /* OVS_KEY_ATTR_ENCAP */
- + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
- + nla_total_size(40) /* OVS_KEY_ATTR_IPV6 */
- + nla_total_size(2) /* OVS_KEY_ATTR_ICMPV6 */
- + nla_total_size(28); /* OVS_KEY_ATTR_ND */
-}
-
-static size_t upcall_msg_size(const struct nlattr *userdata,
+static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
unsigned int hdrlen)
{
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
- + nla_total_size(key_attr_size()); /* OVS_PACKET_ATTR_KEY */
+ + nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */
/* OVS_PACKET_ATTR_USERDATA */
- if (userdata)
- size += NLA_ALIGN(userdata->nla_len);
+ if (upcall_info->userdata)
+ size += NLA_ALIGN(upcall_info->userdata->nla_len);
+
+ /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
+ if (upcall_info->egress_tun_info)
+ size += nla_total_size(ovs_tun_key_attr_size());
return size;
}
static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
const struct dp_upcall_info *upcall_info)
{
struct ovs_header *upcall;
else
hlen = skb->len;
- len = upcall_msg_size(upcall_info->userdata, hlen);
+ len = upcall_msg_size(upcall_info, hlen);
user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
upcall->dp_ifindex = dp_ifindex;
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY);
- err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb);
+ err = ovs_nla_put_flow(key, key, user_skb);
BUG_ON(err);
nla_nest_end(user_skb, nla);
nla_len(upcall_info->userdata),
nla_data(upcall_info->userdata));
+ if (upcall_info->egress_tun_info) {
+ nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
+ err = ovs_nla_put_egress_tunnel_key(user_skb,
+ upcall_info->egress_tun_info);
+ BUG_ON(err);
+ nla_nest_end(user_skb, nla);
+ }
+
/* Only reserve room for attribute header, packet data is added
* in skb_zerocopy() */
if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
struct sw_flow_actions *acts;
struct sk_buff *packet;
struct sw_flow *flow;
+ struct sw_flow_actions *sf_acts;
struct datapath *dp;
struct ethhdr *eth;
struct vport *input_vport;
int len;
int err;
+ bool log = !a[OVS_FLOW_ATTR_PROBE];
err = -EINVAL;
if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
goto err_kfree_skb;
err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet,
- &flow->key);
+ &flow->key, log);
if (err)
goto err_flow_free;
- acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_PACKET_ATTR_ACTIONS]));
- err = PTR_ERR(acts);
- if (IS_ERR(acts))
- goto err_flow_free;
-
err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS],
- &flow->key, 0, &acts);
+ &flow->key, &acts, log);
if (err)
goto err_flow_free;
rcu_assign_pointer(flow->sf_acts, acts);
-
OVS_CB(packet)->egress_tun_info = NULL;
- OVS_CB(packet)->flow = flow;
packet->priority = flow->key.phy.priority;
packet->mark = flow->key.phy.skb_mark;
rcu_read_lock();
- dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+ dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
goto err_unlock;
goto err_unlock;
OVS_CB(packet)->input_vport = input_vport;
+ sf_acts = rcu_dereference(flow->sf_acts);
local_bh_disable();
- err = ovs_execute_actions(dp, packet, &flow->key);
+ err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
local_bh_enable();
rcu_read_unlock();
.n_ops = ARRAY_SIZE(dp_packet_genl_ops),
};
-static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats,
+static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats,
struct ovs_dp_megaflow_stats *mega_stats)
{
int i;
static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
{
return NLMSG_ALIGN(sizeof(struct ovs_header))
- + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */
- + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_MASK */
+ + nla_total_size(ovs_key_attr_size()) /* OVS_FLOW_ATTR_KEY */
+ + nla_total_size(ovs_key_attr_size()) /* OVS_FLOW_ATTR_MASK */
+ nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
+ nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
+ nla_total_size(8) /* OVS_FLOW_ATTR_USED */
}
/* Called with ovs_mutex or RCU read lock. */
-static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
- struct sk_buff *skb, u32 portid,
- u32 seq, u32 flags, u8 cmd)
+static int ovs_flow_cmd_fill_match(const struct sw_flow *flow,
+ struct sk_buff *skb)
{
- const int skb_orig_len = skb->len;
- struct nlattr *start;
- struct ovs_flow_stats stats;
- __be16 tcp_flags;
- unsigned long used;
- struct ovs_header *ovs_header;
struct nlattr *nla;
int err;
- ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd);
- if (!ovs_header)
- return -EMSGSIZE;
-
- ovs_header->dp_ifindex = dp_ifindex;
-
/* Fill flow key. */
nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY);
if (!nla)
- goto nla_put_failure;
+ return -EMSGSIZE;
err = ovs_nla_put_flow(&flow->unmasked_key, &flow->unmasked_key, skb);
if (err)
- goto error;
+ return err;
+
nla_nest_end(skb, nla);
+ /* Fill flow mask. */
nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK);
if (!nla)
- goto nla_put_failure;
+ return -EMSGSIZE;
err = ovs_nla_put_flow(&flow->key, &flow->mask->key, skb);
if (err)
- goto error;
+ return err;
nla_nest_end(skb, nla);
+ return 0;
+}
+
+/* Called with ovs_mutex or RCU read lock. */
+static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
+ struct sk_buff *skb)
+{
+ struct ovs_flow_stats stats;
+ __be16 tcp_flags;
+ unsigned long used;
ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
if (used &&
nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
- goto nla_put_failure;
+ return -EMSGSIZE;
if (stats.n_packets &&
nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats))
- goto nla_put_failure;
+ return -EMSGSIZE;
if ((u8)ntohs(tcp_flags) &&
nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
- goto nla_put_failure;
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+/* Called with ovs_mutex or RCU read lock. */
+static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow,
+ struct sk_buff *skb, int skb_orig_len)
+{
+ struct nlattr *start;
+ int err;
/* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
* this is the first flow to be dumped into 'skb'. This is unusual for
nla_nest_end(skb, start);
else {
if (skb_orig_len)
- goto error;
+ return err;
nla_nest_cancel(skb, start);
}
- } else if (skb_orig_len)
- goto nla_put_failure;
+ } else if (skb_orig_len) {
+ return -EMSGSIZE;
+ }
+
+ return 0;
+}
+
+/* Called with ovs_mutex or RCU read lock. */
+static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
+ struct sk_buff *skb, u32 portid,
+ u32 seq, u32 flags, u8 cmd)
+{
+ const int skb_orig_len = skb->len;
+ struct ovs_header *ovs_header;
+ int err;
+
+ ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family,
+ flags, cmd);
+ if (!ovs_header)
+ return -EMSGSIZE;
+
+ ovs_header->dp_ifindex = dp_ifindex;
+
+ err = ovs_flow_cmd_fill_match(flow, skb);
+ if (err)
+ goto error;
+
+ err = ovs_flow_cmd_fill_stats(flow, skb);
+ if (err)
+ goto error;
+
+ err = ovs_flow_cmd_fill_actions(flow, skb, skb_orig_len);
+ if (err)
+ goto error;
return genlmsg_end(skb, ovs_header);
-nla_put_failure:
- err = -EMSGSIZE;
error:
genlmsg_cancel(skb, ovs_header);
return err;
struct sw_flow_actions *acts;
struct sw_flow_match match;
int error;
+ bool log = !a[OVS_FLOW_ATTR_PROBE];
/* Must have key and actions. */
error = -EINVAL;
- if (!a[OVS_FLOW_ATTR_KEY])
+ if (!a[OVS_FLOW_ATTR_KEY]) {
+ OVS_NLERR(log, "Flow key attr not present in new flow.");
goto error;
- if (!a[OVS_FLOW_ATTR_ACTIONS])
+ }
+ if (!a[OVS_FLOW_ATTR_ACTIONS]) {
+ OVS_NLERR(log, "Flow actions attr not present in new flow.");
goto error;
+ }
/* Most of the time we need to allocate a new flow, do it before
* locking.
/* Extract key. */
ovs_match_init(&match, &new_flow->unmasked_key, &mask);
- error = ovs_nla_get_match(&match,
- a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
+ error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
+ a[OVS_FLOW_ATTR_MASK], log);
if (error)
goto err_kfree_flow;
ovs_flow_mask_key(&new_flow->key, &new_flow->unmasked_key, &mask);
/* Validate actions. */
- acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS]));
- error = PTR_ERR(acts);
- if (IS_ERR(acts))
- goto err_kfree_flow;
-
error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
- 0, &acts);
+ &acts, log);
if (error) {
- OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
- goto err_kfree_acts;
+ OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
+ goto err_kfree_flow;
}
reply = ovs_flow_cmd_alloc_info(acts, info, false);
}
/* The unmasked key has to be the same for flow updates. */
if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
+ /* Look for any overlapping flow. */
flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);
if (!flow) {
error = -ENOENT;
return error;
}
+/* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
const struct sw_flow_key *key,
- const struct sw_flow_mask *mask)
+ const struct sw_flow_mask *mask,
+ bool log)
{
struct sw_flow_actions *acts;
struct sw_flow_key masked_key;
int error;
- acts = ovs_nla_alloc_flow_actions(nla_len(a));
- if (IS_ERR(acts))
- return acts;
-
ovs_flow_mask_key(&masked_key, key, mask);
- error = ovs_nla_copy_actions(a, &masked_key, 0, &acts);
+ error = ovs_nla_copy_actions(a, &masked_key, &acts, log);
if (error) {
- OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
- kfree(acts);
+ OVS_NLERR(log,
+ "Actions may not be safe on all matching packets");
return ERR_PTR(error);
}
struct sw_flow_actions *old_acts = NULL, *acts = NULL;
struct sw_flow_match match;
int error;
+ bool log = !a[OVS_FLOW_ATTR_PROBE];
/* Extract key. */
error = -EINVAL;
- if (!a[OVS_FLOW_ATTR_KEY])
+ if (!a[OVS_FLOW_ATTR_KEY]) {
+ OVS_NLERR(log, "Flow key attribute not present in set flow.");
goto error;
+ }
ovs_match_init(&match, &key, &mask);
- error = ovs_nla_get_match(&match,
- a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
+ error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
+ a[OVS_FLOW_ATTR_MASK], log);
if (error)
goto error;
/* Validate actions. */
if (a[OVS_FLOW_ATTR_ACTIONS]) {
- acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask);
+ acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask,
+ log);
if (IS_ERR(acts)) {
error = PTR_ERR(acts);
goto error;
}
- }
- /* Can allocate before locking if have acts. */
- if (acts) {
+ /* Can allocate before locking if have acts. */
reply = ovs_flow_cmd_alloc_info(acts, info, false);
if (IS_ERR(reply)) {
error = PTR_ERR(reply);
struct datapath *dp;
struct sw_flow_match match;
int err;
+ bool log = !a[OVS_FLOW_ATTR_PROBE];
if (!a[OVS_FLOW_ATTR_KEY]) {
- OVS_NLERR("Flow get message rejected, Key attribute missing.\n");
+ OVS_NLERR(log,
+ "Flow get message rejected, Key attribute missing.");
return -EINVAL;
}
ovs_match_init(&match, &key, NULL);
- err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+ err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, log);
if (err)
return err;
struct datapath *dp;
struct sw_flow_match match;
int err;
+ bool log = !a[OVS_FLOW_ATTR_PROBE];
if (likely(a[OVS_FLOW_ATTR_KEY])) {
ovs_match_init(&match, &key, NULL);
- err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+ err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL,
+ log);
if (unlikely(err))
return err;
}
struct datapath *dp;
rcu_read_lock();
- dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+ dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
if (!dp) {
rcu_read_unlock();
return -ENODEV;
static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
[OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
+ [OVS_FLOW_ATTR_MASK] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
[OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
+ [OVS_FLOW_ATTR_PROBE] = { .type = NLA_FLAG },
};
static const struct genl_ops dp_flow_genl_ops[] = {
/* Called with rcu_read_lock or ovs_mutex. */
static struct datapath *lookup_datapath(struct net *net,
- struct ovs_header *ovs_header,
+ const struct ovs_header *ovs_header,
struct nlattr *a[OVS_DP_ATTR_MAX + 1])
{
struct datapath *dp;
dp->user_features = 0;
}
-static void ovs_dp_change(struct datapath *dp, struct nlattr **a)
+static void ovs_dp_change(struct datapath *dp, struct nlattr *a[])
{
if (a[OVS_DP_ATTR_USER_FEATURES])
dp->user_features = nla_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
err_destroy_percpu:
free_percpu(dp->stats_percpu);
err_destroy_table:
- ovs_flow_tbl_destroy(&dp->table, false);
+ ovs_flow_tbl_destroy(&dp->table);
err_free_dp:
release_net(ovs_dp_get_net(dp));
kfree(dp);
ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
/* RCU destroy the flow table */
- ovs_flow_tbl_destroy(&dp->table, true);
-
call_rcu(&dp->rcu, destroy_dp_rcu);
}
/* Called with ovs_mutex or RCU read lock. */
static struct vport *lookup_vport(struct net *net,
- struct ovs_header *ovs_header,
+ const struct ovs_header *ovs_header,
struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
{
struct datapath *dp;
return -ENOMEM;
ovs_lock();
+restart:
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
vport = new_vport(&parms);
err = PTR_ERR(vport);
- if (IS_ERR(vport))
+ if (IS_ERR(vport)) {
+ if (err == -EAGAIN)
+ goto restart;
goto exit_unlock_free;
+ }
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
info->snd_seq, 0, OVS_VPORT_CMD_NEW);
int i, j = 0;
rcu_read_lock();
- dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+ dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
if (!dp) {
rcu_read_unlock();
return -ENODEV;
if (err)
goto error_netns_exit;
+ err = ovs_netdev_init();
+ if (err)
+ goto error_unreg_notifier;
+
err = dp_register_genl();
if (err < 0)
- goto error_unreg_notifier;
+ goto error_unreg_netdev;
return 0;
+error_unreg_netdev:
+ ovs_netdev_exit();
error_unreg_notifier:
unregister_netdevice_notifier(&ovs_dp_device_notifier);
error_netns_exit:
static void dp_cleanup(void)
{
dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
+ ovs_netdev_exit();
unregister_netdevice_notifier(&ovs_dp_device_notifier);
unregister_pernet_device(&ovs_net_ops);
rcu_barrier();
/**
* struct ovs_skb_cb - OVS data in skb CB
- * @flow: The flow associated with this packet. May be %NULL if no flow.
* @egress_tun_key: Tunnel information about this packet on egress path.
* NULL if the packet is not being tunneled.
* @input_vport: The original vport packet came in on. This value is cached
* when a packet is received by OVS.
*/
struct ovs_skb_cb {
- struct sw_flow *flow;
struct ovs_tunnel_info *egress_tun_info;
struct vport *input_vport;
};
/**
* struct dp_upcall - metadata to include with a packet to send to userspace
* @cmd: One of %OVS_PACKET_CMD_*.
- * @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull.
* @userdata: If nonnull, its variable-length value is passed to userspace as
* %OVS_PACKET_ATTR_USERDATA.
- * @pid: Netlink PID to which packet should be sent. If @pid is 0 then no
- * packet is sent and the packet is accounted in the datapath's @n_lost
+ * @portid: Netlink portid to which packet should be sent. If @portid is 0
+ * then no packet is sent and the packet is accounted in the datapath's @n_lost
* counter.
+ * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
*/
struct dp_upcall_info {
- u8 cmd;
- const struct sw_flow_key *key;
+ const struct ovs_tunnel_info *egress_tun_info;
const struct nlattr *userdata;
u32 portid;
+ u8 cmd;
};
/**
#define rcu_dereference_ovsl(p) \
rcu_dereference_check(p, lockdep_ovsl_is_held())
-static inline struct net *ovs_dp_get_net(struct datapath *dp)
+static inline struct net *ovs_dp_get_net(const struct datapath *dp)
{
return read_pnet(&dp->net);
}
void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
void ovs_dp_detach_port(struct vport *);
int ovs_dp_upcall(struct datapath *, struct sk_buff *,
- const struct dp_upcall_info *);
+ const struct sw_flow_key *, const struct dp_upcall_info *);
const char *ovs_dp_name(const struct datapath *dp);
struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
u8 cmd);
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
- struct sw_flow_key *);
+ const struct sw_flow_actions *, struct sw_flow_key *);
void ovs_dp_notify_wq(struct work_struct *work);
int action_fifos_init(void);
void action_fifos_exit(void);
-#define OVS_NLERR(fmt, ...) \
+#define OVS_NLERR(logging_allowed, fmt, ...) \
do { \
- if (net_ratelimit()) \
- pr_info("netlink: " fmt, ##__VA_ARGS__); \
+ if (logging_allowed && net_ratelimit()) \
+ pr_info("netlink: " fmt "\n", ##__VA_ARGS__); \
} while (0)
#endif /* datapath.h */
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <linux/mpls.h>
#include <linux/sctp.h>
#include <linux/smp.h>
#include <linux/tcp.h>
#include <net/ip.h>
#include <net/ip_tunnels.h>
#include <net/ipv6.h>
+#include <net/mpls.h>
#include <net/ndisc.h>
#include "datapath.h"
#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF))
void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
- struct sk_buff *skb)
+ const struct sk_buff *skb)
{
struct flow_stats *stats;
int node = numa_node_id();
return -ENOMEM;
skb_reset_network_header(skb);
+ skb_reset_mac_len(skb);
__skb_push(skb, skb->data - skb_mac_header(skb));
/* Network layer. */
memset(&key->ip, 0, sizeof(key->ip));
memset(&key->ipv4, 0, sizeof(key->ipv4));
}
+ } else if (eth_p_mpls(key->eth.type)) {
+ size_t stack_len = MPLS_HLEN;
+
+ /* In the presence of an MPLS label stack the end of the L2
+ * header and the beginning of the L3 header differ.
+ *
+ * Advance network_header to the beginning of the L3
+ * header. mac_len corresponds to the end of the L2 header.
+ */
+ while (1) {
+ __be32 lse;
+
+ error = check_header(skb, skb->mac_len + stack_len);
+ if (unlikely(error))
+ return 0;
+
+ memcpy(&lse, skb_network_header(skb), MPLS_HLEN);
+
+ if (stack_len == MPLS_HLEN)
+ memcpy(&key->mpls.top_lse, &lse, MPLS_HLEN);
+
+ skb_set_network_header(skb, skb->mac_len + stack_len);
+ if (lse & htonl(MPLS_LS_S_MASK))
+ break;
+
+ stack_len += MPLS_HLEN;
+ }
} else if (key->eth.type == htons(ETH_P_IPV6)) {
int nh_len; /* IPv6 Header + Extensions */
return key_extract(skb, key);
}
-int ovs_flow_key_extract(struct ovs_tunnel_info *tun_info,
+int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,
struct sk_buff *skb, struct sw_flow_key *key)
{
/* Extract metadata from packet. */
int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb,
- struct sw_flow_key *key)
+ struct sw_flow_key *key, bool log)
{
int err;
/* Extract metadata from netlink attributes. */
- err = ovs_nla_get_flow_metadata(attr, key);
+ err = ovs_nla_get_flow_metadata(attr, key, log);
if (err)
return err;
/* Used to memset ovs_key_ipv4_tunnel padding. */
#define OVS_TUNNEL_KEY_SIZE \
- (offsetof(struct ovs_key_ipv4_tunnel, ipv4_ttl) + \
- FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, ipv4_ttl))
+ (offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
+ FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))
struct ovs_key_ipv4_tunnel {
__be64 tun_id;
__be16 tun_flags;
u8 ipv4_tos;
u8 ipv4_ttl;
+ __be16 tp_src;
+ __be16 tp_dst;
} __packed __aligned(4); /* Minimize padding. */
struct ovs_tunnel_info {
struct ovs_key_ipv4_tunnel tunnel;
- struct geneve_opt *options;
+ const struct geneve_opt *options;
u8 options_len;
};
FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \
opt_len))
-static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
- const struct iphdr *iph,
- __be64 tun_id, __be16 tun_flags,
- struct geneve_opt *opts,
- u8 opts_len)
+static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
+ __be32 saddr, __be32 daddr,
+ u8 tos, u8 ttl,
+ __be16 tp_src,
+ __be16 tp_dst,
+ __be64 tun_id,
+ __be16 tun_flags,
+ const struct geneve_opt *opts,
+ u8 opts_len)
{
tun_info->tunnel.tun_id = tun_id;
- tun_info->tunnel.ipv4_src = iph->saddr;
- tun_info->tunnel.ipv4_dst = iph->daddr;
- tun_info->tunnel.ipv4_tos = iph->tos;
- tun_info->tunnel.ipv4_ttl = iph->ttl;
+ tun_info->tunnel.ipv4_src = saddr;
+ tun_info->tunnel.ipv4_dst = daddr;
+ tun_info->tunnel.ipv4_tos = tos;
+ tun_info->tunnel.ipv4_ttl = ttl;
tun_info->tunnel.tun_flags = tun_flags;
- /* clear struct padding. */
- memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, 0,
- sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
+ /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
+ * the upper tunnel are used.
+ * E.g: GRE over IPSEC, the tp_src and tp_port are zero.
+ */
+ tun_info->tunnel.tp_src = tp_src;
+ tun_info->tunnel.tp_dst = tp_dst;
+
+ /* Clear struct padding. */
+ if (sizeof(tun_info->tunnel) != OVS_TUNNEL_KEY_SIZE)
+ memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE,
+ 0, sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
tun_info->options = opts;
tun_info->options_len = opts_len;
}
+static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
+ const struct iphdr *iph,
+ __be16 tp_src,
+ __be16 tp_dst,
+ __be64 tun_id,
+ __be16 tun_flags,
+ const struct geneve_opt *opts,
+ u8 opts_len)
+{
+ __ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
+ iph->tos, iph->ttl,
+ tp_src, tp_dst,
+ tun_id, tun_flags,
+ opts, opts_len);
+}
+
+#define OVS_SW_FLOW_KEY_METADATA_SIZE \
+ (offsetof(struct sw_flow_key, recirc_id) + \
+ FIELD_SIZEOF(struct sw_flow_key, recirc_id))
+
struct sw_flow_key {
u8 tun_opts[255];
u8 tun_opts_len;
__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
__be16 type; /* Ethernet frame type. */
} eth;
- struct {
- u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
- u8 tos; /* IP ToS. */
- u8 ttl; /* IP TTL/hop limit. */
- u8 frag; /* One of OVS_FRAG_TYPE_*. */
- } ip;
+ union {
+ struct {
+ __be32 top_lse; /* top label stack entry */
+ } mpls;
+ struct {
+ u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
+ u8 tos; /* IP ToS. */
+ u8 ttl; /* IP TTL/hop limit. */
+ u8 frag; /* One of OVS_FRAG_TYPE_*. */
+ } ip;
+ };
struct {
__be16 src; /* TCP/UDP/SCTP source port. */
__be16 dst; /* TCP/UDP/SCTP destination port. */
} __packed;
void ovs_flow_stats_update(struct sw_flow *, __be16 tcp_flags,
- struct sk_buff *);
+ const struct sk_buff *);
void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
unsigned long *used, __be16 *tcp_flags);
void ovs_flow_stats_clear(struct sw_flow *);
u64 ovs_flow_used_time(unsigned long flow_jiffies);
int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key);
-int ovs_flow_key_extract(struct ovs_tunnel_info *tun_info, struct sk_buff *skb,
+int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info,
+ struct sk_buff *skb,
struct sw_flow_key *key);
/* Extract key from packet coming from userspace. */
int ovs_flow_key_extract_userspace(const struct nlattr *attr,
struct sk_buff *skb,
- struct sw_flow_key *key);
+ struct sw_flow_key *key, bool log);
#endif /* flow.h */
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ndisc.h>
+#include <net/mpls.h>
#include "flow_netlink.h"
-static void update_range__(struct sw_flow_match *match,
- size_t offset, size_t size, bool is_mask)
+static void update_range(struct sw_flow_match *match,
+ size_t offset, size_t size, bool is_mask)
{
- struct sw_flow_key_range *range = NULL;
+ struct sw_flow_key_range *range;
size_t start = rounddown(offset, sizeof(long));
size_t end = roundup(offset + size, sizeof(long));
if (!is_mask)
range = &match->range;
- else if (match->mask)
+ else
range = &match->mask->range;
- if (!range)
- return;
-
if (range->start == range->end) {
range->start = start;
range->end = end;
#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \
do { \
- update_range__(match, offsetof(struct sw_flow_key, field), \
- sizeof((match)->key->field), is_mask); \
- if (is_mask) { \
- if ((match)->mask) \
- (match)->mask->key.field = value; \
- } else { \
+ update_range(match, offsetof(struct sw_flow_key, field), \
+ sizeof((match)->key->field), is_mask); \
+ if (is_mask) \
+ (match)->mask->key.field = value; \
+ else \
(match)->key->field = value; \
- } \
} while (0)
#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \
do { \
- update_range__(match, offset, len, is_mask); \
+ update_range(match, offset, len, is_mask); \
if (is_mask) \
memcpy((u8 *)&(match)->mask->key + offset, value_p, \
- len); \
+ len); \
else \
memcpy((u8 *)(match)->key + offset, value_p, len); \
} while (0)
SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
value_p, len, is_mask)
-#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \
- do { \
- update_range__(match, offsetof(struct sw_flow_key, field), \
- sizeof((match)->key->field), is_mask); \
- if (is_mask) { \
- if ((match)->mask) \
- memset((u8 *)&(match)->mask->key.field, value,\
- sizeof((match)->mask->key.field)); \
- } else { \
+#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \
+ do { \
+ update_range(match, offsetof(struct sw_flow_key, field), \
+ sizeof((match)->key->field), is_mask); \
+ if (is_mask) \
+ memset((u8 *)&(match)->mask->key.field, value, \
+ sizeof((match)->mask->key.field)); \
+ else \
memset((u8 *)&(match)->key->field, value, \
sizeof((match)->key->field)); \
- } \
} while (0)
static bool match_validate(const struct sw_flow_match *match,
- u64 key_attrs, u64 mask_attrs)
+ u64 key_attrs, u64 mask_attrs, bool log)
{
u64 key_expected = 1 << OVS_KEY_ATTR_ETHERNET;
u64 mask_allowed = key_attrs; /* At most allow all key attributes */
| (1 << OVS_KEY_ATTR_ICMP)
| (1 << OVS_KEY_ATTR_ICMPV6)
| (1 << OVS_KEY_ATTR_ARP)
- | (1 << OVS_KEY_ATTR_ND));
+ | (1 << OVS_KEY_ATTR_ND)
+ | (1 << OVS_KEY_ATTR_MPLS));
/* Always allowed mask fields. */
mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)
mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
}
+ if (eth_p_mpls(match->key->eth.type)) {
+ key_expected |= 1 << OVS_KEY_ATTR_MPLS;
+ if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
+ mask_allowed |= 1 << OVS_KEY_ATTR_MPLS;
+ }
+
if (match->key->eth.type == htons(ETH_P_IP)) {
key_expected |= 1 << OVS_KEY_ATTR_IPV4;
if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
if ((key_attrs & key_expected) != key_expected) {
/* Key attributes check failed. */
- OVS_NLERR("Missing expected key attributes (key_attrs=%llx, expected=%llx).\n",
- (unsigned long long)key_attrs, (unsigned long long)key_expected);
+ OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)",
+ (unsigned long long)key_attrs,
+ (unsigned long long)key_expected);
return false;
}
if ((mask_attrs & mask_allowed) != mask_attrs) {
/* Mask attributes check failed. */
- OVS_NLERR("Contain more than allowed mask fields (mask_attrs=%llx, mask_allowed=%llx).\n",
- (unsigned long long)mask_attrs, (unsigned long long)mask_allowed);
+ OVS_NLERR(log, "Unexpected mask (mask=%llx, allowed=%llx)",
+ (unsigned long long)mask_attrs,
+ (unsigned long long)mask_allowed);
return false;
}
return true;
}
+size_t ovs_tun_key_attr_size(void)
+{
+ /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
+ * updating this function.
+ */
+ return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
+ + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
+ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
+ + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
+ + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+ + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
+ + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
+ + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
+ + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
+ + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
+}
+
+size_t ovs_key_attr_size(void)
+{
+ /* Whenever adding new OVS_KEY_ FIELDS, we should consider
+ * updating this function.
+ */
+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 22);
+
+ return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
+ + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
+ + ovs_tun_key_attr_size()
+ + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
+ + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
+ + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
+ + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
+ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
+ + nla_total_size(0) /* OVS_KEY_ATTR_ENCAP */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ + nla_total_size(40) /* OVS_KEY_ATTR_IPV6 */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ICMPV6 */
+ + nla_total_size(28); /* OVS_KEY_ATTR_ND */
+}
+
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[OVS_KEY_ATTR_ENCAP] = -1,
[OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32),
[OVS_KEY_ATTR_DP_HASH] = sizeof(u32),
[OVS_KEY_ATTR_TUNNEL] = -1,
+ [OVS_KEY_ATTR_MPLS] = sizeof(struct ovs_key_mpls),
};
static bool is_all_zero(const u8 *fp, size_t size)
static int __parse_flow_nlattrs(const struct nlattr *attr,
const struct nlattr *a[],
- u64 *attrsp, bool nz)
+ u64 *attrsp, bool log, bool nz)
{
const struct nlattr *nla;
u64 attrs;
int expected_len;
if (type > OVS_KEY_ATTR_MAX) {
- OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n",
+ OVS_NLERR(log, "Key type %d is out of range max %d",
type, OVS_KEY_ATTR_MAX);
return -EINVAL;
}
if (attrs & (1 << type)) {
- OVS_NLERR("Duplicate key attribute (type %d).\n", type);
+ OVS_NLERR(log, "Duplicate key (type %d).", type);
return -EINVAL;
}
expected_len = ovs_key_lens[type];
if (nla_len(nla) != expected_len && expected_len != -1) {
- OVS_NLERR("Key attribute has unexpected length (type=%d"
- ", length=%d, expected=%d).\n", type,
- nla_len(nla), expected_len);
+ OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
+ type, nla_len(nla), expected_len);
return -EINVAL;
}
}
}
if (rem) {
- OVS_NLERR("Message has %d unknown bytes.\n", rem);
+ OVS_NLERR(log, "Message has %d unknown bytes.", rem);
return -EINVAL;
}
}
static int parse_flow_mask_nlattrs(const struct nlattr *attr,
- const struct nlattr *a[], u64 *attrsp)
+ const struct nlattr *a[], u64 *attrsp,
+ bool log)
{
- return __parse_flow_nlattrs(attr, a, attrsp, true);
+ return __parse_flow_nlattrs(attr, a, attrsp, log, true);
}
static int parse_flow_nlattrs(const struct nlattr *attr,
- const struct nlattr *a[], u64 *attrsp)
+ const struct nlattr *a[], u64 *attrsp,
+ bool log)
{
- return __parse_flow_nlattrs(attr, a, attrsp, false);
+ return __parse_flow_nlattrs(attr, a, attrsp, log, false);
+}
+
+static int genev_tun_opt_from_nlattr(const struct nlattr *a,
+ struct sw_flow_match *match, bool is_mask,
+ bool log)
+{
+ unsigned long opt_key_offset;
+
+ if (nla_len(a) > sizeof(match->key->tun_opts)) {
+ OVS_NLERR(log, "Geneve option length err (len %d, max %zu).",
+ nla_len(a), sizeof(match->key->tun_opts));
+ return -EINVAL;
+ }
+
+ if (nla_len(a) % 4 != 0) {
+ OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.",
+ nla_len(a));
+ return -EINVAL;
+ }
+
+ /* We need to record the length of the options passed
+ * down, otherwise packets with the same format but
+ * additional options will be silently matched.
+ */
+ if (!is_mask) {
+ SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
+ false);
+ } else {
+ /* This is somewhat unusual because it looks at
+ * both the key and mask while parsing the
+ * attributes (and by extension assumes the key
+ * is parsed first). Normally, we would verify
+ * that each is the correct length and that the
+ * attributes line up in the validate function.
+ * However, that is difficult because this is
+ * variable length and we won't have the
+ * information later.
+ */
+ if (match->key->tun_opts_len != nla_len(a)) {
+ OVS_NLERR(log, "Geneve option len %d != mask len %d",
+ match->key->tun_opts_len, nla_len(a));
+ return -EINVAL;
+ }
+
+ SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
+ }
+
+ opt_key_offset = (unsigned long)GENEVE_OPTS((struct sw_flow_key *)0,
+ nla_len(a));
+ SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
+ nla_len(a), is_mask);
+ return 0;
}
static int ipv4_tun_from_nlattr(const struct nlattr *attr,
- struct sw_flow_match *match, bool is_mask)
+ struct sw_flow_match *match, bool is_mask,
+ bool log)
{
struct nlattr *a;
int rem;
bool ttl = false;
__be16 tun_flags = 0;
- unsigned long opt_key_offset;
nla_for_each_nested(a, attr, rem) {
int type = nla_type(a);
+ int err;
+
static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
[OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64),
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32),
[OVS_TUNNEL_KEY_ATTR_TTL] = 1,
[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
[OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
+ [OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16),
+ [OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16),
[OVS_TUNNEL_KEY_ATTR_OAM] = 0,
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
};
if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
- OVS_NLERR("Unknown IPv4 tunnel attribute (type=%d, max=%d).\n",
- type, OVS_TUNNEL_KEY_ATTR_MAX);
+ OVS_NLERR(log, "Tunnel attr %d out of range max %d",
+ type, OVS_TUNNEL_KEY_ATTR_MAX);
return -EINVAL;
}
if (ovs_tunnel_key_lens[type] != nla_len(a) &&
ovs_tunnel_key_lens[type] != -1) {
- OVS_NLERR("IPv4 tunnel attribute type has unexpected "
- " length (type=%d, length=%d, expected=%d).\n",
+ OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
type, nla_len(a), ovs_tunnel_key_lens[type]);
return -EINVAL;
}
case OVS_TUNNEL_KEY_ATTR_CSUM:
tun_flags |= TUNNEL_CSUM;
break;
+ case OVS_TUNNEL_KEY_ATTR_TP_SRC:
+ SW_FLOW_KEY_PUT(match, tun_key.tp_src,
+ nla_get_be16(a), is_mask);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TP_DST:
+ SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
+ nla_get_be16(a), is_mask);
+ break;
case OVS_TUNNEL_KEY_ATTR_OAM:
tun_flags |= TUNNEL_OAM;
break;
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
- tun_flags |= TUNNEL_OPTIONS_PRESENT;
- if (nla_len(a) > sizeof(match->key->tun_opts)) {
- OVS_NLERR("Geneve option length exceeds maximum size (len %d, max %zu).\n",
- nla_len(a),
- sizeof(match->key->tun_opts));
- return -EINVAL;
- }
-
- if (nla_len(a) % 4 != 0) {
- OVS_NLERR("Geneve option length is not a multiple of 4 (len %d).\n",
- nla_len(a));
- return -EINVAL;
- }
-
- /* We need to record the length of the options passed
- * down, otherwise packets with the same format but
- * additional options will be silently matched.
- */
- if (!is_mask) {
- SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
- false);
- } else {
- /* This is somewhat unusual because it looks at
- * both the key and mask while parsing the
- * attributes (and by extension assumes the key
- * is parsed first). Normally, we would verify
- * that each is the correct length and that the
- * attributes line up in the validate function.
- * However, that is difficult because this is
- * variable length and we won't have the
- * information later.
- */
- if (match->key->tun_opts_len != nla_len(a)) {
- OVS_NLERR("Geneve option key length (%d) is different from mask length (%d).",
- match->key->tun_opts_len,
- nla_len(a));
- return -EINVAL;
- }
-
- SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff,
- true);
- }
+ err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
+ if (err)
+ return err;
- opt_key_offset = (unsigned long)GENEVE_OPTS(
- (struct sw_flow_key *)0,
- nla_len(a));
- SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset,
- nla_data(a), nla_len(a),
- is_mask);
+ tun_flags |= TUNNEL_OPTIONS_PRESENT;
break;
default:
- OVS_NLERR("Unknown IPv4 tunnel attribute (%d).\n",
+ OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d",
type);
return -EINVAL;
}
SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
if (rem > 0) {
- OVS_NLERR("IPv4 tunnel attribute has %d unknown bytes.\n", rem);
+ OVS_NLERR(log, "IPv4 tunnel attribute has %d unknown bytes.",
+ rem);
return -EINVAL;
}
if (!is_mask) {
if (!match->key->tun_key.ipv4_dst) {
- OVS_NLERR("IPv4 tunnel destination address is zero.\n");
+ OVS_NLERR(log, "IPv4 tunnel dst address is zero");
return -EINVAL;
}
if (!ttl) {
- OVS_NLERR("IPv4 tunnel TTL not specified.\n");
+ OVS_NLERR(log, "IPv4 tunnel TTL not specified.");
return -EINVAL;
}
}
if ((output->tun_flags & TUNNEL_CSUM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
return -EMSGSIZE;
+ if (output->tp_src &&
+ nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
+ return -EMSGSIZE;
+ if (output->tp_dst &&
+ nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
+ return -EMSGSIZE;
if ((output->tun_flags & TUNNEL_OAM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
return -EMSGSIZE;
return 0;
}
-
static int ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *output,
const struct geneve_opt *tun_opts,
return 0;
}
+int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
+ const struct ovs_tunnel_info *egress_tun_info)
+{
+ return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel,
+ egress_tun_info->options,
+ egress_tun_info->options_len);
+}
+
static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
- const struct nlattr **a, bool is_mask)
+ const struct nlattr **a, bool is_mask,
+ bool log)
{
if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) {
u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
- if (is_mask)
+ if (is_mask) {
in_port = 0xffffffff; /* Always exact match in_port. */
- else if (in_port >= DP_MAX_PORTS)
+ } else if (in_port >= DP_MAX_PORTS) {
+ OVS_NLERR(log, "Port %d exceeds max allowable %d",
+ in_port, DP_MAX_PORTS);
return -EINVAL;
+ }
SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
*attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT);
}
if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
- is_mask))
+ is_mask, log))
return -EINVAL;
*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
}
}
static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
- const struct nlattr **a, bool is_mask)
+ const struct nlattr **a, bool is_mask,
+ bool log)
{
int err;
- u64 orig_attrs = attrs;
- err = metadata_from_nlattrs(match, &attrs, a, is_mask);
+ err = metadata_from_nlattrs(match, &attrs, a, is_mask, log);
if (err)
return err;
tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
if (!(tci & htons(VLAN_TAG_PRESENT))) {
if (is_mask)
- OVS_NLERR("VLAN TCI mask does not have exact match for VLAN_TAG_PRESENT bit.\n");
+ OVS_NLERR(log, "VLAN TCI mask does not have exact match for VLAN_TAG_PRESENT bit.");
else
- OVS_NLERR("VLAN TCI does not have VLAN_TAG_PRESENT bit set.\n");
+ OVS_NLERR(log, "VLAN TCI does not have VLAN_TAG_PRESENT bit set.");
return -EINVAL;
}
SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
attrs &= ~(1 << OVS_KEY_ATTR_VLAN);
- } else if (!is_mask)
- SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
+ }
if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
__be16 eth_type;
/* Always exact match EtherType. */
eth_type = htons(0xffff);
} else if (ntohs(eth_type) < ETH_P_802_3_MIN) {
- OVS_NLERR("EtherType is less than minimum (type=%x, min=%x).\n",
- ntohs(eth_type), ETH_P_802_3_MIN);
+ OVS_NLERR(log, "EtherType %x is less than min %x",
+ ntohs(eth_type), ETH_P_802_3_MIN);
return -EINVAL;
}
ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
- OVS_NLERR("Unknown IPv4 fragment type (value=%d, max=%d).\n",
- ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX);
+ OVS_NLERR(log, "IPv4 frag type %d is out of range max %d",
+ ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX);
return -EINVAL;
}
SW_FLOW_KEY_PUT(match, ip.proto,
ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
- OVS_NLERR("Unknown IPv6 fragment type (value=%d, max=%d).\n",
- ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
+ OVS_NLERR(log, "IPv6 frag type %d is out of range max %d",
+ ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
return -EINVAL;
}
SW_FLOW_KEY_PUT(match, ipv6.label,
arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
if (!is_mask && (arp_key->arp_op & htons(0xff00))) {
- OVS_NLERR("Unknown ARP opcode (opcode=%d).\n",
+ OVS_NLERR(log, "Unknown ARP opcode (opcode=%d).",
arp_key->arp_op);
return -EINVAL;
}
attrs &= ~(1 << OVS_KEY_ATTR_ARP);
}
+ if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
+ const struct ovs_key_mpls *mpls_key;
+
+ mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]);
+ SW_FLOW_KEY_PUT(match, mpls.top_lse,
+ mpls_key->mpls_lse, is_mask);
+
+ attrs &= ~(1 << OVS_KEY_ATTR_MPLS);
+ }
+
if (attrs & (1 << OVS_KEY_ATTR_TCP)) {
const struct ovs_key_tcp *tcp_key;
}
if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) {
- if (orig_attrs & (1 << OVS_KEY_ATTR_IPV4)) {
- SW_FLOW_KEY_PUT(match, tp.flags,
- nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
- is_mask);
- } else {
- SW_FLOW_KEY_PUT(match, tp.flags,
- nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
- is_mask);
- }
+ SW_FLOW_KEY_PUT(match, tp.flags,
+ nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
+ is_mask);
attrs &= ~(1 << OVS_KEY_ATTR_TCP_FLAGS);
}
attrs &= ~(1 << OVS_KEY_ATTR_ND);
}
- if (attrs != 0)
+ if (attrs != 0) {
+ OVS_NLERR(log, "Unknown key attributes %llx",
+ (unsigned long long)attrs);
return -EINVAL;
+ }
return 0;
}
* of this flow.
* @mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink
* attribute specifies the mask field of the wildcarded flow.
+ * @log: Boolean to allow kernel error logging. Normally true, but when
+ * probing for feature compatibility this should be passed in as false to
+ * suppress unnecessary error logging.
*/
int ovs_nla_get_match(struct sw_flow_match *match,
- const struct nlattr *key,
- const struct nlattr *mask)
+ const struct nlattr *nla_key,
+ const struct nlattr *nla_mask,
+ bool log)
{
const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
const struct nlattr *encap;
bool encap_valid = false;
int err;
- err = parse_flow_nlattrs(key, a, &key_attrs);
+ err = parse_flow_nlattrs(nla_key, a, &key_attrs, log);
if (err)
return err;
if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) &&
(key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) {
- OVS_NLERR("Invalid Vlan frame.\n");
+ OVS_NLERR(log, "Invalid Vlan frame.");
return -EINVAL;
}
encap_valid = true;
if (tci & htons(VLAN_TAG_PRESENT)) {
- err = parse_flow_nlattrs(encap, a, &key_attrs);
+ err = parse_flow_nlattrs(encap, a, &key_attrs, log);
if (err)
return err;
} else if (!tci) {
/* Corner case for truncated 802.1Q header. */
if (nla_len(encap)) {
- OVS_NLERR("Truncated 802.1Q header has non-zero encap attribute.\n");
+ OVS_NLERR(log, "Truncated 802.1Q header has non-zero encap attribute.");
return -EINVAL;
}
} else {
- OVS_NLERR("Encap attribute is set for a non-VLAN frame.\n");
+ OVS_NLERR(log, "Encap attr is set for non-VLAN frame");
return -EINVAL;
}
}
- err = ovs_key_from_nlattrs(match, key_attrs, a, false);
+ err = ovs_key_from_nlattrs(match, key_attrs, a, false, log);
if (err)
return err;
- if (match->mask && !mask) {
- /* Create an exact match mask. We need to set to 0xff all the
- * 'match->mask' fields that have been touched in 'match->key'.
- * We cannot simply memset 'match->mask', because padding bytes
- * and fields not specified in 'match->key' should be left to 0.
- * Instead, we use a stream of netlink attributes, copied from
- * 'key' and set to 0xff: ovs_key_from_nlattrs() will take care
- * of filling 'match->mask' appropriately.
- */
- newmask = kmemdup(key, nla_total_size(nla_len(key)),
- GFP_KERNEL);
- if (!newmask)
- return -ENOMEM;
+ if (match->mask) {
+ if (!nla_mask) {
+ /* Create an exact match mask. We need to set to 0xff
+ * all the 'match->mask' fields that have been touched
+ * in 'match->key'. We cannot simply memset
+ * 'match->mask', because padding bytes and fields not
+ * specified in 'match->key' should be left to 0.
+ * Instead, we use a stream of netlink attributes,
+ * copied from 'key' and set to 0xff.
+ * ovs_key_from_nlattrs() will take care of filling
+ * 'match->mask' appropriately.
+ */
+ newmask = kmemdup(nla_key,
+ nla_total_size(nla_len(nla_key)),
+ GFP_KERNEL);
+ if (!newmask)
+ return -ENOMEM;
- mask_set_nlattr(newmask, 0xff);
+ mask_set_nlattr(newmask, 0xff);
- /* The userspace does not send tunnel attributes that are 0,
- * but we should not wildcard them nonetheless.
- */
- if (match->key->tun_key.ipv4_dst)
- SW_FLOW_KEY_MEMSET_FIELD(match, tun_key, 0xff, true);
+ /* The userspace does not send tunnel attributes that
+ * are 0, but we should not wildcard them nonetheless.
+ */
+ if (match->key->tun_key.ipv4_dst)
+ SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
+ 0xff, true);
- mask = newmask;
- }
+ nla_mask = newmask;
+ }
- if (mask) {
- err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
+ err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log);
if (err)
goto free_newmask;
+ /* Always match on tci. */
+ SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
+
if (mask_attrs & 1 << OVS_KEY_ATTR_ENCAP) {
__be16 eth_type = 0;
__be16 tci = 0;
if (!encap_valid) {
- OVS_NLERR("Encap mask attribute is set for non-VLAN frame.\n");
+ OVS_NLERR(log, "Encap mask attribute is set for non-VLAN frame.");
err = -EINVAL;
goto free_newmask;
}
if (eth_type == htons(0xffff)) {
mask_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
encap = a[OVS_KEY_ATTR_ENCAP];
- err = parse_flow_mask_nlattrs(encap, a, &mask_attrs);
+ err = parse_flow_mask_nlattrs(encap, a,
+ &mask_attrs, log);
if (err)
goto free_newmask;
} else {
- OVS_NLERR("VLAN frames must have an exact match on the TPID (mask=%x).\n",
- ntohs(eth_type));
+ OVS_NLERR(log, "VLAN frames must have an exact match on the TPID (mask=%x).",
+ ntohs(eth_type));
err = -EINVAL;
goto free_newmask;
}
tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
if (!(tci & htons(VLAN_TAG_PRESENT))) {
- OVS_NLERR("VLAN tag present bit must have an exact match (tci_mask=%x).\n", ntohs(tci));
+ OVS_NLERR(log, "VLAN tag present bit must have an exact match (tci_mask=%x).",
+ ntohs(tci));
err = -EINVAL;
goto free_newmask;
}
}
- err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
+ err = ovs_key_from_nlattrs(match, mask_attrs, a, true, log);
if (err)
goto free_newmask;
}
- if (!match_validate(match, key_attrs, mask_attrs))
+ if (!match_validate(match, key_attrs, mask_attrs, log))
err = -EINVAL;
free_newmask:
* @key: Receives extracted in_port, priority, tun_key and skb_mark.
* @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
* sequence.
+ * @log: Boolean to allow kernel error logging. Normally true, but when
+ * probing for feature compatibility this should be passed in as false to
+ * suppress unnecessary error logging.
*
* This parses a series of Netlink attributes that form a flow key, which must
* take the same form accepted by flow_from_nlattrs(), but only enough of it to
*/
int ovs_nla_get_flow_metadata(const struct nlattr *attr,
- struct sw_flow_key *key)
+ struct sw_flow_key *key,
+ bool log)
{
const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
struct sw_flow_match match;
u64 attrs = 0;
int err;
- err = parse_flow_nlattrs(attr, a, &attrs);
+ err = parse_flow_nlattrs(attr, a, &attrs, log);
if (err)
return -EINVAL;
key->phy.in_port = DP_MAX_PORTS;
- return metadata_from_nlattrs(&match, &attrs, a, false);
+ return metadata_from_nlattrs(&match, &attrs, a, false, log);
}
int ovs_nla_put_flow(const struct sw_flow_key *swkey,
arp_key->arp_op = htons(output->ip.proto);
ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha);
ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha);
+ } else if (eth_p_mpls(swkey->eth.type)) {
+ struct ovs_key_mpls *mpls_key;
+
+ nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS, sizeof(*mpls_key));
+ if (!nla)
+ goto nla_put_failure;
+ mpls_key = nla_data(nla);
+ mpls_key->mpls_lse = output->mpls.top_lse;
}
if ((swkey->eth.type == htons(ETH_P_IP) ||
#define MAX_ACTIONS_BUFSIZE (32 * 1024)
-struct sw_flow_actions *ovs_nla_alloc_flow_actions(int size)
+static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log)
{
struct sw_flow_actions *sfa;
- if (size > MAX_ACTIONS_BUFSIZE)
+ if (size > MAX_ACTIONS_BUFSIZE) {
+ OVS_NLERR(log, "Flow action size %u bytes exceeds max", size);
return ERR_PTR(-EINVAL);
+ }
sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
if (!sfa)
}
static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,
- int attr_len)
+ int attr_len, bool log)
{
struct sw_flow_actions *acts;
new_acts_size = MAX_ACTIONS_BUFSIZE;
}
- acts = ovs_nla_alloc_flow_actions(new_acts_size);
+ acts = nla_alloc_flow_actions(new_acts_size, log);
if (IS_ERR(acts))
return (void *)acts;
}
static struct nlattr *__add_action(struct sw_flow_actions **sfa,
- int attrtype, void *data, int len)
+ int attrtype, void *data, int len, bool log)
{
struct nlattr *a;
- a = reserve_sfa_size(sfa, nla_attr_size(len));
+ a = reserve_sfa_size(sfa, nla_attr_size(len), log);
if (IS_ERR(a))
return a;
}
static int add_action(struct sw_flow_actions **sfa, int attrtype,
- void *data, int len)
+ void *data, int len, bool log)
{
struct nlattr *a;
- a = __add_action(sfa, attrtype, data, len);
+ a = __add_action(sfa, attrtype, data, len, log);
if (IS_ERR(a))
return PTR_ERR(a);
}
static inline int add_nested_action_start(struct sw_flow_actions **sfa,
- int attrtype)
+ int attrtype, bool log)
{
int used = (*sfa)->actions_len;
int err;
- err = add_action(sfa, attrtype, NULL, 0);
+ err = add_action(sfa, attrtype, NULL, 0, log);
if (err)
return err;
a->nla_len = sfa->actions_len - st_offset;
}
+static int __ovs_nla_copy_actions(const struct nlattr *attr,
+ const struct sw_flow_key *key,
+ int depth, struct sw_flow_actions **sfa,
+ __be16 eth_type, __be16 vlan_tci, bool log);
+
static int validate_and_copy_sample(const struct nlattr *attr,
const struct sw_flow_key *key, int depth,
- struct sw_flow_actions **sfa)
+ struct sw_flow_actions **sfa,
+ __be16 eth_type, __be16 vlan_tci, bool log)
{
const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
const struct nlattr *probability, *actions;
return -EINVAL;
/* validation done, copy sample action. */
- start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE);
+ start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log);
if (start < 0)
return start;
err = add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY,
- nla_data(probability), sizeof(u32));
+ nla_data(probability), sizeof(u32), log);
if (err)
return err;
- st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS);
+ st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS, log);
if (st_acts < 0)
return st_acts;
- err = ovs_nla_copy_actions(actions, key, depth + 1, sfa);
+ err = __ovs_nla_copy_actions(actions, key, depth + 1, sfa,
+ eth_type, vlan_tci, log);
if (err)
return err;
return 0;
}
-static int validate_tp_port(const struct sw_flow_key *flow_key)
+static int validate_tp_port(const struct sw_flow_key *flow_key,
+ __be16 eth_type)
{
- if ((flow_key->eth.type == htons(ETH_P_IP) ||
- flow_key->eth.type == htons(ETH_P_IPV6)) &&
+ if ((eth_type == htons(ETH_P_IP) || eth_type == htons(ETH_P_IPV6)) &&
(flow_key->tp.src || flow_key->tp.dst))
return 0;
}
static int validate_and_copy_set_tun(const struct nlattr *attr,
- struct sw_flow_actions **sfa)
+ struct sw_flow_actions **sfa, bool log)
{
struct sw_flow_match match;
struct sw_flow_key key;
int err, start;
ovs_match_init(&match, &key, NULL);
- err = ipv4_tun_from_nlattr(nla_data(attr), &match, false);
+ err = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log);
if (err)
return err;
key.tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0;
};
- start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET);
+ start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
if (start < 0)
return start;
a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
- sizeof(*tun_info) + key.tun_opts_len);
+ sizeof(*tun_info) + key.tun_opts_len, log);
if (IS_ERR(a))
return PTR_ERR(a);
static int validate_set(const struct nlattr *a,
const struct sw_flow_key *flow_key,
struct sw_flow_actions **sfa,
- bool *set_tun)
+ bool *set_tun, __be16 eth_type, bool log)
{
const struct nlattr *ovs_key = nla_data(a);
int key_type = nla_type(ovs_key);
break;
case OVS_KEY_ATTR_TUNNEL:
+ if (eth_p_mpls(eth_type))
+ return -EINVAL;
+
*set_tun = true;
- err = validate_and_copy_set_tun(a, sfa);
+ err = validate_and_copy_set_tun(a, sfa, log);
if (err)
return err;
break;
case OVS_KEY_ATTR_IPV4:
- if (flow_key->eth.type != htons(ETH_P_IP))
+ if (eth_type != htons(ETH_P_IP))
return -EINVAL;
if (!flow_key->ip.proto)
break;
case OVS_KEY_ATTR_IPV6:
- if (flow_key->eth.type != htons(ETH_P_IPV6))
+ if (eth_type != htons(ETH_P_IPV6))
return -EINVAL;
if (!flow_key->ip.proto)
if (flow_key->ip.proto != IPPROTO_TCP)
return -EINVAL;
- return validate_tp_port(flow_key);
+ return validate_tp_port(flow_key, eth_type);
case OVS_KEY_ATTR_UDP:
if (flow_key->ip.proto != IPPROTO_UDP)
return -EINVAL;
- return validate_tp_port(flow_key);
+ return validate_tp_port(flow_key, eth_type);
+
+ case OVS_KEY_ATTR_MPLS:
+ if (!eth_p_mpls(eth_type))
+ return -EINVAL;
+ break;
case OVS_KEY_ATTR_SCTP:
if (flow_key->ip.proto != IPPROTO_SCTP)
return -EINVAL;
- return validate_tp_port(flow_key);
+ return validate_tp_port(flow_key, eth_type);
default:
return -EINVAL;
static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
+ [OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
};
struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
int error;
}
static int copy_action(const struct nlattr *from,
- struct sw_flow_actions **sfa)
+ struct sw_flow_actions **sfa, bool log)
{
int totlen = NLA_ALIGN(from->nla_len);
struct nlattr *to;
- to = reserve_sfa_size(sfa, from->nla_len);
+ to = reserve_sfa_size(sfa, from->nla_len, log);
if (IS_ERR(to))
return PTR_ERR(to);
return 0;
}
-int ovs_nla_copy_actions(const struct nlattr *attr,
- const struct sw_flow_key *key,
- int depth,
- struct sw_flow_actions **sfa)
+static int __ovs_nla_copy_actions(const struct nlattr *attr,
+ const struct sw_flow_key *key,
+ int depth, struct sw_flow_actions **sfa,
+ __be16 eth_type, __be16 vlan_tci, bool log)
{
const struct nlattr *a;
+ bool out_tnl_port = false;
int rem, err;
if (depth >= SAMPLE_ACTION_DEPTH)
[OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
[OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
[OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
+ [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
+ [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
[OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
[OVS_ACTION_ATTR_POP_VLAN] = 0,
[OVS_ACTION_ATTR_SET] = (u32)-1,
case OVS_ACTION_ATTR_OUTPUT:
if (nla_get_u32(a) >= DP_MAX_PORTS)
return -EINVAL;
+ out_tnl_port = false;
+
break;
case OVS_ACTION_ATTR_HASH: {
}
case OVS_ACTION_ATTR_POP_VLAN:
+ vlan_tci = htons(0);
break;
case OVS_ACTION_ATTR_PUSH_VLAN:
return -EINVAL;
if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT)))
return -EINVAL;
+ vlan_tci = vlan->vlan_tci;
break;
case OVS_ACTION_ATTR_RECIRC:
break;
+ case OVS_ACTION_ATTR_PUSH_MPLS: {
+ const struct ovs_action_push_mpls *mpls = nla_data(a);
+
+ /* Networking stack do not allow simultaneous Tunnel
+ * and MPLS GSO.
+ */
+ if (out_tnl_port)
+ return -EINVAL;
+
+ if (!eth_p_mpls(mpls->mpls_ethertype))
+ return -EINVAL;
+ /* Prohibit push MPLS other than to a white list
+ * for packets that have a known tag order.
+ */
+ if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
+ (eth_type != htons(ETH_P_IP) &&
+ eth_type != htons(ETH_P_IPV6) &&
+ eth_type != htons(ETH_P_ARP) &&
+ eth_type != htons(ETH_P_RARP) &&
+ !eth_p_mpls(eth_type)))
+ return -EINVAL;
+ eth_type = mpls->mpls_ethertype;
+ break;
+ }
+
+ case OVS_ACTION_ATTR_POP_MPLS:
+ if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
+ !eth_p_mpls(eth_type))
+ return -EINVAL;
+
+ /* Disallow subsequent L2.5+ set and mpls_pop actions
+ * as there is no check here to ensure that the new
+ * eth_type is valid and thus set actions could
+ * write off the end of the packet or otherwise
+ * corrupt it.
+ *
+ * Support for these actions is planned using packet
+ * recirculation.
+ */
+ eth_type = htons(0);
+ break;
+
case OVS_ACTION_ATTR_SET:
- err = validate_set(a, key, sfa, &skip_copy);
+ err = validate_set(a, key, sfa,
+ &out_tnl_port, eth_type, log);
if (err)
return err;
+
+ skip_copy = out_tnl_port;
break;
case OVS_ACTION_ATTR_SAMPLE:
- err = validate_and_copy_sample(a, key, depth, sfa);
+ err = validate_and_copy_sample(a, key, depth, sfa,
+ eth_type, vlan_tci, log);
if (err)
return err;
skip_copy = true;
break;
default:
+ OVS_NLERR(log, "Unknown Action type %d", type);
return -EINVAL;
}
if (!skip_copy) {
- err = copy_action(a, sfa);
+ err = copy_action(a, sfa, log);
if (err)
return err;
}
return 0;
}
+int ovs_nla_copy_actions(const struct nlattr *attr,
+ const struct sw_flow_key *key,
+ struct sw_flow_actions **sfa, bool log)
+{
+ int err;
+
+ *sfa = nla_alloc_flow_actions(nla_len(attr), log);
+ if (IS_ERR(*sfa))
+ return PTR_ERR(*sfa);
+
+ err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type,
+ key->eth.tci, log);
+ if (err)
+ kfree(*sfa);
+
+ return err;
+}
+
static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb)
{
const struct nlattr *a;
#include "flow.h"
+size_t ovs_tun_key_attr_size(void);
+size_t ovs_key_attr_size(void);
+
void ovs_match_init(struct sw_flow_match *match,
struct sw_flow_key *key, struct sw_flow_mask *mask);
int ovs_nla_put_flow(const struct sw_flow_key *,
const struct sw_flow_key *, struct sk_buff *);
-int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *);
+int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *,
+ bool log);
-int ovs_nla_get_match(struct sw_flow_match *match,
- const struct nlattr *,
- const struct nlattr *);
+int ovs_nla_get_match(struct sw_flow_match *, const struct nlattr *key,
+ const struct nlattr *mask, bool log);
+int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
+ const struct ovs_tunnel_info *);
int ovs_nla_copy_actions(const struct nlattr *attr,
- const struct sw_flow_key *key, int depth,
- struct sw_flow_actions **sfa);
+ const struct sw_flow_key *key,
+ struct sw_flow_actions **sfa, bool log);
int ovs_nla_put_actions(const struct nlattr *attr,
int len, struct sk_buff *skb);
-struct sw_flow_actions *ovs_nla_alloc_flow_actions(int actions_len);
void ovs_nla_free_flow_actions(struct sw_flow_actions *);
#endif /* flow_netlink.h */
/*
- * Copyright (c) 2007-2013 Nicira, Inc.
+ * Copyright (c) 2007-2014 Nicira, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
return ERR_PTR(-ENOMEM);
}
-int ovs_flow_tbl_count(struct flow_table *table)
+int ovs_flow_tbl_count(const struct flow_table *table)
{
return table->count;
}
__table_instance_destroy(ti);
}
-void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
+/* No need for locking this function is called from RCU callback or
+ * error path.
+ */
+void ovs_flow_tbl_destroy(struct flow_table *table)
{
- struct table_instance *ti = ovsl_dereference(table->ti);
+ struct table_instance *ti = rcu_dereference_raw(table->ti);
- table_instance_destroy(ti, deferred);
+ table_instance_destroy(ti, false);
}
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
}
bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
- struct sw_flow_match *match)
+ const struct sw_flow_match *match)
{
struct sw_flow_key *key = match->key;
int key_start = flow_key_start(key);
static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
const struct sw_flow_key *unmasked,
- struct sw_flow_mask *mask)
+ const struct sw_flow_mask *mask)
{
struct sw_flow *flow;
struct hlist_head *head;
}
struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl,
- struct sw_flow_match *match)
+ const struct sw_flow_match *match)
{
struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
struct sw_flow_mask *mask;
/* Add 'mask' into the mask list, if it is not already there. */
static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
- struct sw_flow_mask *new)
+ const struct sw_flow_mask *new)
{
struct sw_flow_mask *mask;
mask = flow_mask_find(tbl, new);
/* Must be called with OVS mutex held. */
int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
- struct sw_flow_mask *mask)
+ const struct sw_flow_mask *mask)
{
struct table_instance *new_ti = NULL;
struct table_instance *ti;
void ovs_flow_free(struct sw_flow *, bool deferred);
int ovs_flow_tbl_init(struct flow_table *);
-int ovs_flow_tbl_count(struct flow_table *table);
-void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
+int ovs_flow_tbl_count(const struct flow_table *table);
+void ovs_flow_tbl_destroy(struct flow_table *table);
int ovs_flow_tbl_flush(struct flow_table *flow_table);
int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
- struct sw_flow_mask *mask);
+ const struct sw_flow_mask *mask);
void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
int ovs_flow_tbl_num_masks(const struct flow_table *table);
struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table,
struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *,
const struct sw_flow_key *);
struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl,
- struct sw_flow_match *match);
+ const struct sw_flow_match *match);
bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
- struct sw_flow_match *match);
+ const struct sw_flow_match *match);
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
const struct sw_flow_mask *mask);
#include <linux/rculist.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
+#include <linux/module.h>
#include <net/geneve.h>
#include <net/icmp.h>
#include "datapath.h"
#include "vport.h"
+static struct vport_ops ovs_geneve_vport_ops;
+
/**
* struct geneve_port - Keeps track of open UDP ports
* @gs: The socket created for this port number.
}
/* Convert 24 bit VNI to 64 bit tunnel ID. */
-static __be64 vni_to_tunnel_id(__u8 *vni)
+static __be64 vni_to_tunnel_id(const __u8 *vni)
{
#ifdef __BIG_ENDIAN
return (vni[0] << 16) | (vni[1] << 8) | vni[2];
key = vni_to_tunnel_id(geneveh->vni);
- ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags,
+ ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
+ udp_hdr(skb)->source, udp_hdr(skb)->dest,
+ key, flags,
geneveh->options, opts_len);
ovs_vport_receive(vport, skb, &tun_info);
return geneve_port->name;
}
-const struct vport_ops ovs_geneve_vport_ops = {
+static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ struct ovs_tunnel_info *egress_tun_info)
+{
+ struct geneve_port *geneve_port = geneve_vport(vport);
+ struct net *net = ovs_dp_get_net(vport->dp);
+ __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport;
+ __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
+
+ /* Get tp_src and tp_dst, refert to geneve_build_header().
+ */
+ return ovs_tunnel_get_egress_info(egress_tun_info,
+ ovs_dp_get_net(vport->dp),
+ OVS_CB(skb)->egress_tun_info,
+ IPPROTO_UDP, skb->mark, sport, dport);
+}
+
+static struct vport_ops ovs_geneve_vport_ops = {
.type = OVS_VPORT_TYPE_GENEVE,
.create = geneve_tnl_create,
.destroy = geneve_tnl_destroy,
.get_name = geneve_get_name,
.get_options = geneve_get_options,
.send = geneve_tnl_send,
+ .owner = THIS_MODULE,
+ .get_egress_tun_info = geneve_get_egress_tun_info,
};
+
+static int __init ovs_geneve_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_geneve_vport_ops);
+}
+
+static void __exit ovs_geneve_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_geneve_vport_ops);
+}
+
+module_init(ovs_geneve_tnl_init);
+module_exit(ovs_geneve_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: Geneve swiching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-5");
#include <linux/jhash.h>
#include <linux/list.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/rculist.h>
#include <net/route.h>
#include "datapath.h"
#include "vport.h"
+static struct vport_ops ovs_gre_vport_ops;
+
/* Returns the least-significant 32 bits of a __be64. */
static __be32 be64_get_low32(__be64 x)
{
return PACKET_REJECT;
key = key_to_tunnel_id(tpi->key, tpi->seq);
- ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key,
+ ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key,
filter_tnl_flags(tpi->flags), NULL, 0);
ovs_vport_receive(vport, skb, &tun_info);
gre_exit();
}
-const struct vport_ops ovs_gre_vport_ops = {
+static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ struct ovs_tunnel_info *egress_tun_info)
+{
+ return ovs_tunnel_get_egress_info(egress_tun_info,
+ ovs_dp_get_net(vport->dp),
+ OVS_CB(skb)->egress_tun_info,
+ IPPROTO_GRE, skb->mark, 0, 0);
+}
+
+static struct vport_ops ovs_gre_vport_ops = {
.type = OVS_VPORT_TYPE_GRE,
.create = gre_create,
.destroy = gre_tnl_destroy,
.get_name = gre_get_name,
.send = gre_tnl_send,
+ .get_egress_tun_info = gre_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_gre_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_gre_vport_ops);
+}
+
+static void __exit ovs_gre_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_gre_vport_ops);
+}
+
+module_init(ovs_gre_tnl_init);
+module_exit(ovs_gre_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: GRE switching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-3");
struct vport *vport;
};
+static struct vport_ops ovs_internal_vport_ops;
+
static struct internal_dev *internal_dev_priv(struct net_device *netdev)
{
return netdev_priv(netdev);
struct net_device *netdev = netdev_vport_priv(vport)->dev;
int len;
+ if (unlikely(!(netdev->flags & IFF_UP))) {
+ kfree_skb(skb);
+ return 0;
+ }
+
len = skb->len;
skb_dst_drop(skb);
return len;
}
-const struct vport_ops ovs_internal_vport_ops = {
+static struct vport_ops ovs_internal_vport_ops = {
.type = OVS_VPORT_TYPE_INTERNAL,
.create = internal_dev_create,
.destroy = internal_dev_destroy,
int ovs_internal_dev_rtnl_link_register(void)
{
- return rtnl_link_register(&internal_dev_link_ops);
+ int err;
+
+ err = rtnl_link_register(&internal_dev_link_ops);
+ if (err < 0)
+ return err;
+
+ err = ovs_vport_ops_register(&ovs_internal_vport_ops);
+ if (err < 0)
+ rtnl_link_unregister(&internal_dev_link_ops);
+
+ return err;
}
void ovs_internal_dev_rtnl_link_unregister(void)
{
+ ovs_vport_ops_unregister(&ovs_internal_vport_ops);
rtnl_link_unregister(&internal_dev_link_ops);
}
#include "vport-internal_dev.h"
#include "vport-netdev.h"
+static struct vport_ops ovs_netdev_vport_ops;
+
/* Must be called with rcu_read_lock. */
static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
{
return RX_HANDLER_CONSUMED;
}
-static struct net_device *get_dpdev(struct datapath *dp)
+static struct net_device *get_dpdev(const struct datapath *dp)
{
struct vport *local;
return NULL;
}
-const struct vport_ops ovs_netdev_vport_ops = {
+static struct vport_ops ovs_netdev_vport_ops = {
.type = OVS_VPORT_TYPE_NETDEV,
.create = netdev_create,
.destroy = netdev_destroy,
.get_name = ovs_netdev_get_name,
.send = netdev_send,
};
+
+int __init ovs_netdev_init(void)
+{
+ return ovs_vport_ops_register(&ovs_netdev_vport_ops);
+}
+
+void ovs_netdev_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_netdev_vport_ops);
+}
const char *ovs_netdev_get_name(const struct vport *);
void ovs_netdev_detach_dev(struct vport *);
+int __init ovs_netdev_init(void);
+void ovs_netdev_exit(void);
+
#endif /* vport_netdev.h */
#include <linux/net.h>
#include <linux/rculist.h>
#include <linux/udp.h>
+#include <linux/module.h>
#include <net/icmp.h>
#include <net/ip.h>
char name[IFNAMSIZ];
};
+static struct vport_ops ovs_vxlan_vport_ops;
+
static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
{
return vport_priv(vport);
/* Save outer tunnel values */
iph = ip_hdr(skb);
key = cpu_to_be64(ntohl(vx_vni) >> 8);
- ovs_flow_tun_info_init(&tun_info, iph, key, TUNNEL_KEY, NULL, 0);
+ ovs_flow_tun_info_init(&tun_info, iph,
+ udp_hdr(skb)->source, udp_hdr(skb)->dest,
+ key, TUNNEL_KEY, NULL, 0);
ovs_vport_receive(vport, skb, &tun_info);
}
return err;
}
+static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ struct ovs_tunnel_info *egress_tun_info)
+{
+ struct net *net = ovs_dp_get_net(vport->dp);
+ struct vxlan_port *vxlan_port = vxlan_vport(vport);
+ __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
+ __be16 src_port;
+ int port_min;
+ int port_max;
+
+ inet_get_local_port_range(net, &port_min, &port_max);
+ src_port = udp_flow_src_port(net, skb, 0, 0, true);
+
+ return ovs_tunnel_get_egress_info(egress_tun_info, net,
+ OVS_CB(skb)->egress_tun_info,
+ IPPROTO_UDP, skb->mark,
+ src_port, dst_port);
+}
+
static const char *vxlan_get_name(const struct vport *vport)
{
struct vxlan_port *vxlan_port = vxlan_vport(vport);
return vxlan_port->name;
}
-const struct vport_ops ovs_vxlan_vport_ops = {
+static struct vport_ops ovs_vxlan_vport_ops = {
.type = OVS_VPORT_TYPE_VXLAN,
.create = vxlan_tnl_create,
.destroy = vxlan_tnl_destroy,
.get_name = vxlan_get_name,
.get_options = vxlan_get_options,
.send = vxlan_tnl_send,
+ .get_egress_tun_info = vxlan_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_vxlan_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_vxlan_vport_ops);
+}
+
+static void __exit ovs_vxlan_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_vxlan_vport_ops);
+}
+
+module_init(ovs_vxlan_tnl_init);
+module_exit(ovs_vxlan_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: VXLAN switching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-4");
#include <linux/rtnetlink.h>
#include <linux/compat.h>
#include <net/net_namespace.h>
+#include <linux/module.h>
#include "datapath.h"
#include "vport.h"
static void ovs_vport_record_error(struct vport *,
enum vport_err_type err_type);
-/* List of statically compiled vport implementations. Don't forget to also
- * add yours to the list at the bottom of vport.h. */
-static const struct vport_ops *vport_ops_list[] = {
- &ovs_netdev_vport_ops,
- &ovs_internal_vport_ops,
-
-#ifdef CONFIG_OPENVSWITCH_GRE
- &ovs_gre_vport_ops,
-#endif
-#ifdef CONFIG_OPENVSWITCH_VXLAN
- &ovs_vxlan_vport_ops,
-#endif
-#ifdef CONFIG_OPENVSWITCH_GENEVE
- &ovs_geneve_vport_ops,
-#endif
-};
+static LIST_HEAD(vport_ops_list);
/* Protected by RCU read lock for reading, ovs_mutex for writing. */
static struct hlist_head *dev_table;
kfree(dev_table);
}
-static struct hlist_head *hash_bucket(struct net *net, const char *name)
+static struct hlist_head *hash_bucket(const struct net *net, const char *name)
{
unsigned int hash = jhash(name, strlen(name), (unsigned long) net);
return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
}
+int ovs_vport_ops_register(struct vport_ops *ops)
+{
+ int err = -EEXIST;
+ struct vport_ops *o;
+
+ ovs_lock();
+ list_for_each_entry(o, &vport_ops_list, list)
+ if (ops->type == o->type)
+ goto errout;
+
+ list_add_tail(&ops->list, &vport_ops_list);
+ err = 0;
+errout:
+ ovs_unlock();
+ return err;
+}
+EXPORT_SYMBOL_GPL(ovs_vport_ops_register);
+
+void ovs_vport_ops_unregister(struct vport_ops *ops)
+{
+ ovs_lock();
+ list_del(&ops->list);
+ ovs_unlock();
+}
+EXPORT_SYMBOL_GPL(ovs_vport_ops_unregister);
+
/**
* ovs_vport_locate - find a port that has already been created
*
*
* Must be called with ovs or RCU read lock.
*/
-struct vport *ovs_vport_locate(struct net *net, const char *name)
+struct vport *ovs_vport_locate(const struct net *net, const char *name)
{
struct hlist_head *bucket = hash_bucket(net, name);
struct vport *vport;
return vport;
}
+EXPORT_SYMBOL_GPL(ovs_vport_alloc);
/**
* ovs_vport_free - uninitialize and free vport
free_percpu(vport->percpu_stats);
kfree(vport);
}
+EXPORT_SYMBOL_GPL(ovs_vport_free);
+
+static struct vport_ops *ovs_vport_lookup(const struct vport_parms *parms)
+{
+ struct vport_ops *ops;
+
+ list_for_each_entry(ops, &vport_ops_list, list)
+ if (ops->type == parms->type)
+ return ops;
+
+ return NULL;
+}
/**
* ovs_vport_add - add vport device (for kernel callers)
*/
struct vport *ovs_vport_add(const struct vport_parms *parms)
{
+ struct vport_ops *ops;
struct vport *vport;
- int err = 0;
- int i;
- for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) {
- if (vport_ops_list[i]->type == parms->type) {
- struct hlist_head *bucket;
+ ops = ovs_vport_lookup(parms);
+ if (ops) {
+ struct hlist_head *bucket;
- vport = vport_ops_list[i]->create(parms);
- if (IS_ERR(vport)) {
- err = PTR_ERR(vport);
- goto out;
- }
+ if (!try_module_get(ops->owner))
+ return ERR_PTR(-EAFNOSUPPORT);
- bucket = hash_bucket(ovs_dp_get_net(vport->dp),
- vport->ops->get_name(vport));
- hlist_add_head_rcu(&vport->hash_node, bucket);
+ vport = ops->create(parms);
+ if (IS_ERR(vport)) {
+ module_put(ops->owner);
return vport;
}
+
+ bucket = hash_bucket(ovs_dp_get_net(vport->dp),
+ vport->ops->get_name(vport));
+ hlist_add_head_rcu(&vport->hash_node, bucket);
+ return vport;
}
- err = -EAFNOSUPPORT;
+ /* Unlock to attempt module load and return -EAGAIN if load
+ * was successful as we need to restart the port addition
+ * workflow.
+ */
+ ovs_unlock();
+ request_module("vport-type-%d", parms->type);
+ ovs_lock();
-out:
- return ERR_PTR(err);
+ if (!ovs_vport_lookup(parms))
+ return ERR_PTR(-EAFNOSUPPORT);
+ else
+ return ERR_PTR(-EAGAIN);
}
/**
hlist_del_rcu(&vport->hash_node);
vport->ops->destroy(vport);
+
+ module_put(vport->ops->owner);
}
/**
*
* Must be called with ovs_mutex.
*/
-int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids)
+int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids)
{
struct vport_portids *old, *vport_portids;
* skb->data should point to the Ethernet header.
*/
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
- struct ovs_tunnel_info *tun_info)
+ const struct ovs_tunnel_info *tun_info)
{
struct pcpu_sw_netstats *stats;
struct sw_flow_key key;
}
ovs_dp_process_packet(skb, &key);
}
+EXPORT_SYMBOL_GPL(ovs_vport_receive);
/**
* ovs_vport_send - send a packet on a device
call_rcu(&vport->rcu, free_vport_rcu);
}
+EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
+
+int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
+ struct net *net,
+ const struct ovs_tunnel_info *tun_info,
+ u8 ipproto,
+ u32 skb_mark,
+ __be16 tp_src,
+ __be16 tp_dst)
+{
+ const struct ovs_key_ipv4_tunnel *tun_key;
+ struct rtable *rt;
+ struct flowi4 fl;
+
+ if (unlikely(!tun_info))
+ return -EINVAL;
+
+ tun_key = &tun_info->tunnel;
+
+ /* Route lookup to get srouce IP address.
+ * The process may need to be changed if the corresponding process
+ * in vports ops changed.
+ */
+ memset(&fl, 0, sizeof(fl));
+ fl.daddr = tun_key->ipv4_dst;
+ fl.saddr = tun_key->ipv4_src;
+ fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos);
+ fl.flowi4_mark = skb_mark;
+ fl.flowi4_proto = IPPROTO_GRE;
+
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
+
+ ip_rt_put(rt);
+
+ /* Generate egress_tun_info based on tun_info,
+ * saddr, tp_src and tp_dst
+ */
+ __ovs_flow_tun_info_init(egress_tun_info,
+ fl.saddr, tun_key->ipv4_dst,
+ tun_key->ipv4_tos,
+ tun_key->ipv4_ttl,
+ tp_src, tp_dst,
+ tun_key->tun_id,
+ tun_key->tun_flags,
+ tun_info->options,
+ tun_info->options_len);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info);
+
+int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ struct ovs_tunnel_info *info)
+{
+ /* get_egress_tun_info() is only implemented on tunnel ports. */
+ if (unlikely(!vport->ops->get_egress_tun_info))
+ return -EINVAL;
+
+ return vport->ops->get_egress_tun_info(vport, skb, info);
+}
struct vport *ovs_vport_add(const struct vport_parms *);
void ovs_vport_del(struct vport *);
-struct vport *ovs_vport_locate(struct net *net, const char *name);
+struct vport *ovs_vport_locate(const struct net *net, const char *name);
void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *);
int ovs_vport_set_options(struct vport *, struct nlattr *options);
int ovs_vport_get_options(const struct vport *, struct sk_buff *);
-int ovs_vport_set_upcall_portids(struct vport *, struct nlattr *pids);
+int ovs_vport_set_upcall_portids(struct vport *, const struct nlattr *pids);
int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *);
u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *);
int ovs_vport_send(struct vport *, struct sk_buff *);
+int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
+ struct net *net,
+ const struct ovs_tunnel_info *tun_info,
+ u8 ipproto,
+ u32 skb_mark,
+ __be16 tp_src,
+ __be16 tp_dst);
+int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ struct ovs_tunnel_info *info);
+
/* The following definitions are for implementers of vport devices: */
struct vport_err_stats {
* @get_name: Get the device's name.
* @send: Send a packet on the device. Returns the length of the packet sent,
* zero for dropped packets or negative for error.
+ * @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for
+ * a packet.
*/
struct vport_ops {
enum ovs_vport_type type;
const char *(*get_name)(const struct vport *);
int (*send)(struct vport *, struct sk_buff *);
+ int (*get_egress_tun_info)(struct vport *, struct sk_buff *,
+ struct ovs_tunnel_info *);
+
+ struct module *owner;
+ struct list_head list;
};
enum vport_err_type {
}
void ovs_vport_receive(struct vport *, struct sk_buff *,
- struct ovs_tunnel_info *);
-
-/* List of statically compiled vport implementations. Don't forget to also
- * add yours to the list at the top of vport.c. */
-extern const struct vport_ops ovs_netdev_vport_ops;
-extern const struct vport_ops ovs_internal_vport_ops;
-extern const struct vport_ops ovs_gre_vport_ops;
-extern const struct vport_ops ovs_vxlan_vport_ops;
-extern const struct vport_ops ovs_geneve_vport_ops;
+ const struct ovs_tunnel_info *);
static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
const void *start, unsigned int len)
skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
}
+int ovs_vport_ops_register(struct vport_ops *ops);
+void ovs_vport_ops_unregister(struct vport_ops *ops);
+
#endif /* vport.h */
msg->msg_flags |= MSG_TRUNC;
}
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
if (err)
goto out_free;
out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
if (!out_dev) {
- LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n",
- pn_sockaddr_get_addr(&sa));
+ net_dbg_ratelimited("No Phonet route to %02X\n",
+ pn_sockaddr_get_addr(&sa));
goto out;
}
__skb_push(skb, sizeof(struct phonethdr));
skb->dev = out_dev;
if (out_dev == dev) {
- LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n",
- pn_sockaddr_get_addr(&sa), dev->name);
+ net_dbg_ratelimited("Phonet loop to %02X on %s\n",
+ pn_sockaddr_get_addr(&sa),
+ dev->name);
goto out_dev;
}
/* Some drivers (e.g. TUN) do not allocate HW header space */
copylen = len;
}
- rval = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copylen);
+ rval = skb_copy_datagram_msg(skb, 0, msg, copylen);
if (rval) {
rval = -EFAULT;
goto out;
len = skb->len;
err = pep_write(sk, skb);
if (err) {
- LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
- dev->name, err);
+ net_dbg_ratelimited("%s: TX error (%d)\n", dev->name, err);
dev->stats.tx_aborted_errors++;
dev->stats.tx_errors++;
} else {
hdr = pnp_hdr(skb);
if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
- LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
- (unsigned int)hdr->data[0]);
+ net_dbg_ratelimited("Phonet unknown PEP type: %u\n",
+ (unsigned int)hdr->data[0]);
return -EOPNOTSUPP;
}
break;
default:
- LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n",
- (unsigned int)hdr->data[1]);
+ net_dbg_ratelimited("Phonet unknown PEP indication: %u\n",
+ (unsigned int)hdr->data[1]);
return -EOPNOTSUPP;
}
if (wake)
break;
default:
- LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n",
- hdr->message_id);
+ net_dbg_ratelimited("Phonet unknown PEP message: %u\n",
+ hdr->message_id);
err = -EINVAL;
}
out:
else
len = skb->len;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+ err = skb_copy_datagram_msg(skb, 0, msg, len);
if (!err)
err = (flags & MSG_TRUNC) ? skb->len : len;
msg->msg_flags |= MSG_TRUNC;
}
- skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ skb_copy_datagram_msg(skb, 0, msg, copied);
if (msg->msg_name) {
struct sockaddr_rose *srose;
if (copy > len - copied)
copy = len - copied;
- ret = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copy);
+ ret = skb_copy_datagram_msg(skb, offset, msg, copy);
if (ret < 0)
goto copy_error;
/*
- * net/sched/gact.c Generic actions
+ * net/sched/act_gact.c Generic actions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
- * net/sched/ipt.c iptables target interface
+ * net/sched/act_ipt.c iptables target interface
*
*TODO: Add other tables. For now we only support the ipv4 table targets
*
/*
- * net/sched/mirred.c packet mirroring and redirect actions
+ * net/sched/act_mirred.c packet mirroring and redirect actions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
- * net/sched/pedit.c Generic packet editor
+ * net/sched/act_pedit.c Generic packet editor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
- * net/sched/police.c Input police filter.
+ * net/sched/act_police.c Input police filter
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
- * net/sched/simp.c Simple example of an action
+ * net/sched/act_simple.c Simple example of an action
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/* Time stamp put into socket buffer control block
* Only valid when skbs are in our internal t(ime)fifo queue.
+ *
+ * As skb->rbnode uses same storage than skb->next, skb->prev and skb->tstamp,
+ * and skb->next & skb->prev are scratch space for a qdisc,
+ * we save skb->tstamp value in skb->cb[] before destroying it.
*/
struct netem_skb_cb {
psched_time_t time_to_send;
ktime_t tstamp_save;
};
-/* Because space in skb->cb[] is tight, netem overloads skb->next/prev/tstamp
- * to hold a rb_node structure.
- *
- * If struct sk_buff layout is changed, the following checks will complain.
- */
-static struct rb_node *netem_rb_node(struct sk_buff *skb)
-{
- BUILD_BUG_ON(offsetof(struct sk_buff, next) != 0);
- BUILD_BUG_ON(offsetof(struct sk_buff, prev) !=
- offsetof(struct sk_buff, next) + sizeof(skb->next));
- BUILD_BUG_ON(offsetof(struct sk_buff, tstamp) !=
- offsetof(struct sk_buff, prev) + sizeof(skb->prev));
- BUILD_BUG_ON(sizeof(struct rb_node) > sizeof(skb->next) +
- sizeof(skb->prev) +
- sizeof(skb->tstamp));
- return (struct rb_node *)&skb->next;
-}
static struct sk_buff *netem_rb_to_skb(struct rb_node *rb)
{
- return (struct sk_buff *)rb;
+ return container_of(rb, struct sk_buff, rbnode);
}
static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
else
p = &parent->rb_left;
}
- rb_link_node(netem_rb_node(nskb), parent, p);
- rb_insert_color(netem_rb_node(nskb), &q->t_root);
+ rb_link_node(&nskb->rbnode, parent, p);
+ rb_insert_color(&nskb->rbnode, &q->t_root);
sch->q.qlen++;
}
if (*pos == 0)
seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
- "REM_ADDR_RTX START\n");
+ "REM_ADDR_RTX START STATE\n");
return (void *)pos;
}
* Note: We don't have a way to tally this at the moment
* so lets just leave it as zero for the moment
*/
- seq_printf(seq, "0 ");
+ seq_puts(seq, "0 ");
/*
* remote address start time (START). This is also not
* currently implemented, but we can record it with a
* jiffies marker in a subsequent patch
*/
- seq_printf(seq, "0");
+ seq_puts(seq, "0 ");
+
+ /*
+ * The current state of this destination. I.e.
+ * SCTP_ACTIVE, SCTP_INACTIVE, ...
+ */
+ seq_printf(seq, "%d", tsp->state);
seq_printf(seq, "\n");
}
if (copied > len)
copied = len;
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
event = sctp_skb2event(skb);
if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN))
goto out_free;
- if (!sctp_ulpevent_is_notification(event))
+ if (!sctp_ulpevent_is_notification(event)) {
sk_mark_napi_id(sk, skb);
-
+ sk_incoming_cpu_update(sk);
+ }
/* Check if the user wishes to receive this event. */
if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe))
goto out_free;
* @*headbuf: in: NULL for first frag, otherwise value returned from prev call
* out: set when successful non-complete reassembly, otherwise NULL
* @*buf: in: the buffer to append. Always defined
- * out: head buf after sucessful complete reassembly, otherwise NULL
+ * out: head buf after successful complete reassembly, otherwise NULL
* Returns 1 when reassembly complete, otherwise 0
*/
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
* @mtu: max allowable size for the bundle buffer, inclusive header
* @dnode: destination node for message. (Not always present in header)
* Replaces buffer if successful
- * Returns true if sucess, otherwise false
+ * Returns true if success, otherwise false
*/
bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode)
{
sz = buf_len;
m->msg_flags |= MSG_TRUNC;
}
- res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg),
- m->msg_iov, sz);
+ res = skb_copy_datagram_msg(buf, msg_hdr_sz(msg), m, sz);
if (res)
goto exit;
res = sz;
needed = (buf_len - sz_copied);
sz_to_copy = (sz <= needed) ? sz : needed;
- res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset,
- m->msg_iov, sz_to_copy);
+ res = skb_copy_datagram_msg(buf, msg_hdr_sz(msg) + offset,
+ m, sz_to_copy);
if (res)
goto exit;
* @tsk: TIPC socket
* @msg: message
*
- * Returns 0 (TIPC_OK) if everyting ok, -TIPC_ERR_NO_PORT otherwise
+ * Returns 0 (TIPC_OK) if everything ok, -TIPC_ERR_NO_PORT otherwise
*/
static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
{
else if (size < skb->len - skip)
msg->msg_flags |= MSG_TRUNC;
- err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
+ err = skb_copy_datagram_msg(skb, skip, msg, size);
if (err)
goto out_free;
}
chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size);
- if (skb_copy_datagram_iovec(skb, UNIXCB(skb).consumed + skip,
- msg->msg_iov, chunk)) {
+ if (skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip,
+ msg, chunk)) {
if (copied == 0)
copied = -EFAULT;
break;
}
/* Place the datagram payload in the user's iovec. */
- err = skb_copy_datagram_iovec(skb, sizeof(*dg), msg->msg_iov,
- payload_len);
+ err = skb_copy_datagram_msg(skb, sizeof(*dg), msg, payload_len);
if (err)
goto out;
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
EXPORT_SYMBOL(cfg80211_chandef_valid);
static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
- int *pri40, int *pri80)
+ u32 *pri40, u32 *pri80)
{
int tmp;
break;
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
*radar_detect |= BIT(wdev->chandef.width);
}
return;
+ case NL80211_IFTYPE_OCB:
+ if (wdev->chandef.chan) {
+ *chan = wdev->chandef.chan;
+ *chanmode = CHAN_MODE_SHARED;
+ return;
+ }
+ break;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
return &rdev->wiphy;
}
-int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
- char *newname)
+static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev,
+ const char *newname)
{
struct cfg80211_registered_device *rdev2;
- int wiphy_idx, taken = -1, result, digits;
+ int wiphy_idx, taken = -1, digits;
ASSERT_RTNL();
return -EINVAL;
}
+ /* Ensure another device does not already have this name. */
+ list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+ if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
+ char *newname)
+{
+ int result;
+
+ ASSERT_RTNL();
/* Ignore nop renames */
- if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+ if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0)
return 0;
- /* Ensure another device does not already have this name. */
- list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
- if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
- return -EINVAL;
+ result = cfg80211_dev_check_name(rdev, newname);
+ if (result < 0)
+ return result;
result = device_rename(&rdev->wiphy.dev, newname);
if (result)
/* exported functions */
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+ const char *requested_name)
{
static atomic_t wiphy_counter = ATOMIC_INIT(0);
rdev->wiphy_idx--;
/* give it a proper name */
- dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+ if (requested_name && requested_name[0]) {
+ int rv;
+
+ rtnl_lock();
+ rv = cfg80211_dev_check_name(rdev, requested_name);
+
+ if (rv < 0) {
+ rtnl_unlock();
+ goto use_default_name;
+ }
+
+ rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name);
+ rtnl_unlock();
+ if (rv)
+ goto use_default_name;
+ } else {
+use_default_name:
+ /* NOTE: This is *probably* safe w/out holding rtnl because of
+ * the restrictions on phy names. Probably this call could
+ * fail if some other part of the kernel (re)named a device
+ * phyX. But, might should add some locking and check return
+ * value, and use a different name if this one exists?
+ */
+ dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+ }
INIT_LIST_HEAD(&rdev->wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
return &rdev->wiphy;
}
-EXPORT_SYMBOL(wiphy_new);
+EXPORT_SYMBOL(wiphy_new_nm);
static int wiphy_verify_combinations(struct wiphy *wiphy)
{
case NL80211_IFTYPE_P2P_GO:
__cfg80211_stop_ap(rdev, dev, true);
break;
- default:
+ case NL80211_IFTYPE_OCB:
+ __cfg80211_leave_ocb(rdev, dev);
+ break;
+ case NL80211_IFTYPE_WDS:
+ /* must be handled by mac80211/driver, has no APIs */
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ /* cannot happen, has no netdev */
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_MONITOR:
+ /* nothing to do */
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NUM_NL80211_IFTYPES:
+ /* invalid */
break;
}
}
struct wireless_dev *wdev,
struct cfg80211_chan_def *chandef);
+/* OCB */
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ocb_setup *setup);
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ocb_setup *setup);
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev);
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev);
+
/* AP */
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool notify);
if (!wdev->current_bss)
return -ENOLINK;
break;
- default:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ case NL80211_IFTYPE_WDS:
+ case NUM_NL80211_IFTYPES:
return -EINVAL;
}
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
CMD(channel_switch, CHANNEL_SWITCH);
CMD(set_qos_map, SET_QOS_MAP);
- if (rdev->wiphy.flags &
- WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)
+ if (rdev->wiphy.features &
+ NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
CMD(add_tx_ts, ADD_TX_TS);
}
/* add into the if now */
!(rdev->wiphy.interface_modes & (1 << type)))
return -EOPNOTSUPP;
- if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) {
+ if ((type == NL80211_IFTYPE_P2P_DEVICE ||
+ rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
+ info->attrs[NL80211_ATTR_MAC]) {
nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
ETH_ALEN);
if (!is_valid_ether_addr(params.macaddr))
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
- u8 *mac_addr = NULL;
+ struct station_del_parameters params;
+
+ memset(¶ms, 0, sizeof(params));
if (info->attrs[NL80211_ATTR_MAC])
- mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
if (!rdev->ops->del_station)
return -EOPNOTSUPP;
- return rdev_del_station(rdev, dev, mac_addr);
+ if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
+ params.subtype =
+ nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
+ if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
+ params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
+ return -EINVAL;
+ } else {
+ /* Default to Deauthentication frame */
+ params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
+ }
+
+ if (info->attrs[NL80211_ATTR_REASON_CODE]) {
+ params.reason_code =
+ nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ if (params.reason_code == 0)
+ return -EINVAL; /* 0 is reserved */
+ } else {
+ /* Default to reason code 2 */
+ params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
+ }
+
+ return rdev_del_station(rdev, dev, ¶ms);
}
static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
return rdev_del_mpath(rdev, dev, dst);
}
+static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ int err;
+ struct net_device *dev = info->user_ptr[1];
+ struct mpath_info pinfo;
+ struct sk_buff *msg;
+ u8 *dst = NULL;
+ u8 mpp[ETH_ALEN];
+
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (!rdev->ops->get_mpp)
+ return -EOPNOTSUPP;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
+ if (err)
+ return err;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
+ dev, dst, mpp, &pinfo) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return genlmsg_reply(msg, info);
+}
+
+static int nl80211_dump_mpp(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct mpath_info pinfo;
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+ u8 dst[ETH_ALEN];
+ u8 mpp[ETH_ALEN];
+ int path_idx = cb->args[2];
+ int err;
+
+ err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+ if (err)
+ return err;
+
+ if (!rdev->ops->dump_mpp) {
+ err = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
+ err = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ while (1) {
+ err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
+ mpp, &pinfo);
+ if (err == -ENOENT)
+ break;
+ if (err)
+ goto out_err;
+
+ if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, dst, mpp,
+ &pinfo) < 0)
+ goto out;
+
+ path_idx++;
+ }
+
+ out:
+ cb->args[2] = path_idx;
+ err = skb->len;
+ out_err:
+ nl80211_finish_wdev_dump(rdev);
+ return err;
+}
+
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
* function is called under RTNL lock, so this should not be a problem.
*/
static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
- u8 radar_detect_width = 0;
int err;
bool need_new_beacon = false;
int len, i;
if (err < 0)
return err;
- if (err > 0) {
- radar_detect_width = BIT(params.chandef.width);
+ if (err > 0)
params.radar_required = true;
- }
if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
params.block_tx = true;
return -EINVAL;
}
+static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct ocb_setup setup = {};
+ int err;
+
+ err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+ if (err)
+ return err;
+
+ return cfg80211_join_ocb(rdev, dev, &setup);
+}
+
+static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+
+ return cfg80211_leave_ocb(rdev, dev);
+}
+
static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
u16 admitted_time = 0;
int err;
- if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
+ if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
return -EINVAL;
/* WMM uses TIDs 0-7 even for TSPEC */
- if (tsid < IEEE80211_FIRST_TSPEC_TSID) {
- if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
- return -EINVAL;
- } else {
+ if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
/* TODO: handle 802.11 TSPEC/admission control
- * need more attributes for that (e.g. BA session requirement)
+ * need more attributes for that (e.g. BA session requirement);
+ * change the WMM adminssion test above to allow both then
*/
return -EINVAL;
}
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_GET_MPP,
+ .doit = nl80211_get_mpp,
+ .dumpit = nl80211_dump_mpp,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
{
.cmd = NL80211_CMD_SET_MPATH,
.doit = nl80211_set_mpath,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_JOIN_OCB,
+ .doit = nl80211_join_ocb,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_LEAVE_OCB,
+ .doit = nl80211_leave_ocb,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
#ifdef CONFIG_PM
{
.cmd = NL80211_CMD_GET_WOWLAN,
--- /dev/null
+/*
+ * OCB mode implementation
+ *
+ * Copyright: (c) 2014 Czech Technical University in Prague
+ * (c) 2014 Volkswagen Group Research
+ * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+#include "core.h"
+#include "rdev-ops.h"
+
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ocb_setup *setup)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+ return -EOPNOTSUPP;
+
+ if (WARN_ON(!setup->chandef.chan))
+ return -EINVAL;
+
+ err = rdev_join_ocb(rdev, dev, setup);
+ if (!err)
+ wdev->chandef = setup->chandef;
+
+ return err;
+}
+
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ocb_setup *setup)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_join_ocb(rdev, dev, setup);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->leave_ocb)
+ return -EOPNOTSUPP;
+
+ err = rdev_leave_ocb(rdev, dev);
+ if (!err)
+ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+
+ return err;
+}
+
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ wdev_lock(wdev);
+ err = __cfg80211_leave_ocb(rdev, dev);
+ wdev_unlock(wdev);
+
+ return err;
+}
}
static inline int rdev_del_station(struct cfg80211_registered_device *rdev,
- struct net_device *dev, u8 *mac)
+ struct net_device *dev,
+ struct station_del_parameters *params)
{
int ret;
- trace_rdev_del_station(&rdev->wiphy, dev, mac);
- ret = rdev->ops->del_station(&rdev->wiphy, dev, mac);
+ trace_rdev_del_station(&rdev->wiphy, dev, params);
+ ret = rdev->ops->del_station(&rdev->wiphy, dev, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
}
+static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ int ret;
+
+ trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
+ ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
+ trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+ return ret;
+}
+
static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, int idx, u8 *dst,
u8 *next_hop, struct mpath_info *pinfo)
int ret;
trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
- pinfo);
+ pinfo);
+ trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+ return ret;
+}
+
+static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, int idx, u8 *dst,
+ u8 *mpp, struct mpath_info *pinfo)
+
+{
+ int ret;
+
+ trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
+ ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
return ret;
}
return ret;
}
+static inline int rdev_join_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct ocb_setup *setup)
+{
+ int ret;
+ trace_rdev_join_ocb(&rdev->wiphy, dev, setup);
+ ret = rdev->ops->join_ocb(&rdev->wiphy, dev, setup);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int rdev_leave_ocb(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ int ret;
+ trace_rdev_leave_ocb(&rdev->wiphy, dev);
+ ret = rdev->ops->leave_ocb(&rdev->wiphy, dev);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline int rdev_change_bss(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct bss_parameters *params)
if (!request)
return -ENOMEM;
- if (wdev->conn->params.channel)
+ if (wdev->conn->params.channel) {
+ enum ieee80211_band band = wdev->conn->params.channel->band;
+ struct ieee80211_supported_band *sband =
+ wdev->wiphy->bands[band];
+
+ if (!sband) {
+ kfree(request);
+ return -EINVAL;
+ }
request->channels[0] = wdev->conn->params.channel;
- else {
+ request->rates[band] = (1 << sband->n_bitrates) - 1;
+ } else {
int i = 0, j;
enum ieee80211_band band;
struct ieee80211_supported_band *bands;
TP_ARGS(wiphy, netdev)
);
+DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ocb,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+ TP_ARGS(wiphy, netdev)
+);
+
DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
TP_ARGS(wiphy, netdev)
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac))
);
-DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station,
- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
- TP_ARGS(wiphy, netdev, mac)
+DECLARE_EVENT_CLASS(station_del,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct station_del_parameters *params),
+ TP_ARGS(wiphy, netdev, params),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(sta_mac)
+ __field(u8, subtype)
+ __field(u16, reason_code)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(sta_mac, params->mac);
+ __entry->subtype = params->subtype;
+ __entry->reason_code = params->reason_code;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+ ", subtype: %u, reason_code: %u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
+ __entry->subtype, __entry->reason_code)
+);
+
+DEFINE_EVENT(station_del, rdev_del_station,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct station_del_parameters *params),
+ TP_ARGS(wiphy, netdev, params)
);
DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station,
MAC_PR_ARG(next_hop))
);
+TRACE_EVENT(rdev_get_mpp,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ u8 *dst, u8 *mpp),
+ TP_ARGS(wiphy, netdev, dst, mpp),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(dst)
+ MAC_ENTRY(mpp)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(dst, dst);
+ MAC_ASSIGN(mpp, mpp);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
+ ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
+ MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
+);
+
+TRACE_EVENT(rdev_dump_mpp,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+ u8 *dst, u8 *mpp),
+ TP_ARGS(wiphy, netdev, idx, mpp, dst),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(dst)
+ MAC_ENTRY(mpp)
+ __field(int, idx)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(dst, dst);
+ MAC_ASSIGN(mpp, mpp);
+ __entry->idx = idx;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
+ MAC_PR_FMT ", mpp: " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
+ MAC_PR_ARG(mpp))
+);
+
TRACE_EVENT(rdev_return_int_mpath_info,
TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
TP_ARGS(wiphy, ret, pinfo),
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid)
);
+TRACE_EVENT(rdev_join_ocb,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ const struct ocb_setup *setup),
+ TP_ARGS(wiphy, netdev, setup),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
TRACE_EVENT(rdev_set_wiphy_params,
TP_PROTO(struct wiphy *wiphy, u32 changed),
TP_ARGS(wiphy, changed),
break;
case cpu_to_le16(0):
if (iftype != NL80211_IFTYPE_ADHOC &&
- iftype != NL80211_IFTYPE_STATION)
+ iftype != NL80211_IFTYPE_STATION &&
+ iftype != NL80211_IFTYPE_OCB)
return -1;
break;
}
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
break;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
if (dev->ieee80211_ptr->use_4addr)
break;
/* fall through */
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_ADHOC:
dev->priv_flags |= IFF_DONT_BRIDGE;
/* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR;
- rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ rc = skb_copy_datagram_msg(skb, 0, msg, copied);
if (rc)
goto out_free_dgram;
},
.result = ACCEPT,
},
+ {
+ "jump test 5",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 2),
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8),
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .result = ACCEPT,
+ },
};
static int probe_filter_length(struct bpf_insn *fp)
static int test(void)
{
- int prog_fd, i;
+ int prog_fd, i, pass_cnt = 0, err_cnt = 0;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
struct bpf_insn *prog = tests[i].insns;
printf("FAIL\nfailed to load prog '%s'\n",
strerror(errno));
printf("%s", bpf_log_buf);
+ err_cnt++;
goto fail;
}
} else {
if (prog_fd >= 0) {
printf("FAIL\nunexpected success to load\n");
printf("%s", bpf_log_buf);
+ err_cnt++;
goto fail;
}
if (strstr(bpf_log_buf, tests[i].errstr) == 0) {
printf("FAIL\nunexpected error message: %s",
bpf_log_buf);
+ err_cnt++;
goto fail;
}
}
+ pass_cnt++;
printf("OK\n");
fail:
if (map_fd >= 0)
close(prog_fd);
}
+ printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt);
return 0;
}