diff options
author | Michael Brown | 2010-12-01 19:51:29 +0100 |
---|---|---|
committer | Michael Brown | 2010-12-01 19:51:29 +0100 |
commit | f14a5045d70fb0f46e8dec9bb2fe847407b0a278 (patch) | |
tree | 11c9bc030b13f72c9e2615629a4b5ae8bf4ea68f | |
parent | [vlan] Expose vlan_find() to network card drivers (diff) | |
download | ipxe-f14a5045d70fb0f46e8dec9bb2fe847407b0a278.tar.gz ipxe-f14a5045d70fb0f46e8dec9bb2fe847407b0a278.tar.xz ipxe-f14a5045d70fb0f46e8dec9bb2fe847407b0a278.zip |
[hermon] Work around hardware stripping of VLAN tags
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/drivers/infiniband/hermon.c | 20 | ||||
-rw-r--r-- | src/include/ipxe/infiniband.h | 4 |
2 files changed, 21 insertions, 3 deletions
diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 65b148cc..63cf7d8c 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/if_ether.h> #include <ipxe/ethernet.h> #include <ipxe/fcoe.h> +#include <ipxe/vlan.h> #include "hermon.h" /** @@ -1648,6 +1649,7 @@ static int hermon_complete ( struct ib_device *ibdev, len = MLX_GET ( &cqe->normal, byte_cnt ); assert ( len <= iob_tailroom ( iobuf ) ); iob_put ( iobuf, len ); + memset ( &recv_av, 0, sizeof ( recv_av ) ); switch ( qp->type ) { case IB_QPT_SMI: case IB_QPT_GSI: @@ -1657,7 +1659,6 @@ static int hermon_complete ( struct ib_device *ibdev, iob_pull ( iobuf, sizeof ( *grh ) ); /* Construct address vector */ av = &recv_av; - memset ( av, 0, sizeof ( *av ) ); av->qpn = MLX_GET ( &cqe->normal, srq_rqpn ); av->lid = MLX_GET ( &cqe->normal, slid_smac47_32 ); av->sl = MLX_GET ( &cqe->normal, sl ); @@ -1668,7 +1669,10 @@ static int hermon_complete ( struct ib_device *ibdev, av = &qp->av; break; case IB_QPT_ETH: - av = NULL; + /* Construct address vector */ + av = &recv_av; + av->vlan_present = MLX_GET ( &cqe->normal, vlan ); + av->vlan = MLX_GET ( &cqe->normal, vid ); break; default: assert ( 0 ); @@ -2275,9 +2279,19 @@ static void hermon_eth_complete_send ( struct ib_device *ibdev __unused, */ static void hermon_eth_complete_recv ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_address_vector *av __unused, + struct ib_address_vector *av, struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); + struct net_device *vlan; + + /* Find VLAN device, if applicable */ + if ( av->vlan_present ) { + if ( ( vlan = vlan_find ( netdev, av->vlan ) ) != NULL ) { + netdev = vlan; + } else if ( rc == 0 ) { + rc = -ENODEV; + } + } /* Hand off to network layer */ if ( rc == 0 ) { diff --git a/src/include/ipxe/infiniband.h b/src/include/ipxe/infiniband.h index be2b6e78..f97a5d4f 100644 --- a/src/include/ipxe/infiniband.h +++ b/src/include/ipxe/infiniband.h @@ -89,6 +89,10 @@ struct ib_address_vector { unsigned int gid_present; /** GID, if present */ union ib_gid gid; + /** VLAN is present */ + unsigned int vlan_present; + /** VLAN, if present */ + unsigned int vlan; }; /** An Infiniband Work Queue */ |