ia64/xen-unstable

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