hyperv/hn: Use vmbus xact for RNDIS initialize.

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D7624
This commit is contained in:
sephe 2016-08-25 05:00:41 +00:00
parent 87e8626558
commit dcbc2f8fcd
6 changed files with 152 additions and 48 deletions

View File

@ -77,7 +77,7 @@ static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
static void hn_nvs_sent_xact(struct hn_send_ctx *, struct hn_softc *sc,
struct vmbus_channel *, const void *, int);
static struct hn_send_ctx hn_send_ctx_none =
struct hn_send_ctx hn_send_ctx_none =
HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
uint32_t

View File

@ -239,6 +239,11 @@ typedef struct {
uint8_t link_state;
} netvsc_device_info;
#define HN_XACT_REQ_PGCNT 2
#define HN_XACT_RESP_PGCNT 2
#define HN_XACT_REQ_SIZE (HN_XACT_REQ_PGCNT * PAGE_SIZE)
#define HN_XACT_RESP_SIZE (HN_XACT_RESP_PGCNT * PAGE_SIZE)
#ifndef HN_USE_TXDESC_BUFRING
struct hn_txdesc;
SLIST_HEAD(hn_txdesc_list, hn_txdesc);
@ -375,6 +380,8 @@ typedef struct hn_softc {
uint32_t hn_chim_gpadl;
struct hyperv_dma hn_chim_dma;
uint32_t hn_rndis_rid;
} hn_softc_t;
#define HN_FLAG_RXBUF_CONNECTED 0x0001

View File

@ -125,9 +125,6 @@ __FBSDID("$FreeBSD$");
/* Short for Hyper-V network interface */
#define NETVSC_DEVNAME "hn"
#define HN_XACT_REQ_SIZE (2 * PAGE_SIZE)
#define HN_XACT_RESP_SIZE (2 * PAGE_SIZE)
/*
* It looks like offset 0 of buf is reserved to hold the softc pointer.
* The sc pointer evidently not needed, and is not presently populated.

View File

@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
#define HN_RNDIS_RID_COMPAT_MASK 0xffff
#define HN_RNDIS_RID_COMPAT_MAX HN_RNDIS_RID_COMPAT_MASK
#define HN_RNDIS_XFER_SIZE 2048
/*
* Forward declarations
*/
@ -95,6 +97,20 @@ static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
struct hn_softc *sc, struct vmbus_channel *chan,
const void *data, int dlen);
static __inline uint32_t
hn_rndis_rid(struct hn_softc *sc)
{
uint32_t rid;
again:
rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
if (rid == 0)
goto again;
/* Use upper 16 bits for non-compat RNDIS messages. */
return ((rid & 0xffff) << 16);
}
/*
* Set the Per-Packet-Info with the specified type
*/
@ -576,6 +592,8 @@ hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
/* Transition time compat code */
hv_rf_receive_response(rndis_dev, rndis_hdr);
} else {
vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
}
break;
@ -872,62 +890,139 @@ hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
return (ret);
}
static const void *
hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
size_t reqlen, size_t min_complen, uint32_t comp_type)
{
struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
const struct rndis_comp_hdr *comp;
bus_addr_t paddr;
size_t comp_len;
int gpa_cnt, error;
KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
("invalid request length %zu", reqlen));
KASSERT(min_complen >= sizeof(*comp),
("invalid minimum complete len %zu", min_complen));
/*
* Setup the SG list.
*/
paddr = vmbus_xact_req_paddr(xact);
KASSERT((paddr & PAGE_MASK) == 0,
("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
int len = PAGE_SIZE;
if (reqlen == 0)
break;
if (reqlen < len)
len = reqlen;
gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
gpa[gpa_cnt].gpa_len = len;
gpa[gpa_cnt].gpa_ofs = 0;
reqlen -= len;
}
KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
/*
* Send this RNDIS control message and wait for its completion
* message.
*/
vmbus_xact_activate(xact);
error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
&hn_send_ctx_none, gpa, gpa_cnt);
if (error) {
vmbus_xact_deactivate(xact);
if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
return (NULL);
}
comp = vmbus_xact_wait(xact, &comp_len);
/*
* Check this RNDIS complete message.
*/
if (comp_len < min_complen) {
if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n", comp_len);
return (NULL);
}
if (comp->rm_len < min_complen) {
if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
comp->rm_len);
return (NULL);
}
if (comp->rm_type != comp_type) {
if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
"expect 0x%08x\n", comp->rm_type, comp_type);
return (NULL);
}
if (comp->rm_rid != rid) {
if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
"expect %u\n", comp->rm_rid, rid);
return (NULL);
}
/* All pass! */
return (comp);
}
/*
* RNDIS filter init device
*/
static int
hv_rf_init_device(rndis_device *device)
{
rndis_request *request;
rndis_initialize_request *init;
rndis_initialize_complete *init_complete;
uint32_t status;
int ret;
struct hn_softc *sc = device->sc;
struct rndis_init_req *req;
const struct rndis_init_comp *comp;
struct vmbus_xact *xact;
uint32_t rid;
int error;
request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
RNDIS_MESSAGE_SIZE(rndis_initialize_request));
if (!request) {
ret = -1;
goto cleanup;
}
/* Set up the rndis set */
init = &request->request_msg.msg.init_request;
init->major_version = RNDIS_VERSION_MAJOR;
init->minor_version = RNDIS_VERSION_MINOR;
/*
* Per the RNDIS document, this should be set to the max MTU
* plus the header size. However, 2048 works fine, so leaving
* it as is.
*/
init->max_xfer_size = 2048;
device->state = RNDIS_DEV_INITIALIZING;
ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
if (ret != 0) {
device->state = RNDIS_DEV_UNINITIALIZED;
goto cleanup;
}
sema_wait(&request->wait_sema);
init_complete = &request->response_msg.msg.init_complete;
status = init_complete->status;
if (status == RNDIS_STATUS_SUCCESS) {
/* XXX */
device->state = RNDIS_DEV_INITIALIZED;
ret = 0;
} else {
device->state = RNDIS_DEV_UNINITIALIZED;
ret = -1;
xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
if (xact == NULL) {
if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
return (ENXIO);
}
rid = hn_rndis_rid(sc);
req = vmbus_xact_req_data(xact);
req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
req->rm_len = sizeof(*req);
req->rm_rid = rid;
req->rm_ver_major = RNDIS_VERSION_MAJOR;
req->rm_ver_minor = RNDIS_VERSION_MINOR;
req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req),
RNDIS_INIT_COMP_SIZE_MIN, REMOTE_NDIS_INITIALIZE_CMPLT);
if (comp == NULL) {
if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
error = EIO;
goto done;
}
cleanup:
if (request) {
hv_put_rndis_request(device, request);
if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
comp->rm_status);
error = EIO;
goto done;
}
if (bootverbose) {
if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
comp->rm_ver_major, comp->rm_ver_minor,
comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
}
error = 0;
return (ret);
done:
if (xact != NULL)
vmbus_xact_put(xact);
return (error);
}
#define HALT_COMPLETION_WAIT_COUNT 25

View File

@ -115,4 +115,6 @@ const void *hn_nvs_xact_execute(struct hn_softc *sc,
uint32_t hn_chim_alloc(struct hn_softc *sc);
void hn_chim_free(struct hn_softc *sc, uint32_t chim_idx);
extern struct hn_send_ctx hn_send_ctx_none;
#endif /* !_IF_HNVAR_H_ */

View File

@ -146,6 +146,9 @@ struct rndis_init_comp {
uint32_t rm_aflistsz;
};
#define RNDIS_INIT_COMP_SIZE_MIN \
__offsetof(struct rndis_init_comp, rm_aflistsz)
/* Halt the device. No response sent. */
#define REMOTE_NDIS_HALT_MSG 0x00000003