Signed-off-by: Gerd Hoffmann Index: source-lnx-stable-22813/drivers/xen/netfront/netfront.c =================================================================== --- source-lnx-stable-22813.orig/drivers/xen/netfront/netfront.c 2006-08-17 15:20:17.000000000 +0200 +++ source-lnx-stable-22813/drivers/xen/netfront/netfront.c 2006-08-17 15:20:17.000000000 +0200 @@ -494,6 +494,7 @@ static int network_open(struct net_devic { struct netfront_info *np = netdev_priv(dev); + DPRINTK("%s\n", np->xbdev->nodename); memset(&np->stats, 0, sizeof(np->stats)); network_alloc_rx_buffers(dev); @@ -1285,10 +1286,80 @@ err: return more_to_do; } +static void netif_release_rx_bufs(struct netfront_info *np) +{ + struct mmu_update *mmu = np->rx_mmu; + struct multicall_entry *mcl = np->rx_mcl; + struct sk_buff *skb; + unsigned long mfn; + int bufs = 0, gnttab = 0, unused = 0; + int id, ref; + + spin_lock(&np->rx_lock); + + for (id = 0; id < NET_RX_RING_SIZE; id++) { + if ((ref = np->grant_rx_ref[id]) == GRANT_INVALID_REF) { + unused++; + continue; + } + if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) { + gnttab++; + continue; + } + + gnttab_release_grant_reference(&np->gref_rx_head, ref); + np->grant_rx_ref[id] = GRANT_INVALID_REF; + + skb = np->rx_skbs[id]; + add_id_to_freelist(np->rx_skbs, id); + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Remap the page. */ + MULTI_update_va_mapping(mcl, (unsigned long)skb->head, + pfn_pte_ma(mfn, PAGE_KERNEL), + 0); + mcl++; + mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) + | MMU_MACHPHYS_UPDATE; + mmu->val = __pa(skb->head) >> PAGE_SHIFT; + mmu++; + + set_phys_to_machine(__pa(skb->head) >> PAGE_SHIFT, + mfn); + } + bufs++; + +#if 0 /* FIXME */ + dev_kfree_skb(skb); +#endif + } + + printk("%s: %d released ok, %d gnttab errs, %d unused slots\n", + __FUNCTION__, bufs, gnttab, unused); + if (0 == bufs) + return; + + /* Some pages are no longer absent... */ + balloon_update_driver_allowance(-bufs); + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + /* Do all the remapping work, and M2P updates, in one big hypercall. */ + mcl->op = __HYPERVISOR_mmu_update; + mcl->args[0] = (unsigned long)np->rx_mmu; + mcl->args[1] = mmu - np->rx_mmu; + mcl->args[2] = 0; + mcl->args[3] = DOMID_SELF; + mcl++; + HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl); + } + + spin_unlock(&np->rx_lock); +} static int network_close(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); + DPRINTK("%s\n", np->xbdev->nodename); netif_stop_queue(np->netdev); return 0; } @@ -1427,6 +1498,8 @@ static void network_connect(struct net_d static void netif_uninit(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); + DPRINTK("%s\n", np->xbdev->nodename); + netif_release_rx_bufs(np); gnttab_free_grant_references(np->gref_tx_head); gnttab_free_grant_references(np->gref_rx_head); }