summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/netvsc
diff options
context:
space:
mode:
authorsephe <sephe@FreeBSD.org>2016-10-17 07:29:10 +0000
committersephe <sephe@FreeBSD.org>2016-10-17 07:29:10 +0000
commitcb50b841cbd0eb9dffcc3a9d7b738ceb3f9e4394 (patch)
tree7c132846e362d2b47763885110c9ca804d28f601 /sys/dev/hyperv/netvsc
parent6830df8d176de91376b918186766be01f4133a7e (diff)
downloadFreeBSD-src-cb50b841cbd0eb9dffcc3a9d7b738ceb3f9e4394.zip
FreeBSD-src-cb50b841cbd0eb9dffcc3a9d7b738ceb3f9e4394.tar.gz
MFC 305049,305050
305049 hyperv/hn: Factor out func to exec RNDIS transaction w/o checking result It will be used by RNDIS HALT and RESET. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7685 305050 hyperv/hn: Switch to new RNDIS transaction execution for halt. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7686
Diffstat (limited to 'sys/dev/hyperv/netvsc')
-rw-r--r--sys/dev/hyperv/netvsc/hv_net_vsc.c4
-rw-r--r--sys/dev/hyperv/netvsc/hv_rndis_filter.c243
-rw-r--r--sys/dev/hyperv/netvsc/if_hnvar.h2
3 files changed, 49 insertions, 200 deletions
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c
index e1552cc..9518824 100644
--- a/sys/dev/hyperv/netvsc/hv_net_vsc.c
+++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c
@@ -74,8 +74,6 @@ static void hv_nv_on_receive(struct hn_softc *sc,
static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
struct hn_softc *, struct vmbus_channel *chan,
const void *, int);
-static void hn_nvs_sent_xact(struct hn_send_ctx *, struct hn_softc *sc,
- struct vmbus_channel *, const void *, int);
struct hn_send_ctx hn_send_ctx_none =
HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
@@ -655,7 +653,7 @@ hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
return (0);
}
-static void
+void
hn_nvs_sent_xact(struct hn_send_ctx *sndc,
struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
const void *data, int dlen)
diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
index b7aa303..b45b33e 100644
--- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c
+++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
@@ -71,8 +71,6 @@ __FBSDID("$FreeBSD$");
/*
* Forward declarations
*/
-static int hv_rf_send_request(rndis_device *device, rndis_request *request,
- uint32_t message_type);
static void hv_rf_receive_response(rndis_device *device,
const rndis_msg *response);
static void hv_rf_receive_indicate_status(rndis_device *device,
@@ -83,12 +81,6 @@ static inline int hv_rf_query_device_mac(rndis_device *device);
static inline int hv_rf_query_device_link_status(rndis_device *device);
static int hv_rf_init_device(rndis_device *device);
-static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
- struct hn_softc *sc, struct vmbus_channel *chan,
- const void *data, int dlen);
-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 int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
const void *idata, size_t idlen, void *odata, size_t *odlen0);
static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
@@ -197,120 +189,6 @@ hv_put_rndis_device(rndis_device *device)
}
/*
- *
- */
-static inline rndis_request *
-hv_rndis_request(rndis_device *device, uint32_t message_type,
- uint32_t message_length)
-{
- rndis_request *request;
- rndis_msg *rndis_mesg;
- rndis_set_request *set;
-
- request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
-
- sema_init(&request->wait_sema, 0, "rndis sema");
-
- rndis_mesg = &request->request_msg;
- rndis_mesg->ndis_msg_type = message_type;
- rndis_mesg->msg_len = message_length;
-
- /*
- * Set the request id. This field is always after the rndis header
- * for request/response packet types so we just use the set_request
- * as a template.
- */
- set = &rndis_mesg->msg.set_request;
- set->request_id = atomic_fetchadd_int(&device->new_request_id, 1) &
- HN_RNDIS_RID_COMPAT_MASK;
-
- /* Add to the request list */
- mtx_lock(&device->req_lock);
- STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
- mtx_unlock(&device->req_lock);
-
- return (request);
-}
-
-/*
- *
- */
-static inline void
-hv_put_rndis_request(rndis_device *device, rndis_request *request)
-{
- mtx_lock(&device->req_lock);
- /* Fixme: Has O(n) performance */
- /*
- * XXXKYS: Use Doubly linked lists.
- */
- STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
- mylist_entry);
- mtx_unlock(&device->req_lock);
-
- sema_destroy(&request->wait_sema);
- free(request, M_NETVSC);
-}
-
-/*
- *
- */
-static int
-hv_rf_send_request(rndis_device *device, rndis_request *request,
- uint32_t message_type)
-{
- struct hn_softc *sc = device->sc;
- uint32_t send_buf_section_idx, tot_data_buf_len;
- struct vmbus_gpa gpa[2];
- int gpa_cnt, send_buf_section_size;
- hn_sent_callback_t cb;
-
- /* Set up the packet to send it */
- tot_data_buf_len = request->request_msg.msg_len;
-
- gpa_cnt = 1;
- gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
- gpa[0].gpa_len = request->request_msg.msg_len;
- gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
-
- if (gpa[0].gpa_ofs + gpa[0].gpa_len > PAGE_SIZE) {
- gpa_cnt = 2;
- gpa[0].gpa_len = PAGE_SIZE - gpa[0].gpa_ofs;
- gpa[1].gpa_page =
- hv_get_phys_addr((char*)&request->request_msg +
- gpa[0].gpa_len) >> PAGE_SHIFT;
- gpa[1].gpa_ofs = 0;
- gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
- }
-
- if (message_type != REMOTE_NDIS_HALT_MSG)
- cb = hn_rndis_sent_cb;
- else
- cb = hn_rndis_sent_halt;
-
- if (tot_data_buf_len < sc->hn_chim_szmax) {
- send_buf_section_idx = hn_chim_alloc(sc);
- if (send_buf_section_idx != HN_NVS_CHIM_IDX_INVALID) {
- uint8_t *dest = sc->hn_chim +
- (send_buf_section_idx * sc->hn_chim_szmax);
-
- memcpy(dest, &request->request_msg, request->request_msg.msg_len);
- send_buf_section_size = tot_data_buf_len;
- gpa_cnt = 0;
- goto sendit;
- }
- /* Failed to allocate chimney send buffer; move on */
- }
- send_buf_section_idx = HN_NVS_CHIM_IDX_INVALID;
- send_buf_section_size = 0;
-
-sendit:
- hn_send_ctx_init(&request->send_ctx, cb, request,
- send_buf_section_idx, send_buf_section_size);
- return hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
- &request->send_ctx, gpa, gpa_cnt);
-}
-
-/*
* RNDIS filter receive response
*/
static void
@@ -602,20 +480,15 @@ static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
};
static const void *
-hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
- size_t reqlen, size_t *comp_len0, uint32_t comp_type)
+hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
+ struct hn_send_ctx *sndc, size_t *comp_len)
{
struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
- const struct rndis_comp_hdr *comp;
- bus_addr_t paddr;
- size_t comp_len, min_complen = *comp_len0;
int gpa_cnt, error;
+ bus_addr_t paddr;
- 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.
@@ -644,14 +517,34 @@ hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid
* 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);
+ error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
+ 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);
+ return (vmbus_xact_wait(xact, comp_len));
+}
+
+static const void *
+hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
+ size_t reqlen, size_t *comp_len0, uint32_t comp_type)
+{
+ const struct rndis_comp_hdr *comp;
+ size_t comp_len, min_complen = *comp_len0;
+
+ KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
+ KASSERT(min_complen >= sizeof(*comp),
+ ("invalid minimum complete len %zu", min_complen));
+
+ /*
+ * Execute the xact setup by the caller.
+ */
+ comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
+ &comp_len);
+ if (comp == NULL)
+ return (NULL);
/*
* Check this RNDIS complete message.
@@ -1037,51 +930,34 @@ done:
return (error);
}
-#define HALT_COMPLETION_WAIT_COUNT 25
-
/*
* RNDIS filter halt device
*/
static int
-hv_rf_halt_device(rndis_device *device)
+hv_rf_halt_device(struct hn_softc *sc)
{
- rndis_request *request;
- int i, ret;
-
- /* Attempt to do a rndis device halt */
- request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
- RNDIS_MESSAGE_SIZE(rndis_halt_request));
- if (request == NULL) {
- return (-1);
- }
-
- /* initialize "poor man's semaphore" */
- request->halt_complete_flag = 0;
-
- ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
- if (ret != 0) {
- return (-1);
- }
+ struct vmbus_xact *xact;
+ struct rndis_halt_req *halt;
+ struct hn_send_ctx sndc;
+ size_t comp_len;
- /*
- * Wait for halt response from halt callback. We must wait for
- * the transaction response before freeing the request and other
- * resources.
- */
- for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
- if (request->halt_complete_flag != 0) {
- break;
- }
- DELAY(400);
- }
- if (i == 0) {
- return (-1);
+ xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
+ if (xact == NULL) {
+ if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
+ return (ENXIO);
}
+ halt = vmbus_xact_req_data(xact);
+ halt->rm_type = REMOTE_NDIS_HALT_MSG;
+ halt->rm_len = sizeof(*halt);
+ halt->rm_rid = hn_rndis_rid(sc);
- device->state = RNDIS_DEV_UNINITIALIZED;
-
- hv_put_rndis_request(device, request);
+ /* No RNDIS completion; rely on NVS message send completion */
+ hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
+ hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
+ vmbus_xact_put(xact);
+ if (bootverbose)
+ if_printf(sc->hn_ifp, "RNDIS halt done\n");
return (0);
}
@@ -1251,7 +1127,7 @@ hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
int ret;
/* Halt and release the rndis device */
- ret = hv_rf_halt_device(rndis_dev);
+ ret = hv_rf_halt_device(sc);
sc->rndis_dev = NULL;
hv_put_rndis_device(rndis_dev);
@@ -1291,33 +1167,6 @@ hv_rf_on_close(struct hn_softc *sc)
return (hn_rndis_set_rxfilter(sc, 0));
}
-static void
-hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct hn_softc *sc,
- struct vmbus_channel *chan __unused, const void *data __unused,
- int dlen __unused)
-{
- if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
- hn_chim_free(sc, sndc->hn_chim_idx);
-}
-
-static void
-hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct hn_softc *sc,
- struct vmbus_channel *chan __unused, const void *data __unused,
- int dlen __unused)
-{
- rndis_request *request = sndc->hn_cbarg;
-
- if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
- hn_chim_free(sc, sndc->hn_chim_idx);
-
- /*
- * Notify hv_rf_halt_device() about halt completion.
- * The halt code must wait for completion before freeing
- * the transaction resources.
- */
- request->halt_complete_flag = 1;
-}
-
void
hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
{
diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h
index a819db3..90fc00b 100644
--- a/sys/dev/hyperv/netvsc/if_hnvar.h
+++ b/sys/dev/hyperv/netvsc/if_hnvar.h
@@ -112,6 +112,8 @@ struct vmbus_xact;
const void *hn_nvs_xact_execute(struct hn_softc *sc,
struct vmbus_xact *xact, void *req, int reqlen,
size_t *resp_len);
+void hn_nvs_sent_xact(struct hn_send_ctx *sndc, struct hn_softc *sc,
+ struct vmbus_channel *chan, const void *data, int dlen);
uint32_t hn_chim_alloc(struct hn_softc *sc);
void hn_chim_free(struct hn_softc *sc, uint32_t chim_idx);
OpenPOWER on IntegriCloud