diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
commit | c324b44c34050cf2a9b58830e11c974806bd85d8 (patch) | |
tree | 3ac45a783221283925cd698334a8f5e7dd4c1df8 /arch/ia64/sn/kernel | |
parent | 2fcf522509cceea524b6e7ece8fd6759b682175a (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'arch/ia64/sn/kernel')
-rw-r--r-- | arch/ia64/sn/kernel/bte.c | 83 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/huberror.c | 2 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/io_init.c | 37 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/irq.c | 75 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/setup.c | 7 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/ptc_deadlock.S | 13 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn2_smp.c | 256 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_hwperf.c | 313 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 4 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/sn2/timer_interrupt.c | 22 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/tiocx.c | 2 |
11 files changed, 642 insertions, 172 deletions
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 647deae9bfcd..45854c637e9c 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c | |||
@@ -29,16 +29,30 @@ | |||
29 | 29 | ||
30 | /* two interfaces on two btes */ | 30 | /* two interfaces on two btes */ |
31 | #define MAX_INTERFACES_TO_TRY 4 | 31 | #define MAX_INTERFACES_TO_TRY 4 |
32 | #define MAX_NODES_TO_TRY 2 | ||
32 | 33 | ||
33 | static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) | 34 | static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) |
34 | { | 35 | { |
35 | nodepda_t *tmp_nodepda; | 36 | nodepda_t *tmp_nodepda; |
36 | 37 | ||
38 | if (nasid_to_cnodeid(nasid) == -1) | ||
39 | return (struct bteinfo_s *)NULL;; | ||
40 | |||
37 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); | 41 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); |
38 | return &tmp_nodepda->bte_if[interface]; | 42 | return &tmp_nodepda->bte_if[interface]; |
39 | 43 | ||
40 | } | 44 | } |
41 | 45 | ||
46 | static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode) | ||
47 | { | ||
48 | if (is_shub2()) { | ||
49 | BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24))); | ||
50 | } else { | ||
51 | BTE_LNSTAT_STORE(bte, len); | ||
52 | BTE_CTRL_STORE(bte, mode); | ||
53 | } | ||
54 | } | ||
55 | |||
42 | /************************************************************************ | 56 | /************************************************************************ |
43 | * Block Transfer Engine copy related functions. | 57 | * Block Transfer Engine copy related functions. |
44 | * | 58 | * |
@@ -67,13 +81,15 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) | |||
67 | { | 81 | { |
68 | u64 transfer_size; | 82 | u64 transfer_size; |
69 | u64 transfer_stat; | 83 | u64 transfer_stat; |
84 | u64 notif_phys_addr; | ||
70 | struct bteinfo_s *bte; | 85 | struct bteinfo_s *bte; |
71 | bte_result_t bte_status; | 86 | bte_result_t bte_status; |
72 | unsigned long irq_flags; | 87 | unsigned long irq_flags; |
73 | unsigned long itc_end = 0; | 88 | unsigned long itc_end = 0; |
74 | struct bteinfo_s *btes_to_try[MAX_INTERFACES_TO_TRY]; | 89 | int nasid_to_try[MAX_NODES_TO_TRY]; |
75 | int bte_if_index; | 90 | int my_nasid = get_nasid(); |
76 | int bte_pri, bte_sec; | 91 | int bte_if_index, nasid_index; |
92 | int bte_first, btes_per_node = BTES_PER_NODE; | ||
77 | 93 | ||
78 | BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", | 94 | BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", |
79 | src, dest, len, mode, notification)); | 95 | src, dest, len, mode, notification)); |
@@ -86,36 +102,26 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) | |||
86 | (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)); | 102 | (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)); |
87 | BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT))); | 103 | BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT))); |
88 | 104 | ||
89 | /* CPU 0 (per node) tries bte0 first, CPU 1 try bte1 first */ | 105 | /* |
90 | if (cpuid_to_subnode(smp_processor_id()) == 0) { | 106 | * Start with interface corresponding to cpu number |
91 | bte_pri = 0; | 107 | */ |
92 | bte_sec = 1; | 108 | bte_first = raw_smp_processor_id() % btes_per_node; |
93 | } else { | ||
94 | bte_pri = 1; | ||
95 | bte_sec = 0; | ||
96 | } | ||
97 | 109 | ||
98 | if (mode & BTE_USE_DEST) { | 110 | if (mode & BTE_USE_DEST) { |
99 | /* try remote then local */ | 111 | /* try remote then local */ |
100 | btes_to_try[0] = bte_if_on_node(NASID_GET(dest), bte_pri); | 112 | nasid_to_try[0] = NASID_GET(dest); |
101 | btes_to_try[1] = bte_if_on_node(NASID_GET(dest), bte_sec); | ||
102 | if (mode & BTE_USE_ANY) { | 113 | if (mode & BTE_USE_ANY) { |
103 | btes_to_try[2] = bte_if_on_node(get_nasid(), bte_pri); | 114 | nasid_to_try[1] = my_nasid; |
104 | btes_to_try[3] = bte_if_on_node(get_nasid(), bte_sec); | ||
105 | } else { | 115 | } else { |
106 | btes_to_try[2] = NULL; | 116 | nasid_to_try[1] = (int)NULL; |
107 | btes_to_try[3] = NULL; | ||
108 | } | 117 | } |
109 | } else { | 118 | } else { |
110 | /* try local then remote */ | 119 | /* try local then remote */ |
111 | btes_to_try[0] = bte_if_on_node(get_nasid(), bte_pri); | 120 | nasid_to_try[0] = my_nasid; |
112 | btes_to_try[1] = bte_if_on_node(get_nasid(), bte_sec); | ||
113 | if (mode & BTE_USE_ANY) { | 121 | if (mode & BTE_USE_ANY) { |
114 | btes_to_try[2] = bte_if_on_node(NASID_GET(dest), bte_pri); | 122 | nasid_to_try[1] = NASID_GET(dest); |
115 | btes_to_try[3] = bte_if_on_node(NASID_GET(dest), bte_sec); | ||
116 | } else { | 123 | } else { |
117 | btes_to_try[2] = NULL; | 124 | nasid_to_try[1] = (int)NULL; |
118 | btes_to_try[3] = NULL; | ||
119 | } | 125 | } |
120 | } | 126 | } |
121 | 127 | ||
@@ -123,11 +129,12 @@ retry_bteop: | |||
123 | do { | 129 | do { |
124 | local_irq_save(irq_flags); | 130 | local_irq_save(irq_flags); |
125 | 131 | ||
126 | bte_if_index = 0; | 132 | bte_if_index = bte_first; |
133 | nasid_index = 0; | ||
127 | 134 | ||
128 | /* Attempt to lock one of the BTE interfaces. */ | 135 | /* Attempt to lock one of the BTE interfaces. */ |
129 | while (bte_if_index < MAX_INTERFACES_TO_TRY) { | 136 | while (nasid_index < MAX_NODES_TO_TRY) { |
130 | bte = btes_to_try[bte_if_index++]; | 137 | bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index); |
131 | 138 | ||
132 | if (bte == NULL) { | 139 | if (bte == NULL) { |
133 | continue; | 140 | continue; |
@@ -143,6 +150,15 @@ retry_bteop: | |||
143 | break; | 150 | break; |
144 | } | 151 | } |
145 | } | 152 | } |
153 | |||
154 | bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */ | ||
155 | if (bte_if_index == bte_first) { | ||
156 | /* | ||
157 | * We've tried all interfaces on this node | ||
158 | */ | ||
159 | nasid_index++; | ||
160 | } | ||
161 | |||
146 | bte = NULL; | 162 | bte = NULL; |
147 | } | 163 | } |
148 | 164 | ||
@@ -169,7 +185,13 @@ retry_bteop: | |||
169 | 185 | ||
170 | /* Initialize the notification to a known value. */ | 186 | /* Initialize the notification to a known value. */ |
171 | *bte->most_rcnt_na = BTE_WORD_BUSY; | 187 | *bte->most_rcnt_na = BTE_WORD_BUSY; |
188 | notif_phys_addr = TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)); | ||
172 | 189 | ||
190 | if (is_shub2()) { | ||
191 | src = SH2_TIO_PHYS_TO_DMA(src); | ||
192 | dest = SH2_TIO_PHYS_TO_DMA(dest); | ||
193 | notif_phys_addr = SH2_TIO_PHYS_TO_DMA(notif_phys_addr); | ||
194 | } | ||
173 | /* Set the source and destination registers */ | 195 | /* Set the source and destination registers */ |
174 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); | 196 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); |
175 | BTE_SRC_STORE(bte, TO_PHYS(src)); | 197 | BTE_SRC_STORE(bte, TO_PHYS(src)); |
@@ -177,14 +199,12 @@ retry_bteop: | |||
177 | BTE_DEST_STORE(bte, TO_PHYS(dest)); | 199 | BTE_DEST_STORE(bte, TO_PHYS(dest)); |
178 | 200 | ||
179 | /* Set the notification register */ | 201 | /* Set the notification register */ |
180 | BTE_PRINTKV(("IBNA = 0x%lx)\n", | 202 | BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr)); |
181 | TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))); | 203 | BTE_NOTIF_STORE(bte, notif_phys_addr); |
182 | BTE_NOTIF_STORE(bte, | ||
183 | TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))); | ||
184 | 204 | ||
185 | /* Initiate the transfer */ | 205 | /* Initiate the transfer */ |
186 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); | 206 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); |
187 | BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode)); | 207 | bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode)); |
188 | 208 | ||
189 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); | 209 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); |
190 | 210 | ||
@@ -195,6 +215,7 @@ retry_bteop: | |||
195 | } | 215 | } |
196 | 216 | ||
197 | while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) { | 217 | while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) { |
218 | cpu_relax(); | ||
198 | if (ia64_get_itc() > itc_end) { | 219 | if (ia64_get_itc() > itc_end) { |
199 | BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n", | 220 | BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n", |
200 | NASID_GET(bte->bte_base_addr), bte->bte_num, | 221 | NASID_GET(bte->bte_base_addr), bte->bte_num, |
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index 5c39b43ba3c0..5c5eb01c50f0 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c | |||
@@ -76,7 +76,7 @@ void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum) | |||
76 | */ | 76 | */ |
77 | REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); | 77 | REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); |
78 | while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND) | 78 | while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND) |
79 | udelay(1); | 79 | cpu_relax(); |
80 | 80 | ||
81 | } | 81 | } |
82 | 82 | ||
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 414cdf2e3c96..906622d9f933 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/sn/simulator.h> | 18 | #include <asm/sn/simulator.h> |
19 | #include <asm/sn/sn_sal.h> | 19 | #include <asm/sn/sn_sal.h> |
20 | #include <asm/sn/tioca_provider.h> | 20 | #include <asm/sn/tioca_provider.h> |
21 | #include <asm/sn/tioce_provider.h> | ||
21 | #include "xtalk/hubdev.h" | 22 | #include "xtalk/hubdev.h" |
22 | #include "xtalk/xwidgetdev.h" | 23 | #include "xtalk/xwidgetdev.h" |
23 | 24 | ||
@@ -44,6 +45,9 @@ int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ | |||
44 | 45 | ||
45 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ | 46 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ |
46 | 47 | ||
48 | static int max_segment_number = 0; /* Default highest segment number */ | ||
49 | static int max_pcibus_number = 255; /* Default highest pci bus number */ | ||
50 | |||
47 | /* | 51 | /* |
48 | * Hooks and struct for unsupported pci providers | 52 | * Hooks and struct for unsupported pci providers |
49 | */ | 53 | */ |
@@ -157,13 +161,28 @@ static void sn_fixup_ionodes(void) | |||
157 | uint64_t nasid; | 161 | uint64_t nasid; |
158 | int i, widget; | 162 | int i, widget; |
159 | 163 | ||
164 | /* | ||
165 | * Get SGI Specific HUB chipset information. | ||
166 | * Inform Prom that this kernel can support domain bus numbering. | ||
167 | */ | ||
160 | for (i = 0; i < numionodes; i++) { | 168 | for (i = 0; i < numionodes; i++) { |
161 | hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); | 169 | hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); |
162 | nasid = cnodeid_to_nasid(i); | 170 | nasid = cnodeid_to_nasid(i); |
171 | hubdev->max_segment_number = 0xffffffff; | ||
172 | hubdev->max_pcibus_number = 0xff; | ||
163 | status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev)); | 173 | status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev)); |
164 | if (status) | 174 | if (status) |
165 | continue; | 175 | continue; |
166 | 176 | ||
177 | /* Save the largest Domain and pcibus numbers found. */ | ||
178 | if (hubdev->max_segment_number) { | ||
179 | /* | ||
180 | * Dealing with a Prom that supports segments. | ||
181 | */ | ||
182 | max_segment_number = hubdev->max_segment_number; | ||
183 | max_pcibus_number = hubdev->max_pcibus_number; | ||
184 | } | ||
185 | |||
167 | /* Attach the error interrupt handlers */ | 186 | /* Attach the error interrupt handlers */ |
168 | if (nasid & 1) | 187 | if (nasid & 1) |
169 | ice_error_init(hubdev); | 188 | ice_error_init(hubdev); |
@@ -230,7 +249,7 @@ void sn_pci_unfixup_slot(struct pci_dev *dev) | |||
230 | void sn_pci_fixup_slot(struct pci_dev *dev) | 249 | void sn_pci_fixup_slot(struct pci_dev *dev) |
231 | { | 250 | { |
232 | int idx; | 251 | int idx; |
233 | int segment = 0; | 252 | int segment = pci_domain_nr(dev->bus); |
234 | int status = 0; | 253 | int status = 0; |
235 | struct pcibus_bussoft *bs; | 254 | struct pcibus_bussoft *bs; |
236 | struct pci_bus *host_pci_bus; | 255 | struct pci_bus *host_pci_bus; |
@@ -283,9 +302,9 @@ void sn_pci_fixup_slot(struct pci_dev *dev) | |||
283 | * PCI host_pci_dev struct and set up host bus linkages | 302 | * PCI host_pci_dev struct and set up host bus linkages |
284 | */ | 303 | */ |
285 | 304 | ||
286 | bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32; | 305 | bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff; |
287 | devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; | 306 | devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; |
288 | host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no); | 307 | host_pci_bus = pci_find_bus(segment, bus_no); |
289 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); | 308 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); |
290 | 309 | ||
291 | SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; | 310 | SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; |
@@ -333,6 +352,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
333 | prom_bussoft_ptr = __va(prom_bussoft_ptr); | 352 | prom_bussoft_ptr = __va(prom_bussoft_ptr); |
334 | 353 | ||
335 | controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL); | 354 | controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL); |
355 | controller->segment = segment; | ||
336 | if (!controller) | 356 | if (!controller) |
337 | BUG(); | 357 | BUG(); |
338 | 358 | ||
@@ -390,7 +410,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
390 | if (controller->node >= num_online_nodes()) { | 410 | if (controller->node >= num_online_nodes()) { |
391 | struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus); | 411 | struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus); |
392 | 412 | ||
393 | printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu" | 413 | printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u" |
394 | "L_IO=%lx L_MEM=%lx BASE=%lx\n", | 414 | "L_IO=%lx L_MEM=%lx BASE=%lx\n", |
395 | b->bs_asic_type, b->bs_xid, b->bs_persist_busnum, | 415 | b->bs_asic_type, b->bs_xid, b->bs_persist_busnum, |
396 | b->bs_legacy_io, b->bs_legacy_mem, b->bs_base); | 416 | b->bs_legacy_io, b->bs_legacy_mem, b->bs_base); |
@@ -411,7 +431,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev) | |||
411 | { | 431 | { |
412 | struct sysdata_el *element; | 432 | struct sysdata_el *element; |
413 | 433 | ||
414 | element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL); | 434 | element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL); |
415 | if (!element) { | 435 | if (!element) { |
416 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); | 436 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); |
417 | return; | 437 | return; |
@@ -445,6 +465,7 @@ sn_sysdata_free_start: | |||
445 | static int __init sn_pci_init(void) | 465 | static int __init sn_pci_init(void) |
446 | { | 466 | { |
447 | int i = 0; | 467 | int i = 0; |
468 | int j = 0; | ||
448 | struct pci_dev *pci_dev = NULL; | 469 | struct pci_dev *pci_dev = NULL; |
449 | extern void sn_init_cpei_timer(void); | 470 | extern void sn_init_cpei_timer(void); |
450 | #ifdef CONFIG_PROC_FS | 471 | #ifdef CONFIG_PROC_FS |
@@ -464,6 +485,7 @@ static int __init sn_pci_init(void) | |||
464 | 485 | ||
465 | pcibr_init_provider(); | 486 | pcibr_init_provider(); |
466 | tioca_init_provider(); | 487 | tioca_init_provider(); |
488 | tioce_init_provider(); | ||
467 | 489 | ||
468 | /* | 490 | /* |
469 | * This is needed to avoid bounce limit checks in the blk layer | 491 | * This is needed to avoid bounce limit checks in the blk layer |
@@ -479,8 +501,9 @@ static int __init sn_pci_init(void) | |||
479 | #endif | 501 | #endif |
480 | 502 | ||
481 | /* busses are not known yet ... */ | 503 | /* busses are not known yet ... */ |
482 | for (i = 0; i < PCI_BUSES_TO_SCAN; i++) | 504 | for (i = 0; i <= max_segment_number; i++) |
483 | sn_pci_controller_fixup(0, i, NULL); | 505 | for (j = 0; j <= max_pcibus_number; j++) |
506 | sn_pci_controller_fixup(i, j, NULL); | ||
484 | 507 | ||
485 | /* | 508 | /* |
486 | * Generic Linux PCI Layer has created the pci_bus and pci_dev | 509 | * Generic Linux PCI Layer has created the pci_bus and pci_dev |
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 84d276a14ecb..9fc74631ba8a 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | 8 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
@@ -76,16 +76,14 @@ static void sn_enable_irq(unsigned int irq) | |||
76 | 76 | ||
77 | static void sn_ack_irq(unsigned int irq) | 77 | static void sn_ack_irq(unsigned int irq) |
78 | { | 78 | { |
79 | uint64_t event_occurred, mask = 0; | 79 | u64 event_occurred, mask = 0; |
80 | int nasid; | ||
81 | 80 | ||
82 | irq = irq & 0xff; | 81 | irq = irq & 0xff; |
83 | nasid = get_nasid(); | ||
84 | event_occurred = | 82 | event_occurred = |
85 | HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED)); | 83 | HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)); |
86 | mask = event_occurred & SH_ALL_INT_MASK; | 84 | mask = event_occurred & SH_ALL_INT_MASK; |
87 | HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), | 85 | HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), |
88 | mask); | 86 | mask); |
89 | __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); | 87 | __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); |
90 | 88 | ||
91 | move_irq(irq); | 89 | move_irq(irq); |
@@ -93,15 +91,12 @@ static void sn_ack_irq(unsigned int irq) | |||
93 | 91 | ||
94 | static void sn_end_irq(unsigned int irq) | 92 | static void sn_end_irq(unsigned int irq) |
95 | { | 93 | { |
96 | int nasid; | ||
97 | int ivec; | 94 | int ivec; |
98 | uint64_t event_occurred; | 95 | u64 event_occurred; |
99 | 96 | ||
100 | ivec = irq & 0xff; | 97 | ivec = irq & 0xff; |
101 | if (ivec == SGI_UART_VECTOR) { | 98 | if (ivec == SGI_UART_VECTOR) { |
102 | nasid = get_nasid(); | 99 | event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR (SH_EVENT_OCCURRED)); |
103 | event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR | ||
104 | (nasid, SH_EVENT_OCCURRED)); | ||
105 | /* If the UART bit is set here, we may have received an | 100 | /* If the UART bit is set here, we may have received an |
106 | * interrupt from the UART that the driver missed. To | 101 | * interrupt from the UART that the driver missed. To |
107 | * make sure, we IPI ourselves to force us to look again. | 102 | * make sure, we IPI ourselves to force us to look again. |
@@ -132,6 +127,7 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | |||
132 | int local_widget, status; | 127 | int local_widget, status; |
133 | nasid_t local_nasid; | 128 | nasid_t local_nasid; |
134 | struct sn_irq_info *new_irq_info; | 129 | struct sn_irq_info *new_irq_info; |
130 | struct sn_pcibus_provider *pci_provider; | ||
135 | 131 | ||
136 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); | 132 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); |
137 | if (new_irq_info == NULL) | 133 | if (new_irq_info == NULL) |
@@ -171,8 +167,9 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | |||
171 | new_irq_info->irq_cpuid = cpuid; | 167 | new_irq_info->irq_cpuid = cpuid; |
172 | register_intr_pda(new_irq_info); | 168 | register_intr_pda(new_irq_info); |
173 | 169 | ||
174 | if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type)) | 170 | pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; |
175 | pcibr_change_devices_irq(new_irq_info); | 171 | if (pci_provider && pci_provider->target_interrupt) |
172 | (pci_provider->target_interrupt)(new_irq_info); | ||
176 | 173 | ||
177 | spin_lock(&sn_irq_info_lock); | 174 | spin_lock(&sn_irq_info_lock); |
178 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); | 175 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); |
@@ -317,6 +314,16 @@ void sn_irq_unfixup(struct pci_dev *pci_dev) | |||
317 | pci_dev_put(pci_dev); | 314 | pci_dev_put(pci_dev); |
318 | } | 315 | } |
319 | 316 | ||
317 | static inline void | ||
318 | sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info) | ||
319 | { | ||
320 | struct sn_pcibus_provider *pci_provider; | ||
321 | |||
322 | pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type]; | ||
323 | if (pci_provider && pci_provider->force_interrupt) | ||
324 | (*pci_provider->force_interrupt)(sn_irq_info); | ||
325 | } | ||
326 | |||
320 | static void force_interrupt(int irq) | 327 | static void force_interrupt(int irq) |
321 | { | 328 | { |
322 | struct sn_irq_info *sn_irq_info; | 329 | struct sn_irq_info *sn_irq_info; |
@@ -325,11 +332,9 @@ static void force_interrupt(int irq) | |||
325 | return; | 332 | return; |
326 | 333 | ||
327 | rcu_read_lock(); | 334 | rcu_read_lock(); |
328 | list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) { | 335 | list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) |
329 | if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) && | 336 | sn_call_force_intr_provider(sn_irq_info); |
330 | (sn_irq_info->irq_bridge != NULL)) | 337 | |
331 | pcibr_force_interrupt(sn_irq_info); | ||
332 | } | ||
333 | rcu_read_unlock(); | 338 | rcu_read_unlock(); |
334 | } | 339 | } |
335 | 340 | ||
@@ -351,6 +356,14 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) | |||
351 | struct pcidev_info *pcidev_info; | 356 | struct pcidev_info *pcidev_info; |
352 | struct pcibus_info *pcibus_info; | 357 | struct pcibus_info *pcibus_info; |
353 | 358 | ||
359 | /* | ||
360 | * Bridge types attached to TIO (anything but PIC) do not need this WAR | ||
361 | * since they do not target Shub II interrupt registers. If that | ||
362 | * ever changes, this check needs to accomodate. | ||
363 | */ | ||
364 | if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC) | ||
365 | return; | ||
366 | |||
354 | pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | 367 | pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; |
355 | if (!pcidev_info) | 368 | if (!pcidev_info) |
356 | return; | 369 | return; |
@@ -377,16 +390,12 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) | |||
377 | break; | 390 | break; |
378 | } | 391 | } |
379 | if (!test_bit(irr_bit, &irr_reg)) { | 392 | if (!test_bit(irr_bit, &irr_reg)) { |
380 | if (!test_bit(irq, pda->sn_soft_irr)) { | 393 | if (!test_bit(irq, pda->sn_in_service_ivecs)) { |
381 | if (!test_bit(irq, pda->sn_in_service_ivecs)) { | 394 | regval &= 0xff; |
382 | regval &= 0xff; | 395 | if (sn_irq_info->irq_int_bit & regval & |
383 | if (sn_irq_info->irq_int_bit & regval & | 396 | sn_irq_info->irq_last_intr) { |
384 | sn_irq_info->irq_last_intr) { | 397 | regval &= ~(sn_irq_info->irq_int_bit & regval); |
385 | regval &= | 398 | sn_call_force_intr_provider(sn_irq_info); |
386 | ~(sn_irq_info-> | ||
387 | irq_int_bit & regval); | ||
388 | pcibr_force_interrupt(sn_irq_info); | ||
389 | } | ||
390 | } | 399 | } |
391 | } | 400 | } |
392 | } | 401 | } |
@@ -404,13 +413,7 @@ void sn_lb_int_war_check(void) | |||
404 | rcu_read_lock(); | 413 | rcu_read_lock(); |
405 | for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) { | 414 | for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) { |
406 | list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) { | 415 | list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) { |
407 | /* | 416 | sn_check_intr(i, sn_irq_info); |
408 | * Only call for PCI bridges that are fully | ||
409 | * initialized. | ||
410 | */ | ||
411 | if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) && | ||
412 | (sn_irq_info->irq_bridge != NULL)) | ||
413 | sn_check_intr(i, sn_irq_info); | ||
414 | } | 417 | } |
415 | } | 418 | } |
416 | rcu_read_unlock(); | 419 | rcu_read_unlock(); |
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 7c7fe441d623..a594aca959e6 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c | |||
@@ -80,8 +80,6 @@ EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid); | |||
80 | DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda); | 80 | DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda); |
81 | EXPORT_PER_CPU_SYMBOL(__sn_nodepda); | 81 | EXPORT_PER_CPU_SYMBOL(__sn_nodepda); |
82 | 82 | ||
83 | partid_t sn_partid = -1; | ||
84 | EXPORT_SYMBOL(sn_partid); | ||
85 | char sn_system_serial_number_string[128]; | 83 | char sn_system_serial_number_string[128]; |
86 | EXPORT_SYMBOL(sn_system_serial_number_string); | 84 | EXPORT_SYMBOL(sn_system_serial_number_string); |
87 | u64 sn_partition_serial_number; | 85 | u64 sn_partition_serial_number; |
@@ -403,6 +401,7 @@ static void __init sn_init_pdas(char **cmdline_p) | |||
403 | memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); | 401 | memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); |
404 | memset(nodepdaindr[cnode]->phys_cpuid, -1, | 402 | memset(nodepdaindr[cnode]->phys_cpuid, -1, |
405 | sizeof(nodepdaindr[cnode]->phys_cpuid)); | 403 | sizeof(nodepdaindr[cnode]->phys_cpuid)); |
404 | spin_lock_init(&nodepdaindr[cnode]->ptc_lock); | ||
406 | } | 405 | } |
407 | 406 | ||
408 | /* | 407 | /* |
@@ -532,8 +531,8 @@ void __init sn_cpu_init(void) | |||
532 | */ | 531 | */ |
533 | { | 532 | { |
534 | u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0}; | 533 | u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0}; |
535 | u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1, | 534 | u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2, |
536 | SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3}; | 535 | SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3}; |
537 | u64 *pio; | 536 | u64 *pio; |
538 | pio = is_shub1() ? pio1 : pio2; | 537 | pio = is_shub1() ? pio1 : pio2; |
539 | pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]); | 538 | pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]); |
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S index 96cb71d15682..3fa95065a446 100644 --- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S +++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <asm/types.h> | 9 | #include <asm/types.h> |
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | #define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT | 12 | #define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT |
13 | #define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK | 13 | #define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK |
14 | #define ALIAS_OFFSET (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0) | 14 | #define ALIAS_OFFSET 8 |
15 | 15 | ||
16 | 16 | ||
17 | .global sn2_ptc_deadlock_recovery_core | 17 | .global sn2_ptc_deadlock_recovery_core |
@@ -36,13 +36,15 @@ sn2_ptc_deadlock_recovery_core: | |||
36 | extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address | 36 | extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address |
37 | dep piowcphy=-1,piowcphy,63,1 | 37 | dep piowcphy=-1,piowcphy,63,1 |
38 | movl mask=WRITECOUNTMASK | 38 | movl mask=WRITECOUNTMASK |
39 | mov r8=r0 | ||
39 | 40 | ||
40 | 1: | 41 | 1: |
41 | add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register | 42 | add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register |
42 | mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR | 43 | ;; |
43 | st8.rel [scr2]=scr1;; | 44 | ld8.acq scr1=[scr2];; |
44 | 45 | ||
45 | 5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. | 46 | 5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. |
47 | hint @pause | ||
46 | and scr2=scr1,mask;; // mask of writecount bits | 48 | and scr2=scr1,mask;; // mask of writecount bits |
47 | cmp.ne p6,p0=zeroval,scr2 | 49 | cmp.ne p6,p0=zeroval,scr2 |
48 | (p6) br.cond.sptk 5b | 50 | (p6) br.cond.sptk 5b |
@@ -57,6 +59,7 @@ sn2_ptc_deadlock_recovery_core: | |||
57 | st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. | 59 | st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. |
58 | 60 | ||
59 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. | 61 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. |
62 | hint @pause | ||
60 | and scr2=scr1,mask;; // mask of writecount bits | 63 | and scr2=scr1,mask;; // mask of writecount bits |
61 | cmp.ne p6,p0=zeroval,scr2 | 64 | cmp.ne p6,p0=zeroval,scr2 |
62 | (p6) br.cond.sptk 5b;; | 65 | (p6) br.cond.sptk 5b;; |
@@ -67,6 +70,7 @@ sn2_ptc_deadlock_recovery_core: | |||
67 | (p7) st8.rel [ptc1]=data1;; // Now write PTC1. | 70 | (p7) st8.rel [ptc1]=data1;; // Now write PTC1. |
68 | 71 | ||
69 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. | 72 | 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. |
73 | hint @pause | ||
70 | and scr2=scr1,mask;; // mask of writecount bits | 74 | and scr2=scr1,mask;; // mask of writecount bits |
71 | cmp.ne p6,p0=zeroval,scr2 | 75 | cmp.ne p6,p0=zeroval,scr2 |
72 | (p6) br.cond.sptk 5b | 76 | (p6) br.cond.sptk 5b |
@@ -77,6 +81,7 @@ sn2_ptc_deadlock_recovery_core: | |||
77 | srlz.i;; | 81 | srlz.i;; |
78 | ////////////// END PHYSICAL MODE //////////////////// | 82 | ////////////// END PHYSICAL MODE //////////////////// |
79 | 83 | ||
84 | (p8) add r8=1,r8 | ||
80 | (p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. | 85 | (p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred. |
81 | 86 | ||
82 | br.ret.sptk rp | 87 | br.ret.sptk rp |
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 7af05a7ac743..0a4ee50c302f 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 8 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/nodemask.h> | 22 | #include <linux/nodemask.h> |
23 | #include <linux/proc_fs.h> | ||
24 | #include <linux/seq_file.h> | ||
23 | 25 | ||
24 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
25 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
@@ -39,12 +41,120 @@ | |||
39 | #include <asm/sn/nodepda.h> | 41 | #include <asm/sn/nodepda.h> |
40 | #include <asm/sn/rw_mmr.h> | 42 | #include <asm/sn/rw_mmr.h> |
41 | 43 | ||
42 | void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0, | 44 | DEFINE_PER_CPU(struct ptc_stats, ptcstats); |
43 | volatile unsigned long *, unsigned long data1); | 45 | DECLARE_PER_CPU(struct ptc_stats, ptcstats); |
44 | 46 | ||
45 | static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock); | 47 | static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock); |
46 | 48 | ||
47 | static unsigned long sn2_ptc_deadlock_count; | 49 | void sn2_ptc_deadlock_recovery(short *, short, int, volatile unsigned long *, unsigned long data0, |
50 | volatile unsigned long *, unsigned long data1); | ||
51 | |||
52 | #ifdef DEBUG_PTC | ||
53 | /* | ||
54 | * ptctest: | ||
55 | * | ||
56 | * xyz - 3 digit hex number: | ||
57 | * x - Force PTC purges to use shub: | ||
58 | * 0 - no force | ||
59 | * 1 - force | ||
60 | * y - interupt enable | ||
61 | * 0 - disable interrupts | ||
62 | * 1 - leave interuupts enabled | ||
63 | * z - type of lock: | ||
64 | * 0 - global lock | ||
65 | * 1 - node local lock | ||
66 | * 2 - no lock | ||
67 | * | ||
68 | * Note: on shub1, only ptctest == 0 is supported. Don't try other values! | ||
69 | */ | ||
70 | |||
71 | static unsigned int sn2_ptctest = 0; | ||
72 | |||
73 | static int __init ptc_test(char *str) | ||
74 | { | ||
75 | get_option(&str, &sn2_ptctest); | ||
76 | return 1; | ||
77 | } | ||
78 | __setup("ptctest=", ptc_test); | ||
79 | |||
80 | static inline int ptc_lock(unsigned long *flagp) | ||
81 | { | ||
82 | unsigned long opt = sn2_ptctest & 255; | ||
83 | |||
84 | switch (opt) { | ||
85 | case 0x00: | ||
86 | spin_lock_irqsave(&sn2_global_ptc_lock, *flagp); | ||
87 | break; | ||
88 | case 0x01: | ||
89 | spin_lock_irqsave(&sn_nodepda->ptc_lock, *flagp); | ||
90 | break; | ||
91 | case 0x02: | ||
92 | local_irq_save(*flagp); | ||
93 | break; | ||
94 | case 0x10: | ||
95 | spin_lock(&sn2_global_ptc_lock); | ||
96 | break; | ||
97 | case 0x11: | ||
98 | spin_lock(&sn_nodepda->ptc_lock); | ||
99 | break; | ||
100 | case 0x12: | ||
101 | break; | ||
102 | default: | ||
103 | BUG(); | ||
104 | } | ||
105 | return opt; | ||
106 | } | ||
107 | |||
108 | static inline void ptc_unlock(unsigned long flags, int opt) | ||
109 | { | ||
110 | switch (opt) { | ||
111 | case 0x00: | ||
112 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | ||
113 | break; | ||
114 | case 0x01: | ||
115 | spin_unlock_irqrestore(&sn_nodepda->ptc_lock, flags); | ||
116 | break; | ||
117 | case 0x02: | ||
118 | local_irq_restore(flags); | ||
119 | break; | ||
120 | case 0x10: | ||
121 | spin_unlock(&sn2_global_ptc_lock); | ||
122 | break; | ||
123 | case 0x11: | ||
124 | spin_unlock(&sn_nodepda->ptc_lock); | ||
125 | break; | ||
126 | case 0x12: | ||
127 | break; | ||
128 | default: | ||
129 | BUG(); | ||
130 | } | ||
131 | } | ||
132 | #else | ||
133 | |||
134 | #define sn2_ptctest 0 | ||
135 | |||
136 | static inline int ptc_lock(unsigned long *flagp) | ||
137 | { | ||
138 | spin_lock_irqsave(&sn2_global_ptc_lock, *flagp); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static inline void ptc_unlock(unsigned long flags, int opt) | ||
143 | { | ||
144 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | struct ptc_stats { | ||
149 | unsigned long ptc_l; | ||
150 | unsigned long change_rid; | ||
151 | unsigned long shub_ptc_flushes; | ||
152 | unsigned long nodes_flushed; | ||
153 | unsigned long deadlocks; | ||
154 | unsigned long lock_itc_clocks; | ||
155 | unsigned long shub_itc_clocks; | ||
156 | unsigned long shub_itc_clocks_max; | ||
157 | }; | ||
48 | 158 | ||
49 | static inline unsigned long wait_piowc(void) | 159 | static inline unsigned long wait_piowc(void) |
50 | { | 160 | { |
@@ -89,9 +199,9 @@ void | |||
89 | sn2_global_tlb_purge(unsigned long start, unsigned long end, | 199 | sn2_global_tlb_purge(unsigned long start, unsigned long end, |
90 | unsigned long nbits) | 200 | unsigned long nbits) |
91 | { | 201 | { |
92 | int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; | 202 | int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; |
93 | volatile unsigned long *ptc0, *ptc1; | 203 | volatile unsigned long *ptc0, *ptc1; |
94 | unsigned long flags = 0, data0 = 0, data1 = 0; | 204 | unsigned long itc, itc2, flags, data0 = 0, data1 = 0; |
95 | struct mm_struct *mm = current->active_mm; | 205 | struct mm_struct *mm = current->active_mm; |
96 | short nasids[MAX_NUMNODES], nix; | 206 | short nasids[MAX_NUMNODES], nix; |
97 | nodemask_t nodes_flushed; | 207 | nodemask_t nodes_flushed; |
@@ -114,16 +224,19 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
114 | start += (1UL << nbits); | 224 | start += (1UL << nbits); |
115 | } while (start < end); | 225 | } while (start < end); |
116 | ia64_srlz_i(); | 226 | ia64_srlz_i(); |
227 | __get_cpu_var(ptcstats).ptc_l++; | ||
117 | preempt_enable(); | 228 | preempt_enable(); |
118 | return; | 229 | return; |
119 | } | 230 | } |
120 | 231 | ||
121 | if (atomic_read(&mm->mm_users) == 1) { | 232 | if (atomic_read(&mm->mm_users) == 1) { |
122 | flush_tlb_mm(mm); | 233 | flush_tlb_mm(mm); |
234 | __get_cpu_var(ptcstats).change_rid++; | ||
123 | preempt_enable(); | 235 | preempt_enable(); |
124 | return; | 236 | return; |
125 | } | 237 | } |
126 | 238 | ||
239 | itc = ia64_get_itc(); | ||
127 | nix = 0; | 240 | nix = 0; |
128 | for_each_node_mask(cnode, nodes_flushed) | 241 | for_each_node_mask(cnode, nodes_flushed) |
129 | nasids[nix++] = cnodeid_to_nasid(cnode); | 242 | nasids[nix++] = cnodeid_to_nasid(cnode); |
@@ -148,7 +261,12 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
148 | 261 | ||
149 | mynasid = get_nasid(); | 262 | mynasid = get_nasid(); |
150 | 263 | ||
151 | spin_lock_irqsave(&sn2_global_ptc_lock, flags); | 264 | itc = ia64_get_itc(); |
265 | opt = ptc_lock(&flags); | ||
266 | itc2 = ia64_get_itc(); | ||
267 | __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc; | ||
268 | __get_cpu_var(ptcstats).shub_ptc_flushes++; | ||
269 | __get_cpu_var(ptcstats).nodes_flushed += nix; | ||
152 | 270 | ||
153 | do { | 271 | do { |
154 | if (shub1) | 272 | if (shub1) |
@@ -157,7 +275,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
157 | data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); | 275 | data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); |
158 | for (i = 0; i < nix; i++) { | 276 | for (i = 0; i < nix; i++) { |
159 | nasid = nasids[i]; | 277 | nasid = nasids[i]; |
160 | if (unlikely(nasid == mynasid)) { | 278 | if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) { |
161 | ia64_ptcga(start, nbits << 2); | 279 | ia64_ptcga(start, nbits << 2); |
162 | ia64_srlz_i(); | 280 | ia64_srlz_i(); |
163 | } else { | 281 | } else { |
@@ -169,18 +287,22 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
169 | flushed = 1; | 287 | flushed = 1; |
170 | } | 288 | } |
171 | } | 289 | } |
172 | |||
173 | if (flushed | 290 | if (flushed |
174 | && (wait_piowc() & | 291 | && (wait_piowc() & |
175 | SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) { | 292 | (SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK))) { |
176 | sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1); | 293 | sn2_ptc_deadlock_recovery(nasids, nix, mynasid, ptc0, data0, ptc1, data1); |
177 | } | 294 | } |
178 | 295 | ||
179 | start += (1UL << nbits); | 296 | start += (1UL << nbits); |
180 | 297 | ||
181 | } while (start < end); | 298 | } while (start < end); |
182 | 299 | ||
183 | spin_unlock_irqrestore(&sn2_global_ptc_lock, flags); | 300 | itc2 = ia64_get_itc() - itc2; |
301 | __get_cpu_var(ptcstats).shub_itc_clocks += itc2; | ||
302 | if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max) | ||
303 | __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2; | ||
304 | |||
305 | ptc_unlock(flags, opt); | ||
184 | 306 | ||
185 | preempt_enable(); | 307 | preempt_enable(); |
186 | } | 308 | } |
@@ -192,31 +314,29 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, | |||
192 | * TLB flush transaction. The recovery sequence is somewhat tricky & is | 314 | * TLB flush transaction. The recovery sequence is somewhat tricky & is |
193 | * coded in assembly language. | 315 | * coded in assembly language. |
194 | */ | 316 | */ |
195 | void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0, | 317 | void sn2_ptc_deadlock_recovery(short *nasids, short nix, int mynasid, volatile unsigned long *ptc0, unsigned long data0, |
196 | volatile unsigned long *ptc1, unsigned long data1) | 318 | volatile unsigned long *ptc1, unsigned long data1) |
197 | { | 319 | { |
198 | extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, | 320 | extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, |
199 | volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); | 321 | volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); |
200 | int cnode, mycnode, nasid; | 322 | short nasid, i; |
201 | volatile unsigned long *piows; | 323 | unsigned long *piows, zeroval; |
202 | volatile unsigned long zeroval; | ||
203 | 324 | ||
204 | sn2_ptc_deadlock_count++; | 325 | __get_cpu_var(ptcstats).deadlocks++; |
205 | 326 | ||
206 | piows = pda->pio_write_status_addr; | 327 | piows = (unsigned long *) pda->pio_write_status_addr; |
207 | zeroval = pda->pio_write_status_val; | 328 | zeroval = pda->pio_write_status_val; |
208 | 329 | ||
209 | mycnode = numa_node_id(); | 330 | for (i=0; i < nix; i++) { |
210 | 331 | nasid = nasids[i]; | |
211 | for_each_online_node(cnode) { | 332 | if (!(sn2_ptctest & 3) && nasid == mynasid) |
212 | if (is_headless_node(cnode) || cnode == mycnode) | ||
213 | continue; | 333 | continue; |
214 | nasid = cnodeid_to_nasid(cnode); | ||
215 | ptc0 = CHANGE_NASID(nasid, ptc0); | 334 | ptc0 = CHANGE_NASID(nasid, ptc0); |
216 | if (ptc1) | 335 | if (ptc1) |
217 | ptc1 = CHANGE_NASID(nasid, ptc1); | 336 | ptc1 = CHANGE_NASID(nasid, ptc1); |
218 | sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); | 337 | sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); |
219 | } | 338 | } |
339 | |||
220 | } | 340 | } |
221 | 341 | ||
222 | /** | 342 | /** |
@@ -293,3 +413,93 @@ void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) | |||
293 | 413 | ||
294 | sn_send_IPI_phys(nasid, physid, vector, delivery_mode); | 414 | sn_send_IPI_phys(nasid, physid, vector, delivery_mode); |
295 | } | 415 | } |
416 | |||
417 | #ifdef CONFIG_PROC_FS | ||
418 | |||
419 | #define PTC_BASENAME "sgi_sn/ptc_statistics" | ||
420 | |||
421 | static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset) | ||
422 | { | ||
423 | if (*offset < NR_CPUS) | ||
424 | return offset; | ||
425 | return NULL; | ||
426 | } | ||
427 | |||
428 | static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset) | ||
429 | { | ||
430 | (*offset)++; | ||
431 | if (*offset < NR_CPUS) | ||
432 | return offset; | ||
433 | return NULL; | ||
434 | } | ||
435 | |||
436 | static void sn2_ptc_seq_stop(struct seq_file *file, void *data) | ||
437 | { | ||
438 | } | ||
439 | |||
440 | static int sn2_ptc_seq_show(struct seq_file *file, void *data) | ||
441 | { | ||
442 | struct ptc_stats *stat; | ||
443 | int cpu; | ||
444 | |||
445 | cpu = *(loff_t *) data; | ||
446 | |||
447 | if (!cpu) { | ||
448 | seq_printf(file, "# ptc_l change_rid shub_ptc_flushes shub_nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max\n"); | ||
449 | seq_printf(file, "# ptctest %d\n", sn2_ptctest); | ||
450 | } | ||
451 | |||
452 | if (cpu < NR_CPUS && cpu_online(cpu)) { | ||
453 | stat = &per_cpu(ptcstats, cpu); | ||
454 | seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l, | ||
455 | stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed, | ||
456 | stat->deadlocks, | ||
457 | 1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec, | ||
458 | 1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec, | ||
459 | 1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec); | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static struct seq_operations sn2_ptc_seq_ops = { | ||
466 | .start = sn2_ptc_seq_start, | ||
467 | .next = sn2_ptc_seq_next, | ||
468 | .stop = sn2_ptc_seq_stop, | ||
469 | .show = sn2_ptc_seq_show | ||
470 | }; | ||
471 | |||
472 | int sn2_ptc_proc_open(struct inode *inode, struct file *file) | ||
473 | { | ||
474 | return seq_open(file, &sn2_ptc_seq_ops); | ||
475 | } | ||
476 | |||
477 | static struct file_operations proc_sn2_ptc_operations = { | ||
478 | .open = sn2_ptc_proc_open, | ||
479 | .read = seq_read, | ||
480 | .llseek = seq_lseek, | ||
481 | .release = seq_release, | ||
482 | }; | ||
483 | |||
484 | static struct proc_dir_entry *proc_sn2_ptc; | ||
485 | |||
486 | static int __init sn2_ptc_init(void) | ||
487 | { | ||
488 | if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) { | ||
489 | printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME); | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations; | ||
493 | spin_lock_init(&sn2_global_ptc_lock); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void __exit sn2_ptc_exit(void) | ||
498 | { | ||
499 | remove_proc_entry(PTC_BASENAME, NULL); | ||
500 | } | ||
501 | |||
502 | module_init(sn2_ptc_init); | ||
503 | module_exit(sn2_ptc_exit); | ||
504 | #endif /* CONFIG_PROC_FS */ | ||
505 | |||
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 833e700fdac9..0513aacac8c1 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <asm/topology.h> | 36 | #include <asm/topology.h> |
37 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
38 | #include <asm/semaphore.h> | 38 | #include <asm/semaphore.h> |
39 | #include <asm/segment.h> | ||
40 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
41 | #include <asm/sal.h> | 40 | #include <asm/sal.h> |
42 | #include <asm/sn/io.h> | 41 | #include <asm/sn/io.h> |
@@ -59,7 +58,7 @@ static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret) | |||
59 | struct sn_hwperf_object_info *objbuf = NULL; | 58 | struct sn_hwperf_object_info *objbuf = NULL; |
60 | 59 | ||
61 | if ((e = sn_hwperf_init()) < 0) { | 60 | if ((e = sn_hwperf_init()) < 0) { |
62 | printk("sn_hwperf_init failed: err %d\n", e); | 61 | printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e); |
63 | goto out; | 62 | goto out; |
64 | } | 63 | } |
65 | 64 | ||
@@ -111,7 +110,7 @@ static int sn_hwperf_geoid_to_cnode(char *location) | |||
111 | if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) | 110 | if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) |
112 | return -1; | 111 | return -1; |
113 | 112 | ||
114 | for (cnode = 0; cnode < numionodes; cnode++) { | 113 | for_each_node(cnode) { |
115 | geoid = cnodeid_get_geoid(cnode); | 114 | geoid = cnodeid_get_geoid(cnode); |
116 | module_id = geo_module(geoid); | 115 | module_id = geo_module(geoid); |
117 | this_rack = MODULE_GET_RACK(module_id); | 116 | this_rack = MODULE_GET_RACK(module_id); |
@@ -124,11 +123,13 @@ static int sn_hwperf_geoid_to_cnode(char *location) | |||
124 | } | 123 | } |
125 | } | 124 | } |
126 | 125 | ||
127 | return cnode < numionodes ? cnode : -1; | 126 | return node_possible(cnode) ? cnode : -1; |
128 | } | 127 | } |
129 | 128 | ||
130 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) | 129 | static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj) |
131 | { | 130 | { |
131 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | ||
132 | BUG(); | ||
132 | if (!obj->sn_hwp_this_part) | 133 | if (!obj->sn_hwp_this_part) |
133 | return -1; | 134 | return -1; |
134 | return sn_hwperf_geoid_to_cnode(obj->location); | 135 | return sn_hwperf_geoid_to_cnode(obj->location); |
@@ -174,31 +175,199 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, | |||
174 | return slabname; | 175 | return slabname; |
175 | } | 176 | } |
176 | 177 | ||
177 | static void print_pci_topology(struct seq_file *s, | 178 | static void print_pci_topology(struct seq_file *s) |
178 | struct sn_hwperf_object_info *obj, int *ordinal, | 179 | { |
179 | u64 rack, u64 bay, u64 slot, u64 slab) | 180 | char *p; |
181 | size_t sz; | ||
182 | int e; | ||
183 | |||
184 | for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) { | ||
185 | if (!(p = (char *)kmalloc(sz, GFP_KERNEL))) | ||
186 | break; | ||
187 | e = ia64_sn_ioif_get_pci_topology(__pa(p), sz); | ||
188 | if (e == SALRET_OK) | ||
189 | seq_puts(s, p); | ||
190 | kfree(p); | ||
191 | if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED) | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | static inline int sn_hwperf_has_cpus(cnodeid_t node) | ||
197 | { | ||
198 | return node_online(node) && nr_cpus_node(node); | ||
199 | } | ||
200 | |||
201 | static inline int sn_hwperf_has_mem(cnodeid_t node) | ||
202 | { | ||
203 | return node_online(node) && NODE_DATA(node)->node_present_pages; | ||
204 | } | ||
205 | |||
206 | static struct sn_hwperf_object_info * | ||
207 | sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf, | ||
208 | int nobj, int id) | ||
180 | { | 209 | { |
181 | char *p1; | 210 | int i; |
182 | char *p2; | 211 | struct sn_hwperf_object_info *p = objbuf; |
183 | char *pg; | 212 | |
184 | 213 | for (i=0; i < nobj; i++, p++) { | |
185 | if (!(pg = (char *)get_zeroed_page(GFP_KERNEL))) | 214 | if (p->id == id) |
186 | return; /* ignore */ | 215 | return p; |
187 | if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, | 216 | } |
188 | __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) { | 217 | |
189 | for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) { | 218 | return NULL; |
190 | if (!(p2 = strchr(p1, '\n'))) | 219 | |
220 | } | ||
221 | |||
222 | static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf, | ||
223 | int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) | ||
224 | { | ||
225 | int e; | ||
226 | struct sn_hwperf_object_info *nodeobj = NULL; | ||
227 | struct sn_hwperf_object_info *op; | ||
228 | struct sn_hwperf_object_info *dest; | ||
229 | struct sn_hwperf_object_info *router; | ||
230 | struct sn_hwperf_port_info ptdata[16]; | ||
231 | int sz, i, j; | ||
232 | cnodeid_t c; | ||
233 | int found_mem = 0; | ||
234 | int found_cpu = 0; | ||
235 | |||
236 | if (!node_possible(node)) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (sn_hwperf_has_cpus(node)) { | ||
240 | if (near_cpu_node) | ||
241 | *near_cpu_node = node; | ||
242 | found_cpu++; | ||
243 | } | ||
244 | |||
245 | if (sn_hwperf_has_mem(node)) { | ||
246 | if (near_mem_node) | ||
247 | *near_mem_node = node; | ||
248 | found_mem++; | ||
249 | } | ||
250 | |||
251 | if (found_cpu && found_mem) | ||
252 | return 0; /* trivially successful */ | ||
253 | |||
254 | /* find the argument node object */ | ||
255 | for (i=0, op=objbuf; i < nobj; i++, op++) { | ||
256 | if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op)) | ||
257 | continue; | ||
258 | if (node == sn_hwperf_obj_to_cnode(op)) { | ||
259 | nodeobj = op; | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | if (!nodeobj) { | ||
264 | e = -ENOENT; | ||
265 | goto err; | ||
266 | } | ||
267 | |||
268 | /* get it's interconnect topology */ | ||
269 | sz = op->ports * sizeof(struct sn_hwperf_port_info); | ||
270 | if (sz > sizeof(ptdata)) | ||
271 | BUG(); | ||
272 | e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, | ||
273 | SN_HWPERF_ENUM_PORTS, nodeobj->id, sz, | ||
274 | (u64)&ptdata, 0, 0, NULL); | ||
275 | if (e != SN_HWPERF_OP_OK) { | ||
276 | e = -EINVAL; | ||
277 | goto err; | ||
278 | } | ||
279 | |||
280 | /* find nearest node with cpus and nearest memory */ | ||
281 | for (router=NULL, j=0; j < op->ports; j++) { | ||
282 | dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id); | ||
283 | if (!dest || SN_HWPERF_FOREIGN(dest) || | ||
284 | !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) { | ||
285 | continue; | ||
286 | } | ||
287 | c = sn_hwperf_obj_to_cnode(dest); | ||
288 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
289 | if (near_cpu_node) | ||
290 | *near_cpu_node = c; | ||
291 | found_cpu++; | ||
292 | } | ||
293 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
294 | if (near_mem_node) | ||
295 | *near_mem_node = c; | ||
296 | found_mem++; | ||
297 | } | ||
298 | if (SN_HWPERF_IS_ROUTER(dest)) | ||
299 | router = dest; | ||
300 | } | ||
301 | |||
302 | if (router && (!found_cpu || !found_mem)) { | ||
303 | /* search for a node connected to the same router */ | ||
304 | sz = router->ports * sizeof(struct sn_hwperf_port_info); | ||
305 | if (sz > sizeof(ptdata)) | ||
306 | BUG(); | ||
307 | e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, | ||
308 | SN_HWPERF_ENUM_PORTS, router->id, sz, | ||
309 | (u64)&ptdata, 0, 0, NULL); | ||
310 | if (e != SN_HWPERF_OP_OK) { | ||
311 | e = -EINVAL; | ||
312 | goto err; | ||
313 | } | ||
314 | for (j=0; j < router->ports; j++) { | ||
315 | dest = sn_hwperf_findobj_id(objbuf, nobj, | ||
316 | ptdata[j].conn_id); | ||
317 | if (!dest || dest->id == node || | ||
318 | SN_HWPERF_FOREIGN(dest) || | ||
319 | !SN_HWPERF_IS_NODE(dest) || | ||
320 | SN_HWPERF_IS_IONODE(dest)) { | ||
321 | continue; | ||
322 | } | ||
323 | c = sn_hwperf_obj_to_cnode(dest); | ||
324 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
325 | if (near_cpu_node) | ||
326 | *near_cpu_node = c; | ||
327 | found_cpu++; | ||
328 | } | ||
329 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
330 | if (near_mem_node) | ||
331 | *near_mem_node = c; | ||
332 | found_mem++; | ||
333 | } | ||
334 | if (found_cpu && found_mem) | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | if (!found_cpu || !found_mem) { | ||
340 | /* resort to _any_ node with CPUs and memory */ | ||
341 | for (i=0, op=objbuf; i < nobj; i++, op++) { | ||
342 | if (SN_HWPERF_FOREIGN(op) || | ||
343 | SN_HWPERF_IS_IONODE(op) || | ||
344 | !SN_HWPERF_IS_NODE(op)) { | ||
345 | continue; | ||
346 | } | ||
347 | c = sn_hwperf_obj_to_cnode(op); | ||
348 | if (!found_cpu && sn_hwperf_has_cpus(c)) { | ||
349 | if (near_cpu_node) | ||
350 | *near_cpu_node = c; | ||
351 | found_cpu++; | ||
352 | } | ||
353 | if (!found_mem && sn_hwperf_has_mem(c)) { | ||
354 | if (near_mem_node) | ||
355 | *near_mem_node = c; | ||
356 | found_mem++; | ||
357 | } | ||
358 | if (found_cpu && found_mem) | ||
191 | break; | 359 | break; |
192 | *p2 = '\0'; | ||
193 | seq_printf(s, "pcibus %d %s-%s\n", | ||
194 | *ordinal, obj->location, p1); | ||
195 | (*ordinal)++; | ||
196 | p1 = p2 + 1; | ||
197 | } | 360 | } |
198 | } | 361 | } |
199 | free_page((unsigned long)pg); | 362 | |
363 | if (!found_cpu || !found_mem) | ||
364 | e = -ENODATA; | ||
365 | |||
366 | err: | ||
367 | return e; | ||
200 | } | 368 | } |
201 | 369 | ||
370 | |||
202 | static int sn_topology_show(struct seq_file *s, void *d) | 371 | static int sn_topology_show(struct seq_file *s, void *d) |
203 | { | 372 | { |
204 | int sz; | 373 | int sz; |
@@ -215,7 +384,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
215 | struct sn_hwperf_object_info *p; | 384 | struct sn_hwperf_object_info *p; |
216 | struct sn_hwperf_object_info *obj = d; /* this object */ | 385 | struct sn_hwperf_object_info *obj = d; /* this object */ |
217 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ | 386 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ |
218 | int rack, bay, slot, slab; | ||
219 | u8 shubtype; | 387 | u8 shubtype; |
220 | u8 system_size; | 388 | u8 system_size; |
221 | u8 sharing_size; | 389 | u8 sharing_size; |
@@ -225,7 +393,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
225 | u8 region_size; | 393 | u8 region_size; |
226 | u16 nasid_mask; | 394 | u16 nasid_mask; |
227 | int nasid_msb; | 395 | int nasid_msb; |
228 | int pci_bus_ordinal = 0; | ||
229 | 396 | ||
230 | if (obj == objs) { | 397 | if (obj == objs) { |
231 | seq_printf(s, "# sn_topology version 2\n"); | 398 | seq_printf(s, "# sn_topology version 2\n"); |
@@ -253,6 +420,8 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
253 | shubtype ? "shub2" : "shub1", | 420 | shubtype ? "shub2" : "shub1", |
254 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, | 421 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, |
255 | system_size, sharing_size, coher, region_size); | 422 | system_size, sharing_size, coher, region_size); |
423 | |||
424 | print_pci_topology(s); | ||
256 | } | 425 | } |
257 | 426 | ||
258 | if (SN_HWPERF_FOREIGN(obj)) { | 427 | if (SN_HWPERF_FOREIGN(obj)) { |
@@ -272,11 +441,24 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
272 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) | 441 | if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)) |
273 | seq_putc(s, '\n'); | 442 | seq_putc(s, '\n'); |
274 | else { | 443 | else { |
444 | cnodeid_t near_mem = -1; | ||
445 | cnodeid_t near_cpu = -1; | ||
446 | |||
275 | seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); | 447 | seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal)); |
276 | for (i=0; i < numionodes; i++) { | 448 | |
277 | seq_printf(s, i ? ":%d" : ", dist %d", | 449 | if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt, |
278 | node_distance(ordinal, i)); | 450 | ordinal, &near_mem, &near_cpu) == 0) { |
451 | seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d", | ||
452 | near_mem, near_cpu); | ||
453 | } | ||
454 | |||
455 | if (!SN_HWPERF_IS_IONODE(obj)) { | ||
456 | for_each_online_node(i) { | ||
457 | seq_printf(s, i ? ":%d" : ", dist %d", | ||
458 | node_distance(ordinal, i)); | ||
459 | } | ||
279 | } | 460 | } |
461 | |||
280 | seq_putc(s, '\n'); | 462 | seq_putc(s, '\n'); |
281 | 463 | ||
282 | /* | 464 | /* |
@@ -300,17 +482,6 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
300 | seq_putc(s, '\n'); | 482 | seq_putc(s, '\n'); |
301 | } | 483 | } |
302 | } | 484 | } |
303 | |||
304 | /* | ||
305 | * PCI busses attached to this node, if any | ||
306 | */ | ||
307 | if (sn_hwperf_location_to_bpos(obj->location, | ||
308 | &rack, &bay, &slot, &slab)) { | ||
309 | /* export pci bus info */ | ||
310 | print_pci_topology(s, obj, &pci_bus_ordinal, | ||
311 | rack, bay, slot, slab); | ||
312 | |||
313 | } | ||
314 | } | 485 | } |
315 | 486 | ||
316 | if (obj->ports) { | 487 | if (obj->ports) { |
@@ -572,6 +743,8 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
572 | if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { | 743 | if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) { |
573 | memset(p, 0, a.sz); | 744 | memset(p, 0, a.sz); |
574 | for (i = 0; i < nobj; i++) { | 745 | for (i = 0; i < nobj; i++) { |
746 | if (!SN_HWPERF_IS_NODE(objs + i)) | ||
747 | continue; | ||
575 | node = sn_hwperf_obj_to_cnode(objs + i); | 748 | node = sn_hwperf_obj_to_cnode(objs + i); |
576 | for_each_online_cpu(j) { | 749 | for_each_online_cpu(j) { |
577 | if (node != cpu_to_node(j)) | 750 | if (node != cpu_to_node(j)) |
@@ -598,7 +771,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
598 | 771 | ||
599 | case SN_HWPERF_GET_NODE_NASID: | 772 | case SN_HWPERF_GET_NODE_NASID: |
600 | if (a.sz != sizeof(u64) || | 773 | if (a.sz != sizeof(u64) || |
601 | (node = a.arg) < 0 || node >= numionodes) { | 774 | (node = a.arg) < 0 || !node_possible(node)) { |
602 | r = -EINVAL; | 775 | r = -EINVAL; |
603 | goto error; | 776 | goto error; |
604 | } | 777 | } |
@@ -627,6 +800,14 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
627 | vfree(objs); | 800 | vfree(objs); |
628 | goto error; | 801 | goto error; |
629 | } | 802 | } |
803 | |||
804 | if (!SN_HWPERF_IS_NODE(objs + i) && | ||
805 | !SN_HWPERF_IS_IONODE(objs + i)) { | ||
806 | r = -ENOENT; | ||
807 | vfree(objs); | ||
808 | goto error; | ||
809 | } | ||
810 | |||
630 | *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); | 811 | *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i); |
631 | vfree(objs); | 812 | vfree(objs); |
632 | } | 813 | } |
@@ -692,6 +873,7 @@ static int sn_hwperf_init(void) | |||
692 | 873 | ||
693 | /* single threaded, once-only initialization */ | 874 | /* single threaded, once-only initialization */ |
694 | down(&sn_hwperf_init_mutex); | 875 | down(&sn_hwperf_init_mutex); |
876 | |||
695 | if (sn_hwperf_salheap) { | 877 | if (sn_hwperf_salheap) { |
696 | up(&sn_hwperf_init_mutex); | 878 | up(&sn_hwperf_init_mutex); |
697 | return e; | 879 | return e; |
@@ -742,19 +924,6 @@ out: | |||
742 | sn_hwperf_salheap = NULL; | 924 | sn_hwperf_salheap = NULL; |
743 | sn_hwperf_obj_cnt = 0; | 925 | sn_hwperf_obj_cnt = 0; |
744 | } | 926 | } |
745 | |||
746 | if (!e) { | ||
747 | /* | ||
748 | * Register a dynamic misc device for ioctl. Platforms | ||
749 | * supporting hotplug will create /dev/sn_hwperf, else | ||
750 | * user can to look up the minor number in /proc/misc. | ||
751 | */ | ||
752 | if ((e = misc_register(&sn_hwperf_dev)) != 0) { | ||
753 | printk(KERN_ERR "sn_hwperf_init: misc register " | ||
754 | "for \"sn_hwperf\" failed, err %d\n", e); | ||
755 | } | ||
756 | } | ||
757 | |||
758 | up(&sn_hwperf_init_mutex); | 927 | up(&sn_hwperf_init_mutex); |
759 | return e; | 928 | return e; |
760 | } | 929 | } |
@@ -782,3 +951,41 @@ int sn_topology_release(struct inode *inode, struct file *file) | |||
782 | vfree(seq->private); | 951 | vfree(seq->private); |
783 | return seq_release(inode, file); | 952 | return seq_release(inode, file); |
784 | } | 953 | } |
954 | |||
955 | int sn_hwperf_get_nearest_node(cnodeid_t node, | ||
956 | cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node) | ||
957 | { | ||
958 | int e; | ||
959 | int nobj; | ||
960 | struct sn_hwperf_object_info *objbuf; | ||
961 | |||
962 | if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) { | ||
963 | e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj, | ||
964 | node, near_mem_node, near_cpu_node); | ||
965 | vfree(objbuf); | ||
966 | } | ||
967 | |||
968 | return e; | ||
969 | } | ||
970 | |||
971 | static int __devinit sn_hwperf_misc_register_init(void) | ||
972 | { | ||
973 | int e; | ||
974 | |||
975 | sn_hwperf_init(); | ||
976 | |||
977 | /* | ||
978 | * Register a dynamic misc device for hwperf ioctls. Platforms | ||
979 | * supporting hotplug will create /dev/sn_hwperf, else user | ||
980 | * can to look up the minor number in /proc/misc. | ||
981 | */ | ||
982 | if ((e = misc_register(&sn_hwperf_dev)) != 0) { | ||
983 | printk(KERN_ERR "sn_hwperf_misc_register_init: failed to " | ||
984 | "register misc device for \"%s\"\n", sn_hwperf_dev.name); | ||
985 | } | ||
986 | |||
987 | return e; | ||
988 | } | ||
989 | |||
990 | device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */ | ||
991 | EXPORT_SYMBOL(sn_hwperf_get_nearest_node); | ||
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 6a80fca807b9..51bf82720d99 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | static int partition_id_show(struct seq_file *s, void *p) | 16 | static int partition_id_show(struct seq_file *s, void *p) |
17 | { | 17 | { |
18 | seq_printf(s, "%d\n", sn_local_partid()); | 18 | seq_printf(s, "%d\n", sn_partition_id); |
19 | return 0; | 19 | return 0; |
20 | } | 20 | } |
21 | 21 | ||
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c index cde7375390b0..adf5db2e2afe 100644 --- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c +++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * | 3 | * |
4 | * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. | 4 | * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
@@ -50,14 +50,16 @@ void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
50 | LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); | 50 | LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT); |
51 | } | 51 | } |
52 | 52 | ||
53 | if (enable_shub_wars_1_1()) { | 53 | if (is_shub1()) { |
54 | /* Bugfix code for SHUB 1.1 */ | 54 | if (enable_shub_wars_1_1()) { |
55 | if (pda->pio_shub_war_cam_addr) | 55 | /* Bugfix code for SHUB 1.1 */ |
56 | *pda->pio_shub_war_cam_addr = 0x8000000000000010UL; | 56 | if (pda->pio_shub_war_cam_addr) |
57 | *pda->pio_shub_war_cam_addr = 0x8000000000000010UL; | ||
58 | } | ||
59 | if (pda->sn_lb_int_war_ticks == 0) | ||
60 | sn_lb_int_war_check(); | ||
61 | pda->sn_lb_int_war_ticks++; | ||
62 | if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL) | ||
63 | pda->sn_lb_int_war_ticks = 0; | ||
57 | } | 64 | } |
58 | if (pda->sn_lb_int_war_ticks == 0) | ||
59 | sn_lb_int_war_check(); | ||
60 | pda->sn_lb_int_war_ticks++; | ||
61 | if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL) | ||
62 | pda->sn_lb_int_war_ticks = 0; | ||
63 | } | 65 | } |
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 254fe15c064b..b45db5133f55 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c | |||
@@ -191,7 +191,7 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num, | |||
191 | { | 191 | { |
192 | struct cx_dev *cx_dev; | 192 | struct cx_dev *cx_dev; |
193 | 193 | ||
194 | cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL); | 194 | cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL); |
195 | DBG("cx_dev= 0x%p\n", cx_dev); | 195 | DBG("cx_dev= 0x%p\n", cx_dev); |
196 | if (cx_dev == NULL) | 196 | if (cx_dev == NULL) |
197 | return -ENOMEM; | 197 | return -ENOMEM; |