Skip site navigation (1)Skip section navigation (2)
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>