Enhance blkif and ring handling to be capable of dealing with bi-modal operation (frontend running in with different word size than backend). Index: sle10-sp1-2006-12-05/drivers/xen/Kconfig =================================================================== --- sle10-sp1-2006-12-05.orig/drivers/xen/Kconfig 2006-12-07 16:43:54.000000000 +0100 +++ sle10-sp1-2006-12-05/drivers/xen/Kconfig 2006-12-07 16:44:54.000000000 +0100 @@ -45,6 +45,14 @@ config XEN_BACKEND Support for backend device drivers that provide I/O services to other virtual machines. +config XEN_BIMODAL_BACKENDS + bool "Bi-modal backend driver support" + depends on XEN_BACKEND && (X86_PAE || X86_64) + default y + help + Build backend device drivers providing support for both + native as well as compatibility guests. + config XEN_BLKDEV_BACKEND tristate "Block-device backend driver" depends on XEN_BACKEND Index: sle10-sp1-2006-12-05/include/xen/interface/io/blkif.h =================================================================== --- sle10-sp1-2006-12-05.orig/include/xen/interface/io/blkif.h 2006-12-07 16:43:54.000000000 +0100 +++ sle10-sp1-2006-12-05/include/xen/interface/io/blkif.h 2006-12-07 16:44:54.000000000 +0100 @@ -25,6 +25,30 @@ */ #ifndef __XEN_PUBLIC_IO_BLKIF_H__ +#ifndef blkif +# ifdef BLKIF_BIMODAL +# define BACKEND_RING_BIMODAL +# if defined(__linux__) && defined(__KERNEL__) +# ifdef CONFIG_64BIT +# pragma pack(push, 4) +# else +# define uint64_t uint64_t __attribute__((__aligned__(8))) +# endif +# else +# error Environment unsupported for bi-modal operation. +# endif +# define blkif(x) blkif_alt_##x +# include "blkif.h" +# if defined(__linux__) && defined(__KERNEL__) +# ifdef CONFIG_64BIT +# pragma pack(pop) +# else +# undef uint64_t +# endif +# endif +# endif +# define blkif(x) blkif_##x +#endif #define __XEN_PUBLIC_IO_BLKIF_H__ #include "ring.h" @@ -71,27 +95,31 @@ */ #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11 -struct blkif_request { +#ifndef BLKIF_RSP_ERROR +struct blkif_request_segment { + grant_ref_t gref; /* reference to I/O buffer frame */ + /* @first_sect: first sector in frame to transfer (inclusive). */ + /* @last_sect: last sector in frame to transfer (inclusive). */ + uint8_t first_sect, last_sect; +}; +#endif + +struct blkif(request) { uint8_t operation; /* BLKIF_OP_??? */ uint8_t nr_segments; /* number of segments */ blkif_vdev_t handle; /* only for read/write requests */ uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - struct blkif_request_segment { - grant_ref_t gref; /* reference to I/O buffer frame */ - /* @first_sect: first sector in frame to transfer (inclusive). */ - /* @last_sect: last sector in frame to transfer (inclusive). */ - uint8_t first_sect, last_sect; - } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; -typedef struct blkif_request blkif_request_t; +typedef struct blkif(request) blkif(request_t); -struct blkif_response { +struct blkif(response) { uint64_t id; /* copied from request */ uint8_t operation; /* copied from request */ int16_t status; /* BLKIF_RSP_??? */ }; -typedef struct blkif_response blkif_response_t; +typedef struct blkif(response) blkif(response_t); /* * STATUS RETURN CODES. @@ -107,12 +135,16 @@ typedef struct blkif_response blkif_resp * Generate blkif ring structures and types. */ +#ifndef BLKIF_BIMODAL DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response); +#endif #define VDISK_CDROM 0x1 #define VDISK_REMOVABLE 0x2 #define VDISK_READONLY 0x4 +#undef blkif +#undef BLKIF_BIMODAL #endif /* __XEN_PUBLIC_IO_BLKIF_H__ */ /* Index: sle10-sp1-2006-12-05/include/xen/interface/io/ring.h =================================================================== --- sle10-sp1-2006-12-05.orig/include/xen/interface/io/ring.h 2006-12-07 16:43:54.000000000 +0100 +++ sle10-sp1-2006-12-05/include/xen/interface/io/ring.h 2006-12-07 16:44:54.000000000 +0100 @@ -78,6 +78,7 @@ typedef unsigned int RING_IDX; */ #define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ +DEFINE_ALT_RING_TYPES(__name); \ \ /* Shared ring entry */ \ union __name##_sring_entry { \ @@ -106,14 +107,72 @@ struct __name##_back_ring { RING_IDX rsp_prod_pvt; \ RING_IDX req_cons; \ unsigned int nr_ents; \ - struct __name##_sring *sring; \ + __name##_sring_u sring; \ }; \ \ +CHECK_RING_TYPES(__name) \ + \ /* Syntactic sugar */ \ typedef struct __name##_sring __name##_sring_t; \ typedef struct __name##_front_ring __name##_front_ring_t; \ typedef struct __name##_back_ring __name##_back_ring_t +#ifdef BACKEND_RING_BIMODAL +#define DEFINE_ALT_RING_TYPES(__name) \ + \ +/* Shared ring entry */ \ +union __name##_alt_sring_entry { \ + struct __name##_alt_request req; \ + struct __name##_alt_response rsp; \ +}; \ + \ +/* Shared ring page */ \ +typedef struct __name##_alt_sring { \ + RING_IDX req_prod, req_event; \ + RING_IDX rsp_prod, rsp_event; \ + uint8_t pad[48]; \ + union __name##_alt_sring_entry ring[1]; /* variable-length */ \ +} __name##_alt_sring_t; \ + \ +typedef union { \ + struct __name##_sring *nat; \ + struct __name##_alt_sring *alt; \ +} __name##_sring_u; \ + \ +typedef union { \ + struct __name##_request nat; \ + struct __name##_alt_request alt; \ +} __name##_request_u; \ + \ +typedef union { \ + struct __name##_response *nat; \ + struct __name##_alt_response *alt; \ +} __name##_response_u + +#define CHECK_SRING_FIELD(__name, __fld) \ + BUILD_BUG_ON(&((struct __name ## _sring *)0)->__fld != \ + &((struct __name ## _alt_sring *)0)->__fld) + +#define CHECK_RING_TYPES(__name) \ +static inline void _##__name##_check_ring_types_(void) { \ + CHECK_SRING_FIELD(__name, req_prod); \ + CHECK_SRING_FIELD(__name, req_event); \ + CHECK_SRING_FIELD(__name, rsp_prod); \ + CHECK_SRING_FIELD(__name, rsp_event); \ + CHECK_SRING_FIELD(__name, pad); \ +} +#define BB_SRING(_s) _s.alt +#else +#define DEFINE_ALT_RING_TYPES(__name) \ +typedef struct __name##_sring *__name##_sring_u; \ +typedef struct __name##_request __name##_request_u; \ +typedef struct __name##_response *__name##_response_u + +#define CHECK_RING_TYPES(__name) + +#define BB_SRING(_s) _s +#endif + /* * Macros for manipulating rings. * @@ -135,6 +194,7 @@ typedef struct __name##_back_ring __name (_s)->req_event = (_s)->rsp_event = 1; \ memset((_s)->pad, 0, sizeof((_s)->pad)); \ } while(0) +#define BB_SHARED_RING_INIT(_s) SHARED_RING_INIT(BB_SRING(_s)) #define FRONT_RING_INIT(_r, _s, __size) do { \ (_r)->req_prod_pvt = 0; \ @@ -143,12 +203,24 @@ typedef struct __name##_back_ring __name (_r)->sring = (_s); \ } while (0) +#ifndef BACKEND_RING_BIMODAL #define BACK_RING_INIT(_r, _s, __size) do { \ (_r)->rsp_prod_pvt = 0; \ (_r)->req_cons = 0; \ (_r)->nr_ents = __RING_SIZE(_s, __size); \ (_r)->sring = (_s); \ } while (0) +#else +#define BACK_RING_INIT(_r, _s, __size) do { \ + (_r)->rsp_prod_pvt = 0; \ + (_r)->req_cons = 0; \ + if (ring_native(_r)) \ + (_r)->nr_ents = __RING_SIZE((_s).nat, __size); \ + else \ + (_r)->nr_ents = __RING_SIZE((_s).alt, __size); \ + (_r)->sring = (_s); \ +} while (0) +#endif /* Initialize to existing shared indexes -- for recovery */ #define FRONT_RING_ATTACH(_r, _s, __size) do { \ @@ -158,12 +230,24 @@ typedef struct __name##_back_ring __name (_r)->nr_ents = __RING_SIZE(_s, __size); \ } while (0) +#ifndef BACKEND_RING_BIMODAL #define BACK_RING_ATTACH(_r, _s, __size) do { \ (_r)->sring = (_s); \ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ (_r)->req_cons = (_s)->req_prod; \ (_r)->nr_ents = __RING_SIZE(_s, __size); \ } while (0) +#else +#define BACK_RING_ATTACH(_r, _s, __size) do { \ + (_r)->sring = (_s); \ + (_r)->rsp_prod_pvt = (_s).alt->rsp_prod; \ + (_r)->req_cons = (_s).alt->req_prod; \ + if (ring_native(_r)) \ + (_r)->nr_ents = __RING_SIZE((_s).nat, __size); \ + else \ + (_r)->nr_ents = __RING_SIZE((_s).alt, __size); \ +} while (0) +#endif /* How big is this ring? */ #define RING_SIZE(_r) \ @@ -180,11 +264,15 @@ typedef struct __name##_back_ring __name (RING_FREE_REQUESTS(_r) == 0) /* Test if there are outstanding messages to be processed on a ring. */ -#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ +#define _RING_HAS_UNCONSUMED_RESPONSES(_r, sring) \ ((_r)->sring->rsp_prod - (_r)->rsp_cons) +#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ + _RING_HAS_UNCONSUMED_RESPONSES(_r, sring) +#define BB_RING_HAS_UNCONSUMED_RESPONSES(_r) \ + _RING_HAS_UNCONSUMED_RESPONSES(_r, BB_SRING(sring)) #ifdef __GNUC__ -#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ +#define _RING_HAS_UNCONSUMED_REQUESTS(_r, sring) ({ \ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ unsigned int rsp = RING_SIZE(_r) - \ ((_r)->req_cons - (_r)->rsp_prod_pvt); \ @@ -192,33 +280,75 @@ typedef struct __name##_back_ring __name }) #else /* Same as above, but without the nice GCC ({ ... }) syntax. */ -#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ +#define _RING_HAS_UNCONSUMED_REQUESTS(_r, sring) \ ((((_r)->sring->req_prod - (_r)->req_cons) < \ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ ((_r)->sring->req_prod - (_r)->req_cons) : \ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) #endif +#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ + _RING_HAS_UNCONSUMED_REQUESTS(_r, sring) +#define BB_RING_HAS_UNCONSUMED_REQUESTS(_r) \ + _RING_HAS_UNCONSUMED_REQUESTS(_r, BB_SRING(sring)) /* Direct access to individual ring elements, by index. */ #define RING_GET_REQUEST(_r, _idx) \ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) +#ifndef BACKEND_RING_BIMODAL +#define BB_RING_GET_REQUEST(_req, _r, _idx) do { \ + (_req) = RING_GET_REQUEST(_r, _idx); \ +} while (0) +#else +#define BB_RING_GET_REQUEST(_req, _r, _idx) do { \ + if (ring_native(_r)) \ + (_req).nat = &(_r)->sring.nat->ring[(_idx) & (RING_SIZE(_r) - 1)].req; \ + else \ + (_req).alt = &(_r)->sring.alt->ring[(_idx) & (RING_SIZE(_r) - 1)].req; \ +} while (0) +#endif + +#define RING_COPY_REQUEST(_req, _r, _idx) \ + memcpy(&(_req), RING_GET_REQUEST(_r, _idx), sizeof(_req)) +#ifndef BACKEND_RING_BIMODAL +#define BB_RING_COPY_REQUEST RING_COPY_REQUEST +#else +#define BB_RING_COPY_REQUEST(_req, _r, _idx) (ring_native(_r) ? \ + memcpy(&(_req), &(_r)->sring.nat->ring[(_idx) & (RING_SIZE(_r) - 1)].req, sizeof((_req).nat)) : \ + memcpy(&(_req), &(_r)->sring.alt->ring[(_idx) & (RING_SIZE(_r) - 1)].req, sizeof((_req).alt))) +#endif #define RING_GET_RESPONSE(_r, _idx) \ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) +#ifndef BACKEND_RING_BIMODAL +#define BB_RING_GET_RESPONSE(_rsp, _r, _idx) do { \ + (_rsp) = RING_GET_RESPONSE(_r, _idx); \ +} while (0) +#else +#define BB_RING_GET_RESPONSE(_rsp, _r, _idx) do { \ + if (ring_native(_r)) \ + (_rsp).nat = &(_r)->sring.nat->ring[(_idx) & (RING_SIZE(_r) - 1)].rsp; \ + else \ + (_rsp).alt = &(_r)->sring.alt->ring[(_idx) & (RING_SIZE(_r) - 1)].rsp; \ +} while (0) +#endif /* Loop termination condition: Would the specified index overflow the ring? */ #define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) -#define RING_PUSH_REQUESTS(_r) do { \ +#define _RING_PUSH_REQUESTS(_r, sring) do { \ wmb(); /* back sees requests /before/ updated producer index */ \ (_r)->sring->req_prod = (_r)->req_prod_pvt; \ } while (0) +#define RING_PUSH_REQUESTS(_r) _RING_PUSH_REQUESTS(_r, sring) +#define BB_RING_PUSH_REQUESTS(_r) _RING_PUSH_REQUESTS(_r, BB_SRING(sring)) -#define RING_PUSH_RESPONSES(_r) do { \ +#define _RING_PUSH_RESPONSES(_r, sring) do { \ wmb(); /* front sees responses /before/ updated producer index */ \ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ } while (0) +#define RING_PUSH_RESPONSES(_r) _RING_PUSH_RESPONSES(_r, sring) +#define BB_RING_PUSH_RESPONSES(_r) _RING_PUSH_RESPONSES(_r, BB_SRING(sring)) /* * Notification hold-off (req_event and rsp_event): @@ -250,7 +380,7 @@ typedef struct __name##_back_ring __name * field appropriately. */ -#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ +#define _RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, sring, _notify) do { \ RING_IDX __old = (_r)->sring->req_prod; \ RING_IDX __new = (_r)->req_prod_pvt; \ wmb(); /* back sees requests /before/ updated producer index */ \ @@ -259,8 +389,12 @@ typedef struct __name##_back_ring __name (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ (RING_IDX)(__new - __old)); \ } while (0) +#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) \ + _RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, sring, _notify) +#define BB_RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) \ + _RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, BB_SRING(sring), _notify) -#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ +#define _RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, sring, _notify) do { \ RING_IDX __old = (_r)->sring->rsp_prod; \ RING_IDX __new = (_r)->rsp_prod_pvt; \ wmb(); /* front sees responses /before/ updated producer index */ \ @@ -269,22 +403,34 @@ typedef struct __name##_back_ring __name (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ (RING_IDX)(__new - __old)); \ } while (0) +#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) \ + _RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, sring, _notify) +#define BB_RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) \ + _RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, BB_SRING(sring), _notify) -#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ - (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ +#define _RING_FINAL_CHECK_FOR_REQUESTS(_r, bb, sring, _work_to_do) do { \ + (_work_to_do) = bb##RING_HAS_UNCONSUMED_REQUESTS(_r); \ if (_work_to_do) break; \ (_r)->sring->req_event = (_r)->req_cons + 1; \ mb(); \ - (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ + (_work_to_do) = bb##RING_HAS_UNCONSUMED_REQUESTS(_r); \ } while (0) +#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) \ + _RING_FINAL_CHECK_FOR_REQUESTS(_r, , sring, _work_to_do) +#define BB_RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) \ + _RING_FINAL_CHECK_FOR_REQUESTS(_r, BB_, BB_SRING(sring), _work_to_do) -#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ - (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ +#define _RING_FINAL_CHECK_FOR_RESPONSES(_r, bb, sring, _work_to_do) do {\ + (_work_to_do) = bb##RING_HAS_UNCONSUMED_RESPONSES(_r); \ if (_work_to_do) break; \ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ mb(); \ - (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ + (_work_to_do) = bb##RING_HAS_UNCONSUMED_RESPONSES(_r); \ } while (0) +#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) \ + _RING_FINAL_CHECK_FOR_RESPONSES(_r, , sring, _work_to_do) +#define BB_RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) \ + _RING_FINAL_CHECK_FOR_RESPONSES(_r, BB_, BB_SRING(sring), _work_to_do) #endif /* __XEN_PUBLIC_IO_RING_H__ */