bcm2838_pci.c: Respect DMA limits of controller.

Fixes for Raspberry Pi 4B PCIe / USB:
- Pass through a DMA tag for the controller.
- In theory the controller can access the lower 3 GB, but testing found
  that unreliable. OpenBSD also restricts DMA to the lowest 960 MiB.
- Rename some constants to be a bit more meaningful.

Submitted by:	Robert Crowston, crowston at protonmail.com
Reviewed by:	mkarels, outside reviewers
Differential Revision:	https://reviews.freebsd.org/D26344
This commit is contained in:
Mike Karels 2020-09-12 23:49:43 +00:00
parent 33fa4ac54f
commit ac89220b05
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=365677

View File

@ -57,9 +57,6 @@ __FBSDID("$FreeBSD$");
#include "pcib_if.h"
#include "msi_if.h"
extern struct bus_space memmap_bus;
#define BUS_SPACE_3G_MAXADDR 0xc0000000
#define PCI_ID_VAL3 0x43c
#define CLASS_SHIFT 0x10
#define SUBCLASS_SHIFT 0x8
@ -69,18 +66,18 @@ extern struct bus_space memmap_bus;
#define BRIDGE_DISABLE_FLAG 0x1
#define BRIDGE_RESET_FLAG 0x2
#define REG_BRIDGE_SERDES_MODE 0x4204
#define REG_BRIDGE_CONFIG 0x4008
#define REG_BRIDGE_MEM_WINDOW_LOW 0x4034
#define REG_BRIDGE_MEM_WINDOW_HIGH 0x4038
#define REG_BRIDGE_MEM_WINDOW_1 0x403c
#define REG_DMA_CONFIG 0x4008
#define REG_DMA_WINDOW_LOW 0x4034
#define REG_DMA_WINDOW_HIGH 0x4038
#define REG_DMA_WINDOW_1 0x403c
#define REG_BRIDGE_GISB_WINDOW 0x402c
#define REG_BRIDGE_STATE 0x4068
#define REG_BRIDGE_LINK_STATE 0x00bc
#define REG_BRIDGE_BUS_WINDOW_LOW 0x400c
#define REG_BRIDGE_BUS_WINDOW_HIGH 0x4010
#define REG_BRIDGE_CPU_WINDOW_LOW 0x4070
#define REG_BRIDGE_CPU_WINDOW_START_HIGH 0x4080
#define REG_BRIDGE_CPU_WINDOW_END_HIGH 0x4084
#define REG_BUS_WINDOW_LOW 0x400c
#define REG_BUS_WINDOW_HIGH 0x4010
#define REG_CPU_WINDOW_LOW 0x4070
#define REG_CPU_WINDOW_START_HIGH 0x4080
#define REG_CPU_WINDOW_END_HIGH 0x4084
#define REG_MSI_ADDR_LOW 0x4044
#define REG_MSI_ADDR_HIGH 0x4048
@ -95,12 +92,27 @@ extern struct bus_space memmap_bus;
#define REG_EP_CONFIG_DATA 0x8000
/*
* These values were obtained from runtime inspection of a Linux system using a
* JTAG. The very limited documentation I have obtained from Broadcom does not
* explain how to compute them.
* The system memory controller can address up to 16 GiB of physical memory
* (although at time of writing the largest memory size available for purchase
* is 8 GiB). However, the system DMA controller is capable of accessing only a
* limited portion of the address space. Worse, the PCI-e controller has further
* constraints for DMA, and those limitations are not wholly clear to the
* author. NetBSD and Linux allow DMA on the lower 3 GiB of the physical memory,
* but experimentation shows DMA performed above 960 MiB results in data
* corruption with this driver. The limit of 960 MiB is taken from OpenBSD, but
* apparently that value was chosen for satisfying a constraint of an unrelated
* peripheral.
*
* Whatever the true maximum address, 960 MiB works.
*/
#define REG_VALUE_4GB_WINDOW 0x11
#define REG_VALUE_4GB_CONFIG 0x88003000
#define DMA_HIGH_LIMIT 0x3c000000
#define MAX_MEMORY_LOG2 0x21
#define REG_VALUE_DMA_WINDOW_LOW (MAX_MEMORY_LOG2 - 0xf)
#define REG_VALUE_DMA_WINDOW_HIGH 0x0
#define DMA_WINDOW_ENABLE 0x3000
#define REG_VALUE_DMA_WINDOW_CONFIG \
(((MAX_MEMORY_LOG2 - 0xf) << 0x1b) | DMA_WINDOW_ENABLE)
#define REG_VALUE_MSI_CONFIG 0xffe06540
struct bcm_pcib_irqsrc {
@ -112,6 +124,7 @@ struct bcm_pcib_irqsrc {
struct bcm_pcib_softc {
struct generic_pcie_fdt_softc base;
device_t dev;
bus_dma_tag_t dmat;
struct mtx config_mtx;
struct mtx msi_mtx;
struct resource *msi_irq_res;
@ -142,6 +155,15 @@ bcm_pcib_probe(device_t dev)
return (BUS_PROBE_DEFAULT);
}
static bus_dma_tag_t
bcm_pcib_get_dma_tag(device_t dev, device_t child)
{
struct bcm_pcib_softc *sc;
sc = device_get_softc(dev);
return (sc->dmat);
}
static void
bcm_pcib_set_reg(struct bcm_pcib_softc *sc, uint32_t reg, uint32_t val)
{
@ -614,6 +636,24 @@ bcm_pcib_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
/*
* This tag will be used in preference to the one created in
* pci_host_generic.c.
*/
error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
1, 0, /* alignment, bounds */
DMA_HIGH_LIMIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
DMA_HIGH_LIMIT, /* maxsize */
BUS_SPACE_UNRESTRICTED, /* nsegments */
DMA_HIGH_LIMIT, /* maxsegsize */
0, /* flags */
NULL, NULL, /* lockfunc, lockarg */
&sc->dmat);
if (error)
return (error);
error = pci_host_generic_setup_fdt(dev);
if (error)
return (error);
@ -632,17 +672,14 @@ bcm_pcib_attach(device_t dev)
/*
* Set PCI->CPU memory window. This encodes the inbound window showing
* up to 4 GiB of system memory to the controller, with zero offset.
* Thus, from the perspective of a device on the PCI-E bus, there is a
* 1:1 map from PCI-E bus addresses to system memory addresses. However,
* a hardware limitation means that the controller can only perform DMA
* on the lower 3 GiB of system memory.
* the system memory to the controller.
*/
bcm_pcib_set_reg(sc, REG_BRIDGE_MEM_WINDOW_LOW, REG_VALUE_4GB_WINDOW);
bcm_pcib_set_reg(sc, REG_BRIDGE_MEM_WINDOW_HIGH, 0);
bcm_pcib_set_reg(sc, REG_BRIDGE_CONFIG, REG_VALUE_4GB_CONFIG);
bcm_pcib_set_reg(sc, REG_DMA_WINDOW_LOW, REG_VALUE_DMA_WINDOW_LOW);
bcm_pcib_set_reg(sc, REG_DMA_WINDOW_HIGH, REG_VALUE_DMA_WINDOW_HIGH);
bcm_pcib_set_reg(sc, REG_DMA_CONFIG, REG_VALUE_DMA_WINDOW_CONFIG);
bcm_pcib_set_reg(sc, REG_BRIDGE_GISB_WINDOW, 0);
bcm_pcib_set_reg(sc, REG_BRIDGE_MEM_WINDOW_1, 0);
bcm_pcib_set_reg(sc, REG_DMA_WINDOW_1, 0);
bcm_pcib_enable_controller(sc);
@ -682,14 +719,14 @@ bcm_pcib_attach(device_t dev)
phys_base = sc->base.base.ranges[0].phys_base;
size = sc->base.base.ranges[0].size;
bcm_pcib_set_reg(sc, REG_BRIDGE_BUS_WINDOW_LOW, pci_base & 0xffffffff);
bcm_pcib_set_reg(sc, REG_BRIDGE_BUS_WINDOW_HIGH, pci_base >> 32);
bcm_pcib_set_reg(sc, REG_BUS_WINDOW_LOW, pci_base & 0xffffffff);
bcm_pcib_set_reg(sc, REG_BUS_WINDOW_HIGH, pci_base >> 32);
bcm_pcib_set_reg(sc, REG_BRIDGE_CPU_WINDOW_LOW,
bcm_pcib_set_reg(sc, REG_CPU_WINDOW_LOW,
encode_cpu_window_low(phys_base, size));
bcm_pcib_set_reg(sc, REG_BRIDGE_CPU_WINDOW_START_HIGH,
bcm_pcib_set_reg(sc, REG_CPU_WINDOW_START_HIGH,
encode_cpu_window_start_high(phys_base));
bcm_pcib_set_reg(sc, REG_BRIDGE_CPU_WINDOW_END_HIGH,
bcm_pcib_set_reg(sc, REG_CPU_WINDOW_END_HIGH,
encode_cpu_window_end_high(phys_base, size));
/*
@ -718,6 +755,9 @@ bcm_pcib_attach(device_t dev)
* Device method table.
*/
static device_method_t bcm_pcib_methods[] = {
/* Bus interface. */
DEVMETHOD(bus_get_dma_tag, bcm_pcib_get_dma_tag),
/* Device interface. */
DEVMETHOD(device_probe, bcm_pcib_probe),
DEVMETHOD(device_attach, bcm_pcib_attach),
@ -739,3 +779,4 @@ DEFINE_CLASS_1(pcib, bcm_pcib_driver, bcm_pcib_methods,
static devclass_t bcm_pcib_devclass;
DRIVER_MODULE(bcm_pcib, simplebus, bcm_pcib_driver, bcm_pcib_devclass, 0, 0);