aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/pvcalls-front.c144
-rw-r--r--drivers/xen/pvcalls-front.h3
2 files changed, 138 insertions, 9 deletions
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index 24ffdc90e217..c7d4251c3678 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -83,6 +83,8 @@ struct sock_mapping {
83 * Only one poll operation can be inflight for a given socket. 83 * Only one poll operation can be inflight for a given socket.
84 */ 84 */
85#define PVCALLS_FLAG_ACCEPT_INFLIGHT 0 85#define PVCALLS_FLAG_ACCEPT_INFLIGHT 0
86#define PVCALLS_FLAG_POLL_INFLIGHT 1
87#define PVCALLS_FLAG_POLL_RET 2
86 uint8_t flags; 88 uint8_t flags;
87 uint32_t inflight_req_id; 89 uint32_t inflight_req_id;
88 struct sock_mapping *accept_map; 90 struct sock_mapping *accept_map;
@@ -154,15 +156,32 @@ again:
154 rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons); 156 rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
155 157
156 req_id = rsp->req_id; 158 req_id = rsp->req_id;
157 dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id); 159 if (rsp->cmd == PVCALLS_POLL) {
158 src = (uint8_t *)rsp + sizeof(rsp->req_id); 160 struct sock_mapping *map = (struct sock_mapping *)(uintptr_t)
159 memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id)); 161 rsp->u.poll.id;
160 /* 162
161 * First copy the rest of the data, then req_id. It is 163 clear_bit(PVCALLS_FLAG_POLL_INFLIGHT,
162 * paired with the barrier when accessing bedata->rsp. 164 (void *)&map->passive.flags);
163 */ 165 /*
164 smp_wmb(); 166 * clear INFLIGHT, then set RET. It pairs with
165 bedata->rsp[req_id].req_id = rsp->req_id; 167 * the checks at the beginning of
168 * pvcalls_front_poll_passive.
169 */
170 smp_wmb();
171 set_bit(PVCALLS_FLAG_POLL_RET,
172 (void *)&map->passive.flags);
173 } else {
174 dst = (uint8_t *)&bedata->rsp[req_id] +
175 sizeof(rsp->req_id);
176 src = (uint8_t *)rsp + sizeof(rsp->req_id);
177 memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id));
178 /*
179 * First copy the rest of the data, then req_id. It is
180 * paired with the barrier when accessing bedata->rsp.
181 */
182 smp_wmb();
183 bedata->rsp[req_id].req_id = req_id;
184 }
166 185
167 done = 1; 186 done = 1;
168 bedata->ring.rsp_cons++; 187 bedata->ring.rsp_cons++;
@@ -846,6 +865,113 @@ received:
846 return ret; 865 return ret;
847} 866}
848 867
868static unsigned int pvcalls_front_poll_passive(struct file *file,
869 struct pvcalls_bedata *bedata,
870 struct sock_mapping *map,
871 poll_table *wait)
872{
873 int notify, req_id, ret;
874 struct xen_pvcalls_request *req;
875
876 if (test_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
877 (void *)&map->passive.flags)) {
878 uint32_t req_id = READ_ONCE(map->passive.inflight_req_id);
879
880 if (req_id != PVCALLS_INVALID_ID &&
881 READ_ONCE(bedata->rsp[req_id].req_id) == req_id)
882 return POLLIN | POLLRDNORM;
883
884 poll_wait(file, &map->passive.inflight_accept_req, wait);
885 return 0;
886 }
887
888 if (test_and_clear_bit(PVCALLS_FLAG_POLL_RET,
889 (void *)&map->passive.flags))
890 return POLLIN | POLLRDNORM;
891
892 /*
893 * First check RET, then INFLIGHT. No barriers necessary to
894 * ensure execution ordering because of the conditional
895 * instructions creating control dependencies.
896 */
897
898 if (test_and_set_bit(PVCALLS_FLAG_POLL_INFLIGHT,
899 (void *)&map->passive.flags)) {
900 poll_wait(file, &bedata->inflight_req, wait);
901 return 0;
902 }
903
904 spin_lock(&bedata->socket_lock);
905 ret = get_request(bedata, &req_id);
906 if (ret < 0) {
907 spin_unlock(&bedata->socket_lock);
908 return ret;
909 }
910 req = RING_GET_REQUEST(&bedata->ring, req_id);
911 req->req_id = req_id;
912 req->cmd = PVCALLS_POLL;
913 req->u.poll.id = (uintptr_t) map;
914
915 bedata->ring.req_prod_pvt++;
916 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
917 spin_unlock(&bedata->socket_lock);
918 if (notify)
919 notify_remote_via_irq(bedata->irq);
920
921 poll_wait(file, &bedata->inflight_req, wait);
922 return 0;
923}
924
925static unsigned int pvcalls_front_poll_active(struct file *file,
926 struct pvcalls_bedata *bedata,
927 struct sock_mapping *map,
928 poll_table *wait)
929{
930 unsigned int mask = 0;
931 int32_t in_error, out_error;
932 struct pvcalls_data_intf *intf = map->active.ring;
933
934 out_error = intf->out_error;
935 in_error = intf->in_error;
936
937 poll_wait(file, &map->active.inflight_conn_req, wait);
938 if (pvcalls_front_write_todo(map))
939 mask |= POLLOUT | POLLWRNORM;
940 if (pvcalls_front_read_todo(map))
941 mask |= POLLIN | POLLRDNORM;
942 if (in_error != 0 || out_error != 0)
943 mask |= POLLERR;
944
945 return mask;
946}
947
948unsigned int pvcalls_front_poll(struct file *file, struct socket *sock,
949 poll_table *wait)
950{
951 struct pvcalls_bedata *bedata;
952 struct sock_mapping *map;
953 int ret;
954
955 pvcalls_enter();
956 if (!pvcalls_front_dev) {
957 pvcalls_exit();
958 return POLLNVAL;
959 }
960 bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
961
962 map = (struct sock_mapping *) sock->sk->sk_send_head;
963 if (!map) {
964 pvcalls_exit();
965 return POLLNVAL;
966 }
967 if (map->active_socket)
968 ret = pvcalls_front_poll_active(file, bedata, map, wait);
969 else
970 ret = pvcalls_front_poll_passive(file, bedata, map, wait);
971 pvcalls_exit();
972 return ret;
973}
974
849static const struct xenbus_device_id pvcalls_front_ids[] = { 975static const struct xenbus_device_id pvcalls_front_ids[] = {
850 { "pvcalls" }, 976 { "pvcalls" },
851 { "" } 977 { "" }
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index de24041e9a86..25e05b8f2d72 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -20,5 +20,8 @@ int pvcalls_front_recvmsg(struct socket *sock,
20 struct msghdr *msg, 20 struct msghdr *msg,
21 size_t len, 21 size_t len,
22 int flags); 22 int flags);
23unsigned int pvcalls_front_poll(struct file *file,
24 struct socket *sock,
25 poll_table *wait);
23 26
24#endif 27#endif