Enable cesa driver to work with Linux DT binding

Linux device tree binding, whose usage is obligatory,
comprises faulty representation of Marvell cryptographic
engine (CESA) - two engines are artificially gathered into
single DT node, in order to avoid certain SW limitation.

This patch improves the cesa driver to support above binding,
depending on compatible string, which helps to ensure
backward compatibility.

Submitted by: Patryk Duda
Obtained from: Semihalf
Sponsored by: Stormshield
Differential Revision: https://reviews.freebsd.org/D14760
This commit is contained in:
mw 2018-04-09 23:36:52 +00:00
parent 9ceceb90cf
commit 9235965263
4 changed files with 222 additions and 2 deletions

View File

@ -108,6 +108,7 @@ static int decode_win_xor_valid(void);
static void decode_win_cpu_setup(void);
static int decode_win_sdram_fixup(void);
static void decode_win_cesa_setup(u_long);
static void decode_win_a38x_cesa_setup(u_long);
static void decode_win_usb_setup(u_long);
static void decode_win_usb3_setup(u_long);
static void decode_win_eth_setup(u_long);
@ -120,6 +121,7 @@ static void decode_win_idma_setup(u_long);
static void decode_win_xor_setup(u_long);
static void decode_win_cesa_dump(u_long);
static void decode_win_a38x_cesa_dump(u_long);
static void decode_win_usb_dump(u_long);
static void decode_win_usb3_dump(u_long);
static void decode_win_eth_dump(u_long base);
@ -226,6 +228,8 @@ static struct soc_node_spec soc_nodes[] = {
{ "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump, &decode_win_idma_valid},
{ "mrvl,cesa", &decode_win_cesa_setup, &decode_win_cesa_dump, &decode_win_cesa_valid},
{ "mrvl,pcie", &decode_win_pcie_setup, &decode_win_pcie_dump, &decode_win_pcie_valid},
{ "marvell,armada-38x-crypto", &decode_win_a38x_cesa_setup,
&decode_win_a38x_cesa_dump, &decode_win_cesa_valid},
{ NULL, NULL, NULL, NULL },
};
@ -1560,6 +1564,20 @@ decode_win_cesa_setup(u_long base)
}
}
static void
decode_win_a38x_cesa_setup(u_long base)
{
decode_win_cesa_setup(base);
decode_win_cesa_setup(base + MV_WIN_CESA_OFFSET);
}
static void
decode_win_a38x_cesa_dump(u_long base)
{
decode_win_cesa_dump(base);
decode_win_cesa_dump(base + MV_WIN_CESA_OFFSET);
}
/**************************************************************************
* USB windows routines
**************************************************************************/

View File

@ -202,6 +202,8 @@
#define MV_WIN_NETA_OFFSET 0x2000
#define MV_WIN_NETA_BASE(n) MV_WIN_ETH_BASE(n) + MV_WIN_NETA_OFFSET
#define MV_WIN_CESA_OFFSET 0x2000
#define MV_WIN_ETH_BASE(n) (0x8 * (n) + 0x200)
#define MV_WIN_ETH_SIZE(n) (0x8 * (n) + 0x204)
#define MV_WIN_ETH_REMAP(n) (0x4 * (n) + 0x280)

View File

@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <machine/resource.h>
#include <machine/fdt.h>
#include <dev/fdt/simplebus.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@ -76,6 +77,7 @@ __FBSDID("$FreeBSD$");
static int cesa_probe(device_t);
static int cesa_attach(device_t);
static int cesa_attach_late(device_t);
static int cesa_detach(device_t);
static void cesa_intr(void *);
static int cesa_newsession(device_t, u_int32_t *, struct cryptoini *);
@ -1003,6 +1005,122 @@ cesa_setup_sram(struct cesa_softc *sc)
return (0);
}
/*
* Function: device_from_node
* This function returns appropriate device_t to phandle_t
* Parameters:
* root - device where you want to start search
* if you provide NULL here, function will take
* "root0" device as root.
* node - we are checking every device_t to be
* appropriate with this.
*/
static device_t
device_from_node(device_t root, phandle_t node)
{
device_t *children, retval;
int nkid, i;
/* Nothing matches no node */
if (node == -1)
return (NULL);
if (root == NULL)
/* Get root of device tree */
if ((root = device_lookup_by_name("root0")) == NULL)
return (NULL);
if (device_get_children(root, &children, &nkid) != 0)
return (NULL);
retval = NULL;
for (i = 0; i < nkid; i++) {
/* Check if device and node matches */
if (OFW_BUS_GET_NODE(root, children[i]) == node) {
retval = children[i];
break;
}
/* or go deeper */
if ((retval = device_from_node(children[i], node)) != NULL)
break;
}
free(children, M_TEMP);
return (retval);
}
static int
cesa_setup_sram_armada(struct cesa_softc *sc)
{
phandle_t sram_node;
ihandle_t sram_ihandle;
pcell_t sram_handle[2];
void *sram_va;
int rv, j;
struct resource_list rl;
struct resource_list_entry *rle;
struct simplebus_softc *ssc;
device_t sdev;
/* Get refs to SRAMS from CESA node */
rv = OF_getencprop(ofw_bus_get_node(sc->sc_dev), "marvell,crypto-srams",
(void *)sram_handle, sizeof(sram_handle));
if (rv <= 0)
return (rv);
if (sc->sc_cesa_engine_id >= 2)
return (ENXIO);
/* Get SRAM node on the basis of sc_cesa_engine_id */
sram_ihandle = (ihandle_t)sram_handle[sc->sc_cesa_engine_id];
sram_node = OF_instance_to_package(sram_ihandle);
/* Get device_t of simplebus (sram_node parent) */
sdev = device_from_node(NULL, OF_parent(sram_node));
if (!sdev)
return (ENXIO);
ssc = device_get_softc(sdev);
resource_list_init(&rl);
/* Parse reg property to resource list */
ofw_bus_reg_to_rl(sdev, sram_node, ssc->acells,
ssc->scells, &rl);
/* We expect only one resource */
rle = resource_list_find(&rl, SYS_RES_MEMORY, 0);
if (rle == NULL)
return (ENXIO);
/* Remap through ranges property */
for (j = 0; j < ssc->nranges; j++) {
if (rle->start >= ssc->ranges[j].bus &&
rle->end < ssc->ranges[j].bus + ssc->ranges[j].size) {
rle->start -= ssc->ranges[j].bus;
rle->start += ssc->ranges[j].host;
rle->end -= ssc->ranges[j].bus;
rle->end += ssc->ranges[j].host;
}
}
sc->sc_sram_base_pa = rle->start;
sc->sc_sram_size = rle->count;
/* SRAM memory was not mapped in platform_sram_devmap(), map it now */
sram_va = pmap_mapdev(sc->sc_sram_base_pa, sc->sc_sram_size);
if (sram_va == NULL)
return (ENOMEM);
sc->sc_sram_base_va = (vm_offset_t)sram_va;
return (0);
}
struct ofw_compat_data cesa_devices[] = {
{ "mrvl,cesa", (uintptr_t)true },
{ "marvell,armada-38x-crypto", (uintptr_t)true },
{ NULL, 0 }
};
static int
cesa_probe(device_t dev)
{
@ -1010,7 +1128,7 @@ cesa_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "mrvl,cesa"))
if (!ofw_bus_search_compatible(dev, cesa_devices)->ocd_data)
return (ENXIO);
device_set_desc(dev, "Marvell Cryptographic Engine and Security "
@ -1021,6 +1139,77 @@ cesa_probe(device_t dev)
static int
cesa_attach(device_t dev)
{
static int engine_idx = 0;
struct simplebus_devinfo *ndi;
struct resource_list *rl;
struct cesa_softc *sc;
if (!ofw_bus_is_compatible(dev, "marvell,armada-38x-crypto"))
return (cesa_attach_late(dev));
/*
* Get simplebus_devinfo which contains
* resource list filled with adresses and
* interrupts read form FDT.
* Let's correct it by splitting resources
* for each engine.
*/
if ((ndi = device_get_ivars(dev)) == NULL)
return (ENXIO);
rl = &ndi->rl;
switch (engine_idx) {
case 0:
/* Update regs values */
resource_list_add(rl, SYS_RES_MEMORY, 0, CESA0_TDMA_ADDR,
CESA0_TDMA_ADDR + CESA_TDMA_SIZE - 1, CESA_TDMA_SIZE);
resource_list_add(rl, SYS_RES_MEMORY, 1, CESA0_CESA_ADDR,
CESA0_CESA_ADDR + CESA_CESA_SIZE - 1, CESA_CESA_SIZE);
/* Remove unused interrupt */
resource_list_delete(rl, SYS_RES_IRQ, 1);
break;
case 1:
/* Update regs values */
resource_list_add(rl, SYS_RES_MEMORY, 0, CESA1_TDMA_ADDR,
CESA1_TDMA_ADDR + CESA_TDMA_SIZE - 1, CESA_TDMA_SIZE);
resource_list_add(rl, SYS_RES_MEMORY, 1, CESA1_CESA_ADDR,
CESA1_CESA_ADDR + CESA_CESA_SIZE - 1, CESA_CESA_SIZE);
/* Remove unused interrupt */
resource_list_delete(rl, SYS_RES_IRQ, 0);
resource_list_find(rl, SYS_RES_IRQ, 1)->rid = 0;
break;
default:
device_printf(dev, "Bad cesa engine_idx\n");
return (ENXIO);
}
sc = device_get_softc(dev);
sc->sc_cesa_engine_id = engine_idx;
/*
* Call simplebus_add_device only once.
* It will create second cesa driver instance
* with the same FDT node as first instance.
* When second driver reach this function,
* it will be configured to use second cesa engine
*/
if (engine_idx == 0)
simplebus_add_device(device_get_parent(dev), ofw_bus_get_node(dev),
0, "cesa", 1, NULL);
engine_idx++;
return (cesa_attach_late(dev));
}
static int
cesa_attach_late(device_t dev)
{
struct cesa_softc *sc;
uint32_t d, r, val;
@ -1086,7 +1275,11 @@ cesa_attach(device_t dev)
}
/* Acquire SRAM base address */
error = cesa_setup_sram(sc);
if (!ofw_bus_is_compatible(dev, "marvell,armada-38x-crypto"))
error = cesa_setup_sram(sc);
else
error = cesa_setup_sram_armada(sc);
if (error) {
device_printf(dev, "could not setup SRAM\n");
goto err1;

View File

@ -239,6 +239,7 @@ struct cesa_softc {
bus_dma_tag_t sc_data_dtag;
int sc_error;
int sc_tperr;
uint8_t sc_cesa_engine_id;
struct mtx sc_sc_lock;
int sc_blocked;
@ -367,4 +368,10 @@ struct cesa_chain_info {
#define CESA_SA_SR 0x0E0C
#define CESA_SA_SR_ACTIVE (1 << 0)
#define CESA_TDMA_SIZE 0x1000
#define CESA_CESA_SIZE 0x1000
#define CESA0_TDMA_ADDR 0x90000
#define CESA0_CESA_ADDR 0x9D000
#define CESA1_TDMA_ADDR 0x92000
#define CESA1_CESA_ADDR 0x9F000
#endif