/* * Translate a virtual address to a physical address by using 4 levels paging. */ unsigned long long vtop4_x86_64(unsigned long vaddr) { unsigned long page_dir, pml4, pgd_paddr, pgd_pte, pmd_paddr, pmd_pte; unsigned long pte_paddr, pte; if (SYMBOL(init_level4_pgt) == NOT_FOUND_SYMBOL) { ERRMSG("Can't get the symbol of init_level4_pgt.\n"); return NOT_PADDR; } /* * Get PGD. */ page_dir = SYMBOL(init_level4_pgt); page_dir += pml4_index(vaddr) * sizeof(unsigned long); if (!readmem(VADDR, page_dir, &pml4, sizeof pml4)) { ERRMSG("Can't get pml4 (page_dir:%lx).\n", page_dir); return NOT_PADDR; } if (info->vaddr_for_vtop == vaddr) MSG(" PGD : %16lx => %16lx\n", page_dir, pml4); if (!(pml4 & _PAGE_PRESENT)) { ERRMSG("Can't get a valid pml4.\n"); return NOT_PADDR; } /* * Get PUD. */ pgd_paddr = pml4 & PHYSICAL_PAGE_MASK; pgd_paddr += pgd_index(vaddr) * sizeof(unsigned long); if (!readmem(PADDR, pgd_paddr, &pgd_pte, sizeof pgd_pte)) { ERRMSG("Can't get pgd_pte (pgd_paddr:%lx).\n", pgd_paddr); return NOT_PADDR; } if (info->vaddr_for_vtop == vaddr) MSG(" PUD : %16lx => %16lx\n", pgd_paddr, pgd_pte); if (!(pgd_pte & _PAGE_PRESENT)) { ERRMSG("Can't get a valid pgd_pte.\n"); return NOT_PADDR; } /* * Get PMD. */ pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long); if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof pmd_pte)) { ERRMSG("Can't get pmd_pte (pmd_paddr:%lx).\n", pmd_paddr); return NOT_PADDR; } if (info->vaddr_for_vtop == vaddr) MSG(" PMD : %16lx => %16lx\n", pmd_paddr, pmd_pte); if (!(pmd_pte & _PAGE_PRESENT)) { ERRMSG("Can't get a valid pmd_pte.\n"); return NOT_PADDR; } if (pmd_pte & _PAGE_PSE) return (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) + (vaddr & ~_2MB_PAGE_MASK); /* * Get PTE. */ pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; pte_paddr += pte_index(vaddr) * sizeof(unsigned long); if (!readmem(PADDR, pte_paddr, &pte, sizeof pte)) { ERRMSG("Can't get pte (pte_paddr:%lx).\n", pte_paddr); return NOT_PADDR; } if (info->vaddr_for_vtop == vaddr) MSG(" PTE : %16lx => %16lx\n", pte_paddr, pte); if (!(pte & _PAGE_PRESENT)) { ERRMSG("Can't get a valid pte.\n"); return NOT_PADDR; } return (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(vaddr); }
/* * Just like above except go through the extra effort of splitting * buffers that cross 4Kbyte boundaries into multiple tx descriptors. */ int dma_tx(dma_info_t *di, void *p0, uint32 coreflags) { void *p, *next; uchar *data; uint plen, len; uchar *page, *start, *end; uint txout; uint32 ctrl; uint32 pa; DMA_TRACE(("%s: dma_tx\n", di->name)); txout = di->txout; ctrl = 0; /* * Walk the chain of packet buffers * splitting those that cross 4 Kbyte boundaries * allocating and initializing transmit descriptor entries. */ for (p = p0; p; p = next) { data = PKTDATA(di->drv, p); plen = PKTLEN(di->drv, p); next = PKTNEXT(di->drv, p); /* PR988 - skip zero length buffers */ if (plen == 0) continue; for (page = (uchar*)PAGEBASE(data); page <= (uchar*)PAGEBASE(data + plen - 1); page += PAGESZ) { /* return nonzero if out of tx descriptors */ if (NEXTTXD(txout) == di->txin) goto outoftxd; start = (page == (uchar*)PAGEBASE(data))? data: page; end = (page == (uchar*)PAGEBASE(data + plen))? (data + plen): (page + PAGESZ); len = end - start; /* build the descriptor control value */ ctrl = len & CTRL_BC_MASK; /* PR3697: Descriptor flags are not ignored for descriptors where SOF is clear */ ctrl |= coreflags; if ((p == p0) && (start == data)) ctrl |= CTRL_SOF; if ((next == NULL) && (end == (data + plen))) ctrl |= (CTRL_IOC | CTRL_EOF); if (txout == (di->ntxd - 1)) ctrl |= CTRL_EOT; /* get physical address of buffer start */ pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p); /* init the tx descriptor */ W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl)); W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset)); ASSERT(di->txp[txout] == NULL); txout = NEXTTXD(txout); } } /* if last txd eof not set, fix it */ if (!(ctrl & CTRL_EOF)) W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF)); /* save the packet */ di->txp[di->txout] = p0; /* bump the tx descriptor index */ di->txout = txout; /* kick the chip */ W_REG(&di->regs->xmtptr, I2B(txout)); /* tx flow control */ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; return (0); outoftxd: DMA_ERROR(("%s: dma_tx: out of txds\n", di->name)); PKTFREE(di->drv, p0, TRUE); di->txavail = 0; di->hnddma.txnobuf++; return (-1); }