debuggers.hg

view linux-2.6.10-rc2-xen-sparse/drivers/xen/netback/interface.c @ 3289:a169836882cb

bitkeeper revision 1.1159.170.59 (41b4c2fdJ2gj_BWy27Vj3ptayZp_yg)

sync w/ head.
author cl349@arcadians.cl.cam.ac.uk
date Mon Dec 06 20:37:17 2004 +0000 (2004-12-06)
parents 13728122c78d
children
line source
1 /******************************************************************************
2 * arch/xen/drivers/netif/backend/interface.c
3 *
4 * Network-device interface management.
5 *
6 * Copyright (c) 2004, Keir Fraser
7 */
9 #include "common.h"
10 #include <linux/rtnetlink.h>
12 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
13 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
14 #endif
16 #define NETIF_HASHSZ 1024
17 #define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
19 static netif_t *netif_hash[NETIF_HASHSZ];
21 netif_t *netif_find_by_handle(domid_t domid, unsigned int handle)
22 {
23 netif_t *netif = netif_hash[NETIF_HASH(domid, handle)];
24 while ( (netif != NULL) &&
25 ((netif->domid != domid) || (netif->handle != handle)) )
26 netif = netif->hash_next;
27 return netif;
28 }
30 static void __netif_disconnect_complete(void *arg)
31 {
32 netif_t *netif = (netif_t *)arg;
33 ctrl_msg_t cmsg;
34 netif_be_disconnect_t disc;
36 /*
37 * These can't be done in netif_disconnect() because at that point there
38 * may be outstanding requests in the network stack whose asynchronous
39 * responses must still be notified to the remote driver.
40 */
41 unbind_evtchn_from_irq(netif->evtchn);
42 vfree(netif->tx); /* Frees netif->rx as well. */
43 rtnl_lock();
44 (void)dev_close(netif->dev);
45 rtnl_unlock();
47 /* Construct the deferred response message. */
48 cmsg.type = CMSG_NETIF_BE;
49 cmsg.subtype = CMSG_NETIF_BE_DISCONNECT;
50 cmsg.id = netif->disconnect_rspid;
51 cmsg.length = sizeof(netif_be_disconnect_t);
52 disc.domid = netif->domid;
53 disc.netif_handle = netif->handle;
54 disc.status = NETIF_BE_STATUS_OKAY;
55 memcpy(cmsg.msg, &disc, sizeof(disc));
57 /*
58 * Make sure message is constructed /before/ status change, because
59 * after the status change the 'netif' structure could be deallocated at
60 * any time. Also make sure we send the response /after/ status change,
61 * as otherwise a subsequent CONNECT request could spuriously fail if
62 * another CPU doesn't see the status change yet.
63 */
64 mb();
65 if ( netif->status != DISCONNECTING )
66 BUG();
67 netif->status = DISCONNECTED;
68 mb();
70 /* Send the successful response. */
71 ctrl_if_send_response(&cmsg);
72 }
74 void netif_disconnect_complete(netif_t *netif)
75 {
76 INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif);
77 schedule_work(&netif->work);
78 }
80 void netif_create(netif_be_create_t *create)
81 {
82 int err = 0;
83 domid_t domid = create->domid;
84 unsigned int handle = create->netif_handle;
85 struct net_device *dev;
86 netif_t **pnetif, *netif;
87 char name[IFNAMSIZ];
89 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
90 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
91 if ( dev == NULL )
92 {
93 DPRINTK("Could not create netif: out of memory\n");
94 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
95 return;
96 }
98 netif = dev->priv;
99 memset(netif, 0, sizeof(*netif));
100 netif->domid = domid;
101 netif->handle = handle;
102 netif->status = DISCONNECTED;
103 spin_lock_init(&netif->rx_lock);
104 spin_lock_init(&netif->tx_lock);
105 atomic_set(&netif->refcnt, 0);
106 netif->dev = dev;
108 netif->credit_bytes = netif->remaining_credit = ~0UL;
109 netif->credit_usec = 0UL;
110 /*init_ac_timer(&new_vif->credit_timeout);*/
112 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
113 while ( *pnetif != NULL )
114 {
115 if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) )
116 {
117 DPRINTK("Could not create netif: already exists\n");
118 create->status = NETIF_BE_STATUS_INTERFACE_EXISTS;
119 free_netdev(dev);
120 return;
121 }
122 pnetif = &(*pnetif)->hash_next;
123 }
125 dev->hard_start_xmit = netif_be_start_xmit;
126 dev->get_stats = netif_be_get_stats;
127 memcpy(dev->dev_addr, create->mac, ETH_ALEN);
129 /* Disable queuing. */
130 dev->tx_queue_len = 0;
132 /* Force a different MAC from remote end. */
133 dev->dev_addr[2] ^= 1;
135 if ( (err = register_netdev(dev)) != 0 )
136 {
137 DPRINTK("Could not register new net device %s: err=%d\n",
138 dev->name, err);
139 create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
140 free_netdev(dev);
141 return;
142 }
144 netif->hash_next = *pnetif;
145 *pnetif = netif;
147 DPRINTK("Successfully created netif\n");
148 create->status = NETIF_BE_STATUS_OKAY;
149 }
151 void netif_destroy(netif_be_destroy_t *destroy)
152 {
153 domid_t domid = destroy->domid;
154 unsigned int handle = destroy->netif_handle;
155 netif_t **pnetif, *netif;
157 pnetif = &netif_hash[NETIF_HASH(domid, handle)];
158 while ( (netif = *pnetif) != NULL )
159 {
160 if ( (netif->domid == domid) && (netif->handle == handle) )
161 {
162 if ( netif->status != DISCONNECTED )
163 goto still_connected;
164 goto destroy;
165 }
166 pnetif = &netif->hash_next;
167 }
169 destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
170 return;
172 still_connected:
173 destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
174 return;
176 destroy:
177 *pnetif = netif->hash_next;
178 unregister_netdev(netif->dev);
179 free_netdev(netif->dev);
180 destroy->status = NETIF_BE_STATUS_OKAY;
181 }
183 void netif_connect(netif_be_connect_t *connect)
184 {
185 domid_t domid = connect->domid;
186 unsigned int handle = connect->netif_handle;
187 unsigned int evtchn = connect->evtchn;
188 unsigned long tx_shmem_frame = connect->tx_shmem_frame;
189 unsigned long rx_shmem_frame = connect->rx_shmem_frame;
190 struct vm_struct *vma;
191 pgprot_t prot;
192 int error;
193 netif_t *netif;
194 #if 0
195 struct net_device *eth0_dev;
196 #endif
198 netif = netif_find_by_handle(domid, handle);
199 if ( unlikely(netif == NULL) )
200 {
201 DPRINTK("netif_connect attempted for non-existent netif (%u,%u)\n",
202 connect->domid, connect->netif_handle);
203 connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
204 return;
205 }
207 if ( netif->status != DISCONNECTED )
208 {
209 connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED;
210 return;
211 }
213 if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL )
214 {
215 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
216 return;
217 }
219 prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
220 error = direct_remap_area_pages(&init_mm,
221 VMALLOC_VMADDR(vma->addr),
222 tx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
223 prot, domid);
224 error |= direct_remap_area_pages(&init_mm,
225 VMALLOC_VMADDR(vma->addr) + PAGE_SIZE,
226 rx_shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
227 prot, domid);
228 if ( error != 0 )
229 {
230 if ( error == -ENOMEM )
231 connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
232 else if ( error == -EFAULT )
233 connect->status = NETIF_BE_STATUS_MAPPING_ERROR;
234 else
235 connect->status = NETIF_BE_STATUS_ERROR;
236 vfree(vma->addr);
237 return;
238 }
240 netif->evtchn = evtchn;
241 netif->irq = bind_evtchn_to_irq(evtchn);
242 netif->tx_shmem_frame = tx_shmem_frame;
243 netif->rx_shmem_frame = rx_shmem_frame;
244 netif->tx =
245 (netif_tx_interface_t *)vma->addr;
246 netif->rx =
247 (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
248 netif->status = CONNECTED;
249 netif_get(netif);
251 netif->tx->resp_prod = netif->rx->resp_prod = 0;
253 rtnl_lock();
254 (void)dev_open(netif->dev);
255 rtnl_unlock();
257 (void)request_irq(netif->irq, netif_be_int, 0, netif->dev->name, netif);
258 netif_start_queue(netif->dev);
260 connect->status = NETIF_BE_STATUS_OKAY;
261 }
263 int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
264 {
265 domid_t domid = disconnect->domid;
266 unsigned int handle = disconnect->netif_handle;
267 netif_t *netif;
269 netif = netif_find_by_handle(domid, handle);
270 if ( unlikely(netif == NULL) )
271 {
272 DPRINTK("netif_disconnect attempted for non-existent netif"
273 " (%u,%u)\n", disconnect->domid, disconnect->netif_handle);
274 disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND;
275 return 1; /* Caller will send response error message. */
276 }
278 if ( netif->status == CONNECTED )
279 {
280 netif->status = DISCONNECTING;
281 netif->disconnect_rspid = rsp_id;
282 wmb(); /* Let other CPUs see the status change. */
283 netif_stop_queue(netif->dev);
284 free_irq(netif->irq, netif);
285 netif_deschedule(netif);
286 netif_put(netif);
287 return 0; /* Caller should not send response message. */
288 }
290 disconnect->status = NETIF_BE_STATUS_OKAY;
291 return 1;
292 }
294 void netif_interface_init(void)
295 {
296 memset(netif_hash, 0, sizeof(netif_hash));
297 }