Added PCI DMA functions
DMA transfers can only happen within a dedicated DMA window, so we need special functions for allocating buffers and for mapping these buffers in and out again. Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
This commit is contained in:
parent
904abb4a8f
commit
4f0a051873
|
@ -81,6 +81,7 @@ OF_FFS_FILES = \
|
|||
$(SLOFCMNDIR)/fs/xmodem.fs \
|
||||
$(SLOFBRDDIR)/default-font.bin \
|
||||
$(SLOFBRDDIR)/pci-phb.fs \
|
||||
$(SLOFBRDDIR)/pci-device-dma.fs \
|
||||
$(SLOFBRDDIR)/rtas.fs \
|
||||
$(FCODE_FFS_FILES)
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
\ *****************************************************************************
|
||||
\ * Copyright (c) 2011 IBM Corporation
|
||||
\ * All rights reserved.
|
||||
\ * This program and the accompanying materials
|
||||
\ * are made available under the terms of the BSD License
|
||||
\ * which accompanies this distribution, and is available at
|
||||
\ * http://www.opensource.org/licenses/bsd-license.php
|
||||
\ *
|
||||
\ * Contributors:
|
||||
\ * IBM Corporation - initial implementation
|
||||
\ ****************************************************************************/
|
||||
\ * Open Firmware 1275 DMA transfer mapping functions
|
||||
\ *****************************************************************************
|
||||
|
||||
0 VALUE dma-debug?
|
||||
|
||||
0 VALUE dma-window-liobn \ Logical I/O bus number
|
||||
0 VALUE dma-window-base \ Start address of window
|
||||
0 VALUE dma-window-size \ Size of the window
|
||||
|
||||
|
||||
\ Read DMA window base and size from ibm,dma-window property
|
||||
: update-dma-window-vars ( -- )
|
||||
s" ibm,dma-window" get-node get-property 0= IF
|
||||
decode-int TO dma-window-liobn
|
||||
decode-64 TO dma-window-base
|
||||
decode-64 TO dma-window-size
|
||||
2drop
|
||||
THEN
|
||||
;
|
||||
update-dma-window-vars
|
||||
|
||||
|
||||
: dma-alloc ( size -- virt )
|
||||
dma-debug? IF cr ." dma-alloc called: " .s cr THEN
|
||||
fff + fff not and \ Align size to next 4k boundary
|
||||
alloc-mem
|
||||
\ alloc-mem always returns aligned memory - double check just to be sure
|
||||
dup fff and IF
|
||||
." Warning: dma-alloc got unaligned memory!" cr
|
||||
THEN
|
||||
;
|
||||
|
||||
: dma-free ( virt size -- )
|
||||
dma-debug? IF cr ." dma-free called: " .s cr THEN
|
||||
fff + fff not and \ Align size to next 4k boundary
|
||||
free-mem
|
||||
;
|
||||
|
||||
|
||||
\ We assume that firmware never maps more than the whole dma-window-size
|
||||
\ so we cheat by calculating the remainder of addr/windowsize instead
|
||||
\ of taking care to maintain a list of assigned device addresses
|
||||
: dma-virt2dev ( virt -- devaddr )
|
||||
dma-window-size mod dma-window-base +
|
||||
;
|
||||
|
||||
: dma-map-in ( virt size cachable? -- devaddr )
|
||||
dma-debug? IF cr ." dma-map-in called: " .s cr THEN
|
||||
drop ( virt size )
|
||||
bounds dup >r ( v+s virt R: virt )
|
||||
swap fff + fff not and \ Align end to next 4k boundary
|
||||
swap fff not and ( v+s' virt' R: virt )
|
||||
?DO
|
||||
\ ." mapping " i . cr
|
||||
dma-window-liobn \ liobn
|
||||
i dma-virt2dev \ ioba
|
||||
i 3 OR \ Make a read- & writeable TCE
|
||||
( liobn ioba tce R: virt )
|
||||
hv-put-tce ABORT" H_PUT_TCE failed"
|
||||
1000 +LOOP
|
||||
r> dma-virt2dev
|
||||
;
|
||||
|
||||
: dma-map-out ( virt devaddr size -- )
|
||||
dma-debug? IF cr ." dma-map-out called: " .s cr THEN
|
||||
nip ( virt size )
|
||||
bounds ( v+s virt )
|
||||
swap fff + fff not and \ Align end to next 4k boundary
|
||||
swap fff not and ( v+s' virt' )
|
||||
?DO
|
||||
\ ." unmapping " i . cr
|
||||
dma-window-liobn \ liobn
|
||||
i dma-virt2dev \ ioba
|
||||
i \ Lowest bits not set => invalid TCE
|
||||
( liobn ioba tce )
|
||||
hv-put-tce ABORT" H_PUT_TCE failed"
|
||||
1000 +LOOP
|
||||
;
|
||||
|
||||
: dma-sync ( virt devaddr size -- )
|
||||
dma-debug? IF cr ." dma-sync called: " .s cr THEN
|
||||
\ TODO: Call flush-cache or sync here?
|
||||
3drop
|
||||
;
|
|
@ -75,6 +75,7 @@ setup-puid
|
|||
dup to my-self
|
||||
dup ihandle>phandle node>instance-size @ \ Remember instance size
|
||||
\ Include the PCI device functions:
|
||||
s" pci-device-dma.fs" included
|
||||
s" pci-device.fs" included
|
||||
\ Clean up the temporary instance. Note that we can not use close-node
|
||||
\ or destroy-instance here since node>instance-size might have changed.
|
||||
|
|
|
@ -102,6 +102,9 @@ typedef int (*k_ioctl_t) (int, int, void *);
|
|||
typedef void (*modules_remove_t) (int);
|
||||
typedef snk_module_t *(*modules_load_t) (int);
|
||||
|
||||
typedef long (*dma_map_in_t)(void *address, long size, int cachable);
|
||||
typedef void (*dma_map_out_t)(void *address, long devaddr, long size);
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
print_t print;
|
||||
|
@ -129,6 +132,8 @@ typedef struct {
|
|||
k_ioctl_t k_ioctl;
|
||||
modules_remove_t modules_remove;
|
||||
modules_load_t modules_load;
|
||||
dma_map_in_t dma_map_in;
|
||||
dma_map_out_t dma_map_out;
|
||||
} snk_kernel_t;
|
||||
|
||||
/* Entry of module */
|
||||
|
|
|
@ -220,6 +220,12 @@ of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3)
|
|||
return arg.args[4];
|
||||
}
|
||||
|
||||
int
|
||||
of_test(const char *name)
|
||||
{
|
||||
return (int) of_1_1("test", p32cast name);
|
||||
}
|
||||
|
||||
int
|
||||
of_interpret_1(void *s, void *ret)
|
||||
{
|
||||
|
@ -373,6 +379,7 @@ bootmsg_error(short id, const char *str)
|
|||
(void) of_2_0("bootmsg-error", id, p32cast str);
|
||||
}
|
||||
|
||||
/*
|
||||
void
|
||||
bootmsg_debugcp(short id, const char *str, short lvl)
|
||||
{
|
||||
|
@ -384,7 +391,7 @@ bootmsg_cp(short id)
|
|||
{
|
||||
(void) of_1_0("bootmsg-cp", id);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
static long
|
||||
of_fileio_read(snk_fileio_t *fileio, char *buf, long len)
|
||||
|
@ -413,6 +420,34 @@ of_fileio_close(snk_fileio_t *fileio)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
dma_map_in(void *address, long size, int cachable)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
/* Is dma-map-in available? */
|
||||
if (of_test("dma-map-in") != 0) {
|
||||
/* No dma-map-in available ==> Assume we can use 1:1 addresses */
|
||||
return (long)address;
|
||||
}
|
||||
|
||||
ret = of_3_1("dma-map-in", p32cast address, (int)size, cachable);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
dma_map_out(void *address, long devaddr, long size)
|
||||
{
|
||||
/* Is dma-map-out available? */
|
||||
if (of_test("dma-map-out") != 0) {
|
||||
/* No dma-map-out available */
|
||||
return;
|
||||
}
|
||||
|
||||
of_3_0("dma-map-out", p32cast address, (int)devaddr, (int)size);
|
||||
}
|
||||
|
||||
|
||||
#define CONFIG_SPACE 0
|
||||
#define IO_SPACE 1
|
||||
|
@ -791,6 +826,7 @@ get_timebase(unsigned int *timebase)
|
|||
of_getprop(cpu, "timebase-frequency", timebase, 4);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
glue_init(snk_kernel_t * snk_kernel_interface, unsigned int * timebase,
|
||||
size_t _client_start, size_t _client_size)
|
||||
|
@ -834,6 +870,9 @@ glue_init(snk_kernel_t * snk_kernel_interface, unsigned int * timebase,
|
|||
snk_kernel_interface->translate_addr = translate_address;
|
||||
snk_kernel_interface->pci_config_read = rtas_pci_config_read;
|
||||
snk_kernel_interface->pci_config_write = rtas_pci_config_write;
|
||||
snk_kernel_interface->dma_map_in = dma_map_in;
|
||||
snk_kernel_interface->dma_map_out = dma_map_out;
|
||||
|
||||
claim_rc=(int)(long)of_claim(client_start, client_size, 0);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue