?? sbus.c
字號:
/* If we are here, we know we have at least one * more page to map. So walk forward until we * hit a page crossing, and begin creating new * mappings from that spot. */ for (;;) { unsigned long tmp; tmp = (unsigned long) SG_ENT_PHYS_ADDRESS(sg); len = sg->length; if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { pteval = tmp & IO_PAGE_MASK; offset = tmp & (IO_PAGE_SIZE - 1UL); break; } if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; offset = 0UL; len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); break; } sg++; } pteval = ((pteval & IOPTE_PAGE) | iopte_bits); while (len > 0) { *iopte++ = __iopte(pteval); pteval += IO_PAGE_SIZE; len -= (IO_PAGE_SIZE - offset); offset = 0; dma_npages--; } pteval = (pteval & IOPTE_PAGE) + len; sg++; /* Skip over any tail mappings we've fully mapped, * adjusting pteval along the way. Stop when we * detect a page crossing event. */ while (sg < sg_end && (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && (pteval == SG_ENT_PHYS_ADDRESS(sg)) && ((pteval ^ (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { pteval += sg->length; sg++; } if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) pteval = ~0UL; } while (dma_npages != 0); dma_sg++; }}int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir){ struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, npages; iopte_t *iopte; u32 dma_base; struct scatterlist *sgtmp; int used; unsigned long iopte_bits; if (dir == SBUS_DMA_NONE) BUG(); /* Fast path single entry scatterlists. */ if (nents == 1) { sg->dma_address = sbus_map_single(sdev, (sg->address ? sg->address : (page_address(sg->page) + sg->offset)), sg->length, dir); sg->dma_length = sg->length; return 1; } npages = prepare_sg(sg, nents); spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_streaming_cluster(iommu, npages); if (iopte == NULL) goto bad; dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT); /* Normalize DVMA addresses. */ sgtmp = sg; used = nents; while (used && sgtmp->dma_length) { sgtmp->dma_address += dma_base; sgtmp++; used--; } used = nents - used; iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; if (dir != SBUS_DMA_TODEVICE) iopte_bits |= IOPTE_WRITE; fill_sg(iopte, sg, used, nents, iopte_bits);#ifdef VERIFY_SG verify_sglist(sg, nents, iopte, npages);#endif spin_unlock_irqrestore(&iommu->lock, flags); return used;bad: spin_unlock_irqrestore(&iommu->lock, flags); BUG(); return 0;}void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction){ unsigned long size, flags; struct sbus_iommu *iommu; u32 dvma_base; int i; /* Fast path single entry scatterlists. */ if (nents == 1) { sbus_unmap_single(sdev, sg->dma_address, sg->dma_length, direction); return; } dvma_base = sg[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nents; i++) { if (sg[i].dma_length == 0) break; } i--; size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - dvma_base; iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags);}void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction){ struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags; size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); spin_lock_irqsave(&iommu->lock, flags); strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags);}void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction){ struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, size; u32 base; int i; base = sg[0].dma_address & IO_PAGE_MASK; for (i = 0; i < nents; i++) { if (sg[i].dma_length == 0) break; } i--; size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; spin_lock_irqsave(&iommu->lock, flags); strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags);}/* Enable 64-bit DVMA mode for the given device. */void sbus_set_sbus64(struct sbus_dev *sdev, int bursts){ struct sbus_iommu *iommu = sdev->bus->iommu; int slot = sdev->slot; unsigned long cfg_reg; u64 val; cfg_reg = iommu->sbus_control_reg; switch (slot) { case 0: cfg_reg += 0x20UL; break; case 1: cfg_reg += 0x28UL; break; case 2: cfg_reg += 0x30UL; break; case 3: cfg_reg += 0x38UL; break; case 13: cfg_reg += 0x40UL; break; case 14: cfg_reg += 0x48UL; break; case 15: cfg_reg += 0x50UL; break; default: return; }; val = upa_readq(cfg_reg); if (val & (1UL << 14UL)) { /* Extended transfer mode already enabled. */ return; } val |= (1UL << 14UL); if (bursts & DMA_BURST8) val |= (1UL << 1UL); if (bursts & DMA_BURST16) val |= (1UL << 2UL); if (bursts & DMA_BURST32) val |= (1UL << 3UL); if (bursts & DMA_BURST64) val |= (1UL << 4UL); upa_writeq(val, cfg_reg);}/* SBUS SYSIO INO number to Sparc PIL level. */static unsigned char sysio_ino_to_pil[] = { 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 0 */ 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 1 */ 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 2 */ 0, 4, 4, 7, 5, 7, 8, 9, /* SBUS slot 3 */ 4, /* Onboard SCSI */ 5, /* Onboard Ethernet *//*XXX*/ 8, /* Onboard BPP */ 0, /* Bogon */ 13, /* Audio *//*XXX*/15, /* PowerFail */ 0, /* Bogon */ 0, /* Bogon */ 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ 11, /* Floppy */ 0, /* Spare Hardware (bogon for now) */ 0, /* Keyboard (bogon for now) */ 0, /* Mouse (bogon for now) */ 0, /* Serial (bogon for now) */ 0, 0, /* Bogon, Bogon */ 10, /* Timer 0 */ 11, /* Timer 1 */ 0, 0, /* Bogon, Bogon */ 15, /* Uncorrectable SBUS Error */ 15, /* Correctable SBUS Error */ 15, /* SBUS Error *//*XXX*/ 0, /* Power Management (bogon for now) */};/* INO number to IMAP register offset for SYSIO external IRQ's. * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */#define SYSIO_IMAP_SLOT0 0x2c04UL#define SYSIO_IMAP_SLOT1 0x2c0cUL#define SYSIO_IMAP_SLOT2 0x2c14UL#define SYSIO_IMAP_SLOT3 0x2c1cUL#define SYSIO_IMAP_SCSI 0x3004UL#define SYSIO_IMAP_ETH 0x300cUL#define SYSIO_IMAP_BPP 0x3014UL#define SYSIO_IMAP_AUDIO 0x301cUL#define SYSIO_IMAP_PFAIL 0x3024UL#define SYSIO_IMAP_KMS 0x302cUL#define SYSIO_IMAP_FLPY 0x3034UL#define SYSIO_IMAP_SHW 0x303cUL#define SYSIO_IMAP_KBD 0x3044UL#define SYSIO_IMAP_MS 0x304cUL#define SYSIO_IMAP_SER 0x3054UL#define SYSIO_IMAP_TIM0 0x3064UL#define SYSIO_IMAP_TIM1 0x306cUL#define SYSIO_IMAP_UE 0x3074UL#define SYSIO_IMAP_CE 0x307cUL#define SYSIO_IMAP_SBERR 0x3084UL#define SYSIO_IMAP_PMGMT 0x308cUL#define SYSIO_IMAP_GFX 0x3094UL#define SYSIO_IMAP_EUPA 0x309cUL#define bogon ((unsigned long) -1)static unsigned long sysio_irq_offsets[] = { /* SBUS Slot 0 --> 3, level 1 --> 7 */ SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, /* Onboard devices (not relevant/used on SunFire). */ SYSIO_IMAP_SCSI, SYSIO_IMAP_ETH, SYSIO_IMAP_BPP, bogon, SYSIO_IMAP_AUDIO, SYSIO_IMAP_PFAIL, bogon, bogon, SYSIO_IMAP_KMS, SYSIO_IMAP_FLPY, SYSIO_IMAP_SHW, SYSIO_IMAP_KBD, SYSIO_IMAP_MS, SYSIO_IMAP_SER, bogon, bogon, SYSIO_IMAP_TIM0, SYSIO_IMAP_TIM1, bogon, bogon, SYSIO_IMAP_UE, SYSIO_IMAP_CE, SYSIO_IMAP_SBERR, SYSIO_IMAP_PMGMT,};#undef bogon#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))/* Convert Interrupt Mapping register pointer to assosciated * Interrupt Clear register pointer, SYSIO specific version. */#define SYSIO_ICLR_UNUSED0 0x3400UL#define SYSIO_ICLR_SLOT0 0x340cUL#define SYSIO_ICLR_SLOT1 0x344cUL#define SYSIO_ICLR_SLOT2 0x348cUL#define SYSIO_ICLR_SLOT3 0x34ccULstatic unsigned long sysio_imap_to_iclr(unsigned long imap){ unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; return imap + diff;}unsigned int sbus_build_irq(void *buscookie, unsigned int ino){ struct sbus_bus *sbus = (struct sbus_bus *)buscookie; struct sbus_iommu *iommu = sbus->iommu; unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long imap, iclr; int pil, sbus_level = 0; pil = sysio_ino_to_pil[ino]; if (!pil) { printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); panic("Bad SYSIO IRQ translations..."); } if (PIL_RESERVED(pil)) BUG(); imap = sysio_irq_offsets[ino]; if (imap == ((unsigned long)-1)) { prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", ino, pil); prom_halt(); } imap += reg_base; /* SYSIO inconsistancy. For external SLOTS, we have to select * the right ICLR register based upon the lower SBUS irq level * bits. */ if (ino >= 0x20) { iclr = sysio_imap_to_iclr(imap); } else { int sbus_slot = (ino & 0x18)>>3; sbus_level = ino & 0x7; switch(sbus_slot) { case 0: iclr = reg_base + SYSIO_ICLR_SLOT0; break; case 1: iclr = reg_base + SYSIO_ICLR_SLOT1; break; case 2: iclr = reg_base + SYSIO_ICLR_SLOT2; break; default: case 3: iclr = reg_base + SYSIO_ICLR_SLOT3; break; }; iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -