diff options
Diffstat (limited to 'arch/powerpc/platforms')
| -rw-r--r-- | arch/powerpc/platforms/powernv/opal-dump.c | 94 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/opal-elog.c | 11 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/opal-flash.c | 118 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/opal-sysparam.c | 32 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/opal.c | 69 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/setup.c | 48 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-cpu.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 10 |
10 files changed, 178 insertions, 215 deletions
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c index b9827b0d87e4..788a1977b9a5 100644 --- a/arch/powerpc/platforms/powernv/opal-dump.c +++ b/arch/powerpc/platforms/powernv/opal-dump.c | |||
| @@ -209,89 +209,20 @@ static struct kobj_type dump_ktype = { | |||
| 209 | .default_attrs = dump_default_attrs, | 209 | .default_attrs = dump_default_attrs, |
| 210 | }; | 210 | }; |
| 211 | 211 | ||
| 212 | static void free_dump_sg_list(struct opal_sg_list *list) | 212 | static int64_t dump_read_info(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type) |
| 213 | { | ||
| 214 | struct opal_sg_list *sg1; | ||
| 215 | while (list) { | ||
| 216 | sg1 = list->next; | ||
| 217 | kfree(list); | ||
| 218 | list = sg1; | ||
| 219 | } | ||
| 220 | list = NULL; | ||
| 221 | } | ||
| 222 | |||
| 223 | static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump) | ||
| 224 | { | ||
| 225 | struct opal_sg_list *sg1, *list = NULL; | ||
| 226 | void *addr; | ||
| 227 | int64_t size; | ||
| 228 | |||
| 229 | addr = dump->buffer; | ||
| 230 | size = dump->size; | ||
| 231 | |||
| 232 | sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 233 | if (!sg1) | ||
| 234 | goto nomem; | ||
| 235 | |||
| 236 | list = sg1; | ||
| 237 | sg1->num_entries = 0; | ||
| 238 | while (size > 0) { | ||
| 239 | /* Translate virtual address to physical address */ | ||
| 240 | sg1->entry[sg1->num_entries].data = | ||
| 241 | (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT); | ||
| 242 | |||
| 243 | if (size > PAGE_SIZE) | ||
| 244 | sg1->entry[sg1->num_entries].length = PAGE_SIZE; | ||
| 245 | else | ||
| 246 | sg1->entry[sg1->num_entries].length = size; | ||
| 247 | |||
| 248 | sg1->num_entries++; | ||
| 249 | if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { | ||
| 250 | sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 251 | if (!sg1->next) | ||
| 252 | goto nomem; | ||
| 253 | |||
| 254 | sg1 = sg1->next; | ||
| 255 | sg1->num_entries = 0; | ||
| 256 | } | ||
| 257 | addr += PAGE_SIZE; | ||
| 258 | size -= PAGE_SIZE; | ||
| 259 | } | ||
| 260 | return list; | ||
| 261 | |||
| 262 | nomem: | ||
| 263 | pr_err("%s : Failed to allocate memory\n", __func__); | ||
| 264 | free_dump_sg_list(list); | ||
| 265 | return NULL; | ||
| 266 | } | ||
| 267 | |||
| 268 | static void sglist_to_phy_addr(struct opal_sg_list *list) | ||
| 269 | { | ||
| 270 | struct opal_sg_list *sg, *next; | ||
| 271 | |||
| 272 | for (sg = list; sg; sg = next) { | ||
| 273 | next = sg->next; | ||
| 274 | /* Don't translate NULL pointer for last entry */ | ||
| 275 | if (sg->next) | ||
| 276 | sg->next = (struct opal_sg_list *)__pa(sg->next); | ||
| 277 | else | ||
| 278 | sg->next = NULL; | ||
| 279 | |||
| 280 | /* Convert num_entries to length */ | ||
| 281 | sg->num_entries = | ||
| 282 | sg->num_entries * sizeof(struct opal_sg_entry) + 16; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type) | ||
| 287 | { | 213 | { |
| 214 | __be32 id, size, type; | ||
| 288 | int rc; | 215 | int rc; |
| 289 | *type = 0xffffffff; | ||
| 290 | 216 | ||
| 291 | rc = opal_dump_info2(id, size, type); | 217 | type = cpu_to_be32(0xffffffff); |
| 292 | 218 | ||
| 219 | rc = opal_dump_info2(&id, &size, &type); | ||
| 293 | if (rc == OPAL_PARAMETER) | 220 | if (rc == OPAL_PARAMETER) |
| 294 | rc = opal_dump_info(id, size); | 221 | rc = opal_dump_info(&id, &size); |
| 222 | |||
| 223 | *dump_id = be32_to_cpu(id); | ||
| 224 | *dump_size = be32_to_cpu(size); | ||
| 225 | *dump_type = be32_to_cpu(type); | ||
| 295 | 226 | ||
| 296 | if (rc) | 227 | if (rc) |
| 297 | pr_warn("%s: Failed to get dump info (%d)\n", | 228 | pr_warn("%s: Failed to get dump info (%d)\n", |
| @@ -314,15 +245,12 @@ static int64_t dump_read_data(struct dump_obj *dump) | |||
| 314 | } | 245 | } |
| 315 | 246 | ||
| 316 | /* Generate SG list */ | 247 | /* Generate SG list */ |
| 317 | list = dump_data_to_sglist(dump); | 248 | list = opal_vmalloc_to_sg_list(dump->buffer, dump->size); |
| 318 | if (!list) { | 249 | if (!list) { |
| 319 | rc = -ENOMEM; | 250 | rc = -ENOMEM; |
| 320 | goto out; | 251 | goto out; |
| 321 | } | 252 | } |
| 322 | 253 | ||
| 323 | /* Translate sg list addr to real address */ | ||
| 324 | sglist_to_phy_addr(list); | ||
| 325 | |||
| 326 | /* First entry address */ | 254 | /* First entry address */ |
| 327 | addr = __pa(list); | 255 | addr = __pa(list); |
| 328 | 256 | ||
| @@ -341,7 +269,7 @@ static int64_t dump_read_data(struct dump_obj *dump) | |||
| 341 | __func__, dump->id); | 269 | __func__, dump->id); |
| 342 | 270 | ||
| 343 | /* Free SG list */ | 271 | /* Free SG list */ |
| 344 | free_dump_sg_list(list); | 272 | opal_free_sg_list(list); |
| 345 | 273 | ||
| 346 | out: | 274 | out: |
| 347 | return rc; | 275 | return rc; |
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c index ef7bc2a97862..10268c41d830 100644 --- a/arch/powerpc/platforms/powernv/opal-elog.c +++ b/arch/powerpc/platforms/powernv/opal-elog.c | |||
| @@ -238,18 +238,25 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type) | |||
| 238 | 238 | ||
| 239 | static void elog_work_fn(struct work_struct *work) | 239 | static void elog_work_fn(struct work_struct *work) |
| 240 | { | 240 | { |
| 241 | size_t elog_size; | 241 | __be64 size; |
| 242 | __be64 id; | ||
| 243 | __be64 type; | ||
| 244 | uint64_t elog_size; | ||
| 242 | uint64_t log_id; | 245 | uint64_t log_id; |
| 243 | uint64_t elog_type; | 246 | uint64_t elog_type; |
| 244 | int rc; | 247 | int rc; |
| 245 | char name[2+16+1]; | 248 | char name[2+16+1]; |
| 246 | 249 | ||
| 247 | rc = opal_get_elog_size(&log_id, &elog_size, &elog_type); | 250 | rc = opal_get_elog_size(&id, &size, &type); |
| 248 | if (rc != OPAL_SUCCESS) { | 251 | if (rc != OPAL_SUCCESS) { |
| 249 | pr_err("ELOG: Opal log read failed\n"); | 252 | pr_err("ELOG: Opal log read failed\n"); |
| 250 | return; | 253 | return; |
| 251 | } | 254 | } |
| 252 | 255 | ||
| 256 | elog_size = be64_to_cpu(size); | ||
| 257 | log_id = be64_to_cpu(id); | ||
| 258 | elog_type = be64_to_cpu(type); | ||
| 259 | |||
| 253 | BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE); | 260 | BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE); |
| 254 | 261 | ||
| 255 | if (elog_size >= OPAL_MAX_ERRLOG_SIZE) | 262 | if (elog_size >= OPAL_MAX_ERRLOG_SIZE) |
diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c index 714ef972406b..dc487ff04704 100644 --- a/arch/powerpc/platforms/powernv/opal-flash.c +++ b/arch/powerpc/platforms/powernv/opal-flash.c | |||
| @@ -79,9 +79,6 @@ | |||
| 79 | /* XXX: Assume candidate image size is <= 1GB */ | 79 | /* XXX: Assume candidate image size is <= 1GB */ |
| 80 | #define MAX_IMAGE_SIZE 0x40000000 | 80 | #define MAX_IMAGE_SIZE 0x40000000 |
| 81 | 81 | ||
| 82 | /* Flash sg list version */ | ||
| 83 | #define SG_LIST_VERSION (1UL) | ||
| 84 | |||
| 85 | /* Image status */ | 82 | /* Image status */ |
| 86 | enum { | 83 | enum { |
| 87 | IMAGE_INVALID, | 84 | IMAGE_INVALID, |
| @@ -131,11 +128,15 @@ static DEFINE_MUTEX(image_data_mutex); | |||
| 131 | */ | 128 | */ |
| 132 | static inline void opal_flash_validate(void) | 129 | static inline void opal_flash_validate(void) |
| 133 | { | 130 | { |
| 134 | struct validate_flash_t *args_buf = &validate_flash_data; | 131 | long ret; |
| 132 | void *buf = validate_flash_data.buf; | ||
| 133 | __be32 size, result; | ||
| 135 | 134 | ||
| 136 | args_buf->status = opal_validate_flash(__pa(args_buf->buf), | 135 | ret = opal_validate_flash(__pa(buf), &size, &result); |
| 137 | &(args_buf->buf_size), | 136 | |
| 138 | &(args_buf->result)); | 137 | validate_flash_data.status = ret; |
| 138 | validate_flash_data.buf_size = be32_to_cpu(size); | ||
| 139 | validate_flash_data.result = be32_to_cpu(result); | ||
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | /* | 142 | /* |
| @@ -268,93 +269,11 @@ static ssize_t manage_store(struct kobject *kobj, | |||
| 268 | } | 269 | } |
| 269 | 270 | ||
| 270 | /* | 271 | /* |
| 271 | * Free sg list | ||
| 272 | */ | ||
| 273 | static void free_sg_list(struct opal_sg_list *list) | ||
| 274 | { | ||
| 275 | struct opal_sg_list *sg1; | ||
| 276 | while (list) { | ||
| 277 | sg1 = list->next; | ||
| 278 | kfree(list); | ||
| 279 | list = sg1; | ||
| 280 | } | ||
| 281 | list = NULL; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Build candidate image scatter gather list | ||
| 286 | * | ||
| 287 | * list format: | ||
| 288 | * ----------------------------------- | ||
| 289 | * | VER (8) | Entry length in bytes | | ||
| 290 | * ----------------------------------- | ||
| 291 | * | Pointer to next entry | | ||
| 292 | * ----------------------------------- | ||
| 293 | * | Address of memory area 1 | | ||
| 294 | * ----------------------------------- | ||
| 295 | * | Length of memory area 1 | | ||
| 296 | * ----------------------------------- | ||
| 297 | * | ......... | | ||
| 298 | * ----------------------------------- | ||
| 299 | * | ......... | | ||
| 300 | * ----------------------------------- | ||
| 301 | * | Address of memory area N | | ||
| 302 | * ----------------------------------- | ||
| 303 | * | Length of memory area N | | ||
| 304 | * ----------------------------------- | ||
| 305 | */ | ||
| 306 | static struct opal_sg_list *image_data_to_sglist(void) | ||
| 307 | { | ||
| 308 | struct opal_sg_list *sg1, *list = NULL; | ||
| 309 | void *addr; | ||
| 310 | int size; | ||
| 311 | |||
| 312 | addr = image_data.data; | ||
| 313 | size = image_data.size; | ||
| 314 | |||
| 315 | sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 316 | if (!sg1) | ||
| 317 | return NULL; | ||
| 318 | |||
| 319 | list = sg1; | ||
| 320 | sg1->num_entries = 0; | ||
| 321 | while (size > 0) { | ||
| 322 | /* Translate virtual address to physical address */ | ||
| 323 | sg1->entry[sg1->num_entries].data = | ||
| 324 | (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT); | ||
| 325 | |||
| 326 | if (size > PAGE_SIZE) | ||
| 327 | sg1->entry[sg1->num_entries].length = PAGE_SIZE; | ||
| 328 | else | ||
| 329 | sg1->entry[sg1->num_entries].length = size; | ||
| 330 | |||
| 331 | sg1->num_entries++; | ||
| 332 | if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { | ||
| 333 | sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 334 | if (!sg1->next) { | ||
| 335 | pr_err("%s : Failed to allocate memory\n", | ||
| 336 | __func__); | ||
| 337 | goto nomem; | ||
| 338 | } | ||
| 339 | |||
| 340 | sg1 = sg1->next; | ||
| 341 | sg1->num_entries = 0; | ||
| 342 | } | ||
| 343 | addr += PAGE_SIZE; | ||
| 344 | size -= PAGE_SIZE; | ||
| 345 | } | ||
| 346 | return list; | ||
| 347 | nomem: | ||
| 348 | free_sg_list(list); | ||
| 349 | return NULL; | ||
| 350 | } | ||
| 351 | |||
| 352 | /* | ||
| 353 | * OPAL update flash | 272 | * OPAL update flash |
| 354 | */ | 273 | */ |
| 355 | static int opal_flash_update(int op) | 274 | static int opal_flash_update(int op) |
| 356 | { | 275 | { |
| 357 | struct opal_sg_list *sg, *list, *next; | 276 | struct opal_sg_list *list; |
| 358 | unsigned long addr; | 277 | unsigned long addr; |
| 359 | int64_t rc = OPAL_PARAMETER; | 278 | int64_t rc = OPAL_PARAMETER; |
| 360 | 279 | ||
| @@ -364,30 +283,13 @@ static int opal_flash_update(int op) | |||
| 364 | goto flash; | 283 | goto flash; |
| 365 | } | 284 | } |
| 366 | 285 | ||
| 367 | list = image_data_to_sglist(); | 286 | list = opal_vmalloc_to_sg_list(image_data.data, image_data.size); |
| 368 | if (!list) | 287 | if (!list) |
| 369 | goto invalid_img; | 288 | goto invalid_img; |
| 370 | 289 | ||
| 371 | /* First entry address */ | 290 | /* First entry address */ |
| 372 | addr = __pa(list); | 291 | addr = __pa(list); |
| 373 | 292 | ||
| 374 | /* Translate sg list address to absolute */ | ||
| 375 | for (sg = list; sg; sg = next) { | ||
| 376 | next = sg->next; | ||
| 377 | /* Don't translate NULL pointer for last entry */ | ||
| 378 | if (sg->next) | ||
| 379 | sg->next = (struct opal_sg_list *)__pa(sg->next); | ||
| 380 | else | ||
| 381 | sg->next = NULL; | ||
| 382 | |||
| 383 | /* | ||
| 384 | * Convert num_entries to version/length format | ||
| 385 | * to satisfy OPAL. | ||
| 386 | */ | ||
| 387 | sg->num_entries = (SG_LIST_VERSION << 56) | | ||
| 388 | (sg->num_entries * sizeof(struct opal_sg_entry) + 16); | ||
| 389 | } | ||
| 390 | |||
| 391 | pr_alert("FLASH: Image is %u bytes\n", image_data.size); | 293 | pr_alert("FLASH: Image is %u bytes\n", image_data.size); |
| 392 | pr_alert("FLASH: Image update requested\n"); | 294 | pr_alert("FLASH: Image update requested\n"); |
| 393 | pr_alert("FLASH: Image will be updated during system reboot\n"); | 295 | pr_alert("FLASH: Image will be updated during system reboot\n"); |
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c index 6b614726baf2..d202f9bc3683 100644 --- a/arch/powerpc/platforms/powernv/opal-sysparam.c +++ b/arch/powerpc/platforms/powernv/opal-sysparam.c | |||
| @@ -39,10 +39,11 @@ struct param_attr { | |||
| 39 | struct kobj_attribute kobj_attr; | 39 | struct kobj_attribute kobj_attr; |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | static int opal_get_sys_param(u32 param_id, u32 length, void *buffer) | 42 | static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer) |
| 43 | { | 43 | { |
| 44 | struct opal_msg msg; | 44 | struct opal_msg msg; |
| 45 | int ret, token; | 45 | ssize_t ret; |
| 46 | int token; | ||
| 46 | 47 | ||
| 47 | token = opal_async_get_token_interruptible(); | 48 | token = opal_async_get_token_interruptible(); |
| 48 | if (token < 0) { | 49 | if (token < 0) { |
| @@ -59,7 +60,7 @@ static int opal_get_sys_param(u32 param_id, u32 length, void *buffer) | |||
| 59 | 60 | ||
| 60 | ret = opal_async_wait_response(token, &msg); | 61 | ret = opal_async_wait_response(token, &msg); |
| 61 | if (ret) { | 62 | if (ret) { |
| 62 | pr_err("%s: Failed to wait for the async response, %d\n", | 63 | pr_err("%s: Failed to wait for the async response, %zd\n", |
| 63 | __func__, ret); | 64 | __func__, ret); |
| 64 | goto out_token; | 65 | goto out_token; |
| 65 | } | 66 | } |
| @@ -111,7 +112,7 @@ static ssize_t sys_param_show(struct kobject *kobj, | |||
| 111 | { | 112 | { |
| 112 | struct param_attr *attr = container_of(kobj_attr, struct param_attr, | 113 | struct param_attr *attr = container_of(kobj_attr, struct param_attr, |
| 113 | kobj_attr); | 114 | kobj_attr); |
| 114 | int ret; | 115 | ssize_t ret; |
| 115 | 116 | ||
| 116 | mutex_lock(&opal_sysparam_mutex); | 117 | mutex_lock(&opal_sysparam_mutex); |
| 117 | ret = opal_get_sys_param(attr->param_id, attr->param_size, | 118 | ret = opal_get_sys_param(attr->param_id, attr->param_size, |
| @@ -121,9 +122,10 @@ static ssize_t sys_param_show(struct kobject *kobj, | |||
| 121 | 122 | ||
| 122 | memcpy(buf, param_data_buf, attr->param_size); | 123 | memcpy(buf, param_data_buf, attr->param_size); |
| 123 | 124 | ||
| 125 | ret = attr->param_size; | ||
| 124 | out: | 126 | out: |
| 125 | mutex_unlock(&opal_sysparam_mutex); | 127 | mutex_unlock(&opal_sysparam_mutex); |
| 126 | return ret ? ret : attr->param_size; | 128 | return ret; |
| 127 | } | 129 | } |
| 128 | 130 | ||
| 129 | static ssize_t sys_param_store(struct kobject *kobj, | 131 | static ssize_t sys_param_store(struct kobject *kobj, |
| @@ -131,14 +133,20 @@ static ssize_t sys_param_store(struct kobject *kobj, | |||
| 131 | { | 133 | { |
| 132 | struct param_attr *attr = container_of(kobj_attr, struct param_attr, | 134 | struct param_attr *attr = container_of(kobj_attr, struct param_attr, |
| 133 | kobj_attr); | 135 | kobj_attr); |
| 134 | int ret; | 136 | ssize_t ret; |
| 137 | |||
| 138 | /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */ | ||
| 139 | if (count > MAX_PARAM_DATA_LEN) | ||
| 140 | count = MAX_PARAM_DATA_LEN; | ||
| 135 | 141 | ||
| 136 | mutex_lock(&opal_sysparam_mutex); | 142 | mutex_lock(&opal_sysparam_mutex); |
| 137 | memcpy(param_data_buf, buf, count); | 143 | memcpy(param_data_buf, buf, count); |
| 138 | ret = opal_set_sys_param(attr->param_id, attr->param_size, | 144 | ret = opal_set_sys_param(attr->param_id, attr->param_size, |
| 139 | param_data_buf); | 145 | param_data_buf); |
| 140 | mutex_unlock(&opal_sysparam_mutex); | 146 | mutex_unlock(&opal_sysparam_mutex); |
| 141 | return ret ? ret : count; | 147 | if (!ret) |
| 148 | ret = count; | ||
| 149 | return ret; | ||
| 142 | } | 150 | } |
| 143 | 151 | ||
| 144 | void __init opal_sys_param_init(void) | 152 | void __init opal_sys_param_init(void) |
| @@ -214,13 +222,13 @@ void __init opal_sys_param_init(void) | |||
| 214 | } | 222 | } |
| 215 | 223 | ||
| 216 | if (of_property_read_u32_array(sysparam, "param-len", size, count)) { | 224 | if (of_property_read_u32_array(sysparam, "param-len", size, count)) { |
| 217 | pr_err("SYSPARAM: Missing propery param-len in the DT\n"); | 225 | pr_err("SYSPARAM: Missing property param-len in the DT\n"); |
| 218 | goto out_free_perm; | 226 | goto out_free_perm; |
| 219 | } | 227 | } |
| 220 | 228 | ||
| 221 | 229 | ||
| 222 | if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) { | 230 | if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) { |
| 223 | pr_err("SYSPARAM: Missing propery param-perm in the DT\n"); | 231 | pr_err("SYSPARAM: Missing property param-perm in the DT\n"); |
| 224 | goto out_free_perm; | 232 | goto out_free_perm; |
| 225 | } | 233 | } |
| 226 | 234 | ||
| @@ -233,6 +241,12 @@ void __init opal_sys_param_init(void) | |||
| 233 | 241 | ||
| 234 | /* For each of the parameters, populate the parameter attributes */ | 242 | /* For each of the parameters, populate the parameter attributes */ |
| 235 | for (i = 0; i < count; i++) { | 243 | for (i = 0; i < count; i++) { |
| 244 | if (size[i] > MAX_PARAM_DATA_LEN) { | ||
| 245 | pr_warn("SYSPARAM: Not creating parameter %d as size " | ||
| 246 | "exceeds buffer length\n", i); | ||
| 247 | continue; | ||
| 248 | } | ||
| 249 | |||
| 236 | sysfs_attr_init(&attr[i].kobj_attr.attr); | 250 | sysfs_attr_init(&attr[i].kobj_attr.attr); |
| 237 | attr[i].param_id = id[i]; | 251 | attr[i].param_id = id[i]; |
| 238 | attr[i].param_size = size[i]; | 252 | attr[i].param_size = size[i]; |
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 49d2f00019e5..360ad80c754c 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c | |||
| @@ -242,14 +242,14 @@ void opal_notifier_update_evt(uint64_t evt_mask, | |||
| 242 | void opal_notifier_enable(void) | 242 | void opal_notifier_enable(void) |
| 243 | { | 243 | { |
| 244 | int64_t rc; | 244 | int64_t rc; |
| 245 | uint64_t evt = 0; | 245 | __be64 evt = 0; |
| 246 | 246 | ||
| 247 | atomic_set(&opal_notifier_hold, 0); | 247 | atomic_set(&opal_notifier_hold, 0); |
| 248 | 248 | ||
| 249 | /* Process pending events */ | 249 | /* Process pending events */ |
| 250 | rc = opal_poll_events(&evt); | 250 | rc = opal_poll_events(&evt); |
| 251 | if (rc == OPAL_SUCCESS && evt) | 251 | if (rc == OPAL_SUCCESS && evt) |
| 252 | opal_do_notifier(evt); | 252 | opal_do_notifier(be64_to_cpu(evt)); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | void opal_notifier_disable(void) | 255 | void opal_notifier_disable(void) |
| @@ -529,7 +529,7 @@ static irqreturn_t opal_interrupt(int irq, void *data) | |||
| 529 | 529 | ||
| 530 | opal_handle_interrupt(virq_to_hw(irq), &events); | 530 | opal_handle_interrupt(virq_to_hw(irq), &events); |
| 531 | 531 | ||
| 532 | opal_do_notifier(events); | 532 | opal_do_notifier(be64_to_cpu(events)); |
| 533 | 533 | ||
| 534 | return IRQ_HANDLED; | 534 | return IRQ_HANDLED; |
| 535 | } | 535 | } |
| @@ -638,3 +638,66 @@ void opal_shutdown(void) | |||
| 638 | 638 | ||
| 639 | /* Export this so that test modules can use it */ | 639 | /* Export this so that test modules can use it */ |
| 640 | EXPORT_SYMBOL_GPL(opal_invalid_call); | 640 | EXPORT_SYMBOL_GPL(opal_invalid_call); |
| 641 | |||
| 642 | /* Convert a region of vmalloc memory to an opal sg list */ | ||
| 643 | struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, | ||
| 644 | unsigned long vmalloc_size) | ||
| 645 | { | ||
| 646 | struct opal_sg_list *sg, *first = NULL; | ||
| 647 | unsigned long i = 0; | ||
| 648 | |||
| 649 | sg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 650 | if (!sg) | ||
| 651 | goto nomem; | ||
| 652 | |||
| 653 | first = sg; | ||
| 654 | |||
| 655 | while (vmalloc_size > 0) { | ||
| 656 | uint64_t data = vmalloc_to_pfn(vmalloc_addr) << PAGE_SHIFT; | ||
| 657 | uint64_t length = min(vmalloc_size, PAGE_SIZE); | ||
| 658 | |||
| 659 | sg->entry[i].data = cpu_to_be64(data); | ||
| 660 | sg->entry[i].length = cpu_to_be64(length); | ||
| 661 | i++; | ||
| 662 | |||
| 663 | if (i >= SG_ENTRIES_PER_NODE) { | ||
| 664 | struct opal_sg_list *next; | ||
| 665 | |||
| 666 | next = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 667 | if (!next) | ||
| 668 | goto nomem; | ||
| 669 | |||
| 670 | sg->length = cpu_to_be64( | ||
| 671 | i * sizeof(struct opal_sg_entry) + 16); | ||
| 672 | i = 0; | ||
| 673 | sg->next = cpu_to_be64(__pa(next)); | ||
| 674 | sg = next; | ||
| 675 | } | ||
| 676 | |||
| 677 | vmalloc_addr += length; | ||
| 678 | vmalloc_size -= length; | ||
| 679 | } | ||
| 680 | |||
| 681 | sg->length = cpu_to_be64(i * sizeof(struct opal_sg_entry) + 16); | ||
| 682 | |||
| 683 | return first; | ||
| 684 | |||
| 685 | nomem: | ||
| 686 | pr_err("%s : Failed to allocate memory\n", __func__); | ||
| 687 | opal_free_sg_list(first); | ||
| 688 | return NULL; | ||
| 689 | } | ||
| 690 | |||
| 691 | void opal_free_sg_list(struct opal_sg_list *sg) | ||
| 692 | { | ||
| 693 | while (sg) { | ||
| 694 | uint64_t next = be64_to_cpu(sg->next); | ||
| 695 | |||
| 696 | kfree(sg); | ||
| 697 | |||
| 698 | if (next) | ||
| 699 | sg = __va(next); | ||
| 700 | else | ||
| 701 | sg = NULL; | ||
| 702 | } | ||
| 703 | } | ||
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 3b2b4fb3585b..98824aa99173 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
| @@ -343,7 +343,6 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) | |||
| 343 | pci_name(dev)); | 343 | pci_name(dev)); |
| 344 | continue; | 344 | continue; |
| 345 | } | 345 | } |
| 346 | pci_dev_get(dev); | ||
| 347 | pdn->pcidev = dev; | 346 | pdn->pcidev = dev; |
| 348 | pdn->pe_number = pe->pe_number; | 347 | pdn->pe_number = pe->pe_number; |
| 349 | pe->dma_weight += pnv_ioda_dma_weight(dev); | 348 | pe->dma_weight += pnv_ioda_dma_weight(dev); |
| @@ -462,7 +461,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev | |||
| 462 | 461 | ||
| 463 | pe = &phb->ioda.pe_array[pdn->pe_number]; | 462 | pe = &phb->ioda.pe_array[pdn->pe_number]; |
| 464 | WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops); | 463 | WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops); |
| 465 | set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table); | 464 | set_iommu_table_base(&pdev->dev, &pe->tce32_table); |
| 466 | } | 465 | } |
| 467 | 466 | ||
| 468 | static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb, | 467 | static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb, |
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 61cf8fa9c61b..8723d32632f5 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c | |||
| @@ -162,18 +162,62 @@ static void pnv_shutdown(void) | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | #ifdef CONFIG_KEXEC | 164 | #ifdef CONFIG_KEXEC |
| 165 | static void pnv_kexec_wait_secondaries_down(void) | ||
| 166 | { | ||
| 167 | int my_cpu, i, notified = -1; | ||
| 168 | |||
| 169 | my_cpu = get_cpu(); | ||
| 170 | |||
| 171 | for_each_online_cpu(i) { | ||
| 172 | uint8_t status; | ||
| 173 | int64_t rc; | ||
| 174 | |||
| 175 | if (i == my_cpu) | ||
| 176 | continue; | ||
| 177 | |||
| 178 | for (;;) { | ||
| 179 | rc = opal_query_cpu_status(get_hard_smp_processor_id(i), | ||
| 180 | &status); | ||
| 181 | if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED) | ||
| 182 | break; | ||
| 183 | barrier(); | ||
| 184 | if (i != notified) { | ||
| 185 | printk(KERN_INFO "kexec: waiting for cpu %d " | ||
| 186 | "(physical %d) to enter OPAL\n", | ||
| 187 | i, paca[i].hw_cpu_id); | ||
| 188 | notified = i; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 165 | static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) | 194 | static void pnv_kexec_cpu_down(int crash_shutdown, int secondary) |
| 166 | { | 195 | { |
| 167 | xics_kexec_teardown_cpu(secondary); | 196 | xics_kexec_teardown_cpu(secondary); |
| 168 | 197 | ||
| 169 | /* Return secondary CPUs to firmware on OPAL v3 */ | 198 | /* On OPAL v3, we return all CPUs to firmware */ |
| 170 | if (firmware_has_feature(FW_FEATURE_OPALv3) && secondary) { | 199 | |
| 200 | if (!firmware_has_feature(FW_FEATURE_OPALv3)) | ||
| 201 | return; | ||
| 202 | |||
| 203 | if (secondary) { | ||
| 204 | /* Return secondary CPUs to firmware on OPAL v3 */ | ||
| 171 | mb(); | 205 | mb(); |
| 172 | get_paca()->kexec_state = KEXEC_STATE_REAL_MODE; | 206 | get_paca()->kexec_state = KEXEC_STATE_REAL_MODE; |
| 173 | mb(); | 207 | mb(); |
| 174 | 208 | ||
| 175 | /* Return the CPU to OPAL */ | 209 | /* Return the CPU to OPAL */ |
| 176 | opal_return_cpu(); | 210 | opal_return_cpu(); |
| 211 | } else if (crash_shutdown) { | ||
| 212 | /* | ||
| 213 | * On crash, we don't wait for secondaries to go | ||
| 214 | * down as they might be unreachable or hung, so | ||
| 215 | * instead we just wait a bit and move on. | ||
| 216 | */ | ||
| 217 | mdelay(1); | ||
| 218 | } else { | ||
| 219 | /* Primary waits for the secondaries to have reached OPAL */ | ||
| 220 | pnv_kexec_wait_secondaries_down(); | ||
| 177 | } | 221 | } |
| 178 | } | 222 | } |
| 179 | #endif /* CONFIG_KEXEC */ | 223 | #endif /* CONFIG_KEXEC */ |
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 908672bdcea6..bf5fcd452168 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <asm/cputhreads.h> | 30 | #include <asm/cputhreads.h> |
| 31 | #include <asm/xics.h> | 31 | #include <asm/xics.h> |
| 32 | #include <asm/opal.h> | 32 | #include <asm/opal.h> |
| 33 | #include <asm/runlatch.h> | ||
| 33 | 34 | ||
| 34 | #include "powernv.h" | 35 | #include "powernv.h" |
| 35 | 36 | ||
| @@ -156,7 +157,9 @@ static void pnv_smp_cpu_kill_self(void) | |||
| 156 | */ | 157 | */ |
| 157 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); | 158 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); |
| 158 | while (!generic_check_cpu_restart(cpu)) { | 159 | while (!generic_check_cpu_restart(cpu)) { |
| 160 | ppc64_runlatch_off(); | ||
| 159 | power7_nap(); | 161 | power7_nap(); |
| 162 | ppc64_runlatch_on(); | ||
| 160 | if (!generic_check_cpu_restart(cpu)) { | 163 | if (!generic_check_cpu_restart(cpu)) { |
| 161 | DBG("CPU%d Unexpected exit while offline !\n", cpu); | 164 | DBG("CPU%d Unexpected exit while offline !\n", cpu); |
| 162 | /* We may be getting an IPI, so we re-enable | 165 | /* We may be getting an IPI, so we re-enable |
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 9b8e05078a63..20d62975856f 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c | |||
| @@ -88,13 +88,14 @@ void set_default_offline_state(int cpu) | |||
| 88 | 88 | ||
| 89 | static void rtas_stop_self(void) | 89 | static void rtas_stop_self(void) |
| 90 | { | 90 | { |
| 91 | struct rtas_args args = { | 91 | static struct rtas_args args = { |
| 92 | .token = cpu_to_be32(rtas_stop_self_token), | ||
| 93 | .nargs = 0, | 92 | .nargs = 0, |
| 94 | .nret = 1, | 93 | .nret = 1, |
| 95 | .rets = &args.args[0], | 94 | .rets = &args.args[0], |
| 96 | }; | 95 | }; |
| 97 | 96 | ||
| 97 | args.token = cpu_to_be32(rtas_stop_self_token); | ||
| 98 | |||
| 98 | local_irq_disable(); | 99 | local_irq_disable(); |
| 99 | 100 | ||
| 100 | BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE); | 101 | BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE); |
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 573b488fc48b..7f75c94af822 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c | |||
| @@ -100,10 +100,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz | |||
| 100 | 100 | ||
| 101 | start_pfn = base >> PAGE_SHIFT; | 101 | start_pfn = base >> PAGE_SHIFT; |
| 102 | 102 | ||
| 103 | if (!pfn_valid(start_pfn)) { | 103 | lock_device_hotplug(); |
| 104 | memblock_remove(base, memblock_size); | 104 | |
| 105 | return 0; | 105 | if (!pfn_valid(start_pfn)) |
| 106 | } | 106 | goto out; |
| 107 | 107 | ||
| 108 | block_sz = memory_block_size_bytes(); | 108 | block_sz = memory_block_size_bytes(); |
| 109 | sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; | 109 | sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; |
| @@ -114,8 +114,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz | |||
| 114 | base += MIN_MEMORY_BLOCK_SIZE; | 114 | base += MIN_MEMORY_BLOCK_SIZE; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | out: | ||
| 117 | /* Update memory regions for memory remove */ | 118 | /* Update memory regions for memory remove */ |
| 118 | memblock_remove(base, memblock_size); | 119 | memblock_remove(base, memblock_size); |
| 120 | unlock_device_hotplug(); | ||
| 119 | return 0; | 121 | return 0; |
| 120 | } | 122 | } |
| 121 | 123 | ||
