Date: Wed, 10 Jun 2009 13:13:14 GMT From: Alexander Motin <mav@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 163986 for review Message-ID: <200906101313.n5ADDEvZ063935@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=163986 Change 163986 by mav@mav_mavbook on 2009/06/10 13:13:05 Change controller DMA memory layout. This allows driver to adapt any defined MAXPHYS size. Separate receive FIS area to different busdma tag as it has different alignment requirements and access patterns. Affected files ... .. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#22 edit .. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#10 edit Differences ... ==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#22 (text+ko) ==== @@ -89,8 +89,6 @@ static void ahciaction(struct cam_sim *sim, union ccb *ccb); static void ahcipoll(struct cam_sim *sim); -#define MAXWSPCSZ PAGE_SIZE*11 - /* * AHCI v1.x compliant SATA chipset support functions */ @@ -631,7 +629,7 @@ work = ch->dma.work_bus + AHCI_CL_OFFSET; ATA_OUTL(ch->r_mem, AHCI_P_CLB, work & 0xffffffff); ATA_OUTL(ch->r_mem, AHCI_P_CLBU, work >> 32); - work = ch->dma.work_bus + AHCI_FB_OFFSET; + work = ch->dma.rfis_bus; ATA_OUTL(ch->r_mem, AHCI_P_FB, work & 0xffffffff); ATA_OUTL(ch->r_mem, AHCI_P_FBU, work >> 32); /* Activate the channel and power/spin up device */ @@ -671,38 +669,46 @@ struct ahci_channel *ch = device_get_softc(dev); struct ahci_dc_cb_args dcba; - ch->dma.alignment = 2; - ch->dma.boundary = 65536; - ch->dma.segsize = 65536; - ch->dma.max_iosize = AHCI_DMA_ENTRIES * PAGE_SIZE; if (ch->caps & AHCI_CAP_64BIT) ch->dma.max_address = BUS_SPACE_MAXADDR; else ch->dma.max_address = BUS_SPACE_MAXADDR_32BIT; - - if (bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 64 * 1024, + /* Command area. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), 1024, 0, ch->dma.max_address, BUS_SPACE_MAXADDR, - NULL, NULL, MAXWSPCSZ, 1, MAXWSPCSZ, + NULL, NULL, AHCI_WORK_SIZE, 1, AHCI_WORK_SIZE, 0, NULL, NULL, &ch->dma.work_tag)) goto error; - if (bus_dmamem_alloc(ch->dma.work_tag, (void **)&ch->dma.work, 0, &ch->dma.work_map)) goto error; - if (bus_dmamap_load(ch->dma.work_tag, ch->dma.work_map, ch->dma.work, - MAXWSPCSZ, ahci_dmasetupc_cb, &dcba, 0) || dcba.error) { + AHCI_WORK_SIZE, ahci_dmasetupc_cb, &dcba, 0) || dcba.error) { bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); goto error; } ch->dma.work_bus = dcba.maddr; - - if (bus_dma_tag_create(bus_get_dma_tag(dev), - ch->dma.alignment, ch->dma.boundary, + /* FIS receive area. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, + ch->dma.max_address, BUS_SPACE_MAXADDR, + NULL, NULL, 4096, 1, 4096, + 0, NULL, NULL, &ch->dma.rfis_tag)) + goto error; + if (bus_dmamem_alloc(ch->dma.rfis_tag, (void **)&ch->dma.rfis, 0, + &ch->dma.rfis_map)) + goto error; + if (bus_dmamap_load(ch->dma.rfis_tag, ch->dma.rfis_map, ch->dma.rfis, + 4096, ahci_dmasetupc_cb, &dcba, 0) || dcba.error) { + bus_dmamem_free(ch->dma.rfis_tag, ch->dma.rfis, ch->dma.rfis_map); + goto error; + } + ch->dma.rfis_bus = dcba.maddr; + /* Data area. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), 2, 0, ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, - ch->dma.max_iosize * ch->numslots, - AHCI_DMA_ENTRIES, ch->dma.segsize, + AHCI_SG_ENTRIES * PAGE_SIZE * ch->numslots, + AHCI_SG_ENTRIES, AHCI_PRD_MAX, 0, busdma_lock_mutex, &ch->mtx, &ch->dma.data_tag)) { goto error; } @@ -731,6 +737,13 @@ bus_dma_tag_destroy(ch->dma.data_tag); ch->dma.data_tag = NULL; } + if (ch->dma.rfis_bus) { + bus_dmamap_unload(ch->dma.rfis_tag, ch->dma.rfis_map); + bus_dmamem_free(ch->dma.rfis_tag, ch->dma.rfis, ch->dma.rfis_map); + ch->dma.rfis_bus = 0; + ch->dma.rfis_map = NULL; + ch->dma.rfis = NULL; + } if (ch->dma.work_bus) { bus_dmamap_unload(ch->dma.work_tag, ch->dma.work_map); bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); @@ -748,7 +761,6 @@ ahci_slotsalloc(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); - struct ahci_dc_cb_args dcba; int i; /* Alloc and setup command/dma slots */ @@ -762,22 +774,6 @@ slot->ccb = NULL; callout_init_mtx(&slot->timeout, &ch->mtx, 0); - if (bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, PAGE_SIZE, - ch->dma.max_address, BUS_SPACE_MAXADDR, - NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, - 0, NULL, NULL, &slot->dma.sg_tag)) { - device_printf(ch->dev, "FAILURE - create sg_tag\n"); - } - - if (bus_dmamem_alloc(slot->dma.sg_tag, (void **)&slot->dma.sg, - 0, &slot->dma.sg_map)) - device_printf(ch->dev, "FAILURE - alloc sg_map\n"); - - if (bus_dmamap_load(slot->dma.sg_tag, slot->dma.sg_map, slot->dma.sg, PAGE_SIZE, - ahci_dmasetupc_cb, &dcba, BUS_DMA_NOWAIT) || dcba.error) - device_printf(ch->dev, "FAILURE - load sg\n"); - slot->dma.sg_bus = dcba.maddr; - if (bus_dmamap_create(ch->dma.data_tag, 0, &slot->dma.data_map)) device_printf(ch->dev, "FAILURE - create data_map\n"); } @@ -793,20 +789,6 @@ for (i = 0; i < ch->numslots; i++) { struct ahci_slot *slot = &ch->slot[i]; - if (slot->dma.sg_tag) { - bus_dma_tag_destroy(slot->dma.sg_tag); - slot->dma.sg_tag = NULL; - } - if (slot->dma.sg_bus) { - bus_dmamap_unload(slot->dma.sg_tag, slot->dma.sg_map); - slot->dma.sg_bus = 0; - } - if (slot->dma.sg_map) { - bus_dmamem_free(slot->dma.sg_tag, slot->dma.sg, slot->dma.sg_map); - bus_dmamap_destroy(slot->dma.sg_tag, slot->dma.sg_map); - slot->dma.sg = NULL; - slot->dma.sg_map = NULL; - } if (slot->dma.data_map) { bus_dmamap_destroy(ch->dma.data_tag, slot->dma.data_map); slot->dma.data_map = NULL; @@ -1007,8 +989,6 @@ prd[i].dbc = htole32((segs[i].ds_len - 1) & AHCI_PRD_MASK); } slot->dma.nsegs = nsegs; - bus_dmamap_sync(slot->dma.sg_tag, slot->dma.sg_map, - BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map, ((slot->ccb->ccb_h.flags & CAM_DIR_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE)); @@ -1055,6 +1035,10 @@ clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot)); + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ch->dma.rfis_tag, ch->dma.rfis_map, + BUS_DMASYNC_PREREAD); /* Set ACTIVE bit for NCQ commands. */ if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { @@ -1148,37 +1132,40 @@ device_t dev = slot->dev; struct ahci_channel *ch = device_get_softc(dev); union ccb *ccb = slot->ccb; -// struct ahci_cmd_list *clp; //device_printf(dev, "%s slot %d\n", __func__, slot->slot); /* Cancel command execution timeout */ callout_stop(&slot->timeout); - /* Read result registers to the result struct */ + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_POSTWRITE); + /* Read result registers to the result struct + * May be incorrect if several commands finished same time, + * so read only when sure. + */ if (ccb->ccb_h.func_code == XPT_ATA_IO) { struct ata_res *res = &ccb->ataio.res; - u_int8_t *fis = ch->dma.work + AHCI_FB_OFFSET + 0x40; + + if (et == AHCI_ERR_REAL || + ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) { + u_int8_t *fis = ch->dma.rfis + 0x40; - res->status = fis[2]; - res->error = fis[3]; - res->lba_low = fis[4]; - res->lba_mid = fis[5]; - res->lba_high = fis[6]; - res->device = fis[7]; - res->lba_low_exp = fis[8]; - res->lba_mid_exp = fis[9]; - res->lba_high_exp = fis[10]; - res->sector_count = fis[12]; - res->sector_count_exp = fis[13]; + bus_dmamap_sync(ch->dma.rfis_tag, ch->dma.rfis_map, + BUS_DMASYNC_POSTREAD); + res->status = fis[2]; + res->error = fis[3]; + res->lba_low = fis[4]; + res->lba_mid = fis[5]; + res->lba_high = fis[6]; + res->device = fis[7]; + res->lba_low_exp = fis[8]; + res->lba_mid_exp = fis[9]; + res->lba_high_exp = fis[10]; + res->sector_count = fis[12]; + res->sector_count_exp = fis[13]; + } else + bzero(res, sizeof(*res)); } -#if 0 - /* record how much data we actually moved */ - clp = (struct ahci_cmd_list *) - (ch->dma.work + AHCI_CL_OFFSET + (AHCI_CL_SIZE * slot->slot)); - request->donecount = clp->bytecount; -#endif if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { - bus_dmamap_sync(slot->dma.sg_tag, slot->dma.sg_map, - BUS_DMASYNC_POSTWRITE); bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map, (ccb->ccb_h.flags & CAM_DIR_IN) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); ==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#10 (text+ko) ==== @@ -240,26 +240,36 @@ #define AHCI_P_SNTF 0x3C #define AHCI_P_FBS 0x40 +/* Just to be sure, if building as module. */ +#if MAXPHYS < 512 * 1024 +#undef MAXPHYS +#define MAXPHYS 512 * 1024 +#endif +/* Pessimistic prognosis on number of required S/G entries */ +#define AHCI_SG_ENTRIES (roundup(btoc(MAXPHYS) + 1, 8)) +/* Command list. 32 commands. First, 1Kbyte aligned. */ +#define AHCI_CL_OFFSET 0 #define AHCI_CL_SIZE 32 -#define AHCI_CL_OFFSET 0 -#define AHCI_FB_OFFSET (AHCI_CL_SIZE * 32) -#define AHCI_CT_OFFSET (AHCI_FB_OFFSET + 4096) -#define AHCI_CT_SIZE (1024 + 128) +/* Command tables. Up to 32 commands, Each, 128byte aligned. */ +#define AHCI_CT_OFFSET (AHCI_CL_OFFSET + AHCI_CL_SIZE * AHCI_MAX_SLOTS) +#define AHCI_CT_SIZE (128 + AHCI_SG_ENTRIES * 16) +/* Total main work area. */ +#define AHCI_WORK_SIZE (AHCI_CT_OFFSET + AHCI_CT_SIZE * ch->numslots) struct ahci_dma_prd { u_int64_t dba; u_int32_t reserved; u_int32_t dbc; /* 0 based */ -#define AHCI_PRD_MASK 0x003fffff /* max 4MB */ -#define AHCI_PRD_IPC (1<<31) +#define AHCI_PRD_MASK 0x003fffff /* max 4MB */ +#define AHCI_PRD_MAX (AHCI_PRD_MASK + 1) +#define AHCI_PRD_IPC (1 << 31) } __packed; struct ahci_cmd_tab { u_int8_t cfis[64]; u_int8_t acmd[32]; u_int8_t reserved[32]; -#define AHCI_DMA_ENTRIES 64 - struct ahci_dma_prd prd_tab[AHCI_DMA_ENTRIES]; + struct ahci_dma_prd prd_tab[AHCI_SG_ENTRIES]; } __packed; struct ahci_cmd_list { @@ -276,24 +286,11 @@ u_int64_t cmd_table_phys; /* 128byte aligned */ } __packed; -/* DMA register defines */ -#define ATA_DMA_ENTRIES 256 - /* misc defines */ #define ATA_IRQ_RID 0 #define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY) -/* structure for holding DMA Physical Region Descriptors (PRD) entries */ -struct ata_dma_prdentry { - u_int32_t addr; - u_int32_t count; -}; - struct ata_dmaslot { - bus_dma_tag_t sg_tag; /* SG list DMA tag */ - bus_dmamap_t sg_map; /* SG list DMA map */ - void *sg; /* DMA transfer table */ - bus_addr_t sg_bus; /* bus address of dmatab */ bus_dmamap_t data_map; /* data DMA map */ int nsegs; /* Number of segs loaded */ }; @@ -302,22 +299,16 @@ struct ata_dma { bus_dma_tag_t work_tag; /* workspace DMA tag */ bus_dmamap_t work_map; /* workspace DMA map */ - u_int8_t *work; /* workspace */ - bus_addr_t work_bus; /* bus address of dmatab */ - + uint8_t *work; /* workspace */ + bus_addr_t work_bus; /* bus address of work */ + bus_dma_tag_t rfis_tag; /* RFIS list DMA tag */ + bus_dmamap_t rfis_map; /* RFIS list DMA map */ + uint8_t *rfis; /* FIS receive area */ + bus_addr_t rfis_bus; /* bus address of rfis */ bus_dma_tag_t data_tag; /* data DMA tag */ - - u_int32_t alignment; /* DMA SG list alignment */ - u_int32_t boundary; /* DMA SG list boundary */ - u_int32_t segsize; /* DMA SG list segment size */ - u_int32_t max_iosize; /* DMA data max IO size */ u_int64_t max_address; /* highest DMA'able address */ }; -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x01 -#define ATA_PM 0x0f - enum ahci_slot_states { AHCI_SLOT_EMPTY, AHCI_SLOT_LOADING, @@ -334,7 +325,6 @@ struct callout timeout; /* Execution timeout */ }; - /* structure describing an ATA channel */ struct ahci_channel { device_t dev; /* Device handle */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906101313.n5ADDEvZ063935>