aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/isp/isp_sbus.c
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2017-03-14 08:03:56 +0000
committerAlexander Motin <mav@FreeBSD.org>2017-03-14 08:03:56 +0000
commita1fa02673afaed21473adc4633faac57b554acc0 (patch)
tree17548ba20920729ca4bef84e31cb17e11b357cb7 /sys/dev/isp/isp_sbus.c
parent3667f39ea3bcb716a7e6dc3ebd973e4cac6980f0 (diff)
downloadsrc-a1fa02673afaed21473adc4633faac57b554acc0.tar.gz
src-a1fa02673afaed21473adc4633faac57b554acc0.zip
Improvements around attach, reset and detach.
This change fixes DMA resource leak on driver unload. Also it removes DMA resources allocation for hardcoded number of requests before fetching the real number from firmware. Also it prepares ground for more flexible IRQs allocation according to firmware capabilities. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=315234
Diffstat (limited to 'sys/dev/isp/isp_sbus.c')
-rw-r--r--sys/dev/isp/isp_sbus.c154
1 files changed, 72 insertions, 82 deletions
diff --git a/sys/dev/isp/isp_sbus.c b/sys/dev/isp/isp_sbus.c
index b3963b9905e5..65c5ee52da1f 100644
--- a/sys/dev/isp/isp_sbus.c
+++ b/sys/dev/isp/isp_sbus.c
@@ -55,11 +55,8 @@ static uint32_t isp_sbus_rd_reg(ispsoftc_t *, int);
static void isp_sbus_wr_reg(ispsoftc_t *, int, uint32_t);
static int isp_sbus_rd_isr(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *);
static int isp_sbus_mbxdma(ispsoftc_t *);
+static void isp_sbus_mbxdmafree(ispsoftc_t *);
static int isp_sbus_dmasetup(ispsoftc_t *, XS_T *, void *);
-
-
-static void isp_sbus_reset0(ispsoftc_t *);
-static void isp_sbus_reset1(ispsoftc_t *);
static void isp_sbus_dumpregs(ispsoftc_t *, const char *);
static struct ispmdvec mdvec = {
@@ -69,8 +66,7 @@ static struct ispmdvec mdvec = {
isp_sbus_mbxdma,
isp_sbus_dmasetup,
isp_common_dmateardown,
- isp_sbus_reset0,
- isp_sbus_reset1,
+ NULL,
isp_sbus_dumpregs,
NULL,
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
@@ -140,20 +136,15 @@ isp_sbus_probe(device_t dev)
static int
isp_sbus_attach(device_t dev)
{
+ struct isp_sbussoftc *sbs = device_get_softc(dev);
+ ispsoftc_t *isp = &sbs->sbus_isp;
int tval, isp_debug, role, ispburst, default_id;
- struct isp_sbussoftc *sbs;
- ispsoftc_t *isp = NULL;
- int locksetup = 0;
int ints_setup = 0;
- sbs = device_get_softc(dev);
- if (sbs == NULL) {
- device_printf(dev, "cannot get softc\n");
- return (ENOMEM);
- }
-
sbs->sbus_dev = dev;
sbs->sbus_mdvec = mdvec;
+ isp->isp_dev = dev;
+ mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
role = 0;
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
@@ -179,7 +170,6 @@ isp_sbus_attach(device_t dev)
sbs->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF;
sbs->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF;
sbs->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
- isp = &sbs->sbus_isp;
isp->isp_regs = sbs->regs;
isp->isp_mdvec = &sbs->sbus_mdvec;
isp->isp_bustype = ISP_BT_SBUS;
@@ -187,7 +177,6 @@ isp_sbus_attach(device_t dev)
isp->isp_param = &sbs->sbus_param;
isp->isp_osinfo.pc.ptr = &sbs->sbus_spi;
isp->isp_revision = 0; /* XXX */
- isp->isp_dev = dev;
isp->isp_nchan = 1;
if (IS_FC(isp))
ISP_FC_PC(isp, 0)->def_role = role;
@@ -266,10 +255,6 @@ isp_sbus_attach(device_t dev)
(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
"debug", &isp_debug);
- /* Make sure the lock is set up. */
- mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
- locksetup++;
-
sbs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sbs->iqd,
RF_ACTIVE | RF_SHAREABLE);
if (sbs->irq == NULL) {
@@ -301,14 +286,13 @@ isp_sbus_attach(device_t dev)
*/
ISP_LOCK(isp);
if (isp_reinit(isp, 1) != 0) {
- isp_uninit(isp);
ISP_UNLOCK(isp);
goto bad;
}
ISP_UNLOCK(isp);
if (isp_attach(isp)) {
ISP_LOCK(isp);
- isp_uninit(isp);
+ isp_shutdown(isp);
ISP_UNLOCK(isp);
goto bad;
}
@@ -324,41 +308,33 @@ bad:
bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq);
}
- if (locksetup && isp) {
- mtx_destroy(&isp->isp_osinfo.lock);
- }
-
if (sbs->regs) {
(void) bus_release_resource(dev, SYS_RES_MEMORY, sbs->rgd,
sbs->regs);
}
+ mtx_destroy(&isp->isp_osinfo.lock);
return (ENXIO);
}
static int
isp_sbus_detach(device_t dev)
{
- struct isp_sbussoftc *sbs;
- ispsoftc_t *isp;
+ struct isp_sbussoftc *sbs = device_get_softc(dev);
+ ispsoftc_t *isp = &sbs->sbus_isp;
int status;
- sbs = device_get_softc(dev);
- if (sbs == NULL) {
- return (ENXIO);
- }
- isp = (ispsoftc_t *) sbs;
status = isp_detach(isp);
if (status)
return (status);
ISP_LOCK(isp);
- isp_uninit(isp);
- if (sbs->ih) {
- (void) bus_teardown_intr(dev, sbs->irq, sbs->ih);
- }
+ isp_shutdown(isp);
ISP_UNLOCK(isp);
- mtx_destroy(&isp->isp_osinfo.lock);
+ if (sbs->ih)
+ (void) bus_teardown_intr(dev, sbs->irq, sbs->ih);
(void) bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq);
(void) bus_release_resource(dev, SYS_RES_MEMORY, sbs->rgd, sbs->regs);
+ isp_sbus_mbxdmafree(isp);
+ mtx_destroy(&isp->isp_osinfo.lock);
return (0);
}
@@ -436,25 +412,14 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
int i, error;
struct imush im;
- /*
- * Already been here? If so, leave...
- */
- if (isp->isp_rquest) {
+ /* Already been here? If so, leave... */
+ if (isp->isp_xflist != NULL)
+ return (0);
+ if (isp->isp_rquest != NULL && isp->isp_maxcmds == 0)
return (0);
- }
-
ISP_UNLOCK(isp);
-
- len = sizeof (struct isp_pcmd) * isp->isp_maxcmds;
- isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *)
- malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
- len = sizeof (isp_hdl_t *) * isp->isp_maxcmds;
- isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
- for (len = 0; len < isp->isp_maxcmds - 1; len++) {
- isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
- }
- isp->isp_xffree = isp->isp_xflist;
- len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
+ if (isp->isp_rquest != NULL)
+ goto gotmaxcmds;
if (isp_dma_tag_create(BUS_DMA_ROOTARG(ISP_SBD(isp)), 1,
BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT,
@@ -480,6 +445,7 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
goto bad;
}
+ isp->isp_rquest = base;
im.error = 0;
if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap,
base, len, imc, &im, 0) || im.error) {
@@ -488,7 +454,6 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
}
isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx",
(uintmax_t)im.maddr, (uintmax_t)len);
- isp->isp_rquest = base;
isp->isp_rquest_dma = im.maddr;
/*
@@ -507,6 +472,7 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
goto bad;
}
+ isp->isp_result = base;
im.error = 0;
if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap,
base, len, imc, &im, 0) || im.error) {
@@ -515,9 +481,17 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
}
isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx",
(uintmax_t)im.maddr, (uintmax_t)len);
- isp->isp_result = base;
isp->isp_result_dma = im.maddr;
+ if (isp->isp_maxcmds == 0) {
+ ISP_LOCK(isp);
+ return (0);
+ }
+
+gotmaxcmds:
+ len = sizeof (struct isp_pcmd) * isp->isp_maxcmds;
+ isp->isp_osinfo.pcmd_pool = (struct isp_pcmd *)
+ malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
for (i = 0; i < isp->isp_maxcmds; i++) {
struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i];
error = bus_dmamap_create(isp->isp_osinfo.dmat, 0, &pcmd->dmap);
@@ -538,33 +512,61 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
}
}
isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0];
+
+ len = sizeof (isp_hdl_t *) * isp->isp_maxcmds;
+ isp->isp_xflist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
+ for (len = 0; len < isp->isp_maxcmds - 1; len++)
+ isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
+ isp->isp_xffree = isp->isp_xflist;
+
ISP_LOCK(isp);
return (0);
bad:
- if (isp->isp_rquest_dma != 0) {
- bus_dmamap_unload(isp->isp_osinfo.reqdmat,
- isp->isp_osinfo.reqmap);
+ isp_sbus_mbxdmafree(isp);
+ ISP_LOCK(isp);
+ return (1);
+}
+
+static void
+isp_sbus_mbxdmafree(ispsoftc_t *isp)
+{
+ int i;
+
+ if (isp->isp_xflist != NULL) {
+ free(isp->isp_xflist, M_DEVBUF);
+ isp->isp_xflist = NULL;
}
- if (isp->isp_rquest != NULL) {
- bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest,
- isp->isp_osinfo.reqmap);
- bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ if (isp->isp_osinfo.pcmd_pool != NULL) {
+ for (i = 0; i < isp->isp_maxcmds; i++) {
+ bus_dmamap_destroy(isp->isp_osinfo.dmat,
+ isp->isp_osinfo.pcmd_pool[i].dmap);
+ }
+ free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
+ isp->isp_osinfo.pcmd_pool = NULL;
}
if (isp->isp_result_dma != 0) {
bus_dmamap_unload(isp->isp_osinfo.respdmat,
isp->isp_osinfo.respmap);
+ isp->isp_result_dma = 0;
}
if (isp->isp_result != NULL) {
bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result,
isp->isp_osinfo.respmap);
bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
+ isp->isp_result = NULL;
+ }
+ if (isp->isp_rquest_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.reqdmat,
+ isp->isp_osinfo.reqmap);
+ isp->isp_rquest_dma = 0;
+ }
+ if (isp->isp_rquest != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest,
+ isp->isp_osinfo.reqmap);
+ bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ isp->isp_rquest = NULL;
}
- free(isp->isp_xflist, M_DEVBUF);
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- isp->isp_rquest = NULL;
- ISP_LOCK(isp);
- return (1);
}
typedef struct {
@@ -663,18 +665,6 @@ isp_sbus_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, void *ff)
}
static void
-isp_sbus_reset0(ispsoftc_t *isp)
-{
- ISP_DISABLE_INTS(isp);
-}
-
-static void
-isp_sbus_reset1(ispsoftc_t *isp)
-{
- ISP_ENABLE_INTS(isp);
-}
-
-static void
isp_sbus_dumpregs(ispsoftc_t *isp, const char *msg)
{
if (msg)