The Loongson 7A1000 bridge chip has been released for several years
since the second half of 2017, but it is not supported by the Linux
mainline kernel while it only works well with the Loongson internal
kernel version. When I update the latest version of Linux mainline
kernel on the Loongson 3A3000 CPU and 7A1000 bridge chip system,
the boot process failed and I feel depressed.
The 7A1000 bridge chip is used a lot with 3A3000 or 3A4000 CPU in
the most Loongson desktop and sever products, it is important to
support Loongson 7A1000 bridge chip by the Linux mainline kernel.
This patch series adds the basic support for the Loongson 7A1000
bridge chip, when apply these patches based on linux-5.6-rc7, the
boot process is successful and we can login normally used with the
latest firmware and discrete graphics card, the next work to do is
power management and some other controller device drivers.
Additionally, when I git clone mips code [1], the speed is too slow
and clone always failed, so this patch series is based on the latest
linux-5.6-rc7 [2].
If you have any questions and suggestions, please let me know.
Thanks,
Tiezhu Yang
v2:
- The split patch series about Loongson vendor ID and SATA controller
has been merged into the linux-block.git by Jens Axboe [3].
- Think about using hierarchy IRQ domain in the patch of interrupt
controller, and this maybe depend on the patch series by Jiaxun
("Modernize Loongson64 Machine"), so the patch about interrupt is
not included in this v2 patch series.
[1] git clone https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
[2] git clone https://github.com/torvalds/linux.git
[3] https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=9acb9fe18d86
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=e49bd683e00b
Tiezhu Yang (3):
MIPS: Loongson: Get host bridge information
MIPS: Loongson: Add DMA support for 7A1000
MIPS: Loongson: Add PCI support for 7A1000
arch/mips/include/asm/mach-loongson64/boot_param.h | 20 ++++++
arch/mips/loongson64/dma.c | 9 ++-
arch/mips/loongson64/env.c | 20 ++++++
arch/mips/loongson64/init.c | 17 +++++
arch/mips/pci/ops-loongson3.c | 72 ++++++++++++++++++++--
5 files changed, 131 insertions(+), 7 deletions(-)
--
2.1.0
Add PCI support for 7A1000 to detect PCI device.
Signed-off-by: Tiezhu Yang <[email protected]>
---
arch/mips/include/asm/mach-loongson64/boot_param.h | 9 +++
arch/mips/loongson64/env.c | 2 +
arch/mips/pci/ops-loongson3.c | 72 ++++++++++++++++++++--
3 files changed, 79 insertions(+), 4 deletions(-)
diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h
index c759b7c..d766a36 100644
--- a/arch/mips/include/asm/mach-loongson64/boot_param.h
+++ b/arch/mips/include/asm/mach-loongson64/boot_param.h
@@ -195,6 +195,7 @@ enum loongson_bridge_type {
LS7A1000 = 2
};
+struct pci_bus;
struct loongson_system_configuration {
u32 nr_cpus;
u32 nr_nodes;
@@ -220,6 +221,8 @@ struct loongson_system_configuration {
struct sensor_device sensors[MAX_SENSORS];
u64 workarounds;
void (*early_config)(void);
+ int (*pci_config_access)(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, int where, u32 *data);
};
extern struct efi_memory_map_loongson *loongson_memmap;
@@ -228,5 +231,11 @@ extern struct loongson_system_configuration loongson_sysconf;
extern u32 node_id_offset;
extern void rs780e_early_config(void);
extern void ls7a1000_early_config(void);
+extern int rs780e_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *data);
+extern int ls7a1000_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *data);
#endif
diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
index 32a3822..1c27f46 100644
--- a/arch/mips/loongson64/env.c
+++ b/arch/mips/loongson64/env.c
@@ -168,9 +168,11 @@ void __init prom_init_env(void)
pr_info("The bridge chip is Loongson 7A1000\n");
loongson_sysconf.bridgetype = LS7A1000;
loongson_sysconf.early_config = ls7a1000_early_config;
+ loongson_sysconf.pci_config_access = ls7a1000_pci_config_access;
} else {
pr_info("The bridge chip is AMD RS780E or SR5690\n");
loongson_sysconf.bridgetype = RS780E;
loongson_sysconf.early_config = rs780e_early_config;
+ loongson_sysconf.pci_config_access = rs780e_pci_config_access;
}
}
diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c
index 2f6ad36..0b8fc5e 100644
--- a/arch/mips/pci/ops-loongson3.c
+++ b/arch/mips/pci/ops-loongson3.c
@@ -13,7 +13,10 @@
#define HT1LO_PCICFG_BASE 0x1a000000
#define HT1LO_PCICFG_BASE_TP1 0x1b000000
-static int loongson3_pci_config_access(unsigned char access_type,
+#define HT1LO_PCICFG_BASE_EXT 0xefe00000000
+#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000
+
+int rs780e_pci_config_access(unsigned char access_type,
struct pci_bus *bus, unsigned int devfn,
int where, u32 *data)
{
@@ -62,11 +65,72 @@ static int loongson3_pci_config_access(unsigned char access_type,
return PCIBIOS_SUCCESSFUL;
}
+
+int ls7a1000_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *data)
+{
+ u_int64_t addr;
+ void *addrp;
+ unsigned char busnum = bus->number;
+ int device = PCI_SLOT(devfn);
+ int function = PCI_FUNC(devfn);
+ int reg = where & ~3;
+
+ if (where >= PCI_CFG_SPACE_EXP_SIZE)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (busnum == 0 && device > 23)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
+ if (busnum == 0) {
+ addr = HT1LO_PCICFG_BASE | addr;
+ addrp = (void *)TO_UNCAC(addr);
+ } else {
+ addr = HT1LO_PCICFG_BASE_TP1 | addr;
+ addrp = (void *)TO_UNCAC(addr);
+ }
+ } else { /* extended config */
+ reg = (reg & 0xff) | ((reg & 0xf00) << 16);
+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
+ if (busnum == 0) {
+ addr = HT1LO_PCICFG_BASE_EXT | addr;
+ addrp = (void *)TO_UNCAC(addr);
+ } else {
+ addr = HT1LO_PCICFG_BASE_TP1_EXT | addr;
+ addrp = (void *)TO_UNCAC(addr);
+ }
+ }
+
+ if (access_type == PCI_ACCESS_WRITE)
+ *(unsigned int *)addrp = cpu_to_le32(*data);
+ else {
+ *data = le32_to_cpu(*(unsigned int *)addrp);
+ if (*data == 0xffffffff) {
+ *data = -1;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void ls7a1000_pci_class_quirk(struct pci_dev *dev)
+{
+ dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+
+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a09, ls7a1000_pci_class_quirk);
+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a19, ls7a1000_pci_class_quirk);
+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a29, ls7a1000_pci_class_quirk);
+
static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
u32 data = 0;
- int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ int ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
bus, devfn, where, &data);
if (ret != PCIBIOS_SUCCESSFUL)
@@ -91,7 +155,7 @@ static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
if (size == 4)
data = val;
else {
- ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
bus, devfn, where, &data);
if (ret != PCIBIOS_SUCCESSFUL)
return ret;
@@ -104,7 +168,7 @@ static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
(val << ((where & 3) << 3));
}
- ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
+ ret = loongson_sysconf.pci_config_access(PCI_ACCESS_WRITE,
bus, devfn, where, &data);
return ret;
--
2.1.0
Implement __phys_to_dma() and __dma_to_phys() according to the
node id offset in the 7A1000 DMA route config register.
Signed-off-by: Tiezhu Yang <[email protected]>
---
arch/mips/include/asm/mach-loongson64/boot_param.h | 5 +++++
arch/mips/loongson64/dma.c | 9 ++++++---
arch/mips/loongson64/env.c | 2 ++
arch/mips/loongson64/init.c | 17 +++++++++++++++++
4 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h b/arch/mips/include/asm/mach-loongson64/boot_param.h
index 5e8c70d..c759b7c 100644
--- a/arch/mips/include/asm/mach-loongson64/boot_param.h
+++ b/arch/mips/include/asm/mach-loongson64/boot_param.h
@@ -219,9 +219,14 @@ struct loongson_system_configuration {
u32 nr_sensors;
struct sensor_device sensors[MAX_SENSORS];
u64 workarounds;
+ void (*early_config)(void);
};
extern struct efi_memory_map_loongson *loongson_memmap;
extern struct loongson_system_configuration loongson_sysconf;
+extern u32 node_id_offset;
+extern void rs780e_early_config(void);
+extern void ls7a1000_early_config(void);
+
#endif
diff --git a/arch/mips/loongson64/dma.c b/arch/mips/loongson64/dma.c
index 5e86635..dbfe6e8 100644
--- a/arch/mips/loongson64/dma.c
+++ b/arch/mips/loongson64/dma.c
@@ -2,21 +2,24 @@
#include <linux/dma-direct.h>
#include <linux/init.h>
#include <linux/swiotlb.h>
+#include <boot_param.h>
dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
{
/* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
* Loongson-3's 48bit address space and embed it into 40bit */
long nid = (paddr >> 44) & 0x3;
- return ((nid << 44) ^ paddr) | (nid << 37);
+
+ return ((nid << 44) ^ paddr) | (nid << node_id_offset);
}
phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
{
/* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
* Loongson-3's 48bit address space and embed it into 40bit */
- long nid = (daddr >> 37) & 0x3;
- return ((nid << 37) ^ daddr) | (nid << 44);
+ long nid = (daddr >> node_id_offset) & 0x3;
+
+ return ((nid << node_id_offset) ^ daddr) | (nid << 44);
}
void __init plat_swiotlb_setup(void)
diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
index 42542c7..32a3822 100644
--- a/arch/mips/loongson64/env.c
+++ b/arch/mips/loongson64/env.c
@@ -167,8 +167,10 @@ void __init prom_init_env(void)
if (vendor == 0x0014 && device == 0x7a00) {
pr_info("The bridge chip is Loongson 7A1000\n");
loongson_sysconf.bridgetype = LS7A1000;
+ loongson_sysconf.early_config = ls7a1000_early_config;
} else {
pr_info("The bridge chip is AMD RS780E or SR5690\n");
loongson_sysconf.bridgetype = RS780E;
+ loongson_sysconf.early_config = rs780e_early_config;
}
}
diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c
index 5ac1a0f..0b6493b 100644
--- a/arch/mips/loongson64/init.c
+++ b/arch/mips/loongson64/init.c
@@ -12,6 +12,11 @@
#include <asm/fw/fw.h>
#include <loongson.h>
+#include <boot_param.h>
+
+#define NODE_ID_OFFSET_ADDR 0x90000e001001041c
+
+u32 node_id_offset;
static void __init mips_nmi_setup(void)
{
@@ -23,6 +28,16 @@ static void __init mips_nmi_setup(void)
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
+void rs780e_early_config(void)
+{
+ node_id_offset = 37;
+}
+
+void ls7a1000_early_config(void)
+{
+ node_id_offset = ((readl((u32 *)NODE_ID_OFFSET_ADDR) >> 8) & 0x1f) + 36;
+}
+
void __init prom_init(void)
{
fw_init_cmdline();
@@ -32,6 +47,8 @@ void __init prom_init(void)
set_io_port_base((unsigned long)
ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+ loongson_sysconf.early_config();
+
prom_init_numa_memory();
/* Hardcode to CPU UART 0 */
--
2.1.0
于 2020年3月23日 GMT+08:00 上午10:59:15, Tiezhu Yang <[email protected]> 写到:
>Add PCI support for 7A1000 to detect PCI device.
>
>Signed-off-by: Tiezhu Yang <[email protected]>
Hi Tiezhu,
See my comments below.
>---
> arch/mips/include/asm/mach-loongson64/boot_param.h | 9 +++
> arch/mips/loongson64/env.c | 2 +
>arch/mips/pci/ops-loongson3.c | 72
>++++++++++++++++++++--
> 3 files changed, 79 insertions(+), 4 deletions(-)
>
>diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h
>b/arch/mips/include/asm/mach-loongson64/boot_param.h
>index c759b7c..d766a36 100644
>--- a/arch/mips/include/asm/mach-loongson64/boot_param.h
>+++ b/arch/mips/include/asm/mach-loongson64/boot_param.h
>@@ -195,6 +195,7 @@ enum loongson_bridge_type {
> LS7A1000 = 2
> };
>
>+struct pci_bus;
> struct loongson_system_configuration {
> u32 nr_cpus;
> u32 nr_nodes;
>@@ -220,6 +221,8 @@ struct loongson_system_configuration {
> struct sensor_device sensors[MAX_SENSORS];
> u64 workarounds;
> void (*early_config)(void);
>+ int (*pci_config_access)(unsigned char access_type, struct pci_bus
>*bus,
>+ unsigned int devfn, int where, u32 *data);
> };
>
> extern struct efi_memory_map_loongson *loongson_memmap;
>@@ -228,5 +231,11 @@ extern struct loongson_system_configuration
>loongson_sysconf;
> extern u32 node_id_offset;
> extern void rs780e_early_config(void);
> extern void ls7a1000_early_config(void);
>+extern int rs780e_pci_config_access(unsigned char access_type,
>+ struct pci_bus *bus, unsigned int devfn,
>+ int where, u32 *data);
>+extern int ls7a1000_pci_config_access(unsigned char access_type,
>+ struct pci_bus *bus, unsigned int devfn,
>+ int where, u32 *data);
>
> #endif
>diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
>index 32a3822..1c27f46 100644
>--- a/arch/mips/loongson64/env.c
>+++ b/arch/mips/loongson64/env.c
>@@ -168,9 +168,11 @@ void __init prom_init_env(void)
> pr_info("The bridge chip is Loongson 7A1000\n");
> loongson_sysconf.bridgetype = LS7A1000;
> loongson_sysconf.early_config = ls7a1000_early_config;
>+ loongson_sysconf.pci_config_access = ls7a1000_pci_config_access;
> } else {
> pr_info("The bridge chip is AMD RS780E or SR5690\n");
> loongson_sysconf.bridgetype = RS780E;
> loongson_sysconf.early_config = rs780e_early_config;
>+ loongson_sysconf.pci_config_access = rs780e_pci_config_access;
> }
> }
>diff --git a/arch/mips/pci/ops-loongson3.c
>b/arch/mips/pci/ops-loongson3.c
>index 2f6ad36..0b8fc5e 100644
>--- a/arch/mips/pci/ops-loongson3.c
>+++ b/arch/mips/pci/ops-loongson3.c
>@@ -13,7 +13,10 @@
> #define HT1LO_PCICFG_BASE 0x1a000000
> #define HT1LO_PCICFG_BASE_TP1 0x1b000000
>
>-static int loongson3_pci_config_access(unsigned char access_type,
>+#define HT1LO_PCICFG_BASE_EXT 0xefe00000000
>+#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000
>+
>+int rs780e_pci_config_access(unsigned char access_type,
> struct pci_bus *bus, unsigned int devfn,
> int where, u32 *data)
> {
>@@ -62,11 +65,72 @@ static int loongson3_pci_config_access(unsigned
>char access_type,
> return PCIBIOS_SUCCESSFUL;
> }
>
>+
>+int ls7a1000_pci_config_access(unsigned char access_type,
>+ struct pci_bus *bus, unsigned int devfn,
>+ int where, u32 *data)
>+{
>+ u_int64_t addr;
>+ void *addrp;
>+ unsigned char busnum = bus->number;
>+ int device = PCI_SLOT(devfn);
>+ int function = PCI_FUNC(devfn);
>+ int reg = where & ~3;
>+
>+ if (where >= PCI_CFG_SPACE_EXP_SIZE)
>+ return PCIBIOS_DEVICE_NOT_FOUND;
>+
>+ if (busnum == 0 && device > 23)
>+ return PCIBIOS_DEVICE_NOT_FOUND;
>+
>+ if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
>+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
>+ if (busnum == 0) {
>+ addr = HT1LO_PCICFG_BASE | addr;
>+ addrp = (void *)TO_UNCAC(addr);
>+ } else {
>+ addr = HT1LO_PCICFG_BASE_TP1 | addr;
>+ addrp = (void *)TO_UNCAC(addr);
>+ }
>+ } else { /* extended config */
>+ reg = (reg & 0xff) | ((reg & 0xf00) << 16);
>+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
>+ if (busnum == 0) {
>+ addr = HT1LO_PCICFG_BASE_EXT | addr;
>+ addrp = (void *)TO_UNCAC(addr);
>+ } else {
>+ addr = HT1LO_PCICFG_BASE_TP1_EXT | addr;
>+ addrp = (void *)TO_UNCAC(addr);
>+ }
>+ }
>+
>+ if (access_type == PCI_ACCESS_WRITE)
>+ *(unsigned int *)addrp = cpu_to_le32(*data);
>+ else {
>+ *data = le32_to_cpu(*(unsigned int *)addrp);
>+ if (*data == 0xffffffff) {
>+ *data = -1;
>+ return PCIBIOS_DEVICE_NOT_FOUND;
>+ }
>+ }
>+
>+ return PCIBIOS_SUCCESSFUL;
>+}
>+
>+static void ls7a1000_pci_class_quirk(struct pci_dev *dev)
>+{
>+ dev->class = PCI_CLASS_BRIDGE_PCI << 8;
>+}
>+
>+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a09, ls7a1000_pci_class_quirk);
>+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a19, ls7a1000_pci_class_quirk);
>+DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a29, ls7a1000_pci_class_quirk);
Please place them to fixup-loongson3.c,
don't mess up with operations.
And you've already added vendor ID to pci_ids.h.
You can use it and tell us "it depends on pci-next tree's commit".
>+
>static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int
>devfn,
> int where, int size, u32 *val)
> {
> u32 data = 0;
>- int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
>+ int ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
> bus, devfn, where, &data);
>
> if (ret != PCIBIOS_SUCCESSFUL)
>@@ -91,7 +155,7 @@ static int loongson3_pci_pcibios_write(struct
>pci_bus *bus, unsigned int devfn,
> if (size == 4)
> data = val;
> else {
>- ret = loongson3_pci_config_access(PCI_ACCESS_READ,
>+ ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
> bus, devfn, where, &data);
> if (ret != PCIBIOS_SUCCESSFUL)
> return ret;
>@@ -104,7 +168,7 @@ static int loongson3_pci_pcibios_write(struct
>pci_bus *bus, unsigned int devfn,
> (val << ((where & 3) << 3));
> }
>
>- ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
>+ ret = loongson_sysconf.pci_config_access(PCI_ACCESS_WRITE,
> bus, devfn, where, &data);
>
> return ret;
--
Jiaxun Yang
于 2020年3月23日 GMT+08:00 上午10:59:12, Tiezhu Yang <[email protected]> 写到:
>The Loongson 7A1000 bridge chip has been released for several years
>since the second half of 2017, but it is not supported by the Linux
>mainline kernel while it only works well with the Loongson internal
>kernel version. When I update the latest version of Linux mainline
>kernel on the Loongson 3A3000 CPU and 7A1000 bridge chip system,
>the boot process failed and I feel depressed.
>
>The 7A1000 bridge chip is used a lot with 3A3000 or 3A4000 CPU in
>the most Loongson desktop and sever products, it is important to
>support Loongson 7A1000 bridge chip by the Linux mainline kernel.
>
>This patch series adds the basic support for the Loongson 7A1000
>bridge chip, when apply these patches based on linux-5.6-rc7, the
>boot process is successful and we can login normally used with the
Is it still true without IRQ driver?
>latest firmware and discrete graphics card, the next work to do is
>power management and some other controller device drivers.
>
>Additionally, when I git clone mips code [1], the speed is too slow
>and clone always failed, so this patch series is based on the latest
>linux-5.6-rc7 [2].
You can clone stable tree from mirrors in China[1] at first,
then add mips tree as a remote and fetch from it.
In this way it will only download a minimal difference set from foreign server so won't spend a lot of time.
[1]: https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git
>
>If you have any questions and suggestions, please let me know.
>
>Thanks,
>
>Tiezhu Yang
>
>v2:
> - The split patch series about Loongson vendor ID and SATA controller
> has been merged into the linux-block.git by Jens Axboe [3].
>
> - Think about using hierarchy IRQ domain in the patch of interrupt
> controller, and this maybe depend on the patch series by Jiaxun
> ("Modernize Loongson64 Machine"), so the patch about interrupt is
> not included in this v2 patch series.
>
>[1] git clone
>https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
>[2] git clone https://github.com/torvalds/linux.git
>[3]
>https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=9acb9fe18d86
>https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=e49bd683e00b
>
>Tiezhu Yang (3):
> MIPS: Loongson: Get host bridge information
> MIPS: Loongson: Add DMA support for 7A1000
> MIPS: Loongson: Add PCI support for 7A1000
>
> arch/mips/include/asm/mach-loongson64/boot_param.h | 20 ++++++
> arch/mips/loongson64/dma.c | 9 ++-
> arch/mips/loongson64/env.c | 20 ++++++
> arch/mips/loongson64/init.c | 17 +++++
>arch/mips/pci/ops-loongson3.c | 72
>++++++++++++++++++++--
> 5 files changed, 131 insertions(+), 7 deletions(-)
--
Jiaxun Yang
On Tue, Mar 24, 2020 at 3:53 PM Jiaxun Yang <[email protected]> wrote:
>
>
>
> 于 2020年3月23日 GMT+08:00 上午10:59:12, Tiezhu Yang <[email protected]> 写到:
> >The Loongson 7A1000 bridge chip has been released for several years
> >since the second half of 2017, but it is not supported by the Linux
> >mainline kernel while it only works well with the Loongson internal
> >kernel version. When I update the latest version of Linux mainline
> >kernel on the Loongson 3A3000 CPU and 7A1000 bridge chip system,
> >the boot process failed and I feel depressed.
> >
> >The 7A1000 bridge chip is used a lot with 3A3000 or 3A4000 CPU in
> >the most Loongson desktop and sever products, it is important to
> >support Loongson 7A1000 bridge chip by the Linux mainline kernel.
> >
> >This patch series adds the basic support for the Loongson 7A1000
> >bridge chip, when apply these patches based on linux-5.6-rc7, the
> >boot process is successful and we can login normally used with the
>
> Is it still true without IRQ driver?
>
> >latest firmware and discrete graphics card, the next work to do is
> >power management and some other controller device drivers.
> >
> >Additionally, when I git clone mips code [1], the speed is too slow
> >and clone always failed, so this patch series is based on the latest
> >linux-5.6-rc7 [2].
>
> You can clone stable tree from mirrors in China[1] at first,
> then add mips tree as a remote and fetch from it.
> In this way it will only download a minimal difference set from foreign server so won't spend a lot of time.
>
>
> [1]: https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git
Maybe the mirror is better
https://kernel.source.codeaurora.cn/pub/scm/linux/kernel/git//stable/linux.git
>
> >
> >If you have any questions and suggestions, please let me know.
> >
> >Thanks,
> >
> >Tiezhu Yang
> >
> >v2:
> > - The split patch series about Loongson vendor ID and SATA controller
> > has been merged into the linux-block.git by Jens Axboe [3].
> >
> > - Think about using hierarchy IRQ domain in the patch of interrupt
> > controller, and this maybe depend on the patch series by Jiaxun
> > ("Modernize Loongson64 Machine"), so the patch about interrupt is
> > not included in this v2 patch series.
> >
> >[1] git clone
> >https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
> >[2] git clone https://github.com/torvalds/linux.git
> >[3]
> >https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=9acb9fe18d86
> >https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=e49bd683e00b
> >
> >Tiezhu Yang (3):
> > MIPS: Loongson: Get host bridge information
> > MIPS: Loongson: Add DMA support for 7A1000
> > MIPS: Loongson: Add PCI support for 7A1000
> >
> > arch/mips/include/asm/mach-loongson64/boot_param.h | 20 ++++++
> > arch/mips/loongson64/dma.c | 9 ++-
> > arch/mips/loongson64/env.c | 20 ++++++
> > arch/mips/loongson64/init.c | 17 +++++
> >arch/mips/pci/ops-loongson3.c | 72
> >++++++++++++++++++++--
> > 5 files changed, 131 insertions(+), 7 deletions(-)
>
> --
> Jiaxun Yang
On 03/24/2020 03:49 PM, Jiaxun Yang wrote:
>
> 于 2020年3月23日 GMT+08:00 上午10:59:12, Tiezhu Yang <[email protected]> 写到:
>> The Loongson 7A1000 bridge chip has been released for several years
>> since the second half of 2017, but it is not supported by the Linux
>> mainline kernel while it only works well with the Loongson internal
>> kernel version. When I update the latest version of Linux mainline
>> kernel on the Loongson 3A3000 CPU and 7A1000 bridge chip system,
>> the boot process failed and I feel depressed.
>>
>> The 7A1000 bridge chip is used a lot with 3A3000 or 3A4000 CPU in
>> the most Loongson desktop and sever products, it is important to
>> support Loongson 7A1000 bridge chip by the Linux mainline kernel.
>>
>> This patch series adds the basic support for the Loongson 7A1000
>> bridge chip, when apply these patches based on linux-5.6-rc7, the
>> boot process is successful and we can login normally used with the
> Is it still true without IRQ driver?
No, I will modify the description.
>
>> latest firmware and discrete graphics card, the next work to do is
>> power management and some other controller device drivers.
>>
>> Additionally, when I git clone mips code [1], the speed is too slow
>> and clone always failed, so this patch series is based on the latest
>> linux-5.6-rc7 [2].
> You can clone stable tree from mirrors in China[1] at first,
> then add mips tree as a remote and fetch from it.
> In this way it will only download a minimal difference set from foreign server so won't spend a lot of time.
Thanks for your suggestion.
>
>
> [1]: https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git
>
>> If you have any questions and suggestions, please let me know.
>>
>> Thanks,
>>
>> Tiezhu Yang
>>
>> v2:
>> - The split patch series about Loongson vendor ID and SATA controller
>> has been merged into the linux-block.git by Jens Axboe [3].
>>
>> - Think about using hierarchy IRQ domain in the patch of interrupt
>> controller, and this maybe depend on the patch series by Jiaxun
>> ("Modernize Loongson64 Machine"), so the patch about interrupt is
>> not included in this v2 patch series.
>>
>> [1] git clone
>> https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
>> [2] git clone https://github.com/torvalds/linux.git
>> [3]
>> https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=9acb9fe18d86
>> https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git/commit/?h=for-next&id=e49bd683e00b
>>
>> Tiezhu Yang (3):
>> MIPS: Loongson: Get host bridge information
>> MIPS: Loongson: Add DMA support for 7A1000
>> MIPS: Loongson: Add PCI support for 7A1000
>>
>> arch/mips/include/asm/mach-loongson64/boot_param.h | 20 ++++++
>> arch/mips/loongson64/dma.c | 9 ++-
>> arch/mips/loongson64/env.c | 20 ++++++
>> arch/mips/loongson64/init.c | 17 +++++
>> arch/mips/pci/ops-loongson3.c | 72
>> ++++++++++++++++++++--
>> 5 files changed, 131 insertions(+), 7 deletions(-)
On 03/24/2020 03:28 PM, Jiaxun Yang wrote:
>
> 于 2020年3月23日 GMT+08:00 上午10:59:15, Tiezhu Yang <[email protected]> 写到:
>> Add PCI support for 7A1000 to detect PCI device.
>>
>> Signed-off-by: Tiezhu Yang <[email protected]>
> Hi Tiezhu,
>
> See my comments below.
>
>> ---
>> arch/mips/include/asm/mach-loongson64/boot_param.h | 9 +++
>> arch/mips/loongson64/env.c | 2 +
>> arch/mips/pci/ops-loongson3.c | 72
>> ++++++++++++++++++++--
>> 3 files changed, 79 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/mips/include/asm/mach-loongson64/boot_param.h
>> b/arch/mips/include/asm/mach-loongson64/boot_param.h
>> index c759b7c..d766a36 100644
>> --- a/arch/mips/include/asm/mach-loongson64/boot_param.h
>> +++ b/arch/mips/include/asm/mach-loongson64/boot_param.h
>> @@ -195,6 +195,7 @@ enum loongson_bridge_type {
>> LS7A1000 = 2
>> };
>>
>> +struct pci_bus;
>> struct loongson_system_configuration {
>> u32 nr_cpus;
>> u32 nr_nodes;
>> @@ -220,6 +221,8 @@ struct loongson_system_configuration {
>> struct sensor_device sensors[MAX_SENSORS];
>> u64 workarounds;
>> void (*early_config)(void);
>> + int (*pci_config_access)(unsigned char access_type, struct pci_bus
>> *bus,
>> + unsigned int devfn, int where, u32 *data);
>> };
>>
>> extern struct efi_memory_map_loongson *loongson_memmap;
>> @@ -228,5 +231,11 @@ extern struct loongson_system_configuration
>> loongson_sysconf;
>> extern u32 node_id_offset;
>> extern void rs780e_early_config(void);
>> extern void ls7a1000_early_config(void);
>> +extern int rs780e_pci_config_access(unsigned char access_type,
>> + struct pci_bus *bus, unsigned int devfn,
>> + int where, u32 *data);
>> +extern int ls7a1000_pci_config_access(unsigned char access_type,
>> + struct pci_bus *bus, unsigned int devfn,
>> + int where, u32 *data);
>>
>> #endif
>> diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
>> index 32a3822..1c27f46 100644
>> --- a/arch/mips/loongson64/env.c
>> +++ b/arch/mips/loongson64/env.c
>> @@ -168,9 +168,11 @@ void __init prom_init_env(void)
>> pr_info("The bridge chip is Loongson 7A1000\n");
>> loongson_sysconf.bridgetype = LS7A1000;
>> loongson_sysconf.early_config = ls7a1000_early_config;
>> + loongson_sysconf.pci_config_access = ls7a1000_pci_config_access;
>> } else {
>> pr_info("The bridge chip is AMD RS780E or SR5690\n");
>> loongson_sysconf.bridgetype = RS780E;
>> loongson_sysconf.early_config = rs780e_early_config;
>> + loongson_sysconf.pci_config_access = rs780e_pci_config_access;
>> }
>> }
>> diff --git a/arch/mips/pci/ops-loongson3.c
>> b/arch/mips/pci/ops-loongson3.c
>> index 2f6ad36..0b8fc5e 100644
>> --- a/arch/mips/pci/ops-loongson3.c
>> +++ b/arch/mips/pci/ops-loongson3.c
>> @@ -13,7 +13,10 @@
>> #define HT1LO_PCICFG_BASE 0x1a000000
>> #define HT1LO_PCICFG_BASE_TP1 0x1b000000
>>
>> -static int loongson3_pci_config_access(unsigned char access_type,
>> +#define HT1LO_PCICFG_BASE_EXT 0xefe00000000
>> +#define HT1LO_PCICFG_BASE_TP1_EXT 0xefe10000000
>> +
>> +int rs780e_pci_config_access(unsigned char access_type,
>> struct pci_bus *bus, unsigned int devfn,
>> int where, u32 *data)
>> {
>> @@ -62,11 +65,72 @@ static int loongson3_pci_config_access(unsigned
>> char access_type,
>> return PCIBIOS_SUCCESSFUL;
>> }
>>
>> +
>> +int ls7a1000_pci_config_access(unsigned char access_type,
>> + struct pci_bus *bus, unsigned int devfn,
>> + int where, u32 *data)
>> +{
>> + u_int64_t addr;
>> + void *addrp;
>> + unsigned char busnum = bus->number;
>> + int device = PCI_SLOT(devfn);
>> + int function = PCI_FUNC(devfn);
>> + int reg = where & ~3;
>> +
>> + if (where >= PCI_CFG_SPACE_EXP_SIZE)
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> +
>> + if (busnum == 0 && device > 23)
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> +
>> + if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
>> + addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
>> + if (busnum == 0) {
>> + addr = HT1LO_PCICFG_BASE | addr;
>> + addrp = (void *)TO_UNCAC(addr);
>> + } else {
>> + addr = HT1LO_PCICFG_BASE_TP1 | addr;
>> + addrp = (void *)TO_UNCAC(addr);
>> + }
>> + } else { /* extended config */
>> + reg = (reg & 0xff) | ((reg & 0xf00) << 16);
>> + addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
>> + if (busnum == 0) {
>> + addr = HT1LO_PCICFG_BASE_EXT | addr;
>> + addrp = (void *)TO_UNCAC(addr);
>> + } else {
>> + addr = HT1LO_PCICFG_BASE_TP1_EXT | addr;
>> + addrp = (void *)TO_UNCAC(addr);
>> + }
>> + }
>> +
>> + if (access_type == PCI_ACCESS_WRITE)
>> + *(unsigned int *)addrp = cpu_to_le32(*data);
>> + else {
>> + *data = le32_to_cpu(*(unsigned int *)addrp);
>> + if (*data == 0xffffffff) {
>> + *data = -1;
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> + }
>> + }
>> +
>> + return PCIBIOS_SUCCESSFUL;
>> +}
>> +
>> +static void ls7a1000_pci_class_quirk(struct pci_dev *dev)
>> +{
>> + dev->class = PCI_CLASS_BRIDGE_PCI << 8;
>> +}
>> +
>> +DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a09, ls7a1000_pci_class_quirk);
>> +DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a19, ls7a1000_pci_class_quirk);
>> +DECLARE_PCI_FIXUP_EARLY(0x0014, 0x7a29, ls7a1000_pci_class_quirk);
> Please place them to fixup-loongson3.c,
> don't mess up with operations.
>
> And you've already added vendor ID to pci_ids.h.
> You can use it and tell us "it depends on pci-next tree's commit".
OK, I will do it. Thank you very much.
>
>> +
>> static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int
>> devfn,
>> int where, int size, u32 *val)
>> {
>> u32 data = 0;
>> - int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
>> + int ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
>> bus, devfn, where, &data);
>>
>> if (ret != PCIBIOS_SUCCESSFUL)
>> @@ -91,7 +155,7 @@ static int loongson3_pci_pcibios_write(struct
>> pci_bus *bus, unsigned int devfn,
>> if (size == 4)
>> data = val;
>> else {
>> - ret = loongson3_pci_config_access(PCI_ACCESS_READ,
>> + ret = loongson_sysconf.pci_config_access(PCI_ACCESS_READ,
>> bus, devfn, where, &data);
>> if (ret != PCIBIOS_SUCCESSFUL)
>> return ret;
>> @@ -104,7 +168,7 @@ static int loongson3_pci_pcibios_write(struct
>> pci_bus *bus, unsigned int devfn,
>> (val << ((where & 3) << 3));
>> }
>>
>> - ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
>> + ret = loongson_sysconf.pci_config_access(PCI_ACCESS_WRITE,
>> bus, devfn, where, &data);
>>
>> return ret;
On Mon, Mar 23, 2020 at 10:59:14AM +0800, Tiezhu Yang wrote:
> Implement __phys_to_dma() and __dma_to_phys() according to the
> node id offset in the 7A1000 DMA route config register.
Can you please try to just use the dma_pfn_offset field in struct device
for all loongson platforms? I'm pretty sure I asked for that last time
around..
On 03/25/2020 09:27 PM, Christoph Hellwig wrote:
> On Mon, Mar 23, 2020 at 10:59:14AM +0800, Tiezhu Yang wrote:
>> Implement __phys_to_dma() and __dma_to_phys() according to the
>> node id offset in the 7A1000 DMA route config register.
> Can you please try to just use the dma_pfn_offset field in struct device
> for all loongson platforms? I'm pretty sure I asked for that last time
> around..
Oh, sorry, I don't quite understand what you mean last time.
Do you mean use the default implementation in include/linux/dma-direct.h
when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set?
#ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
#include <asm/dma-direct.h>
#else
static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t
paddr)
{
dma_addr_t dev_addr = (dma_addr_t)paddr;
return dev_addr - ((dma_addr_t)dev->dma_pfn_offset << PAGE_SHIFT);
}
static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t
dev_addr)
{
phys_addr_t paddr = (phys_addr_t)dev_addr;
return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT);
}
#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
If so, I will verify it used with the AMD RS780E and Loongson 7A1000
bridge chip.
Thanks,
Tiezhu Yang
于 2020年3月25日 GMT+08:00 下午9:27:56, Christoph Hellwig <[email protected]> 写到:
>On Mon, Mar 23, 2020 at 10:59:14AM +0800, Tiezhu Yang wrote:
>> Implement __phys_to_dma() and __dma_to_phys() according to the
>> node id offset in the 7A1000 DMA route config register.
>
>Can you please try to just use the dma_pfn_offset field in struct
>device
>for all loongson platforms? I'm pretty sure I asked for that last time
>around..
Here we have a problem that dma_pfn_offset doesn't fit our platform.
We have multiple dma-ranges that translate in to different address and
dma_pfn_offset can only handle single range
with fixed offset.
Thanks.
--
Jiaxun Yang
On 03/25/2020 09:27 PM, Christoph Hellwig wrote:
> On Mon, Mar 23, 2020 at 10:59:14AM +0800, Tiezhu Yang wrote:
>> Implement __phys_to_dma() and __dma_to_phys() according to the
>> node id offset in the 7A1000 DMA route config register.
> Can you please try to just use the dma_pfn_offset field in struct device
> for all loongson platforms? I'm pretty sure I asked for that last time
> around..
Hi Christoph,
In the current market, the most used bridge chip on the Loongson platform
are AMD RS780E and Loongson 7A1000, the AMD RS780E is already supported by
the mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with 7A1000 on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The Loongson 7A1000 has dma_node_id_offset field in the DMA route config
register, the hardware can use the dma_node_id_offset to translate address
of node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility to
support the AMD RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Thanks,
Tiezhu Yang