Skip to contentSkip to conversation

PCI root complex changes for tile architecture

PATCH In review Chris Metcalf 3 participants 27 messages Aug 5, 2013 – Aug 12, 2013 1 message not in the archive PCI

lore
Share & tools
lore
#0 lore raw

cover PCI root complex changes for tile architecture

These changes add new features and fix bugs in the Tilera PCI root complex subsystem. Among the new tilegx features are support for I/O space access, more MXI-X interrupt vectors, and support for TRIO 0 MAC 0 on Gx72 systems.

Chris Metcalf (20):
tile PCI RC: cleanups for tilepro PCI RC
tile PCI RC: tilepro conflict with PCI and RAM addresses tile PCI RC: support pci=off boot arg for tilepro tile PCI RC: tweak the the pcie_rc_delay support tile PCI RC: handle case that PCI link is already up
tile: support LSI MEGARAID SAS HBA hybrid dma_ops tile PCI RC: support more MSI-X interrupt vectors tile PCI RC: gentler warning for missing plug-in PCI tile PCI RC: support I/O space access
tile PCI DMA: handle a NULL dev argument properly tile PCI RC: restructure TRIO initialization tile PCI RC: eliminate pci_controller.mem_resources field tile PCI RC: include pci/pcie/Kconfig
tile PCI RC: bomb comments and whitespace format tile PCI RC: use proper accessor function
tile PCI RC: add dma_get_required_mask()
tile PCI DMA: fix bug in non-page-aligned accessors tile PCI RC: support PCIe TRIO 0 MAC 0 on Gx72 system tile PCI RC: reduce driver's vmalloc space usage tile PCI RC: remove stale include of linux/numa.h

 arch/tile/Kconfig                    |  12 +
 arch/tile/gxio/iorpc_trio.c          |  23 ++
 arch/tile/include/arch/trio.h        |  39 ++
 arch/tile/include/asm/dma-mapping.h  |   8 +-
 arch/tile/include/asm/io.h           | 126 ++++++-
 arch/tile/include/asm/pci.h          |  17 +-
 arch/tile/include/gxio/iorpc_trio.h  |   5 +
 arch/tile/include/hv/drv_trio_intf.h |   8 +-
 arch/tile/kernel/pci-dma.c           |  44 ++-
 arch/tile/kernel/pci.c               |  33 +-
 arch/tile/kernel/pci_gx.c            | 710 ++++++++++++++++++++---------------
 arch/tile/kernel/setup.c             |   9 +-
 12 files changed, 678 insertions(+), 356 deletions(-)
Signature · 1 line
1.8.3.1
#1 lore raw

PATCH 1/20 tile PCI RC: cleanups for tilepro PCI RC

- remove unneeded <linux/bootmem.h> include in pci.c
- eliminate unused pci_controller.first_busno field
- prefer msleep to mdelay
- remove stale comment about pci_scan_bus_parented()

---
 arch/tile/include/asm/pci.h |  1 -
 arch/tile/kernel/pci.c      | 16 +++-------------
 2 files changed, 3 insertions(+), 14 deletions(-)
arch/tile/include/asm/pci.h +0 -1
index 54a9242..cd10e65 100644
@@ -29,7 +29,6 @@ struct pci_controller {
 	int index;		/* PCI domain number */
 	struct pci_bus *root_bus;
 
-	int first_busno;
 	int last_busno;
 
 	int hv_cfg_fd[2];	/* config{0,1} fds for this PCIe controller */
arch/tile/kernel/pci.c +3 -13
index 67237d3..1dae3b2 100644
@@ -20,7 +20,6 @@
 #include <linux/capability.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/bootmem.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -192,7 +191,6 @@ int __init tile_pci_init(void)
 			controller->hv_cfg_fd[0] = hv_cfg_fd0;
 			controller->hv_cfg_fd[1] = hv_cfg_fd1;
 			controller->hv_mem_fd = hv_mem_fd;
-			controller->first_busno = 0;
 			controller->last_busno = 0xff;
 			controller->ops = &tile_cfg_ops;
 
@@ -283,7 +281,7 @@ int __init pcibios_init(void)
 	 * known to require at least 20ms here, but we use a more
 	 * conservative value.
 	 */
-	mdelay(250);
+	msleep(250);
 
 	/* Scan all of the recorded PCI controllers.  */
 	for (i = 0; i < TILE_NUM_PCIE; i++) {
@@ -304,18 +302,10 @@ int __init pcibios_init(void)
 
 			pr_info("PCI: initializing controller #%d\n", i);
 
-			/*
-			 * This comes from the generic Linux PCI driver.
-			 *
-			 * It reads the PCI tree for this bus into the Linux
-			 * data structures.
-			 *
-			 * This is inlined in linux/pci.h and calls into
-			 * pci_scan_bus_parented() in probe.c.
-			 */
 			pci_add_resource(&resources, &ioport_resource);
 			pci_add_resource(&resources, &iomem_resource);
-			bus = pci_scan_root_bus(NULL, 0, controller->ops, controller, &resources);
+			bus = pci_scan_root_bus(NULL, 0, controller->ops,
+						controller, &resources);
 			controller->root_bus = bus;
 			controller->last_busno = bus->busn_res.end;
 		}
Signature · 1 line
1.8.3.1
#2 lore raw

PATCH 2/20 tile PCI RC: tilepro conflict with PCI and RAM addresses

In reply to Chris Metcalf

Fix a bug in the tilepro PCI resource allocation code that could make the bootmem allocator unhappy if 4GB is installed on mshim 0.

---
 arch/tile/kernel/setup.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
arch/tile/kernel/setup.c +5 -4
index 68b5426..676e155 100644
@@ -614,11 +614,12 @@ static void __init setup_bootmem_allocator_node(int i)
 	/*
 	 * Throw away any memory aliased by the PCI region.
 	 */
-	if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start)
-		reserve_bootmem(PFN_PHYS(pci_reserve_start_pfn),
-				PFN_PHYS(pci_reserve_end_pfn -
-					 pci_reserve_start_pfn),
+	if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start) {
+		start = max(pci_reserve_start_pfn, start);
+		end = min(pci_reserve_end_pfn, end);
+		reserve_bootmem(PFN_PHYS(start), PFN_PHYS(end - start),
 				BOOTMEM_EXCLUSIVE);
+	}
 #endif
 }
 
Signature · 1 line
1.8.3.1
#3 lore raw

PATCH 3/20 tile PCI RC: support pci=off boot arg for tilepro

In reply to Chris Metcalf
---
 arch/tile/kernel/pci.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
arch/tile/kernel/pci.c +17 -0
index 1dae3b2..af75835 100644
@@ -51,6 +51,8 @@
  *
  */
 
+static int pci_probe = 1;
+
 /*
  * This flag tells if the platform is TILEmpower that needs
  * special configuration for the PLX switch chip.
@@ -143,6 +145,11 @@ int __init tile_pci_init(void)
 {
 	int i;
 
+	if (!pci_probe) {
+		pr_info("PCI: disabled by boot argument\n");
+		return 0;
+	}
+
 	pr_info("PCI: Searching for controllers...\n");
 
 	/* Re-init number of PCIe controllers to support hot-plug feature. */
@@ -378,6 +385,16 @@ void pcibios_set_master(struct pci_dev *dev)
 	/* No special bus mastering setup handling. */
 }
 
+/* Process any "pci=" kernel boot arguments. */
+char * __init pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+	return str;
+}
+
 /*
  * Enable memory and/or address decoding, as appropriate, for the
  * device described by the 'dev' struct.
Signature · 1 line
1.8.3.1
#4 lore raw

PATCH 4/20 tile PCI RC: tweak the the pcie_rc_delay support

In reply to Chris Metcalf

Allow longer delays if requested, and print the info messages as we are performing the delay, not when parsing the arguments.

---
 arch/tile/kernel/pci_gx.c | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)
arch/tile/kernel/pci_gx.c +16 -19
index 1142563..e99809e 100644
@@ -69,17 +69,14 @@ static int pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
  * a HW PCIe link-training bug. The exact delay is specified with
  * a kernel boot argument in the form of "pcie_rc_delay=T,P,S",
  * where T is the TRIO instance number, P is the port number and S is
- * the delay in seconds. If the delay is not provided, the value
- * will be DEFAULT_RC_DELAY.
+ * the delay in seconds. If the argument is specified, but the delay is
+ * not provided, the value will be DEFAULT_RC_DELAY.
  */
 static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
 
 /* Default number of seconds that the PCIe RC port probe can be delayed. */
 #define DEFAULT_RC_DELAY	10
 
-/* Max number of seconds that the PCIe RC port probe can be delayed. */
-#define MAX_RC_DELAY		20
-
 /* Array of the PCIe ports configuration info obtained from the BIB. */
 struct pcie_port_property pcie_ports[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
 
@@ -570,14 +567,9 @@ static int setup_pcie_rc_delay(char *str)
 		if (!isdigit(*str))
 			return -EINVAL;
 		delay = simple_strtoul(str, (char **)&str, 10);
-		if (delay > MAX_RC_DELAY)
-			return -EINVAL;
 	}
 
 	rc_delay[trio_index][mac] = delay ? : DEFAULT_RC_DELAY;
-	pr_info("Delaying PCIe RC link training for %u sec"
-		" on MAC %lu on TRIO %lu\n", rc_delay[trio_index][mac],
-		mac, trio_index);
 	return 0;
 }
 early_param("pcie_rc_delay", setup_pcie_rc_delay);
@@ -682,12 +674,6 @@ int __init pcibios_init(void)
 			continue;
 		}
 
-		/*
-		 * Delay the RC link training if needed.
-		 */
-		if (rc_delay[trio_index][mac])
-			msleep(rc_delay[trio_index][mac] * 1000);
-
 		ret = gxio_trio_force_rc_link_up(trio_context, mac);
 		if (ret < 0)
 			pr_err("PCI: PCIE_FORCE_LINK_UP failure, "
@@ -697,10 +683,21 @@ int __init pcibios_init(void)
 			trio_index, controller->mac);
 
 		/*
-		 * Wait a bit here because some EP devices take longer
-		 * to come up.
+		 * Delay the bus probe if needed.
 		 */
-		msleep(1000);
+		if (rc_delay[trio_index][mac]) {
+			pr_info("Delaying PCIe RC bus enumerating %d sec"
+				" on MAC %d on TRIO %d\n",
+				rc_delay[trio_index][mac], mac,
+				trio_index);
+			msleep(rc_delay[trio_index][mac] * 1000);
+		} else {
+			/*
+			 * Wait a bit here because some EP devices
+			 * take longer to come up.
+			 */
+			msleep(1000);
+		}
 
 		/*
 		 * Check for PCIe link-up status.
Signature · 1 line
1.8.3.1
#5 lore raw

PATCH 5/20 tile PCI RC: handle case that PCI link is already up

In reply to Chris Metcalf

If we are rebooting (e.g. via kexec) then the PCI RC link may already be up. In that case, we don't want to do the software fixup to force the link up, since that can degrade it to Gen1.

---
 arch/tile/kernel/pci_gx.c | 41 ++++++++++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 13 deletions(-)
arch/tile/kernel/pci_gx.c +28 -13
index e99809e..2cc3e64 100644
@@ -674,10 +674,33 @@ int __init pcibios_init(void)
 			continue;
 		}
 
-		ret = gxio_trio_force_rc_link_up(trio_context, mac);
-		if (ret < 0)
-			pr_err("PCI: PCIE_FORCE_LINK_UP failure, "
-				"MAC %d on TRIO %d\n", mac, trio_index);
+		/*
+		 * Check for PCIe link-up status to decide if we need
+		 * to force the link to come up.
+		 */
+		reg_offset =
+			(TRIO_PCIE_INTFC_PORT_STATUS <<
+				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
+			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
+				TRIO_CFG_REGION_ADDR__INTFC_SHIFT) |
+			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
+
+		port_status.word =
+			__gxio_mmio_read(trio_context->mmio_base_mac +
+					 reg_offset);
+		if (!port_status.dl_up) {
+			if (rc_delay[trio_index][mac]) {
+				pr_info("Delaying PCIe RC TRIO init %d sec"
+					" on MAC %d on TRIO %d\n",
+					rc_delay[trio_index][mac], mac,
+					trio_index);
+				msleep(rc_delay[trio_index][mac] * 1000);
+			}
+			ret = gxio_trio_force_rc_link_up(trio_context, mac);
+			if (ret < 0)
+				pr_err("PCI: PCIE_FORCE_LINK_UP failure, "
+					"MAC %d on TRIO %d\n", mac, trio_index);
+		}
 
 		pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i,
 			trio_index, controller->mac);
@@ -700,16 +723,8 @@ int __init pcibios_init(void)
 		}
 
 		/*
-		 * Check for PCIe link-up status.
+		 * Check for PCIe link-up status again.
 		 */
-
-		reg_offset =
-			(TRIO_PCIE_INTFC_PORT_STATUS <<
-				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
-			(TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE <<
-				TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) |
-			(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
-
 		port_status.word =
 			__gxio_mmio_read(trio_context->mmio_base_mac +
 					 reg_offset);
Signature · 1 line
1.8.3.1
#6 lore raw

PATCH 6/20 tile: support LSI MEGARAID SAS HBA hybrid dma_ops

In reply to Chris Metcalf

The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers. According to LSI, the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

---
 arch/tile/include/asm/dma-mapping.h |  4 ++--
 arch/tile/kernel/pci-dma.c          | 17 +++++++++++------
 2 files changed, 13 insertions(+), 8 deletions(-)
arch/tile/include/asm/dma-mapping.h +2 -2
index f2ff191..6da0540 100644
@@ -44,12 +44,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-	return paddr + get_dma_offset(dev);
+	return paddr;
 }
 
 static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-	return daddr - get_dma_offset(dev);
+	return daddr;
 }
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
arch/tile/kernel/pci-dma.c +11 -6
index b9fe80e..7e98371 100644
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
 
 	addr = page_to_phys(pg);
 
-	*dma_handle = phys_to_dma(dev, addr);
+	*dma_handle = addr + get_dma_offset(dev);
 
 	return page_address(pg);
 }
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 		sg->dma_address = sg_phys(sg);
 		__dma_prep_pa_range(sg->dma_address, sg->length, direction);
 
-		sg->dma_address = phys_to_dma(dev, sg->dma_address);
+		sg->dma_address = sg->dma_address + get_dma_offset(dev);
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
 		sg->dma_length = sg->length;
 #endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
 	BUG_ON(offset + size > PAGE_SIZE);
 	__dma_prep_page(page, offset, size, direction);
 
-	return phys_to_dma(dev, page_to_pa(page) + offset);
+	return page_to_pa(page) + offset + get_dma_offset(dev);
 }
 
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_address = dma_to_phys(dev, dma_address);
+	dma_address -= get_dma_offset(dev);
 
 	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
 			    dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_complete_pa_range(dma_handle, size, direction);
 }
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
 						enum dma_data_direction
 						direction)
 {
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_prep_pa_range(dma_handle, size, direction);
 }
@@ -573,6 +573,11 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
 	if (((dma_ops == gx_pci_dma_map_ops) ||
 	    (dma_ops == gx_legacy_pci_dma_map_ops)) &&
 	    (mask <= DMA_BIT_MASK(32))) {
+		if (dma_ops == gx_pci_dma_map_ops) {
+			dma_ops->alloc = tile_swiotlb_alloc_coherent;
+			dma_ops->free = tile_swiotlb_free_coherent;
+		}
+
 		if (mask > dev->archdata.max_direct_dma_addr)
 			mask = dev->archdata.max_direct_dma_addr;
 	}
Signature · 1 line
1.8.3.1
#7 lore raw

Re: [PATCH 06/20] tile: support LSI MEGARAID SAS HBA hybrid dma_ops

Quoted 6 lines · Chris Metcalf

The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers. According to LSI, the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

If this is generic to LSI MegaRAID HBA shouldn't this change also be done for the other platforms?

Or perhaps some other changes to make it work with other devices?

Quoted 85 lines
---
 arch/tile/include/asm/dma-mapping.h |  4 ++--
 arch/tile/kernel/pci-dma.c          | 17 +++++++++++------
 2 files changed, 13 insertions(+), 8 deletions(-)
arch/tile/include/asm/dma-mapping.h +2 -2
index f2ff191..6da0540 100644
@@ -44,12 +44,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-	return paddr + get_dma_offset(dev);
+	return paddr;
 }
 
 static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-	return daddr - get_dma_offset(dev);
+	return daddr;
 }
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
arch/tile/kernel/pci-dma.c +6 -6
index b9fe80e..7e98371 100644
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
 
 	addr = page_to_phys(pg);
 
-	*dma_handle = phys_to_dma(dev, addr);
+	*dma_handle = addr + get_dma_offset(dev);
 
 	return page_address(pg);
 }
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 		sg->dma_address = sg_phys(sg);
 		__dma_prep_pa_range(sg->dma_address, sg->length, direction);
 
-		sg->dma_address = phys_to_dma(dev, sg->dma_address);
+		sg->dma_address = sg->dma_address + get_dma_offset(dev);
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
 		sg->dma_length = sg->length;
 #endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
 	BUG_ON(offset + size > PAGE_SIZE);
 	__dma_prep_page(page, offset, size, direction);
 
-	return phys_to_dma(dev, page_to_pa(page) + offset);
+	return page_to_pa(page) + offset + get_dma_offset(dev);
 }
 
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_address = dma_to_phys(dev, dma_address);
+	dma_address -= get_dma_offset(dev);
 
 	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
 			    dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_complete_pa_range(dma_handle, size, direction);
 }
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
 						enum dma_data_direction
 						direction)
 {
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_prep_pa_range(dma_handle, size, direction);
 }

arch/tile/kernel/pci-dma.c int dma_set_coherent_mask(struct device *dev, u64 mask) · line 580

Quoted 8 lines
arch/tile/kernel/pci-dma.c +5 -0
@@ -573,6 +573,11 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
 	if (((dma_ops == gx_pci_dma_map_ops) ||
 	    (dma_ops == gx_legacy_pci_dma_map_ops)) &&
 	    (mask <= DMA_BIT_MASK(32))) {
+		if (dma_ops == gx_pci_dma_map_ops) {
+			dma_ops->alloc = tile_swiotlb_alloc_coherent;
+			dma_ops->free = tile_swiotlb_free_coherent;
+		}
+

So.. that would change it for all of the devices on the host, not just for this specific one. That is not good is it?

Quoted 6 lines
arch/tile/kernel/pci-dma.c +0 -0
 		if (mask > dev->archdata.max_direct_dma_addr)
 			mask = dev->archdata.max_direct_dma_addr;
 	}
Signature · 1 line
1.8.3.1
#8 lore raw

Re: [PATCH 06/20] tile: support LSI MEGARAID SAS HBA hybrid dma_ops

Quoted 11 lines · Konrad Rzeszutek Wilk
Quoted 6 lines · Chris Metcalf

The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers. According to LSI, the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

If this is generic to LSI MegaRAID HBA shouldn't this change also be done for the other platforms?

Or perhaps some other changes to make it work with other devices?

No, it's really specific to how tilegx maps the 64-bit PCI space, 32-bit PCI space, and memory. I'll add more commentary to the git commit message to make this clearer.

Quoted 11 lines

arch/tile/kernel/pci-dma.c int dma_set_coherent_mask(struct device *dev, u64 mask) · line 580

Quoted 9 lines
arch/tile/kernel/pci-dma.c +5 -0
@@ -573,6 +573,11 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
 	if (((dma_ops == gx_pci_dma_map_ops) ||
 	    (dma_ops == gx_legacy_pci_dma_map_ops)) &&
 	    (mask <= DMA_BIT_MASK(32))) {
+		if (dma_ops == gx_pci_dma_map_ops) {
+			dma_ops->alloc = tile_swiotlb_alloc_coherent;
+			dma_ops->free = tile_swiotlb_free_coherent;
+		}
+

So.. that would change it for all of the devices on the host, not just for this specific one. That is not good is it?

Yes, good point; doing it this way might have some performance impact on other devices on the same host. See following email for a revised change that updates the dma_ops pointer for that single device instead.

Signature · 2 lines
Chris Metcalf, Tilera Corp.
http://www.tilera.com
#9 lore raw

PATCH v2 1/1 tile: support LSI MEGARAID SAS HBA hybrid dma_ops

The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers. According to LSI, the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

Note that on most other platforms, the 64-bit DMA addressing space is the same as the 32-bit DMA space and they overlap the physical memory space. No special arrangement is needed to support this kind of mixed DMA capability. On TILE-Gx, the 64-bit DMA space is completely separate from the 32-bit DMA space. Due to the use of the IOMMU, the 64-bit DMA space doesn't overlap the physical memory space. On the other hand, the 32-bit DMA space overlaps the physical memory space under 4GB. The separate address spaces make it necessary to have separate dma_ops.

---
 arch/tile/include/asm/dma-mapping.h | 10 +++++++---
 arch/tile/kernel/pci-dma.c          | 40 ++++++++++++++++++++++++++++---------
 2 files changed, 38 insertions(+), 12 deletions(-)
arch/tile/include/asm/dma-mapping.h +7 -3
index f2ff191..4a60059 100644
@@ -23,6 +23,7 @@
 extern struct dma_map_ops *tile_dma_map_ops;
 extern struct dma_map_ops *gx_pci_dma_map_ops;
 extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+extern struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
@@ -44,12 +45,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-	return paddr + get_dma_offset(dev);
+	return paddr;
 }
 
 static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-	return daddr - get_dma_offset(dev);
+	return daddr;
 }
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
@@ -88,7 +89,10 @@ dma_set_mask(struct device *dev, u64 mask)
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
 	/* Handle legacy PCI devices with limited memory addressability. */
-	if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) {
+	if ((dma_ops == gx_pci_dma_map_ops ||
+	     dma_ops == gx_hybrid_pci_dma_map_ops ||
+	     dma_ops == gx_legacy_pci_dma_map_ops) &&
+	    (mask <= DMA_BIT_MASK(32))) {
 		set_dma_ops(dev, gx_legacy_pci_dma_map_ops);
 		set_dma_offset(dev, 0);
 		if (mask > dev->archdata.max_direct_dma_addr)
arch/tile/kernel/pci-dma.c +31 -9
index b9fe80e..7e22e73 100644
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
 
 	addr = page_to_phys(pg);
 
-	*dma_handle = phys_to_dma(dev, addr);
+	*dma_handle = addr + get_dma_offset(dev);
 
 	return page_address(pg);
 }
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 		sg->dma_address = sg_phys(sg);
 		__dma_prep_pa_range(sg->dma_address, sg->length, direction);
 
-		sg->dma_address = phys_to_dma(dev, sg->dma_address);
+		sg->dma_address = sg->dma_address + get_dma_offset(dev);
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
 		sg->dma_length = sg->length;
 #endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
 	BUG_ON(offset + size > PAGE_SIZE);
 	__dma_prep_page(page, offset, size, direction);
 
-	return phys_to_dma(dev, page_to_pa(page) + offset);
+	return page_to_pa(page) + offset + get_dma_offset(dev);
 }
 
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_address = dma_to_phys(dev, dma_address);
+	dma_address -= get_dma_offset(dev);
 
 	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
 			    dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
 {
 	BUG_ON(!valid_dma_direction(direction));
 
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_complete_pa_range(dma_handle, size, direction);
 }
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
 						enum dma_data_direction
 						direction)
 {
-	dma_handle = dma_to_phys(dev, dma_handle);
+	dma_handle -= get_dma_offset(dev);
 
 	__dma_prep_pa_range(dma_handle, size, direction);
 }
@@ -558,21 +558,43 @@ static struct dma_map_ops pci_swiotlb_dma_ops = {
 	.mapping_error = swiotlb_dma_mapping_error,
 };
 
+static struct dma_map_ops pci_hybrid_dma_ops = {
+	.alloc = tile_swiotlb_alloc_coherent,
+	.free = tile_swiotlb_free_coherent,
+	.map_page = tile_pci_dma_map_page,
+	.unmap_page = tile_pci_dma_unmap_page,
+	.map_sg = tile_pci_dma_map_sg,
+	.unmap_sg = tile_pci_dma_unmap_sg,
+	.sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu,
+	.sync_single_for_device = tile_pci_dma_sync_single_for_device,
+	.sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu,
+	.sync_sg_for_device = tile_pci_dma_sync_sg_for_device,
+	.mapping_error = tile_pci_dma_mapping_error,
+	.dma_supported = tile_pci_dma_supported
+};
+
 struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops;
 #else
 struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 #endif
 EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops);
+EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops);
 
 #ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
 int dma_set_coherent_mask(struct device *dev, u64 mask)
 {
 	struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-	/* Handle legacy PCI devices with limited memory addressability. */
-	if (((dma_ops == gx_pci_dma_map_ops) ||
-	    (dma_ops == gx_legacy_pci_dma_map_ops)) &&
+	/* Handle hybrid PCI devices with limited memory addressability. */
+	if ((dma_ops == gx_pci_dma_map_ops ||
+	     dma_ops == gx_hybrid_pci_dma_map_ops ||
+	     dma_ops == gx_legacy_pci_dma_map_ops) &&
 	    (mask <= DMA_BIT_MASK(32))) {
+		if (dma_ops == gx_pci_dma_map_ops)
+			set_dma_ops(dev, gx_hybrid_pci_dma_map_ops);
+
 		if (mask > dev->archdata.max_direct_dma_addr)
 			mask = dev->archdata.max_direct_dma_addr;
 	}
Signature · 1 line
1.8.3.1
maintainer
#10 lore raw

Re: [PATCH v2] tile: support LSI MEGARAID SAS HBA hybrid dma_ops

[+cc Myron, Adam]

Quoted 4 lines · Chris Metcalf

The LSI MEGARAID SAS HBA suffers from the problem where it can do 64-bit DMA to streaming buffers but not to consistent buffers. In other words, 64-bit DMA is used for disk data transfers and 32-bit DMA must be used for control message transfers.

Is this related at all to the make_local_pdev() hacks in megaraid.c? The intent there seems to be to use a 32-bit DMA mask for certain transactions and a 64-bit mask for others. But I think it's actually broken, because the implementation changes the mask to 32-bit for *all* future transactions, not just the one using make_local_pdev().

Quoted 9 lines

According to LSI,
the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

Note that on most other platforms, the 64-bit DMA addressing space is the same as the 32-bit DMA space and they overlap the physical memory space. No special arrangement is needed to support this kind of mixed DMA capability. On TILE-Gx, the 64-bit DMA space is completely separate from the 32-bit DMA space.

Help me understand what's going on here. My understanding is that on typical systems, the 32-bit DMA space is a subset of the 64-bit DMA space. In conventional PCI, "a master that supports 64-bit addressing must generate a SAC, instead of a DAC, when the upper 32 bits of the address are zero" (PCI spec r3.0, sec 3.9). PCIe doesn't have SAC/DAC, but it has both 32-bit and 64-bit address headers and has a similar requirement: "For Addresses below 4GB, Requesters must use the 32-bit format" (PCIe spec r3.0, sec 2.2.4.1).

Those imply to me that the 0-4GB region of the 64-bit DMA space must be identical to the 0-4GB 32-bit DMA space, and in fact, the receiver of a transaction shouldn't be able to distinguish them.

But it sounds like something's different on TILE-Gx? Does it translate bus addresses to physical memory addresses based on the type of the transaction (SAC vs DAC, or 32-bit vs 64-bit header) in addition to the address? Even if it does, the spec doesn't allow a DAC cycle or a 64-bit header where the 32 high-order bits are zero, so it shouldn't matter.

Bjorn

Quoted 162 lines

Due to the use of the IOMMU, the 64-bit DMA
space doesn't overlap the physical memory space. On the other hand, the 32-bit DMA space overlaps the physical memory space under 4GB. The separate address spaces make it necessary to have separate dma_ops.

---
 arch/tile/include/asm/dma-mapping.h | 10 +++++++---
 arch/tile/kernel/pci-dma.c          | 40 ++++++++++++++++++++++++++++---------
 2 files changed, 38 insertions(+), 12 deletions(-)
arch/tile/include/asm/dma-mapping.h +7 -3
index f2ff191..4a60059 100644
@@ -23,6 +23,7 @@
 extern struct dma_map_ops *tile_dma_map_ops;
 extern struct dma_map_ops *gx_pci_dma_map_ops;
 extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+extern struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
@@ -44,12 +45,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-       return paddr + get_dma_offset(dev);
+       return paddr;
 }
 
 static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-       return daddr - get_dma_offset(dev);
+       return daddr;
 }
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
@@ -88,7 +89,10 @@ dma_set_mask(struct device *dev, u64 mask)
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
        /* Handle legacy PCI devices with limited memory addressability. */
-       if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) {
+       if ((dma_ops == gx_pci_dma_map_ops ||
+            dma_ops == gx_hybrid_pci_dma_map_ops ||
+            dma_ops == gx_legacy_pci_dma_map_ops) &&
+           (mask <= DMA_BIT_MASK(32))) {
                set_dma_ops(dev, gx_legacy_pci_dma_map_ops);
                set_dma_offset(dev, 0);
                if (mask > dev->archdata.max_direct_dma_addr)
arch/tile/kernel/pci-dma.c +31 -10
index b9fe80e..7e22e73 100644
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
 
        addr = page_to_phys(pg);
 
-       *dma_handle = phys_to_dma(dev, addr);
+       *dma_handle = addr + get_dma_offset(dev);
 
        return page_address(pg);
 }
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                sg->dma_address = sg_phys(sg);
                __dma_prep_pa_range(sg->dma_address, sg->length, direction);
 
-               sg->dma_address = phys_to_dma(dev, sg->dma_address);
+               sg->dma_address = sg->dma_address + get_dma_offset(dev);
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
                sg->dma_length = sg->length;
 #endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
        BUG_ON(offset + size > PAGE_SIZE);
        __dma_prep_page(page, offset, size, direction);
 
-       return phys_to_dma(dev, page_to_pa(page) + offset);
+       return page_to_pa(page) + offset + get_dma_offset(dev);
 }
 
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 {
        BUG_ON(!valid_dma_direction(direction));
 
-       dma_address = dma_to_phys(dev, dma_address);
+       dma_address -= get_dma_offset(dev);
 
        __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
                            dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
 {
        BUG_ON(!valid_dma_direction(direction));
 
-       dma_handle = dma_to_phys(dev, dma_handle);
+       dma_handle -= get_dma_offset(dev);
 
        __dma_complete_pa_range(dma_handle, size, direction);
 }
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
                                                enum dma_data_direction
                                                direction)
 {
-       dma_handle = dma_to_phys(dev, dma_handle);
+       dma_handle -= get_dma_offset(dev);
 
        __dma_prep_pa_range(dma_handle, size, direction);
 }
@@ -558,21 +558,43 @@ static struct dma_map_ops pci_swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
 };
 
+static struct dma_map_ops pci_hybrid_dma_ops = {
+       .alloc = tile_swiotlb_alloc_coherent,
+       .free = tile_swiotlb_free_coherent,
+       .map_page = tile_pci_dma_map_page,
+       .unmap_page = tile_pci_dma_unmap_page,
+       .map_sg = tile_pci_dma_map_sg,
+       .unmap_sg = tile_pci_dma_unmap_sg,
+       .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu,
+       .sync_single_for_device = tile_pci_dma_sync_single_for_device,
+       .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu,
+       .sync_sg_for_device = tile_pci_dma_sync_sg_for_device,
+       .mapping_error = tile_pci_dma_mapping_error,
+       .dma_supported = tile_pci_dma_supported
+};
+
 struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops;
 #else
 struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 #endif
 EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops);
+EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops);
 
 #ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
 int dma_set_coherent_mask(struct device *dev, u64 mask)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-       /* Handle legacy PCI devices with limited memory addressability. */
-       if (((dma_ops == gx_pci_dma_map_ops) ||
-           (dma_ops == gx_legacy_pci_dma_map_ops)) &&
+       /* Handle hybrid PCI devices with limited memory addressability. */
+       if ((dma_ops == gx_pci_dma_map_ops ||
+            dma_ops == gx_hybrid_pci_dma_map_ops ||
+            dma_ops == gx_legacy_pci_dma_map_ops) &&
            (mask <= DMA_BIT_MASK(32))) {
+               if (dma_ops == gx_pci_dma_map_ops)
+                       set_dma_ops(dev, gx_hybrid_pci_dma_map_ops);
+
                if (mask > dev->archdata.max_direct_dma_addr)
                        mask = dev->archdata.max_direct_dma_addr;
        }
--

1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#12 lore raw

Re: [PATCH v2] tile: support LSI MEGARAID SAS HBA hybrid dma_ops

Quoted 33 lines · Chris Metcalf
Quoted 25 lines · Bjorn Helgaas

[+cc Myron, Adam]

Quoted 9 lines · Chris Metcalf

According to LSI,
the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

Note that on most other platforms, the 64-bit DMA addressing space is the same as the 32-bit DMA space and they overlap the physical memory space. No special arrangement is needed to support this kind of mixed DMA capability. On TILE-Gx, the 64-bit DMA space is completely separate from the 32-bit DMA space.

Help me understand what's going on here. My understanding is that on typical systems, the 32-bit DMA space is a subset of the 64-bit DMA space. In conventional PCI, "a master that supports 64-bit addressing must generate a SAC, instead of a DAC, when the upper 32 bits of the address are zero" (PCI spec r3.0, sec 3.9). PCIe doesn't have SAC/DAC, but it has both 32-bit and 64-bit address headers and has a similar requirement: "For Addresses below 4GB, Requesters must use the 32-bit format" (PCIe spec r3.0, sec 2.2.4.1).

Those imply to me that the 0-4GB region of the 64-bit DMA space must be identical to the 0-4GB 32-bit DMA space, and in fact, the receiver of a transaction shouldn't be able to distinguish them.

Quoted 6 lines

But it sounds like something's different on TILE-Gx? Does it translate bus addresses to physical memory addresses based on the type of the transaction (SAC vs DAC, or 32-bit vs 64-bit header) in addition to the address? Even if it does, the spec doesn't allow a DAC cycle or a 64-bit header where the 32 high-order bits are zero, so it shouldn't matter.

Quoted 7 lines

No, we don't translate based on the type of the transaction. Using "DMA space" in the commit message was probably misleading. What's really going on is different DMA windows. 32-bit DMA has the obvious naive implementation where [0,4GB] in DMA space maps to [0,4GB] in PA space. However, for 64-bit DMA, we use DMA addresses with a non-zero high 32 bits, in the [1TB,2TB] range, but map the results down to PA [0,1TB] using our IOMMU.

I guess this means devices can DMA to physical addresses [0,3GB] using either 32-bit bus addresses in the [0,3GB] range or 64-bit bus addresses in the [1TB,1TB+3GB] range, right?

Quoted 11 lines

We did consider having the 64-bit DMA window be [0,1TB] and map directly to PA space, like the 32-bit window. But this design suffers from the “PCI hole” problem. Basically, the BAR space is usually under 4GB (it occupies the range [3GB, 4GB] on tilegx) and the host bridge uses negative decoding in passing DMA traffic upstream. That is, DMA traffic with target address in [3GB, 4GB] are not passed to the host memory. This means that the same amount of physical memory as the BAR space cannot be used for DMA purpose. And because it is not easy avoid this region in allocating DMA memory, the kernel is simply told to not use this chunk of PA at all, so it is wasted.

OK, so physical memory in the [3GB,4GB] range is unreachable via DMA as you describe. And even if DMA *could* reach it, the CPU couldn't see it because CPU accesses to that range would go to PCI for the memory-mapped BAR space, not to memory.

But I can't figure out why Tile needs to do something special. I think other arches handle the PCI hole for MMIO space the same way.

I don't know if other arches alias the [0,3GB] physical address range in both 32-bit and 64-bit DMA space like you do, but if that's part of the problem, it seems like you could easily avoid the aliasing by making the 64-bit DMA space [1TB+4GB,2TB] instead of [1TB,2TB].

Quoted 5 lines

For the LSI device, the way we manage it is to ensure that the device’s streaming buffers and the consistent buffers come from different pools, with the latter using the under-4GB bounce buffers. Obviously, normal devices use the same buffer pool for both streaming and consistent, either under 4GB or the whole PA.

It seems like you could make your DMA space be the union of [0,3GB] and [1TB+4GB,2TB], then use pci_set_dma_mask(dev, DMA_BIT_MASK(64)) and pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)) (I assume the driver already sets those masks correctly if it works on other arches).

Quoted 2 lines

Given all of that, does this change make sense? I can certainly amend the commit description to include more commentary.

Obviously, I'm missing something. I guess it really doesn't matter because this is all arch code and I don't need to understand it, but it does niggle at me somehow.

Bjorn

Quoted 167 lines
Quoted 162 lines
Quoted 162 lines

Due to the use of the IOMMU, the 64-bit DMA
space doesn't overlap the physical memory space. On the other hand, the 32-bit DMA space overlaps the physical memory space under 4GB. The separate address spaces make it necessary to have separate dma_ops.

---
 arch/tile/include/asm/dma-mapping.h | 10 +++++++---
 arch/tile/kernel/pci-dma.c          | 40 ++++++++++++++++++++++++++++---------
 2 files changed, 38 insertions(+), 12 deletions(-)
arch/tile/include/asm/dma-mapping.h +7 -3
index f2ff191..4a60059 100644
@@ -23,6 +23,7 @@
 extern struct dma_map_ops *tile_dma_map_ops;
 extern struct dma_map_ops *gx_pci_dma_map_ops;
 extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+extern struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
@@ -44,12 +45,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off)
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-       return paddr + get_dma_offset(dev);
+       return paddr;
 }
 
 static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-       return daddr - get_dma_offset(dev);
+       return daddr;
 }
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
@@ -88,7 +89,10 @@ dma_set_mask(struct device *dev, u64 mask)
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
        /* Handle legacy PCI devices with limited memory addressability. */
-       if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) {
+       if ((dma_ops == gx_pci_dma_map_ops ||
+            dma_ops == gx_hybrid_pci_dma_map_ops ||
+            dma_ops == gx_legacy_pci_dma_map_ops) &&
+           (mask <= DMA_BIT_MASK(32))) {
                set_dma_ops(dev, gx_legacy_pci_dma_map_ops);
                set_dma_offset(dev, 0);
                if (mask > dev->archdata.max_direct_dma_addr)
arch/tile/kernel/pci-dma.c +31 -10
index b9fe80e..7e22e73 100644
@@ -357,7 +357,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
 
        addr = page_to_phys(pg);
 
-       *dma_handle = phys_to_dma(dev, addr);
+       *dma_handle = addr + get_dma_offset(dev);
 
        return page_address(pg);
 }
@@ -387,7 +387,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                sg->dma_address = sg_phys(sg);
                __dma_prep_pa_range(sg->dma_address, sg->length, direction);
 
-               sg->dma_address = phys_to_dma(dev, sg->dma_address);
+               sg->dma_address = sg->dma_address + get_dma_offset(dev);
 #ifdef CONFIG_NEED_SG_DMA_LENGTH
                sg->dma_length = sg->length;
 #endif
@@ -422,7 +422,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
        BUG_ON(offset + size > PAGE_SIZE);
        __dma_prep_page(page, offset, size, direction);
 
-       return phys_to_dma(dev, page_to_pa(page) + offset);
+       return page_to_pa(page) + offset + get_dma_offset(dev);
 }
 
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
@@ -432,7 +432,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 {
        BUG_ON(!valid_dma_direction(direction));
 
-       dma_address = dma_to_phys(dev, dma_address);
+       dma_address -= get_dma_offset(dev);
 
        __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
                            dma_address & PAGE_OFFSET, size, direction);
@@ -445,7 +445,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
 {
        BUG_ON(!valid_dma_direction(direction));
 
-       dma_handle = dma_to_phys(dev, dma_handle);
+       dma_handle -= get_dma_offset(dev);
 
        __dma_complete_pa_range(dma_handle, size, direction);
 }
@@ -456,7 +456,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev,
                                                enum dma_data_direction
                                                direction)
 {
-       dma_handle = dma_to_phys(dev, dma_handle);
+       dma_handle -= get_dma_offset(dev);
 
        __dma_prep_pa_range(dma_handle, size, direction);
 }
@@ -558,21 +558,43 @@ static struct dma_map_ops pci_swiotlb_dma_ops = {
        .mapping_error = swiotlb_dma_mapping_error,
 };
 
+static struct dma_map_ops pci_hybrid_dma_ops = {
+       .alloc = tile_swiotlb_alloc_coherent,
+       .free = tile_swiotlb_free_coherent,
+       .map_page = tile_pci_dma_map_page,
+       .unmap_page = tile_pci_dma_unmap_page,
+       .map_sg = tile_pci_dma_map_sg,
+       .unmap_sg = tile_pci_dma_unmap_sg,
+       .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu,
+       .sync_single_for_device = tile_pci_dma_sync_single_for_device,
+       .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu,
+       .sync_sg_for_device = tile_pci_dma_sync_sg_for_device,
+       .mapping_error = tile_pci_dma_mapping_error,
+       .dma_supported = tile_pci_dma_supported
+};
+
 struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops;
 #else
 struct dma_map_ops *gx_legacy_pci_dma_map_ops;
+struct dma_map_ops *gx_hybrid_pci_dma_map_ops;
 #endif
 EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops);
+EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops);
 
 #ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK
 int dma_set_coherent_mask(struct device *dev, u64 mask)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-       /* Handle legacy PCI devices with limited memory addressability. */
-       if (((dma_ops == gx_pci_dma_map_ops) ||
-           (dma_ops == gx_legacy_pci_dma_map_ops)) &&
+       /* Handle hybrid PCI devices with limited memory addressability. */
+       if ((dma_ops == gx_pci_dma_map_ops ||
+            dma_ops == gx_hybrid_pci_dma_map_ops ||
+            dma_ops == gx_legacy_pci_dma_map_ops) &&
            (mask <= DMA_BIT_MASK(32))) {
+               if (dma_ops == gx_pci_dma_map_ops)
+                       set_dma_ops(dev, gx_hybrid_pci_dma_map_ops);
+
                if (mask > dev->archdata.max_direct_dma_addr)
                        mask = dev->archdata.max_direct_dma_addr;
        }
--

1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
Chris Metcalf, Tilera Corp.
http://www.tilera.com
#13 lore raw

Re: [PATCH v2] tile: support LSI MEGARAID SAS HBA hybrid dma_ops

(Oops, resending without the helpful [SPAM] marker that our mail system appears to have injected into the subject line.)

Quoted 40 lines · Bjorn Helgaas
Quoted 32 lines · Chris Metcalf
Quoted 25 lines · Bjorn Helgaas

[+cc Myron, Adam]

Quoted 9 lines · Chris Metcalf

According to LSI,
the firmware is not fully functional yet. This change implements a kind of hybrid dma_ops to support this.

Note that on most other platforms, the 64-bit DMA addressing space is the same as the 32-bit DMA space and they overlap the physical memory space. No special arrangement is needed to support this kind of mixed DMA capability. On TILE-Gx, the 64-bit DMA space is completely separate from the 32-bit DMA space.

Help me understand what's going on here. My understanding is that on typical systems, the 32-bit DMA space is a subset of the 64-bit DMA space. In conventional PCI, "a master that supports 64-bit addressing must generate a SAC, instead of a DAC, when the upper 32 bits of the address are zero" (PCI spec r3.0, sec 3.9). PCIe doesn't have SAC/DAC, but it has both 32-bit and 64-bit address headers and has a similar requirement: "For Addresses below 4GB, Requesters must use the 32-bit format" (PCIe spec r3.0, sec 2.2.4.1).

Those imply to me that the 0-4GB region of the 64-bit DMA space must be identical to the 0-4GB 32-bit DMA space, and in fact, the receiver of a transaction shouldn't be able to distinguish them.

Quoted 6 lines

But it sounds like something's different on TILE-Gx? Does it translate bus addresses to physical memory addresses based on the type of the transaction (SAC vs DAC, or 32-bit vs 64-bit header) in addition to the address? Even if it does, the spec doesn't allow a DAC cycle or a 64-bit header where the 32 high-order bits are zero, so it shouldn't matter.

Quoted 7 lines

No, we don't translate based on the type of the transaction. Using "DMA space" in the commit message was probably misleading. What's really going on is different DMA windows. 32-bit DMA has the obvious naive implementation where [0,4GB] in DMA space maps to [0,4GB] in PA space. However, for 64-bit DMA, we use DMA addresses with a non-zero high 32 bits, in the [1TB,2TB] range, but map the results down to PA [0,1TB] using our IOMMU.

Quoted 3 lines

I guess this means devices can DMA to physical addresses [0,3GB] using either 32-bit bus addresses in the [0,3GB] range or 64-bit bus addresses in the [1TB,1TB+3GB] range, right?

True in general, but not true for any specific individual device.

64-bit capable devices won’t generate 32-bit bus addresses, because the dma_ops makes sure that only bus/DMA addresses in [1TB,1TB+3GB] are handed out to the devices.

32-bit only devices use bus addresses in [0,3GB] to access the PA [0,3GB]. PA in [3GB, 4GB] is not accessed by the 32-bit only devices because the bounce buffers are allocated under 3GB limit.

Quoted 11 lines
Quoted 11 lines

We did consider having the 64-bit DMA window be [0,1TB] and map directly to PA space, like the 32-bit window. But this design suffers from the “PCI hole” problem. Basically, the BAR space is usually under 4GB (it occupies the range [3GB, 4GB] on tilegx) and the host bridge uses negative decoding in passing DMA traffic upstream. That is, DMA traffic with target address in [3GB, 4GB] are not passed to the host memory. This means that the same amount of physical memory as the BAR space cannot be used for DMA purpose. And because it is not easy avoid this region in allocating DMA memory, the kernel is simply told to not use this chunk of PA at all, so it is wasted.

Quoted 4 lines

OK, so physical memory in the [3GB,4GB] range is unreachable via DMA as you describe. And even if DMA *could* reach it, the CPU couldn't see it because CPU accesses to that range would go to PCI for the memory-mapped BAR space, not to memory.

Right. Unreachability is only a problem if the DMA window overlaps [3G, 4G], and since the 64-bit DMA window is [1TB,2TB], the whole PA space can be reached by 64-bit capable devices.

Quoted 8 lines

But I can't figure out why Tile needs to do something special. I think other arches handle the PCI hole for MMIO space the same way.

I don't know if other arches alias the [0,3GB] physical address range in both 32-bit and 64-bit DMA space like you do, but if that's part of the problem, it seems like you could easily avoid the aliasing by making the 64-bit DMA space [1TB+4GB,2TB] instead of [1TB,2TB].

Perhaps, but since 64-bit capable devices can't actually see the aliasing (since they aren't offered the [0,4GB] address range) they only see an un-aliased space.

Quoted 10 lines
Quoted 5 lines

For the LSI device, the way we manage it is to ensure that the device’s streaming buffers and the consistent buffers come from different pools, with the latter using the under-4GB bounce buffers. Obviously, normal devices use the same buffer pool for both streaming and consistent, either under 4GB or the whole PA.

It seems like you could make your DMA space be the union of [0,3GB] and [1TB+4GB,2TB], then use pci_set_dma_mask(dev, DMA_BIT_MASK(64)) and pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)) (I assume the driver already sets those masks correctly if it works on other arches).

Unfortunately, the Megaraid driver doesn’t even call pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)).

More generally, your proposed DMA space suggestion isn't optimal because then the PA in [3GB, 4GB] can’t be reached by 64-bit capable devices.

Quoted 5 lines
Quoted 2 lines

Given all of that, does this change make sense? I can certainly amend the commit description to include more commentary.

Obviously, I'm missing something. I guess it really doesn't matter because this is all arch code and I don't need to understand it, but it does niggle at me somehow.

I will add the following comment to <asm/pci.h> in hopes of making it a bit clearer:

/*
[...]
+ * This design lets us avoid the "PCI hole" problem where the host bridge
+ * won't pass DMA traffic with target addresses that happen to fall within the
+ * BAR space. This enables us to use all the physical memory for DMA, instead
+ * of wasting the same amount of physical memory as the BAR window size. */
#define TILE_PCI_MEM_MAP_BASE_OFFSET (1ULL << CHIP_PA_WIDTH())

Signature · 2 lines
Chris Metcalf, Tilera Corp.
http://www.tilera.com
#14 lore raw

PATCH 7/20 tile PCI RC: support more MSI-X interrupt vectors

In reply to Chris Metcalf

To support PCIe devices with higher number of MSI-X interrupt vectors, e.g. 16 for the LSI RAID card, enhance the Gx RC stack to provide more MSI-X vectors by using the TRIO Scatter Queues, which provide 8 more vectors in addition to ~10 from the Map Mem regions.

---
 arch/tile/gxio/iorpc_trio.c         | 23 +++++++++++++++
 arch/tile/include/arch/trio.h       | 39 ++++++++++++++++++++++++
 arch/tile/include/gxio/iorpc_trio.h |  5 ++++
 arch/tile/kernel/pci_gx.c           | 59 ++++++++++++++++++++++++-------------
 4 files changed, 106 insertions(+), 20 deletions(-)
arch/tile/gxio/iorpc_trio.c +23 -0
index cef4b22..da6e18e 100644
@@ -61,6 +61,29 @@ int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
 
 EXPORT_SYMBOL(gxio_trio_alloc_memory_maps);
 
+struct alloc_scatter_queues_param {
+	unsigned int count;
+	unsigned int first;
+	unsigned int flags;
+};
+
+int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
+				   unsigned int count, unsigned int first,
+				   unsigned int flags)
+{
+	struct alloc_scatter_queues_param temp;
+	struct alloc_scatter_queues_param *params = &temp;
+
+	params->count = count;
+	params->first = first;
+	params->flags = flags;
+
+	return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+			     sizeof(*params),
+			     GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES);
+}
+
+EXPORT_SYMBOL(gxio_trio_alloc_scatter_queues);
 
 struct alloc_pio_regions_param {
 	unsigned int count;
arch/tile/include/arch/trio.h +39 -0
index d3000a8..c0ddedc 100644
@@ -23,6 +23,45 @@
 #ifndef __ASSEMBLER__
 
 /*
+ * Map SQ Doorbell Format.
+ * This describes the format of the write-only doorbell register that exists
+ * in the last 8-bytes of the MAP_SQ_BASE/LIM range.  This register is only
+ * writable from PCIe space.  Writes to this register will not be written to
+ * Tile memory space and thus no IO VA translation is required if the last
+ * page of the BASE/LIM range is not otherwise written.
+ */
+
+__extension__
+typedef union
+{
+  struct
+  {
+#ifndef __BIG_ENDIAN__
+    /*
+     * When written with a 1, the associated MAP_SQ region's doorbell
+     * interrupt will be triggered once all previous writes are visible to
+     * Tile software.
+     */
+    uint_reg_t doorbell   : 1;
+    /*
+     * When written with a 1, the descriptor at the head of the associated
+     * MAP_SQ's FIFO will be dequeued.
+     */
+    uint_reg_t pop        : 1;
+    /* Reserved. */
+    uint_reg_t __reserved : 62;
+#else   /* __BIG_ENDIAN__ */
+    uint_reg_t __reserved : 62;
+    uint_reg_t pop        : 1;
+    uint_reg_t doorbell   : 1;
+#endif
+  };
+
+  uint_reg_t word;
+} TRIO_MAP_SQ_DOORBELL_FMT_t;
+
+
+/*
  * Tile PIO Region Configuration - CFG Address Format.
  * This register describes the address format for PIO accesses when the
  * associated region is setup with TYPE=CFG.
arch/tile/include/gxio/iorpc_trio.h +5 -0
index 58105c3..d95b96f 100644
@@ -30,6 +30,7 @@
 
 #define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404)
 
+#define GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e)
 #define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412)
 
 #define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414)
@@ -54,6 +55,10 @@ int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
 				unsigned int flags);
 
 
+int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
+				   unsigned int count, unsigned int first,
+				   unsigned int flags);
+
 int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
 				unsigned int count, unsigned int first,
 				unsigned int flags);
arch/tile/kernel/pci_gx.c +39 -20

84 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#15 lore raw

PATCH 8/20 tile PCI RC: gentler warning for missing plug-in PCI

In reply to Chris Metcalf

Besides using pr_info() to print the linkdown status for a plug-in slot, add extra indication that this is expected if the slot is empty.

---
 arch/tile/include/hv/drv_trio_intf.h |  5 +++--
 arch/tile/kernel/pci_gx.c            | 10 ++++++++--
 2 files changed, 11 insertions(+), 4 deletions(-)
arch/tile/include/hv/drv_trio_intf.h +3 -2
index ef9f3f5..ec643a0 100644
@@ -64,8 +64,9 @@ struct pcie_port_property
    *  will not consider it an error if the link comes up as a x8 link. */
   uint8_t allow_x8: 1;
 
-  /** Reserved. */
-  uint8_t reserved: 1;
+  /** If true, this link is connected to a device which may or may not
+   *  be present. */
+  uint8_t removable: 1;
 
 };
 
arch/tile/kernel/pci_gx.c +8 -2
index e0d6664..bf8c69d 100644
@@ -729,8 +729,14 @@ int __init pcibios_init(void)
 			__gxio_mmio_read(trio_context->mmio_base_mac +
 					 reg_offset);
 		if (!port_status.dl_up) {
-			pr_err("PCI: link is down, MAC %d on TRIO %d\n",
-				mac, trio_index);
+			if (pcie_ports[trio_index][mac].removable) {
+				pr_info("PCI: link is down, MAC %d on TRIO %d\n",
+					mac, trio_index);
+				pr_info("This is expected if no PCIe card"
+					" is connected to this link\n");
+			} else
+				pr_err("PCI: link is down, MAC %d on TRIO %d\n",
+					mac, trio_index);
 			continue;
 		}
 
Signature · 1 line
1.8.3.1
#16 lore raw

PATCH 9/20 tile PCI RC: support I/O space access

In reply to Chris Metcalf

To enable this functionality, configure CONFIG_TILE_PCI_IO. Without this flag, the kernel still assigns I/O address ranges to the devices, but no TRIO resource and mapping support is provided.

We assign disjoint I/O address ranges to separate PCIe domains.

---
 arch/tile/Kconfig           |  10 ++++
 arch/tile/include/asm/io.h  | 126 +++++++++++++++++++++++++++++++++++++++----
 arch/tile/include/asm/pci.h |  11 +++-
 arch/tile/kernel/pci_gx.c   | 128 +++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 257 insertions(+), 18 deletions(-)
arch/tile/Kconfig +10 -0
index 24565a7..bfff769 100644
@@ -396,6 +396,16 @@ config NO_IOMEM
 config NO_IOPORT
 	def_bool !PCI
 
+config TILE_PCI_IO
+	bool "PCI I/O space support"
+	default n
+	depends on PCI
+	depends on TILEGX
+	---help---
+	  Enable PCI I/O space support on TILEGx. Since the PCI I/O space
+	  is used by few modern PCIe endpoint devices, its support is disabled
+	  by default to save the TRIO PIO Region resource for other purposes.
+
 source "drivers/pci/Kconfig"
 
 config TILE_USB
arch/tile/include/asm/io.h +117 -9

158 lines not on this page · raw message

arch/tile/include/asm/pci.h +10 -1
index cd10e65..9cf5308 100644
@@ -144,6 +144,10 @@ struct pci_controller {
 
 	int pio_mem_index;	/* PIO region index for memory access */
 
+#ifdef CONFIG_TILE_PCI_IO
+	int pio_io_index;	/* PIO region index for I/O space access */
+#endif
+
 	/*
 	 * Mem-Map regions for all the memory controllers so that Linux can
 	 * map all of its physical memory space to the PCI bus.
@@ -153,6 +157,10 @@ struct pci_controller {
 	int index;		/* PCI domain number */
 	struct pci_bus *root_bus;
 
+	/* PCI I/O space resource for this controller. */
+	struct resource io_space;
+	char io_space_name[32];
+
 	/* PCI memory space resource for this controller. */
 	struct resource mem_space;
 	char mem_space_name[32];
@@ -210,7 +218,8 @@ static inline int pcibios_assign_all_busses(void)
 }
 
 #define PCIBIOS_MIN_MEM		0
-#define PCIBIOS_MIN_IO		0
+/* Minimum PCI I/O address, starting at the page boundary. */
+#define PCIBIOS_MIN_IO		PAGE_SIZE
 
 /* Use any cpu for PCI. */
 #define cpumask_of_pcibus(bus) cpu_online_mask
arch/tile/kernel/pci_gx.c +120 -8

182 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#17 lore raw

PATCH 10/20 tile PCI DMA: handle a NULL dev argument properly

In reply to Chris Metcalf
---
 arch/tile/kernel/pci-dma.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/tile/kernel/pci-dma.c +3 -2
index 7e98371..d16cfc1 100644
@@ -36,8 +36,9 @@ static void *tile_dma_alloc_coherent(struct device *dev, size_t size,
 				     dma_addr_t *dma_handle, gfp_t gfp,
 				     struct dma_attrs *attrs)
 {
-	u64 dma_mask = dev->coherent_dma_mask ?: DMA_BIT_MASK(32);
-	int node = dev_to_node(dev);
+	u64 dma_mask = (dev && dev->coherent_dma_mask) ?
+		dev->coherent_dma_mask : DMA_BIT_MASK(32);
+	int node = dev ? dev_to_node(dev) : 0;
 	int order = get_order(size);
 	struct page *pg;
 	dma_addr_t addr;
Signature · 1 line
1.8.3.1
#18 lore raw

PATCH 11/20 tile PCI RC: restructure TRIO initialization

In reply to Chris Metcalf

The TRIO shim initialization is shared with other kernel drivers such as the endpoint and StreamIO drivers, so reorganize the initialization flow to ensure that the root complex driver properly initializes TRIO state regardless of what kind of TRIO driver will end up using the shim.

---
 arch/tile/include/asm/pci.h |   1 +
 arch/tile/kernel/pci_gx.c   | 209 +++++++++++++++++++++++++-------------------
 2 files changed, 118 insertions(+), 92 deletions(-)
arch/tile/include/asm/pci.h +1 -0
index 9cf5308..1f1b654 100644
@@ -180,6 +180,7 @@ struct pci_controller {
 
 extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES];
 extern gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO];
+extern int num_trio_shims;
 
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
arch/tile/kernel/pci_gx.c +117 -92

306 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#19 lore raw

PATCH 12/20 tile PCI RC: eliminate pci_controller.mem_resources field

In reply to Chris Metcalf

The .mem_resources[] field in the pci_controller struct is now obsoleted by the .mem_space and .io_space fields.

---
 arch/tile/include/asm/pci.h |  3 --
 arch/tile/kernel/pci_gx.c   | 71 ++++++++-------------------------------------
 2 files changed, 12 insertions(+), 62 deletions(-)
arch/tile/include/asm/pci.h +0 -3
index 1f1b654..2c001b2 100644
@@ -173,9 +173,6 @@ struct pci_controller {
 
 	/* Table that maps the INTx numbers to Linux irq numbers. */
 	int irq_intx_table[4];
-
-	/* Address ranges that are routed to this controller/bridge. */
-	struct resource mem_resources[3];
 };
 
 extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES];
arch/tile/kernel/pci_gx.c +12 -59

128 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#20 lore raw

PATCH 13/20 tile PCI RC: include pci/pcie/Kconfig

In reply to Chris Metcalf
---
 arch/tile/Kconfig | 2 ++
 1 file changed, 2 insertions(+)
arch/tile/Kconfig +2 -0
index bfff769..e41a381 100644
@@ -408,6 +408,8 @@ config TILE_PCI_IO
 
 source "drivers/pci/Kconfig"
 
+source "drivers/pci/pcie/Kconfig"
+
 config TILE_USB
 	tristate "Tilera USB host adapter support"
 	default y
Signature · 1 line
1.8.3.1
#21 lore raw

PATCH 14/20 tile PCI RC: bomb comments and whitespace format

In reply to Chris Metcalf

This change is purely stylistic but improves the readability of the tile PCI RC driver.

---
 arch/tile/kernel/pci_gx.c | 180 +++++++++++++++-------------------------------
 1 file changed, 56 insertions(+), 124 deletions(-)
arch/tile/kernel/pci_gx.c +56 -124
index 6837be2..8352d85 100644
@@ -108,17 +108,15 @@ static struct pci_ops tile_cfg_ops;
 /* Mask of CPUs that should receive PCIe interrupts. */
 static struct cpumask intr_cpus_map;
 
-/*
- * We don't need to worry about the alignment of resources.
- */
+/* We don't need to worry about the alignment of resources. */
 resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
+				       resource_size_t size,
+				       resource_size_t align)
 {
 	return res->start;
 }
 EXPORT_SYMBOL(pcibios_align_resource);
 
-
 /*
  * Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #.
  * For now, we simply send interrupts to non-dataplane CPUs.
@@ -146,25 +144,19 @@ static int tile_irq_cpu(int irq)
 	return cpu;
 }
 
-/*
- * Open a file descriptor to the TRIO shim.
- */
+/* Open a file descriptor to the TRIO shim. */
 static int tile_pcie_open(int trio_index)
 {
 	gxio_trio_context_t *context = &trio_contexts[trio_index];
 	int ret;
 	int mac;
 
-	/*
-	 * This opens a file descriptor to the TRIO shim.
-	 */
+	/* This opens a file descriptor to the TRIO shim. */
 	ret = gxio_trio_init(context, trio_index);
 	if (ret < 0)
 		goto gxio_trio_init_failure;
 
-	/*
-	 * Allocate an ASID for the kernel.
-	 */
+	/* Allocate an ASID for the kernel. */
 	ret = gxio_trio_alloc_asids(context, 1, 0, 0);
 	if (ret < 0) {
 		pr_err("PCI: ASID alloc failure on TRIO %d, give up\n",
@@ -285,20 +277,17 @@ static int __init tile_trio_init(void)
 }
 postcore_initcall(tile_trio_init);
 
-static void
-tilegx_legacy_irq_ack(struct irq_data *d)
+static void tilegx_legacy_irq_ack(struct irq_data *d)
 {
 	__insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq);
 }
 
-static void
-tilegx_legacy_irq_mask(struct irq_data *d)
+static void tilegx_legacy_irq_mask(struct irq_data *d)
 {
 	__insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq);
 }
 
-static void
-tilegx_legacy_irq_unmask(struct irq_data *d)
+static void tilegx_legacy_irq_unmask(struct irq_data *d)
 {
 	__insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq);
 }
@@ -319,8 +308,7 @@ static struct irq_chip tilegx_legacy_irq_chip = {
  * to Linux which just calls handle_level_irq() after clearing the
  * MAC INTx Assert status bit associated with this interrupt.
  */
-static void
-trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
+static void trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
 {
 	struct pci_controller *controller = irq_desc_get_handler_data(desc);
 	gxio_trio_context_t *trio_context = controller->trio;
@@ -386,9 +374,7 @@ static int tile_init_irqs(struct pci_controller *controller)
 			goto free_irqs;
 		}
 
-		/*
-		 * Register the IRQ handler with the kernel.
-		 */
+		/* Register the IRQ handler with the kernel. */
 		irq_set_chip_and_handler(irq, &tilegx_legacy_irq_chip,
 					trio_handle_level_irq);
 		irq_set_chip_data(irq, (void *)(uint64_t)i);
@@ -471,15 +457,11 @@ int __init tile_pci_init(void)
 		}
 	}
 
-	/*
-	 * Return if no PCIe ports are configured to operate in RC mode.
-	 */
+	/* Return if no PCIe ports are configured to operate in RC mode. */
 	if (num_rc_controllers == 0)
 		return 0;
 
-	/*
-	 * Set the TRIO pointer and MAC index for each PCIe RC port.
-	 */
+	/* Set the TRIO pointer and MAC index for each PCIe RC port. */
 	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
 		for (j = 0; j < TILEGX_TRIO_PCIES; j++) {
 			if (pcie_rc[i][j]) {
@@ -495,14 +477,10 @@ int __init tile_pci_init(void)
 	}
 
 out:
-	/*
-	 * Configure each PCIe RC port.
-	 */
+	/* Configure each PCIe RC port. */
 	for (i = 0; i < num_rc_controllers; i++) {
-		/*
-		 * Configure the PCIe MAC to run in RC mode.
-		 */
 
+		/* Configure the PCIe MAC to run in RC mode. */
 		struct pci_controller *controller = &pci_controllers[i];
 
 		controller->index = i;
@@ -525,7 +503,6 @@ out:
 		 * is in range [3GB, 4GB - 1] of a 4GB space beyond the
 		 * PA space.
 		 */
-
 		controller->mem_offset = TILE_PCI_MEM_START +
 			(i * TILE_PCI_BAR_WINDOW_TOP);
 		controller->mem_space.start = controller->mem_offset +
@@ -553,7 +530,6 @@ static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin)
 	return controller->irq_intx_table[pin - 1];
 }
 
-
 static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 {
 	gxio_trio_context_t *trio_context = controller->trio;
@@ -567,9 +543,7 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 
 	mac = controller->mac;
 
-	/*
-	 * Set our max read request size to be 4KB.
-	 */
+	/* Set our max read request size to be 4KB. */
 	reg_offset =
 		(TRIO_PCIE_RC_DEVICE_CONTROL <<
 			TRIO_CFG_REGION_ADDR__REG_SHIFT) |
@@ -578,10 +552,10 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
 
 	dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
-						reg_offset);
+					      reg_offset);
 	dev_control.max_read_req_sz = 5;
 	__gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
-						dev_control.word);
+			    dev_control.word);
 
 	/*
 	 * Set the max payload size supported by this Gx PCIe MAC.
@@ -597,10 +571,10 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 		(mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT);
 
 	rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac +
-						reg_offset);
+					     reg_offset);
 	rc_dev_cap.mps_sup = 1;
 	__gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset,
-						rc_dev_cap.word);
+			    rc_dev_cap.word);
 
 	/* Configure PCI Express MPS setting. */
 	list_for_each_entry(child, &root_bus->children, node) {
@@ -628,7 +602,7 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 				    dev_control.max_payload_size,
 				    dev_control.max_read_req_sz,
 				    mac);
-        if (err < 0) {
+	if (err < 0) {
 		pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, "
 			"MAC %d on TRIO %d\n",
 			mac, controller->trio_index);
@@ -672,9 +646,7 @@ static int setup_pcie_rc_delay(char *str)
 }
 early_param("pcie_rc_delay", setup_pcie_rc_delay);
 
-/*
- * PCI initialization entry point, called by subsys_initcall.
- */
+/* PCI initialization entry point, called by subsys_initcall. */
 int __init pcibios_init(void)
 {
 	resource_size_t offset;
@@ -744,9 +716,7 @@ int __init pcibios_init(void)
 		pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i,
 			trio_index, controller->mac);
 
-		/*
-		 * Delay the bus probe if needed.
-		 */
+		/* Delay the bus probe if needed. */
 		if (rc_delay[trio_index][mac]) {
 			pr_info("Delaying PCIe RC bus enumerating %d sec"
 				" on MAC %d on TRIO %d\n",
@@ -761,9 +731,7 @@ int __init pcibios_init(void)
 			msleep(1000);
 		}
 
-		/*
-		 * Check for PCIe link-up status again.
-		 */
+		/* Check for PCIe link-up status again. */
 		port_status.word =
 			__gxio_mmio_read(trio_context->mmio_base_mac +
 					 reg_offset);
@@ -801,7 +769,6 @@ int __init pcibios_init(void)
 		 * Change the device ID so that Linux bus crawl doesn't confuse
 		 * the internal bridge with any Tilera endpoints.
 		 */
-
 		reg_offset =
 			(TRIO_PCIE_RC_DEVICE_ID_VEN_ID <<
 				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
@@ -814,10 +781,7 @@ int __init pcibios_init(void)
 				    TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) |
 				    TILERA_VENDOR_ID);
 
-		/*
-		 * Set the internal P2P bridge class code.
-		 */
-
+		/* Set the internal P2P bridge class code. */
 		reg_offset =
 			(TRIO_PCIE_RC_REVISION_ID <<
 				TRIO_CFG_REGION_ADDR__REG_SHIFT) |
@@ -828,26 +792,22 @@ int __init pcibios_init(void)
 		class_code_revision =
 			__gxio_mmio_read32(trio_context->mmio_base_mac +
 					   reg_offset);
-		class_code_revision = (class_code_revision & 0xff ) |
-					(PCI_CLASS_BRIDGE_PCI << 16);
+		class_code_revision = (class_code_revision & 0xff) |
+			(PCI_CLASS_BRIDGE_PCI << 16);
 
 		__gxio_mmio_write32(trio_context->mmio_base_mac +
 				    reg_offset, class_code_revision);
 
 #ifdef USE_SHARED_PCIE_CONFIG_REGION
 
-		/*
-		 * Map in the MMIO space for the PIO region.
-		 */
+		/* Map in the MMIO space for the PIO region. */
 		offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) |
 			(((unsigned long long)mac) <<
 			TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT);
 
 #else
 
-		/*
-		 * Alloc a PIO region for PCI config access per MAC.
-		 */
+		/* Alloc a PIO region for PCI config access per MAC. */
 		ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
 		if (ret < 0) {
 			pr_err("PCI: PCI CFG PIO alloc failure for mac %d "
@@ -858,9 +818,7 @@ int __init pcibios_init(void)
 
 		trio_context->pio_cfg_index[mac] = ret;
 
-		/*
-		 * For PIO CFG, the bus_address_hi parameter is 0.
-		 */
+		/* For PIO CFG, the bus_address_hi parameter is 0. */
 		ret = gxio_trio_init_pio_region_aux(trio_context,
 			trio_context->pio_cfg_index[mac],
 			mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE);
@@ -887,9 +845,7 @@ int __init pcibios_init(void)
 			continue;
 		}
 
-		/*
-		 * Initialize the PCIe interrupts.
-		 */
+		/* Initialize the PCIe interrupts. */
 		if (tile_init_irqs(controller)) {
 			pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n",
 				mac, trio_index);
@@ -921,7 +877,6 @@ int __init pcibios_init(void)
 	 * It allocates all of the resources (I/O memory, etc)
 	 * associated with the devices read in above.
 	 */
-
 	pci_assign_unassigned_resources();
 
 	/* Record the I/O resources in the PCI controller structure. */
@@ -942,14 +897,12 @@ int __init pcibios_init(void)
 		/* Configure the max_payload_size values for this domain. */
 		fixup_read_and_payload_sizes(controller);
 
-		/*
-		 * Alloc a PIO region for PCI memory access for each RC port.
-		 */
+		/* Alloc a PIO region for PCI memory access for each RC port. */
 		ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
 		if (ret < 0) {
 			pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, "
-				"give up\n", controller->trio_index,
-				controller->mac);
+			       "give up\n", controller->trio_index,
+			       controller->mac);
 
 			continue;
 		}
@@ -967,8 +920,8 @@ int __init pcibios_init(void)
 						    0);
 		if (ret < 0) {
 			pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, "
-				"give up\n", controller->trio_index,
-				controller->mac);
+			       "give up\n", controller->trio_index,
+			       controller->mac);
 
 			continue;
 		}
@@ -980,8 +933,8 @@ int __init pcibios_init(void)
 		ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0);
 		if (ret < 0) {
 			pr_err("PCI: I/O PIO alloc failure on TRIO %d mac %d, "
-				"give up\n", controller->trio_index,
-				controller->mac);
+			       "give up\n", controller->trio_index,
+			       controller->mac);
 
 			continue;
 		}
@@ -999,8 +952,8 @@ int __init pcibios_init(void)
 						    HV_TRIO_PIO_FLAG_IO_SPACE);
 		if (ret < 0) {
 			pr_err("PCI: I/O PIO init failure on TRIO %d mac %d, "
-				"give up\n", controller->trio_index,
-				controller->mac);
+			       "give up\n", controller->trio_index,
+			       controller->mac);
 
 			continue;
 		}
@@ -1020,9 +973,9 @@ int __init pcibios_init(void)
 							  0);
 			if (ret < 0) {
 				pr_err("PCI: Mem-Map alloc failure on TRIO %d "
-					"mac %d for MC %d, give up\n",
-					controller->trio_index,
-					controller->mac, j);
+				       "mac %d for MC %d, give up\n",
+				       controller->trio_index,
+				       controller->mac, j);
 
 				goto alloc_mem_map_failed;
 			}
@@ -1053,9 +1006,9 @@ int __init pcibios_init(void)
 				GXIO_TRIO_ORDER_MODE_UNORDERED);
 			if (ret < 0) {
 				pr_err("PCI: Mem-Map init failure on TRIO %d "
-					"mac %d for MC %d, give up\n",
-					controller->trio_index,
-					controller->mac, j);
+				       "mac %d for MC %d, give up\n",
+				       controller->trio_index,
+				       controller->mac, j);
 
 				goto alloc_mem_map_failed;
 			}
@@ -1064,22 +1017,18 @@ int __init pcibios_init(void)
 alloc_mem_map_failed:
 			break;
 		}
-
 	}
 
 	return 0;
 }
 subsys_initcall(pcibios_init);
 
-/* Note: to be deleted after Linux 3.6 merge. */
+/* No bus fixups needed. */
 void pcibios_fixup_bus(struct pci_bus *bus)
 {
 }
 
-/*
- * This can be called from the generic PCI layer, but doesn't need to
- * do anything.
- */
+/* Process any "pci=" kernel boot arguments. */
 char *pcibios_setup(char *str)
 {
 	if (!strcmp(str, "off")) {
@@ -1130,7 +1079,6 @@ void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
 	 * By searching phys_addr in each controller's mem_space, we can
 	 * determine the controller that should accept the PCI memory access.
 	 */
-
 	for (i = 0; i < num_rc_controllers; i++) {
 		/*
 		 * Skip controllers that are not properly initialized or
@@ -1158,9 +1106,7 @@ void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
 
 	offset = HV_TRIO_PIO_OFFSET(controller->pio_mem_index) + start;
 
-	/*
-	 * We need to keep the PCI bus address's in-page offset in the VA.
-	 */
+	/* We need to keep the PCI bus address's in-page offset in the VA. */
 	return iorpc_ioremap(trio_fd, offset, size) +
 		(start & (PAGE_SIZE - 1));
 }
@@ -1186,7 +1132,6 @@ void __iomem *ioport_map(unsigned long port, unsigned int size)
 	 * By searching the port in each controller's io_space, we can
 	 * determine the controller that should accept the PCI I/O access.
 	 */
-
 	for (i = 0; i < num_rc_controllers; i++) {
 		/*
 		 * Skip controllers that are not properly initialized or
@@ -1214,9 +1159,7 @@ void __iomem *ioport_map(unsigned long port, unsigned int size)
 
 	offset = HV_TRIO_PIO_OFFSET(controller->pio_io_index) + port;
 
-	/*
-	 * We need to keep the PCI bus address's in-page offset in the VA.
-	 */
+	/* We need to keep the PCI bus address's in-page offset in the VA. */
 	return iorpc_ioremap(trio_fd, offset, size) + (port & (PAGE_SIZE - 1));
 }
 EXPORT_SYMBOL(ioport_map);
@@ -1249,7 +1192,6 @@ EXPORT_SYMBOL(pci_iounmap);
  * offset is in bytes, from the start of config space for the
  * specified bus & device.
  */
-
 static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
 			 int size, u32 *val)
 {
@@ -1299,7 +1241,6 @@ static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
 	 * Accesses to the directly attached device have to be
 	 * sent as type-0 configs.
 	 */
-
 	if (busnum == (controller->first_busno + 1)) {
 		/*
 		 * There is only one device off of our built-in P2P bridge.
@@ -1321,9 +1262,8 @@ static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
 	 * Note that we don't set the mac field in cfg_addr because the
 	 * mapping is per port.
 	 */
-
 	mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] +
-			cfg_addr.word;
+		cfg_addr.word;
 
 valid_device:
 
@@ -1427,7 +1367,6 @@ static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
 	 * Accesses to the directly attached device have to be
 	 * sent as type-0 configs.
 	 */
-
 	if (busnum == (controller->first_busno + 1)) {
 		/*
 		 * There is only one device off of our built-in P2P bridge.
@@ -1449,7 +1388,6 @@ static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
 	 * Note that we don't set the mac field in cfg_addr because the
 	 * mapping is per port.
 	 */
-
 	mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] +
 			cfg_addr.word;
 
@@ -1487,11 +1425,8 @@ static struct pci_ops tile_cfg_ops = {
 };
 
 
-/*
- * MSI support starts here.
- */
-static unsigned int
-tilegx_msi_startup(struct irq_data *d)
+/* MSI support starts here. */
+static unsigned int tilegx_msi_startup(struct irq_data *d)
 {
 	if (d->msi_desc)
 		unmask_msi_irq(d);
@@ -1499,21 +1434,18 @@ tilegx_msi_startup(struct irq_data *d)
 	return 0;
 }
 
-static void
-tilegx_msi_ack(struct irq_data *d)
+static void tilegx_msi_ack(struct irq_data *d)
 {
 	__insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq);
 }
 
-static void
-tilegx_msi_mask(struct irq_data *d)
+static void tilegx_msi_mask(struct irq_data *d)
 {
 	mask_msi_irq(d);
 	__insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq);
 }
 
-static void
-tilegx_msi_unmask(struct irq_data *d)
+static void tilegx_msi_unmask(struct irq_data *d)
 {
 	__insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq);
 	unmask_msi_irq(d);
Signature · 1 line
1.8.3.1
#22 lore raw

PATCH 15/20 tile PCI RC: use proper accessor function

In reply to Chris Metcalf

Using the low-level hv_dev_pread() API makes assumptions about the layout of datastructures in the Tilera hypervisor API; it's better to use the gxio_XXX accessor and the pcie_trio_ports_property struct.

---
 arch/tile/kernel/pci_gx.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)
arch/tile/kernel/pci_gx.c +11 -13
index 8352d85..de5008b 100644
@@ -91,7 +91,7 @@ static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
 	TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1
 
 /* Array of the PCIe ports configuration info obtained from the BIB. */
-struct pcie_port_property pcie_ports[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+struct pcie_trio_ports_property pcie_ports[TILEGX_NUM_TRIO];
 
 /* Number of configured TRIO instances. */
 int num_trio_shims;
@@ -195,10 +195,7 @@ static int tile_pcie_open(int trio_index)
 #endif
 
 	/* Get the properties of the PCIe ports on this TRIO instance. */
-	ret = hv_dev_pread(context->fd, 0,
-		(HV_VirtAddr)&pcie_ports[trio_index][0],
-		sizeof(struct pcie_port_property) * TILEGX_TRIO_PCIES,
-		GXIO_TRIO_OP_GET_PORT_PROPERTY);
+	ret = gxio_trio_get_port_property(context, &pcie_ports[trio_index]);
 	if (ret < 0) {
 		pr_err("PCI: PCIE_GET_PORT_PROPERTY failure, error %d,"
 		       " on TRIO %d\n", ret, trio_index);
@@ -221,8 +218,8 @@ static int tile_pcie_open(int trio_index)
 		unsigned int reg_offset;
 
 		/* Ignore ports that are not specified in the BIB. */
-		if (!pcie_ports[trio_index][mac].allow_rc &&
-		    !pcie_ports[trio_index][mac].allow_ep)
+		if (!pcie_ports[trio_index].ports[mac].allow_rc &&
+		    !pcie_ports[trio_index].ports[mac].allow_ep)
 			continue;
 
 		reg_offset =
@@ -243,7 +240,7 @@ static int tile_pcie_open(int trio_index)
 			 */
 			if (port_config.strap_state == AUTO_CONFIG_EP ||
 			    port_config.strap_state == AUTO_CONFIG_EP_G1)
-				pcie_ports[trio_index][mac].allow_ep = 1;
+				pcie_ports[trio_index].ports[mac].allow_ep = 1;
 		}
 	}
 
@@ -438,9 +435,10 @@ int __init tile_pci_init(void)
 		return 0;
 
 	/*
-	 * Now determine which PCIe ports are configured to operate in RC mode.
-	 * We look at the Board Information Block first and then see if there
-	 * are any overriding configuration by the HW strapping pin.
+	 * Now determine which PCIe ports are configured to operate in RC
+	 * mode.  To use a port, it must be allowed to be in RC mode by the
+	 * Board Information Block, and the hardware strapping pins must be
+	 * set to RC mode.
 	 */
 	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
 		gxio_trio_context_t *context = &trio_contexts[i];
@@ -449,7 +447,7 @@ int __init tile_pci_init(void)
 			continue;
 
 		for (j = 0; j < TILEGX_TRIO_PCIES; j++) {
-			if (pcie_ports[i][j].allow_rc &&
+			if (pcie_ports[i].ports[j].allow_rc &&
 			    strapped_for_rc(context, j)) {
 				pcie_rc[i][j] = 1;
 				num_rc_controllers++;
@@ -736,7 +734,7 @@ int __init pcibios_init(void)
 			__gxio_mmio_read(trio_context->mmio_base_mac +
 					 reg_offset);
 		if (!port_status.dl_up) {
-			if (pcie_ports[trio_index][mac].removable) {
+			if (pcie_ports[trio_index].ports[mac].removable) {
 				pr_info("PCI: link is down, MAC %d on TRIO %d\n",
 					mac, trio_index);
 				pr_info("This is expected if no PCIe card"
Signature · 1 line
1.8.3.1
#23 lore raw

PATCH 16/20 tile PCI RC: add dma_get_required_mask()

In reply to Chris Metcalf

The standard kernel function dma_get_required_mask() uses the highest DRAM address to determine if 32-bit or 64-bit DMA addressing is needed. This only works on architectures that have direct mapping between the PA and the PCI address space, i.e. those that don't have I/O TLBs or have I/O TLB but choose to use direct mapping. Neither of these are true for tilegx. Whether to use 64-bit DMA should depend on the PCI device's capability only, not on the amount of DRAM installeds, so we now advertise a 64-bit DMA mask unconditionally.

---
 arch/tile/include/asm/dma-mapping.h |  4 ++++
 arch/tile/kernel/pci-dma.c          | 18 ++++++++++++++++++
 2 files changed, 22 insertions(+)
arch/tile/include/asm/dma-mapping.h +4 -0
index 6da0540..bd8387d 100644
@@ -20,6 +20,10 @@
 #include <linux/cache.h>
 #include <linux/io.h>
 
+#ifdef __tilegx__
+#define ARCH_HAS_DMA_GET_REQUIRED_MASK
+#endif
+
 extern struct dma_map_ops *tile_dma_map_ops;
 extern struct dma_map_ops *gx_pci_dma_map_ops;
 extern struct dma_map_ops *gx_legacy_pci_dma_map_ops;
arch/tile/kernel/pci-dma.c +18 -0
index d16cfc1..3570ff7 100644
@@ -590,3 +590,21 @@ int dma_set_coherent_mask(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_set_coherent_mask);
 #endif
+
+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
+/*
+ * The generic dma_get_required_mask() uses the highest physical address
+ * (max_pfn) to provide the hint to the PCI drivers regarding 32-bit or
+ * 64-bit DMA configuration. Since TILEGx has I/O TLB/MMU, allowing the
+ * DMAs to use the full 64-bit PCI address space and not limited by
+ * the physical memory space, we always let the PCI devices use
+ * 64-bit DMA if they have that capability, by returning the 64-bit
+ * DMA mask here. The device driver has the option to use 32-bit DMA if
+ * the device is not capable of 64-bit DMA.
+ */
+u64 dma_get_required_mask(struct device *dev)
+{
+	return DMA_BIT_MASK(64);
+}
+EXPORT_SYMBOL_GPL(dma_get_required_mask);
+#endif
Signature · 1 line
1.8.3.1
#24 lore raw

PATCH 17/20 tile PCI DMA: fix bug in non-page-aligned accessors

In reply to Chris Metcalf

The code incorrectly masked with PAGE_OFFSET instead of PAGE_SIZE-1. This only matters when trying to do a non page-aligned DMA; it was noticed during code inspection.

---
 arch/tile/kernel/pci-dma.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/tile/kernel/pci-dma.c +2 -2
index 3570ff7..cbc6fc4 100644
@@ -257,7 +257,7 @@ static void tile_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 	BUG_ON(!valid_dma_direction(direction));
 
 	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
-			    dma_address & PAGE_OFFSET, size, direction);
+			    dma_address & (PAGE_SIZE - 1), size, direction);
 }
 
 static void tile_dma_sync_single_for_cpu(struct device *dev,
@@ -436,7 +436,7 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 	dma_address -= get_dma_offset(dev);
 
 	__dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)),
-			    dma_address & PAGE_OFFSET, size, direction);
+			    dma_address & (PAGE_SIZE - 1), size, direction);
 }
 
 static void tile_pci_dma_sync_single_for_cpu(struct device *dev,
Signature · 1 line
1.8.3.1
#25 lore raw

PATCH 18/20 tile PCI RC: support PCIe TRIO 0 MAC 0 on Gx72 system

In reply to Chris Metcalf

On Tilera Gx72 systems, the logic for figuring out whether a given port is root complex is slightly different.

---
 arch/tile/include/hv/drv_trio_intf.h |  3 +++
 arch/tile/kernel/pci_gx.c            | 33 ++++++++++++++++++++++++++++++---
 2 files changed, 33 insertions(+), 3 deletions(-)
arch/tile/include/hv/drv_trio_intf.h +3 -0
index ec643a0..237e04d 100644
@@ -168,6 +168,9 @@ pcie_stream_intr_config_sel_t;
 struct pcie_trio_ports_property
 {
   struct pcie_port_property ports[TILEGX_TRIO_PCIES];
+
+  /** Set if this TRIO belongs to a Gx72 device. */
+  uint8_t is_gx72;
 };
 
 /* Flags indicating traffic class. */
arch/tile/kernel/pci_gx.c +30 -3
index de5008b..f2bf200 100644
@@ -436,9 +436,26 @@ int __init tile_pci_init(void)
 
 	/*
 	 * Now determine which PCIe ports are configured to operate in RC
-	 * mode.  To use a port, it must be allowed to be in RC mode by the
+	 * mode. There is a differece in the port configuration capability
+	 * between the Gx36 and Gx72 devices.
+	 *
+	 * The Gx36 has configuration capability for each of the 3 PCIe
+	 * interfaces (disable, auto endpoint, auto RC, etc.).
+	 * On the Gx72, you can only select one of the 3 PCIe interfaces per
+	 * TRIO to train automatically. Further, the allowable training modes
+	 * are reduced to four options (auto endpoint, auto RC, stream x1,
+	 * stream x4).
+	 *
+	 * For Gx36 ports, it must be allowed to be in RC mode by the
 	 * Board Information Block, and the hardware strapping pins must be
 	 * set to RC mode.
+	 *
+	 * For Gx72 ports, the port will operate in RC mode if either of the
+	 * following is true:
+	 * 1. It is allowed to be in RC mode by the Board Information Block,
+	 *    and the BIB doesn't allow the EP mode.
+	 * 2. It is allowed to be in either the RC or the EP mode by the BIB,
+	 *    and the hardware strapping pin is set to RC mode.
 	 */
 	for (i = 0; i < TILEGX_NUM_TRIO; i++) {
 		gxio_trio_context_t *context = &trio_contexts[i];
@@ -447,8 +464,18 @@ int __init tile_pci_init(void)
 			continue;
 
 		for (j = 0; j < TILEGX_TRIO_PCIES; j++) {
-			if (pcie_ports[i].ports[j].allow_rc &&
-			    strapped_for_rc(context, j)) {
+			int is_rc = 0;
+
+			if (pcie_ports[i].is_gx72 &&
+			    pcie_ports[i].ports[j].allow_rc) {
+				if (!pcie_ports[i].ports[j].allow_ep ||
+				    strapped_for_rc(context, j))
+					is_rc = 1;
+			} else if (pcie_ports[i].ports[j].allow_rc &&
+				   strapped_for_rc(context, j)) {
+				is_rc = 1;
+			}
+			if (is_rc) {
 				pcie_rc[i][j] = 1;
 				num_rc_controllers++;
 			}
Signature · 1 line
1.8.3.1
#26 lore raw

PATCH 19/20 tile PCI RC: reduce driver's vmalloc space usage

In reply to Chris Metcalf

We can take advantage of the fact that bit 29 is hard-wired to zero in register TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR. This is handy since at the moment we only allocate one 4GB region for vmalloc, and with this change we can allocate four or more TRIO MACs without using up all the vmalloc space.

---
 arch/tile/kernel/pci_gx.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
arch/tile/kernel/pci_gx.c +8 -2
index f2bf200..4843881 100644
@@ -860,9 +860,15 @@ int __init pcibios_init(void)
 
 #endif
 
+		/*
+		 * To save VMALLOC space, we take advantage of the fact that
+		 * bit 29 in the PIO CFG address format is reserved 0. With
+		 * TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT being 30,
+		 * this cuts VMALLOC space usage from 1GB to 512MB per mac.
+		 */
 		trio_context->mmio_base_pio_cfg[mac] =
-			iorpc_ioremap(trio_context->fd, offset,
-			(1 << TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT));
+			iorpc_ioremap(trio_context->fd, offset, (1UL <<
+			(TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT - 1)));
 		if (trio_context->mmio_base_pio_cfg[mac] == NULL) {
 			pr_err("PCI: PIO map failure for mac %d on TRIO %d\n",
 				mac, trio_index);
Signature · 1 line
1.8.3.1
#27 lore raw

PATCH 20/20 tile PCI RC: remove stale include of linux/numa.h

In reply to Chris Metcalf
---
 arch/tile/include/asm/pci.h | 1 -
 1 file changed, 1 deletion(-)
arch/tile/include/asm/pci.h +0 -1
index 2c001b2..c99ad44 100644
@@ -17,7 +17,6 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/pci.h>
-#include <linux/numa.h>
 #include <asm-generic/pci_iomap.h>
 
 #ifndef __tilegx__
Signature · 1 line
1.8.3.1