diff options
Diffstat (limited to 'arch/powerpc/platforms')
93 files changed, 4214 insertions, 1484 deletions
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index f591a9fc19b9..4be6e7a17b66 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c | |||
@@ -54,7 +54,7 @@ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, | |||
54 | struct pci_controller *hose = bus->sysdata; | 54 | struct pci_controller *hose = bus->sysdata; |
55 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | 55 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) |
56 | | (((bus->number - hose->first_busno) & 0xff) << 16) | 56 | | (((bus->number - hose->first_busno) & 0xff) << 16) |
57 | | (hose->index << 24); | 57 | | (hose->global_number << 24); |
58 | int ret = -1; | 58 | int ret = -1; |
59 | int rval; | 59 | int rval; |
60 | 60 | ||
@@ -69,7 +69,7 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, | |||
69 | struct pci_controller *hose = bus->sysdata; | 69 | struct pci_controller *hose = bus->sysdata; |
70 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | 70 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) |
71 | | (((bus->number - hose->first_busno) & 0xff) << 16) | 71 | | (((bus->number - hose->first_busno) & 0xff) << 16) |
72 | | (hose->index << 24); | 72 | | (hose->global_number << 24); |
73 | int rval; | 73 | int rval; |
74 | 74 | ||
75 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, | 75 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, |
@@ -83,7 +83,7 @@ static struct pci_ops rtas_pci_ops = { | |||
83 | }; | 83 | }; |
84 | 84 | ||
85 | 85 | ||
86 | void __init efika_pcisetup(void) | 86 | static void __init efika_pcisetup(void) |
87 | { | 87 | { |
88 | const int *bus_range; | 88 | const int *bus_range; |
89 | int len; | 89 | int len; |
@@ -128,7 +128,7 @@ void __init efika_pcisetup(void) | |||
128 | printk(" controlled by %s\n", pcictrl->full_name); | 128 | printk(" controlled by %s\n", pcictrl->full_name); |
129 | printk("\n"); | 129 | printk("\n"); |
130 | 130 | ||
131 | hose = pcibios_alloc_controller(); | 131 | hose = pcibios_alloc_controller(of_node_get(pcictrl)); |
132 | if (!hose) { | 132 | if (!hose) { |
133 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | 133 | printk(KERN_WARNING EFIKA_PLATFORM_NAME |
134 | ": Can't allocate PCI controller structure for %s\n", | 134 | ": Can't allocate PCI controller structure for %s\n", |
@@ -136,7 +136,6 @@ void __init efika_pcisetup(void) | |||
136 | return; | 136 | return; |
137 | } | 137 | } |
138 | 138 | ||
139 | hose->arch_data = of_node_get(pcictrl); | ||
140 | hose->first_busno = bus_range[0]; | 139 | hose->first_busno = bus_range[0]; |
141 | hose->last_busno = bus_range[1]; | 140 | hose->last_busno = bus_range[1]; |
142 | hose->ops = &rtas_pci_ops; | 141 | hose->ops = &rtas_pci_ops; |
@@ -145,7 +144,7 @@ void __init efika_pcisetup(void) | |||
145 | } | 144 | } |
146 | 145 | ||
147 | #else | 146 | #else |
148 | void __init efika_pcisetup(void) | 147 | static void __init efika_pcisetup(void) |
149 | {} | 148 | {} |
150 | #endif | 149 | #endif |
151 | 150 | ||
@@ -252,6 +251,8 @@ define_machine(efika) | |||
252 | .progress = rtas_progress, | 251 | .progress = rtas_progress, |
253 | .get_boot_time = rtas_get_boot_time, | 252 | .get_boot_time = rtas_get_boot_time, |
254 | .calibrate_decr = generic_calibrate_decr, | 253 | .calibrate_decr = generic_calibrate_decr, |
254 | #ifdef CONFIG_PCI | ||
255 | .phys_mem_access_prot = pci_phys_mem_access_prot, | 255 | .phys_mem_access_prot = pci_phys_mem_access_prot, |
256 | #endif | ||
256 | }; | 257 | }; |
257 | 258 | ||
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 1cfc00dfb99a..5c46e898fd45 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c | |||
@@ -156,7 +156,7 @@ static void __init lite5200_setup_arch(void) | |||
156 | 156 | ||
157 | } | 157 | } |
158 | 158 | ||
159 | void lite5200_show_cpuinfo(struct seq_file *m) | 159 | static void lite5200_show_cpuinfo(struct seq_file *m) |
160 | { | 160 | { |
161 | struct device_node* np = of_find_all_nodes(NULL); | 161 | struct device_node* np = of_find_all_nodes(NULL); |
162 | const char *model = NULL; | 162 | const char *model = NULL; |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 34d34a26d305..4c6c82a684b1 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c | |||
@@ -112,18 +112,18 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, | |||
112 | u32 value; | 112 | u32 value; |
113 | 113 | ||
114 | if (ppc_md.pci_exclude_device) | 114 | if (ppc_md.pci_exclude_device) |
115 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | 115 | if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) |
116 | return PCIBIOS_DEVICE_NOT_FOUND; | 116 | return PCIBIOS_DEVICE_NOT_FOUND; |
117 | 117 | ||
118 | out_be32(hose->cfg_addr, | 118 | out_be32(hose->cfg_addr, |
119 | (1 << 31) | | 119 | (1 << 31) | |
120 | ((bus->number - hose->bus_offset) << 16) | | 120 | (bus->number << 16) | |
121 | (devfn << 8) | | 121 | (devfn << 8) | |
122 | (offset & 0xfc)); | 122 | (offset & 0xfc)); |
123 | mb(); | 123 | mb(); |
124 | 124 | ||
125 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) | 125 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) |
126 | if (bus->number != hose->bus_offset) { | 126 | if (bus->number) { |
127 | /* workaround for the bug 435 of the MPC5200 (L25R); | 127 | /* workaround for the bug 435 of the MPC5200 (L25R); |
128 | * Don't do 32 bits config access during type-1 cycles */ | 128 | * Don't do 32 bits config access during type-1 cycles */ |
129 | switch (len) { | 129 | switch (len) { |
@@ -169,18 +169,18 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, | |||
169 | u32 value, mask; | 169 | u32 value, mask; |
170 | 170 | ||
171 | if (ppc_md.pci_exclude_device) | 171 | if (ppc_md.pci_exclude_device) |
172 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | 172 | if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) |
173 | return PCIBIOS_DEVICE_NOT_FOUND; | 173 | return PCIBIOS_DEVICE_NOT_FOUND; |
174 | 174 | ||
175 | out_be32(hose->cfg_addr, | 175 | out_be32(hose->cfg_addr, |
176 | (1 << 31) | | 176 | (1 << 31) | |
177 | ((bus->number - hose->bus_offset) << 16) | | 177 | (bus->number << 16) | |
178 | (devfn << 8) | | 178 | (devfn << 8) | |
179 | (offset & 0xfc)); | 179 | (offset & 0xfc)); |
180 | mb(); | 180 | mb(); |
181 | 181 | ||
182 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) | 182 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) |
183 | if (bus->number != hose->bus_offset) { | 183 | if (bus->number) { |
184 | /* workaround for the bug 435 of the MPC5200 (L25R); | 184 | /* workaround for the bug 435 of the MPC5200 (L25R); |
185 | * Don't do 32 bits config access during type-1 cycles */ | 185 | * Don't do 32 bits config access during type-1 cycles */ |
186 | switch (len) { | 186 | switch (len) { |
@@ -385,17 +385,13 @@ mpc52xx_add_bridge(struct device_node *node) | |||
385 | * tree are needed to configure the 52xx PCI controller. Rather | 385 | * tree are needed to configure the 52xx PCI controller. Rather |
386 | * than parse the tree here, let pci_process_bridge_OF_ranges() | 386 | * than parse the tree here, let pci_process_bridge_OF_ranges() |
387 | * do it for us and extract the values after the fact */ | 387 | * do it for us and extract the values after the fact */ |
388 | hose = pcibios_alloc_controller(); | 388 | hose = pcibios_alloc_controller(node); |
389 | if (!hose) | 389 | if (!hose) |
390 | return -ENOMEM; | 390 | return -ENOMEM; |
391 | 391 | ||
392 | hose->arch_data = node; | ||
393 | hose->set_cfg_type = 1; | ||
394 | |||
395 | hose->first_busno = bus_range ? bus_range[0] : 0; | 392 | hose->first_busno = bus_range ? bus_range[0] : 0; |
396 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 393 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
397 | 394 | ||
398 | hose->bus_offset = 0; | ||
399 | hose->ops = &mpc52xx_pci_ops; | 395 | hose->ops = &mpc52xx_pci_ops; |
400 | 396 | ||
401 | pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); | 397 | pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index fd40044d16cd..ee2e7639c63e 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c | |||
@@ -9,8 +9,8 @@ | |||
9 | 9 | ||
10 | 10 | ||
11 | /* these are defined in mpc52xx_sleep.S, and only used here */ | 11 | /* these are defined in mpc52xx_sleep.S, and only used here */ |
12 | extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs, | 12 | extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs, |
13 | struct mpc52xx_cdm *, struct mpc52xx_intr *); | 13 | struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*); |
14 | extern void mpc52xx_ds_sram(void); | 14 | extern void mpc52xx_ds_sram(void); |
15 | extern const long mpc52xx_ds_sram_size; | 15 | extern const long mpc52xx_ds_sram_size; |
16 | extern void mpc52xx_ds_cached(void); | 16 | extern void mpc52xx_ds_cached(void); |
@@ -21,7 +21,7 @@ static void __iomem *sdram; | |||
21 | static struct mpc52xx_cdm __iomem *cdm; | 21 | static struct mpc52xx_cdm __iomem *cdm; |
22 | static struct mpc52xx_intr __iomem *intr; | 22 | static struct mpc52xx_intr __iomem *intr; |
23 | static struct mpc52xx_gpio_wkup __iomem *gpiow; | 23 | static struct mpc52xx_gpio_wkup __iomem *gpiow; |
24 | static void *sram; | 24 | static void __iomem *sram; |
25 | static int sram_size; | 25 | static int sram_size; |
26 | 26 | ||
27 | struct mpc52xx_suspend mpc52xx_suspend; | 27 | struct mpc52xx_suspend mpc52xx_suspend; |
@@ -100,7 +100,7 @@ int mpc52xx_pm_enter(suspend_state_t state) | |||
100 | u32 clk_enables; | 100 | u32 clk_enables; |
101 | u32 msr, hid0; | 101 | u32 msr, hid0; |
102 | u32 intr_main_mask; | 102 | u32 intr_main_mask; |
103 | void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500; | 103 | void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500; |
104 | unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size; | 104 | unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size; |
105 | char saved_0x500[mpc52xx_ds_cached_size]; | 105 | char saved_0x500[mpc52xx_ds_cached_size]; |
106 | 106 | ||
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index de7fce9cb6eb..89fde43895c5 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | choice | 1 | choice |
2 | prompt "Machine Type" | 2 | prompt "82xx Board Type" |
3 | depends on PPC_82xx | 3 | depends on PPC_82xx |
4 | default MPC82xx_ADS | 4 | default MPC82xx_ADS |
5 | 5 | ||
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 47cb09f08052..da20832b27f1 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c | |||
@@ -49,7 +49,7 @@ | |||
49 | #include <linux/fs_enet_pd.h> | 49 | #include <linux/fs_enet_pd.h> |
50 | 50 | ||
51 | #include <sysdev/fsl_soc.h> | 51 | #include <sysdev/fsl_soc.h> |
52 | #include <../sysdev/cpm2_pic.h> | 52 | #include <sysdev/cpm2_pic.h> |
53 | 53 | ||
54 | #include "pq2ads.h" | 54 | #include "pq2ads.h" |
55 | 55 | ||
@@ -507,7 +507,8 @@ void m82xx_pci_init_irq(void) | |||
507 | return; | 507 | return; |
508 | } | 508 | } |
509 | 509 | ||
510 | static int m82xx_pci_exclude_device(u_char bus, u_char devfn) | 510 | static int m82xx_pci_exclude_device(struct pci_controller *hose, |
511 | u_char bus, u_char devfn) | ||
511 | { | 512 | { |
512 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 513 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
513 | return PCIBIOS_DEVICE_NOT_FOUND; | 514 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -515,7 +516,7 @@ static int m82xx_pci_exclude_device(u_char bus, u_char devfn) | |||
515 | return PCIBIOS_SUCCESSFUL; | 516 | return PCIBIOS_SUCCESSFUL; |
516 | } | 517 | } |
517 | 518 | ||
518 | void __init add_bridge(struct device_node *np) | 519 | static void __init mpc82xx_add_bridge(struct device_node *np) |
519 | { | 520 | { |
520 | int len; | 521 | int len; |
521 | struct pci_controller *hose; | 522 | struct pci_controller *hose; |
@@ -542,19 +543,13 @@ void __init add_bridge(struct device_node *np) | |||
542 | 543 | ||
543 | pci_assign_all_buses = 1; | 544 | pci_assign_all_buses = 1; |
544 | 545 | ||
545 | hose = pcibios_alloc_controller(); | 546 | hose = pcibios_alloc_controller(np); |
546 | 547 | ||
547 | if (!hose) | 548 | if (!hose) |
548 | return; | 549 | return; |
549 | 550 | ||
550 | hose->arch_data = np; | ||
551 | hose->set_cfg_type = 1; | ||
552 | |||
553 | hose->first_busno = bus_range ? bus_range[0] : 0; | 551 | hose->first_busno = bus_range ? bus_range[0] : 0; |
554 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 552 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
555 | hose->bus_offset = 0; | ||
556 | |||
557 | hose->set_cfg_type = 1; | ||
558 | 553 | ||
559 | setup_indirect_pci(hose, | 554 | setup_indirect_pci(hose, |
560 | r.start + offsetof(pci_cpm2_t, pci_cfg_addr), | 555 | r.start + offsetof(pci_cpm2_t, pci_cfg_addr), |
@@ -584,7 +579,7 @@ static void __init mpc82xx_ads_setup_arch(void) | |||
584 | #ifdef CONFIG_PCI | 579 | #ifdef CONFIG_PCI |
585 | ppc_md.pci_exclude_device = m82xx_pci_exclude_device; | 580 | ppc_md.pci_exclude_device = m82xx_pci_exclude_device; |
586 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 581 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
587 | add_bridge(np); | 582 | mpc82xx_add_bridge(np); |
588 | 583 | ||
589 | of_node_put(np); | 584 | of_node_put(np); |
590 | #endif | 585 | #endif |
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 19cafdf6df93..ec305f18abd8 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | choice | 1 | choice |
2 | prompt "Machine Type" | 2 | prompt "83xx Board Type" |
3 | depends on PPC_83xx | 3 | depends on PPC_83xx |
4 | default MPC834x_MDS | 4 | default MPC834x_MDS |
5 | 5 | ||
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 31a91b53f528..5a98f885779f 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the PowerPC 83xx linux kernel. | 2 | # Makefile for the PowerPC 83xx linux kernel. |
3 | # | 3 | # |
4 | obj-y := misc.o | 4 | obj-y := misc.o usb.o |
5 | obj-$(CONFIG_PCI) += pci.o | 5 | obj-$(CONFIG_PCI) += pci.o |
6 | obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o | 6 | obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o |
7 | obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o | 7 | obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o |
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 96970ac887ee..3edfe170a03b 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c | |||
@@ -28,11 +28,6 @@ | |||
28 | #define DBG(fmt...) | 28 | #define DBG(fmt...) |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | #ifndef CONFIG_PCI | ||
32 | unsigned long isa_io_base = 0; | ||
33 | unsigned long isa_mem_base = 0; | ||
34 | #endif | ||
35 | |||
36 | /* ************************************************************************ | 31 | /* ************************************************************************ |
37 | * | 32 | * |
38 | * Setup the architecture | 33 | * Setup the architecture |
@@ -49,10 +44,11 @@ static void __init mpc8313_rdb_setup_arch(void) | |||
49 | 44 | ||
50 | #ifdef CONFIG_PCI | 45 | #ifdef CONFIG_PCI |
51 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 46 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
52 | add_bridge(np); | 47 | mpc83xx_add_bridge(np); |
53 | 48 | ||
54 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 49 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
55 | #endif | 50 | #endif |
51 | mpc831x_usb_cfg(); | ||
56 | } | 52 | } |
57 | 53 | ||
58 | void __init mpc8313_rdb_init_IRQ(void) | 54 | void __init mpc8313_rdb_init_IRQ(void) |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 94843ed52a93..b39cb52c6fb9 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
@@ -49,11 +49,6 @@ | |||
49 | #define DBG(fmt...) | 49 | #define DBG(fmt...) |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #ifndef CONFIG_PCI | ||
53 | unsigned long isa_io_base = 0; | ||
54 | unsigned long isa_mem_base = 0; | ||
55 | #endif | ||
56 | |||
57 | static u8 *bcsr_regs = NULL; | 52 | static u8 *bcsr_regs = NULL; |
58 | 53 | ||
59 | /* ************************************************************************ | 54 | /* ************************************************************************ |
@@ -80,7 +75,7 @@ static void __init mpc832x_sys_setup_arch(void) | |||
80 | 75 | ||
81 | #ifdef CONFIG_PCI | 76 | #ifdef CONFIG_PCI |
82 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 77 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
83 | add_bridge(np); | 78 | mpc83xx_add_bridge(np); |
84 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 79 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
85 | #endif | 80 | #endif |
86 | 81 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 3db68b73fc32..b2b28a44738c 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c | |||
@@ -32,11 +32,6 @@ | |||
32 | #define DBG(fmt...) | 32 | #define DBG(fmt...) |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | #ifndef CONFIG_PCI | ||
36 | unsigned long isa_io_base = 0; | ||
37 | unsigned long isa_mem_base = 0; | ||
38 | #endif | ||
39 | |||
40 | /* ************************************************************************ | 35 | /* ************************************************************************ |
41 | * | 36 | * |
42 | * Setup the architecture | 37 | * Setup the architecture |
@@ -53,7 +48,7 @@ static void __init mpc832x_rdb_setup_arch(void) | |||
53 | 48 | ||
54 | #ifdef CONFIG_PCI | 49 | #ifdef CONFIG_PCI |
55 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 50 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
56 | add_bridge(np); | 51 | mpc83xx_add_bridge(np); |
57 | 52 | ||
58 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 53 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
59 | #endif | 54 | #endif |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 40a01947d684..47ba5446f63c 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c | |||
@@ -38,11 +38,6 @@ | |||
38 | 38 | ||
39 | #include "mpc83xx.h" | 39 | #include "mpc83xx.h" |
40 | 40 | ||
41 | #ifndef CONFIG_PCI | ||
42 | unsigned long isa_io_base = 0; | ||
43 | unsigned long isa_mem_base = 0; | ||
44 | #endif | ||
45 | |||
46 | /* ************************************************************************ | 41 | /* ************************************************************************ |
47 | * | 42 | * |
48 | * Setup the architecture | 43 | * Setup the architecture |
@@ -59,10 +54,12 @@ static void __init mpc834x_itx_setup_arch(void) | |||
59 | 54 | ||
60 | #ifdef CONFIG_PCI | 55 | #ifdef CONFIG_PCI |
61 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 56 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
62 | add_bridge(np); | 57 | mpc83xx_add_bridge(np); |
63 | 58 | ||
64 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 59 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
65 | #endif | 60 | #endif |
61 | |||
62 | mpc834x_usb_cfg(); | ||
66 | } | 63 | } |
67 | 64 | ||
68 | static void __init mpc834x_itx_init_IRQ(void) | 65 | static void __init mpc834x_itx_init_IRQ(void) |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 10394b2d7e7a..4c9ff9cadfe4 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c | |||
@@ -38,61 +38,17 @@ | |||
38 | 38 | ||
39 | #include "mpc83xx.h" | 39 | #include "mpc83xx.h" |
40 | 40 | ||
41 | #ifndef CONFIG_PCI | ||
42 | unsigned long isa_io_base = 0; | ||
43 | unsigned long isa_mem_base = 0; | ||
44 | #endif | ||
45 | |||
46 | #define BCSR5_INT_USB 0x02 | 41 | #define BCSR5_INT_USB 0x02 |
47 | /* Note: This is only for PB, not for PB+PIB | 42 | static int mpc834xemds_usb_cfg(void) |
48 | * On PB only port0 is connected using ULPI */ | ||
49 | static int mpc834x_usb_cfg(void) | ||
50 | { | 43 | { |
51 | unsigned long sccr, sicrl; | 44 | struct device_node *np; |
52 | void __iomem *immap; | ||
53 | void __iomem *bcsr_regs = NULL; | 45 | void __iomem *bcsr_regs = NULL; |
54 | u8 bcsr5; | 46 | u8 bcsr5; |
55 | struct device_node *np = NULL; | ||
56 | int port0_is_dr = 0; | ||
57 | |||
58 | if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr")) != NULL) | ||
59 | port0_is_dr = 1; | ||
60 | if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph")) != NULL){ | ||
61 | if (port0_is_dr) { | ||
62 | printk(KERN_WARNING | ||
63 | "There is only one USB port on PB board! \n"); | ||
64 | return -1; | ||
65 | } else if (!port0_is_dr) | ||
66 | /* No usb port enabled */ | ||
67 | return -1; | ||
68 | } | ||
69 | |||
70 | immap = ioremap(get_immrbase(), 0x1000); | ||
71 | if (!immap) | ||
72 | return -1; | ||
73 | |||
74 | /* Configure clock */ | ||
75 | sccr = in_be32(immap + MPC83XX_SCCR_OFFS); | ||
76 | if (port0_is_dr) | ||
77 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
78 | else | ||
79 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ | ||
80 | out_be32(immap + MPC83XX_SCCR_OFFS, sccr); | ||
81 | |||
82 | /* Configure Pin */ | ||
83 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS); | ||
84 | /* set port0 only */ | ||
85 | if (port0_is_dr) | ||
86 | sicrl |= MPC83XX_SICRL_USB0; | ||
87 | else | ||
88 | sicrl &= ~(MPC83XX_SICRL_USB0); | ||
89 | out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); | ||
90 | |||
91 | iounmap(immap); | ||
92 | 47 | ||
48 | mpc834x_usb_cfg(); | ||
93 | /* Map BCSR area */ | 49 | /* Map BCSR area */ |
94 | np = of_find_node_by_name(NULL, "bcsr"); | 50 | np = of_find_node_by_name(NULL, "bcsr"); |
95 | if (np != 0) { | 51 | if (np) { |
96 | struct resource res; | 52 | struct resource res; |
97 | 53 | ||
98 | of_address_to_resource(np, 0, &res); | 54 | of_address_to_resource(np, 0, &res); |
@@ -129,12 +85,12 @@ static void __init mpc834x_mds_setup_arch(void) | |||
129 | 85 | ||
130 | #ifdef CONFIG_PCI | 86 | #ifdef CONFIG_PCI |
131 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 87 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
132 | add_bridge(np); | 88 | mpc83xx_add_bridge(np); |
133 | 89 | ||
134 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 90 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
135 | #endif | 91 | #endif |
136 | 92 | ||
137 | mpc834x_usb_cfg(); | 93 | mpc834xemds_usb_cfg(); |
138 | } | 94 | } |
139 | 95 | ||
140 | static void __init mpc834x_mds_init_IRQ(void) | 96 | static void __init mpc834x_mds_init_IRQ(void) |
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index bceeff8bbfd2..0e615fd65c1f 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c | |||
@@ -55,11 +55,6 @@ | |||
55 | #define DBG(fmt...) | 55 | #define DBG(fmt...) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | #ifndef CONFIG_PCI | ||
59 | unsigned long isa_io_base = 0; | ||
60 | unsigned long isa_mem_base = 0; | ||
61 | #endif | ||
62 | |||
63 | static u8 *bcsr_regs = NULL; | 58 | static u8 *bcsr_regs = NULL; |
64 | 59 | ||
65 | /* ************************************************************************ | 60 | /* ************************************************************************ |
@@ -86,7 +81,7 @@ static void __init mpc836x_mds_setup_arch(void) | |||
86 | 81 | ||
87 | #ifdef CONFIG_PCI | 82 | #ifdef CONFIG_PCI |
88 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 83 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
89 | add_bridge(np); | 84 | mpc83xx_add_bridge(np); |
90 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 85 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
91 | #endif | 86 | #endif |
92 | 87 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 9cd03b59c8f4..589ee55730f3 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h | |||
@@ -3,9 +3,11 @@ | |||
3 | 3 | ||
4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <asm/pci-bridge.h> | ||
6 | 7 | ||
7 | /* System Clock Control Register */ | 8 | /* System Clock Control Register */ |
8 | #define MPC83XX_SCCR_OFFS 0xA08 | 9 | #define MPC83XX_SCCR_OFFS 0xA08 |
10 | #define MPC83XX_SCCR_USB_MASK 0x00f00000 | ||
9 | #define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000 | 11 | #define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000 |
10 | #define MPC83XX_SCCR_USB_MPHCM_01 0x00400000 | 12 | #define MPC83XX_SCCR_USB_MPHCM_01 0x00400000 |
11 | #define MPC83XX_SCCR_USB_MPHCM_10 0x00800000 | 13 | #define MPC83XX_SCCR_USB_MPHCM_10 0x00800000 |
@@ -15,21 +17,43 @@ | |||
15 | 17 | ||
16 | /* system i/o configuration register low */ | 18 | /* system i/o configuration register low */ |
17 | #define MPC83XX_SICRL_OFFS 0x114 | 19 | #define MPC83XX_SICRL_OFFS 0x114 |
18 | #define MPC83XX_SICRL_USB0 0x40000000 | 20 | #define MPC834X_SICRL_USB_MASK 0x60000000 |
19 | #define MPC83XX_SICRL_USB1 0x20000000 | 21 | #define MPC834X_SICRL_USB0 0x40000000 |
22 | #define MPC834X_SICRL_USB1 0x20000000 | ||
23 | #define MPC831X_SICRL_USB_MASK 0x00000c00 | ||
24 | #define MPC831X_SICRL_USB_ULPI 0x00000800 | ||
20 | 25 | ||
21 | /* system i/o configuration register high */ | 26 | /* system i/o configuration register high */ |
22 | #define MPC83XX_SICRH_OFFS 0x118 | 27 | #define MPC83XX_SICRH_OFFS 0x118 |
23 | #define MPC83XX_SICRH_USB_UTMI 0x00020000 | 28 | #define MPC834X_SICRH_USB_UTMI 0x00020000 |
29 | #define MPC831X_SICRH_USB_MASK 0x000000e0 | ||
30 | #define MPC831X_SICRH_USB_ULPI 0x000000a0 | ||
31 | |||
32 | /* USB Control Register */ | ||
33 | #define FSL_USB2_CONTROL_OFFS 0x500 | ||
34 | #define CONTROL_UTMI_PHY_EN 0x00000200 | ||
35 | #define CONTROL_REFSEL_48MHZ 0x00000080 | ||
36 | #define CONTROL_PHY_CLK_SEL_ULPI 0x00000400 | ||
37 | #define CONTROL_OTG_PORT 0x00000020 | ||
38 | |||
39 | /* USB PORTSC Registers */ | ||
40 | #define FSL_USB2_PORTSC1_OFFS 0x184 | ||
41 | #define FSL_USB2_PORTSC2_OFFS 0x188 | ||
42 | #define PORTSCX_PTW_16BIT 0x10000000 | ||
43 | #define PORTSCX_PTS_UTMI 0x00000000 | ||
44 | #define PORTSCX_PTS_ULPI 0x80000000 | ||
24 | 45 | ||
25 | /* | 46 | /* |
26 | * Declaration for the various functions exported by the | 47 | * Declaration for the various functions exported by the |
27 | * mpc83xx_* files. Mostly for use by mpc83xx_setup | 48 | * mpc83xx_* files. Mostly for use by mpc83xx_setup |
28 | */ | 49 | */ |
29 | 50 | ||
30 | extern int add_bridge(struct device_node *dev); | 51 | extern int mpc83xx_add_bridge(struct device_node *dev); |
31 | extern int mpc83xx_exclude_device(u_char bus, u_char devfn); | 52 | extern int mpc83xx_exclude_device(struct pci_controller *hose, |
53 | u_char bus, u_char devfn); | ||
32 | extern void mpc83xx_restart(char *cmd); | 54 | extern void mpc83xx_restart(char *cmd); |
33 | extern long mpc83xx_time_init(void); | 55 | extern long mpc83xx_time_init(void); |
56 | extern int mpc834x_usb_cfg(void); | ||
57 | extern int mpc831x_usb_cfg(void); | ||
34 | 58 | ||
35 | #endif /* __MPC83XX_H__ */ | 59 | #endif /* __MPC83XX_H__ */ |
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 774457d09e94..c0e2b89154e5 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c | |||
@@ -33,19 +33,14 @@ | |||
33 | #define DBG(x...) | 33 | #define DBG(x...) |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | int mpc83xx_pci2_busno; | 36 | int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) |
37 | |||
38 | int mpc83xx_exclude_device(u_char bus, u_char devfn) | ||
39 | { | 37 | { |
40 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 38 | if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) |
41 | return PCIBIOS_DEVICE_NOT_FOUND; | 39 | return PCIBIOS_DEVICE_NOT_FOUND; |
42 | if (mpc83xx_pci2_busno) | ||
43 | if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0) | ||
44 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
45 | return PCIBIOS_SUCCESSFUL; | 40 | return PCIBIOS_SUCCESSFUL; |
46 | } | 41 | } |
47 | 42 | ||
48 | int __init add_bridge(struct device_node *dev) | 43 | int __init mpc83xx_add_bridge(struct device_node *dev) |
49 | { | 44 | { |
50 | int len; | 45 | int len; |
51 | struct pci_controller *hose; | 46 | struct pci_controller *hose; |
@@ -66,11 +61,10 @@ int __init add_bridge(struct device_node *dev) | |||
66 | " bus 0\n", dev->full_name); | 61 | " bus 0\n", dev->full_name); |
67 | } | 62 | } |
68 | 63 | ||
69 | hose = pcibios_alloc_controller(); | 64 | pci_assign_all_buses = 1; |
65 | hose = pcibios_alloc_controller(dev); | ||
70 | if (!hose) | 66 | if (!hose) |
71 | return -ENOMEM; | 67 | return -ENOMEM; |
72 | hose->arch_data = dev; | ||
73 | hose->set_cfg_type = 1; | ||
74 | 68 | ||
75 | hose->first_busno = bus_range ? bus_range[0] : 0; | 69 | hose->first_busno = bus_range ? bus_range[0] : 0; |
76 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 70 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
@@ -86,8 +80,6 @@ int __init add_bridge(struct device_node *dev) | |||
86 | if ((rsrc.start & 0xfffff) == 0x8600) { | 80 | if ((rsrc.start & 0xfffff) == 0x8600) { |
87 | setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384); | 81 | setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384); |
88 | primary = 0; | 82 | primary = 0; |
89 | hose->bus_offset = hose->first_busno; | ||
90 | mpc83xx_pci2_busno = hose->first_busno; | ||
91 | } | 83 | } |
92 | 84 | ||
93 | printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " | 85 | printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " |
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c new file mode 100644 index 000000000000..e7fdf013cd39 --- /dev/null +++ b/arch/powerpc/platforms/83xx/usb.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Freescale 83xx USB SOC setup code | ||
3 | * | ||
4 | * Copyright (C) 2007 Freescale Semiconductor, Inc. | ||
5 | * Author: Li Yang | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | |||
14 | #include <linux/stddef.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | |||
18 | #include <asm/io.h> | ||
19 | #include <asm/prom.h> | ||
20 | #include <sysdev/fsl_soc.h> | ||
21 | |||
22 | #include "mpc83xx.h" | ||
23 | |||
24 | |||
25 | #ifdef CONFIG_MPC834x | ||
26 | int mpc834x_usb_cfg(void) | ||
27 | { | ||
28 | unsigned long sccr, sicrl, sicrh; | ||
29 | void __iomem *immap; | ||
30 | struct device_node *np = NULL; | ||
31 | int port0_is_dr = 0, port1_is_dr = 0; | ||
32 | const void *prop, *dr_mode; | ||
33 | |||
34 | immap = ioremap(get_immrbase(), 0x1000); | ||
35 | if (!immap) | ||
36 | return -ENOMEM; | ||
37 | |||
38 | /* Read registers */ | ||
39 | /* Note: DR and MPH must use the same clock setting in SCCR */ | ||
40 | sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK; | ||
41 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; | ||
42 | sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; | ||
43 | |||
44 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | ||
45 | if (np) { | ||
46 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
47 | |||
48 | prop = of_get_property(np, "phy_type", NULL); | ||
49 | if (prop && (!strcmp(prop, "utmi") || | ||
50 | !strcmp(prop, "utmi_wide"))) { | ||
51 | sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; | ||
52 | sicrh |= MPC834X_SICRH_USB_UTMI; | ||
53 | port1_is_dr = 1; | ||
54 | } else if (prop && !strcmp(prop, "serial")) { | ||
55 | dr_mode = of_get_property(np, "dr_mode", NULL); | ||
56 | if (dr_mode && !strcmp(dr_mode, "otg")) { | ||
57 | sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; | ||
58 | port1_is_dr = 1; | ||
59 | } else { | ||
60 | sicrl |= MPC834X_SICRL_USB0; | ||
61 | } | ||
62 | } else if (prop && !strcmp(prop, "ulpi")) { | ||
63 | sicrl |= MPC834X_SICRL_USB0; | ||
64 | } else { | ||
65 | printk(KERN_WARNING "834x USB PHY type not supported\n"); | ||
66 | } | ||
67 | port0_is_dr = 1; | ||
68 | of_node_put(np); | ||
69 | } | ||
70 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph"); | ||
71 | if (np) { | ||
72 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ | ||
73 | |||
74 | prop = of_get_property(np, "port0", NULL); | ||
75 | if (prop) { | ||
76 | if (port0_is_dr) | ||
77 | printk(KERN_WARNING | ||
78 | "834x USB port0 can't be used by both DR and MPH!\n"); | ||
79 | sicrl |= MPC834X_SICRL_USB0; | ||
80 | } | ||
81 | prop = of_get_property(np, "port1", NULL); | ||
82 | if (prop) { | ||
83 | if (port1_is_dr) | ||
84 | printk(KERN_WARNING | ||
85 | "834x USB port1 can't be used by both DR and MPH!\n"); | ||
86 | sicrl |= MPC834X_SICRL_USB1; | ||
87 | } | ||
88 | of_node_put(np); | ||
89 | } | ||
90 | |||
91 | /* Write back */ | ||
92 | out_be32(immap + MPC83XX_SCCR_OFFS, sccr); | ||
93 | out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); | ||
94 | out_be32(immap + MPC83XX_SICRH_OFFS, sicrh); | ||
95 | |||
96 | iounmap(immap); | ||
97 | return 0; | ||
98 | } | ||
99 | #endif /* CONFIG_MPC834x */ | ||
100 | |||
101 | #ifdef CONFIG_PPC_MPC831x | ||
102 | int mpc831x_usb_cfg(void) | ||
103 | { | ||
104 | u32 temp; | ||
105 | void __iomem *immap, *usb_regs; | ||
106 | struct device_node *np = NULL; | ||
107 | const void *prop; | ||
108 | struct resource res; | ||
109 | int ret = 0; | ||
110 | #ifdef CONFIG_USB_OTG | ||
111 | const void *dr_mode; | ||
112 | #endif | ||
113 | |||
114 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | ||
115 | if (!np) | ||
116 | return -ENODEV; | ||
117 | prop = of_get_property(np, "phy_type", NULL); | ||
118 | |||
119 | /* Map IMMR space for pin and clock settings */ | ||
120 | immap = ioremap(get_immrbase(), 0x1000); | ||
121 | if (!immap) { | ||
122 | of_node_put(np); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | |||
126 | /* Configure clock */ | ||
127 | temp = in_be32(immap + MPC83XX_SCCR_OFFS); | ||
128 | temp &= ~MPC83XX_SCCR_USB_MASK; | ||
129 | temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
130 | out_be32(immap + MPC83XX_SCCR_OFFS, temp); | ||
131 | |||
132 | /* Configure pin mux for ULPI. There is no pin mux for UTMI */ | ||
133 | if (!strcmp(prop, "ulpi")) { | ||
134 | temp = in_be32(immap + MPC83XX_SICRL_OFFS); | ||
135 | temp &= ~MPC831X_SICRL_USB_MASK; | ||
136 | temp |= MPC831X_SICRL_USB_ULPI; | ||
137 | out_be32(immap + MPC83XX_SICRL_OFFS, temp); | ||
138 | |||
139 | temp = in_be32(immap + MPC83XX_SICRH_OFFS); | ||
140 | temp &= ~MPC831X_SICRH_USB_MASK; | ||
141 | temp |= MPC831X_SICRH_USB_ULPI; | ||
142 | out_be32(immap + MPC83XX_SICRH_OFFS, temp); | ||
143 | } | ||
144 | |||
145 | iounmap(immap); | ||
146 | |||
147 | /* Map USB SOC space */ | ||
148 | ret = of_address_to_resource(np, 0, &res); | ||
149 | if (ret) { | ||
150 | of_node_put(np); | ||
151 | return ret; | ||
152 | } | ||
153 | usb_regs = ioremap(res.start, res.end - res.start + 1); | ||
154 | |||
155 | /* Using on-chip PHY */ | ||
156 | if (!strcmp(prop, "utmi_wide") || | ||
157 | !strcmp(prop, "utmi")) { | ||
158 | /* Set UTMI_PHY_EN, REFSEL to 48MHZ */ | ||
159 | out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, | ||
160 | CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ); | ||
161 | /* Using external UPLI PHY */ | ||
162 | } else if (!strcmp(prop, "ulpi")) { | ||
163 | /* Set PHY_CLK_SEL to ULPI */ | ||
164 | temp = CONTROL_PHY_CLK_SEL_ULPI; | ||
165 | #ifdef CONFIG_USB_OTG | ||
166 | /* Set OTG_PORT */ | ||
167 | dr_mode = of_get_property(np, "dr_mode", NULL); | ||
168 | if (dr_mode && !strcmp(dr_mode, "otg")) | ||
169 | temp |= CONTROL_OTG_PORT; | ||
170 | #endif /* CONFIG_USB_OTG */ | ||
171 | out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp); | ||
172 | } else { | ||
173 | printk(KERN_WARNING "831x USB PHY type not supported\n"); | ||
174 | ret = -EINVAL; | ||
175 | } | ||
176 | |||
177 | iounmap(usb_regs); | ||
178 | of_node_put(np); | ||
179 | return ret; | ||
180 | } | ||
181 | #endif /* CONFIG_PPC_MPC831x */ | ||
diff --git a/arch/powerpc/platforms/85xx/misc.c b/arch/powerpc/platforms/85xx/misc.c index 3e62fcb04c1c..4fe376e9c3b6 100644 --- a/arch/powerpc/platforms/85xx/misc.c +++ b/arch/powerpc/platforms/85xx/misc.c | |||
@@ -13,11 +13,43 @@ | |||
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <asm/irq.h> | 15 | #include <asm/irq.h> |
16 | #include <asm/io.h> | ||
17 | #include <asm/prom.h> | ||
18 | #include <sysdev/fsl_soc.h> | ||
19 | |||
20 | static __be32 __iomem *rstcr; | ||
16 | 21 | ||
17 | extern void abort(void); | 22 | extern void abort(void); |
18 | 23 | ||
24 | static int __init mpc85xx_rstcr(void) | ||
25 | { | ||
26 | struct device_node *np; | ||
27 | np = of_find_node_by_name(NULL, "global-utilities"); | ||
28 | if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { | ||
29 | const u32 *prop = of_get_property(np, "reg", NULL); | ||
30 | if (prop) { | ||
31 | /* map reset control register | ||
32 | * 0xE00B0 is offset of reset control register | ||
33 | */ | ||
34 | rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); | ||
35 | if (!rstcr) | ||
36 | printk (KERN_EMERG "Error: reset control " | ||
37 | "register not mapped!\n"); | ||
38 | } | ||
39 | } else | ||
40 | printk (KERN_INFO "rstcr compatible register does not exist!\n"); | ||
41 | if (np) | ||
42 | of_node_put(np); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | arch_initcall(mpc85xx_rstcr); | ||
47 | |||
19 | void mpc85xx_restart(char *cmd) | 48 | void mpc85xx_restart(char *cmd) |
20 | { | 49 | { |
21 | local_irq_disable(); | 50 | local_irq_disable(); |
51 | if (rstcr) | ||
52 | /* set reset control register */ | ||
53 | out_be32(rstcr, 0x2); /* HRESET_REQ */ | ||
22 | abort(); | 54 | abort(); |
23 | } | 55 | } |
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c index bec84ffe708e..6fb90aab879f 100644 --- a/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c | |||
@@ -61,24 +61,11 @@ void __init mpc8544_ds_pic_init(void) | |||
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | 63 | ||
64 | /* Alloc mpic structure and per isu has 16 INT entries. */ | ||
65 | mpic = mpic_alloc(np, r.start, | 64 | mpic = mpic_alloc(np, r.start, |
66 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 65 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, |
67 | 16, 64, " OPENPIC "); | 66 | 0, 256, " OpenPIC "); |
68 | BUG_ON(mpic == NULL); | 67 | BUG_ON(mpic == NULL); |
69 | 68 | ||
70 | /* | ||
71 | * 48 Internal Interrupts | ||
72 | */ | ||
73 | mpic_assign_isu(mpic, 0, r.start + 0x10200); | ||
74 | mpic_assign_isu(mpic, 1, r.start + 0x10400); | ||
75 | mpic_assign_isu(mpic, 2, r.start + 0x10600); | ||
76 | |||
77 | /* | ||
78 | * 16 External interrupts | ||
79 | */ | ||
80 | mpic_assign_isu(mpic, 3, r.start + 0x10000); | ||
81 | |||
82 | mpic_init(mpic); | 69 | mpic_init(mpic); |
83 | 70 | ||
84 | #ifdef CONFIG_PPC_I8259 | 71 | #ifdef CONFIG_PPC_I8259 |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index 83415db33378..7286ffac2c1d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h | |||
@@ -15,4 +15,4 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | extern void mpc85xx_restart(char *); | 17 | extern void mpc85xx_restart(char *); |
18 | extern int add_bridge(struct device_node *dev); | 18 | extern int mpc85xx_add_bridge(struct device_node *dev); |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 5d27621f0927..7235f702394c 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
@@ -38,13 +38,9 @@ | |||
38 | #include <asm/fs_pd.h> | 38 | #include <asm/fs_pd.h> |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | #ifndef CONFIG_PCI | ||
42 | unsigned long isa_io_base = 0; | ||
43 | unsigned long isa_mem_base = 0; | ||
44 | #endif | ||
45 | |||
46 | #ifdef CONFIG_PCI | 41 | #ifdef CONFIG_PCI |
47 | static int mpc85xx_exclude_device(u_char bus, u_char devfn) | 42 | static int mpc85xx_exclude_device(struct pci_controller *hose, |
43 | u_char bus, u_char devfn) | ||
48 | { | 44 | { |
49 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 45 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
50 | return PCIBIOS_DEVICE_NOT_FOUND; | 46 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -91,30 +87,10 @@ static void __init mpc85xx_ads_pic_init(void) | |||
91 | 87 | ||
92 | mpic = mpic_alloc(np, r.start, | 88 | mpic = mpic_alloc(np, r.start, |
93 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 89 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, |
94 | 4, 0, " OpenPIC "); | 90 | 0, 256, " OpenPIC "); |
95 | BUG_ON(mpic == NULL); | 91 | BUG_ON(mpic == NULL); |
96 | of_node_put(np); | 92 | of_node_put(np); |
97 | 93 | ||
98 | mpic_assign_isu(mpic, 0, r.start + 0x10200); | ||
99 | mpic_assign_isu(mpic, 1, r.start + 0x10280); | ||
100 | mpic_assign_isu(mpic, 2, r.start + 0x10300); | ||
101 | mpic_assign_isu(mpic, 3, r.start + 0x10380); | ||
102 | mpic_assign_isu(mpic, 4, r.start + 0x10400); | ||
103 | mpic_assign_isu(mpic, 5, r.start + 0x10480); | ||
104 | mpic_assign_isu(mpic, 6, r.start + 0x10500); | ||
105 | mpic_assign_isu(mpic, 7, r.start + 0x10580); | ||
106 | |||
107 | /* Unused on this platform (leave room for 8548) */ | ||
108 | mpic_assign_isu(mpic, 8, r.start + 0x10600); | ||
109 | mpic_assign_isu(mpic, 9, r.start + 0x10680); | ||
110 | mpic_assign_isu(mpic, 10, r.start + 0x10700); | ||
111 | mpic_assign_isu(mpic, 11, r.start + 0x10780); | ||
112 | |||
113 | /* External Interrupts */ | ||
114 | mpic_assign_isu(mpic, 12, r.start + 0x10000); | ||
115 | mpic_assign_isu(mpic, 13, r.start + 0x10080); | ||
116 | mpic_assign_isu(mpic, 14, r.start + 0x10100); | ||
117 | |||
118 | mpic_init(mpic); | 94 | mpic_init(mpic); |
119 | 95 | ||
120 | #ifdef CONFIG_CPM2 | 96 | #ifdef CONFIG_CPM2 |
@@ -241,7 +217,7 @@ static void __init mpc85xx_ads_setup_arch(void) | |||
241 | 217 | ||
242 | #ifdef CONFIG_PCI | 218 | #ifdef CONFIG_PCI |
243 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 219 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
244 | add_bridge(np); | 220 | mpc85xx_add_bridge(np); |
245 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; | 221 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; |
246 | #endif | 222 | #endif |
247 | } | 223 | } |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 1490eb3ce0d3..50c8d6458362 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c | |||
@@ -47,11 +47,6 @@ | |||
47 | #include <sysdev/fsl_soc.h> | 47 | #include <sysdev/fsl_soc.h> |
48 | #include "mpc85xx.h" | 48 | #include "mpc85xx.h" |
49 | 49 | ||
50 | #ifndef CONFIG_PCI | ||
51 | unsigned long isa_io_base = 0; | ||
52 | unsigned long isa_mem_base = 0; | ||
53 | #endif | ||
54 | |||
55 | static int cds_pci_slot = 2; | 50 | static int cds_pci_slot = 2; |
56 | static volatile u8 *cadmus; | 51 | static volatile u8 *cadmus; |
57 | 52 | ||
@@ -60,15 +55,11 @@ static volatile u8 *cadmus; | |||
60 | #define ARCADIA_HOST_BRIDGE_IDSEL 17 | 55 | #define ARCADIA_HOST_BRIDGE_IDSEL 17 |
61 | #define ARCADIA_2ND_BRIDGE_IDSEL 3 | 56 | #define ARCADIA_2ND_BRIDGE_IDSEL 3 |
62 | 57 | ||
63 | extern int mpc85xx_pci2_busno; | 58 | static int mpc85xx_exclude_device(struct pci_controller *hose, |
64 | 59 | u_char bus, u_char devfn) | |
65 | static int mpc85xx_exclude_device(u_char bus, u_char devfn) | ||
66 | { | 60 | { |
67 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 61 | if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) |
68 | return PCIBIOS_DEVICE_NOT_FOUND; | 62 | return PCIBIOS_DEVICE_NOT_FOUND; |
69 | if (mpc85xx_pci2_busno) | ||
70 | if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0) | ||
71 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
72 | /* We explicitly do not go past the Tundra 320 Bridge */ | 63 | /* We explicitly do not go past the Tundra 320 Bridge */ |
73 | if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) | 64 | if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) |
74 | return PCIBIOS_DEVICE_NOT_FOUND; | 65 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -78,52 +69,44 @@ static int mpc85xx_exclude_device(u_char bus, u_char devfn) | |||
78 | return PCIBIOS_SUCCESSFUL; | 69 | return PCIBIOS_SUCCESSFUL; |
79 | } | 70 | } |
80 | 71 | ||
81 | static void __init mpc85xx_cds_pcibios_fixup(void) | 72 | static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) |
82 | { | 73 | { |
83 | struct pci_dev *dev; | 74 | u_char c; |
84 | u_char c; | 75 | if (dev->vendor == PCI_VENDOR_ID_VIA) { |
85 | 76 | switch (dev->device) { | |
86 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, | 77 | case PCI_DEVICE_ID_VIA_82C586_1: |
87 | PCI_DEVICE_ID_VIA_82C586_1, NULL))) { | 78 | /* |
79 | * U-Boot does not set the enable bits | ||
80 | * for the IDE device. Force them on here. | ||
81 | */ | ||
82 | pci_read_config_byte(dev, 0x40, &c); | ||
83 | c |= 0x03; /* IDE: Chip Enable Bits */ | ||
84 | pci_write_config_byte(dev, 0x40, c); | ||
85 | |||
86 | /* | ||
87 | * Since only primary interface works, force the | ||
88 | * IDE function to standard primary IDE interrupt | ||
89 | * w/ 8259 offset | ||
90 | */ | ||
91 | dev->irq = 14; | ||
92 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
93 | break; | ||
88 | /* | 94 | /* |
89 | * U-Boot does not set the enable bits | 95 | * Force legacy USB interrupt routing |
90 | * for the IDE device. Force them on here. | ||
91 | */ | 96 | */ |
92 | pci_read_config_byte(dev, 0x40, &c); | 97 | case PCI_DEVICE_ID_VIA_82C586_2: |
93 | c |= 0x03; /* IDE: Chip Enable Bits */ | 98 | /* There are two USB controllers. |
94 | pci_write_config_byte(dev, 0x40, c); | 99 | * Identify them by functon number |
95 | |||
96 | /* | ||
97 | * Since only primary interface works, force the | ||
98 | * IDE function to standard primary IDE interrupt | ||
99 | * w/ 8259 offset | ||
100 | */ | 100 | */ |
101 | dev->irq = 14; | 101 | if (PCI_FUNC(dev->devfn)) |
102 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | 102 | dev->irq = 11; |
103 | pci_dev_put(dev); | 103 | else |
104 | } | 104 | dev->irq = 10; |
105 | 105 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | |
106 | /* | 106 | default: |
107 | * Force legacy USB interrupt routing | 107 | break; |
108 | */ | 108 | } |
109 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, | ||
110 | PCI_DEVICE_ID_VIA_82C586_2, NULL))) { | ||
111 | dev->irq = 10; | ||
112 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); | ||
113 | pci_dev_put(dev); | ||
114 | } | ||
115 | |||
116 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, | ||
117 | PCI_DEVICE_ID_VIA_82C586_2, dev))) { | ||
118 | dev->irq = 11; | ||
119 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); | ||
120 | pci_dev_put(dev); | ||
121 | } | 109 | } |
122 | |||
123 | /* Now map all the PCI irqs */ | ||
124 | dev = NULL; | ||
125 | for_each_pci_dev(dev) | ||
126 | pci_read_irq_line(dev); | ||
127 | } | 110 | } |
128 | 111 | ||
129 | #ifdef CONFIG_PPC_I8259 | 112 | #ifdef CONFIG_PPC_I8259 |
@@ -165,33 +148,12 @@ static void __init mpc85xx_cds_pic_init(void) | |||
165 | 148 | ||
166 | mpic = mpic_alloc(np, r.start, | 149 | mpic = mpic_alloc(np, r.start, |
167 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 150 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, |
168 | 4, 0, " OpenPIC "); | 151 | 0, 256, " OpenPIC "); |
169 | BUG_ON(mpic == NULL); | 152 | BUG_ON(mpic == NULL); |
170 | 153 | ||
171 | /* Return the mpic node */ | 154 | /* Return the mpic node */ |
172 | of_node_put(np); | 155 | of_node_put(np); |
173 | 156 | ||
174 | mpic_assign_isu(mpic, 0, r.start + 0x10200); | ||
175 | mpic_assign_isu(mpic, 1, r.start + 0x10280); | ||
176 | mpic_assign_isu(mpic, 2, r.start + 0x10300); | ||
177 | mpic_assign_isu(mpic, 3, r.start + 0x10380); | ||
178 | mpic_assign_isu(mpic, 4, r.start + 0x10400); | ||
179 | mpic_assign_isu(mpic, 5, r.start + 0x10480); | ||
180 | mpic_assign_isu(mpic, 6, r.start + 0x10500); | ||
181 | mpic_assign_isu(mpic, 7, r.start + 0x10580); | ||
182 | |||
183 | /* Used only for 8548 so far, but no harm in | ||
184 | * allocating them for everyone */ | ||
185 | mpic_assign_isu(mpic, 8, r.start + 0x10600); | ||
186 | mpic_assign_isu(mpic, 9, r.start + 0x10680); | ||
187 | mpic_assign_isu(mpic, 10, r.start + 0x10700); | ||
188 | mpic_assign_isu(mpic, 11, r.start + 0x10780); | ||
189 | |||
190 | /* External Interrupts */ | ||
191 | mpic_assign_isu(mpic, 12, r.start + 0x10000); | ||
192 | mpic_assign_isu(mpic, 13, r.start + 0x10080); | ||
193 | mpic_assign_isu(mpic, 14, r.start + 0x10100); | ||
194 | |||
195 | mpic_init(mpic); | 157 | mpic_init(mpic); |
196 | 158 | ||
197 | #ifdef CONFIG_PPC_I8259 | 159 | #ifdef CONFIG_PPC_I8259 |
@@ -257,9 +219,9 @@ static void __init mpc85xx_cds_setup_arch(void) | |||
257 | 219 | ||
258 | #ifdef CONFIG_PCI | 220 | #ifdef CONFIG_PCI |
259 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 221 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
260 | add_bridge(np); | 222 | mpc85xx_add_bridge(np); |
261 | 223 | ||
262 | ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; | 224 | ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; |
263 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; | 225 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; |
264 | #endif | 226 | #endif |
265 | } | 227 | } |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index e3dddbfe66ff..004b80bd0b84 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -59,11 +59,6 @@ | |||
59 | #define DBG(fmt...) | 59 | #define DBG(fmt...) |
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | #ifndef CONFIG_PCI | ||
63 | unsigned long isa_io_base = 0; | ||
64 | unsigned long isa_mem_base = 0; | ||
65 | #endif | ||
66 | |||
67 | /* ************************************************************************ | 62 | /* ************************************************************************ |
68 | * | 63 | * |
69 | * Setup the architecture | 64 | * Setup the architecture |
@@ -100,7 +95,7 @@ static void __init mpc85xx_mds_setup_arch(void) | |||
100 | 95 | ||
101 | #ifdef CONFIG_PCI | 96 | #ifdef CONFIG_PCI |
102 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { | 97 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { |
103 | add_bridge(np); | 98 | mpc85xx_add_bridge(np); |
104 | } | 99 | } |
105 | of_node_put(np); | 100 | of_node_put(np); |
106 | #endif | 101 | #endif |
@@ -181,29 +176,10 @@ static void __init mpc85xx_mds_pic_init(void) | |||
181 | 176 | ||
182 | mpic = mpic_alloc(np, r.start, | 177 | mpic = mpic_alloc(np, r.start, |
183 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 178 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, |
184 | 4, 0, " OpenPIC "); | 179 | 0, 256, " OpenPIC "); |
185 | BUG_ON(mpic == NULL); | 180 | BUG_ON(mpic == NULL); |
186 | of_node_put(np); | 181 | of_node_put(np); |
187 | 182 | ||
188 | /* Internal Interrupts */ | ||
189 | mpic_assign_isu(mpic, 0, r.start + 0x10200); | ||
190 | mpic_assign_isu(mpic, 1, r.start + 0x10280); | ||
191 | mpic_assign_isu(mpic, 2, r.start + 0x10300); | ||
192 | mpic_assign_isu(mpic, 3, r.start + 0x10380); | ||
193 | mpic_assign_isu(mpic, 4, r.start + 0x10400); | ||
194 | mpic_assign_isu(mpic, 5, r.start + 0x10480); | ||
195 | mpic_assign_isu(mpic, 6, r.start + 0x10500); | ||
196 | mpic_assign_isu(mpic, 7, r.start + 0x10580); | ||
197 | mpic_assign_isu(mpic, 8, r.start + 0x10600); | ||
198 | mpic_assign_isu(mpic, 9, r.start + 0x10680); | ||
199 | mpic_assign_isu(mpic, 10, r.start + 0x10700); | ||
200 | mpic_assign_isu(mpic, 11, r.start + 0x10780); | ||
201 | |||
202 | /* External Interrupts */ | ||
203 | mpic_assign_isu(mpic, 12, r.start + 0x10000); | ||
204 | mpic_assign_isu(mpic, 13, r.start + 0x10080); | ||
205 | mpic_assign_isu(mpic, 14, r.start + 0x10100); | ||
206 | |||
207 | mpic_init(mpic); | 183 | mpic_init(mpic); |
208 | 184 | ||
209 | #ifdef CONFIG_QUICC_ENGINE | 185 | #ifdef CONFIG_QUICC_ENGINE |
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index 48f17e23d771..8118417b7364 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c | |||
@@ -33,10 +33,8 @@ | |||
33 | #define DBG(x...) | 33 | #define DBG(x...) |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | int mpc85xx_pci2_busno = 0; | ||
37 | |||
38 | #ifdef CONFIG_PCI | 36 | #ifdef CONFIG_PCI |
39 | int __init add_bridge(struct device_node *dev) | 37 | int __init mpc85xx_add_bridge(struct device_node *dev) |
40 | { | 38 | { |
41 | int len; | 39 | int len; |
42 | struct pci_controller *hose; | 40 | struct pci_controller *hose; |
@@ -57,11 +55,10 @@ int __init add_bridge(struct device_node *dev) | |||
57 | " bus 0\n", dev->full_name); | 55 | " bus 0\n", dev->full_name); |
58 | } | 56 | } |
59 | 57 | ||
60 | hose = pcibios_alloc_controller(); | 58 | pci_assign_all_buses = 1; |
59 | hose = pcibios_alloc_controller(dev); | ||
61 | if (!hose) | 60 | if (!hose) |
62 | return -ENOMEM; | 61 | return -ENOMEM; |
63 | hose->arch_data = dev; | ||
64 | hose->set_cfg_type = 1; | ||
65 | 62 | ||
66 | hose->first_busno = bus_range ? bus_range[0] : 0; | 63 | hose->first_busno = bus_range ? bus_range[0] : 0; |
67 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 64 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
@@ -74,8 +71,6 @@ int __init add_bridge(struct device_node *dev) | |||
74 | if ((rsrc.start & 0xfffff) == 0x9000) { | 71 | if ((rsrc.start & 0xfffff) == 0x9000) { |
75 | setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004); | 72 | setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004); |
76 | primary = 0; | 73 | primary = 0; |
77 | hose->bus_offset = hose->first_busno; | ||
78 | mpc85xx_pci2_busno = hose->first_busno; | ||
79 | } | 74 | } |
80 | 75 | ||
81 | printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. " | 76 | printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. " |
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index d1bcff500464..0faebfdc1596 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | choice | 1 | choice |
2 | prompt "Machine Type" | 2 | prompt "86xx Board Type" |
3 | depends on PPC_86xx | 3 | depends on PPC_86xx |
4 | default MPC8641_HPCN | 4 | default MPC8641_HPCN |
5 | 5 | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 2834462590b8..23f7ed2a7f88 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h | |||
@@ -15,15 +15,10 @@ | |||
15 | * mpc86xx_* files. Mostly for use by mpc86xx_setup(). | 15 | * mpc86xx_* files. Mostly for use by mpc86xx_setup(). |
16 | */ | 16 | */ |
17 | 17 | ||
18 | extern int add_bridge(struct device_node *dev); | 18 | extern int mpc86xx_add_bridge(struct device_node *dev); |
19 | 19 | ||
20 | extern int mpc86xx_exclude_device(u_char bus, u_char devfn); | 20 | extern int mpc86xx_exclude_device(struct pci_controller *hose, |
21 | 21 | u_char bus, u_char devfn); | |
22 | extern void setup_indirect_pcie(struct pci_controller *hose, | ||
23 | u32 cfg_addr, u32 cfg_data); | ||
24 | extern void setup_indirect_pcie_nomap(struct pci_controller *hose, | ||
25 | void __iomem *cfg_addr, | ||
26 | void __iomem *cfg_data); | ||
27 | 22 | ||
28 | extern void __init mpc86xx_smp_init(void); | 23 | extern void __init mpc86xx_smp_init(void); |
29 | 24 | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 1051702c8d4f..5b01ec7c13dc 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | |||
@@ -44,13 +44,6 @@ | |||
44 | #define DBG(fmt...) do { } while(0) | 44 | #define DBG(fmt...) do { } while(0) |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #ifndef CONFIG_PCI | ||
48 | unsigned long isa_io_base = 0; | ||
49 | unsigned long isa_mem_base = 0; | ||
50 | unsigned long pci_dram_offset = 0; | ||
51 | #endif | ||
52 | |||
53 | |||
54 | #ifdef CONFIG_PCI | 47 | #ifdef CONFIG_PCI |
55 | static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) | 48 | static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) |
56 | { | 49 | { |
@@ -81,22 +74,9 @@ mpc86xx_hpcn_init_irq(void) | |||
81 | /* Alloc mpic structure and per isu has 16 INT entries. */ | 74 | /* Alloc mpic structure and per isu has 16 INT entries. */ |
82 | mpic1 = mpic_alloc(np, res.start, | 75 | mpic1 = mpic_alloc(np, res.start, |
83 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 76 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, |
84 | 16, NR_IRQS - 4, | 77 | 0, 256, " MPIC "); |
85 | " MPIC "); | ||
86 | BUG_ON(mpic1 == NULL); | 78 | BUG_ON(mpic1 == NULL); |
87 | 79 | ||
88 | mpic_assign_isu(mpic1, 0, res.start + 0x10000); | ||
89 | |||
90 | /* 48 Internal Interrupts */ | ||
91 | mpic_assign_isu(mpic1, 1, res.start + 0x10200); | ||
92 | mpic_assign_isu(mpic1, 2, res.start + 0x10400); | ||
93 | mpic_assign_isu(mpic1, 3, res.start + 0x10600); | ||
94 | |||
95 | /* 16 External interrupts | ||
96 | * Moving them from [0 - 15] to [64 - 79] | ||
97 | */ | ||
98 | mpic_assign_isu(mpic1, 4, res.start + 0x10000); | ||
99 | |||
100 | mpic_init(mpic1); | 80 | mpic_init(mpic1); |
101 | 81 | ||
102 | #ifdef CONFIG_PCI | 82 | #ifdef CONFIG_PCI |
@@ -319,6 +299,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev) | |||
319 | { | 299 | { |
320 | unsigned short temp; | 300 | unsigned short temp; |
321 | pci_write_config_word(dev, 0x04, 0x0405); | 301 | pci_write_config_word(dev, 0x04, 0x0405); |
302 | dev->class &= ~0x5; | ||
322 | pci_read_config_word(dev, 0x4a, &temp); | 303 | pci_read_config_word(dev, 0x4a, &temp); |
323 | temp |= 0x1000; | 304 | temp |= 0x1000; |
324 | pci_write_config_word(dev, 0x4a, temp); | 305 | pci_write_config_word(dev, 0x4a, temp); |
@@ -364,9 +345,7 @@ mpc86xx_hpcn_setup_arch(void) | |||
364 | 345 | ||
365 | #ifdef CONFIG_PCI | 346 | #ifdef CONFIG_PCI |
366 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 347 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
367 | add_bridge(np); | 348 | mpc86xx_add_bridge(np); |
368 | |||
369 | ppc_md.pci_exclude_device = mpc86xx_exclude_device; | ||
370 | #endif | 349 | #endif |
371 | 350 | ||
372 | printk("MPC86xx HPCN board from Freescale Semiconductor\n"); | 351 | printk("MPC86xx HPCN board from Freescale Semiconductor\n"); |
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 8235c562661f..73cd5b05a84e 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c | |||
@@ -122,7 +122,6 @@ static void __init | |||
122 | mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) | 122 | mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) |
123 | { | 123 | { |
124 | u16 cmd; | 124 | u16 cmd; |
125 | unsigned int temps; | ||
126 | 125 | ||
127 | DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", | 126 | DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", |
128 | pcie_offset, pcie_size); | 127 | pcie_offset, pcie_size); |
@@ -133,22 +132,49 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) | |||
133 | early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); | 132 | early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); |
134 | 133 | ||
135 | early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); | 134 | early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); |
136 | |||
137 | /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ | ||
138 | early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); | ||
139 | temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); | ||
140 | early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); | ||
141 | } | 135 | } |
142 | 136 | ||
143 | int mpc86xx_exclude_device(u_char bus, u_char devfn) | 137 | static void __devinit quirk_fsl_pcie_transparent(struct pci_dev *dev) |
144 | { | 138 | { |
145 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 139 | struct resource *res; |
146 | return PCIBIOS_DEVICE_NOT_FOUND; | 140 | int i, res_idx = PCI_BRIDGE_RESOURCES; |
141 | struct pci_controller *hose; | ||
147 | 142 | ||
148 | return PCIBIOS_SUCCESSFUL; | 143 | /* |
144 | * Make the bridge be transparent. | ||
145 | */ | ||
146 | dev->transparent = 1; | ||
147 | |||
148 | hose = pci_bus_to_host(dev->bus); | ||
149 | if (!hose) { | ||
150 | printk(KERN_ERR "Can't find hose for bus %d\n", | ||
151 | dev->bus->number); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | if (hose->io_resource.flags) { | ||
156 | res = &dev->resource[res_idx++]; | ||
157 | res->start = hose->io_resource.start; | ||
158 | res->end = hose->io_resource.end; | ||
159 | res->flags = hose->io_resource.flags; | ||
160 | } | ||
161 | |||
162 | for (i = 0; i < 3; i++) { | ||
163 | res = &dev->resource[res_idx + i]; | ||
164 | res->start = hose->mem_resources[i].start; | ||
165 | res->end = hose->mem_resources[i].end; | ||
166 | res->flags = hose->mem_resources[i].flags; | ||
167 | } | ||
149 | } | 168 | } |
150 | 169 | ||
151 | int __init add_bridge(struct device_node *dev) | 170 | |
171 | DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7010, quirk_fsl_pcie_transparent); | ||
172 | DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7011, quirk_fsl_pcie_transparent); | ||
173 | |||
174 | #define PCIE_LTSSM 0x404 /* PCIe Link Training and Status */ | ||
175 | #define PCIE_LTSSM_L0 0x16 /* L0 state */ | ||
176 | |||
177 | int __init mpc86xx_add_bridge(struct device_node *dev) | ||
152 | { | 178 | { |
153 | int len; | 179 | int len; |
154 | struct pci_controller *hose; | 180 | struct pci_controller *hose; |
@@ -156,6 +182,7 @@ int __init add_bridge(struct device_node *dev) | |||
156 | const int *bus_range; | 182 | const int *bus_range; |
157 | int has_address = 0; | 183 | int has_address = 0; |
158 | int primary = 0; | 184 | int primary = 0; |
185 | u16 val; | ||
159 | 186 | ||
160 | DBG("Adding PCIE host bridge %s\n", dev->full_name); | 187 | DBG("Adding PCIE host bridge %s\n", dev->full_name); |
161 | 188 | ||
@@ -168,17 +195,23 @@ int __init add_bridge(struct device_node *dev) | |||
168 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | 195 | printk(KERN_WARNING "Can't get bus-range for %s, assume" |
169 | " bus 0\n", dev->full_name); | 196 | " bus 0\n", dev->full_name); |
170 | 197 | ||
171 | hose = pcibios_alloc_controller(); | 198 | pci_assign_all_buses = 1; |
199 | hose = pcibios_alloc_controller(dev); | ||
172 | if (!hose) | 200 | if (!hose) |
173 | return -ENOMEM; | 201 | return -ENOMEM; |
174 | hose->arch_data = dev; | ||
175 | hose->set_cfg_type = 1; | ||
176 | 202 | ||
177 | /* last_busno = 0xfe cause by MPC8641 PCIE bug */ | 203 | hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG | |
204 | PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS; | ||
205 | |||
178 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | 206 | hose->first_busno = bus_range ? bus_range[0] : 0x0; |
179 | hose->last_busno = bus_range ? bus_range[1] : 0xfe; | 207 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
208 | |||
209 | setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4); | ||
180 | 210 | ||
181 | setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); | 211 | /* Probe the hose link training status */ |
212 | early_read_config_word(hose, 0, 0, PCIE_LTSSM, &val); | ||
213 | if (val < PCIE_LTSSM_L0) | ||
214 | return -ENXIO; | ||
182 | 215 | ||
183 | /* Setup the PCIE host controller. */ | 216 | /* Setup the PCIE host controller. */ |
184 | mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); | 217 | mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); |
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 0901dbada350..f1693550c70c 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/root_dev.h> | 32 | #include <linux/root_dev.h> |
33 | #include <linux/time.h> | 33 | #include <linux/time.h> |
34 | #include <linux/rtc.h> | 34 | #include <linux/rtc.h> |
35 | #include <linux/fsl_devices.h> | ||
35 | 36 | ||
36 | #include <asm/mmu.h> | 37 | #include <asm/mmu.h> |
37 | #include <asm/reg.h> | 38 | #include <asm/reg.h> |
@@ -49,6 +50,10 @@ | |||
49 | 50 | ||
50 | #include "sysdev/mpc8xx_pic.h" | 51 | #include "sysdev/mpc8xx_pic.h" |
51 | 52 | ||
53 | #ifdef CONFIG_PCMCIA_M8XX | ||
54 | struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; | ||
55 | #endif | ||
56 | |||
52 | void m8xx_calibrate_decr(void); | 57 | void m8xx_calibrate_decr(void); |
53 | extern void m8xx_wdt_handler_install(bd_t *bp); | 58 | extern void m8xx_wdt_handler_install(bd_t *bp); |
54 | extern int cpm_pic_init(void); | 59 | extern int cpm_pic_init(void); |
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index c36e475d93dc..dc27dab48df0 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/fs_enet_pd.h> | 23 | #include <linux/fs_enet_pd.h> |
24 | #include <linux/fs_uart_pd.h> | 24 | #include <linux/fs_uart_pd.h> |
25 | #include <linux/fsl_devices.h> | ||
25 | #include <linux/mii.h> | 26 | #include <linux/mii.h> |
26 | 27 | ||
27 | #include <asm/delay.h> | 28 | #include <asm/delay.h> |
@@ -51,6 +52,70 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); | |||
51 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); | 52 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); |
52 | static void init_scc3_ioports(struct fs_platform_info* ptr); | 53 | static void init_scc3_ioports(struct fs_platform_info* ptr); |
53 | 54 | ||
55 | #ifdef CONFIG_PCMCIA_M8XX | ||
56 | static void pcmcia_hw_setup(int slot, int enable) | ||
57 | { | ||
58 | unsigned *bcsr_io; | ||
59 | |||
60 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
61 | if (enable) | ||
62 | clrbits32(bcsr_io, BCSR1_PCCEN); | ||
63 | else | ||
64 | setbits32(bcsr_io, BCSR1_PCCEN); | ||
65 | |||
66 | iounmap(bcsr_io); | ||
67 | } | ||
68 | |||
69 | static int pcmcia_set_voltage(int slot, int vcc, int vpp) | ||
70 | { | ||
71 | u32 reg = 0; | ||
72 | unsigned *bcsr_io; | ||
73 | |||
74 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
75 | |||
76 | switch(vcc) { | ||
77 | case 0: | ||
78 | break; | ||
79 | case 33: | ||
80 | reg |= BCSR1_PCCVCC0; | ||
81 | break; | ||
82 | case 50: | ||
83 | reg |= BCSR1_PCCVCC1; | ||
84 | break; | ||
85 | default: | ||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | switch(vpp) { | ||
90 | case 0: | ||
91 | break; | ||
92 | case 33: | ||
93 | case 50: | ||
94 | if(vcc == vpp) | ||
95 | reg |= BCSR1_PCCVPP1; | ||
96 | else | ||
97 | return 1; | ||
98 | break; | ||
99 | case 120: | ||
100 | if ((vcc == 33) || (vcc == 50)) | ||
101 | reg |= BCSR1_PCCVPP0; | ||
102 | else | ||
103 | return 1; | ||
104 | default: | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | /* first, turn off all power */ | ||
109 | clrbits32(bcsr_io, 0x00610000); | ||
110 | |||
111 | /* enable new powersettings */ | ||
112 | setbits32(bcsr_io, reg); | ||
113 | |||
114 | iounmap(bcsr_io); | ||
115 | return 0; | ||
116 | } | ||
117 | #endif | ||
118 | |||
54 | void __init mpc885ads_board_setup(void) | 119 | void __init mpc885ads_board_setup(void) |
55 | { | 120 | { |
56 | cpm8xx_t *cp; | 121 | cpm8xx_t *cp; |
@@ -115,6 +180,12 @@ void __init mpc885ads_board_setup(void) | |||
115 | immr_unmap(io_port); | 180 | immr_unmap(io_port); |
116 | 181 | ||
117 | #endif | 182 | #endif |
183 | |||
184 | #ifdef CONFIG_PCMCIA_M8XX | ||
185 | /*Set up board specific hook-ups*/ | ||
186 | m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; | ||
187 | m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; | ||
188 | #endif | ||
118 | } | 189 | } |
119 | 190 | ||
120 | 191 | ||
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 361acfa2894c..33545d352e92 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
@@ -2,7 +2,7 @@ menu "Platform support" | |||
2 | 2 | ||
3 | choice | 3 | choice |
4 | prompt "Machine type" | 4 | prompt "Machine type" |
5 | depends on PPC64 || CLASSIC32 | 5 | depends on PPC64 || 6xx |
6 | default PPC_MULTIPLATFORM | 6 | default PPC_MULTIPLATFORM |
7 | 7 | ||
8 | config PPC_MULTIPLATFORM | 8 | config PPC_MULTIPLATFORM |
@@ -16,15 +16,30 @@ config EMBEDDED6xx | |||
16 | bool "Embedded 6xx/7xx/7xxx-based board" | 16 | bool "Embedded 6xx/7xx/7xxx-based board" |
17 | depends on PPC32 && (BROKEN||BROKEN_ON_SMP) | 17 | depends on PPC32 && (BROKEN||BROKEN_ON_SMP) |
18 | 18 | ||
19 | config APUS | 19 | config PPC_82xx |
20 | bool "Amiga-APUS" | 20 | bool "Freescale 82xx" |
21 | depends on PPC32 && BROKEN | 21 | depends on 6xx |
22 | |||
23 | config PPC_83xx | ||
24 | bool "Freescale 83xx" | ||
25 | depends on 6xx | ||
26 | select FSL_SOC | ||
27 | select 83xx | ||
28 | select WANT_DEVICE_TREE | ||
29 | |||
30 | config PPC_86xx | ||
31 | bool "Freescale 86xx" | ||
32 | depends on 6xx | ||
33 | select FSL_SOC | ||
34 | select ALTIVEC | ||
22 | help | 35 | help |
23 | Select APUS if configuring for a PowerUP Amiga. | 36 | The Freescale E600 SoCs have 74xx cores. |
24 | More information is available at: | ||
25 | <http://linux-apus.sourceforge.net/>. | ||
26 | endchoice | 37 | endchoice |
27 | 38 | ||
39 | config CLASSIC32 | ||
40 | def_bool y | ||
41 | depends on 6xx && PPC_MULTIPLATFORM | ||
42 | |||
28 | source "arch/powerpc/platforms/pseries/Kconfig" | 43 | source "arch/powerpc/platforms/pseries/Kconfig" |
29 | source "arch/powerpc/platforms/iseries/Kconfig" | 44 | source "arch/powerpc/platforms/iseries/Kconfig" |
30 | source "arch/powerpc/platforms/chrp/Kconfig" | 45 | source "arch/powerpc/platforms/chrp/Kconfig" |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype new file mode 100644 index 000000000000..b8b5fde94668 --- /dev/null +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -0,0 +1,221 @@ | |||
1 | config PPC64 | ||
2 | bool "64-bit kernel" | ||
3 | default n | ||
4 | help | ||
5 | This option selects whether a 32-bit or a 64-bit kernel | ||
6 | will be built. | ||
7 | |||
8 | menu "Processor support" | ||
9 | choice | ||
10 | prompt "Processor Type" | ||
11 | depends on PPC32 | ||
12 | default 6xx | ||
13 | help | ||
14 | There are five families of 32 bit PowerPC chips supported. | ||
15 | The most common ones are the desktop and server CPUs (601, 603, | ||
16 | 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their | ||
17 | embedded 52xx/82xx/83xx/86xx counterparts. | ||
18 | The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500 | ||
19 | (85xx) each form a family of their own that is not compatible | ||
20 | with the others. | ||
21 | |||
22 | If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx. | ||
23 | |||
24 | config 6xx | ||
25 | bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx" | ||
26 | select PPC_FPU | ||
27 | |||
28 | config PPC_85xx | ||
29 | bool "Freescale 85xx" | ||
30 | select E500 | ||
31 | select FSL_SOC | ||
32 | select 85xx | ||
33 | select WANT_DEVICE_TREE | ||
34 | |||
35 | config PPC_8xx | ||
36 | bool "Freescale 8xx" | ||
37 | select FSL_SOC | ||
38 | select 8xx | ||
39 | |||
40 | config 40x | ||
41 | bool "AMCC 40x" | ||
42 | select PPC_DCR_NATIVE | ||
43 | |||
44 | config 44x | ||
45 | bool "AMCC 44x" | ||
46 | select PPC_DCR_NATIVE | ||
47 | select WANT_DEVICE_TREE | ||
48 | |||
49 | config E200 | ||
50 | bool "Freescale e200" | ||
51 | |||
52 | endchoice | ||
53 | |||
54 | config POWER4_ONLY | ||
55 | bool "Optimize for POWER4" | ||
56 | depends on PPC64 | ||
57 | default n | ||
58 | ---help--- | ||
59 | Cause the compiler to optimize for POWER4/POWER5/PPC970 processors. | ||
60 | The resulting binary will not work on POWER3 or RS64 processors | ||
61 | when compiled with binutils 2.15 or later. | ||
62 | |||
63 | config POWER3 | ||
64 | bool | ||
65 | depends on PPC64 | ||
66 | default y if !POWER4_ONLY | ||
67 | |||
68 | config POWER4 | ||
69 | depends on PPC64 | ||
70 | def_bool y | ||
71 | |||
72 | config 6xx | ||
73 | bool | ||
74 | |||
75 | # this is temp to handle compat with arch=ppc | ||
76 | config 8xx | ||
77 | bool | ||
78 | |||
79 | # this is temp to handle compat with arch=ppc | ||
80 | config 83xx | ||
81 | bool | ||
82 | |||
83 | # this is temp to handle compat with arch=ppc | ||
84 | config 85xx | ||
85 | bool | ||
86 | |||
87 | config E500 | ||
88 | bool | ||
89 | |||
90 | config PPC_FPU | ||
91 | bool | ||
92 | default y if PPC64 | ||
93 | |||
94 | config 4xx | ||
95 | bool | ||
96 | depends on 40x || 44x | ||
97 | default y | ||
98 | |||
99 | config BOOKE | ||
100 | bool | ||
101 | depends on E200 || E500 || 44x | ||
102 | default y | ||
103 | |||
104 | config FSL_BOOKE | ||
105 | bool | ||
106 | depends on E200 || E500 | ||
107 | default y | ||
108 | |||
109 | config PTE_64BIT | ||
110 | bool | ||
111 | depends on 44x || E500 | ||
112 | default y if 44x | ||
113 | default y if E500 && PHYS_64BIT | ||
114 | |||
115 | config PHYS_64BIT | ||
116 | bool 'Large physical address support' if E500 | ||
117 | depends on 44x || E500 | ||
118 | select RESOURCES_64BIT | ||
119 | default y if 44x | ||
120 | ---help--- | ||
121 | This option enables kernel support for larger than 32-bit physical | ||
122 | addresses. This features is not be available on all e500 cores. | ||
123 | |||
124 | If in doubt, say N here. | ||
125 | |||
126 | config ALTIVEC | ||
127 | bool "AltiVec Support" | ||
128 | depends on CLASSIC32 || POWER4 | ||
129 | ---help--- | ||
130 | This option enables kernel support for the Altivec extensions to the | ||
131 | PowerPC processor. The kernel currently supports saving and restoring | ||
132 | altivec registers, and turning on the 'altivec enable' bit so user | ||
133 | processes can execute altivec instructions. | ||
134 | |||
135 | This option is only usefully if you have a processor that supports | ||
136 | altivec (G4, otherwise known as 74xx series), but does not have | ||
137 | any affect on a non-altivec cpu (it does, however add code to the | ||
138 | kernel). | ||
139 | |||
140 | If in doubt, say Y here. | ||
141 | |||
142 | config SPE | ||
143 | bool "SPE Support" | ||
144 | depends on E200 || E500 | ||
145 | default y | ||
146 | ---help--- | ||
147 | This option enables kernel support for the Signal Processing | ||
148 | Extensions (SPE) to the PowerPC processor. The kernel currently | ||
149 | supports saving and restoring SPE registers, and turning on the | ||
150 | 'spe enable' bit so user processes can execute SPE instructions. | ||
151 | |||
152 | This option is only useful if you have a processor that supports | ||
153 | SPE (e500, otherwise known as 85xx series), but does not have any | ||
154 | effect on a non-spe cpu (it does, however add code to the kernel). | ||
155 | |||
156 | If in doubt, say Y here. | ||
157 | |||
158 | config PPC_STD_MMU | ||
159 | bool | ||
160 | depends on 6xx || POWER3 || POWER4 || PPC64 | ||
161 | default y | ||
162 | |||
163 | config PPC_STD_MMU_32 | ||
164 | def_bool y | ||
165 | depends on PPC_STD_MMU && PPC32 | ||
166 | |||
167 | config PPC_MM_SLICES | ||
168 | bool | ||
169 | default y if HUGETLB_PAGE | ||
170 | default n | ||
171 | |||
172 | config VIRT_CPU_ACCOUNTING | ||
173 | bool "Deterministic task and CPU time accounting" | ||
174 | depends on PPC64 | ||
175 | default y | ||
176 | help | ||
177 | Select this option to enable more accurate task and CPU time | ||
178 | accounting. This is done by reading a CPU counter on each | ||
179 | kernel entry and exit and on transitions within the kernel | ||
180 | between system, softirq and hardirq state, so there is a | ||
181 | small performance impact. This also enables accounting of | ||
182 | stolen time on logically-partitioned systems running on | ||
183 | IBM POWER5-based machines. | ||
184 | |||
185 | If in doubt, say Y here. | ||
186 | |||
187 | config SMP | ||
188 | depends on PPC_STD_MMU | ||
189 | bool "Symmetric multi-processing support" | ||
190 | ---help--- | ||
191 | This enables support for systems with more than one CPU. If you have | ||
192 | a system with only one CPU, say N. If you have a system with more | ||
193 | than one CPU, say Y. Note that the kernel does not currently | ||
194 | support SMP machines with 603/603e/603ev or PPC750 ("G3") processors | ||
195 | since they have inadequate hardware support for multiprocessor | ||
196 | operation. | ||
197 | |||
198 | If you say N here, the kernel will run on single and multiprocessor | ||
199 | machines, but will use only one CPU of a multiprocessor machine. If | ||
200 | you say Y here, the kernel will run on single-processor machines. | ||
201 | On a single-processor machine, the kernel will run faster if you say | ||
202 | N here. | ||
203 | |||
204 | If you don't know what to do here, say N. | ||
205 | |||
206 | config NR_CPUS | ||
207 | int "Maximum number of CPUs (2-128)" | ||
208 | range 2 128 | ||
209 | depends on SMP | ||
210 | default "32" if PPC64 | ||
211 | default "4" | ||
212 | |||
213 | config NOT_COHERENT_CACHE | ||
214 | bool | ||
215 | depends on 4xx || 8xx || E200 | ||
216 | default y | ||
217 | |||
218 | config CONFIG_CHECK_CACHE_COHERENCY | ||
219 | bool | ||
220 | |||
221 | endmenu | ||
diff --git a/arch/powerpc/platforms/apus/Kconfig b/arch/powerpc/platforms/apus/Kconfig deleted file mode 100644 index 6bde3bffed86..000000000000 --- a/arch/powerpc/platforms/apus/Kconfig +++ /dev/null | |||
@@ -1,130 +0,0 @@ | |||
1 | |||
2 | config AMIGA | ||
3 | bool | ||
4 | depends on APUS | ||
5 | default y | ||
6 | help | ||
7 | This option enables support for the Amiga series of computers. | ||
8 | |||
9 | config ZORRO | ||
10 | bool | ||
11 | depends on APUS | ||
12 | default y | ||
13 | help | ||
14 | This enables support for the Zorro bus in the Amiga. If you have | ||
15 | expansion cards in your Amiga that conform to the Amiga | ||
16 | AutoConfig(tm) specification, say Y, otherwise N. Note that even | ||
17 | expansion cards that do not fit in the Zorro slots but fit in e.g. | ||
18 | the CPU slot may fall in this category, so you have to say Y to let | ||
19 | Linux use these. | ||
20 | |||
21 | config ABSTRACT_CONSOLE | ||
22 | bool | ||
23 | depends on APUS | ||
24 | default y | ||
25 | |||
26 | config APUS_FAST_EXCEPT | ||
27 | bool | ||
28 | depends on APUS | ||
29 | default y | ||
30 | |||
31 | config AMIGA_PCMCIA | ||
32 | bool "Amiga 1200/600 PCMCIA support" | ||
33 | depends on APUS && EXPERIMENTAL | ||
34 | help | ||
35 | Include support in the kernel for pcmcia on Amiga 1200 and Amiga | ||
36 | 600. If you intend to use pcmcia cards say Y; otherwise say N. | ||
37 | |||
38 | config AMIGA_BUILTIN_SERIAL | ||
39 | tristate "Amiga builtin serial support" | ||
40 | depends on APUS | ||
41 | help | ||
42 | If you want to use your Amiga's built-in serial port in Linux, | ||
43 | answer Y. | ||
44 | |||
45 | To compile this driver as a module, choose M here. | ||
46 | |||
47 | config GVPIOEXT | ||
48 | tristate "GVP IO-Extender support" | ||
49 | depends on APUS | ||
50 | help | ||
51 | If you want to use a GVP IO-Extender serial card in Linux, say Y. | ||
52 | Otherwise, say N. | ||
53 | |||
54 | config GVPIOEXT_LP | ||
55 | tristate "GVP IO-Extender parallel printer support" | ||
56 | depends on GVPIOEXT | ||
57 | help | ||
58 | Say Y to enable driving a printer from the parallel port on your | ||
59 | GVP IO-Extender card, N otherwise. | ||
60 | |||
61 | config GVPIOEXT_PLIP | ||
62 | tristate "GVP IO-Extender PLIP support" | ||
63 | depends on GVPIOEXT | ||
64 | help | ||
65 | Say Y to enable doing IP over the parallel port on your GVP | ||
66 | IO-Extender card, N otherwise. | ||
67 | |||
68 | config MULTIFACE_III_TTY | ||
69 | tristate "Multiface Card III serial support" | ||
70 | depends on APUS | ||
71 | help | ||
72 | If you want to use a Multiface III card's serial port in Linux, | ||
73 | answer Y. | ||
74 | |||
75 | To compile this driver as a module, choose M here. | ||
76 | |||
77 | config A2232 | ||
78 | tristate "Commodore A2232 serial support (EXPERIMENTAL)" | ||
79 | depends on EXPERIMENTAL && APUS | ||
80 | ---help--- | ||
81 | This option supports the 2232 7-port serial card shipped with the | ||
82 | Amiga 2000 and other Zorro-bus machines, dating from 1989. At | ||
83 | a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip | ||
84 | each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The | ||
85 | ports were connected with 8 pin DIN connectors on the card bracket, | ||
86 | for which 8 pin to DB25 adapters were supplied. The card also had | ||
87 | jumpers internally to toggle various pinning configurations. | ||
88 | |||
89 | This driver can be built as a module; but then "generic_serial" | ||
90 | will also be built as a module. This has to be loaded before | ||
91 | "ser_a2232". If you want to do this, answer M here. | ||
92 | |||
93 | config WHIPPET_SERIAL | ||
94 | tristate "Hisoft Whippet PCMCIA serial support" | ||
95 | depends on AMIGA_PCMCIA | ||
96 | help | ||
97 | HiSoft has a web page at <http://www.hisoft.co.uk/>, but there | ||
98 | is no listing for the Whippet in their Amiga section. | ||
99 | |||
100 | config APNE | ||
101 | tristate "PCMCIA NE2000 support" | ||
102 | depends on AMIGA_PCMCIA | ||
103 | help | ||
104 | If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, | ||
105 | say N. | ||
106 | |||
107 | To compile this driver as a module, choose M here: the | ||
108 | module will be called apne. | ||
109 | |||
110 | config SERIAL_CONSOLE | ||
111 | bool "Support for serial port console" | ||
112 | depends on APUS && (AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y) | ||
113 | |||
114 | config HEARTBEAT | ||
115 | bool "Use power LED as a heartbeat" | ||
116 | depends on APUS | ||
117 | help | ||
118 | Use the power-on LED on your machine as a load meter. The exact | ||
119 | behavior is platform-dependent, but normally the flash frequency is | ||
120 | a hyperbolic function of the 5-minute load average. | ||
121 | |||
122 | config PROC_HARDWARE | ||
123 | bool "/proc/hardware support" | ||
124 | depends on APUS | ||
125 | |||
126 | source "drivers/zorro/Kconfig" | ||
127 | |||
128 | config PCI_PERMEDIA | ||
129 | bool "PCI for Permedia2" | ||
130 | depends on !4xx && !8xx && APUS | ||
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c index 7fb92f23f380..9d7c2ef940a8 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/platforms/cell/io-workarounds.c | |||
@@ -102,7 +102,7 @@ static void spider_io_flush(const volatile void __iomem *addr) | |||
102 | vaddr = (unsigned long)PCI_FIX_ADDR(addr); | 102 | vaddr = (unsigned long)PCI_FIX_ADDR(addr); |
103 | 103 | ||
104 | /* Check if it's in allowed range for PIO */ | 104 | /* Check if it's in allowed range for PIO */ |
105 | if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE) | 105 | if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END) |
106 | return; | 106 | return; |
107 | 107 | ||
108 | /* Try to find a PTE. If not, clear the paddr, we'll do | 108 | /* Try to find a PTE. If not, clear the paddr, we'll do |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index a7f5a7653c62..e4d0c9f42abd 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -183,7 +183,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
183 | spu->slb_replace = 0; | 183 | spu->slb_replace = 0; |
184 | 184 | ||
185 | spu_restart_dma(spu); | 185 | spu_restart_dma(spu); |
186 | 186 | spu->stats.slb_flt++; | |
187 | return 0; | 187 | return 0; |
188 | } | 188 | } |
189 | 189 | ||
@@ -332,6 +332,7 @@ spu_irq_class_2(int irq, void *data) | |||
332 | if (stat & 0x10) /* SPU mailbox threshold */ | 332 | if (stat & 0x10) /* SPU mailbox threshold */ |
333 | spu->wbox_callback(spu); | 333 | spu->wbox_callback(spu); |
334 | 334 | ||
335 | spu->stats.class2_intr++; | ||
335 | return stat ? IRQ_HANDLED : IRQ_NONE; | 336 | return stat ? IRQ_HANDLED : IRQ_NONE; |
336 | } | 337 | } |
337 | 338 | ||
@@ -462,8 +463,18 @@ void spu_free(struct spu *spu) | |||
462 | } | 463 | } |
463 | EXPORT_SYMBOL_GPL(spu_free); | 464 | EXPORT_SYMBOL_GPL(spu_free); |
464 | 465 | ||
466 | static int spu_shutdown(struct sys_device *sysdev) | ||
467 | { | ||
468 | struct spu *spu = container_of(sysdev, struct spu, sysdev); | ||
469 | |||
470 | spu_free_irqs(spu); | ||
471 | spu_destroy_spu(spu); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
465 | struct sysdev_class spu_sysdev_class = { | 475 | struct sysdev_class spu_sysdev_class = { |
466 | set_kset_name("spu") | 476 | set_kset_name("spu"), |
477 | .shutdown = spu_shutdown, | ||
467 | }; | 478 | }; |
468 | 479 | ||
469 | int spu_add_sysdev_attr(struct sysdev_attribute *attr) | 480 | int spu_add_sysdev_attr(struct sysdev_attribute *attr) |
@@ -574,6 +585,9 @@ static int __init create_spu(void *data) | |||
574 | spin_unlock_irqrestore(&spu_list_lock, flags); | 585 | spin_unlock_irqrestore(&spu_list_lock, flags); |
575 | mutex_unlock(&spu_mutex); | 586 | mutex_unlock(&spu_mutex); |
576 | 587 | ||
588 | spu->stats.utilization_state = SPU_UTIL_IDLE; | ||
589 | spu->stats.tstamp = jiffies; | ||
590 | |||
577 | goto out; | 591 | goto out; |
578 | 592 | ||
579 | out_free_irqs: | 593 | out_free_irqs: |
@@ -586,6 +600,45 @@ out: | |||
586 | return ret; | 600 | return ret; |
587 | } | 601 | } |
588 | 602 | ||
603 | static const char *spu_state_names[] = { | ||
604 | "user", "system", "iowait", "idle" | ||
605 | }; | ||
606 | |||
607 | static unsigned long long spu_acct_time(struct spu *spu, | ||
608 | enum spu_utilization_state state) | ||
609 | { | ||
610 | unsigned long long time = spu->stats.times[state]; | ||
611 | |||
612 | if (spu->stats.utilization_state == state) | ||
613 | time += jiffies - spu->stats.tstamp; | ||
614 | |||
615 | return jiffies_to_msecs(time); | ||
616 | } | ||
617 | |||
618 | |||
619 | static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf) | ||
620 | { | ||
621 | struct spu *spu = container_of(sysdev, struct spu, sysdev); | ||
622 | |||
623 | return sprintf(buf, "%s %llu %llu %llu %llu " | ||
624 | "%llu %llu %llu %llu %llu %llu %llu %llu\n", | ||
625 | spu_state_names[spu->stats.utilization_state], | ||
626 | spu_acct_time(spu, SPU_UTIL_USER), | ||
627 | spu_acct_time(spu, SPU_UTIL_SYSTEM), | ||
628 | spu_acct_time(spu, SPU_UTIL_IOWAIT), | ||
629 | spu_acct_time(spu, SPU_UTIL_IDLE), | ||
630 | spu->stats.vol_ctx_switch, | ||
631 | spu->stats.invol_ctx_switch, | ||
632 | spu->stats.slb_flt, | ||
633 | spu->stats.hash_flt, | ||
634 | spu->stats.min_flt, | ||
635 | spu->stats.maj_flt, | ||
636 | spu->stats.class2_intr, | ||
637 | spu->stats.libassist); | ||
638 | } | ||
639 | |||
640 | static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); | ||
641 | |||
589 | static int __init init_spu_base(void) | 642 | static int __init init_spu_base(void) |
590 | { | 643 | { |
591 | int i, ret = 0; | 644 | int i, ret = 0; |
@@ -611,6 +664,8 @@ static int __init init_spu_base(void) | |||
611 | 664 | ||
612 | xmon_register_spus(&spu_full_list); | 665 | xmon_register_spus(&spu_full_list); |
613 | 666 | ||
667 | spu_add_sysdev_attr(&attr_stat); | ||
668 | |||
614 | return 0; | 669 | return 0; |
615 | 670 | ||
616 | out_unregister_sysdev_class: | 671 | out_unregister_sysdev_class: |
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index d32db9ffc6eb..07a0e815abf5 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c | |||
@@ -320,6 +320,12 @@ static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask, | |||
320 | /* FIXME: what are the side-effects of this? */ | 320 | /* FIXME: what are the side-effects of this? */ |
321 | prob->dma_querymask_RW = mask; | 321 | prob->dma_querymask_RW = mask; |
322 | prob->dma_querytype_RW = mode; | 322 | prob->dma_querytype_RW = mode; |
323 | /* In the current implementation, the SPU context is always | ||
324 | * acquired in runnable state when new bits are added to the | ||
325 | * mask (tagwait), so it's sufficient just to mask | ||
326 | * dma_tagstatus_R with the 'mask' parameter here. | ||
327 | */ | ||
328 | ctx->csa.prob.dma_tagstatus_R &= mask; | ||
323 | out: | 329 | out: |
324 | spin_unlock(&ctx->csa.register_lock); | 330 | spin_unlock(&ctx->csa.register_lock); |
325 | 331 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 7c51cb54bca1..6d7bd60f5380 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -23,10 +23,14 @@ | |||
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <asm/atomic.h> | ||
26 | #include <asm/spu.h> | 27 | #include <asm/spu.h> |
27 | #include <asm/spu_csa.h> | 28 | #include <asm/spu_csa.h> |
28 | #include "spufs.h" | 29 | #include "spufs.h" |
29 | 30 | ||
31 | |||
32 | atomic_t nr_spu_contexts = ATOMIC_INIT(0); | ||
33 | |||
30 | struct spu_context *alloc_spu_context(struct spu_gang *gang) | 34 | struct spu_context *alloc_spu_context(struct spu_gang *gang) |
31 | { | 35 | { |
32 | struct spu_context *ctx; | 36 | struct spu_context *ctx; |
@@ -53,10 +57,12 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
53 | INIT_LIST_HEAD(&ctx->rq); | 57 | INIT_LIST_HEAD(&ctx->rq); |
54 | if (gang) | 58 | if (gang) |
55 | spu_gang_add_ctx(gang, ctx); | 59 | spu_gang_add_ctx(gang, ctx); |
56 | ctx->rt_priority = current->rt_priority; | 60 | ctx->cpus_allowed = current->cpus_allowed; |
57 | ctx->policy = current->policy; | 61 | spu_set_timeslice(ctx); |
58 | ctx->prio = current->prio; | 62 | ctx->stats.execution_state = SPUCTX_UTIL_USER; |
59 | INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); | 63 | ctx->stats.tstamp = jiffies; |
64 | |||
65 | atomic_inc(&nr_spu_contexts); | ||
60 | goto out; | 66 | goto out; |
61 | out_free: | 67 | out_free: |
62 | kfree(ctx); | 68 | kfree(ctx); |
@@ -76,6 +82,7 @@ void destroy_spu_context(struct kref *kref) | |||
76 | if (ctx->gang) | 82 | if (ctx->gang) |
77 | spu_gang_remove_ctx(ctx->gang, ctx); | 83 | spu_gang_remove_ctx(ctx->gang, ctx); |
78 | BUG_ON(!list_empty(&ctx->rq)); | 84 | BUG_ON(!list_empty(&ctx->rq)); |
85 | atomic_dec(&nr_spu_contexts); | ||
79 | kfree(ctx); | 86 | kfree(ctx); |
80 | } | 87 | } |
81 | 88 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index 0f75c07e29d8..e064d0c0d80e 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c | |||
@@ -33,7 +33,8 @@ | |||
33 | * function. Currently, there are a few corner cases that we haven't had | 33 | * function. Currently, there are a few corner cases that we haven't had |
34 | * to handle fortunately. | 34 | * to handle fortunately. |
35 | */ | 35 | */ |
36 | static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) | 36 | static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, |
37 | unsigned long dsisr, unsigned *flt) | ||
37 | { | 38 | { |
38 | struct vm_area_struct *vma; | 39 | struct vm_area_struct *vma; |
39 | unsigned long is_write; | 40 | unsigned long is_write; |
@@ -73,7 +74,8 @@ good_area: | |||
73 | goto bad_area; | 74 | goto bad_area; |
74 | } | 75 | } |
75 | ret = 0; | 76 | ret = 0; |
76 | switch (handle_mm_fault(mm, vma, ea, is_write)) { | 77 | *flt = handle_mm_fault(mm, vma, ea, is_write); |
78 | switch (*flt) { | ||
77 | case VM_FAULT_MINOR: | 79 | case VM_FAULT_MINOR: |
78 | current->min_flt++; | 80 | current->min_flt++; |
79 | break; | 81 | break; |
@@ -153,6 +155,7 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
153 | { | 155 | { |
154 | u64 ea, dsisr, access; | 156 | u64 ea, dsisr, access; |
155 | unsigned long flags; | 157 | unsigned long flags; |
158 | unsigned flt = 0; | ||
156 | int ret; | 159 | int ret; |
157 | 160 | ||
158 | /* | 161 | /* |
@@ -178,9 +181,17 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
178 | if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) | 181 | if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) |
179 | return 0; | 182 | return 0; |
180 | 183 | ||
184 | spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT); | ||
185 | |||
181 | pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, | 186 | pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, |
182 | dsisr, ctx->state); | 187 | dsisr, ctx->state); |
183 | 188 | ||
189 | ctx->stats.hash_flt++; | ||
190 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
191 | ctx->spu->stats.hash_flt++; | ||
192 | spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT); | ||
193 | } | ||
194 | |||
184 | /* we must not hold the lock when entering spu_handle_mm_fault */ | 195 | /* we must not hold the lock when entering spu_handle_mm_fault */ |
185 | spu_release(ctx); | 196 | spu_release(ctx); |
186 | 197 | ||
@@ -192,7 +203,7 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
192 | 203 | ||
193 | /* hashing failed, so try the actual fault handler */ | 204 | /* hashing failed, so try the actual fault handler */ |
194 | if (ret) | 205 | if (ret) |
195 | ret = spu_handle_mm_fault(current->mm, ea, dsisr); | 206 | ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); |
196 | 207 | ||
197 | spu_acquire(ctx); | 208 | spu_acquire(ctx); |
198 | /* | 209 | /* |
@@ -201,11 +212,23 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
201 | * In case of unhandled error report the problem to user space. | 212 | * In case of unhandled error report the problem to user space. |
202 | */ | 213 | */ |
203 | if (!ret) { | 214 | if (!ret) { |
215 | if (flt == VM_FAULT_MINOR) | ||
216 | ctx->stats.min_flt++; | ||
217 | else | ||
218 | ctx->stats.maj_flt++; | ||
219 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
220 | if (flt == VM_FAULT_MINOR) | ||
221 | ctx->spu->stats.min_flt++; | ||
222 | else | ||
223 | ctx->spu->stats.maj_flt++; | ||
224 | } | ||
225 | |||
204 | if (ctx->spu) | 226 | if (ctx->spu) |
205 | ctx->ops->restart_dma(ctx); | 227 | ctx->ops->restart_dma(ctx); |
206 | } else | 228 | } else |
207 | spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); | 229 | spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); |
208 | 230 | ||
231 | spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); | ||
209 | return ret; | 232 | return ret; |
210 | } | 233 | } |
211 | EXPORT_SYMBOL_GPL(spufs_handle_class1); | 234 | EXPORT_SYMBOL_GPL(spufs_handle_class1); |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index b1e7e2f8a2e9..c2814ea96af2 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
29 | #include <linux/poll.h> | 29 | #include <linux/poll.h> |
30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
31 | #include <linux/seq_file.h> | ||
31 | 32 | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | #include <asm/semaphore.h> | 34 | #include <asm/semaphore.h> |
@@ -39,6 +40,7 @@ | |||
39 | 40 | ||
40 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) | 41 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) |
41 | 42 | ||
43 | |||
42 | static int | 44 | static int |
43 | spufs_mem_open(struct inode *inode, struct file *file) | 45 | spufs_mem_open(struct inode *inode, struct file *file) |
44 | { | 46 | { |
@@ -216,12 +218,12 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, | |||
216 | #endif /* CONFIG_SPU_FS_64K_LS */ | 218 | #endif /* CONFIG_SPU_FS_64K_LS */ |
217 | 219 | ||
218 | static const struct file_operations spufs_mem_fops = { | 220 | static const struct file_operations spufs_mem_fops = { |
219 | .open = spufs_mem_open, | 221 | .open = spufs_mem_open, |
220 | .release = spufs_mem_release, | 222 | .release = spufs_mem_release, |
221 | .read = spufs_mem_read, | 223 | .read = spufs_mem_read, |
222 | .write = spufs_mem_write, | 224 | .write = spufs_mem_write, |
223 | .llseek = generic_file_llseek, | 225 | .llseek = generic_file_llseek, |
224 | .mmap = spufs_mem_mmap, | 226 | .mmap = spufs_mem_mmap, |
225 | #ifdef CONFIG_SPU_FS_64K_LS | 227 | #ifdef CONFIG_SPU_FS_64K_LS |
226 | .get_unmapped_area = spufs_get_unmapped_area, | 228 | .get_unmapped_area = spufs_get_unmapped_area, |
227 | #endif | 229 | #endif |
@@ -1497,14 +1499,15 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | |||
1497 | if (status) | 1499 | if (status) |
1498 | ret = status; | 1500 | ret = status; |
1499 | } | 1501 | } |
1500 | spu_release(ctx); | ||
1501 | 1502 | ||
1502 | if (ret) | 1503 | if (ret) |
1503 | goto out; | 1504 | goto out_unlock; |
1504 | 1505 | ||
1505 | ctx->tagwait |= 1 << cmd.tag; | 1506 | ctx->tagwait |= 1 << cmd.tag; |
1506 | ret = size; | 1507 | ret = size; |
1507 | 1508 | ||
1509 | out_unlock: | ||
1510 | spu_release(ctx); | ||
1508 | out: | 1511 | out: |
1509 | return ret; | 1512 | return ret; |
1510 | } | 1513 | } |
@@ -1515,14 +1518,14 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) | |||
1515 | u32 free_elements, tagstatus; | 1518 | u32 free_elements, tagstatus; |
1516 | unsigned int mask; | 1519 | unsigned int mask; |
1517 | 1520 | ||
1521 | poll_wait(file, &ctx->mfc_wq, wait); | ||
1522 | |||
1518 | spu_acquire(ctx); | 1523 | spu_acquire(ctx); |
1519 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); | 1524 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); |
1520 | free_elements = ctx->ops->get_mfc_free_elements(ctx); | 1525 | free_elements = ctx->ops->get_mfc_free_elements(ctx); |
1521 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); | 1526 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); |
1522 | spu_release(ctx); | 1527 | spu_release(ctx); |
1523 | 1528 | ||
1524 | poll_wait(file, &ctx->mfc_wq, wait); | ||
1525 | |||
1526 | mask = 0; | 1529 | mask = 0; |
1527 | if (free_elements & 0xffff) | 1530 | if (free_elements & 0xffff) |
1528 | mask |= POLLOUT | POLLWRNORM; | 1531 | mask |= POLLOUT | POLLWRNORM; |
@@ -1797,6 +1800,29 @@ static int spufs_info_open(struct inode *inode, struct file *file) | |||
1797 | return 0; | 1800 | return 0; |
1798 | } | 1801 | } |
1799 | 1802 | ||
1803 | static int spufs_caps_show(struct seq_file *s, void *private) | ||
1804 | { | ||
1805 | struct spu_context *ctx = s->private; | ||
1806 | |||
1807 | if (!(ctx->flags & SPU_CREATE_NOSCHED)) | ||
1808 | seq_puts(s, "sched\n"); | ||
1809 | if (!(ctx->flags & SPU_CREATE_ISOLATE)) | ||
1810 | seq_puts(s, "step\n"); | ||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1814 | static int spufs_caps_open(struct inode *inode, struct file *file) | ||
1815 | { | ||
1816 | return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); | ||
1817 | } | ||
1818 | |||
1819 | static const struct file_operations spufs_caps_fops = { | ||
1820 | .open = spufs_caps_open, | ||
1821 | .read = seq_read, | ||
1822 | .llseek = seq_lseek, | ||
1823 | .release = single_release, | ||
1824 | }; | ||
1825 | |||
1800 | static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, | 1826 | static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, |
1801 | char __user *buf, size_t len, loff_t *pos) | 1827 | char __user *buf, size_t len, loff_t *pos) |
1802 | { | 1828 | { |
@@ -2014,7 +2040,105 @@ static const struct file_operations spufs_proxydma_info_fops = { | |||
2014 | .read = spufs_proxydma_info_read, | 2040 | .read = spufs_proxydma_info_read, |
2015 | }; | 2041 | }; |
2016 | 2042 | ||
2043 | static int spufs_show_tid(struct seq_file *s, void *private) | ||
2044 | { | ||
2045 | struct spu_context *ctx = s->private; | ||
2046 | |||
2047 | seq_printf(s, "%d\n", ctx->tid); | ||
2048 | return 0; | ||
2049 | } | ||
2050 | |||
2051 | static int spufs_tid_open(struct inode *inode, struct file *file) | ||
2052 | { | ||
2053 | return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); | ||
2054 | } | ||
2055 | |||
2056 | static const struct file_operations spufs_tid_fops = { | ||
2057 | .open = spufs_tid_open, | ||
2058 | .read = seq_read, | ||
2059 | .llseek = seq_lseek, | ||
2060 | .release = single_release, | ||
2061 | }; | ||
2062 | |||
2063 | static const char *ctx_state_names[] = { | ||
2064 | "user", "system", "iowait", "loaded" | ||
2065 | }; | ||
2066 | |||
2067 | static unsigned long long spufs_acct_time(struct spu_context *ctx, | ||
2068 | enum spuctx_execution_state state) | ||
2069 | { | ||
2070 | unsigned long time = ctx->stats.times[state]; | ||
2071 | |||
2072 | if (ctx->stats.execution_state == state) | ||
2073 | time += jiffies - ctx->stats.tstamp; | ||
2074 | |||
2075 | return jiffies_to_msecs(time); | ||
2076 | } | ||
2077 | |||
2078 | static unsigned long long spufs_slb_flts(struct spu_context *ctx) | ||
2079 | { | ||
2080 | unsigned long long slb_flts = ctx->stats.slb_flt; | ||
2081 | |||
2082 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
2083 | slb_flts += (ctx->spu->stats.slb_flt - | ||
2084 | ctx->stats.slb_flt_base); | ||
2085 | } | ||
2086 | |||
2087 | return slb_flts; | ||
2088 | } | ||
2089 | |||
2090 | static unsigned long long spufs_class2_intrs(struct spu_context *ctx) | ||
2091 | { | ||
2092 | unsigned long long class2_intrs = ctx->stats.class2_intr; | ||
2093 | |||
2094 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
2095 | class2_intrs += (ctx->spu->stats.class2_intr - | ||
2096 | ctx->stats.class2_intr_base); | ||
2097 | } | ||
2098 | |||
2099 | return class2_intrs; | ||
2100 | } | ||
2101 | |||
2102 | |||
2103 | static int spufs_show_stat(struct seq_file *s, void *private) | ||
2104 | { | ||
2105 | struct spu_context *ctx = s->private; | ||
2106 | |||
2107 | spu_acquire(ctx); | ||
2108 | seq_printf(s, "%s %llu %llu %llu %llu " | ||
2109 | "%llu %llu %llu %llu %llu %llu %llu %llu\n", | ||
2110 | ctx_state_names[ctx->stats.execution_state], | ||
2111 | spufs_acct_time(ctx, SPUCTX_UTIL_USER), | ||
2112 | spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM), | ||
2113 | spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT), | ||
2114 | spufs_acct_time(ctx, SPUCTX_UTIL_LOADED), | ||
2115 | ctx->stats.vol_ctx_switch, | ||
2116 | ctx->stats.invol_ctx_switch, | ||
2117 | spufs_slb_flts(ctx), | ||
2118 | ctx->stats.hash_flt, | ||
2119 | ctx->stats.min_flt, | ||
2120 | ctx->stats.maj_flt, | ||
2121 | spufs_class2_intrs(ctx), | ||
2122 | ctx->stats.libassist); | ||
2123 | spu_release(ctx); | ||
2124 | return 0; | ||
2125 | } | ||
2126 | |||
2127 | static int spufs_stat_open(struct inode *inode, struct file *file) | ||
2128 | { | ||
2129 | return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); | ||
2130 | } | ||
2131 | |||
2132 | static const struct file_operations spufs_stat_fops = { | ||
2133 | .open = spufs_stat_open, | ||
2134 | .read = seq_read, | ||
2135 | .llseek = seq_lseek, | ||
2136 | .release = single_release, | ||
2137 | }; | ||
2138 | |||
2139 | |||
2017 | struct tree_descr spufs_dir_contents[] = { | 2140 | struct tree_descr spufs_dir_contents[] = { |
2141 | { "capabilities", &spufs_caps_fops, 0444, }, | ||
2018 | { "mem", &spufs_mem_fops, 0666, }, | 2142 | { "mem", &spufs_mem_fops, 0666, }, |
2019 | { "regs", &spufs_regs_fops, 0666, }, | 2143 | { "regs", &spufs_regs_fops, 0666, }, |
2020 | { "mbox", &spufs_mbox_fops, 0444, }, | 2144 | { "mbox", &spufs_mbox_fops, 0444, }, |
@@ -2046,10 +2170,13 @@ struct tree_descr spufs_dir_contents[] = { | |||
2046 | { "wbox_info", &spufs_wbox_info_fops, 0444, }, | 2170 | { "wbox_info", &spufs_wbox_info_fops, 0444, }, |
2047 | { "dma_info", &spufs_dma_info_fops, 0444, }, | 2171 | { "dma_info", &spufs_dma_info_fops, 0444, }, |
2048 | { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, | 2172 | { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, |
2173 | { "tid", &spufs_tid_fops, 0444, }, | ||
2174 | { "stat", &spufs_stat_fops, 0444, }, | ||
2049 | {}, | 2175 | {}, |
2050 | }; | 2176 | }; |
2051 | 2177 | ||
2052 | struct tree_descr spufs_dir_nosched_contents[] = { | 2178 | struct tree_descr spufs_dir_nosched_contents[] = { |
2179 | { "capabilities", &spufs_caps_fops, 0444, }, | ||
2053 | { "mem", &spufs_mem_fops, 0666, }, | 2180 | { "mem", &spufs_mem_fops, 0666, }, |
2054 | { "mbox", &spufs_mbox_fops, 0444, }, | 2181 | { "mbox", &spufs_mbox_fops, 0444, }, |
2055 | { "ibox", &spufs_ibox_fops, 0444, }, | 2182 | { "ibox", &spufs_ibox_fops, 0444, }, |
@@ -2068,6 +2195,8 @@ struct tree_descr spufs_dir_nosched_contents[] = { | |||
2068 | { "psmap", &spufs_psmap_fops, 0666, }, | 2195 | { "psmap", &spufs_psmap_fops, 0666, }, |
2069 | { "phys-id", &spufs_id_ops, 0666, }, | 2196 | { "phys-id", &spufs_id_ops, 0666, }, |
2070 | { "object-id", &spufs_object_id_ops, 0666, }, | 2197 | { "object-id", &spufs_object_id_ops, 0666, }, |
2198 | { "tid", &spufs_tid_fops, 0444, }, | ||
2199 | { "stat", &spufs_stat_fops, 0444, }, | ||
2071 | {}, | 2200 | {}, |
2072 | }; | 2201 | }; |
2073 | 2202 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 9807206e0219..f37460e5bfd2 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -232,10 +232,6 @@ static int spufs_dir_close(struct inode *inode, struct file *file) | |||
232 | return dcache_dir_close(inode, file); | 232 | return dcache_dir_close(inode, file); |
233 | } | 233 | } |
234 | 234 | ||
235 | const struct inode_operations spufs_dir_inode_operations = { | ||
236 | .lookup = simple_lookup, | ||
237 | }; | ||
238 | |||
239 | const struct file_operations spufs_context_fops = { | 235 | const struct file_operations spufs_context_fops = { |
240 | .open = dcache_dir_open, | 236 | .open = dcache_dir_open, |
241 | .release = spufs_dir_close, | 237 | .release = spufs_dir_close, |
@@ -269,7 +265,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, | |||
269 | goto out_iput; | 265 | goto out_iput; |
270 | 266 | ||
271 | ctx->flags = flags; | 267 | ctx->flags = flags; |
272 | inode->i_op = &spufs_dir_inode_operations; | 268 | inode->i_op = &simple_dir_inode_operations; |
273 | inode->i_fop = &simple_dir_operations; | 269 | inode->i_fop = &simple_dir_operations; |
274 | if (flags & SPU_CREATE_NOSCHED) | 270 | if (flags & SPU_CREATE_NOSCHED) |
275 | ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, | 271 | ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, |
@@ -386,7 +382,7 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) | |||
386 | if (!gang) | 382 | if (!gang) |
387 | goto out_iput; | 383 | goto out_iput; |
388 | 384 | ||
389 | inode->i_op = &spufs_dir_inode_operations; | 385 | inode->i_op = &simple_dir_inode_operations; |
390 | inode->i_fop = &simple_dir_operations; | 386 | inode->i_fop = &simple_dir_operations; |
391 | 387 | ||
392 | d_instantiate(dentry, inode); | 388 | d_instantiate(dentry, inode); |
@@ -593,7 +589,7 @@ spufs_create_root(struct super_block *sb, void *data) | |||
593 | if (!inode) | 589 | if (!inode) |
594 | goto out; | 590 | goto out; |
595 | 591 | ||
596 | inode->i_op = &spufs_dir_inode_operations; | 592 | inode->i_op = &simple_dir_inode_operations; |
597 | inode->i_fop = &simple_dir_operations; | 593 | inode->i_fop = &simple_dir_operations; |
598 | SPUFS_I(inode)->i_ctx = NULL; | 594 | SPUFS_I(inode)->i_ctx = NULL; |
599 | 595 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 57626600b1a4..58ae13b7de84 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -29,7 +29,8 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat) | |||
29 | spu = ctx->spu; | 29 | spu = ctx->spu; |
30 | pte_fault = spu->dsisr & | 30 | pte_fault = spu->dsisr & |
31 | (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); | 31 | (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); |
32 | return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; | 32 | return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? |
33 | 1 : 0; | ||
33 | } | 34 | } |
34 | 35 | ||
35 | static int spu_setup_isolated(struct spu_context *ctx) | 36 | static int spu_setup_isolated(struct spu_context *ctx) |
@@ -142,8 +143,11 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc) | |||
142 | runcntl = SPU_RUNCNTL_RUNNABLE; | 143 | runcntl = SPU_RUNCNTL_RUNNABLE; |
143 | ctx->ops->runcntl_write(ctx, runcntl); | 144 | ctx->ops->runcntl_write(ctx, runcntl); |
144 | } else { | 145 | } else { |
145 | spu_start_tick(ctx); | 146 | unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL; |
146 | ctx->ops->npc_write(ctx, *npc); | 147 | ctx->ops->npc_write(ctx, *npc); |
148 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
149 | mode = SPU_PRIVCNTL_MODE_SINGLE_STEP; | ||
150 | out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode); | ||
147 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | 151 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); |
148 | } | 152 | } |
149 | 153 | ||
@@ -155,7 +159,6 @@ static int spu_run_fini(struct spu_context *ctx, u32 * npc, | |||
155 | { | 159 | { |
156 | int ret = 0; | 160 | int ret = 0; |
157 | 161 | ||
158 | spu_stop_tick(ctx); | ||
159 | *status = ctx->ops->status_read(ctx); | 162 | *status = ctx->ops->status_read(ctx); |
160 | *npc = ctx->ops->npc_read(ctx); | 163 | *npc = ctx->ops->npc_read(ctx); |
161 | spu_release(ctx); | 164 | spu_release(ctx); |
@@ -298,9 +301,22 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, | |||
298 | ctx->ops->master_start(ctx); | 301 | ctx->ops->master_start(ctx); |
299 | ctx->event_return = 0; | 302 | ctx->event_return = 0; |
300 | 303 | ||
301 | ret = spu_acquire_runnable(ctx, 0); | 304 | spu_acquire(ctx); |
302 | if (ret) | 305 | if (ctx->state == SPU_STATE_SAVED) { |
303 | return ret; | 306 | __spu_update_sched_info(ctx); |
307 | |||
308 | ret = spu_activate(ctx, 0); | ||
309 | if (ret) { | ||
310 | spu_release(ctx); | ||
311 | goto out; | ||
312 | } | ||
313 | } else { | ||
314 | /* | ||
315 | * We have to update the scheduling priority under active_mutex | ||
316 | * to protect against find_victim(). | ||
317 | */ | ||
318 | spu_update_sched_info(ctx); | ||
319 | } | ||
304 | 320 | ||
305 | ret = spu_run_init(ctx, npc); | 321 | ret = spu_run_init(ctx, npc); |
306 | if (ret) { | 322 | if (ret) { |
@@ -325,16 +341,20 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, | |||
325 | 341 | ||
326 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | 342 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { |
327 | ret = spu_reacquire_runnable(ctx, npc, &status); | 343 | ret = spu_reacquire_runnable(ctx, npc, &status); |
328 | if (ret) { | 344 | if (ret) |
329 | spu_stop_tick(ctx); | ||
330 | goto out2; | 345 | goto out2; |
331 | } | ||
332 | continue; | 346 | continue; |
333 | } | 347 | } |
334 | ret = spu_process_events(ctx); | 348 | ret = spu_process_events(ctx); |
335 | 349 | ||
336 | } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | | 350 | } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | |
337 | SPU_STATUS_STOPPED_BY_HALT))); | 351 | SPU_STATUS_STOPPED_BY_HALT | |
352 | SPU_STATUS_SINGLE_STEP))); | ||
353 | |||
354 | if ((status & SPU_STATUS_STOPPED_BY_STOP) && | ||
355 | (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && | ||
356 | (ctx->state == SPU_STATE_RUNNABLE)) | ||
357 | ctx->stats.libassist++; | ||
338 | 358 | ||
339 | ctx->ops->master_stop(ctx); | 359 | ctx->ops->master_stop(ctx); |
340 | ret = spu_run_fini(ctx, npc, &status); | 360 | ret = spu_run_fini(ctx, npc, &status); |
@@ -344,10 +364,15 @@ out2: | |||
344 | if ((ret == 0) || | 364 | if ((ret == 0) || |
345 | ((ret == -ERESTARTSYS) && | 365 | ((ret == -ERESTARTSYS) && |
346 | ((status & SPU_STATUS_STOPPED_BY_HALT) || | 366 | ((status & SPU_STATUS_STOPPED_BY_HALT) || |
367 | (status & SPU_STATUS_SINGLE_STEP) || | ||
347 | ((status & SPU_STATUS_STOPPED_BY_STOP) && | 368 | ((status & SPU_STATUS_STOPPED_BY_STOP) && |
348 | (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) | 369 | (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) |
349 | ret = status; | 370 | ret = status; |
350 | 371 | ||
372 | /* Note: we don't need to force_sig SIGTRAP on single-step | ||
373 | * since we have TIF_SINGLESTEP set, thus the kernel will do | ||
374 | * it upon return from the syscall anyawy | ||
375 | */ | ||
351 | if ((status & SPU_STATUS_STOPPED_BY_STOP) | 376 | if ((status & SPU_STATUS_STOPPED_BY_STOP) |
352 | && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { | 377 | && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { |
353 | force_sig(SIGTRAP, current); | 378 | force_sig(SIGTRAP, current); |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 3b831e07f1ed..e5b4dd1db286 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -35,6 +35,10 @@ | |||
35 | #include <linux/numa.h> | 35 | #include <linux/numa.h> |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/notifier.h> | 37 | #include <linux/notifier.h> |
38 | #include <linux/kthread.h> | ||
39 | #include <linux/pid_namespace.h> | ||
40 | #include <linux/proc_fs.h> | ||
41 | #include <linux/seq_file.h> | ||
38 | 42 | ||
39 | #include <asm/io.h> | 43 | #include <asm/io.h> |
40 | #include <asm/mmu_context.h> | 44 | #include <asm/mmu_context.h> |
@@ -43,54 +47,126 @@ | |||
43 | #include <asm/spu_priv1.h> | 47 | #include <asm/spu_priv1.h> |
44 | #include "spufs.h" | 48 | #include "spufs.h" |
45 | 49 | ||
46 | #define SPU_TIMESLICE (HZ) | ||
47 | |||
48 | struct spu_prio_array { | 50 | struct spu_prio_array { |
49 | DECLARE_BITMAP(bitmap, MAX_PRIO); | 51 | DECLARE_BITMAP(bitmap, MAX_PRIO); |
50 | struct list_head runq[MAX_PRIO]; | 52 | struct list_head runq[MAX_PRIO]; |
51 | spinlock_t runq_lock; | 53 | spinlock_t runq_lock; |
52 | struct list_head active_list[MAX_NUMNODES]; | 54 | struct list_head active_list[MAX_NUMNODES]; |
53 | struct mutex active_mutex[MAX_NUMNODES]; | 55 | struct mutex active_mutex[MAX_NUMNODES]; |
56 | int nr_active[MAX_NUMNODES]; | ||
57 | int nr_waiting; | ||
54 | }; | 58 | }; |
55 | 59 | ||
60 | static unsigned long spu_avenrun[3]; | ||
56 | static struct spu_prio_array *spu_prio; | 61 | static struct spu_prio_array *spu_prio; |
57 | static struct workqueue_struct *spu_sched_wq; | 62 | static struct task_struct *spusched_task; |
63 | static struct timer_list spusched_timer; | ||
64 | |||
65 | /* | ||
66 | * Priority of a normal, non-rt, non-niced'd process (aka nice level 0). | ||
67 | */ | ||
68 | #define NORMAL_PRIO 120 | ||
69 | |||
70 | /* | ||
71 | * Frequency of the spu scheduler tick. By default we do one SPU scheduler | ||
72 | * tick for every 10 CPU scheduler ticks. | ||
73 | */ | ||
74 | #define SPUSCHED_TICK (10) | ||
58 | 75 | ||
59 | static inline int node_allowed(int node) | 76 | /* |
77 | * These are the 'tuning knobs' of the scheduler: | ||
78 | * | ||
79 | * Minimum timeslice is 5 msecs (or 1 spu scheduler tick, whichever is | ||
80 | * larger), default timeslice is 100 msecs, maximum timeslice is 800 msecs. | ||
81 | */ | ||
82 | #define MIN_SPU_TIMESLICE max(5 * HZ / (1000 * SPUSCHED_TICK), 1) | ||
83 | #define DEF_SPU_TIMESLICE (100 * HZ / (1000 * SPUSCHED_TICK)) | ||
84 | |||
85 | #define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO) | ||
86 | #define SCALE_PRIO(x, prio) \ | ||
87 | max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE) | ||
88 | |||
89 | /* | ||
90 | * scale user-nice values [ -20 ... 0 ... 19 ] to time slice values: | ||
91 | * [800ms ... 100ms ... 5ms] | ||
92 | * | ||
93 | * The higher a thread's priority, the bigger timeslices | ||
94 | * it gets during one round of execution. But even the lowest | ||
95 | * priority thread gets MIN_TIMESLICE worth of execution time. | ||
96 | */ | ||
97 | void spu_set_timeslice(struct spu_context *ctx) | ||
60 | { | 98 | { |
61 | cpumask_t mask; | 99 | if (ctx->prio < NORMAL_PRIO) |
100 | ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE * 4, ctx->prio); | ||
101 | else | ||
102 | ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio); | ||
103 | } | ||
62 | 104 | ||
63 | if (!nr_cpus_node(node)) | 105 | /* |
64 | return 0; | 106 | * Update scheduling information from the owning thread. |
65 | mask = node_to_cpumask(node); | 107 | */ |
66 | if (!cpus_intersects(mask, current->cpus_allowed)) | 108 | void __spu_update_sched_info(struct spu_context *ctx) |
67 | return 0; | 109 | { |
68 | return 1; | 110 | /* |
111 | * 32-Bit assignment are atomic on powerpc, and we don't care about | ||
112 | * memory ordering here because retriving the controlling thread is | ||
113 | * per defintion racy. | ||
114 | */ | ||
115 | ctx->tid = current->pid; | ||
116 | |||
117 | /* | ||
118 | * We do our own priority calculations, so we normally want | ||
119 | * ->static_prio to start with. Unfortunately thies field | ||
120 | * contains junk for threads with a realtime scheduling | ||
121 | * policy so we have to look at ->prio in this case. | ||
122 | */ | ||
123 | if (rt_prio(current->prio)) | ||
124 | ctx->prio = current->prio; | ||
125 | else | ||
126 | ctx->prio = current->static_prio; | ||
127 | ctx->policy = current->policy; | ||
128 | |||
129 | /* | ||
130 | * A lot of places that don't hold active_mutex poke into | ||
131 | * cpus_allowed, including grab_runnable_context which | ||
132 | * already holds the runq_lock. So abuse runq_lock | ||
133 | * to protect this field aswell. | ||
134 | */ | ||
135 | spin_lock(&spu_prio->runq_lock); | ||
136 | ctx->cpus_allowed = current->cpus_allowed; | ||
137 | spin_unlock(&spu_prio->runq_lock); | ||
69 | } | 138 | } |
70 | 139 | ||
71 | void spu_start_tick(struct spu_context *ctx) | 140 | void spu_update_sched_info(struct spu_context *ctx) |
72 | { | 141 | { |
73 | if (ctx->policy == SCHED_RR) { | 142 | int node = ctx->spu->node; |
74 | /* | 143 | |
75 | * Make sure the exiting bit is cleared. | 144 | mutex_lock(&spu_prio->active_mutex[node]); |
76 | */ | 145 | __spu_update_sched_info(ctx); |
77 | clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags); | 146 | mutex_unlock(&spu_prio->active_mutex[node]); |
78 | mb(); | ||
79 | queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); | ||
80 | } | ||
81 | } | 147 | } |
82 | 148 | ||
83 | void spu_stop_tick(struct spu_context *ctx) | 149 | static int __node_allowed(struct spu_context *ctx, int node) |
84 | { | 150 | { |
85 | if (ctx->policy == SCHED_RR) { | 151 | if (nr_cpus_node(node)) { |
86 | /* | 152 | cpumask_t mask = node_to_cpumask(node); |
87 | * While the work can be rearming normally setting this flag | 153 | |
88 | * makes sure it does not rearm itself anymore. | 154 | if (cpus_intersects(mask, ctx->cpus_allowed)) |
89 | */ | 155 | return 1; |
90 | set_bit(SPU_SCHED_EXITING, &ctx->sched_flags); | ||
91 | mb(); | ||
92 | cancel_delayed_work(&ctx->sched_work); | ||
93 | } | 156 | } |
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int node_allowed(struct spu_context *ctx, int node) | ||
162 | { | ||
163 | int rval; | ||
164 | |||
165 | spin_lock(&spu_prio->runq_lock); | ||
166 | rval = __node_allowed(ctx, node); | ||
167 | spin_unlock(&spu_prio->runq_lock); | ||
168 | |||
169 | return rval; | ||
94 | } | 170 | } |
95 | 171 | ||
96 | /** | 172 | /** |
@@ -99,9 +175,18 @@ void spu_stop_tick(struct spu_context *ctx) | |||
99 | */ | 175 | */ |
100 | static void spu_add_to_active_list(struct spu *spu) | 176 | static void spu_add_to_active_list(struct spu *spu) |
101 | { | 177 | { |
102 | mutex_lock(&spu_prio->active_mutex[spu->node]); | 178 | int node = spu->node; |
103 | list_add_tail(&spu->list, &spu_prio->active_list[spu->node]); | 179 | |
104 | mutex_unlock(&spu_prio->active_mutex[spu->node]); | 180 | mutex_lock(&spu_prio->active_mutex[node]); |
181 | spu_prio->nr_active[node]++; | ||
182 | list_add_tail(&spu->list, &spu_prio->active_list[node]); | ||
183 | mutex_unlock(&spu_prio->active_mutex[node]); | ||
184 | } | ||
185 | |||
186 | static void __spu_remove_from_active_list(struct spu *spu) | ||
187 | { | ||
188 | list_del_init(&spu->list); | ||
189 | spu_prio->nr_active[spu->node]--; | ||
105 | } | 190 | } |
106 | 191 | ||
107 | /** | 192 | /** |
@@ -113,7 +198,7 @@ static void spu_remove_from_active_list(struct spu *spu) | |||
113 | int node = spu->node; | 198 | int node = spu->node; |
114 | 199 | ||
115 | mutex_lock(&spu_prio->active_mutex[node]); | 200 | mutex_lock(&spu_prio->active_mutex[node]); |
116 | list_del_init(&spu->list); | 201 | __spu_remove_from_active_list(spu); |
117 | mutex_unlock(&spu_prio->active_mutex[node]); | 202 | mutex_unlock(&spu_prio->active_mutex[node]); |
118 | } | 203 | } |
119 | 204 | ||
@@ -144,6 +229,10 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) | |||
144 | { | 229 | { |
145 | pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, | 230 | pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, |
146 | spu->number, spu->node); | 231 | spu->number, spu->node); |
232 | |||
233 | ctx->stats.slb_flt_base = spu->stats.slb_flt; | ||
234 | ctx->stats.class2_intr_base = spu->stats.class2_intr; | ||
235 | |||
147 | spu->ctx = ctx; | 236 | spu->ctx = ctx; |
148 | spu->flags = 0; | 237 | spu->flags = 0; |
149 | ctx->spu = spu; | 238 | ctx->spu = spu; |
@@ -161,8 +250,8 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) | |||
161 | spu->timestamp = jiffies; | 250 | spu->timestamp = jiffies; |
162 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); | 251 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); |
163 | spu_switch_notify(spu, ctx); | 252 | spu_switch_notify(spu, ctx); |
164 | spu_add_to_active_list(spu); | ||
165 | ctx->state = SPU_STATE_RUNNABLE; | 253 | ctx->state = SPU_STATE_RUNNABLE; |
254 | spu_switch_state(spu, SPU_UTIL_SYSTEM); | ||
166 | } | 255 | } |
167 | 256 | ||
168 | /** | 257 | /** |
@@ -175,7 +264,8 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
175 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, | 264 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, |
176 | spu->pid, spu->number, spu->node); | 265 | spu->pid, spu->number, spu->node); |
177 | 266 | ||
178 | spu_remove_from_active_list(spu); | 267 | spu_switch_state(spu, SPU_UTIL_IDLE); |
268 | |||
179 | spu_switch_notify(spu, NULL); | 269 | spu_switch_notify(spu, NULL); |
180 | spu_unmap_mappings(ctx); | 270 | spu_unmap_mappings(ctx); |
181 | spu_save(&ctx->csa, spu); | 271 | spu_save(&ctx->csa, spu); |
@@ -192,6 +282,11 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
192 | ctx->spu = NULL; | 282 | ctx->spu = NULL; |
193 | spu->flags = 0; | 283 | spu->flags = 0; |
194 | spu->ctx = NULL; | 284 | spu->ctx = NULL; |
285 | |||
286 | ctx->stats.slb_flt += | ||
287 | (spu->stats.slb_flt - ctx->stats.slb_flt_base); | ||
288 | ctx->stats.class2_intr += | ||
289 | (spu->stats.class2_intr - ctx->stats.class2_intr_base); | ||
195 | } | 290 | } |
196 | 291 | ||
197 | /** | 292 | /** |
@@ -200,20 +295,39 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
200 | */ | 295 | */ |
201 | static void __spu_add_to_rq(struct spu_context *ctx) | 296 | static void __spu_add_to_rq(struct spu_context *ctx) |
202 | { | 297 | { |
203 | int prio = ctx->prio; | 298 | /* |
204 | 299 | * Unfortunately this code path can be called from multiple threads | |
205 | list_add_tail(&ctx->rq, &spu_prio->runq[prio]); | 300 | * on behalf of a single context due to the way the problem state |
206 | set_bit(prio, spu_prio->bitmap); | 301 | * mmap support works. |
302 | * | ||
303 | * Fortunately we need to wake up all these threads at the same time | ||
304 | * and can simply skip the runqueue addition for every but the first | ||
305 | * thread getting into this codepath. | ||
306 | * | ||
307 | * It's still quite hacky, and long-term we should proxy all other | ||
308 | * threads through the owner thread so that spu_run is in control | ||
309 | * of all the scheduling activity for a given context. | ||
310 | */ | ||
311 | if (list_empty(&ctx->rq)) { | ||
312 | list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); | ||
313 | set_bit(ctx->prio, spu_prio->bitmap); | ||
314 | if (!spu_prio->nr_waiting++) | ||
315 | __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); | ||
316 | } | ||
207 | } | 317 | } |
208 | 318 | ||
209 | static void __spu_del_from_rq(struct spu_context *ctx) | 319 | static void __spu_del_from_rq(struct spu_context *ctx) |
210 | { | 320 | { |
211 | int prio = ctx->prio; | 321 | int prio = ctx->prio; |
212 | 322 | ||
213 | if (!list_empty(&ctx->rq)) | 323 | if (!list_empty(&ctx->rq)) { |
324 | if (!--spu_prio->nr_waiting) | ||
325 | del_timer(&spusched_timer); | ||
214 | list_del_init(&ctx->rq); | 326 | list_del_init(&ctx->rq); |
215 | if (list_empty(&spu_prio->runq[prio])) | 327 | |
216 | clear_bit(prio, spu_prio->bitmap); | 328 | if (list_empty(&spu_prio->runq[prio])) |
329 | clear_bit(prio, spu_prio->bitmap); | ||
330 | } | ||
217 | } | 331 | } |
218 | 332 | ||
219 | static void spu_prio_wait(struct spu_context *ctx) | 333 | static void spu_prio_wait(struct spu_context *ctx) |
@@ -244,7 +358,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx) | |||
244 | 358 | ||
245 | for (n = 0; n < MAX_NUMNODES; n++, node++) { | 359 | for (n = 0; n < MAX_NUMNODES; n++, node++) { |
246 | node = (node < MAX_NUMNODES) ? node : 0; | 360 | node = (node < MAX_NUMNODES) ? node : 0; |
247 | if (!node_allowed(node)) | 361 | if (!node_allowed(ctx, node)) |
248 | continue; | 362 | continue; |
249 | spu = spu_alloc_node(node); | 363 | spu = spu_alloc_node(node); |
250 | if (spu) | 364 | if (spu) |
@@ -276,15 +390,15 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
276 | node = cpu_to_node(raw_smp_processor_id()); | 390 | node = cpu_to_node(raw_smp_processor_id()); |
277 | for (n = 0; n < MAX_NUMNODES; n++, node++) { | 391 | for (n = 0; n < MAX_NUMNODES; n++, node++) { |
278 | node = (node < MAX_NUMNODES) ? node : 0; | 392 | node = (node < MAX_NUMNODES) ? node : 0; |
279 | if (!node_allowed(node)) | 393 | if (!node_allowed(ctx, node)) |
280 | continue; | 394 | continue; |
281 | 395 | ||
282 | mutex_lock(&spu_prio->active_mutex[node]); | 396 | mutex_lock(&spu_prio->active_mutex[node]); |
283 | list_for_each_entry(spu, &spu_prio->active_list[node], list) { | 397 | list_for_each_entry(spu, &spu_prio->active_list[node], list) { |
284 | struct spu_context *tmp = spu->ctx; | 398 | struct spu_context *tmp = spu->ctx; |
285 | 399 | ||
286 | if (tmp->rt_priority < ctx->rt_priority && | 400 | if (tmp->prio > ctx->prio && |
287 | (!victim || tmp->rt_priority < victim->rt_priority)) | 401 | (!victim || tmp->prio > victim->prio)) |
288 | victim = spu->ctx; | 402 | victim = spu->ctx; |
289 | } | 403 | } |
290 | mutex_unlock(&spu_prio->active_mutex[node]); | 404 | mutex_unlock(&spu_prio->active_mutex[node]); |
@@ -312,7 +426,10 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
312 | victim = NULL; | 426 | victim = NULL; |
313 | goto restart; | 427 | goto restart; |
314 | } | 428 | } |
429 | spu_remove_from_active_list(spu); | ||
315 | spu_unbind_context(spu, victim); | 430 | spu_unbind_context(spu, victim); |
431 | victim->stats.invol_ctx_switch++; | ||
432 | spu->stats.invol_ctx_switch++; | ||
316 | mutex_unlock(&victim->state_mutex); | 433 | mutex_unlock(&victim->state_mutex); |
317 | /* | 434 | /* |
318 | * We need to break out of the wait loop in spu_run | 435 | * We need to break out of the wait loop in spu_run |
@@ -338,22 +455,30 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
338 | */ | 455 | */ |
339 | int spu_activate(struct spu_context *ctx, unsigned long flags) | 456 | int spu_activate(struct spu_context *ctx, unsigned long flags) |
340 | { | 457 | { |
341 | 458 | spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); | |
342 | if (ctx->spu) | ||
343 | return 0; | ||
344 | 459 | ||
345 | do { | 460 | do { |
346 | struct spu *spu; | 461 | struct spu *spu; |
347 | 462 | ||
463 | /* | ||
464 | * If there are multiple threads waiting for a single context | ||
465 | * only one actually binds the context while the others will | ||
466 | * only be able to acquire the state_mutex once the context | ||
467 | * already is in runnable state. | ||
468 | */ | ||
469 | if (ctx->spu) | ||
470 | return 0; | ||
471 | |||
348 | spu = spu_get_idle(ctx); | 472 | spu = spu_get_idle(ctx); |
349 | /* | 473 | /* |
350 | * If this is a realtime thread we try to get it running by | 474 | * If this is a realtime thread we try to get it running by |
351 | * preempting a lower priority thread. | 475 | * preempting a lower priority thread. |
352 | */ | 476 | */ |
353 | if (!spu && ctx->rt_priority) | 477 | if (!spu && rt_prio(ctx->prio)) |
354 | spu = find_victim(ctx); | 478 | spu = find_victim(ctx); |
355 | if (spu) { | 479 | if (spu) { |
356 | spu_bind_context(spu, ctx); | 480 | spu_bind_context(spu, ctx); |
481 | spu_add_to_active_list(spu); | ||
357 | return 0; | 482 | return 0; |
358 | } | 483 | } |
359 | 484 | ||
@@ -369,23 +494,28 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) | |||
369 | * Remove the highest priority context on the runqueue and return it | 494 | * Remove the highest priority context on the runqueue and return it |
370 | * to the caller. Returns %NULL if no runnable context was found. | 495 | * to the caller. Returns %NULL if no runnable context was found. |
371 | */ | 496 | */ |
372 | static struct spu_context *grab_runnable_context(int prio) | 497 | static struct spu_context *grab_runnable_context(int prio, int node) |
373 | { | 498 | { |
374 | struct spu_context *ctx = NULL; | 499 | struct spu_context *ctx; |
375 | int best; | 500 | int best; |
376 | 501 | ||
377 | spin_lock(&spu_prio->runq_lock); | 502 | spin_lock(&spu_prio->runq_lock); |
378 | best = sched_find_first_bit(spu_prio->bitmap); | 503 | best = sched_find_first_bit(spu_prio->bitmap); |
379 | if (best < prio) { | 504 | while (best < prio) { |
380 | struct list_head *rq = &spu_prio->runq[best]; | 505 | struct list_head *rq = &spu_prio->runq[best]; |
381 | 506 | ||
382 | BUG_ON(list_empty(rq)); | 507 | list_for_each_entry(ctx, rq, rq) { |
383 | 508 | /* XXX(hch): check for affinity here aswell */ | |
384 | ctx = list_entry(rq->next, struct spu_context, rq); | 509 | if (__node_allowed(ctx, node)) { |
385 | __spu_del_from_rq(ctx); | 510 | __spu_del_from_rq(ctx); |
511 | goto found; | ||
512 | } | ||
513 | } | ||
514 | best++; | ||
386 | } | 515 | } |
516 | ctx = NULL; | ||
517 | found: | ||
387 | spin_unlock(&spu_prio->runq_lock); | 518 | spin_unlock(&spu_prio->runq_lock); |
388 | |||
389 | return ctx; | 519 | return ctx; |
390 | } | 520 | } |
391 | 521 | ||
@@ -395,9 +525,12 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) | |||
395 | struct spu_context *new = NULL; | 525 | struct spu_context *new = NULL; |
396 | 526 | ||
397 | if (spu) { | 527 | if (spu) { |
398 | new = grab_runnable_context(max_prio); | 528 | new = grab_runnable_context(max_prio, spu->node); |
399 | if (new || force) { | 529 | if (new || force) { |
530 | spu_remove_from_active_list(spu); | ||
400 | spu_unbind_context(spu, ctx); | 531 | spu_unbind_context(spu, ctx); |
532 | ctx->stats.vol_ctx_switch++; | ||
533 | spu->stats.vol_ctx_switch++; | ||
401 | spu_free(spu); | 534 | spu_free(spu); |
402 | if (new) | 535 | if (new) |
403 | wake_up(&new->stop_wq); | 536 | wake_up(&new->stop_wq); |
@@ -417,7 +550,17 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) | |||
417 | */ | 550 | */ |
418 | void spu_deactivate(struct spu_context *ctx) | 551 | void spu_deactivate(struct spu_context *ctx) |
419 | { | 552 | { |
553 | /* | ||
554 | * We must never reach this for a nosched context, | ||
555 | * but handle the case gracefull instead of panicing. | ||
556 | */ | ||
557 | if (ctx->flags & SPU_CREATE_NOSCHED) { | ||
558 | WARN_ON(1); | ||
559 | return; | ||
560 | } | ||
561 | |||
420 | __spu_deactivate(ctx, 1, MAX_PRIO); | 562 | __spu_deactivate(ctx, 1, MAX_PRIO); |
563 | spuctx_switch_state(ctx, SPUCTX_UTIL_USER); | ||
421 | } | 564 | } |
422 | 565 | ||
423 | /** | 566 | /** |
@@ -432,56 +575,178 @@ void spu_yield(struct spu_context *ctx) | |||
432 | { | 575 | { |
433 | if (!(ctx->flags & SPU_CREATE_NOSCHED)) { | 576 | if (!(ctx->flags & SPU_CREATE_NOSCHED)) { |
434 | mutex_lock(&ctx->state_mutex); | 577 | mutex_lock(&ctx->state_mutex); |
435 | __spu_deactivate(ctx, 0, MAX_PRIO); | 578 | if (__spu_deactivate(ctx, 0, MAX_PRIO)) |
579 | spuctx_switch_state(ctx, SPUCTX_UTIL_USER); | ||
580 | else { | ||
581 | spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); | ||
582 | spu_switch_state(ctx->spu, SPU_UTIL_USER); | ||
583 | } | ||
436 | mutex_unlock(&ctx->state_mutex); | 584 | mutex_unlock(&ctx->state_mutex); |
437 | } | 585 | } |
438 | } | 586 | } |
439 | 587 | ||
440 | void spu_sched_tick(struct work_struct *work) | 588 | static void spusched_tick(struct spu_context *ctx) |
441 | { | 589 | { |
442 | struct spu_context *ctx = | 590 | if (ctx->flags & SPU_CREATE_NOSCHED) |
443 | container_of(work, struct spu_context, sched_work.work); | 591 | return; |
444 | int preempted; | 592 | if (ctx->policy == SCHED_FIFO) |
593 | return; | ||
594 | |||
595 | if (--ctx->time_slice) | ||
596 | return; | ||
445 | 597 | ||
446 | /* | 598 | /* |
447 | * If this context is being stopped avoid rescheduling from the | 599 | * Unfortunately active_mutex ranks outside of state_mutex, so |
448 | * scheduler tick because we would block on the state_mutex. | 600 | * we have to trylock here. If we fail give the context another |
449 | * The caller will yield the spu later on anyway. | 601 | * tick and try again. |
450 | */ | 602 | */ |
451 | if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) | 603 | if (mutex_trylock(&ctx->state_mutex)) { |
452 | return; | 604 | struct spu *spu = ctx->spu; |
605 | struct spu_context *new; | ||
453 | 606 | ||
454 | mutex_lock(&ctx->state_mutex); | 607 | new = grab_runnable_context(ctx->prio + 1, spu->node); |
455 | preempted = __spu_deactivate(ctx, 0, ctx->prio + 1); | 608 | if (new) { |
456 | mutex_unlock(&ctx->state_mutex); | ||
457 | 609 | ||
458 | if (preempted) { | 610 | __spu_remove_from_active_list(spu); |
459 | /* | 611 | spu_unbind_context(spu, ctx); |
460 | * We need to break out of the wait loop in spu_run manually | 612 | ctx->stats.invol_ctx_switch++; |
461 | * to ensure this context gets put on the runqueue again | 613 | spu->stats.invol_ctx_switch++; |
462 | * ASAP. | 614 | spu_free(spu); |
463 | */ | 615 | wake_up(&new->stop_wq); |
464 | wake_up(&ctx->stop_wq); | 616 | /* |
617 | * We need to break out of the wait loop in | ||
618 | * spu_run manually to ensure this context | ||
619 | * gets put on the runqueue again ASAP. | ||
620 | */ | ||
621 | wake_up(&ctx->stop_wq); | ||
622 | } | ||
623 | spu_set_timeslice(ctx); | ||
624 | mutex_unlock(&ctx->state_mutex); | ||
465 | } else { | 625 | } else { |
466 | spu_start_tick(ctx); | 626 | ctx->time_slice++; |
467 | } | 627 | } |
468 | } | 628 | } |
469 | 629 | ||
470 | int __init spu_sched_init(void) | 630 | /** |
631 | * count_active_contexts - count nr of active tasks | ||
632 | * | ||
633 | * Return the number of tasks currently running or waiting to run. | ||
634 | * | ||
635 | * Note that we don't take runq_lock / active_mutex here. Reading | ||
636 | * a single 32bit value is atomic on powerpc, and we don't care | ||
637 | * about memory ordering issues here. | ||
638 | */ | ||
639 | static unsigned long count_active_contexts(void) | ||
471 | { | 640 | { |
472 | int i; | 641 | int nr_active = 0, node; |
473 | 642 | ||
474 | spu_sched_wq = create_singlethread_workqueue("spusched"); | 643 | for (node = 0; node < MAX_NUMNODES; node++) |
475 | if (!spu_sched_wq) | 644 | nr_active += spu_prio->nr_active[node]; |
476 | return 1; | 645 | nr_active += spu_prio->nr_waiting; |
477 | 646 | ||
478 | spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); | 647 | return nr_active; |
479 | if (!spu_prio) { | 648 | } |
480 | printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", | 649 | |
481 | __FUNCTION__); | 650 | /** |
482 | destroy_workqueue(spu_sched_wq); | 651 | * spu_calc_load - given tick count, update the avenrun load estimates. |
483 | return 1; | 652 | * @tick: tick count |
653 | * | ||
654 | * No locking against reading these values from userspace, as for | ||
655 | * the CPU loadavg code. | ||
656 | */ | ||
657 | static void spu_calc_load(unsigned long ticks) | ||
658 | { | ||
659 | unsigned long active_tasks; /* fixed-point */ | ||
660 | static int count = LOAD_FREQ; | ||
661 | |||
662 | count -= ticks; | ||
663 | |||
664 | if (unlikely(count < 0)) { | ||
665 | active_tasks = count_active_contexts() * FIXED_1; | ||
666 | do { | ||
667 | CALC_LOAD(spu_avenrun[0], EXP_1, active_tasks); | ||
668 | CALC_LOAD(spu_avenrun[1], EXP_5, active_tasks); | ||
669 | CALC_LOAD(spu_avenrun[2], EXP_15, active_tasks); | ||
670 | count += LOAD_FREQ; | ||
671 | } while (count < 0); | ||
484 | } | 672 | } |
673 | } | ||
674 | |||
675 | static void spusched_wake(unsigned long data) | ||
676 | { | ||
677 | mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); | ||
678 | wake_up_process(spusched_task); | ||
679 | spu_calc_load(SPUSCHED_TICK); | ||
680 | } | ||
681 | |||
682 | static int spusched_thread(void *unused) | ||
683 | { | ||
684 | struct spu *spu, *next; | ||
685 | int node; | ||
686 | |||
687 | while (!kthread_should_stop()) { | ||
688 | set_current_state(TASK_INTERRUPTIBLE); | ||
689 | schedule(); | ||
690 | for (node = 0; node < MAX_NUMNODES; node++) { | ||
691 | mutex_lock(&spu_prio->active_mutex[node]); | ||
692 | list_for_each_entry_safe(spu, next, | ||
693 | &spu_prio->active_list[node], | ||
694 | list) | ||
695 | spusched_tick(spu->ctx); | ||
696 | mutex_unlock(&spu_prio->active_mutex[node]); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | #define LOAD_INT(x) ((x) >> FSHIFT) | ||
704 | #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) | ||
705 | |||
706 | static int show_spu_loadavg(struct seq_file *s, void *private) | ||
707 | { | ||
708 | int a, b, c; | ||
709 | |||
710 | a = spu_avenrun[0] + (FIXED_1/200); | ||
711 | b = spu_avenrun[1] + (FIXED_1/200); | ||
712 | c = spu_avenrun[2] + (FIXED_1/200); | ||
713 | |||
714 | /* | ||
715 | * Note that last_pid doesn't really make much sense for the | ||
716 | * SPU loadavg (it even seems very odd on the CPU side..), | ||
717 | * but we include it here to have a 100% compatible interface. | ||
718 | */ | ||
719 | seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n", | ||
720 | LOAD_INT(a), LOAD_FRAC(a), | ||
721 | LOAD_INT(b), LOAD_FRAC(b), | ||
722 | LOAD_INT(c), LOAD_FRAC(c), | ||
723 | count_active_contexts(), | ||
724 | atomic_read(&nr_spu_contexts), | ||
725 | current->nsproxy->pid_ns->last_pid); | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int spu_loadavg_open(struct inode *inode, struct file *file) | ||
730 | { | ||
731 | return single_open(file, show_spu_loadavg, NULL); | ||
732 | } | ||
733 | |||
734 | static const struct file_operations spu_loadavg_fops = { | ||
735 | .open = spu_loadavg_open, | ||
736 | .read = seq_read, | ||
737 | .llseek = seq_lseek, | ||
738 | .release = single_release, | ||
739 | }; | ||
740 | |||
741 | int __init spu_sched_init(void) | ||
742 | { | ||
743 | struct proc_dir_entry *entry; | ||
744 | int err = -ENOMEM, i; | ||
745 | |||
746 | spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); | ||
747 | if (!spu_prio) | ||
748 | goto out; | ||
749 | |||
485 | for (i = 0; i < MAX_PRIO; i++) { | 750 | for (i = 0; i < MAX_PRIO; i++) { |
486 | INIT_LIST_HEAD(&spu_prio->runq[i]); | 751 | INIT_LIST_HEAD(&spu_prio->runq[i]); |
487 | __clear_bit(i, spu_prio->bitmap); | 752 | __clear_bit(i, spu_prio->bitmap); |
@@ -492,7 +757,30 @@ int __init spu_sched_init(void) | |||
492 | INIT_LIST_HEAD(&spu_prio->active_list[i]); | 757 | INIT_LIST_HEAD(&spu_prio->active_list[i]); |
493 | } | 758 | } |
494 | spin_lock_init(&spu_prio->runq_lock); | 759 | spin_lock_init(&spu_prio->runq_lock); |
760 | |||
761 | setup_timer(&spusched_timer, spusched_wake, 0); | ||
762 | |||
763 | spusched_task = kthread_run(spusched_thread, NULL, "spusched"); | ||
764 | if (IS_ERR(spusched_task)) { | ||
765 | err = PTR_ERR(spusched_task); | ||
766 | goto out_free_spu_prio; | ||
767 | } | ||
768 | |||
769 | entry = create_proc_entry("spu_loadavg", 0, NULL); | ||
770 | if (!entry) | ||
771 | goto out_stop_kthread; | ||
772 | entry->proc_fops = &spu_loadavg_fops; | ||
773 | |||
774 | pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n", | ||
775 | SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE); | ||
495 | return 0; | 776 | return 0; |
777 | |||
778 | out_stop_kthread: | ||
779 | kthread_stop(spusched_task); | ||
780 | out_free_spu_prio: | ||
781 | kfree(spu_prio); | ||
782 | out: | ||
783 | return err; | ||
496 | } | 784 | } |
497 | 785 | ||
498 | void __exit spu_sched_exit(void) | 786 | void __exit spu_sched_exit(void) |
@@ -500,6 +788,11 @@ void __exit spu_sched_exit(void) | |||
500 | struct spu *spu, *tmp; | 788 | struct spu *spu, *tmp; |
501 | int node; | 789 | int node; |
502 | 790 | ||
791 | remove_proc_entry("spu_loadavg", NULL); | ||
792 | |||
793 | del_timer_sync(&spusched_timer); | ||
794 | kthread_stop(spusched_task); | ||
795 | |||
503 | for (node = 0; node < MAX_NUMNODES; node++) { | 796 | for (node = 0; node < MAX_NUMNODES; node++) { |
504 | mutex_lock(&spu_prio->active_mutex[node]); | 797 | mutex_lock(&spu_prio->active_mutex[node]); |
505 | list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node], | 798 | list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node], |
@@ -510,5 +803,4 @@ void __exit spu_sched_exit(void) | |||
510 | mutex_unlock(&spu_prio->active_mutex[node]); | 803 | mutex_unlock(&spu_prio->active_mutex[node]); |
511 | } | 804 | } |
512 | kfree(spu_prio); | 805 | kfree(spu_prio); |
513 | destroy_workqueue(spu_sched_wq); | ||
514 | } | 806 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c index 0bf723dcd677..4e19ed7a0756 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_restore.c +++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c | |||
@@ -296,7 +296,7 @@ static inline void restore_complete(void) | |||
296 | * This code deviates from the documented sequence in the | 296 | * This code deviates from the documented sequence in the |
297 | * following aspects: | 297 | * following aspects: |
298 | * | 298 | * |
299 | * 1. The EA for LSCSA is passed from PPE in the | 299 | * 1. The EA for LSCSA is passed from PPE in the |
300 | * signal notification channels. | 300 | * signal notification channels. |
301 | * 2. The register spill area is pulled by SPU | 301 | * 2. The register spill area is pulled by SPU |
302 | * into LS, rather than pushed by PPE. | 302 | * into LS, rather than pushed by PPE. |
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c index 196033b8a579..ae95cc1701e9 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_save.c +++ b/arch/powerpc/platforms/cell/spufs/spu_save.c | |||
@@ -44,7 +44,7 @@ static inline void save_event_mask(void) | |||
44 | * Read the SPU_RdEventMsk channel and save to the LSCSA. | 44 | * Read the SPU_RdEventMsk channel and save to the LSCSA. |
45 | */ | 45 | */ |
46 | offset = LSCSA_QW_OFFSET(event_mask); | 46 | offset = LSCSA_QW_OFFSET(event_mask); |
47 | regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask); | 47 | regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask); |
48 | } | 48 | } |
49 | 49 | ||
50 | static inline void save_tag_mask(void) | 50 | static inline void save_tag_mask(void) |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 47617e8014a5..08b3530288ac 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/cpumask.h> | ||
29 | 30 | ||
30 | #include <asm/spu.h> | 31 | #include <asm/spu.h> |
31 | #include <asm/spu_csa.h> | 32 | #include <asm/spu_csa.h> |
@@ -39,9 +40,17 @@ enum { | |||
39 | struct spu_context_ops; | 40 | struct spu_context_ops; |
40 | struct spu_gang; | 41 | struct spu_gang; |
41 | 42 | ||
42 | /* ctx->sched_flags */ | 43 | /* |
43 | enum { | 44 | * This is the state for spu utilization reporting to userspace. |
44 | SPU_SCHED_EXITING = 0, | 45 | * Because this state is visible to userspace it must never change and needs |
46 | * to be kept strictly separate from any internal state kept by the kernel. | ||
47 | */ | ||
48 | enum spuctx_execution_state { | ||
49 | SPUCTX_UTIL_USER = 0, | ||
50 | SPUCTX_UTIL_SYSTEM, | ||
51 | SPUCTX_UTIL_IOWAIT, | ||
52 | SPUCTX_UTIL_LOADED, | ||
53 | SPUCTX_UTIL_MAX | ||
45 | }; | 54 | }; |
46 | 55 | ||
47 | struct spu_context { | 56 | struct spu_context { |
@@ -81,13 +90,34 @@ struct spu_context { | |||
81 | struct list_head gang_list; | 90 | struct list_head gang_list; |
82 | struct spu_gang *gang; | 91 | struct spu_gang *gang; |
83 | 92 | ||
93 | /* owner thread */ | ||
94 | pid_t tid; | ||
95 | |||
84 | /* scheduler fields */ | 96 | /* scheduler fields */ |
85 | struct list_head rq; | 97 | struct list_head rq; |
86 | struct delayed_work sched_work; | 98 | unsigned int time_slice; |
87 | unsigned long sched_flags; | 99 | unsigned long sched_flags; |
88 | unsigned long rt_priority; | 100 | cpumask_t cpus_allowed; |
89 | int policy; | 101 | int policy; |
90 | int prio; | 102 | int prio; |
103 | |||
104 | /* statistics */ | ||
105 | struct { | ||
106 | /* updates protected by ctx->state_mutex */ | ||
107 | enum spuctx_execution_state execution_state; | ||
108 | unsigned long tstamp; /* time of last ctx switch */ | ||
109 | unsigned long times[SPUCTX_UTIL_MAX]; | ||
110 | unsigned long long vol_ctx_switch; | ||
111 | unsigned long long invol_ctx_switch; | ||
112 | unsigned long long min_flt; | ||
113 | unsigned long long maj_flt; | ||
114 | unsigned long long hash_flt; | ||
115 | unsigned long long slb_flt; | ||
116 | unsigned long long slb_flt_base; /* # at last ctx switch */ | ||
117 | unsigned long long class2_intr; | ||
118 | unsigned long long class2_intr_base; /* # at last ctx switch */ | ||
119 | unsigned long long libassist; | ||
120 | } stats; | ||
91 | }; | 121 | }; |
92 | 122 | ||
93 | struct spu_gang { | 123 | struct spu_gang { |
@@ -177,6 +207,7 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | |||
177 | int spufs_handle_class1(struct spu_context *ctx); | 207 | int spufs_handle_class1(struct spu_context *ctx); |
178 | 208 | ||
179 | /* context management */ | 209 | /* context management */ |
210 | extern atomic_t nr_spu_contexts; | ||
180 | static inline void spu_acquire(struct spu_context *ctx) | 211 | static inline void spu_acquire(struct spu_context *ctx) |
181 | { | 212 | { |
182 | mutex_lock(&ctx->state_mutex); | 213 | mutex_lock(&ctx->state_mutex); |
@@ -200,9 +231,9 @@ void spu_acquire_saved(struct spu_context *ctx); | |||
200 | int spu_activate(struct spu_context *ctx, unsigned long flags); | 231 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
201 | void spu_deactivate(struct spu_context *ctx); | 232 | void spu_deactivate(struct spu_context *ctx); |
202 | void spu_yield(struct spu_context *ctx); | 233 | void spu_yield(struct spu_context *ctx); |
203 | void spu_start_tick(struct spu_context *ctx); | 234 | void spu_set_timeslice(struct spu_context *ctx); |
204 | void spu_stop_tick(struct spu_context *ctx); | 235 | void spu_update_sched_info(struct spu_context *ctx); |
205 | void spu_sched_tick(struct work_struct *work); | 236 | void __spu_update_sched_info(struct spu_context *ctx); |
206 | int __init spu_sched_init(void); | 237 | int __init spu_sched_init(void); |
207 | void __exit spu_sched_exit(void); | 238 | void __exit spu_sched_exit(void); |
208 | 239 | ||
@@ -210,7 +241,7 @@ extern char *isolated_loader; | |||
210 | 241 | ||
211 | /* | 242 | /* |
212 | * spufs_wait | 243 | * spufs_wait |
213 | * Same as wait_event_interruptible(), except that here | 244 | * Same as wait_event_interruptible(), except that here |
214 | * we need to call spu_release(ctx) before sleeping, and | 245 | * we need to call spu_release(ctx) before sleeping, and |
215 | * then spu_acquire(ctx) when awoken. | 246 | * then spu_acquire(ctx) when awoken. |
216 | */ | 247 | */ |
@@ -256,4 +287,37 @@ struct spufs_coredump_reader { | |||
256 | extern struct spufs_coredump_reader spufs_coredump_read[]; | 287 | extern struct spufs_coredump_reader spufs_coredump_read[]; |
257 | extern int spufs_coredump_num_notes; | 288 | extern int spufs_coredump_num_notes; |
258 | 289 | ||
290 | /* | ||
291 | * This function is a little bit too large for an inline, but | ||
292 | * as fault.c is built into the kernel we can't move it out of | ||
293 | * line. | ||
294 | */ | ||
295 | static inline void spuctx_switch_state(struct spu_context *ctx, | ||
296 | enum spuctx_execution_state new_state) | ||
297 | { | ||
298 | WARN_ON(!mutex_is_locked(&ctx->state_mutex)); | ||
299 | |||
300 | if (ctx->stats.execution_state != new_state) { | ||
301 | unsigned long curtime = jiffies; | ||
302 | |||
303 | ctx->stats.times[ctx->stats.execution_state] += | ||
304 | curtime - ctx->stats.tstamp; | ||
305 | ctx->stats.tstamp = curtime; | ||
306 | ctx->stats.execution_state = new_state; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | static inline void spu_switch_state(struct spu *spu, | ||
311 | enum spuctx_execution_state new_state) | ||
312 | { | ||
313 | if (spu->stats.utilization_state != new_state) { | ||
314 | unsigned long curtime = jiffies; | ||
315 | |||
316 | spu->stats.times[spu->stats.utilization_state] += | ||
317 | curtime - spu->stats.tstamp; | ||
318 | spu->stats.tstamp = curtime; | ||
319 | spu->stats.utilization_state = new_state; | ||
320 | } | ||
321 | } | ||
322 | |||
259 | #endif | 323 | #endif |
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 71a0b41adb8c..9c506ba08cdc 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c | |||
@@ -70,7 +70,7 @@ | |||
70 | } | 70 | } |
71 | #endif /* debug */ | 71 | #endif /* debug */ |
72 | 72 | ||
73 | #define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c)) | 73 | #define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c)) |
74 | 74 | ||
75 | static inline void acquire_spu_lock(struct spu *spu) | 75 | static inline void acquire_spu_lock(struct spu *spu) |
76 | { | 76 | { |
@@ -387,6 +387,19 @@ static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu) | |||
387 | csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW); | 387 | csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW); |
388 | } | 388 | } |
389 | 389 | ||
390 | static inline void save_ppu_tagstatus(struct spu_state *csa, struct spu *spu) | ||
391 | { | ||
392 | struct spu_problem __iomem *prob = spu->problem; | ||
393 | |||
394 | /* Save the Prxy_TagStatus register in the CSA. | ||
395 | * | ||
396 | * It is unnecessary to restore dma_tagstatus_R, however, | ||
397 | * dma_tagstatus_R in the CSA is accessed via backing_ops, so | ||
398 | * we must save it. | ||
399 | */ | ||
400 | csa->prob.dma_tagstatus_R = in_be32(&prob->dma_tagstatus_R); | ||
401 | } | ||
402 | |||
390 | static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) | 403 | static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) |
391 | { | 404 | { |
392 | struct spu_priv2 __iomem *priv2 = spu->priv2; | 405 | struct spu_priv2 __iomem *priv2 = spu->priv2; |
@@ -1812,6 +1825,7 @@ static void save_csa(struct spu_state *prev, struct spu *spu) | |||
1812 | save_mfc_queues(prev, spu); /* Step 19. */ | 1825 | save_mfc_queues(prev, spu); /* Step 19. */ |
1813 | save_ppu_querymask(prev, spu); /* Step 20. */ | 1826 | save_ppu_querymask(prev, spu); /* Step 20. */ |
1814 | save_ppu_querytype(prev, spu); /* Step 21. */ | 1827 | save_ppu_querytype(prev, spu); /* Step 21. */ |
1828 | save_ppu_tagstatus(prev, spu); /* NEW. */ | ||
1815 | save_mfc_csr_tsq(prev, spu); /* Step 22. */ | 1829 | save_mfc_csr_tsq(prev, spu); /* Step 22. */ |
1816 | save_mfc_csr_cmd(prev, spu); /* Step 23. */ | 1830 | save_mfc_csr_cmd(prev, spu); /* Step 23. */ |
1817 | save_mfc_csr_ato(prev, spu); /* Step 24. */ | 1831 | save_mfc_csr_ato(prev, spu); /* Step 24. */ |
@@ -1930,7 +1944,7 @@ static void harvest(struct spu_state *prev, struct spu *spu) | |||
1930 | reset_spu_privcntl(prev, spu); /* Step 16. */ | 1944 | reset_spu_privcntl(prev, spu); /* Step 16. */ |
1931 | reset_spu_lslr(prev, spu); /* Step 17. */ | 1945 | reset_spu_lslr(prev, spu); /* Step 17. */ |
1932 | setup_mfc_sr1(prev, spu); /* Step 18. */ | 1946 | setup_mfc_sr1(prev, spu); /* Step 18. */ |
1933 | spu_invalidate_slbs(spu); /* Step 19. */ | 1947 | spu_invalidate_slbs(spu); /* Step 19. */ |
1934 | reset_ch_part1(prev, spu); /* Step 20. */ | 1948 | reset_ch_part1(prev, spu); /* Step 20. */ |
1935 | reset_ch_part2(prev, spu); /* Step 21. */ | 1949 | reset_ch_part2(prev, spu); /* Step 21. */ |
1936 | enable_interrupts(prev, spu); /* Step 22. */ | 1950 | enable_interrupts(prev, spu); /* Step 22. */ |
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig index d2c690531963..22b4b4e3b6f0 100644 --- a/arch/powerpc/platforms/chrp/Kconfig +++ b/arch/powerpc/platforms/chrp/Kconfig | |||
@@ -8,4 +8,5 @@ config PPC_CHRP | |||
8 | select PPC_MPC106 | 8 | select PPC_MPC106 |
9 | select PPC_UDBG_16550 | 9 | select PPC_UDBG_16550 |
10 | select PPC_NATIVE | 10 | select PPC_NATIVE |
11 | select PCI | ||
11 | default y | 12 | default y |
diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile index 902feb1ac431..4b3bfadc70fa 100644 --- a/arch/powerpc/platforms/chrp/Makefile +++ b/arch/powerpc/platforms/chrp/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | obj-y += setup.o time.o pegasos_eth.o | 1 | obj-y += setup.o time.o pegasos_eth.o pci.o |
2 | obj-$(CONFIG_PCI) += pci.o | ||
3 | obj-$(CONFIG_SMP) += smp.o | 2 | obj-$(CONFIG_SMP) += smp.o |
4 | obj-$(CONFIG_NVRAM) += nvram.o | 3 | obj-$(CONFIG_NVRAM) += nvram.o |
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d32fedc991d3..3690624e49d4 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c | |||
@@ -99,7 +99,7 @@ int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, | |||
99 | struct pci_controller *hose = bus->sysdata; | 99 | struct pci_controller *hose = bus->sysdata; |
100 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | 100 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) |
101 | | (((bus->number - hose->first_busno) & 0xff) << 16) | 101 | | (((bus->number - hose->first_busno) & 0xff) << 16) |
102 | | (hose->index << 24); | 102 | | (hose->global_number << 24); |
103 | int ret = -1; | 103 | int ret = -1; |
104 | int rval; | 104 | int rval; |
105 | 105 | ||
@@ -114,7 +114,7 @@ int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, | |||
114 | struct pci_controller *hose = bus->sysdata; | 114 | struct pci_controller *hose = bus->sysdata; |
115 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | 115 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) |
116 | | (((bus->number - hose->first_busno) & 0xff) << 16) | 116 | | (((bus->number - hose->first_busno) & 0xff) << 16) |
117 | | (hose->index << 24); | 117 | | (hose->global_number << 24); |
118 | int rval; | 118 | int rval; |
119 | 119 | ||
120 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, | 120 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, |
@@ -254,13 +254,12 @@ chrp_find_bridges(void) | |||
254 | printk(" at %llx", (unsigned long long)r.start); | 254 | printk(" at %llx", (unsigned long long)r.start); |
255 | printk("\n"); | 255 | printk("\n"); |
256 | 256 | ||
257 | hose = pcibios_alloc_controller(); | 257 | hose = pcibios_alloc_controller(dev); |
258 | if (!hose) { | 258 | if (!hose) { |
259 | printk("Can't allocate PCI controller structure for %s\n", | 259 | printk("Can't allocate PCI controller structure for %s\n", |
260 | dev->full_name); | 260 | dev->full_name); |
261 | continue; | 261 | continue; |
262 | } | 262 | } |
263 | hose->arch_data = dev; | ||
264 | hose->first_busno = bus_range[0]; | 263 | hose->first_busno = bus_range[0]; |
265 | hose->last_busno = bus_range[1]; | 264 | hose->last_busno = bus_range[1]; |
266 | 265 | ||
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index f2d26268ca6f..bec772674e40 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig | |||
@@ -28,6 +28,7 @@ config PPC_HOLLY | |||
28 | bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" | 28 | bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" |
29 | select TSI108_BRIDGE | 29 | select TSI108_BRIDGE |
30 | select PPC_UDBG_16550 | 30 | select PPC_UDBG_16550 |
31 | select WANT_DEVICE_TREE | ||
31 | help | 32 | help |
32 | Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval | 33 | Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval |
33 | Board with TSI108/9 bridge (Hickory/Holly) | 34 | Board with TSI108/9 bridge (Hickory/Holly) |
@@ -44,6 +45,7 @@ endchoice | |||
44 | config TSI108_BRIDGE | 45 | config TSI108_BRIDGE |
45 | bool | 46 | bool |
46 | depends on MPC7448HPC2 || PPC_HOLLY | 47 | depends on MPC7448HPC2 || PPC_HOLLY |
48 | select PCI | ||
47 | select MPIC | 49 | select MPIC |
48 | select MPIC_WEIRD | 50 | select MPIC_WEIRD |
49 | default y | 51 | default y |
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 3a0b4a01401c..6292e36dc577 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | #define HOLLY_PCI_CFG_PHYS 0x7c000000 | 46 | #define HOLLY_PCI_CFG_PHYS 0x7c000000 |
47 | 47 | ||
48 | int holly_exclude_device(u_char bus, u_char devfn) | 48 | int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) |
49 | { | 49 | { |
50 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 50 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
51 | return PCIBIOS_DEVICE_NOT_FOUND; | 51 | return PCIBIOS_DEVICE_NOT_FOUND; |
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index b412f006a9c5..f4d0a7a603f5 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c | |||
@@ -54,8 +54,9 @@ static struct mtd_partition linkstation_physmap_partitions[] = { | |||
54 | }, | 54 | }, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static int __init add_bridge(struct device_node *dev) | 57 | static int __init linkstation_add_bridge(struct device_node *dev) |
58 | { | 58 | { |
59 | #ifdef CONFIG_PCI | ||
59 | int len; | 60 | int len; |
60 | struct pci_controller *hose; | 61 | struct pci_controller *hose; |
61 | const int *bus_range; | 62 | const int *bus_range; |
@@ -67,18 +68,17 @@ static int __init add_bridge(struct device_node *dev) | |||
67 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | 68 | printk(KERN_WARNING "Can't get bus-range for %s, assume" |
68 | " bus 0\n", dev->full_name); | 69 | " bus 0\n", dev->full_name); |
69 | 70 | ||
70 | hose = pcibios_alloc_controller(); | 71 | hose = pcibios_alloc_controller(dev); |
71 | if (hose == NULL) | 72 | if (hose == NULL) |
72 | return -ENOMEM; | 73 | return -ENOMEM; |
73 | hose->first_busno = bus_range ? bus_range[0] : 0; | 74 | hose->first_busno = bus_range ? bus_range[0] : 0; |
74 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 75 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
75 | hose->arch_data = dev; | ||
76 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000); | 76 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000); |
77 | 77 | ||
78 | /* Interpret the "ranges" property */ | 78 | /* Interpret the "ranges" property */ |
79 | /* This also maps the I/O region and sets isa_io/mem_base */ | 79 | /* This also maps the I/O region and sets isa_io/mem_base */ |
80 | pci_process_bridge_OF_ranges(hose, dev, 1); | 80 | pci_process_bridge_OF_ranges(hose, dev, 1); |
81 | 81 | #endif | |
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | 84 | ||
@@ -92,7 +92,7 @@ static void __init linkstation_setup_arch(void) | |||
92 | 92 | ||
93 | /* Lookup PCI host bridges */ | 93 | /* Lookup PCI host bridges */ |
94 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 94 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
95 | add_bridge(np); | 95 | linkstation_add_bridge(np); |
96 | 96 | ||
97 | printk(KERN_INFO "BUFFALO Network Attached Storage Series\n"); | 97 | printk(KERN_INFO "BUFFALO Network Attached Storage Series\n"); |
98 | printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n"); | 98 | printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n"); |
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 4542e0c837c0..1e3cc69487b5 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | |||
@@ -54,15 +54,10 @@ | |||
54 | 54 | ||
55 | #define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 | 55 | #define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 |
56 | 56 | ||
57 | #ifndef CONFIG_PCI | ||
58 | isa_io_base = MPC7448_HPC2_ISA_IO_BASE; | ||
59 | isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE; | ||
60 | pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET; | ||
61 | #endif | ||
62 | |||
63 | extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); | 57 | extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); |
64 | 58 | ||
65 | int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) | 59 | int mpc7448_hpc2_exclude_device(struct pci_controller *hose, |
60 | u_char bus, u_char devfn) | ||
66 | { | 61 | { |
67 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 62 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
68 | return PCIBIOS_DEVICE_NOT_FOUND; | 63 | return PCIBIOS_DEVICE_NOT_FOUND; |
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h index a543a5242e34..f7e0e0c7f8d8 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h | |||
@@ -18,9 +18,4 @@ | |||
18 | 18 | ||
19 | #include <asm/ppcboot.h> | 19 | #include <asm/ppcboot.h> |
20 | 20 | ||
21 | /* Base Addresses for the PCI bus | ||
22 | */ | ||
23 | #define MPC7448_HPC2_PCI_MEM_OFFSET (0x00000000) | ||
24 | #define MPC7448_HPC2_ISA_IO_BASE (0x00000000) | ||
25 | #define MPC7448_HPC2_ISA_MEM_BASE (0x00000000) | ||
26 | #endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ | 21 | #endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ |
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h index a843b0f87b72..8d95fe4b554e 100644 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ b/arch/powerpc/platforms/iseries/call_hpt.h | |||
@@ -76,24 +76,25 @@ static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, | |||
76 | return compressedStatus; | 76 | return compressedStatus; |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline u64 HvCallHpt_findValid(hpte_t *hpte, u64 vpn) | 79 | static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) |
80 | { | 80 | { |
81 | return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); | 81 | return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); |
82 | } | 82 | } |
83 | 83 | ||
84 | static inline u64 HvCallHpt_findNextValid(hpte_t *hpte, u32 hpteIndex, | 84 | static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, |
85 | u8 bitson, u8 bitsoff) | 85 | u8 bitson, u8 bitsoff) |
86 | { | 86 | { |
87 | return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, | 87 | return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, |
88 | bitson, bitsoff); | 88 | bitson, bitsoff); |
89 | } | 89 | } |
90 | 90 | ||
91 | static inline void HvCallHpt_get(hpte_t *hpte, u32 hpteIndex) | 91 | static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) |
92 | { | 92 | { |
93 | HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); | 93 | HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); |
94 | } | 94 | } |
95 | 95 | ||
96 | static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, hpte_t *hpte) | 96 | static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, |
97 | struct hash_pte *hpte) | ||
97 | { | 98 | { |
98 | HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); | 99 | HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); |
99 | } | 100 | } |
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index ed44dfceaa45..b4e2c7a038e1 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c | |||
@@ -44,7 +44,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
44 | unsigned long vflags, int psize) | 44 | unsigned long vflags, int psize) |
45 | { | 45 | { |
46 | long slot; | 46 | long slot; |
47 | hpte_t lhpte; | 47 | struct hash_pte lhpte; |
48 | int secondary = 0; | 48 | int secondary = 0; |
49 | 49 | ||
50 | BUG_ON(psize != MMU_PAGE_4K); | 50 | BUG_ON(psize != MMU_PAGE_4K); |
@@ -99,7 +99,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
99 | 99 | ||
100 | static unsigned long iSeries_hpte_getword0(unsigned long slot) | 100 | static unsigned long iSeries_hpte_getword0(unsigned long slot) |
101 | { | 101 | { |
102 | hpte_t hpte; | 102 | struct hash_pte hpte; |
103 | 103 | ||
104 | HvCallHpt_get(&hpte, slot); | 104 | HvCallHpt_get(&hpte, slot); |
105 | return hpte.v; | 105 | return hpte.v; |
@@ -144,7 +144,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) | |||
144 | static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, | 144 | static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, |
145 | unsigned long va, int psize, int local) | 145 | unsigned long va, int psize, int local) |
146 | { | 146 | { |
147 | hpte_t hpte; | 147 | struct hash_pte hpte; |
148 | unsigned long want_v; | 148 | unsigned long want_v; |
149 | 149 | ||
150 | iSeries_hlock(slot); | 150 | iSeries_hlock(slot); |
@@ -176,7 +176,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
176 | */ | 176 | */ |
177 | static long iSeries_hpte_find(unsigned long vpn) | 177 | static long iSeries_hpte_find(unsigned long vpn) |
178 | { | 178 | { |
179 | hpte_t hpte; | 179 | struct hash_pte hpte; |
180 | long slot; | 180 | long slot; |
181 | 181 | ||
182 | /* | 182 | /* |
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 9c974227155e..da87162000f0 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c | |||
@@ -742,6 +742,11 @@ void __init iSeries_pcibios_init(void) | |||
742 | /* Install IO hooks */ | 742 | /* Install IO hooks */ |
743 | ppc_pci_io = iseries_pci_io; | 743 | ppc_pci_io = iseries_pci_io; |
744 | 744 | ||
745 | /* iSeries has no IO space in the common sense, it needs to set | ||
746 | * the IO base to 0 | ||
747 | */ | ||
748 | pci_io_base = 0; | ||
749 | |||
745 | if (root == NULL) { | 750 | if (root == NULL) { |
746 | printk(KERN_CRIT "iSeries_pcibios_init: can't find root " | 751 | printk(KERN_CRIT "iSeries_pcibios_init: can't find root " |
747 | "of device tree\n"); | 752 | "of device tree\n"); |
@@ -763,7 +768,7 @@ void __init iSeries_pcibios_init(void) | |||
763 | if (phb == NULL) | 768 | if (phb == NULL) |
764 | continue; | 769 | continue; |
765 | 770 | ||
766 | phb->pci_mem_offset = phb->local_number = bus; | 771 | phb->pci_mem_offset = bus; |
767 | phb->first_busno = bus; | 772 | phb->first_busno = bus; |
768 | phb->last_busno = bus; | 773 | phb->last_busno = bus; |
769 | phb->ops = &iSeries_pci_ops; | 774 | phb->ops = &iSeries_pci_ops; |
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7f5dcee814d4..13a8b1908ded 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -79,8 +79,6 @@ extern void iSeries_pci_final_fixup(void); | |||
79 | static void iSeries_pci_final_fixup(void) { } | 79 | static void iSeries_pci_final_fixup(void) { } |
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | extern unsigned long iSeries_recal_tb; | ||
83 | extern unsigned long iSeries_recal_titan; | ||
84 | 82 | ||
85 | struct MemoryBlock { | 83 | struct MemoryBlock { |
86 | unsigned long absStart; | 84 | unsigned long absStart; |
@@ -292,8 +290,8 @@ static void __init iSeries_init_early(void) | |||
292 | { | 290 | { |
293 | DBG(" -> iSeries_init_early()\n"); | 291 | DBG(" -> iSeries_init_early()\n"); |
294 | 292 | ||
295 | iSeries_recal_tb = get_tb(); | 293 | /* Snapshot the timebase, for use in later recalibration */ |
296 | iSeries_recal_titan = HvCallXm_loadTod(); | 294 | iSeries_time_init_early(); |
297 | 295 | ||
298 | /* | 296 | /* |
299 | * Initialize the DMA/TCE management | 297 | * Initialize the DMA/TCE management |
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 7aaa5bbc9363..fceaae40fe70 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c | |||
@@ -444,7 +444,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
444 | u3_ht = hose; | 444 | u3_ht = hose; |
445 | } | 445 | } |
446 | 446 | ||
447 | static int __init add_bridge(struct device_node *dev) | 447 | static int __init maple_add_bridge(struct device_node *dev) |
448 | { | 448 | { |
449 | int len; | 449 | int len; |
450 | struct pci_controller *hose; | 450 | struct pci_controller *hose; |
@@ -519,23 +519,6 @@ void __devinit maple_pci_irq_fixup(struct pci_dev *dev) | |||
519 | DBG(" <- maple_pci_irq_fixup\n"); | 519 | DBG(" <- maple_pci_irq_fixup\n"); |
520 | } | 520 | } |
521 | 521 | ||
522 | static void __init maple_fixup_phb_resources(void) | ||
523 | { | ||
524 | struct pci_controller *hose, *tmp; | ||
525 | |||
526 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
527 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
528 | |||
529 | hose->io_resource.start += offset; | ||
530 | hose->io_resource.end += offset; | ||
531 | |||
532 | printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n", | ||
533 | hose->global_number, | ||
534 | (unsigned long long)hose->io_resource.start, | ||
535 | (unsigned long long)hose->io_resource.end); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | void __init maple_pci_init(void) | 522 | void __init maple_pci_init(void) |
540 | { | 523 | { |
541 | struct device_node *np, *root; | 524 | struct device_node *np, *root; |
@@ -558,7 +541,7 @@ void __init maple_pci_init(void) | |||
558 | continue; | 541 | continue; |
559 | if ((of_device_is_compatible(np, "u4-pcie") || | 542 | if ((of_device_is_compatible(np, "u4-pcie") || |
560 | of_device_is_compatible(np, "u3-agp")) && | 543 | of_device_is_compatible(np, "u3-agp")) && |
561 | add_bridge(np) == 0) | 544 | maple_add_bridge(np) == 0) |
562 | of_node_get(np); | 545 | of_node_get(np); |
563 | 546 | ||
564 | if (of_device_is_compatible(np, "u3-ht")) { | 547 | if (of_device_is_compatible(np, "u3-ht")) { |
@@ -570,27 +553,9 @@ void __init maple_pci_init(void) | |||
570 | 553 | ||
571 | /* Now setup the HyperTransport host if we found any | 554 | /* Now setup the HyperTransport host if we found any |
572 | */ | 555 | */ |
573 | if (ht && add_bridge(ht) != 0) | 556 | if (ht && maple_add_bridge(ht) != 0) |
574 | of_node_put(ht); | 557 | of_node_put(ht); |
575 | 558 | ||
576 | /* | ||
577 | * We need to call pci_setup_phb_io for the HT bridge first | ||
578 | * so it gets the I/O port numbers starting at 0, and we | ||
579 | * need to call it for the AGP bridge after that so it gets | ||
580 | * small positive I/O port numbers. | ||
581 | */ | ||
582 | if (u3_ht) | ||
583 | pci_setup_phb_io(u3_ht, 1); | ||
584 | if (u3_agp) | ||
585 | pci_setup_phb_io(u3_agp, 0); | ||
586 | if (u4_pcie) | ||
587 | pci_setup_phb_io(u4_pcie, 0); | ||
588 | |||
589 | /* Fixup the IO resources on our host bridges as the common code | ||
590 | * does it only for childs of the host bridges | ||
591 | */ | ||
592 | maple_fixup_phb_resources(); | ||
593 | |||
594 | /* Setup the linkage between OF nodes and PHBs */ | 559 | /* Setup the linkage between OF nodes and PHBs */ |
595 | pci_devs_phb_init(); | 560 | pci_devs_phb_init(); |
596 | 561 | ||
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 7c5076e38ea1..95cd90fd81c7 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig | |||
@@ -25,4 +25,13 @@ config PPC_PASEMI_MDIO | |||
25 | help | 25 | help |
26 | Driver for MDIO via GPIO on PWRficient platforms | 26 | Driver for MDIO via GPIO on PWRficient platforms |
27 | 27 | ||
28 | config ELECTRA_IDE | ||
29 | tristate "Electra IDE driver" | ||
30 | default y | ||
31 | depends on PPC_PASEMI && ATA | ||
32 | select PATA_PLATFORM | ||
33 | help | ||
34 | This includes driver support for the Electra on-board IDE | ||
35 | interface. | ||
36 | |||
28 | endmenu | 37 | endmenu |
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile index 2cd2a4f26a48..f47fcac7e581 100644 --- a/arch/powerpc/platforms/pasemi/Makefile +++ b/arch/powerpc/platforms/pasemi/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o | 1 | obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o |
2 | obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o | 2 | obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o |
3 | obj-$(CONFIG_ELECTRA_IDE) += electra_ide.o | ||
3 | obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o | 4 | obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o |
diff --git a/arch/powerpc/platforms/pasemi/electra_ide.c b/arch/powerpc/platforms/pasemi/electra_ide.c new file mode 100644 index 000000000000..12fb0c949263 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/electra_ide.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 PA Semi, Inc | ||
3 | * | ||
4 | * Maintained by: Olof Johansson <olof@lixom.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include <asm/prom.h> | ||
23 | #include <asm/system.h> | ||
24 | |||
25 | /* The electra IDE interface is incredibly simple: Just a device on the localbus | ||
26 | * with interrupts hooked up to one of the GPIOs. The device tree contains the | ||
27 | * address window and interrupt mappings already, and the pata_platform driver handles | ||
28 | * the rest. We just need to hook the two up. | ||
29 | */ | ||
30 | |||
31 | #define MAX_IFS 4 /* really, we have only one */ | ||
32 | |||
33 | static struct platform_device *pdevs[MAX_IFS]; | ||
34 | |||
35 | static int __devinit electra_ide_init(void) | ||
36 | { | ||
37 | struct device_node *np; | ||
38 | struct resource r[3]; | ||
39 | int ret = 0; | ||
40 | int i; | ||
41 | |||
42 | np = of_find_compatible_node(NULL, "ide", "electra-ide"); | ||
43 | i = 0; | ||
44 | |||
45 | while (np && i < MAX_IFS) { | ||
46 | memset(r, 0, sizeof(r)); | ||
47 | |||
48 | /* pata_platform wants two address ranges: one for the base registers, | ||
49 | * another for the control (altstatus). It's located at offset 0x3f6 in | ||
50 | * the window, but the device tree only has one large register window | ||
51 | * that covers both ranges. So we need to split it up by hand here: | ||
52 | */ | ||
53 | |||
54 | ret = of_address_to_resource(np, 0, &r[0]); | ||
55 | if (ret) | ||
56 | goto out; | ||
57 | ret = of_address_to_resource(np, 0, &r[1]); | ||
58 | if (ret) | ||
59 | goto out; | ||
60 | |||
61 | r[1].start += 0x3f6; | ||
62 | r[0].end = r[1].start-1; | ||
63 | |||
64 | r[2].start = irq_of_parse_and_map(np, 0); | ||
65 | r[2].end = irq_of_parse_and_map(np, 0); | ||
66 | r[2].flags = IORESOURCE_IRQ; | ||
67 | |||
68 | pr_debug("registering platform device at 0x%lx/0x%lx, irq is %ld\n", | ||
69 | r[0].start, r[1].start, r[2].start); | ||
70 | pdevs[i] = platform_device_register_simple("pata_platform", i, r, 3); | ||
71 | if (IS_ERR(pdevs[i])) { | ||
72 | ret = PTR_ERR(pdevs[i]); | ||
73 | pdevs[i] = NULL; | ||
74 | goto out; | ||
75 | } | ||
76 | np = of_find_compatible_node(np, "ide", "electra-ide"); | ||
77 | } | ||
78 | out: | ||
79 | return ret; | ||
80 | } | ||
81 | module_init(electra_ide_init); | ||
82 | |||
83 | static void __devexit electra_ide_exit(void) | ||
84 | { | ||
85 | int i; | ||
86 | |||
87 | for (i = 0; i < MAX_IFS; i++) | ||
88 | if (pdevs[i]) | ||
89 | platform_device_unregister(pdevs[i]); | ||
90 | } | ||
91 | module_exit(electra_ide_exit); | ||
92 | |||
93 | |||
94 | MODULE_LICENSE("GPL"); | ||
95 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); | ||
96 | MODULE_DESCRIPTION("PA Semi Electra IDE driver"); | ||
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index bbc6dfcfaa91..ab1f5f62bcd8 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c | |||
@@ -132,7 +132,7 @@ static void __init setup_pa_pxp(struct pci_controller *hose) | |||
132 | hose->cfg_data = ioremap(0xe0000000, 0x10000000); | 132 | hose->cfg_data = ioremap(0xe0000000, 0x10000000); |
133 | } | 133 | } |
134 | 134 | ||
135 | static int __init add_bridge(struct device_node *dev) | 135 | static int __init pas_add_bridge(struct device_node *dev) |
136 | { | 136 | { |
137 | struct pci_controller *hose; | 137 | struct pci_controller *hose; |
138 | 138 | ||
@@ -150,29 +150,11 @@ static int __init add_bridge(struct device_node *dev) | |||
150 | printk(KERN_INFO "Found PA-PXP PCI host bridge.\n"); | 150 | printk(KERN_INFO "Found PA-PXP PCI host bridge.\n"); |
151 | 151 | ||
152 | /* Interpret the "ranges" property */ | 152 | /* Interpret the "ranges" property */ |
153 | /* This also maps the I/O region and sets isa_io/mem_base */ | ||
154 | pci_process_bridge_OF_ranges(hose, dev, 1); | 153 | pci_process_bridge_OF_ranges(hose, dev, 1); |
155 | pci_setup_phb_io(hose, 1); | ||
156 | 154 | ||
157 | return 0; | 155 | return 0; |
158 | } | 156 | } |
159 | 157 | ||
160 | |||
161 | static void __init pas_fixup_phb_resources(void) | ||
162 | { | ||
163 | struct pci_controller *hose, *tmp; | ||
164 | |||
165 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
166 | unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; | ||
167 | hose->io_resource.start += offset; | ||
168 | hose->io_resource.end += offset; | ||
169 | printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", | ||
170 | hose->global_number, | ||
171 | hose->io_resource.start, hose->io_resource.end); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | |||
176 | void __init pas_pci_init(void) | 158 | void __init pas_pci_init(void) |
177 | { | 159 | { |
178 | struct device_node *np, *root; | 160 | struct device_node *np, *root; |
@@ -185,13 +167,11 @@ void __init pas_pci_init(void) | |||
185 | } | 167 | } |
186 | 168 | ||
187 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) | 169 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) |
188 | if (np->name && !strcmp(np->name, "pxp") && !add_bridge(np)) | 170 | if (np->name && !strcmp(np->name, "pxp") && !pas_add_bridge(np)) |
189 | of_node_get(np); | 171 | of_node_get(np); |
190 | 172 | ||
191 | of_node_put(root); | 173 | of_node_put(root); |
192 | 174 | ||
193 | pas_fixup_phb_resources(); | ||
194 | |||
195 | /* Setup the linkage between OF nodes and PHBs */ | 175 | /* Setup the linkage between OF nodes and PHBs */ |
196 | pci_devs_phb_init(); | 176 | pci_devs_phb_init(); |
197 | 177 | ||
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index c5a3f61f8d85..ffe6528048b5 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c | |||
@@ -239,7 +239,7 @@ static int __init pas_probe(void) | |||
239 | return 1; | 239 | return 1; |
240 | } | 240 | } |
241 | 241 | ||
242 | define_machine(pas) { | 242 | define_machine(pasemi) { |
243 | .name = "PA Semi PA6T-1682M", | 243 | .name = "PA Semi PA6T-1682M", |
244 | .probe = pas_probe, | 244 | .probe = pas_probe, |
245 | .setup_arch = pas_setup_arch, | 245 | .setup_arch = pas_setup_arch, |
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index 5b7afe50039a..055990ca8ce6 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig | |||
@@ -2,6 +2,7 @@ config PPC_PMAC | |||
2 | bool "Apple PowerMac based machines" | 2 | bool "Apple PowerMac based machines" |
3 | depends on PPC_MULTIPLATFORM | 3 | depends on PPC_MULTIPLATFORM |
4 | select MPIC | 4 | select MPIC |
5 | select PCI | ||
5 | select PPC_INDIRECT_PCI if PPC32 | 6 | select PPC_INDIRECT_PCI if PPC32 |
6 | select PPC_MPC106 if PPC32 | 7 | select PPC_MPC106 if PPC32 |
7 | select PPC_NATIVE | 8 | select PPC_NATIVE |
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 3f507ab9c5e5..efdf5eb81ecc 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/interrupt.h> | 42 | #include <linux/interrupt.h> |
43 | #include <linux/completion.h> | 43 | #include <linux/completion.h> |
44 | #include <linux/timer.h> | 44 | #include <linux/timer.h> |
45 | #include <linux/mutex.h> | ||
45 | #include <asm/keylargo.h> | 46 | #include <asm/keylargo.h> |
46 | #include <asm/uninorth.h> | 47 | #include <asm/uninorth.h> |
47 | #include <asm/io.h> | 48 | #include <asm/io.h> |
@@ -84,7 +85,7 @@ struct pmac_i2c_bus | |||
84 | void *hostdata; | 85 | void *hostdata; |
85 | int channel; /* some hosts have multiple */ | 86 | int channel; /* some hosts have multiple */ |
86 | int mode; /* current mode */ | 87 | int mode; /* current mode */ |
87 | struct semaphore sem; | 88 | struct mutex mutex; |
88 | int opened; | 89 | int opened; |
89 | int polled; /* open mode */ | 90 | int polled; /* open mode */ |
90 | struct platform_device *platform_dev; | 91 | struct platform_device *platform_dev; |
@@ -104,7 +105,7 @@ static LIST_HEAD(pmac_i2c_busses); | |||
104 | 105 | ||
105 | struct pmac_i2c_host_kw | 106 | struct pmac_i2c_host_kw |
106 | { | 107 | { |
107 | struct semaphore mutex; /* Access mutex for use by | 108 | struct mutex mutex; /* Access mutex for use by |
108 | * i2c-keywest */ | 109 | * i2c-keywest */ |
109 | void __iomem *base; /* register base address */ | 110 | void __iomem *base; /* register base address */ |
110 | int bsteps; /* register stepping */ | 111 | int bsteps; /* register stepping */ |
@@ -375,14 +376,14 @@ static void kw_i2c_timeout(unsigned long data) | |||
375 | static int kw_i2c_open(struct pmac_i2c_bus *bus) | 376 | static int kw_i2c_open(struct pmac_i2c_bus *bus) |
376 | { | 377 | { |
377 | struct pmac_i2c_host_kw *host = bus->hostdata; | 378 | struct pmac_i2c_host_kw *host = bus->hostdata; |
378 | down(&host->mutex); | 379 | mutex_lock(&host->mutex); |
379 | return 0; | 380 | return 0; |
380 | } | 381 | } |
381 | 382 | ||
382 | static void kw_i2c_close(struct pmac_i2c_bus *bus) | 383 | static void kw_i2c_close(struct pmac_i2c_bus *bus) |
383 | { | 384 | { |
384 | struct pmac_i2c_host_kw *host = bus->hostdata; | 385 | struct pmac_i2c_host_kw *host = bus->hostdata; |
385 | up(&host->mutex); | 386 | mutex_unlock(&host->mutex); |
386 | } | 387 | } |
387 | 388 | ||
388 | static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | 389 | static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, |
@@ -498,7 +499,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) | |||
498 | kfree(host); | 499 | kfree(host); |
499 | return NULL; | 500 | return NULL; |
500 | } | 501 | } |
501 | init_MUTEX(&host->mutex); | 502 | mutex_init(&host->mutex); |
502 | init_completion(&host->complete); | 503 | init_completion(&host->complete); |
503 | spin_lock_init(&host->lock); | 504 | spin_lock_init(&host->lock); |
504 | init_timer(&host->timeout_timer); | 505 | init_timer(&host->timeout_timer); |
@@ -571,7 +572,7 @@ static void __init kw_i2c_add(struct pmac_i2c_host_kw *host, | |||
571 | bus->open = kw_i2c_open; | 572 | bus->open = kw_i2c_open; |
572 | bus->close = kw_i2c_close; | 573 | bus->close = kw_i2c_close; |
573 | bus->xfer = kw_i2c_xfer; | 574 | bus->xfer = kw_i2c_xfer; |
574 | init_MUTEX(&bus->sem); | 575 | mutex_init(&bus->mutex); |
575 | if (controller == busnode) | 576 | if (controller == busnode) |
576 | bus->flags = pmac_i2c_multibus; | 577 | bus->flags = pmac_i2c_multibus; |
577 | list_add(&bus->link, &pmac_i2c_busses); | 578 | list_add(&bus->link, &pmac_i2c_busses); |
@@ -798,7 +799,7 @@ static void __init pmu_i2c_probe(void) | |||
798 | bus->mode = pmac_i2c_mode_std; | 799 | bus->mode = pmac_i2c_mode_std; |
799 | bus->hostdata = bus + 1; | 800 | bus->hostdata = bus + 1; |
800 | bus->xfer = pmu_i2c_xfer; | 801 | bus->xfer = pmu_i2c_xfer; |
801 | init_MUTEX(&bus->sem); | 802 | mutex_init(&bus->mutex); |
802 | bus->flags = pmac_i2c_multibus; | 803 | bus->flags = pmac_i2c_multibus; |
803 | list_add(&bus->link, &pmac_i2c_busses); | 804 | list_add(&bus->link, &pmac_i2c_busses); |
804 | 805 | ||
@@ -921,7 +922,7 @@ static void __init smu_i2c_probe(void) | |||
921 | bus->mode = pmac_i2c_mode_std; | 922 | bus->mode = pmac_i2c_mode_std; |
922 | bus->hostdata = bus + 1; | 923 | bus->hostdata = bus + 1; |
923 | bus->xfer = smu_i2c_xfer; | 924 | bus->xfer = smu_i2c_xfer; |
924 | init_MUTEX(&bus->sem); | 925 | mutex_init(&bus->mutex); |
925 | bus->flags = 0; | 926 | bus->flags = 0; |
926 | list_add(&bus->link, &pmac_i2c_busses); | 927 | list_add(&bus->link, &pmac_i2c_busses); |
927 | 928 | ||
@@ -1093,13 +1094,13 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) | |||
1093 | { | 1094 | { |
1094 | int rc; | 1095 | int rc; |
1095 | 1096 | ||
1096 | down(&bus->sem); | 1097 | mutex_lock(&bus->mutex); |
1097 | bus->polled = polled || pmac_i2c_force_poll; | 1098 | bus->polled = polled || pmac_i2c_force_poll; |
1098 | bus->opened = 1; | 1099 | bus->opened = 1; |
1099 | bus->mode = pmac_i2c_mode_std; | 1100 | bus->mode = pmac_i2c_mode_std; |
1100 | if (bus->open && (rc = bus->open(bus)) != 0) { | 1101 | if (bus->open && (rc = bus->open(bus)) != 0) { |
1101 | bus->opened = 0; | 1102 | bus->opened = 0; |
1102 | up(&bus->sem); | 1103 | mutex_unlock(&bus->mutex); |
1103 | return rc; | 1104 | return rc; |
1104 | } | 1105 | } |
1105 | return 0; | 1106 | return 0; |
@@ -1112,7 +1113,7 @@ void pmac_i2c_close(struct pmac_i2c_bus *bus) | |||
1112 | if (bus->close) | 1113 | if (bus->close) |
1113 | bus->close(bus); | 1114 | bus->close(bus); |
1114 | bus->opened = 0; | 1115 | bus->opened = 0; |
1115 | up(&bus->sem); | 1116 | mutex_unlock(&bus->mutex); |
1116 | } | 1117 | } |
1117 | EXPORT_SYMBOL_GPL(pmac_i2c_close); | 1118 | EXPORT_SYMBOL_GPL(pmac_i2c_close); |
1118 | 1119 | ||
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index c4af9e21ac93..92586db19754 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -35,8 +35,6 @@ | |||
35 | #define DBG(x...) | 35 | #define DBG(x...) |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | static int add_bridge(struct device_node *dev); | ||
39 | |||
40 | /* XXX Could be per-controller, but I don't think we risk anything by | 38 | /* XXX Could be per-controller, but I don't think we risk anything by |
41 | * assuming we won't have both UniNorth and Bandit */ | 39 | * assuming we won't have both UniNorth and Bandit */ |
42 | static int has_uninorth; | 40 | static int has_uninorth; |
@@ -897,7 +895,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
897 | * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, | 895 | * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, |
898 | * if we have one or more bandit or chaos bridges, we don't have a MPC106. | 896 | * if we have one or more bandit or chaos bridges, we don't have a MPC106. |
899 | */ | 897 | */ |
900 | static int __init add_bridge(struct device_node *dev) | 898 | static int __init pmac_add_bridge(struct device_node *dev) |
901 | { | 899 | { |
902 | int len; | 900 | int len; |
903 | struct pci_controller *hose; | 901 | struct pci_controller *hose; |
@@ -918,15 +916,9 @@ static int __init add_bridge(struct device_node *dev) | |||
918 | " bus 0\n", dev->full_name); | 916 | " bus 0\n", dev->full_name); |
919 | } | 917 | } |
920 | 918 | ||
921 | /* XXX Different prototypes, to be merged */ | ||
922 | #ifdef CONFIG_PPC64 | ||
923 | hose = pcibios_alloc_controller(dev); | 919 | hose = pcibios_alloc_controller(dev); |
924 | #else | ||
925 | hose = pcibios_alloc_controller(); | ||
926 | #endif | ||
927 | if (!hose) | 920 | if (!hose) |
928 | return -ENOMEM; | 921 | return -ENOMEM; |
929 | hose->arch_data = dev; | ||
930 | hose->first_busno = bus_range ? bus_range[0] : 0; | 922 | hose->first_busno = bus_range ? bus_range[0] : 0; |
931 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | 923 | hose->last_busno = bus_range ? bus_range[1] : 0xff; |
932 | 924 | ||
@@ -1006,19 +998,6 @@ void __devinit pmac_pci_irq_fixup(struct pci_dev *dev) | |||
1006 | #endif /* CONFIG_PPC32 */ | 998 | #endif /* CONFIG_PPC32 */ |
1007 | } | 999 | } |
1008 | 1000 | ||
1009 | #ifdef CONFIG_PPC64 | ||
1010 | static void __init pmac_fixup_phb_resources(void) | ||
1011 | { | ||
1012 | struct pci_controller *hose, *tmp; | ||
1013 | |||
1014 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
1015 | printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", | ||
1016 | hose->global_number, | ||
1017 | hose->io_resource.start, hose->io_resource.end); | ||
1018 | } | ||
1019 | } | ||
1020 | #endif | ||
1021 | |||
1022 | void __init pmac_pci_init(void) | 1001 | void __init pmac_pci_init(void) |
1023 | { | 1002 | { |
1024 | struct device_node *np, *root; | 1003 | struct device_node *np, *root; |
@@ -1036,7 +1015,7 @@ void __init pmac_pci_init(void) | |||
1036 | if (strcmp(np->name, "bandit") == 0 | 1015 | if (strcmp(np->name, "bandit") == 0 |
1037 | || strcmp(np->name, "chaos") == 0 | 1016 | || strcmp(np->name, "chaos") == 0 |
1038 | || strcmp(np->name, "pci") == 0) { | 1017 | || strcmp(np->name, "pci") == 0) { |
1039 | if (add_bridge(np) == 0) | 1018 | if (pmac_add_bridge(np) == 0) |
1040 | of_node_get(np); | 1019 | of_node_get(np); |
1041 | } | 1020 | } |
1042 | if (strcmp(np->name, "ht") == 0) { | 1021 | if (strcmp(np->name, "ht") == 0) { |
@@ -1050,28 +1029,9 @@ void __init pmac_pci_init(void) | |||
1050 | /* Probe HT last as it relies on the agp resources to be already | 1029 | /* Probe HT last as it relies on the agp resources to be already |
1051 | * setup | 1030 | * setup |
1052 | */ | 1031 | */ |
1053 | if (ht && add_bridge(ht) != 0) | 1032 | if (ht && pmac_add_bridge(ht) != 0) |
1054 | of_node_put(ht); | 1033 | of_node_put(ht); |
1055 | 1034 | ||
1056 | /* | ||
1057 | * We need to call pci_setup_phb_io for the HT bridge first | ||
1058 | * so it gets the I/O port numbers starting at 0, and we | ||
1059 | * need to call it for the AGP bridge after that so it gets | ||
1060 | * small positive I/O port numbers. | ||
1061 | */ | ||
1062 | if (u3_ht) | ||
1063 | pci_setup_phb_io(u3_ht, 1); | ||
1064 | if (u3_agp) | ||
1065 | pci_setup_phb_io(u3_agp, 0); | ||
1066 | if (u4_pcie) | ||
1067 | pci_setup_phb_io(u4_pcie, 0); | ||
1068 | |||
1069 | /* | ||
1070 | * On ppc64, fixup the IO resources on our host bridges as | ||
1071 | * the common code does it only for children of the host bridges | ||
1072 | */ | ||
1073 | pmac_fixup_phb_resources(); | ||
1074 | |||
1075 | /* Setup the linkage between OF nodes and PHBs */ | 1035 | /* Setup the linkage between OF nodes and PHBs */ |
1076 | pci_devs_phb_init(); | 1036 | pci_devs_phb_init(); |
1077 | 1037 | ||
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 40f0008af4d1..a05079b07696 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig | |||
@@ -7,6 +7,7 @@ config PPC_PS3 | |||
7 | select USB_OHCI_BIG_ENDIAN_MMIO | 7 | select USB_OHCI_BIG_ENDIAN_MMIO |
8 | select USB_ARCH_HAS_EHCI | 8 | select USB_ARCH_HAS_EHCI |
9 | select USB_EHCI_BIG_ENDIAN_MMIO | 9 | select USB_EHCI_BIG_ENDIAN_MMIO |
10 | select MEMORY_HOTPLUG | ||
10 | help | 11 | help |
11 | This option enables support for the Sony PS3 game console | 12 | This option enables support for the Sony PS3 game console |
12 | and other platforms using the PS3 hypervisor. | 13 | and other platforms using the PS3 hypervisor. |
@@ -73,18 +74,12 @@ config PS3_USE_LPAR_ADDR | |||
73 | 74 | ||
74 | config PS3_VUART | 75 | config PS3_VUART |
75 | depends on PPC_PS3 | 76 | depends on PPC_PS3 |
76 | bool "PS3 Virtual UART support" if PS3_ADVANCED | 77 | tristate |
77 | default y | ||
78 | help | ||
79 | Include support for the PS3 Virtual UART. | ||
80 | |||
81 | This support is required for several system services | ||
82 | including the System Manager and AV Settings. In | ||
83 | general, all users will say Y. | ||
84 | 78 | ||
85 | config PS3_PS3AV | 79 | config PS3_PS3AV |
80 | depends on PPC_PS3 | ||
86 | tristate "PS3 AV settings driver" if PS3_ADVANCED | 81 | tristate "PS3 AV settings driver" if PS3_ADVANCED |
87 | depends on PS3_VUART | 82 | select PS3_VUART |
88 | default y | 83 | default y |
89 | help | 84 | help |
90 | Include support for the PS3 AV Settings driver. | 85 | Include support for the PS3 AV Settings driver. |
@@ -93,13 +88,18 @@ config PS3_PS3AV | |||
93 | general, all users will say Y or M. | 88 | general, all users will say Y or M. |
94 | 89 | ||
95 | config PS3_SYS_MANAGER | 90 | config PS3_SYS_MANAGER |
96 | bool "PS3 System Manager driver" if PS3_ADVANCED | 91 | depends on PPC_PS3 |
97 | depends on PS3_VUART | 92 | tristate "PS3 System Manager driver" if PS3_ADVANCED |
98 | default y | 93 | select PS3_VUART |
94 | default m | ||
99 | help | 95 | help |
100 | Include support for the PS3 System Manager. | 96 | Include support for the PS3 System Manager. |
101 | 97 | ||
102 | This support is required for system control. In | 98 | This support is required for system control. In |
103 | general, all users will say Y. | 99 | general, all users will say Y or M. |
100 | |||
101 | config PS3_STORAGE | ||
102 | depends on PPC_PS3 | ||
103 | tristate | ||
104 | 104 | ||
105 | endmenu | 105 | endmenu |
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index a0048fcf0866..ac1bdf844eca 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile | |||
@@ -4,3 +4,4 @@ obj-y += system-bus.o | |||
4 | 4 | ||
5 | obj-$(CONFIG_SMP) += smp.o | 5 | obj-$(CONFIG_SMP) += smp.o |
6 | obj-$(CONFIG_SPU_BASE) += spu.o | 6 | obj-$(CONFIG_SPU_BASE) += spu.o |
7 | obj-y += device-init.o | ||
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c new file mode 100644 index 000000000000..825ebb2cbc2a --- /dev/null +++ b/arch/powerpc/platforms/ps3/device-init.c | |||
@@ -0,0 +1,785 @@ | |||
1 | /* | ||
2 | * PS3 device registration routines. | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/delay.h> | ||
22 | #include <linux/freezer.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/kthread.h> | ||
25 | #include <linux/init.h> | ||
26 | |||
27 | #include <asm/firmware.h> | ||
28 | #include <asm/lv1call.h> | ||
29 | #include <asm/ps3stor.h> | ||
30 | |||
31 | #include "platform.h" | ||
32 | |||
33 | /** | ||
34 | * ps3_setup_gelic_device - Setup and register a gelic device instance. | ||
35 | * | ||
36 | * Allocates memory for a struct ps3_system_bus_device instance, initialises the | ||
37 | * structure members, and registers the device instance with the system bus. | ||
38 | */ | ||
39 | |||
40 | static int __init ps3_setup_gelic_device( | ||
41 | const struct ps3_repository_device *repo) | ||
42 | { | ||
43 | int result; | ||
44 | struct layout { | ||
45 | struct ps3_system_bus_device dev; | ||
46 | struct ps3_dma_region d_region; | ||
47 | } *p; | ||
48 | |||
49 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
50 | |||
51 | BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); | ||
52 | BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_GELIC); | ||
53 | |||
54 | p = kzalloc(sizeof(struct layout), GFP_KERNEL); | ||
55 | |||
56 | if (!p) { | ||
57 | result = -ENOMEM; | ||
58 | goto fail_malloc; | ||
59 | } | ||
60 | |||
61 | p->dev.match_id = PS3_MATCH_ID_GELIC; | ||
62 | p->dev.dev_type = PS3_DEVICE_TYPE_SB; | ||
63 | p->dev.bus_id = repo->bus_id; | ||
64 | p->dev.dev_id = repo->dev_id; | ||
65 | p->dev.d_region = &p->d_region; | ||
66 | |||
67 | result = ps3_repository_find_interrupt(repo, | ||
68 | PS3_INTERRUPT_TYPE_EVENT_PORT, &p->dev.interrupt_id); | ||
69 | |||
70 | if (result) { | ||
71 | pr_debug("%s:%d ps3_repository_find_interrupt failed\n", | ||
72 | __func__, __LINE__); | ||
73 | goto fail_find_interrupt; | ||
74 | } | ||
75 | |||
76 | BUG_ON(p->dev.interrupt_id != 0); | ||
77 | |||
78 | result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, | ||
79 | PS3_DMA_OTHER, NULL, 0); | ||
80 | |||
81 | if (result) { | ||
82 | pr_debug("%s:%d ps3_dma_region_init failed\n", | ||
83 | __func__, __LINE__); | ||
84 | goto fail_dma_init; | ||
85 | } | ||
86 | |||
87 | result = ps3_system_bus_device_register(&p->dev); | ||
88 | |||
89 | if (result) { | ||
90 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
91 | __func__, __LINE__); | ||
92 | goto fail_device_register; | ||
93 | } | ||
94 | |||
95 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
96 | return result; | ||
97 | |||
98 | fail_device_register: | ||
99 | fail_dma_init: | ||
100 | fail_find_interrupt: | ||
101 | kfree(p); | ||
102 | fail_malloc: | ||
103 | pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); | ||
104 | return result; | ||
105 | } | ||
106 | |||
107 | static int __init_refok ps3_setup_uhc_device( | ||
108 | const struct ps3_repository_device *repo, enum ps3_match_id match_id, | ||
109 | enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type) | ||
110 | { | ||
111 | int result; | ||
112 | struct layout { | ||
113 | struct ps3_system_bus_device dev; | ||
114 | struct ps3_dma_region d_region; | ||
115 | struct ps3_mmio_region m_region; | ||
116 | } *p; | ||
117 | u64 bus_addr; | ||
118 | u64 len; | ||
119 | |||
120 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
121 | |||
122 | BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); | ||
123 | BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB); | ||
124 | |||
125 | p = kzalloc(sizeof(struct layout), GFP_KERNEL); | ||
126 | |||
127 | if (!p) { | ||
128 | result = -ENOMEM; | ||
129 | goto fail_malloc; | ||
130 | } | ||
131 | |||
132 | p->dev.match_id = match_id; | ||
133 | p->dev.dev_type = PS3_DEVICE_TYPE_SB; | ||
134 | p->dev.bus_id = repo->bus_id; | ||
135 | p->dev.dev_id = repo->dev_id; | ||
136 | p->dev.d_region = &p->d_region; | ||
137 | p->dev.m_region = &p->m_region; | ||
138 | |||
139 | result = ps3_repository_find_interrupt(repo, | ||
140 | interrupt_type, &p->dev.interrupt_id); | ||
141 | |||
142 | if (result) { | ||
143 | pr_debug("%s:%d ps3_repository_find_interrupt failed\n", | ||
144 | __func__, __LINE__); | ||
145 | goto fail_find_interrupt; | ||
146 | } | ||
147 | |||
148 | result = ps3_repository_find_reg(repo, reg_type, | ||
149 | &bus_addr, &len); | ||
150 | |||
151 | if (result) { | ||
152 | pr_debug("%s:%d ps3_repository_find_reg failed\n", | ||
153 | __func__, __LINE__); | ||
154 | goto fail_find_reg; | ||
155 | } | ||
156 | |||
157 | result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, | ||
158 | PS3_DMA_INTERNAL, NULL, 0); | ||
159 | |||
160 | if (result) { | ||
161 | pr_debug("%s:%d ps3_dma_region_init failed\n", | ||
162 | __func__, __LINE__); | ||
163 | goto fail_dma_init; | ||
164 | } | ||
165 | |||
166 | result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len, | ||
167 | PS3_MMIO_4K); | ||
168 | |||
169 | if (result) { | ||
170 | pr_debug("%s:%d ps3_mmio_region_init failed\n", | ||
171 | __func__, __LINE__); | ||
172 | goto fail_mmio_init; | ||
173 | } | ||
174 | |||
175 | result = ps3_system_bus_device_register(&p->dev); | ||
176 | |||
177 | if (result) { | ||
178 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
179 | __func__, __LINE__); | ||
180 | goto fail_device_register; | ||
181 | } | ||
182 | |||
183 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
184 | return result; | ||
185 | |||
186 | fail_device_register: | ||
187 | fail_mmio_init: | ||
188 | fail_dma_init: | ||
189 | fail_find_reg: | ||
190 | fail_find_interrupt: | ||
191 | kfree(p); | ||
192 | fail_malloc: | ||
193 | pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); | ||
194 | return result; | ||
195 | } | ||
196 | |||
197 | static int __init ps3_setup_ehci_device( | ||
198 | const struct ps3_repository_device *repo) | ||
199 | { | ||
200 | return ps3_setup_uhc_device(repo, PS3_MATCH_ID_EHCI, | ||
201 | PS3_INTERRUPT_TYPE_SB_EHCI, PS3_REG_TYPE_SB_EHCI); | ||
202 | } | ||
203 | |||
204 | static int __init ps3_setup_ohci_device( | ||
205 | const struct ps3_repository_device *repo) | ||
206 | { | ||
207 | return ps3_setup_uhc_device(repo, PS3_MATCH_ID_OHCI, | ||
208 | PS3_INTERRUPT_TYPE_SB_OHCI, PS3_REG_TYPE_SB_OHCI); | ||
209 | } | ||
210 | |||
211 | static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, | ||
212 | unsigned int port_number) | ||
213 | { | ||
214 | int result; | ||
215 | struct layout { | ||
216 | struct ps3_system_bus_device dev; | ||
217 | } *p; | ||
218 | |||
219 | pr_debug(" -> %s:%d: match_id %u, port %u\n", __func__, __LINE__, | ||
220 | match_id, port_number); | ||
221 | |||
222 | p = kzalloc(sizeof(struct layout), GFP_KERNEL); | ||
223 | |||
224 | if (!p) | ||
225 | return -ENOMEM; | ||
226 | |||
227 | p->dev.match_id = match_id; | ||
228 | p->dev.dev_type = PS3_DEVICE_TYPE_VUART; | ||
229 | p->dev.port_number = port_number; | ||
230 | |||
231 | result = ps3_system_bus_device_register(&p->dev); | ||
232 | |||
233 | if (result) | ||
234 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
235 | __func__, __LINE__); | ||
236 | |||
237 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
238 | return result; | ||
239 | } | ||
240 | |||
241 | static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, | ||
242 | unsigned int timeout) | ||
243 | { | ||
244 | int result = -1; | ||
245 | unsigned int retries = 0; | ||
246 | u64 status; | ||
247 | |||
248 | for (retries = 0; retries < timeout; retries++) { | ||
249 | result = lv1_storage_check_async_status(dev_id, tag, &status); | ||
250 | if (!result) | ||
251 | break; | ||
252 | |||
253 | msleep(1); | ||
254 | } | ||
255 | |||
256 | if (result) | ||
257 | pr_debug("%s:%u: check_async_status: %s, status %lx\n", | ||
258 | __func__, __LINE__, ps3_result(result), status); | ||
259 | |||
260 | return result; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * ps3_storage_wait_for_device - Wait for a storage device to become ready. | ||
265 | * @repo: The repository device to wait for. | ||
266 | * | ||
267 | * Uses the hypervisor's storage device notification mechanism to wait until | ||
268 | * a storage device is ready. The device notification mechanism uses a | ||
269 | * psuedo device (id = -1) to asynchronously notify the guest when storage | ||
270 | * devices become ready. The notification device has a block size of 512 | ||
271 | * bytes. | ||
272 | */ | ||
273 | |||
274 | static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) | ||
275 | { | ||
276 | int result; | ||
277 | const u64 notification_dev_id = (u64)-1LL; | ||
278 | const unsigned int timeout = HZ; | ||
279 | u64 lpar; | ||
280 | u64 tag; | ||
281 | struct { | ||
282 | u64 operation_code; /* must be zero */ | ||
283 | u64 event_mask; /* 1 = device ready */ | ||
284 | } *notify_cmd; | ||
285 | struct { | ||
286 | u64 event_type; /* notify_device_ready */ | ||
287 | u64 bus_id; | ||
288 | u64 dev_id; | ||
289 | u64 dev_type; | ||
290 | u64 dev_port; | ||
291 | } *notify_event; | ||
292 | enum { | ||
293 | notify_device_ready = 1 | ||
294 | }; | ||
295 | |||
296 | pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__, | ||
297 | __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); | ||
298 | |||
299 | notify_cmd = kzalloc(512, GFP_KERNEL); | ||
300 | notify_event = (void *)notify_cmd; | ||
301 | if (!notify_cmd) | ||
302 | return -ENOMEM; | ||
303 | |||
304 | lpar = ps3_mm_phys_to_lpar(__pa(notify_cmd)); | ||
305 | |||
306 | result = lv1_open_device(repo->bus_id, notification_dev_id, 0); | ||
307 | if (result) { | ||
308 | printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, | ||
309 | __LINE__, ps3_result(result)); | ||
310 | result = -ENODEV; | ||
311 | goto fail_free; | ||
312 | } | ||
313 | |||
314 | /* Setup and write the request for device notification. */ | ||
315 | |||
316 | notify_cmd->operation_code = 0; /* must be zero */ | ||
317 | notify_cmd->event_mask = 0x01; /* device ready */ | ||
318 | |||
319 | result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, | ||
320 | &tag); | ||
321 | if (result) { | ||
322 | printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, | ||
323 | ps3_result(result)); | ||
324 | result = -ENODEV; | ||
325 | goto fail_close; | ||
326 | } | ||
327 | |||
328 | /* Wait for the write completion */ | ||
329 | |||
330 | result = ps3stor_wait_for_completion(notification_dev_id, tag, | ||
331 | timeout); | ||
332 | if (result) { | ||
333 | printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, | ||
334 | __LINE__, ps3_result(result)); | ||
335 | result = -ENODEV; | ||
336 | goto fail_close; | ||
337 | } | ||
338 | |||
339 | /* Loop here processing the requested notification events. */ | ||
340 | |||
341 | result = -ENODEV; | ||
342 | while (1) { | ||
343 | memset(notify_event, 0, sizeof(*notify_event)); | ||
344 | |||
345 | result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, | ||
346 | lpar, &tag); | ||
347 | if (result) { | ||
348 | printk(KERN_ERR "%s:%u: write failed %s\n", __func__, | ||
349 | __LINE__, ps3_result(result)); | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | result = ps3stor_wait_for_completion(notification_dev_id, tag, | ||
354 | timeout); | ||
355 | if (result) { | ||
356 | printk(KERN_ERR "%s:%u: read not completed %s\n", | ||
357 | __func__, __LINE__, ps3_result(result)); | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | if (notify_event->event_type != notify_device_ready || | ||
362 | notify_event->bus_id != repo->bus_id) { | ||
363 | pr_debug("%s:%u: bad notify_event: event %lu, " | ||
364 | "dev_id %lu, dev_type %lu\n", | ||
365 | __func__, __LINE__, notify_event->event_type, | ||
366 | notify_event->dev_id, notify_event->dev_type); | ||
367 | break; | ||
368 | } | ||
369 | |||
370 | if (notify_event->dev_id == repo->dev_id && | ||
371 | notify_event->dev_type == repo->dev_type) { | ||
372 | pr_debug("%s:%u: device ready: dev_id %u\n", __func__, | ||
373 | __LINE__, repo->dev_id); | ||
374 | result = 0; | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | if (notify_event->dev_id == repo->dev_id && | ||
379 | notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { | ||
380 | pr_debug("%s:%u: no access: dev_id %u\n", __func__, | ||
381 | __LINE__, repo->dev_id); | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | fail_close: | ||
387 | lv1_close_device(repo->bus_id, notification_dev_id); | ||
388 | fail_free: | ||
389 | kfree(notify_cmd); | ||
390 | pr_debug(" <- %s:%u\n", __func__, __LINE__); | ||
391 | return result; | ||
392 | } | ||
393 | |||
394 | static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, | ||
395 | enum ps3_match_id match_id) | ||
396 | { | ||
397 | int result; | ||
398 | struct ps3_storage_device *p; | ||
399 | u64 port, blk_size, num_blocks; | ||
400 | unsigned int num_regions, i; | ||
401 | |||
402 | pr_debug(" -> %s:%u: match_id %u\n", __func__, __LINE__, match_id); | ||
403 | |||
404 | result = ps3_repository_read_stor_dev_info(repo->bus_index, | ||
405 | repo->dev_index, &port, | ||
406 | &blk_size, &num_blocks, | ||
407 | &num_regions); | ||
408 | if (result) { | ||
409 | printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n", | ||
410 | __func__, __LINE__, result); | ||
411 | return -ENODEV; | ||
412 | } | ||
413 | |||
414 | pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu " | ||
415 | "num_regions %u\n", __func__, __LINE__, repo->bus_index, | ||
416 | repo->dev_index, port, blk_size, num_blocks, num_regions); | ||
417 | |||
418 | p = kzalloc(sizeof(struct ps3_storage_device) + | ||
419 | num_regions * sizeof(struct ps3_storage_region), | ||
420 | GFP_KERNEL); | ||
421 | if (!p) { | ||
422 | result = -ENOMEM; | ||
423 | goto fail_malloc; | ||
424 | } | ||
425 | |||
426 | p->sbd.match_id = match_id; | ||
427 | p->sbd.dev_type = PS3_DEVICE_TYPE_SB; | ||
428 | p->sbd.bus_id = repo->bus_id; | ||
429 | p->sbd.dev_id = repo->dev_id; | ||
430 | p->sbd.d_region = &p->dma_region; | ||
431 | p->blk_size = blk_size; | ||
432 | p->num_regions = num_regions; | ||
433 | |||
434 | result = ps3_repository_find_interrupt(repo, | ||
435 | PS3_INTERRUPT_TYPE_EVENT_PORT, | ||
436 | &p->sbd.interrupt_id); | ||
437 | if (result) { | ||
438 | printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__, | ||
439 | __LINE__, result); | ||
440 | result = -ENODEV; | ||
441 | goto fail_find_interrupt; | ||
442 | } | ||
443 | |||
444 | /* FIXME: Arrange to only do this on a 'cold' boot */ | ||
445 | |||
446 | result = ps3_storage_wait_for_device(repo); | ||
447 | if (result) { | ||
448 | printk(KERN_ERR "%s:%u: storage_notification failed %d\n", | ||
449 | __func__, __LINE__, result); | ||
450 | result = -ENODEV; | ||
451 | goto fail_probe_notification; | ||
452 | } | ||
453 | |||
454 | for (i = 0; i < num_regions; i++) { | ||
455 | unsigned int id; | ||
456 | u64 start, size; | ||
457 | |||
458 | result = ps3_repository_read_stor_dev_region(repo->bus_index, | ||
459 | repo->dev_index, | ||
460 | i, &id, &start, | ||
461 | &size); | ||
462 | if (result) { | ||
463 | printk(KERN_ERR | ||
464 | "%s:%u: read_stor_dev_region failed %d\n", | ||
465 | __func__, __LINE__, result); | ||
466 | result = -ENODEV; | ||
467 | goto fail_read_region; | ||
468 | } | ||
469 | pr_debug("%s:%u: region %u: id %u start %lu size %lu\n", | ||
470 | __func__, __LINE__, i, id, start, size); | ||
471 | |||
472 | p->regions[i].id = id; | ||
473 | p->regions[i].start = start; | ||
474 | p->regions[i].size = size; | ||
475 | } | ||
476 | |||
477 | result = ps3_system_bus_device_register(&p->sbd); | ||
478 | if (result) { | ||
479 | pr_debug("%s:%u ps3_system_bus_device_register failed\n", | ||
480 | __func__, __LINE__); | ||
481 | goto fail_device_register; | ||
482 | } | ||
483 | |||
484 | pr_debug(" <- %s:%u\n", __func__, __LINE__); | ||
485 | return 0; | ||
486 | |||
487 | fail_device_register: | ||
488 | fail_read_region: | ||
489 | fail_probe_notification: | ||
490 | fail_find_interrupt: | ||
491 | kfree(p); | ||
492 | fail_malloc: | ||
493 | pr_debug(" <- %s:%u: fail.\n", __func__, __LINE__); | ||
494 | return result; | ||
495 | } | ||
496 | |||
497 | static int __init ps3_register_vuart_devices(void) | ||
498 | { | ||
499 | int result; | ||
500 | unsigned int port_number; | ||
501 | |||
502 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
503 | |||
504 | result = ps3_repository_read_vuart_av_port(&port_number); | ||
505 | if (result) | ||
506 | port_number = 0; /* av default */ | ||
507 | |||
508 | result = ps3_setup_vuart_device(PS3_MATCH_ID_AV_SETTINGS, port_number); | ||
509 | WARN_ON(result); | ||
510 | |||
511 | result = ps3_repository_read_vuart_sysmgr_port(&port_number); | ||
512 | if (result) | ||
513 | port_number = 2; /* sysmgr default */ | ||
514 | |||
515 | result = ps3_setup_vuart_device(PS3_MATCH_ID_SYSTEM_MANAGER, | ||
516 | port_number); | ||
517 | WARN_ON(result); | ||
518 | |||
519 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
520 | return result; | ||
521 | } | ||
522 | |||
523 | static int __init ps3_register_sound_devices(void) | ||
524 | { | ||
525 | int result; | ||
526 | struct layout { | ||
527 | struct ps3_system_bus_device dev; | ||
528 | struct ps3_dma_region d_region; | ||
529 | struct ps3_mmio_region m_region; | ||
530 | } *p; | ||
531 | |||
532 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
533 | |||
534 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
535 | if (!p) | ||
536 | return -ENOMEM; | ||
537 | |||
538 | p->dev.match_id = PS3_MATCH_ID_SOUND; | ||
539 | p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; | ||
540 | p->dev.d_region = &p->d_region; | ||
541 | p->dev.m_region = &p->m_region; | ||
542 | |||
543 | result = ps3_system_bus_device_register(&p->dev); | ||
544 | |||
545 | if (result) | ||
546 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
547 | __func__, __LINE__); | ||
548 | |||
549 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
550 | return result; | ||
551 | } | ||
552 | |||
553 | static int __init ps3_register_graphics_devices(void) | ||
554 | { | ||
555 | int result; | ||
556 | struct layout { | ||
557 | struct ps3_system_bus_device dev; | ||
558 | } *p; | ||
559 | |||
560 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
561 | |||
562 | p = kzalloc(sizeof(struct layout), GFP_KERNEL); | ||
563 | |||
564 | if (!p) | ||
565 | return -ENOMEM; | ||
566 | |||
567 | p->dev.match_id = PS3_MATCH_ID_GRAPHICS; | ||
568 | p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; | ||
569 | |||
570 | result = ps3_system_bus_device_register(&p->dev); | ||
571 | |||
572 | if (result) | ||
573 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
574 | __func__, __LINE__); | ||
575 | |||
576 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
577 | return result; | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * ps3_register_repository_device - Register a device from the repositiory info. | ||
582 | * | ||
583 | */ | ||
584 | |||
585 | static int ps3_register_repository_device( | ||
586 | const struct ps3_repository_device *repo) | ||
587 | { | ||
588 | int result; | ||
589 | |||
590 | switch (repo->dev_type) { | ||
591 | case PS3_DEV_TYPE_SB_GELIC: | ||
592 | result = ps3_setup_gelic_device(repo); | ||
593 | if (result) { | ||
594 | pr_debug("%s:%d ps3_setup_gelic_device failed\n", | ||
595 | __func__, __LINE__); | ||
596 | } | ||
597 | break; | ||
598 | case PS3_DEV_TYPE_SB_USB: | ||
599 | |||
600 | /* Each USB device has both an EHCI and an OHCI HC */ | ||
601 | |||
602 | result = ps3_setup_ehci_device(repo); | ||
603 | |||
604 | if (result) { | ||
605 | pr_debug("%s:%d ps3_setup_ehci_device failed\n", | ||
606 | __func__, __LINE__); | ||
607 | } | ||
608 | |||
609 | result = ps3_setup_ohci_device(repo); | ||
610 | |||
611 | if (result) { | ||
612 | pr_debug("%s:%d ps3_setup_ohci_device failed\n", | ||
613 | __func__, __LINE__); | ||
614 | } | ||
615 | break; | ||
616 | case PS3_DEV_TYPE_STOR_DISK: | ||
617 | result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); | ||
618 | |||
619 | /* Some devices are not accessable from the Other OS lpar. */ | ||
620 | if (result == -ENODEV) { | ||
621 | result = 0; | ||
622 | pr_debug("%s:%u: not accessable\n", __func__, | ||
623 | __LINE__); | ||
624 | } | ||
625 | |||
626 | if (result) | ||
627 | pr_debug("%s:%u ps3_setup_storage_dev failed\n", | ||
628 | __func__, __LINE__); | ||
629 | break; | ||
630 | |||
631 | case PS3_DEV_TYPE_STOR_ROM: | ||
632 | result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ROM); | ||
633 | if (result) | ||
634 | pr_debug("%s:%u ps3_setup_storage_dev failed\n", | ||
635 | __func__, __LINE__); | ||
636 | break; | ||
637 | |||
638 | case PS3_DEV_TYPE_STOR_FLASH: | ||
639 | result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_FLASH); | ||
640 | if (result) | ||
641 | pr_debug("%s:%u ps3_setup_storage_dev failed\n", | ||
642 | __func__, __LINE__); | ||
643 | break; | ||
644 | |||
645 | default: | ||
646 | result = 0; | ||
647 | pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__, | ||
648 | repo->dev_type); | ||
649 | } | ||
650 | |||
651 | return result; | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * ps3_probe_thread - Background repository probing at system startup. | ||
656 | * | ||
657 | * This implementation only supports background probing on a single bus. | ||
658 | */ | ||
659 | |||
660 | static int ps3_probe_thread(void *data) | ||
661 | { | ||
662 | struct ps3_repository_device *repo = data; | ||
663 | int result; | ||
664 | unsigned int ms = 250; | ||
665 | |||
666 | pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); | ||
667 | |||
668 | do { | ||
669 | try_to_freeze(); | ||
670 | |||
671 | pr_debug("%s:%u: probing...\n", __func__, __LINE__); | ||
672 | |||
673 | do { | ||
674 | result = ps3_repository_find_device(repo); | ||
675 | |||
676 | if (result == -ENODEV) | ||
677 | pr_debug("%s:%u: nothing new\n", __func__, | ||
678 | __LINE__); | ||
679 | else if (result) | ||
680 | pr_debug("%s:%u: find device error.\n", | ||
681 | __func__, __LINE__); | ||
682 | else { | ||
683 | pr_debug("%s:%u: found device\n", __func__, | ||
684 | __LINE__); | ||
685 | ps3_register_repository_device(repo); | ||
686 | ps3_repository_bump_device(repo); | ||
687 | ms = 250; | ||
688 | } | ||
689 | } while (!result); | ||
690 | |||
691 | pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms); | ||
692 | |||
693 | if ( ms > 60000) | ||
694 | break; | ||
695 | |||
696 | msleep_interruptible(ms); | ||
697 | |||
698 | /* An exponential backoff. */ | ||
699 | ms <<= 1; | ||
700 | |||
701 | } while (!kthread_should_stop()); | ||
702 | |||
703 | pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * ps3_start_probe_thread - Starts the background probe thread. | ||
710 | * | ||
711 | */ | ||
712 | |||
713 | static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) | ||
714 | { | ||
715 | int result; | ||
716 | struct task_struct *task; | ||
717 | static struct ps3_repository_device repo; /* must be static */ | ||
718 | |||
719 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
720 | |||
721 | memset(&repo, 0, sizeof(repo)); | ||
722 | |||
723 | repo.bus_type = bus_type; | ||
724 | |||
725 | result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); | ||
726 | |||
727 | if (result) { | ||
728 | printk(KERN_ERR "%s: Cannot find bus (%d)\n", __func__, result); | ||
729 | return -ENODEV; | ||
730 | } | ||
731 | |||
732 | result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); | ||
733 | |||
734 | if (result) { | ||
735 | printk(KERN_ERR "%s: read_bus_id failed %d\n", __func__, | ||
736 | result); | ||
737 | return -ENODEV; | ||
738 | } | ||
739 | |||
740 | task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type); | ||
741 | |||
742 | if (IS_ERR(task)) { | ||
743 | result = PTR_ERR(task); | ||
744 | printk(KERN_ERR "%s: kthread_run failed %d\n", __func__, | ||
745 | result); | ||
746 | return result; | ||
747 | } | ||
748 | |||
749 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | /** | ||
754 | * ps3_register_devices - Probe the system and register devices found. | ||
755 | * | ||
756 | * A device_initcall() routine. | ||
757 | */ | ||
758 | |||
759 | static int __init ps3_register_devices(void) | ||
760 | { | ||
761 | int result; | ||
762 | |||
763 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
764 | return -ENODEV; | ||
765 | |||
766 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
767 | |||
768 | /* ps3_repository_dump_bus_info(); */ | ||
769 | |||
770 | result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE); | ||
771 | |||
772 | ps3_register_vuart_devices(); | ||
773 | |||
774 | ps3_register_graphics_devices(); | ||
775 | |||
776 | ps3_repository_find_devices(PS3_BUS_TYPE_SB, | ||
777 | ps3_register_repository_device); | ||
778 | |||
779 | ps3_register_sound_devices(); | ||
780 | |||
781 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | device_initcall(ps3_register_devices); | ||
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index a1409e450c70..5d2e176a1b18 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c | |||
@@ -29,12 +29,12 @@ | |||
29 | #include "platform.h" | 29 | #include "platform.h" |
30 | 30 | ||
31 | #if defined(DEBUG) | 31 | #if defined(DEBUG) |
32 | #define DBG(fmt...) udbg_printf(fmt) | 32 | #define DBG udbg_printf |
33 | #else | 33 | #else |
34 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 34 | #define DBG pr_debug |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | static hpte_t *htab; | 37 | static struct hash_pte *htab; |
38 | static unsigned long htab_addr; | 38 | static unsigned long htab_addr; |
39 | static unsigned char *bolttab; | 39 | static unsigned char *bolttab; |
40 | static unsigned char *inusetab; | 40 | static unsigned char *inusetab; |
@@ -44,8 +44,8 @@ static DEFINE_SPINLOCK(ps3_bolttab_lock); | |||
44 | #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \ | 44 | #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \ |
45 | _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) | 45 | _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) |
46 | static void _debug_dump_hpte(unsigned long pa, unsigned long va, | 46 | static void _debug_dump_hpte(unsigned long pa, unsigned long va, |
47 | unsigned long group, unsigned long bitmap, hpte_t lhpte, int psize, | 47 | unsigned long group, unsigned long bitmap, struct hash_pte lhpte, |
48 | unsigned long slot, const char* func, int line) | 48 | int psize, unsigned long slot, const char* func, int line) |
49 | { | 49 | { |
50 | DBG("%s:%d: pa = %lxh\n", func, line, pa); | 50 | DBG("%s:%d: pa = %lxh\n", func, line, pa); |
51 | DBG("%s:%d: lpar = %lxh\n", func, line, | 51 | DBG("%s:%d: lpar = %lxh\n", func, line, |
@@ -63,7 +63,7 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
63 | unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) | 63 | unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) |
64 | { | 64 | { |
65 | unsigned long slot; | 65 | unsigned long slot; |
66 | hpte_t lhpte; | 66 | struct hash_pte lhpte; |
67 | int secondary = 0; | 67 | int secondary = 0; |
68 | unsigned long result; | 68 | unsigned long result; |
69 | unsigned long bitmap; | 69 | unsigned long bitmap; |
@@ -234,10 +234,17 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, | |||
234 | 234 | ||
235 | static void ps3_hpte_clear(void) | 235 | static void ps3_hpte_clear(void) |
236 | { | 236 | { |
237 | /* Make sure to clean up the frame buffer device first */ | 237 | int result; |
238 | ps3fb_cleanup(); | ||
239 | 238 | ||
240 | lv1_unmap_htab(htab_addr); | 239 | DBG(" -> %s:%d\n", __func__, __LINE__); |
240 | |||
241 | result = lv1_unmap_htab(htab_addr); | ||
242 | BUG_ON(result); | ||
243 | |||
244 | ps3_mm_shutdown(); | ||
245 | ps3_mm_vas_destroy(); | ||
246 | |||
247 | DBG(" <- %s:%d\n", __func__, __LINE__); | ||
241 | } | 248 | } |
242 | 249 | ||
243 | void __init ps3_hpte_init(unsigned long htab_size) | 250 | void __init ps3_hpte_init(unsigned long htab_size) |
@@ -255,7 +262,7 @@ void __init ps3_hpte_init(unsigned long htab_size) | |||
255 | 262 | ||
256 | ppc64_pft_size = __ilog2(htab_size); | 263 | ppc64_pft_size = __ilog2(htab_size); |
257 | 264 | ||
258 | bitmap_size = htab_size / sizeof(hpte_t) / 8; | 265 | bitmap_size = htab_size / sizeof(struct hash_pte) / 8; |
259 | 266 | ||
260 | bolttab = __va(lmb_alloc(bitmap_size, 1)); | 267 | bolttab = __va(lmb_alloc(bitmap_size, 1)); |
261 | inusetab = __va(lmb_alloc(bitmap_size, 1)); | 268 | inusetab = __va(lmb_alloc(bitmap_size, 1)); |
@@ -273,8 +280,8 @@ void __init ps3_map_htab(void) | |||
273 | 280 | ||
274 | result = lv1_map_htab(0, &htab_addr); | 281 | result = lv1_map_htab(0, &htab_addr); |
275 | 282 | ||
276 | htab = (hpte_t *)__ioremap(htab_addr, htab_size, | 283 | htab = (__force struct hash_pte *)ioremap_flags(htab_addr, htab_size, |
277 | pgprot_val(PAGE_READONLY_X)); | 284 | pgprot_val(PAGE_READONLY_X)); |
278 | 285 | ||
279 | DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__, | 286 | DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__, |
280 | htab_addr, (unsigned long)htab); | 287 | htab_addr, (unsigned long)htab); |
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index ec9030dbb5f1..67e32ec9b37e 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include "platform.h" | 30 | #include "platform.h" |
31 | 31 | ||
32 | #if defined(DEBUG) | 32 | #if defined(DEBUG) |
33 | #define DBG(fmt...) udbg_printf(fmt) | 33 | #define DBG udbg_printf |
34 | #else | 34 | #else |
35 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 35 | #define DBG pr_debug |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | /** | 38 | /** |
@@ -78,19 +78,85 @@ struct ps3_bmp { | |||
78 | /** | 78 | /** |
79 | * struct ps3_private - a per cpu data structure | 79 | * struct ps3_private - a per cpu data structure |
80 | * @bmp: ps3_bmp structure | 80 | * @bmp: ps3_bmp structure |
81 | * @node: HV logical_ppe_id | 81 | * @ppe_id: HV logical_ppe_id |
82 | * @cpu: HV thread_id | 82 | * @thread_id: HV thread_id |
83 | */ | 83 | */ |
84 | 84 | ||
85 | struct ps3_private { | 85 | struct ps3_private { |
86 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); | 86 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); |
87 | u64 node; | 87 | u64 ppe_id; |
88 | unsigned int cpu; | 88 | u64 thread_id; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | 91 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); |
92 | 92 | ||
93 | /** | 93 | /** |
94 | * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. | ||
95 | * @virq: The assigned Linux virq. | ||
96 | * | ||
97 | * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). | ||
98 | */ | ||
99 | |||
100 | static void ps3_chip_mask(unsigned int virq) | ||
101 | { | ||
102 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
103 | unsigned long flags; | ||
104 | |||
105 | pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, | ||
106 | pd->thread_id, virq); | ||
107 | |||
108 | local_irq_save(flags); | ||
109 | clear_bit(63 - virq, &pd->bmp.mask); | ||
110 | lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); | ||
111 | local_irq_restore(flags); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. | ||
116 | * @virq: The assigned Linux virq. | ||
117 | * | ||
118 | * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). | ||
119 | */ | ||
120 | |||
121 | static void ps3_chip_unmask(unsigned int virq) | ||
122 | { | ||
123 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
124 | unsigned long flags; | ||
125 | |||
126 | pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, | ||
127 | pd->thread_id, virq); | ||
128 | |||
129 | local_irq_save(flags); | ||
130 | set_bit(63 - virq, &pd->bmp.mask); | ||
131 | lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); | ||
132 | local_irq_restore(flags); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * ps3_chip_eoi - HV end-of-interrupt. | ||
137 | * @virq: The assigned Linux virq. | ||
138 | * | ||
139 | * Calls lv1_end_of_interrupt_ext(). | ||
140 | */ | ||
141 | |||
142 | static void ps3_chip_eoi(unsigned int virq) | ||
143 | { | ||
144 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
145 | lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq); | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. | ||
150 | */ | ||
151 | |||
152 | static struct irq_chip ps3_irq_chip = { | ||
153 | .typename = "ps3", | ||
154 | .mask = ps3_chip_mask, | ||
155 | .unmask = ps3_chip_unmask, | ||
156 | .eoi = ps3_chip_eoi, | ||
157 | }; | ||
158 | |||
159 | /** | ||
94 | * ps3_virq_setup - virq related setup. | 160 | * ps3_virq_setup - virq related setup. |
95 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | 161 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
96 | * serviced on. | 162 | * serviced on. |
@@ -134,6 +200,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, | |||
134 | goto fail_set; | 200 | goto fail_set; |
135 | } | 201 | } |
136 | 202 | ||
203 | ps3_chip_mask(*virq); | ||
204 | |||
137 | return result; | 205 | return result; |
138 | 206 | ||
139 | fail_set: | 207 | fail_set: |
@@ -153,8 +221,8 @@ int ps3_virq_destroy(unsigned int virq) | |||
153 | { | 221 | { |
154 | const struct ps3_private *pd = get_irq_chip_data(virq); | 222 | const struct ps3_private *pd = get_irq_chip_data(virq); |
155 | 223 | ||
156 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | 224 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, |
157 | pd->node, pd->cpu, virq); | 225 | __LINE__, pd->ppe_id, pd->thread_id, virq); |
158 | 226 | ||
159 | set_irq_chip_data(virq, NULL); | 227 | set_irq_chip_data(virq, NULL); |
160 | irq_dispose_mapping(virq); | 228 | irq_dispose_mapping(virq); |
@@ -190,7 +258,8 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, | |||
190 | 258 | ||
191 | /* Binds outlet to cpu + virq. */ | 259 | /* Binds outlet to cpu + virq. */ |
192 | 260 | ||
193 | result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); | 261 | result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, |
262 | outlet, 0); | ||
194 | 263 | ||
195 | if (result) { | 264 | if (result) { |
196 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", | 265 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", |
@@ -222,10 +291,12 @@ int ps3_irq_plug_destroy(unsigned int virq) | |||
222 | int result; | 291 | int result; |
223 | const struct ps3_private *pd = get_irq_chip_data(virq); | 292 | const struct ps3_private *pd = get_irq_chip_data(virq); |
224 | 293 | ||
225 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | 294 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, |
226 | pd->node, pd->cpu, virq); | 295 | __LINE__, pd->ppe_id, pd->thread_id, virq); |
296 | |||
297 | ps3_chip_mask(virq); | ||
227 | 298 | ||
228 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | 299 | result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); |
229 | 300 | ||
230 | if (result) | 301 | if (result) |
231 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", | 302 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", |
@@ -282,7 +353,9 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
282 | { | 353 | { |
283 | int result; | 354 | int result; |
284 | 355 | ||
285 | pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq); | 356 | pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); |
357 | |||
358 | ps3_chip_mask(virq); | ||
286 | 359 | ||
287 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); | 360 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); |
288 | 361 | ||
@@ -290,17 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
290 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", | 363 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", |
291 | __func__, __LINE__, ps3_result(result)); | 364 | __func__, __LINE__, ps3_result(result)); |
292 | 365 | ||
293 | /* lv1_destruct_event_receive_port() destroys the IRQ plug, | 366 | /* |
294 | * so don't call ps3_irq_plug_destroy() here. | 367 | * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() |
368 | * calls from interrupt context (smp_call_function) when kexecing. | ||
295 | */ | 369 | */ |
296 | 370 | ||
297 | result = ps3_virq_destroy(virq); | ||
298 | BUG_ON(result); | ||
299 | |||
300 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 371 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
301 | return result; | 372 | return result; |
302 | } | 373 | } |
303 | EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy); | ||
304 | 374 | ||
305 | int ps3_send_event_locally(unsigned int virq) | 375 | int ps3_send_event_locally(unsigned int virq) |
306 | { | 376 | { |
@@ -311,17 +381,15 @@ int ps3_send_event_locally(unsigned int virq) | |||
311 | * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. | 381 | * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. |
312 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | 382 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
313 | * serviced on. | 383 | * serviced on. |
314 | * @did: The HV device identifier read from the system repository. | 384 | * @dev: The system bus device instance. |
315 | * @interrupt_id: The device interrupt id read from the system repository. | ||
316 | * @virq: The assigned Linux virq. | 385 | * @virq: The assigned Linux virq. |
317 | * | 386 | * |
318 | * An event irq represents a virtual device interrupt. The interrupt_id | 387 | * An event irq represents a virtual device interrupt. The interrupt_id |
319 | * coresponds to the software interrupt number. | 388 | * coresponds to the software interrupt number. |
320 | */ | 389 | */ |
321 | 390 | ||
322 | int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | 391 | int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, |
323 | const struct ps3_device_id *did, unsigned int interrupt_id, | 392 | enum ps3_cpu_binding cpu, unsigned int *virq) |
324 | unsigned int *virq) | ||
325 | { | 393 | { |
326 | /* this should go in system-bus.c */ | 394 | /* this should go in system-bus.c */ |
327 | 395 | ||
@@ -332,8 +400,8 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | |||
332 | if (result) | 400 | if (result) |
333 | return result; | 401 | return result; |
334 | 402 | ||
335 | result = lv1_connect_interrupt_event_receive_port(did->bus_id, | 403 | result = lv1_connect_interrupt_event_receive_port(dev->bus_id, |
336 | did->dev_id, virq_to_hw(*virq), interrupt_id); | 404 | dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); |
337 | 405 | ||
338 | if (result) { | 406 | if (result) { |
339 | pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" | 407 | pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" |
@@ -345,24 +413,24 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | |||
345 | } | 413 | } |
346 | 414 | ||
347 | pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, | 415 | pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, |
348 | interrupt_id, *virq); | 416 | dev->interrupt_id, *virq); |
349 | 417 | ||
350 | return 0; | 418 | return 0; |
351 | } | 419 | } |
352 | EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); | 420 | EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); |
353 | 421 | ||
354 | int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, | 422 | int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, |
355 | unsigned int interrupt_id, unsigned int virq) | 423 | unsigned int virq) |
356 | { | 424 | { |
357 | /* this should go in system-bus.c */ | 425 | /* this should go in system-bus.c */ |
358 | 426 | ||
359 | int result; | 427 | int result; |
360 | 428 | ||
361 | pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, | 429 | pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, |
362 | interrupt_id, virq); | 430 | dev->interrupt_id, virq); |
363 | 431 | ||
364 | result = lv1_disconnect_interrupt_event_receive_port(did->bus_id, | 432 | result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, |
365 | did->dev_id, virq_to_hw(virq), interrupt_id); | 433 | dev->dev_id, virq_to_hw(virq), dev->interrupt_id); |
366 | 434 | ||
367 | if (result) | 435 | if (result) |
368 | pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" | 436 | pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" |
@@ -372,6 +440,14 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, | |||
372 | result = ps3_event_receive_port_destroy(virq); | 440 | result = ps3_event_receive_port_destroy(virq); |
373 | BUG_ON(result); | 441 | BUG_ON(result); |
374 | 442 | ||
443 | /* | ||
444 | * ps3_event_receive_port_destroy() destroys the IRQ plug, | ||
445 | * so don't call ps3_irq_plug_destroy() here. | ||
446 | */ | ||
447 | |||
448 | result = ps3_virq_destroy(virq); | ||
449 | BUG_ON(result); | ||
450 | |||
375 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 451 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
376 | return result; | 452 | return result; |
377 | } | 453 | } |
@@ -412,16 +488,24 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup); | |||
412 | int ps3_io_irq_destroy(unsigned int virq) | 488 | int ps3_io_irq_destroy(unsigned int virq) |
413 | { | 489 | { |
414 | int result; | 490 | int result; |
491 | unsigned long outlet = virq_to_hw(virq); | ||
415 | 492 | ||
416 | result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); | 493 | ps3_chip_mask(virq); |
417 | 494 | ||
418 | if (result) | 495 | /* |
419 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | 496 | * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, |
420 | __func__, __LINE__, ps3_result(result)); | 497 | * so call ps3_irq_plug_destroy() first. |
498 | */ | ||
421 | 499 | ||
422 | result = ps3_irq_plug_destroy(virq); | 500 | result = ps3_irq_plug_destroy(virq); |
423 | BUG_ON(result); | 501 | BUG_ON(result); |
424 | 502 | ||
503 | result = lv1_destruct_io_irq_outlet(outlet); | ||
504 | |||
505 | if (result) | ||
506 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | ||
507 | __func__, __LINE__, ps3_result(result)); | ||
508 | |||
425 | return result; | 509 | return result; |
426 | } | 510 | } |
427 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); | 511 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); |
@@ -461,11 +545,13 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, | |||
461 | 545 | ||
462 | return result; | 546 | return result; |
463 | } | 547 | } |
548 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); | ||
464 | 549 | ||
465 | int ps3_vuart_irq_destroy(unsigned int virq) | 550 | int ps3_vuart_irq_destroy(unsigned int virq) |
466 | { | 551 | { |
467 | int result; | 552 | int result; |
468 | 553 | ||
554 | ps3_chip_mask(virq); | ||
469 | result = lv1_deconfigure_virtual_uart_irq(); | 555 | result = lv1_deconfigure_virtual_uart_irq(); |
470 | 556 | ||
471 | if (result) { | 557 | if (result) { |
@@ -479,6 +565,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) | |||
479 | 565 | ||
480 | return result; | 566 | return result; |
481 | } | 567 | } |
568 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); | ||
482 | 569 | ||
483 | /** | 570 | /** |
484 | * ps3_spe_irq_setup - Setup an spe virq. | 571 | * ps3_spe_irq_setup - Setup an spe virq. |
@@ -514,9 +601,14 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, | |||
514 | 601 | ||
515 | int ps3_spe_irq_destroy(unsigned int virq) | 602 | int ps3_spe_irq_destroy(unsigned int virq) |
516 | { | 603 | { |
517 | int result = ps3_irq_plug_destroy(virq); | 604 | int result; |
605 | |||
606 | ps3_chip_mask(virq); | ||
607 | |||
608 | result = ps3_irq_plug_destroy(virq); | ||
518 | BUG_ON(result); | 609 | BUG_ON(result); |
519 | return 0; | 610 | |
611 | return result; | ||
520 | } | 612 | } |
521 | 613 | ||
522 | 614 | ||
@@ -533,7 +625,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, | |||
533 | *p & 0xffff); | 625 | *p & 0xffff); |
534 | } | 626 | } |
535 | 627 | ||
536 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, | 628 | static void __maybe_unused _dump_256_bmp(const char *header, |
537 | const u64 *p, unsigned cpu, const char* func, int line) | 629 | const u64 *p, unsigned cpu, const char* func, int line) |
538 | { | 630 | { |
539 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", | 631 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", |
@@ -546,86 +638,25 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line) | |||
546 | unsigned long flags; | 638 | unsigned long flags; |
547 | 639 | ||
548 | spin_lock_irqsave(&pd->bmp.lock, flags); | 640 | spin_lock_irqsave(&pd->bmp.lock, flags); |
549 | _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line); | 641 | _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); |
550 | _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); | 642 | _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); |
551 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 643 | spin_unlock_irqrestore(&pd->bmp.lock, flags); |
552 | } | 644 | } |
553 | 645 | ||
554 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) | 646 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) |
555 | static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd, | 647 | static void __maybe_unused _dump_mask(struct ps3_private *pd, |
556 | const char* func, int line) | 648 | const char* func, int line) |
557 | { | 649 | { |
558 | unsigned long flags; | 650 | unsigned long flags; |
559 | 651 | ||
560 | spin_lock_irqsave(&pd->bmp.lock, flags); | 652 | spin_lock_irqsave(&pd->bmp.lock, flags); |
561 | _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); | 653 | _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); |
562 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 654 | spin_unlock_irqrestore(&pd->bmp.lock, flags); |
563 | } | 655 | } |
564 | #else | 656 | #else |
565 | static void dump_bmp(struct ps3_private* pd) {}; | 657 | static void dump_bmp(struct ps3_private* pd) {}; |
566 | #endif /* defined(DEBUG) */ | 658 | #endif /* defined(DEBUG) */ |
567 | 659 | ||
568 | static void ps3_chip_mask(unsigned int virq) | ||
569 | { | ||
570 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
571 | u64 bit = 0x8000000000000000UL >> virq; | ||
572 | u64 *p = &pd->bmp.mask; | ||
573 | u64 old; | ||
574 | unsigned long flags; | ||
575 | |||
576 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | ||
577 | |||
578 | local_irq_save(flags); | ||
579 | asm volatile( | ||
580 | "1: ldarx %0,0,%3\n" | ||
581 | "andc %0,%0,%2\n" | ||
582 | "stdcx. %0,0,%3\n" | ||
583 | "bne- 1b" | ||
584 | : "=&r" (old), "+m" (*p) | ||
585 | : "r" (bit), "r" (p) | ||
586 | : "cc" ); | ||
587 | |||
588 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | ||
589 | local_irq_restore(flags); | ||
590 | } | ||
591 | |||
592 | static void ps3_chip_unmask(unsigned int virq) | ||
593 | { | ||
594 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
595 | u64 bit = 0x8000000000000000UL >> virq; | ||
596 | u64 *p = &pd->bmp.mask; | ||
597 | u64 old; | ||
598 | unsigned long flags; | ||
599 | |||
600 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | ||
601 | |||
602 | local_irq_save(flags); | ||
603 | asm volatile( | ||
604 | "1: ldarx %0,0,%3\n" | ||
605 | "or %0,%0,%2\n" | ||
606 | "stdcx. %0,0,%3\n" | ||
607 | "bne- 1b" | ||
608 | : "=&r" (old), "+m" (*p) | ||
609 | : "r" (bit), "r" (p) | ||
610 | : "cc" ); | ||
611 | |||
612 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | ||
613 | local_irq_restore(flags); | ||
614 | } | ||
615 | |||
616 | static void ps3_chip_eoi(unsigned int virq) | ||
617 | { | ||
618 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
619 | lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); | ||
620 | } | ||
621 | |||
622 | static struct irq_chip irq_chip = { | ||
623 | .typename = "ps3", | ||
624 | .mask = ps3_chip_mask, | ||
625 | .unmask = ps3_chip_unmask, | ||
626 | .eoi = ps3_chip_eoi, | ||
627 | }; | ||
628 | |||
629 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) | 660 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) |
630 | { | 661 | { |
631 | set_irq_chip_data(virq, NULL); | 662 | set_irq_chip_data(virq, NULL); |
@@ -637,7 +668,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, | |||
637 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, | 668 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, |
638 | virq); | 669 | virq); |
639 | 670 | ||
640 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); | 671 | set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); |
641 | 672 | ||
642 | return 0; | 673 | return 0; |
643 | } | 674 | } |
@@ -657,7 +688,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | |||
657 | cpu, virq, pd->bmp.ipi_debug_brk_mask); | 688 | cpu, virq, pd->bmp.ipi_debug_brk_mask); |
658 | } | 689 | } |
659 | 690 | ||
660 | unsigned int ps3_get_irq(void) | 691 | static unsigned int ps3_get_irq(void) |
661 | { | 692 | { |
662 | struct ps3_private *pd = &__get_cpu_var(ps3_private); | 693 | struct ps3_private *pd = &__get_cpu_var(ps3_private); |
663 | u64 x = (pd->bmp.status & pd->bmp.mask); | 694 | u64 x = (pd->bmp.status & pd->bmp.mask); |
@@ -672,8 +703,8 @@ unsigned int ps3_get_irq(void) | |||
672 | plug &= 0x3f; | 703 | plug &= 0x3f; |
673 | 704 | ||
674 | if (unlikely(plug) == NO_IRQ) { | 705 | if (unlikely(plug) == NO_IRQ) { |
675 | pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, | 706 | pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__, |
676 | pd->cpu); | 707 | __LINE__, pd->thread_id); |
677 | dump_bmp(&per_cpu(ps3_private, 0)); | 708 | dump_bmp(&per_cpu(ps3_private, 0)); |
678 | dump_bmp(&per_cpu(ps3_private, 1)); | 709 | dump_bmp(&per_cpu(ps3_private, 1)); |
679 | return NO_IRQ; | 710 | return NO_IRQ; |
@@ -703,16 +734,16 @@ void __init ps3_init_IRQ(void) | |||
703 | for_each_possible_cpu(cpu) { | 734 | for_each_possible_cpu(cpu) { |
704 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); | 735 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); |
705 | 736 | ||
706 | lv1_get_logical_ppe_id(&pd->node); | 737 | lv1_get_logical_ppe_id(&pd->ppe_id); |
707 | pd->cpu = get_hard_smp_processor_id(cpu); | 738 | pd->thread_id = get_hard_smp_processor_id(cpu); |
708 | spin_lock_init(&pd->bmp.lock); | 739 | spin_lock_init(&pd->bmp.lock); |
709 | 740 | ||
710 | pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__, | 741 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, bmp %lxh\n", |
711 | __LINE__, pd->node, pd->cpu, | 742 | __func__, __LINE__, pd->ppe_id, pd->thread_id, |
712 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | 743 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); |
713 | 744 | ||
714 | result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu, | 745 | result = lv1_configure_irq_state_bitmap(pd->ppe_id, |
715 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | 746 | pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); |
716 | 747 | ||
717 | if (result) | 748 | if (result) |
718 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" | 749 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" |
@@ -722,3 +753,16 @@ void __init ps3_init_IRQ(void) | |||
722 | 753 | ||
723 | ppc_md.get_irq = ps3_get_irq; | 754 | ppc_md.get_irq = ps3_get_irq; |
724 | } | 755 | } |
756 | |||
757 | void ps3_shutdown_IRQ(int cpu) | ||
758 | { | ||
759 | int result; | ||
760 | u64 ppe_id; | ||
761 | u64 thread_id = get_hard_smp_processor_id(cpu); | ||
762 | |||
763 | lv1_get_logical_ppe_id(&ppe_id); | ||
764 | result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); | ||
765 | |||
766 | DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__, | ||
767 | __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); | ||
768 | } | ||
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index f8a3e206c584..7bb3e1620974 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include "platform.h" | 30 | #include "platform.h" |
31 | 31 | ||
32 | #if defined(DEBUG) | 32 | #if defined(DEBUG) |
33 | #define DBG(fmt...) udbg_printf(fmt) | 33 | #define DBG udbg_printf |
34 | #else | 34 | #else |
35 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 35 | #define DBG pr_debug |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | enum { | 38 | enum { |
@@ -115,7 +115,8 @@ struct map { | |||
115 | }; | 115 | }; |
116 | 116 | ||
117 | #define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__) | 117 | #define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__) |
118 | static void _debug_dump_map(const struct map* m, const char* func, int line) | 118 | static void __maybe_unused _debug_dump_map(const struct map *m, |
119 | const char *func, int line) | ||
119 | { | 120 | { |
120 | DBG("%s:%d: map.total = %lxh\n", func, line, m->total); | 121 | DBG("%s:%d: map.total = %lxh\n", func, line, m->total); |
121 | DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size); | 122 | DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size); |
@@ -212,9 +213,15 @@ fail: | |||
212 | 213 | ||
213 | void ps3_mm_vas_destroy(void) | 214 | void ps3_mm_vas_destroy(void) |
214 | { | 215 | { |
216 | int result; | ||
217 | |||
218 | DBG("%s:%d: map.vas_id = %lu\n", __func__, __LINE__, map.vas_id); | ||
219 | |||
215 | if (map.vas_id) { | 220 | if (map.vas_id) { |
216 | lv1_select_virtual_address_space(0); | 221 | result = lv1_select_virtual_address_space(0); |
217 | lv1_destruct_virtual_address_space(map.vas_id); | 222 | BUG_ON(result); |
223 | result = lv1_destruct_virtual_address_space(map.vas_id); | ||
224 | BUG_ON(result); | ||
218 | map.vas_id = 0; | 225 | map.vas_id = 0; |
219 | } | 226 | } |
220 | } | 227 | } |
@@ -232,7 +239,7 @@ void ps3_mm_vas_destroy(void) | |||
232 | * @size is rounded down to a multiple of the vas large page size. | 239 | * @size is rounded down to a multiple of the vas large page size. |
233 | */ | 240 | */ |
234 | 241 | ||
235 | int ps3_mm_region_create(struct mem_region *r, unsigned long size) | 242 | static int ps3_mm_region_create(struct mem_region *r, unsigned long size) |
236 | { | 243 | { |
237 | int result; | 244 | int result; |
238 | unsigned long muid; | 245 | unsigned long muid; |
@@ -273,10 +280,14 @@ zero_region: | |||
273 | * @r: pointer to struct mem_region | 280 | * @r: pointer to struct mem_region |
274 | */ | 281 | */ |
275 | 282 | ||
276 | void ps3_mm_region_destroy(struct mem_region *r) | 283 | static void ps3_mm_region_destroy(struct mem_region *r) |
277 | { | 284 | { |
285 | int result; | ||
286 | |||
287 | DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base); | ||
278 | if (r->base) { | 288 | if (r->base) { |
279 | lv1_release_memory(r->base); | 289 | result = lv1_release_memory(r->base); |
290 | BUG_ON(result); | ||
280 | r->size = r->base = r->offset = 0; | 291 | r->size = r->base = r->offset = 0; |
281 | map.total = map.rm.size; | 292 | map.total = map.rm.size; |
282 | } | 293 | } |
@@ -329,31 +340,34 @@ core_initcall(ps3_mm_add_memory); | |||
329 | /*============================================================================*/ | 340 | /*============================================================================*/ |
330 | 341 | ||
331 | /** | 342 | /** |
332 | * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address. | 343 | * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address. |
333 | * @r: pointer to dma region structure | 344 | * @r: pointer to dma region structure |
334 | * @lpar_addr: HV lpar address | 345 | * @lpar_addr: HV lpar address |
335 | */ | 346 | */ |
336 | 347 | ||
337 | static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r, | 348 | static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, |
338 | unsigned long lpar_addr) | 349 | unsigned long lpar_addr) |
339 | { | 350 | { |
340 | BUG_ON(lpar_addr >= map.r1.base + map.r1.size); | 351 | if (lpar_addr >= map.rm.size) |
341 | return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr | 352 | lpar_addr -= map.r1.offset; |
342 | : lpar_addr - map.r1.offset); | 353 | BUG_ON(lpar_addr < r->offset); |
354 | BUG_ON(lpar_addr >= r->offset + r->len); | ||
355 | return r->bus_addr + lpar_addr - r->offset; | ||
343 | } | 356 | } |
344 | 357 | ||
345 | #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__) | 358 | #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__) |
346 | static void _dma_dump_region(const struct ps3_dma_region *r, const char* func, | 359 | static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, |
347 | int line) | 360 | const char *func, int line) |
348 | { | 361 | { |
349 | DBG("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | 362 | DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, |
350 | r->did.dev_id); | 363 | r->dev->dev_id); |
351 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); | 364 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); |
352 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 365 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); |
353 | DBG("%s:%d: len %lxh\n", func, line, r->len); | 366 | DBG("%s:%d: len %lxh\n", func, line, r->len); |
367 | DBG("%s:%d: offset %lxh\n", func, line, r->offset); | ||
354 | } | 368 | } |
355 | 369 | ||
356 | /** | 370 | /** |
357 | * dma_chunk - A chunk of dma pages mapped by the io controller. | 371 | * dma_chunk - A chunk of dma pages mapped by the io controller. |
358 | * @region - The dma region that owns this chunk. | 372 | * @region - The dma region that owns this chunk. |
359 | * @lpar_addr: Starting lpar address of the area to map. | 373 | * @lpar_addr: Starting lpar address of the area to map. |
@@ -381,10 +395,11 @@ static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, | |||
381 | int line) | 395 | int line) |
382 | { | 396 | { |
383 | DBG("%s:%d: r.dev %u:%u\n", func, line, | 397 | DBG("%s:%d: r.dev %u:%u\n", func, line, |
384 | c->region->did.bus_id, c->region->did.dev_id); | 398 | c->region->dev->bus_id, c->region->dev->dev_id); |
385 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); | 399 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); |
386 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); | 400 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); |
387 | DBG("%s:%d: r.len %lxh\n", func, line, c->region->len); | 401 | DBG("%s:%d: r.len %lxh\n", func, line, c->region->len); |
402 | DBG("%s:%d: r.offset %lxh\n", func, line, c->region->offset); | ||
388 | DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr); | 403 | DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr); |
389 | DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr); | 404 | DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr); |
390 | DBG("%s:%d: c.len %lxh\n", func, line, c->len); | 405 | DBG("%s:%d: c.len %lxh\n", func, line, c->len); |
@@ -395,39 +410,68 @@ static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r, | |||
395 | { | 410 | { |
396 | struct dma_chunk *c; | 411 | struct dma_chunk *c; |
397 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); | 412 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); |
398 | unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); | 413 | unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus, |
414 | 1 << r->page_size); | ||
399 | 415 | ||
400 | list_for_each_entry(c, &r->chunk_list.head, link) { | 416 | list_for_each_entry(c, &r->chunk_list.head, link) { |
401 | /* intersection */ | 417 | /* intersection */ |
402 | if (aligned_bus >= c->bus_addr | 418 | if (aligned_bus >= c->bus_addr && |
403 | && aligned_bus < c->bus_addr + c->len | 419 | aligned_bus + aligned_len <= c->bus_addr + c->len) |
404 | && aligned_bus + aligned_len <= c->bus_addr + c->len) { | ||
405 | return c; | 420 | return c; |
406 | } | 421 | |
407 | /* below */ | 422 | /* below */ |
408 | if (aligned_bus + aligned_len <= c->bus_addr) { | 423 | if (aligned_bus + aligned_len <= c->bus_addr) |
409 | continue; | 424 | continue; |
410 | } | 425 | |
411 | /* above */ | 426 | /* above */ |
412 | if (aligned_bus >= c->bus_addr + c->len) { | 427 | if (aligned_bus >= c->bus_addr + c->len) |
413 | continue; | 428 | continue; |
414 | } | ||
415 | 429 | ||
416 | /* we don't handle the multi-chunk case for now */ | 430 | /* we don't handle the multi-chunk case for now */ |
417 | |||
418 | dma_dump_chunk(c); | 431 | dma_dump_chunk(c); |
419 | BUG(); | 432 | BUG(); |
420 | } | 433 | } |
421 | return NULL; | 434 | return NULL; |
422 | } | 435 | } |
423 | 436 | ||
424 | static int dma_free_chunk(struct dma_chunk *c) | 437 | static struct dma_chunk *dma_find_chunk_lpar(struct ps3_dma_region *r, |
438 | unsigned long lpar_addr, unsigned long len) | ||
439 | { | ||
440 | struct dma_chunk *c; | ||
441 | unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size); | ||
442 | unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar, | ||
443 | 1 << r->page_size); | ||
444 | |||
445 | list_for_each_entry(c, &r->chunk_list.head, link) { | ||
446 | /* intersection */ | ||
447 | if (c->lpar_addr <= aligned_lpar && | ||
448 | aligned_lpar < c->lpar_addr + c->len) { | ||
449 | if (aligned_lpar + aligned_len <= c->lpar_addr + c->len) | ||
450 | return c; | ||
451 | else { | ||
452 | dma_dump_chunk(c); | ||
453 | BUG(); | ||
454 | } | ||
455 | } | ||
456 | /* below */ | ||
457 | if (aligned_lpar + aligned_len <= c->lpar_addr) { | ||
458 | continue; | ||
459 | } | ||
460 | /* above */ | ||
461 | if (c->lpar_addr + c->len <= aligned_lpar) { | ||
462 | continue; | ||
463 | } | ||
464 | } | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
468 | static int dma_sb_free_chunk(struct dma_chunk *c) | ||
425 | { | 469 | { |
426 | int result = 0; | 470 | int result = 0; |
427 | 471 | ||
428 | if (c->bus_addr) { | 472 | if (c->bus_addr) { |
429 | result = lv1_unmap_device_dma_region(c->region->did.bus_id, | 473 | result = lv1_unmap_device_dma_region(c->region->dev->bus_id, |
430 | c->region->did.dev_id, c->bus_addr, c->len); | 474 | c->region->dev->dev_id, c->bus_addr, c->len); |
431 | BUG_ON(result); | 475 | BUG_ON(result); |
432 | } | 476 | } |
433 | 477 | ||
@@ -435,8 +479,39 @@ static int dma_free_chunk(struct dma_chunk *c) | |||
435 | return result; | 479 | return result; |
436 | } | 480 | } |
437 | 481 | ||
482 | static int dma_ioc0_free_chunk(struct dma_chunk *c) | ||
483 | { | ||
484 | int result = 0; | ||
485 | int iopage; | ||
486 | unsigned long offset; | ||
487 | struct ps3_dma_region *r = c->region; | ||
488 | |||
489 | DBG("%s:start\n", __func__); | ||
490 | for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) { | ||
491 | offset = (1 << r->page_size) * iopage; | ||
492 | /* put INVALID entry */ | ||
493 | result = lv1_put_iopte(0, | ||
494 | c->bus_addr + offset, | ||
495 | c->lpar_addr + offset, | ||
496 | r->ioid, | ||
497 | 0); | ||
498 | DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__, | ||
499 | c->bus_addr + offset, | ||
500 | c->lpar_addr + offset, | ||
501 | r->ioid); | ||
502 | |||
503 | if (result) { | ||
504 | DBG("%s:%d: lv1_put_iopte failed: %s\n", __func__, | ||
505 | __LINE__, ps3_result(result)); | ||
506 | } | ||
507 | } | ||
508 | kfree(c); | ||
509 | DBG("%s:end\n", __func__); | ||
510 | return result; | ||
511 | } | ||
512 | |||
438 | /** | 513 | /** |
439 | * dma_map_pages - Maps dma pages into the io controller bus address space. | 514 | * dma_sb_map_pages - Maps dma pages into the io controller bus address space. |
440 | * @r: Pointer to a struct ps3_dma_region. | 515 | * @r: Pointer to a struct ps3_dma_region. |
441 | * @phys_addr: Starting physical address of the area to map. | 516 | * @phys_addr: Starting physical address of the area to map. |
442 | * @len: Length in bytes of the area to map. | 517 | * @len: Length in bytes of the area to map. |
@@ -446,8 +521,8 @@ static int dma_free_chunk(struct dma_chunk *c) | |||
446 | * make the HV call to add the pages into the io controller address space. | 521 | * make the HV call to add the pages into the io controller address space. |
447 | */ | 522 | */ |
448 | 523 | ||
449 | static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | 524 | static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, |
450 | unsigned long len, struct dma_chunk **c_out) | 525 | unsigned long len, struct dma_chunk **c_out, u64 iopte_flag) |
451 | { | 526 | { |
452 | int result; | 527 | int result; |
453 | struct dma_chunk *c; | 528 | struct dma_chunk *c; |
@@ -461,13 +536,13 @@ static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | |||
461 | 536 | ||
462 | c->region = r; | 537 | c->region = r; |
463 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | 538 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); |
464 | c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr); | 539 | c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr); |
465 | c->len = len; | 540 | c->len = len; |
466 | 541 | ||
467 | result = lv1_map_device_dma_region(c->region->did.bus_id, | 542 | BUG_ON(iopte_flag != 0xf800000000000000UL); |
468 | c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len, | 543 | result = lv1_map_device_dma_region(c->region->dev->bus_id, |
469 | 0xf800000000000000UL); | 544 | c->region->dev->dev_id, c->lpar_addr, |
470 | 545 | c->bus_addr, c->len, iopte_flag); | |
471 | if (result) { | 546 | if (result) { |
472 | DBG("%s:%d: lv1_map_device_dma_region failed: %s\n", | 547 | DBG("%s:%d: lv1_map_device_dma_region failed: %s\n", |
473 | __func__, __LINE__, ps3_result(result)); | 548 | __func__, __LINE__, ps3_result(result)); |
@@ -487,26 +562,120 @@ fail_alloc: | |||
487 | return result; | 562 | return result; |
488 | } | 563 | } |
489 | 564 | ||
565 | static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | ||
566 | unsigned long len, struct dma_chunk **c_out, | ||
567 | u64 iopte_flag) | ||
568 | { | ||
569 | int result; | ||
570 | struct dma_chunk *c, *last; | ||
571 | int iopage, pages; | ||
572 | unsigned long offset; | ||
573 | |||
574 | DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__, | ||
575 | phys_addr, ps3_mm_phys_to_lpar(phys_addr), len); | ||
576 | c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC); | ||
577 | |||
578 | if (!c) { | ||
579 | result = -ENOMEM; | ||
580 | goto fail_alloc; | ||
581 | } | ||
582 | |||
583 | c->region = r; | ||
584 | c->len = len; | ||
585 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | ||
586 | /* allocate IO address */ | ||
587 | if (list_empty(&r->chunk_list.head)) { | ||
588 | /* first one */ | ||
589 | c->bus_addr = r->bus_addr; | ||
590 | } else { | ||
591 | /* derive from last bus addr*/ | ||
592 | last = list_entry(r->chunk_list.head.next, | ||
593 | struct dma_chunk, link); | ||
594 | c->bus_addr = last->bus_addr + last->len; | ||
595 | DBG("%s: last bus=%#lx, len=%#lx\n", __func__, | ||
596 | last->bus_addr, last->len); | ||
597 | } | ||
598 | |||
599 | /* FIXME: check whether length exceeds region size */ | ||
600 | |||
601 | /* build ioptes for the area */ | ||
602 | pages = len >> r->page_size; | ||
603 | DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__, | ||
604 | r->page_size, r->len, pages, iopte_flag); | ||
605 | for (iopage = 0; iopage < pages; iopage++) { | ||
606 | offset = (1 << r->page_size) * iopage; | ||
607 | result = lv1_put_iopte(0, | ||
608 | c->bus_addr + offset, | ||
609 | c->lpar_addr + offset, | ||
610 | r->ioid, | ||
611 | iopte_flag); | ||
612 | if (result) { | ||
613 | printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region " | ||
614 | "failed: %s\n", __func__, __LINE__, | ||
615 | ps3_result(result)); | ||
616 | goto fail_map; | ||
617 | } | ||
618 | DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__, | ||
619 | iopage, c->bus_addr + offset, c->lpar_addr + offset, | ||
620 | r->ioid); | ||
621 | } | ||
622 | |||
623 | /* be sure that last allocated one is inserted at head */ | ||
624 | list_add(&c->link, &r->chunk_list.head); | ||
625 | |||
626 | *c_out = c; | ||
627 | DBG("%s: end\n", __func__); | ||
628 | return 0; | ||
629 | |||
630 | fail_map: | ||
631 | for (iopage--; 0 <= iopage; iopage--) { | ||
632 | lv1_put_iopte(0, | ||
633 | c->bus_addr + offset, | ||
634 | c->lpar_addr + offset, | ||
635 | r->ioid, | ||
636 | 0); | ||
637 | } | ||
638 | kfree(c); | ||
639 | fail_alloc: | ||
640 | *c_out = NULL; | ||
641 | return result; | ||
642 | } | ||
643 | |||
490 | /** | 644 | /** |
491 | * dma_region_create - Create a device dma region. | 645 | * dma_sb_region_create - Create a device dma region. |
492 | * @r: Pointer to a struct ps3_dma_region. | 646 | * @r: Pointer to a struct ps3_dma_region. |
493 | * | 647 | * |
494 | * This is the lowest level dma region create routine, and is the one that | 648 | * This is the lowest level dma region create routine, and is the one that |
495 | * will make the HV call to create the region. | 649 | * will make the HV call to create the region. |
496 | */ | 650 | */ |
497 | 651 | ||
498 | static int dma_region_create(struct ps3_dma_region* r) | 652 | static int dma_sb_region_create(struct ps3_dma_region *r) |
499 | { | 653 | { |
500 | int result; | 654 | int result; |
501 | 655 | ||
502 | r->len = _ALIGN_UP(map.total, 1 << r->page_size); | 656 | pr_info(" -> %s:%d:\n", __func__, __LINE__); |
657 | |||
658 | BUG_ON(!r); | ||
659 | |||
660 | if (!r->dev->bus_id) { | ||
661 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | ||
662 | r->dev->bus_id, r->dev->dev_id); | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__, | ||
667 | __LINE__, r->len, r->page_size, r->offset); | ||
668 | |||
669 | BUG_ON(!r->len); | ||
670 | BUG_ON(!r->page_size); | ||
671 | BUG_ON(!r->region_ops); | ||
672 | |||
503 | INIT_LIST_HEAD(&r->chunk_list.head); | 673 | INIT_LIST_HEAD(&r->chunk_list.head); |
504 | spin_lock_init(&r->chunk_list.lock); | 674 | spin_lock_init(&r->chunk_list.lock); |
505 | 675 | ||
506 | result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id, | 676 | result = lv1_allocate_device_dma_region(r->dev->bus_id, r->dev->dev_id, |
507 | r->len, r->page_size, r->region_type, &r->bus_addr); | 677 | roundup_pow_of_two(r->len), r->page_size, r->region_type, |
508 | 678 | &r->bus_addr); | |
509 | dma_dump_region(r); | ||
510 | 679 | ||
511 | if (result) { | 680 | if (result) { |
512 | DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n", | 681 | DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n", |
@@ -517,6 +686,27 @@ static int dma_region_create(struct ps3_dma_region* r) | |||
517 | return result; | 686 | return result; |
518 | } | 687 | } |
519 | 688 | ||
689 | static int dma_ioc0_region_create(struct ps3_dma_region *r) | ||
690 | { | ||
691 | int result; | ||
692 | |||
693 | INIT_LIST_HEAD(&r->chunk_list.head); | ||
694 | spin_lock_init(&r->chunk_list.lock); | ||
695 | |||
696 | result = lv1_allocate_io_segment(0, | ||
697 | r->len, | ||
698 | r->page_size, | ||
699 | &r->bus_addr); | ||
700 | if (result) { | ||
701 | DBG("%s:%d: lv1_allocate_io_segment failed: %s\n", | ||
702 | __func__, __LINE__, ps3_result(result)); | ||
703 | r->len = r->bus_addr = 0; | ||
704 | } | ||
705 | DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__, | ||
706 | r->len, r->page_size, r->bus_addr); | ||
707 | return result; | ||
708 | } | ||
709 | |||
520 | /** | 710 | /** |
521 | * dma_region_free - Free a device dma region. | 711 | * dma_region_free - Free a device dma region. |
522 | * @r: Pointer to a struct ps3_dma_region. | 712 | * @r: Pointer to a struct ps3_dma_region. |
@@ -525,31 +715,62 @@ static int dma_region_create(struct ps3_dma_region* r) | |||
525 | * will make the HV call to free the region. | 715 | * will make the HV call to free the region. |
526 | */ | 716 | */ |
527 | 717 | ||
528 | static int dma_region_free(struct ps3_dma_region* r) | 718 | static int dma_sb_region_free(struct ps3_dma_region *r) |
529 | { | 719 | { |
530 | int result; | 720 | int result; |
531 | struct dma_chunk *c; | 721 | struct dma_chunk *c; |
532 | struct dma_chunk *tmp; | 722 | struct dma_chunk *tmp; |
533 | 723 | ||
724 | BUG_ON(!r); | ||
725 | |||
726 | if (!r->dev->bus_id) { | ||
727 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | ||
728 | r->dev->bus_id, r->dev->dev_id); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
534 | list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) { | 732 | list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) { |
535 | list_del(&c->link); | 733 | list_del(&c->link); |
536 | dma_free_chunk(c); | 734 | dma_sb_free_chunk(c); |
537 | } | 735 | } |
538 | 736 | ||
539 | result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id, | 737 | result = lv1_free_device_dma_region(r->dev->bus_id, r->dev->dev_id, |
540 | r->bus_addr); | 738 | r->bus_addr); |
541 | 739 | ||
542 | if (result) | 740 | if (result) |
543 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", | 741 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", |
544 | __func__, __LINE__, ps3_result(result)); | 742 | __func__, __LINE__, ps3_result(result)); |
545 | 743 | ||
546 | r->len = r->bus_addr = 0; | 744 | r->bus_addr = 0; |
745 | |||
746 | return result; | ||
747 | } | ||
748 | |||
749 | static int dma_ioc0_region_free(struct ps3_dma_region *r) | ||
750 | { | ||
751 | int result; | ||
752 | struct dma_chunk *c, *n; | ||
753 | |||
754 | DBG("%s: start\n", __func__); | ||
755 | list_for_each_entry_safe(c, n, &r->chunk_list.head, link) { | ||
756 | list_del(&c->link); | ||
757 | dma_ioc0_free_chunk(c); | ||
758 | } | ||
759 | |||
760 | result = lv1_release_io_segment(0, r->bus_addr); | ||
761 | |||
762 | if (result) | ||
763 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", | ||
764 | __func__, __LINE__, ps3_result(result)); | ||
765 | |||
766 | r->bus_addr = 0; | ||
767 | DBG("%s: end\n", __func__); | ||
547 | 768 | ||
548 | return result; | 769 | return result; |
549 | } | 770 | } |
550 | 771 | ||
551 | /** | 772 | /** |
552 | * dma_map_area - Map an area of memory into a device dma region. | 773 | * dma_sb_map_area - Map an area of memory into a device dma region. |
553 | * @r: Pointer to a struct ps3_dma_region. | 774 | * @r: Pointer to a struct ps3_dma_region. |
554 | * @virt_addr: Starting virtual address of the area to map. | 775 | * @virt_addr: Starting virtual address of the area to map. |
555 | * @len: Length in bytes of the area to map. | 776 | * @len: Length in bytes of the area to map. |
@@ -559,16 +780,19 @@ static int dma_region_free(struct ps3_dma_region* r) | |||
559 | * This is the common dma mapping routine. | 780 | * This is the common dma mapping routine. |
560 | */ | 781 | */ |
561 | 782 | ||
562 | static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | 783 | static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr, |
563 | unsigned long len, unsigned long *bus_addr) | 784 | unsigned long len, unsigned long *bus_addr, |
785 | u64 iopte_flag) | ||
564 | { | 786 | { |
565 | int result; | 787 | int result; |
566 | unsigned long flags; | 788 | unsigned long flags; |
567 | struct dma_chunk *c; | 789 | struct dma_chunk *c; |
568 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | 790 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) |
569 | : virt_addr; | 791 | : virt_addr; |
570 | 792 | unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); | |
571 | *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | 793 | unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, |
794 | 1 << r->page_size); | ||
795 | *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | ||
572 | 796 | ||
573 | if (!USE_DYNAMIC_DMA) { | 797 | if (!USE_DYNAMIC_DMA) { |
574 | unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | 798 | unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr); |
@@ -588,17 +812,18 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
588 | c = dma_find_chunk(r, *bus_addr, len); | 812 | c = dma_find_chunk(r, *bus_addr, len); |
589 | 813 | ||
590 | if (c) { | 814 | if (c) { |
815 | DBG("%s:%d: reusing mapped chunk", __func__, __LINE__); | ||
816 | dma_dump_chunk(c); | ||
591 | c->usage_count++; | 817 | c->usage_count++; |
592 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 818 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
593 | return 0; | 819 | return 0; |
594 | } | 820 | } |
595 | 821 | ||
596 | result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size), | 822 | result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag); |
597 | _ALIGN_UP(len, 1 << r->page_size), &c); | ||
598 | 823 | ||
599 | if (result) { | 824 | if (result) { |
600 | *bus_addr = 0; | 825 | *bus_addr = 0; |
601 | DBG("%s:%d: dma_map_pages failed (%d)\n", | 826 | DBG("%s:%d: dma_sb_map_pages failed (%d)\n", |
602 | __func__, __LINE__, result); | 827 | __func__, __LINE__, result); |
603 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 828 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
604 | return result; | 829 | return result; |
@@ -610,8 +835,57 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
610 | return result; | 835 | return result; |
611 | } | 836 | } |
612 | 837 | ||
838 | static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | ||
839 | unsigned long len, unsigned long *bus_addr, | ||
840 | u64 iopte_flag) | ||
841 | { | ||
842 | int result; | ||
843 | unsigned long flags; | ||
844 | struct dma_chunk *c; | ||
845 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | ||
846 | : virt_addr; | ||
847 | unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); | ||
848 | unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, | ||
849 | 1 << r->page_size); | ||
850 | |||
851 | DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__, | ||
852 | virt_addr, len); | ||
853 | DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__, | ||
854 | phys_addr, aligned_phys, aligned_len); | ||
855 | |||
856 | spin_lock_irqsave(&r->chunk_list.lock, flags); | ||
857 | c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len); | ||
858 | |||
859 | if (c) { | ||
860 | /* FIXME */ | ||
861 | BUG(); | ||
862 | *bus_addr = c->bus_addr + phys_addr - aligned_phys; | ||
863 | c->usage_count++; | ||
864 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c, | ||
869 | iopte_flag); | ||
870 | |||
871 | if (result) { | ||
872 | *bus_addr = 0; | ||
873 | DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n", | ||
874 | __func__, __LINE__, result); | ||
875 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
876 | return result; | ||
877 | } | ||
878 | *bus_addr = c->bus_addr + phys_addr - aligned_phys; | ||
879 | DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__, | ||
880 | virt_addr, phys_addr, aligned_phys, *bus_addr); | ||
881 | c->usage_count = 1; | ||
882 | |||
883 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
884 | return result; | ||
885 | } | ||
886 | |||
613 | /** | 887 | /** |
614 | * dma_unmap_area - Unmap an area of memory from a device dma region. | 888 | * dma_sb_unmap_area - Unmap an area of memory from a device dma region. |
615 | * @r: Pointer to a struct ps3_dma_region. | 889 | * @r: Pointer to a struct ps3_dma_region. |
616 | * @bus_addr: The starting ioc bus address of the area to unmap. | 890 | * @bus_addr: The starting ioc bus address of the area to unmap. |
617 | * @len: Length in bytes of the area to unmap. | 891 | * @len: Length in bytes of the area to unmap. |
@@ -619,7 +893,7 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
619 | * This is the common dma unmap routine. | 893 | * This is the common dma unmap routine. |
620 | */ | 894 | */ |
621 | 895 | ||
622 | int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | 896 | static int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, |
623 | unsigned long len) | 897 | unsigned long len) |
624 | { | 898 | { |
625 | unsigned long flags; | 899 | unsigned long flags; |
@@ -631,7 +905,8 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | |||
631 | if (!c) { | 905 | if (!c) { |
632 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, | 906 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, |
633 | 1 << r->page_size); | 907 | 1 << r->page_size); |
634 | unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); | 908 | unsigned long aligned_len = _ALIGN_UP(len + bus_addr |
909 | - aligned_bus, 1 << r->page_size); | ||
635 | DBG("%s:%d: not found: bus_addr %lxh\n", | 910 | DBG("%s:%d: not found: bus_addr %lxh\n", |
636 | __func__, __LINE__, bus_addr); | 911 | __func__, __LINE__, bus_addr); |
637 | DBG("%s:%d: not found: len %lxh\n", | 912 | DBG("%s:%d: not found: len %lxh\n", |
@@ -647,94 +922,166 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | |||
647 | 922 | ||
648 | if (!c->usage_count) { | 923 | if (!c->usage_count) { |
649 | list_del(&c->link); | 924 | list_del(&c->link); |
650 | dma_free_chunk(c); | 925 | dma_sb_free_chunk(c); |
651 | } | 926 | } |
652 | 927 | ||
653 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 928 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
654 | return 0; | 929 | return 0; |
655 | } | 930 | } |
656 | 931 | ||
932 | static int dma_ioc0_unmap_area(struct ps3_dma_region *r, | ||
933 | unsigned long bus_addr, unsigned long len) | ||
934 | { | ||
935 | unsigned long flags; | ||
936 | struct dma_chunk *c; | ||
937 | |||
938 | DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len); | ||
939 | spin_lock_irqsave(&r->chunk_list.lock, flags); | ||
940 | c = dma_find_chunk(r, bus_addr, len); | ||
941 | |||
942 | if (!c) { | ||
943 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, | ||
944 | 1 << r->page_size); | ||
945 | unsigned long aligned_len = _ALIGN_UP(len + bus_addr | ||
946 | - aligned_bus, | ||
947 | 1 << r->page_size); | ||
948 | DBG("%s:%d: not found: bus_addr %lxh\n", | ||
949 | __func__, __LINE__, bus_addr); | ||
950 | DBG("%s:%d: not found: len %lxh\n", | ||
951 | __func__, __LINE__, len); | ||
952 | DBG("%s:%d: not found: aligned_bus %lxh\n", | ||
953 | __func__, __LINE__, aligned_bus); | ||
954 | DBG("%s:%d: not found: aligned_len %lxh\n", | ||
955 | __func__, __LINE__, aligned_len); | ||
956 | BUG(); | ||
957 | } | ||
958 | |||
959 | c->usage_count--; | ||
960 | |||
961 | if (!c->usage_count) { | ||
962 | list_del(&c->link); | ||
963 | dma_ioc0_free_chunk(c); | ||
964 | } | ||
965 | |||
966 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
967 | DBG("%s: end\n", __func__); | ||
968 | return 0; | ||
969 | } | ||
970 | |||
657 | /** | 971 | /** |
658 | * dma_region_create_linear - Setup a linear dma maping for a device. | 972 | * dma_sb_region_create_linear - Setup a linear dma mapping for a device. |
659 | * @r: Pointer to a struct ps3_dma_region. | 973 | * @r: Pointer to a struct ps3_dma_region. |
660 | * | 974 | * |
661 | * This routine creates an HV dma region for the device and maps all available | 975 | * This routine creates an HV dma region for the device and maps all available |
662 | * ram into the io controller bus address space. | 976 | * ram into the io controller bus address space. |
663 | */ | 977 | */ |
664 | 978 | ||
665 | static int dma_region_create_linear(struct ps3_dma_region *r) | 979 | static int dma_sb_region_create_linear(struct ps3_dma_region *r) |
666 | { | 980 | { |
667 | int result; | 981 | int result; |
668 | unsigned long tmp; | 982 | unsigned long virt_addr, len, tmp; |
669 | 983 | ||
670 | /* force 16M dma pages for linear mapping */ | 984 | if (r->len > 16*1024*1024) { /* FIXME: need proper fix */ |
671 | 985 | /* force 16M dma pages for linear mapping */ | |
672 | if (r->page_size != PS3_DMA_16M) { | 986 | if (r->page_size != PS3_DMA_16M) { |
673 | pr_info("%s:%d: forcing 16M pages for linear map\n", | 987 | pr_info("%s:%d: forcing 16M pages for linear map\n", |
674 | __func__, __LINE__); | 988 | __func__, __LINE__); |
675 | r->page_size = PS3_DMA_16M; | 989 | r->page_size = PS3_DMA_16M; |
990 | r->len = _ALIGN_UP(r->len, 1 << r->page_size); | ||
991 | } | ||
676 | } | 992 | } |
677 | 993 | ||
678 | result = dma_region_create(r); | 994 | result = dma_sb_region_create(r); |
679 | BUG_ON(result); | 995 | BUG_ON(result); |
680 | 996 | ||
681 | result = dma_map_area(r, map.rm.base, map.rm.size, &tmp); | 997 | if (r->offset < map.rm.size) { |
682 | BUG_ON(result); | 998 | /* Map (part of) 1st RAM chunk */ |
683 | 999 | virt_addr = map.rm.base + r->offset; | |
684 | if (USE_LPAR_ADDR) | 1000 | len = map.rm.size - r->offset; |
685 | result = dma_map_area(r, map.r1.base, map.r1.size, | 1001 | if (len > r->len) |
686 | &tmp); | 1002 | len = r->len; |
687 | else | 1003 | result = dma_sb_map_area(r, virt_addr, len, &tmp, |
688 | result = dma_map_area(r, map.rm.size, map.r1.size, | 1004 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); |
689 | &tmp); | 1005 | BUG_ON(result); |
1006 | } | ||
690 | 1007 | ||
691 | BUG_ON(result); | 1008 | if (r->offset + r->len > map.rm.size) { |
1009 | /* Map (part of) 2nd RAM chunk */ | ||
1010 | virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; | ||
1011 | len = r->len; | ||
1012 | if (r->offset >= map.rm.size) | ||
1013 | virt_addr += r->offset - map.rm.size; | ||
1014 | else | ||
1015 | len -= map.rm.size - r->offset; | ||
1016 | result = dma_sb_map_area(r, virt_addr, len, &tmp, | ||
1017 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); | ||
1018 | BUG_ON(result); | ||
1019 | } | ||
692 | 1020 | ||
693 | return result; | 1021 | return result; |
694 | } | 1022 | } |
695 | 1023 | ||
696 | /** | 1024 | /** |
697 | * dma_region_free_linear - Free a linear dma mapping for a device. | 1025 | * dma_sb_region_free_linear - Free a linear dma mapping for a device. |
698 | * @r: Pointer to a struct ps3_dma_region. | 1026 | * @r: Pointer to a struct ps3_dma_region. |
699 | * | 1027 | * |
700 | * This routine will unmap all mapped areas and free the HV dma region. | 1028 | * This routine will unmap all mapped areas and free the HV dma region. |
701 | */ | 1029 | */ |
702 | 1030 | ||
703 | static int dma_region_free_linear(struct ps3_dma_region *r) | 1031 | static int dma_sb_region_free_linear(struct ps3_dma_region *r) |
704 | { | 1032 | { |
705 | int result; | 1033 | int result; |
1034 | unsigned long bus_addr, len, lpar_addr; | ||
1035 | |||
1036 | if (r->offset < map.rm.size) { | ||
1037 | /* Unmap (part of) 1st RAM chunk */ | ||
1038 | lpar_addr = map.rm.base + r->offset; | ||
1039 | len = map.rm.size - r->offset; | ||
1040 | if (len > r->len) | ||
1041 | len = r->len; | ||
1042 | bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); | ||
1043 | result = dma_sb_unmap_area(r, bus_addr, len); | ||
1044 | BUG_ON(result); | ||
1045 | } | ||
706 | 1046 | ||
707 | result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size); | 1047 | if (r->offset + r->len > map.rm.size) { |
708 | BUG_ON(result); | 1048 | /* Unmap (part of) 2nd RAM chunk */ |
709 | 1049 | lpar_addr = map.r1.base; | |
710 | result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base), | 1050 | len = r->len; |
711 | map.r1.size); | 1051 | if (r->offset >= map.rm.size) |
712 | BUG_ON(result); | 1052 | lpar_addr += r->offset - map.rm.size; |
1053 | else | ||
1054 | len -= map.rm.size - r->offset; | ||
1055 | bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); | ||
1056 | result = dma_sb_unmap_area(r, bus_addr, len); | ||
1057 | BUG_ON(result); | ||
1058 | } | ||
713 | 1059 | ||
714 | result = dma_region_free(r); | 1060 | result = dma_sb_region_free(r); |
715 | BUG_ON(result); | 1061 | BUG_ON(result); |
716 | 1062 | ||
717 | return result; | 1063 | return result; |
718 | } | 1064 | } |
719 | 1065 | ||
720 | /** | 1066 | /** |
721 | * dma_map_area_linear - Map an area of memory into a device dma region. | 1067 | * dma_sb_map_area_linear - Map an area of memory into a device dma region. |
722 | * @r: Pointer to a struct ps3_dma_region. | 1068 | * @r: Pointer to a struct ps3_dma_region. |
723 | * @virt_addr: Starting virtual address of the area to map. | 1069 | * @virt_addr: Starting virtual address of the area to map. |
724 | * @len: Length in bytes of the area to map. | 1070 | * @len: Length in bytes of the area to map. |
725 | * @bus_addr: A pointer to return the starting ioc bus address of the area to | 1071 | * @bus_addr: A pointer to return the starting ioc bus address of the area to |
726 | * map. | 1072 | * map. |
727 | * | 1073 | * |
728 | * This routine just returns the coresponding bus address. Actual mapping | 1074 | * This routine just returns the corresponding bus address. Actual mapping |
729 | * occurs in dma_region_create_linear(). | 1075 | * occurs in dma_region_create_linear(). |
730 | */ | 1076 | */ |
731 | 1077 | ||
732 | static int dma_map_area_linear(struct ps3_dma_region *r, | 1078 | static int dma_sb_map_area_linear(struct ps3_dma_region *r, |
733 | unsigned long virt_addr, unsigned long len, unsigned long *bus_addr) | 1079 | unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, |
1080 | u64 iopte_flag) | ||
734 | { | 1081 | { |
735 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | 1082 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) |
736 | : virt_addr; | 1083 | : virt_addr; |
737 | *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | 1084 | *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); |
738 | return 0; | 1085 | return 0; |
739 | } | 1086 | } |
740 | 1087 | ||
@@ -744,42 +1091,98 @@ static int dma_map_area_linear(struct ps3_dma_region *r, | |||
744 | * @bus_addr: The starting ioc bus address of the area to unmap. | 1091 | * @bus_addr: The starting ioc bus address of the area to unmap. |
745 | * @len: Length in bytes of the area to unmap. | 1092 | * @len: Length in bytes of the area to unmap. |
746 | * | 1093 | * |
747 | * This routine does nothing. Unmapping occurs in dma_region_free_linear(). | 1094 | * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear(). |
748 | */ | 1095 | */ |
749 | 1096 | ||
750 | static int dma_unmap_area_linear(struct ps3_dma_region *r, | 1097 | static int dma_sb_unmap_area_linear(struct ps3_dma_region *r, |
751 | unsigned long bus_addr, unsigned long len) | 1098 | unsigned long bus_addr, unsigned long len) |
752 | { | 1099 | { |
753 | return 0; | 1100 | return 0; |
1101 | }; | ||
1102 | |||
1103 | static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = { | ||
1104 | .create = dma_sb_region_create, | ||
1105 | .free = dma_sb_region_free, | ||
1106 | .map = dma_sb_map_area, | ||
1107 | .unmap = dma_sb_unmap_area | ||
1108 | }; | ||
1109 | |||
1110 | static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = { | ||
1111 | .create = dma_sb_region_create_linear, | ||
1112 | .free = dma_sb_region_free_linear, | ||
1113 | .map = dma_sb_map_area_linear, | ||
1114 | .unmap = dma_sb_unmap_area_linear | ||
1115 | }; | ||
1116 | |||
1117 | static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = { | ||
1118 | .create = dma_ioc0_region_create, | ||
1119 | .free = dma_ioc0_region_free, | ||
1120 | .map = dma_ioc0_map_area, | ||
1121 | .unmap = dma_ioc0_unmap_area | ||
1122 | }; | ||
1123 | |||
1124 | int ps3_dma_region_init(struct ps3_system_bus_device *dev, | ||
1125 | struct ps3_dma_region *r, enum ps3_dma_page_size page_size, | ||
1126 | enum ps3_dma_region_type region_type, void *addr, unsigned long len) | ||
1127 | { | ||
1128 | unsigned long lpar_addr; | ||
1129 | |||
1130 | lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0; | ||
1131 | |||
1132 | r->dev = dev; | ||
1133 | r->page_size = page_size; | ||
1134 | r->region_type = region_type; | ||
1135 | r->offset = lpar_addr; | ||
1136 | if (r->offset >= map.rm.size) | ||
1137 | r->offset -= map.r1.offset; | ||
1138 | r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size); | ||
1139 | |||
1140 | switch (dev->dev_type) { | ||
1141 | case PS3_DEVICE_TYPE_SB: | ||
1142 | r->region_ops = (USE_DYNAMIC_DMA) | ||
1143 | ? &ps3_dma_sb_region_ops | ||
1144 | : &ps3_dma_sb_region_linear_ops; | ||
1145 | break; | ||
1146 | case PS3_DEVICE_TYPE_IOC0: | ||
1147 | r->region_ops = &ps3_dma_ioc0_region_ops; | ||
1148 | break; | ||
1149 | default: | ||
1150 | BUG(); | ||
1151 | return -EINVAL; | ||
1152 | } | ||
1153 | return 0; | ||
754 | } | 1154 | } |
1155 | EXPORT_SYMBOL(ps3_dma_region_init); | ||
755 | 1156 | ||
756 | int ps3_dma_region_create(struct ps3_dma_region *r) | 1157 | int ps3_dma_region_create(struct ps3_dma_region *r) |
757 | { | 1158 | { |
758 | return (USE_DYNAMIC_DMA) | 1159 | BUG_ON(!r); |
759 | ? dma_region_create(r) | 1160 | BUG_ON(!r->region_ops); |
760 | : dma_region_create_linear(r); | 1161 | BUG_ON(!r->region_ops->create); |
1162 | return r->region_ops->create(r); | ||
761 | } | 1163 | } |
1164 | EXPORT_SYMBOL(ps3_dma_region_create); | ||
762 | 1165 | ||
763 | int ps3_dma_region_free(struct ps3_dma_region *r) | 1166 | int ps3_dma_region_free(struct ps3_dma_region *r) |
764 | { | 1167 | { |
765 | return (USE_DYNAMIC_DMA) | 1168 | BUG_ON(!r); |
766 | ? dma_region_free(r) | 1169 | BUG_ON(!r->region_ops); |
767 | : dma_region_free_linear(r); | 1170 | BUG_ON(!r->region_ops->free); |
1171 | return r->region_ops->free(r); | ||
768 | } | 1172 | } |
1173 | EXPORT_SYMBOL(ps3_dma_region_free); | ||
769 | 1174 | ||
770 | int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, | 1175 | int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, |
771 | unsigned long len, unsigned long *bus_addr) | 1176 | unsigned long len, unsigned long *bus_addr, |
1177 | u64 iopte_flag) | ||
772 | { | 1178 | { |
773 | return (USE_DYNAMIC_DMA) | 1179 | return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag); |
774 | ? dma_map_area(r, virt_addr, len, bus_addr) | ||
775 | : dma_map_area_linear(r, virt_addr, len, bus_addr); | ||
776 | } | 1180 | } |
777 | 1181 | ||
778 | int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, | 1182 | int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, |
779 | unsigned long len) | 1183 | unsigned long len) |
780 | { | 1184 | { |
781 | return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len) | 1185 | return r->region_ops->unmap(r, bus_addr, len); |
782 | : dma_unmap_area_linear(r, bus_addr, len); | ||
783 | } | 1186 | } |
784 | 1187 | ||
785 | /*============================================================================*/ | 1188 | /*============================================================================*/ |
@@ -810,12 +1213,13 @@ void __init ps3_mm_init(void) | |||
810 | BUG_ON(map.rm.base); | 1213 | BUG_ON(map.rm.base); |
811 | BUG_ON(!map.rm.size); | 1214 | BUG_ON(!map.rm.size); |
812 | 1215 | ||
813 | lmb_add(map.rm.base, map.rm.size); | ||
814 | lmb_analyze(); | ||
815 | 1216 | ||
816 | /* arrange to do this in ps3_mm_add_memory */ | 1217 | /* arrange to do this in ps3_mm_add_memory */ |
817 | ps3_mm_region_create(&map.r1, map.total - map.rm.size); | 1218 | ps3_mm_region_create(&map.r1, map.total - map.rm.size); |
818 | 1219 | ||
1220 | /* correct map.total for the real total amount of memory we use */ | ||
1221 | map.total = map.rm.size + map.r1.size; | ||
1222 | |||
819 | DBG(" <- %s:%d\n", __func__, __LINE__); | 1223 | DBG(" <- %s:%d\n", __func__, __LINE__); |
820 | } | 1224 | } |
821 | 1225 | ||
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 5c3da08bc0c4..b70e474014f0 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c | |||
@@ -133,7 +133,7 @@ struct saved_params { | |||
133 | } static saved_params; | 133 | } static saved_params; |
134 | 134 | ||
135 | #define dump_header(_a) _dump_header(_a, __func__, __LINE__) | 135 | #define dump_header(_a) _dump_header(_a, __func__, __LINE__) |
136 | static void _dump_header(const struct os_area_header __iomem *h, const char* func, | 136 | static void _dump_header(const struct os_area_header *h, const char *func, |
137 | int line) | 137 | int line) |
138 | { | 138 | { |
139 | pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, | 139 | pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, |
@@ -151,7 +151,7 @@ static void _dump_header(const struct os_area_header __iomem *h, const char* fun | |||
151 | } | 151 | } |
152 | 152 | ||
153 | #define dump_params(_a) _dump_params(_a, __func__, __LINE__) | 153 | #define dump_params(_a) _dump_params(_a, __func__, __LINE__) |
154 | static void _dump_params(const struct os_area_params __iomem *p, const char* func, | 154 | static void _dump_params(const struct os_area_params *p, const char *func, |
155 | int line) | 155 | int line) |
156 | { | 156 | { |
157 | pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag); | 157 | pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag); |
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index ca04f03305c7..87d52060fec0 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -41,6 +41,7 @@ void ps3_mm_shutdown(void); | |||
41 | /* irq */ | 41 | /* irq */ |
42 | 42 | ||
43 | void ps3_init_IRQ(void); | 43 | void ps3_init_IRQ(void); |
44 | void ps3_shutdown_IRQ(int cpu); | ||
44 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); | 45 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); |
45 | 46 | ||
46 | /* smp */ | 47 | /* smp */ |
@@ -82,6 +83,7 @@ enum ps3_dev_type { | |||
82 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ | 83 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ |
83 | PS3_DEV_TYPE_SB_GPIO = 6, | 84 | PS3_DEV_TYPE_SB_GPIO = 6, |
84 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ | 85 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ |
86 | PS3_DEV_TYPE_NOACCESS = 255, | ||
85 | }; | 87 | }; |
86 | 88 | ||
87 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | 89 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, |
@@ -129,24 +131,28 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, | |||
129 | /* repository bus enumerators */ | 131 | /* repository bus enumerators */ |
130 | 132 | ||
131 | struct ps3_repository_device { | 133 | struct ps3_repository_device { |
134 | enum ps3_bus_type bus_type; | ||
132 | unsigned int bus_index; | 135 | unsigned int bus_index; |
136 | unsigned int bus_id; | ||
137 | enum ps3_dev_type dev_type; | ||
133 | unsigned int dev_index; | 138 | unsigned int dev_index; |
134 | struct ps3_device_id did; | 139 | unsigned int dev_id; |
135 | }; | 140 | }; |
136 | 141 | ||
137 | int ps3_repository_find_device(enum ps3_bus_type bus_type, | 142 | static inline struct ps3_repository_device *ps3_repository_bump_device( |
138 | enum ps3_dev_type dev_type, | 143 | struct ps3_repository_device *repo) |
139 | const struct ps3_repository_device *start_dev, | ||
140 | struct ps3_repository_device *dev); | ||
141 | static inline int ps3_repository_find_first_device( | ||
142 | enum ps3_bus_type bus_type, enum ps3_dev_type dev_type, | ||
143 | struct ps3_repository_device *dev) | ||
144 | { | 144 | { |
145 | return ps3_repository_find_device(bus_type, dev_type, NULL, dev); | 145 | repo->dev_index++; |
146 | return repo; | ||
146 | } | 147 | } |
147 | int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | 148 | int ps3_repository_find_device(struct ps3_repository_device *repo); |
149 | int ps3_repository_find_devices(enum ps3_bus_type bus_type, | ||
150 | int (*callback)(const struct ps3_repository_device *repo)); | ||
151 | int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, | ||
152 | unsigned int *bus_index); | ||
153 | int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, | ||
148 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); | 154 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); |
149 | int ps3_repository_find_reg(const struct ps3_repository_device *dev, | 155 | int ps3_repository_find_reg(const struct ps3_repository_device *repo, |
150 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); | 156 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); |
151 | 157 | ||
152 | /* repository block device info */ | 158 | /* repository block device info */ |
@@ -216,4 +222,19 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); | |||
216 | int ps3_repository_read_spu_resource_id(unsigned int res_index, | 222 | int ps3_repository_read_spu_resource_id(unsigned int res_index, |
217 | enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); | 223 | enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); |
218 | 224 | ||
225 | /* repository vuart info */ | ||
226 | |||
227 | int ps3_repository_read_vuart_av_port(unsigned int *port); | ||
228 | int ps3_repository_read_vuart_sysmgr_port(unsigned int *port); | ||
229 | |||
230 | /* Page table entries */ | ||
231 | #define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ | ||
232 | #define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ | ||
233 | #define IOPTE_M 0x2000000000000000ul /* coherency required */ | ||
234 | #define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ | ||
235 | #define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ | ||
236 | #define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ | ||
237 | #define IOPTE_H 0x0000000000000800ul /* cache hint */ | ||
238 | #define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ | ||
239 | |||
219 | #endif | 240 | #endif |
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index ae586a0e5d3f..8cc37cfea0f2 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c | |||
@@ -138,7 +138,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, | |||
138 | pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n", | 138 | pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n", |
139 | __func__, __LINE__, ps3_result(result)); | 139 | __func__, __LINE__, ps3_result(result)); |
140 | dump_node_name(lpar_id, n1, n2, n3, n4); | 140 | dump_node_name(lpar_id, n1, n2, n3, n4); |
141 | return result; | 141 | return -ENOENT; |
142 | } | 142 | } |
143 | 143 | ||
144 | dump_node(lpar_id, n1, n2, n3, n4, v1, v2); | 144 | dump_node(lpar_id, n1, n2, n3, n4, v1, v2); |
@@ -155,7 +155,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, | |||
155 | pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\n", | 155 | pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\n", |
156 | __func__, __LINE__, v2); | 156 | __func__, __LINE__, v2); |
157 | 157 | ||
158 | return result; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
161 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | 161 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, |
@@ -314,324 +314,140 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, | |||
314 | reg_index, bus_addr, len); | 314 | reg_index, bus_addr, len); |
315 | } | 315 | } |
316 | 316 | ||
317 | #if defined(DEBUG) | ||
318 | int ps3_repository_dump_resource_info(unsigned int bus_index, | ||
319 | unsigned int dev_index) | ||
320 | { | ||
321 | int result = 0; | ||
322 | unsigned int res_index; | ||
323 | 317 | ||
324 | pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, | ||
325 | bus_index, dev_index); | ||
326 | 318 | ||
327 | for (res_index = 0; res_index < 10; res_index++) { | 319 | int ps3_repository_find_device(struct ps3_repository_device *repo) |
328 | enum ps3_interrupt_type intr_type; | 320 | { |
329 | unsigned int interrupt_id; | 321 | int result; |
322 | struct ps3_repository_device tmp = *repo; | ||
323 | unsigned int num_dev; | ||
330 | 324 | ||
331 | result = ps3_repository_read_dev_intr(bus_index, dev_index, | 325 | BUG_ON(repo->bus_index > 10); |
332 | res_index, &intr_type, &interrupt_id); | 326 | BUG_ON(repo->dev_index > 10); |
333 | 327 | ||
334 | if (result) { | 328 | result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); |
335 | if (result != LV1_NO_ENTRY) | ||
336 | pr_debug("%s:%d ps3_repository_read_dev_intr" | ||
337 | " (%u:%u) failed\n", __func__, __LINE__, | ||
338 | bus_index, dev_index); | ||
339 | break; | ||
340 | } | ||
341 | 329 | ||
342 | pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", | 330 | if (result) { |
343 | __func__, __LINE__, bus_index, dev_index, intr_type, | 331 | pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); |
344 | interrupt_id); | 332 | return result; |
345 | } | 333 | } |
346 | 334 | ||
347 | for (res_index = 0; res_index < 10; res_index++) { | 335 | pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", |
348 | enum ps3_reg_type reg_type; | 336 | __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, |
349 | u64 bus_addr; | 337 | num_dev); |
350 | u64 len; | ||
351 | |||
352 | result = ps3_repository_read_dev_reg(bus_index, dev_index, | ||
353 | res_index, ®_type, &bus_addr, &len); | ||
354 | 338 | ||
355 | if (result) { | 339 | if (tmp.dev_index >= num_dev) { |
356 | if (result != LV1_NO_ENTRY) | 340 | pr_debug("%s:%d: no device found\n", __func__, __LINE__); |
357 | pr_debug("%s:%d ps3_repository_read_dev_reg" | 341 | return -ENODEV; |
358 | " (%u:%u) failed\n", __func__, __LINE__, | ||
359 | bus_index, dev_index); | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", | ||
364 | __func__, __LINE__, bus_index, dev_index, reg_type, | ||
365 | bus_addr, len); | ||
366 | } | 342 | } |
367 | 343 | ||
368 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 344 | result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, |
369 | return result; | 345 | &tmp.dev_type); |
370 | } | ||
371 | |||
372 | static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index) | ||
373 | { | ||
374 | int result = 0; | ||
375 | unsigned int num_regions, region_index; | ||
376 | u64 port, blk_size, num_blocks; | ||
377 | |||
378 | pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, | ||
379 | bus_index, dev_index); | ||
380 | 346 | ||
381 | result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port, | ||
382 | &blk_size, &num_blocks, &num_regions); | ||
383 | if (result) { | 347 | if (result) { |
384 | pr_debug("%s:%d ps3_repository_read_stor_dev_info" | 348 | pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__); |
385 | " (%u:%u) failed\n", __func__, __LINE__, | 349 | return result; |
386 | bus_index, dev_index); | ||
387 | goto out; | ||
388 | } | 350 | } |
389 | 351 | ||
390 | pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " | 352 | result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, |
391 | "%lu, num_regions %u\n", | 353 | &tmp.dev_id); |
392 | __func__, __LINE__, bus_index, dev_index, port, | ||
393 | blk_size, num_blocks, num_regions); | ||
394 | |||
395 | for (region_index = 0; region_index < num_regions; region_index++) { | ||
396 | unsigned int region_id; | ||
397 | u64 region_start, region_size; | ||
398 | |||
399 | result = ps3_repository_read_stor_dev_region(bus_index, | ||
400 | dev_index, region_index, ®ion_id, ®ion_start, | ||
401 | ®ion_size); | ||
402 | if (result) { | ||
403 | pr_debug("%s:%d ps3_repository_read_stor_dev_region" | ||
404 | " (%u:%u) failed\n", __func__, __LINE__, | ||
405 | bus_index, dev_index); | ||
406 | break; | ||
407 | } | ||
408 | 354 | ||
409 | pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", | 355 | if (result) { |
410 | __func__, __LINE__, bus_index, dev_index, region_id, | 356 | pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, |
411 | region_start, region_size); | 357 | __LINE__); |
358 | return result; | ||
412 | } | 359 | } |
413 | 360 | ||
414 | out: | 361 | pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", |
415 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 362 | __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); |
416 | return result; | ||
417 | } | ||
418 | |||
419 | static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type, | ||
420 | unsigned int num_dev) | ||
421 | { | ||
422 | int result = 0; | ||
423 | unsigned int dev_index; | ||
424 | |||
425 | pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, bus_index); | ||
426 | |||
427 | for (dev_index = 0; dev_index < num_dev; dev_index++) { | ||
428 | enum ps3_dev_type dev_type; | ||
429 | unsigned int dev_id; | ||
430 | |||
431 | result = ps3_repository_read_dev_type(bus_index, dev_index, | ||
432 | &dev_type); | ||
433 | |||
434 | if (result) { | ||
435 | pr_debug("%s:%d ps3_repository_read_dev_type" | ||
436 | " (%u:%u) failed\n", __func__, __LINE__, | ||
437 | bus_index, dev_index); | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | result = ps3_repository_read_dev_id(bus_index, dev_index, | ||
442 | &dev_id); | ||
443 | |||
444 | if (result) { | ||
445 | pr_debug("%s:%d ps3_repository_read_dev_id" | ||
446 | " (%u:%u) failed\n", __func__, __LINE__, | ||
447 | bus_index, dev_index); | ||
448 | continue; | ||
449 | } | ||
450 | 363 | ||
451 | pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, | 364 | *repo = tmp; |
452 | __LINE__, bus_index, dev_index, dev_type, dev_id); | 365 | return 0; |
453 | |||
454 | ps3_repository_dump_resource_info(bus_index, dev_index); | ||
455 | |||
456 | if (bus_type == PS3_BUS_TYPE_STORAGE) | ||
457 | dump_stor_dev_info(bus_index, dev_index); | ||
458 | } | ||
459 | |||
460 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
461 | return result; | ||
462 | } | 366 | } |
463 | 367 | ||
464 | int ps3_repository_dump_bus_info(void) | 368 | int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, |
369 | int (*callback)(const struct ps3_repository_device *repo)) | ||
465 | { | 370 | { |
466 | int result = 0; | 371 | int result = 0; |
467 | unsigned int bus_index; | 372 | struct ps3_repository_device repo; |
468 | 373 | ||
469 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | 374 | pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); |
470 | 375 | ||
471 | for (bus_index = 0; bus_index < 10; bus_index++) { | 376 | for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { |
472 | enum ps3_bus_type bus_type; | ||
473 | unsigned int bus_id; | ||
474 | unsigned int num_dev; | ||
475 | 377 | ||
476 | result = ps3_repository_read_bus_type(bus_index, &bus_type); | 378 | result = ps3_repository_read_bus_type(repo.bus_index, |
379 | &repo.bus_type); | ||
477 | 380 | ||
478 | if (result) { | 381 | if (result) { |
479 | pr_debug("%s:%d read_bus_type(%u) failed\n", | 382 | pr_debug("%s:%d read_bus_type(%u) failed\n", |
480 | __func__, __LINE__, bus_index); | 383 | __func__, __LINE__, repo.bus_index); |
481 | break; | 384 | break; |
482 | } | 385 | } |
483 | 386 | ||
484 | result = ps3_repository_read_bus_id(bus_index, &bus_id); | 387 | if (repo.bus_type != bus_type) { |
485 | 388 | pr_debug("%s:%d: skip, bus_type %u\n", __func__, | |
486 | if (result) { | 389 | __LINE__, repo.bus_type); |
487 | pr_debug("%s:%d read_bus_id(%u) failed\n", | ||
488 | __func__, __LINE__, bus_index); | ||
489 | continue; | 390 | continue; |
490 | } | 391 | } |
491 | 392 | ||
492 | if (bus_index != bus_id) | 393 | result = ps3_repository_read_bus_id(repo.bus_index, |
493 | pr_debug("%s:%d bus_index != bus_id\n", | 394 | &repo.bus_id); |
494 | __func__, __LINE__); | ||
495 | |||
496 | result = ps3_repository_read_bus_num_dev(bus_index, &num_dev); | ||
497 | 395 | ||
498 | if (result) { | 396 | if (result) { |
499 | pr_debug("%s:%d read_bus_num_dev(%u) failed\n", | 397 | pr_debug("%s:%d read_bus_id(%u) failed\n", |
500 | __func__, __LINE__, bus_index); | 398 | __func__, __LINE__, repo.bus_index); |
501 | continue; | 399 | continue; |
502 | } | 400 | } |
503 | 401 | ||
504 | pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", | 402 | for (repo.dev_index = 0; ; repo.dev_index++) { |
505 | __func__, __LINE__, bus_index, bus_type, bus_id, | 403 | result = ps3_repository_find_device(&repo); |
506 | num_dev); | ||
507 | 404 | ||
508 | dump_device_info(bus_index, bus_type, num_dev); | 405 | if (result == -ENODEV) { |
509 | } | 406 | result = 0; |
407 | break; | ||
408 | } else if (result) | ||
409 | break; | ||
510 | 410 | ||
511 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 411 | result = callback(&repo); |
512 | return result; | ||
513 | } | ||
514 | #endif /* defined(DEBUG) */ | ||
515 | |||
516 | static int find_device(unsigned int bus_index, unsigned int num_dev, | ||
517 | unsigned int start_dev_index, enum ps3_dev_type dev_type, | ||
518 | struct ps3_repository_device *dev) | ||
519 | { | ||
520 | int result = 0; | ||
521 | unsigned int dev_index; | ||
522 | 412 | ||
523 | pr_debug("%s:%d: find dev_type %u\n", __func__, __LINE__, dev_type); | 413 | if (result) { |
524 | 414 | pr_debug("%s:%d: abort at callback\n", __func__, | |
525 | dev->dev_index = UINT_MAX; | 415 | __LINE__); |
526 | 416 | break; | |
527 | for (dev_index = start_dev_index; dev_index < num_dev; dev_index++) { | 417 | } |
528 | enum ps3_dev_type x; | ||
529 | |||
530 | result = ps3_repository_read_dev_type(bus_index, dev_index, | ||
531 | &x); | ||
532 | |||
533 | if (result) { | ||
534 | pr_debug("%s:%d read_dev_type failed\n", | ||
535 | __func__, __LINE__); | ||
536 | return result; | ||
537 | } | 418 | } |
538 | 419 | break; | |
539 | if (x == dev_type) | ||
540 | break; | ||
541 | } | ||
542 | |||
543 | if (dev_index == num_dev) | ||
544 | return -1; | ||
545 | |||
546 | pr_debug("%s:%d: found dev_type %u at dev_index %u\n", | ||
547 | __func__, __LINE__, dev_type, dev_index); | ||
548 | |||
549 | result = ps3_repository_read_dev_id(bus_index, dev_index, | ||
550 | &dev->did.dev_id); | ||
551 | |||
552 | if (result) { | ||
553 | pr_debug("%s:%d read_dev_id failed\n", | ||
554 | __func__, __LINE__); | ||
555 | return result; | ||
556 | } | 420 | } |
557 | 421 | ||
558 | dev->dev_index = dev_index; | 422 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
559 | |||
560 | pr_debug("%s:%d found: dev_id %u\n", __func__, __LINE__, | ||
561 | dev->did.dev_id); | ||
562 | |||
563 | return result; | 423 | return result; |
564 | } | 424 | } |
565 | 425 | ||
566 | int ps3_repository_find_device (enum ps3_bus_type bus_type, | 426 | int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, |
567 | enum ps3_dev_type dev_type, | 427 | unsigned int *bus_index) |
568 | const struct ps3_repository_device *start_dev, | ||
569 | struct ps3_repository_device *dev) | ||
570 | { | 428 | { |
571 | int result = 0; | 429 | unsigned int i; |
572 | unsigned int bus_index; | 430 | enum ps3_bus_type type; |
573 | unsigned int num_dev; | 431 | int error; |
574 | |||
575 | pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, | ||
576 | bus_type, dev_type); | ||
577 | |||
578 | BUG_ON(start_dev && start_dev->bus_index > 10); | ||
579 | |||
580 | for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; | ||
581 | bus_index++) { | ||
582 | enum ps3_bus_type x; | ||
583 | |||
584 | result = ps3_repository_read_bus_type(bus_index, &x); | ||
585 | 432 | ||
586 | if (result) { | 433 | for (i = from; i < 10; i++) { |
434 | error = ps3_repository_read_bus_type(i, &type); | ||
435 | if (error) { | ||
587 | pr_debug("%s:%d read_bus_type failed\n", | 436 | pr_debug("%s:%d read_bus_type failed\n", |
588 | __func__, __LINE__); | 437 | __func__, __LINE__); |
589 | dev->bus_index = UINT_MAX; | 438 | *bus_index = UINT_MAX; |
590 | return result; | 439 | return error; |
440 | } | ||
441 | if (type == bus_type) { | ||
442 | *bus_index = i; | ||
443 | return 0; | ||
591 | } | 444 | } |
592 | if (x == bus_type) | ||
593 | break; | ||
594 | } | ||
595 | |||
596 | if (bus_index >= 10) | ||
597 | return -ENODEV; | ||
598 | |||
599 | pr_debug("%s:%d: found bus_type %u at bus_index %u\n", | ||
600 | __func__, __LINE__, bus_type, bus_index); | ||
601 | |||
602 | result = ps3_repository_read_bus_num_dev(bus_index, &num_dev); | ||
603 | |||
604 | if (result) { | ||
605 | pr_debug("%s:%d read_bus_num_dev failed\n", | ||
606 | __func__, __LINE__); | ||
607 | return result; | ||
608 | } | ||
609 | |||
610 | result = find_device(bus_index, num_dev, start_dev | ||
611 | ? start_dev->dev_index + 1 : 0, dev_type, dev); | ||
612 | |||
613 | if (result) { | ||
614 | pr_debug("%s:%d get_did failed\n", __func__, __LINE__); | ||
615 | return result; | ||
616 | } | ||
617 | |||
618 | result = ps3_repository_read_bus_id(bus_index, &dev->did.bus_id); | ||
619 | |||
620 | if (result) { | ||
621 | pr_debug("%s:%d read_bus_id failed\n", | ||
622 | __func__, __LINE__); | ||
623 | return result; | ||
624 | } | 445 | } |
625 | 446 | *bus_index = UINT_MAX; | |
626 | dev->bus_index = bus_index; | 447 | return -ENODEV; |
627 | |||
628 | pr_debug("%s:%d found: bus_id %u, dev_id %u\n", | ||
629 | __func__, __LINE__, dev->did.bus_id, dev->did.dev_id); | ||
630 | |||
631 | return result; | ||
632 | } | 448 | } |
633 | 449 | ||
634 | int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | 450 | int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, |
635 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id) | 451 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id) |
636 | { | 452 | { |
637 | int result = 0; | 453 | int result = 0; |
@@ -645,8 +461,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | |||
645 | enum ps3_interrupt_type t; | 461 | enum ps3_interrupt_type t; |
646 | unsigned int id; | 462 | unsigned int id; |
647 | 463 | ||
648 | result = ps3_repository_read_dev_intr(dev->bus_index, | 464 | result = ps3_repository_read_dev_intr(repo->bus_index, |
649 | dev->dev_index, res_index, &t, &id); | 465 | repo->dev_index, res_index, &t, &id); |
650 | 466 | ||
651 | if (result) { | 467 | if (result) { |
652 | pr_debug("%s:%d read_dev_intr failed\n", | 468 | pr_debug("%s:%d read_dev_intr failed\n", |
@@ -669,7 +485,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | |||
669 | return result; | 485 | return result; |
670 | } | 486 | } |
671 | 487 | ||
672 | int ps3_repository_find_reg(const struct ps3_repository_device *dev, | 488 | int ps3_repository_find_reg(const struct ps3_repository_device *repo, |
673 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) | 489 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) |
674 | { | 490 | { |
675 | int result = 0; | 491 | int result = 0; |
@@ -684,8 +500,8 @@ int ps3_repository_find_reg(const struct ps3_repository_device *dev, | |||
684 | u64 a; | 500 | u64 a; |
685 | u64 l; | 501 | u64 l; |
686 | 502 | ||
687 | result = ps3_repository_read_dev_reg(dev->bus_index, | 503 | result = ps3_repository_read_dev_reg(repo->bus_index, |
688 | dev->dev_index, res_index, &t, &a, &l); | 504 | repo->dev_index, res_index, &t, &a, &l); |
689 | 505 | ||
690 | if (result) { | 506 | if (result) { |
691 | pr_debug("%s:%d read_dev_reg failed\n", | 507 | pr_debug("%s:%d read_dev_reg failed\n", |
@@ -965,6 +781,36 @@ int ps3_repository_read_boot_dat_size(unsigned int *size) | |||
965 | return result; | 781 | return result; |
966 | } | 782 | } |
967 | 783 | ||
784 | int ps3_repository_read_vuart_av_port(unsigned int *port) | ||
785 | { | ||
786 | int result; | ||
787 | u64 v1; | ||
788 | |||
789 | result = read_node(PS3_LPAR_ID_CURRENT, | ||
790 | make_first_field("bi", 0), | ||
791 | make_field("vir_uart", 0), | ||
792 | make_field("port", 0), | ||
793 | make_field("avset", 0), | ||
794 | &v1, 0); | ||
795 | *port = v1; | ||
796 | return result; | ||
797 | } | ||
798 | |||
799 | int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) | ||
800 | { | ||
801 | int result; | ||
802 | u64 v1; | ||
803 | |||
804 | result = read_node(PS3_LPAR_ID_CURRENT, | ||
805 | make_first_field("bi", 0), | ||
806 | make_field("vir_uart", 0), | ||
807 | make_field("port", 0), | ||
808 | make_field("sysmgr", 0), | ||
809 | &v1, 0); | ||
810 | *port = v1; | ||
811 | return result; | ||
812 | } | ||
813 | |||
968 | /** | 814 | /** |
969 | * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area. | 815 | * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area. |
970 | * address: lpar address of cell_ext_os_area | 816 | * address: lpar address of cell_ext_os_area |
@@ -1026,3 +872,205 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) | |||
1026 | return result ? result | 872 | return result ? result |
1027 | : ps3_repository_read_tb_freq(node_id, tb_freq); | 873 | : ps3_repository_read_tb_freq(node_id, tb_freq); |
1028 | } | 874 | } |
875 | |||
876 | #if defined(DEBUG) | ||
877 | |||
878 | int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) | ||
879 | { | ||
880 | int result = 0; | ||
881 | unsigned int res_index; | ||
882 | |||
883 | pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, | ||
884 | repo->bus_index, repo->dev_index); | ||
885 | |||
886 | for (res_index = 0; res_index < 10; res_index++) { | ||
887 | enum ps3_interrupt_type intr_type; | ||
888 | unsigned int interrupt_id; | ||
889 | |||
890 | result = ps3_repository_read_dev_intr(repo->bus_index, | ||
891 | repo->dev_index, res_index, &intr_type, &interrupt_id); | ||
892 | |||
893 | if (result) { | ||
894 | if (result != LV1_NO_ENTRY) | ||
895 | pr_debug("%s:%d ps3_repository_read_dev_intr" | ||
896 | " (%u:%u) failed\n", __func__, __LINE__, | ||
897 | repo->bus_index, repo->dev_index); | ||
898 | break; | ||
899 | } | ||
900 | |||
901 | pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", | ||
902 | __func__, __LINE__, repo->bus_index, repo->dev_index, | ||
903 | intr_type, interrupt_id); | ||
904 | } | ||
905 | |||
906 | for (res_index = 0; res_index < 10; res_index++) { | ||
907 | enum ps3_reg_type reg_type; | ||
908 | u64 bus_addr; | ||
909 | u64 len; | ||
910 | |||
911 | result = ps3_repository_read_dev_reg(repo->bus_index, | ||
912 | repo->dev_index, res_index, ®_type, &bus_addr, &len); | ||
913 | |||
914 | if (result) { | ||
915 | if (result != LV1_NO_ENTRY) | ||
916 | pr_debug("%s:%d ps3_repository_read_dev_reg" | ||
917 | " (%u:%u) failed\n", __func__, __LINE__, | ||
918 | repo->bus_index, repo->dev_index); | ||
919 | break; | ||
920 | } | ||
921 | |||
922 | pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", | ||
923 | __func__, __LINE__, repo->bus_index, repo->dev_index, | ||
924 | reg_type, bus_addr, len); | ||
925 | } | ||
926 | |||
927 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
928 | return result; | ||
929 | } | ||
930 | |||
931 | static int dump_stor_dev_info(struct ps3_repository_device *repo) | ||
932 | { | ||
933 | int result = 0; | ||
934 | unsigned int num_regions, region_index; | ||
935 | u64 port, blk_size, num_blocks; | ||
936 | |||
937 | pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, | ||
938 | repo->bus_index, repo->dev_index); | ||
939 | |||
940 | result = ps3_repository_read_stor_dev_info(repo->bus_index, | ||
941 | repo->dev_index, &port, &blk_size, &num_blocks, &num_regions); | ||
942 | if (result) { | ||
943 | pr_debug("%s:%d ps3_repository_read_stor_dev_info" | ||
944 | " (%u:%u) failed\n", __func__, __LINE__, | ||
945 | repo->bus_index, repo->dev_index); | ||
946 | goto out; | ||
947 | } | ||
948 | |||
949 | pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " | ||
950 | "%lu, num_regions %u\n", | ||
951 | __func__, __LINE__, repo->bus_index, repo->dev_index, port, | ||
952 | blk_size, num_blocks, num_regions); | ||
953 | |||
954 | for (region_index = 0; region_index < num_regions; region_index++) { | ||
955 | unsigned int region_id; | ||
956 | u64 region_start, region_size; | ||
957 | |||
958 | result = ps3_repository_read_stor_dev_region(repo->bus_index, | ||
959 | repo->dev_index, region_index, ®ion_id, | ||
960 | ®ion_start, ®ion_size); | ||
961 | if (result) { | ||
962 | pr_debug("%s:%d ps3_repository_read_stor_dev_region" | ||
963 | " (%u:%u) failed\n", __func__, __LINE__, | ||
964 | repo->bus_index, repo->dev_index); | ||
965 | break; | ||
966 | } | ||
967 | |||
968 | pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", | ||
969 | __func__, __LINE__, repo->bus_index, repo->dev_index, | ||
970 | region_id, region_start, region_size); | ||
971 | } | ||
972 | |||
973 | out: | ||
974 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
975 | return result; | ||
976 | } | ||
977 | |||
978 | static int dump_device_info(struct ps3_repository_device *repo, | ||
979 | unsigned int num_dev) | ||
980 | { | ||
981 | int result = 0; | ||
982 | |||
983 | pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); | ||
984 | |||
985 | for (repo->dev_index = 0; repo->dev_index < num_dev; | ||
986 | repo->dev_index++) { | ||
987 | |||
988 | result = ps3_repository_read_dev_type(repo->bus_index, | ||
989 | repo->dev_index, &repo->dev_type); | ||
990 | |||
991 | if (result) { | ||
992 | pr_debug("%s:%d ps3_repository_read_dev_type" | ||
993 | " (%u:%u) failed\n", __func__, __LINE__, | ||
994 | repo->bus_index, repo->dev_index); | ||
995 | break; | ||
996 | } | ||
997 | |||
998 | result = ps3_repository_read_dev_id(repo->bus_index, | ||
999 | repo->dev_index, &repo->dev_id); | ||
1000 | |||
1001 | if (result) { | ||
1002 | pr_debug("%s:%d ps3_repository_read_dev_id" | ||
1003 | " (%u:%u) failed\n", __func__, __LINE__, | ||
1004 | repo->bus_index, repo->dev_index); | ||
1005 | continue; | ||
1006 | } | ||
1007 | |||
1008 | pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, | ||
1009 | __LINE__, repo->bus_index, repo->dev_index, | ||
1010 | repo->dev_type, repo->dev_id); | ||
1011 | |||
1012 | ps3_repository_dump_resource_info(repo); | ||
1013 | |||
1014 | if (repo->bus_type == PS3_BUS_TYPE_STORAGE) | ||
1015 | dump_stor_dev_info(repo); | ||
1016 | } | ||
1017 | |||
1018 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
1019 | return result; | ||
1020 | } | ||
1021 | |||
1022 | int ps3_repository_dump_bus_info(void) | ||
1023 | { | ||
1024 | int result = 0; | ||
1025 | struct ps3_repository_device repo; | ||
1026 | |||
1027 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
1028 | |||
1029 | memset(&repo, 0, sizeof(repo)); | ||
1030 | |||
1031 | for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { | ||
1032 | unsigned int num_dev; | ||
1033 | |||
1034 | result = ps3_repository_read_bus_type(repo.bus_index, | ||
1035 | &repo.bus_type); | ||
1036 | |||
1037 | if (result) { | ||
1038 | pr_debug("%s:%d read_bus_type(%u) failed\n", | ||
1039 | __func__, __LINE__, repo.bus_index); | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | result = ps3_repository_read_bus_id(repo.bus_index, | ||
1044 | &repo.bus_id); | ||
1045 | |||
1046 | if (result) { | ||
1047 | pr_debug("%s:%d read_bus_id(%u) failed\n", | ||
1048 | __func__, __LINE__, repo.bus_index); | ||
1049 | continue; | ||
1050 | } | ||
1051 | |||
1052 | if (repo.bus_index != repo.bus_id) | ||
1053 | pr_debug("%s:%d bus_index != bus_id\n", | ||
1054 | __func__, __LINE__); | ||
1055 | |||
1056 | result = ps3_repository_read_bus_num_dev(repo.bus_index, | ||
1057 | &num_dev); | ||
1058 | |||
1059 | if (result) { | ||
1060 | pr_debug("%s:%d read_bus_num_dev(%u) failed\n", | ||
1061 | __func__, __LINE__, repo.bus_index); | ||
1062 | continue; | ||
1063 | } | ||
1064 | |||
1065 | pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", | ||
1066 | __func__, __LINE__, repo.bus_index, repo.bus_type, | ||
1067 | repo.bus_id, num_dev); | ||
1068 | |||
1069 | dump_device_info(&repo, num_dev); | ||
1070 | } | ||
1071 | |||
1072 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
1073 | return result; | ||
1074 | } | ||
1075 | |||
1076 | #endif /* defined(DEBUG) */ | ||
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 935396766621..aa05288de64e 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c | |||
@@ -37,27 +37,35 @@ | |||
37 | #include "platform.h" | 37 | #include "platform.h" |
38 | 38 | ||
39 | #if defined(DEBUG) | 39 | #if defined(DEBUG) |
40 | #define DBG(fmt...) udbg_printf(fmt) | 40 | #define DBG udbg_printf |
41 | #else | 41 | #else |
42 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 42 | #define DBG pr_debug |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | #if !defined(CONFIG_SMP) | 45 | #if !defined(CONFIG_SMP) |
46 | static void smp_send_stop(void) {} | 46 | static void smp_send_stop(void) {} |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | int ps3_get_firmware_version(union ps3_firmware_version *v) | 49 | static union ps3_firmware_version ps3_firmware_version; |
50 | |||
51 | void ps3_get_firmware_version(union ps3_firmware_version *v) | ||
50 | { | 52 | { |
51 | int result = lv1_get_version_info(&v->raw); | 53 | *v = ps3_firmware_version; |
54 | } | ||
55 | EXPORT_SYMBOL_GPL(ps3_get_firmware_version); | ||
52 | 56 | ||
53 | if (result) { | 57 | int ps3_compare_firmware_version(u16 major, u16 minor, u16 rev) |
54 | v->raw = 0; | 58 | { |
55 | return -1; | 59 | union ps3_firmware_version x; |
56 | } | 60 | |
61 | x.pad = 0; | ||
62 | x.major = major; | ||
63 | x.minor = minor; | ||
64 | x.rev = rev; | ||
57 | 65 | ||
58 | return result; | 66 | return (ps3_firmware_version.raw - x.raw); |
59 | } | 67 | } |
60 | EXPORT_SYMBOL_GPL(ps3_get_firmware_version); | 68 | EXPORT_SYMBOL_GPL(ps3_compare_firmware_version); |
61 | 69 | ||
62 | static void ps3_power_save(void) | 70 | static void ps3_power_save(void) |
63 | { | 71 | { |
@@ -99,7 +107,8 @@ static void ps3_panic(char *str) | |||
99 | while(1); | 107 | while(1); |
100 | } | 108 | } |
101 | 109 | ||
102 | #ifdef CONFIG_FB_PS3 | 110 | #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \ |
111 | defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) | ||
103 | static void prealloc(struct ps3_prealloc *p) | 112 | static void prealloc(struct ps3_prealloc *p) |
104 | { | 113 | { |
105 | if (!p->size) | 114 | if (!p->size) |
@@ -115,12 +124,15 @@ static void prealloc(struct ps3_prealloc *p) | |||
115 | printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, | 124 | printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, |
116 | p->address); | 125 | p->address); |
117 | } | 126 | } |
127 | #endif | ||
118 | 128 | ||
129 | #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) | ||
119 | struct ps3_prealloc ps3fb_videomemory = { | 130 | struct ps3_prealloc ps3fb_videomemory = { |
120 | .name = "ps3fb videomemory", | 131 | .name = "ps3fb videomemory", |
121 | .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, | 132 | .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, |
122 | .align = 1024*1024 /* the GPU requires 1 MiB alignment */ | 133 | .align = 1024*1024 /* the GPU requires 1 MiB alignment */ |
123 | }; | 134 | }; |
135 | EXPORT_SYMBOL_GPL(ps3fb_videomemory); | ||
124 | #define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) | 136 | #define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) |
125 | 137 | ||
126 | static int __init early_parse_ps3fb(char *p) | 138 | static int __init early_parse_ps3fb(char *p) |
@@ -137,6 +149,30 @@ early_param("ps3fb", early_parse_ps3fb); | |||
137 | #define prealloc_ps3fb_videomemory() do { } while (0) | 149 | #define prealloc_ps3fb_videomemory() do { } while (0) |
138 | #endif | 150 | #endif |
139 | 151 | ||
152 | #if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) | ||
153 | struct ps3_prealloc ps3flash_bounce_buffer = { | ||
154 | .name = "ps3flash bounce buffer", | ||
155 | .size = 256*1024, | ||
156 | .align = 256*1024 | ||
157 | }; | ||
158 | EXPORT_SYMBOL_GPL(ps3flash_bounce_buffer); | ||
159 | #define prealloc_ps3flash_bounce_buffer() prealloc(&ps3flash_bounce_buffer) | ||
160 | |||
161 | static int __init early_parse_ps3flash(char *p) | ||
162 | { | ||
163 | if (!p) | ||
164 | return 1; | ||
165 | |||
166 | if (!strcmp(p, "off")) | ||
167 | ps3flash_bounce_buffer.size = 0; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | early_param("ps3flash", early_parse_ps3flash); | ||
172 | #else | ||
173 | #define prealloc_ps3flash_bounce_buffer() do { } while (0) | ||
174 | #endif | ||
175 | |||
140 | static int ps3_set_dabr(u64 dabr) | 176 | static int ps3_set_dabr(u64 dabr) |
141 | { | 177 | { |
142 | enum {DABR_USER = 1, DABR_KERNEL = 2,}; | 178 | enum {DABR_USER = 1, DABR_KERNEL = 2,}; |
@@ -146,13 +182,13 @@ static int ps3_set_dabr(u64 dabr) | |||
146 | 182 | ||
147 | static void __init ps3_setup_arch(void) | 183 | static void __init ps3_setup_arch(void) |
148 | { | 184 | { |
149 | union ps3_firmware_version v; | ||
150 | 185 | ||
151 | DBG(" -> %s:%d\n", __func__, __LINE__); | 186 | DBG(" -> %s:%d\n", __func__, __LINE__); |
152 | 187 | ||
153 | ps3_get_firmware_version(&v); | 188 | lv1_get_version_info(&ps3_firmware_version.raw); |
154 | printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor, | 189 | printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", |
155 | v.rev); | 190 | ps3_firmware_version.major, ps3_firmware_version.minor, |
191 | ps3_firmware_version.rev); | ||
156 | 192 | ||
157 | ps3_spu_set_platform(); | 193 | ps3_spu_set_platform(); |
158 | ps3_map_htab(); | 194 | ps3_map_htab(); |
@@ -166,6 +202,8 @@ static void __init ps3_setup_arch(void) | |||
166 | #endif | 202 | #endif |
167 | 203 | ||
168 | prealloc_ps3fb_videomemory(); | 204 | prealloc_ps3fb_videomemory(); |
205 | prealloc_ps3flash_bounce_buffer(); | ||
206 | |||
169 | ppc_md.power_save = ps3_power_save; | 207 | ppc_md.power_save = ps3_power_save; |
170 | 208 | ||
171 | DBG(" <- %s:%d\n", __func__, __LINE__); | 209 | DBG(" <- %s:%d\n", __func__, __LINE__); |
@@ -184,7 +222,7 @@ static int __init ps3_probe(void) | |||
184 | DBG(" -> %s:%d\n", __func__, __LINE__); | 222 | DBG(" -> %s:%d\n", __func__, __LINE__); |
185 | 223 | ||
186 | dt_root = of_get_flat_dt_root(); | 224 | dt_root = of_get_flat_dt_root(); |
187 | if (!of_flat_dt_is_compatible(dt_root, "PS3")) | 225 | if (!of_flat_dt_is_compatible(dt_root, "sony,ps3")) |
188 | return 0; | 226 | return 0; |
189 | 227 | ||
190 | powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; | 228 | powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; |
@@ -201,31 +239,12 @@ static int __init ps3_probe(void) | |||
201 | #if defined(CONFIG_KEXEC) | 239 | #if defined(CONFIG_KEXEC) |
202 | static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) | 240 | static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) |
203 | { | 241 | { |
204 | DBG(" -> %s:%d\n", __func__, __LINE__); | 242 | int cpu = smp_processor_id(); |
205 | |||
206 | if (secondary) { | ||
207 | int cpu; | ||
208 | for_each_online_cpu(cpu) | ||
209 | if (cpu) | ||
210 | ps3_smp_cleanup_cpu(cpu); | ||
211 | } else | ||
212 | ps3_smp_cleanup_cpu(0); | ||
213 | |||
214 | DBG(" <- %s:%d\n", __func__, __LINE__); | ||
215 | } | ||
216 | |||
217 | static void ps3_machine_kexec(struct kimage *image) | ||
218 | { | ||
219 | unsigned long ppe_id; | ||
220 | |||
221 | DBG(" -> %s:%d\n", __func__, __LINE__); | ||
222 | 243 | ||
223 | lv1_get_logical_ppe_id(&ppe_id); | 244 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); |
224 | lv1_configure_irq_state_bitmap(ppe_id, 0, 0); | ||
225 | ps3_mm_shutdown(); | ||
226 | ps3_mm_vas_destroy(); | ||
227 | 245 | ||
228 | default_machine_kexec(image); | 246 | ps3_smp_cleanup_cpu(cpu); |
247 | ps3_shutdown_IRQ(cpu); | ||
229 | 248 | ||
230 | DBG(" <- %s:%d\n", __func__, __LINE__); | 249 | DBG(" <- %s:%d\n", __func__, __LINE__); |
231 | } | 250 | } |
@@ -247,7 +266,7 @@ define_machine(ps3) { | |||
247 | .power_off = ps3_power_off, | 266 | .power_off = ps3_power_off, |
248 | #if defined(CONFIG_KEXEC) | 267 | #if defined(CONFIG_KEXEC) |
249 | .kexec_cpu_down = ps3_kexec_cpu_down, | 268 | .kexec_cpu_down = ps3_kexec_cpu_down, |
250 | .machine_kexec = ps3_machine_kexec, | 269 | .machine_kexec = default_machine_kexec, |
251 | .machine_kexec_prepare = default_machine_kexec_prepare, | 270 | .machine_kexec_prepare = default_machine_kexec_prepare, |
252 | .machine_crash_shutdown = default_machine_crash_shutdown, | 271 | .machine_crash_shutdown = default_machine_crash_shutdown, |
253 | #endif | 272 | #endif |
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 53416ec5198b..f0b12f212363 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c | |||
@@ -27,9 +27,9 @@ | |||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | 28 | ||
29 | #if defined(DEBUG) | 29 | #if defined(DEBUG) |
30 | #define DBG(fmt...) udbg_printf(fmt) | 30 | #define DBG udbg_printf |
31 | #else | 31 | #else |
32 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 32 | #define DBG pr_debug |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | static irqreturn_t ipi_function_handler(int irq, void *msg) | 35 | static irqreturn_t ipi_function_handler(int irq, void *msg) |
@@ -39,11 +39,11 @@ static irqreturn_t ipi_function_handler(int irq, void *msg) | |||
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | /** |
42 | * virqs - a per cpu array of virqs for ipi use | 42 | * ps3_ipi_virqs - a per cpu array of virqs for ipi use |
43 | */ | 43 | */ |
44 | 44 | ||
45 | #define MSG_COUNT 4 | 45 | #define MSG_COUNT 4 |
46 | static DEFINE_PER_CPU(unsigned int, virqs[MSG_COUNT]); | 46 | static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]); |
47 | 47 | ||
48 | static const char *names[MSG_COUNT] = { | 48 | static const char *names[MSG_COUNT] = { |
49 | "ipi call", | 49 | "ipi call", |
@@ -62,7 +62,7 @@ static void do_message_pass(int target, int msg) | |||
62 | return; | 62 | return; |
63 | } | 63 | } |
64 | 64 | ||
65 | virq = per_cpu(virqs, target)[msg]; | 65 | virq = per_cpu(ps3_ipi_virqs, target)[msg]; |
66 | result = ps3_send_event_locally(virq); | 66 | result = ps3_send_event_locally(virq); |
67 | 67 | ||
68 | if (result) | 68 | if (result) |
@@ -94,13 +94,13 @@ static int ps3_smp_probe(void) | |||
94 | static void __init ps3_smp_setup_cpu(int cpu) | 94 | static void __init ps3_smp_setup_cpu(int cpu) |
95 | { | 95 | { |
96 | int result; | 96 | int result; |
97 | unsigned int *virqs = per_cpu(virqs, cpu); | 97 | unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); |
98 | int i; | 98 | int i; |
99 | 99 | ||
100 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); | 100 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * Check assumptions on virqs[] indexing. If this | 103 | * Check assumptions on ps3_ipi_virqs[] indexing. If this |
104 | * check fails, then a different mapping of PPC_MSG_ | 104 | * check fails, then a different mapping of PPC_MSG_ |
105 | * to index needs to be setup. | 105 | * to index needs to be setup. |
106 | */ | 106 | */ |
@@ -132,13 +132,13 @@ static void __init ps3_smp_setup_cpu(int cpu) | |||
132 | 132 | ||
133 | void ps3_smp_cleanup_cpu(int cpu) | 133 | void ps3_smp_cleanup_cpu(int cpu) |
134 | { | 134 | { |
135 | unsigned int *virqs = per_cpu(virqs, cpu); | 135 | unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); |
136 | int i; | 136 | int i; |
137 | 137 | ||
138 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); | 138 | DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); |
139 | 139 | ||
140 | for (i = 0; i < MSG_COUNT; i++) { | 140 | for (i = 0; i < MSG_COUNT; i++) { |
141 | free_irq(virqs[i], (void*)(long)i); | 141 | /* Can't call free_irq from interrupt context. */ |
142 | ps3_event_receive_port_destroy(virqs[i]); | 142 | ps3_event_receive_port_destroy(virqs[i]); |
143 | virqs[i] = NO_IRQ; | 143 | virqs[i] = NO_IRQ; |
144 | } | 144 | } |
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 651437cb2c18..c7f734c89462 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -182,15 +182,18 @@ static int __init setup_areas(struct spu *spu) | |||
182 | { | 182 | { |
183 | struct table {char* name; unsigned long addr; unsigned long size;}; | 183 | struct table {char* name; unsigned long addr; unsigned long size;}; |
184 | 184 | ||
185 | spu_pdata(spu)->shadow = __ioremap( | 185 | spu_pdata(spu)->shadow = ioremap_flags(spu_pdata(spu)->shadow_addr, |
186 | spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), | 186 | sizeof(struct spe_shadow), |
187 | pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED); | 187 | pgprot_val(PAGE_READONLY) | |
188 | _PAGE_NO_CACHE); | ||
188 | if (!spu_pdata(spu)->shadow) { | 189 | if (!spu_pdata(spu)->shadow) { |
189 | pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__); | 190 | pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__); |
190 | goto fail_ioremap; | 191 | goto fail_ioremap; |
191 | } | 192 | } |
192 | 193 | ||
193 | spu->local_store = ioremap(spu->local_store_phys, LS_SIZE); | 194 | spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys, |
195 | LS_SIZE, _PAGE_NO_CACHE); | ||
196 | |||
194 | if (!spu->local_store) { | 197 | if (!spu->local_store) { |
195 | pr_debug("%s:%d: ioremap local_store failed\n", | 198 | pr_debug("%s:%d: ioremap local_store failed\n", |
196 | __func__, __LINE__); | 199 | __func__, __LINE__); |
@@ -199,6 +202,7 @@ static int __init setup_areas(struct spu *spu) | |||
199 | 202 | ||
200 | spu->problem = ioremap(spu->problem_phys, | 203 | spu->problem = ioremap(spu->problem_phys, |
201 | sizeof(struct spu_problem)); | 204 | sizeof(struct spu_problem)); |
205 | |||
202 | if (!spu->problem) { | 206 | if (!spu->problem) { |
203 | pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__); | 207 | pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__); |
204 | goto fail_ioremap; | 208 | goto fail_ioremap; |
@@ -206,6 +210,7 @@ static int __init setup_areas(struct spu *spu) | |||
206 | 210 | ||
207 | spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr, | 211 | spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr, |
208 | sizeof(struct spu_priv2)); | 212 | sizeof(struct spu_priv2)); |
213 | |||
209 | if (!spu->priv2) { | 214 | if (!spu->priv2) { |
210 | pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__); | 215 | pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__); |
211 | goto fail_ioremap; | 216 | goto fail_ioremap; |
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6bda51027cc6..4bb634a17e43 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -30,22 +30,228 @@ | |||
30 | 30 | ||
31 | #include "platform.h" | 31 | #include "platform.h" |
32 | 32 | ||
33 | static struct device ps3_system_bus = { | ||
34 | .bus_id = "ps3_system", | ||
35 | }; | ||
36 | |||
37 | /* FIXME: need device usage counters! */ | ||
38 | struct { | ||
39 | struct mutex mutex; | ||
40 | int sb_11; /* usb 0 */ | ||
41 | int sb_12; /* usb 0 */ | ||
42 | int gpu; | ||
43 | } static usage_hack; | ||
44 | |||
45 | static int ps3_is_device(struct ps3_system_bus_device *dev, | ||
46 | unsigned int bus_id, unsigned int dev_id) | ||
47 | { | ||
48 | return dev->bus_id == bus_id && dev->dev_id == dev_id; | ||
49 | } | ||
50 | |||
51 | static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev) | ||
52 | { | ||
53 | int result; | ||
54 | |||
55 | BUG_ON(!dev->bus_id); | ||
56 | mutex_lock(&usage_hack.mutex); | ||
57 | |||
58 | if (ps3_is_device(dev, 1, 1)) { | ||
59 | usage_hack.sb_11++; | ||
60 | if (usage_hack.sb_11 > 1) { | ||
61 | result = 0; | ||
62 | goto done; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | if (ps3_is_device(dev, 1, 2)) { | ||
67 | usage_hack.sb_12++; | ||
68 | if (usage_hack.sb_12 > 1) { | ||
69 | result = 0; | ||
70 | goto done; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | result = lv1_open_device(dev->bus_id, dev->dev_id, 0); | ||
75 | |||
76 | if (result) { | ||
77 | pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__, | ||
78 | __LINE__, ps3_result(result)); | ||
79 | result = -EPERM; | ||
80 | } | ||
81 | |||
82 | done: | ||
83 | mutex_unlock(&usage_hack.mutex); | ||
84 | return result; | ||
85 | } | ||
86 | |||
87 | static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev) | ||
88 | { | ||
89 | int result; | ||
90 | |||
91 | BUG_ON(!dev->bus_id); | ||
92 | mutex_lock(&usage_hack.mutex); | ||
93 | |||
94 | if (ps3_is_device(dev, 1, 1)) { | ||
95 | usage_hack.sb_11--; | ||
96 | if (usage_hack.sb_11) { | ||
97 | result = 0; | ||
98 | goto done; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (ps3_is_device(dev, 1, 2)) { | ||
103 | usage_hack.sb_12--; | ||
104 | if (usage_hack.sb_12) { | ||
105 | result = 0; | ||
106 | goto done; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | result = lv1_close_device(dev->bus_id, dev->dev_id); | ||
111 | BUG_ON(result); | ||
112 | |||
113 | done: | ||
114 | mutex_unlock(&usage_hack.mutex); | ||
115 | return result; | ||
116 | } | ||
117 | |||
118 | static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev) | ||
119 | { | ||
120 | int result; | ||
121 | |||
122 | mutex_lock(&usage_hack.mutex); | ||
123 | |||
124 | usage_hack.gpu++; | ||
125 | if (usage_hack.gpu > 1) { | ||
126 | result = 0; | ||
127 | goto done; | ||
128 | } | ||
129 | |||
130 | result = lv1_gpu_open(0); | ||
131 | |||
132 | if (result) { | ||
133 | pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__, | ||
134 | __LINE__, ps3_result(result)); | ||
135 | result = -EPERM; | ||
136 | } | ||
137 | |||
138 | done: | ||
139 | mutex_unlock(&usage_hack.mutex); | ||
140 | return result; | ||
141 | } | ||
142 | |||
143 | static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev) | ||
144 | { | ||
145 | int result; | ||
146 | |||
147 | mutex_lock(&usage_hack.mutex); | ||
148 | |||
149 | usage_hack.gpu--; | ||
150 | if (usage_hack.gpu) { | ||
151 | result = 0; | ||
152 | goto done; | ||
153 | } | ||
154 | |||
155 | result = lv1_gpu_close(); | ||
156 | BUG_ON(result); | ||
157 | |||
158 | done: | ||
159 | mutex_unlock(&usage_hack.mutex); | ||
160 | return result; | ||
161 | } | ||
162 | |||
163 | int ps3_open_hv_device(struct ps3_system_bus_device *dev) | ||
164 | { | ||
165 | BUG_ON(!dev); | ||
166 | pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); | ||
167 | |||
168 | switch (dev->match_id) { | ||
169 | case PS3_MATCH_ID_EHCI: | ||
170 | case PS3_MATCH_ID_OHCI: | ||
171 | case PS3_MATCH_ID_GELIC: | ||
172 | case PS3_MATCH_ID_STOR_DISK: | ||
173 | case PS3_MATCH_ID_STOR_ROM: | ||
174 | case PS3_MATCH_ID_STOR_FLASH: | ||
175 | return ps3_open_hv_device_sb(dev); | ||
176 | |||
177 | case PS3_MATCH_ID_SOUND: | ||
178 | case PS3_MATCH_ID_GRAPHICS: | ||
179 | return ps3_open_hv_device_gpu(dev); | ||
180 | |||
181 | case PS3_MATCH_ID_AV_SETTINGS: | ||
182 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
183 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | ||
184 | __LINE__, dev->match_id); | ||
185 | pr_debug("%s:%d: bus_id: %u\n", __func__, | ||
186 | __LINE__, dev->bus_id); | ||
187 | BUG(); | ||
188 | return -EINVAL; | ||
189 | |||
190 | default: | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, | ||
195 | dev->match_id); | ||
196 | BUG(); | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | EXPORT_SYMBOL_GPL(ps3_open_hv_device); | ||
200 | |||
201 | int ps3_close_hv_device(struct ps3_system_bus_device *dev) | ||
202 | { | ||
203 | BUG_ON(!dev); | ||
204 | pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); | ||
205 | |||
206 | switch (dev->match_id) { | ||
207 | case PS3_MATCH_ID_EHCI: | ||
208 | case PS3_MATCH_ID_OHCI: | ||
209 | case PS3_MATCH_ID_GELIC: | ||
210 | case PS3_MATCH_ID_STOR_DISK: | ||
211 | case PS3_MATCH_ID_STOR_ROM: | ||
212 | case PS3_MATCH_ID_STOR_FLASH: | ||
213 | return ps3_close_hv_device_sb(dev); | ||
214 | |||
215 | case PS3_MATCH_ID_SOUND: | ||
216 | case PS3_MATCH_ID_GRAPHICS: | ||
217 | return ps3_close_hv_device_gpu(dev); | ||
218 | |||
219 | case PS3_MATCH_ID_AV_SETTINGS: | ||
220 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
221 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | ||
222 | __LINE__, dev->match_id); | ||
223 | pr_debug("%s:%d: bus_id: %u\n", __func__, | ||
224 | __LINE__, dev->bus_id); | ||
225 | BUG(); | ||
226 | return -EINVAL; | ||
227 | |||
228 | default: | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, | ||
233 | dev->match_id); | ||
234 | BUG(); | ||
235 | return -ENODEV; | ||
236 | } | ||
237 | EXPORT_SYMBOL_GPL(ps3_close_hv_device); | ||
238 | |||
33 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) | 239 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) |
34 | static void _dump_mmio_region(const struct ps3_mmio_region* r, | 240 | static void _dump_mmio_region(const struct ps3_mmio_region* r, |
35 | const char* func, int line) | 241 | const char* func, int line) |
36 | { | 242 | { |
37 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | 243 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, |
38 | r->did.dev_id); | 244 | r->dev->dev_id); |
39 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 245 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); |
40 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); | 246 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); |
41 | pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); | 247 | pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); |
42 | } | 248 | } |
43 | 249 | ||
44 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | 250 | static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r) |
45 | { | 251 | { |
46 | int result; | 252 | int result; |
47 | 253 | ||
48 | result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, | 254 | result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id, |
49 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); | 255 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); |
50 | 256 | ||
51 | if (result) { | 257 | if (result) { |
@@ -57,13 +263,26 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r) | |||
57 | dump_mmio_region(r); | 263 | dump_mmio_region(r); |
58 | return result; | 264 | return result; |
59 | } | 265 | } |
266 | |||
267 | static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r) | ||
268 | { | ||
269 | /* device specific; do nothing currently */ | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | ||
274 | { | ||
275 | return r->mmio_ops->create(r); | ||
276 | } | ||
60 | EXPORT_SYMBOL_GPL(ps3_mmio_region_create); | 277 | EXPORT_SYMBOL_GPL(ps3_mmio_region_create); |
61 | 278 | ||
62 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | 279 | static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r) |
63 | { | 280 | { |
64 | int result; | 281 | int result; |
65 | 282 | ||
66 | result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, | 283 | dump_mmio_region(r); |
284 | ; | ||
285 | result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id, | ||
67 | r->lpar_addr); | 286 | r->lpar_addr); |
68 | 287 | ||
69 | if (result) | 288 | if (result) |
@@ -73,14 +292,60 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r) | |||
73 | r->lpar_addr = 0; | 292 | r->lpar_addr = 0; |
74 | return result; | 293 | return result; |
75 | } | 294 | } |
295 | |||
296 | static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r) | ||
297 | { | ||
298 | /* device specific; do nothing currently */ | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | |||
303 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | ||
304 | { | ||
305 | return r->mmio_ops->free(r); | ||
306 | } | ||
307 | |||
76 | EXPORT_SYMBOL_GPL(ps3_free_mmio_region); | 308 | EXPORT_SYMBOL_GPL(ps3_free_mmio_region); |
77 | 309 | ||
310 | static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = { | ||
311 | .create = ps3_sb_mmio_region_create, | ||
312 | .free = ps3_sb_free_mmio_region | ||
313 | }; | ||
314 | |||
315 | static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = { | ||
316 | .create = ps3_ioc0_mmio_region_create, | ||
317 | .free = ps3_ioc0_free_mmio_region | ||
318 | }; | ||
319 | |||
320 | int ps3_mmio_region_init(struct ps3_system_bus_device *dev, | ||
321 | struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len, | ||
322 | enum ps3_mmio_page_size page_size) | ||
323 | { | ||
324 | r->dev = dev; | ||
325 | r->bus_addr = bus_addr; | ||
326 | r->len = len; | ||
327 | r->page_size = page_size; | ||
328 | switch (dev->dev_type) { | ||
329 | case PS3_DEVICE_TYPE_SB: | ||
330 | r->mmio_ops = &ps3_mmio_sb_region_ops; | ||
331 | break; | ||
332 | case PS3_DEVICE_TYPE_IOC0: | ||
333 | r->mmio_ops = &ps3_mmio_ioc0_region_ops; | ||
334 | break; | ||
335 | default: | ||
336 | BUG(); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | return 0; | ||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(ps3_mmio_region_init); | ||
342 | |||
78 | static int ps3_system_bus_match(struct device *_dev, | 343 | static int ps3_system_bus_match(struct device *_dev, |
79 | struct device_driver *_drv) | 344 | struct device_driver *_drv) |
80 | { | 345 | { |
81 | int result; | 346 | int result; |
82 | struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); | 347 | struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv); |
83 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 348 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
84 | 349 | ||
85 | result = dev->match_id == drv->match_id; | 350 | result = dev->match_id == drv->match_id; |
86 | 351 | ||
@@ -92,32 +357,14 @@ static int ps3_system_bus_match(struct device *_dev, | |||
92 | 357 | ||
93 | static int ps3_system_bus_probe(struct device *_dev) | 358 | static int ps3_system_bus_probe(struct device *_dev) |
94 | { | 359 | { |
95 | int result; | 360 | int result = 0; |
96 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 361 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
97 | struct ps3_system_bus_driver *drv = | 362 | struct ps3_system_bus_driver *drv; |
98 | to_ps3_system_bus_driver(_dev->driver); | ||
99 | |||
100 | result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); | ||
101 | |||
102 | if (result) { | ||
103 | pr_debug("%s:%d: lv1_open_device failed (%d)\n", | ||
104 | __func__, __LINE__, result); | ||
105 | result = -EACCES; | ||
106 | goto clean_none; | ||
107 | } | ||
108 | |||
109 | if (dev->d_region->did.bus_id) { | ||
110 | result = ps3_dma_region_create(dev->d_region); | ||
111 | 363 | ||
112 | if (result) { | 364 | BUG_ON(!dev); |
113 | pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", | 365 | pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); |
114 | __func__, __LINE__, result); | ||
115 | BUG_ON("check region type"); | ||
116 | result = -EINVAL; | ||
117 | goto clean_device; | ||
118 | } | ||
119 | } | ||
120 | 366 | ||
367 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
121 | BUG_ON(!drv); | 368 | BUG_ON(!drv); |
122 | 369 | ||
123 | if (drv->probe) | 370 | if (drv->probe) |
@@ -126,56 +373,127 @@ static int ps3_system_bus_probe(struct device *_dev) | |||
126 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, | 373 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, |
127 | dev->core.bus_id); | 374 | dev->core.bus_id); |
128 | 375 | ||
129 | if (result) { | 376 | pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); |
130 | pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); | ||
131 | goto clean_dma; | ||
132 | } | ||
133 | |||
134 | return result; | ||
135 | |||
136 | clean_dma: | ||
137 | ps3_dma_region_free(dev->d_region); | ||
138 | clean_device: | ||
139 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
140 | clean_none: | ||
141 | return result; | 377 | return result; |
142 | } | 378 | } |
143 | 379 | ||
144 | static int ps3_system_bus_remove(struct device *_dev) | 380 | static int ps3_system_bus_remove(struct device *_dev) |
145 | { | 381 | { |
146 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 382 | int result = 0; |
147 | struct ps3_system_bus_driver *drv = | 383 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
148 | to_ps3_system_bus_driver(_dev->driver); | 384 | struct ps3_system_bus_driver *drv; |
385 | |||
386 | BUG_ON(!dev); | ||
387 | pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); | ||
388 | |||
389 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
390 | BUG_ON(!drv); | ||
149 | 391 | ||
150 | if (drv->remove) | 392 | if (drv->remove) |
151 | drv->remove(dev); | 393 | result = drv->remove(dev); |
152 | else | 394 | else |
153 | pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, | 395 | dev_dbg(&dev->core, "%s:%d %s: no remove method\n", |
154 | dev->core.bus_id); | 396 | __func__, __LINE__, drv->core.name); |
397 | |||
398 | pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | static void ps3_system_bus_shutdown(struct device *_dev) | ||
403 | { | ||
404 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
405 | struct ps3_system_bus_driver *drv; | ||
406 | |||
407 | BUG_ON(!dev); | ||
408 | |||
409 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, | ||
410 | dev->match_id); | ||
411 | |||
412 | if (!dev->core.driver) { | ||
413 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, | ||
414 | __LINE__); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
419 | |||
420 | BUG_ON(!drv); | ||
421 | |||
422 | dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__, | ||
423 | dev->core.bus_id, drv->core.name); | ||
424 | |||
425 | if (drv->shutdown) | ||
426 | drv->shutdown(dev); | ||
427 | else if (drv->remove) { | ||
428 | dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n", | ||
429 | __func__, __LINE__, drv->core.name); | ||
430 | drv->remove(dev); | ||
431 | } else { | ||
432 | dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n", | ||
433 | __func__, __LINE__, drv->core.name); | ||
434 | BUG(); | ||
435 | } | ||
436 | |||
437 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
438 | } | ||
439 | |||
440 | static int ps3_system_bus_uevent(struct device *_dev, char **envp, | ||
441 | int num_envp, char *buffer, int buffer_size) | ||
442 | { | ||
443 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
444 | int i = 0, length = 0; | ||
155 | 445 | ||
156 | ps3_dma_region_free(dev->d_region); | 446 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, |
157 | ps3_free_mmio_region(dev->m_region); | 447 | &length, "MODALIAS=ps3:%d", |
158 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | 448 | dev->match_id)) |
449 | return -ENOMEM; | ||
159 | 450 | ||
451 | envp[i] = NULL; | ||
160 | return 0; | 452 | return 0; |
161 | } | 453 | } |
162 | 454 | ||
455 | static ssize_t modalias_show(struct device *_dev, struct device_attribute *a, | ||
456 | char *buf) | ||
457 | { | ||
458 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
459 | int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id); | ||
460 | |||
461 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | ||
462 | } | ||
463 | |||
464 | static struct device_attribute ps3_system_bus_dev_attrs[] = { | ||
465 | __ATTR_RO(modalias), | ||
466 | __ATTR_NULL, | ||
467 | }; | ||
468 | |||
163 | struct bus_type ps3_system_bus_type = { | 469 | struct bus_type ps3_system_bus_type = { |
164 | .name = "ps3_system_bus", | 470 | .name = "ps3_system_bus", |
165 | .match = ps3_system_bus_match, | 471 | .match = ps3_system_bus_match, |
472 | .uevent = ps3_system_bus_uevent, | ||
166 | .probe = ps3_system_bus_probe, | 473 | .probe = ps3_system_bus_probe, |
167 | .remove = ps3_system_bus_remove, | 474 | .remove = ps3_system_bus_remove, |
475 | .shutdown = ps3_system_bus_shutdown, | ||
476 | .dev_attrs = ps3_system_bus_dev_attrs, | ||
168 | }; | 477 | }; |
169 | 478 | ||
170 | int __init ps3_system_bus_init(void) | 479 | static int __init ps3_system_bus_init(void) |
171 | { | 480 | { |
172 | int result; | 481 | int result; |
173 | 482 | ||
174 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 483 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
175 | return -ENODEV; | 484 | return -ENODEV; |
176 | 485 | ||
486 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
487 | |||
488 | mutex_init(&usage_hack.mutex); | ||
489 | |||
490 | result = device_register(&ps3_system_bus); | ||
491 | BUG_ON(result); | ||
492 | |||
177 | result = bus_register(&ps3_system_bus_type); | 493 | result = bus_register(&ps3_system_bus_type); |
178 | BUG_ON(result); | 494 | BUG_ON(result); |
495 | |||
496 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
179 | return result; | 497 | return result; |
180 | } | 498 | } |
181 | 499 | ||
@@ -185,16 +503,13 @@ core_initcall(ps3_system_bus_init); | |||
185 | * Returns the virtual address of the buffer and sets dma_handle | 503 | * Returns the virtual address of the buffer and sets dma_handle |
186 | * to the dma address (mapping) of the first page. | 504 | * to the dma address (mapping) of the first page. |
187 | */ | 505 | */ |
188 | |||
189 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, | 506 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, |
190 | dma_addr_t *dma_handle, gfp_t flag) | 507 | dma_addr_t *dma_handle, gfp_t flag) |
191 | { | 508 | { |
192 | int result; | 509 | int result; |
193 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 510 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
194 | unsigned long virt_addr; | 511 | unsigned long virt_addr; |
195 | 512 | ||
196 | BUG_ON(!dev->d_region->bus_addr); | ||
197 | |||
198 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); | 513 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); |
199 | flag |= __GFP_ZERO; | 514 | flag |= __GFP_ZERO; |
200 | 515 | ||
@@ -205,7 +520,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, | |||
205 | goto clean_none; | 520 | goto clean_none; |
206 | } | 521 | } |
207 | 522 | ||
208 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); | 523 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, |
524 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); | ||
209 | 525 | ||
210 | if (result) { | 526 | if (result) { |
211 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 527 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -226,7 +542,7 @@ clean_none: | |||
226 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | 542 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, |
227 | dma_addr_t dma_handle) | 543 | dma_addr_t dma_handle) |
228 | { | 544 | { |
229 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 545 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
230 | 546 | ||
231 | ps3_dma_unmap(dev->d_region, dma_handle, size); | 547 | ps3_dma_unmap(dev->d_region, dma_handle, size); |
232 | free_pages((unsigned long)vaddr, get_order(size)); | 548 | free_pages((unsigned long)vaddr, get_order(size)); |
@@ -239,15 +555,16 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | |||
239 | * byte within the page as vaddr. | 555 | * byte within the page as vaddr. |
240 | */ | 556 | */ |
241 | 557 | ||
242 | static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | 558 | static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, |
243 | enum dma_data_direction direction) | 559 | enum dma_data_direction direction) |
244 | { | 560 | { |
245 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 561 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
246 | int result; | 562 | int result; |
247 | unsigned long bus_addr; | 563 | unsigned long bus_addr; |
248 | 564 | ||
249 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | 565 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, |
250 | &bus_addr); | 566 | &bus_addr, |
567 | IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); | ||
251 | 568 | ||
252 | if (result) { | 569 | if (result) { |
253 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 570 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -257,10 +574,44 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | |||
257 | return bus_addr; | 574 | return bus_addr; |
258 | } | 575 | } |
259 | 576 | ||
577 | static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, | ||
578 | size_t size, | ||
579 | enum dma_data_direction direction) | ||
580 | { | ||
581 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
582 | int result; | ||
583 | unsigned long bus_addr; | ||
584 | u64 iopte_flag; | ||
585 | |||
586 | iopte_flag = IOPTE_M; | ||
587 | switch (direction) { | ||
588 | case DMA_BIDIRECTIONAL: | ||
589 | iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; | ||
590 | break; | ||
591 | case DMA_TO_DEVICE: | ||
592 | iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; | ||
593 | break; | ||
594 | case DMA_FROM_DEVICE: | ||
595 | iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; | ||
596 | break; | ||
597 | default: | ||
598 | /* not happned */ | ||
599 | BUG(); | ||
600 | }; | ||
601 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | ||
602 | &bus_addr, iopte_flag); | ||
603 | |||
604 | if (result) { | ||
605 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
606 | __func__, __LINE__, result); | ||
607 | } | ||
608 | return bus_addr; | ||
609 | } | ||
610 | |||
260 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | 611 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, |
261 | size_t size, enum dma_data_direction direction) | 612 | size_t size, enum dma_data_direction direction) |
262 | { | 613 | { |
263 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 614 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
264 | int result; | 615 | int result; |
265 | 616 | ||
266 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); | 617 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); |
@@ -271,20 +622,20 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | |||
271 | } | 622 | } |
272 | } | 623 | } |
273 | 624 | ||
274 | static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | 625 | static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents, |
275 | enum dma_data_direction direction) | 626 | enum dma_data_direction direction) |
276 | { | 627 | { |
277 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 628 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
278 | BUG_ON("do"); | 629 | BUG_ON("do"); |
279 | return -EPERM; | 630 | return -EPERM; |
280 | #else | 631 | #else |
281 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 632 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
282 | int i; | 633 | int i; |
283 | 634 | ||
284 | for (i = 0; i < nents; i++, sg++) { | 635 | for (i = 0; i < nents; i++, sg++) { |
285 | int result = ps3_dma_map(dev->d_region, | 636 | int result = ps3_dma_map(dev->d_region, |
286 | page_to_phys(sg->page) + sg->offset, sg->length, | 637 | page_to_phys(sg->page) + sg->offset, sg->length, |
287 | &sg->dma_address); | 638 | &sg->dma_address, 0); |
288 | 639 | ||
289 | if (result) { | 640 | if (result) { |
290 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 641 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -299,7 +650,15 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | |||
299 | #endif | 650 | #endif |
300 | } | 651 | } |
301 | 652 | ||
302 | static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | 653 | static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, |
654 | int nents, | ||
655 | enum dma_data_direction direction) | ||
656 | { | ||
657 | BUG(); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
303 | int nents, enum dma_data_direction direction) | 662 | int nents, enum dma_data_direction direction) |
304 | { | 663 | { |
305 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 664 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
@@ -307,18 +666,34 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | |||
307 | #endif | 666 | #endif |
308 | } | 667 | } |
309 | 668 | ||
669 | static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
670 | int nents, enum dma_data_direction direction) | ||
671 | { | ||
672 | BUG(); | ||
673 | } | ||
674 | |||
310 | static int ps3_dma_supported(struct device *_dev, u64 mask) | 675 | static int ps3_dma_supported(struct device *_dev, u64 mask) |
311 | { | 676 | { |
312 | return mask >= DMA_32BIT_MASK; | 677 | return mask >= DMA_32BIT_MASK; |
313 | } | 678 | } |
314 | 679 | ||
315 | static struct dma_mapping_ops ps3_dma_ops = { | 680 | static struct dma_mapping_ops ps3_sb_dma_ops = { |
316 | .alloc_coherent = ps3_alloc_coherent, | 681 | .alloc_coherent = ps3_alloc_coherent, |
317 | .free_coherent = ps3_free_coherent, | 682 | .free_coherent = ps3_free_coherent, |
318 | .map_single = ps3_map_single, | 683 | .map_single = ps3_sb_map_single, |
319 | .unmap_single = ps3_unmap_single, | 684 | .unmap_single = ps3_unmap_single, |
320 | .map_sg = ps3_map_sg, | 685 | .map_sg = ps3_sb_map_sg, |
321 | .unmap_sg = ps3_unmap_sg, | 686 | .unmap_sg = ps3_sb_unmap_sg, |
687 | .dma_supported = ps3_dma_supported | ||
688 | }; | ||
689 | |||
690 | static struct dma_mapping_ops ps3_ioc0_dma_ops = { | ||
691 | .alloc_coherent = ps3_alloc_coherent, | ||
692 | .free_coherent = ps3_free_coherent, | ||
693 | .map_single = ps3_ioc0_map_single, | ||
694 | .unmap_single = ps3_unmap_single, | ||
695 | .map_sg = ps3_ioc0_map_sg, | ||
696 | .unmap_sg = ps3_ioc0_unmap_sg, | ||
322 | .dma_supported = ps3_dma_supported | 697 | .dma_supported = ps3_dma_supported |
323 | }; | 698 | }; |
324 | 699 | ||
@@ -328,7 +703,7 @@ static struct dma_mapping_ops ps3_dma_ops = { | |||
328 | 703 | ||
329 | static void ps3_system_bus_release_device(struct device *_dev) | 704 | static void ps3_system_bus_release_device(struct device *_dev) |
330 | { | 705 | { |
331 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 706 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
332 | kfree(dev); | 707 | kfree(dev); |
333 | } | 708 | } |
334 | 709 | ||
@@ -343,19 +718,38 @@ static void ps3_system_bus_release_device(struct device *_dev) | |||
343 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | 718 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) |
344 | { | 719 | { |
345 | int result; | 720 | int result; |
346 | static unsigned int dev_count = 1; | 721 | static unsigned int dev_ioc0_count; |
722 | static unsigned int dev_sb_count; | ||
723 | static unsigned int dev_vuart_count; | ||
347 | 724 | ||
348 | dev->core.parent = NULL; | 725 | if (!dev->core.parent) |
726 | dev->core.parent = &ps3_system_bus; | ||
349 | dev->core.bus = &ps3_system_bus_type; | 727 | dev->core.bus = &ps3_system_bus_type; |
350 | dev->core.release = ps3_system_bus_release_device; | 728 | dev->core.release = ps3_system_bus_release_device; |
351 | 729 | ||
730 | switch (dev->dev_type) { | ||
731 | case PS3_DEVICE_TYPE_IOC0: | ||
732 | dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops; | ||
733 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
734 | "ioc0_%02x", ++dev_ioc0_count); | ||
735 | break; | ||
736 | case PS3_DEVICE_TYPE_SB: | ||
737 | dev->core.archdata.dma_ops = &ps3_sb_dma_ops; | ||
738 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
739 | "sb_%02x", ++dev_sb_count); | ||
740 | |||
741 | break; | ||
742 | case PS3_DEVICE_TYPE_VUART: | ||
743 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
744 | "vuart_%02x", ++dev_vuart_count); | ||
745 | break; | ||
746 | default: | ||
747 | BUG(); | ||
748 | }; | ||
749 | |||
352 | dev->core.archdata.of_node = NULL; | 750 | dev->core.archdata.of_node = NULL; |
353 | dev->core.archdata.dma_ops = &ps3_dma_ops; | ||
354 | dev->core.archdata.numa_node = 0; | 751 | dev->core.archdata.numa_node = 0; |
355 | 752 | ||
356 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", | ||
357 | dev_count++); | ||
358 | |||
359 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); | 753 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); |
360 | 754 | ||
361 | result = device_register(&dev->core); | 755 | result = device_register(&dev->core); |
@@ -368,9 +762,15 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) | |||
368 | { | 762 | { |
369 | int result; | 763 | int result; |
370 | 764 | ||
765 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
766 | |||
767 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
768 | return -ENODEV; | ||
769 | |||
371 | drv->core.bus = &ps3_system_bus_type; | 770 | drv->core.bus = &ps3_system_bus_type; |
372 | 771 | ||
373 | result = driver_register(&drv->core); | 772 | result = driver_register(&drv->core); |
773 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
374 | return result; | 774 | return result; |
375 | } | 775 | } |
376 | 776 | ||
@@ -378,7 +778,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | |||
378 | 778 | ||
379 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | 779 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) |
380 | { | 780 | { |
781 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
381 | driver_unregister(&drv->core); | 782 | driver_unregister(&drv->core); |
783 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
382 | } | 784 | } |
383 | 785 | ||
384 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | 786 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); |
diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index 1bae8b19b363..802a9ccacb5e 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c | |||
@@ -39,7 +39,7 @@ static void _dump_tm(const struct rtc_time *tm, const char* func, int line) | |||
39 | } | 39 | } |
40 | 40 | ||
41 | #define dump_time(_a) _dump_time(_a, __func__, __LINE__) | 41 | #define dump_time(_a) _dump_time(_a, __func__, __LINE__) |
42 | static void __attribute__ ((unused)) _dump_time(int time, const char* func, | 42 | static void __maybe_unused _dump_time(int time, const char *func, |
43 | int line) | 43 | int line) |
44 | { | 44 | { |
45 | struct rtc_time tm; | 45 | struct rtc_time tm; |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index ae1fc92dc1c9..992ba6753cf2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -8,7 +8,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | |||
8 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
9 | obj-$(CONFIG_XICS) += xics.o | 9 | obj-$(CONFIG_XICS) += xics.o |
10 | obj-$(CONFIG_SCANLOG) += scanlog.o | 10 | obj-$(CONFIG_SCANLOG) += scanlog.o |
11 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o | 11 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o |
12 | obj-$(CONFIG_KEXEC) += kexec.o | 12 | obj-$(CONFIG_KEXEC) += kexec.o |
13 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o | 13 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o |
14 | obj-$(CONFIG_PCI_MSI) += msi.o | 14 | obj-$(CONFIG_PCI_MSI) += msi.o |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 5f3e6d8659fe..b8770395013d 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -1,6 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.c | 2 | * eeh.c |
3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation | 3 | * Copyright IBM Corporation 2001, 2005, 2006 |
4 | * Copyright Dave Engebretsen & Todd Inglett 2001 | ||
5 | * Copyright Linas Vepstas 2005, 2006 | ||
4 | * | 6 | * |
5 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -15,6 +17,8 @@ | |||
15 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | * | ||
21 | * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com> | ||
18 | */ | 22 | */ |
19 | 23 | ||
20 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
@@ -117,7 +121,6 @@ static unsigned long no_cfg_addr; | |||
117 | static unsigned long ignored_check; | 121 | static unsigned long ignored_check; |
118 | static unsigned long total_mmio_ffs; | 122 | static unsigned long total_mmio_ffs; |
119 | static unsigned long false_positives; | 123 | static unsigned long false_positives; |
120 | static unsigned long ignored_failures; | ||
121 | static unsigned long slot_resets; | 124 | static unsigned long slot_resets; |
122 | 125 | ||
123 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) | 126 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) |
@@ -505,6 +508,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
505 | printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", | 508 | printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", |
506 | ret, dn->full_name); | 509 | ret, dn->full_name); |
507 | false_positives++; | 510 | false_positives++; |
511 | pdn->eeh_false_positives ++; | ||
508 | rc = 0; | 512 | rc = 0; |
509 | goto dn_unlock; | 513 | goto dn_unlock; |
510 | } | 514 | } |
@@ -513,6 +517,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
513 | * they are empty when they don't have children. */ | 517 | * they are empty when they don't have children. */ |
514 | if ((rets[0] == 5) && (dn->child == NULL)) { | 518 | if ((rets[0] == 5) && (dn->child == NULL)) { |
515 | false_positives++; | 519 | false_positives++; |
520 | pdn->eeh_false_positives ++; | ||
516 | rc = 0; | 521 | rc = 0; |
517 | goto dn_unlock; | 522 | goto dn_unlock; |
518 | } | 523 | } |
@@ -522,6 +527,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
522 | printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", | 527 | printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", |
523 | ret, dn->full_name); | 528 | ret, dn->full_name); |
524 | false_positives++; | 529 | false_positives++; |
530 | pdn->eeh_false_positives ++; | ||
525 | rc = 0; | 531 | rc = 0; |
526 | goto dn_unlock; | 532 | goto dn_unlock; |
527 | } | 533 | } |
@@ -529,6 +535,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
529 | /* If not the kind of error we know about, punt. */ | 535 | /* If not the kind of error we know about, punt. */ |
530 | if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { | 536 | if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { |
531 | false_positives++; | 537 | false_positives++; |
538 | pdn->eeh_false_positives ++; | ||
532 | rc = 0; | 539 | rc = 0; |
533 | goto dn_unlock; | 540 | goto dn_unlock; |
534 | } | 541 | } |
@@ -921,6 +928,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
921 | pdn->eeh_mode = 0; | 928 | pdn->eeh_mode = 0; |
922 | pdn->eeh_check_count = 0; | 929 | pdn->eeh_check_count = 0; |
923 | pdn->eeh_freeze_count = 0; | 930 | pdn->eeh_freeze_count = 0; |
931 | pdn->eeh_false_positives = 0; | ||
924 | 932 | ||
925 | if (status && strcmp(status, "ok") != 0) | 933 | if (status && strcmp(status, "ok") != 0) |
926 | return NULL; /* ignore devices with bad status */ | 934 | return NULL; /* ignore devices with bad status */ |
@@ -1139,7 +1147,8 @@ static void eeh_add_device_late(struct pci_dev *dev) | |||
1139 | pdn = PCI_DN(dn); | 1147 | pdn = PCI_DN(dn); |
1140 | pdn->pcidev = dev; | 1148 | pdn->pcidev = dev; |
1141 | 1149 | ||
1142 | pci_addr_cache_insert_device (dev); | 1150 | pci_addr_cache_insert_device(dev); |
1151 | eeh_sysfs_add_device(dev); | ||
1143 | } | 1152 | } |
1144 | 1153 | ||
1145 | void eeh_add_device_tree_late(struct pci_bus *bus) | 1154 | void eeh_add_device_tree_late(struct pci_bus *bus) |
@@ -1178,6 +1187,7 @@ static void eeh_remove_device(struct pci_dev *dev) | |||
1178 | printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); | 1187 | printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); |
1179 | #endif | 1188 | #endif |
1180 | pci_addr_cache_remove_device(dev); | 1189 | pci_addr_cache_remove_device(dev); |
1190 | eeh_sysfs_remove_device(dev); | ||
1181 | 1191 | ||
1182 | dn = pci_device_to_OF_node(dev); | 1192 | dn = pci_device_to_OF_node(dev); |
1183 | if (PCI_DN(dn)->pcidev) { | 1193 | if (PCI_DN(dn)->pcidev) { |
@@ -1214,11 +1224,10 @@ static int proc_eeh_show(struct seq_file *m, void *v) | |||
1214 | "check not wanted=%ld\n" | 1224 | "check not wanted=%ld\n" |
1215 | "eeh_total_mmio_ffs=%ld\n" | 1225 | "eeh_total_mmio_ffs=%ld\n" |
1216 | "eeh_false_positives=%ld\n" | 1226 | "eeh_false_positives=%ld\n" |
1217 | "eeh_ignored_failures=%ld\n" | ||
1218 | "eeh_slot_resets=%ld\n", | 1227 | "eeh_slot_resets=%ld\n", |
1219 | no_device, no_dn, no_cfg_addr, | 1228 | no_device, no_dn, no_cfg_addr, |
1220 | ignored_check, total_mmio_ffs, | 1229 | ignored_check, total_mmio_ffs, |
1221 | false_positives, ignored_failures, | 1230 | false_positives, |
1222 | slot_resets); | 1231 | slot_resets); |
1223 | } | 1232 | } |
1224 | 1233 | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index f2bae04424f8..e49c815eae23 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c | |||
@@ -2,7 +2,8 @@ | |||
2 | * eeh_cache.c | 2 | * eeh_cache.c |
3 | * PCI address cache; allows the lookup of PCI devices based on I/O address | 3 | * PCI address cache; allows the lookup of PCI devices based on I/O address |
4 | * | 4 | * |
5 | * Copyright (C) 2004 Linas Vepstas <linas@austin.ibm.com> IBM Corporation | 5 | * Copyright IBM Corporation 2004 |
6 | * Copyright Linas Vepstas <linas@austin.ibm.com> 2004 | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -295,6 +296,8 @@ void __init pci_addr_cache_build(void) | |||
295 | continue; | 296 | continue; |
296 | pci_dev_get (dev); /* matching put is in eeh_remove_device() */ | 297 | pci_dev_get (dev); /* matching put is in eeh_remove_device() */ |
297 | PCI_DN(dn)->pcidev = dev; | 298 | PCI_DN(dn)->pcidev = dev; |
299 | |||
300 | eeh_sysfs_add_device(dev); | ||
298 | } | 301 | } |
299 | 302 | ||
300 | #ifdef DEBUG | 303 | #ifdef DEBUG |
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 161a5844ab6c..15e015ef6865 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PCI Error Recovery Driver for RPA-compliant PPC64 platform. | 2 | * PCI Error Recovery Driver for RPA-compliant PPC64 platform. |
3 | * Copyright (C) 2004, 2005 Linas Vepstas <linas@linas.org> | 3 | * Copyright IBM Corp. 2004 2005 |
4 | * Copyright Linas Vepstas <linas@linas.org> 2004, 2005 | ||
4 | * | 5 | * |
5 | * All rights reserved. | 6 | * All rights reserved. |
6 | * | 7 | * |
@@ -19,8 +20,7 @@ | |||
19 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | * | 22 | * |
22 | * Send feedback to <linas@us.ibm.com> | 23 | * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com> |
23 | * | ||
24 | */ | 24 | */ |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c new file mode 100644 index 000000000000..15e13b568904 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Sysfs entries for PCI Error Recovery for PAPR-compliant platform. | ||
3 | * Copyright IBM Corporation 2007 | ||
4 | * Copyright Linas Vepstas <linas@austin.ibm.com> 2007 | ||
5 | * | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
16 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com> | ||
24 | */ | ||
25 | #include <linux/pci.h> | ||
26 | #include <asm/ppc-pci.h> | ||
27 | #include <asm/pci-bridge.h> | ||
28 | #include <linux/kobject.h> | ||
29 | |||
30 | /** | ||
31 | * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic | ||
32 | * @_name: name of file in sysfs directory | ||
33 | * @_memb: name of member in struct pci_dn to access | ||
34 | * @_format: printf format for display | ||
35 | * | ||
36 | * All of the attributes look very similar, so just | ||
37 | * auto-gen a cut-n-paste routine to display them. | ||
38 | */ | ||
39 | #define EEH_SHOW_ATTR(_name,_memb,_format) \ | ||
40 | static ssize_t eeh_show_##_name(struct device *dev, \ | ||
41 | struct device_attribute *attr, char *buf) \ | ||
42 | { \ | ||
43 | struct pci_dev *pdev = to_pci_dev(dev); \ | ||
44 | struct device_node *dn = pci_device_to_OF_node(pdev); \ | ||
45 | struct pci_dn *pdn; \ | ||
46 | \ | ||
47 | if (!dn || PCI_DN(dn) == NULL) \ | ||
48 | return 0; \ | ||
49 | \ | ||
50 | pdn = PCI_DN(dn); \ | ||
51 | return sprintf(buf, _format "\n", pdn->_memb); \ | ||
52 | } \ | ||
53 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); | ||
54 | |||
55 | |||
56 | EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); | ||
57 | EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); | ||
58 | EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); | ||
59 | EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); | ||
60 | EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); | ||
61 | EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); | ||
62 | |||
63 | void eeh_sysfs_add_device(struct pci_dev *pdev) | ||
64 | { | ||
65 | int rc=0; | ||
66 | |||
67 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); | ||
68 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); | ||
69 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | ||
70 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_check_count); | ||
71 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_false_positives); | ||
72 | rc += device_create_file(&pdev->dev, &dev_attr_eeh_freeze_count); | ||
73 | |||
74 | if (rc) | ||
75 | printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); | ||
76 | } | ||
77 | |||
78 | void eeh_sysfs_remove_device(struct pci_dev *pdev) | ||
79 | { | ||
80 | device_remove_file(&pdev->dev, &dev_attr_eeh_mode); | ||
81 | device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); | ||
82 | device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); | ||
83 | device_remove_file(&pdev->dev, &dev_attr_eeh_check_count); | ||
84 | device_remove_file(&pdev->dev, &dev_attr_eeh_false_positives); | ||
85 | device_remove_file(&pdev->dev, &dev_attr_eeh_freeze_count); | ||
86 | } | ||
87 | |||
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 362dfbc260a6..8cc6eeeaae2f 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -373,12 +373,23 @@ static void pSeries_lpar_hptab_clear(void) | |||
373 | { | 373 | { |
374 | unsigned long size_bytes = 1UL << ppc64_pft_size; | 374 | unsigned long size_bytes = 1UL << ppc64_pft_size; |
375 | unsigned long hpte_count = size_bytes >> 4; | 375 | unsigned long hpte_count = size_bytes >> 4; |
376 | unsigned long dummy1, dummy2; | 376 | unsigned long dummy1, dummy2, dword0; |
377 | long lpar_rc; | ||
377 | int i; | 378 | int i; |
378 | 379 | ||
379 | /* TODO: Use bulk call */ | 380 | /* TODO: Use bulk call */ |
380 | for (i = 0; i < hpte_count; i++) | 381 | for (i = 0; i < hpte_count; i++) { |
381 | plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2); | 382 | /* dont remove HPTEs with VRMA mappings */ |
383 | lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG, | ||
384 | &dummy1, &dummy2); | ||
385 | if (lpar_rc == H_NOT_FOUND) { | ||
386 | lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1); | ||
387 | if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK) | ||
388 | != HPTE_V_VRMA_MASK)) | ||
389 | /* Can be hpte for 1TB Seg. So remove it */ | ||
390 | plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2); | ||
391 | } | ||
392 | } | ||
382 | } | 393 | } |
383 | 394 | ||
384 | /* | 395 | /* |
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index ffaf6c5c517b..47f0e0857f0e 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -110,8 +110,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | } | 112 | } |
113 | |||
114 | eeh_add_device_tree_late(bus); | ||
115 | } | 113 | } |
116 | EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); | 114 | EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); |
117 | 115 | ||
@@ -139,6 +137,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev) | |||
139 | 137 | ||
140 | /* Make the discovered devices available */ | 138 | /* Make the discovered devices available */ |
141 | pci_bus_add_devices(child_bus); | 139 | pci_bus_add_devices(child_bus); |
140 | |||
141 | eeh_add_device_tree_late(child_bus); | ||
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
144 | 144 | ||
@@ -171,6 +171,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) | |||
171 | if (!list_empty(&bus->devices)) { | 171 | if (!list_empty(&bus->devices)) { |
172 | pcibios_fixup_new_pci_devices(bus, 0); | 172 | pcibios_fixup_new_pci_devices(bus, 0); |
173 | pci_bus_add_devices(bus); | 173 | pci_bus_add_devices(bus); |
174 | eeh_add_device_tree_late(bus); | ||
174 | } | 175 | } |
175 | } else if (mode == PCI_PROBE_NORMAL) { | 176 | } else if (mode == PCI_PROBE_NORMAL) { |
176 | /* use legacy probe */ | 177 | /* use legacy probe */ |
@@ -179,6 +180,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) | |||
179 | if (num) { | 180 | if (num) { |
180 | pcibios_fixup_new_pci_devices(bus, 1); | 181 | pcibios_fixup_new_pci_devices(bus, 1); |
181 | pci_bus_add_devices(bus); | 182 | pci_bus_add_devices(bus); |
183 | eeh_add_device_tree_late(bus); | ||
182 | } | 184 | } |
183 | 185 | ||
184 | list_for_each_entry(dev, &bus->devices, bus_list) | 186 | list_for_each_entry(dev, &bus->devices, bus_list) |
@@ -200,8 +202,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
200 | rtas_setup_phb(phb); | 202 | rtas_setup_phb(phb); |
201 | pci_process_bridge_OF_ranges(phb, dn, 0); | 203 | pci_process_bridge_OF_ranges(phb, dn, 0); |
202 | 204 | ||
203 | pci_setup_phb_io_dynamic(phb, primary); | ||
204 | |||
205 | pci_devs_phb_init_dynamic(phb); | 205 | pci_devs_phb_init_dynamic(phb); |
206 | 206 | ||
207 | if (dn->child) | 207 | if (dn->child) |
@@ -210,6 +210,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
210 | scan_phb(phb); | 210 | scan_phb(phb); |
211 | pcibios_fixup_new_pci_devices(phb->bus, 0); | 211 | pcibios_fixup_new_pci_devices(phb->bus, 0); |
212 | pci_bus_add_devices(phb->bus); | 212 | pci_bus_add_devices(phb->bus); |
213 | eeh_add_device_tree_late(phb->bus); | ||
213 | 214 | ||
214 | return phb; | 215 | return phb; |
215 | } | 216 | } |
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 2e4d10c9eea8..d003c80fa31d 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h | |||
@@ -108,6 +108,21 @@ static inline long plpar_pte_read(unsigned long flags, unsigned long ptex, | |||
108 | return rc; | 108 | return rc; |
109 | } | 109 | } |
110 | 110 | ||
111 | /* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */ | ||
112 | static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, | ||
113 | unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) | ||
114 | { | ||
115 | long rc; | ||
116 | unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; | ||
117 | |||
118 | rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex); | ||
119 | |||
120 | *old_pteh_ret = retbuf[0]; | ||
121 | *old_ptel_ret = retbuf[1]; | ||
122 | |||
123 | return rc; | ||
124 | } | ||
125 | |||
111 | static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, | 126 | static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, |
112 | unsigned long avpn) | 127 | unsigned long avpn) |
113 | { | 128 | { |
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 2729d559fd91..61e19f78b923 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -33,6 +33,8 @@ static inline void setup_kexec_cpu_down_xics(void) { } | |||
33 | static inline void setup_kexec_cpu_down_mpic(void) { } | 33 | static inline void setup_kexec_cpu_down_mpic(void) { } |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | extern void pSeries_final_fixup(void); | ||
37 | |||
36 | /* Poweron flag used for enabling auto ups restart */ | 38 | /* Poweron flag used for enabling auto ups restart */ |
37 | extern unsigned long rtas_poweron_auto; | 39 | extern unsigned long rtas_poweron_auto; |
38 | 40 | ||
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 5aa97aff3391..c02f8742c54d 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -123,7 +123,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist | |||
123 | strcpy(np->full_name, path); | 123 | strcpy(np->full_name, path); |
124 | 124 | ||
125 | np->properties = proplist; | 125 | np->properties = proplist; |
126 | OF_MARK_DYNAMIC(np); | 126 | of_node_set_flag(np, OF_DYNAMIC); |
127 | kref_init(&np->kref); | 127 | kref_init(&np->kref); |
128 | 128 | ||
129 | np->parent = derive_parent(path); | 129 | np->parent = derive_parent(path); |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 470db6efaeb6..de6c2efd0479 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -399,6 +399,7 @@ static void pseries_dedicated_idle_sleep(void) | |||
399 | * a good time to find other work to dispatch. | 399 | * a good time to find other work to dispatch. |
400 | */ | 400 | */ |
401 | get_lppaca()->idle = 1; | 401 | get_lppaca()->idle = 1; |
402 | get_lppaca()->donate_dedicated_cpu = 1; | ||
402 | 403 | ||
403 | /* | 404 | /* |
404 | * We come in with interrupts disabled, and need_resched() | 405 | * We come in with interrupts disabled, and need_resched() |
@@ -431,6 +432,7 @@ static void pseries_dedicated_idle_sleep(void) | |||
431 | 432 | ||
432 | out: | 433 | out: |
433 | HMT_medium(); | 434 | HMT_medium(); |
435 | get_lppaca()->donate_dedicated_cpu = 0; | ||
434 | get_lppaca()->idle = 0; | 436 | get_lppaca()->idle = 0; |
435 | } | 437 | } |
436 | 438 | ||
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index f1df942072bb..5bd90a7eb763 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -156,9 +156,9 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) | |||
156 | 156 | ||
157 | 157 | ||
158 | #ifdef CONFIG_SMP | 158 | #ifdef CONFIG_SMP |
159 | static int get_irq_server(unsigned int virq) | 159 | static int get_irq_server(unsigned int virq, unsigned int strict_check) |
160 | { | 160 | { |
161 | unsigned int server; | 161 | int server; |
162 | /* For the moment only implement delivery to all cpus or one cpu */ | 162 | /* For the moment only implement delivery to all cpus or one cpu */ |
163 | cpumask_t cpumask = irq_desc[virq].affinity; | 163 | cpumask_t cpumask = irq_desc[virq].affinity; |
164 | cpumask_t tmp = CPU_MASK_NONE; | 164 | cpumask_t tmp = CPU_MASK_NONE; |
@@ -166,22 +166,25 @@ static int get_irq_server(unsigned int virq) | |||
166 | if (!distribute_irqs) | 166 | if (!distribute_irqs) |
167 | return default_server; | 167 | return default_server; |
168 | 168 | ||
169 | if (cpus_equal(cpumask, CPU_MASK_ALL)) { | 169 | if (!cpus_equal(cpumask, CPU_MASK_ALL)) { |
170 | server = default_distrib_server; | ||
171 | } else { | ||
172 | cpus_and(tmp, cpu_online_map, cpumask); | 170 | cpus_and(tmp, cpu_online_map, cpumask); |
173 | 171 | ||
174 | if (cpus_empty(tmp)) | 172 | server = first_cpu(tmp); |
175 | server = default_distrib_server; | 173 | |
176 | else | 174 | if (server < NR_CPUS) |
177 | server = get_hard_smp_processor_id(first_cpu(tmp)); | 175 | return get_hard_smp_processor_id(server); |
176 | |||
177 | if (strict_check) | ||
178 | return -1; | ||
178 | } | 179 | } |
179 | 180 | ||
180 | return server; | 181 | if (cpus_equal(cpu_online_map, cpu_present_map)) |
182 | return default_distrib_server; | ||
181 | 183 | ||
184 | return default_server; | ||
182 | } | 185 | } |
183 | #else | 186 | #else |
184 | static int get_irq_server(unsigned int virq) | 187 | static int get_irq_server(unsigned int virq, unsigned int strict_check) |
185 | { | 188 | { |
186 | return default_server; | 189 | return default_server; |
187 | } | 190 | } |
@@ -192,7 +195,7 @@ static void xics_unmask_irq(unsigned int virq) | |||
192 | { | 195 | { |
193 | unsigned int irq; | 196 | unsigned int irq; |
194 | int call_status; | 197 | int call_status; |
195 | unsigned int server; | 198 | int server; |
196 | 199 | ||
197 | pr_debug("xics: unmask virq %d\n", virq); | 200 | pr_debug("xics: unmask virq %d\n", virq); |
198 | 201 | ||
@@ -201,7 +204,7 @@ static void xics_unmask_irq(unsigned int virq) | |||
201 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) | 204 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) |
202 | return; | 205 | return; |
203 | 206 | ||
204 | server = get_irq_server(virq); | 207 | server = get_irq_server(virq, 0); |
205 | 208 | ||
206 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, | 209 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, |
207 | DEFAULT_PRIORITY); | 210 | DEFAULT_PRIORITY); |
@@ -398,8 +401,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
398 | unsigned int irq; | 401 | unsigned int irq; |
399 | int status; | 402 | int status; |
400 | int xics_status[2]; | 403 | int xics_status[2]; |
401 | unsigned long newmask; | 404 | int irq_server; |
402 | cpumask_t tmp = CPU_MASK_NONE; | ||
403 | 405 | ||
404 | irq = (unsigned int)irq_map[virq].hwirq; | 406 | irq = (unsigned int)irq_map[virq].hwirq; |
405 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) | 407 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) |
@@ -413,18 +415,21 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
413 | return; | 415 | return; |
414 | } | 416 | } |
415 | 417 | ||
416 | /* For the moment only implement delivery to all cpus or one cpu */ | 418 | /* |
417 | if (cpus_equal(cpumask, CPU_MASK_ALL)) { | 419 | * For the moment only implement delivery to all cpus or one cpu. |
418 | newmask = default_distrib_server; | 420 | * Get current irq_server for the given irq |
419 | } else { | 421 | */ |
420 | cpus_and(tmp, cpu_online_map, cpumask); | 422 | irq_server = get_irq_server(irq, 1); |
421 | if (cpus_empty(tmp)) | 423 | if (irq_server == -1) { |
422 | return; | 424 | char cpulist[128]; |
423 | newmask = get_hard_smp_processor_id(first_cpu(tmp)); | 425 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); |
426 | printk(KERN_WARNING "xics_set_affinity: No online cpus in " | ||
427 | "the mask %s for irq %d\n", cpulist, virq); | ||
428 | return; | ||
424 | } | 429 | } |
425 | 430 | ||
426 | status = rtas_call(ibm_set_xive, 3, 1, NULL, | 431 | status = rtas_call(ibm_set_xive, 3, 1, NULL, |
427 | irq, newmask, xics_status[1]); | 432 | irq, irq_server, xics_status[1]); |
428 | 433 | ||
429 | if (status) { | 434 | if (status) { |
430 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " | 435 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " |