diff options
| author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 15:21:04 -0500 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-03-08 15:21:04 -0500 |
| commit | 988addf82e4c03739375279de73929580a2d4a6a (patch) | |
| tree | 989ae1cd4e264bbad80c65f04480486246e7b9f3 /drivers/misc | |
| parent | 004c1c7096659d352b83047a7593e91d8a30e3c5 (diff) | |
| parent | 25cf84cf377c0aae5dbcf937ea89bc7893db5176 (diff) | |
Merge branch 'origin' into devel-stable
Conflicts:
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
sound/soc/pxa/pxa-ssp.c
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/misc/iwmc3200top/fw-download.c | 50 | ||||
| -rw-r--r-- | drivers/misc/iwmc3200top/iwmc3200top.h | 4 | ||||
| -rw-r--r-- | drivers/misc/iwmc3200top/log.h | 31 | ||||
| -rw-r--r-- | drivers/misc/iwmc3200top/main.c | 61 | ||||
| -rw-r--r-- | drivers/misc/lkdtm.c | 472 | ||||
| -rw-r--r-- | drivers/misc/sgi-xp/xpnet.c | 2 |
7 files changed, 473 insertions, 156 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index e3551d20464f..d16af6a423fb 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -212,6 +212,15 @@ config CS5535_MFGPT_DEFAULT_IRQ | |||
| 212 | want to use a different IRQ by default. This is here for | 212 | want to use a different IRQ by default. This is here for |
| 213 | architectures to set as necessary. | 213 | architectures to set as necessary. |
| 214 | 214 | ||
| 215 | config CS5535_CLOCK_EVENT_SRC | ||
| 216 | tristate "CS5535/CS5536 high-res timer (MFGPT) events" | ||
| 217 | depends on GENERIC_TIME && GENERIC_CLOCKEVENTS && CS5535_MFGPT | ||
| 218 | help | ||
| 219 | This driver provides a clock event source based on the MFGPT | ||
| 220 | timer(s) in the CS5535 and CS5536 companion chips. | ||
| 221 | MFGPTs have a better resolution and max interval than the | ||
| 222 | generic PIT, and are suitable for use as high-res timers. | ||
| 223 | |||
| 215 | config HP_ILO | 224 | config HP_ILO |
| 216 | tristate "Channel interface driver for HP iLO/iLO2 processor" | 225 | tristate "Channel interface driver for HP iLO/iLO2 processor" |
| 217 | depends on PCI | 226 | depends on PCI |
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c index 50d431e469f5..9dbaeb574e63 100644 --- a/drivers/misc/iwmc3200top/fw-download.c +++ b/drivers/misc/iwmc3200top/fw-download.c | |||
| @@ -43,15 +43,14 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, | |||
| 43 | struct iwmct_parser *parser = &priv->parser; | 43 | struct iwmct_parser *parser = &priv->parser; |
| 44 | struct iwmct_fw_hdr *fw_hdr = &parser->versions; | 44 | struct iwmct_fw_hdr *fw_hdr = &parser->versions; |
| 45 | 45 | ||
| 46 | LOG_INFOEX(priv, INIT, "-->\n"); | 46 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); |
| 47 | 47 | ||
| 48 | LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); | 48 | LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); |
| 49 | 49 | ||
| 50 | parser->file = file; | 50 | parser->file = file; |
| 51 | parser->file_size = file_size; | 51 | parser->file_size = file_size; |
| 52 | parser->cur_pos = 0; | 52 | parser->cur_pos = 0; |
| 53 | parser->buf = NULL; | 53 | parser->entry_point = 0; |
| 54 | |||
| 55 | parser->buf = kzalloc(block_size, GFP_KERNEL); | 54 | parser->buf = kzalloc(block_size, GFP_KERNEL); |
| 56 | if (!parser->buf) { | 55 | if (!parser->buf) { |
| 57 | LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); | 56 | LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); |
| @@ -70,7 +69,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, | |||
| 70 | 69 | ||
| 71 | parser->cur_pos += sizeof(struct iwmct_fw_hdr); | 70 | parser->cur_pos += sizeof(struct iwmct_fw_hdr); |
| 72 | 71 | ||
| 73 | LOG_INFOEX(priv, INIT, "<--\n"); | 72 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); |
| 74 | return 0; | 73 | return 0; |
| 75 | } | 74 | } |
| 76 | 75 | ||
| @@ -113,7 +112,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, | |||
| 113 | struct iwmct_dbg *dbg = &priv->dbg; | 112 | struct iwmct_dbg *dbg = &priv->dbg; |
| 114 | struct iwmct_fw_sec_hdr *sec_hdr; | 113 | struct iwmct_fw_sec_hdr *sec_hdr; |
| 115 | 114 | ||
| 116 | LOG_INFOEX(priv, INIT, "-->\n"); | 115 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); |
| 117 | 116 | ||
| 118 | while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) | 117 | while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) |
| 119 | <= parser->file_size) { | 118 | <= parser->file_size) { |
| @@ -152,7 +151,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, | |||
| 152 | "finished with section cur_pos=%zd\n", parser->cur_pos); | 151 | "finished with section cur_pos=%zd\n", parser->cur_pos); |
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | LOG_INFOEX(priv, INIT, "<--\n"); | 154 | LOG_TRACE(priv, INIT, "<--\n"); |
| 156 | return 0; | 155 | return 0; |
| 157 | } | 156 | } |
| 158 | 157 | ||
| @@ -167,7 +166,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, | |||
| 167 | int ret = 0; | 166 | int ret = 0; |
| 168 | u32 cmd = 0; | 167 | u32 cmd = 0; |
| 169 | 168 | ||
| 170 | LOG_INFOEX(priv, INIT, "-->\n"); | 169 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); |
| 171 | LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", | 170 | LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", |
| 172 | addr, sec_size); | 171 | addr, sec_size); |
| 173 | 172 | ||
| @@ -229,7 +228,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, | |||
| 229 | hdr->cmd = cpu_to_le32(cmd); | 228 | hdr->cmd = cpu_to_le32(cmd); |
| 230 | /* send it down */ | 229 | /* send it down */ |
| 231 | /* TODO: add more proper sending and error checking */ | 230 | /* TODO: add more proper sending and error checking */ |
| 232 | ret = iwmct_tx(priv, 0, parser->buf, trans_size); | 231 | ret = iwmct_tx(priv, parser->buf, trans_size); |
| 233 | if (ret != 0) { | 232 | if (ret != 0) { |
| 234 | LOG_INFO(priv, FW_DOWNLOAD, | 233 | LOG_INFO(priv, FW_DOWNLOAD, |
| 235 | "iwmct_tx returned %d\n", ret); | 234 | "iwmct_tx returned %d\n", ret); |
| @@ -251,7 +250,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, | |||
| 251 | if (sent < sec_size) | 250 | if (sent < sec_size) |
| 252 | ret = -EINVAL; | 251 | ret = -EINVAL; |
| 253 | exit: | 252 | exit: |
| 254 | LOG_INFOEX(priv, INIT, "<--\n"); | 253 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); |
| 255 | return ret; | 254 | return ret; |
| 256 | } | 255 | } |
| 257 | 256 | ||
| @@ -262,7 +261,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) | |||
| 262 | int ret; | 261 | int ret; |
| 263 | u32 cmd; | 262 | u32 cmd; |
| 264 | 263 | ||
| 265 | LOG_INFOEX(priv, INIT, "-->\n"); | 264 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); |
| 266 | 265 | ||
| 267 | memset(parser->buf, 0, parser->buf_size); | 266 | memset(parser->buf, 0, parser->buf_size); |
| 268 | cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; | 267 | cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; |
| @@ -281,11 +280,11 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) | |||
| 281 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); | 280 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); |
| 282 | /* send it down */ | 281 | /* send it down */ |
| 283 | /* TODO: add more proper sending and error checking */ | 282 | /* TODO: add more proper sending and error checking */ |
| 284 | ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE); | 283 | ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE); |
| 285 | if (ret) | 284 | if (ret) |
| 286 | LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); | 285 | LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); |
| 287 | 286 | ||
| 288 | LOG_INFOEX(priv, INIT, "<--\n"); | 287 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); |
| 289 | return 0; | 288 | return 0; |
| 290 | } | 289 | } |
| 291 | 290 | ||
| @@ -298,8 +297,16 @@ int iwmct_fw_load(struct iwmct_priv *priv) | |||
| 298 | __le32 addr; | 297 | __le32 addr; |
| 299 | int ret; | 298 | int ret; |
| 300 | 299 | ||
| 301 | /* clear parser struct */ | 300 | |
| 302 | memset(&priv->parser, 0, sizeof(struct iwmct_parser)); | 301 | LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n", |
| 302 | priv->barker); | ||
| 303 | LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n", | ||
| 304 | (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); | ||
| 305 | LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n", | ||
| 306 | (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); | ||
| 307 | LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n", | ||
| 308 | (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); | ||
| 309 | |||
| 303 | 310 | ||
| 304 | /* get the firmware */ | 311 | /* get the firmware */ |
| 305 | ret = request_firmware(&raw, fw_name, &priv->func->dev); | 312 | ret = request_firmware(&raw, fw_name, &priv->func->dev); |
| @@ -317,6 +324,7 @@ int iwmct_fw_load(struct iwmct_priv *priv) | |||
| 317 | 324 | ||
| 318 | LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); | 325 | LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); |
| 319 | 326 | ||
| 327 | /* clear parser struct */ | ||
| 320 | ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); | 328 | ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); |
| 321 | if (ret < 0) { | 329 | if (ret < 0) { |
| 322 | LOG_ERROR(priv, FW_DOWNLOAD, | 330 | LOG_ERROR(priv, FW_DOWNLOAD, |
| @@ -324,7 +332,6 @@ int iwmct_fw_load(struct iwmct_priv *priv) | |||
| 324 | goto exit; | 332 | goto exit; |
| 325 | } | 333 | } |
| 326 | 334 | ||
| 327 | /* checksum */ | ||
| 328 | if (!iwmct_checksum(priv)) { | 335 | if (!iwmct_checksum(priv)) { |
| 329 | LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); | 336 | LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); |
| 330 | ret = -EINVAL; | 337 | ret = -EINVAL; |
| @@ -333,23 +340,18 @@ int iwmct_fw_load(struct iwmct_priv *priv) | |||
| 333 | 340 | ||
| 334 | /* download firmware to device */ | 341 | /* download firmware to device */ |
| 335 | while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { | 342 | while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { |
| 336 | if (iwmct_download_section(priv, pdata, len, addr)) { | 343 | ret = iwmct_download_section(priv, pdata, len, addr); |
| 344 | if (ret) { | ||
| 337 | LOG_ERROR(priv, FW_DOWNLOAD, | 345 | LOG_ERROR(priv, FW_DOWNLOAD, |
| 338 | "%s download section failed\n", fw_name); | 346 | "%s download section failed\n", fw_name); |
| 339 | ret = -EIO; | ||
| 340 | goto exit; | 347 | goto exit; |
| 341 | } | 348 | } |
| 342 | } | 349 | } |
| 343 | 350 | ||
| 344 | iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); | 351 | ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); |
| 345 | 352 | ||
| 346 | exit: | 353 | exit: |
| 347 | kfree(priv->parser.buf); | 354 | kfree(priv->parser.buf); |
| 348 | 355 | release_firmware(raw); | |
| 349 | if (raw) | ||
| 350 | release_firmware(raw); | ||
| 351 | |||
| 352 | raw = NULL; | ||
| 353 | |||
| 354 | return ret; | 356 | return ret; |
| 355 | } | 357 | } |
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h index 43bd510e1872..740ff0738ea8 100644 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ b/drivers/misc/iwmc3200top/iwmc3200top.h | |||
| @@ -196,9 +196,7 @@ struct iwmct_priv { | |||
| 196 | struct list_head read_req_list; | 196 | struct list_head read_req_list; |
| 197 | }; | 197 | }; |
| 198 | 198 | ||
| 199 | extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr, | 199 | extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count); |
| 200 | void *src, int count); | ||
| 201 | |||
| 202 | extern int iwmct_fw_load(struct iwmct_priv *priv); | 200 | extern int iwmct_fw_load(struct iwmct_priv *priv); |
| 203 | 201 | ||
| 204 | extern void iwmct_dbg_init_params(struct iwmct_priv *drv); | 202 | extern void iwmct_dbg_init_params(struct iwmct_priv *drv); |
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h index aba8121f978c..4434bb16cea7 100644 --- a/drivers/misc/iwmc3200top/log.h +++ b/drivers/misc/iwmc3200top/log.h | |||
| @@ -37,13 +37,26 @@ | |||
| 37 | #define LOG_SEV_INFO 3 | 37 | #define LOG_SEV_INFO 3 |
| 38 | #define LOG_SEV_INFOEX 4 | 38 | #define LOG_SEV_INFOEX 4 |
| 39 | 39 | ||
| 40 | #define LOG_SEV_FILTER_ALL \ | 40 | /* Log levels not defined for FW */ |
| 41 | (BIT(LOG_SEV_CRITICAL) | \ | 41 | #define LOG_SEV_TRACE 5 |
| 42 | BIT(LOG_SEV_ERROR) | \ | 42 | #define LOG_SEV_DUMP 6 |
| 43 | BIT(LOG_SEV_WARNING) | \ | 43 | |
| 44 | BIT(LOG_SEV_INFO) | \ | 44 | #define LOG_SEV_FW_FILTER_ALL \ |
| 45 | (BIT(LOG_SEV_CRITICAL) | \ | ||
| 46 | BIT(LOG_SEV_ERROR) | \ | ||
| 47 | BIT(LOG_SEV_WARNING) | \ | ||
| 48 | BIT(LOG_SEV_INFO) | \ | ||
| 45 | BIT(LOG_SEV_INFOEX)) | 49 | BIT(LOG_SEV_INFOEX)) |
| 46 | 50 | ||
| 51 | #define LOG_SEV_FILTER_ALL \ | ||
| 52 | (BIT(LOG_SEV_CRITICAL) | \ | ||
| 53 | BIT(LOG_SEV_ERROR) | \ | ||
| 54 | BIT(LOG_SEV_WARNING) | \ | ||
| 55 | BIT(LOG_SEV_INFO) | \ | ||
| 56 | BIT(LOG_SEV_INFOEX) | \ | ||
| 57 | BIT(LOG_SEV_TRACE) | \ | ||
| 58 | BIT(LOG_SEV_DUMP)) | ||
| 59 | |||
| 47 | /* log source */ | 60 | /* log source */ |
| 48 | #define LOG_SRC_INIT 0 | 61 | #define LOG_SRC_INIT 0 |
| 49 | #define LOG_SRC_DEBUGFS 1 | 62 | #define LOG_SRC_DEBUGFS 1 |
| @@ -104,16 +117,16 @@ do { \ | |||
| 104 | __func__, __LINE__, ##args); \ | 117 | __func__, __LINE__, ##args); \ |
| 105 | } while (0) | 118 | } while (0) |
| 106 | 119 | ||
| 107 | #define LOG_INFOEX(priv, src, fmt, args...) \ | 120 | #define LOG_TRACE(priv, src, fmt, args...) \ |
| 108 | do { \ | 121 | do { \ |
| 109 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \ | 122 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \ |
| 110 | dev_dbg(priv2dev(priv), "%s %d: " fmt, \ | 123 | dev_dbg(priv2dev(priv), "%s %d: " fmt, \ |
| 111 | __func__, __LINE__, ##args); \ | 124 | __func__, __LINE__, ##args); \ |
| 112 | } while (0) | 125 | } while (0) |
| 113 | 126 | ||
| 114 | #define LOG_HEXDUMP(src, ptr, len) \ | 127 | #define LOG_HEXDUMP(src, ptr, len) \ |
| 115 | do { \ | 128 | do { \ |
| 116 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \ | 129 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \ |
| 117 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ | 130 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ |
| 118 | 16, 1, ptr, len, false); \ | 131 | 16, 1, ptr, len, false); \ |
| 119 | } while (0) | 132 | } while (0) |
| @@ -142,7 +155,7 @@ ssize_t store_iwmct_log_level_fw(struct device *d, | |||
| 142 | #define LOG_ERROR(priv, src, fmt, args...) | 155 | #define LOG_ERROR(priv, src, fmt, args...) |
| 143 | #define LOG_WARNING(priv, src, fmt, args...) | 156 | #define LOG_WARNING(priv, src, fmt, args...) |
| 144 | #define LOG_INFO(priv, src, fmt, args...) | 157 | #define LOG_INFO(priv, src, fmt, args...) |
| 145 | #define LOG_INFOEX(priv, src, fmt, args...) | 158 | #define LOG_TRACE(priv, src, fmt, args...) |
| 146 | #define LOG_HEXDUMP(src, ptr, len) | 159 | #define LOG_HEXDUMP(src, ptr, len) |
| 147 | 160 | ||
| 148 | static inline void iwmct_log_top_message(struct iwmct_priv *priv, | 161 | static inline void iwmct_log_top_message(struct iwmct_priv *priv, |
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index fafcaa481d74..3b7292a5cea9 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c | |||
| @@ -49,6 +49,20 @@ MODULE_LICENSE("GPL"); | |||
| 49 | MODULE_AUTHOR(DRIVER_COPYRIGHT); | 49 | MODULE_AUTHOR(DRIVER_COPYRIGHT); |
| 50 | MODULE_FIRMWARE(FW_NAME(FW_API_VER)); | 50 | MODULE_FIRMWARE(FW_NAME(FW_API_VER)); |
| 51 | 51 | ||
| 52 | |||
| 53 | static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
| 54 | { | ||
| 55 | return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count); | ||
| 56 | |||
| 57 | } | ||
| 58 | int iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
| 59 | { | ||
| 60 | int ret; | ||
| 61 | sdio_claim_host(priv->func); | ||
| 62 | ret = __iwmct_tx(priv, src, count); | ||
| 63 | sdio_release_host(priv->func); | ||
| 64 | return ret; | ||
| 65 | } | ||
| 52 | /* | 66 | /* |
| 53 | * This workers main task is to wait for OP_OPR_ALIVE | 67 | * This workers main task is to wait for OP_OPR_ALIVE |
| 54 | * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. | 68 | * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. |
| @@ -66,7 +80,7 @@ static void iwmct_rescan_worker(struct work_struct *ws) | |||
| 66 | 80 | ||
| 67 | ret = bus_rescan_devices(priv->func->dev.bus); | 81 | ret = bus_rescan_devices(priv->func->dev.bus); |
| 68 | if (ret < 0) | 82 | if (ret < 0) |
| 69 | LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n"); | 83 | LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n"); |
| 70 | } | 84 | } |
| 71 | 85 | ||
| 72 | static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) | 86 | static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) |
| @@ -137,7 +151,7 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) | |||
| 137 | int ret; | 151 | int ret; |
| 138 | u8 *buf; | 152 | u8 *buf; |
| 139 | 153 | ||
| 140 | LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n"); | 154 | LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n"); |
| 141 | 155 | ||
| 142 | /* add padding to 256 for IWMC */ | 156 | /* add padding to 256 for IWMC */ |
| 143 | ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; | 157 | ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; |
| @@ -158,27 +172,12 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) | |||
| 158 | } | 172 | } |
| 159 | 173 | ||
| 160 | memcpy(buf, cmd, len); | 174 | memcpy(buf, cmd, len); |
| 161 | 175 | ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE); | |
| 162 | sdio_claim_host(priv->func); | ||
| 163 | ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf, | ||
| 164 | FW_HCMD_BLOCK_SIZE); | ||
| 165 | sdio_release_host(priv->func); | ||
| 166 | 176 | ||
| 167 | kfree(buf); | 177 | kfree(buf); |
| 168 | return ret; | 178 | return ret; |
| 169 | } | 179 | } |
| 170 | 180 | ||
| 171 | int iwmct_tx(struct iwmct_priv *priv, unsigned int addr, | ||
| 172 | void *src, int count) | ||
| 173 | { | ||
| 174 | int ret; | ||
| 175 | |||
| 176 | sdio_claim_host(priv->func); | ||
| 177 | ret = sdio_memcpy_toio(priv->func, addr, src, count); | ||
| 178 | sdio_release_host(priv->func); | ||
| 179 | |||
| 180 | return ret; | ||
| 181 | } | ||
| 182 | 181 | ||
| 183 | static void iwmct_irq_read_worker(struct work_struct *ws) | 182 | static void iwmct_irq_read_worker(struct work_struct *ws) |
| 184 | { | 183 | { |
| @@ -192,7 +191,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) | |||
| 192 | 191 | ||
| 193 | priv = container_of(ws, struct iwmct_priv, isr_worker); | 192 | priv = container_of(ws, struct iwmct_priv, isr_worker); |
| 194 | 193 | ||
| 195 | LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); | 194 | LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); |
| 196 | 195 | ||
| 197 | /* --------------------- Handshake with device -------------------- */ | 196 | /* --------------------- Handshake with device -------------------- */ |
| 198 | sdio_claim_host(priv->func); | 197 | sdio_claim_host(priv->func); |
| @@ -273,8 +272,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) | |||
| 273 | 272 | ||
| 274 | if (barker & BARKER_DNLOAD_SYNC_MSK) { | 273 | if (barker & BARKER_DNLOAD_SYNC_MSK) { |
| 275 | /* Send the same barker back */ | 274 | /* Send the same barker back */ |
| 276 | ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, | 275 | ret = __iwmct_tx(priv, buf, iosize); |
| 277 | buf, iosize); | ||
| 278 | if (ret) { | 276 | if (ret) { |
| 279 | LOG_ERROR(priv, IRQ, | 277 | LOG_ERROR(priv, IRQ, |
| 280 | "error %d echoing barker\n", ret); | 278 | "error %d echoing barker\n", ret); |
| @@ -292,15 +290,6 @@ static void iwmct_irq_read_worker(struct work_struct *ws) | |||
| 292 | 290 | ||
| 293 | sdio_release_host(priv->func); | 291 | sdio_release_host(priv->func); |
| 294 | 292 | ||
| 295 | |||
| 296 | LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker); | ||
| 297 | LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n", | ||
| 298 | (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); | ||
| 299 | LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n", | ||
| 300 | (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); | ||
| 301 | LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n", | ||
| 302 | (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); | ||
| 303 | |||
| 304 | if (priv->dbg.fw_download) | 293 | if (priv->dbg.fw_download) |
| 305 | iwmct_fw_load(priv); | 294 | iwmct_fw_load(priv); |
| 306 | else | 295 | else |
| @@ -312,7 +301,7 @@ exit_release: | |||
| 312 | sdio_release_host(priv->func); | 301 | sdio_release_host(priv->func); |
| 313 | exit: | 302 | exit: |
| 314 | kfree(buf); | 303 | kfree(buf); |
| 315 | LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n"); | 304 | LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n"); |
| 316 | } | 305 | } |
| 317 | 306 | ||
| 318 | static void iwmct_irq(struct sdio_func *func) | 307 | static void iwmct_irq(struct sdio_func *func) |
| @@ -325,12 +314,12 @@ static void iwmct_irq(struct sdio_func *func) | |||
| 325 | 314 | ||
| 326 | priv = sdio_get_drvdata(func); | 315 | priv = sdio_get_drvdata(func); |
| 327 | 316 | ||
| 328 | LOG_INFO(priv, IRQ, "enter iwmct_irq\n"); | 317 | LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); |
| 329 | 318 | ||
| 330 | /* read the function's status register */ | 319 | /* read the function's status register */ |
| 331 | val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); | 320 | val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); |
| 332 | 321 | ||
| 333 | LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); | 322 | LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); |
| 334 | 323 | ||
| 335 | if (!val) { | 324 | if (!val) { |
| 336 | LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); | 325 | LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); |
| @@ -372,7 +361,7 @@ static void iwmct_irq(struct sdio_func *func) | |||
| 372 | 361 | ||
| 373 | queue_work(priv->wq, &priv->isr_worker); | 362 | queue_work(priv->wq, &priv->isr_worker); |
| 374 | 363 | ||
| 375 | LOG_INFO(priv, IRQ, "exit iwmct_irq\n"); | 364 | LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); |
| 376 | 365 | ||
| 377 | return; | 366 | return; |
| 378 | 367 | ||
| @@ -608,8 +597,6 @@ static void iwmct_remove(struct sdio_func *func) | |||
| 608 | struct iwmct_work_struct *read_req; | 597 | struct iwmct_work_struct *read_req; |
| 609 | struct iwmct_priv *priv = sdio_get_drvdata(func); | 598 | struct iwmct_priv *priv = sdio_get_drvdata(func); |
| 610 | 599 | ||
| 611 | priv = sdio_get_drvdata(func); | ||
| 612 | |||
| 613 | LOG_INFO(priv, INIT, "enter\n"); | 600 | LOG_INFO(priv, INIT, "enter\n"); |
| 614 | 601 | ||
| 615 | sdio_claim_host(func); | 602 | sdio_claim_host(func); |
| @@ -660,7 +647,7 @@ static int __init iwmct_init(void) | |||
| 660 | 647 | ||
| 661 | /* Default log filter settings */ | 648 | /* Default log filter settings */ |
| 662 | iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); | 649 | iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); |
| 663 | iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL); | 650 | iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL); |
| 664 | iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); | 651 | iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); |
| 665 | 652 | ||
| 666 | rc = sdio_register_driver(&iwmct_driver); | 653 | rc = sdio_register_driver(&iwmct_driver); |
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 3648b23d5c92..4a0648301fdf 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
| @@ -26,21 +26,9 @@ | |||
| 26 | * It is adapted from the Linux Kernel Dump Test Tool by | 26 | * It is adapted from the Linux Kernel Dump Test Tool by |
| 27 | * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> | 27 | * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> |
| 28 | * | 28 | * |
| 29 | * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<> | 29 | * Debugfs support added by Simon Kagstrom <simon.kagstrom@netinsight.net> |
| 30 | * [cpoint_count={>0}] | ||
| 31 | * | 30 | * |
| 32 | * recur_count : Recursion level for the stack overflow test. Default is 10. | 31 | * See Documentation/fault-injection/provoke-crashes.txt for instructions |
| 33 | * | ||
| 34 | * cpoint_name : Crash point where the kernel is to be crashed. It can be | ||
| 35 | * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY, | ||
| 36 | * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD, | ||
| 37 | * IDE_CORE_CP | ||
| 38 | * | ||
| 39 | * cpoint_type : Indicates the action to be taken on hitting the crash point. | ||
| 40 | * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW | ||
| 41 | * | ||
| 42 | * cpoint_count : Indicates the number of times the crash point is to be hit | ||
| 43 | * to trigger an action. The default is 10. | ||
| 44 | */ | 32 | */ |
| 45 | 33 | ||
| 46 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
| @@ -53,13 +41,12 @@ | |||
| 53 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
| 54 | #include <linux/hrtimer.h> | 42 | #include <linux/hrtimer.h> |
| 55 | #include <scsi/scsi_cmnd.h> | 43 | #include <scsi/scsi_cmnd.h> |
| 44 | #include <linux/debugfs.h> | ||
| 56 | 45 | ||
| 57 | #ifdef CONFIG_IDE | 46 | #ifdef CONFIG_IDE |
| 58 | #include <linux/ide.h> | 47 | #include <linux/ide.h> |
| 59 | #endif | 48 | #endif |
| 60 | 49 | ||
| 61 | #define NUM_CPOINTS 8 | ||
| 62 | #define NUM_CPOINT_TYPES 5 | ||
| 63 | #define DEFAULT_COUNT 10 | 50 | #define DEFAULT_COUNT 10 |
| 64 | #define REC_NUM_DEFAULT 10 | 51 | #define REC_NUM_DEFAULT 10 |
| 65 | 52 | ||
| @@ -72,7 +59,8 @@ enum cname { | |||
| 72 | MEM_SWAPOUT, | 59 | MEM_SWAPOUT, |
| 73 | TIMERADD, | 60 | TIMERADD, |
| 74 | SCSI_DISPATCH_CMD, | 61 | SCSI_DISPATCH_CMD, |
| 75 | IDE_CORE_CP | 62 | IDE_CORE_CP, |
| 63 | DIRECT, | ||
| 76 | }; | 64 | }; |
| 77 | 65 | ||
| 78 | enum ctype { | 66 | enum ctype { |
| @@ -81,7 +69,11 @@ enum ctype { | |||
| 81 | BUG, | 69 | BUG, |
| 82 | EXCEPTION, | 70 | EXCEPTION, |
| 83 | LOOP, | 71 | LOOP, |
| 84 | OVERFLOW | 72 | OVERFLOW, |
| 73 | CORRUPT_STACK, | ||
| 74 | UNALIGNED_LOAD_STORE_WRITE, | ||
| 75 | OVERWRITE_ALLOCATION, | ||
| 76 | WRITE_AFTER_FREE, | ||
| 85 | }; | 77 | }; |
| 86 | 78 | ||
| 87 | static char* cp_name[] = { | 79 | static char* cp_name[] = { |
| @@ -92,7 +84,8 @@ static char* cp_name[] = { | |||
| 92 | "MEM_SWAPOUT", | 84 | "MEM_SWAPOUT", |
| 93 | "TIMERADD", | 85 | "TIMERADD", |
| 94 | "SCSI_DISPATCH_CMD", | 86 | "SCSI_DISPATCH_CMD", |
| 95 | "IDE_CORE_CP" | 87 | "IDE_CORE_CP", |
| 88 | "DIRECT", | ||
| 96 | }; | 89 | }; |
| 97 | 90 | ||
| 98 | static char* cp_type[] = { | 91 | static char* cp_type[] = { |
| @@ -100,7 +93,11 @@ static char* cp_type[] = { | |||
| 100 | "BUG", | 93 | "BUG", |
| 101 | "EXCEPTION", | 94 | "EXCEPTION", |
| 102 | "LOOP", | 95 | "LOOP", |
| 103 | "OVERFLOW" | 96 | "OVERFLOW", |
| 97 | "CORRUPT_STACK", | ||
| 98 | "UNALIGNED_LOAD_STORE_WRITE", | ||
| 99 | "OVERWRITE_ALLOCATION", | ||
| 100 | "WRITE_AFTER_FREE", | ||
| 104 | }; | 101 | }; |
| 105 | 102 | ||
| 106 | static struct jprobe lkdtm; | 103 | static struct jprobe lkdtm; |
| @@ -193,34 +190,66 @@ int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, | |||
| 193 | } | 190 | } |
| 194 | #endif | 191 | #endif |
| 195 | 192 | ||
| 193 | /* Return the crashpoint number or NONE if the name is invalid */ | ||
| 194 | static enum ctype parse_cp_type(const char *what, size_t count) | ||
| 195 | { | ||
| 196 | int i; | ||
| 197 | |||
| 198 | for (i = 0; i < ARRAY_SIZE(cp_type); i++) { | ||
| 199 | if (!strcmp(what, cp_type[i])) | ||
| 200 | return i + 1; | ||
| 201 | } | ||
| 202 | |||
| 203 | return NONE; | ||
| 204 | } | ||
| 205 | |||
| 206 | static const char *cp_type_to_str(enum ctype type) | ||
| 207 | { | ||
| 208 | if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type)) | ||
| 209 | return "None"; | ||
| 210 | |||
| 211 | return cp_type[type - 1]; | ||
| 212 | } | ||
| 213 | |||
| 214 | static const char *cp_name_to_str(enum cname name) | ||
| 215 | { | ||
| 216 | if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) | ||
| 217 | return "INVALID"; | ||
| 218 | |||
| 219 | return cp_name[name - 1]; | ||
| 220 | } | ||
| 221 | |||
| 222 | |||
| 196 | static int lkdtm_parse_commandline(void) | 223 | static int lkdtm_parse_commandline(void) |
| 197 | { | 224 | { |
| 198 | int i; | 225 | int i; |
| 199 | 226 | ||
| 200 | if (cpoint_name == NULL || cpoint_type == NULL || | 227 | if (cpoint_count < 1 || recur_count < 1) |
| 201 | cpoint_count < 1 || recur_count < 1) | ||
| 202 | return -EINVAL; | 228 | return -EINVAL; |
| 203 | 229 | ||
| 204 | for (i = 0; i < NUM_CPOINTS; ++i) { | 230 | count = cpoint_count; |
| 231 | |||
| 232 | /* No special parameters */ | ||
| 233 | if (!cpoint_type && !cpoint_name) | ||
| 234 | return 0; | ||
| 235 | |||
| 236 | /* Neither or both of these need to be set */ | ||
| 237 | if (!cpoint_type || !cpoint_name) | ||
| 238 | return -EINVAL; | ||
| 239 | |||
| 240 | cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); | ||
| 241 | if (cptype == NONE) | ||
| 242 | return -EINVAL; | ||
| 243 | |||
| 244 | for (i = 0; i < ARRAY_SIZE(cp_name); i++) { | ||
| 205 | if (!strcmp(cpoint_name, cp_name[i])) { | 245 | if (!strcmp(cpoint_name, cp_name[i])) { |
| 206 | cpoint = i + 1; | 246 | cpoint = i + 1; |
| 207 | break; | 247 | return 0; |
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | for (i = 0; i < NUM_CPOINT_TYPES; ++i) { | ||
| 212 | if (!strcmp(cpoint_type, cp_type[i])) { | ||
| 213 | cptype = i + 1; | ||
| 214 | break; | ||
| 215 | } | 248 | } |
| 216 | } | 249 | } |
| 217 | 250 | ||
| 218 | if (cpoint == INVALID || cptype == NONE) | 251 | /* Could not find a valid crash point */ |
| 219 | return -EINVAL; | 252 | return -EINVAL; |
| 220 | |||
| 221 | count = cpoint_count; | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | } | 253 | } |
| 225 | 254 | ||
| 226 | static int recursive_loop(int a) | 255 | static int recursive_loop(int a) |
| @@ -235,53 +264,92 @@ static int recursive_loop(int a) | |||
| 235 | return recursive_loop(a); | 264 | return recursive_loop(a); |
| 236 | } | 265 | } |
| 237 | 266 | ||
| 238 | void lkdtm_handler(void) | 267 | static void lkdtm_do_action(enum ctype which) |
| 239 | { | 268 | { |
| 240 | printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n", | 269 | switch (which) { |
| 241 | cpoint_name, cpoint_type); | 270 | case PANIC: |
| 242 | --count; | 271 | panic("dumptest"); |
| 272 | break; | ||
| 273 | case BUG: | ||
| 274 | BUG(); | ||
| 275 | break; | ||
| 276 | case EXCEPTION: | ||
| 277 | *((int *) 0) = 0; | ||
| 278 | break; | ||
| 279 | case LOOP: | ||
| 280 | for (;;) | ||
| 281 | ; | ||
| 282 | break; | ||
| 283 | case OVERFLOW: | ||
| 284 | (void) recursive_loop(0); | ||
| 285 | break; | ||
| 286 | case CORRUPT_STACK: { | ||
| 287 | volatile u32 data[8]; | ||
| 288 | volatile u32 *p = data; | ||
| 289 | |||
| 290 | p[12] = 0x12345678; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | case UNALIGNED_LOAD_STORE_WRITE: { | ||
| 294 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, | ||
| 295 | 3, 4, 5}; | ||
| 296 | u32 *p; | ||
| 297 | u32 val = 0x12345678; | ||
| 298 | |||
| 299 | p = (u32 *)(data + 1); | ||
| 300 | if (*p == 0) | ||
| 301 | val = 0x87654321; | ||
| 302 | *p = val; | ||
| 303 | break; | ||
| 304 | } | ||
| 305 | case OVERWRITE_ALLOCATION: { | ||
| 306 | size_t len = 1020; | ||
| 307 | u32 *data = kmalloc(len, GFP_KERNEL); | ||
| 308 | |||
| 309 | data[1024 / sizeof(u32)] = 0x12345678; | ||
| 310 | kfree(data); | ||
| 311 | break; | ||
| 312 | } | ||
| 313 | case WRITE_AFTER_FREE: { | ||
| 314 | size_t len = 1024; | ||
| 315 | u32 *data = kmalloc(len, GFP_KERNEL); | ||
| 316 | |||
| 317 | kfree(data); | ||
| 318 | schedule(); | ||
| 319 | memset(data, 0x78, len); | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | case NONE: | ||
| 323 | default: | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | |||
| 327 | } | ||
| 328 | |||
| 329 | static void lkdtm_handler(void) | ||
| 330 | { | ||
| 331 | count--; | ||
| 332 | printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", | ||
| 333 | cp_name_to_str(cpoint), cp_type_to_str(cptype), count); | ||
| 243 | 334 | ||
| 244 | if (count == 0) { | 335 | if (count == 0) { |
| 245 | switch (cptype) { | 336 | lkdtm_do_action(cptype); |
| 246 | case NONE: | ||
| 247 | break; | ||
| 248 | case PANIC: | ||
| 249 | printk(KERN_INFO "lkdtm : PANIC\n"); | ||
| 250 | panic("dumptest"); | ||
| 251 | break; | ||
| 252 | case BUG: | ||
| 253 | printk(KERN_INFO "lkdtm : BUG\n"); | ||
| 254 | BUG(); | ||
| 255 | break; | ||
| 256 | case EXCEPTION: | ||
| 257 | printk(KERN_INFO "lkdtm : EXCEPTION\n"); | ||
| 258 | *((int *) 0) = 0; | ||
| 259 | break; | ||
| 260 | case LOOP: | ||
| 261 | printk(KERN_INFO "lkdtm : LOOP\n"); | ||
| 262 | for (;;); | ||
| 263 | break; | ||
| 264 | case OVERFLOW: | ||
| 265 | printk(KERN_INFO "lkdtm : OVERFLOW\n"); | ||
| 266 | (void) recursive_loop(0); | ||
| 267 | break; | ||
| 268 | default: | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | count = cpoint_count; | 337 | count = cpoint_count; |
| 272 | } | 338 | } |
| 273 | } | 339 | } |
| 274 | 340 | ||
| 275 | static int __init lkdtm_module_init(void) | 341 | static int lkdtm_register_cpoint(enum cname which) |
| 276 | { | 342 | { |
| 277 | int ret; | 343 | int ret; |
| 278 | 344 | ||
| 279 | if (lkdtm_parse_commandline() == -EINVAL) { | 345 | cpoint = INVALID; |
| 280 | printk(KERN_INFO "lkdtm : Invalid command\n"); | 346 | if (lkdtm.entry != NULL) |
| 281 | return -EINVAL; | 347 | unregister_jprobe(&lkdtm); |
| 282 | } | ||
| 283 | 348 | ||
| 284 | switch (cpoint) { | 349 | switch (which) { |
| 350 | case DIRECT: | ||
| 351 | lkdtm_do_action(cptype); | ||
| 352 | return 0; | ||
| 285 | case INT_HARDWARE_ENTRY: | 353 | case INT_HARDWARE_ENTRY: |
| 286 | lkdtm.kp.symbol_name = "do_IRQ"; | 354 | lkdtm.kp.symbol_name = "do_IRQ"; |
| 287 | lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; | 355 | lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; |
| @@ -315,28 +383,268 @@ static int __init lkdtm_module_init(void) | |||
| 315 | lkdtm.kp.symbol_name = "generic_ide_ioctl"; | 383 | lkdtm.kp.symbol_name = "generic_ide_ioctl"; |
| 316 | lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; | 384 | lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; |
| 317 | #else | 385 | #else |
| 318 | printk(KERN_INFO "lkdtm : Crash point not available\n"); | 386 | printk(KERN_INFO "lkdtm: Crash point not available\n"); |
| 387 | return -EINVAL; | ||
| 319 | #endif | 388 | #endif |
| 320 | break; | 389 | break; |
| 321 | default: | 390 | default: |
| 322 | printk(KERN_INFO "lkdtm : Invalid Crash Point\n"); | 391 | printk(KERN_INFO "lkdtm: Invalid Crash Point\n"); |
| 323 | break; | 392 | return -EINVAL; |
| 324 | } | 393 | } |
| 325 | 394 | ||
| 395 | cpoint = which; | ||
| 326 | if ((ret = register_jprobe(&lkdtm)) < 0) { | 396 | if ((ret = register_jprobe(&lkdtm)) < 0) { |
| 327 | printk(KERN_INFO "lkdtm : Couldn't register jprobe\n"); | 397 | printk(KERN_INFO "lkdtm: Couldn't register jprobe\n"); |
| 328 | return ret; | 398 | cpoint = INVALID; |
| 399 | } | ||
| 400 | |||
| 401 | return ret; | ||
| 402 | } | ||
| 403 | |||
| 404 | static ssize_t do_register_entry(enum cname which, struct file *f, | ||
| 405 | const char __user *user_buf, size_t count, loff_t *off) | ||
| 406 | { | ||
| 407 | char *buf; | ||
| 408 | int err; | ||
| 409 | |||
| 410 | if (count >= PAGE_SIZE) | ||
| 411 | return -EINVAL; | ||
| 412 | |||
| 413 | buf = (char *)__get_free_page(GFP_KERNEL); | ||
| 414 | if (!buf) | ||
| 415 | return -ENOMEM; | ||
| 416 | if (copy_from_user(buf, user_buf, count)) { | ||
| 417 | free_page((unsigned long) buf); | ||
| 418 | return -EFAULT; | ||
| 419 | } | ||
| 420 | /* NULL-terminate and remove enter */ | ||
| 421 | buf[count] = '\0'; | ||
| 422 | strim(buf); | ||
| 423 | |||
| 424 | cptype = parse_cp_type(buf, count); | ||
| 425 | free_page((unsigned long) buf); | ||
| 426 | |||
| 427 | if (cptype == NONE) | ||
| 428 | return -EINVAL; | ||
| 429 | |||
| 430 | err = lkdtm_register_cpoint(which); | ||
| 431 | if (err < 0) | ||
| 432 | return err; | ||
| 433 | |||
| 434 | *off += count; | ||
| 435 | |||
| 436 | return count; | ||
| 437 | } | ||
| 438 | |||
| 439 | /* Generic read callback that just prints out the available crash types */ | ||
| 440 | static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, | ||
| 441 | size_t count, loff_t *off) | ||
| 442 | { | ||
| 443 | char *buf; | ||
| 444 | int i, n, out; | ||
| 445 | |||
| 446 | buf = (char *)__get_free_page(GFP_KERNEL); | ||
| 447 | |||
| 448 | n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); | ||
| 449 | for (i = 0; i < ARRAY_SIZE(cp_type); i++) | ||
| 450 | n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); | ||
| 451 | buf[n] = '\0'; | ||
| 452 | |||
| 453 | out = simple_read_from_buffer(user_buf, count, off, | ||
| 454 | buf, n); | ||
| 455 | free_page((unsigned long) buf); | ||
| 456 | |||
| 457 | return out; | ||
| 458 | } | ||
| 459 | |||
| 460 | static int lkdtm_debugfs_open(struct inode *inode, struct file *file) | ||
| 461 | { | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | static ssize_t int_hardware_entry(struct file *f, const char __user *buf, | ||
| 467 | size_t count, loff_t *off) | ||
| 468 | { | ||
| 469 | return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off); | ||
| 470 | } | ||
| 471 | |||
| 472 | static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, | ||
| 473 | size_t count, loff_t *off) | ||
| 474 | { | ||
| 475 | return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off); | ||
| 476 | } | ||
| 477 | |||
| 478 | static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, | ||
| 479 | size_t count, loff_t *off) | ||
| 480 | { | ||
| 481 | return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off); | ||
| 482 | } | ||
| 483 | |||
| 484 | static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, | ||
| 485 | size_t count, loff_t *off) | ||
| 486 | { | ||
| 487 | return do_register_entry(FS_DEVRW, f, buf, count, off); | ||
| 488 | } | ||
| 489 | |||
| 490 | static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, | ||
| 491 | size_t count, loff_t *off) | ||
| 492 | { | ||
| 493 | return do_register_entry(MEM_SWAPOUT, f, buf, count, off); | ||
| 494 | } | ||
| 495 | |||
| 496 | static ssize_t timeradd_entry(struct file *f, const char __user *buf, | ||
| 497 | size_t count, loff_t *off) | ||
| 498 | { | ||
| 499 | return do_register_entry(TIMERADD, f, buf, count, off); | ||
| 500 | } | ||
| 501 | |||
| 502 | static ssize_t scsi_dispatch_cmd_entry(struct file *f, | ||
| 503 | const char __user *buf, size_t count, loff_t *off) | ||
| 504 | { | ||
| 505 | return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off); | ||
| 506 | } | ||
| 507 | |||
| 508 | static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, | ||
| 509 | size_t count, loff_t *off) | ||
| 510 | { | ||
| 511 | return do_register_entry(IDE_CORE_CP, f, buf, count, off); | ||
| 512 | } | ||
| 513 | |||
| 514 | /* Special entry to just crash directly. Available without KPROBEs */ | ||
| 515 | static ssize_t direct_entry(struct file *f, const char __user *user_buf, | ||
| 516 | size_t count, loff_t *off) | ||
| 517 | { | ||
| 518 | enum ctype type; | ||
| 519 | char *buf; | ||
| 520 | |||
| 521 | if (count >= PAGE_SIZE) | ||
| 522 | return -EINVAL; | ||
| 523 | if (count < 1) | ||
| 524 | return -EINVAL; | ||
| 525 | |||
| 526 | buf = (char *)__get_free_page(GFP_KERNEL); | ||
| 527 | if (!buf) | ||
| 528 | return -ENOMEM; | ||
| 529 | if (copy_from_user(buf, user_buf, count)) { | ||
| 530 | free_page((unsigned long) buf); | ||
| 531 | return -EFAULT; | ||
| 532 | } | ||
| 533 | /* NULL-terminate and remove enter */ | ||
| 534 | buf[count] = '\0'; | ||
| 535 | strim(buf); | ||
| 536 | |||
| 537 | type = parse_cp_type(buf, count); | ||
| 538 | free_page((unsigned long) buf); | ||
| 539 | if (type == NONE) | ||
| 540 | return -EINVAL; | ||
| 541 | |||
| 542 | printk(KERN_INFO "lkdtm: Performing direct entry %s\n", | ||
| 543 | cp_type_to_str(type)); | ||
| 544 | lkdtm_do_action(type); | ||
| 545 | *off += count; | ||
| 546 | |||
| 547 | return count; | ||
| 548 | } | ||
| 549 | |||
| 550 | struct crash_entry { | ||
| 551 | const char *name; | ||
| 552 | const struct file_operations fops; | ||
| 553 | }; | ||
| 554 | |||
| 555 | static const struct crash_entry crash_entries[] = { | ||
| 556 | {"DIRECT", {.read = lkdtm_debugfs_read, | ||
| 557 | .open = lkdtm_debugfs_open, | ||
| 558 | .write = direct_entry} }, | ||
| 559 | {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, | ||
| 560 | .open = lkdtm_debugfs_open, | ||
| 561 | .write = int_hardware_entry} }, | ||
| 562 | {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, | ||
| 563 | .open = lkdtm_debugfs_open, | ||
| 564 | .write = int_hw_irq_en} }, | ||
| 565 | {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, | ||
| 566 | .open = lkdtm_debugfs_open, | ||
| 567 | .write = int_tasklet_entry} }, | ||
| 568 | {"FS_DEVRW", {.read = lkdtm_debugfs_read, | ||
| 569 | .open = lkdtm_debugfs_open, | ||
| 570 | .write = fs_devrw_entry} }, | ||
| 571 | {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, | ||
| 572 | .open = lkdtm_debugfs_open, | ||
| 573 | .write = mem_swapout_entry} }, | ||
| 574 | {"TIMERADD", {.read = lkdtm_debugfs_read, | ||
| 575 | .open = lkdtm_debugfs_open, | ||
| 576 | .write = timeradd_entry} }, | ||
| 577 | {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, | ||
| 578 | .open = lkdtm_debugfs_open, | ||
| 579 | .write = scsi_dispatch_cmd_entry} }, | ||
| 580 | {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, | ||
| 581 | .open = lkdtm_debugfs_open, | ||
| 582 | .write = ide_core_cp_entry} }, | ||
| 583 | }; | ||
| 584 | |||
| 585 | static struct dentry *lkdtm_debugfs_root; | ||
| 586 | |||
| 587 | static int __init lkdtm_module_init(void) | ||
| 588 | { | ||
| 589 | int ret = -EINVAL; | ||
| 590 | int n_debugfs_entries = 1; /* Assume only the direct entry */ | ||
| 591 | int i; | ||
| 592 | |||
| 593 | /* Register debugfs interface */ | ||
| 594 | lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); | ||
| 595 | if (!lkdtm_debugfs_root) { | ||
| 596 | printk(KERN_ERR "lkdtm: creating root dir failed\n"); | ||
| 597 | return -ENODEV; | ||
| 598 | } | ||
| 599 | |||
| 600 | #ifdef CONFIG_KPROBES | ||
| 601 | n_debugfs_entries = ARRAY_SIZE(crash_entries); | ||
| 602 | #endif | ||
| 603 | |||
| 604 | for (i = 0; i < n_debugfs_entries; i++) { | ||
| 605 | const struct crash_entry *cur = &crash_entries[i]; | ||
| 606 | struct dentry *de; | ||
| 607 | |||
| 608 | de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, | ||
| 609 | NULL, &cur->fops); | ||
| 610 | if (de == NULL) { | ||
| 611 | printk(KERN_ERR "lkdtm: could not create %s\n", | ||
| 612 | cur->name); | ||
| 613 | goto out_err; | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | if (lkdtm_parse_commandline() == -EINVAL) { | ||
| 618 | printk(KERN_INFO "lkdtm: Invalid command\n"); | ||
| 619 | goto out_err; | ||
| 620 | } | ||
| 621 | |||
| 622 | if (cpoint != INVALID && cptype != NONE) { | ||
| 623 | ret = lkdtm_register_cpoint(cpoint); | ||
| 624 | if (ret < 0) { | ||
| 625 | printk(KERN_INFO "lkdtm: Invalid crash point %d\n", | ||
| 626 | cpoint); | ||
| 627 | goto out_err; | ||
| 628 | } | ||
| 629 | printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n", | ||
| 630 | cpoint_name, cpoint_type); | ||
| 631 | } else { | ||
| 632 | printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n"); | ||
| 329 | } | 633 | } |
| 330 | 634 | ||
| 331 | printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n", | ||
| 332 | cpoint_name, cpoint_type); | ||
| 333 | return 0; | 635 | return 0; |
| 636 | |||
| 637 | out_err: | ||
| 638 | debugfs_remove_recursive(lkdtm_debugfs_root); | ||
| 639 | return ret; | ||
| 334 | } | 640 | } |
| 335 | 641 | ||
| 336 | static void __exit lkdtm_module_exit(void) | 642 | static void __exit lkdtm_module_exit(void) |
| 337 | { | 643 | { |
| 338 | unregister_jprobe(&lkdtm); | 644 | debugfs_remove_recursive(lkdtm_debugfs_root); |
| 339 | printk(KERN_INFO "lkdtm : Crash point unregistered\n"); | 645 | |
| 646 | unregister_jprobe(&lkdtm); | ||
| 647 | printk(KERN_INFO "lkdtm: Crash point unregistered\n"); | ||
| 340 | } | 648 | } |
| 341 | 649 | ||
| 342 | module_init(lkdtm_module_init); | 650 | module_init(lkdtm_module_init); |
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 16f0abda1423..57b152f8d1b9 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
| @@ -475,7 +475,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 475 | 475 | ||
| 476 | if (skb->data[0] == 0xff) { | 476 | if (skb->data[0] == 0xff) { |
| 477 | /* we are being asked to broadcast to all partitions */ | 477 | /* we are being asked to broadcast to all partitions */ |
| 478 | for_each_bit(dest_partid, xpnet_broadcast_partitions, | 478 | for_each_set_bit(dest_partid, xpnet_broadcast_partitions, |
| 479 | xp_max_npartitions) { | 479 | xp_max_npartitions) { |
| 480 | 480 | ||
| 481 | xpnet_send(skb, queued_msg, start_addr, end_addr, | 481 | xpnet_send(skb, queued_msg, start_addr, end_addr, |
