ia64/xen-unstable

annotate linux-2.6-xen-sparse/drivers/xen/usbback/interface.c @ 6697:a9a78ca76cd2

Replace direct_remap_area_pages with direct_remap_pfn_range to help fix PAE domain building.
Signed-off-by: ian@xensource.com
author iap10@freefall.cl.cam.ac.uk
date Wed Sep 07 23:10:49 2005 +0000 (2005-09-07)
parents dd668f7527cb
children 4cdf880c9463
rev   line source
cl349@4113 1 /******************************************************************************
cl349@4113 2 * arch/xen/drivers/usbif/backend/interface.c
cl349@4113 3 *
cl349@4113 4 * USB device interface management.
cl349@4113 5 *
cl349@4113 6 * by Mark Williamson, Copyright (c) 2004
cl349@4113 7 */
cl349@4113 8
cl349@4113 9 #include "common.h"
cl349@4113 10
cl349@4113 11 #define USBIF_HASHSZ 1024
cl349@4113 12 #define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
cl349@4113 13
cl349@4113 14 static kmem_cache_t *usbif_priv_cachep;
cl349@4113 15 static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ];
cl349@4113 16
cl349@4113 17 usbif_priv_t *usbif_find(domid_t domid)
cl349@4113 18 {
cl349@4113 19 usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
cl349@4113 20 while ( (up != NULL ) && ( up->domid != domid ) )
cl349@4113 21 up = up->hash_next;
cl349@4113 22 return up;
cl349@4113 23 }
cl349@4113 24
cl349@4113 25 static void __usbif_disconnect_complete(void *arg)
cl349@4113 26 {
cl349@4113 27 usbif_priv_t *usbif = (usbif_priv_t *)arg;
cl349@4113 28 ctrl_msg_t cmsg;
cl349@4113 29 usbif_be_disconnect_t disc;
cl349@4113 30
cl349@4113 31 /*
cl349@4113 32 * These can't be done in usbif_disconnect() because at that point there
cl349@4113 33 * may be outstanding requests at the device whose asynchronous responses
cl349@4113 34 * must still be notified to the remote driver.
cl349@4113 35 */
cl349@4113 36 vfree(usbif->usb_ring.sring);
cl349@4113 37
cl349@4113 38 /* Construct the deferred response message. */
cl349@4113 39 cmsg.type = CMSG_USBIF_BE;
cl349@4113 40 cmsg.subtype = CMSG_USBIF_BE_DISCONNECT;
cl349@4113 41 cmsg.id = usbif->disconnect_rspid;
cl349@4113 42 cmsg.length = sizeof(usbif_be_disconnect_t);
cl349@4113 43 disc.domid = usbif->domid;
cl349@4113 44 disc.status = USBIF_BE_STATUS_OKAY;
cl349@4113 45 memcpy(cmsg.msg, &disc, sizeof(disc));
cl349@4113 46
cl349@4113 47 /*
cl349@4113 48 * Make sure message is constructed /before/ status change, because
cl349@4113 49 * after the status change the 'usbif' structure could be deallocated at
cl349@4113 50 * any time. Also make sure we send the response /after/ status change,
cl349@4113 51 * as otherwise a subsequent CONNECT request could spuriously fail if
cl349@4113 52 * another CPU doesn't see the status change yet.
cl349@4113 53 */
cl349@4113 54 mb();
cl349@4113 55 if ( usbif->status != DISCONNECTING )
cl349@4113 56 BUG();
cl349@4113 57 usbif->status = DISCONNECTED;
cl349@4113 58 mb();
cl349@4113 59
cl349@4113 60 /* Send the successful response. */
cl349@4113 61 ctrl_if_send_response(&cmsg);
cl349@4113 62 }
cl349@4113 63
cl349@4113 64 void usbif_disconnect_complete(usbif_priv_t *up)
cl349@4113 65 {
cl349@4113 66 INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
cl349@4113 67 schedule_work(&up->work);
cl349@4113 68 }
cl349@4113 69
cl349@4113 70 void usbif_create(usbif_be_create_t *create)
cl349@4113 71 {
cl349@4113 72 domid_t domid = create->domid;
cl349@4113 73 usbif_priv_t **pup, *up;
cl349@4113 74
cl349@4113 75 if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
cl349@4113 76 {
cl349@4113 77 DPRINTK("Could not create usbif: out of memory\n");
cl349@4113 78 create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
cl349@4113 79 return;
cl349@4113 80 }
cl349@4113 81
cl349@4113 82 memset(up, 0, sizeof(*up));
cl349@4113 83 up->domid = domid;
cl349@4113 84 up->status = DISCONNECTED;
cl349@4113 85 spin_lock_init(&up->usb_ring_lock);
cl349@4113 86 atomic_set(&up->refcnt, 0);
cl349@4113 87
cl349@4113 88 pup = &usbif_priv_hash[USBIF_HASH(domid)];
cl349@4113 89 while ( *pup != NULL )
cl349@4113 90 {
cl349@4113 91 if ( (*pup)->domid == domid )
cl349@4113 92 {
cl349@4113 93 create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
cl349@4113 94 kmem_cache_free(usbif_priv_cachep, up);
cl349@4113 95 return;
cl349@4113 96 }
cl349@4113 97 pup = &(*pup)->hash_next;
cl349@4113 98 }
cl349@4113 99
cl349@4113 100 up->hash_next = *pup;
cl349@4113 101 *pup = up;
cl349@4113 102
cl349@4113 103 create->status = USBIF_BE_STATUS_OKAY;
cl349@4113 104 }
cl349@4113 105
cl349@4113 106 void usbif_destroy(usbif_be_destroy_t *destroy)
cl349@4113 107 {
cl349@4113 108 domid_t domid = destroy->domid;
cl349@4113 109 usbif_priv_t **pup, *up;
cl349@4113 110
cl349@4113 111 pup = &usbif_priv_hash[USBIF_HASH(domid)];
cl349@4113 112 while ( (up = *pup) != NULL )
cl349@4113 113 {
cl349@4113 114 if ( up->domid == domid )
cl349@4113 115 {
cl349@4113 116 if ( up->status != DISCONNECTED )
cl349@4113 117 goto still_connected;
cl349@4113 118 goto destroy;
cl349@4113 119 }
cl349@4113 120 pup = &up->hash_next;
cl349@4113 121 }
cl349@4113 122
cl349@4113 123 destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
cl349@4113 124 return;
cl349@4113 125
cl349@4113 126 still_connected:
cl349@4113 127 destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
cl349@4113 128 return;
cl349@4113 129
cl349@4113 130 destroy:
cl349@4113 131 *pup = up->hash_next;
cl349@4113 132 usbif_release_ports(up);
cl349@4113 133 kmem_cache_free(usbif_priv_cachep, up);
cl349@4113 134 destroy->status = USBIF_BE_STATUS_OKAY;
cl349@4113 135 }
cl349@4113 136
cl349@4113 137 void usbif_connect(usbif_be_connect_t *connect)
cl349@4113 138 {
cl349@4113 139 domid_t domid = connect->domid;
cl349@4113 140 unsigned int evtchn = connect->evtchn;
cl349@4113 141 unsigned long shmem_frame = connect->shmem_frame;
cl349@4113 142 struct vm_struct *vma;
cl349@4113 143 pgprot_t prot;
cl349@4113 144 int error;
cl349@4113 145 usbif_priv_t *up;
cl349@4113 146 usbif_sring_t *sring;
cl349@4113 147
cl349@4113 148 up = usbif_find(domid);
cl349@4113 149 if ( unlikely(up == NULL) )
cl349@4113 150 {
cl349@4113 151 DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n",
cl349@4113 152 connect->domid);
cl349@4113 153 connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
cl349@4113 154 return;
cl349@4113 155 }
cl349@4113 156
cl349@4113 157 if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
cl349@4113 158 {
cl349@4113 159 connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
cl349@4113 160 return;
cl349@4113 161 }
cl349@4113 162
kaf24@5574 163 prot = __pgprot(_KERNPG_TABLE);
iap10@6697 164 error = direct_remap_pfn_range(&init_mm, VMALLOC_VMADDR(vma->addr),
iap10@6697 165 shmem_frame, PAGE_SIZE,
cl349@4113 166 prot, domid);
cl349@4113 167 if ( error != 0 )
cl349@4113 168 {
cl349@4113 169 if ( error == -ENOMEM )
cl349@4113 170 connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
cl349@4113 171 else if ( error == -EFAULT )
cl349@4113 172 connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
cl349@4113 173 else
cl349@4113 174 connect->status = USBIF_BE_STATUS_ERROR;
cl349@4113 175 vfree(vma->addr);
cl349@4113 176 return;
cl349@4113 177 }
cl349@4113 178
cl349@4113 179 if ( up->status != DISCONNECTED )
cl349@4113 180 {
cl349@4113 181 connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
cl349@4113 182 vfree(vma->addr);
cl349@4113 183 return;
cl349@4113 184 }
cl349@4113 185
cl349@4113 186 sring = (usbif_sring_t *)vma->addr;
cl349@4113 187 SHARED_RING_INIT(sring);
kaf24@4429 188 BACK_RING_INIT(&up->usb_ring, sring, PAGE_SIZE);
cl349@4113 189
cl349@4113 190 up->evtchn = evtchn;
cl349@4113 191 up->shmem_frame = shmem_frame;
cl349@4113 192 up->status = CONNECTED;
cl349@4113 193 usbif_get(up);
cl349@4113 194
kaf24@6020 195 (void)bind_evtchn_to_irqhandler(
kaf24@6020 196 evtchn, usbif_be_int, 0, "usbif-backend", up);
cl349@4113 197
cl349@4113 198 connect->status = USBIF_BE_STATUS_OKAY;
cl349@4113 199 }
cl349@4113 200
cl349@4113 201 /* Remove URBs for this interface before destroying it. */
cl349@4113 202 void usbif_deschedule(usbif_priv_t *up)
cl349@4113 203 {
cl349@4113 204 remove_from_usbif_list(up);
cl349@4113 205 }
cl349@4113 206
cl349@4113 207 int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
cl349@4113 208 {
cl349@4113 209 domid_t domid = disconnect->domid;
cl349@4113 210 usbif_priv_t *up;
cl349@4113 211
cl349@4113 212 up = usbif_find(domid);
cl349@4113 213 if ( unlikely(up == NULL) )
cl349@4113 214 {
cl349@4113 215 DPRINTK("usbif_disconnect attempted for non-existent usbif"
cl349@4113 216 " (%u)\n", disconnect->domid);
cl349@4113 217 disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
cl349@4113 218 return 1; /* Caller will send response error message. */
cl349@4113 219 }
cl349@4113 220
cl349@4113 221 if ( up->status == CONNECTED )
cl349@4113 222 {
cl349@4113 223 up->status = DISCONNECTING;
cl349@4113 224 up->disconnect_rspid = rsp_id;
cl349@4113 225 wmb(); /* Let other CPUs see the status change. */
kaf24@6020 226 unbind_evtchn_from_irqhandler(up->evtchn, up);
cl349@4113 227 usbif_deschedule(up);
cl349@4113 228 usbif_put(up);
cl349@4113 229 return 0; /* Caller should not send response message. */
cl349@4113 230 }
cl349@4113 231
cl349@4113 232 disconnect->status = USBIF_BE_STATUS_OKAY;
cl349@4113 233 return 1;
cl349@4113 234 }
cl349@4113 235
cl349@4113 236 void __init usbif_interface_init(void)
cl349@4113 237 {
cl349@4113 238 usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
cl349@4113 239 sizeof(usbif_priv_t),
cl349@4113 240 0, 0, NULL, NULL);
cl349@4113 241 memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
cl349@4113 242 }