15084Sjohnlev /****************************************************************************** 25084Sjohnlev * ring.h 35084Sjohnlev * 45084Sjohnlev * Shared producer-consumer ring macros. 55084Sjohnlev * 65084Sjohnlev * Permission is hereby granted, free of charge, to any person obtaining a copy 75084Sjohnlev * of this software and associated documentation files (the "Software"), to 85084Sjohnlev * deal in the Software without restriction, including without limitation the 95084Sjohnlev * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 105084Sjohnlev * sell copies of the Software, and to permit persons to whom the Software is 115084Sjohnlev * furnished to do so, subject to the following conditions: 125084Sjohnlev * 135084Sjohnlev * The above copyright notice and this permission notice shall be included in 145084Sjohnlev * all copies or substantial portions of the Software. 155084Sjohnlev * 165084Sjohnlev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175084Sjohnlev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 185084Sjohnlev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 195084Sjohnlev * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 205084Sjohnlev * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 215084Sjohnlev * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 225084Sjohnlev * DEALINGS IN THE SOFTWARE. 235084Sjohnlev * 245084Sjohnlev * Tim Deegan and Andrew Warfield November 2004. 255084Sjohnlev */ 265084Sjohnlev 275084Sjohnlev #ifndef __XEN_PUBLIC_IO_RING_H__ 285084Sjohnlev #define __XEN_PUBLIC_IO_RING_H__ 295084Sjohnlev 30*10175SStuart.Maybee@Sun.COM #include "../xen-compat.h" 31*10175SStuart.Maybee@Sun.COM 32*10175SStuart.Maybee@Sun.COM #if __XEN_INTERFACE_VERSION__ < 0x00030208 33*10175SStuart.Maybee@Sun.COM #define xen_mb() mb() 34*10175SStuart.Maybee@Sun.COM #define xen_rmb() rmb() 35*10175SStuart.Maybee@Sun.COM #define xen_wmb() wmb() 36*10175SStuart.Maybee@Sun.COM #endif 37*10175SStuart.Maybee@Sun.COM 385084Sjohnlev typedef unsigned int RING_IDX; 395084Sjohnlev 405084Sjohnlev /* Round a 32-bit unsigned constant down to the nearest power of two. */ 415084Sjohnlev #define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) 425084Sjohnlev #define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x)) 435084Sjohnlev #define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x)) 445084Sjohnlev #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) 455084Sjohnlev #define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x)) 465084Sjohnlev 475084Sjohnlev /* 485084Sjohnlev * Calculate size of a shared ring, given the total available space for the 495084Sjohnlev * ring and indexes (_sz), and the name tag of the request/response structure. 505084Sjohnlev * A ring contains as many entries as will fit, rounded down to the nearest 515084Sjohnlev * power of two (so we can mask with (size-1) to loop around). 525084Sjohnlev */ 535084Sjohnlev #define __RING_SIZE(_s, _sz) \ 545084Sjohnlev (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) 555084Sjohnlev 565084Sjohnlev /* 575084Sjohnlev * Macros to make the correct C datatypes for a new kind of ring. 585084Sjohnlev * 595084Sjohnlev * To make a new ring datatype, you need to have two message structures, 605084Sjohnlev * let's say request_t, and response_t already defined. 615084Sjohnlev * 625084Sjohnlev * In a header where you want the ring datatype declared, you then do: 635084Sjohnlev * 645084Sjohnlev * DEFINE_RING_TYPES(mytag, request_t, response_t); 655084Sjohnlev * 665084Sjohnlev * These expand out to give you a set of types, as you can see below. 675084Sjohnlev * The most important of these are: 685084Sjohnlev * 695084Sjohnlev * mytag_sring_t - The shared ring. 705084Sjohnlev * mytag_front_ring_t - The 'front' half of the ring. 715084Sjohnlev * mytag_back_ring_t - The 'back' half of the ring. 725084Sjohnlev * 735084Sjohnlev * To initialize a ring in your code you need to know the location and size 745084Sjohnlev * of the shared memory area (PAGE_SIZE, for instance). To initialise 755084Sjohnlev * the front half: 765084Sjohnlev * 775084Sjohnlev * mytag_front_ring_t front_ring; 785084Sjohnlev * SHARED_RING_INIT((mytag_sring_t *)shared_page); 795084Sjohnlev * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); 805084Sjohnlev * 815084Sjohnlev * Initializing the back follows similarly (note that only the front 825084Sjohnlev * initializes the shared ring): 835084Sjohnlev * 845084Sjohnlev * mytag_back_ring_t back_ring; 855084Sjohnlev * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); 865084Sjohnlev */ 875084Sjohnlev 885084Sjohnlev #define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ 895084Sjohnlev \ 905084Sjohnlev /* Shared ring entry */ \ 915084Sjohnlev union __name##_sring_entry { \ 925084Sjohnlev __req_t req; \ 935084Sjohnlev __rsp_t rsp; \ 945084Sjohnlev }; \ 955084Sjohnlev \ 965084Sjohnlev /* Shared ring page */ \ 975084Sjohnlev struct __name##_sring { \ 985084Sjohnlev RING_IDX req_prod, req_event; \ 995084Sjohnlev RING_IDX rsp_prod, rsp_event; \ 1005084Sjohnlev uint8_t pad[48]; \ 1015084Sjohnlev union __name##_sring_entry ring[1]; /* variable-length */ \ 1025084Sjohnlev }; \ 1035084Sjohnlev \ 1045084Sjohnlev /* "Front" end's private variables */ \ 1055084Sjohnlev struct __name##_front_ring { \ 1065084Sjohnlev RING_IDX req_prod_pvt; \ 1075084Sjohnlev RING_IDX rsp_cons; \ 1085084Sjohnlev unsigned int nr_ents; \ 1095084Sjohnlev struct __name##_sring *sring; \ 1105084Sjohnlev }; \ 1115084Sjohnlev \ 1125084Sjohnlev /* "Back" end's private variables */ \ 1135084Sjohnlev struct __name##_back_ring { \ 1145084Sjohnlev RING_IDX rsp_prod_pvt; \ 1155084Sjohnlev RING_IDX req_cons; \ 1165084Sjohnlev unsigned int nr_ents; \ 1175084Sjohnlev struct __name##_sring *sring; \ 1185084Sjohnlev }; \ 1195084Sjohnlev \ 1205084Sjohnlev /* Syntactic sugar */ \ 1215084Sjohnlev typedef struct __name##_sring __name##_sring_t; \ 1225084Sjohnlev typedef struct __name##_front_ring __name##_front_ring_t; \ 1235084Sjohnlev typedef struct __name##_back_ring __name##_back_ring_t 1245084Sjohnlev 1255084Sjohnlev /* 1265084Sjohnlev * Macros for manipulating rings. 1275084Sjohnlev * 1285084Sjohnlev * FRONT_RING_whatever works on the "front end" of a ring: here 1295084Sjohnlev * requests are pushed on to the ring and responses taken off it. 1305084Sjohnlev * 1315084Sjohnlev * BACK_RING_whatever works on the "back end" of a ring: here 1325084Sjohnlev * requests are taken off the ring and responses put on. 1335084Sjohnlev * 1345084Sjohnlev * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL. 1355084Sjohnlev * This is OK in 1-for-1 request-response situations where the 1365084Sjohnlev * requestor (front end) never has more than RING_SIZE()-1 1375084Sjohnlev * outstanding requests. 1385084Sjohnlev */ 1395084Sjohnlev 1405084Sjohnlev /* Initialising empty rings */ 1415084Sjohnlev #define SHARED_RING_INIT(_s) do { \ 1425084Sjohnlev (_s)->req_prod = (_s)->rsp_prod = 0; \ 1435084Sjohnlev (_s)->req_event = (_s)->rsp_event = 1; \ 1445084Sjohnlev (void)memset((_s)->pad, 0, sizeof((_s)->pad)); \ 1455084Sjohnlev } while(0) 1465084Sjohnlev 1475084Sjohnlev #define FRONT_RING_INIT(_r, _s, __size) do { \ 1485084Sjohnlev (_r)->req_prod_pvt = 0; \ 1495084Sjohnlev (_r)->rsp_cons = 0; \ 1505084Sjohnlev (_r)->nr_ents = __RING_SIZE(_s, __size); \ 1515084Sjohnlev (_r)->sring = (_s); \ 1525084Sjohnlev } while (0) 1535084Sjohnlev 1545084Sjohnlev #define BACK_RING_INIT(_r, _s, __size) do { \ 1555084Sjohnlev (_r)->rsp_prod_pvt = 0; \ 1565084Sjohnlev (_r)->req_cons = 0; \ 1575084Sjohnlev (_r)->nr_ents = __RING_SIZE(_s, __size); \ 1585084Sjohnlev (_r)->sring = (_s); \ 1595084Sjohnlev } while (0) 1605084Sjohnlev 1615084Sjohnlev /* Initialize to existing shared indexes -- for recovery */ 1625084Sjohnlev #define FRONT_RING_ATTACH(_r, _s, __size) do { \ 1635084Sjohnlev (_r)->sring = (_s); \ 1645084Sjohnlev (_r)->req_prod_pvt = (_s)->req_prod; \ 1655084Sjohnlev (_r)->rsp_cons = (_s)->rsp_prod; \ 1665084Sjohnlev (_r)->nr_ents = __RING_SIZE(_s, __size); \ 1675084Sjohnlev } while (0) 1685084Sjohnlev 1695084Sjohnlev #define BACK_RING_ATTACH(_r, _s, __size) do { \ 1705084Sjohnlev (_r)->sring = (_s); \ 1715084Sjohnlev (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ 1725084Sjohnlev (_r)->req_cons = (_s)->req_prod; \ 1735084Sjohnlev (_r)->nr_ents = __RING_SIZE(_s, __size); \ 1745084Sjohnlev } while (0) 1755084Sjohnlev 1765084Sjohnlev /* How big is this ring? */ 1775084Sjohnlev #define RING_SIZE(_r) \ 1785084Sjohnlev ((_r)->nr_ents) 1795084Sjohnlev 1805084Sjohnlev /* Number of free requests (for use on front side only). */ 1815084Sjohnlev #define RING_FREE_REQUESTS(_r) \ 1825084Sjohnlev (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons)) 1835084Sjohnlev 1845084Sjohnlev /* Test if there is an empty slot available on the front ring. 1855084Sjohnlev * (This is only meaningful from the front. ) 1865084Sjohnlev */ 1875084Sjohnlev #define RING_FULL(_r) \ 1885084Sjohnlev (RING_FREE_REQUESTS(_r) == 0) 1895084Sjohnlev 1905084Sjohnlev /* Test if there are outstanding messages to be processed on a ring. */ 1915084Sjohnlev #define RING_HAS_UNCONSUMED_RESPONSES(_r) \ 1925084Sjohnlev ((_r)->sring->rsp_prod - (_r)->rsp_cons) 1935084Sjohnlev 1945084Sjohnlev #ifdef __GNUC__ 1955084Sjohnlev #define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ 1965084Sjohnlev unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ 1975084Sjohnlev unsigned int rsp = RING_SIZE(_r) - \ 1985084Sjohnlev ((_r)->req_cons - (_r)->rsp_prod_pvt); \ 1995084Sjohnlev req < rsp ? req : rsp; \ 2005084Sjohnlev }) 2015084Sjohnlev #else 2025084Sjohnlev /* Same as above, but without the nice GCC ({ ... }) syntax. */ 2035084Sjohnlev #define RING_HAS_UNCONSUMED_REQUESTS(_r) \ 2045084Sjohnlev ((((_r)->sring->req_prod - (_r)->req_cons) < \ 2055084Sjohnlev (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ 2065084Sjohnlev ((_r)->sring->req_prod - (_r)->req_cons) : \ 2075084Sjohnlev (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) 2085084Sjohnlev #endif 2095084Sjohnlev 2105084Sjohnlev /* Direct access to individual ring elements, by index. */ 2115084Sjohnlev #define RING_GET_REQUEST(_r, _idx) \ 2125084Sjohnlev (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) 2135084Sjohnlev 2145084Sjohnlev #define RING_GET_RESPONSE(_r, _idx) \ 2155084Sjohnlev (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) 2165084Sjohnlev 2175084Sjohnlev /* Loop termination condition: Would the specified index overflow the ring? */ 2185084Sjohnlev #define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ 2195084Sjohnlev (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) 2205084Sjohnlev 2215084Sjohnlev #define RING_PUSH_REQUESTS(_r) do { \ 222*10175SStuart.Maybee@Sun.COM xen_wmb(); /* back sees requests /before/ updated producer index */ \ 2235084Sjohnlev (_r)->sring->req_prod = (_r)->req_prod_pvt; \ 2245084Sjohnlev } while (0) 2255084Sjohnlev 2265084Sjohnlev #define RING_PUSH_RESPONSES(_r) do { \ 227*10175SStuart.Maybee@Sun.COM xen_wmb(); /* front sees resps /before/ updated producer index */ \ 2285084Sjohnlev (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ 2295084Sjohnlev } while (0) 2305084Sjohnlev 2315084Sjohnlev /* 2325084Sjohnlev * Notification hold-off (req_event and rsp_event): 2335084Sjohnlev * 2345084Sjohnlev * When queueing requests or responses on a shared ring, it may not always be 2355084Sjohnlev * necessary to notify the remote end. For example, if requests are in flight 2365084Sjohnlev * in a backend, the front may be able to queue further requests without 2375084Sjohnlev * notifying the back (if the back checks for new requests when it queues 2385084Sjohnlev * responses). 2395084Sjohnlev * 2405084Sjohnlev * When enqueuing requests or responses: 2415084Sjohnlev * 2425084Sjohnlev * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument 2435084Sjohnlev * is a boolean return value. True indicates that the receiver requires an 2445084Sjohnlev * asynchronous notification. 2455084Sjohnlev * 2465084Sjohnlev * After dequeuing requests or responses (before sleeping the connection): 2475084Sjohnlev * 2485084Sjohnlev * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES(). 2495084Sjohnlev * The second argument is a boolean return value. True indicates that there 2505084Sjohnlev * are pending messages on the ring (i.e., the connection should not be put 2515084Sjohnlev * to sleep). 2525084Sjohnlev * 2535084Sjohnlev * These macros will set the req_event/rsp_event field to trigger a 2545084Sjohnlev * notification on the very next message that is enqueued. If you want to 2555084Sjohnlev * create batches of work (i.e., only receive a notification after several 2565084Sjohnlev * messages have been enqueued) then you will need to create a customised 2575084Sjohnlev * version of the FINAL_CHECK macro in your own code, which sets the event 2585084Sjohnlev * field appropriately. 2595084Sjohnlev */ 2605084Sjohnlev 2615084Sjohnlev #define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ 2625084Sjohnlev RING_IDX __old = (_r)->sring->req_prod; \ 2635084Sjohnlev RING_IDX __new = (_r)->req_prod_pvt; \ 264*10175SStuart.Maybee@Sun.COM xen_wmb(); /* back sees requests /before/ updated producer index */ \ 2655084Sjohnlev (_r)->sring->req_prod = __new; \ 266*10175SStuart.Maybee@Sun.COM xen_mb(); /* back sees new requests /before/ we check req_event */ \ 2675084Sjohnlev (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ 2685084Sjohnlev (RING_IDX)(__new - __old)); \ 2695084Sjohnlev } while (0) 2705084Sjohnlev 2715084Sjohnlev #define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ 2725084Sjohnlev RING_IDX __old = (_r)->sring->rsp_prod; \ 2735084Sjohnlev RING_IDX __new = (_r)->rsp_prod_pvt; \ 274*10175SStuart.Maybee@Sun.COM xen_wmb(); /* front sees resps /before/ updated producer index */ \ 2755084Sjohnlev (_r)->sring->rsp_prod = __new; \ 276*10175SStuart.Maybee@Sun.COM xen_mb(); /* front sees new resps /before/ we check rsp_event */ \ 2775084Sjohnlev (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ 2785084Sjohnlev (RING_IDX)(__new - __old)); \ 2795084Sjohnlev } while (0) 2805084Sjohnlev 2815084Sjohnlev #define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ 2825084Sjohnlev (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ 2835084Sjohnlev if (_work_to_do) break; \ 2845084Sjohnlev (_r)->sring->req_event = (_r)->req_cons + 1; \ 285*10175SStuart.Maybee@Sun.COM xen_mb(); \ 2865084Sjohnlev (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ 2875084Sjohnlev } while (0) 2885084Sjohnlev 2895084Sjohnlev #define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ 2905084Sjohnlev (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ 2915084Sjohnlev if (_work_to_do) break; \ 2925084Sjohnlev (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ 293*10175SStuart.Maybee@Sun.COM xen_mb(); \ 2945084Sjohnlev (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ 2955084Sjohnlev } while (0) 2965084Sjohnlev 2975084Sjohnlev #endif /* __XEN_PUBLIC_IO_RING_H__ */ 2985084Sjohnlev 2995084Sjohnlev /* 3005084Sjohnlev * Local variables: 3015084Sjohnlev * mode: C 3025084Sjohnlev * c-set-style: "BSD" 3035084Sjohnlev * c-basic-offset: 4 3045084Sjohnlev * tab-width: 4 3055084Sjohnlev * indent-tabs-mode: nil 3065084Sjohnlev * End: 3075084Sjohnlev */ 308