By restructuring the ncr53c8xx driver a little, we can provide the same functionality as the dma_declare_coherent_memory interface without touching the generic dma paths. Signed-off-by: Matthew Wilcox <willy@xxxxxxxxxxxxxxx> --- drivers/scsi/NCR_Q720.c | 45 ++++++++----------- drivers/scsi/ncr53c8xx.c | 113 +++++++++++++++++++++++++++++++++++++--------- drivers/scsi/ncr53c8xx.h | 13 +++++ 3 files changed, 124 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index a8bbdc2..8db20a6 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c @@ -36,9 +36,10 @@ MODULE_LICENSE("GPL"); #define NCR_Q720_VERSION "0.9" -/* We needs this helper because we have up to four hosts per struct device */ +/* We have up to four hosts per struct device */ struct NCR_Q720_private { struct device *dev; + struct ncr_mem ncr_mem; void __iomem * mem_base; __u32 phys_mem_base; __u32 mem_size; @@ -105,6 +106,7 @@ NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop, device.slot.base_v = vaddr; device.slot.irq = irq; device.differential = differential ? 2 : 0; + device.ncr_mem = &p->ncr_mem; printk("Q720 probe unit %d (siop%d) at 0x%lx, diff = %d, vers = %d\n", unit, siop, (unsigned long)paddr, differential, version); @@ -214,28 +216,21 @@ NCR_Q720_probe(struct device *dev) (unsigned long)(base_addr + mem_size)); goto out_free; } - - if (dma_declare_coherent_memory(dev, base_addr, base_addr, - mem_size, DMA_MEMORY_MAP) - != DMA_MEMORY_MAP) { - printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n"); - goto out_release_region; - } - /* The first 1k of the memory buffer is a memory map of the registers - */ - mem_base = dma_mark_declared_memory_occupied(dev, base_addr, - 1024); - if (IS_ERR(mem_base)) { - printk("NCR_Q720 failed to reserve memory mapped region\n"); - goto out_release; - } + mem_base = ioremap(base_addr, mem_size); + if (!mem_base) + goto out_free; + + p->ncr_mem.virt_base = mem_base; + p->ncr_mem.device_base = base_addr; + ncr_declare_coherent_memory(&p->ncr_mem, mem_size); + + /* The first 1k of the memory buffer are the registers */ + ncr_reserve_declared_memory(&p->ncr_mem, 0, 1024); /* now also enable accesses in asr 2 */ asr2 = inb(io_base + 0x0a); - asr2 |= 0x01; - outb(asr2, io_base + 0x0a); /* get the number of SIOPs (this should be 2 or 4) */ @@ -250,7 +245,6 @@ NCR_Q720_probe(struct device *dev) irq = readb(mem_base + 5) & 0x0f; - /* now do the bus related transforms */ irq = mca_device_transform_irq(mca_dev, irq); @@ -297,10 +291,8 @@ NCR_Q720_probe(struct device *dev) found++; } - if (!found) { - kfree(p); - return -ENODEV; - } + if (!found) + goto out_release; mca_device_set_claim(mca_dev, 1); mca_device_set_name(mca_dev, "NCR_Q720"); @@ -309,8 +301,8 @@ NCR_Q720_probe(struct device *dev) return 0; out_release: - dma_release_declared_memory(dev); - out_release_region: + ncr_release_declared_memory(&p->ncr_mem); + iounmap(mem_base); release_mem_region(base_addr, mem_size); out_free: kfree(p); @@ -335,7 +327,8 @@ NCR_Q720_remove(struct device *dev) if(p->hosts[i]) NCR_Q720_remove_one(p->hosts[i]); - dma_release_declared_memory(dev); + ncr_release_declared_memory(&p->ncr_mem); + iounmap(p->ncr_mem.virt_base); release_mem_region(p->phys_mem_base, p->mem_size); free_irq(p->irq, p); kfree(p); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 016c462..149a42b 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -128,6 +128,14 @@ #define NAME53C8XX "ncr53c8xx" +/* Linux host data structure */ + +struct host_data { + struct ncb *ncb; + struct ncr_mem *ncr_mem; + struct device *dev; +}; + /*========================================================== ** ** Debugging tags @@ -172,6 +180,74 @@ static inline struct list_head *ncr_list_pop(struct list_head *head) return NULL; } +/* + * Support the onboard memory on the NCR Q720 + * + * XXX: This is only coherent because it's only present on x86. + */ + +int ncr_declare_coherent_memory(struct ncr_mem *mem, unsigned size) +{ + int pages = size >> PAGE_SHIFT; + int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); + + mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!mem->bitmap) + return -ENOMEM; + + mem->size = pages; + return 0; +} +EXPORT_SYMBOL(ncr_declare_coherent_memory); + +void ncr_release_declared_memory(struct ncr_mem *mem) +{ + kfree(mem->bitmap); +} +EXPORT_SYMBOL(ncr_release_declared_memory); + +void ncr_reserve_declared_memory(struct ncr_mem *mem, unsigned start, + unsigned len) +{ + int pages = (start & ~PAGE_MASK) + len + PAGE_SIZE - 1; + start >>= PAGE_SHIFT; + bitmap_allocate_region(mem->bitmap, start, get_order(pages)); +} +EXPORT_SYMBOL(ncr_reserve_declared_memory); + +static void *ncr_alloc_coherent(struct host_data *hd, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + struct ncr_mem *mem = hd->ncr_mem; + if (mem) { + unsigned order = get_order(size); + int page = bitmap_find_free_region(mem->bitmap, + mem->size, order); + if (page >= 0) { + void *addr = mem->virt_base + (page << PAGE_SHIFT); + *dma_handle = mem->device_base + (page << PAGE_SHIFT); + memset(addr, 0, size); + return addr; + } + } + + return dma_alloc_coherent(hd->dev, size, dma_handle, gfp); +} + +static void ncr_free_coherent(struct host_data *hd, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + struct ncr_mem *mem = hd->ncr_mem; + if (mem && (vaddr >= mem->virt_base) && + (vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT)))) { + unsigned order = get_order(size); + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + bitmap_release_region(mem->bitmap, page, order); + } else { + dma_free_coherent(hd->dev, size, vaddr, dma_handle); + } +} + /*========================================================== ** ** Simple power of two buddy-like allocator. @@ -204,7 +280,7 @@ static inline struct list_head *ncr_list_pop(struct list_head *head) #define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ -typedef struct device *m_bush_t; /* Something that addresses DMAable */ +typedef struct host_data *m_bush_t; /* Something that addresses DMAable */ typedef struct m_link { /* Link between free memory chunks */ struct m_link *next; @@ -388,7 +464,7 @@ static m_addr_t ___dma_getp(m_pool_s *mp) vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); if (vbp) { dma_addr_t daddr; - vp = (m_addr_t) dma_alloc_coherent(mp->bush, + vp = (m_addr_t) ncr_alloc_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER, &daddr, GFP_ATOMIC); if (vp) { @@ -417,7 +493,7 @@ static void ___dma_freep(m_pool_s *mp, m_addr_t m) if (*vbpp) { vbp = *vbpp; *vbpp = (*vbpp)->next; - dma_free_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER, + ncr_free_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER, (void *)vbp->vaddr, (dma_addr_t)vbp->baddr); __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); --mp->nump; @@ -510,11 +586,11 @@ static m_addr_t __vtobus(m_bush_t bush, void *m) return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; } -#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->dev, s, n) -#define _m_free_dma(np, p, s, n) __m_free_dma(np->dev, p, s, n) +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->hd, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->hd, p, s, n) #define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) #define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) -#define _vtobus(np, p) __vtobus(np->dev, p) +#define _vtobus(np, p) __vtobus(np->hd, p) #define vtobus(p) _vtobus(np, p) /* @@ -525,7 +601,7 @@ static m_addr_t __vtobus(m_bush_t bush, void *m) #define __data_mapped SCp.phase #define __data_mapping SCp.have_data_in -static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd) +static void __unmap_scsi_data(struct scsi_cmnd *cmd) { switch(cmd->__data_mapped) { case 2: @@ -535,7 +611,7 @@ static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd) cmd->__data_mapped = 0; } -static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd) +static int __map_scsi_sg_data(struct scsi_cmnd *cmd) { int use_sg; @@ -549,8 +625,8 @@ static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd) return use_sg; } -#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd) -#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd) +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(cmd) /*========================================================== ** @@ -1679,7 +1755,8 @@ struct ncb { ** General controller parameters and configuration. **---------------------------------------------------------------- */ - struct device *dev; + struct host_data *hd; + u_char revision_id; /* PCI device revision id */ u32 irq; /* IRQ level */ u32 features; /* Chip features map */ @@ -3666,14 +3743,6 @@ ncr_script_copy_and_bind (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len) } } -/* -** Linux host data structure -*/ - -struct host_data { - struct ncb *ncb; -}; - #define PRINT_ADDR(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg) static void ncr_print_msg(struct ccb *cp, char *label, u_char *msg) @@ -8324,12 +8393,14 @@ struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt, if (!instance) goto attach_error; host_data = (struct host_data *) instance->hostdata; + host_data->dev = device->dev; + host_data->ncr_mem = device->ncr_mem; - np = __m_calloc_dma(device->dev, sizeof(struct ncb), "NCB"); + np = __m_calloc_dma(host_data, sizeof(struct ncb), "NCB"); if (!np) goto attach_error; spin_lock_init(&np->smp_lock); - np->dev = device->dev; + np->hd = host_data; np->p_ncb = vtobus(np); host_data->ncb = np; diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index 0e008da..23d2f6c 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -1314,6 +1314,7 @@ struct ncr_slot { */ struct ncr_device { struct device *dev; + struct ncr_mem *ncr_mem; struct ncr_slot slot; struct ncr_chip chip; u_char host_id; @@ -1326,4 +1327,16 @@ irqreturn_t ncr53c8xx_intr(int irq, void *dev_id); extern int ncr53c8xx_init(void); extern void ncr53c8xx_exit(void); +struct ncr_mem { + void *virt_base; + unsigned long *bitmap; + dma_addr_t device_base; + int size; +}; + +extern int ncr_declare_coherent_memory(struct ncr_mem *mem, unsigned size); +extern void ncr_release_declared_memory(struct ncr_mem *mem); +extern void ncr_reserve_declared_memory(struct ncr_mem *mem, unsigned start, + unsigned len); + #endif /* NCR53C8XX_H */ -- 1.5.3.4 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html