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 <[EMAIL PROTECTED]>
---
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-arch" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html