📄 1006.ide.patch
字号:
+ // initialize ide_hwifs data structure+ // supports only one interface+ for (i = index; i < index + 1; ++i) {+ // register DMA handler+ hwif = &ide_hwifs[i];+ hwif->OUTB = em86xx_ide_OUTB;+ hwif->OUTW = em86xx_ide_OUTW;+ hwif->OUTBSYNC = em86xx_ide_OUTBSYNC;+ hwif->INB = em86xx_ide_INB;+ hwif->INW = em86xx_ide_INW;+ hwif->INSW = em86xx_ide_INSW;+ hwif->OUTSW = em86xx_ide_OUTSW;+ // MBUS can transfer two separate chunks of data blocks+ // but kernel usually allocate 4KB for each buffer cache,+ // which can hold 8 sectors, and usually they are not continous+ // So TANGO2X IDE interface can handle 16 sectors in best performance+ // If the request queue is bigger than this, driver need to use+ // bounce buffer+ hwif->rqsize = 16;+ if (!noautodma) {+#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEDMA+ hwif->autodma = 1;+ hwif->atapi_dma = 1;+#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEUDMA+ hwif->ultra_mask = 0x7f; // enable all Ultra DMA +#else+ hwif->ultra_mask = 0x00; // disable all Ultra DMA+#endif+ hwif->udma_four = 1;+ hwif->mwdma_mask = 0x07; // enable all Multi-word DMA (0/1/2)+ hwif->swdma_mask = 0x80; // disable all Single-word DMA++ // registers+ hwif->dma_command = REG_BASE_host_interface + IDECTRL_bmic;+ hwif->dma_status = REG_BASE_host_interface + IDECTRL_bmis;+ hwif->dma_prdtable = REG_BASE_host_interface + IDECTRL_bmidtp;++ // handlers+ hwif->ide_dma_read = em86xx_bmide_dma_read;+ hwif->ide_dma_write = em86xx_bmide_dma_write;+ hwif->ide_dma_begin = em86xx_bmide_dma_begin;+ hwif->ide_dma_end = em86xx_bmide_dma_end;+ hwif->ide_dma_check = em86xx_bmide_dma_check;+ hwif->ide_dma_on = em86xx_ide_dma_on;+ hwif->ide_dma_off = em86xx_ide_dma_off;+ hwif->ide_dma_off_quietly = em86xx_ide_dma_off_quietly;+ hwif->ide_dma_test_irq = em86xx_ide_dma_test_irq;+ hwif->ide_dma_host_on = em86xx_bmide_dma_host_on;+ hwif->ide_dma_host_off = em86xx_bmide_dma_host_off;+ hwif->ide_dma_bad_drive = em86xx_ide_dma_bad_drive;+ hwif->ide_dma_good_drive = em86xx_ide_dma_good_drive;+ hwif->ide_dma_count = em86xx_ide_dma_count;+ hwif->ide_dma_verbose = em86xx_ide_dma_verbose;+ hwif->ide_dma_retune = em86xx_ide_dma_retune;+ hwif->ide_dma_lostirq = em86xx_bmide_dma_lostirq;+ hwif->ide_dma_timeout = em86xx_bmide_dma_timeout;+ hwif->speedproc = em86xx_bmide_tune_chipset;+#endif+ }+ }++ // set to maximum PIO mode+ for (i = 0; i < MAX_DRIVES; ++i)+ em86xx_bmide_tune_chipset_drive(i, XFER_PIO_4, 0);++ if (!noautodma) {+#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEDMA+ if ((g_bounce_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, DMA_BOUNCE_BUF_ORDER)) == NULL)+ printk("IDE: Can not allocate buffer for IDE transfer\n");++#ifdef EM86XX_BOUNCE_BUFFER_NOCACHE+ g_bounce_buf = (unsigned char *)KSEG1ADDR((unsigned long)g_bounce_buf);+ printk("Bounce buffer starts at 0x%08lx\n", (unsigned long)g_bounce_buf);+#endif++#endif // EM86XX_BMIDEDMA+ }+ return 0;+}++#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEDMA++//+// IDE DMA handlers+//++int em86xx_bmide_dma_read(ide_drive_t *drive)+{+ struct request *rq;++ drive->waiting_for_dma = 1;+ rq = HWGROUP(drive)->rq;+ // printk("em86xx_bmide_dma_read : nsect = %ld\n", rq->nr_sectors);+ return em86xx_bmide_rwdma(drive, 1, rq);+}++int em86xx_bmide_dma_write(ide_drive_t *drive)+{+ struct request *rq;++ drive->waiting_for_dma = 1;+ rq = HWGROUP(drive)->rq;+ // printk("em86xx_bmide_dma_write : sector = %ld, nsect = %ld\n", rq->sector, rq->nr_sectors);+ return em86xx_bmide_rwdma(drive, 0, rq);+}++int em86xx_bmide_dma_begin(ide_drive_t *drive)+{+ return(0);+}++int em86xx_bmide_dma_end(ide_drive_t *drive)+{+ int status;++ drive->waiting_for_dma = 0;+ status = em86xx_bmide_dma_end_io(drive);+ return(status);+}++int em86xx_bmide_dma_lostirq(ide_drive_t *drive)+{+ struct request *rq = HWGROUP(drive)->rq;+ unsigned int regbase = ((rq->cmd == READ) ? g_regbase_read : g_regbase_write);++ if (em86xx_mbus_inuse(regbase) != 0) + em86xx_mbus_reset(regbase, SBOX_IDEDVD);+ return 0;+}++int em86xx_bmide_dma_timeout(ide_drive_t *drive)+{+ struct request *rq = HWGROUP(drive)->rq;+ unsigned int regbase = ((rq->cmd == READ) ? g_regbase_read : g_regbase_write);++ if (em86xx_mbus_inuse(regbase) != 0) + em86xx_mbus_reset(regbase, SBOX_IDEDVD);+ return 0;+}++int em86xx_bmide_dma_check(ide_drive_t *drive)+{+ int mode;++#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEUDMA+ if ((gbus_read_uint32(pGBus, REG_BASE_host_interface + IDECTRL_idestatus) & 0x02) == 0x02)+ mode = 1; // 40 donductor cable (UDMA33) : Mode 0/1/2+ else + mode = 4; // 80 conductor cable : Mode 0/1/2/3/4/5/6+#else+ mode = 0; // MW DMA mode 2+#endif++ return em86xx_ide_config_drive_for_dma(drive, mode);+}++int em86xx_bmide_dma_host_on(ide_drive_t *drive)+{+ if (drive->using_dma) {+ ide_hwif_t *hwif = HWIF(drive);+ u8 unit = (drive->select.b.unit & 0x01);+ u8 dma_stat = hwif->INB(hwif->dma_status);++ hwif->OUTB((dma_stat | (1 << (5 + unit))), hwif->dma_status);+ return 0;+ }+ return 1;+}++int em86xx_bmide_dma_host_off(ide_drive_t *drive)+{+ ide_hwif_t *hwif = HWIF(drive);+ u8 unit = (drive->select.b.unit & 0x01);+ u8 dma_stat = hwif->INB(hwif->dma_status);++ hwif->OUTB((dma_stat & ~(1 << (5 + unit))), hwif->dma_status);++ return 0;+}++int em86xx_bmide_tune_chipset(ide_drive_t *drive, u8 speed)+{+ em86xx_bmide_tune_chipset_drive(drive->select.b.unit, speed, 1);++ return ide_config_drive_speed(drive, speed);+}++//+// helper functions+//++#ifdef EM86XX_BMIDE_DMA_MERGE_BH+#define MBUS_LINEAR_MAX (0x2000 - 1)+#endif++/* Get the I/O size of given request */+static inline int get_request_size(struct request *rq)+{+ unsigned int rq_size;+ struct buffer_head *bh;++ for (rq_size = 0, bh = rq->bh; bh != NULL; bh = bh->b_reqnext) + rq_size += bh->b_size;++ return(rq_size);+}++#ifdef CONFIG_BLK_DEV_TANGO2_BMIDEDMA+// return the number of fragmented blocks+static __inline__ int em86xx_bmide_request_fragment(struct request *rq)+{+ int ntransfer = 0;+ struct buffer_head *bh = rq->bh;++#ifdef EM86XX_BMIDE_DMA_MERGE_BH+ unsigned long addr;+ unsigned int size;+ unsigned int sector;++ if (rq == crq)+ return(crq_ntransfer);++ /* Try to merge multiple BH if possible -- deal with one fragment only */+ for (ntransfer = 0, bh = rq->bh;;) {+ if (bh == NULL)+ break;+ else {+ if (++ntransfer > 1) /* More than one fragment found */+ break; + }+ addr = (unsigned long)bh->b_data;+ size = bh->b_size;+ sector = bh->b_rsector;+ for (bh = bh->b_reqnext; bh != NULL; bh = bh->b_reqnext) {+ if ((addr + size) != (unsigned long)bh->b_data)+ break; /* data is not contiguous */+ else { /* Merge the next BH */+ size += bh->b_size;+ }+ } + }+ if (ntransfer < 2) /* This can be done with one fragment (linear or rectangular) */+ goto done;++ /* Try to merge multiple BH if possible -- deal with two fragments or more */+ for (ntransfer = 0, bh = rq->bh;;) {+ if (bh == NULL)+ break;+ else+ ++ntransfer;+ addr = (unsigned long)bh->b_data;+ size = bh->b_size;+ sector = bh->b_rsector;+ for (bh = bh->b_reqnext; bh != NULL; bh = bh->b_reqnext) {+ if ((addr + size) != (unsigned long)bh->b_data)+ break; /* data is not contiguous */+ else if ((size + bh->b_size) > MBUS_LINEAR_MAX)+ break; /* Size too large */+ else { /* Merge the next BH */+ size += bh->b_size;+ }+ } + }+#else+ if (rq == crq)+ return(crq_ntransfer);++ do {+ ++ntransfer;+ } while ((bh = bh->b_reqnext) != NULL);+#endif++done:+ return ntransfer;+}++// prepare MBUS for DMA transfer+// stop_if_fragment must be non-zero+static struct buffer_head *em86xx_bmide_dma_setup(int read, struct request *rq, int stop_if_fragment)+{+ struct buffer_head *bh = rq->bh;++ // scans buffer head and calculate the requested transfer size+ // MBUS can't transfer to more than two separate regions. + // So if the buffer head is too fragmented, return non-NULL value+#ifdef EM86XX_BMIDE_DMA_MERGE_BH+ struct {+ unsigned long addr;+ unsigned int size;+ unsigned int sector;+ } transfer[2], *ptransfer;+ unsigned int ntransfer;++ crq = rq;++ /* Try to merge multiple BH if possible -- one fragment only */+ for (ntransfer = 0, ptransfer = &transfer[0], bh = rq->bh;; ptransfer++) {+ if (bh == NULL)+ break;+ else if (++ntransfer > 1)+ break;++ ptransfer->addr = (unsigned long)bh->b_data;+ ptransfer->size = bh->b_size;+ ptransfer->sector = bh->b_rsector;+ for (bh = bh->b_reqnext; bh != NULL; bh = bh->b_reqnext) {+ if ((ptransfer->addr + ptransfer->size) != (unsigned long)bh->b_data)+ break; /* data is not contiguous */+ else { /* Merge the next BH */+ ptransfer->size += bh->b_size;+ }+ } + }+ if (ntransfer < 2) /* This can be done with one fragment (linear or rectangular) */+ goto start_transfer;++ /* Try to merge multiple BH if possible */+ for (ntransfer = 0, ptransfer = &transfer[0], bh = rq->bh;; ptransfer++) {+ if (bh == NULL)+ break;+ else if (++ntransfer > 2)+ break;++ ptransfer->addr = (unsigned long)bh->b_data;+ ptransfer->size = bh->b_size;+ ptransfer->sector = bh->b_rsector;+ for (bh = bh->b_reqnext; bh != NULL; bh = bh->b_reqnext) {+ if ((ptransfer->addr + ptransfer->size) != (unsigned long)bh->b_data)+ break; /* data is not contiguous */+ else if ((ptransfer->size + bh->b_size) > MBUS_LINEAR_MAX)+ break; /* Size too large */+ else { /* Merge the next BH */+ ptransfer->size += bh->b_size;+ }+ } + }++ if ((ntransfer > 2) && (stop_if_fragment != 0)) {+ crq_ntransfer = ntransfer;+ return bh;+ }+#else+ struct buffer_head *prevbh;++ struct {+ unsigned long addr;+ unsigned int size;+ } transfer[2], *ptransfer;+ unsigned int ntransfer, size;++ crq = rq;++ for (prevbh = NULL, ntransfer = 0, ptransfer = transfer, size = 0; bh != NULL; prevbh = bh, bh = bh->b_reqnext) {+ if (++ntransfer > 2) {+ if (stop_if_fragment) {+ crq_ntransfer = ntransfer;+ return bh;+ }+ break;+ }+ ptransfer->addr = (unsigned long) bh->b_data;+ ptransfer->size = bh->b_size;+ // printk("MBUS : bh = %p, bh->next = %p, %08x, %08x\n", bh, bh->b_reqnext, ptransfer->addr, ptransfer->size);+ ++ptransfer;+ size += bh->b_size;+ }+#endif++start_transfer:++ crq_ntransfer = ntransfer;++ // setup MBUS+ if (ntransfer == 1) {+#ifdef CONFIG_NONCOHERENT_IO+ if (!is_physical(transfer[0].addr)) {+ if (read) + dma_cache_inv(transfer[0].addr, transfer[0].size);+ else+ dma_cache_wback_inv(transfer[0].addr, transfer[0].size);+ }+#endif+ if (transfer[0].size <= MBUS_LINEAR_MAX) {+ /* Do linear transfer */+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -