ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/interface.c @ 6433:0610add7c3fe

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 16:27:04 2005 +0000 (2005-08-25)
parents b54144915ae6 37030498b978
children b4b3f6be5226
line source
1 /******************************************************************************
2 * arch/xen/drivers/netif/backend/interface.c
3 *
4 * Network-device interface management.
5 *
6 * Copyright (c) 2004-2005, Keir Fraser
7 */
9 #include "common.h"
10 #include <linux/rtnetlink.h>
12 static void __netif_up(netif_t *netif)
13 {
14 struct net_device *dev = netif->dev;
15 spin_lock_bh(&dev->xmit_lock);
16 netif->active = 1;
17 spin_unlock_bh(&dev->xmit_lock);
18 (void)bind_evtchn_to_irqhandler(
19 netif->evtchn, netif_be_int, 0, dev->name, netif);
20 netif_schedule_work(netif);
21 }
23 static void __netif_down(netif_t *netif)
24 {
25 struct net_device *dev = netif->dev;
26 spin_lock_bh(&dev->xmit_lock);
27 netif->active = 0;
28 spin_unlock_bh(&dev->xmit_lock);
29 unbind_evtchn_from_irqhandler(netif->evtchn, netif);
30 netif_deschedule_work(netif);
31 }
33 static int net_open(struct net_device *dev)
34 {
35 netif_t *netif = netdev_priv(dev);
36 if (netif->status == CONNECTED)
37 __netif_up(netif);
38 netif_start_queue(dev);
39 return 0;
40 }
42 static int net_close(struct net_device *dev)
43 {
44 netif_t *netif = netdev_priv(dev);
45 netif_stop_queue(dev);
46 if (netif->status == CONNECTED)
47 __netif_down(netif);
48 return 0;
49 }
51 netif_t *alloc_netif(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
52 {
53 int err = 0, i;
54 struct net_device *dev;
55 netif_t *netif;
56 char name[IFNAMSIZ] = {};
58 snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
59 dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
60 if (dev == NULL) {
61 DPRINTK("Could not create netif: out of memory\n");
62 return NULL;
63 }
65 netif = netdev_priv(dev);
66 memset(netif, 0, sizeof(*netif));
67 netif->domid = domid;
68 netif->handle = handle;
69 netif->status = DISCONNECTED;
70 atomic_set(&netif->refcnt, 0);
71 netif->dev = dev;
73 netif->credit_bytes = netif->remaining_credit = ~0UL;
74 netif->credit_usec = 0UL;
75 init_timer(&netif->credit_timeout);
77 dev->hard_start_xmit = netif_be_start_xmit;
78 dev->get_stats = netif_be_get_stats;
79 dev->open = net_open;
80 dev->stop = net_close;
81 dev->features = NETIF_F_NO_CSUM;
83 /* Disable queuing. */
84 dev->tx_queue_len = 0;
86 for (i = 0; i < ETH_ALEN; i++)
87 if (be_mac[i] != 0)
88 break;
89 if (i == ETH_ALEN) {
90 /*
91 * Initialise a dummy MAC address. We choose the numerically largest
92 * non-broadcast address to prevent the address getting stolen by an
93 * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
94 */
95 memset(dev->dev_addr, 0xFF, ETH_ALEN);
96 dev->dev_addr[0] &= ~0x01;
97 } else
98 memcpy(dev->dev_addr, be_mac, ETH_ALEN);
100 rtnl_lock();
101 err = register_netdevice(dev);
102 rtnl_unlock();
103 if (err) {
104 DPRINTK("Could not register new net device %s: err=%d\n",
105 dev->name, err);
106 free_netdev(dev);
107 return NULL;
108 }
110 DPRINTK("Successfully created netif\n");
111 return netif;
112 }
114 static int map_frontend_page(netif_t *netif, unsigned long localaddr,
115 unsigned long tx_ring_ref, unsigned long rx_ring_ref)
116 {
117 #if !defined(CONFIG_XEN_NETDEV_GRANT_TX)||!defined(CONFIG_XEN_NETDEV_GRANT_RX)
118 pgprot_t prot = __pgprot(_KERNPG_TABLE);
119 int err;
120 #endif
121 #if defined(CONFIG_XEN_NETDEV_GRANT_TX)
122 {
123 struct gnttab_map_grant_ref op;
125 /* Map: Use the Grant table reference */
126 op.host_addr = localaddr;
127 op.flags = GNTMAP_host_map;
128 op.ref = tx_ring_ref;
129 op.dom = netif->domid;
131 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
132 if (op.handle < 0) {
133 DPRINTK(" Grant table operation failure !\n");
134 return op.handle;
135 }
137 netif->tx_shmem_ref = tx_ring_ref;
138 netif->tx_shmem_handle = op.handle;
139 netif->tx_shmem_vaddr = localaddr;
140 }
141 #else
142 err = direct_remap_area_pages(&init_mm, localaddr,
143 tx_ring_ref<<PAGE_SHIFT, PAGE_SIZE,
144 prot, netif->domid);
145 if (err)
146 return err;
147 #endif
149 #if defined(CONFIG_XEN_NETDEV_GRANT_RX)
150 {
151 struct gnttab_map_grant_ref op;
153 /* Map: Use the Grant table reference */
154 op.host_addr = localaddr + PAGE_SIZE;
155 op.flags = GNTMAP_host_map;
156 op.ref = rx_ring_ref;
157 op.dom = netif->domid;
159 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
160 if (op.handle < 0) {
161 DPRINTK(" Grant table operation failure !\n");
162 return op.handle;
163 }
165 netif->rx_shmem_ref = rx_ring_ref;
166 netif->rx_shmem_handle = op.handle;
167 netif->rx_shmem_vaddr = localaddr + PAGE_SIZE;
168 }
169 #else
170 err = direct_remap_area_pages(&init_mm, localaddr + PAGE_SIZE,
171 rx_ring_ref<<PAGE_SHIFT, PAGE_SIZE,
172 prot, netif->domid);
173 if (err)
174 return err;
175 #endif
177 return 0;
178 }
180 static void unmap_frontend_page(netif_t *netif)
181 {
182 #if defined(CONFIG_XEN_NETDEV_GRANT_RX) || defined(CONFIG_XEN_NETDEV_GRANT_TX)
183 struct gnttab_unmap_grant_ref op;
184 #endif
186 #ifdef CONFIG_XEN_NETDEV_GRANT_TX
187 op.host_addr = netif->tx_shmem_vaddr;
188 op.handle = netif->tx_shmem_handle;
189 op.dev_bus_addr = 0;
190 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
191 #endif
193 #ifdef CONFIG_XEN_NETDEV_GRANT_RX
194 op.host_addr = netif->rx_shmem_vaddr;
195 op.handle = netif->rx_shmem_handle;
196 op.dev_bus_addr = 0;
197 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
198 #endif
199 }
201 int netif_map(netif_t *netif, unsigned long tx_ring_ref,
202 unsigned long rx_ring_ref, unsigned int evtchn)
203 {
204 struct vm_struct *vma;
205 evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
206 int err;
208 vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP);
209 if (vma == NULL)
210 return -ENOMEM;
212 err = map_frontend_page(netif, (unsigned long)vma->addr, tx_ring_ref,
213 rx_ring_ref);
214 if (err) {
215 vfree(vma->addr);
216 return err;
217 }
219 op.u.bind_interdomain.dom1 = DOMID_SELF;
220 op.u.bind_interdomain.dom2 = netif->domid;
221 op.u.bind_interdomain.port1 = 0;
222 op.u.bind_interdomain.port2 = evtchn;
223 err = HYPERVISOR_event_channel_op(&op);
224 if (err) {
225 unmap_frontend_page(netif);
226 vfree(vma->addr);
227 return err;
228 }
230 netif->evtchn = op.u.bind_interdomain.port1;
231 netif->remote_evtchn = evtchn;
233 netif->tx = (netif_tx_interface_t *)vma->addr;
234 netif->rx = (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE);
235 netif->tx->resp_prod = netif->rx->resp_prod = 0;
236 netif_get(netif);
237 wmb(); /* Other CPUs see new state before interface is started. */
239 rtnl_lock();
240 netif->status = CONNECTED;
241 wmb();
242 if (netif_running(netif->dev))
243 __netif_up(netif);
244 rtnl_unlock();
246 return 0;
247 }
249 static void free_netif(void *arg)
250 {
251 evtchn_op_t op = { .cmd = EVTCHNOP_close };
252 netif_t *netif = (netif_t *)arg;
254 /*
255 * These can't be done in netif_disconnect() because at that point there
256 * may be outstanding requests in the network stack whose asynchronous
257 * responses must still be notified to the remote driver.
258 */
260 op.u.close.port = netif->evtchn;
261 op.u.close.dom = DOMID_SELF;
262 HYPERVISOR_event_channel_op(&op);
263 op.u.close.port = netif->remote_evtchn;
264 op.u.close.dom = netif->domid;
265 HYPERVISOR_event_channel_op(&op);
267 unregister_netdev(netif->dev);
269 if (netif->tx) {
270 unmap_frontend_page(netif);
271 vfree(netif->tx); /* Frees netif->rx as well. */
272 }
274 free_netdev(netif->dev);
275 }
277 void free_netif_callback(netif_t *netif)
278 {
279 INIT_WORK(&netif->free_work, free_netif, (void *)netif);
280 schedule_work(&netif->free_work);
281 }
283 void netif_creditlimit(netif_t *netif)
284 {
285 #if 0
286 /* Set the credit limit (reset remaining credit to new limit). */
287 netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes;
288 netif->credit_usec = creditlimit->period_usec;
290 if (netif->status == CONNECTED) {
291 /*
292 * Schedule work so that any packets waiting under previous credit
293 * limit are dealt with (acts like a replenishment point).
294 */
295 netif->credit_timeout.expires = jiffies;
296 netif_schedule_work(netif);
297 }
298 #endif
299 }
301 int netif_disconnect(netif_t *netif)
302 {
304 if (netif->status == CONNECTED) {
305 rtnl_lock();
306 netif->status = DISCONNECTING;
307 wmb();
308 if (netif_running(netif->dev))
309 __netif_down(netif);
310 rtnl_unlock();
311 netif_put(netif);
312 return 0; /* Caller should not send response message. */
313 }
315 return 1;
316 }