diff options
author | Corey Minyard <cminyard@mvista.com> | 2016-02-03 11:45:28 -0500 |
---|---|---|
committer | Corey Minyard <cminyard@mvista.com> | 2017-06-19 13:49:38 -0400 |
commit | 0944d889a237b6107f9ceeee053fe7221cdd1089 (patch) | |
tree | 7da1960bd53c5d63bcc9cff81f893ec0e2aa9318 | |
parent | 9f88145f1871456de67ae6a242ac2661187bd4ff (diff) |
ipmi: Convert DMI handling over to a platform device
Now that the IPMI DMI code creates a platform device for IPMI devices
in the firmware, use that instead of handling all the DMI work
in the IPMI drivers themselves.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Andy Lutomirski <luto@kernel.org>
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 261 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_ssif.c | 162 |
2 files changed, 219 insertions, 204 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b89078bff1c1..edaf6284c663 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <linux/ipmi_smi.h> | 61 | #include <linux/ipmi_smi.h> |
62 | #include <asm/io.h> | 62 | #include <asm/io.h> |
63 | #include "ipmi_si_sm.h" | 63 | #include "ipmi_si_sm.h" |
64 | #include "ipmi_dmi.h" | ||
64 | #include <linux/dmi.h> | 65 | #include <linux/dmi.h> |
65 | #include <linux/string.h> | 66 | #include <linux/string.h> |
66 | #include <linux/ctype.h> | 67 | #include <linux/ctype.h> |
@@ -2273,136 +2274,105 @@ static void spmi_find_bmc(void) | |||
2273 | } | 2274 | } |
2274 | #endif | 2275 | #endif |
2275 | 2276 | ||
2276 | #ifdef CONFIG_DMI | 2277 | #if defined(CONFIG_DMI) || defined(CONFIG_ACPI) |
2277 | struct dmi_ipmi_data { | 2278 | struct resource *ipmi_get_info_from_resources(struct platform_device *pdev, |
2278 | u8 type; | 2279 | struct smi_info *info) |
2279 | u8 addr_space; | ||
2280 | unsigned long base_addr; | ||
2281 | u8 irq; | ||
2282 | u8 offset; | ||
2283 | u8 slave_addr; | ||
2284 | }; | ||
2285 | |||
2286 | static int decode_dmi(const struct dmi_header *dm, | ||
2287 | struct dmi_ipmi_data *dmi) | ||
2288 | { | 2280 | { |
2289 | const u8 *data = (const u8 *)dm; | 2281 | struct resource *res, *res_second; |
2290 | unsigned long base_addr; | ||
2291 | u8 reg_spacing; | ||
2292 | u8 len = dm->length; | ||
2293 | |||
2294 | dmi->type = data[4]; | ||
2295 | 2282 | ||
2296 | memcpy(&base_addr, data+8, sizeof(unsigned long)); | 2283 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
2297 | if (len >= 0x11) { | 2284 | if (res) { |
2298 | if (base_addr & 1) { | 2285 | info->io_setup = port_setup; |
2299 | /* I/O */ | 2286 | info->io.addr_type = IPMI_IO_ADDR_SPACE; |
2300 | base_addr &= 0xFFFE; | ||
2301 | dmi->addr_space = IPMI_IO_ADDR_SPACE; | ||
2302 | } else | ||
2303 | /* Memory */ | ||
2304 | dmi->addr_space = IPMI_MEM_ADDR_SPACE; | ||
2305 | |||
2306 | /* If bit 4 of byte 0x10 is set, then the lsb for the address | ||
2307 | is odd. */ | ||
2308 | dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); | ||
2309 | |||
2310 | dmi->irq = data[0x11]; | ||
2311 | |||
2312 | /* The top two bits of byte 0x10 hold the register spacing. */ | ||
2313 | reg_spacing = (data[0x10] & 0xC0) >> 6; | ||
2314 | switch (reg_spacing) { | ||
2315 | case 0x00: /* Byte boundaries */ | ||
2316 | dmi->offset = 1; | ||
2317 | break; | ||
2318 | case 0x01: /* 32-bit boundaries */ | ||
2319 | dmi->offset = 4; | ||
2320 | break; | ||
2321 | case 0x02: /* 16-byte boundaries */ | ||
2322 | dmi->offset = 16; | ||
2323 | break; | ||
2324 | default: | ||
2325 | /* Some other interface, just ignore it. */ | ||
2326 | return -EIO; | ||
2327 | } | ||
2328 | } else { | 2287 | } else { |
2329 | /* Old DMI spec. */ | 2288 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2330 | /* | 2289 | if (res) { |
2331 | * Note that technically, the lower bit of the base | 2290 | info->io_setup = mem_setup; |
2332 | * address should be 1 if the address is I/O and 0 if | 2291 | info->io.addr_type = IPMI_MEM_ADDR_SPACE; |
2333 | * the address is in memory. So many systems get that | 2292 | } |
2334 | * wrong (and all that I have seen are I/O) so we just | ||
2335 | * ignore that bit and assume I/O. Systems that use | ||
2336 | * memory should use the newer spec, anyway. | ||
2337 | */ | ||
2338 | dmi->base_addr = base_addr & 0xfffe; | ||
2339 | dmi->addr_space = IPMI_IO_ADDR_SPACE; | ||
2340 | dmi->offset = 1; | ||
2341 | } | 2293 | } |
2294 | if (!res) { | ||
2295 | dev_err(&pdev->dev, "no I/O or memory address\n"); | ||
2296 | return NULL; | ||
2297 | } | ||
2298 | info->io.addr_data = res->start; | ||
2342 | 2299 | ||
2343 | dmi->slave_addr = data[6]; | 2300 | info->io.regspacing = DEFAULT_REGSPACING; |
2301 | res_second = platform_get_resource(pdev, | ||
2302 | (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? | ||
2303 | IORESOURCE_IO : IORESOURCE_MEM, | ||
2304 | 1); | ||
2305 | if (res_second) { | ||
2306 | if (res_second->start > info->io.addr_data) | ||
2307 | info->io.regspacing = | ||
2308 | res_second->start - info->io.addr_data; | ||
2309 | } | ||
2310 | info->io.regsize = DEFAULT_REGSIZE; | ||
2311 | info->io.regshift = 0; | ||
2344 | 2312 | ||
2345 | return 0; | 2313 | return res; |
2346 | } | 2314 | } |
2347 | 2315 | ||
2348 | static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) | 2316 | #endif |
2317 | |||
2318 | #ifdef CONFIG_DMI | ||
2319 | static int dmi_ipmi_probe(struct platform_device *pdev) | ||
2349 | { | 2320 | { |
2350 | struct smi_info *info; | 2321 | struct smi_info *info; |
2322 | u8 type, slave_addr; | ||
2323 | int rv; | ||
2324 | |||
2325 | if (!si_trydmi) | ||
2326 | return -ENODEV; | ||
2327 | |||
2328 | rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); | ||
2329 | if (rv) | ||
2330 | return -ENODEV; | ||
2351 | 2331 | ||
2352 | info = smi_info_alloc(); | 2332 | info = smi_info_alloc(); |
2353 | if (!info) { | 2333 | if (!info) { |
2354 | pr_err(PFX "Could not allocate SI data\n"); | 2334 | pr_err(PFX "Could not allocate SI data\n"); |
2355 | return; | 2335 | return -ENOMEM; |
2356 | } | 2336 | } |
2357 | 2337 | ||
2358 | info->addr_source = SI_SMBIOS; | 2338 | info->addr_source = SI_SMBIOS; |
2359 | pr_info(PFX "probing via SMBIOS\n"); | 2339 | pr_info(PFX "probing via SMBIOS\n"); |
2360 | 2340 | ||
2361 | switch (ipmi_data->type) { | 2341 | switch (type) { |
2362 | case 0x01: /* KCS */ | 2342 | case IPMI_DMI_TYPE_KCS: |
2363 | info->si_type = SI_KCS; | 2343 | info->si_type = SI_KCS; |
2364 | break; | 2344 | break; |
2365 | case 0x02: /* SMIC */ | 2345 | case IPMI_DMI_TYPE_SMIC: |
2366 | info->si_type = SI_SMIC; | 2346 | info->si_type = SI_SMIC; |
2367 | break; | 2347 | break; |
2368 | case 0x03: /* BT */ | 2348 | case IPMI_DMI_TYPE_BT: |
2369 | info->si_type = SI_BT; | 2349 | info->si_type = SI_BT; |
2370 | break; | 2350 | break; |
2371 | default: | 2351 | default: |
2372 | kfree(info); | 2352 | kfree(info); |
2373 | return; | 2353 | return -EINVAL; |
2374 | } | 2354 | } |
2375 | 2355 | ||
2376 | switch (ipmi_data->addr_space) { | 2356 | if (!ipmi_get_info_from_resources(pdev, info)) { |
2377 | case IPMI_MEM_ADDR_SPACE: | 2357 | rv = -EINVAL; |
2378 | info->io_setup = mem_setup; | 2358 | goto err_free; |
2379 | info->io.addr_type = IPMI_MEM_ADDR_SPACE; | ||
2380 | break; | ||
2381 | |||
2382 | case IPMI_IO_ADDR_SPACE: | ||
2383 | info->io_setup = port_setup; | ||
2384 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | ||
2385 | break; | ||
2386 | |||
2387 | default: | ||
2388 | kfree(info); | ||
2389 | pr_warn(PFX "Unknown SMBIOS I/O Address type: %d\n", | ||
2390 | ipmi_data->addr_space); | ||
2391 | return; | ||
2392 | } | 2359 | } |
2393 | info->io.addr_data = ipmi_data->base_addr; | ||
2394 | 2360 | ||
2395 | info->io.regspacing = ipmi_data->offset; | 2361 | rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); |
2396 | if (!info->io.regspacing) | 2362 | if (rv) { |
2397 | info->io.regspacing = DEFAULT_REGSPACING; | 2363 | dev_warn(&pdev->dev, "device has no slave-addr property"); |
2398 | info->io.regsize = DEFAULT_REGSIZE; | 2364 | info->slave_addr = 0x20; |
2399 | info->io.regshift = 0; | 2365 | } else { |
2400 | 2366 | info->slave_addr = slave_addr; | |
2401 | info->slave_addr = ipmi_data->slave_addr; | 2367 | } |
2402 | 2368 | ||
2403 | info->irq = ipmi_data->irq; | 2369 | info->irq = platform_get_irq(pdev, 0); |
2404 | if (info->irq) | 2370 | if (info->irq > 0) |
2405 | info->irq_setup = std_irq_setup; | 2371 | info->irq_setup = std_irq_setup; |
2372 | else | ||
2373 | info->irq = 0; | ||
2374 | |||
2375 | info->dev = &pdev->dev; | ||
2406 | 2376 | ||
2407 | pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", | 2377 | pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", |
2408 | (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", | 2378 | (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", |
@@ -2411,21 +2381,17 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) | |||
2411 | 2381 | ||
2412 | if (add_smi(info)) | 2382 | if (add_smi(info)) |
2413 | kfree(info); | 2383 | kfree(info); |
2414 | } | ||
2415 | 2384 | ||
2416 | static void dmi_find_bmc(void) | 2385 | return 0; |
2417 | { | ||
2418 | const struct dmi_device *dev = NULL; | ||
2419 | struct dmi_ipmi_data data; | ||
2420 | int rv; | ||
2421 | 2386 | ||
2422 | while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { | 2387 | err_free: |
2423 | memset(&data, 0, sizeof(data)); | 2388 | kfree(info); |
2424 | rv = decode_dmi((const struct dmi_header *) dev->device_data, | 2389 | return rv; |
2425 | &data); | 2390 | } |
2426 | if (!rv) | 2391 | #else |
2427 | try_init_dmi(&data); | 2392 | static int dmi_ipmi_probe(struct platform_device *pdev) |
2428 | } | 2393 | { |
2394 | return -ENODEV; | ||
2429 | } | 2395 | } |
2430 | #endif /* CONFIG_DMI */ | 2396 | #endif /* CONFIG_DMI */ |
2431 | 2397 | ||
@@ -2684,17 +2650,47 @@ static int of_ipmi_probe(struct platform_device *dev) | |||
2684 | #endif | 2650 | #endif |
2685 | 2651 | ||
2686 | #ifdef CONFIG_ACPI | 2652 | #ifdef CONFIG_ACPI |
2653 | static int find_slave_address(struct smi_info *info, int slave_addr) | ||
2654 | { | ||
2655 | #ifdef CONFIG_IPMI_DMI_DECODE | ||
2656 | if (!slave_addr) { | ||
2657 | int type = -1; | ||
2658 | u32 flags = IORESOURCE_IO; | ||
2659 | |||
2660 | switch (info->si_type) { | ||
2661 | case SI_KCS: | ||
2662 | type = IPMI_DMI_TYPE_KCS; | ||
2663 | break; | ||
2664 | case SI_BT: | ||
2665 | type = IPMI_DMI_TYPE_BT; | ||
2666 | break; | ||
2667 | case SI_SMIC: | ||
2668 | type = IPMI_DMI_TYPE_SMIC; | ||
2669 | break; | ||
2670 | } | ||
2671 | |||
2672 | if (info->io.addr_type == IPMI_MEM_ADDR_SPACE) | ||
2673 | flags = IORESOURCE_MEM; | ||
2674 | |||
2675 | slave_addr = ipmi_dmi_get_slave_addr(type, flags, | ||
2676 | info->io.addr_data); | ||
2677 | } | ||
2678 | #endif | ||
2679 | |||
2680 | return slave_addr; | ||
2681 | } | ||
2682 | |||
2687 | static int acpi_ipmi_probe(struct platform_device *dev) | 2683 | static int acpi_ipmi_probe(struct platform_device *dev) |
2688 | { | 2684 | { |
2689 | struct smi_info *info; | 2685 | struct smi_info *info; |
2690 | struct resource *res, *res_second; | ||
2691 | acpi_handle handle; | 2686 | acpi_handle handle; |
2692 | acpi_status status; | 2687 | acpi_status status; |
2693 | unsigned long long tmp; | 2688 | unsigned long long tmp; |
2689 | struct resource *res; | ||
2694 | int rv = -EINVAL; | 2690 | int rv = -EINVAL; |
2695 | 2691 | ||
2696 | if (!si_tryacpi) | 2692 | if (!si_tryacpi) |
2697 | return 0; | 2693 | return -ENODEV; |
2698 | 2694 | ||
2699 | handle = ACPI_HANDLE(&dev->dev); | 2695 | handle = ACPI_HANDLE(&dev->dev); |
2700 | if (!handle) | 2696 | if (!handle) |
@@ -2734,35 +2730,11 @@ static int acpi_ipmi_probe(struct platform_device *dev) | |||
2734 | goto err_free; | 2730 | goto err_free; |
2735 | } | 2731 | } |
2736 | 2732 | ||
2737 | res = platform_get_resource(dev, IORESOURCE_IO, 0); | 2733 | res = ipmi_get_info_from_resources(dev, info); |
2738 | if (res) { | ||
2739 | info->io_setup = port_setup; | ||
2740 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | ||
2741 | } else { | ||
2742 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
2743 | if (res) { | ||
2744 | info->io_setup = mem_setup; | ||
2745 | info->io.addr_type = IPMI_MEM_ADDR_SPACE; | ||
2746 | } | ||
2747 | } | ||
2748 | if (!res) { | 2734 | if (!res) { |
2749 | dev_err(&dev->dev, "no I/O or memory address\n"); | 2735 | rv = -EINVAL; |
2750 | goto err_free; | 2736 | goto err_free; |
2751 | } | 2737 | } |
2752 | info->io.addr_data = res->start; | ||
2753 | |||
2754 | info->io.regspacing = DEFAULT_REGSPACING; | ||
2755 | res_second = platform_get_resource(dev, | ||
2756 | (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? | ||
2757 | IORESOURCE_IO : IORESOURCE_MEM, | ||
2758 | 1); | ||
2759 | if (res_second) { | ||
2760 | if (res_second->start > info->io.addr_data) | ||
2761 | info->io.regspacing = | ||
2762 | res_second->start - info->io.addr_data; | ||
2763 | } | ||
2764 | info->io.regsize = DEFAULT_REGSIZE; | ||
2765 | info->io.regshift = 0; | ||
2766 | 2738 | ||
2767 | /* If _GPE exists, use it; otherwise use standard interrupts */ | 2739 | /* If _GPE exists, use it; otherwise use standard interrupts */ |
2768 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); | 2740 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); |
@@ -2778,6 +2750,8 @@ static int acpi_ipmi_probe(struct platform_device *dev) | |||
2778 | } | 2750 | } |
2779 | } | 2751 | } |
2780 | 2752 | ||
2753 | info->slave_addr = find_slave_address(info, info->slave_addr); | ||
2754 | |||
2781 | info->dev = &dev->dev; | 2755 | info->dev = &dev->dev; |
2782 | platform_set_drvdata(dev, info); | 2756 | platform_set_drvdata(dev, info); |
2783 | 2757 | ||
@@ -2813,7 +2787,10 @@ static int ipmi_probe(struct platform_device *dev) | |||
2813 | if (of_ipmi_probe(dev) == 0) | 2787 | if (of_ipmi_probe(dev) == 0) |
2814 | return 0; | 2788 | return 0; |
2815 | 2789 | ||
2816 | return acpi_ipmi_probe(dev); | 2790 | if (acpi_ipmi_probe(dev) == 0) |
2791 | return 0; | ||
2792 | |||
2793 | return dmi_ipmi_probe(dev); | ||
2817 | } | 2794 | } |
2818 | 2795 | ||
2819 | static int ipmi_remove(struct platform_device *dev) | 2796 | static int ipmi_remove(struct platform_device *dev) |
@@ -3786,11 +3763,6 @@ static int init_ipmi_si(void) | |||
3786 | } | 3763 | } |
3787 | #endif | 3764 | #endif |
3788 | 3765 | ||
3789 | #ifdef CONFIG_DMI | ||
3790 | if (si_trydmi) | ||
3791 | dmi_find_bmc(); | ||
3792 | #endif | ||
3793 | |||
3794 | #ifdef CONFIG_ACPI | 3766 | #ifdef CONFIG_ACPI |
3795 | if (si_tryacpi) | 3767 | if (si_tryacpi) |
3796 | spmi_find_bmc(); | 3768 | spmi_find_bmc(); |
@@ -3938,6 +3910,7 @@ static void cleanup_ipmi_si(void) | |||
3938 | } | 3910 | } |
3939 | module_exit(cleanup_ipmi_si); | 3911 | module_exit(cleanup_ipmi_si); |
3940 | 3912 | ||
3913 | MODULE_ALIAS("platform:dmi-ipmi-si"); | ||
3941 | MODULE_LICENSE("GPL"); | 3914 | MODULE_LICENSE("GPL"); |
3942 | MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); | 3915 | MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); |
3943 | MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" | 3916 | MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" |
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 05e18041c357..61434830e641 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/acpi.h> | 53 | #include <linux/acpi.h> |
54 | #include <linux/ctype.h> | 54 | #include <linux/ctype.h> |
55 | #include <linux/time64.h> | 55 | #include <linux/time64.h> |
56 | #include "ipmi_dmi.h" | ||
56 | 57 | ||
57 | #define PFX "ipmi_ssif: " | 58 | #define PFX "ipmi_ssif: " |
58 | #define DEVICE_NAME "ipmi_ssif" | 59 | #define DEVICE_NAME "ipmi_ssif" |
@@ -180,6 +181,8 @@ struct ssif_addr_info { | |||
180 | int slave_addr; | 181 | int slave_addr; |
181 | enum ipmi_addr_src addr_src; | 182 | enum ipmi_addr_src addr_src; |
182 | union ipmi_smi_info_union addr_info; | 183 | union ipmi_smi_info_union addr_info; |
184 | struct device *dev; | ||
185 | struct i2c_client *client; | ||
183 | 186 | ||
184 | struct mutex clients_mutex; | 187 | struct mutex clients_mutex; |
185 | struct list_head clients; | 188 | struct list_head clients; |
@@ -1171,6 +1174,7 @@ static LIST_HEAD(ssif_infos); | |||
1171 | static int ssif_remove(struct i2c_client *client) | 1174 | static int ssif_remove(struct i2c_client *client) |
1172 | { | 1175 | { |
1173 | struct ssif_info *ssif_info = i2c_get_clientdata(client); | 1176 | struct ssif_info *ssif_info = i2c_get_clientdata(client); |
1177 | struct ssif_addr_info *addr_info; | ||
1174 | int rv; | 1178 | int rv; |
1175 | 1179 | ||
1176 | if (!ssif_info) | 1180 | if (!ssif_info) |
@@ -1198,6 +1202,13 @@ static int ssif_remove(struct i2c_client *client) | |||
1198 | kthread_stop(ssif_info->thread); | 1202 | kthread_stop(ssif_info->thread); |
1199 | } | 1203 | } |
1200 | 1204 | ||
1205 | list_for_each_entry(addr_info, &ssif_infos, link) { | ||
1206 | if (addr_info->client == client) { | ||
1207 | addr_info->client = NULL; | ||
1208 | break; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1201 | /* | 1212 | /* |
1202 | * No message can be outstanding now, we have removed the | 1213 | * No message can be outstanding now, we have removed the |
1203 | * upper layer and it permitted us to do so. | 1214 | * upper layer and it permitted us to do so. |
@@ -1406,27 +1417,13 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) | |||
1406 | 1417 | ||
1407 | static int find_slave_address(struct i2c_client *client, int slave_addr) | 1418 | static int find_slave_address(struct i2c_client *client, int slave_addr) |
1408 | { | 1419 | { |
1409 | struct ssif_addr_info *info; | 1420 | #ifdef CONFIG_IPMI_DMI_DECODE |
1410 | 1421 | if (!slave_addr) | |
1411 | if (slave_addr) | 1422 | slave_addr = ipmi_dmi_get_slave_addr( |
1412 | return slave_addr; | 1423 | IPMI_DMI_TYPE_SSIF, |
1413 | 1424 | i2c_adapter_id(client->adapter), | |
1414 | /* | 1425 | client->addr); |
1415 | * Came in without a slave address, search around to see if | 1426 | #endif |
1416 | * the other sources have a slave address. This lets us pick | ||
1417 | * up an SMBIOS slave address when using ACPI. | ||
1418 | */ | ||
1419 | list_for_each_entry(info, &ssif_infos, link) { | ||
1420 | if (info->binfo.addr != client->addr) | ||
1421 | continue; | ||
1422 | if (info->adapter_name && strcmp_nospace(info->adapter_name, | ||
1423 | client->adapter->name)) | ||
1424 | continue; | ||
1425 | if (info->slave_addr) { | ||
1426 | slave_addr = info->slave_addr; | ||
1427 | break; | ||
1428 | } | ||
1429 | } | ||
1430 | 1427 | ||
1431 | return slave_addr; | 1428 | return slave_addr; |
1432 | } | 1429 | } |
@@ -1448,7 +1445,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1448 | u8 slave_addr = 0; | 1445 | u8 slave_addr = 0; |
1449 | struct ssif_addr_info *addr_info = NULL; | 1446 | struct ssif_addr_info *addr_info = NULL; |
1450 | 1447 | ||
1451 | |||
1452 | resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); | 1448 | resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); |
1453 | if (!resp) | 1449 | if (!resp) |
1454 | return -ENOMEM; | 1450 | return -ENOMEM; |
@@ -1469,6 +1465,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1469 | ssif_info->addr_source = addr_info->addr_src; | 1465 | ssif_info->addr_source = addr_info->addr_src; |
1470 | ssif_info->ssif_debug = addr_info->debug; | 1466 | ssif_info->ssif_debug = addr_info->debug; |
1471 | ssif_info->addr_info = addr_info->addr_info; | 1467 | ssif_info->addr_info = addr_info->addr_info; |
1468 | addr_info->client = client; | ||
1472 | slave_addr = addr_info->slave_addr; | 1469 | slave_addr = addr_info->slave_addr; |
1473 | } | 1470 | } |
1474 | } | 1471 | } |
@@ -1707,8 +1704,19 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1707 | } | 1704 | } |
1708 | 1705 | ||
1709 | out: | 1706 | out: |
1710 | if (rv) | 1707 | if (rv) { |
1708 | /* | ||
1709 | * Note that if addr_info->client is assigned, we | ||
1710 | * leave it. The i2c client hangs around even if we | ||
1711 | * return a failure here, and the failure here is not | ||
1712 | * propagated back to the i2c code. This seems to be | ||
1713 | * design intent, strange as it may be. But if we | ||
1714 | * don't leave it, ssif_platform_remove will not remove | ||
1715 | * the client like it should. | ||
1716 | */ | ||
1717 | dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv); | ||
1711 | kfree(ssif_info); | 1718 | kfree(ssif_info); |
1719 | } | ||
1712 | kfree(resp); | 1720 | kfree(resp); |
1713 | return rv; | 1721 | return rv; |
1714 | 1722 | ||
@@ -1733,7 +1741,8 @@ static int ssif_adapter_handler(struct device *adev, void *opaque) | |||
1733 | 1741 | ||
1734 | static int new_ssif_client(int addr, char *adapter_name, | 1742 | static int new_ssif_client(int addr, char *adapter_name, |
1735 | int debug, int slave_addr, | 1743 | int debug, int slave_addr, |
1736 | enum ipmi_addr_src addr_src) | 1744 | enum ipmi_addr_src addr_src, |
1745 | struct device *dev) | ||
1737 | { | 1746 | { |
1738 | struct ssif_addr_info *addr_info; | 1747 | struct ssif_addr_info *addr_info; |
1739 | int rv = 0; | 1748 | int rv = 0; |
@@ -1766,6 +1775,9 @@ static int new_ssif_client(int addr, char *adapter_name, | |||
1766 | addr_info->debug = debug; | 1775 | addr_info->debug = debug; |
1767 | addr_info->slave_addr = slave_addr; | 1776 | addr_info->slave_addr = slave_addr; |
1768 | addr_info->addr_src = addr_src; | 1777 | addr_info->addr_src = addr_src; |
1778 | addr_info->dev = dev; | ||
1779 | |||
1780 | dev_set_drvdata(dev, addr_info); | ||
1769 | 1781 | ||
1770 | list_add_tail(&addr_info->link, &ssif_infos); | 1782 | list_add_tail(&addr_info->link, &ssif_infos); |
1771 | 1783 | ||
@@ -1904,7 +1916,7 @@ static int try_init_spmi(struct SPMITable *spmi) | |||
1904 | 1916 | ||
1905 | myaddr = spmi->addr.address & 0x7f; | 1917 | myaddr = spmi->addr.address & 0x7f; |
1906 | 1918 | ||
1907 | return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI); | 1919 | return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI, NULL); |
1908 | } | 1920 | } |
1909 | 1921 | ||
1910 | static void spmi_find_bmc(void) | 1922 | static void spmi_find_bmc(void) |
@@ -1933,48 +1945,40 @@ static void spmi_find_bmc(void) { } | |||
1933 | #endif | 1945 | #endif |
1934 | 1946 | ||
1935 | #ifdef CONFIG_DMI | 1947 | #ifdef CONFIG_DMI |
1936 | static int decode_dmi(const struct dmi_device *dmi_dev) | 1948 | static int dmi_ipmi_probe(struct platform_device *pdev) |
1937 | { | 1949 | { |
1938 | struct dmi_header *dm = dmi_dev->device_data; | 1950 | u8 type, slave_addr = 0; |
1939 | u8 *data = (u8 *) dm; | 1951 | u16 i2c_addr; |
1940 | u8 len = dm->length; | 1952 | int rv; |
1941 | unsigned short myaddr; | ||
1942 | int slave_addr; | ||
1943 | 1953 | ||
1944 | if (num_addrs >= MAX_SSIF_BMCS) | 1954 | if (!ssif_trydmi) |
1945 | return -1; | 1955 | return -ENODEV; |
1946 | 1956 | ||
1947 | if (len < 9) | 1957 | rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); |
1948 | return -1; | 1958 | if (rv) |
1959 | return -ENODEV; | ||
1949 | 1960 | ||
1950 | if (data[0x04] != 4) /* Not SSIF */ | 1961 | if (type != IPMI_DMI_TYPE_SSIF) |
1951 | return -1; | 1962 | return -ENODEV; |
1952 | 1963 | ||
1953 | if ((data[8] >> 1) == 0) { | 1964 | rv = device_property_read_u16(&pdev->dev, "i2c-addr", &i2c_addr); |
1954 | /* | 1965 | if (rv) { |
1955 | * Some broken systems put the I2C address in | 1966 | dev_warn(&pdev->dev, PFX "No i2c-addr property\n"); |
1956 | * the slave address field. We try to | 1967 | return -ENODEV; |
1957 | * accommodate them here. | ||
1958 | */ | ||
1959 | myaddr = data[6] >> 1; | ||
1960 | slave_addr = 0; | ||
1961 | } else { | ||
1962 | myaddr = data[8] >> 1; | ||
1963 | slave_addr = data[6]; | ||
1964 | } | 1968 | } |
1965 | 1969 | ||
1966 | return new_ssif_client(myaddr, NULL, 0, slave_addr, SI_SMBIOS); | 1970 | rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); |
1967 | } | 1971 | if (rv) |
1968 | 1972 | dev_warn(&pdev->dev, "device has no slave-addr property"); | |
1969 | static void dmi_iterator(void) | ||
1970 | { | ||
1971 | const struct dmi_device *dev = NULL; | ||
1972 | 1973 | ||
1973 | while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) | 1974 | return new_ssif_client(i2c_addr, NULL, 0, |
1974 | decode_dmi(dev); | 1975 | slave_addr, SI_SMBIOS, &pdev->dev); |
1975 | } | 1976 | } |
1976 | #else | 1977 | #else |
1977 | static void dmi_iterator(void) { } | 1978 | static int dmi_ipmi_probe(struct platform_device *pdev) |
1979 | { | ||
1980 | return -ENODEV; | ||
1981 | } | ||
1978 | #endif | 1982 | #endif |
1979 | 1983 | ||
1980 | static const struct i2c_device_id ssif_id[] = { | 1984 | static const struct i2c_device_id ssif_id[] = { |
@@ -1995,6 +1999,36 @@ static struct i2c_driver ssif_i2c_driver = { | |||
1995 | .detect = ssif_detect | 1999 | .detect = ssif_detect |
1996 | }; | 2000 | }; |
1997 | 2001 | ||
2002 | static int ssif_platform_probe(struct platform_device *dev) | ||
2003 | { | ||
2004 | return dmi_ipmi_probe(dev); | ||
2005 | } | ||
2006 | |||
2007 | static int ssif_platform_remove(struct platform_device *dev) | ||
2008 | { | ||
2009 | struct ssif_addr_info *addr_info = dev_get_drvdata(&dev->dev); | ||
2010 | |||
2011 | if (!addr_info) | ||
2012 | return 0; | ||
2013 | |||
2014 | mutex_lock(&ssif_infos_mutex); | ||
2015 | if (addr_info->client) | ||
2016 | i2c_unregister_device(addr_info->client); | ||
2017 | |||
2018 | list_del(&addr_info->link); | ||
2019 | kfree(addr_info); | ||
2020 | mutex_unlock(&ssif_infos_mutex); | ||
2021 | return 0; | ||
2022 | } | ||
2023 | |||
2024 | static struct platform_driver ipmi_driver = { | ||
2025 | .driver = { | ||
2026 | .name = DEVICE_NAME, | ||
2027 | }, | ||
2028 | .probe = ssif_platform_probe, | ||
2029 | .remove = ssif_platform_remove, | ||
2030 | }; | ||
2031 | |||
1998 | static int init_ipmi_ssif(void) | 2032 | static int init_ipmi_ssif(void) |
1999 | { | 2033 | { |
2000 | int i; | 2034 | int i; |
@@ -2009,7 +2043,7 @@ static int init_ipmi_ssif(void) | |||
2009 | for (i = 0; i < num_addrs; i++) { | 2043 | for (i = 0; i < num_addrs; i++) { |
2010 | rv = new_ssif_client(addr[i], adapter_name[i], | 2044 | rv = new_ssif_client(addr[i], adapter_name[i], |
2011 | dbg[i], slave_addrs[i], | 2045 | dbg[i], slave_addrs[i], |
2012 | SI_HARDCODED); | 2046 | SI_HARDCODED, NULL); |
2013 | if (rv) | 2047 | if (rv) |
2014 | pr_err(PFX | 2048 | pr_err(PFX |
2015 | "Couldn't add hardcoded device at addr 0x%x\n", | 2049 | "Couldn't add hardcoded device at addr 0x%x\n", |
@@ -2019,11 +2053,16 @@ static int init_ipmi_ssif(void) | |||
2019 | if (ssif_tryacpi) | 2053 | if (ssif_tryacpi) |
2020 | ssif_i2c_driver.driver.acpi_match_table = | 2054 | ssif_i2c_driver.driver.acpi_match_table = |
2021 | ACPI_PTR(ssif_acpi_match); | 2055 | ACPI_PTR(ssif_acpi_match); |
2022 | if (ssif_trydmi) | 2056 | |
2023 | dmi_iterator(); | ||
2024 | if (ssif_tryacpi) | 2057 | if (ssif_tryacpi) |
2025 | spmi_find_bmc(); | 2058 | spmi_find_bmc(); |
2026 | 2059 | ||
2060 | if (ssif_trydmi) { | ||
2061 | rv = platform_driver_register(&ipmi_driver); | ||
2062 | if (rv) | ||
2063 | pr_err(PFX "Unable to register driver: %d\n", rv); | ||
2064 | } | ||
2065 | |||
2027 | ssif_i2c_driver.address_list = ssif_address_list(); | 2066 | ssif_i2c_driver.address_list = ssif_address_list(); |
2028 | 2067 | ||
2029 | rv = i2c_add_driver(&ssif_i2c_driver); | 2068 | rv = i2c_add_driver(&ssif_i2c_driver); |
@@ -2043,10 +2082,13 @@ static void cleanup_ipmi_ssif(void) | |||
2043 | 2082 | ||
2044 | i2c_del_driver(&ssif_i2c_driver); | 2083 | i2c_del_driver(&ssif_i2c_driver); |
2045 | 2084 | ||
2085 | platform_driver_unregister(&ipmi_driver); | ||
2086 | |||
2046 | free_ssif_clients(); | 2087 | free_ssif_clients(); |
2047 | } | 2088 | } |
2048 | module_exit(cleanup_ipmi_ssif); | 2089 | module_exit(cleanup_ipmi_ssif); |
2049 | 2090 | ||
2091 | MODULE_ALIAS("platform:dmi-ipmi-ssif"); | ||
2050 | MODULE_AUTHOR("Todd C Davis <todd.c.davis@intel.com>, Corey Minyard <minyard@acm.org>"); | 2092 | MODULE_AUTHOR("Todd C Davis <todd.c.davis@intel.com>, Corey Minyard <minyard@acm.org>"); |
2051 | MODULE_DESCRIPTION("IPMI driver for management controllers on a SMBus"); | 2093 | MODULE_DESCRIPTION("IPMI driver for management controllers on a SMBus"); |
2052 | MODULE_LICENSE("GPL"); | 2094 | MODULE_LICENSE("GPL"); |