mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Highlights:
- Gustavo A. R. Silva keeps working on the implicit switch fallthru
changes.
- Support 802.11ax High-Efficiency wireless in cfg80211 et al, From
Luca Coelho.
- Re-enable ASPM in r8169, from Kai-Heng Feng.
- Add virtual XFRM interfaces, which avoids all of the limitations of
existing IPSEC tunnels. From Steffen Klassert.
- Convert GRO over to use a hash table, so that when we have many
flows active we don't traverse a long list during accumluation.
- Many new self tests for routing, TC, tunnels, etc. Too many
contributors to mention them all, but I'm really happy to keep
seeing this stuff.
- Hardware timestamping support for dpaa_eth/fsl-fman from Yangbo Lu.
- Lots of cleanups and fixes in L2TP code from Guillaume Nault.
- Add IPSEC offload support to netdevsim, from Shannon Nelson.
- Add support for slotting with non-uniform distribution to netem
packet scheduler, from Yousuk Seung.
- Add UDP GSO support to mlx5e, from Boris Pismenny.
- Support offloading of Team LAG in NFP, from John Hurley.
- Allow to configure TX queue selection based upon RX queue, from
Amritha Nambiar.
- Support ethtool ring size configuration in aquantia, from Anton
Mikaev.
- Support DSCP and flowlabel per-transport in SCTP, from Xin Long.
- Support list based batching and stack traversal of SKBs, this is
very exciting work. From Edward Cree.
- Busyloop optimizations in vhost_net, from Toshiaki Makita.
- Introduce the ETF qdisc, which allows time based transmissions. IGB
can offload this in hardware. From Vinicius Costa Gomes.
- Add parameter support to devlink, from Moshe Shemesh.
- Several multiplication and division optimizations for BPF JIT in
nfp driver, from Jiong Wang.
- Lots of prepatory work to make more of the packet scheduler layer
lockless, when possible, from Vlad Buslov.
- Add ACK filter and NAT awareness to sch_cake packet scheduler, from
Toke Høiland-Jørgensen.
- Support regions and region snapshots in devlink, from Alex Vesker.
- Allow to attach XDP programs to both HW and SW at the same time on
a given device, with initial support in nfp. From Jakub Kicinski.
- Add TLS RX offload and support in mlx5, from Ilya Lesokhin.
- Use PHYLIB in r8169 driver, from Heiner Kallweit.
- All sorts of changes to support Spectrum 2 in mlxsw driver, from
Ido Schimmel.
- PTP support in mv88e6xxx DSA driver, from Andrew Lunn.
- Make TCP_USER_TIMEOUT socket option more accurate, from Jon
Maxwell.
- Support for templates in packet scheduler classifier, from Jiri
Pirko.
- IPV6 support in RDS, from Ka-Cheong Poon.
- Native tproxy support in nf_tables, from Máté Eckl.
- Maintain IP fragment queue in an rbtree, but optimize properly for
in-order frags. From Peter Oskolkov.
- Improvde handling of ACKs on hole repairs, from Yuchung Cheng"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1996 commits)
bpf: test: fix spelling mistake "REUSEEPORT" -> "REUSEPORT"
hv/netvsc: Fix NULL dereference at single queue mode fallback
net: filter: mark expected switch fall-through
xen-netfront: fix warn message as irq device name has '/'
cxgb4: Add new T5 PCI device ids 0x50af and 0x50b0
net: dsa: mv88e6xxx: missing unlock on error path
rds: fix building with IPV6=m
inet/connection_sock: prefer _THIS_IP_ to current_text_addr
net: dsa: mv88e6xxx: bitwise vs logical bug
net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
ieee802154: hwsim: using right kind of iteration
net: hns3: Add vlan filter setting by ethtool command -K
net: hns3: Set tx ring' tc info when netdev is up
net: hns3: Remove tx ring BD len register in hns3_enet
net: hns3: Fix desc num set to default when setting channel
net: hns3: Fix for phy link issue when using marvell phy driver
net: hns3: Fix for information of phydev lost problem when down/up
net: hns3: Fix for command format parsing error in hclge_is_all_function_id_zero
net: hns3: Add support for serdes loopback selftest
bnxt_en: take coredump_record structure off stack
...
This commit is contained in:
commit
9a76aba02a
1752 changed files with 119401 additions and 29298 deletions
|
|
@ -95,4 +95,14 @@ config CCWGROUP
|
|||
tristate
|
||||
default (LCS || CTCM || QETH)
|
||||
|
||||
config ISM
|
||||
tristate "Support for ISM vPCI Adapter"
|
||||
depends on PCI && SMC
|
||||
default n
|
||||
help
|
||||
Select this option if you want to use the Internal Shared Memory
|
||||
vPCI Adapter.
|
||||
|
||||
To compile as a module choose M. The module name is ism.
|
||||
If unsure, choose N.
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -15,3 +15,6 @@ qeth_l2-y += qeth_l2_main.o qeth_l2_sys.o
|
|||
obj-$(CONFIG_QETH_L2) += qeth_l2.o
|
||||
qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o
|
||||
obj-$(CONFIG_QETH_L3) += qeth_l3.o
|
||||
|
||||
ism-y := ism_drv.o
|
||||
obj-$(CONFIG_ISM) += ism.o
|
||||
|
|
|
|||
221
drivers/s390/net/ism.h
Normal file
221
drivers/s390/net/ism.h
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef S390_ISM_H
|
||||
#define S390_ISM_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <net/smc.h>
|
||||
|
||||
#define UTIL_STR_LEN 16
|
||||
|
||||
/*
|
||||
* Do not use the first word of the DMB bits to ensure 8 byte aligned access.
|
||||
*/
|
||||
#define ISM_DMB_WORD_OFFSET 1
|
||||
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
|
||||
#define ISM_NR_DMBS 1920
|
||||
|
||||
#define ISM_REG_SBA 0x1
|
||||
#define ISM_REG_IEQ 0x2
|
||||
#define ISM_READ_GID 0x3
|
||||
#define ISM_ADD_VLAN_ID 0x4
|
||||
#define ISM_DEL_VLAN_ID 0x5
|
||||
#define ISM_SET_VLAN 0x6
|
||||
#define ISM_RESET_VLAN 0x7
|
||||
#define ISM_QUERY_INFO 0x8
|
||||
#define ISM_QUERY_RGID 0x9
|
||||
#define ISM_REG_DMB 0xA
|
||||
#define ISM_UNREG_DMB 0xB
|
||||
#define ISM_SIGNAL_IEQ 0xE
|
||||
#define ISM_UNREG_SBA 0x11
|
||||
#define ISM_UNREG_IEQ 0x12
|
||||
|
||||
#define ISM_ERROR 0xFFFF
|
||||
|
||||
struct ism_req_hdr {
|
||||
u32 cmd;
|
||||
u16 : 16;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
struct ism_resp_hdr {
|
||||
u32 cmd;
|
||||
u16 ret;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
union ism_reg_sba {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 sba;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
union ism_reg_ieq {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 ieq;
|
||||
u64 len;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
union ism_read_gid {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
u64 gid;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
union ism_qi {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
u32 version;
|
||||
u32 max_len;
|
||||
u64 ism_state;
|
||||
u64 my_gid;
|
||||
u64 sba;
|
||||
u64 ieq;
|
||||
u32 ieq_len;
|
||||
u32 : 32;
|
||||
u32 dmbs_owned;
|
||||
u32 dmbs_used;
|
||||
u32 vlan_required;
|
||||
u32 vlan_nr_ids;
|
||||
u16 vlan_id[64];
|
||||
} response;
|
||||
} __aligned(64);
|
||||
|
||||
union ism_query_rgid {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 rgid;
|
||||
u32 vlan_valid;
|
||||
u32 vlan_id;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
union ism_reg_dmb {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 dmb;
|
||||
u32 dmb_len;
|
||||
u32 sba_idx;
|
||||
u32 vlan_valid;
|
||||
u32 vlan_id;
|
||||
u64 rgid;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
u64 dmb_tok;
|
||||
} response;
|
||||
} __aligned(32);
|
||||
|
||||
union ism_sig_ieq {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 rgid;
|
||||
u32 trigger_irq;
|
||||
u32 event_code;
|
||||
u64 info;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(32);
|
||||
|
||||
union ism_unreg_dmb {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 dmb_tok;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
union ism_cmd_simple {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(8);
|
||||
|
||||
union ism_set_vlan_id {
|
||||
struct {
|
||||
struct ism_req_hdr hdr;
|
||||
u64 vlan_id;
|
||||
} request;
|
||||
struct {
|
||||
struct ism_resp_hdr hdr;
|
||||
} response;
|
||||
} __aligned(16);
|
||||
|
||||
struct ism_eq_header {
|
||||
u64 idx;
|
||||
u64 ieq_len;
|
||||
u64 entry_len;
|
||||
u64 : 64;
|
||||
};
|
||||
|
||||
struct ism_eq {
|
||||
struct ism_eq_header header;
|
||||
struct smcd_event entry[15];
|
||||
};
|
||||
|
||||
struct ism_sba {
|
||||
u32 s : 1; /* summary bit */
|
||||
u32 e : 1; /* event bit */
|
||||
u32 : 30;
|
||||
u32 dmb_bits[ISM_NR_DMBS / 32];
|
||||
u32 reserved[3];
|
||||
u16 dmbe_mask[ISM_NR_DMBS];
|
||||
};
|
||||
|
||||
struct ism_dev {
|
||||
spinlock_t lock;
|
||||
struct pci_dev *pdev;
|
||||
struct smcd_dev *smcd;
|
||||
|
||||
void __iomem *ctl;
|
||||
|
||||
struct ism_sba *sba;
|
||||
dma_addr_t sba_dma_addr;
|
||||
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
|
||||
|
||||
struct ism_eq *ieq;
|
||||
dma_addr_t ieq_dma_addr;
|
||||
|
||||
int ieq_idx;
|
||||
};
|
||||
|
||||
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \
|
||||
((dmb) | (idx) << 24 | (sf) << 23 | (offset))
|
||||
|
||||
static inline int __ism_move(struct ism_dev *ism, u64 dmb_req, void *data,
|
||||
unsigned int size)
|
||||
{
|
||||
struct zpci_dev *zdev = to_zpci(ism->pdev);
|
||||
u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, size);
|
||||
|
||||
return zpci_write_block(req, data, dmb_req);
|
||||
}
|
||||
|
||||
#endif /* S390_ISM_H */
|
||||
623
drivers/s390/net/ism_drv.c
Normal file
623
drivers/s390/net/ism_drv.c
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ISM driver for s390.
|
||||
*
|
||||
* Copyright IBM Corp. 2018
|
||||
*/
|
||||
#define KMSG_COMPONENT "ism"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/err.h>
|
||||
#include <net/smc.h>
|
||||
|
||||
#include <asm/debug.h>
|
||||
|
||||
#include "ism.h"
|
||||
|
||||
MODULE_DESCRIPTION("ISM driver for s390");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define PCI_DEVICE_ID_IBM_ISM 0x04ED
|
||||
#define DRV_NAME "ism"
|
||||
|
||||
static const struct pci_device_id ism_device_table[] = {
|
||||
{ PCI_VDEVICE(IBM, PCI_DEVICE_ID_IBM_ISM), 0 },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ism_device_table);
|
||||
|
||||
static debug_info_t *ism_debug_info;
|
||||
|
||||
static int ism_cmd(struct ism_dev *ism, void *cmd)
|
||||
{
|
||||
struct ism_req_hdr *req = cmd;
|
||||
struct ism_resp_hdr *resp = cmd;
|
||||
|
||||
memcpy_toio(ism->ctl + sizeof(*req), req + 1, req->len - sizeof(*req));
|
||||
memcpy_toio(ism->ctl, req, sizeof(*req));
|
||||
|
||||
WRITE_ONCE(resp->ret, ISM_ERROR);
|
||||
|
||||
memcpy_fromio(resp, ism->ctl, sizeof(*resp));
|
||||
if (resp->ret) {
|
||||
debug_text_event(ism_debug_info, 0, "cmd failure");
|
||||
debug_event(ism_debug_info, 0, resp, sizeof(*resp));
|
||||
goto out;
|
||||
}
|
||||
memcpy_fromio(resp + 1, ism->ctl + sizeof(*resp),
|
||||
resp->len - sizeof(*resp));
|
||||
out:
|
||||
return resp->ret;
|
||||
}
|
||||
|
||||
static int ism_cmd_simple(struct ism_dev *ism, u32 cmd_code)
|
||||
{
|
||||
union ism_cmd_simple cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = cmd_code;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
return ism_cmd(ism, &cmd);
|
||||
}
|
||||
|
||||
static int query_info(struct ism_dev *ism)
|
||||
{
|
||||
union ism_qi cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_QUERY_INFO;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
if (ism_cmd(ism, &cmd))
|
||||
goto out;
|
||||
|
||||
debug_text_event(ism_debug_info, 3, "query info");
|
||||
debug_event(ism_debug_info, 3, &cmd.response, sizeof(cmd.response));
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_sba(struct ism_dev *ism)
|
||||
{
|
||||
union ism_reg_sba cmd;
|
||||
dma_addr_t dma_handle;
|
||||
struct ism_sba *sba;
|
||||
|
||||
sba = dma_zalloc_coherent(&ism->pdev->dev, PAGE_SIZE,
|
||||
&dma_handle, GFP_KERNEL);
|
||||
if (!sba)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_REG_SBA;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
cmd.request.sba = dma_handle;
|
||||
|
||||
if (ism_cmd(ism, &cmd)) {
|
||||
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, sba, dma_handle);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ism->sba = sba;
|
||||
ism->sba_dma_addr = dma_handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ieq(struct ism_dev *ism)
|
||||
{
|
||||
union ism_reg_ieq cmd;
|
||||
dma_addr_t dma_handle;
|
||||
struct ism_eq *ieq;
|
||||
|
||||
ieq = dma_zalloc_coherent(&ism->pdev->dev, PAGE_SIZE,
|
||||
&dma_handle, GFP_KERNEL);
|
||||
if (!ieq)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_REG_IEQ;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
cmd.request.ieq = dma_handle;
|
||||
cmd.request.len = sizeof(*ieq);
|
||||
|
||||
if (ism_cmd(ism, &cmd)) {
|
||||
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, ieq, dma_handle);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ism->ieq = ieq;
|
||||
ism->ieq_idx = -1;
|
||||
ism->ieq_dma_addr = dma_handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unregister_sba(struct ism_dev *ism)
|
||||
{
|
||||
if (!ism->sba)
|
||||
return 0;
|
||||
|
||||
if (ism_cmd_simple(ism, ISM_UNREG_SBA))
|
||||
return -EIO;
|
||||
|
||||
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
|
||||
ism->sba, ism->sba_dma_addr);
|
||||
|
||||
ism->sba = NULL;
|
||||
ism->sba_dma_addr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unregister_ieq(struct ism_dev *ism)
|
||||
{
|
||||
if (!ism->ieq)
|
||||
return 0;
|
||||
|
||||
if (ism_cmd_simple(ism, ISM_UNREG_IEQ))
|
||||
return -EIO;
|
||||
|
||||
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
|
||||
ism->ieq, ism->ieq_dma_addr);
|
||||
|
||||
ism->ieq = NULL;
|
||||
ism->ieq_dma_addr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ism_read_local_gid(struct ism_dev *ism)
|
||||
{
|
||||
union ism_read_gid cmd;
|
||||
int ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_READ_GID;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
ret = ism_cmd(ism, &cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ism->smcd->local_gid = cmd.response.gid;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ism_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
|
||||
u32 vid)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_query_rgid cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_QUERY_RGID;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.rgid = rgid;
|
||||
cmd.request.vlan_valid = vid_valid;
|
||||
cmd.request.vlan_id = vid;
|
||||
|
||||
return ism_cmd(ism, &cmd);
|
||||
}
|
||||
|
||||
static void ism_free_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
|
||||
{
|
||||
clear_bit(dmb->sba_idx, ism->sba_bitmap);
|
||||
dma_free_coherent(&ism->pdev->dev, dmb->dmb_len,
|
||||
dmb->cpu_addr, dmb->dma_addr);
|
||||
}
|
||||
|
||||
static int ism_alloc_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
|
||||
{
|
||||
unsigned long bit;
|
||||
|
||||
if (PAGE_ALIGN(dmb->dmb_len) > dma_get_max_seg_size(&ism->pdev->dev))
|
||||
return -EINVAL;
|
||||
|
||||
if (!dmb->sba_idx) {
|
||||
bit = find_next_zero_bit(ism->sba_bitmap, ISM_NR_DMBS,
|
||||
ISM_DMB_BIT_OFFSET);
|
||||
if (bit == ISM_NR_DMBS)
|
||||
return -ENOMEM;
|
||||
|
||||
dmb->sba_idx = bit;
|
||||
}
|
||||
if (dmb->sba_idx < ISM_DMB_BIT_OFFSET ||
|
||||
test_and_set_bit(dmb->sba_idx, ism->sba_bitmap))
|
||||
return -EINVAL;
|
||||
|
||||
dmb->cpu_addr = dma_zalloc_coherent(&ism->pdev->dev, dmb->dmb_len,
|
||||
&dmb->dma_addr, GFP_KERNEL |
|
||||
__GFP_NOWARN | __GFP_NOMEMALLOC |
|
||||
__GFP_COMP | __GFP_NORETRY);
|
||||
if (!dmb->cpu_addr)
|
||||
clear_bit(dmb->sba_idx, ism->sba_bitmap);
|
||||
|
||||
return dmb->cpu_addr ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static int ism_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_reg_dmb cmd;
|
||||
int ret;
|
||||
|
||||
ret = ism_alloc_dmb(ism, dmb);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_REG_DMB;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.dmb = dmb->dma_addr;
|
||||
cmd.request.dmb_len = dmb->dmb_len;
|
||||
cmd.request.sba_idx = dmb->sba_idx;
|
||||
cmd.request.vlan_valid = dmb->vlan_valid;
|
||||
cmd.request.vlan_id = dmb->vlan_id;
|
||||
cmd.request.rgid = dmb->rgid;
|
||||
|
||||
ret = ism_cmd(ism, &cmd);
|
||||
if (ret) {
|
||||
ism_free_dmb(ism, dmb);
|
||||
goto out;
|
||||
}
|
||||
dmb->dmb_tok = cmd.response.dmb_tok;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ism_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_unreg_dmb cmd;
|
||||
int ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_UNREG_DMB;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.dmb_tok = dmb->dmb_tok;
|
||||
|
||||
ret = ism_cmd(ism, &cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ism_free_dmb(ism, dmb);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ism_add_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_set_vlan_id cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_ADD_VLAN_ID;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.vlan_id = vlan_id;
|
||||
|
||||
return ism_cmd(ism, &cmd);
|
||||
}
|
||||
|
||||
static int ism_del_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_set_vlan_id cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_DEL_VLAN_ID;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.vlan_id = vlan_id;
|
||||
|
||||
return ism_cmd(ism, &cmd);
|
||||
}
|
||||
|
||||
static int ism_set_vlan_required(struct smcd_dev *smcd)
|
||||
{
|
||||
return ism_cmd_simple(smcd->priv, ISM_SET_VLAN);
|
||||
}
|
||||
|
||||
static int ism_reset_vlan_required(struct smcd_dev *smcd)
|
||||
{
|
||||
return ism_cmd_simple(smcd->priv, ISM_RESET_VLAN);
|
||||
}
|
||||
|
||||
static int ism_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq,
|
||||
u32 event_code, u64 info)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
union ism_sig_ieq cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.request.hdr.cmd = ISM_SIGNAL_IEQ;
|
||||
cmd.request.hdr.len = sizeof(cmd.request);
|
||||
|
||||
cmd.request.rgid = rgid;
|
||||
cmd.request.trigger_irq = trigger_irq;
|
||||
cmd.request.event_code = event_code;
|
||||
cmd.request.info = info;
|
||||
|
||||
return ism_cmd(ism, &cmd);
|
||||
}
|
||||
|
||||
static unsigned int max_bytes(unsigned int start, unsigned int len,
|
||||
unsigned int boundary)
|
||||
{
|
||||
return min(boundary - (start & (boundary - 1)), len);
|
||||
}
|
||||
|
||||
static int ism_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
|
||||
bool sf, unsigned int offset, void *data, unsigned int size)
|
||||
{
|
||||
struct ism_dev *ism = smcd->priv;
|
||||
unsigned int bytes;
|
||||
u64 dmb_req;
|
||||
int ret;
|
||||
|
||||
while (size) {
|
||||
bytes = max_bytes(offset, size, PAGE_SIZE);
|
||||
dmb_req = ISM_CREATE_REQ(dmb_tok, idx, size == bytes ? sf : 0,
|
||||
offset);
|
||||
|
||||
ret = __ism_move(ism, dmb_req, data, bytes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
size -= bytes;
|
||||
data += bytes;
|
||||
offset += bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ism_handle_event(struct ism_dev *ism)
|
||||
{
|
||||
struct smcd_event *entry;
|
||||
|
||||
while ((ism->ieq_idx + 1) != READ_ONCE(ism->ieq->header.idx)) {
|
||||
if (++(ism->ieq_idx) == ARRAY_SIZE(ism->ieq->entry))
|
||||
ism->ieq_idx = 0;
|
||||
|
||||
entry = &ism->ieq->entry[ism->ieq_idx];
|
||||
debug_event(ism_debug_info, 2, entry, sizeof(*entry));
|
||||
smcd_handle_event(ism->smcd, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ism_handle_irq(int irq, void *data)
|
||||
{
|
||||
struct ism_dev *ism = data;
|
||||
unsigned long bit, end;
|
||||
unsigned long *bv;
|
||||
|
||||
bv = (void *) &ism->sba->dmb_bits[ISM_DMB_WORD_OFFSET];
|
||||
end = sizeof(ism->sba->dmb_bits) * BITS_PER_BYTE - ISM_DMB_BIT_OFFSET;
|
||||
|
||||
spin_lock(&ism->lock);
|
||||
ism->sba->s = 0;
|
||||
barrier();
|
||||
for (bit = 0;;) {
|
||||
bit = find_next_bit_inv(bv, end, bit);
|
||||
if (bit >= end)
|
||||
break;
|
||||
|
||||
clear_bit_inv(bit, bv);
|
||||
barrier();
|
||||
smcd_handle_irq(ism->smcd, bit + ISM_DMB_BIT_OFFSET);
|
||||
ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0;
|
||||
}
|
||||
|
||||
if (ism->sba->e) {
|
||||
ism->sba->e = 0;
|
||||
barrier();
|
||||
ism_handle_event(ism);
|
||||
}
|
||||
spin_unlock(&ism->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct smcd_ops ism_ops = {
|
||||
.query_remote_gid = ism_query_rgid,
|
||||
.register_dmb = ism_register_dmb,
|
||||
.unregister_dmb = ism_unregister_dmb,
|
||||
.add_vlan_id = ism_add_vlan_id,
|
||||
.del_vlan_id = ism_del_vlan_id,
|
||||
.set_vlan_required = ism_set_vlan_required,
|
||||
.reset_vlan_required = ism_reset_vlan_required,
|
||||
.signal_event = ism_signal_ieq,
|
||||
.move_data = ism_move,
|
||||
};
|
||||
|
||||
static int ism_dev_init(struct ism_dev *ism)
|
||||
{
|
||||
struct pci_dev *pdev = ism->pdev;
|
||||
int ret;
|
||||
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
ret = request_irq(pci_irq_vector(pdev, 0), ism_handle_irq, 0,
|
||||
pci_name(pdev), ism);
|
||||
if (ret)
|
||||
goto free_vectors;
|
||||
|
||||
ret = register_sba(ism);
|
||||
if (ret)
|
||||
goto free_irq;
|
||||
|
||||
ret = register_ieq(ism);
|
||||
if (ret)
|
||||
goto unreg_sba;
|
||||
|
||||
ret = ism_read_local_gid(ism);
|
||||
if (ret)
|
||||
goto unreg_ieq;
|
||||
|
||||
ret = smcd_register_dev(ism->smcd);
|
||||
if (ret)
|
||||
goto unreg_ieq;
|
||||
|
||||
query_info(ism);
|
||||
return 0;
|
||||
|
||||
unreg_ieq:
|
||||
unregister_ieq(ism);
|
||||
unreg_sba:
|
||||
unregister_sba(ism);
|
||||
free_irq:
|
||||
free_irq(pci_irq_vector(pdev, 0), ism);
|
||||
free_vectors:
|
||||
pci_free_irq_vectors(pdev);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ism_dev *ism;
|
||||
int ret;
|
||||
|
||||
ism = kzalloc(sizeof(*ism), GFP_KERNEL);
|
||||
if (!ism)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&ism->lock);
|
||||
dev_set_drvdata(&pdev->dev, ism);
|
||||
ism->pdev = pdev;
|
||||
|
||||
ret = pci_enable_device_mem(pdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = pci_request_mem_regions(pdev, DRV_NAME);
|
||||
if (ret)
|
||||
goto err_disable;
|
||||
|
||||
ism->ctl = pci_iomap(pdev, 2, 0);
|
||||
if (!ism->ctl)
|
||||
goto err_resource;
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
pci_set_dma_seg_boundary(pdev, SZ_1M - 1);
|
||||
pci_set_dma_max_seg_size(pdev, SZ_1M);
|
||||
pci_set_master(pdev);
|
||||
|
||||
ism->smcd = smcd_alloc_dev(&pdev->dev, dev_name(&pdev->dev), &ism_ops,
|
||||
ISM_NR_DMBS);
|
||||
if (!ism->smcd)
|
||||
goto err_unmap;
|
||||
|
||||
ism->smcd->priv = ism;
|
||||
ret = ism_dev_init(ism);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
smcd_free_dev(ism->smcd);
|
||||
err_unmap:
|
||||
pci_iounmap(pdev, ism->ctl);
|
||||
err_resource:
|
||||
pci_release_mem_regions(pdev);
|
||||
err_disable:
|
||||
pci_disable_device(pdev);
|
||||
err:
|
||||
kfree(ism);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ism_dev_exit(struct ism_dev *ism)
|
||||
{
|
||||
struct pci_dev *pdev = ism->pdev;
|
||||
|
||||
smcd_unregister_dev(ism->smcd);
|
||||
unregister_ieq(ism);
|
||||
unregister_sba(ism);
|
||||
free_irq(pci_irq_vector(pdev, 0), ism);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
static void ism_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ism_dev *ism = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
ism_dev_exit(ism);
|
||||
|
||||
smcd_free_dev(ism->smcd);
|
||||
pci_iounmap(pdev, ism->ctl);
|
||||
pci_release_mem_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
kfree(ism);
|
||||
}
|
||||
|
||||
static int ism_suspend(struct device *dev)
|
||||
{
|
||||
struct ism_dev *ism = dev_get_drvdata(dev);
|
||||
|
||||
ism_dev_exit(ism);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ism_resume(struct device *dev)
|
||||
{
|
||||
struct ism_dev *ism = dev_get_drvdata(dev);
|
||||
|
||||
return ism_dev_init(ism);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ism_pm_ops, ism_suspend, ism_resume);
|
||||
|
||||
static struct pci_driver ism_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = ism_device_table,
|
||||
.probe = ism_probe,
|
||||
.remove = ism_remove,
|
||||
.driver = {
|
||||
.pm = &ism_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ism_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ism_debug_info = debug_register("ism", 2, 1, 16);
|
||||
if (!ism_debug_info)
|
||||
return -ENODEV;
|
||||
|
||||
debug_register_view(ism_debug_info, &debug_hex_ascii_view);
|
||||
ret = pci_register_driver(&ism_driver);
|
||||
if (ret)
|
||||
debug_unregister(ism_debug_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ism_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ism_driver);
|
||||
debug_unregister(ism_debug_info);
|
||||
}
|
||||
|
||||
module_init(ism_init);
|
||||
module_exit(ism_exit);
|
||||
|
|
@ -104,6 +104,7 @@ struct qeth_dbf_info {
|
|||
struct qeth_perf_stats {
|
||||
unsigned int bufs_rec;
|
||||
unsigned int bufs_sent;
|
||||
unsigned int buf_elements_sent;
|
||||
|
||||
unsigned int skbs_sent_pack;
|
||||
unsigned int bufs_sent_pack;
|
||||
|
|
@ -137,7 +138,6 @@ struct qeth_perf_stats {
|
|||
unsigned int large_send_bytes;
|
||||
unsigned int large_send_cnt;
|
||||
unsigned int sg_skbs_sent;
|
||||
unsigned int sg_frags_sent;
|
||||
/* initial values when measuring starts */
|
||||
unsigned long initial_rx_packets;
|
||||
unsigned long initial_tx_packets;
|
||||
|
|
@ -235,6 +235,8 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
|
|||
#define QETH_IDX_FUNC_LEVEL_IQD 0x4108
|
||||
|
||||
#define QETH_BUFSIZE 4096
|
||||
#define CCW_CMD_WRITE 0x01
|
||||
#define CCW_CMD_READ 0x02
|
||||
|
||||
/**
|
||||
* some more defs
|
||||
|
|
@ -465,7 +467,6 @@ struct qeth_qdio_out_buffer {
|
|||
struct sk_buff_head skb_list;
|
||||
int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER];
|
||||
|
||||
struct qaob *aob;
|
||||
struct qeth_qdio_out_q *q;
|
||||
struct qeth_qdio_out_buffer *next_pending;
|
||||
};
|
||||
|
|
@ -593,7 +594,7 @@ static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
|
|||
*/
|
||||
struct qeth_channel {
|
||||
enum qeth_channel_states state;
|
||||
struct ccw1 ccw;
|
||||
struct ccw1 *ccw;
|
||||
spinlock_t iob_lock;
|
||||
wait_queue_head_t wait_q;
|
||||
struct ccw_device *ccwdev;
|
||||
|
|
@ -659,12 +660,8 @@ struct qeth_card_info {
|
|||
char mcl_level[QETH_MCL_LENGTH + 1];
|
||||
int guestlan;
|
||||
int mac_bits;
|
||||
int portno;
|
||||
enum qeth_card_types type;
|
||||
enum qeth_link_types link_type;
|
||||
int is_multicast_different;
|
||||
int initial_mtu;
|
||||
int max_mtu;
|
||||
int broadcast_capable;
|
||||
int unique_id;
|
||||
bool layer_enforced;
|
||||
|
|
@ -935,6 +932,19 @@ static inline int qeth_send_simple_setassparms_v6(struct qeth_card *card,
|
|||
data, QETH_PROT_IPV6);
|
||||
}
|
||||
|
||||
int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
|
||||
int ipv);
|
||||
static inline struct qeth_qdio_out_q *qeth_get_tx_queue(struct qeth_card *card,
|
||||
struct sk_buff *skb,
|
||||
int ipv, int cast_type)
|
||||
{
|
||||
if (IS_IQD(card) && cast_type != RTN_UNICAST)
|
||||
return card->qdio.out_qs[card->qdio.no_out_queues - 1];
|
||||
if (!card->qdio.do_prio_queueing)
|
||||
return card->qdio.out_qs[card->qdio.default_out_queue];
|
||||
return card->qdio.out_qs[qeth_get_priority_queue(card, skb, ipv)];
|
||||
}
|
||||
|
||||
extern struct qeth_discipline qeth_l2_discipline;
|
||||
extern struct qeth_discipline qeth_l3_discipline;
|
||||
extern const struct attribute_group *qeth_generic_attr_groups[];
|
||||
|
|
@ -955,6 +965,7 @@ extern struct qeth_card_list_struct qeth_core_card_list;
|
|||
extern struct kmem_cache *qeth_core_header_cache;
|
||||
extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS];
|
||||
|
||||
struct net_device *qeth_clone_netdev(struct net_device *orig);
|
||||
void qeth_set_recovery_task(struct qeth_card *);
|
||||
void qeth_clear_recovery_task(struct qeth_card *);
|
||||
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
|
||||
|
|
@ -972,7 +983,6 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
|
|||
void *);
|
||||
struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
|
||||
enum qeth_ipa_cmds, enum qeth_prot_versions);
|
||||
int qeth_query_setadapterparms(struct qeth_card *);
|
||||
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
|
||||
struct qeth_qdio_buffer *, struct qdio_buffer_element **, int *,
|
||||
struct qeth_hdr **);
|
||||
|
|
@ -985,24 +995,18 @@ void qeth_clear_cmd_buffers(struct qeth_channel *);
|
|||
void qeth_clear_qdio_buffers(struct qeth_card *);
|
||||
void qeth_setadp_promisc_mode(struct qeth_card *);
|
||||
struct net_device_stats *qeth_get_stats(struct net_device *);
|
||||
int qeth_change_mtu(struct net_device *, int);
|
||||
int qeth_setadpparms_change_macaddr(struct qeth_card *);
|
||||
void qeth_tx_timeout(struct net_device *);
|
||||
void qeth_prepare_control_data(struct qeth_card *, int,
|
||||
struct qeth_cmd_buffer *);
|
||||
void qeth_release_buffer(struct qeth_channel *, struct qeth_cmd_buffer *);
|
||||
void qeth_prepare_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, char);
|
||||
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob);
|
||||
struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
|
||||
int qeth_query_switch_attributes(struct qeth_card *card,
|
||||
struct qeth_switch_info *sw_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);
|
||||
int qeth_bridgeport_query_ports(struct qeth_card *card,
|
||||
enum qeth_sbp_roles *role, enum qeth_sbp_states *state);
|
||||
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
|
||||
int qeth_bridgeport_an_set(struct qeth_card *card, int enable);
|
||||
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
|
||||
int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb,
|
||||
int extra_elems, int data_offset);
|
||||
int qeth_get_elements_for_frags(struct sk_buff *);
|
||||
|
|
@ -1026,7 +1030,6 @@ int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);
|
|||
int qeth_hdr_chk_and_bounce(struct sk_buff *, struct qeth_hdr **, int);
|
||||
int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
|
||||
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
|
||||
int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
|
||||
void qeth_trace_features(struct qeth_card *);
|
||||
void qeth_close_dev(struct qeth_card *);
|
||||
int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
|
||||
|
|
@ -1046,7 +1049,9 @@ netdev_features_t qeth_features_check(struct sk_buff *skb,
|
|||
struct net_device *dev,
|
||||
netdev_features_t features);
|
||||
int qeth_vm_request_mac(struct qeth_card *card);
|
||||
int qeth_push_hdr(struct sk_buff *skb, struct qeth_hdr **hdr, unsigned int len);
|
||||
int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_hdr **hdr, unsigned int hdr_len,
|
||||
unsigned int proto_len, unsigned int *elements);
|
||||
|
||||
/* exports for OSN */
|
||||
int qeth_osn_assist(struct net_device *, void *, int);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -146,17 +146,6 @@ unsigned char IPA_PDU_HEADER[] = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(IPA_PDU_HEADER);
|
||||
|
||||
unsigned char WRITE_CCW[] = {
|
||||
0x01, CCW_FLAG_SLI, 0, 0,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
unsigned char READ_CCW[] = {
|
||||
0x02, CCW_FLAG_SLI, 0, 0,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
struct ipa_rc_msg {
|
||||
enum qeth_ipa_return_codes rc;
|
||||
char *msg;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ enum qeth_card_types {
|
|||
QETH_CARD_TYPE_OSX = 2,
|
||||
};
|
||||
|
||||
#define IS_IQD(card) ((card)->info.type == QETH_CARD_TYPE_IQD)
|
||||
#define IS_OSN(card) ((card)->info.type == QETH_CARD_TYPE_OSN)
|
||||
|
||||
#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
|
||||
/* only the first two bytes are looked at in qeth_get_cardname_short */
|
||||
enum qeth_link_types {
|
||||
|
|
@ -815,10 +818,6 @@ extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
|
|||
/* END OF IP Assist related definitions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
extern unsigned char WRITE_CCW[];
|
||||
extern unsigned char READ_CCW[];
|
||||
|
||||
extern unsigned char CM_ENABLE[];
|
||||
#define CM_ENABLE_SIZE 0x63
|
||||
#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer + 0x2c)
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ static ssize_t qeth_dev_portno_show(struct device *dev,
|
|||
if (!card)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%i\n", card->info.portno);
|
||||
return sprintf(buf, "%i\n", card->dev->dev_port);
|
||||
}
|
||||
|
||||
static ssize_t qeth_dev_portno_store(struct device *dev,
|
||||
|
|
@ -143,9 +143,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
|
|||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
card->info.portno = portno;
|
||||
if (card->dev)
|
||||
card->dev->dev_port = portno;
|
||||
card->dev->dev_port = portno;
|
||||
out:
|
||||
mutex_unlock(&card->conf_mutex);
|
||||
return rc ? rc : count;
|
||||
|
|
@ -388,6 +386,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(dev);
|
||||
struct net_device *ndev;
|
||||
char *tmp;
|
||||
int i, rc = 0;
|
||||
enum qeth_discipline_id newdis;
|
||||
|
|
@ -424,8 +423,19 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
|
|||
|
||||
card->info.mac_bits = 0;
|
||||
if (card->discipline) {
|
||||
/* start with a new, pristine netdevice: */
|
||||
ndev = qeth_clone_netdev(card->dev);
|
||||
if (!ndev) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
card->discipline->remove(card->gdev);
|
||||
qeth_core_free_discipline(card);
|
||||
card->options.layer2 = -1;
|
||||
|
||||
free_netdev(card->dev);
|
||||
card->dev = ndev;
|
||||
}
|
||||
|
||||
rc = qeth_core_load_discipline(card, newdis);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ extern const struct attribute_group *qeth_l2_attr_groups[];
|
|||
int qeth_l2_create_device_attributes(struct device *);
|
||||
void qeth_l2_remove_device_attributes(struct device *);
|
||||
void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
|
||||
int qeth_bridgeport_query_ports(struct qeth_card *card,
|
||||
enum qeth_sbp_roles *role,
|
||||
enum qeth_sbp_states *state);
|
||||
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
|
||||
int qeth_bridgeport_an_set(struct qeth_card *card, int enable);
|
||||
|
||||
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state);
|
||||
int qeth_l2_vnicc_get_state(struct qeth_card *card, u32 vnicc, bool *state);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
static int qeth_l2_set_offline(struct ccwgroup_device *);
|
||||
static int qeth_l2_stop(struct net_device *);
|
||||
static void qeth_l2_set_rx_mode(struct net_device *);
|
||||
static void qeth_bridgeport_query_support(struct qeth_card *card);
|
||||
static void qeth_bridge_state_change(struct qeth_card *card,
|
||||
struct qeth_ipa_cmd *cmd);
|
||||
|
|
@ -186,12 +185,12 @@ static void qeth_l2_del_all_macs(struct qeth_card *card)
|
|||
static int qeth_l2_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
|
||||
{
|
||||
if (card->info.type == QETH_CARD_TYPE_OSN)
|
||||
return RTN_UNSPEC;
|
||||
return RTN_UNICAST;
|
||||
if (is_broadcast_ether_addr(skb->data))
|
||||
return RTN_BROADCAST;
|
||||
if (is_multicast_ether_addr(skb->data))
|
||||
return RTN_MULTICAST;
|
||||
return RTN_UNSPEC;
|
||||
return RTN_UNICAST;
|
||||
}
|
||||
|
||||
static void qeth_l2_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb,
|
||||
|
|
@ -344,7 +343,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
|
|||
rc = qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
|
||||
kfree(tmpid);
|
||||
}
|
||||
qeth_l2_set_rx_mode(card->dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -643,97 +641,58 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
|
|||
qeth_promisc_to_bridge(card);
|
||||
}
|
||||
|
||||
static int qeth_l2_xmit_iqd(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int cast_type)
|
||||
static int qeth_l2_xmit(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int cast_type, int ipv)
|
||||
{
|
||||
unsigned int data_offset = ETH_HLEN;
|
||||
struct qeth_hdr *hdr;
|
||||
int rc;
|
||||
|
||||
hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
|
||||
if (!hdr)
|
||||
return -ENOMEM;
|
||||
qeth_l2_fill_header(hdr, skb, cast_type, skb->len);
|
||||
skb_copy_from_linear_data(skb, ((char *)hdr) + sizeof(*hdr),
|
||||
data_offset);
|
||||
|
||||
if (!qeth_get_elements_no(card, skb, 1, data_offset)) {
|
||||
rc = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
|
||||
sizeof(*hdr) + data_offset);
|
||||
out:
|
||||
if (rc)
|
||||
kmem_cache_free(qeth_core_header_cache, hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int cast_type,
|
||||
int ipv)
|
||||
{
|
||||
int push_len = sizeof(struct qeth_hdr);
|
||||
unsigned int elements, nr_frags;
|
||||
unsigned int hdr_elements = 0;
|
||||
const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0;
|
||||
const unsigned int hw_hdr_len = sizeof(struct qeth_hdr);
|
||||
unsigned int frame_len = skb->len;
|
||||
unsigned int data_offset = 0;
|
||||
struct qeth_hdr *hdr = NULL;
|
||||
unsigned int hd_len = 0;
|
||||
int rc;
|
||||
unsigned int elements;
|
||||
int push_len, rc;
|
||||
bool is_sg;
|
||||
|
||||
/* fix hardware limitation: as long as we do not have sbal
|
||||
* chaining we can not send long frag lists
|
||||
*/
|
||||
if (!qeth_get_elements_no(card, skb, 0, 0)) {
|
||||
rc = skb_linearize(skb);
|
||||
|
||||
if (card->options.performance_stats) {
|
||||
if (rc)
|
||||
card->perf_stats.tx_linfail++;
|
||||
else
|
||||
card->perf_stats.tx_lin++;
|
||||
}
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
rc = skb_cow_head(skb, push_len);
|
||||
rc = skb_cow_head(skb, hw_hdr_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
push_len = qeth_push_hdr(skb, &hdr, push_len);
|
||||
|
||||
push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
|
||||
&elements);
|
||||
if (push_len < 0)
|
||||
return push_len;
|
||||
if (!push_len) {
|
||||
/* hdr was allocated from cache */
|
||||
hd_len = sizeof(*hdr);
|
||||
hdr_elements = 1;
|
||||
/* HW header needs its own buffer element. */
|
||||
hd_len = hw_hdr_len + proto_len;
|
||||
data_offset = proto_len;
|
||||
}
|
||||
qeth_l2_fill_header(hdr, skb, cast_type, skb->len - push_len);
|
||||
qeth_l2_fill_header(hdr, skb, cast_type, frame_len);
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.tx_csum++;
|
||||
}
|
||||
|
||||
elements = qeth_get_elements_no(card, skb, hdr_elements, 0);
|
||||
if (!elements) {
|
||||
rc = -E2BIG;
|
||||
goto out;
|
||||
is_sg = skb_is_nonlinear(skb);
|
||||
if (IS_IQD(card)) {
|
||||
rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
|
||||
hd_len);
|
||||
} else {
|
||||
/* TODO: drop skb_orphan() once TX completion is fast enough */
|
||||
skb_orphan(skb);
|
||||
rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
|
||||
hd_len, elements);
|
||||
}
|
||||
elements += hdr_elements;
|
||||
|
||||
/* TODO: remove the skb_orphan() once TX completion is fast enough */
|
||||
skb_orphan(skb);
|
||||
rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len, elements);
|
||||
out:
|
||||
if (!rc) {
|
||||
if (card->options.performance_stats && nr_frags) {
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
/* nr_frags + skb->data */
|
||||
card->perf_stats.sg_frags_sent += nr_frags + 1;
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.buf_elements_sent += elements;
|
||||
if (is_sg)
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
}
|
||||
} else {
|
||||
if (hd_len)
|
||||
if (!push_len)
|
||||
kmem_cache_free(qeth_core_header_cache, hdr);
|
||||
if (rc == -EBUSY)
|
||||
/* roll back to ETH header */
|
||||
|
|
@ -770,34 +729,23 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
|
|||
int tx_bytes = skb->len;
|
||||
int rc;
|
||||
|
||||
if (card->qdio.do_prio_queueing || (cast_type &&
|
||||
card->info.is_multicast_different))
|
||||
queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb,
|
||||
ipv, cast_type)];
|
||||
else
|
||||
queue = card->qdio.out_qs[card->qdio.default_out_queue];
|
||||
|
||||
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
|
||||
card->stats.tx_carrier_errors++;
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
|
||||
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.outbound_cnt++;
|
||||
card->perf_stats.outbound_start_time = qeth_get_micros();
|
||||
}
|
||||
netif_stop_queue(dev);
|
||||
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_OSN:
|
||||
if (IS_OSN(card))
|
||||
rc = qeth_l2_xmit_osn(card, skb, queue);
|
||||
break;
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
rc = qeth_l2_xmit_iqd(card, skb, queue, cast_type);
|
||||
break;
|
||||
default:
|
||||
rc = qeth_l2_xmit_osa(card, skb, queue, cast_type, ipv);
|
||||
}
|
||||
else
|
||||
rc = qeth_l2_xmit(card, skb, queue, cast_type, ipv);
|
||||
|
||||
if (!rc) {
|
||||
card->stats.tx_packets++;
|
||||
|
|
@ -906,13 +854,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
|
|||
|
||||
if (cgdev->state == CCWGROUP_ONLINE)
|
||||
qeth_l2_set_offline(cgdev);
|
||||
|
||||
if (card->dev) {
|
||||
unregister_netdev(card->dev);
|
||||
free_netdev(card->dev);
|
||||
card->dev = NULL;
|
||||
}
|
||||
return;
|
||||
unregister_netdev(card->dev);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops qeth_l2_ethtool_ops = {
|
||||
|
|
@ -941,7 +883,6 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
|
|||
.ndo_set_rx_mode = qeth_l2_set_rx_mode,
|
||||
.ndo_do_ioctl = qeth_do_ioctl,
|
||||
.ndo_set_mac_address = qeth_l2_set_mac_address,
|
||||
.ndo_change_mtu = qeth_change_mtu,
|
||||
.ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid,
|
||||
.ndo_tx_timeout = qeth_tx_timeout,
|
||||
|
|
@ -951,35 +892,19 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
|
|||
|
||||
static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
{
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN,
|
||||
ether_setup);
|
||||
break;
|
||||
case QETH_CARD_TYPE_OSN:
|
||||
card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN,
|
||||
ether_setup);
|
||||
break;
|
||||
default:
|
||||
card->dev = alloc_etherdev(0);
|
||||
}
|
||||
int rc;
|
||||
|
||||
if (!card->dev)
|
||||
return -ENODEV;
|
||||
if (card->dev->netdev_ops)
|
||||
return 0;
|
||||
|
||||
card->dev->ml_priv = card;
|
||||
card->dev->priv_flags |= IFF_UNICAST_FLT;
|
||||
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
|
||||
card->dev->mtu = card->info.initial_mtu;
|
||||
card->dev->min_mtu = 64;
|
||||
card->dev->max_mtu = ETH_MAX_MTU;
|
||||
card->dev->dev_port = card->info.portno;
|
||||
card->dev->netdev_ops = &qeth_l2_netdev_ops;
|
||||
if (card->info.type == QETH_CARD_TYPE_OSN) {
|
||||
card->dev->ethtool_ops = &qeth_l2_osn_ops;
|
||||
card->dev->flags |= IFF_NOARP;
|
||||
} else {
|
||||
card->dev->ethtool_ops = &qeth_l2_ethtool_ops;
|
||||
card->dev->needed_headroom = sizeof(struct qeth_hdr);
|
||||
}
|
||||
|
||||
if (card->info.type == QETH_CARD_TYPE_OSM)
|
||||
|
|
@ -987,14 +912,6 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
|||
else
|
||||
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
|
||||
if (card->info.type != QETH_CARD_TYPE_OSN &&
|
||||
card->info.type != QETH_CARD_TYPE_IQD) {
|
||||
card->dev->priv_flags &= ~IFF_TX_SKB_SHARING;
|
||||
card->dev->needed_headroom = sizeof(struct qeth_hdr);
|
||||
card->dev->hw_features |= NETIF_F_SG;
|
||||
card->dev->vlan_features |= NETIF_F_SG;
|
||||
}
|
||||
|
||||
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
|
||||
card->dev->features |= NETIF_F_SG;
|
||||
/* OSA 3S and earlier has no RX/TX support */
|
||||
|
|
@ -1013,12 +930,12 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
|||
card->dev->vlan_features |= NETIF_F_RXCSUM;
|
||||
}
|
||||
|
||||
card->info.broadcast_capable = 1;
|
||||
qeth_l2_request_initial_mac(card);
|
||||
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
|
||||
netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
|
||||
netif_carrier_off(card->dev);
|
||||
return register_netdev(card->dev);
|
||||
rc = register_netdev(card->dev);
|
||||
if (rc)
|
||||
card->dev->netdev_ops = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l2_start_ipassists(struct qeth_card *card)
|
||||
|
|
@ -1064,10 +981,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
|||
dev_info(&card->gdev->dev,
|
||||
"The device represents a Bridge Capable Port\n");
|
||||
|
||||
if (!card->dev && qeth_l2_setup_netdev(card)) {
|
||||
rc = -ENODEV;
|
||||
rc = qeth_l2_setup_netdev(card);
|
||||
if (rc)
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
if (card->info.type != QETH_CARD_TYPE_OSN &&
|
||||
!qeth_l2_send_setmac(card, card->dev->dev_addr))
|
||||
|
|
@ -1125,13 +1041,12 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
|||
if (recovery_mode &&
|
||||
card->info.type != QETH_CARD_TYPE_OSN) {
|
||||
__qeth_l2_open(card->dev);
|
||||
qeth_l2_set_rx_mode(card->dev);
|
||||
} else {
|
||||
rtnl_lock();
|
||||
dev_open(card->dev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
/* this also sets saved unicast addresses */
|
||||
qeth_l2_set_rx_mode(card->dev);
|
||||
}
|
||||
/* let user_space know that device is online */
|
||||
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
|
||||
|
|
@ -1171,8 +1086,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
|
|||
QETH_DBF_TEXT(SETUP, 3, "setoffl");
|
||||
QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
|
||||
|
||||
if (card->dev && netif_carrier_ok(card->dev))
|
||||
netif_carrier_off(card->dev);
|
||||
netif_carrier_off(card->dev);
|
||||
recover_flag = card->state;
|
||||
if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
|
||||
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
|
||||
|
|
@ -1245,8 +1159,7 @@ static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
|
|||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
|
||||
|
||||
if (card->dev)
|
||||
netif_device_detach(card->dev);
|
||||
netif_device_detach(card->dev);
|
||||
qeth_set_allowed_threads(card, 0, 1);
|
||||
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
|
||||
if (gdev->state == CCWGROUP_OFFLINE)
|
||||
|
|
@ -1279,8 +1192,7 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
|
|||
rc = __qeth_l2_set_online(card->gdev, 0);
|
||||
out:
|
||||
qeth_set_allowed_threads(card, 0xffffffff, 0);
|
||||
if (card->dev)
|
||||
netif_device_attach(card->dev);
|
||||
netif_device_attach(card->dev);
|
||||
if (rc)
|
||||
dev_warn(&card->gdev->dev, "The qeth device driver "
|
||||
"failed to recover an error on the device\n");
|
||||
|
|
@ -1327,25 +1239,26 @@ EXPORT_SYMBOL_GPL(qeth_l2_discipline);
|
|||
static int qeth_osn_send_control_data(struct qeth_card *card, int len,
|
||||
struct qeth_cmd_buffer *iob)
|
||||
{
|
||||
struct qeth_channel *channel = iob->channel;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
QETH_CARD_TEXT(card, 5, "osndctrd");
|
||||
|
||||
wait_event(card->wait_q,
|
||||
atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
|
||||
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
|
||||
qeth_prepare_control_data(card, len, iob);
|
||||
QETH_CARD_TEXT(card, 6, "osnoirqp");
|
||||
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
|
||||
rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
|
||||
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
|
||||
(addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
if (rc) {
|
||||
QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
|
||||
"ccw_device_start rc = %i\n", rc);
|
||||
QETH_CARD_TEXT_(card, 2, " err%d", rc);
|
||||
qeth_release_buffer(iob->channel, iob);
|
||||
atomic_set(&card->write.irq_pending, 0);
|
||||
qeth_release_buffer(channel, iob);
|
||||
atomic_set(&channel->irq_pending, 0);
|
||||
wake_up(&card->wait_q);
|
||||
}
|
||||
return rc;
|
||||
|
|
@ -1358,7 +1271,7 @@ static int qeth_osn_send_ipa_cmd(struct qeth_card *card,
|
|||
|
||||
QETH_CARD_TEXT(card, 4, "osndipa");
|
||||
|
||||
qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);
|
||||
qeth_prepare_ipa_cmd(card, iob);
|
||||
s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);
|
||||
s2 = (u16)data_len;
|
||||
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
|
||||
|
|
@ -1877,7 +1790,6 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
|
|||
return rc;
|
||||
return qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
|
||||
|
||||
static int qeth_bridgeport_set_cb(struct qeth_card *card,
|
||||
struct qeth_reply *reply, unsigned long data)
|
||||
|
|
@ -2025,7 +1937,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
|
|||
rc = qdio_pnso_brinfo(schid, 0, &response, NULL, NULL);
|
||||
return qeth_anset_makerc(card, rc, response);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qeth_bridgeport_an_set);
|
||||
|
||||
static bool qeth_bridgeport_is_in_use(struct qeth_card *card)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,9 +117,9 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
|
|||
int rc = 0;
|
||||
|
||||
if (!card->ipato.enabled)
|
||||
return 0;
|
||||
return false;
|
||||
if (addr->type != QETH_IP_TYPE_NORMAL)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
qeth_l3_convert_addr_to_bits((u8 *) &addr->u, addr_bits,
|
||||
(addr->proto == QETH_PROT_IPV4)? 4:16);
|
||||
|
|
@ -1978,17 +1978,17 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)
|
|||
(cast_type == RTN_MULTICAST) ||
|
||||
(cast_type == RTN_ANYCAST))
|
||||
return cast_type;
|
||||
return RTN_UNSPEC;
|
||||
return RTN_UNICAST;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
|
||||
if (be16_to_cpu(skb->protocol) == ETH_P_IPV6)
|
||||
return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
|
||||
RTN_MULTICAST : RTN_UNSPEC;
|
||||
RTN_MULTICAST : RTN_UNICAST;
|
||||
else if (be16_to_cpu(skb->protocol) == ETH_P_IP)
|
||||
return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
|
||||
RTN_MULTICAST : RTN_UNSPEC;
|
||||
RTN_MULTICAST : RTN_UNICAST;
|
||||
|
||||
/* ... and MAC address */
|
||||
if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast))
|
||||
|
|
@ -1997,22 +1997,21 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)
|
|||
return RTN_MULTICAST;
|
||||
|
||||
/* default to unicast */
|
||||
return RTN_UNSPEC;
|
||||
return RTN_UNICAST;
|
||||
}
|
||||
|
||||
static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
|
||||
struct qeth_hdr *hdr, struct sk_buff *skb)
|
||||
static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb,
|
||||
unsigned int data_len)
|
||||
{
|
||||
char daddr[16];
|
||||
struct af_iucv_trans_hdr *iucv_hdr;
|
||||
|
||||
memset(hdr, 0, sizeof(struct qeth_hdr));
|
||||
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
|
||||
hdr->hdr.l3.ext_flags = 0;
|
||||
hdr->hdr.l3.length = skb->len - ETH_HLEN;
|
||||
hdr->hdr.l3.length = data_len;
|
||||
hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
|
||||
|
||||
iucv_hdr = (struct af_iucv_trans_hdr *) (skb->data + ETH_HLEN);
|
||||
iucv_hdr = (struct af_iucv_trans_hdr *)(skb_mac_header(skb) + ETH_HLEN);
|
||||
memset(daddr, 0, sizeof(daddr));
|
||||
daddr[0] = 0xfe;
|
||||
daddr[1] = 0x80;
|
||||
|
|
@ -2051,6 +2050,12 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
|
|||
hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
|
||||
}
|
||||
|
||||
if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.tx_csum++;
|
||||
}
|
||||
|
||||
/* OSA only: */
|
||||
if (!ipv) {
|
||||
hdr->hdr.l3.flags = QETH_HDR_PASSTHRU;
|
||||
|
|
@ -2156,106 +2161,121 @@ static int qeth_l3_get_elements_no_tso(struct qeth_card *card,
|
|||
return elements;
|
||||
}
|
||||
|
||||
static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int ipv,
|
||||
int cast_type)
|
||||
{
|
||||
int rc;
|
||||
const unsigned int hw_hdr_len = sizeof(struct qeth_hdr);
|
||||
unsigned int frame_len, elements;
|
||||
unsigned char eth_hdr[ETH_HLEN];
|
||||
struct qeth_hdr *hdr = NULL;
|
||||
unsigned int hd_len = 0;
|
||||
int push_len, rc;
|
||||
bool is_sg;
|
||||
|
||||
/* re-use the L2 header area for the HW header: */
|
||||
rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN);
|
||||
if (rc)
|
||||
return rc;
|
||||
skb_copy_from_linear_data(skb, eth_hdr, ETH_HLEN);
|
||||
skb_pull(skb, ETH_HLEN);
|
||||
frame_len = skb->len;
|
||||
|
||||
push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, 0,
|
||||
&elements);
|
||||
if (push_len < 0)
|
||||
return push_len;
|
||||
if (!push_len) {
|
||||
/* hdr was added discontiguous from skb->data */
|
||||
hd_len = hw_hdr_len;
|
||||
}
|
||||
|
||||
if (skb->protocol == htons(ETH_P_AF_IUCV))
|
||||
qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len);
|
||||
else
|
||||
qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len);
|
||||
|
||||
is_sg = skb_is_nonlinear(skb);
|
||||
if (IS_IQD(card)) {
|
||||
rc = qeth_do_send_packet_fast(queue, skb, hdr, 0, hd_len);
|
||||
} else {
|
||||
/* TODO: drop skb_orphan() once TX completion is fast enough */
|
||||
skb_orphan(skb);
|
||||
rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len,
|
||||
elements);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.buf_elements_sent += elements;
|
||||
if (is_sg)
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
}
|
||||
} else {
|
||||
if (!push_len)
|
||||
kmem_cache_free(qeth_core_header_cache, hdr);
|
||||
if (rc == -EBUSY) {
|
||||
/* roll back to ETH header */
|
||||
skb_pull(skb, push_len);
|
||||
skb_push(skb, ETH_HLEN);
|
||||
skb_copy_to_linear_data(skb, eth_hdr, ETH_HLEN);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int ipv, int cast_type)
|
||||
{
|
||||
int elements, len, rc;
|
||||
__be16 *tag;
|
||||
struct qeth_hdr *hdr = NULL;
|
||||
int hdr_elements = 0;
|
||||
int elements;
|
||||
struct qeth_card *card = dev->ml_priv;
|
||||
struct sk_buff *new_skb = NULL;
|
||||
int ipv = qeth_get_ip_version(skb);
|
||||
int cast_type = qeth_l3_get_cast_type(skb);
|
||||
struct qeth_qdio_out_q *queue =
|
||||
card->qdio.out_qs[card->qdio.do_prio_queueing
|
||||
|| (cast_type && card->info.is_multicast_different) ?
|
||||
qeth_get_priority_queue(card, skb, ipv, cast_type) :
|
||||
card->qdio.default_out_queue];
|
||||
int tx_bytes = skb->len;
|
||||
unsigned int hd_len = 0;
|
||||
bool use_tso;
|
||||
int data_offset = -1;
|
||||
unsigned int nr_frags;
|
||||
|
||||
if (((card->info.type == QETH_CARD_TYPE_IQD) &&
|
||||
(((card->options.cq != QETH_CQ_ENABLED) && !ipv) ||
|
||||
((card->options.cq == QETH_CQ_ENABLED) &&
|
||||
(be16_to_cpu(skb->protocol) != ETH_P_AF_IUCV)))) ||
|
||||
card->options.sniffer)
|
||||
goto tx_drop;
|
||||
|
||||
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
|
||||
card->stats.tx_carrier_errors++;
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
if ((cast_type == RTN_BROADCAST) &&
|
||||
(card->info.broadcast_capable == 0))
|
||||
goto tx_drop;
|
||||
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.outbound_cnt++;
|
||||
card->perf_stats.outbound_start_time = qeth_get_micros();
|
||||
}
|
||||
unsigned int hd_len;
|
||||
bool use_tso, is_sg;
|
||||
|
||||
/* Ignore segment size from skb_is_gso(), 1 page is always used. */
|
||||
use_tso = skb_is_gso(skb) &&
|
||||
(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4);
|
||||
|
||||
if (card->info.type == QETH_CARD_TYPE_IQD) {
|
||||
new_skb = skb;
|
||||
data_offset = ETH_HLEN;
|
||||
hd_len = sizeof(*hdr);
|
||||
hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
|
||||
if (!hdr)
|
||||
goto tx_drop;
|
||||
hdr_elements++;
|
||||
} else {
|
||||
/* create a clone with writeable headroom */
|
||||
new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso)
|
||||
+ VLAN_HLEN);
|
||||
if (!new_skb)
|
||||
goto tx_drop;
|
||||
/* create a clone with writeable headroom */
|
||||
new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) +
|
||||
VLAN_HLEN);
|
||||
if (!new_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ipv == 4) {
|
||||
skb_pull(new_skb, ETH_HLEN);
|
||||
}
|
||||
|
||||
if (ipv != 4 && skb_vlan_tag_present(new_skb)) {
|
||||
skb_push(new_skb, VLAN_HLEN);
|
||||
skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
|
||||
skb_copy_to_linear_data_offset(new_skb, 4,
|
||||
new_skb->data + 8, 4);
|
||||
skb_copy_to_linear_data_offset(new_skb, 8,
|
||||
new_skb->data + 12, 4);
|
||||
tag = (__be16 *)(new_skb->data + 12);
|
||||
*tag = cpu_to_be16(ETH_P_8021Q);
|
||||
*(tag + 1) = cpu_to_be16(skb_vlan_tag_get(new_skb));
|
||||
}
|
||||
if (ipv == 4) {
|
||||
skb_pull(new_skb, ETH_HLEN);
|
||||
} else if (skb_vlan_tag_present(new_skb)) {
|
||||
skb_push(new_skb, VLAN_HLEN);
|
||||
skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
|
||||
skb_copy_to_linear_data_offset(new_skb, 4,
|
||||
new_skb->data + 8, 4);
|
||||
skb_copy_to_linear_data_offset(new_skb, 8,
|
||||
new_skb->data + 12, 4);
|
||||
tag = (__be16 *)(new_skb->data + 12);
|
||||
*tag = cpu_to_be16(ETH_P_8021Q);
|
||||
*(tag + 1) = cpu_to_be16(skb_vlan_tag_get(new_skb));
|
||||
}
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
/* fix hardware limitation: as long as we do not have sbal
|
||||
* chaining we can not send long frag lists
|
||||
*/
|
||||
if ((card->info.type != QETH_CARD_TYPE_IQD) &&
|
||||
((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) ||
|
||||
(!use_tso && !qeth_get_elements_no(card, new_skb, 0, 0)))) {
|
||||
int lin_rc = skb_linearize(new_skb);
|
||||
if ((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) ||
|
||||
(!use_tso && !qeth_get_elements_no(card, new_skb, 0, 0))) {
|
||||
rc = skb_linearize(new_skb);
|
||||
|
||||
if (card->options.performance_stats) {
|
||||
if (lin_rc)
|
||||
if (rc)
|
||||
card->perf_stats.tx_linfail++;
|
||||
else
|
||||
card->perf_stats.tx_lin++;
|
||||
}
|
||||
if (lin_rc)
|
||||
goto tx_drop;
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
nr_frags = skb_shinfo(new_skb)->nr_frags;
|
||||
|
||||
if (use_tso) {
|
||||
hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso));
|
||||
|
|
@ -2265,97 +2285,112 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
|
|||
qeth_tso_fill_header(card, hdr, new_skb);
|
||||
hdr_elements++;
|
||||
} else {
|
||||
if (data_offset < 0) {
|
||||
hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
|
||||
qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
|
||||
new_skb->len -
|
||||
sizeof(struct qeth_hdr));
|
||||
} else {
|
||||
if (be16_to_cpu(new_skb->protocol) == ETH_P_AF_IUCV)
|
||||
qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb);
|
||||
else {
|
||||
qeth_l3_fill_header(card, hdr, new_skb, ipv,
|
||||
cast_type,
|
||||
new_skb->len - data_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
qeth_tx_csum(new_skb, &hdr->hdr.l3.ext_flags, ipv);
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.tx_csum++;
|
||||
}
|
||||
hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
|
||||
qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
|
||||
new_skb->len - sizeof(struct qeth_hdr));
|
||||
}
|
||||
|
||||
elements = use_tso ?
|
||||
qeth_l3_get_elements_no_tso(card, new_skb, hdr_elements) :
|
||||
qeth_get_elements_no(card, new_skb, hdr_elements,
|
||||
(data_offset > 0) ? data_offset : 0);
|
||||
qeth_get_elements_no(card, new_skb, hdr_elements, 0);
|
||||
if (!elements) {
|
||||
if (data_offset >= 0)
|
||||
kmem_cache_free(qeth_core_header_cache, hdr);
|
||||
goto tx_drop;
|
||||
rc = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
elements += hdr_elements;
|
||||
|
||||
if (card->info.type != QETH_CARD_TYPE_IQD) {
|
||||
int len;
|
||||
if (use_tso) {
|
||||
hd_len = sizeof(struct qeth_hdr_tso) +
|
||||
ip_hdrlen(new_skb) + tcp_hdrlen(new_skb);
|
||||
len = hd_len;
|
||||
} else {
|
||||
len = sizeof(struct qeth_hdr_layer3);
|
||||
}
|
||||
if (use_tso) {
|
||||
hd_len = sizeof(struct qeth_hdr_tso) +
|
||||
ip_hdrlen(new_skb) + tcp_hdrlen(new_skb);
|
||||
len = hd_len;
|
||||
} else {
|
||||
hd_len = 0;
|
||||
len = sizeof(struct qeth_hdr_layer3);
|
||||
}
|
||||
|
||||
if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len))
|
||||
goto tx_drop;
|
||||
rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len,
|
||||
hd_len, elements);
|
||||
} else
|
||||
rc = qeth_do_send_packet_fast(queue, new_skb, hdr, data_offset,
|
||||
hd_len);
|
||||
if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
is_sg = skb_is_nonlinear(new_skb);
|
||||
rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len, hd_len,
|
||||
elements);
|
||||
out:
|
||||
if (!rc) {
|
||||
card->stats.tx_packets++;
|
||||
card->stats.tx_bytes += tx_bytes;
|
||||
if (new_skb != skb)
|
||||
dev_kfree_skb_any(skb);
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.buf_elements_sent += elements;
|
||||
if (is_sg)
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
if (use_tso) {
|
||||
card->perf_stats.large_send_bytes += tx_bytes;
|
||||
card->perf_stats.large_send_cnt++;
|
||||
}
|
||||
if (nr_frags) {
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
/* nr_frags + skb->data */
|
||||
card->perf_stats.sg_frags_sent += nr_frags + 1;
|
||||
}
|
||||
}
|
||||
rc = NETDEV_TX_OK;
|
||||
} else {
|
||||
if (data_offset >= 0)
|
||||
kmem_cache_free(qeth_core_header_cache, hdr);
|
||||
if (new_skb != skb)
|
||||
dev_kfree_skb_any(new_skb);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == -EBUSY) {
|
||||
if (new_skb != skb)
|
||||
dev_kfree_skb_any(new_skb);
|
||||
return NETDEV_TX_BUSY;
|
||||
} else
|
||||
static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
int cast_type = qeth_l3_get_cast_type(skb);
|
||||
struct qeth_card *card = dev->ml_priv;
|
||||
int ipv = qeth_get_ip_version(skb);
|
||||
struct qeth_qdio_out_q *queue;
|
||||
int tx_bytes = skb->len;
|
||||
int rc;
|
||||
|
||||
if (IS_IQD(card)) {
|
||||
if (card->options.sniffer)
|
||||
goto tx_drop;
|
||||
if ((card->options.cq != QETH_CQ_ENABLED && !ipv) ||
|
||||
(card->options.cq == QETH_CQ_ENABLED &&
|
||||
skb->protocol != htons(ETH_P_AF_IUCV)))
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
netif_wake_queue(dev);
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.outbound_time += qeth_get_micros() -
|
||||
card->perf_stats.outbound_start_time;
|
||||
return rc;
|
||||
if (card->state != CARD_STATE_UP || !card->lan_online) {
|
||||
card->stats.tx_carrier_errors++;
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
if (cast_type == RTN_BROADCAST && !card->info.broadcast_capable)
|
||||
goto tx_drop;
|
||||
|
||||
queue = qeth_get_tx_queue(card, skb, ipv, cast_type);
|
||||
|
||||
if (card->options.performance_stats) {
|
||||
card->perf_stats.outbound_cnt++;
|
||||
card->perf_stats.outbound_start_time = qeth_get_micros();
|
||||
}
|
||||
netif_stop_queue(dev);
|
||||
|
||||
if (IS_IQD(card) || (!skb_is_gso(skb) && ipv == 4))
|
||||
rc = qeth_l3_xmit_offload(card, skb, queue, ipv, cast_type);
|
||||
else
|
||||
rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type);
|
||||
|
||||
if (!rc) {
|
||||
card->stats.tx_packets++;
|
||||
card->stats.tx_bytes += tx_bytes;
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.outbound_time += qeth_get_micros() -
|
||||
card->perf_stats.outbound_start_time;
|
||||
netif_wake_queue(dev);
|
||||
return NETDEV_TX_OK;
|
||||
} else if (rc == -EBUSY) {
|
||||
return NETDEV_TX_BUSY;
|
||||
} /* else fall through */
|
||||
|
||||
tx_drop:
|
||||
card->stats.tx_dropped++;
|
||||
card->stats.tx_errors++;
|
||||
if ((new_skb != skb) && new_skb)
|
||||
dev_kfree_skb_any(new_skb);
|
||||
dev_kfree_skb_any(skb);
|
||||
netif_wake_queue(dev);
|
||||
return NETDEV_TX_OK;
|
||||
|
|
@ -2449,7 +2484,6 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
|
|||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_rx_mode = qeth_l3_set_rx_mode,
|
||||
.ndo_do_ioctl = qeth_do_ioctl,
|
||||
.ndo_change_mtu = qeth_change_mtu,
|
||||
.ndo_fix_features = qeth_fix_features,
|
||||
.ndo_set_features = qeth_set_features,
|
||||
.ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
|
||||
|
|
@ -2466,7 +2500,6 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
|
|||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_set_rx_mode = qeth_l3_set_rx_mode,
|
||||
.ndo_do_ioctl = qeth_do_ioctl,
|
||||
.ndo_change_mtu = qeth_change_mtu,
|
||||
.ndo_fix_features = qeth_fix_features,
|
||||
.ndo_set_features = qeth_set_features,
|
||||
.ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
|
||||
|
|
@ -2479,6 +2512,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
|
|||
{
|
||||
int rc;
|
||||
|
||||
if (card->dev->netdev_ops)
|
||||
return 0;
|
||||
|
||||
if (card->info.type == QETH_CARD_TYPE_OSD ||
|
||||
card->info.type == QETH_CARD_TYPE_OSX) {
|
||||
if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
|
||||
|
|
@ -2487,9 +2523,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
card->dev = alloc_etherdev(0);
|
||||
if (!card->dev)
|
||||
return -ENODEV;
|
||||
card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
|
||||
|
||||
/*IPv6 address autoconfiguration stuff*/
|
||||
|
|
@ -2497,9 +2530,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
|
|||
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
|
||||
card->dev->dev_id = card->info.unique_id & 0xffff;
|
||||
|
||||
card->dev->hw_features |= NETIF_F_SG;
|
||||
card->dev->vlan_features |= NETIF_F_SG;
|
||||
|
||||
if (!card->info.guestlan) {
|
||||
card->dev->features |= NETIF_F_SG;
|
||||
card->dev->hw_features |= NETIF_F_TSO |
|
||||
|
|
@ -2513,38 +2543,35 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
|
|||
card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
|
||||
}
|
||||
} else if (card->info.type == QETH_CARD_TYPE_IQD) {
|
||||
card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN,
|
||||
ether_setup);
|
||||
if (!card->dev)
|
||||
return -ENODEV;
|
||||
card->dev->flags |= IFF_NOARP;
|
||||
card->dev->netdev_ops = &qeth_l3_netdev_ops;
|
||||
|
||||
rc = qeth_l3_iqd_read_initial_mac(card);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto out;
|
||||
|
||||
if (card->options.hsuid[0])
|
||||
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
card->dev->ml_priv = card;
|
||||
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
|
||||
card->dev->mtu = card->info.initial_mtu;
|
||||
card->dev->min_mtu = 64;
|
||||
card->dev->max_mtu = ETH_MAX_MTU;
|
||||
card->dev->dev_port = card->info.portno;
|
||||
card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
|
||||
card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
|
||||
card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
netif_keep_dst(card->dev);
|
||||
netif_set_gso_max_size(card->dev, (QETH_MAX_BUFFER_ELEMENTS(card) - 1) *
|
||||
PAGE_SIZE);
|
||||
|
||||
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
|
||||
netif_keep_dst(card->dev);
|
||||
if (card->dev->hw_features & NETIF_F_TSO)
|
||||
netif_set_gso_max_size(card->dev,
|
||||
PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));
|
||||
|
||||
netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
|
||||
netif_carrier_off(card->dev);
|
||||
return register_netdev(card->dev);
|
||||
rc = register_netdev(card->dev);
|
||||
out:
|
||||
if (rc)
|
||||
card->dev->netdev_ops = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct device_type qeth_l3_devtype = {
|
||||
|
|
@ -2582,15 +2609,9 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
|
|||
if (cgdev->state == CCWGROUP_ONLINE)
|
||||
qeth_l3_set_offline(cgdev);
|
||||
|
||||
if (card->dev) {
|
||||
unregister_netdev(card->dev);
|
||||
free_netdev(card->dev);
|
||||
card->dev = NULL;
|
||||
}
|
||||
|
||||
unregister_netdev(card->dev);
|
||||
qeth_l3_clear_ip_htable(card, 0);
|
||||
qeth_l3_clear_ipato_list(card);
|
||||
return;
|
||||
}
|
||||
|
||||
static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
||||
|
|
@ -2612,10 +2633,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
|||
goto out_remove;
|
||||
}
|
||||
|
||||
if (!card->dev && qeth_l3_setup_netdev(card)) {
|
||||
rc = -ENODEV;
|
||||
rc = qeth_l3_setup_netdev(card);
|
||||
if (rc)
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
|
||||
if (card->info.hwtrap &&
|
||||
|
|
@ -2666,11 +2686,12 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
|||
qeth_enable_hw_features(card->dev);
|
||||
if (recover_flag == CARD_STATE_RECOVER) {
|
||||
rtnl_lock();
|
||||
if (recovery_mode)
|
||||
if (recovery_mode) {
|
||||
__qeth_l3_open(card->dev);
|
||||
else
|
||||
qeth_l3_set_rx_mode(card->dev);
|
||||
} else {
|
||||
dev_open(card->dev);
|
||||
qeth_l3_set_rx_mode(card->dev);
|
||||
}
|
||||
rtnl_unlock();
|
||||
}
|
||||
qeth_trace_features(card);
|
||||
|
|
@ -2711,8 +2732,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
|
|||
QETH_DBF_TEXT(SETUP, 3, "setoffl");
|
||||
QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
|
||||
|
||||
if (card->dev && netif_carrier_ok(card->dev))
|
||||
netif_carrier_off(card->dev);
|
||||
netif_carrier_off(card->dev);
|
||||
recover_flag = card->state;
|
||||
if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
|
||||
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
|
||||
|
|
@ -2780,8 +2800,7 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
|
|||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
|
||||
|
||||
if (card->dev)
|
||||
netif_device_detach(card->dev);
|
||||
netif_device_detach(card->dev);
|
||||
qeth_set_allowed_threads(card, 0, 1);
|
||||
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
|
||||
if (gdev->state == CCWGROUP_OFFLINE)
|
||||
|
|
@ -2814,8 +2833,7 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
|
|||
rc = __qeth_l3_set_online(card->gdev, 0);
|
||||
out:
|
||||
qeth_set_allowed_threads(card, 0xffffffff, 0);
|
||||
if (card->dev)
|
||||
netif_device_attach(card->dev);
|
||||
netif_device_attach(card->dev);
|
||||
if (rc)
|
||||
dev_warn(&card->gdev->dev, "The qeth device driver "
|
||||
"failed to recover an error on the device\n");
|
||||
|
|
|
|||
|
|
@ -299,8 +299,7 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
if (strlen(tmp) == 0) {
|
||||
/* delete ip address only */
|
||||
card->options.hsuid[0] = '\0';
|
||||
if (card->dev)
|
||||
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
||||
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
||||
qeth_configure_cq(card, QETH_CQ_DISABLED);
|
||||
return count;
|
||||
}
|
||||
|
|
@ -311,8 +310,7 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|||
snprintf(card->options.hsuid, sizeof(card->options.hsuid),
|
||||
"%-8s", tmp);
|
||||
ASCEBC(card->options.hsuid, 8);
|
||||
if (card->dev)
|
||||
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
||||
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
||||
|
||||
rc = qeth_l3_modify_hsuid(card, true);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue