1 /* 2 * arch/s390/kernel/setup.c 3 * 4 * S390 version 5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation 6 * Author(s): Hartmut Penner (hp@de.ibm.com), 7 * Martin Schwidefsky (schwidefsky@de.ibm.com) 8 * 9 * Derived from "arch/i386/kernel/setup.c" 10 * Copyright (C) 1995, Linus Torvalds 11 */ 12 13 /* 14 * This file handles the architecture-dependent parts of initialization 15 */ 16 17 #include <linux/errno.h> 18 #include <linux/module.h> 19 #include <linux/sched.h> 20 #include <linux/kernel.h> 21 #include <linux/mm.h> 22 #include <linux/stddef.h> 23 #include <linux/unistd.h> 24 #include <linux/ptrace.h> 25 #include <linux/slab.h> 26 #include <linux/user.h> 27 #include <linux/a.out.h> 28 #include <linux/tty.h> 29 #include <linux/ioport.h> 30 #include <linux/delay.h> 31 #include <linux/config.h> 32 #include <linux/init.h> 33 #include <linux/initrd.h> 34 #include <linux/bootmem.h> 35 #include <linux/root_dev.h> 36 #include <linux/console.h> 37 #include <linux/seq_file.h> 38 #include <linux/kernel_stat.h> 39 40 #include <asm/uaccess.h> 41 #include <asm/system.h> 42 #include <asm/smp.h> 43 #include <asm/mmu_context.h> 44 #include <asm/cpcmd.h> 45 #include <asm/lowcore.h> 46 #include <asm/irq.h> 47 #include <asm/page.h> 48 #include <asm/ptrace.h> 49 50 /* 51 * Machine setup.. 52 */ 53 unsigned int console_mode = 0; 54 unsigned int console_devno = -1; 55 unsigned int console_irq = -1; 56 unsigned long memory_size = 0; 57 unsigned long machine_flags = 0; 58 struct { 59 unsigned long addr, size, type; 60 } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; 61 #define CHUNK_READ_WRITE 0 62 #define CHUNK_READ_ONLY 1 63 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ 64 unsigned long __initdata zholes_size[MAX_NR_ZONES]; 65 static unsigned long __initdata memory_end; 66 67 /* 68 * Setup options 69 */ 70 extern int _text,_etext, _edata, _end; 71 72 /* 73 * This is set up by the setup-routine at boot-time 74 * for S390 need to find out, what we have to setup 75 * using address 0x10400 ... 76 */ 77 78 #include <asm/setup.h> 79 80 static char command_line[COMMAND_LINE_SIZE] = { 0, }; 81 82 static struct resource code_resource = { 83 .name = "Kernel code", 84 .start = (unsigned long) &_text, 85 .end = (unsigned long) &_etext - 1, 86 .flags = IORESOURCE_BUSY | IORESOURCE_MEM, 87 }; 88 89 static struct resource data_resource = { 90 .name = "Kernel data", 91 .start = (unsigned long) &_etext, 92 .end = (unsigned long) &_edata - 1, 93 .flags = IORESOURCE_BUSY | IORESOURCE_MEM, 94 }; 95 96 /* 97 * cpu_init() initializes state that is per-CPU. 98 */ 99 void __devinit cpu_init (void) 100 { 101 int addr = hard_smp_processor_id(); 102 103 /* 104 * Store processor id in lowcore (used e.g. in timer_interrupt) 105 */ 106 asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); 107 S390_lowcore.cpu_data.cpu_addr = addr; 108 109 /* 110 * Force FPU initialization: 111 */ 112 clear_thread_flag(TIF_USEDFPU); 113 clear_used_math(); 114 115 atomic_inc(&init_mm.mm_count); 116 current->active_mm = &init_mm; 117 if (current->mm) 118 BUG(); 119 enter_lazy_tlb(&init_mm, current); 120 } 121 122 /* 123 * VM halt and poweroff setup routines 124 */ 125 char vmhalt_cmd[128] = ""; 126 char vmpoff_cmd[128] = ""; 127 128 static inline void strncpy_skip_quote(char *dst, char *src, int n) 129 { 130 int sx, dx; 131 132 dx = 0; 133 for (sx = 0; src[sx] != 0; sx++) { 134 if (src[sx] == '"') continue; 135 dst[dx++] = src[sx]; 136 if (dx >= n) break; 137 } 138 } 139 140 static int __init vmhalt_setup(char *str) 141 { 142 strncpy_skip_quote(vmhalt_cmd, str, 127); 143 vmhalt_cmd[127] = 0; 144 return 1; 145 } 146 147 __setup("vmhalt=", vmhalt_setup); 148 149 static int __init vmpoff_setup(char *str) 150 { 151 strncpy_skip_quote(vmpoff_cmd, str, 127); 152 vmpoff_cmd[127] = 0; 153 return 1; 154 } 155 156 __setup("vmpoff=", vmpoff_setup); 157 158 /* 159 * condev= and conmode= setup parameter. 160 */ 161 162 static int __init condev_setup(char *str) 163 { 164 int vdev; 165 166 vdev = simple_strtoul(str, &str, 0); 167 if (vdev >= 0 && vdev < 65536) { 168 console_devno = vdev; 169 console_irq = -1; 170 } 171 return 1; 172 } 173 174 __setup("condev=", condev_setup); 175 176 static int __init conmode_setup(char *str) 177 { 178 #if defined(CONFIG_SCLP_CONSOLE) 179 if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) 180 SET_CONSOLE_SCLP; 181 #endif 182 #if defined(CONFIG_TN3215_CONSOLE) 183 if (strncmp(str, "3215", 5) == 0) 184 SET_CONSOLE_3215; 185 #endif 186 #if defined(CONFIG_TN3270_CONSOLE) 187 if (strncmp(str, "3270", 5) == 0) 188 SET_CONSOLE_3270; 189 #endif 190 return 1; 191 } 192 193 __setup("conmode=", conmode_setup); 194 195 static void __init conmode_default(void) 196 { 197 char query_buffer[1024]; 198 char *ptr; 199 200 if (MACHINE_IS_VM) { 201 __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); 202 console_devno = simple_strtoul(query_buffer + 5, NULL, 16); 203 ptr = strstr(query_buffer, "SUBCHANNEL ="); 204 console_irq = simple_strtoul(ptr + 13, NULL, 16); 205 __cpcmd("QUERY TERM", query_buffer, 1024, NULL); 206 ptr = strstr(query_buffer, "CONMODE"); 207 /* 208 * Set the conmode to 3215 so that the device recognition 209 * will set the cu_type of the console to 3215. If the 210 * conmode is 3270 and we don't set it back then both 211 * 3215 and the 3270 driver will try to access the console 212 * device (3215 as console and 3270 as normal tty). 213 */ 214 __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); 215 if (ptr == NULL) { 216 #if defined(CONFIG_SCLP_CONSOLE) 217 SET_CONSOLE_SCLP; 218 #endif 219 return; 220 } 221 if (strncmp(ptr + 8, "3270", 4) == 0) { 222 #if defined(CONFIG_TN3270_CONSOLE) 223 SET_CONSOLE_3270; 224 #elif defined(CONFIG_TN3215_CONSOLE) 225 SET_CONSOLE_3215; 226 #elif defined(CONFIG_SCLP_CONSOLE) 227 SET_CONSOLE_SCLP; 228 #endif 229 } else if (strncmp(ptr + 8, "3215", 4) == 0) { 230 #if defined(CONFIG_TN3215_CONSOLE) 231 SET_CONSOLE_3215; 232 #elif defined(CONFIG_TN3270_CONSOLE) 233 SET_CONSOLE_3270; 234 #elif defined(CONFIG_SCLP_CONSOLE) 235 SET_CONSOLE_SCLP; 236 #endif 237 } 238 } else if (MACHINE_IS_P390) { 239 #if defined(CONFIG_TN3215_CONSOLE) 240 SET_CONSOLE_3215; 241 #elif defined(CONFIG_TN3270_CONSOLE) 242 SET_CONSOLE_3270; 243 #endif 244 } else { 245 #if defined(CONFIG_SCLP_CONSOLE) 246 SET_CONSOLE_SCLP; 247 #endif 248 } 249 } 250 251 #ifdef CONFIG_SMP 252 extern void machine_restart_smp(char *); 253 extern void machine_halt_smp(void); 254 extern void machine_power_off_smp(void); 255 256 void (*_machine_restart)(char *command) = machine_restart_smp; 257 void (*_machine_halt)(void) = machine_halt_smp; 258 void (*_machine_power_off)(void) = machine_power_off_smp; 259 #else 260 /* 261 * Reboot, halt and power_off routines for non SMP. 262 */ 263 extern void reipl(unsigned long devno); 264 extern void reipl_diag(void); 265 static void do_machine_restart_nonsmp(char * __unused) 266 { 267 reipl_diag(); 268 269 if (MACHINE_IS_VM) 270 cpcmd ("IPL", NULL, 0); 271 else 272 reipl (0x10000 | S390_lowcore.ipl_device); 273 } 274 275 static void do_machine_halt_nonsmp(void) 276 { 277 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 278 cpcmd(vmhalt_cmd, NULL, 0); 279 signal_processor(smp_processor_id(), sigp_stop_and_store_status); 280 } 281 282 static void do_machine_power_off_nonsmp(void) 283 { 284 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) 285 cpcmd(vmpoff_cmd, NULL, 0); 286 signal_processor(smp_processor_id(), sigp_stop_and_store_status); 287 } 288 289 void (*_machine_restart)(char *command) = do_machine_restart_nonsmp; 290 void (*_machine_halt)(void) = do_machine_halt_nonsmp; 291 void (*_machine_power_off)(void) = do_machine_power_off_nonsmp; 292 #endif 293 294 /* 295 * Reboot, halt and power_off stubs. They just call _machine_restart, 296 * _machine_halt or _machine_power_off. 297 */ 298 299 void machine_restart(char *command) 300 { 301 console_unblank(); 302 _machine_restart(command); 303 } 304 305 void machine_halt(void) 306 { 307 console_unblank(); 308 _machine_halt(); 309 } 310 311 void machine_power_off(void) 312 { 313 console_unblank(); 314 _machine_power_off(); 315 } 316 317 static void __init 318 add_memory_hole(unsigned long start, unsigned long end) 319 { 320 unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; 321 322 if (end <= dma_pfn) 323 zholes_size[ZONE_DMA] += end - start + 1; 324 else if (start > dma_pfn) 325 zholes_size[ZONE_NORMAL] += end - start + 1; 326 else { 327 zholes_size[ZONE_DMA] += dma_pfn - start + 1; 328 zholes_size[ZONE_NORMAL] += end - dma_pfn; 329 } 330 } 331 332 static void __init 333 parse_cmdline_early(char **cmdline_p) 334 { 335 char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; 336 unsigned long delay = 0; 337 338 /* Save unparsed command line copy for /proc/cmdline */ 339 memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); 340 saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; 341 342 for (;;) { 343 /* 344 * "mem=XXX[kKmM]" sets memsize 345 */ 346 if (c == ' ' && strncmp(from, "mem=", 4) == 0) { 347 memory_end = simple_strtoul(from+4, &from, 0); 348 if ( *from == 'K' || *from == 'k' ) { 349 memory_end = memory_end << 10; 350 from++; 351 } else if ( *from == 'M' || *from == 'm' ) { 352 memory_end = memory_end << 20; 353 from++; 354 } 355 } 356 /* 357 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes 358 */ 359 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { 360 delay = simple_strtoul(from+9, &from, 0); 361 if (*from == 's' || *from == 'S') { 362 delay = delay*1000000; 363 from++; 364 } else if (*from == 'm' || *from == 'M') { 365 delay = delay*60*1000000; 366 from++; 367 } 368 /* now wait for the requested amount of time */ 369 udelay(delay); 370 } 371 cn = *(from++); 372 if (!cn) 373 break; 374 if (cn == '\n') 375 cn = ' '; /* replace newlines with space */ 376 if (cn == 0x0d) 377 cn = ' '; /* replace 0x0d with space */ 378 if (cn == ' ' && c == ' ') 379 continue; /* remove additional spaces */ 380 c = cn; 381 if (to - command_line >= COMMAND_LINE_SIZE) 382 break; 383 *(to++) = c; 384 } 385 if (c == ' ' && to > command_line) to--; 386 *to = '\0'; 387 *cmdline_p = command_line; 388 } 389 390 static void __init 391 setup_lowcore(void) 392 { 393 struct _lowcore *lc; 394 int lc_pages; 395 396 /* 397 * Setup lowcore for boot cpu 398 */ 399 lc_pages = sizeof(void *) == 8 ? 2 : 1; 400 lc = (struct _lowcore *) 401 __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0); 402 memset(lc, 0, lc_pages * PAGE_SIZE); 403 lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; 404 lc->restart_psw.addr = 405 PSW_ADDR_AMODE | (unsigned long) restart_int_handler; 406 lc->external_new_psw.mask = PSW_KERNEL_BITS; 407 lc->external_new_psw.addr = 408 PSW_ADDR_AMODE | (unsigned long) ext_int_handler; 409 lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; 410 lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; 411 lc->program_new_psw.mask = PSW_KERNEL_BITS; 412 lc->program_new_psw.addr = 413 PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; 414 lc->mcck_new_psw.mask = 415 PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; 416 lc->mcck_new_psw.addr = 417 PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; 418 lc->io_new_psw.mask = PSW_KERNEL_BITS; 419 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; 420 lc->ipl_device = S390_lowcore.ipl_device; 421 lc->jiffy_timer = -1LL; 422 lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; 423 lc->async_stack = (unsigned long) 424 __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; 425 lc->panic_stack = (unsigned long) 426 __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; 427 lc->current_task = (unsigned long) init_thread_union.thread_info.task; 428 lc->thread_info = (unsigned long) &init_thread_union; 429 #ifndef CONFIG_ARCH_S390X 430 if (MACHINE_HAS_IEEE) { 431 lc->extended_save_area_addr = (__u32) 432 __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); 433 /* enable extended save area */ 434 ctl_set_bit(14, 29); 435 } 436 #endif 437 set_prefix((u32)(unsigned long) lc); 438 } 439 440 static void __init 441 setup_resources(void) 442 { 443 struct resource *res; 444 int i; 445 446 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { 447 res = alloc_bootmem_low(sizeof(struct resource)); 448 res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; 449 switch (memory_chunk[i].type) { 450 case CHUNK_READ_WRITE: 451 res->name = "System RAM"; 452 break; 453 case CHUNK_READ_ONLY: 454 res->name = "System ROM"; 455 res->flags |= IORESOURCE_READONLY; 456 break; 457 default: 458 res->name = "reserved"; 459 } 460 res->start = memory_chunk[i].addr; 461 res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; 462 request_resource(&iomem_resource, res); 463 request_resource(res, &code_resource); 464 request_resource(res, &data_resource); 465 } 466 } 467 468 static void __init 469 setup_memory(void) 470 { 471 unsigned long bootmap_size; 472 unsigned long start_pfn, end_pfn, init_pfn; 473 unsigned long last_rw_end; 474 int i; 475 476 /* 477 * partially used pages are not usable - thus 478 * we are rounding upwards: 479 */ 480 start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT; 481 end_pfn = max_pfn = memory_end >> PAGE_SHIFT; 482 483 /* Initialize storage key for kernel pages */ 484 for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) 485 page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); 486 487 /* 488 * Initialize the boot-time allocator (with low memory only): 489 */ 490 bootmap_size = init_bootmem(start_pfn, end_pfn); 491 492 /* 493 * Register RAM areas with the bootmem allocator. 494 */ 495 last_rw_end = start_pfn; 496 497 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { 498 unsigned long start_chunk, end_chunk; 499 500 if (memory_chunk[i].type != CHUNK_READ_WRITE) 501 continue; 502 start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1); 503 start_chunk >>= PAGE_SHIFT; 504 end_chunk = (memory_chunk[i].addr + memory_chunk[i].size); 505 end_chunk >>= PAGE_SHIFT; 506 if (start_chunk < start_pfn) 507 start_chunk = start_pfn; 508 if (end_chunk > end_pfn) 509 end_chunk = end_pfn; 510 if (start_chunk < end_chunk) { 511 /* Initialize storage key for RAM pages */ 512 for (init_pfn = start_chunk ; init_pfn < end_chunk; 513 init_pfn++) 514 page_set_storage_key(init_pfn << PAGE_SHIFT, 515 PAGE_DEFAULT_KEY); 516 free_bootmem(start_chunk << PAGE_SHIFT, 517 (end_chunk - start_chunk) << PAGE_SHIFT); 518 if (last_rw_end < start_chunk) 519 add_memory_hole(last_rw_end, start_chunk - 1); 520 last_rw_end = end_chunk; 521 } 522 } 523 524 psw_set_key(PAGE_DEFAULT_KEY); 525 526 if (last_rw_end < end_pfn - 1) 527 add_memory_hole(last_rw_end, end_pfn - 1); 528 529 /* 530 * Reserve the bootmem bitmap itself as well. We do this in two 531 * steps (first step was init_bootmem()) because this catches 532 * the (very unlikely) case of us accidentally initializing the 533 * bootmem allocator with an invalid RAM area. 534 */ 535 reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); 536 537 #ifdef CONFIG_BLK_DEV_INITRD 538 if (INITRD_START) { 539 if (INITRD_START + INITRD_SIZE <= memory_end) { 540 reserve_bootmem(INITRD_START, INITRD_SIZE); 541 initrd_start = INITRD_START; 542 initrd_end = initrd_start + INITRD_SIZE; 543 } else { 544 printk("initrd extends beyond end of memory " 545 "(0x%08lx > 0x%08lx)\ndisabling initrd\n", 546 initrd_start + INITRD_SIZE, memory_end); 547 initrd_start = initrd_end = 0; 548 } 549 } 550 #endif 551 } 552 553 /* 554 * Setup function called from init/main.c just after the banner 555 * was printed. 556 */ 557 558 void __init 559 setup_arch(char **cmdline_p) 560 { 561 /* 562 * print what head.S has found out about the machine 563 */ 564 #ifndef CONFIG_ARCH_S390X 565 printk((MACHINE_IS_VM) ? 566 "We are running under VM (31 bit mode)\n" : 567 "We are running native (31 bit mode)\n"); 568 printk((MACHINE_HAS_IEEE) ? 569 "This machine has an IEEE fpu\n" : 570 "This machine has no IEEE fpu\n"); 571 #else /* CONFIG_ARCH_S390X */ 572 printk((MACHINE_IS_VM) ? 573 "We are running under VM (64 bit mode)\n" : 574 "We are running native (64 bit mode)\n"); 575 #endif /* CONFIG_ARCH_S390X */ 576 577 ROOT_DEV = Root_RAM0; 578 #ifndef CONFIG_ARCH_S390X 579 memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */ 580 /* 581 * We need some free virtual space to be able to do vmalloc. 582 * On a machine with 2GB memory we make sure that we have at 583 * least 128 MB free space for vmalloc. 584 */ 585 if (memory_end > 1920*1024*1024) 586 memory_end = 1920*1024*1024; 587 #else /* CONFIG_ARCH_S390X */ 588 memory_end = memory_size & ~0x200000UL; /* detected in head.s */ 589 #endif /* CONFIG_ARCH_S390X */ 590 591 init_mm.start_code = PAGE_OFFSET; 592 init_mm.end_code = (unsigned long) &_etext; 593 init_mm.end_data = (unsigned long) &_edata; 594 init_mm.brk = (unsigned long) &_end; 595 596 parse_cmdline_early(cmdline_p); 597 598 setup_memory(); 599 setup_resources(); 600 setup_lowcore(); 601 602 cpu_init(); 603 __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; 604 605 /* 606 * Create kernel page tables and switch to virtual addressing. 607 */ 608 paging_init(); 609 610 /* Setup default console */ 611 conmode_default(); 612 } 613 614 void print_cpu_info(struct cpuinfo_S390 *cpuinfo) 615 { 616 printk("cpu %d " 617 #ifdef CONFIG_SMP 618 "phys_idx=%d " 619 #endif 620 "vers=%02X ident=%06X machine=%04X unused=%04X\n", 621 cpuinfo->cpu_nr, 622 #ifdef CONFIG_SMP 623 cpuinfo->cpu_addr, 624 #endif 625 cpuinfo->cpu_id.version, 626 cpuinfo->cpu_id.ident, 627 cpuinfo->cpu_id.machine, 628 cpuinfo->cpu_id.unused); 629 } 630 631 /* 632 * show_cpuinfo - Get information on one CPU for use by procfs. 633 */ 634 635 static int show_cpuinfo(struct seq_file *m, void *v) 636 { 637 struct cpuinfo_S390 *cpuinfo; 638 unsigned long n = (unsigned long) v - 1; 639 640 preempt_disable(); 641 if (!n) { 642 seq_printf(m, "vendor_id : IBM/S390\n" 643 "# processors : %i\n" 644 "bogomips per cpu: %lu.%02lu\n", 645 num_online_cpus(), loops_per_jiffy/(500000/HZ), 646 (loops_per_jiffy/(5000/HZ))%100); 647 } 648 if (cpu_online(n)) { 649 #ifdef CONFIG_SMP 650 if (smp_processor_id() == n) 651 cpuinfo = &S390_lowcore.cpu_data; 652 else 653 cpuinfo = &lowcore_ptr[n]->cpu_data; 654 #else 655 cpuinfo = &S390_lowcore.cpu_data; 656 #endif 657 seq_printf(m, "processor %li: " 658 "version = %02X, " 659 "identification = %06X, " 660 "machine = %04X\n", 661 n, cpuinfo->cpu_id.version, 662 cpuinfo->cpu_id.ident, 663 cpuinfo->cpu_id.machine); 664 } 665 preempt_enable(); 666 return 0; 667 } 668 669 static void *c_start(struct seq_file *m, loff_t *pos) 670 { 671 return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; 672 } 673 static void *c_next(struct seq_file *m, void *v, loff_t *pos) 674 { 675 ++*pos; 676 return c_start(m, pos); 677 } 678 static void c_stop(struct seq_file *m, void *v) 679 { 680 } 681 struct seq_operations cpuinfo_op = { 682 .start = c_start, 683 .next = c_next, 684 .stop = c_stop, 685 .show = show_cpuinfo, 686 }; 687 688