- Add a workaround for the DMA bugs on some alpha chipsets that ATA DMA

trips over often.  Specifically, in these chipsets DMA transfers that
  cross a page boundary result in data corruption.  The workaround is to
  not allow any DMA transfers for non-static DMA maps (i.e. "real"
  transfers as opposed to work areas allocated with bus_dmamem_alloc()) to
  cross a page in a single S/G element.  This behavior is enabled by
  setting 'busdma_pyxis_bug' to 1.
- Add a new tunable 'machdep.busdma_pyxis_bug' that can be used to enable
  the workaround from the loader.  This can be used to enable it on
  chipsets where we don't automatically enable it.
- Auto-enable the workaround for buggy PYXIS 1 chipsets supported via
  cia(4).

PR:		alpha/75317
This commit is contained in:
jhb 2007-12-10 20:14:16 +00:00
parent 368a32e277
commit 04328504a1
3 changed files with 25 additions and 6 deletions

View File

@ -77,7 +77,8 @@ struct bounce_page {
STAILQ_ENTRY(bounce_page) links;
};
int busdma_swi_pending;
int busdma_pyxis_bug, busdma_swi_pending;
TUNABLE_INT("machdep.busdma_pyxis_bug", &busdma_pyxis_bug);
static struct mtx bounce_lock;
static STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
@ -514,6 +515,22 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
vm_offset_t vaddr;
bus_addr_t paddr;
int seg;
bus_size_t boundary;
bus_size_t maxsegsz;
/*
* Enforce a boundary of 8k for buffers that aren't allocated
* via bus_dmamem_alloc() on systems with the Pyxis pass 1 DMA
* bug. This is somewhat gross.
*/
boundary = dmat->boundary;
maxsegsz = dmat->maxsegsz;
if (busdma_pyxis_bug && map != &nobounce_dmamap) {
if (boundary == 0 || boundary > 8192)
boundary = 8192;
if (boundary < maxsegsz)
maxsegsz = boundary;
}
/*
* If we are being called during a callback, pagesneeded will
@ -566,7 +583,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
vaddr = (vm_offset_t)buf;
lastaddr = *lastaddrp;
bmask = ~(dmat->boundary - 1);
bmask = ~(boundary - 1);
for (seg = *segp; buflen > 0 ; ) {
/*
@ -587,8 +604,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
/*
* Make sure we don't cross any boundaries.
*/
if (dmat->boundary > 0) {
baddr = (curaddr + dmat->boundary) & bmask;
if (boundary > 0) {
baddr = (curaddr + boundary) & bmask;
if (sgsize > (baddr - curaddr))
sgsize = (baddr - curaddr);
}
@ -611,8 +628,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
first = 0;
} else {
if (curaddr == lastaddr &&
(segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
(dmat->boundary == 0 ||
(segs[seg].ds_len + sgsize) <= maxsegsz &&
(boundary == 0 ||
(segs[seg].ds_addr & bmask) == (curaddr & bmask)))
segs[seg].ds_len += sgsize;
else {

View File

@ -50,6 +50,7 @@ extern int szfreebsd4_sigcode;
#endif
extern long Maxmem;
extern int busdma_swi_pending;
extern int busdma_pyxis_bug;
extern struct rpb *hwrpb;
extern volatile int mc_expected;
extern volatile int mc_received;

View File

@ -490,6 +490,7 @@ cia_attach(device_t dev)
ctrl &= ~(CTRL_RD_TYPE|CTRL_RL_TYPE|CTRL_RM_TYPE);
REGVAL(CIA_CSR_CTRL) = ctrl;
alpha_mb();
busdma_pyxis_bug = 1;
}
#endif