diff options
Diffstat (limited to 'drivers')
252 files changed, 16361 insertions, 3733 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 7916f4b86d23..707650ab77a7 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -84,4 +84,7 @@ source "drivers/auxdisplay/Kconfig" | |||
84 | 84 | ||
85 | source "drivers/kvm/Kconfig" | 85 | source "drivers/kvm/Kconfig" |
86 | 86 | ||
87 | source "drivers/uio/Kconfig" | ||
88 | |||
89 | source "drivers/lguest/Kconfig" | ||
87 | endmenu | 90 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index 6d9d7fab77f5..0ea8e3237c0d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -40,6 +40,7 @@ obj-$(CONFIG_ATA) += ata/ | |||
40 | obj-$(CONFIG_FUSION) += message/ | 40 | obj-$(CONFIG_FUSION) += message/ |
41 | obj-$(CONFIG_FIREWIRE) += firewire/ | 41 | obj-$(CONFIG_FIREWIRE) += firewire/ |
42 | obj-$(CONFIG_IEEE1394) += ieee1394/ | 42 | obj-$(CONFIG_IEEE1394) += ieee1394/ |
43 | obj-$(CONFIG_UIO) += uio/ | ||
43 | obj-y += cdrom/ | 44 | obj-y += cdrom/ |
44 | obj-y += auxdisplay/ | 45 | obj-y += auxdisplay/ |
45 | obj-$(CONFIG_MTD) += mtd/ | 46 | obj-$(CONFIG_MTD) += mtd/ |
@@ -72,6 +73,7 @@ obj-$(CONFIG_ISDN) += isdn/ | |||
72 | obj-$(CONFIG_EDAC) += edac/ | 73 | obj-$(CONFIG_EDAC) += edac/ |
73 | obj-$(CONFIG_MCA) += mca/ | 74 | obj-$(CONFIG_MCA) += mca/ |
74 | obj-$(CONFIG_EISA) += eisa/ | 75 | obj-$(CONFIG_EISA) += eisa/ |
76 | obj-$(CONFIG_LGUEST_GUEST) += lguest/ | ||
75 | obj-$(CONFIG_CPU_FREQ) += cpufreq/ | 77 | obj-$(CONFIG_CPU_FREQ) += cpufreq/ |
76 | obj-$(CONFIG_MMC) += mmc/ | 78 | obj-$(CONFIG_MMC) += mmc/ |
77 | obj-$(CONFIG_NEW_LEDS) += leds/ | 79 | obj-$(CONFIG_NEW_LEDS) += leds/ |
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index bc7e16ec8393..42127c0d612c 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -217,10 +217,26 @@ static void acpi_hibernation_finish(void) | |||
217 | } | 217 | } |
218 | } | 218 | } |
219 | 219 | ||
220 | static int acpi_hibernation_pre_restore(void) | ||
221 | { | ||
222 | acpi_status status; | ||
223 | |||
224 | status = acpi_hw_disable_all_gpes(); | ||
225 | |||
226 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | ||
227 | } | ||
228 | |||
229 | static void acpi_hibernation_restore_cleanup(void) | ||
230 | { | ||
231 | acpi_hw_enable_all_runtime_gpes(); | ||
232 | } | ||
233 | |||
220 | static struct hibernation_ops acpi_hibernation_ops = { | 234 | static struct hibernation_ops acpi_hibernation_ops = { |
221 | .prepare = acpi_hibernation_prepare, | 235 | .prepare = acpi_hibernation_prepare, |
222 | .enter = acpi_hibernation_enter, | 236 | .enter = acpi_hibernation_enter, |
223 | .finish = acpi_hibernation_finish, | 237 | .finish = acpi_hibernation_finish, |
238 | .pre_restore = acpi_hibernation_pre_restore, | ||
239 | .restore_cleanup = acpi_hibernation_restore_cleanup, | ||
224 | }; | 240 | }; |
225 | #endif /* CONFIG_SOFTWARE_SUSPEND */ | 241 | #endif /* CONFIG_SOFTWARE_SUSPEND */ |
226 | 242 | ||
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index d9801eff6489..39e40d56b034 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c | |||
@@ -39,7 +39,13 @@ int acpi_sleep_prepare(u32 acpi_state) | |||
39 | 39 | ||
40 | #ifdef CONFIG_PM | 40 | #ifdef CONFIG_PM |
41 | 41 | ||
42 | void acpi_power_off(void) | 42 | static void acpi_power_off_prepare(void) |
43 | { | ||
44 | /* Prepare to power off the system */ | ||
45 | acpi_sleep_prepare(ACPI_STATE_S5); | ||
46 | } | ||
47 | |||
48 | static void acpi_power_off(void) | ||
43 | { | 49 | { |
44 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ | 50 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ |
45 | printk("%s called\n", __FUNCTION__); | 51 | printk("%s called\n", __FUNCTION__); |
@@ -48,30 +54,6 @@ void acpi_power_off(void) | |||
48 | acpi_enter_sleep_state(ACPI_STATE_S5); | 54 | acpi_enter_sleep_state(ACPI_STATE_S5); |
49 | } | 55 | } |
50 | 56 | ||
51 | static int acpi_shutdown(struct sys_device *x) | ||
52 | { | ||
53 | switch (system_state) { | ||
54 | case SYSTEM_POWER_OFF: | ||
55 | /* Prepare to power off the system */ | ||
56 | return acpi_sleep_prepare(ACPI_STATE_S5); | ||
57 | case SYSTEM_SUSPEND_DISK: | ||
58 | /* Prepare to suspend the system to disk */ | ||
59 | return acpi_sleep_prepare(ACPI_STATE_S4); | ||
60 | default: | ||
61 | return 0; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static struct sysdev_class acpi_sysclass = { | ||
66 | set_kset_name("acpi"), | ||
67 | .shutdown = acpi_shutdown | ||
68 | }; | ||
69 | |||
70 | static struct sys_device device_acpi = { | ||
71 | .id = 0, | ||
72 | .cls = &acpi_sysclass, | ||
73 | }; | ||
74 | |||
75 | static int acpi_poweroff_init(void) | 57 | static int acpi_poweroff_init(void) |
76 | { | 58 | { |
77 | if (!acpi_disabled) { | 59 | if (!acpi_disabled) { |
@@ -81,13 +63,8 @@ static int acpi_poweroff_init(void) | |||
81 | status = | 63 | status = |
82 | acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); | 64 | acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); |
83 | if (ACPI_SUCCESS(status)) { | 65 | if (ACPI_SUCCESS(status)) { |
84 | int error; | 66 | pm_power_off_prepare = acpi_power_off_prepare; |
85 | error = sysdev_class_register(&acpi_sysclass); | 67 | pm_power_off = acpi_power_off; |
86 | if (!error) | ||
87 | error = sysdev_register(&device_acpi); | ||
88 | if (!error) | ||
89 | pm_power_off = acpi_power_off; | ||
90 | return error; | ||
91 | } | 68 | } |
92 | } | 69 | } |
93 | return 0; | 70 | return 0; |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 0455aa78fa13..3599ab2506d2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include "base.h" | 24 | #include "base.h" |
25 | #include "power/power.h" | 25 | #include "power/power.h" |
26 | 26 | ||
27 | extern const char *kobject_actions[]; | ||
28 | |||
27 | int (*platform_notify)(struct device * dev) = NULL; | 29 | int (*platform_notify)(struct device * dev) = NULL; |
28 | int (*platform_notify_remove)(struct device * dev) = NULL; | 30 | int (*platform_notify_remove)(struct device * dev) = NULL; |
29 | 31 | ||
@@ -303,10 +305,25 @@ out: | |||
303 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | 305 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, |
304 | const char *buf, size_t count) | 306 | const char *buf, size_t count) |
305 | { | 307 | { |
306 | if (memcmp(buf, "add", 3) != 0) | 308 | size_t len = count; |
307 | dev_err(dev, "uevent: unsupported action-string; this will " | 309 | enum kobject_action action; |
308 | "be ignored in a future kernel version"); | 310 | |
311 | if (len && buf[len-1] == '\n') | ||
312 | len--; | ||
313 | |||
314 | for (action = 0; action < KOBJ_MAX; action++) { | ||
315 | if (strncmp(kobject_actions[action], buf, len) != 0) | ||
316 | continue; | ||
317 | if (kobject_actions[action][len] != '\0') | ||
318 | continue; | ||
319 | kobject_uevent(&dev->kobj, action); | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | dev_err(dev, "uevent: unsupported action-string; this will " | ||
324 | "be ignored in a future kernel version\n"); | ||
309 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 325 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
326 | out: | ||
310 | return count; | 327 | return count; |
311 | } | 328 | } |
312 | 329 | ||
@@ -643,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
643 | return 0; | 660 | return 0; |
644 | } | 661 | } |
645 | 662 | ||
663 | static int device_add_class_symlinks(struct device *dev) | ||
664 | { | ||
665 | int error; | ||
666 | |||
667 | if (!dev->class) | ||
668 | return 0; | ||
669 | error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | ||
670 | "subsystem"); | ||
671 | if (error) | ||
672 | goto out; | ||
673 | /* | ||
674 | * If this is not a "fake" compatible device, then create the | ||
675 | * symlink from the class to the device. | ||
676 | */ | ||
677 | if (dev->kobj.parent != &dev->class->subsys.kobj) { | ||
678 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | ||
679 | dev->bus_id); | ||
680 | if (error) | ||
681 | goto out_subsys; | ||
682 | } | ||
683 | /* only bus-device parents get a "device"-link */ | ||
684 | if (dev->parent && dev->parent->bus) { | ||
685 | error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
686 | "device"); | ||
687 | if (error) | ||
688 | goto out_busid; | ||
689 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
690 | { | ||
691 | char * class_name = make_class_name(dev->class->name, | ||
692 | &dev->kobj); | ||
693 | if (class_name) | ||
694 | error = sysfs_create_link(&dev->parent->kobj, | ||
695 | &dev->kobj, class_name); | ||
696 | kfree(class_name); | ||
697 | if (error) | ||
698 | goto out_device; | ||
699 | } | ||
700 | #endif | ||
701 | } | ||
702 | return 0; | ||
703 | |||
704 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
705 | out_device: | ||
706 | if (dev->parent) | ||
707 | sysfs_remove_link(&dev->kobj, "device"); | ||
708 | #endif | ||
709 | out_busid: | ||
710 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
711 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
712 | out_subsys: | ||
713 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
714 | out: | ||
715 | return error; | ||
716 | } | ||
717 | |||
718 | static void device_remove_class_symlinks(struct device *dev) | ||
719 | { | ||
720 | if (!dev->class) | ||
721 | return; | ||
722 | if (dev->parent) { | ||
723 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
724 | char *class_name; | ||
725 | |||
726 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
727 | if (class_name) { | ||
728 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
729 | kfree(class_name); | ||
730 | } | ||
731 | #endif | ||
732 | sysfs_remove_link(&dev->kobj, "device"); | ||
733 | } | ||
734 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
735 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
736 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
737 | } | ||
738 | |||
646 | /** | 739 | /** |
647 | * device_add - add device to device hierarchy. | 740 | * device_add - add device to device hierarchy. |
648 | * @dev: device. | 741 | * @dev: device. |
@@ -657,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
657 | int device_add(struct device *dev) | 750 | int device_add(struct device *dev) |
658 | { | 751 | { |
659 | struct device *parent = NULL; | 752 | struct device *parent = NULL; |
660 | char *class_name = NULL; | ||
661 | struct class_interface *class_intf; | 753 | struct class_interface *class_intf; |
662 | int error = -EINVAL; | 754 | int error = -EINVAL; |
663 | 755 | ||
@@ -697,27 +789,9 @@ int device_add(struct device *dev) | |||
697 | goto ueventattrError; | 789 | goto ueventattrError; |
698 | } | 790 | } |
699 | 791 | ||
700 | if (dev->class) { | 792 | error = device_add_class_symlinks(dev); |
701 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | 793 | if (error) |
702 | "subsystem"); | 794 | goto SymlinkError; |
703 | /* If this is not a "fake" compatible device, then create the | ||
704 | * symlink from the class to the device. */ | ||
705 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
706 | sysfs_create_link(&dev->class->subsys.kobj, | ||
707 | &dev->kobj, dev->bus_id); | ||
708 | if (parent) { | ||
709 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
710 | "device"); | ||
711 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
712 | class_name = make_class_name(dev->class->name, | ||
713 | &dev->kobj); | ||
714 | if (class_name) | ||
715 | sysfs_create_link(&dev->parent->kobj, | ||
716 | &dev->kobj, class_name); | ||
717 | #endif | ||
718 | } | ||
719 | } | ||
720 | |||
721 | error = device_add_attrs(dev); | 795 | error = device_add_attrs(dev); |
722 | if (error) | 796 | if (error) |
723 | goto AttrsError; | 797 | goto AttrsError; |
@@ -744,7 +818,6 @@ int device_add(struct device *dev) | |||
744 | up(&dev->class->sem); | 818 | up(&dev->class->sem); |
745 | } | 819 | } |
746 | Done: | 820 | Done: |
747 | kfree(class_name); | ||
748 | put_device(dev); | 821 | put_device(dev); |
749 | return error; | 822 | return error; |
750 | BusError: | 823 | BusError: |
@@ -755,6 +828,8 @@ int device_add(struct device *dev) | |||
755 | BUS_NOTIFY_DEL_DEVICE, dev); | 828 | BUS_NOTIFY_DEL_DEVICE, dev); |
756 | device_remove_attrs(dev); | 829 | device_remove_attrs(dev); |
757 | AttrsError: | 830 | AttrsError: |
831 | device_remove_class_symlinks(dev); | ||
832 | SymlinkError: | ||
758 | if (MAJOR(dev->devt)) | 833 | if (MAJOR(dev->devt)) |
759 | device_remove_file(dev, &devt_attr); | 834 | device_remove_file(dev, &devt_attr); |
760 | 835 | ||
@@ -1139,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name) | |||
1139 | { | 1214 | { |
1140 | char *old_class_name = NULL; | 1215 | char *old_class_name = NULL; |
1141 | char *new_class_name = NULL; | 1216 | char *new_class_name = NULL; |
1142 | char *old_symlink_name = NULL; | 1217 | char *old_device_name = NULL; |
1143 | int error; | 1218 | int error; |
1144 | 1219 | ||
1145 | dev = get_device(dev); | 1220 | dev = get_device(dev); |
@@ -1153,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name) | |||
1153 | old_class_name = make_class_name(dev->class->name, &dev->kobj); | 1228 | old_class_name = make_class_name(dev->class->name, &dev->kobj); |
1154 | #endif | 1229 | #endif |
1155 | 1230 | ||
1156 | if (dev->class) { | 1231 | old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); |
1157 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | 1232 | if (!old_device_name) { |
1158 | if (!old_symlink_name) { | 1233 | error = -ENOMEM; |
1159 | error = -ENOMEM; | 1234 | goto out; |
1160 | goto out_free_old_class; | ||
1161 | } | ||
1162 | strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); | ||
1163 | } | 1235 | } |
1164 | 1236 | strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); | |
1165 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); | 1237 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); |
1166 | 1238 | ||
1167 | error = kobject_rename(&dev->kobj, new_name); | 1239 | error = kobject_rename(&dev->kobj, new_name); |
1240 | if (error) { | ||
1241 | strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); | ||
1242 | goto out; | ||
1243 | } | ||
1168 | 1244 | ||
1169 | #ifdef CONFIG_SYSFS_DEPRECATED | 1245 | #ifdef CONFIG_SYSFS_DEPRECATED |
1170 | if (old_class_name) { | 1246 | if (old_class_name) { |
1171 | new_class_name = make_class_name(dev->class->name, &dev->kobj); | 1247 | new_class_name = make_class_name(dev->class->name, &dev->kobj); |
1172 | if (new_class_name) { | 1248 | if (new_class_name) { |
1173 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, | 1249 | error = sysfs_create_link(&dev->parent->kobj, |
1174 | new_class_name); | 1250 | &dev->kobj, new_class_name); |
1251 | if (error) | ||
1252 | goto out; | ||
1175 | sysfs_remove_link(&dev->parent->kobj, old_class_name); | 1253 | sysfs_remove_link(&dev->parent->kobj, old_class_name); |
1176 | } | 1254 | } |
1177 | } | 1255 | } |
1178 | #endif | 1256 | #endif |
1179 | 1257 | ||
1180 | if (dev->class) { | 1258 | if (dev->class) { |
1181 | sysfs_remove_link(&dev->class->subsys.kobj, | 1259 | sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); |
1182 | old_symlink_name); | 1260 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, |
1183 | sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | 1261 | dev->bus_id); |
1184 | dev->bus_id); | 1262 | if (error) { |
1263 | /* Uh... how to unravel this if restoring can fail? */ | ||
1264 | dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", | ||
1265 | __FUNCTION__, error); | ||
1266 | } | ||
1185 | } | 1267 | } |
1268 | out: | ||
1186 | put_device(dev); | 1269 | put_device(dev); |
1187 | 1270 | ||
1188 | kfree(new_class_name); | 1271 | kfree(new_class_name); |
1189 | kfree(old_symlink_name); | ||
1190 | out_free_old_class: | ||
1191 | kfree(old_class_name); | 1272 | kfree(old_class_name); |
1273 | kfree(old_device_name); | ||
1192 | 1274 | ||
1193 | return error; | 1275 | return error; |
1194 | } | 1276 | } |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 91f230939c1e..966a5e287415 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -1,10 +1,10 @@ | |||
1 | obj-y := shutdown.o | 1 | obj-y := shutdown.o |
2 | obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o | 2 | obj-$(CONFIG_PM) += main.o suspend.o resume.o sysfs.o |
3 | obj-$(CONFIG_PM_TRACE) += trace.o | 3 | obj-$(CONFIG_PM_TRACE) += trace.o |
4 | 4 | ||
5 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 5 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
6 | EXTRA_CFLAGS += -DDEBUG | 6 | EXTRA_CFLAGS += -DDEBUG |
7 | endif | 7 | endif |
8 | ifeq ($(CONFIG_PM_DEBUG),y) | 8 | ifeq ($(CONFIG_PM_VERBOSE),y) |
9 | EXTRA_CFLAGS += -DDEBUG | 9 | EXTRA_CFLAGS += -DDEBUG |
10 | endif | 10 | endif |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 2760f25b3ac5..591a0dd5deee 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -62,11 +62,6 @@ extern int resume_device(struct device *); | |||
62 | */ | 62 | */ |
63 | extern int suspend_device(struct device *, pm_message_t); | 63 | extern int suspend_device(struct device *, pm_message_t); |
64 | 64 | ||
65 | |||
66 | /* | ||
67 | * runtime.c | ||
68 | */ | ||
69 | |||
70 | #else /* CONFIG_PM */ | 65 | #else /* CONFIG_PM */ |
71 | 66 | ||
72 | 67 | ||
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c deleted file mode 100644 index df6174d85866..000000000000 --- a/drivers/base/power/runtime.c +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/base/power/runtime.c - Handling dynamic device power management. | ||
3 | * | ||
4 | * Copyright (c) 2003 Patrick Mochel | ||
5 | * Copyright (c) 2003 Open Source Development Lab | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/device.h> | ||
10 | #include "power.h" | ||
11 | |||
12 | |||
13 | static void runtime_resume(struct device * dev) | ||
14 | { | ||
15 | dev_dbg(dev, "resuming\n"); | ||
16 | if (!dev->power.power_state.event) | ||
17 | return; | ||
18 | if (!resume_device(dev)) | ||
19 | dev->power.power_state = PMSG_ON; | ||
20 | } | ||
21 | |||
22 | |||
23 | /** | ||
24 | * dpm_runtime_resume - Power one device back on. | ||
25 | * @dev: Device. | ||
26 | * | ||
27 | * Bring one device back to the on state by first powering it | ||
28 | * on, then restoring state. We only operate on devices that aren't | ||
29 | * already on. | ||
30 | * FIXME: We need to handle devices that are in an unknown state. | ||
31 | */ | ||
32 | |||
33 | void dpm_runtime_resume(struct device * dev) | ||
34 | { | ||
35 | mutex_lock(&dpm_mtx); | ||
36 | runtime_resume(dev); | ||
37 | mutex_unlock(&dpm_mtx); | ||
38 | } | ||
39 | EXPORT_SYMBOL(dpm_runtime_resume); | ||
40 | |||
41 | |||
42 | /** | ||
43 | * dpm_runtime_suspend - Put one device in low-power state. | ||
44 | * @dev: Device. | ||
45 | * @state: State to enter. | ||
46 | */ | ||
47 | |||
48 | int dpm_runtime_suspend(struct device * dev, pm_message_t state) | ||
49 | { | ||
50 | int error = 0; | ||
51 | |||
52 | mutex_lock(&dpm_mtx); | ||
53 | if (dev->power.power_state.event == state.event) | ||
54 | goto Done; | ||
55 | |||
56 | if (dev->power.power_state.event) | ||
57 | runtime_resume(dev); | ||
58 | |||
59 | if (!(error = suspend_device(dev, state))) | ||
60 | dev->power.power_state = state; | ||
61 | Done: | ||
62 | mutex_unlock(&dpm_mtx); | ||
63 | return error; | ||
64 | } | ||
65 | EXPORT_SYMBOL(dpm_runtime_suspend); | ||
66 | |||
67 | |||
68 | #if 0 | ||
69 | /** | ||
70 | * dpm_set_power_state - Update power_state field. | ||
71 | * @dev: Device. | ||
72 | * @state: Power state device is in. | ||
73 | * | ||
74 | * This is an update mechanism for drivers to notify the core | ||
75 | * what power state a device is in. Device probing code may not | ||
76 | * always be able to tell, but we need accurate information to | ||
77 | * work reliably. | ||
78 | */ | ||
79 | void dpm_set_power_state(struct device * dev, pm_message_t state) | ||
80 | { | ||
81 | mutex_lock(&dpm_mtx); | ||
82 | dev->power.power_state = state; | ||
83 | mutex_unlock(&dpm_mtx); | ||
84 | } | ||
85 | #endif /* 0 */ | ||
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 2d47517dbe32..f2ed179cd695 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -7,69 +7,6 @@ | |||
7 | #include "power.h" | 7 | #include "power.h" |
8 | 8 | ||
9 | 9 | ||
10 | #ifdef CONFIG_PM_SYSFS_DEPRECATED | ||
11 | |||
12 | /** | ||
13 | * state - Control current power state of device | ||
14 | * | ||
15 | * show() returns the current power state of the device. '0' indicates | ||
16 | * the device is on. Other values (2) indicate the device is in some low | ||
17 | * power state. | ||
18 | * | ||
19 | * store() sets the current power state, which is an integer valued | ||
20 | * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early() | ||
21 | * methods fail this operation; those methods couldn't be called. | ||
22 | * Otherwise, | ||
23 | * | ||
24 | * - If the recorded dev->power.power_state.event matches the | ||
25 | * target value, nothing is done. | ||
26 | * - If the recorded event code is nonzero, the device is reactivated | ||
27 | * by calling bus.resume() and/or class.resume(). | ||
28 | * - If the target value is nonzero, the device is suspended by | ||
29 | * calling class.suspend() and/or bus.suspend() with event code | ||
30 | * PM_EVENT_SUSPEND. | ||
31 | * | ||
32 | * This mechanism is DEPRECATED and should only be used for testing. | ||
33 | */ | ||
34 | |||
35 | static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf) | ||
36 | { | ||
37 | if (dev->power.power_state.event) | ||
38 | return sprintf(buf, "2\n"); | ||
39 | else | ||
40 | return sprintf(buf, "0\n"); | ||
41 | } | ||
42 | |||
43 | static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n) | ||
44 | { | ||
45 | pm_message_t state; | ||
46 | int error = -EINVAL; | ||
47 | |||
48 | /* disallow incomplete suspend sequences */ | ||
49 | if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early)) | ||
50 | return error; | ||
51 | |||
52 | state.event = PM_EVENT_SUSPEND; | ||
53 | /* Older apps expected to write "3" here - confused with PCI D3 */ | ||
54 | if ((n == 1) && !strcmp(buf, "3")) | ||
55 | error = dpm_runtime_suspend(dev, state); | ||
56 | |||
57 | if ((n == 1) && !strcmp(buf, "2")) | ||
58 | error = dpm_runtime_suspend(dev, state); | ||
59 | |||
60 | if ((n == 1) && !strcmp(buf, "0")) { | ||
61 | dpm_runtime_resume(dev); | ||
62 | error = 0; | ||
63 | } | ||
64 | |||
65 | return error ? error : n; | ||
66 | } | ||
67 | |||
68 | static DEVICE_ATTR(state, 0644, state_show, state_store); | ||
69 | |||
70 | |||
71 | #endif /* CONFIG_PM_SYSFS_DEPRECATED */ | ||
72 | |||
73 | /* | 10 | /* |
74 | * wakeup - Report/change current wakeup option for device | 11 | * wakeup - Report/change current wakeup option for device |
75 | * | 12 | * |
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); | |||
143 | 80 | ||
144 | 81 | ||
145 | static struct attribute * power_attrs[] = { | 82 | static struct attribute * power_attrs[] = { |
146 | #ifdef CONFIG_PM_SYSFS_DEPRECATED | ||
147 | &dev_attr_state.attr, | ||
148 | #endif | ||
149 | &dev_attr_wakeup.attr, | 83 | &dev_attr_wakeup.attr, |
150 | NULL, | 84 | NULL, |
151 | }; | 85 | }; |
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 3e31532df0ed..819c829125fb 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile | |||
@@ -30,3 +30,4 @@ obj-$(CONFIG_BLK_DEV_SX8) += sx8.o | |||
30 | obj-$(CONFIG_BLK_DEV_UB) += ub.o | 30 | obj-$(CONFIG_BLK_DEV_UB) += ub.o |
31 | 31 | ||
32 | obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o | 32 | obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o |
33 | obj-$(CONFIG_LGUEST_GUEST) += lguest_blk.o | ||
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c new file mode 100644 index 000000000000..1634c2dd25ec --- /dev/null +++ b/drivers/block/lguest_blk.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /* A simple block driver for lguest. | ||
2 | * | ||
3 | * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | //#define DEBUG | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/blkdev.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/lguest_bus.h> | ||
25 | |||
26 | static char next_block_index = 'a'; | ||
27 | |||
28 | struct blockdev | ||
29 | { | ||
30 | spinlock_t lock; | ||
31 | |||
32 | /* The disk structure for the kernel. */ | ||
33 | struct gendisk *disk; | ||
34 | |||
35 | /* The major number for this disk. */ | ||
36 | int major; | ||
37 | int irq; | ||
38 | |||
39 | unsigned long phys_addr; | ||
40 | /* The mapped block page. */ | ||
41 | struct lguest_block_page *lb_page; | ||
42 | |||
43 | /* We only have a single request outstanding at a time. */ | ||
44 | struct lguest_dma dma; | ||
45 | struct request *req; | ||
46 | }; | ||
47 | |||
48 | /* Jens gave me this nice helper to end all chunks of a request. */ | ||
49 | static void end_entire_request(struct request *req, int uptodate) | ||
50 | { | ||
51 | if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) | ||
52 | BUG(); | ||
53 | add_disk_randomness(req->rq_disk); | ||
54 | blkdev_dequeue_request(req); | ||
55 | end_that_request_last(req, uptodate); | ||
56 | } | ||
57 | |||
58 | static irqreturn_t lgb_irq(int irq, void *_bd) | ||
59 | { | ||
60 | struct blockdev *bd = _bd; | ||
61 | unsigned long flags; | ||
62 | |||
63 | if (!bd->req) { | ||
64 | pr_debug("No work!\n"); | ||
65 | return IRQ_NONE; | ||
66 | } | ||
67 | |||
68 | if (!bd->lb_page->result) { | ||
69 | pr_debug("No result!\n"); | ||
70 | return IRQ_NONE; | ||
71 | } | ||
72 | |||
73 | spin_lock_irqsave(&bd->lock, flags); | ||
74 | end_entire_request(bd->req, bd->lb_page->result == 1); | ||
75 | bd->req = NULL; | ||
76 | bd->dma.used_len = 0; | ||
77 | blk_start_queue(bd->disk->queue); | ||
78 | spin_unlock_irqrestore(&bd->lock, flags); | ||
79 | return IRQ_HANDLED; | ||
80 | } | ||
81 | |||
82 | static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) | ||
83 | { | ||
84 | unsigned int i = 0, idx, len = 0; | ||
85 | struct bio *bio; | ||
86 | |||
87 | rq_for_each_bio(bio, req) { | ||
88 | struct bio_vec *bvec; | ||
89 | bio_for_each_segment(bvec, bio, idx) { | ||
90 | BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); | ||
91 | BUG_ON(!bvec->bv_len); | ||
92 | dma->addr[i] = page_to_phys(bvec->bv_page) | ||
93 | + bvec->bv_offset; | ||
94 | dma->len[i] = bvec->bv_len; | ||
95 | len += bvec->bv_len; | ||
96 | i++; | ||
97 | } | ||
98 | } | ||
99 | if (i < LGUEST_MAX_DMA_SECTIONS) | ||
100 | dma->len[i] = 0; | ||
101 | return len; | ||
102 | } | ||
103 | |||
104 | static void empty_dma(struct lguest_dma *dma) | ||
105 | { | ||
106 | dma->len[0] = 0; | ||
107 | } | ||
108 | |||
109 | static void setup_req(struct blockdev *bd, | ||
110 | int type, struct request *req, struct lguest_dma *dma) | ||
111 | { | ||
112 | bd->lb_page->type = type; | ||
113 | bd->lb_page->sector = req->sector; | ||
114 | bd->lb_page->result = 0; | ||
115 | bd->req = req; | ||
116 | bd->lb_page->bytes = req_to_dma(req, dma); | ||
117 | } | ||
118 | |||
119 | static void do_write(struct blockdev *bd, struct request *req) | ||
120 | { | ||
121 | struct lguest_dma send; | ||
122 | |||
123 | pr_debug("lgb: WRITE sector %li\n", (long)req->sector); | ||
124 | setup_req(bd, 1, req, &send); | ||
125 | |||
126 | lguest_send_dma(bd->phys_addr, &send); | ||
127 | } | ||
128 | |||
129 | static void do_read(struct blockdev *bd, struct request *req) | ||
130 | { | ||
131 | struct lguest_dma ping; | ||
132 | |||
133 | pr_debug("lgb: READ sector %li\n", (long)req->sector); | ||
134 | setup_req(bd, 0, req, &bd->dma); | ||
135 | |||
136 | empty_dma(&ping); | ||
137 | lguest_send_dma(bd->phys_addr, &ping); | ||
138 | } | ||
139 | |||
140 | static void do_lgb_request(request_queue_t *q) | ||
141 | { | ||
142 | struct blockdev *bd; | ||
143 | struct request *req; | ||
144 | |||
145 | again: | ||
146 | req = elv_next_request(q); | ||
147 | if (!req) | ||
148 | return; | ||
149 | |||
150 | bd = req->rq_disk->private_data; | ||
151 | /* Sometimes we get repeated requests after blk_stop_queue. */ | ||
152 | if (bd->req) | ||
153 | return; | ||
154 | |||
155 | if (!blk_fs_request(req)) { | ||
156 | pr_debug("Got non-command 0x%08x\n", req->cmd_type); | ||
157 | req->errors++; | ||
158 | end_entire_request(req, 0); | ||
159 | goto again; | ||
160 | } | ||
161 | |||
162 | if (rq_data_dir(req) == WRITE) | ||
163 | do_write(bd, req); | ||
164 | else | ||
165 | do_read(bd, req); | ||
166 | |||
167 | /* Wait for interrupt to tell us it's done. */ | ||
168 | blk_stop_queue(q); | ||
169 | } | ||
170 | |||
171 | static struct block_device_operations lguestblk_fops = { | ||
172 | .owner = THIS_MODULE, | ||
173 | }; | ||
174 | |||
175 | static int lguestblk_probe(struct lguest_device *lgdev) | ||
176 | { | ||
177 | struct blockdev *bd; | ||
178 | int err; | ||
179 | int irqflags = IRQF_SHARED; | ||
180 | |||
181 | bd = kmalloc(sizeof(*bd), GFP_KERNEL); | ||
182 | if (!bd) | ||
183 | return -ENOMEM; | ||
184 | |||
185 | spin_lock_init(&bd->lock); | ||
186 | bd->irq = lgdev_irq(lgdev); | ||
187 | bd->req = NULL; | ||
188 | bd->dma.used_len = 0; | ||
189 | bd->dma.len[0] = 0; | ||
190 | bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT); | ||
191 | |||
192 | bd->lb_page = lguest_map(bd->phys_addr, 1); | ||
193 | if (!bd->lb_page) { | ||
194 | err = -ENOMEM; | ||
195 | goto out_free_bd; | ||
196 | } | ||
197 | |||
198 | bd->major = register_blkdev(0, "lguestblk"); | ||
199 | if (bd->major < 0) { | ||
200 | err = bd->major; | ||
201 | goto out_unmap; | ||
202 | } | ||
203 | |||
204 | bd->disk = alloc_disk(1); | ||
205 | if (!bd->disk) { | ||
206 | err = -ENOMEM; | ||
207 | goto out_unregister_blkdev; | ||
208 | } | ||
209 | |||
210 | bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock); | ||
211 | if (!bd->disk->queue) { | ||
212 | err = -ENOMEM; | ||
213 | goto out_put_disk; | ||
214 | } | ||
215 | |||
216 | /* We can only handle a certain number of sg entries */ | ||
217 | blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS); | ||
218 | /* Buffers must not cross page boundaries */ | ||
219 | blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1); | ||
220 | |||
221 | sprintf(bd->disk->disk_name, "lgb%c", next_block_index++); | ||
222 | if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS) | ||
223 | irqflags |= IRQF_SAMPLE_RANDOM; | ||
224 | err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd); | ||
225 | if (err) | ||
226 | goto out_cleanup_queue; | ||
227 | |||
228 | err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq); | ||
229 | if (err) | ||
230 | goto out_free_irq; | ||
231 | |||
232 | bd->disk->major = bd->major; | ||
233 | bd->disk->first_minor = 0; | ||
234 | bd->disk->private_data = bd; | ||
235 | bd->disk->fops = &lguestblk_fops; | ||
236 | /* This is initialized to the disk size by the other end. */ | ||
237 | set_capacity(bd->disk, bd->lb_page->num_sectors); | ||
238 | add_disk(bd->disk); | ||
239 | |||
240 | printk(KERN_INFO "%s: device %i at major %d\n", | ||
241 | bd->disk->disk_name, lgdev->index, bd->major); | ||
242 | |||
243 | lgdev->private = bd; | ||
244 | return 0; | ||
245 | |||
246 | out_free_irq: | ||
247 | free_irq(bd->irq, bd); | ||
248 | out_cleanup_queue: | ||
249 | blk_cleanup_queue(bd->disk->queue); | ||
250 | out_put_disk: | ||
251 | put_disk(bd->disk); | ||
252 | out_unregister_blkdev: | ||
253 | unregister_blkdev(bd->major, "lguestblk"); | ||
254 | out_unmap: | ||
255 | lguest_unmap(bd->lb_page); | ||
256 | out_free_bd: | ||
257 | kfree(bd); | ||
258 | return err; | ||
259 | } | ||
260 | |||
261 | static struct lguest_driver lguestblk_drv = { | ||
262 | .name = "lguestblk", | ||
263 | .owner = THIS_MODULE, | ||
264 | .device_type = LGUEST_DEVICE_T_BLOCK, | ||
265 | .probe = lguestblk_probe, | ||
266 | }; | ||
267 | |||
268 | static __init int lguestblk_init(void) | ||
269 | { | ||
270 | return register_lguest_driver(&lguestblk_drv); | ||
271 | } | ||
272 | module_init(lguestblk_init); | ||
273 | |||
274 | MODULE_DESCRIPTION("Lguest block driver"); | ||
275 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 54509eb3391b..949ae93499e5 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c | |||
@@ -1608,7 +1608,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1608 | } | 1608 | } |
1609 | #endif | 1609 | #endif |
1610 | 1610 | ||
1611 | host = kmalloc(sizeof(*host), GFP_KERNEL); | 1611 | host = kzalloc(sizeof(*host), GFP_KERNEL); |
1612 | if (!host) { | 1612 | if (!host) { |
1613 | printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", | 1613 | printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", |
1614 | pci_name(pdev)); | 1614 | pci_name(pdev)); |
@@ -1616,7 +1616,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1616 | goto err_out_regions; | 1616 | goto err_out_regions; |
1617 | } | 1617 | } |
1618 | 1618 | ||
1619 | memset(host, 0, sizeof(*host)); | ||
1620 | host->pdev = pdev; | 1619 | host->pdev = pdev; |
1621 | host->flags = pci_dac ? FL_DAC : 0; | 1620 | host->flags = pci_dac ? FL_DAC : 0; |
1622 | spin_lock_init(&host->lock); | 1621 | spin_lock_init(&host->lock); |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 8852b8d643cf..4e6f387fd189 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -42,6 +42,7 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o | |||
42 | obj-$(CONFIG_N_HDLC) += n_hdlc.o | 42 | obj-$(CONFIG_N_HDLC) += n_hdlc.o |
43 | obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o | 43 | obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o |
44 | obj-$(CONFIG_SX) += sx.o generic_serial.o | 44 | obj-$(CONFIG_SX) += sx.o generic_serial.o |
45 | obj-$(CONFIG_LGUEST_GUEST) += hvc_lguest.o | ||
45 | obj-$(CONFIG_RIO) += rio/ generic_serial.o | 46 | obj-$(CONFIG_RIO) += rio/ generic_serial.o |
46 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o | 47 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o |
47 | obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o | 48 | obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 7b02bf1289a2..3d468f502d2d 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -1721,12 +1721,11 @@ static int get_async_struct(int line, struct async_struct **ret_info) | |||
1721 | *ret_info = sstate->info; | 1721 | *ret_info = sstate->info; |
1722 | return 0; | 1722 | return 0; |
1723 | } | 1723 | } |
1724 | info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); | 1724 | info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); |
1725 | if (!info) { | 1725 | if (!info) { |
1726 | sstate->count--; | 1726 | sstate->count--; |
1727 | return -ENOMEM; | 1727 | return -ENOMEM; |
1728 | } | 1728 | } |
1729 | memset(info, 0, sizeof(struct async_struct)); | ||
1730 | #ifdef DECLARE_WAITQUEUE | 1729 | #ifdef DECLARE_WAITQUEUE |
1731 | init_waitqueue_head(&info->open_wait); | 1730 | init_waitqueue_head(&info->open_wait); |
1732 | init_waitqueue_head(&info->close_wait); | 1731 | init_waitqueue_head(&info->close_wait); |
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index fdb8609dd76f..832de1d9ba7e 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c | |||
@@ -273,10 +273,9 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg) | |||
273 | vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / | 273 | vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / |
274 | vsg->descriptors_per_page; | 274 | vsg->descriptors_per_page; |
275 | 275 | ||
276 | if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL))) | 276 | if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL))) |
277 | return DRM_ERR(ENOMEM); | 277 | return DRM_ERR(ENOMEM); |
278 | 278 | ||
279 | memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages); | ||
280 | vsg->state = dr_via_desc_pages_alloc; | 279 | vsg->state = dr_via_desc_pages_alloc; |
281 | for (i=0; i<vsg->num_desc_pages; ++i) { | 280 | for (i=0; i<vsg->num_desc_pages; ++i) { |
282 | if (NULL == (vsg->desc_pages[i] = | 281 | if (NULL == (vsg->desc_pages[i] = |
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 74cd5118af57..2e7ae42a5503 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
@@ -2459,7 +2459,7 @@ static int __init espserial_init(void) | |||
2459 | return 1; | 2459 | return 1; |
2460 | } | 2460 | } |
2461 | 2461 | ||
2462 | info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); | 2462 | info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); |
2463 | 2463 | ||
2464 | if (!info) | 2464 | if (!info) |
2465 | { | 2465 | { |
@@ -2469,7 +2469,6 @@ static int __init espserial_init(void) | |||
2469 | return 1; | 2469 | return 1; |
2470 | } | 2470 | } |
2471 | 2471 | ||
2472 | memset((void *)info, 0, sizeof(struct esp_struct)); | ||
2473 | spin_lock_init(&info->lock); | 2472 | spin_lock_init(&info->lock); |
2474 | /* rx_trigger, tx_trigger are needed by autoconfig */ | 2473 | /* rx_trigger, tx_trigger are needed by autoconfig */ |
2475 | info->config.rx_trigger = rx_trigger; | 2474 | info->config.rx_trigger = rx_trigger; |
@@ -2527,7 +2526,7 @@ static int __init espserial_init(void) | |||
2527 | if (!dma) | 2526 | if (!dma) |
2528 | info->stat_flags |= ESP_STAT_NEVER_DMA; | 2527 | info->stat_flags |= ESP_STAT_NEVER_DMA; |
2529 | 2528 | ||
2530 | info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); | 2529 | info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); |
2531 | if (!info) | 2530 | if (!info) |
2532 | { | 2531 | { |
2533 | printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); | 2532 | printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); |
@@ -2536,7 +2535,6 @@ static int __init espserial_init(void) | |||
2536 | return 0; | 2535 | return 0; |
2537 | } | 2536 | } |
2538 | 2537 | ||
2539 | memset((void *)info, 0, sizeof(struct esp_struct)); | ||
2540 | /* rx_trigger, tx_trigger are needed by autoconfig */ | 2538 | /* rx_trigger, tx_trigger are needed by autoconfig */ |
2541 | info->config.rx_trigger = rx_trigger; | 2539 | info->config.rx_trigger = rx_trigger; |
2542 | info->config.tx_trigger = tx_trigger; | 2540 | info->config.tx_trigger = tx_trigger; |
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c new file mode 100644 index 000000000000..e7b889e404a7 --- /dev/null +++ b/drivers/char/hvc_lguest.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* Simple console for lguest. | ||
2 | * | ||
3 | * Copyright (C) 2006 Rusty Russell, IBM Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/lguest_bus.h> | ||
22 | #include "hvc_console.h" | ||
23 | |||
24 | static char inbuf[256]; | ||
25 | static struct lguest_dma cons_input = { .used_len = 0, | ||
26 | .addr[0] = __pa(inbuf), | ||
27 | .len[0] = sizeof(inbuf), | ||
28 | .len[1] = 0 }; | ||
29 | |||
30 | static int put_chars(u32 vtermno, const char *buf, int count) | ||
31 | { | ||
32 | struct lguest_dma dma; | ||
33 | |||
34 | /* FIXME: what if it's over a page boundary? */ | ||
35 | dma.len[0] = count; | ||
36 | dma.len[1] = 0; | ||
37 | dma.addr[0] = __pa(buf); | ||
38 | |||
39 | lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma); | ||
40 | return count; | ||
41 | } | ||
42 | |||
43 | static int get_chars(u32 vtermno, char *buf, int count) | ||
44 | { | ||
45 | static int cons_offset; | ||
46 | |||
47 | if (!cons_input.used_len) | ||
48 | return 0; | ||
49 | |||
50 | if (cons_input.used_len - cons_offset < count) | ||
51 | count = cons_input.used_len - cons_offset; | ||
52 | |||
53 | memcpy(buf, inbuf + cons_offset, count); | ||
54 | cons_offset += count; | ||
55 | if (cons_offset == cons_input.used_len) { | ||
56 | cons_offset = 0; | ||
57 | cons_input.used_len = 0; | ||
58 | } | ||
59 | return count; | ||
60 | } | ||
61 | |||
62 | static struct hv_ops lguest_cons = { | ||
63 | .get_chars = get_chars, | ||
64 | .put_chars = put_chars, | ||
65 | }; | ||
66 | |||
67 | static int __init cons_init(void) | ||
68 | { | ||
69 | if (strcmp(paravirt_ops.name, "lguest") != 0) | ||
70 | return 0; | ||
71 | |||
72 | return hvc_instantiate(0, 0, &lguest_cons); | ||
73 | } | ||
74 | console_initcall(cons_init); | ||
75 | |||
76 | static int lguestcons_probe(struct lguest_device *lgdev) | ||
77 | { | ||
78 | int err; | ||
79 | |||
80 | lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256); | ||
81 | if (IS_ERR(lgdev->private)) | ||
82 | return PTR_ERR(lgdev->private); | ||
83 | |||
84 | err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1, | ||
85 | lgdev_irq(lgdev)); | ||
86 | if (err) | ||
87 | printk("lguest console: failed to bind buffer.\n"); | ||
88 | return err; | ||
89 | } | ||
90 | |||
91 | static struct lguest_driver lguestcons_drv = { | ||
92 | .name = "lguestcons", | ||
93 | .owner = THIS_MODULE, | ||
94 | .device_type = LGUEST_DEVICE_T_CONSOLE, | ||
95 | .probe = lguestcons_probe, | ||
96 | }; | ||
97 | |||
98 | static int __init hvc_lguest_init(void) | ||
99 | { | ||
100 | return register_lguest_driver(&lguestcons_drv); | ||
101 | } | ||
102 | module_init(hvc_lguest_init); | ||
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 207f7343ba60..17f96e04266f 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -784,12 +784,10 @@ static int __devinit hvcs_probe( | |||
784 | return -EFAULT; | 784 | return -EFAULT; |
785 | } | 785 | } |
786 | 786 | ||
787 | hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL); | 787 | hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL); |
788 | if (!hvcsd) | 788 | if (!hvcsd) |
789 | return -ENODEV; | 789 | return -ENODEV; |
790 | 790 | ||
791 | /* hvcsd->tty is zeroed out with the memset */ | ||
792 | memset(hvcsd, 0x00, sizeof(*hvcsd)); | ||
793 | 791 | ||
794 | spin_lock_init(&hvcsd->lock); | 792 | spin_lock_init(&hvcsd->lock); |
795 | /* Automatically incs the refcount the first time */ | 793 | /* Automatically incs the refcount the first time */ |
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 83c7258d3580..6005b5225772 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -425,9 +425,7 @@ cleanup_module(void) | |||
425 | printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); | 425 | printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); |
426 | } | 426 | } |
427 | put_tty_driver(ip2_tty_driver); | 427 | put_tty_driver(ip2_tty_driver); |
428 | if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { | 428 | unregister_chrdev(IP2_IPL_MAJOR, pcIpl); |
429 | printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); | ||
430 | } | ||
431 | remove_proc_entry("ip2mem", &proc_root); | 429 | remove_proc_entry("ip2mem", &proc_root); |
432 | 430 | ||
433 | // free memory | 431 | // free memory |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b5df7e61aeb2..6a01dd9e43f8 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -2639,10 +2639,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | |||
2639 | return -ENODEV; | 2639 | return -ENODEV; |
2640 | } | 2640 | } |
2641 | 2641 | ||
2642 | intf = kmalloc(sizeof(*intf), GFP_KERNEL); | 2642 | intf = kzalloc(sizeof(*intf), GFP_KERNEL); |
2643 | if (!intf) | 2643 | if (!intf) |
2644 | return -ENOMEM; | 2644 | return -ENOMEM; |
2645 | memset(intf, 0, sizeof(*intf)); | ||
2646 | 2645 | ||
2647 | intf->ipmi_version_major = ipmi_version_major(device_id); | 2646 | intf->ipmi_version_major = ipmi_version_major(device_id); |
2648 | intf->ipmi_version_minor = ipmi_version_minor(device_id); | 2647 | intf->ipmi_version_minor = ipmi_version_minor(device_id); |
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 57f9115a456c..7ee5d9444926 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c | |||
@@ -39,14 +39,14 @@ | |||
39 | #else | 39 | #else |
40 | #define DBG(fmt...) | 40 | #define DBG(fmt...) |
41 | #endif | 41 | #endif |
42 | int mbcs_major; | 42 | static int mbcs_major; |
43 | 43 | ||
44 | LIST_HEAD(soft_list); | 44 | static LIST_HEAD(soft_list); |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * file operations | 47 | * file operations |
48 | */ | 48 | */ |
49 | const struct file_operations mbcs_ops = { | 49 | static const struct file_operations mbcs_ops = { |
50 | .open = mbcs_open, | 50 | .open = mbcs_open, |
51 | .llseek = mbcs_sram_llseek, | 51 | .llseek = mbcs_sram_llseek, |
52 | .read = mbcs_sram_read, | 52 | .read = mbcs_sram_read, |
@@ -377,7 +377,7 @@ dmaread_exit: | |||
377 | return rv; | 377 | return rv; |
378 | } | 378 | } |
379 | 379 | ||
380 | int mbcs_open(struct inode *ip, struct file *fp) | 380 | static int mbcs_open(struct inode *ip, struct file *fp) |
381 | { | 381 | { |
382 | struct mbcs_soft *soft; | 382 | struct mbcs_soft *soft; |
383 | int minor; | 383 | int minor; |
@@ -394,7 +394,7 @@ int mbcs_open(struct inode *ip, struct file *fp) | |||
394 | return -ENODEV; | 394 | return -ENODEV; |
395 | } | 395 | } |
396 | 396 | ||
397 | ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) | 397 | static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off) |
398 | { | 398 | { |
399 | struct cx_dev *cx_dev = fp->private_data; | 399 | struct cx_dev *cx_dev = fp->private_data; |
400 | struct mbcs_soft *soft = cx_dev->soft; | 400 | struct mbcs_soft *soft = cx_dev->soft; |
@@ -418,7 +418,7 @@ ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * | |||
418 | return rv; | 418 | return rv; |
419 | } | 419 | } |
420 | 420 | ||
421 | ssize_t | 421 | static ssize_t |
422 | mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off) | 422 | mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off) |
423 | { | 423 | { |
424 | struct cx_dev *cx_dev = fp->private_data; | 424 | struct cx_dev *cx_dev = fp->private_data; |
@@ -443,7 +443,7 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o | |||
443 | return rv; | 443 | return rv; |
444 | } | 444 | } |
445 | 445 | ||
446 | loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) | 446 | static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) |
447 | { | 447 | { |
448 | loff_t newpos; | 448 | loff_t newpos; |
449 | 449 | ||
@@ -491,7 +491,7 @@ static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft) | |||
491 | soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); | 491 | soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START); |
492 | } | 492 | } |
493 | 493 | ||
494 | int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) | 494 | static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma) |
495 | { | 495 | { |
496 | struct cx_dev *cx_dev = fp->private_data; | 496 | struct cx_dev *cx_dev = fp->private_data; |
497 | struct mbcs_soft *soft = cx_dev->soft; | 497 | struct mbcs_soft *soft = cx_dev->soft; |
@@ -793,7 +793,7 @@ static int mbcs_remove(struct cx_dev *dev) | |||
793 | return 0; | 793 | return 0; |
794 | } | 794 | } |
795 | 795 | ||
796 | const struct cx_device_id __devinitdata mbcs_id_table[] = { | 796 | static const struct cx_device_id __devinitdata mbcs_id_table[] = { |
797 | { | 797 | { |
798 | .part_num = MBCS_PART_NUM, | 798 | .part_num = MBCS_PART_NUM, |
799 | .mfg_num = MBCS_MFG_NUM, | 799 | .mfg_num = MBCS_MFG_NUM, |
@@ -807,7 +807,7 @@ const struct cx_device_id __devinitdata mbcs_id_table[] = { | |||
807 | 807 | ||
808 | MODULE_DEVICE_TABLE(cx, mbcs_id_table); | 808 | MODULE_DEVICE_TABLE(cx, mbcs_id_table); |
809 | 809 | ||
810 | struct cx_drv mbcs_driver = { | 810 | static struct cx_drv mbcs_driver = { |
811 | .name = DEVICE_NAME, | 811 | .name = DEVICE_NAME, |
812 | .id_table = mbcs_id_table, | 812 | .id_table = mbcs_id_table, |
813 | .probe = mbcs_probe, | 813 | .probe = mbcs_probe, |
@@ -816,12 +816,7 @@ struct cx_drv mbcs_driver = { | |||
816 | 816 | ||
817 | static void __exit mbcs_exit(void) | 817 | static void __exit mbcs_exit(void) |
818 | { | 818 | { |
819 | int rv; | 819 | unregister_chrdev(mbcs_major, DEVICE_NAME); |
820 | |||
821 | rv = unregister_chrdev(mbcs_major, DEVICE_NAME); | ||
822 | if (rv < 0) | ||
823 | DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv); | ||
824 | |||
825 | cx_driver_unregister(&mbcs_driver); | 820 | cx_driver_unregister(&mbcs_driver); |
826 | } | 821 | } |
827 | 822 | ||
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h index e7fd47e43257..c9905a3c3353 100644 --- a/drivers/char/mbcs.h +++ b/drivers/char/mbcs.h | |||
@@ -542,12 +542,12 @@ struct mbcs_soft { | |||
542 | struct semaphore algolock; | 542 | struct semaphore algolock; |
543 | }; | 543 | }; |
544 | 544 | ||
545 | extern int mbcs_open(struct inode *ip, struct file *fp); | 545 | static int mbcs_open(struct inode *ip, struct file *fp); |
546 | extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, | 546 | static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, |
547 | loff_t * off); | 547 | loff_t * off); |
548 | extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, | 548 | static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, |
549 | loff_t * off); | 549 | loff_t * off); |
550 | extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); | 550 | static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); |
551 | extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); | 551 | static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); |
552 | 552 | ||
553 | #endif // __MBCS_H__ | 553 | #endif // __MBCS_H__ |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 13808f6083a0..2b889317461e 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -540,13 +540,12 @@ static int mgslpc_probe(struct pcmcia_device *link) | |||
540 | if (debug_level >= DEBUG_LEVEL_INFO) | 540 | if (debug_level >= DEBUG_LEVEL_INFO) |
541 | printk("mgslpc_attach\n"); | 541 | printk("mgslpc_attach\n"); |
542 | 542 | ||
543 | info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); | 543 | info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); |
544 | if (!info) { | 544 | if (!info) { |
545 | printk("Error can't allocate device instance data\n"); | 545 | printk("Error can't allocate device instance data\n"); |
546 | return -ENOMEM; | 546 | return -ENOMEM; |
547 | } | 547 | } |
548 | 548 | ||
549 | memset(info, 0, sizeof(MGSLPC_INFO)); | ||
550 | info->magic = MGSLPC_MAGIC; | 549 | info->magic = MGSLPC_MAGIC; |
551 | INIT_WORK(&info->task, bh_handler); | 550 | INIT_WORK(&info->task, bh_handler); |
552 | info->max_frame_size = 4096; | 551 | info->max_frame_size = 4096; |
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 294e9cb0c449..0ce96670f979 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c | |||
@@ -803,9 +803,7 @@ static void *ckmalloc(int size) | |||
803 | { | 803 | { |
804 | void *p; | 804 | void *p; |
805 | 805 | ||
806 | p = kmalloc(size, GFP_KERNEL); | 806 | p = kzalloc(size, GFP_KERNEL); |
807 | if (p) | ||
808 | memset(p, 0, size); | ||
809 | return p; | 807 | return p; |
810 | } | 808 | } |
811 | 809 | ||
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 8cc60b693460..7321d002c34f 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c | |||
@@ -556,9 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void) | |||
556 | { | 556 | { |
557 | struct CmdBlk *CmdBlkP; | 557 | struct CmdBlk *CmdBlkP; |
558 | 558 | ||
559 | CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC); | 559 | CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC); |
560 | if (CmdBlkP) | ||
561 | memset(CmdBlkP, 0, sizeof(struct CmdBlk)); | ||
562 | return CmdBlkP; | 560 | return CmdBlkP; |
563 | } | 561 | } |
564 | 562 | ||
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c index 7e988357326e..991119c9f473 100644 --- a/drivers/char/rio/riotable.c +++ b/drivers/char/rio/riotable.c | |||
@@ -863,8 +863,7 @@ int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP) | |||
863 | if (PortP->TxRingBuffer) | 863 | if (PortP->TxRingBuffer) |
864 | memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); | 864 | memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); |
865 | else if (p->RIOBufferSize) { | 865 | else if (p->RIOBufferSize) { |
866 | PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL); | 866 | PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL); |
867 | memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); | ||
868 | } | 867 | } |
869 | PortP->TxBufferOut = 0; | 868 | PortP->TxBufferOut = 0; |
870 | PortP->TxBufferIn = 0; | 869 | PortP->TxBufferIn = 0; |
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0270080ff0c0..56cbba7b6ec0 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c | |||
@@ -635,12 +635,11 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) | |||
635 | ctlp = sCtlNumToCtlPtr(board); | 635 | ctlp = sCtlNumToCtlPtr(board); |
636 | 636 | ||
637 | /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ | 637 | /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ |
638 | info = kmalloc(sizeof (struct r_port), GFP_KERNEL); | 638 | info = kzalloc(sizeof (struct r_port), GFP_KERNEL); |
639 | if (!info) { | 639 | if (!info) { |
640 | printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); | 640 | printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); |
641 | return; | 641 | return; |
642 | } | 642 | } |
643 | memset(info, 0, sizeof (struct r_port)); | ||
644 | 643 | ||
645 | info->magic = RPORT_MAGIC; | 644 | info->magic = RPORT_MAGIC; |
646 | info->line = line; | 645 | info->line = line; |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 93d0bb8b4c0f..4a80b2f864e0 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
@@ -4795,7 +4795,6 @@ static void __exit stallion_module_exit(void) | |||
4795 | { | 4795 | { |
4796 | struct stlbrd *brdp; | 4796 | struct stlbrd *brdp; |
4797 | unsigned int i, j; | 4797 | unsigned int i, j; |
4798 | int retval; | ||
4799 | 4798 | ||
4800 | pr_debug("cleanup_module()\n"); | 4799 | pr_debug("cleanup_module()\n"); |
4801 | 4800 | ||
@@ -4818,9 +4817,7 @@ static void __exit stallion_module_exit(void) | |||
4818 | 4817 | ||
4819 | for (i = 0; i < 4; i++) | 4818 | for (i = 0; i < 4; i++) |
4820 | class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); | 4819 | class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); |
4821 | if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) | 4820 | unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); |
4822 | printk("STALLION: failed to un-register serial memory device, " | ||
4823 | "errno=%d\n", -retval); | ||
4824 | class_destroy(stallion_class); | 4821 | class_destroy(stallion_class); |
4825 | 4822 | ||
4826 | pci_unregister_driver(&stl_pcidriver); | 4823 | pci_unregister_driver(&stl_pcidriver); |
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index f53e51ddb9d7..fdc256b380b8 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c | |||
@@ -4324,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void) | |||
4324 | { | 4324 | { |
4325 | struct mgsl_struct *info; | 4325 | struct mgsl_struct *info; |
4326 | 4326 | ||
4327 | info = kmalloc(sizeof(struct mgsl_struct), | 4327 | info = kzalloc(sizeof(struct mgsl_struct), |
4328 | GFP_KERNEL); | 4328 | GFP_KERNEL); |
4329 | 4329 | ||
4330 | if (!info) { | 4330 | if (!info) { |
4331 | printk("Error can't allocate device instance data\n"); | 4331 | printk("Error can't allocate device instance data\n"); |
4332 | } else { | 4332 | } else { |
4333 | memset(info, 0, sizeof(struct mgsl_struct)); | ||
4334 | info->magic = MGSL_MAGIC; | 4333 | info->magic = MGSL_MAGIC; |
4335 | INIT_WORK(&info->task, mgsl_bh_handler); | 4334 | INIT_WORK(&info->task, mgsl_bh_handler); |
4336 | info->max_frame_size = 4096; | 4335 | info->max_frame_size = 4096; |
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 428b514201f4..372a37e25620 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -3414,13 +3414,12 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev | |||
3414 | { | 3414 | { |
3415 | struct slgt_info *info; | 3415 | struct slgt_info *info; |
3416 | 3416 | ||
3417 | info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL); | 3417 | info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL); |
3418 | 3418 | ||
3419 | if (!info) { | 3419 | if (!info) { |
3420 | DBGERR(("%s device alloc failed adapter=%d port=%d\n", | 3420 | DBGERR(("%s device alloc failed adapter=%d port=%d\n", |
3421 | driver_name, adapter_num, port_num)); | 3421 | driver_name, adapter_num, port_num)); |
3422 | } else { | 3422 | } else { |
3423 | memset(info, 0, sizeof(struct slgt_info)); | ||
3424 | info->magic = MGSL_MAGIC; | 3423 | info->magic = MGSL_MAGIC; |
3425 | INIT_WORK(&info->task, bh_handler); | 3424 | INIT_WORK(&info->task, bh_handler); |
3426 | info->max_frame_size = 4096; | 3425 | info->max_frame_size = 4096; |
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index a65407b32079..c63013b2fc36 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c | |||
@@ -3786,14 +3786,13 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) | |||
3786 | { | 3786 | { |
3787 | SLMP_INFO *info; | 3787 | SLMP_INFO *info; |
3788 | 3788 | ||
3789 | info = kmalloc(sizeof(SLMP_INFO), | 3789 | info = kzalloc(sizeof(SLMP_INFO), |
3790 | GFP_KERNEL); | 3790 | GFP_KERNEL); |
3791 | 3791 | ||
3792 | if (!info) { | 3792 | if (!info) { |
3793 | printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", | 3793 | printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", |
3794 | __FILE__,__LINE__, adapter_num, port_num); | 3794 | __FILE__,__LINE__, adapter_num, port_num); |
3795 | } else { | 3795 | } else { |
3796 | memset(info, 0, sizeof(SLMP_INFO)); | ||
3797 | info->magic = MGSL_MAGIC; | 3796 | info->magic = MGSL_MAGIC; |
3798 | INIT_WORK(&info->task, bh_handler); | 3797 | INIT_WORK(&info->task, bh_handler); |
3799 | info->max_frame_size = 4096; | 3798 | info->max_frame_size = 4096; |
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index db57277117bb..e12275df6ea2 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c | |||
@@ -1098,15 +1098,10 @@ static int chg_state(int index, unsigned char new_state, struct file *file) | |||
1098 | /* Cleanup */ | 1098 | /* Cleanup */ |
1099 | static void __exit viotap_exit(void) | 1099 | static void __exit viotap_exit(void) |
1100 | { | 1100 | { |
1101 | int ret; | ||
1102 | |||
1103 | remove_proc_entry("iSeries/viotape", NULL); | 1101 | remove_proc_entry("iSeries/viotape", NULL); |
1104 | vio_unregister_driver(&viotape_driver); | 1102 | vio_unregister_driver(&viotape_driver); |
1105 | class_destroy(tape_class); | 1103 | class_destroy(tape_class); |
1106 | ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); | 1104 | unregister_chrdev(VIOTAPE_MAJOR, "viotape"); |
1107 | if (ret < 0) | ||
1108 | printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n", | ||
1109 | ret); | ||
1110 | if (viotape_unitinfo) | 1105 | if (viotape_unitinfo) |
1111 | dma_free_coherent(iSeries_vio_dev, | 1106 | dma_free_coherent(iSeries_vio_dev, |
1112 | sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, | 1107 | sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, |
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index e88947f8fe53..0d2b27735419 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c | |||
@@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) | |||
328 | goto err_out; | 328 | goto err_out; |
329 | } | 329 | } |
330 | 330 | ||
331 | wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL); | 331 | wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL); |
332 | if (!wdt) { | 332 | if (!wdt) { |
333 | ret = -ENOMEM; | 333 | ret = -ENOMEM; |
334 | goto err_out; | 334 | goto err_out; |
335 | } | 335 | } |
336 | memset(wdt, 0, sizeof(struct mpcore_wdt)); | ||
337 | 336 | ||
338 | wdt->dev = &dev->dev; | 337 | wdt->dev = &dev->dev; |
339 | wdt->irq = platform_get_irq(dev, 0); | 338 | wdt->irq = platform_get_irq(dev, 0); |
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 1e7a6719d5ba..0f3fd6c9c354 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c | |||
@@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
626 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | 626 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); |
627 | 627 | ||
628 | /* allocate memory for our device and initialize it */ | 628 | /* allocate memory for our device and initialize it */ |
629 | usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); | 629 | usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); |
630 | if (usb_pcwd == NULL) { | 630 | if (usb_pcwd == NULL) { |
631 | printk(KERN_ERR PFX "Out of memory\n"); | 631 | printk(KERN_ERR PFX "Out of memory\n"); |
632 | goto error; | 632 | goto error; |
633 | } | 633 | } |
634 | memset (usb_pcwd, 0x00, sizeof (*usb_pcwd)); | ||
635 | 634 | ||
636 | usb_pcwd_device = usb_pcwd; | 635 | usb_pcwd_device = usb_pcwd; |
637 | 636 | ||
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index debf1d8e8b41..1724c41d2414 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -3,18 +3,18 @@ | |||
3 | # Copyright (c) 2003 Linux Networx | 3 | # Copyright (c) 2003 Linux Networx |
4 | # Licensed and distributed under the GPL | 4 | # Licensed and distributed under the GPL |
5 | # | 5 | # |
6 | # $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $ | ||
7 | # | ||
8 | 6 | ||
9 | menuconfig EDAC | 7 | menuconfig EDAC |
10 | tristate "EDAC - error detection and reporting (EXPERIMENTAL)" | 8 | bool "EDAC - error detection and reporting (EXPERIMENTAL)" |
11 | depends on HAS_IOMEM | 9 | depends on HAS_IOMEM |
12 | depends on X86 && EXPERIMENTAL | 10 | depends on EXPERIMENTAL |
11 | depends on X86 || MIPS || PPC | ||
13 | help | 12 | help |
14 | EDAC is designed to report errors in the core system. | 13 | EDAC is designed to report errors in the core system. |
15 | These are low-level errors that are reported in the CPU or | 14 | These are low-level errors that are reported in the CPU or |
16 | supporting chipset: memory errors, cache errors, PCI errors, | 15 | supporting chipset or other subsystems: |
17 | thermal throttling, etc.. If unsure, select 'Y'. | 16 | memory errors, cache errors, PCI errors, thermal throttling, etc.. |
17 | If unsure, select 'Y'. | ||
18 | 18 | ||
19 | If this code is reporting problems on your system, please | 19 | If this code is reporting problems on your system, please |
20 | see the EDAC project web pages for more information at: | 20 | see the EDAC project web pages for more information at: |
@@ -73,6 +73,14 @@ config EDAC_E752X | |||
73 | Support for error detection and correction on the Intel | 73 | Support for error detection and correction on the Intel |
74 | E7520, E7525, E7320 server chipsets. | 74 | E7520, E7525, E7320 server chipsets. |
75 | 75 | ||
76 | config EDAC_I82443BXGX | ||
77 | tristate "Intel 82443BX/GX (440BX/GX)" | ||
78 | depends on EDAC_MM_EDAC && PCI && X86_32 | ||
79 | depends on BROKEN | ||
80 | help | ||
81 | Support for error detection and correction on the Intel | ||
82 | 82443BX/GX memory controllers (440BX/GX chipsets). | ||
83 | |||
76 | config EDAC_I82875P | 84 | config EDAC_I82875P |
77 | tristate "Intel 82875p (D82875P, E7210)" | 85 | tristate "Intel 82875p (D82875P, E7210)" |
78 | depends on EDAC_MM_EDAC && PCI && X86_32 | 86 | depends on EDAC_MM_EDAC && PCI && X86_32 |
@@ -80,6 +88,20 @@ config EDAC_I82875P | |||
80 | Support for error detection and correction on the Intel | 88 | Support for error detection and correction on the Intel |
81 | DP82785P and E7210 server chipsets. | 89 | DP82785P and E7210 server chipsets. |
82 | 90 | ||
91 | config EDAC_I82975X | ||
92 | tristate "Intel 82975x (D82975x)" | ||
93 | depends on EDAC_MM_EDAC && PCI && X86 | ||
94 | help | ||
95 | Support for error detection and correction on the Intel | ||
96 | DP82975x server chipsets. | ||
97 | |||
98 | config EDAC_I3000 | ||
99 | tristate "Intel 3000/3010" | ||
100 | depends on EDAC_MM_EDAC && PCI && X86_32 | ||
101 | help | ||
102 | Support for error detection and correction on the Intel | ||
103 | 3000 and 3010 server chipsets. | ||
104 | |||
83 | config EDAC_I82860 | 105 | config EDAC_I82860 |
84 | tristate "Intel 82860" | 106 | tristate "Intel 82860" |
85 | depends on EDAC_MM_EDAC && PCI && X86_32 | 107 | depends on EDAC_MM_EDAC && PCI && X86_32 |
@@ -94,15 +116,20 @@ config EDAC_R82600 | |||
94 | Support for error detection and correction on the Radisys | 116 | Support for error detection and correction on the Radisys |
95 | 82600 embedded chipset. | 117 | 82600 embedded chipset. |
96 | 118 | ||
97 | choice | 119 | config EDAC_I5000 |
98 | prompt "Error detecting method" | 120 | tristate "Intel Greencreek/Blackford chipset" |
99 | default EDAC_POLL | 121 | depends on EDAC_MM_EDAC && X86 && PCI |
122 | help | ||
123 | Support for error detection and correction the Intel | ||
124 | Greekcreek/Blackford chipsets. | ||
100 | 125 | ||
101 | config EDAC_POLL | 126 | config EDAC_PASEMI |
102 | bool "Poll for errors" | 127 | tristate "PA Semi PWRficient" |
128 | depends on EDAC_MM_EDAC && PCI | ||
129 | depends on PPC | ||
103 | help | 130 | help |
104 | Poll the chipset periodically to detect errors. | 131 | Support for error detection and correction on PA Semi |
132 | PWRficient. | ||
105 | 133 | ||
106 | endchoice | ||
107 | 134 | ||
108 | endif # EDAC | 135 | endif # EDAC |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 93137fdab4b3..02c09f0ff157 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -5,14 +5,27 @@ | |||
5 | # This file may be distributed under the terms of the | 5 | # This file may be distributed under the terms of the |
6 | # GNU General Public License. | 6 | # GNU General Public License. |
7 | # | 7 | # |
8 | # $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $ | ||
9 | 8 | ||
10 | 9 | ||
11 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_mc.o | 10 | obj-$(CONFIG_EDAC) := edac_stub.o |
11 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o | ||
12 | |||
13 | edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o | ||
14 | edac_core-objs += edac_module.o edac_device_sysfs.o | ||
15 | |||
16 | ifdef CONFIG_PCI | ||
17 | edac_core-objs += edac_pci.o edac_pci_sysfs.o | ||
18 | endif | ||
19 | |||
12 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o | 20 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o |
21 | obj-$(CONFIG_EDAC_I5000) += i5000_edac.o | ||
13 | obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o | 22 | obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o |
14 | obj-$(CONFIG_EDAC_E752X) += e752x_edac.o | 23 | obj-$(CONFIG_EDAC_E752X) += e752x_edac.o |
24 | obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o | ||
15 | obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o | 25 | obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o |
26 | obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o | ||
27 | obj-$(CONFIG_EDAC_I3000) += i3000_edac.o | ||
16 | obj-$(CONFIG_EDAC_I82860) += i82860_edac.o | 28 | obj-$(CONFIG_EDAC_I82860) += i82860_edac.o |
17 | obj-$(CONFIG_EDAC_R82600) += r82600_edac.o | 29 | obj-$(CONFIG_EDAC_R82600) += r82600_edac.o |
30 | obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o | ||
18 | 31 | ||
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index f79f6b587bfa..f22075410591 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c | |||
@@ -17,9 +17,9 @@ | |||
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <linux/pci_ids.h> | 18 | #include <linux/pci_ids.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include "edac_mc.h" | 20 | #include "edac_core.h" |
21 | 21 | ||
22 | #define AMD76X_REVISION " Ver: 2.0.1 " __DATE__ | 22 | #define AMD76X_REVISION " Ver: 2.0.2 " __DATE__ |
23 | #define EDAC_MOD_STR "amd76x_edac" | 23 | #define EDAC_MOD_STR "amd76x_edac" |
24 | 24 | ||
25 | #define amd76x_printk(level, fmt, arg...) \ | 25 | #define amd76x_printk(level, fmt, arg...) \ |
@@ -86,13 +86,13 @@ struct amd76x_dev_info { | |||
86 | 86 | ||
87 | static const struct amd76x_dev_info amd76x_devs[] = { | 87 | static const struct amd76x_dev_info amd76x_devs[] = { |
88 | [AMD761] = { | 88 | [AMD761] = { |
89 | .ctl_name = "AMD761" | 89 | .ctl_name = "AMD761"}, |
90 | }, | ||
91 | [AMD762] = { | 90 | [AMD762] = { |
92 | .ctl_name = "AMD762" | 91 | .ctl_name = "AMD762"}, |
93 | }, | ||
94 | }; | 92 | }; |
95 | 93 | ||
94 | static struct edac_pci_ctl_info *amd76x_pci; | ||
95 | |||
96 | /** | 96 | /** |
97 | * amd76x_get_error_info - fetch error information | 97 | * amd76x_get_error_info - fetch error information |
98 | * @mci: Memory controller | 98 | * @mci: Memory controller |
@@ -102,21 +102,21 @@ static const struct amd76x_dev_info amd76x_devs[] = { | |||
102 | * on the chip so that further errors will be reported | 102 | * on the chip so that further errors will be reported |
103 | */ | 103 | */ |
104 | static void amd76x_get_error_info(struct mem_ctl_info *mci, | 104 | static void amd76x_get_error_info(struct mem_ctl_info *mci, |
105 | struct amd76x_error_info *info) | 105 | struct amd76x_error_info *info) |
106 | { | 106 | { |
107 | struct pci_dev *pdev; | 107 | struct pci_dev *pdev; |
108 | 108 | ||
109 | pdev = to_pci_dev(mci->dev); | 109 | pdev = to_pci_dev(mci->dev); |
110 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, | 110 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, |
111 | &info->ecc_mode_status); | 111 | &info->ecc_mode_status); |
112 | 112 | ||
113 | if (info->ecc_mode_status & BIT(8)) | 113 | if (info->ecc_mode_status & BIT(8)) |
114 | pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, | 114 | pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, |
115 | (u32) BIT(8), (u32) BIT(8)); | 115 | (u32) BIT(8), (u32) BIT(8)); |
116 | 116 | ||
117 | if (info->ecc_mode_status & BIT(9)) | 117 | if (info->ecc_mode_status & BIT(9)) |
118 | pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, | 118 | pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, |
119 | (u32) BIT(9), (u32) BIT(9)); | 119 | (u32) BIT(9), (u32) BIT(9)); |
120 | } | 120 | } |
121 | 121 | ||
122 | /** | 122 | /** |
@@ -130,7 +130,8 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci, | |||
130 | * then attempt to handle and clean up after the error | 130 | * then attempt to handle and clean up after the error |
131 | */ | 131 | */ |
132 | static int amd76x_process_error_info(struct mem_ctl_info *mci, | 132 | static int amd76x_process_error_info(struct mem_ctl_info *mci, |
133 | struct amd76x_error_info *info, int handle_errors) | 133 | struct amd76x_error_info *info, |
134 | int handle_errors) | ||
134 | { | 135 | { |
135 | int error_found; | 136 | int error_found; |
136 | u32 row; | 137 | u32 row; |
@@ -138,7 +139,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, | |||
138 | error_found = 0; | 139 | error_found = 0; |
139 | 140 | ||
140 | /* | 141 | /* |
141 | * Check for an uncorrectable error | 142 | * Check for an uncorrectable error |
142 | */ | 143 | */ |
143 | if (info->ecc_mode_status & BIT(8)) { | 144 | if (info->ecc_mode_status & BIT(8)) { |
144 | error_found = 1; | 145 | error_found = 1; |
@@ -146,12 +147,12 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, | |||
146 | if (handle_errors) { | 147 | if (handle_errors) { |
147 | row = (info->ecc_mode_status >> 4) & 0xf; | 148 | row = (info->ecc_mode_status >> 4) & 0xf; |
148 | edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0, | 149 | edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0, |
149 | row, mci->ctl_name); | 150 | row, mci->ctl_name); |
150 | } | 151 | } |
151 | } | 152 | } |
152 | 153 | ||
153 | /* | 154 | /* |
154 | * Check for a correctable error | 155 | * Check for a correctable error |
155 | */ | 156 | */ |
156 | if (info->ecc_mode_status & BIT(9)) { | 157 | if (info->ecc_mode_status & BIT(9)) { |
157 | error_found = 1; | 158 | error_found = 1; |
@@ -159,7 +160,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, | |||
159 | if (handle_errors) { | 160 | if (handle_errors) { |
160 | row = info->ecc_mode_status & 0xf; | 161 | row = info->ecc_mode_status & 0xf; |
161 | edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0, | 162 | edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0, |
162 | 0, row, 0, mci->ctl_name); | 163 | 0, row, 0, mci->ctl_name); |
163 | } | 164 | } |
164 | } | 165 | } |
165 | 166 | ||
@@ -182,7 +183,7 @@ static void amd76x_check(struct mem_ctl_info *mci) | |||
182 | } | 183 | } |
183 | 184 | ||
184 | static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | 185 | static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
185 | enum edac_type edac_mode) | 186 | enum edac_type edac_mode) |
186 | { | 187 | { |
187 | struct csrow_info *csrow; | 188 | struct csrow_info *csrow; |
188 | u32 mba, mba_base, mba_mask, dms; | 189 | u32 mba, mba_base, mba_mask, dms; |
@@ -193,8 +194,7 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
193 | 194 | ||
194 | /* find the DRAM Chip Select Base address and mask */ | 195 | /* find the DRAM Chip Select Base address and mask */ |
195 | pci_read_config_dword(pdev, | 196 | pci_read_config_dword(pdev, |
196 | AMD76X_MEM_BASE_ADDR + (index * 4), | 197 | AMD76X_MEM_BASE_ADDR + (index * 4), &mba); |
197 | &mba); | ||
198 | 198 | ||
199 | if (!(mba & BIT(0))) | 199 | if (!(mba & BIT(0))) |
200 | continue; | 200 | continue; |
@@ -238,7 +238,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
238 | debugf0("%s()\n", __func__); | 238 | debugf0("%s()\n", __func__); |
239 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); | 239 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); |
240 | ems_mode = (ems >> 10) & 0x3; | 240 | ems_mode = (ems >> 10) & 0x3; |
241 | mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS); | 241 | mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0); |
242 | 242 | ||
243 | if (mci == NULL) { | 243 | if (mci == NULL) { |
244 | return -ENOMEM; | 244 | return -ENOMEM; |
@@ -249,24 +249,36 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
249 | mci->mtype_cap = MEM_FLAG_RDDR; | 249 | mci->mtype_cap = MEM_FLAG_RDDR; |
250 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | 250 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
251 | mci->edac_cap = ems_mode ? | 251 | mci->edac_cap = ems_mode ? |
252 | (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; | 252 | (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; |
253 | mci->mod_name = EDAC_MOD_STR; | 253 | mci->mod_name = EDAC_MOD_STR; |
254 | mci->mod_ver = AMD76X_REVISION; | 254 | mci->mod_ver = AMD76X_REVISION; |
255 | mci->ctl_name = amd76x_devs[dev_idx].ctl_name; | 255 | mci->ctl_name = amd76x_devs[dev_idx].ctl_name; |
256 | mci->dev_name = pci_name(pdev); | ||
256 | mci->edac_check = amd76x_check; | 257 | mci->edac_check = amd76x_check; |
257 | mci->ctl_page_to_phys = NULL; | 258 | mci->ctl_page_to_phys = NULL; |
258 | 259 | ||
259 | amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]); | 260 | amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]); |
260 | amd76x_get_error_info(mci, &discard); /* clear counters */ | 261 | amd76x_get_error_info(mci, &discard); /* clear counters */ |
261 | 262 | ||
262 | /* Here we assume that we will never see multiple instances of this | 263 | /* Here we assume that we will never see multiple instances of this |
263 | * type of memory controller. The ID is therefore hardcoded to 0. | 264 | * type of memory controller. The ID is therefore hardcoded to 0. |
264 | */ | 265 | */ |
265 | if (edac_mc_add_mc(mci,0)) { | 266 | if (edac_mc_add_mc(mci)) { |
266 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 267 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
267 | goto fail; | 268 | goto fail; |
268 | } | 269 | } |
269 | 270 | ||
271 | /* allocating generic PCI control info */ | ||
272 | amd76x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
273 | if (!amd76x_pci) { | ||
274 | printk(KERN_WARNING | ||
275 | "%s(): Unable to create PCI control\n", | ||
276 | __func__); | ||
277 | printk(KERN_WARNING | ||
278 | "%s(): PCI error report via EDAC not setup\n", | ||
279 | __func__); | ||
280 | } | ||
281 | |||
270 | /* get this far and it's successful */ | 282 | /* get this far and it's successful */ |
271 | debugf3("%s(): success\n", __func__); | 283 | debugf3("%s(): success\n", __func__); |
272 | return 0; | 284 | return 0; |
@@ -278,7 +290,7 @@ fail: | |||
278 | 290 | ||
279 | /* returns count (>= 0), or negative on error */ | 291 | /* returns count (>= 0), or negative on error */ |
280 | static int __devinit amd76x_init_one(struct pci_dev *pdev, | 292 | static int __devinit amd76x_init_one(struct pci_dev *pdev, |
281 | const struct pci_device_id *ent) | 293 | const struct pci_device_id *ent) |
282 | { | 294 | { |
283 | debugf0("%s()\n", __func__); | 295 | debugf0("%s()\n", __func__); |
284 | 296 | ||
@@ -300,6 +312,9 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev) | |||
300 | 312 | ||
301 | debugf0("%s()\n", __func__); | 313 | debugf0("%s()\n", __func__); |
302 | 314 | ||
315 | if (amd76x_pci) | ||
316 | edac_pci_release_generic_ctl(amd76x_pci); | ||
317 | |||
303 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 318 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
304 | return; | 319 | return; |
305 | 320 | ||
@@ -308,16 +323,14 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev) | |||
308 | 323 | ||
309 | static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { | 324 | static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { |
310 | { | 325 | { |
311 | PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 326 | PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
312 | AMD762 | 327 | AMD762}, |
313 | }, | ||
314 | { | 328 | { |
315 | PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 329 | PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
316 | AMD761 | 330 | AMD761}, |
317 | }, | ||
318 | { | 331 | { |
319 | 0, | 332 | 0, |
320 | } /* 0 terminated list. */ | 333 | } /* 0 terminated list. */ |
321 | }; | 334 | }; |
322 | 335 | ||
323 | MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); | 336 | MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); |
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 8bcc887692ab..3bba224cb55d 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c | |||
@@ -22,13 +22,16 @@ | |||
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/pci_ids.h> | 23 | #include <linux/pci_ids.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include "edac_mc.h" | 25 | #include <linux/edac.h> |
26 | #include "edac_core.h" | ||
26 | 27 | ||
27 | #define E752X_REVISION " Ver: 2.0.1 " __DATE__ | 28 | #define E752X_REVISION " Ver: 2.0.2 " __DATE__ |
28 | #define EDAC_MOD_STR "e752x_edac" | 29 | #define EDAC_MOD_STR "e752x_edac" |
29 | 30 | ||
30 | static int force_function_unhide; | 31 | static int force_function_unhide; |
31 | 32 | ||
33 | static struct edac_pci_ctl_info *e752x_pci; | ||
34 | |||
32 | #define e752x_printk(level, fmt, arg...) \ | 35 | #define e752x_printk(level, fmt, arg...) \ |
33 | edac_printk(level, "e752x", fmt, ##arg) | 36 | edac_printk(level, "e752x", fmt, ##arg) |
34 | 37 | ||
@@ -203,25 +206,22 @@ static const struct e752x_dev_info e752x_devs[] = { | |||
203 | [E7520] = { | 206 | [E7520] = { |
204 | .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, | 207 | .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, |
205 | .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0, | 208 | .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0, |
206 | .ctl_name = "E7520" | 209 | .ctl_name = "E7520"}, |
207 | }, | ||
208 | [E7525] = { | 210 | [E7525] = { |
209 | .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, | 211 | .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, |
210 | .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0, | 212 | .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0, |
211 | .ctl_name = "E7525" | 213 | .ctl_name = "E7525"}, |
212 | }, | ||
213 | [E7320] = { | 214 | [E7320] = { |
214 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, | 215 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, |
215 | .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, | 216 | .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, |
216 | .ctl_name = "E7320" | 217 | .ctl_name = "E7320"}, |
217 | }, | ||
218 | }; | 218 | }; |
219 | 219 | ||
220 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | 220 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, |
221 | unsigned long page) | 221 | unsigned long page) |
222 | { | 222 | { |
223 | u32 remap; | 223 | u32 remap; |
224 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 224 | struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; |
225 | 225 | ||
226 | debugf3("%s()\n", __func__); | 226 | debugf3("%s()\n", __func__); |
227 | 227 | ||
@@ -241,13 +241,13 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | |||
241 | } | 241 | } |
242 | 242 | ||
243 | static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | 243 | static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, |
244 | u32 sec1_add, u16 sec1_syndrome) | 244 | u32 sec1_add, u16 sec1_syndrome) |
245 | { | 245 | { |
246 | u32 page; | 246 | u32 page; |
247 | int row; | 247 | int row; |
248 | int channel; | 248 | int channel; |
249 | int i; | 249 | int i; |
250 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 250 | struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; |
251 | 251 | ||
252 | debugf3("%s()\n", __func__); | 252 | debugf3("%s()\n", __func__); |
253 | 253 | ||
@@ -261,7 +261,8 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
261 | e752x_printk(KERN_WARNING, | 261 | e752x_printk(KERN_WARNING, |
262 | "Test row %d Table %d %d %d %d %d %d %d %d\n", row, | 262 | "Test row %d Table %d %d %d %d %d %d %d %d\n", row, |
263 | pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3], | 263 | pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3], |
264 | pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]); | 264 | pvt->map[4], pvt->map[5], pvt->map[6], |
265 | pvt->map[7]); | ||
265 | 266 | ||
266 | /* test for channel remapping */ | 267 | /* test for channel remapping */ |
267 | for (i = 0; i < 8; i++) { | 268 | for (i = 0; i < 8; i++) { |
@@ -275,24 +276,22 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
275 | row = i; | 276 | row = i; |
276 | else | 277 | else |
277 | e752x_mc_printk(mci, KERN_WARNING, | 278 | e752x_mc_printk(mci, KERN_WARNING, |
278 | "row %d not found in remap table\n", row); | 279 | "row %d not found in remap table\n", |
280 | row); | ||
279 | } else | 281 | } else |
280 | row = edac_mc_find_csrow_by_page(mci, page); | 282 | row = edac_mc_find_csrow_by_page(mci, page); |
281 | 283 | ||
282 | /* 0 = channel A, 1 = channel B */ | 284 | /* 0 = channel A, 1 = channel B */ |
283 | channel = !(error_one & 1); | 285 | channel = !(error_one & 1); |
284 | 286 | ||
285 | if (!pvt->map_type) | ||
286 | row = 7 - row; | ||
287 | |||
288 | /* e752x mc reads 34:6 of the DRAM linear address */ | 287 | /* e752x mc reads 34:6 of the DRAM linear address */ |
289 | edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4), | 288 | edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4), |
290 | sec1_syndrome, row, channel, "e752x CE"); | 289 | sec1_syndrome, row, channel, "e752x CE"); |
291 | } | 290 | } |
292 | 291 | ||
293 | static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, | 292 | static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, |
294 | u32 sec1_add, u16 sec1_syndrome, int *error_found, | 293 | u32 sec1_add, u16 sec1_syndrome, int *error_found, |
295 | int handle_error) | 294 | int handle_error) |
296 | { | 295 | { |
297 | *error_found = 1; | 296 | *error_found = 1; |
298 | 297 | ||
@@ -301,11 +300,11 @@ static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
301 | } | 300 | } |
302 | 301 | ||
303 | static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, | 302 | static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, |
304 | u32 ded_add, u32 scrb_add) | 303 | u32 ded_add, u32 scrb_add) |
305 | { | 304 | { |
306 | u32 error_2b, block_page; | 305 | u32 error_2b, block_page; |
307 | int row; | 306 | int row; |
308 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 307 | struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; |
309 | 308 | ||
310 | debugf3("%s()\n", __func__); | 309 | debugf3("%s()\n", __func__); |
311 | 310 | ||
@@ -316,14 +315,14 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, | |||
316 | block_page = error_2b >> (PAGE_SHIFT - 4); | 315 | block_page = error_2b >> (PAGE_SHIFT - 4); |
317 | 316 | ||
318 | row = pvt->mc_symmetric ? | 317 | row = pvt->mc_symmetric ? |
319 | /* chip select are bits 14 & 13 */ | 318 | /* chip select are bits 14 & 13 */ |
320 | ((block_page >> 1) & 3) : | 319 | ((block_page >> 1) & 3) : |
321 | edac_mc_find_csrow_by_page(mci, block_page); | 320 | edac_mc_find_csrow_by_page(mci, block_page); |
322 | 321 | ||
323 | /* e752x mc reads 34:6 of the DRAM linear address */ | 322 | /* e752x mc reads 34:6 of the DRAM linear address */ |
324 | edac_mc_handle_ue(mci, block_page, | 323 | edac_mc_handle_ue(mci, block_page, |
325 | offset_in_page(error_2b << 4), | 324 | offset_in_page(error_2b << 4), |
326 | row, "e752x UE from Read"); | 325 | row, "e752x UE from Read"); |
327 | } | 326 | } |
328 | if (error_one & 0x0404) { | 327 | if (error_one & 0x0404) { |
329 | error_2b = scrb_add; | 328 | error_2b = scrb_add; |
@@ -332,19 +331,20 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, | |||
332 | block_page = error_2b >> (PAGE_SHIFT - 4); | 331 | block_page = error_2b >> (PAGE_SHIFT - 4); |
333 | 332 | ||
334 | row = pvt->mc_symmetric ? | 333 | row = pvt->mc_symmetric ? |
335 | /* chip select are bits 14 & 13 */ | 334 | /* chip select are bits 14 & 13 */ |
336 | ((block_page >> 1) & 3) : | 335 | ((block_page >> 1) & 3) : |
337 | edac_mc_find_csrow_by_page(mci, block_page); | 336 | edac_mc_find_csrow_by_page(mci, block_page); |
338 | 337 | ||
339 | /* e752x mc reads 34:6 of the DRAM linear address */ | 338 | /* e752x mc reads 34:6 of the DRAM linear address */ |
340 | edac_mc_handle_ue(mci, block_page, | 339 | edac_mc_handle_ue(mci, block_page, |
341 | offset_in_page(error_2b << 4), | 340 | offset_in_page(error_2b << 4), |
342 | row, "e752x UE from Scruber"); | 341 | row, "e752x UE from Scruber"); |
343 | } | 342 | } |
344 | } | 343 | } |
345 | 344 | ||
346 | static inline void process_ue(struct mem_ctl_info *mci, u16 error_one, | 345 | static inline void process_ue(struct mem_ctl_info *mci, u16 error_one, |
347 | u32 ded_add, u32 scrb_add, int *error_found, int handle_error) | 346 | u32 ded_add, u32 scrb_add, int *error_found, |
347 | int handle_error) | ||
348 | { | 348 | { |
349 | *error_found = 1; | 349 | *error_found = 1; |
350 | 350 | ||
@@ -353,7 +353,7 @@ static inline void process_ue(struct mem_ctl_info *mci, u16 error_one, | |||
353 | } | 353 | } |
354 | 354 | ||
355 | static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, | 355 | static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, |
356 | int *error_found, int handle_error) | 356 | int *error_found, int handle_error) |
357 | { | 357 | { |
358 | *error_found = 1; | 358 | *error_found = 1; |
359 | 359 | ||
@@ -365,24 +365,24 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, | |||
365 | } | 365 | } |
366 | 366 | ||
367 | static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, | 367 | static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, |
368 | u32 retry_add) | 368 | u32 retry_add) |
369 | { | 369 | { |
370 | u32 error_1b, page; | 370 | u32 error_1b, page; |
371 | int row; | 371 | int row; |
372 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 372 | struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; |
373 | 373 | ||
374 | error_1b = retry_add; | 374 | error_1b = retry_add; |
375 | page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ | 375 | page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ |
376 | row = pvt->mc_symmetric ? | 376 | row = pvt->mc_symmetric ? ((page >> 1) & 3) : /* chip select are bits 14 & 13 */ |
377 | ((page >> 1) & 3) : /* chip select are bits 14 & 13 */ | ||
378 | edac_mc_find_csrow_by_page(mci, page); | 377 | edac_mc_find_csrow_by_page(mci, page); |
379 | e752x_mc_printk(mci, KERN_WARNING, | 378 | e752x_mc_printk(mci, KERN_WARNING, |
380 | "CE page 0x%lx, row %d : Memory read retry\n", | 379 | "CE page 0x%lx, row %d : Memory read retry\n", |
381 | (long unsigned int) page, row); | 380 | (long unsigned int)page, row); |
382 | } | 381 | } |
383 | 382 | ||
384 | static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, | 383 | static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, |
385 | u32 retry_add, int *error_found, int handle_error) | 384 | u32 retry_add, int *error_found, |
385 | int handle_error) | ||
386 | { | 386 | { |
387 | *error_found = 1; | 387 | *error_found = 1; |
388 | 388 | ||
@@ -391,7 +391,7 @@ static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, | |||
391 | } | 391 | } |
392 | 392 | ||
393 | static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, | 393 | static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, |
394 | int *error_found, int handle_error) | 394 | int *error_found, int handle_error) |
395 | { | 395 | { |
396 | *error_found = 1; | 396 | *error_found = 1; |
397 | 397 | ||
@@ -420,7 +420,7 @@ static void do_global_error(int fatal, u32 errors) | |||
420 | } | 420 | } |
421 | 421 | ||
422 | static inline void global_error(int fatal, u32 errors, int *error_found, | 422 | static inline void global_error(int fatal, u32 errors, int *error_found, |
423 | int handle_error) | 423 | int handle_error) |
424 | { | 424 | { |
425 | *error_found = 1; | 425 | *error_found = 1; |
426 | 426 | ||
@@ -447,7 +447,7 @@ static void do_hub_error(int fatal, u8 errors) | |||
447 | } | 447 | } |
448 | 448 | ||
449 | static inline void hub_error(int fatal, u8 errors, int *error_found, | 449 | static inline void hub_error(int fatal, u8 errors, int *error_found, |
450 | int handle_error) | 450 | int handle_error) |
451 | { | 451 | { |
452 | *error_found = 1; | 452 | *error_found = 1; |
453 | 453 | ||
@@ -505,7 +505,7 @@ static void do_sysbus_error(int fatal, u32 errors) | |||
505 | } | 505 | } |
506 | 506 | ||
507 | static inline void sysbus_error(int fatal, u32 errors, int *error_found, | 507 | static inline void sysbus_error(int fatal, u32 errors, int *error_found, |
508 | int handle_error) | 508 | int handle_error) |
509 | { | 509 | { |
510 | *error_found = 1; | 510 | *error_found = 1; |
511 | 511 | ||
@@ -514,7 +514,7 @@ static inline void sysbus_error(int fatal, u32 errors, int *error_found, | |||
514 | } | 514 | } |
515 | 515 | ||
516 | static void e752x_check_hub_interface(struct e752x_error_info *info, | 516 | static void e752x_check_hub_interface(struct e752x_error_info *info, |
517 | int *error_found, int handle_error) | 517 | int *error_found, int handle_error) |
518 | { | 518 | { |
519 | u8 stat8; | 519 | u8 stat8; |
520 | 520 | ||
@@ -522,33 +522,32 @@ static void e752x_check_hub_interface(struct e752x_error_info *info, | |||
522 | 522 | ||
523 | stat8 = info->hi_ferr; | 523 | stat8 = info->hi_ferr; |
524 | 524 | ||
525 | if(stat8 & 0x7f) { /* Error, so process */ | 525 | if (stat8 & 0x7f) { /* Error, so process */ |
526 | stat8 &= 0x7f; | 526 | stat8 &= 0x7f; |
527 | 527 | ||
528 | if(stat8 & 0x2b) | 528 | if (stat8 & 0x2b) |
529 | hub_error(1, stat8 & 0x2b, error_found, handle_error); | 529 | hub_error(1, stat8 & 0x2b, error_found, handle_error); |
530 | 530 | ||
531 | if(stat8 & 0x54) | 531 | if (stat8 & 0x54) |
532 | hub_error(0, stat8 & 0x54, error_found, handle_error); | 532 | hub_error(0, stat8 & 0x54, error_found, handle_error); |
533 | } | 533 | } |
534 | |||
535 | //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); | 534 | //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); |
536 | 535 | ||
537 | stat8 = info->hi_nerr; | 536 | stat8 = info->hi_nerr; |
538 | 537 | ||
539 | if(stat8 & 0x7f) { /* Error, so process */ | 538 | if (stat8 & 0x7f) { /* Error, so process */ |
540 | stat8 &= 0x7f; | 539 | stat8 &= 0x7f; |
541 | 540 | ||
542 | if (stat8 & 0x2b) | 541 | if (stat8 & 0x2b) |
543 | hub_error(1, stat8 & 0x2b, error_found, handle_error); | 542 | hub_error(1, stat8 & 0x2b, error_found, handle_error); |
544 | 543 | ||
545 | if(stat8 & 0x54) | 544 | if (stat8 & 0x54) |
546 | hub_error(0, stat8 & 0x54, error_found, handle_error); | 545 | hub_error(0, stat8 & 0x54, error_found, handle_error); |
547 | } | 546 | } |
548 | } | 547 | } |
549 | 548 | ||
550 | static void e752x_check_sysbus(struct e752x_error_info *info, | 549 | static void e752x_check_sysbus(struct e752x_error_info *info, |
551 | int *error_found, int handle_error) | 550 | int *error_found, int handle_error) |
552 | { | 551 | { |
553 | u32 stat32, error32; | 552 | u32 stat32, error32; |
554 | 553 | ||
@@ -556,47 +555,47 @@ static void e752x_check_sysbus(struct e752x_error_info *info, | |||
556 | stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16); | 555 | stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16); |
557 | 556 | ||
558 | if (stat32 == 0) | 557 | if (stat32 == 0) |
559 | return; /* no errors */ | 558 | return; /* no errors */ |
560 | 559 | ||
561 | error32 = (stat32 >> 16) & 0x3ff; | 560 | error32 = (stat32 >> 16) & 0x3ff; |
562 | stat32 = stat32 & 0x3ff; | 561 | stat32 = stat32 & 0x3ff; |
563 | 562 | ||
564 | if(stat32 & 0x087) | 563 | if (stat32 & 0x087) |
565 | sysbus_error(1, stat32 & 0x087, error_found, handle_error); | 564 | sysbus_error(1, stat32 & 0x087, error_found, handle_error); |
566 | 565 | ||
567 | if(stat32 & 0x378) | 566 | if (stat32 & 0x378) |
568 | sysbus_error(0, stat32 & 0x378, error_found, handle_error); | 567 | sysbus_error(0, stat32 & 0x378, error_found, handle_error); |
569 | 568 | ||
570 | if(error32 & 0x087) | 569 | if (error32 & 0x087) |
571 | sysbus_error(1, error32 & 0x087, error_found, handle_error); | 570 | sysbus_error(1, error32 & 0x087, error_found, handle_error); |
572 | 571 | ||
573 | if(error32 & 0x378) | 572 | if (error32 & 0x378) |
574 | sysbus_error(0, error32 & 0x378, error_found, handle_error); | 573 | sysbus_error(0, error32 & 0x378, error_found, handle_error); |
575 | } | 574 | } |
576 | 575 | ||
577 | static void e752x_check_membuf (struct e752x_error_info *info, | 576 | static void e752x_check_membuf(struct e752x_error_info *info, |
578 | int *error_found, int handle_error) | 577 | int *error_found, int handle_error) |
579 | { | 578 | { |
580 | u8 stat8; | 579 | u8 stat8; |
581 | 580 | ||
582 | stat8 = info->buf_ferr; | 581 | stat8 = info->buf_ferr; |
583 | 582 | ||
584 | if (stat8 & 0x0f) { /* Error, so process */ | 583 | if (stat8 & 0x0f) { /* Error, so process */ |
585 | stat8 &= 0x0f; | 584 | stat8 &= 0x0f; |
586 | membuf_error(stat8, error_found, handle_error); | 585 | membuf_error(stat8, error_found, handle_error); |
587 | } | 586 | } |
588 | 587 | ||
589 | stat8 = info->buf_nerr; | 588 | stat8 = info->buf_nerr; |
590 | 589 | ||
591 | if (stat8 & 0x0f) { /* Error, so process */ | 590 | if (stat8 & 0x0f) { /* Error, so process */ |
592 | stat8 &= 0x0f; | 591 | stat8 &= 0x0f; |
593 | membuf_error(stat8, error_found, handle_error); | 592 | membuf_error(stat8, error_found, handle_error); |
594 | } | 593 | } |
595 | } | 594 | } |
596 | 595 | ||
597 | static void e752x_check_dram (struct mem_ctl_info *mci, | 596 | static void e752x_check_dram(struct mem_ctl_info *mci, |
598 | struct e752x_error_info *info, int *error_found, | 597 | struct e752x_error_info *info, int *error_found, |
599 | int handle_error) | 598 | int handle_error) |
600 | { | 599 | { |
601 | u16 error_one, error_next; | 600 | u16 error_one, error_next; |
602 | 601 | ||
@@ -604,55 +603,52 @@ static void e752x_check_dram (struct mem_ctl_info *mci, | |||
604 | error_next = info->dram_nerr; | 603 | error_next = info->dram_nerr; |
605 | 604 | ||
606 | /* decode and report errors */ | 605 | /* decode and report errors */ |
607 | if(error_one & 0x0101) /* check first error correctable */ | 606 | if (error_one & 0x0101) /* check first error correctable */ |
608 | process_ce(mci, error_one, info->dram_sec1_add, | 607 | process_ce(mci, error_one, info->dram_sec1_add, |
609 | info->dram_sec1_syndrome, error_found, | 608 | info->dram_sec1_syndrome, error_found, handle_error); |
610 | handle_error); | ||
611 | 609 | ||
612 | if(error_next & 0x0101) /* check next error correctable */ | 610 | if (error_next & 0x0101) /* check next error correctable */ |
613 | process_ce(mci, error_next, info->dram_sec2_add, | 611 | process_ce(mci, error_next, info->dram_sec2_add, |
614 | info->dram_sec2_syndrome, error_found, | 612 | info->dram_sec2_syndrome, error_found, handle_error); |
615 | handle_error); | ||
616 | 613 | ||
617 | if(error_one & 0x4040) | 614 | if (error_one & 0x4040) |
618 | process_ue_no_info_wr(mci, error_found, handle_error); | 615 | process_ue_no_info_wr(mci, error_found, handle_error); |
619 | 616 | ||
620 | if(error_next & 0x4040) | 617 | if (error_next & 0x4040) |
621 | process_ue_no_info_wr(mci, error_found, handle_error); | 618 | process_ue_no_info_wr(mci, error_found, handle_error); |
622 | 619 | ||
623 | if(error_one & 0x2020) | 620 | if (error_one & 0x2020) |
624 | process_ded_retry(mci, error_one, info->dram_retr_add, | 621 | process_ded_retry(mci, error_one, info->dram_retr_add, |
625 | error_found, handle_error); | 622 | error_found, handle_error); |
626 | 623 | ||
627 | if(error_next & 0x2020) | 624 | if (error_next & 0x2020) |
628 | process_ded_retry(mci, error_next, info->dram_retr_add, | 625 | process_ded_retry(mci, error_next, info->dram_retr_add, |
629 | error_found, handle_error); | 626 | error_found, handle_error); |
630 | 627 | ||
631 | if(error_one & 0x0808) | 628 | if (error_one & 0x0808) |
632 | process_threshold_ce(mci, error_one, error_found, | 629 | process_threshold_ce(mci, error_one, error_found, handle_error); |
633 | handle_error); | ||
634 | 630 | ||
635 | if(error_next & 0x0808) | 631 | if (error_next & 0x0808) |
636 | process_threshold_ce(mci, error_next, error_found, | 632 | process_threshold_ce(mci, error_next, error_found, |
637 | handle_error); | 633 | handle_error); |
638 | 634 | ||
639 | if(error_one & 0x0606) | 635 | if (error_one & 0x0606) |
640 | process_ue(mci, error_one, info->dram_ded_add, | 636 | process_ue(mci, error_one, info->dram_ded_add, |
641 | info->dram_scrb_add, error_found, handle_error); | 637 | info->dram_scrb_add, error_found, handle_error); |
642 | 638 | ||
643 | if(error_next & 0x0606) | 639 | if (error_next & 0x0606) |
644 | process_ue(mci, error_next, info->dram_ded_add, | 640 | process_ue(mci, error_next, info->dram_ded_add, |
645 | info->dram_scrb_add, error_found, handle_error); | 641 | info->dram_scrb_add, error_found, handle_error); |
646 | } | 642 | } |
647 | 643 | ||
648 | static void e752x_get_error_info (struct mem_ctl_info *mci, | 644 | static void e752x_get_error_info(struct mem_ctl_info *mci, |
649 | struct e752x_error_info *info) | 645 | struct e752x_error_info *info) |
650 | { | 646 | { |
651 | struct pci_dev *dev; | 647 | struct pci_dev *dev; |
652 | struct e752x_pvt *pvt; | 648 | struct e752x_pvt *pvt; |
653 | 649 | ||
654 | memset(info, 0, sizeof(*info)); | 650 | memset(info, 0, sizeof(*info)); |
655 | pvt = (struct e752x_pvt *) mci->pvt_info; | 651 | pvt = (struct e752x_pvt *)mci->pvt_info; |
656 | dev = pvt->dev_d0f1; | 652 | dev = pvt->dev_d0f1; |
657 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); | 653 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); |
658 | 654 | ||
@@ -661,8 +657,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci, | |||
661 | pci_read_config_word(dev, E752X_SYSBUS_FERR, | 657 | pci_read_config_word(dev, E752X_SYSBUS_FERR, |
662 | &info->sysbus_ferr); | 658 | &info->sysbus_ferr); |
663 | pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); | 659 | pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); |
664 | pci_read_config_word(dev, E752X_DRAM_FERR, | 660 | pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr); |
665 | &info->dram_ferr); | ||
666 | pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD, | 661 | pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD, |
667 | &info->dram_sec1_add); | 662 | &info->dram_sec1_add); |
668 | pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME, | 663 | pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME, |
@@ -688,7 +683,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci, | |||
688 | 683 | ||
689 | if (info->dram_ferr) | 684 | if (info->dram_ferr) |
690 | pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, | 685 | pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, |
691 | info->dram_ferr, info->dram_ferr); | 686 | info->dram_ferr, info->dram_ferr); |
692 | 687 | ||
693 | pci_write_config_dword(dev, E752X_FERR_GLOBAL, | 688 | pci_write_config_dword(dev, E752X_FERR_GLOBAL, |
694 | info->ferr_global); | 689 | info->ferr_global); |
@@ -701,8 +696,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci, | |||
701 | pci_read_config_word(dev, E752X_SYSBUS_NERR, | 696 | pci_read_config_word(dev, E752X_SYSBUS_NERR, |
702 | &info->sysbus_nerr); | 697 | &info->sysbus_nerr); |
703 | pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); | 698 | pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); |
704 | pci_read_config_word(dev, E752X_DRAM_NERR, | 699 | pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr); |
705 | &info->dram_nerr); | ||
706 | pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD, | 700 | pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD, |
707 | &info->dram_sec2_add); | 701 | &info->dram_sec2_add); |
708 | pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME, | 702 | pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME, |
@@ -722,15 +716,16 @@ static void e752x_get_error_info (struct mem_ctl_info *mci, | |||
722 | 716 | ||
723 | if (info->dram_nerr) | 717 | if (info->dram_nerr) |
724 | pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, | 718 | pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, |
725 | info->dram_nerr, info->dram_nerr); | 719 | info->dram_nerr, info->dram_nerr); |
726 | 720 | ||
727 | pci_write_config_dword(dev, E752X_NERR_GLOBAL, | 721 | pci_write_config_dword(dev, E752X_NERR_GLOBAL, |
728 | info->nerr_global); | 722 | info->nerr_global); |
729 | } | 723 | } |
730 | } | 724 | } |
731 | 725 | ||
732 | static int e752x_process_error_info (struct mem_ctl_info *mci, | 726 | static int e752x_process_error_info(struct mem_ctl_info *mci, |
733 | struct e752x_error_info *info, int handle_errors) | 727 | struct e752x_error_info *info, |
728 | int handle_errors) | ||
734 | { | 729 | { |
735 | u32 error32, stat32; | 730 | u32 error32, stat32; |
736 | int error_found; | 731 | int error_found; |
@@ -776,26 +771,38 @@ static inline int dual_channel_active(u16 ddrcsr) | |||
776 | return (((ddrcsr >> 12) & 3) == 3); | 771 | return (((ddrcsr >> 12) & 3) == 3); |
777 | } | 772 | } |
778 | 773 | ||
774 | /* Remap csrow index numbers if map_type is "reverse" | ||
775 | */ | ||
776 | static inline int remap_csrow_index(struct mem_ctl_info *mci, int index) | ||
777 | { | ||
778 | struct e752x_pvt *pvt = mci->pvt_info; | ||
779 | |||
780 | if (!pvt->map_type) | ||
781 | return (7 - index); | ||
782 | |||
783 | return (index); | ||
784 | } | ||
785 | |||
779 | static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | 786 | static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
780 | u16 ddrcsr) | 787 | u16 ddrcsr) |
781 | { | 788 | { |
782 | struct csrow_info *csrow; | 789 | struct csrow_info *csrow; |
783 | unsigned long last_cumul_size; | 790 | unsigned long last_cumul_size; |
784 | int index, mem_dev, drc_chan; | 791 | int index, mem_dev, drc_chan; |
785 | int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ | 792 | int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ |
786 | int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ | 793 | int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ |
787 | u8 value; | 794 | u8 value; |
788 | u32 dra, drc, cumul_size; | 795 | u32 dra, drc, cumul_size; |
789 | 796 | ||
790 | dra = 0; | 797 | dra = 0; |
791 | for (index=0; index < 4; index++) { | 798 | for (index = 0; index < 4; index++) { |
792 | u8 dra_reg; | 799 | u8 dra_reg; |
793 | pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg); | 800 | pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg); |
794 | dra |= dra_reg << (index * 8); | 801 | dra |= dra_reg << (index * 8); |
795 | } | 802 | } |
796 | pci_read_config_dword(pdev, E752X_DRC, &drc); | 803 | pci_read_config_dword(pdev, E752X_DRC, &drc); |
797 | drc_chan = dual_channel_active(ddrcsr); | 804 | drc_chan = dual_channel_active(ddrcsr); |
798 | drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ | 805 | drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ |
799 | drc_ddim = (drc >> 20) & 0x3; | 806 | drc_ddim = (drc >> 20) & 0x3; |
800 | 807 | ||
801 | /* The dram row boundary (DRB) reg values are boundary address for | 808 | /* The dram row boundary (DRB) reg values are boundary address for |
@@ -806,7 +813,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
806 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | 813 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { |
807 | /* mem_dev 0=x8, 1=x4 */ | 814 | /* mem_dev 0=x8, 1=x4 */ |
808 | mem_dev = (dra >> (index * 4 + 2)) & 0x3; | 815 | mem_dev = (dra >> (index * 4 + 2)) & 0x3; |
809 | csrow = &mci->csrows[index]; | 816 | csrow = &mci->csrows[remap_csrow_index(mci, index)]; |
810 | 817 | ||
811 | mem_dev = (mem_dev == 2); | 818 | mem_dev = (mem_dev == 2); |
812 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | 819 | pci_read_config_byte(pdev, E752X_DRB + index, &value); |
@@ -843,10 +850,10 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
843 | } | 850 | } |
844 | 851 | ||
845 | static void e752x_init_mem_map_table(struct pci_dev *pdev, | 852 | static void e752x_init_mem_map_table(struct pci_dev *pdev, |
846 | struct e752x_pvt *pvt) | 853 | struct e752x_pvt *pvt) |
847 | { | 854 | { |
848 | int index; | 855 | int index; |
849 | u8 value, last, row, stat8; | 856 | u8 value, last, row; |
850 | 857 | ||
851 | last = 0; | 858 | last = 0; |
852 | row = 0; | 859 | row = 0; |
@@ -858,7 +865,7 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev, | |||
858 | /* no dimm in the slot, so flag it as empty */ | 865 | /* no dimm in the slot, so flag it as empty */ |
859 | pvt->map[index] = 0xff; | 866 | pvt->map[index] = 0xff; |
860 | pvt->map[index + 1] = 0xff; | 867 | pvt->map[index + 1] = 0xff; |
861 | } else { /* there is a dimm in the slot */ | 868 | } else { /* there is a dimm in the slot */ |
862 | pvt->map[index] = row; | 869 | pvt->map[index] = row; |
863 | row++; | 870 | row++; |
864 | last = value; | 871 | last = value; |
@@ -866,31 +873,25 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev, | |||
866 | * sided | 873 | * sided |
867 | */ | 874 | */ |
868 | pci_read_config_byte(pdev, E752X_DRB + index + 1, | 875 | pci_read_config_byte(pdev, E752X_DRB + index + 1, |
869 | &value); | 876 | &value); |
870 | pvt->map[index + 1] = (value == last) ? | 877 | |
871 | 0xff : /* the dimm is single sided, | 878 | /* the dimm is single sided, so flag as empty */ |
872 | so flag as empty */ | 879 | /* this is a double sided dimm to save the next row #*/ |
873 | row; /* this is a double sided dimm | 880 | pvt->map[index + 1] = (value == last) ? 0xff : row; |
874 | to save the next row # */ | ||
875 | row++; | 881 | row++; |
876 | last = value; | 882 | last = value; |
877 | } | 883 | } |
878 | } | 884 | } |
879 | |||
880 | /* set the map type. 1 = normal, 0 = reversed */ | ||
881 | pci_read_config_byte(pdev, E752X_DRM, &stat8); | ||
882 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); | ||
883 | } | 885 | } |
884 | 886 | ||
885 | /* Return 0 on success or 1 on failure. */ | 887 | /* Return 0 on success or 1 on failure. */ |
886 | static int e752x_get_devs(struct pci_dev *pdev, int dev_idx, | 888 | static int e752x_get_devs(struct pci_dev *pdev, int dev_idx, |
887 | struct e752x_pvt *pvt) | 889 | struct e752x_pvt *pvt) |
888 | { | 890 | { |
889 | struct pci_dev *dev; | 891 | struct pci_dev *dev; |
890 | 892 | ||
891 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | 893 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, |
892 | pvt->dev_info->err_dev, | 894 | pvt->dev_info->err_dev, pvt->bridge_ck); |
893 | pvt->bridge_ck); | ||
894 | 895 | ||
895 | if (pvt->bridge_ck == NULL) | 896 | if (pvt->bridge_ck == NULL) |
896 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, | 897 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, |
@@ -898,13 +899,13 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx, | |||
898 | 899 | ||
899 | if (pvt->bridge_ck == NULL) { | 900 | if (pvt->bridge_ck == NULL) { |
900 | e752x_printk(KERN_ERR, "error reporting device not found:" | 901 | e752x_printk(KERN_ERR, "error reporting device not found:" |
901 | "vendor %x device 0x%x (broken BIOS?)\n", | 902 | "vendor %x device 0x%x (broken BIOS?)\n", |
902 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); | 903 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); |
903 | return 1; | 904 | return 1; |
904 | } | 905 | } |
905 | 906 | ||
906 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, | 907 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, |
907 | NULL); | 908 | NULL); |
908 | 909 | ||
909 | if (dev == NULL) | 910 | if (dev == NULL) |
910 | goto fail; | 911 | goto fail; |
@@ -942,12 +943,22 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
942 | struct mem_ctl_info *mci; | 943 | struct mem_ctl_info *mci; |
943 | struct e752x_pvt *pvt; | 944 | struct e752x_pvt *pvt; |
944 | u16 ddrcsr; | 945 | u16 ddrcsr; |
945 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ | 946 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ |
946 | struct e752x_error_info discard; | 947 | struct e752x_error_info discard; |
947 | 948 | ||
948 | debugf0("%s(): mci\n", __func__); | 949 | debugf0("%s(): mci\n", __func__); |
949 | debugf0("Starting Probe1\n"); | 950 | debugf0("Starting Probe1\n"); |
950 | 951 | ||
952 | /* make sure error reporting method is sane */ | ||
953 | switch (edac_op_state) { | ||
954 | case EDAC_OPSTATE_POLL: | ||
955 | case EDAC_OPSTATE_NMI: | ||
956 | break; | ||
957 | default: | ||
958 | edac_op_state = EDAC_OPSTATE_POLL; | ||
959 | break; | ||
960 | } | ||
961 | |||
951 | /* check to see if device 0 function 1 is enabled; if it isn't, we | 962 | /* check to see if device 0 function 1 is enabled; if it isn't, we |
952 | * assume the BIOS has reserved it for a reason and is expecting | 963 | * assume the BIOS has reserved it for a reason and is expecting |
953 | * exclusive access, we take care not to violate that assumption and | 964 | * exclusive access, we take care not to violate that assumption and |
@@ -966,7 +977,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
966 | /* Dual channel = 1, Single channel = 0 */ | 977 | /* Dual channel = 1, Single channel = 0 */ |
967 | drc_chan = dual_channel_active(ddrcsr); | 978 | drc_chan = dual_channel_active(ddrcsr); |
968 | 979 | ||
969 | mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1); | 980 | mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0); |
970 | 981 | ||
971 | if (mci == NULL) { | 982 | if (mci == NULL) { |
972 | return -ENOMEM; | 983 | return -ENOMEM; |
@@ -975,14 +986,14 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
975 | debugf3("%s(): init mci\n", __func__); | 986 | debugf3("%s(): init mci\n", __func__); |
976 | mci->mtype_cap = MEM_FLAG_RDDR; | 987 | mci->mtype_cap = MEM_FLAG_RDDR; |
977 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | 988 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | |
978 | EDAC_FLAG_S4ECD4ED; | 989 | EDAC_FLAG_S4ECD4ED; |
979 | /* FIXME - what if different memory types are in different csrows? */ | 990 | /* FIXME - what if different memory types are in different csrows? */ |
980 | mci->mod_name = EDAC_MOD_STR; | 991 | mci->mod_name = EDAC_MOD_STR; |
981 | mci->mod_ver = E752X_REVISION; | 992 | mci->mod_ver = E752X_REVISION; |
982 | mci->dev = &pdev->dev; | 993 | mci->dev = &pdev->dev; |
983 | 994 | ||
984 | debugf3("%s(): init pvt\n", __func__); | 995 | debugf3("%s(): init pvt\n", __func__); |
985 | pvt = (struct e752x_pvt *) mci->pvt_info; | 996 | pvt = (struct e752x_pvt *)mci->pvt_info; |
986 | pvt->dev_info = &e752x_devs[dev_idx]; | 997 | pvt->dev_info = &e752x_devs[dev_idx]; |
987 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); | 998 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); |
988 | 999 | ||
@@ -993,16 +1004,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
993 | 1004 | ||
994 | debugf3("%s(): more mci init\n", __func__); | 1005 | debugf3("%s(): more mci init\n", __func__); |
995 | mci->ctl_name = pvt->dev_info->ctl_name; | 1006 | mci->ctl_name = pvt->dev_info->ctl_name; |
1007 | mci->dev_name = pci_name(pdev); | ||
996 | mci->edac_check = e752x_check; | 1008 | mci->edac_check = e752x_check; |
997 | mci->ctl_page_to_phys = ctl_page_to_phys; | 1009 | mci->ctl_page_to_phys = ctl_page_to_phys; |
998 | 1010 | ||
999 | e752x_init_csrows(mci, pdev, ddrcsr); | 1011 | /* set the map type. 1 = normal, 0 = reversed |
1000 | e752x_init_mem_map_table(pdev, pvt); | 1012 | * Must be set before e752x_init_csrows in case csrow mapping |
1001 | 1013 | * is reversed. | |
1002 | /* set the map type. 1 = normal, 0 = reversed */ | 1014 | */ |
1003 | pci_read_config_byte(pdev, E752X_DRM, &stat8); | 1015 | pci_read_config_byte(pdev, E752X_DRM, &stat8); |
1004 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); | 1016 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); |
1005 | 1017 | ||
1018 | e752x_init_csrows(mci, pdev, ddrcsr); | ||
1019 | e752x_init_mem_map_table(pdev, pvt); | ||
1020 | |||
1006 | mci->edac_cap |= EDAC_FLAG_NONE; | 1021 | mci->edac_cap |= EDAC_FLAG_NONE; |
1007 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); | 1022 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); |
1008 | 1023 | ||
@@ -1014,19 +1029,29 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
1014 | pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data); | 1029 | pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data); |
1015 | pvt->remaplimit = ((u32) pci_data) << 14; | 1030 | pvt->remaplimit = ((u32) pci_data) << 14; |
1016 | e752x_printk(KERN_INFO, | 1031 | e752x_printk(KERN_INFO, |
1017 | "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, | 1032 | "tolm = %x, remapbase = %x, remaplimit = %x\n", |
1018 | pvt->remapbase, pvt->remaplimit); | 1033 | pvt->tolm, pvt->remapbase, pvt->remaplimit); |
1019 | 1034 | ||
1020 | /* Here we assume that we will never see multiple instances of this | 1035 | /* Here we assume that we will never see multiple instances of this |
1021 | * type of memory controller. The ID is therefore hardcoded to 0. | 1036 | * type of memory controller. The ID is therefore hardcoded to 0. |
1022 | */ | 1037 | */ |
1023 | if (edac_mc_add_mc(mci,0)) { | 1038 | if (edac_mc_add_mc(mci)) { |
1024 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 1039 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
1025 | goto fail; | 1040 | goto fail; |
1026 | } | 1041 | } |
1027 | 1042 | ||
1028 | e752x_init_error_reporting_regs(pvt); | 1043 | e752x_init_error_reporting_regs(pvt); |
1029 | e752x_get_error_info(mci, &discard); /* clear other MCH errors */ | 1044 | e752x_get_error_info(mci, &discard); /* clear other MCH errors */ |
1045 | |||
1046 | /* allocating generic PCI control info */ | ||
1047 | e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
1048 | if (!e752x_pci) { | ||
1049 | printk(KERN_WARNING | ||
1050 | "%s(): Unable to create PCI control\n", __func__); | ||
1051 | printk(KERN_WARNING | ||
1052 | "%s(): PCI error report via EDAC not setup\n", | ||
1053 | __func__); | ||
1054 | } | ||
1030 | 1055 | ||
1031 | /* get this far and it's successful */ | 1056 | /* get this far and it's successful */ |
1032 | debugf3("%s(): success\n", __func__); | 1057 | debugf3("%s(): success\n", __func__); |
@@ -1043,12 +1068,12 @@ fail: | |||
1043 | 1068 | ||
1044 | /* returns count (>= 0), or negative on error */ | 1069 | /* returns count (>= 0), or negative on error */ |
1045 | static int __devinit e752x_init_one(struct pci_dev *pdev, | 1070 | static int __devinit e752x_init_one(struct pci_dev *pdev, |
1046 | const struct pci_device_id *ent) | 1071 | const struct pci_device_id *ent) |
1047 | { | 1072 | { |
1048 | debugf0("%s()\n", __func__); | 1073 | debugf0("%s()\n", __func__); |
1049 | 1074 | ||
1050 | /* wake up and enable device */ | 1075 | /* wake up and enable device */ |
1051 | if(pci_enable_device(pdev) < 0) | 1076 | if (pci_enable_device(pdev) < 0) |
1052 | return -EIO; | 1077 | return -EIO; |
1053 | 1078 | ||
1054 | return e752x_probe1(pdev, ent->driver_data); | 1079 | return e752x_probe1(pdev, ent->driver_data); |
@@ -1061,10 +1086,13 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev) | |||
1061 | 1086 | ||
1062 | debugf0("%s()\n", __func__); | 1087 | debugf0("%s()\n", __func__); |
1063 | 1088 | ||
1089 | if (e752x_pci) | ||
1090 | edac_pci_release_generic_ctl(e752x_pci); | ||
1091 | |||
1064 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 1092 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
1065 | return; | 1093 | return; |
1066 | 1094 | ||
1067 | pvt = (struct e752x_pvt *) mci->pvt_info; | 1095 | pvt = (struct e752x_pvt *)mci->pvt_info; |
1068 | pci_dev_put(pvt->dev_d0f0); | 1096 | pci_dev_put(pvt->dev_d0f0); |
1069 | pci_dev_put(pvt->dev_d0f1); | 1097 | pci_dev_put(pvt->dev_d0f1); |
1070 | pci_dev_put(pvt->bridge_ck); | 1098 | pci_dev_put(pvt->bridge_ck); |
@@ -1073,20 +1101,17 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev) | |||
1073 | 1101 | ||
1074 | static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { | 1102 | static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { |
1075 | { | 1103 | { |
1076 | PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1104 | PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1077 | E7520 | 1105 | E7520}, |
1078 | }, | ||
1079 | { | 1106 | { |
1080 | PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1107 | PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1081 | E7525 | 1108 | E7525}, |
1082 | }, | ||
1083 | { | 1109 | { |
1084 | PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1110 | PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1085 | E7320 | 1111 | E7320}, |
1086 | }, | ||
1087 | { | 1112 | { |
1088 | 0, | 1113 | 0, |
1089 | } /* 0 terminated list. */ | 1114 | } /* 0 terminated list. */ |
1090 | }; | 1115 | }; |
1091 | 1116 | ||
1092 | MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); | 1117 | MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); |
@@ -1122,5 +1147,6 @@ MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); | |||
1122 | 1147 | ||
1123 | module_param(force_function_unhide, int, 0444); | 1148 | module_param(force_function_unhide, int, 0444); |
1124 | MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" | 1149 | MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" |
1125 | " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); | 1150 | " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); |
1126 | 1151 | module_param(edac_op_state, int, 0444); | |
1152 | MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); | ||
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 310d91b41c96..96ecc4926641 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c | |||
@@ -27,9 +27,10 @@ | |||
27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
28 | #include <linux/pci_ids.h> | 28 | #include <linux/pci_ids.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include "edac_mc.h" | 30 | #include <linux/edac.h> |
31 | #include "edac_core.h" | ||
31 | 32 | ||
32 | #define E7XXX_REVISION " Ver: 2.0.1 " __DATE__ | 33 | #define E7XXX_REVISION " Ver: 2.0.2 " __DATE__ |
33 | #define EDAC_MOD_STR "e7xxx_edac" | 34 | #define EDAC_MOD_STR "e7xxx_edac" |
34 | 35 | ||
35 | #define e7xxx_printk(level, fmt, arg...) \ | 36 | #define e7xxx_printk(level, fmt, arg...) \ |
@@ -143,23 +144,21 @@ struct e7xxx_error_info { | |||
143 | u32 dram_uelog_add; | 144 | u32 dram_uelog_add; |
144 | }; | 145 | }; |
145 | 146 | ||
147 | static struct edac_pci_ctl_info *e7xxx_pci; | ||
148 | |||
146 | static const struct e7xxx_dev_info e7xxx_devs[] = { | 149 | static const struct e7xxx_dev_info e7xxx_devs[] = { |
147 | [E7500] = { | 150 | [E7500] = { |
148 | .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, | 151 | .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, |
149 | .ctl_name = "E7500" | 152 | .ctl_name = "E7500"}, |
150 | }, | ||
151 | [E7501] = { | 153 | [E7501] = { |
152 | .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, | 154 | .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, |
153 | .ctl_name = "E7501" | 155 | .ctl_name = "E7501"}, |
154 | }, | ||
155 | [E7505] = { | 156 | [E7505] = { |
156 | .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, | 157 | .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, |
157 | .ctl_name = "E7505" | 158 | .ctl_name = "E7505"}, |
158 | }, | ||
159 | [E7205] = { | 159 | [E7205] = { |
160 | .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, | 160 | .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, |
161 | .ctl_name = "E7205" | 161 | .ctl_name = "E7205"}, |
162 | }, | ||
163 | }; | 162 | }; |
164 | 163 | ||
165 | /* FIXME - is this valid for both SECDED and S4ECD4ED? */ | 164 | /* FIXME - is this valid for both SECDED and S4ECD4ED? */ |
@@ -180,15 +179,15 @@ static inline int e7xxx_find_channel(u16 syndrome) | |||
180 | } | 179 | } |
181 | 180 | ||
182 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | 181 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, |
183 | unsigned long page) | 182 | unsigned long page) |
184 | { | 183 | { |
185 | u32 remap; | 184 | u32 remap; |
186 | struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info; | 185 | struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info; |
187 | 186 | ||
188 | debugf3("%s()\n", __func__); | 187 | debugf3("%s()\n", __func__); |
189 | 188 | ||
190 | if ((page < pvt->tolm) || | 189 | if ((page < pvt->tolm) || |
191 | ((page >= 0x100000) && (page < pvt->remapbase))) | 190 | ((page >= 0x100000) && (page < pvt->remapbase))) |
192 | return page; | 191 | return page; |
193 | 192 | ||
194 | remap = (page - pvt->tolm) + pvt->remapbase; | 193 | remap = (page - pvt->tolm) + pvt->remapbase; |
@@ -200,8 +199,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | |||
200 | return pvt->tolm - 1; | 199 | return pvt->tolm - 1; |
201 | } | 200 | } |
202 | 201 | ||
203 | static void process_ce(struct mem_ctl_info *mci, | 202 | static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info) |
204 | struct e7xxx_error_info *info) | ||
205 | { | 203 | { |
206 | u32 error_1b, page; | 204 | u32 error_1b, page; |
207 | u16 syndrome; | 205 | u16 syndrome; |
@@ -212,7 +210,7 @@ static void process_ce(struct mem_ctl_info *mci, | |||
212 | /* read the error address */ | 210 | /* read the error address */ |
213 | error_1b = info->dram_celog_add; | 211 | error_1b = info->dram_celog_add; |
214 | /* FIXME - should use PAGE_SHIFT */ | 212 | /* FIXME - should use PAGE_SHIFT */ |
215 | page = error_1b >> 6; /* convert the address to 4k page */ | 213 | page = error_1b >> 6; /* convert the address to 4k page */ |
216 | /* read the syndrome */ | 214 | /* read the syndrome */ |
217 | syndrome = info->dram_celog_syndrome; | 215 | syndrome = info->dram_celog_syndrome; |
218 | /* FIXME - check for -1 */ | 216 | /* FIXME - check for -1 */ |
@@ -228,8 +226,7 @@ static void process_ce_no_info(struct mem_ctl_info *mci) | |||
228 | edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); | 226 | edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); |
229 | } | 227 | } |
230 | 228 | ||
231 | static void process_ue(struct mem_ctl_info *mci, | 229 | static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) |
232 | struct e7xxx_error_info *info) | ||
233 | { | 230 | { |
234 | u32 error_2b, block_page; | 231 | u32 error_2b, block_page; |
235 | int row; | 232 | int row; |
@@ -238,7 +235,7 @@ static void process_ue(struct mem_ctl_info *mci, | |||
238 | /* read the error address */ | 235 | /* read the error address */ |
239 | error_2b = info->dram_uelog_add; | 236 | error_2b = info->dram_uelog_add; |
240 | /* FIXME - should use PAGE_SHIFT */ | 237 | /* FIXME - should use PAGE_SHIFT */ |
241 | block_page = error_2b >> 6; /* convert to 4k address */ | 238 | block_page = error_2b >> 6; /* convert to 4k address */ |
242 | row = edac_mc_find_csrow_by_page(mci, block_page); | 239 | row = edac_mc_find_csrow_by_page(mci, block_page); |
243 | edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); | 240 | edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); |
244 | } | 241 | } |
@@ -249,16 +246,14 @@ static void process_ue_no_info(struct mem_ctl_info *mci) | |||
249 | edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); | 246 | edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); |
250 | } | 247 | } |
251 | 248 | ||
252 | static void e7xxx_get_error_info (struct mem_ctl_info *mci, | 249 | static void e7xxx_get_error_info(struct mem_ctl_info *mci, |
253 | struct e7xxx_error_info *info) | 250 | struct e7xxx_error_info *info) |
254 | { | 251 | { |
255 | struct e7xxx_pvt *pvt; | 252 | struct e7xxx_pvt *pvt; |
256 | 253 | ||
257 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | 254 | pvt = (struct e7xxx_pvt *)mci->pvt_info; |
258 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, | 255 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr); |
259 | &info->dram_ferr); | 256 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr); |
260 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, | ||
261 | &info->dram_nerr); | ||
262 | 257 | ||
263 | if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) { | 258 | if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) { |
264 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD, | 259 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD, |
@@ -279,8 +274,9 @@ static void e7xxx_get_error_info (struct mem_ctl_info *mci, | |||
279 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); | 274 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); |
280 | } | 275 | } |
281 | 276 | ||
282 | static int e7xxx_process_error_info (struct mem_ctl_info *mci, | 277 | static int e7xxx_process_error_info(struct mem_ctl_info *mci, |
283 | struct e7xxx_error_info *info, int handle_errors) | 278 | struct e7xxx_error_info *info, |
279 | int handle_errors) | ||
284 | { | 280 | { |
285 | int error_found; | 281 | int error_found; |
286 | 282 | ||
@@ -341,7 +337,6 @@ static inline int dual_channel_active(u32 drc, int dev_idx) | |||
341 | return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1; | 337 | return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1; |
342 | } | 338 | } |
343 | 339 | ||
344 | |||
345 | /* Return DRB granularity (0=32mb, 1=64mb). */ | 340 | /* Return DRB granularity (0=32mb, 1=64mb). */ |
346 | static inline int drb_granularity(u32 drc, int dev_idx) | 341 | static inline int drb_granularity(u32 drc, int dev_idx) |
347 | { | 342 | { |
@@ -349,9 +344,8 @@ static inline int drb_granularity(u32 drc, int dev_idx) | |||
349 | return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1; | 344 | return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1; |
350 | } | 345 | } |
351 | 346 | ||
352 | |||
353 | static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | 347 | static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
354 | int dev_idx, u32 drc) | 348 | int dev_idx, u32 drc) |
355 | { | 349 | { |
356 | unsigned long last_cumul_size; | 350 | unsigned long last_cumul_size; |
357 | int index; | 351 | int index; |
@@ -419,10 +413,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
419 | struct e7xxx_error_info discard; | 413 | struct e7xxx_error_info discard; |
420 | 414 | ||
421 | debugf0("%s(): mci\n", __func__); | 415 | debugf0("%s(): mci\n", __func__); |
416 | |||
417 | /* make sure error reporting method is sane */ | ||
418 | switch (edac_op_state) { | ||
419 | case EDAC_OPSTATE_POLL: | ||
420 | case EDAC_OPSTATE_NMI: | ||
421 | break; | ||
422 | default: | ||
423 | edac_op_state = EDAC_OPSTATE_POLL; | ||
424 | break; | ||
425 | } | ||
426 | |||
422 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); | 427 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); |
423 | 428 | ||
424 | drc_chan = dual_channel_active(drc, dev_idx); | 429 | drc_chan = dual_channel_active(drc, dev_idx); |
425 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); | 430 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0); |
426 | 431 | ||
427 | if (mci == NULL) | 432 | if (mci == NULL) |
428 | return -ENOMEM; | 433 | return -ENOMEM; |
@@ -430,17 +435,16 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
430 | debugf3("%s(): init mci\n", __func__); | 435 | debugf3("%s(): init mci\n", __func__); |
431 | mci->mtype_cap = MEM_FLAG_RDDR; | 436 | mci->mtype_cap = MEM_FLAG_RDDR; |
432 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | 437 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | |
433 | EDAC_FLAG_S4ECD4ED; | 438 | EDAC_FLAG_S4ECD4ED; |
434 | /* FIXME - what if different memory types are in different csrows? */ | 439 | /* FIXME - what if different memory types are in different csrows? */ |
435 | mci->mod_name = EDAC_MOD_STR; | 440 | mci->mod_name = EDAC_MOD_STR; |
436 | mci->mod_ver = E7XXX_REVISION; | 441 | mci->mod_ver = E7XXX_REVISION; |
437 | mci->dev = &pdev->dev; | 442 | mci->dev = &pdev->dev; |
438 | debugf3("%s(): init pvt\n", __func__); | 443 | debugf3("%s(): init pvt\n", __func__); |
439 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | 444 | pvt = (struct e7xxx_pvt *)mci->pvt_info; |
440 | pvt->dev_info = &e7xxx_devs[dev_idx]; | 445 | pvt->dev_info = &e7xxx_devs[dev_idx]; |
441 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | 446 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, |
442 | pvt->dev_info->err_dev, | 447 | pvt->dev_info->err_dev, pvt->bridge_ck); |
443 | pvt->bridge_ck); | ||
444 | 448 | ||
445 | if (!pvt->bridge_ck) { | 449 | if (!pvt->bridge_ck) { |
446 | e7xxx_printk(KERN_ERR, "error reporting device not found:" | 450 | e7xxx_printk(KERN_ERR, "error reporting device not found:" |
@@ -451,6 +455,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
451 | 455 | ||
452 | debugf3("%s(): more mci init\n", __func__); | 456 | debugf3("%s(): more mci init\n", __func__); |
453 | mci->ctl_name = pvt->dev_info->ctl_name; | 457 | mci->ctl_name = pvt->dev_info->ctl_name; |
458 | mci->dev_name = pci_name(pdev); | ||
454 | mci->edac_check = e7xxx_check; | 459 | mci->edac_check = e7xxx_check; |
455 | mci->ctl_page_to_phys = ctl_page_to_phys; | 460 | mci->ctl_page_to_phys = ctl_page_to_phys; |
456 | e7xxx_init_csrows(mci, pdev, dev_idx, drc); | 461 | e7xxx_init_csrows(mci, pdev, dev_idx, drc); |
@@ -473,11 +478,22 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
473 | /* Here we assume that we will never see multiple instances of this | 478 | /* Here we assume that we will never see multiple instances of this |
474 | * type of memory controller. The ID is therefore hardcoded to 0. | 479 | * type of memory controller. The ID is therefore hardcoded to 0. |
475 | */ | 480 | */ |
476 | if (edac_mc_add_mc(mci,0)) { | 481 | if (edac_mc_add_mc(mci)) { |
477 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 482 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
478 | goto fail1; | 483 | goto fail1; |
479 | } | 484 | } |
480 | 485 | ||
486 | /* allocating generic PCI control info */ | ||
487 | e7xxx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
488 | if (!e7xxx_pci) { | ||
489 | printk(KERN_WARNING | ||
490 | "%s(): Unable to create PCI control\n", | ||
491 | __func__); | ||
492 | printk(KERN_WARNING | ||
493 | "%s(): PCI error report via EDAC not setup\n", | ||
494 | __func__); | ||
495 | } | ||
496 | |||
481 | /* get this far and it's successful */ | 497 | /* get this far and it's successful */ |
482 | debugf3("%s(): success\n", __func__); | 498 | debugf3("%s(): success\n", __func__); |
483 | return 0; | 499 | return 0; |
@@ -493,7 +509,7 @@ fail0: | |||
493 | 509 | ||
494 | /* returns count (>= 0), or negative on error */ | 510 | /* returns count (>= 0), or negative on error */ |
495 | static int __devinit e7xxx_init_one(struct pci_dev *pdev, | 511 | static int __devinit e7xxx_init_one(struct pci_dev *pdev, |
496 | const struct pci_device_id *ent) | 512 | const struct pci_device_id *ent) |
497 | { | 513 | { |
498 | debugf0("%s()\n", __func__); | 514 | debugf0("%s()\n", __func__); |
499 | 515 | ||
@@ -509,34 +525,33 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev) | |||
509 | 525 | ||
510 | debugf0("%s()\n", __func__); | 526 | debugf0("%s()\n", __func__); |
511 | 527 | ||
528 | if (e7xxx_pci) | ||
529 | edac_pci_release_generic_ctl(e7xxx_pci); | ||
530 | |||
512 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 531 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
513 | return; | 532 | return; |
514 | 533 | ||
515 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | 534 | pvt = (struct e7xxx_pvt *)mci->pvt_info; |
516 | pci_dev_put(pvt->bridge_ck); | 535 | pci_dev_put(pvt->bridge_ck); |
517 | edac_mc_free(mci); | 536 | edac_mc_free(mci); |
518 | } | 537 | } |
519 | 538 | ||
520 | static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { | 539 | static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { |
521 | { | 540 | { |
522 | PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 541 | PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
523 | E7205 | 542 | E7205}, |
524 | }, | ||
525 | { | 543 | { |
526 | PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 544 | PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
527 | E7500 | 545 | E7500}, |
528 | }, | ||
529 | { | 546 | { |
530 | PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 547 | PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
531 | E7501 | 548 | E7501}, |
532 | }, | ||
533 | { | 549 | { |
534 | PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 550 | PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
535 | E7505 | 551 | E7505}, |
536 | }, | ||
537 | { | 552 | { |
538 | 0, | 553 | 0, |
539 | } /* 0 terminated list. */ | 554 | } /* 0 terminated list. */ |
540 | }; | 555 | }; |
541 | 556 | ||
542 | MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); | 557 | MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); |
@@ -563,5 +578,7 @@ module_exit(e7xxx_exit); | |||
563 | 578 | ||
564 | MODULE_LICENSE("GPL"); | 579 | MODULE_LICENSE("GPL"); |
565 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" | 580 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" |
566 | "Based on.work by Dan Hollis et al"); | 581 | "Based on.work by Dan Hollis et al"); |
567 | MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); | 582 | MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); |
583 | module_param(edac_op_state, int, 0444); | ||
584 | MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); | ||
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_core.h index 713444cc4105..4e6bad15c4ba 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_core.h | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * MC kernel module | 2 | * Defines, structures, APIs for edac_core module |
3 | * (C) 2003 Linux Networx (http://lnxi.com) | 3 | * |
4 | * (C) 2007 Linux Networx (http://lnxi.com) | ||
4 | * This file may be distributed under the terms of the | 5 | * This file may be distributed under the terms of the |
5 | * GNU General Public License. | 6 | * GNU General Public License. |
6 | * | 7 | * |
@@ -11,12 +12,13 @@ | |||
11 | * NMI handling support added by | 12 | * NMI handling support added by |
12 | * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com> | 13 | * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com> |
13 | * | 14 | * |
14 | * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $ | 15 | * Refactored for multi-source files: |
16 | * Doug Thompson <norsk5@xmission.com> | ||
15 | * | 17 | * |
16 | */ | 18 | */ |
17 | 19 | ||
18 | #ifndef _EDAC_MC_H_ | 20 | #ifndef _EDAC_CORE_H_ |
19 | #define _EDAC_MC_H_ | 21 | #define _EDAC_CORE_H_ |
20 | 22 | ||
21 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
22 | #include <linux/types.h> | 24 | #include <linux/types.h> |
@@ -30,9 +32,14 @@ | |||
30 | #include <linux/completion.h> | 32 | #include <linux/completion.h> |
31 | #include <linux/kobject.h> | 33 | #include <linux/kobject.h> |
32 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/sysdev.h> | ||
36 | #include <linux/workqueue.h> | ||
37 | #include <linux/version.h> | ||
33 | 38 | ||
34 | #define EDAC_MC_LABEL_LEN 31 | 39 | #define EDAC_MC_LABEL_LEN 31 |
35 | #define MC_PROC_NAME_MAX_LEN 7 | 40 | #define EDAC_DEVICE_NAME_LEN 31 |
41 | #define EDAC_ATTRIB_VALUE_LEN 15 | ||
42 | #define MC_PROC_NAME_MAX_LEN 7 | ||
36 | 43 | ||
37 | #if PAGE_SHIFT < 20 | 44 | #if PAGE_SHIFT < 20 |
38 | #define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) | 45 | #define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) |
@@ -49,6 +56,14 @@ | |||
49 | #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ | 56 | #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ |
50 | printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) | 57 | printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) |
51 | 58 | ||
59 | /* edac_device printk */ | ||
60 | #define edac_device_printk(ctl, level, fmt, arg...) \ | ||
61 | printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg) | ||
62 | |||
63 | /* edac_pci printk */ | ||
64 | #define edac_pci_printk(ctl, level, fmt, arg...) \ | ||
65 | printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg) | ||
66 | |||
52 | /* prefixes for edac_printk() and edac_mc_printk() */ | 67 | /* prefixes for edac_printk() and edac_mc_printk() */ |
53 | #define EDAC_MC "MC" | 68 | #define EDAC_MC "MC" |
54 | #define EDAC_PCI "PCI" | 69 | #define EDAC_PCI "PCI" |
@@ -60,7 +75,7 @@ extern int edac_debug_level; | |||
60 | #define edac_debug_printk(level, fmt, arg...) \ | 75 | #define edac_debug_printk(level, fmt, arg...) \ |
61 | do { \ | 76 | do { \ |
62 | if (level <= edac_debug_level) \ | 77 | if (level <= edac_debug_level) \ |
63 | edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ | 78 | edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \ |
64 | } while(0) | 79 | } while(0) |
65 | 80 | ||
66 | #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) | 81 | #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) |
@@ -69,7 +84,7 @@ extern int edac_debug_level; | |||
69 | #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) | 84 | #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) |
70 | #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) | 85 | #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) |
71 | 86 | ||
72 | #else /* !CONFIG_EDAC_DEBUG */ | 87 | #else /* !CONFIG_EDAC_DEBUG */ |
73 | 88 | ||
74 | #define debugf0( ... ) | 89 | #define debugf0( ... ) |
75 | #define debugf1( ... ) | 90 | #define debugf1( ... ) |
@@ -77,18 +92,14 @@ extern int edac_debug_level; | |||
77 | #define debugf3( ... ) | 92 | #define debugf3( ... ) |
78 | #define debugf4( ... ) | 93 | #define debugf4( ... ) |
79 | 94 | ||
80 | #endif /* !CONFIG_EDAC_DEBUG */ | 95 | #endif /* !CONFIG_EDAC_DEBUG */ |
81 | 96 | ||
82 | #define BIT(x) (1 << (x)) | 97 | #define BIT(x) (1 << (x)) |
83 | 98 | ||
84 | #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ | 99 | #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ |
85 | PCI_DEVICE_ID_ ## vend ## _ ## dev | 100 | PCI_DEVICE_ID_ ## vend ## _ ## dev |
86 | 101 | ||
87 | #if defined(CONFIG_X86) && defined(CONFIG_PCI) | 102 | #define dev_name(dev) (dev)->dev_name |
88 | #define dev_name(dev) pci_name(to_pci_dev(dev)) | ||
89 | #else | ||
90 | #define dev_name(dev) to_platform_device(dev)->name | ||
91 | #endif | ||
92 | 103 | ||
93 | /* memory devices */ | 104 | /* memory devices */ |
94 | enum dev_type { | 105 | enum dev_type { |
@@ -124,8 +135,9 @@ enum mem_type { | |||
124 | MEM_DDR, /* Double data rate SDRAM */ | 135 | MEM_DDR, /* Double data rate SDRAM */ |
125 | MEM_RDDR, /* Registered Double data rate SDRAM */ | 136 | MEM_RDDR, /* Registered Double data rate SDRAM */ |
126 | MEM_RMBS, /* Rambus DRAM */ | 137 | MEM_RMBS, /* Rambus DRAM */ |
127 | MEM_DDR2, /* DDR2 RAM */ | 138 | MEM_DDR2, /* DDR2 RAM */ |
128 | MEM_FB_DDR2, /* fully buffered DDR2 */ | 139 | MEM_FB_DDR2, /* fully buffered DDR2 */ |
140 | MEM_RDDR2, /* Registered DDR2 RAM */ | ||
129 | }; | 141 | }; |
130 | 142 | ||
131 | #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) | 143 | #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) |
@@ -141,6 +153,7 @@ enum mem_type { | |||
141 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) | 153 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) |
142 | #define MEM_FLAG_DDR2 BIT(MEM_DDR2) | 154 | #define MEM_FLAG_DDR2 BIT(MEM_DDR2) |
143 | #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) | 155 | #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) |
156 | #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) | ||
144 | 157 | ||
145 | /* chipset Error Detection and Correction capabilities and mode */ | 158 | /* chipset Error Detection and Correction capabilities and mode */ |
146 | enum edac_type { | 159 | enum edac_type { |
@@ -181,16 +194,23 @@ enum scrub_type { | |||
181 | }; | 194 | }; |
182 | 195 | ||
183 | #define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG) | 196 | #define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG) |
184 | #define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC_CORR) | 197 | #define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC) |
185 | #define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR) | 198 | #define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC) |
186 | #define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE) | 199 | #define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE) |
187 | #define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG) | 200 | #define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG) |
188 | #define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC_CORR) | 201 | #define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC) |
189 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) | 202 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC) |
190 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) | 203 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) |
191 | 204 | ||
192 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ | 205 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ |
193 | 206 | ||
207 | /* EDAC internal operation states */ | ||
208 | #define OP_ALLOC 0x100 | ||
209 | #define OP_RUNNING_POLL 0x201 | ||
210 | #define OP_RUNNING_INTERRUPT 0x202 | ||
211 | #define OP_RUNNING_POLL_INTR 0x203 | ||
212 | #define OP_OFFLINE 0x300 | ||
213 | |||
194 | /* | 214 | /* |
195 | * There are several things to be aware of that aren't at all obvious: | 215 | * There are several things to be aware of that aren't at all obvious: |
196 | * | 216 | * |
@@ -276,7 +296,7 @@ enum scrub_type { | |||
276 | struct channel_info { | 296 | struct channel_info { |
277 | int chan_idx; /* channel index */ | 297 | int chan_idx; /* channel index */ |
278 | u32 ce_count; /* Correctable Errors for this CHANNEL */ | 298 | u32 ce_count; /* Correctable Errors for this CHANNEL */ |
279 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ | 299 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ |
280 | struct csrow_info *csrow; /* the parent */ | 300 | struct csrow_info *csrow; /* the parent */ |
281 | }; | 301 | }; |
282 | 302 | ||
@@ -297,15 +317,29 @@ struct csrow_info { | |||
297 | struct mem_ctl_info *mci; /* the parent */ | 317 | struct mem_ctl_info *mci; /* the parent */ |
298 | 318 | ||
299 | struct kobject kobj; /* sysfs kobject for this csrow */ | 319 | struct kobject kobj; /* sysfs kobject for this csrow */ |
300 | struct completion kobj_complete; | ||
301 | 320 | ||
302 | /* FIXME the number of CHANNELs might need to become dynamic */ | 321 | /* channel information for this csrow */ |
303 | u32 nr_channels; | 322 | u32 nr_channels; |
304 | struct channel_info *channels; | 323 | struct channel_info *channels; |
305 | }; | 324 | }; |
306 | 325 | ||
326 | /* mcidev_sysfs_attribute structure | ||
327 | * used for driver sysfs attributes and in mem_ctl_info | ||
328 | * sysfs top level entries | ||
329 | */ | ||
330 | struct mcidev_sysfs_attribute { | ||
331 | struct attribute attr; | ||
332 | ssize_t (*show)(struct mem_ctl_info *,char *); | ||
333 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); | ||
334 | }; | ||
335 | |||
336 | /* MEMORY controller information structure | ||
337 | */ | ||
307 | struct mem_ctl_info { | 338 | struct mem_ctl_info { |
308 | struct list_head link; /* for global list of mem_ctl_info structs */ | 339 | struct list_head link; /* for global list of mem_ctl_info structs */ |
340 | |||
341 | struct module *owner; /* Module owner of this control struct */ | ||
342 | |||
309 | unsigned long mtype_cap; /* memory types supported by mc */ | 343 | unsigned long mtype_cap; /* memory types supported by mc */ |
310 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ | 344 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ |
311 | unsigned long edac_cap; /* configuration capabilities - this is | 345 | unsigned long edac_cap; /* configuration capabilities - this is |
@@ -322,14 +356,15 @@ struct mem_ctl_info { | |||
322 | /* Translates sdram memory scrub rate given in bytes/sec to the | 356 | /* Translates sdram memory scrub rate given in bytes/sec to the |
323 | internal representation and configures whatever else needs | 357 | internal representation and configures whatever else needs |
324 | to be configured. | 358 | to be configured. |
325 | */ | 359 | */ |
326 | int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); | 360 | int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); |
327 | 361 | ||
328 | /* Get the current sdram memory scrub rate from the internal | 362 | /* Get the current sdram memory scrub rate from the internal |
329 | representation and converts it to the closest matching | 363 | representation and converts it to the closest matching |
330 | bandwith in bytes/sec. | 364 | bandwith in bytes/sec. |
331 | */ | 365 | */ |
332 | int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); | 366 | int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw); |
367 | |||
333 | 368 | ||
334 | /* pointer to edac checking routine */ | 369 | /* pointer to edac checking routine */ |
335 | void (*edac_check) (struct mem_ctl_info * mci); | 370 | void (*edac_check) (struct mem_ctl_info * mci); |
@@ -340,7 +375,7 @@ struct mem_ctl_info { | |||
340 | */ | 375 | */ |
341 | /* FIXME - why not send the phys page to begin with? */ | 376 | /* FIXME - why not send the phys page to begin with? */ |
342 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, | 377 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, |
343 | unsigned long page); | 378 | unsigned long page); |
344 | int mc_idx; | 379 | int mc_idx; |
345 | int nr_csrows; | 380 | int nr_csrows; |
346 | struct csrow_info *csrows; | 381 | struct csrow_info *csrows; |
@@ -353,6 +388,7 @@ struct mem_ctl_info { | |||
353 | const char *mod_name; | 388 | const char *mod_name; |
354 | const char *mod_ver; | 389 | const char *mod_ver; |
355 | const char *ctl_name; | 390 | const char *ctl_name; |
391 | const char *dev_name; | ||
356 | char proc_name[MC_PROC_NAME_MAX_LEN + 1]; | 392 | char proc_name[MC_PROC_NAME_MAX_LEN + 1]; |
357 | void *pvt_info; | 393 | void *pvt_info; |
358 | u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */ | 394 | u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */ |
@@ -369,14 +405,327 @@ struct mem_ctl_info { | |||
369 | 405 | ||
370 | /* edac sysfs device control */ | 406 | /* edac sysfs device control */ |
371 | struct kobject edac_mci_kobj; | 407 | struct kobject edac_mci_kobj; |
372 | struct completion kobj_complete; | 408 | |
409 | /* Additional top controller level attributes, but specified | ||
410 | * by the low level driver. | ||
411 | * | ||
412 | * Set by the low level driver to provide attributes at the | ||
413 | * controller level, same level as 'ue_count' and 'ce_count' above. | ||
414 | * An array of structures, NULL terminated | ||
415 | * | ||
416 | * If attributes are desired, then set to array of attributes | ||
417 | * If no attributes are desired, leave NULL | ||
418 | */ | ||
419 | struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; | ||
420 | |||
421 | /* work struct for this MC */ | ||
422 | struct delayed_work work; | ||
423 | |||
424 | /* the internal state of this controller instance */ | ||
425 | int op_state; | ||
426 | }; | ||
427 | |||
428 | /* | ||
429 | * The following are the structures to provide for a generic | ||
430 | * or abstract 'edac_device'. This set of structures and the | ||
431 | * code that implements the APIs for the same, provide for | ||
432 | * registering EDAC type devices which are NOT standard memory. | ||
433 | * | ||
434 | * CPU caches (L1 and L2) | ||
435 | * DMA engines | ||
436 | * Core CPU swithces | ||
437 | * Fabric switch units | ||
438 | * PCIe interface controllers | ||
439 | * other EDAC/ECC type devices that can be monitored for | ||
440 | * errors, etc. | ||
441 | * | ||
442 | * It allows for a 2 level set of hiearchry. For example: | ||
443 | * | ||
444 | * cache could be composed of L1, L2 and L3 levels of cache. | ||
445 | * Each CPU core would have its own L1 cache, while sharing | ||
446 | * L2 and maybe L3 caches. | ||
447 | * | ||
448 | * View them arranged, via the sysfs presentation: | ||
449 | * /sys/devices/system/edac/.. | ||
450 | * | ||
451 | * mc/ <existing memory device directory> | ||
452 | * cpu/cpu0/.. <L1 and L2 block directory> | ||
453 | * /L1-cache/ce_count | ||
454 | * /ue_count | ||
455 | * /L2-cache/ce_count | ||
456 | * /ue_count | ||
457 | * cpu/cpu1/.. <L1 and L2 block directory> | ||
458 | * /L1-cache/ce_count | ||
459 | * /ue_count | ||
460 | * /L2-cache/ce_count | ||
461 | * /ue_count | ||
462 | * ... | ||
463 | * | ||
464 | * the L1 and L2 directories would be "edac_device_block's" | ||
465 | */ | ||
466 | |||
467 | struct edac_device_counter { | ||
468 | u32 ue_count; | ||
469 | u32 ce_count; | ||
470 | }; | ||
471 | |||
472 | /* forward reference */ | ||
473 | struct edac_device_ctl_info; | ||
474 | struct edac_device_block; | ||
475 | |||
476 | /* edac_dev_sysfs_attribute structure | ||
477 | * used for driver sysfs attributes in mem_ctl_info | ||
478 | * for extra controls and attributes: | ||
479 | * like high level error Injection controls | ||
480 | */ | ||
481 | struct edac_dev_sysfs_attribute { | ||
482 | struct attribute attr; | ||
483 | ssize_t (*show)(struct edac_device_ctl_info *, char *); | ||
484 | ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); | ||
485 | }; | ||
486 | |||
487 | /* edac_dev_sysfs_block_attribute structure | ||
488 | * | ||
489 | * used in leaf 'block' nodes for adding controls/attributes | ||
490 | * | ||
491 | * each block in each instance of the containing control structure | ||
492 | * can have an array of the following. The show and store functions | ||
493 | * will be filled in with the show/store function in the | ||
494 | * low level driver. | ||
495 | * | ||
496 | * The 'value' field will be the actual value field used for | ||
497 | * counting | ||
498 | */ | ||
499 | struct edac_dev_sysfs_block_attribute { | ||
500 | struct attribute attr; | ||
501 | ssize_t (*show)(struct kobject *, struct attribute *, char *); | ||
502 | ssize_t (*store)(struct kobject *, struct attribute *, | ||
503 | const char *, size_t); | ||
504 | struct edac_device_block *block; | ||
505 | |||
506 | unsigned int value; | ||
507 | }; | ||
508 | |||
509 | /* device block control structure */ | ||
510 | struct edac_device_block { | ||
511 | struct edac_device_instance *instance; /* Up Pointer */ | ||
512 | char name[EDAC_DEVICE_NAME_LEN + 1]; | ||
513 | |||
514 | struct edac_device_counter counters; /* basic UE and CE counters */ | ||
515 | |||
516 | int nr_attribs; /* how many attributes */ | ||
517 | |||
518 | /* this block's attributes, could be NULL */ | ||
519 | struct edac_dev_sysfs_block_attribute *block_attributes; | ||
520 | |||
521 | /* edac sysfs device control */ | ||
522 | struct kobject kobj; | ||
523 | }; | ||
524 | |||
525 | /* device instance control structure */ | ||
526 | struct edac_device_instance { | ||
527 | struct edac_device_ctl_info *ctl; /* Up pointer */ | ||
528 | char name[EDAC_DEVICE_NAME_LEN + 4]; | ||
529 | |||
530 | struct edac_device_counter counters; /* instance counters */ | ||
531 | |||
532 | u32 nr_blocks; /* how many blocks */ | ||
533 | struct edac_device_block *blocks; /* block array */ | ||
534 | |||
535 | /* edac sysfs device control */ | ||
536 | struct kobject kobj; | ||
537 | }; | ||
538 | |||
539 | |||
540 | /* | ||
541 | * Abstract edac_device control info structure | ||
542 | * | ||
543 | */ | ||
544 | struct edac_device_ctl_info { | ||
545 | /* for global list of edac_device_ctl_info structs */ | ||
546 | struct list_head link; | ||
547 | |||
548 | struct module *owner; /* Module owner of this control struct */ | ||
549 | |||
550 | int dev_idx; | ||
551 | |||
552 | /* Per instance controls for this edac_device */ | ||
553 | int log_ue; /* boolean for logging UEs */ | ||
554 | int log_ce; /* boolean for logging CEs */ | ||
555 | int panic_on_ue; /* boolean for panic'ing on an UE */ | ||
556 | unsigned poll_msec; /* number of milliseconds to poll interval */ | ||
557 | unsigned long delay; /* number of jiffies for poll_msec */ | ||
558 | |||
559 | /* Additional top controller level attributes, but specified | ||
560 | * by the low level driver. | ||
561 | * | ||
562 | * Set by the low level driver to provide attributes at the | ||
563 | * controller level, same level as 'ue_count' and 'ce_count' above. | ||
564 | * An array of structures, NULL terminated | ||
565 | * | ||
566 | * If attributes are desired, then set to array of attributes | ||
567 | * If no attributes are desired, leave NULL | ||
568 | */ | ||
569 | struct edac_dev_sysfs_attribute *sysfs_attributes; | ||
570 | |||
571 | /* pointer to main 'edac' class in sysfs */ | ||
572 | struct sysdev_class *edac_class; | ||
573 | |||
574 | /* the internal state of this controller instance */ | ||
575 | int op_state; | ||
576 | /* work struct for this instance */ | ||
577 | struct delayed_work work; | ||
578 | |||
579 | /* pointer to edac polling checking routine: | ||
580 | * If NOT NULL: points to polling check routine | ||
581 | * If NULL: Then assumes INTERRUPT operation, where | ||
582 | * MC driver will receive events | ||
583 | */ | ||
584 | void (*edac_check) (struct edac_device_ctl_info * edac_dev); | ||
585 | |||
586 | struct device *dev; /* pointer to device structure */ | ||
587 | |||
588 | const char *mod_name; /* module name */ | ||
589 | const char *ctl_name; /* edac controller name */ | ||
590 | const char *dev_name; /* pci/platform/etc... name */ | ||
591 | |||
592 | void *pvt_info; /* pointer to 'private driver' info */ | ||
593 | |||
594 | unsigned long start_time; /* edac_device load start time (jiffies) */ | ||
595 | |||
596 | /* these are for safe removal of mc devices from global list while | ||
597 | * NMI handlers may be traversing list | ||
598 | */ | ||
599 | struct rcu_head rcu; | ||
600 | struct completion removal_complete; | ||
601 | |||
602 | /* sysfs top name under 'edac' directory | ||
603 | * and instance name: | ||
604 | * cpu/cpu0/... | ||
605 | * cpu/cpu1/... | ||
606 | * cpu/cpu2/... | ||
607 | * ... | ||
608 | */ | ||
609 | char name[EDAC_DEVICE_NAME_LEN + 1]; | ||
610 | |||
611 | /* Number of instances supported on this control structure | ||
612 | * and the array of those instances | ||
613 | */ | ||
614 | u32 nr_instances; | ||
615 | struct edac_device_instance *instances; | ||
616 | |||
617 | /* Event counters for the this whole EDAC Device */ | ||
618 | struct edac_device_counter counters; | ||
619 | |||
620 | /* edac sysfs device control for the 'name' | ||
621 | * device this structure controls | ||
622 | */ | ||
623 | struct kobject kobj; | ||
373 | }; | 624 | }; |
374 | 625 | ||
626 | /* To get from the instance's wq to the beginning of the ctl structure */ | ||
627 | #define to_edac_mem_ctl_work(w) \ | ||
628 | container_of(w, struct mem_ctl_info, work) | ||
629 | |||
630 | #define to_edac_device_ctl_work(w) \ | ||
631 | container_of(w,struct edac_device_ctl_info,work) | ||
632 | |||
633 | /* | ||
634 | * The alloc() and free() functions for the 'edac_device' control info | ||
635 | * structure. A MC driver will allocate one of these for each edac_device | ||
636 | * it is going to control/register with the EDAC CORE. | ||
637 | */ | ||
638 | extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( | ||
639 | unsigned sizeof_private, | ||
640 | char *edac_device_name, unsigned nr_instances, | ||
641 | char *edac_block_name, unsigned nr_blocks, | ||
642 | unsigned offset_value, | ||
643 | struct edac_dev_sysfs_block_attribute *block_attributes, | ||
644 | unsigned nr_attribs, | ||
645 | int device_index); | ||
646 | |||
647 | /* The offset value can be: | ||
648 | * -1 indicating no offset value | ||
649 | * 0 for zero-based block numbers | ||
650 | * 1 for 1-based block number | ||
651 | * other for other-based block number | ||
652 | */ | ||
653 | #define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1) | ||
654 | |||
655 | extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info); | ||
656 | |||
375 | #ifdef CONFIG_PCI | 657 | #ifdef CONFIG_PCI |
376 | 658 | ||
659 | struct edac_pci_counter { | ||
660 | atomic_t pe_count; | ||
661 | atomic_t npe_count; | ||
662 | }; | ||
663 | |||
664 | /* | ||
665 | * Abstract edac_pci control info structure | ||
666 | * | ||
667 | */ | ||
668 | struct edac_pci_ctl_info { | ||
669 | /* for global list of edac_pci_ctl_info structs */ | ||
670 | struct list_head link; | ||
671 | |||
672 | int pci_idx; | ||
673 | |||
674 | struct sysdev_class *edac_class; /* pointer to class */ | ||
675 | |||
676 | /* the internal state of this controller instance */ | ||
677 | int op_state; | ||
678 | /* work struct for this instance */ | ||
679 | struct delayed_work work; | ||
680 | |||
681 | /* pointer to edac polling checking routine: | ||
682 | * If NOT NULL: points to polling check routine | ||
683 | * If NULL: Then assumes INTERRUPT operation, where | ||
684 | * MC driver will receive events | ||
685 | */ | ||
686 | void (*edac_check) (struct edac_pci_ctl_info * edac_dev); | ||
687 | |||
688 | struct device *dev; /* pointer to device structure */ | ||
689 | |||
690 | const char *mod_name; /* module name */ | ||
691 | const char *ctl_name; /* edac controller name */ | ||
692 | const char *dev_name; /* pci/platform/etc... name */ | ||
693 | |||
694 | void *pvt_info; /* pointer to 'private driver' info */ | ||
695 | |||
696 | unsigned long start_time; /* edac_pci load start time (jiffies) */ | ||
697 | |||
698 | /* these are for safe removal of devices from global list while | ||
699 | * NMI handlers may be traversing list | ||
700 | */ | ||
701 | struct rcu_head rcu; | ||
702 | struct completion complete; | ||
703 | |||
704 | /* sysfs top name under 'edac' directory | ||
705 | * and instance name: | ||
706 | * cpu/cpu0/... | ||
707 | * cpu/cpu1/... | ||
708 | * cpu/cpu2/... | ||
709 | * ... | ||
710 | */ | ||
711 | char name[EDAC_DEVICE_NAME_LEN + 1]; | ||
712 | |||
713 | /* Event counters for the this whole EDAC Device */ | ||
714 | struct edac_pci_counter counters; | ||
715 | |||
716 | /* edac sysfs device control for the 'name' | ||
717 | * device this structure controls | ||
718 | */ | ||
719 | struct kobject kobj; | ||
720 | struct completion kobj_complete; | ||
721 | }; | ||
722 | |||
723 | #define to_edac_pci_ctl_work(w) \ | ||
724 | container_of(w, struct edac_pci_ctl_info,work) | ||
725 | |||
377 | /* write all or some bits in a byte-register*/ | 726 | /* write all or some bits in a byte-register*/ |
378 | static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, | 727 | static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, |
379 | u8 mask) | 728 | u8 mask) |
380 | { | 729 | { |
381 | if (mask != 0xff) { | 730 | if (mask != 0xff) { |
382 | u8 buf; | 731 | u8 buf; |
@@ -392,7 +741,7 @@ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, | |||
392 | 741 | ||
393 | /* write all or some bits in a word-register*/ | 742 | /* write all or some bits in a word-register*/ |
394 | static inline void pci_write_bits16(struct pci_dev *pdev, int offset, | 743 | static inline void pci_write_bits16(struct pci_dev *pdev, int offset, |
395 | u16 value, u16 mask) | 744 | u16 value, u16 mask) |
396 | { | 745 | { |
397 | if (mask != 0xffff) { | 746 | if (mask != 0xffff) { |
398 | u16 buf; | 747 | u16 buf; |
@@ -408,7 +757,7 @@ static inline void pci_write_bits16(struct pci_dev *pdev, int offset, | |||
408 | 757 | ||
409 | /* write all or some bits in a dword-register*/ | 758 | /* write all or some bits in a dword-register*/ |
410 | static inline void pci_write_bits32(struct pci_dev *pdev, int offset, | 759 | static inline void pci_write_bits32(struct pci_dev *pdev, int offset, |
411 | u32 value, u32 mask) | 760 | u32 value, u32 mask) |
412 | { | 761 | { |
413 | if (mask != 0xffff) { | 762 | if (mask != 0xffff) { |
414 | u32 buf; | 763 | u32 buf; |
@@ -422,20 +771,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, | |||
422 | pci_write_config_dword(pdev, offset, value); | 771 | pci_write_config_dword(pdev, offset, value); |
423 | } | 772 | } |
424 | 773 | ||
425 | #endif /* CONFIG_PCI */ | 774 | #endif /* CONFIG_PCI */ |
426 | 775 | ||
427 | #ifdef CONFIG_EDAC_DEBUG | 776 | extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, |
428 | void edac_mc_dump_channel(struct channel_info *chan); | 777 | unsigned nr_chans, int edac_index); |
429 | void edac_mc_dump_mci(struct mem_ctl_info *mci); | 778 | extern int edac_mc_add_mc(struct mem_ctl_info *mci); |
430 | void edac_mc_dump_csrow(struct csrow_info *csrow); | 779 | extern void edac_mc_free(struct mem_ctl_info *mci); |
431 | #endif /* CONFIG_EDAC_DEBUG */ | 780 | extern struct mem_ctl_info *edac_mc_find(int idx); |
432 | 781 | extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); | |
433 | extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx); | ||
434 | extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev); | ||
435 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | 782 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, |
436 | unsigned long page); | 783 | unsigned long page); |
437 | extern void edac_mc_scrub_block(unsigned long page, unsigned long offset, | ||
438 | u32 size); | ||
439 | 784 | ||
440 | /* | 785 | /* |
441 | * The no info errors are used when error overflows are reported. | 786 | * The no info errors are used when error overflows are reported. |
@@ -448,34 +793,59 @@ extern void edac_mc_scrub_block(unsigned long page, unsigned long offset, | |||
448 | * statement clutter and extra function arguments. | 793 | * statement clutter and extra function arguments. |
449 | */ | 794 | */ |
450 | extern void edac_mc_handle_ce(struct mem_ctl_info *mci, | 795 | extern void edac_mc_handle_ce(struct mem_ctl_info *mci, |
451 | unsigned long page_frame_number, unsigned long offset_in_page, | 796 | unsigned long page_frame_number, |
452 | unsigned long syndrome, int row, int channel, | 797 | unsigned long offset_in_page, |
453 | const char *msg); | 798 | unsigned long syndrome, int row, int channel, |
799 | const char *msg); | ||
454 | extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, | 800 | extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, |
455 | const char *msg); | 801 | const char *msg); |
456 | extern void edac_mc_handle_ue(struct mem_ctl_info *mci, | 802 | extern void edac_mc_handle_ue(struct mem_ctl_info *mci, |
457 | unsigned long page_frame_number, unsigned long offset_in_page, | 803 | unsigned long page_frame_number, |
458 | int row, const char *msg); | 804 | unsigned long offset_in_page, int row, |
805 | const char *msg); | ||
459 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, | 806 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, |
460 | const char *msg); | 807 | const char *msg); |
461 | extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | 808 | extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow, |
462 | unsigned int csrow, | 809 | unsigned int channel0, unsigned int channel1, |
463 | unsigned int channel0, | 810 | char *msg); |
464 | unsigned int channel1, | 811 | extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow, |
465 | char *msg); | 812 | unsigned int channel, char *msg); |
466 | extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | ||
467 | unsigned int csrow, | ||
468 | unsigned int channel, | ||
469 | char *msg); | ||
470 | 813 | ||
471 | /* | 814 | /* |
472 | * This kmalloc's and initializes all the structures. | 815 | * edac_device APIs |
473 | * Can't be used if all structures don't have the same lifetime. | ||
474 | */ | 816 | */ |
475 | extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | 817 | extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev); |
476 | unsigned nr_chans); | 818 | extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev); |
819 | extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, | ||
820 | int inst_nr, int block_nr, const char *msg); | ||
821 | extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, | ||
822 | int inst_nr, int block_nr, const char *msg); | ||
477 | 823 | ||
478 | /* Free an mc previously allocated by edac_mc_alloc() */ | 824 | /* |
479 | extern void edac_mc_free(struct mem_ctl_info *mci); | 825 | * edac_pci APIs |
826 | */ | ||
827 | extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, | ||
828 | const char *edac_pci_name); | ||
829 | |||
830 | extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); | ||
831 | |||
832 | extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, | ||
833 | unsigned long value); | ||
834 | |||
835 | extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); | ||
836 | extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); | ||
837 | |||
838 | extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl( | ||
839 | struct device *dev, | ||
840 | const char *mod_name); | ||
841 | |||
842 | extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci); | ||
843 | extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci); | ||
844 | extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci); | ||
845 | |||
846 | /* | ||
847 | * edac misc APIs | ||
848 | */ | ||
849 | extern char *edac_op_state_to_string(int op_state); | ||
480 | 850 | ||
481 | #endif /* _EDAC_MC_H_ */ | 851 | #endif /* _EDAC_CORE_H_ */ |
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c new file mode 100644 index 000000000000..f3690a697cf9 --- /dev/null +++ b/drivers/edac/edac_device.c | |||
@@ -0,0 +1,746 @@ | |||
1 | |||
2 | /* | ||
3 | * edac_device.c | ||
4 | * (C) 2007 www.douglaskthompson.com | ||
5 | * | ||
6 | * This file may be distributed under the terms of the | ||
7 | * GNU General Public License. | ||
8 | * | ||
9 | * Written by Doug Thompson <norsk5@xmission.com> | ||
10 | * | ||
11 | * edac_device API implementation | ||
12 | * 19 Jan 2007 | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/smp.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/sysctl.h> | ||
20 | #include <linux/highmem.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/sysdev.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/page.h> | ||
31 | |||
32 | #include "edac_core.h" | ||
33 | #include "edac_module.h" | ||
34 | |||
35 | /* lock for the list: 'edac_device_list', manipulation of this list | ||
36 | * is protected by the 'device_ctls_mutex' lock | ||
37 | */ | ||
38 | static DEFINE_MUTEX(device_ctls_mutex); | ||
39 | static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list); | ||
40 | |||
41 | #ifdef CONFIG_EDAC_DEBUG | ||
42 | static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) | ||
43 | { | ||
44 | debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx); | ||
45 | debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check); | ||
46 | debugf3("\tdev = %p\n", edac_dev->dev); | ||
47 | debugf3("\tmod_name:ctl_name = %s:%s\n", | ||
48 | edac_dev->mod_name, edac_dev->ctl_name); | ||
49 | debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info); | ||
50 | } | ||
51 | #endif /* CONFIG_EDAC_DEBUG */ | ||
52 | |||
53 | |||
54 | /* | ||
55 | * edac_device_alloc_ctl_info() | ||
56 | * Allocate a new edac device control info structure | ||
57 | * | ||
58 | * The control structure is allocated in complete chunk | ||
59 | * from the OS. It is in turn sub allocated to the | ||
60 | * various objects that compose the struture | ||
61 | * | ||
62 | * The structure has a 'nr_instance' array within itself. | ||
63 | * Each instance represents a major component | ||
64 | * Example: L1 cache and L2 cache are 2 instance components | ||
65 | * | ||
66 | * Within each instance is an array of 'nr_blocks' blockoffsets | ||
67 | */ | ||
68 | struct edac_device_ctl_info *edac_device_alloc_ctl_info( | ||
69 | unsigned sz_private, | ||
70 | char *edac_device_name, unsigned nr_instances, | ||
71 | char *edac_block_name, unsigned nr_blocks, | ||
72 | unsigned offset_value, /* zero, 1, or other based offset */ | ||
73 | struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib, | ||
74 | int device_index) | ||
75 | { | ||
76 | struct edac_device_ctl_info *dev_ctl; | ||
77 | struct edac_device_instance *dev_inst, *inst; | ||
78 | struct edac_device_block *dev_blk, *blk_p, *blk; | ||
79 | struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib; | ||
80 | unsigned total_size; | ||
81 | unsigned count; | ||
82 | unsigned instance, block, attr; | ||
83 | void *pvt; | ||
84 | int err; | ||
85 | |||
86 | debugf4("%s() instances=%d blocks=%d\n", | ||
87 | __func__, nr_instances, nr_blocks); | ||
88 | |||
89 | /* Calculate the size of memory we need to allocate AND | ||
90 | * determine the offsets of the various item arrays | ||
91 | * (instance,block,attrib) from the start of an allocated structure. | ||
92 | * We want the alignment of each item (instance,block,attrib) | ||
93 | * to be at least as stringent as what the compiler would | ||
94 | * provide if we could simply hardcode everything into a single struct. | ||
95 | */ | ||
96 | dev_ctl = (struct edac_device_ctl_info *)NULL; | ||
97 | |||
98 | /* Calc the 'end' offset past end of ONE ctl_info structure | ||
99 | * which will become the start of the 'instance' array | ||
100 | */ | ||
101 | dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst)); | ||
102 | |||
103 | /* Calc the 'end' offset past the instance array within the ctl_info | ||
104 | * which will become the start of the block array | ||
105 | */ | ||
106 | dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk)); | ||
107 | |||
108 | /* Calc the 'end' offset past the dev_blk array | ||
109 | * which will become the start of the attrib array, if any. | ||
110 | */ | ||
111 | count = nr_instances * nr_blocks; | ||
112 | dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib)); | ||
113 | |||
114 | /* Check for case of when an attribute array is specified */ | ||
115 | if (nr_attrib > 0) { | ||
116 | /* calc how many nr_attrib we need */ | ||
117 | count *= nr_attrib; | ||
118 | |||
119 | /* Calc the 'end' offset past the attributes array */ | ||
120 | pvt = edac_align_ptr(&dev_attrib[count], sz_private); | ||
121 | } else { | ||
122 | /* no attribute array specificed */ | ||
123 | pvt = edac_align_ptr(dev_attrib, sz_private); | ||
124 | } | ||
125 | |||
126 | /* 'pvt' now points to where the private data area is. | ||
127 | * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib) | ||
128 | * is baselined at ZERO | ||
129 | */ | ||
130 | total_size = ((unsigned long)pvt) + sz_private; | ||
131 | |||
132 | /* Allocate the amount of memory for the set of control structures */ | ||
133 | dev_ctl = kzalloc(total_size, GFP_KERNEL); | ||
134 | if (dev_ctl == NULL) | ||
135 | return NULL; | ||
136 | |||
137 | /* Adjust pointers so they point within the actual memory we | ||
138 | * just allocated rather than an imaginary chunk of memory | ||
139 | * located at address 0. | ||
140 | * 'dev_ctl' points to REAL memory, while the others are | ||
141 | * ZERO based and thus need to be adjusted to point within | ||
142 | * the allocated memory. | ||
143 | */ | ||
144 | dev_inst = (struct edac_device_instance *) | ||
145 | (((char *)dev_ctl) + ((unsigned long)dev_inst)); | ||
146 | dev_blk = (struct edac_device_block *) | ||
147 | (((char *)dev_ctl) + ((unsigned long)dev_blk)); | ||
148 | dev_attrib = (struct edac_dev_sysfs_block_attribute *) | ||
149 | (((char *)dev_ctl) + ((unsigned long)dev_attrib)); | ||
150 | pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL; | ||
151 | |||
152 | /* Begin storing the information into the control info structure */ | ||
153 | dev_ctl->dev_idx = device_index; | ||
154 | dev_ctl->nr_instances = nr_instances; | ||
155 | dev_ctl->instances = dev_inst; | ||
156 | dev_ctl->pvt_info = pvt; | ||
157 | |||
158 | /* Name of this edac device */ | ||
159 | snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name); | ||
160 | |||
161 | debugf4("%s() edac_dev=%p next after end=%p\n", | ||
162 | __func__, dev_ctl, pvt + sz_private ); | ||
163 | |||
164 | /* Initialize every Instance */ | ||
165 | for (instance = 0; instance < nr_instances; instance++) { | ||
166 | inst = &dev_inst[instance]; | ||
167 | inst->ctl = dev_ctl; | ||
168 | inst->nr_blocks = nr_blocks; | ||
169 | blk_p = &dev_blk[instance * nr_blocks]; | ||
170 | inst->blocks = blk_p; | ||
171 | |||
172 | /* name of this instance */ | ||
173 | snprintf(inst->name, sizeof(inst->name), | ||
174 | "%s%u", edac_device_name, instance); | ||
175 | |||
176 | /* Initialize every block in each instance */ | ||
177 | for (block = 0; block < nr_blocks; block++) { | ||
178 | blk = &blk_p[block]; | ||
179 | blk->instance = inst; | ||
180 | snprintf(blk->name, sizeof(blk->name), | ||
181 | "%s%d", edac_block_name, block+offset_value); | ||
182 | |||
183 | debugf4("%s() instance=%d inst_p=%p block=#%d " | ||
184 | "block_p=%p name='%s'\n", | ||
185 | __func__, instance, inst, block, | ||
186 | blk, blk->name); | ||
187 | |||
188 | /* if there are NO attributes OR no attribute pointer | ||
189 | * then continue on to next block iteration | ||
190 | */ | ||
191 | if ((nr_attrib == 0) || (attrib_spec == NULL)) | ||
192 | continue; | ||
193 | |||
194 | /* setup the attribute array for this block */ | ||
195 | blk->nr_attribs = nr_attrib; | ||
196 | attrib_p = &dev_attrib[block*nr_instances*nr_attrib]; | ||
197 | blk->block_attributes = attrib_p; | ||
198 | |||
199 | debugf4("%s() THIS BLOCK_ATTRIB=%p\n", | ||
200 | __func__, blk->block_attributes); | ||
201 | |||
202 | /* Initialize every user specified attribute in this | ||
203 | * block with the data the caller passed in | ||
204 | * Each block gets its own copy of pointers, | ||
205 | * and its unique 'value' | ||
206 | */ | ||
207 | for (attr = 0; attr < nr_attrib; attr++) { | ||
208 | attrib = &attrib_p[attr]; | ||
209 | |||
210 | /* populate the unique per attrib | ||
211 | * with the code pointers and info | ||
212 | */ | ||
213 | attrib->attr = attrib_spec[attr].attr; | ||
214 | attrib->show = attrib_spec[attr].show; | ||
215 | attrib->store = attrib_spec[attr].store; | ||
216 | |||
217 | attrib->block = blk; /* up link */ | ||
218 | |||
219 | debugf4("%s() alloc-attrib=%p attrib_name='%s' " | ||
220 | "attrib-spec=%p spec-name=%s\n", | ||
221 | __func__, attrib, attrib->attr.name, | ||
222 | &attrib_spec[attr], | ||
223 | attrib_spec[attr].attr.name | ||
224 | ); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /* Mark this instance as merely ALLOCATED */ | ||
230 | dev_ctl->op_state = OP_ALLOC; | ||
231 | |||
232 | /* | ||
233 | * Initialize the 'root' kobj for the edac_device controller | ||
234 | */ | ||
235 | err = edac_device_register_sysfs_main_kobj(dev_ctl); | ||
236 | if (err) { | ||
237 | kfree(dev_ctl); | ||
238 | return NULL; | ||
239 | } | ||
240 | |||
241 | /* at this point, the root kobj is valid, and in order to | ||
242 | * 'free' the object, then the function: | ||
243 | * edac_device_unregister_sysfs_main_kobj() must be called | ||
244 | * which will perform kobj unregistration and the actual free | ||
245 | * will occur during the kobject callback operation | ||
246 | */ | ||
247 | |||
248 | return dev_ctl; | ||
249 | } | ||
250 | EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); | ||
251 | |||
252 | /* | ||
253 | * edac_device_free_ctl_info() | ||
254 | * frees the memory allocated by the edac_device_alloc_ctl_info() | ||
255 | * function | ||
256 | */ | ||
257 | void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) | ||
258 | { | ||
259 | edac_device_unregister_sysfs_main_kobj(ctl_info); | ||
260 | } | ||
261 | EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); | ||
262 | |||
263 | /* | ||
264 | * find_edac_device_by_dev | ||
265 | * scans the edac_device list for a specific 'struct device *' | ||
266 | * | ||
267 | * lock to be held prior to call: device_ctls_mutex | ||
268 | * | ||
269 | * Return: | ||
270 | * pointer to control structure managing 'dev' | ||
271 | * NULL if not found on list | ||
272 | */ | ||
273 | static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev) | ||
274 | { | ||
275 | struct edac_device_ctl_info *edac_dev; | ||
276 | struct list_head *item; | ||
277 | |||
278 | debugf0("%s()\n", __func__); | ||
279 | |||
280 | list_for_each(item, &edac_device_list) { | ||
281 | edac_dev = list_entry(item, struct edac_device_ctl_info, link); | ||
282 | |||
283 | if (edac_dev->dev == dev) | ||
284 | return edac_dev; | ||
285 | } | ||
286 | |||
287 | return NULL; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * add_edac_dev_to_global_list | ||
292 | * Before calling this function, caller must | ||
293 | * assign a unique value to edac_dev->dev_idx. | ||
294 | * | ||
295 | * lock to be held prior to call: device_ctls_mutex | ||
296 | * | ||
297 | * Return: | ||
298 | * 0 on success | ||
299 | * 1 on failure. | ||
300 | */ | ||
301 | static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev) | ||
302 | { | ||
303 | struct list_head *item, *insert_before; | ||
304 | struct edac_device_ctl_info *rover; | ||
305 | |||
306 | insert_before = &edac_device_list; | ||
307 | |||
308 | /* Determine if already on the list */ | ||
309 | rover = find_edac_device_by_dev(edac_dev->dev); | ||
310 | if (unlikely(rover != NULL)) | ||
311 | goto fail0; | ||
312 | |||
313 | /* Insert in ascending order by 'dev_idx', so find position */ | ||
314 | list_for_each(item, &edac_device_list) { | ||
315 | rover = list_entry(item, struct edac_device_ctl_info, link); | ||
316 | |||
317 | if (rover->dev_idx >= edac_dev->dev_idx) { | ||
318 | if (unlikely(rover->dev_idx == edac_dev->dev_idx)) | ||
319 | goto fail1; | ||
320 | |||
321 | insert_before = item; | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | list_add_tail_rcu(&edac_dev->link, insert_before); | ||
327 | return 0; | ||
328 | |||
329 | fail0: | ||
330 | edac_printk(KERN_WARNING, EDAC_MC, | ||
331 | "%s (%s) %s %s already assigned %d\n", | ||
332 | rover->dev->bus_id, dev_name(rover), | ||
333 | rover->mod_name, rover->ctl_name, rover->dev_idx); | ||
334 | return 1; | ||
335 | |||
336 | fail1: | ||
337 | edac_printk(KERN_WARNING, EDAC_MC, | ||
338 | "bug in low-level driver: attempt to assign\n" | ||
339 | " duplicate dev_idx %d in %s()\n", rover->dev_idx, | ||
340 | __func__); | ||
341 | return 1; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * complete_edac_device_list_del | ||
346 | * | ||
347 | * callback function when reference count is zero | ||
348 | */ | ||
349 | static void complete_edac_device_list_del(struct rcu_head *head) | ||
350 | { | ||
351 | struct edac_device_ctl_info *edac_dev; | ||
352 | |||
353 | edac_dev = container_of(head, struct edac_device_ctl_info, rcu); | ||
354 | INIT_LIST_HEAD(&edac_dev->link); | ||
355 | complete(&edac_dev->removal_complete); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * del_edac_device_from_global_list | ||
360 | * | ||
361 | * remove the RCU, setup for a callback call, | ||
362 | * then wait for the callback to occur | ||
363 | */ | ||
364 | static void del_edac_device_from_global_list(struct edac_device_ctl_info | ||
365 | *edac_device) | ||
366 | { | ||
367 | list_del_rcu(&edac_device->link); | ||
368 | |||
369 | init_completion(&edac_device->removal_complete); | ||
370 | call_rcu(&edac_device->rcu, complete_edac_device_list_del); | ||
371 | wait_for_completion(&edac_device->removal_complete); | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * edac_device_find | ||
376 | * Search for a edac_device_ctl_info structure whose index is 'idx'. | ||
377 | * | ||
378 | * If found, return a pointer to the structure. | ||
379 | * Else return NULL. | ||
380 | * | ||
381 | * Caller must hold device_ctls_mutex. | ||
382 | */ | ||
383 | struct edac_device_ctl_info *edac_device_find(int idx) | ||
384 | { | ||
385 | struct list_head *item; | ||
386 | struct edac_device_ctl_info *edac_dev; | ||
387 | |||
388 | /* Iterate over list, looking for exact match of ID */ | ||
389 | list_for_each(item, &edac_device_list) { | ||
390 | edac_dev = list_entry(item, struct edac_device_ctl_info, link); | ||
391 | |||
392 | if (edac_dev->dev_idx >= idx) { | ||
393 | if (edac_dev->dev_idx == idx) | ||
394 | return edac_dev; | ||
395 | |||
396 | /* not on list, so terminate early */ | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return NULL; | ||
402 | } | ||
403 | EXPORT_SYMBOL_GPL(edac_device_find); | ||
404 | |||
405 | /* | ||
406 | * edac_device_workq_function | ||
407 | * performs the operation scheduled by a workq request | ||
408 | * | ||
409 | * this workq is embedded within an edac_device_ctl_info | ||
410 | * structure, that needs to be polled for possible error events. | ||
411 | * | ||
412 | * This operation is to acquire the list mutex lock | ||
413 | * (thus preventing insertation or deletion) | ||
414 | * and then call the device's poll function IFF this device is | ||
415 | * running polled and there is a poll function defined. | ||
416 | */ | ||
417 | static void edac_device_workq_function(struct work_struct *work_req) | ||
418 | { | ||
419 | struct delayed_work *d_work = (struct delayed_work *)work_req; | ||
420 | struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work); | ||
421 | |||
422 | mutex_lock(&device_ctls_mutex); | ||
423 | |||
424 | /* Only poll controllers that are running polled and have a check */ | ||
425 | if ((edac_dev->op_state == OP_RUNNING_POLL) && | ||
426 | (edac_dev->edac_check != NULL)) { | ||
427 | edac_dev->edac_check(edac_dev); | ||
428 | } | ||
429 | |||
430 | mutex_unlock(&device_ctls_mutex); | ||
431 | |||
432 | /* Reschedule the workq for the next time period to start again | ||
433 | * if the number of msec is for 1 sec, then adjust to the next | ||
434 | * whole one second to save timers fireing all over the period | ||
435 | * between integral seconds | ||
436 | */ | ||
437 | if (edac_dev->poll_msec == 1000) | ||
438 | queue_delayed_work(edac_workqueue, &edac_dev->work, | ||
439 | round_jiffies(edac_dev->delay)); | ||
440 | else | ||
441 | queue_delayed_work(edac_workqueue, &edac_dev->work, | ||
442 | edac_dev->delay); | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * edac_device_workq_setup | ||
447 | * initialize a workq item for this edac_device instance | ||
448 | * passing in the new delay period in msec | ||
449 | */ | ||
450 | void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | ||
451 | unsigned msec) | ||
452 | { | ||
453 | debugf0("%s()\n", __func__); | ||
454 | |||
455 | /* take the arg 'msec' and set it into the control structure | ||
456 | * to used in the time period calculation | ||
457 | * then calc the number of jiffies that represents | ||
458 | */ | ||
459 | edac_dev->poll_msec = msec; | ||
460 | edac_dev->delay = msecs_to_jiffies(msec); | ||
461 | |||
462 | INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function); | ||
463 | |||
464 | /* optimize here for the 1 second case, which will be normal value, to | ||
465 | * fire ON the 1 second time event. This helps reduce all sorts of | ||
466 | * timers firing on sub-second basis, while they are happy | ||
467 | * to fire together on the 1 second exactly | ||
468 | */ | ||
469 | if (edac_dev->poll_msec == 1000) | ||
470 | queue_delayed_work(edac_workqueue, &edac_dev->work, | ||
471 | round_jiffies(edac_dev->delay)); | ||
472 | else | ||
473 | queue_delayed_work(edac_workqueue, &edac_dev->work, | ||
474 | edac_dev->delay); | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * edac_device_workq_teardown | ||
479 | * stop the workq processing on this edac_dev | ||
480 | */ | ||
481 | void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) | ||
482 | { | ||
483 | int status; | ||
484 | |||
485 | status = cancel_delayed_work(&edac_dev->work); | ||
486 | if (status == 0) { | ||
487 | /* workq instance might be running, wait for it */ | ||
488 | flush_workqueue(edac_workqueue); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * edac_device_reset_delay_period | ||
494 | * | ||
495 | * need to stop any outstanding workq queued up at this time | ||
496 | * because we will be resetting the sleep time. | ||
497 | * Then restart the workq on the new delay | ||
498 | */ | ||
499 | void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, | ||
500 | unsigned long value) | ||
501 | { | ||
502 | /* cancel the current workq request, without the mutex lock */ | ||
503 | edac_device_workq_teardown(edac_dev); | ||
504 | |||
505 | /* acquire the mutex before doing the workq setup */ | ||
506 | mutex_lock(&device_ctls_mutex); | ||
507 | |||
508 | /* restart the workq request, with new delay value */ | ||
509 | edac_device_workq_setup(edac_dev, value); | ||
510 | |||
511 | mutex_unlock(&device_ctls_mutex); | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * edac_device_add_device: Insert the 'edac_dev' structure into the | ||
516 | * edac_device global list and create sysfs entries associated with | ||
517 | * edac_device structure. | ||
518 | * @edac_device: pointer to the edac_device structure to be added to the list | ||
519 | * 'edac_device' structure. | ||
520 | * | ||
521 | * Return: | ||
522 | * 0 Success | ||
523 | * !0 Failure | ||
524 | */ | ||
525 | int edac_device_add_device(struct edac_device_ctl_info *edac_dev) | ||
526 | { | ||
527 | debugf0("%s()\n", __func__); | ||
528 | |||
529 | #ifdef CONFIG_EDAC_DEBUG | ||
530 | if (edac_debug_level >= 3) | ||
531 | edac_device_dump_device(edac_dev); | ||
532 | #endif | ||
533 | mutex_lock(&device_ctls_mutex); | ||
534 | |||
535 | if (add_edac_dev_to_global_list(edac_dev)) | ||
536 | goto fail0; | ||
537 | |||
538 | /* set load time so that error rate can be tracked */ | ||
539 | edac_dev->start_time = jiffies; | ||
540 | |||
541 | /* create this instance's sysfs entries */ | ||
542 | if (edac_device_create_sysfs(edac_dev)) { | ||
543 | edac_device_printk(edac_dev, KERN_WARNING, | ||
544 | "failed to create sysfs device\n"); | ||
545 | goto fail1; | ||
546 | } | ||
547 | |||
548 | /* If there IS a check routine, then we are running POLLED */ | ||
549 | if (edac_dev->edac_check != NULL) { | ||
550 | /* This instance is NOW RUNNING */ | ||
551 | edac_dev->op_state = OP_RUNNING_POLL; | ||
552 | |||
553 | /* | ||
554 | * enable workq processing on this instance, | ||
555 | * default = 1000 msec | ||
556 | */ | ||
557 | edac_device_workq_setup(edac_dev, 1000); | ||
558 | } else { | ||
559 | edac_dev->op_state = OP_RUNNING_INTERRUPT; | ||
560 | } | ||
561 | |||
562 | /* Report action taken */ | ||
563 | edac_device_printk(edac_dev, KERN_INFO, | ||
564 | "Giving out device to module '%s' controller " | ||
565 | "'%s': DEV '%s' (%s)\n", | ||
566 | edac_dev->mod_name, | ||
567 | edac_dev->ctl_name, | ||
568 | dev_name(edac_dev), | ||
569 | edac_op_state_to_string(edac_dev->op_state)); | ||
570 | |||
571 | mutex_unlock(&device_ctls_mutex); | ||
572 | return 0; | ||
573 | |||
574 | fail1: | ||
575 | /* Some error, so remove the entry from the lsit */ | ||
576 | del_edac_device_from_global_list(edac_dev); | ||
577 | |||
578 | fail0: | ||
579 | mutex_unlock(&device_ctls_mutex); | ||
580 | return 1; | ||
581 | } | ||
582 | EXPORT_SYMBOL_GPL(edac_device_add_device); | ||
583 | |||
584 | /** | ||
585 | * edac_device_del_device: | ||
586 | * Remove sysfs entries for specified edac_device structure and | ||
587 | * then remove edac_device structure from global list | ||
588 | * | ||
589 | * @pdev: | ||
590 | * Pointer to 'struct device' representing edac_device | ||
591 | * structure to remove. | ||
592 | * | ||
593 | * Return: | ||
594 | * Pointer to removed edac_device structure, | ||
595 | * OR NULL if device not found. | ||
596 | */ | ||
597 | struct edac_device_ctl_info *edac_device_del_device(struct device *dev) | ||
598 | { | ||
599 | struct edac_device_ctl_info *edac_dev; | ||
600 | |||
601 | debugf0("%s()\n", __func__); | ||
602 | |||
603 | mutex_lock(&device_ctls_mutex); | ||
604 | |||
605 | /* Find the structure on the list, if not there, then leave */ | ||
606 | edac_dev = find_edac_device_by_dev(dev); | ||
607 | if (edac_dev == NULL) { | ||
608 | mutex_unlock(&device_ctls_mutex); | ||
609 | return NULL; | ||
610 | } | ||
611 | |||
612 | /* mark this instance as OFFLINE */ | ||
613 | edac_dev->op_state = OP_OFFLINE; | ||
614 | |||
615 | /* clear workq processing on this instance */ | ||
616 | edac_device_workq_teardown(edac_dev); | ||
617 | |||
618 | /* deregister from global list */ | ||
619 | del_edac_device_from_global_list(edac_dev); | ||
620 | |||
621 | mutex_unlock(&device_ctls_mutex); | ||
622 | |||
623 | /* Tear down the sysfs entries for this instance */ | ||
624 | edac_device_remove_sysfs(edac_dev); | ||
625 | |||
626 | edac_printk(KERN_INFO, EDAC_MC, | ||
627 | "Removed device %d for %s %s: DEV %s\n", | ||
628 | edac_dev->dev_idx, | ||
629 | edac_dev->mod_name, edac_dev->ctl_name, dev_name(edac_dev)); | ||
630 | |||
631 | return edac_dev; | ||
632 | } | ||
633 | EXPORT_SYMBOL_GPL(edac_device_del_device); | ||
634 | |||
635 | static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev) | ||
636 | { | ||
637 | return edac_dev->log_ce; | ||
638 | } | ||
639 | |||
640 | static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev) | ||
641 | { | ||
642 | return edac_dev->log_ue; | ||
643 | } | ||
644 | |||
645 | static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info | ||
646 | *edac_dev) | ||
647 | { | ||
648 | return edac_dev->panic_on_ue; | ||
649 | } | ||
650 | |||
651 | /* | ||
652 | * edac_device_handle_ce | ||
653 | * perform a common output and handling of an 'edac_dev' CE event | ||
654 | */ | ||
655 | void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, | ||
656 | int inst_nr, int block_nr, const char *msg) | ||
657 | { | ||
658 | struct edac_device_instance *instance; | ||
659 | struct edac_device_block *block = NULL; | ||
660 | |||
661 | if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) { | ||
662 | edac_device_printk(edac_dev, KERN_ERR, | ||
663 | "INTERNAL ERROR: 'instance' out of range " | ||
664 | "(%d >= %d)\n", inst_nr, | ||
665 | edac_dev->nr_instances); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | instance = edac_dev->instances + inst_nr; | ||
670 | |||
671 | if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) { | ||
672 | edac_device_printk(edac_dev, KERN_ERR, | ||
673 | "INTERNAL ERROR: instance %d 'block' " | ||
674 | "out of range (%d >= %d)\n", | ||
675 | inst_nr, block_nr, | ||
676 | instance->nr_blocks); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | if (instance->nr_blocks > 0) { | ||
681 | block = instance->blocks + block_nr; | ||
682 | block->counters.ce_count++; | ||
683 | } | ||
684 | |||
685 | /* Propogate the count up the 'totals' tree */ | ||
686 | instance->counters.ce_count++; | ||
687 | edac_dev->counters.ce_count++; | ||
688 | |||
689 | if (edac_device_get_log_ce(edac_dev)) | ||
690 | edac_device_printk(edac_dev, KERN_WARNING, | ||
691 | "CE: %s instance: %s block: %s '%s'\n", | ||
692 | edac_dev->ctl_name, instance->name, | ||
693 | block ? block->name : "N/A", msg); | ||
694 | } | ||
695 | EXPORT_SYMBOL_GPL(edac_device_handle_ce); | ||
696 | |||
697 | /* | ||
698 | * edac_device_handle_ue | ||
699 | * perform a common output and handling of an 'edac_dev' UE event | ||
700 | */ | ||
701 | void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, | ||
702 | int inst_nr, int block_nr, const char *msg) | ||
703 | { | ||
704 | struct edac_device_instance *instance; | ||
705 | struct edac_device_block *block = NULL; | ||
706 | |||
707 | if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) { | ||
708 | edac_device_printk(edac_dev, KERN_ERR, | ||
709 | "INTERNAL ERROR: 'instance' out of range " | ||
710 | "(%d >= %d)\n", inst_nr, | ||
711 | edac_dev->nr_instances); | ||
712 | return; | ||
713 | } | ||
714 | |||
715 | instance = edac_dev->instances + inst_nr; | ||
716 | |||
717 | if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) { | ||
718 | edac_device_printk(edac_dev, KERN_ERR, | ||
719 | "INTERNAL ERROR: instance %d 'block' " | ||
720 | "out of range (%d >= %d)\n", | ||
721 | inst_nr, block_nr, | ||
722 | instance->nr_blocks); | ||
723 | return; | ||
724 | } | ||
725 | |||
726 | if (instance->nr_blocks > 0) { | ||
727 | block = instance->blocks + block_nr; | ||
728 | block->counters.ue_count++; | ||
729 | } | ||
730 | |||
731 | /* Propogate the count up the 'totals' tree */ | ||
732 | instance->counters.ue_count++; | ||
733 | edac_dev->counters.ue_count++; | ||
734 | |||
735 | if (edac_device_get_log_ue(edac_dev)) | ||
736 | edac_device_printk(edac_dev, KERN_EMERG, | ||
737 | "UE: %s instance: %s block: %s '%s'\n", | ||
738 | edac_dev->ctl_name, instance->name, | ||
739 | block ? block->name : "N/A", msg); | ||
740 | |||
741 | if (edac_device_get_panic_on_ue(edac_dev)) | ||
742 | panic("EDAC %s: UE instance: %s block %s '%s'\n", | ||
743 | edac_dev->ctl_name, instance->name, | ||
744 | block ? block->name : "N/A", msg); | ||
745 | } | ||
746 | EXPORT_SYMBOL_GPL(edac_device_handle_ue); | ||
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c new file mode 100644 index 000000000000..70b837f23c43 --- /dev/null +++ b/drivers/edac/edac_device_sysfs.c | |||
@@ -0,0 +1,896 @@ | |||
1 | /* | ||
2 | * file for managing the edac_device class of devices for EDAC | ||
3 | * | ||
4 | * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com) | ||
5 | * | ||
6 | * This file may be distributed under the terms of the | ||
7 | * GNU General Public License. | ||
8 | * | ||
9 | * Written Doug Thompson <norsk5@xmission.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/ctype.h> | ||
14 | #include <linux/module.h> | ||
15 | |||
16 | #include "edac_core.h" | ||
17 | #include "edac_module.h" | ||
18 | |||
19 | #define EDAC_DEVICE_SYMLINK "device" | ||
20 | |||
21 | #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj) | ||
22 | #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr) | ||
23 | |||
24 | |||
25 | /* | ||
26 | * Set of edac_device_ctl_info attribute store/show functions | ||
27 | */ | ||
28 | |||
29 | /* 'log_ue' */ | ||
30 | static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info | ||
31 | *ctl_info, char *data) | ||
32 | { | ||
33 | return sprintf(data, "%u\n", ctl_info->log_ue); | ||
34 | } | ||
35 | |||
36 | static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info | ||
37 | *ctl_info, const char *data, | ||
38 | size_t count) | ||
39 | { | ||
40 | /* if parameter is zero, turn off flag, if non-zero turn on flag */ | ||
41 | ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0); | ||
42 | |||
43 | return count; | ||
44 | } | ||
45 | |||
46 | /* 'log_ce' */ | ||
47 | static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info | ||
48 | *ctl_info, char *data) | ||
49 | { | ||
50 | return sprintf(data, "%u\n", ctl_info->log_ce); | ||
51 | } | ||
52 | |||
53 | static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info | ||
54 | *ctl_info, const char *data, | ||
55 | size_t count) | ||
56 | { | ||
57 | /* if parameter is zero, turn off flag, if non-zero turn on flag */ | ||
58 | ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0); | ||
59 | |||
60 | return count; | ||
61 | } | ||
62 | |||
63 | /* 'panic_on_ue' */ | ||
64 | static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info | ||
65 | *ctl_info, char *data) | ||
66 | { | ||
67 | return sprintf(data, "%u\n", ctl_info->panic_on_ue); | ||
68 | } | ||
69 | |||
70 | static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info | ||
71 | *ctl_info, const char *data, | ||
72 | size_t count) | ||
73 | { | ||
74 | /* if parameter is zero, turn off flag, if non-zero turn on flag */ | ||
75 | ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0); | ||
76 | |||
77 | return count; | ||
78 | } | ||
79 | |||
80 | /* 'poll_msec' show and store functions*/ | ||
81 | static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info | ||
82 | *ctl_info, char *data) | ||
83 | { | ||
84 | return sprintf(data, "%u\n", ctl_info->poll_msec); | ||
85 | } | ||
86 | |||
87 | static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info | ||
88 | *ctl_info, const char *data, | ||
89 | size_t count) | ||
90 | { | ||
91 | unsigned long value; | ||
92 | |||
93 | /* get the value and enforce that it is non-zero, must be at least | ||
94 | * one millisecond for the delay period, between scans | ||
95 | * Then cancel last outstanding delay for the work request | ||
96 | * and set a new one. | ||
97 | */ | ||
98 | value = simple_strtoul(data, NULL, 0); | ||
99 | edac_device_reset_delay_period(ctl_info, value); | ||
100 | |||
101 | return count; | ||
102 | } | ||
103 | |||
104 | /* edac_device_ctl_info specific attribute structure */ | ||
105 | struct ctl_info_attribute { | ||
106 | struct attribute attr; | ||
107 | ssize_t(*show) (struct edac_device_ctl_info *, char *); | ||
108 | ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t); | ||
109 | }; | ||
110 | |||
111 | #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj) | ||
112 | #define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr) | ||
113 | |||
114 | /* Function to 'show' fields from the edac_dev 'ctl_info' structure */ | ||
115 | static ssize_t edac_dev_ctl_info_show(struct kobject *kobj, | ||
116 | struct attribute *attr, char *buffer) | ||
117 | { | ||
118 | struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj); | ||
119 | struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr); | ||
120 | |||
121 | if (ctl_info_attr->show) | ||
122 | return ctl_info_attr->show(edac_dev, buffer); | ||
123 | return -EIO; | ||
124 | } | ||
125 | |||
126 | /* Function to 'store' fields into the edac_dev 'ctl_info' structure */ | ||
127 | static ssize_t edac_dev_ctl_info_store(struct kobject *kobj, | ||
128 | struct attribute *attr, | ||
129 | const char *buffer, size_t count) | ||
130 | { | ||
131 | struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj); | ||
132 | struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr); | ||
133 | |||
134 | if (ctl_info_attr->store) | ||
135 | return ctl_info_attr->store(edac_dev, buffer, count); | ||
136 | return -EIO; | ||
137 | } | ||
138 | |||
139 | /* edac_dev file operations for an 'ctl_info' */ | ||
140 | static struct sysfs_ops device_ctl_info_ops = { | ||
141 | .show = edac_dev_ctl_info_show, | ||
142 | .store = edac_dev_ctl_info_store | ||
143 | }; | ||
144 | |||
145 | #define CTL_INFO_ATTR(_name,_mode,_show,_store) \ | ||
146 | static struct ctl_info_attribute attr_ctl_info_##_name = { \ | ||
147 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
148 | .show = _show, \ | ||
149 | .store = _store, \ | ||
150 | }; | ||
151 | |||
152 | /* Declare the various ctl_info attributes here and their respective ops */ | ||
153 | CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR, | ||
154 | edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store); | ||
155 | CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR, | ||
156 | edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store); | ||
157 | CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR, | ||
158 | edac_device_ctl_panic_on_ue_show, | ||
159 | edac_device_ctl_panic_on_ue_store); | ||
160 | CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR, | ||
161 | edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store); | ||
162 | |||
163 | /* Base Attributes of the EDAC_DEVICE ECC object */ | ||
164 | static struct ctl_info_attribute *device_ctrl_attr[] = { | ||
165 | &attr_ctl_info_panic_on_ue, | ||
166 | &attr_ctl_info_log_ue, | ||
167 | &attr_ctl_info_log_ce, | ||
168 | &attr_ctl_info_poll_msec, | ||
169 | NULL, | ||
170 | }; | ||
171 | |||
172 | /* | ||
173 | * edac_device_ctrl_master_release | ||
174 | * | ||
175 | * called when the reference count for the 'main' kobj | ||
176 | * for a edac_device control struct reaches zero | ||
177 | * | ||
178 | * Reference count model: | ||
179 | * One 'main' kobject for each control structure allocated. | ||
180 | * That main kobj is initially set to one AND | ||
181 | * the reference count for the EDAC 'core' module is | ||
182 | * bumped by one, thus added 'keep in memory' dependency. | ||
183 | * | ||
184 | * Each new internal kobj (in instances and blocks) then | ||
185 | * bumps the 'main' kobject. | ||
186 | * | ||
187 | * When they are released their release functions decrement | ||
188 | * the 'main' kobj. | ||
189 | * | ||
190 | * When the main kobj reaches zero (0) then THIS function | ||
191 | * is called which then decrements the EDAC 'core' module. | ||
192 | * When the module reference count reaches zero then the | ||
193 | * module no longer has dependency on keeping the release | ||
194 | * function code in memory and module can be unloaded. | ||
195 | * | ||
196 | * This will support several control objects as well, each | ||
197 | * with its own 'main' kobj. | ||
198 | */ | ||
199 | static void edac_device_ctrl_master_release(struct kobject *kobj) | ||
200 | { | ||
201 | struct edac_device_ctl_info *edac_dev = to_edacdev(kobj); | ||
202 | |||
203 | debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx); | ||
204 | |||
205 | /* decrement the EDAC CORE module ref count */ | ||
206 | module_put(edac_dev->owner); | ||
207 | |||
208 | /* free the control struct containing the 'main' kobj | ||
209 | * passed in to this routine | ||
210 | */ | ||
211 | kfree(edac_dev); | ||
212 | } | ||
213 | |||
214 | /* ktype for the main (master) kobject */ | ||
215 | static struct kobj_type ktype_device_ctrl = { | ||
216 | .release = edac_device_ctrl_master_release, | ||
217 | .sysfs_ops = &device_ctl_info_ops, | ||
218 | .default_attrs = (struct attribute **)device_ctrl_attr, | ||
219 | }; | ||
220 | |||
221 | /* | ||
222 | * edac_device_register_sysfs_main_kobj | ||
223 | * | ||
224 | * perform the high level setup for the new edac_device instance | ||
225 | * | ||
226 | * Return: 0 SUCCESS | ||
227 | * !0 FAILURE | ||
228 | */ | ||
229 | int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) | ||
230 | { | ||
231 | struct sysdev_class *edac_class; | ||
232 | int err; | ||
233 | |||
234 | debugf1("%s()\n", __func__); | ||
235 | |||
236 | /* get the /sys/devices/system/edac reference */ | ||
237 | edac_class = edac_get_edac_class(); | ||
238 | if (edac_class == NULL) { | ||
239 | debugf1("%s() no edac_class error\n", __func__); | ||
240 | err = -ENODEV; | ||
241 | goto err_out; | ||
242 | } | ||
243 | |||
244 | /* Point to the 'edac_class' this instance 'reports' to */ | ||
245 | edac_dev->edac_class = edac_class; | ||
246 | |||
247 | /* Init the devices's kobject */ | ||
248 | memset(&edac_dev->kobj, 0, sizeof(struct kobject)); | ||
249 | edac_dev->kobj.ktype = &ktype_device_ctrl; | ||
250 | |||
251 | /* set this new device under the edac_class kobject */ | ||
252 | edac_dev->kobj.parent = &edac_class->kset.kobj; | ||
253 | |||
254 | /* generate sysfs "..../edac/<name>" */ | ||
255 | debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name); | ||
256 | err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); | ||
257 | if (err) | ||
258 | goto err_out; | ||
259 | |||
260 | /* Record which module 'owns' this control structure | ||
261 | * and bump the ref count of the module | ||
262 | */ | ||
263 | edac_dev->owner = THIS_MODULE; | ||
264 | |||
265 | if (!try_module_get(edac_dev->owner)) { | ||
266 | err = -ENODEV; | ||
267 | goto err_out; | ||
268 | } | ||
269 | |||
270 | /* register */ | ||
271 | err = kobject_register(&edac_dev->kobj); | ||
272 | if (err) { | ||
273 | debugf1("%s()Failed to register '.../edac/%s'\n", | ||
274 | __func__, edac_dev->name); | ||
275 | goto err_kobj_reg; | ||
276 | } | ||
277 | |||
278 | /* At this point, to 'free' the control struct, | ||
279 | * edac_device_unregister_sysfs_main_kobj() must be used | ||
280 | */ | ||
281 | |||
282 | debugf4("%s() Registered '.../edac/%s' kobject\n", | ||
283 | __func__, edac_dev->name); | ||
284 | |||
285 | return 0; | ||
286 | |||
287 | /* Error exit stack */ | ||
288 | err_kobj_reg: | ||
289 | module_put(edac_dev->owner); | ||
290 | |||
291 | err_out: | ||
292 | return err; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * edac_device_unregister_sysfs_main_kobj: | ||
297 | * the '..../edac/<name>' kobject | ||
298 | */ | ||
299 | void edac_device_unregister_sysfs_main_kobj( | ||
300 | struct edac_device_ctl_info *edac_dev) | ||
301 | { | ||
302 | debugf0("%s()\n", __func__); | ||
303 | debugf4("%s() name of kobject is: %s\n", | ||
304 | __func__, kobject_name(&edac_dev->kobj)); | ||
305 | |||
306 | /* | ||
307 | * Unregister the edac device's kobject and | ||
308 | * allow for reference count to reach 0 at which point | ||
309 | * the callback will be called to: | ||
310 | * a) module_put() this module | ||
311 | * b) 'kfree' the memory | ||
312 | */ | ||
313 | kobject_unregister(&edac_dev->kobj); | ||
314 | } | ||
315 | |||
316 | /* edac_dev -> instance information */ | ||
317 | |||
318 | /* | ||
319 | * Set of low-level instance attribute show functions | ||
320 | */ | ||
321 | static ssize_t instance_ue_count_show(struct edac_device_instance *instance, | ||
322 | char *data) | ||
323 | { | ||
324 | return sprintf(data, "%u\n", instance->counters.ue_count); | ||
325 | } | ||
326 | |||
327 | static ssize_t instance_ce_count_show(struct edac_device_instance *instance, | ||
328 | char *data) | ||
329 | { | ||
330 | return sprintf(data, "%u\n", instance->counters.ce_count); | ||
331 | } | ||
332 | |||
333 | #define to_instance(k) container_of(k, struct edac_device_instance, kobj) | ||
334 | #define to_instance_attr(a) container_of(a,struct instance_attribute,attr) | ||
335 | |||
336 | /* DEVICE instance kobject release() function */ | ||
337 | static void edac_device_ctrl_instance_release(struct kobject *kobj) | ||
338 | { | ||
339 | struct edac_device_instance *instance; | ||
340 | |||
341 | debugf1("%s()\n", __func__); | ||
342 | |||
343 | /* map from this kobj to the main control struct | ||
344 | * and then dec the main kobj count | ||
345 | */ | ||
346 | instance = to_instance(kobj); | ||
347 | kobject_put(&instance->ctl->kobj); | ||
348 | } | ||
349 | |||
350 | /* instance specific attribute structure */ | ||
351 | struct instance_attribute { | ||
352 | struct attribute attr; | ||
353 | ssize_t(*show) (struct edac_device_instance *, char *); | ||
354 | ssize_t(*store) (struct edac_device_instance *, const char *, size_t); | ||
355 | }; | ||
356 | |||
357 | /* Function to 'show' fields from the edac_dev 'instance' structure */ | ||
358 | static ssize_t edac_dev_instance_show(struct kobject *kobj, | ||
359 | struct attribute *attr, char *buffer) | ||
360 | { | ||
361 | struct edac_device_instance *instance = to_instance(kobj); | ||
362 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
363 | |||
364 | if (instance_attr->show) | ||
365 | return instance_attr->show(instance, buffer); | ||
366 | return -EIO; | ||
367 | } | ||
368 | |||
369 | /* Function to 'store' fields into the edac_dev 'instance' structure */ | ||
370 | static ssize_t edac_dev_instance_store(struct kobject *kobj, | ||
371 | struct attribute *attr, | ||
372 | const char *buffer, size_t count) | ||
373 | { | ||
374 | struct edac_device_instance *instance = to_instance(kobj); | ||
375 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
376 | |||
377 | if (instance_attr->store) | ||
378 | return instance_attr->store(instance, buffer, count); | ||
379 | return -EIO; | ||
380 | } | ||
381 | |||
382 | /* edac_dev file operations for an 'instance' */ | ||
383 | static struct sysfs_ops device_instance_ops = { | ||
384 | .show = edac_dev_instance_show, | ||
385 | .store = edac_dev_instance_store | ||
386 | }; | ||
387 | |||
388 | #define INSTANCE_ATTR(_name,_mode,_show,_store) \ | ||
389 | static struct instance_attribute attr_instance_##_name = { \ | ||
390 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
391 | .show = _show, \ | ||
392 | .store = _store, \ | ||
393 | }; | ||
394 | |||
395 | /* | ||
396 | * Define attributes visible for the edac_device instance object | ||
397 | * Each contains a pointer to a show and an optional set | ||
398 | * function pointer that does the low level output/input | ||
399 | */ | ||
400 | INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL); | ||
401 | INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL); | ||
402 | |||
403 | /* list of edac_dev 'instance' attributes */ | ||
404 | static struct instance_attribute *device_instance_attr[] = { | ||
405 | &attr_instance_ce_count, | ||
406 | &attr_instance_ue_count, | ||
407 | NULL, | ||
408 | }; | ||
409 | |||
410 | /* The 'ktype' for each edac_dev 'instance' */ | ||
411 | static struct kobj_type ktype_instance_ctrl = { | ||
412 | .release = edac_device_ctrl_instance_release, | ||
413 | .sysfs_ops = &device_instance_ops, | ||
414 | .default_attrs = (struct attribute **)device_instance_attr, | ||
415 | }; | ||
416 | |||
417 | /* edac_dev -> instance -> block information */ | ||
418 | |||
419 | #define to_block(k) container_of(k, struct edac_device_block, kobj) | ||
420 | #define to_block_attr(a) \ | ||
421 | container_of(a, struct edac_dev_sysfs_block_attribute, attr) | ||
422 | |||
423 | /* | ||
424 | * Set of low-level block attribute show functions | ||
425 | */ | ||
426 | static ssize_t block_ue_count_show(struct kobject *kobj, | ||
427 | struct attribute *attr, char *data) | ||
428 | { | ||
429 | struct edac_device_block *block = to_block(kobj); | ||
430 | |||
431 | return sprintf(data, "%u\n", block->counters.ue_count); | ||
432 | } | ||
433 | |||
434 | static ssize_t block_ce_count_show(struct kobject *kobj, | ||
435 | struct attribute *attr, char *data) | ||
436 | { | ||
437 | struct edac_device_block *block = to_block(kobj); | ||
438 | |||
439 | return sprintf(data, "%u\n", block->counters.ce_count); | ||
440 | } | ||
441 | |||
442 | /* DEVICE block kobject release() function */ | ||
443 | static void edac_device_ctrl_block_release(struct kobject *kobj) | ||
444 | { | ||
445 | struct edac_device_block *block; | ||
446 | |||
447 | debugf1("%s()\n", __func__); | ||
448 | |||
449 | /* get the container of the kobj */ | ||
450 | block = to_block(kobj); | ||
451 | |||
452 | /* map from 'block kobj' to 'block->instance->controller->main_kobj' | ||
453 | * now 'release' the block kobject | ||
454 | */ | ||
455 | kobject_put(&block->instance->ctl->kobj); | ||
456 | } | ||
457 | |||
458 | |||
459 | /* Function to 'show' fields from the edac_dev 'block' structure */ | ||
460 | static ssize_t edac_dev_block_show(struct kobject *kobj, | ||
461 | struct attribute *attr, char *buffer) | ||
462 | { | ||
463 | struct edac_dev_sysfs_block_attribute *block_attr = | ||
464 | to_block_attr(attr); | ||
465 | |||
466 | if (block_attr->show) | ||
467 | return block_attr->show(kobj, attr, buffer); | ||
468 | return -EIO; | ||
469 | } | ||
470 | |||
471 | /* Function to 'store' fields into the edac_dev 'block' structure */ | ||
472 | static ssize_t edac_dev_block_store(struct kobject *kobj, | ||
473 | struct attribute *attr, | ||
474 | const char *buffer, size_t count) | ||
475 | { | ||
476 | struct edac_dev_sysfs_block_attribute *block_attr; | ||
477 | |||
478 | block_attr = to_block_attr(attr); | ||
479 | |||
480 | if (block_attr->store) | ||
481 | return block_attr->store(kobj, attr, buffer, count); | ||
482 | return -EIO; | ||
483 | } | ||
484 | |||
485 | /* edac_dev file operations for a 'block' */ | ||
486 | static struct sysfs_ops device_block_ops = { | ||
487 | .show = edac_dev_block_show, | ||
488 | .store = edac_dev_block_store | ||
489 | }; | ||
490 | |||
491 | #define BLOCK_ATTR(_name,_mode,_show,_store) \ | ||
492 | static struct edac_dev_sysfs_block_attribute attr_block_##_name = { \ | ||
493 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
494 | .show = _show, \ | ||
495 | .store = _store, \ | ||
496 | }; | ||
497 | |||
498 | BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL); | ||
499 | BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL); | ||
500 | |||
501 | /* list of edac_dev 'block' attributes */ | ||
502 | static struct edac_dev_sysfs_block_attribute *device_block_attr[] = { | ||
503 | &attr_block_ce_count, | ||
504 | &attr_block_ue_count, | ||
505 | NULL, | ||
506 | }; | ||
507 | |||
508 | /* The 'ktype' for each edac_dev 'block' */ | ||
509 | static struct kobj_type ktype_block_ctrl = { | ||
510 | .release = edac_device_ctrl_block_release, | ||
511 | .sysfs_ops = &device_block_ops, | ||
512 | .default_attrs = (struct attribute **)device_block_attr, | ||
513 | }; | ||
514 | |||
515 | /* block ctor/dtor code */ | ||
516 | |||
517 | /* | ||
518 | * edac_device_create_block | ||
519 | */ | ||
520 | static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, | ||
521 | struct edac_device_instance *instance, | ||
522 | struct edac_device_block *block) | ||
523 | { | ||
524 | int i; | ||
525 | int err; | ||
526 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; | ||
527 | struct kobject *main_kobj; | ||
528 | |||
529 | debugf4("%s() Instance '%s' inst_p=%p block '%s' block_p=%p\n", | ||
530 | __func__, instance->name, instance, block->name, block); | ||
531 | debugf4("%s() block kobj=%p block kobj->parent=%p\n", | ||
532 | __func__, &block->kobj, &block->kobj.parent); | ||
533 | |||
534 | /* init this block's kobject */ | ||
535 | memset(&block->kobj, 0, sizeof(struct kobject)); | ||
536 | block->kobj.parent = &instance->kobj; | ||
537 | block->kobj.ktype = &ktype_block_ctrl; | ||
538 | |||
539 | err = kobject_set_name(&block->kobj, "%s", block->name); | ||
540 | if (err) | ||
541 | return err; | ||
542 | |||
543 | /* bump the main kobject's reference count for this controller | ||
544 | * and this instance is dependant on the main | ||
545 | */ | ||
546 | main_kobj = kobject_get(&edac_dev->kobj); | ||
547 | if (!main_kobj) { | ||
548 | err = -ENODEV; | ||
549 | goto err_out; | ||
550 | } | ||
551 | |||
552 | /* Add this block's kobject */ | ||
553 | err = kobject_register(&block->kobj); | ||
554 | if (err) { | ||
555 | debugf1("%s() Failed to register instance '%s'\n", | ||
556 | __func__, block->name); | ||
557 | kobject_put(main_kobj); | ||
558 | err = -ENODEV; | ||
559 | goto err_out; | ||
560 | } | ||
561 | |||
562 | /* If there are driver level block attributes, then added them | ||
563 | * to the block kobject | ||
564 | */ | ||
565 | sysfs_attrib = block->block_attributes; | ||
566 | if (sysfs_attrib && block->nr_attribs) { | ||
567 | for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) { | ||
568 | |||
569 | debugf4("%s() creating block attrib='%s' " | ||
570 | "attrib->%p to kobj=%p\n", | ||
571 | __func__, | ||
572 | sysfs_attrib->attr.name, | ||
573 | sysfs_attrib, &block->kobj); | ||
574 | |||
575 | /* Create each block_attribute file */ | ||
576 | err = sysfs_create_file(&block->kobj, | ||
577 | &sysfs_attrib->attr); | ||
578 | if (err) | ||
579 | goto err_on_attrib; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | return 0; | ||
584 | |||
585 | /* Error unwind stack */ | ||
586 | err_on_attrib: | ||
587 | kobject_unregister(&block->kobj); | ||
588 | |||
589 | err_out: | ||
590 | return err; | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * edac_device_delete_block(edac_dev,block); | ||
595 | */ | ||
596 | static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, | ||
597 | struct edac_device_block *block) | ||
598 | { | ||
599 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; | ||
600 | int i; | ||
601 | |||
602 | /* if this block has 'attributes' then we need to iterate over the list | ||
603 | * and 'remove' the attributes on this block | ||
604 | */ | ||
605 | sysfs_attrib = block->block_attributes; | ||
606 | if (sysfs_attrib && block->nr_attribs) { | ||
607 | for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) { | ||
608 | |||
609 | /* remove each block_attrib file */ | ||
610 | sysfs_remove_file(&block->kobj, | ||
611 | (struct attribute *) sysfs_attrib); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | /* unregister this block's kobject, SEE: | ||
616 | * edac_device_ctrl_block_release() callback operation | ||
617 | */ | ||
618 | kobject_unregister(&block->kobj); | ||
619 | } | ||
620 | |||
621 | /* instance ctor/dtor code */ | ||
622 | |||
623 | /* | ||
624 | * edac_device_create_instance | ||
625 | * create just one instance of an edac_device 'instance' | ||
626 | */ | ||
627 | static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | ||
628 | int idx) | ||
629 | { | ||
630 | int i, j; | ||
631 | int err; | ||
632 | struct edac_device_instance *instance; | ||
633 | struct kobject *main_kobj; | ||
634 | |||
635 | instance = &edac_dev->instances[idx]; | ||
636 | |||
637 | /* Init the instance's kobject */ | ||
638 | memset(&instance->kobj, 0, sizeof(struct kobject)); | ||
639 | |||
640 | /* set this new device under the edac_device main kobject */ | ||
641 | instance->kobj.parent = &edac_dev->kobj; | ||
642 | instance->kobj.ktype = &ktype_instance_ctrl; | ||
643 | instance->ctl = edac_dev; | ||
644 | |||
645 | err = kobject_set_name(&instance->kobj, "%s", instance->name); | ||
646 | if (err) | ||
647 | goto err_out; | ||
648 | |||
649 | /* bump the main kobject's reference count for this controller | ||
650 | * and this instance is dependant on the main | ||
651 | */ | ||
652 | main_kobj = kobject_get(&edac_dev->kobj); | ||
653 | if (!main_kobj) { | ||
654 | err = -ENODEV; | ||
655 | goto err_out; | ||
656 | } | ||
657 | |||
658 | /* Formally register this instance's kobject */ | ||
659 | err = kobject_register(&instance->kobj); | ||
660 | if (err != 0) { | ||
661 | debugf2("%s() Failed to register instance '%s'\n", | ||
662 | __func__, instance->name); | ||
663 | kobject_put(main_kobj); | ||
664 | goto err_out; | ||
665 | } | ||
666 | |||
667 | debugf4("%s() now register '%d' blocks for instance %d\n", | ||
668 | __func__, instance->nr_blocks, idx); | ||
669 | |||
670 | /* register all blocks of this instance */ | ||
671 | for (i = 0; i < instance->nr_blocks; i++) { | ||
672 | err = edac_device_create_block(edac_dev, instance, | ||
673 | &instance->blocks[i]); | ||
674 | if (err) { | ||
675 | /* If any fail, remove all previous ones */ | ||
676 | for (j = 0; j < i; j++) | ||
677 | edac_device_delete_block(edac_dev, | ||
678 | &instance->blocks[j]); | ||
679 | goto err_release_instance_kobj; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | debugf4("%s() Registered instance %d '%s' kobject\n", | ||
684 | __func__, idx, instance->name); | ||
685 | |||
686 | return 0; | ||
687 | |||
688 | /* error unwind stack */ | ||
689 | err_release_instance_kobj: | ||
690 | kobject_unregister(&instance->kobj); | ||
691 | |||
692 | err_out: | ||
693 | return err; | ||
694 | } | ||
695 | |||
696 | /* | ||
697 | * edac_device_remove_instance | ||
698 | * remove an edac_device instance | ||
699 | */ | ||
700 | static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, | ||
701 | int idx) | ||
702 | { | ||
703 | struct edac_device_instance *instance; | ||
704 | int i; | ||
705 | |||
706 | instance = &edac_dev->instances[idx]; | ||
707 | |||
708 | /* unregister all blocks in this instance */ | ||
709 | for (i = 0; i < instance->nr_blocks; i++) | ||
710 | edac_device_delete_block(edac_dev, &instance->blocks[i]); | ||
711 | |||
712 | /* unregister this instance's kobject, SEE: | ||
713 | * edac_device_ctrl_instance_release() for callback operation | ||
714 | */ | ||
715 | kobject_unregister(&instance->kobj); | ||
716 | } | ||
717 | |||
718 | /* | ||
719 | * edac_device_create_instances | ||
720 | * create the first level of 'instances' for this device | ||
721 | * (ie 'cache' might have 'cache0', 'cache1', 'cache2', etc | ||
722 | */ | ||
723 | static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev) | ||
724 | { | ||
725 | int i, j; | ||
726 | int err; | ||
727 | |||
728 | debugf0("%s()\n", __func__); | ||
729 | |||
730 | /* iterate over creation of the instances */ | ||
731 | for (i = 0; i < edac_dev->nr_instances; i++) { | ||
732 | err = edac_device_create_instance(edac_dev, i); | ||
733 | if (err) { | ||
734 | /* unwind previous instances on error */ | ||
735 | for (j = 0; j < i; j++) | ||
736 | edac_device_delete_instance(edac_dev, j); | ||
737 | return err; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * edac_device_delete_instances(edac_dev); | ||
746 | * unregister all the kobjects of the instances | ||
747 | */ | ||
748 | static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev) | ||
749 | { | ||
750 | int i; | ||
751 | |||
752 | /* iterate over creation of the instances */ | ||
753 | for (i = 0; i < edac_dev->nr_instances; i++) | ||
754 | edac_device_delete_instance(edac_dev, i); | ||
755 | } | ||
756 | |||
757 | /* edac_dev sysfs ctor/dtor code */ | ||
758 | |||
759 | /* | ||
760 | * edac_device_add_main_sysfs_attributes | ||
761 | * add some attributes to this instance's main kobject | ||
762 | */ | ||
763 | static int edac_device_add_main_sysfs_attributes( | ||
764 | struct edac_device_ctl_info *edac_dev) | ||
765 | { | ||
766 | struct edac_dev_sysfs_attribute *sysfs_attrib; | ||
767 | int err = 0; | ||
768 | |||
769 | sysfs_attrib = edac_dev->sysfs_attributes; | ||
770 | if (sysfs_attrib) { | ||
771 | /* iterate over the array and create an attribute for each | ||
772 | * entry in the list | ||
773 | */ | ||
774 | while (sysfs_attrib->attr.name != NULL) { | ||
775 | err = sysfs_create_file(&edac_dev->kobj, | ||
776 | (struct attribute*) sysfs_attrib); | ||
777 | if (err) | ||
778 | goto err_out; | ||
779 | |||
780 | sysfs_attrib++; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | err_out: | ||
785 | return err; | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * edac_device_remove_main_sysfs_attributes | ||
790 | * remove any attributes to this instance's main kobject | ||
791 | */ | ||
792 | static void edac_device_remove_main_sysfs_attributes( | ||
793 | struct edac_device_ctl_info *edac_dev) | ||
794 | { | ||
795 | struct edac_dev_sysfs_attribute *sysfs_attrib; | ||
796 | |||
797 | /* if there are main attributes, defined, remove them. First, | ||
798 | * point to the start of the array and iterate over it | ||
799 | * removing each attribute listed from this device's instance's kobject | ||
800 | */ | ||
801 | sysfs_attrib = edac_dev->sysfs_attributes; | ||
802 | if (sysfs_attrib) { | ||
803 | while (sysfs_attrib->attr.name != NULL) { | ||
804 | sysfs_remove_file(&edac_dev->kobj, | ||
805 | (struct attribute *) sysfs_attrib); | ||
806 | sysfs_attrib++; | ||
807 | } | ||
808 | } | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * edac_device_create_sysfs() Constructor | ||
813 | * | ||
814 | * accept a created edac_device control structure | ||
815 | * and 'export' it to sysfs. The 'main' kobj should already have been | ||
816 | * created. 'instance' and 'block' kobjects should be registered | ||
817 | * along with any 'block' attributes from the low driver. In addition, | ||
818 | * the main attributes (if any) are connected to the main kobject of | ||
819 | * the control structure. | ||
820 | * | ||
821 | * Return: | ||
822 | * 0 Success | ||
823 | * !0 Failure | ||
824 | */ | ||
825 | int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | ||
826 | { | ||
827 | int err; | ||
828 | struct kobject *edac_kobj = &edac_dev->kobj; | ||
829 | |||
830 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); | ||
831 | |||
832 | /* go create any main attributes callers wants */ | ||
833 | err = edac_device_add_main_sysfs_attributes(edac_dev); | ||
834 | if (err) { | ||
835 | debugf0("%s() failed to add sysfs attribs\n", __func__); | ||
836 | goto err_out; | ||
837 | } | ||
838 | |||
839 | /* create a symlink from the edac device | ||
840 | * to the platform 'device' being used for this | ||
841 | */ | ||
842 | err = sysfs_create_link(edac_kobj, | ||
843 | &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK); | ||
844 | if (err) { | ||
845 | debugf0("%s() sysfs_create_link() returned err= %d\n", | ||
846 | __func__, err); | ||
847 | goto err_remove_main_attribs; | ||
848 | } | ||
849 | |||
850 | /* Create the first level instance directories | ||
851 | * In turn, the nested blocks beneath the instances will | ||
852 | * be registered as well | ||
853 | */ | ||
854 | err = edac_device_create_instances(edac_dev); | ||
855 | if (err) { | ||
856 | debugf0("%s() edac_device_create_instances() " | ||
857 | "returned err= %d\n", __func__, err); | ||
858 | goto err_remove_link; | ||
859 | } | ||
860 | |||
861 | |||
862 | debugf4("%s() create-instances done, idx=%d\n", | ||
863 | __func__, edac_dev->dev_idx); | ||
864 | |||
865 | return 0; | ||
866 | |||
867 | /* Error unwind stack */ | ||
868 | err_remove_link: | ||
869 | /* remove the sym link */ | ||
870 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | ||
871 | |||
872 | err_remove_main_attribs: | ||
873 | edac_device_remove_main_sysfs_attributes(edac_dev); | ||
874 | |||
875 | err_out: | ||
876 | return err; | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * edac_device_remove_sysfs() destructor | ||
881 | * | ||
882 | * given an edac_device struct, tear down the kobject resources | ||
883 | */ | ||
884 | void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev) | ||
885 | { | ||
886 | debugf0("%s()\n", __func__); | ||
887 | |||
888 | /* remove any main attributes for this device */ | ||
889 | edac_device_remove_main_sysfs_attributes(edac_dev); | ||
890 | |||
891 | /* remove the device sym link */ | ||
892 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | ||
893 | |||
894 | /* walk the instance/block kobject tree, deconstructing it */ | ||
895 | edac_device_delete_instances(edac_dev); | ||
896 | } | ||
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 804875de5801..4471be362599 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -27,1200 +27,20 @@ | |||
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/sysdev.h> | 28 | #include <linux/sysdev.h> |
29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/kthread.h> | 30 | #include <linux/edac.h> |
31 | #include <linux/freezer.h> | ||
32 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
33 | #include <asm/page.h> | 32 | #include <asm/page.h> |
34 | #include <asm/edac.h> | 33 | #include <asm/edac.h> |
35 | #include "edac_mc.h" | 34 | #include "edac_core.h" |
36 | 35 | #include "edac_module.h" | |
37 | #define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__ | ||
38 | |||
39 | |||
40 | #ifdef CONFIG_EDAC_DEBUG | ||
41 | /* Values of 0 to 4 will generate output */ | ||
42 | int edac_debug_level = 1; | ||
43 | EXPORT_SYMBOL_GPL(edac_debug_level); | ||
44 | #endif | ||
45 | |||
46 | /* EDAC Controls, setable by module parameter, and sysfs */ | ||
47 | static int log_ue = 1; | ||
48 | static int log_ce = 1; | ||
49 | static int panic_on_ue; | ||
50 | static int poll_msec = 1000; | ||
51 | 36 | ||
52 | /* lock to memory controller's control array */ | 37 | /* lock to memory controller's control array */ |
53 | static DECLARE_MUTEX(mem_ctls_mutex); | 38 | static DEFINE_MUTEX(mem_ctls_mutex); |
54 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); | 39 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); |
55 | 40 | ||
56 | static struct task_struct *edac_thread; | ||
57 | |||
58 | #ifdef CONFIG_PCI | ||
59 | static int check_pci_parity = 0; /* default YES check PCI parity */ | ||
60 | static int panic_on_pci_parity; /* default no panic on PCI Parity */ | ||
61 | static atomic_t pci_parity_count = ATOMIC_INIT(0); | ||
62 | |||
63 | static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ | ||
64 | static struct completion edac_pci_kobj_complete; | ||
65 | #endif /* CONFIG_PCI */ | ||
66 | |||
67 | /* START sysfs data and methods */ | ||
68 | |||
69 | |||
70 | static const char *mem_types[] = { | ||
71 | [MEM_EMPTY] = "Empty", | ||
72 | [MEM_RESERVED] = "Reserved", | ||
73 | [MEM_UNKNOWN] = "Unknown", | ||
74 | [MEM_FPM] = "FPM", | ||
75 | [MEM_EDO] = "EDO", | ||
76 | [MEM_BEDO] = "BEDO", | ||
77 | [MEM_SDR] = "Unbuffered-SDR", | ||
78 | [MEM_RDR] = "Registered-SDR", | ||
79 | [MEM_DDR] = "Unbuffered-DDR", | ||
80 | [MEM_RDDR] = "Registered-DDR", | ||
81 | [MEM_RMBS] = "RMBS" | ||
82 | }; | ||
83 | |||
84 | static const char *dev_types[] = { | ||
85 | [DEV_UNKNOWN] = "Unknown", | ||
86 | [DEV_X1] = "x1", | ||
87 | [DEV_X2] = "x2", | ||
88 | [DEV_X4] = "x4", | ||
89 | [DEV_X8] = "x8", | ||
90 | [DEV_X16] = "x16", | ||
91 | [DEV_X32] = "x32", | ||
92 | [DEV_X64] = "x64" | ||
93 | }; | ||
94 | |||
95 | static const char *edac_caps[] = { | ||
96 | [EDAC_UNKNOWN] = "Unknown", | ||
97 | [EDAC_NONE] = "None", | ||
98 | [EDAC_RESERVED] = "Reserved", | ||
99 | [EDAC_PARITY] = "PARITY", | ||
100 | [EDAC_EC] = "EC", | ||
101 | [EDAC_SECDED] = "SECDED", | ||
102 | [EDAC_S2ECD2ED] = "S2ECD2ED", | ||
103 | [EDAC_S4ECD4ED] = "S4ECD4ED", | ||
104 | [EDAC_S8ECD8ED] = "S8ECD8ED", | ||
105 | [EDAC_S16ECD16ED] = "S16ECD16ED" | ||
106 | }; | ||
107 | |||
108 | /* sysfs object: /sys/devices/system/edac */ | ||
109 | static struct sysdev_class edac_class = { | ||
110 | set_kset_name("edac"), | ||
111 | }; | ||
112 | |||
113 | /* sysfs object: | ||
114 | * /sys/devices/system/edac/mc | ||
115 | */ | ||
116 | static struct kobject edac_memctrl_kobj; | ||
117 | |||
118 | /* We use these to wait for the reference counts on edac_memctrl_kobj and | ||
119 | * edac_pci_kobj to reach 0. | ||
120 | */ | ||
121 | static struct completion edac_memctrl_kobj_complete; | ||
122 | |||
123 | /* | ||
124 | * /sys/devices/system/edac/mc; | ||
125 | * data structures and methods | ||
126 | */ | ||
127 | static ssize_t memctrl_int_show(void *ptr, char *buffer) | ||
128 | { | ||
129 | int *value = (int*) ptr; | ||
130 | return sprintf(buffer, "%u\n", *value); | ||
131 | } | ||
132 | |||
133 | static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) | ||
134 | { | ||
135 | int *value = (int*) ptr; | ||
136 | |||
137 | if (isdigit(*buffer)) | ||
138 | *value = simple_strtoul(buffer, NULL, 0); | ||
139 | |||
140 | return count; | ||
141 | } | ||
142 | |||
143 | struct memctrl_dev_attribute { | ||
144 | struct attribute attr; | ||
145 | void *value; | ||
146 | ssize_t (*show)(void *,char *); | ||
147 | ssize_t (*store)(void *, const char *, size_t); | ||
148 | }; | ||
149 | |||
150 | /* Set of show/store abstract level functions for memory control object */ | ||
151 | static ssize_t memctrl_dev_show(struct kobject *kobj, | ||
152 | struct attribute *attr, char *buffer) | ||
153 | { | ||
154 | struct memctrl_dev_attribute *memctrl_dev; | ||
155 | memctrl_dev = (struct memctrl_dev_attribute*)attr; | ||
156 | |||
157 | if (memctrl_dev->show) | ||
158 | return memctrl_dev->show(memctrl_dev->value, buffer); | ||
159 | |||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, | ||
164 | const char *buffer, size_t count) | ||
165 | { | ||
166 | struct memctrl_dev_attribute *memctrl_dev; | ||
167 | memctrl_dev = (struct memctrl_dev_attribute*)attr; | ||
168 | |||
169 | if (memctrl_dev->store) | ||
170 | return memctrl_dev->store(memctrl_dev->value, buffer, count); | ||
171 | |||
172 | return -EIO; | ||
173 | } | ||
174 | |||
175 | static struct sysfs_ops memctrlfs_ops = { | ||
176 | .show = memctrl_dev_show, | ||
177 | .store = memctrl_dev_store | ||
178 | }; | ||
179 | |||
180 | #define MEMCTRL_ATTR(_name,_mode,_show,_store) \ | ||
181 | struct memctrl_dev_attribute attr_##_name = { \ | ||
182 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
183 | .value = &_name, \ | ||
184 | .show = _show, \ | ||
185 | .store = _store, \ | ||
186 | }; | ||
187 | |||
188 | #define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \ | ||
189 | struct memctrl_dev_attribute attr_##_name = { \ | ||
190 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
191 | .value = _data, \ | ||
192 | .show = _show, \ | ||
193 | .store = _store, \ | ||
194 | }; | ||
195 | |||
196 | /* csrow<id> control files */ | ||
197 | MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | ||
198 | MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | ||
199 | MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | ||
200 | MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | ||
201 | |||
202 | /* Base Attributes of the memory ECC object */ | ||
203 | static struct memctrl_dev_attribute *memctrl_attr[] = { | ||
204 | &attr_panic_on_ue, | ||
205 | &attr_log_ue, | ||
206 | &attr_log_ce, | ||
207 | &attr_poll_msec, | ||
208 | NULL, | ||
209 | }; | ||
210 | |||
211 | /* Main MC kobject release() function */ | ||
212 | static void edac_memctrl_master_release(struct kobject *kobj) | ||
213 | { | ||
214 | debugf1("%s()\n", __func__); | ||
215 | complete(&edac_memctrl_kobj_complete); | ||
216 | } | ||
217 | |||
218 | static struct kobj_type ktype_memctrl = { | ||
219 | .release = edac_memctrl_master_release, | ||
220 | .sysfs_ops = &memctrlfs_ops, | ||
221 | .default_attrs = (struct attribute **) memctrl_attr, | ||
222 | }; | ||
223 | |||
224 | /* Initialize the main sysfs entries for edac: | ||
225 | * /sys/devices/system/edac | ||
226 | * | ||
227 | * and children | ||
228 | * | ||
229 | * Return: 0 SUCCESS | ||
230 | * !0 FAILURE | ||
231 | */ | ||
232 | static int edac_sysfs_memctrl_setup(void) | ||
233 | { | ||
234 | int err = 0; | ||
235 | |||
236 | debugf1("%s()\n", __func__); | ||
237 | |||
238 | /* create the /sys/devices/system/edac directory */ | ||
239 | err = sysdev_class_register(&edac_class); | ||
240 | |||
241 | if (err) { | ||
242 | debugf1("%s() error=%d\n", __func__, err); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | /* Init the MC's kobject */ | ||
247 | memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); | ||
248 | edac_memctrl_kobj.parent = &edac_class.kset.kobj; | ||
249 | edac_memctrl_kobj.ktype = &ktype_memctrl; | ||
250 | |||
251 | /* generate sysfs "..../edac/mc" */ | ||
252 | err = kobject_set_name(&edac_memctrl_kobj,"mc"); | ||
253 | |||
254 | if (err) | ||
255 | goto fail; | ||
256 | |||
257 | /* FIXME: maybe new sysdev_create_subdir() */ | ||
258 | err = kobject_register(&edac_memctrl_kobj); | ||
259 | |||
260 | if (err) { | ||
261 | debugf1("Failed to register '.../edac/mc'\n"); | ||
262 | goto fail; | ||
263 | } | ||
264 | |||
265 | debugf1("Registered '.../edac/mc' kobject\n"); | ||
266 | |||
267 | return 0; | ||
268 | |||
269 | fail: | ||
270 | sysdev_class_unregister(&edac_class); | ||
271 | return err; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * MC teardown: | ||
276 | * the '..../edac/mc' kobject followed by '..../edac' itself | ||
277 | */ | ||
278 | static void edac_sysfs_memctrl_teardown(void) | ||
279 | { | ||
280 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
281 | |||
282 | /* Unregister the MC's kobject and wait for reference count to reach | ||
283 | * 0. | ||
284 | */ | ||
285 | init_completion(&edac_memctrl_kobj_complete); | ||
286 | kobject_unregister(&edac_memctrl_kobj); | ||
287 | wait_for_completion(&edac_memctrl_kobj_complete); | ||
288 | |||
289 | /* Unregister the 'edac' object */ | ||
290 | sysdev_class_unregister(&edac_class); | ||
291 | } | ||
292 | |||
293 | #ifdef CONFIG_PCI | ||
294 | static ssize_t edac_pci_int_show(void *ptr, char *buffer) | ||
295 | { | ||
296 | int *value = ptr; | ||
297 | return sprintf(buffer,"%d\n",*value); | ||
298 | } | ||
299 | |||
300 | static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count) | ||
301 | { | ||
302 | int *value = ptr; | ||
303 | |||
304 | if (isdigit(*buffer)) | ||
305 | *value = simple_strtoul(buffer,NULL,0); | ||
306 | |||
307 | return count; | ||
308 | } | ||
309 | |||
310 | struct edac_pci_dev_attribute { | ||
311 | struct attribute attr; | ||
312 | void *value; | ||
313 | ssize_t (*show)(void *,char *); | ||
314 | ssize_t (*store)(void *, const char *,size_t); | ||
315 | }; | ||
316 | |||
317 | /* Set of show/store abstract level functions for PCI Parity object */ | ||
318 | static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, | ||
319 | char *buffer) | ||
320 | { | ||
321 | struct edac_pci_dev_attribute *edac_pci_dev; | ||
322 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; | ||
323 | |||
324 | if (edac_pci_dev->show) | ||
325 | return edac_pci_dev->show(edac_pci_dev->value, buffer); | ||
326 | return -EIO; | ||
327 | } | ||
328 | |||
329 | static ssize_t edac_pci_dev_store(struct kobject *kobj, | ||
330 | struct attribute *attr, const char *buffer, size_t count) | ||
331 | { | ||
332 | struct edac_pci_dev_attribute *edac_pci_dev; | ||
333 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; | ||
334 | |||
335 | if (edac_pci_dev->show) | ||
336 | return edac_pci_dev->store(edac_pci_dev->value, buffer, count); | ||
337 | return -EIO; | ||
338 | } | ||
339 | |||
340 | static struct sysfs_ops edac_pci_sysfs_ops = { | ||
341 | .show = edac_pci_dev_show, | ||
342 | .store = edac_pci_dev_store | ||
343 | }; | ||
344 | |||
345 | #define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ | ||
346 | struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | ||
347 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
348 | .value = &_name, \ | ||
349 | .show = _show, \ | ||
350 | .store = _store, \ | ||
351 | }; | ||
352 | |||
353 | #define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \ | ||
354 | struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | ||
355 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
356 | .value = _data, \ | ||
357 | .show = _show, \ | ||
358 | .store = _store, \ | ||
359 | }; | ||
360 | |||
361 | /* PCI Parity control files */ | ||
362 | EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, | ||
363 | edac_pci_int_store); | ||
364 | EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, | ||
365 | edac_pci_int_store); | ||
366 | EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); | ||
367 | |||
368 | /* Base Attributes of the memory ECC object */ | ||
369 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { | ||
370 | &edac_pci_attr_check_pci_parity, | ||
371 | &edac_pci_attr_panic_on_pci_parity, | ||
372 | &edac_pci_attr_pci_parity_count, | ||
373 | NULL, | ||
374 | }; | ||
375 | |||
376 | /* No memory to release */ | ||
377 | static void edac_pci_release(struct kobject *kobj) | ||
378 | { | ||
379 | debugf1("%s()\n", __func__); | ||
380 | complete(&edac_pci_kobj_complete); | ||
381 | } | ||
382 | |||
383 | static struct kobj_type ktype_edac_pci = { | ||
384 | .release = edac_pci_release, | ||
385 | .sysfs_ops = &edac_pci_sysfs_ops, | ||
386 | .default_attrs = (struct attribute **) edac_pci_attr, | ||
387 | }; | ||
388 | |||
389 | /** | ||
390 | * edac_sysfs_pci_setup() | ||
391 | * | ||
392 | */ | ||
393 | static int edac_sysfs_pci_setup(void) | ||
394 | { | ||
395 | int err; | ||
396 | |||
397 | debugf1("%s()\n", __func__); | ||
398 | |||
399 | memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); | ||
400 | edac_pci_kobj.parent = &edac_class.kset.kobj; | ||
401 | edac_pci_kobj.ktype = &ktype_edac_pci; | ||
402 | err = kobject_set_name(&edac_pci_kobj, "pci"); | ||
403 | |||
404 | if (!err) { | ||
405 | /* Instanstiate the csrow object */ | ||
406 | /* FIXME: maybe new sysdev_create_subdir() */ | ||
407 | err = kobject_register(&edac_pci_kobj); | ||
408 | |||
409 | if (err) | ||
410 | debugf1("Failed to register '.../edac/pci'\n"); | ||
411 | else | ||
412 | debugf1("Registered '.../edac/pci' kobject\n"); | ||
413 | } | ||
414 | |||
415 | return err; | ||
416 | } | ||
417 | |||
418 | static void edac_sysfs_pci_teardown(void) | ||
419 | { | ||
420 | debugf0("%s()\n", __func__); | ||
421 | init_completion(&edac_pci_kobj_complete); | ||
422 | kobject_unregister(&edac_pci_kobj); | ||
423 | wait_for_completion(&edac_pci_kobj_complete); | ||
424 | } | ||
425 | |||
426 | |||
427 | static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) | ||
428 | { | ||
429 | int where; | ||
430 | u16 status; | ||
431 | |||
432 | where = secondary ? PCI_SEC_STATUS : PCI_STATUS; | ||
433 | pci_read_config_word(dev, where, &status); | ||
434 | |||
435 | /* If we get back 0xFFFF then we must suspect that the card has been | ||
436 | * pulled but the Linux PCI layer has not yet finished cleaning up. | ||
437 | * We don't want to report on such devices | ||
438 | */ | ||
439 | |||
440 | if (status == 0xFFFF) { | ||
441 | u32 sanity; | ||
442 | |||
443 | pci_read_config_dword(dev, 0, &sanity); | ||
444 | |||
445 | if (sanity == 0xFFFFFFFF) | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | | ||
450 | PCI_STATUS_PARITY; | ||
451 | |||
452 | if (status) | ||
453 | /* reset only the bits we are interested in */ | ||
454 | pci_write_config_word(dev, where, status); | ||
455 | |||
456 | return status; | ||
457 | } | ||
458 | |||
459 | typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); | ||
460 | |||
461 | /* Clear any PCI parity errors logged by this device. */ | ||
462 | static void edac_pci_dev_parity_clear(struct pci_dev *dev) | ||
463 | { | ||
464 | u8 header_type; | ||
465 | |||
466 | get_pci_parity_status(dev, 0); | ||
467 | |||
468 | /* read the device TYPE, looking for bridges */ | ||
469 | pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); | ||
470 | |||
471 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) | ||
472 | get_pci_parity_status(dev, 1); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * PCI Parity polling | ||
477 | * | ||
478 | */ | ||
479 | static void edac_pci_dev_parity_test(struct pci_dev *dev) | ||
480 | { | ||
481 | u16 status; | ||
482 | u8 header_type; | ||
483 | |||
484 | /* read the STATUS register on this device | ||
485 | */ | ||
486 | status = get_pci_parity_status(dev, 0); | ||
487 | |||
488 | debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id ); | ||
489 | |||
490 | /* check the status reg for errors */ | ||
491 | if (status) { | ||
492 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | ||
493 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
494 | "Signaled System Error on %s\n", | ||
495 | pci_name(dev)); | ||
496 | |||
497 | if (status & (PCI_STATUS_PARITY)) { | ||
498 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
499 | "Master Data Parity Error on %s\n", | ||
500 | pci_name(dev)); | ||
501 | |||
502 | atomic_inc(&pci_parity_count); | ||
503 | } | ||
504 | |||
505 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | ||
506 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
507 | "Detected Parity Error on %s\n", | ||
508 | pci_name(dev)); | ||
509 | |||
510 | atomic_inc(&pci_parity_count); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | /* read the device TYPE, looking for bridges */ | ||
515 | pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); | ||
516 | |||
517 | debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id ); | ||
518 | |||
519 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | ||
520 | /* On bridges, need to examine secondary status register */ | ||
521 | status = get_pci_parity_status(dev, 1); | ||
522 | |||
523 | debugf2("PCI SEC_STATUS= 0x%04x %s\n", | ||
524 | status, dev->dev.bus_id ); | ||
525 | |||
526 | /* check the secondary status reg for errors */ | ||
527 | if (status) { | ||
528 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | ||
529 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
530 | "Signaled System Error on %s\n", | ||
531 | pci_name(dev)); | ||
532 | |||
533 | if (status & (PCI_STATUS_PARITY)) { | ||
534 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
535 | "Master Data Parity Error on " | ||
536 | "%s\n", pci_name(dev)); | ||
537 | |||
538 | atomic_inc(&pci_parity_count); | ||
539 | } | ||
540 | |||
541 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | ||
542 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
543 | "Detected Parity Error on %s\n", | ||
544 | pci_name(dev)); | ||
545 | |||
546 | atomic_inc(&pci_parity_count); | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * pci_dev parity list iterator | ||
554 | * Scan the PCI device list for one iteration, looking for SERRORs | ||
555 | * Master Parity ERRORS or Parity ERRORs on primary or secondary devices | ||
556 | */ | ||
557 | static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) | ||
558 | { | ||
559 | struct pci_dev *dev = NULL; | ||
560 | |||
561 | /* request for kernel access to the next PCI device, if any, | ||
562 | * and while we are looking at it have its reference count | ||
563 | * bumped until we are done with it | ||
564 | */ | ||
565 | while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | ||
566 | fn(dev); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | static void do_pci_parity_check(void) | ||
571 | { | ||
572 | unsigned long flags; | ||
573 | int before_count; | ||
574 | |||
575 | debugf3("%s()\n", __func__); | ||
576 | |||
577 | if (!check_pci_parity) | ||
578 | return; | ||
579 | |||
580 | before_count = atomic_read(&pci_parity_count); | ||
581 | |||
582 | /* scan all PCI devices looking for a Parity Error on devices and | ||
583 | * bridges | ||
584 | */ | ||
585 | local_irq_save(flags); | ||
586 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); | ||
587 | local_irq_restore(flags); | ||
588 | |||
589 | /* Only if operator has selected panic on PCI Error */ | ||
590 | if (panic_on_pci_parity) { | ||
591 | /* If the count is different 'after' from 'before' */ | ||
592 | if (before_count != atomic_read(&pci_parity_count)) | ||
593 | panic("EDAC: PCI Parity Error"); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | static inline void clear_pci_parity_errors(void) | ||
598 | { | ||
599 | /* Clear any PCI bus parity errors that devices initially have logged | ||
600 | * in their registers. | ||
601 | */ | ||
602 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); | ||
603 | } | ||
604 | |||
605 | #else /* CONFIG_PCI */ | ||
606 | |||
607 | /* pre-process these away */ | ||
608 | #define do_pci_parity_check() | ||
609 | #define clear_pci_parity_errors() | ||
610 | #define edac_sysfs_pci_teardown() | ||
611 | #define edac_sysfs_pci_setup() (0) | ||
612 | |||
613 | #endif /* CONFIG_PCI */ | ||
614 | |||
615 | /* EDAC sysfs CSROW data structures and methods | ||
616 | */ | ||
617 | |||
618 | /* Set of more default csrow<id> attribute show/store functions */ | ||
619 | static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private) | ||
620 | { | ||
621 | return sprintf(data,"%u\n", csrow->ue_count); | ||
622 | } | ||
623 | |||
624 | static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private) | ||
625 | { | ||
626 | return sprintf(data,"%u\n", csrow->ce_count); | ||
627 | } | ||
628 | |||
629 | static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private) | ||
630 | { | ||
631 | return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); | ||
632 | } | ||
633 | |||
634 | static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private) | ||
635 | { | ||
636 | return sprintf(data,"%s\n", mem_types[csrow->mtype]); | ||
637 | } | ||
638 | |||
639 | static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private) | ||
640 | { | ||
641 | return sprintf(data,"%s\n", dev_types[csrow->dtype]); | ||
642 | } | ||
643 | |||
644 | static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private) | ||
645 | { | ||
646 | return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); | ||
647 | } | ||
648 | |||
649 | /* show/store functions for DIMM Label attributes */ | ||
650 | static ssize_t channel_dimm_label_show(struct csrow_info *csrow, | ||
651 | char *data, int channel) | ||
652 | { | ||
653 | return snprintf(data, EDAC_MC_LABEL_LEN,"%s", | ||
654 | csrow->channels[channel].label); | ||
655 | } | ||
656 | |||
657 | static ssize_t channel_dimm_label_store(struct csrow_info *csrow, | ||
658 | const char *data, | ||
659 | size_t count, | ||
660 | int channel) | ||
661 | { | ||
662 | ssize_t max_size = 0; | ||
663 | |||
664 | max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1); | ||
665 | strncpy(csrow->channels[channel].label, data, max_size); | ||
666 | csrow->channels[channel].label[max_size] = '\0'; | ||
667 | |||
668 | return max_size; | ||
669 | } | ||
670 | |||
671 | /* show function for dynamic chX_ce_count attribute */ | ||
672 | static ssize_t channel_ce_count_show(struct csrow_info *csrow, | ||
673 | char *data, | ||
674 | int channel) | ||
675 | { | ||
676 | return sprintf(data, "%u\n", csrow->channels[channel].ce_count); | ||
677 | } | ||
678 | |||
679 | /* csrow specific attribute structure */ | ||
680 | struct csrowdev_attribute { | ||
681 | struct attribute attr; | ||
682 | ssize_t (*show)(struct csrow_info *,char *,int); | ||
683 | ssize_t (*store)(struct csrow_info *, const char *,size_t,int); | ||
684 | int private; | ||
685 | }; | ||
686 | |||
687 | #define to_csrow(k) container_of(k, struct csrow_info, kobj) | ||
688 | #define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) | ||
689 | |||
690 | /* Set of show/store higher level functions for default csrow attributes */ | ||
691 | static ssize_t csrowdev_show(struct kobject *kobj, | ||
692 | struct attribute *attr, | ||
693 | char *buffer) | ||
694 | { | ||
695 | struct csrow_info *csrow = to_csrow(kobj); | ||
696 | struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); | ||
697 | |||
698 | if (csrowdev_attr->show) | ||
699 | return csrowdev_attr->show(csrow, | ||
700 | buffer, | ||
701 | csrowdev_attr->private); | ||
702 | return -EIO; | ||
703 | } | ||
704 | |||
705 | static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, | ||
706 | const char *buffer, size_t count) | ||
707 | { | ||
708 | struct csrow_info *csrow = to_csrow(kobj); | ||
709 | struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); | ||
710 | |||
711 | if (csrowdev_attr->store) | ||
712 | return csrowdev_attr->store(csrow, | ||
713 | buffer, | ||
714 | count, | ||
715 | csrowdev_attr->private); | ||
716 | return -EIO; | ||
717 | } | ||
718 | |||
719 | static struct sysfs_ops csrowfs_ops = { | ||
720 | .show = csrowdev_show, | ||
721 | .store = csrowdev_store | ||
722 | }; | ||
723 | |||
724 | #define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \ | ||
725 | struct csrowdev_attribute attr_##_name = { \ | ||
726 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
727 | .show = _show, \ | ||
728 | .store = _store, \ | ||
729 | .private = _private, \ | ||
730 | }; | ||
731 | |||
732 | /* default cwrow<id>/attribute files */ | ||
733 | CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0); | ||
734 | CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0); | ||
735 | CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0); | ||
736 | CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0); | ||
737 | CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0); | ||
738 | CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0); | ||
739 | |||
740 | /* default attributes of the CSROW<id> object */ | ||
741 | static struct csrowdev_attribute *default_csrow_attr[] = { | ||
742 | &attr_dev_type, | ||
743 | &attr_mem_type, | ||
744 | &attr_edac_mode, | ||
745 | &attr_size_mb, | ||
746 | &attr_ue_count, | ||
747 | &attr_ce_count, | ||
748 | NULL, | ||
749 | }; | ||
750 | |||
751 | |||
752 | /* possible dynamic channel DIMM Label attribute files */ | ||
753 | CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR, | ||
754 | channel_dimm_label_show, | ||
755 | channel_dimm_label_store, | ||
756 | 0 ); | ||
757 | CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR, | ||
758 | channel_dimm_label_show, | ||
759 | channel_dimm_label_store, | ||
760 | 1 ); | ||
761 | CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR, | ||
762 | channel_dimm_label_show, | ||
763 | channel_dimm_label_store, | ||
764 | 2 ); | ||
765 | CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR, | ||
766 | channel_dimm_label_show, | ||
767 | channel_dimm_label_store, | ||
768 | 3 ); | ||
769 | CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR, | ||
770 | channel_dimm_label_show, | ||
771 | channel_dimm_label_store, | ||
772 | 4 ); | ||
773 | CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR, | ||
774 | channel_dimm_label_show, | ||
775 | channel_dimm_label_store, | ||
776 | 5 ); | ||
777 | |||
778 | /* Total possible dynamic DIMM Label attribute file table */ | ||
779 | static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = { | ||
780 | &attr_ch0_dimm_label, | ||
781 | &attr_ch1_dimm_label, | ||
782 | &attr_ch2_dimm_label, | ||
783 | &attr_ch3_dimm_label, | ||
784 | &attr_ch4_dimm_label, | ||
785 | &attr_ch5_dimm_label | ||
786 | }; | ||
787 | |||
788 | /* possible dynamic channel ce_count attribute files */ | ||
789 | CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR, | ||
790 | channel_ce_count_show, | ||
791 | NULL, | ||
792 | 0 ); | ||
793 | CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR, | ||
794 | channel_ce_count_show, | ||
795 | NULL, | ||
796 | 1 ); | ||
797 | CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR, | ||
798 | channel_ce_count_show, | ||
799 | NULL, | ||
800 | 2 ); | ||
801 | CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR, | ||
802 | channel_ce_count_show, | ||
803 | NULL, | ||
804 | 3 ); | ||
805 | CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR, | ||
806 | channel_ce_count_show, | ||
807 | NULL, | ||
808 | 4 ); | ||
809 | CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR, | ||
810 | channel_ce_count_show, | ||
811 | NULL, | ||
812 | 5 ); | ||
813 | |||
814 | /* Total possible dynamic ce_count attribute file table */ | ||
815 | static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = { | ||
816 | &attr_ch0_ce_count, | ||
817 | &attr_ch1_ce_count, | ||
818 | &attr_ch2_ce_count, | ||
819 | &attr_ch3_ce_count, | ||
820 | &attr_ch4_ce_count, | ||
821 | &attr_ch5_ce_count | ||
822 | }; | ||
823 | |||
824 | |||
825 | #define EDAC_NR_CHANNELS 6 | ||
826 | |||
827 | /* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */ | ||
828 | static int edac_create_channel_files(struct kobject *kobj, int chan) | ||
829 | { | ||
830 | int err=-ENODEV; | ||
831 | |||
832 | if (chan >= EDAC_NR_CHANNELS) | ||
833 | return err; | ||
834 | |||
835 | /* create the DIMM label attribute file */ | ||
836 | err = sysfs_create_file(kobj, | ||
837 | (struct attribute *) dynamic_csrow_dimm_attr[chan]); | ||
838 | |||
839 | if (!err) { | ||
840 | /* create the CE Count attribute file */ | ||
841 | err = sysfs_create_file(kobj, | ||
842 | (struct attribute *) dynamic_csrow_ce_count_attr[chan]); | ||
843 | } else { | ||
844 | debugf1("%s() dimm labels and ce_count files created", __func__); | ||
845 | } | ||
846 | |||
847 | return err; | ||
848 | } | ||
849 | |||
850 | /* No memory to release for this kobj */ | ||
851 | static void edac_csrow_instance_release(struct kobject *kobj) | ||
852 | { | ||
853 | struct csrow_info *cs; | ||
854 | |||
855 | cs = container_of(kobj, struct csrow_info, kobj); | ||
856 | complete(&cs->kobj_complete); | ||
857 | } | ||
858 | |||
859 | /* the kobj_type instance for a CSROW */ | ||
860 | static struct kobj_type ktype_csrow = { | ||
861 | .release = edac_csrow_instance_release, | ||
862 | .sysfs_ops = &csrowfs_ops, | ||
863 | .default_attrs = (struct attribute **) default_csrow_attr, | ||
864 | }; | ||
865 | |||
866 | /* Create a CSROW object under specifed edac_mc_device */ | ||
867 | static int edac_create_csrow_object( | ||
868 | struct kobject *edac_mci_kobj, | ||
869 | struct csrow_info *csrow, | ||
870 | int index) | ||
871 | { | ||
872 | int err = 0; | ||
873 | int chan; | ||
874 | |||
875 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); | ||
876 | |||
877 | /* generate ..../edac/mc/mc<id>/csrow<index> */ | ||
878 | |||
879 | csrow->kobj.parent = edac_mci_kobj; | ||
880 | csrow->kobj.ktype = &ktype_csrow; | ||
881 | |||
882 | /* name this instance of csrow<id> */ | ||
883 | err = kobject_set_name(&csrow->kobj,"csrow%d",index); | ||
884 | if (err) | ||
885 | goto error_exit; | ||
886 | |||
887 | /* Instanstiate the csrow object */ | ||
888 | err = kobject_register(&csrow->kobj); | ||
889 | if (!err) { | ||
890 | /* Create the dyanmic attribute files on this csrow, | ||
891 | * namely, the DIMM labels and the channel ce_count | ||
892 | */ | ||
893 | for (chan = 0; chan < csrow->nr_channels; chan++) { | ||
894 | err = edac_create_channel_files(&csrow->kobj,chan); | ||
895 | if (err) | ||
896 | break; | ||
897 | } | ||
898 | } | ||
899 | |||
900 | error_exit: | ||
901 | return err; | ||
902 | } | ||
903 | |||
904 | /* default sysfs methods and data structures for the main MCI kobject */ | ||
905 | |||
906 | static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, | ||
907 | const char *data, size_t count) | ||
908 | { | ||
909 | int row, chan; | ||
910 | |||
911 | mci->ue_noinfo_count = 0; | ||
912 | mci->ce_noinfo_count = 0; | ||
913 | mci->ue_count = 0; | ||
914 | mci->ce_count = 0; | ||
915 | |||
916 | for (row = 0; row < mci->nr_csrows; row++) { | ||
917 | struct csrow_info *ri = &mci->csrows[row]; | ||
918 | |||
919 | ri->ue_count = 0; | ||
920 | ri->ce_count = 0; | ||
921 | |||
922 | for (chan = 0; chan < ri->nr_channels; chan++) | ||
923 | ri->channels[chan].ce_count = 0; | ||
924 | } | ||
925 | |||
926 | mci->start_time = jiffies; | ||
927 | return count; | ||
928 | } | ||
929 | |||
930 | /* memory scrubbing */ | ||
931 | static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, | ||
932 | const char *data, size_t count) | ||
933 | { | ||
934 | u32 bandwidth = -1; | ||
935 | |||
936 | if (mci->set_sdram_scrub_rate) { | ||
937 | |||
938 | memctrl_int_store(&bandwidth, data, count); | ||
939 | |||
940 | if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) { | ||
941 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
942 | "Scrub rate set successfully, applied: %d\n", | ||
943 | bandwidth); | ||
944 | } else { | ||
945 | /* FIXME: error codes maybe? */ | ||
946 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
947 | "Scrub rate set FAILED, could not apply: %d\n", | ||
948 | bandwidth); | ||
949 | } | ||
950 | } else { | ||
951 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
952 | edac_printk(KERN_WARNING, EDAC_MC, | ||
953 | "Memory scrubbing 'set'control is not implemented!\n"); | ||
954 | } | ||
955 | return count; | ||
956 | } | ||
957 | |||
958 | static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) | ||
959 | { | ||
960 | u32 bandwidth = -1; | ||
961 | |||
962 | if (mci->get_sdram_scrub_rate) { | ||
963 | if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) { | ||
964 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
965 | "Scrub rate successfully, fetched: %d\n", | ||
966 | bandwidth); | ||
967 | } else { | ||
968 | /* FIXME: error codes maybe? */ | ||
969 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
970 | "Scrub rate fetch FAILED, got: %d\n", | ||
971 | bandwidth); | ||
972 | } | ||
973 | } else { | ||
974 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
975 | edac_printk(KERN_WARNING, EDAC_MC, | ||
976 | "Memory scrubbing 'get' control is not implemented!\n"); | ||
977 | } | ||
978 | return sprintf(data, "%d\n", bandwidth); | ||
979 | } | ||
980 | |||
981 | /* default attribute files for the MCI object */ | ||
982 | static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) | ||
983 | { | ||
984 | return sprintf(data,"%d\n", mci->ue_count); | ||
985 | } | ||
986 | |||
987 | static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) | ||
988 | { | ||
989 | return sprintf(data,"%d\n", mci->ce_count); | ||
990 | } | ||
991 | |||
992 | static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) | ||
993 | { | ||
994 | return sprintf(data,"%d\n", mci->ce_noinfo_count); | ||
995 | } | ||
996 | |||
997 | static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data) | ||
998 | { | ||
999 | return sprintf(data,"%d\n", mci->ue_noinfo_count); | ||
1000 | } | ||
1001 | |||
1002 | static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data) | ||
1003 | { | ||
1004 | return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ); | ||
1005 | } | ||
1006 | |||
1007 | static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) | ||
1008 | { | ||
1009 | return sprintf(data,"%s\n", mci->ctl_name); | ||
1010 | } | ||
1011 | |||
1012 | static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) | ||
1013 | { | ||
1014 | int total_pages, csrow_idx; | ||
1015 | |||
1016 | for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows; | ||
1017 | csrow_idx++) { | ||
1018 | struct csrow_info *csrow = &mci->csrows[csrow_idx]; | ||
1019 | |||
1020 | if (!csrow->nr_pages) | ||
1021 | continue; | ||
1022 | |||
1023 | total_pages += csrow->nr_pages; | ||
1024 | } | ||
1025 | |||
1026 | return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages)); | ||
1027 | } | ||
1028 | |||
1029 | struct mcidev_attribute { | ||
1030 | struct attribute attr; | ||
1031 | ssize_t (*show)(struct mem_ctl_info *,char *); | ||
1032 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); | ||
1033 | }; | ||
1034 | |||
1035 | #define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) | ||
1036 | #define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) | ||
1037 | |||
1038 | /* MCI show/store functions for top most object */ | ||
1039 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, | ||
1040 | char *buffer) | ||
1041 | { | ||
1042 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | ||
1043 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); | ||
1044 | |||
1045 | if (mcidev_attr->show) | ||
1046 | return mcidev_attr->show(mem_ctl_info, buffer); | ||
1047 | |||
1048 | return -EIO; | ||
1049 | } | ||
1050 | |||
1051 | static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, | ||
1052 | const char *buffer, size_t count) | ||
1053 | { | ||
1054 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | ||
1055 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); | ||
1056 | |||
1057 | if (mcidev_attr->store) | ||
1058 | return mcidev_attr->store(mem_ctl_info, buffer, count); | ||
1059 | |||
1060 | return -EIO; | ||
1061 | } | ||
1062 | |||
1063 | static struct sysfs_ops mci_ops = { | ||
1064 | .show = mcidev_show, | ||
1065 | .store = mcidev_store | ||
1066 | }; | ||
1067 | |||
1068 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ | ||
1069 | struct mcidev_attribute mci_attr_##_name = { \ | ||
1070 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
1071 | .show = _show, \ | ||
1072 | .store = _store, \ | ||
1073 | }; | ||
1074 | |||
1075 | /* default Control file */ | ||
1076 | MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store); | ||
1077 | |||
1078 | /* default Attribute files */ | ||
1079 | MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL); | ||
1080 | MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL); | ||
1081 | MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL); | ||
1082 | MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL); | ||
1083 | MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL); | ||
1084 | MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); | ||
1085 | MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); | ||
1086 | |||
1087 | /* memory scrubber attribute file */ | ||
1088 | MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store); | ||
1089 | |||
1090 | static struct mcidev_attribute *mci_attr[] = { | ||
1091 | &mci_attr_reset_counters, | ||
1092 | &mci_attr_mc_name, | ||
1093 | &mci_attr_size_mb, | ||
1094 | &mci_attr_seconds_since_reset, | ||
1095 | &mci_attr_ue_noinfo_count, | ||
1096 | &mci_attr_ce_noinfo_count, | ||
1097 | &mci_attr_ue_count, | ||
1098 | &mci_attr_ce_count, | ||
1099 | &mci_attr_sdram_scrub_rate, | ||
1100 | NULL | ||
1101 | }; | ||
1102 | |||
1103 | /* | ||
1104 | * Release of a MC controlling instance | ||
1105 | */ | ||
1106 | static void edac_mci_instance_release(struct kobject *kobj) | ||
1107 | { | ||
1108 | struct mem_ctl_info *mci; | ||
1109 | |||
1110 | mci = to_mci(kobj); | ||
1111 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | ||
1112 | complete(&mci->kobj_complete); | ||
1113 | } | ||
1114 | |||
1115 | static struct kobj_type ktype_mci = { | ||
1116 | .release = edac_mci_instance_release, | ||
1117 | .sysfs_ops = &mci_ops, | ||
1118 | .default_attrs = (struct attribute **) mci_attr, | ||
1119 | }; | ||
1120 | |||
1121 | |||
1122 | #define EDAC_DEVICE_SYMLINK "device" | ||
1123 | |||
1124 | /* | ||
1125 | * Create a new Memory Controller kobject instance, | ||
1126 | * mc<id> under the 'mc' directory | ||
1127 | * | ||
1128 | * Return: | ||
1129 | * 0 Success | ||
1130 | * !0 Failure | ||
1131 | */ | ||
1132 | static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | ||
1133 | { | ||
1134 | int i; | ||
1135 | int err; | ||
1136 | struct csrow_info *csrow; | ||
1137 | struct kobject *edac_mci_kobj=&mci->edac_mci_kobj; | ||
1138 | |||
1139 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | ||
1140 | memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); | ||
1141 | |||
1142 | /* set the name of the mc<id> object */ | ||
1143 | err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); | ||
1144 | if (err) | ||
1145 | return err; | ||
1146 | |||
1147 | /* link to our parent the '..../edac/mc' object */ | ||
1148 | edac_mci_kobj->parent = &edac_memctrl_kobj; | ||
1149 | edac_mci_kobj->ktype = &ktype_mci; | ||
1150 | |||
1151 | /* register the mc<id> kobject */ | ||
1152 | err = kobject_register(edac_mci_kobj); | ||
1153 | if (err) | ||
1154 | return err; | ||
1155 | |||
1156 | /* create a symlink for the device */ | ||
1157 | err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj, | ||
1158 | EDAC_DEVICE_SYMLINK); | ||
1159 | if (err) | ||
1160 | goto fail0; | ||
1161 | |||
1162 | /* Make directories for each CSROW object | ||
1163 | * under the mc<id> kobject | ||
1164 | */ | ||
1165 | for (i = 0; i < mci->nr_csrows; i++) { | ||
1166 | csrow = &mci->csrows[i]; | ||
1167 | |||
1168 | /* Only expose populated CSROWs */ | ||
1169 | if (csrow->nr_pages > 0) { | ||
1170 | err = edac_create_csrow_object(edac_mci_kobj,csrow,i); | ||
1171 | if (err) | ||
1172 | goto fail1; | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | return 0; | ||
1177 | |||
1178 | /* CSROW error: backout what has already been registered, */ | ||
1179 | fail1: | ||
1180 | for ( i--; i >= 0; i--) { | ||
1181 | if (csrow->nr_pages > 0) { | ||
1182 | init_completion(&csrow->kobj_complete); | ||
1183 | kobject_unregister(&mci->csrows[i].kobj); | ||
1184 | wait_for_completion(&csrow->kobj_complete); | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | fail0: | ||
1189 | init_completion(&mci->kobj_complete); | ||
1190 | kobject_unregister(edac_mci_kobj); | ||
1191 | wait_for_completion(&mci->kobj_complete); | ||
1192 | return err; | ||
1193 | } | ||
1194 | |||
1195 | /* | ||
1196 | * remove a Memory Controller instance | ||
1197 | */ | ||
1198 | static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | ||
1199 | { | ||
1200 | int i; | ||
1201 | |||
1202 | debugf0("%s()\n", __func__); | ||
1203 | |||
1204 | /* remove all csrow kobjects */ | ||
1205 | for (i = 0; i < mci->nr_csrows; i++) { | ||
1206 | if (mci->csrows[i].nr_pages > 0) { | ||
1207 | init_completion(&mci->csrows[i].kobj_complete); | ||
1208 | kobject_unregister(&mci->csrows[i].kobj); | ||
1209 | wait_for_completion(&mci->csrows[i].kobj_complete); | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | ||
1214 | init_completion(&mci->kobj_complete); | ||
1215 | kobject_unregister(&mci->edac_mci_kobj); | ||
1216 | wait_for_completion(&mci->kobj_complete); | ||
1217 | } | ||
1218 | |||
1219 | /* END OF sysfs data and methods */ | ||
1220 | |||
1221 | #ifdef CONFIG_EDAC_DEBUG | 41 | #ifdef CONFIG_EDAC_DEBUG |
1222 | 42 | ||
1223 | void edac_mc_dump_channel(struct channel_info *chan) | 43 | static void edac_mc_dump_channel(struct channel_info *chan) |
1224 | { | 44 | { |
1225 | debugf4("\tchannel = %p\n", chan); | 45 | debugf4("\tchannel = %p\n", chan); |
1226 | debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); | 46 | debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); |
@@ -1228,25 +48,21 @@ void edac_mc_dump_channel(struct channel_info *chan) | |||
1228 | debugf4("\tchannel->label = '%s'\n", chan->label); | 48 | debugf4("\tchannel->label = '%s'\n", chan->label); |
1229 | debugf4("\tchannel->csrow = %p\n\n", chan->csrow); | 49 | debugf4("\tchannel->csrow = %p\n\n", chan->csrow); |
1230 | } | 50 | } |
1231 | EXPORT_SYMBOL_GPL(edac_mc_dump_channel); | ||
1232 | 51 | ||
1233 | void edac_mc_dump_csrow(struct csrow_info *csrow) | 52 | static void edac_mc_dump_csrow(struct csrow_info *csrow) |
1234 | { | 53 | { |
1235 | debugf4("\tcsrow = %p\n", csrow); | 54 | debugf4("\tcsrow = %p\n", csrow); |
1236 | debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx); | 55 | debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx); |
1237 | debugf4("\tcsrow->first_page = 0x%lx\n", | 56 | debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page); |
1238 | csrow->first_page); | ||
1239 | debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); | 57 | debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); |
1240 | debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); | 58 | debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); |
1241 | debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); | 59 | debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); |
1242 | debugf4("\tcsrow->nr_channels = %d\n", | 60 | debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels); |
1243 | csrow->nr_channels); | ||
1244 | debugf4("\tcsrow->channels = %p\n", csrow->channels); | 61 | debugf4("\tcsrow->channels = %p\n", csrow->channels); |
1245 | debugf4("\tcsrow->mci = %p\n\n", csrow->mci); | 62 | debugf4("\tcsrow->mci = %p\n\n", csrow->mci); |
1246 | } | 63 | } |
1247 | EXPORT_SYMBOL_GPL(edac_mc_dump_csrow); | ||
1248 | 64 | ||
1249 | void edac_mc_dump_mci(struct mem_ctl_info *mci) | 65 | static void edac_mc_dump_mci(struct mem_ctl_info *mci) |
1250 | { | 66 | { |
1251 | debugf3("\tmci = %p\n", mci); | 67 | debugf3("\tmci = %p\n", mci); |
1252 | debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap); | 68 | debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap); |
@@ -1256,13 +72,11 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci) | |||
1256 | debugf3("\tmci->nr_csrows = %d, csrows = %p\n", | 72 | debugf3("\tmci->nr_csrows = %d, csrows = %p\n", |
1257 | mci->nr_csrows, mci->csrows); | 73 | mci->nr_csrows, mci->csrows); |
1258 | debugf3("\tdev = %p\n", mci->dev); | 74 | debugf3("\tdev = %p\n", mci->dev); |
1259 | debugf3("\tmod_name:ctl_name = %s:%s\n", | 75 | debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name); |
1260 | mci->mod_name, mci->ctl_name); | ||
1261 | debugf3("\tpvt_info = %p\n\n", mci->pvt_info); | 76 | debugf3("\tpvt_info = %p\n\n", mci->pvt_info); |
1262 | } | 77 | } |
1263 | EXPORT_SYMBOL_GPL(edac_mc_dump_mci); | ||
1264 | 78 | ||
1265 | #endif /* CONFIG_EDAC_DEBUG */ | 79 | #endif /* CONFIG_EDAC_DEBUG */ |
1266 | 80 | ||
1267 | /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. | 81 | /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. |
1268 | * Adjust 'ptr' so that its alignment is at least as stringent as what the | 82 | * Adjust 'ptr' so that its alignment is at least as stringent as what the |
@@ -1271,7 +85,7 @@ EXPORT_SYMBOL_GPL(edac_mc_dump_mci); | |||
1271 | * If 'size' is a constant, the compiler will optimize this whole function | 85 | * If 'size' is a constant, the compiler will optimize this whole function |
1272 | * down to either a no-op or the addition of a constant to the value of 'ptr'. | 86 | * down to either a no-op or the addition of a constant to the value of 'ptr'. |
1273 | */ | 87 | */ |
1274 | static inline char * align_ptr(void *ptr, unsigned size) | 88 | void *edac_align_ptr(void *ptr, unsigned size) |
1275 | { | 89 | { |
1276 | unsigned align, r; | 90 | unsigned align, r; |
1277 | 91 | ||
@@ -1288,14 +102,14 @@ static inline char * align_ptr(void *ptr, unsigned size) | |||
1288 | else if (size > sizeof(char)) | 102 | else if (size > sizeof(char)) |
1289 | align = sizeof(short); | 103 | align = sizeof(short); |
1290 | else | 104 | else |
1291 | return (char *) ptr; | 105 | return (char *)ptr; |
1292 | 106 | ||
1293 | r = size % align; | 107 | r = size % align; |
1294 | 108 | ||
1295 | if (r == 0) | 109 | if (r == 0) |
1296 | return (char *) ptr; | 110 | return (char *)ptr; |
1297 | 111 | ||
1298 | return (char *) (((unsigned long) ptr) + align - r); | 112 | return (void *)(((unsigned long)ptr) + align - r); |
1299 | } | 113 | } |
1300 | 114 | ||
1301 | /** | 115 | /** |
@@ -1315,7 +129,7 @@ static inline char * align_ptr(void *ptr, unsigned size) | |||
1315 | * struct mem_ctl_info pointer | 129 | * struct mem_ctl_info pointer |
1316 | */ | 130 | */ |
1317 | struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | 131 | struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, |
1318 | unsigned nr_chans) | 132 | unsigned nr_chans, int edac_index) |
1319 | { | 133 | { |
1320 | struct mem_ctl_info *mci; | 134 | struct mem_ctl_info *mci; |
1321 | struct csrow_info *csi, *csrow; | 135 | struct csrow_info *csi, *csrow; |
@@ -1323,30 +137,32 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
1323 | void *pvt; | 137 | void *pvt; |
1324 | unsigned size; | 138 | unsigned size; |
1325 | int row, chn; | 139 | int row, chn; |
140 | int err; | ||
1326 | 141 | ||
1327 | /* Figure out the offsets of the various items from the start of an mc | 142 | /* Figure out the offsets of the various items from the start of an mc |
1328 | * structure. We want the alignment of each item to be at least as | 143 | * structure. We want the alignment of each item to be at least as |
1329 | * stringent as what the compiler would provide if we could simply | 144 | * stringent as what the compiler would provide if we could simply |
1330 | * hardcode everything into a single struct. | 145 | * hardcode everything into a single struct. |
1331 | */ | 146 | */ |
1332 | mci = (struct mem_ctl_info *) 0; | 147 | mci = (struct mem_ctl_info *)0; |
1333 | csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi)); | 148 | csi = edac_align_ptr(&mci[1], sizeof(*csi)); |
1334 | chi = (struct channel_info *) | 149 | chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi)); |
1335 | align_ptr(&csi[nr_csrows], sizeof(*chi)); | 150 | pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); |
1336 | pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); | 151 | size = ((unsigned long)pvt) + sz_pvt; |
1337 | size = ((unsigned long) pvt) + sz_pvt; | 152 | |
1338 | 153 | mci = kzalloc(size, GFP_KERNEL); | |
1339 | if ((mci = kmalloc(size, GFP_KERNEL)) == NULL) | 154 | if (mci == NULL) |
1340 | return NULL; | 155 | return NULL; |
1341 | 156 | ||
1342 | /* Adjust pointers so they point within the memory we just allocated | 157 | /* Adjust pointers so they point within the memory we just allocated |
1343 | * rather than an imaginary chunk of memory located at address 0. | 158 | * rather than an imaginary chunk of memory located at address 0. |
1344 | */ | 159 | */ |
1345 | csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi)); | 160 | csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); |
1346 | chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi)); | 161 | chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi)); |
1347 | pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL; | 162 | pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; |
1348 | 163 | ||
1349 | memset(mci, 0, size); /* clear all fields */ | 164 | /* setup index and various internal pointers */ |
165 | mci->mc_idx = edac_index; | ||
1350 | mci->csrows = csi; | 166 | mci->csrows = csi; |
1351 | mci->pvt_info = pvt; | 167 | mci->pvt_info = pvt; |
1352 | mci->nr_csrows = nr_csrows; | 168 | mci->nr_csrows = nr_csrows; |
@@ -1366,17 +182,35 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
1366 | } | 182 | } |
1367 | } | 183 | } |
1368 | 184 | ||
185 | mci->op_state = OP_ALLOC; | ||
186 | |||
187 | /* | ||
188 | * Initialize the 'root' kobj for the edac_mc controller | ||
189 | */ | ||
190 | err = edac_mc_register_sysfs_main_kobj(mci); | ||
191 | if (err) { | ||
192 | kfree(mci); | ||
193 | return NULL; | ||
194 | } | ||
195 | |||
196 | /* at this point, the root kobj is valid, and in order to | ||
197 | * 'free' the object, then the function: | ||
198 | * edac_mc_unregister_sysfs_main_kobj() must be called | ||
199 | * which will perform kobj unregistration and the actual free | ||
200 | * will occur during the kobject callback operation | ||
201 | */ | ||
1369 | return mci; | 202 | return mci; |
1370 | } | 203 | } |
1371 | EXPORT_SYMBOL_GPL(edac_mc_alloc); | 204 | EXPORT_SYMBOL_GPL(edac_mc_alloc); |
1372 | 205 | ||
1373 | /** | 206 | /** |
1374 | * edac_mc_free: Free a previously allocated 'mci' structure | 207 | * edac_mc_free |
208 | * 'Free' a previously allocated 'mci' structure | ||
1375 | * @mci: pointer to a struct mem_ctl_info structure | 209 | * @mci: pointer to a struct mem_ctl_info structure |
1376 | */ | 210 | */ |
1377 | void edac_mc_free(struct mem_ctl_info *mci) | 211 | void edac_mc_free(struct mem_ctl_info *mci) |
1378 | { | 212 | { |
1379 | kfree(mci); | 213 | edac_mc_unregister_sysfs_main_kobj(mci); |
1380 | } | 214 | } |
1381 | EXPORT_SYMBOL_GPL(edac_mc_free); | 215 | EXPORT_SYMBOL_GPL(edac_mc_free); |
1382 | 216 | ||
@@ -1397,18 +231,136 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev) | |||
1397 | return NULL; | 231 | return NULL; |
1398 | } | 232 | } |
1399 | 233 | ||
234 | /* | ||
235 | * handler for EDAC to check if NMI type handler has asserted interrupt | ||
236 | */ | ||
237 | static int edac_mc_assert_error_check_and_clear(void) | ||
238 | { | ||
239 | int old_state; | ||
240 | |||
241 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
242 | return 1; | ||
243 | |||
244 | old_state = edac_err_assert; | ||
245 | edac_err_assert = 0; | ||
246 | |||
247 | return old_state; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * edac_mc_workq_function | ||
252 | * performs the operation scheduled by a workq request | ||
253 | */ | ||
254 | static void edac_mc_workq_function(struct work_struct *work_req) | ||
255 | { | ||
256 | struct delayed_work *d_work = (struct delayed_work *)work_req; | ||
257 | struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work); | ||
258 | |||
259 | mutex_lock(&mem_ctls_mutex); | ||
260 | |||
261 | /* if this control struct has movd to offline state, we are done */ | ||
262 | if (mci->op_state == OP_OFFLINE) { | ||
263 | mutex_unlock(&mem_ctls_mutex); | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | /* Only poll controllers that are running polled and have a check */ | ||
268 | if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL)) | ||
269 | mci->edac_check(mci); | ||
270 | |||
271 | /* | ||
272 | * FIXME: temp place holder for PCI checks, | ||
273 | * goes away when we break out PCI | ||
274 | */ | ||
275 | edac_pci_do_parity_check(); | ||
276 | |||
277 | mutex_unlock(&mem_ctls_mutex); | ||
278 | |||
279 | /* Reschedule */ | ||
280 | queue_delayed_work(edac_workqueue, &mci->work, | ||
281 | msecs_to_jiffies(edac_mc_get_poll_msec())); | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * edac_mc_workq_setup | ||
286 | * initialize a workq item for this mci | ||
287 | * passing in the new delay period in msec | ||
288 | * | ||
289 | * locking model: | ||
290 | * | ||
291 | * called with the mem_ctls_mutex held | ||
292 | */ | ||
293 | static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) | ||
294 | { | ||
295 | debugf0("%s()\n", __func__); | ||
296 | |||
297 | /* if this instance is not in the POLL state, then simply return */ | ||
298 | if (mci->op_state != OP_RUNNING_POLL) | ||
299 | return; | ||
300 | |||
301 | INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); | ||
302 | queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * edac_mc_workq_teardown | ||
307 | * stop the workq processing on this mci | ||
308 | * | ||
309 | * locking model: | ||
310 | * | ||
311 | * called WITHOUT lock held | ||
312 | */ | ||
313 | static void edac_mc_workq_teardown(struct mem_ctl_info *mci) | ||
314 | { | ||
315 | int status; | ||
316 | |||
317 | /* if not running POLL, leave now */ | ||
318 | if (mci->op_state == OP_RUNNING_POLL) { | ||
319 | status = cancel_delayed_work(&mci->work); | ||
320 | if (status == 0) { | ||
321 | debugf0("%s() not canceled, flush the queue\n", | ||
322 | __func__); | ||
323 | |||
324 | /* workq instance might be running, wait for it */ | ||
325 | flush_workqueue(edac_workqueue); | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * edac_reset_delay_period | ||
332 | */ | ||
333 | static void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value) | ||
334 | { | ||
335 | /* cancel the current workq request */ | ||
336 | edac_mc_workq_teardown(mci); | ||
337 | |||
338 | /* lock the list of devices for the new setup */ | ||
339 | mutex_lock(&mem_ctls_mutex); | ||
340 | |||
341 | /* restart the workq request, with new delay value */ | ||
342 | edac_mc_workq_setup(mci, value); | ||
343 | |||
344 | mutex_unlock(&mem_ctls_mutex); | ||
345 | } | ||
346 | |||
1400 | /* Return 0 on success, 1 on failure. | 347 | /* Return 0 on success, 1 on failure. |
1401 | * Before calling this function, caller must | 348 | * Before calling this function, caller must |
1402 | * assign a unique value to mci->mc_idx. | 349 | * assign a unique value to mci->mc_idx. |
350 | * | ||
351 | * locking model: | ||
352 | * | ||
353 | * called with the mem_ctls_mutex lock held | ||
1403 | */ | 354 | */ |
1404 | static int add_mc_to_global_list (struct mem_ctl_info *mci) | 355 | static int add_mc_to_global_list(struct mem_ctl_info *mci) |
1405 | { | 356 | { |
1406 | struct list_head *item, *insert_before; | 357 | struct list_head *item, *insert_before; |
1407 | struct mem_ctl_info *p; | 358 | struct mem_ctl_info *p; |
1408 | 359 | ||
1409 | insert_before = &mc_devices; | 360 | insert_before = &mc_devices; |
1410 | 361 | ||
1411 | if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL)) | 362 | p = find_mci_by_dev(mci->dev); |
363 | if (unlikely(p != NULL)) | ||
1412 | goto fail0; | 364 | goto fail0; |
1413 | 365 | ||
1414 | list_for_each(item, &mc_devices) { | 366 | list_for_each(item, &mc_devices) { |
@@ -1424,18 +376,19 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci) | |||
1424 | } | 376 | } |
1425 | 377 | ||
1426 | list_add_tail_rcu(&mci->link, insert_before); | 378 | list_add_tail_rcu(&mci->link, insert_before); |
379 | atomic_inc(&edac_handlers); | ||
1427 | return 0; | 380 | return 0; |
1428 | 381 | ||
1429 | fail0: | 382 | fail0: |
1430 | edac_printk(KERN_WARNING, EDAC_MC, | 383 | edac_printk(KERN_WARNING, EDAC_MC, |
1431 | "%s (%s) %s %s already assigned %d\n", p->dev->bus_id, | 384 | "%s (%s) %s %s already assigned %d\n", p->dev->bus_id, |
1432 | dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx); | 385 | dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx); |
1433 | return 1; | 386 | return 1; |
1434 | 387 | ||
1435 | fail1: | 388 | fail1: |
1436 | edac_printk(KERN_WARNING, EDAC_MC, | 389 | edac_printk(KERN_WARNING, EDAC_MC, |
1437 | "bug in low-level driver: attempt to assign\n" | 390 | "bug in low-level driver: attempt to assign\n" |
1438 | " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__); | 391 | " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__); |
1439 | return 1; | 392 | return 1; |
1440 | } | 393 | } |
1441 | 394 | ||
@@ -1450,6 +403,7 @@ static void complete_mc_list_del(struct rcu_head *head) | |||
1450 | 403 | ||
1451 | static void del_mc_from_global_list(struct mem_ctl_info *mci) | 404 | static void del_mc_from_global_list(struct mem_ctl_info *mci) |
1452 | { | 405 | { |
406 | atomic_dec(&edac_handlers); | ||
1453 | list_del_rcu(&mci->link); | 407 | list_del_rcu(&mci->link); |
1454 | init_completion(&mci->complete); | 408 | init_completion(&mci->complete); |
1455 | call_rcu(&mci->rcu, complete_mc_list_del); | 409 | call_rcu(&mci->rcu, complete_mc_list_del); |
@@ -1457,6 +411,34 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci) | |||
1457 | } | 411 | } |
1458 | 412 | ||
1459 | /** | 413 | /** |
414 | * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'. | ||
415 | * | ||
416 | * If found, return a pointer to the structure. | ||
417 | * Else return NULL. | ||
418 | * | ||
419 | * Caller must hold mem_ctls_mutex. | ||
420 | */ | ||
421 | struct mem_ctl_info *edac_mc_find(int idx) | ||
422 | { | ||
423 | struct list_head *item; | ||
424 | struct mem_ctl_info *mci; | ||
425 | |||
426 | list_for_each(item, &mc_devices) { | ||
427 | mci = list_entry(item, struct mem_ctl_info, link); | ||
428 | |||
429 | if (mci->mc_idx >= idx) { | ||
430 | if (mci->mc_idx == idx) | ||
431 | return mci; | ||
432 | |||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | return NULL; | ||
438 | } | ||
439 | EXPORT_SYMBOL(edac_mc_find); | ||
440 | |||
441 | /** | ||
1460 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and | 442 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and |
1461 | * create sysfs entries associated with mci structure | 443 | * create sysfs entries associated with mci structure |
1462 | * @mci: pointer to the mci structure to be added to the list | 444 | * @mci: pointer to the mci structure to be added to the list |
@@ -1468,10 +450,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci) | |||
1468 | */ | 450 | */ |
1469 | 451 | ||
1470 | /* FIXME - should a warning be printed if no error detection? correction? */ | 452 | /* FIXME - should a warning be printed if no error detection? correction? */ |
1471 | int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx) | 453 | int edac_mc_add_mc(struct mem_ctl_info *mci) |
1472 | { | 454 | { |
1473 | debugf0("%s()\n", __func__); | 455 | debugf0("%s()\n", __func__); |
1474 | mci->mc_idx = mc_idx; | 456 | |
1475 | #ifdef CONFIG_EDAC_DEBUG | 457 | #ifdef CONFIG_EDAC_DEBUG |
1476 | if (edac_debug_level >= 3) | 458 | if (edac_debug_level >= 3) |
1477 | edac_mc_dump_mci(mci); | 459 | edac_mc_dump_mci(mci); |
@@ -1484,12 +466,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx) | |||
1484 | 466 | ||
1485 | edac_mc_dump_csrow(&mci->csrows[i]); | 467 | edac_mc_dump_csrow(&mci->csrows[i]); |
1486 | for (j = 0; j < mci->csrows[i].nr_channels; j++) | 468 | for (j = 0; j < mci->csrows[i].nr_channels; j++) |
1487 | edac_mc_dump_channel( | 469 | edac_mc_dump_channel(&mci->csrows[i]. |
1488 | &mci->csrows[i].channels[j]); | 470 | channels[j]); |
1489 | } | 471 | } |
1490 | } | 472 | } |
1491 | #endif | 473 | #endif |
1492 | down(&mem_ctls_mutex); | 474 | mutex_lock(&mem_ctls_mutex); |
1493 | 475 | ||
1494 | if (add_mc_to_global_list(mci)) | 476 | if (add_mc_to_global_list(mci)) |
1495 | goto fail0; | 477 | goto fail0; |
@@ -1503,18 +485,28 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx) | |||
1503 | goto fail1; | 485 | goto fail1; |
1504 | } | 486 | } |
1505 | 487 | ||
488 | /* If there IS a check routine, then we are running POLLED */ | ||
489 | if (mci->edac_check != NULL) { | ||
490 | /* This instance is NOW RUNNING */ | ||
491 | mci->op_state = OP_RUNNING_POLL; | ||
492 | |||
493 | edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); | ||
494 | } else { | ||
495 | mci->op_state = OP_RUNNING_INTERRUPT; | ||
496 | } | ||
497 | |||
1506 | /* Report action taken */ | 498 | /* Report action taken */ |
1507 | edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n", | 499 | edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':" |
1508 | mci->mod_name, mci->ctl_name, dev_name(mci->dev)); | 500 | " DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci)); |
1509 | 501 | ||
1510 | up(&mem_ctls_mutex); | 502 | mutex_unlock(&mem_ctls_mutex); |
1511 | return 0; | 503 | return 0; |
1512 | 504 | ||
1513 | fail1: | 505 | fail1: |
1514 | del_mc_from_global_list(mci); | 506 | del_mc_from_global_list(mci); |
1515 | 507 | ||
1516 | fail0: | 508 | fail0: |
1517 | up(&mem_ctls_mutex); | 509 | mutex_unlock(&mem_ctls_mutex); |
1518 | return 1; | 510 | return 1; |
1519 | } | 511 | } |
1520 | EXPORT_SYMBOL_GPL(edac_mc_add_mc); | 512 | EXPORT_SYMBOL_GPL(edac_mc_add_mc); |
@@ -1526,29 +518,41 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc); | |||
1526 | * | 518 | * |
1527 | * Return pointer to removed mci structure, or NULL if device not found. | 519 | * Return pointer to removed mci structure, or NULL if device not found. |
1528 | */ | 520 | */ |
1529 | struct mem_ctl_info * edac_mc_del_mc(struct device *dev) | 521 | struct mem_ctl_info *edac_mc_del_mc(struct device *dev) |
1530 | { | 522 | { |
1531 | struct mem_ctl_info *mci; | 523 | struct mem_ctl_info *mci; |
1532 | 524 | ||
1533 | debugf0("MC: %s()\n", __func__); | 525 | debugf0("%s()\n", __func__); |
1534 | down(&mem_ctls_mutex); | 526 | |
527 | mutex_lock(&mem_ctls_mutex); | ||
1535 | 528 | ||
1536 | if ((mci = find_mci_by_dev(dev)) == NULL) { | 529 | /* find the requested mci struct in the global list */ |
1537 | up(&mem_ctls_mutex); | 530 | mci = find_mci_by_dev(dev); |
531 | if (mci == NULL) { | ||
532 | mutex_unlock(&mem_ctls_mutex); | ||
1538 | return NULL; | 533 | return NULL; |
1539 | } | 534 | } |
1540 | 535 | ||
1541 | edac_remove_sysfs_mci_device(mci); | 536 | /* marking MCI offline */ |
537 | mci->op_state = OP_OFFLINE; | ||
538 | |||
1542 | del_mc_from_global_list(mci); | 539 | del_mc_from_global_list(mci); |
1543 | up(&mem_ctls_mutex); | 540 | mutex_unlock(&mem_ctls_mutex); |
541 | |||
542 | /* flush workq processes and remove sysfs */ | ||
543 | edac_mc_workq_teardown(mci); | ||
544 | edac_remove_sysfs_mci_device(mci); | ||
545 | |||
1544 | edac_printk(KERN_INFO, EDAC_MC, | 546 | edac_printk(KERN_INFO, EDAC_MC, |
1545 | "Removed device %d for %s %s: DEV %s\n", mci->mc_idx, | 547 | "Removed device %d for %s %s: DEV %s\n", mci->mc_idx, |
1546 | mci->mod_name, mci->ctl_name, dev_name(mci->dev)); | 548 | mci->mod_name, mci->ctl_name, dev_name(mci)); |
549 | |||
1547 | return mci; | 550 | return mci; |
1548 | } | 551 | } |
1549 | EXPORT_SYMBOL_GPL(edac_mc_del_mc); | 552 | EXPORT_SYMBOL_GPL(edac_mc_del_mc); |
1550 | 553 | ||
1551 | void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size) | 554 | static void edac_mc_scrub_block(unsigned long page, unsigned long offset, |
555 | u32 size) | ||
1552 | { | 556 | { |
1553 | struct page *pg; | 557 | struct page *pg; |
1554 | void *virt_addr; | 558 | void *virt_addr; |
@@ -1557,7 +561,7 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size) | |||
1557 | debugf3("%s()\n", __func__); | 561 | debugf3("%s()\n", __func__); |
1558 | 562 | ||
1559 | /* ECC error page was not in our memory. Ignore it. */ | 563 | /* ECC error page was not in our memory. Ignore it. */ |
1560 | if(!pfn_valid(page)) | 564 | if (!pfn_valid(page)) |
1561 | return; | 565 | return; |
1562 | 566 | ||
1563 | /* Find the actual page structure then map it and fix */ | 567 | /* Find the actual page structure then map it and fix */ |
@@ -1577,7 +581,6 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size) | |||
1577 | if (PageHighMem(pg)) | 581 | if (PageHighMem(pg)) |
1578 | local_irq_restore(flags); | 582 | local_irq_restore(flags); |
1579 | } | 583 | } |
1580 | EXPORT_SYMBOL_GPL(edac_mc_scrub_block); | ||
1581 | 584 | ||
1582 | /* FIXME - should return -1 */ | 585 | /* FIXME - should return -1 */ |
1583 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) | 586 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) |
@@ -1611,7 +614,7 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) | |||
1611 | if (row == -1) | 614 | if (row == -1) |
1612 | edac_mc_printk(mci, KERN_ERR, | 615 | edac_mc_printk(mci, KERN_ERR, |
1613 | "could not look up page error address %lx\n", | 616 | "could not look up page error address %lx\n", |
1614 | (unsigned long) page); | 617 | (unsigned long)page); |
1615 | 618 | ||
1616 | return row; | 619 | return row; |
1617 | } | 620 | } |
@@ -1620,8 +623,9 @@ EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); | |||
1620 | /* FIXME - setable log (warning/emerg) levels */ | 623 | /* FIXME - setable log (warning/emerg) levels */ |
1621 | /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ | 624 | /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ |
1622 | void edac_mc_handle_ce(struct mem_ctl_info *mci, | 625 | void edac_mc_handle_ce(struct mem_ctl_info *mci, |
1623 | unsigned long page_frame_number, unsigned long offset_in_page, | 626 | unsigned long page_frame_number, |
1624 | unsigned long syndrome, int row, int channel, const char *msg) | 627 | unsigned long offset_in_page, unsigned long syndrome, |
628 | int row, int channel, const char *msg) | ||
1625 | { | 629 | { |
1626 | unsigned long remapped_page; | 630 | unsigned long remapped_page; |
1627 | 631 | ||
@@ -1647,7 +651,7 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci, | |||
1647 | return; | 651 | return; |
1648 | } | 652 | } |
1649 | 653 | ||
1650 | if (log_ce) | 654 | if (edac_mc_get_log_ce()) |
1651 | /* FIXME - put in DIMM location */ | 655 | /* FIXME - put in DIMM location */ |
1652 | edac_mc_printk(mci, KERN_WARNING, | 656 | edac_mc_printk(mci, KERN_WARNING, |
1653 | "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " | 657 | "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " |
@@ -1671,18 +675,18 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci, | |||
1671 | * page - which can then be scrubbed. | 675 | * page - which can then be scrubbed. |
1672 | */ | 676 | */ |
1673 | remapped_page = mci->ctl_page_to_phys ? | 677 | remapped_page = mci->ctl_page_to_phys ? |
1674 | mci->ctl_page_to_phys(mci, page_frame_number) : | 678 | mci->ctl_page_to_phys(mci, page_frame_number) : |
1675 | page_frame_number; | 679 | page_frame_number; |
1676 | 680 | ||
1677 | edac_mc_scrub_block(remapped_page, offset_in_page, | 681 | edac_mc_scrub_block(remapped_page, offset_in_page, |
1678 | mci->csrows[row].grain); | 682 | mci->csrows[row].grain); |
1679 | } | 683 | } |
1680 | } | 684 | } |
1681 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce); | 685 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce); |
1682 | 686 | ||
1683 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) | 687 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) |
1684 | { | 688 | { |
1685 | if (log_ce) | 689 | if (edac_mc_get_log_ce()) |
1686 | edac_mc_printk(mci, KERN_WARNING, | 690 | edac_mc_printk(mci, KERN_WARNING, |
1687 | "CE - no information available: %s\n", msg); | 691 | "CE - no information available: %s\n", msg); |
1688 | 692 | ||
@@ -1692,8 +696,8 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) | |||
1692 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); | 696 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); |
1693 | 697 | ||
1694 | void edac_mc_handle_ue(struct mem_ctl_info *mci, | 698 | void edac_mc_handle_ue(struct mem_ctl_info *mci, |
1695 | unsigned long page_frame_number, unsigned long offset_in_page, | 699 | unsigned long page_frame_number, |
1696 | int row, const char *msg) | 700 | unsigned long offset_in_page, int row, const char *msg) |
1697 | { | 701 | { |
1698 | int len = EDAC_MC_LABEL_LEN * 4; | 702 | int len = EDAC_MC_LABEL_LEN * 4; |
1699 | char labels[len + 1]; | 703 | char labels[len + 1]; |
@@ -1714,26 +718,26 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci, | |||
1714 | } | 718 | } |
1715 | 719 | ||
1716 | chars = snprintf(pos, len + 1, "%s", | 720 | chars = snprintf(pos, len + 1, "%s", |
1717 | mci->csrows[row].channels[0].label); | 721 | mci->csrows[row].channels[0].label); |
1718 | len -= chars; | 722 | len -= chars; |
1719 | pos += chars; | 723 | pos += chars; |
1720 | 724 | ||
1721 | for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); | 725 | for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); |
1722 | chan++) { | 726 | chan++) { |
1723 | chars = snprintf(pos, len + 1, ":%s", | 727 | chars = snprintf(pos, len + 1, ":%s", |
1724 | mci->csrows[row].channels[chan].label); | 728 | mci->csrows[row].channels[chan].label); |
1725 | len -= chars; | 729 | len -= chars; |
1726 | pos += chars; | 730 | pos += chars; |
1727 | } | 731 | } |
1728 | 732 | ||
1729 | if (log_ue) | 733 | if (edac_mc_get_log_ue()) |
1730 | edac_mc_printk(mci, KERN_EMERG, | 734 | edac_mc_printk(mci, KERN_EMERG, |
1731 | "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " | 735 | "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " |
1732 | "labels \"%s\": %s\n", page_frame_number, | 736 | "labels \"%s\": %s\n", page_frame_number, |
1733 | offset_in_page, mci->csrows[row].grain, row, labels, | 737 | offset_in_page, mci->csrows[row].grain, row, |
1734 | msg); | 738 | labels, msg); |
1735 | 739 | ||
1736 | if (panic_on_ue) | 740 | if (edac_mc_get_panic_on_ue()) |
1737 | panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " | 741 | panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " |
1738 | "row %d, labels \"%s\": %s\n", mci->mc_idx, | 742 | "row %d, labels \"%s\": %s\n", mci->mc_idx, |
1739 | page_frame_number, offset_in_page, | 743 | page_frame_number, offset_in_page, |
@@ -1746,10 +750,10 @@ EXPORT_SYMBOL_GPL(edac_mc_handle_ue); | |||
1746 | 750 | ||
1747 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | 751 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) |
1748 | { | 752 | { |
1749 | if (panic_on_ue) | 753 | if (edac_mc_get_panic_on_ue()) |
1750 | panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); | 754 | panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); |
1751 | 755 | ||
1752 | if (log_ue) | 756 | if (edac_mc_get_log_ue()) |
1753 | edac_mc_printk(mci, KERN_WARNING, | 757 | edac_mc_printk(mci, KERN_WARNING, |
1754 | "UE - no information available: %s\n", msg); | 758 | "UE - no information available: %s\n", msg); |
1755 | mci->ue_noinfo_count++; | 759 | mci->ue_noinfo_count++; |
@@ -1757,16 +761,14 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | |||
1757 | } | 761 | } |
1758 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); | 762 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); |
1759 | 763 | ||
1760 | |||
1761 | /************************************************************* | 764 | /************************************************************* |
1762 | * On Fully Buffered DIMM modules, this help function is | 765 | * On Fully Buffered DIMM modules, this help function is |
1763 | * called to process UE events | 766 | * called to process UE events |
1764 | */ | 767 | */ |
1765 | void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | 768 | void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, |
1766 | unsigned int csrow, | 769 | unsigned int csrow, |
1767 | unsigned int channela, | 770 | unsigned int channela, |
1768 | unsigned int channelb, | 771 | unsigned int channelb, char *msg) |
1769 | char *msg) | ||
1770 | { | 772 | { |
1771 | int len = EDAC_MC_LABEL_LEN * 4; | 773 | int len = EDAC_MC_LABEL_LEN * 4; |
1772 | char labels[len + 1]; | 774 | char labels[len + 1]; |
@@ -1808,20 +810,21 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | |||
1808 | /* Generate the DIMM labels from the specified channels */ | 810 | /* Generate the DIMM labels from the specified channels */ |
1809 | chars = snprintf(pos, len + 1, "%s", | 811 | chars = snprintf(pos, len + 1, "%s", |
1810 | mci->csrows[csrow].channels[channela].label); | 812 | mci->csrows[csrow].channels[channela].label); |
1811 | len -= chars; pos += chars; | 813 | len -= chars; |
814 | pos += chars; | ||
1812 | chars = snprintf(pos, len + 1, "-%s", | 815 | chars = snprintf(pos, len + 1, "-%s", |
1813 | mci->csrows[csrow].channels[channelb].label); | 816 | mci->csrows[csrow].channels[channelb].label); |
1814 | 817 | ||
1815 | if (log_ue) | 818 | if (edac_mc_get_log_ue()) |
1816 | edac_mc_printk(mci, KERN_EMERG, | 819 | edac_mc_printk(mci, KERN_EMERG, |
1817 | "UE row %d, channel-a= %d channel-b= %d " | 820 | "UE row %d, channel-a= %d channel-b= %d " |
1818 | "labels \"%s\": %s\n", csrow, channela, channelb, | 821 | "labels \"%s\": %s\n", csrow, channela, channelb, |
1819 | labels, msg); | 822 | labels, msg); |
1820 | 823 | ||
1821 | if (panic_on_ue) | 824 | if (edac_mc_get_panic_on_ue()) |
1822 | panic("UE row %d, channel-a= %d channel-b= %d " | 825 | panic("UE row %d, channel-a= %d channel-b= %d " |
1823 | "labels \"%s\": %s\n", csrow, channela, | 826 | "labels \"%s\": %s\n", csrow, channela, |
1824 | channelb, labels, msg); | 827 | channelb, labels, msg); |
1825 | } | 828 | } |
1826 | EXPORT_SYMBOL(edac_mc_handle_fbd_ue); | 829 | EXPORT_SYMBOL(edac_mc_handle_fbd_ue); |
1827 | 830 | ||
@@ -1830,9 +833,7 @@ EXPORT_SYMBOL(edac_mc_handle_fbd_ue); | |||
1830 | * called to process CE events | 833 | * called to process CE events |
1831 | */ | 834 | */ |
1832 | void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | 835 | void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, |
1833 | unsigned int csrow, | 836 | unsigned int csrow, unsigned int channel, char *msg) |
1834 | unsigned int channel, | ||
1835 | char *msg) | ||
1836 | { | 837 | { |
1837 | 838 | ||
1838 | /* Ensure boundary values */ | 839 | /* Ensure boundary values */ |
@@ -1853,13 +854,12 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | |||
1853 | return; | 854 | return; |
1854 | } | 855 | } |
1855 | 856 | ||
1856 | if (log_ce) | 857 | if (edac_mc_get_log_ce()) |
1857 | /* FIXME - put in DIMM location */ | 858 | /* FIXME - put in DIMM location */ |
1858 | edac_mc_printk(mci, KERN_WARNING, | 859 | edac_mc_printk(mci, KERN_WARNING, |
1859 | "CE row %d, channel %d, label \"%s\": %s\n", | 860 | "CE row %d, channel %d, label \"%s\": %s\n", |
1860 | csrow, channel, | 861 | csrow, channel, |
1861 | mci->csrows[csrow].channels[channel].label, | 862 | mci->csrows[csrow].channels[channel].label, msg); |
1862 | msg); | ||
1863 | 863 | ||
1864 | mci->ce_count++; | 864 | mci->ce_count++; |
1865 | mci->csrows[csrow].ce_count++; | 865 | mci->csrows[csrow].ce_count++; |
@@ -1867,17 +867,16 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | |||
1867 | } | 867 | } |
1868 | EXPORT_SYMBOL(edac_mc_handle_fbd_ce); | 868 | EXPORT_SYMBOL(edac_mc_handle_fbd_ce); |
1869 | 869 | ||
1870 | |||
1871 | /* | 870 | /* |
1872 | * Iterate over all MC instances and check for ECC, et al, errors | 871 | * Iterate over all MC instances and check for ECC, et al, errors |
1873 | */ | 872 | */ |
1874 | static inline void check_mc_devices(void) | 873 | void edac_check_mc_devices(void) |
1875 | { | 874 | { |
1876 | struct list_head *item; | 875 | struct list_head *item; |
1877 | struct mem_ctl_info *mci; | 876 | struct mem_ctl_info *mci; |
1878 | 877 | ||
1879 | debugf3("%s()\n", __func__); | 878 | debugf3("%s()\n", __func__); |
1880 | down(&mem_ctls_mutex); | 879 | mutex_lock(&mem_ctls_mutex); |
1881 | 880 | ||
1882 | list_for_each(item, &mc_devices) { | 881 | list_for_each(item, &mc_devices) { |
1883 | mci = list_entry(item, struct mem_ctl_info, link); | 882 | mci = list_entry(item, struct mem_ctl_info, link); |
@@ -1886,120 +885,5 @@ static inline void check_mc_devices(void) | |||
1886 | mci->edac_check(mci); | 885 | mci->edac_check(mci); |
1887 | } | 886 | } |
1888 | 887 | ||
1889 | up(&mem_ctls_mutex); | 888 | mutex_unlock(&mem_ctls_mutex); |
1890 | } | ||
1891 | |||
1892 | /* | ||
1893 | * Check MC status every poll_msec. | ||
1894 | * Check PCI status every poll_msec as well. | ||
1895 | * | ||
1896 | * This where the work gets done for edac. | ||
1897 | * | ||
1898 | * SMP safe, doesn't use NMI, and auto-rate-limits. | ||
1899 | */ | ||
1900 | static void do_edac_check(void) | ||
1901 | { | ||
1902 | debugf3("%s()\n", __func__); | ||
1903 | check_mc_devices(); | ||
1904 | do_pci_parity_check(); | ||
1905 | } | ||
1906 | |||
1907 | static int edac_kernel_thread(void *arg) | ||
1908 | { | ||
1909 | set_freezable(); | ||
1910 | while (!kthread_should_stop()) { | ||
1911 | do_edac_check(); | ||
1912 | |||
1913 | /* goto sleep for the interval */ | ||
1914 | schedule_timeout_interruptible((HZ * poll_msec) / 1000); | ||
1915 | try_to_freeze(); | ||
1916 | } | ||
1917 | |||
1918 | return 0; | ||
1919 | } | 889 | } |
1920 | |||
1921 | /* | ||
1922 | * edac_mc_init | ||
1923 | * module initialization entry point | ||
1924 | */ | ||
1925 | static int __init edac_mc_init(void) | ||
1926 | { | ||
1927 | edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n"); | ||
1928 | |||
1929 | /* | ||
1930 | * Harvest and clear any boot/initialization PCI parity errors | ||
1931 | * | ||
1932 | * FIXME: This only clears errors logged by devices present at time of | ||
1933 | * module initialization. We should also do an initial clear | ||
1934 | * of each newly hotplugged device. | ||
1935 | */ | ||
1936 | clear_pci_parity_errors(); | ||
1937 | |||
1938 | /* Create the MC sysfs entries */ | ||
1939 | if (edac_sysfs_memctrl_setup()) { | ||
1940 | edac_printk(KERN_ERR, EDAC_MC, | ||
1941 | "Error initializing sysfs code\n"); | ||
1942 | return -ENODEV; | ||
1943 | } | ||
1944 | |||
1945 | /* Create the PCI parity sysfs entries */ | ||
1946 | if (edac_sysfs_pci_setup()) { | ||
1947 | edac_sysfs_memctrl_teardown(); | ||
1948 | edac_printk(KERN_ERR, EDAC_MC, | ||
1949 | "EDAC PCI: Error initializing sysfs code\n"); | ||
1950 | return -ENODEV; | ||
1951 | } | ||
1952 | |||
1953 | /* create our kernel thread */ | ||
1954 | edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); | ||
1955 | |||
1956 | if (IS_ERR(edac_thread)) { | ||
1957 | /* remove the sysfs entries */ | ||
1958 | edac_sysfs_memctrl_teardown(); | ||
1959 | edac_sysfs_pci_teardown(); | ||
1960 | return PTR_ERR(edac_thread); | ||
1961 | } | ||
1962 | |||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1966 | /* | ||
1967 | * edac_mc_exit() | ||
1968 | * module exit/termination functioni | ||
1969 | */ | ||
1970 | static void __exit edac_mc_exit(void) | ||
1971 | { | ||
1972 | debugf0("%s()\n", __func__); | ||
1973 | kthread_stop(edac_thread); | ||
1974 | |||
1975 | /* tear down the sysfs device */ | ||
1976 | edac_sysfs_memctrl_teardown(); | ||
1977 | edac_sysfs_pci_teardown(); | ||
1978 | } | ||
1979 | |||
1980 | module_init(edac_mc_init); | ||
1981 | module_exit(edac_mc_exit); | ||
1982 | |||
1983 | MODULE_LICENSE("GPL"); | ||
1984 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" | ||
1985 | "Based on work by Dan Hollis et al"); | ||
1986 | MODULE_DESCRIPTION("Core library routines for MC reporting"); | ||
1987 | |||
1988 | module_param(panic_on_ue, int, 0644); | ||
1989 | MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on"); | ||
1990 | #ifdef CONFIG_PCI | ||
1991 | module_param(check_pci_parity, int, 0644); | ||
1992 | MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); | ||
1993 | module_param(panic_on_pci_parity, int, 0644); | ||
1994 | MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); | ||
1995 | #endif | ||
1996 | module_param(log_ue, int, 0644); | ||
1997 | MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on"); | ||
1998 | module_param(log_ce, int, 0644); | ||
1999 | MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on"); | ||
2000 | module_param(poll_msec, int, 0644); | ||
2001 | MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds"); | ||
2002 | #ifdef CONFIG_EDAC_DEBUG | ||
2003 | module_param(edac_debug_level, int, 0644); | ||
2004 | MODULE_PARM_DESC(edac_debug_level, "Debug level"); | ||
2005 | #endif | ||
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c new file mode 100644 index 000000000000..cd090b0677a7 --- /dev/null +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -0,0 +1,1024 @@ | |||
1 | /* | ||
2 | * edac_mc kernel module | ||
3 | * (C) 2005-2007 Linux Networx (http://lnxi.com) | ||
4 | * | ||
5 | * This file may be distributed under the terms of the | ||
6 | * GNU General Public License. | ||
7 | * | ||
8 | * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/ctype.h> | ||
13 | #include <linux/bug.h> | ||
14 | |||
15 | #include "edac_core.h" | ||
16 | #include "edac_module.h" | ||
17 | |||
18 | |||
19 | /* MC EDAC Controls, setable by module parameter, and sysfs */ | ||
20 | static int edac_mc_log_ue = 1; | ||
21 | static int edac_mc_log_ce = 1; | ||
22 | static int edac_mc_panic_on_ue; | ||
23 | static int edac_mc_poll_msec = 1000; | ||
24 | |||
25 | /* Getter functions for above */ | ||
26 | int edac_mc_get_log_ue(void) | ||
27 | { | ||
28 | return edac_mc_log_ue; | ||
29 | } | ||
30 | |||
31 | int edac_mc_get_log_ce(void) | ||
32 | { | ||
33 | return edac_mc_log_ce; | ||
34 | } | ||
35 | |||
36 | int edac_mc_get_panic_on_ue(void) | ||
37 | { | ||
38 | return edac_mc_panic_on_ue; | ||
39 | } | ||
40 | |||
41 | /* this is temporary */ | ||
42 | int edac_mc_get_poll_msec(void) | ||
43 | { | ||
44 | return edac_mc_poll_msec; | ||
45 | } | ||
46 | |||
47 | /* Parameter declarations for above */ | ||
48 | module_param(edac_mc_panic_on_ue, int, 0644); | ||
49 | MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on"); | ||
50 | module_param(edac_mc_log_ue, int, 0644); | ||
51 | MODULE_PARM_DESC(edac_mc_log_ue, | ||
52 | "Log uncorrectable error to console: 0=off 1=on"); | ||
53 | module_param(edac_mc_log_ce, int, 0644); | ||
54 | MODULE_PARM_DESC(edac_mc_log_ce, | ||
55 | "Log correctable error to console: 0=off 1=on"); | ||
56 | module_param(edac_mc_poll_msec, int, 0644); | ||
57 | MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); | ||
58 | |||
59 | /* | ||
60 | * various constants for Memory Controllers | ||
61 | */ | ||
62 | static const char *mem_types[] = { | ||
63 | [MEM_EMPTY] = "Empty", | ||
64 | [MEM_RESERVED] = "Reserved", | ||
65 | [MEM_UNKNOWN] = "Unknown", | ||
66 | [MEM_FPM] = "FPM", | ||
67 | [MEM_EDO] = "EDO", | ||
68 | [MEM_BEDO] = "BEDO", | ||
69 | [MEM_SDR] = "Unbuffered-SDR", | ||
70 | [MEM_RDR] = "Registered-SDR", | ||
71 | [MEM_DDR] = "Unbuffered-DDR", | ||
72 | [MEM_RDDR] = "Registered-DDR", | ||
73 | [MEM_RMBS] = "RMBS", | ||
74 | [MEM_DDR2] = "Unbuffered-DDR2", | ||
75 | [MEM_FB_DDR2] = "FullyBuffered-DDR2", | ||
76 | [MEM_RDDR2] = "Registered-DDR2" | ||
77 | }; | ||
78 | |||
79 | static const char *dev_types[] = { | ||
80 | [DEV_UNKNOWN] = "Unknown", | ||
81 | [DEV_X1] = "x1", | ||
82 | [DEV_X2] = "x2", | ||
83 | [DEV_X4] = "x4", | ||
84 | [DEV_X8] = "x8", | ||
85 | [DEV_X16] = "x16", | ||
86 | [DEV_X32] = "x32", | ||
87 | [DEV_X64] = "x64" | ||
88 | }; | ||
89 | |||
90 | static const char *edac_caps[] = { | ||
91 | [EDAC_UNKNOWN] = "Unknown", | ||
92 | [EDAC_NONE] = "None", | ||
93 | [EDAC_RESERVED] = "Reserved", | ||
94 | [EDAC_PARITY] = "PARITY", | ||
95 | [EDAC_EC] = "EC", | ||
96 | [EDAC_SECDED] = "SECDED", | ||
97 | [EDAC_S2ECD2ED] = "S2ECD2ED", | ||
98 | [EDAC_S4ECD4ED] = "S4ECD4ED", | ||
99 | [EDAC_S8ECD8ED] = "S8ECD8ED", | ||
100 | [EDAC_S16ECD16ED] = "S16ECD16ED" | ||
101 | }; | ||
102 | |||
103 | |||
104 | |||
105 | /* | ||
106 | * /sys/devices/system/edac/mc; | ||
107 | * data structures and methods | ||
108 | */ | ||
109 | static ssize_t memctrl_int_show(void *ptr, char *buffer) | ||
110 | { | ||
111 | int *value = (int *)ptr; | ||
112 | return sprintf(buffer, "%u\n", *value); | ||
113 | } | ||
114 | |||
115 | static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) | ||
116 | { | ||
117 | int *value = (int *)ptr; | ||
118 | |||
119 | if (isdigit(*buffer)) | ||
120 | *value = simple_strtoul(buffer, NULL, 0); | ||
121 | |||
122 | return count; | ||
123 | } | ||
124 | |||
125 | |||
126 | /* EDAC sysfs CSROW data structures and methods | ||
127 | */ | ||
128 | |||
129 | /* Set of more default csrow<id> attribute show/store functions */ | ||
130 | static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, | ||
131 | int private) | ||
132 | { | ||
133 | return sprintf(data, "%u\n", csrow->ue_count); | ||
134 | } | ||
135 | |||
136 | static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, | ||
137 | int private) | ||
138 | { | ||
139 | return sprintf(data, "%u\n", csrow->ce_count); | ||
140 | } | ||
141 | |||
142 | static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, | ||
143 | int private) | ||
144 | { | ||
145 | return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages)); | ||
146 | } | ||
147 | |||
148 | static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, | ||
149 | int private) | ||
150 | { | ||
151 | return sprintf(data, "%s\n", mem_types[csrow->mtype]); | ||
152 | } | ||
153 | |||
154 | static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, | ||
155 | int private) | ||
156 | { | ||
157 | return sprintf(data, "%s\n", dev_types[csrow->dtype]); | ||
158 | } | ||
159 | |||
160 | static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, | ||
161 | int private) | ||
162 | { | ||
163 | return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]); | ||
164 | } | ||
165 | |||
166 | /* show/store functions for DIMM Label attributes */ | ||
167 | static ssize_t channel_dimm_label_show(struct csrow_info *csrow, | ||
168 | char *data, int channel) | ||
169 | { | ||
170 | return snprintf(data, EDAC_MC_LABEL_LEN, "%s", | ||
171 | csrow->channels[channel].label); | ||
172 | } | ||
173 | |||
174 | static ssize_t channel_dimm_label_store(struct csrow_info *csrow, | ||
175 | const char *data, | ||
176 | size_t count, int channel) | ||
177 | { | ||
178 | ssize_t max_size = 0; | ||
179 | |||
180 | max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); | ||
181 | strncpy(csrow->channels[channel].label, data, max_size); | ||
182 | csrow->channels[channel].label[max_size] = '\0'; | ||
183 | |||
184 | return max_size; | ||
185 | } | ||
186 | |||
187 | /* show function for dynamic chX_ce_count attribute */ | ||
188 | static ssize_t channel_ce_count_show(struct csrow_info *csrow, | ||
189 | char *data, int channel) | ||
190 | { | ||
191 | return sprintf(data, "%u\n", csrow->channels[channel].ce_count); | ||
192 | } | ||
193 | |||
194 | /* csrow specific attribute structure */ | ||
195 | struct csrowdev_attribute { | ||
196 | struct attribute attr; | ||
197 | ssize_t(*show) (struct csrow_info *, char *, int); | ||
198 | ssize_t(*store) (struct csrow_info *, const char *, size_t, int); | ||
199 | int private; | ||
200 | }; | ||
201 | |||
202 | #define to_csrow(k) container_of(k, struct csrow_info, kobj) | ||
203 | #define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) | ||
204 | |||
205 | /* Set of show/store higher level functions for default csrow attributes */ | ||
206 | static ssize_t csrowdev_show(struct kobject *kobj, | ||
207 | struct attribute *attr, char *buffer) | ||
208 | { | ||
209 | struct csrow_info *csrow = to_csrow(kobj); | ||
210 | struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); | ||
211 | |||
212 | if (csrowdev_attr->show) | ||
213 | return csrowdev_attr->show(csrow, | ||
214 | buffer, csrowdev_attr->private); | ||
215 | return -EIO; | ||
216 | } | ||
217 | |||
218 | static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, | ||
219 | const char *buffer, size_t count) | ||
220 | { | ||
221 | struct csrow_info *csrow = to_csrow(kobj); | ||
222 | struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); | ||
223 | |||
224 | if (csrowdev_attr->store) | ||
225 | return csrowdev_attr->store(csrow, | ||
226 | buffer, | ||
227 | count, csrowdev_attr->private); | ||
228 | return -EIO; | ||
229 | } | ||
230 | |||
231 | static struct sysfs_ops csrowfs_ops = { | ||
232 | .show = csrowdev_show, | ||
233 | .store = csrowdev_store | ||
234 | }; | ||
235 | |||
236 | #define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \ | ||
237 | static struct csrowdev_attribute attr_##_name = { \ | ||
238 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
239 | .show = _show, \ | ||
240 | .store = _store, \ | ||
241 | .private = _private, \ | ||
242 | }; | ||
243 | |||
244 | /* default cwrow<id>/attribute files */ | ||
245 | CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0); | ||
246 | CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0); | ||
247 | CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0); | ||
248 | CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0); | ||
249 | CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0); | ||
250 | CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0); | ||
251 | |||
252 | /* default attributes of the CSROW<id> object */ | ||
253 | static struct csrowdev_attribute *default_csrow_attr[] = { | ||
254 | &attr_dev_type, | ||
255 | &attr_mem_type, | ||
256 | &attr_edac_mode, | ||
257 | &attr_size_mb, | ||
258 | &attr_ue_count, | ||
259 | &attr_ce_count, | ||
260 | NULL, | ||
261 | }; | ||
262 | |||
263 | /* possible dynamic channel DIMM Label attribute files */ | ||
264 | CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR, | ||
265 | channel_dimm_label_show, channel_dimm_label_store, 0); | ||
266 | CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR, | ||
267 | channel_dimm_label_show, channel_dimm_label_store, 1); | ||
268 | CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR, | ||
269 | channel_dimm_label_show, channel_dimm_label_store, 2); | ||
270 | CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR, | ||
271 | channel_dimm_label_show, channel_dimm_label_store, 3); | ||
272 | CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR, | ||
273 | channel_dimm_label_show, channel_dimm_label_store, 4); | ||
274 | CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR, | ||
275 | channel_dimm_label_show, channel_dimm_label_store, 5); | ||
276 | |||
277 | /* Total possible dynamic DIMM Label attribute file table */ | ||
278 | static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = { | ||
279 | &attr_ch0_dimm_label, | ||
280 | &attr_ch1_dimm_label, | ||
281 | &attr_ch2_dimm_label, | ||
282 | &attr_ch3_dimm_label, | ||
283 | &attr_ch4_dimm_label, | ||
284 | &attr_ch5_dimm_label | ||
285 | }; | ||
286 | |||
287 | /* possible dynamic channel ce_count attribute files */ | ||
288 | CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0); | ||
289 | CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1); | ||
290 | CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2); | ||
291 | CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3); | ||
292 | CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4); | ||
293 | CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5); | ||
294 | |||
295 | /* Total possible dynamic ce_count attribute file table */ | ||
296 | static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = { | ||
297 | &attr_ch0_ce_count, | ||
298 | &attr_ch1_ce_count, | ||
299 | &attr_ch2_ce_count, | ||
300 | &attr_ch3_ce_count, | ||
301 | &attr_ch4_ce_count, | ||
302 | &attr_ch5_ce_count | ||
303 | }; | ||
304 | |||
305 | #define EDAC_NR_CHANNELS 6 | ||
306 | |||
307 | /* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */ | ||
308 | static int edac_create_channel_files(struct kobject *kobj, int chan) | ||
309 | { | ||
310 | int err = -ENODEV; | ||
311 | |||
312 | if (chan >= EDAC_NR_CHANNELS) | ||
313 | return err; | ||
314 | |||
315 | /* create the DIMM label attribute file */ | ||
316 | err = sysfs_create_file(kobj, | ||
317 | (struct attribute *) | ||
318 | dynamic_csrow_dimm_attr[chan]); | ||
319 | |||
320 | if (!err) { | ||
321 | /* create the CE Count attribute file */ | ||
322 | err = sysfs_create_file(kobj, | ||
323 | (struct attribute *) | ||
324 | dynamic_csrow_ce_count_attr[chan]); | ||
325 | } else { | ||
326 | debugf1("%s() dimm labels and ce_count files created", | ||
327 | __func__); | ||
328 | } | ||
329 | |||
330 | return err; | ||
331 | } | ||
332 | |||
333 | /* No memory to release for this kobj */ | ||
334 | static void edac_csrow_instance_release(struct kobject *kobj) | ||
335 | { | ||
336 | struct mem_ctl_info *mci; | ||
337 | struct csrow_info *cs; | ||
338 | |||
339 | debugf1("%s()\n", __func__); | ||
340 | |||
341 | cs = container_of(kobj, struct csrow_info, kobj); | ||
342 | mci = cs->mci; | ||
343 | |||
344 | kobject_put(&mci->edac_mci_kobj); | ||
345 | } | ||
346 | |||
347 | /* the kobj_type instance for a CSROW */ | ||
348 | static struct kobj_type ktype_csrow = { | ||
349 | .release = edac_csrow_instance_release, | ||
350 | .sysfs_ops = &csrowfs_ops, | ||
351 | .default_attrs = (struct attribute **)default_csrow_attr, | ||
352 | }; | ||
353 | |||
354 | /* Create a CSROW object under specifed edac_mc_device */ | ||
355 | static int edac_create_csrow_object(struct mem_ctl_info *mci, | ||
356 | struct csrow_info *csrow, int index) | ||
357 | { | ||
358 | struct kobject *kobj_mci = &mci->edac_mci_kobj; | ||
359 | struct kobject *kobj; | ||
360 | int chan; | ||
361 | int err; | ||
362 | |||
363 | /* generate ..../edac/mc/mc<id>/csrow<index> */ | ||
364 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); | ||
365 | csrow->mci = mci; /* include container up link */ | ||
366 | csrow->kobj.parent = kobj_mci; | ||
367 | csrow->kobj.ktype = &ktype_csrow; | ||
368 | |||
369 | /* name this instance of csrow<id> */ | ||
370 | err = kobject_set_name(&csrow->kobj, "csrow%d", index); | ||
371 | if (err) | ||
372 | goto err_out; | ||
373 | |||
374 | /* bump the mci instance's kobject's ref count */ | ||
375 | kobj = kobject_get(&mci->edac_mci_kobj); | ||
376 | if (!kobj) { | ||
377 | err = -ENODEV; | ||
378 | goto err_out; | ||
379 | } | ||
380 | |||
381 | /* Instanstiate the csrow object */ | ||
382 | err = kobject_register(&csrow->kobj); | ||
383 | if (err) | ||
384 | goto err_release_top_kobj; | ||
385 | |||
386 | /* At this point, to release a csrow kobj, one must | ||
387 | * call the kobject_unregister and allow that tear down | ||
388 | * to work the releasing | ||
389 | */ | ||
390 | |||
391 | /* Create the dyanmic attribute files on this csrow, | ||
392 | * namely, the DIMM labels and the channel ce_count | ||
393 | */ | ||
394 | for (chan = 0; chan < csrow->nr_channels; chan++) { | ||
395 | err = edac_create_channel_files(&csrow->kobj, chan); | ||
396 | if (err) { | ||
397 | /* special case the unregister here */ | ||
398 | kobject_unregister(&csrow->kobj); | ||
399 | goto err_out; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | |||
405 | /* error unwind stack */ | ||
406 | err_release_top_kobj: | ||
407 | kobject_put(&mci->edac_mci_kobj); | ||
408 | |||
409 | err_out: | ||
410 | return err; | ||
411 | } | ||
412 | |||
413 | /* default sysfs methods and data structures for the main MCI kobject */ | ||
414 | |||
415 | static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, | ||
416 | const char *data, size_t count) | ||
417 | { | ||
418 | int row, chan; | ||
419 | |||
420 | mci->ue_noinfo_count = 0; | ||
421 | mci->ce_noinfo_count = 0; | ||
422 | mci->ue_count = 0; | ||
423 | mci->ce_count = 0; | ||
424 | |||
425 | for (row = 0; row < mci->nr_csrows; row++) { | ||
426 | struct csrow_info *ri = &mci->csrows[row]; | ||
427 | |||
428 | ri->ue_count = 0; | ||
429 | ri->ce_count = 0; | ||
430 | |||
431 | for (chan = 0; chan < ri->nr_channels; chan++) | ||
432 | ri->channels[chan].ce_count = 0; | ||
433 | } | ||
434 | |||
435 | mci->start_time = jiffies; | ||
436 | return count; | ||
437 | } | ||
438 | |||
439 | /* memory scrubbing */ | ||
440 | static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, | ||
441 | const char *data, size_t count) | ||
442 | { | ||
443 | u32 bandwidth = -1; | ||
444 | |||
445 | if (mci->set_sdram_scrub_rate) { | ||
446 | |||
447 | memctrl_int_store(&bandwidth, data, count); | ||
448 | |||
449 | if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) { | ||
450 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
451 | "Scrub rate set successfully, applied: %d\n", | ||
452 | bandwidth); | ||
453 | } else { | ||
454 | /* FIXME: error codes maybe? */ | ||
455 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
456 | "Scrub rate set FAILED, could not apply: %d\n", | ||
457 | bandwidth); | ||
458 | } | ||
459 | } else { | ||
460 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
461 | edac_printk(KERN_WARNING, EDAC_MC, | ||
462 | "Memory scrubbing 'set'control is not implemented!\n"); | ||
463 | } | ||
464 | return count; | ||
465 | } | ||
466 | |||
467 | static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) | ||
468 | { | ||
469 | u32 bandwidth = -1; | ||
470 | |||
471 | if (mci->get_sdram_scrub_rate) { | ||
472 | if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) { | ||
473 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
474 | "Scrub rate successfully, fetched: %d\n", | ||
475 | bandwidth); | ||
476 | } else { | ||
477 | /* FIXME: error codes maybe? */ | ||
478 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
479 | "Scrub rate fetch FAILED, got: %d\n", | ||
480 | bandwidth); | ||
481 | } | ||
482 | } else { | ||
483 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
484 | edac_printk(KERN_WARNING, EDAC_MC, | ||
485 | "Memory scrubbing 'get' control is not implemented\n"); | ||
486 | } | ||
487 | return sprintf(data, "%d\n", bandwidth); | ||
488 | } | ||
489 | |||
490 | /* default attribute files for the MCI object */ | ||
491 | static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) | ||
492 | { | ||
493 | return sprintf(data, "%d\n", mci->ue_count); | ||
494 | } | ||
495 | |||
496 | static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) | ||
497 | { | ||
498 | return sprintf(data, "%d\n", mci->ce_count); | ||
499 | } | ||
500 | |||
501 | static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) | ||
502 | { | ||
503 | return sprintf(data, "%d\n", mci->ce_noinfo_count); | ||
504 | } | ||
505 | |||
506 | static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data) | ||
507 | { | ||
508 | return sprintf(data, "%d\n", mci->ue_noinfo_count); | ||
509 | } | ||
510 | |||
511 | static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data) | ||
512 | { | ||
513 | return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ); | ||
514 | } | ||
515 | |||
516 | static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) | ||
517 | { | ||
518 | return sprintf(data, "%s\n", mci->ctl_name); | ||
519 | } | ||
520 | |||
521 | static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) | ||
522 | { | ||
523 | int total_pages, csrow_idx; | ||
524 | |||
525 | for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows; | ||
526 | csrow_idx++) { | ||
527 | struct csrow_info *csrow = &mci->csrows[csrow_idx]; | ||
528 | |||
529 | if (!csrow->nr_pages) | ||
530 | continue; | ||
531 | |||
532 | total_pages += csrow->nr_pages; | ||
533 | } | ||
534 | |||
535 | return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages)); | ||
536 | } | ||
537 | |||
538 | #define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) | ||
539 | #define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr) | ||
540 | |||
541 | /* MCI show/store functions for top most object */ | ||
542 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, | ||
543 | char *buffer) | ||
544 | { | ||
545 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | ||
546 | struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); | ||
547 | |||
548 | if (mcidev_attr->show) | ||
549 | return mcidev_attr->show(mem_ctl_info, buffer); | ||
550 | |||
551 | return -EIO; | ||
552 | } | ||
553 | |||
554 | static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, | ||
555 | const char *buffer, size_t count) | ||
556 | { | ||
557 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | ||
558 | struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); | ||
559 | |||
560 | if (mcidev_attr->store) | ||
561 | return mcidev_attr->store(mem_ctl_info, buffer, count); | ||
562 | |||
563 | return -EIO; | ||
564 | } | ||
565 | |||
566 | /* Intermediate show/store table */ | ||
567 | static struct sysfs_ops mci_ops = { | ||
568 | .show = mcidev_show, | ||
569 | .store = mcidev_store | ||
570 | }; | ||
571 | |||
572 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ | ||
573 | static struct mcidev_sysfs_attribute mci_attr_##_name = { \ | ||
574 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
575 | .show = _show, \ | ||
576 | .store = _store, \ | ||
577 | }; | ||
578 | |||
579 | /* default Control file */ | ||
580 | MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); | ||
581 | |||
582 | /* default Attribute files */ | ||
583 | MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL); | ||
584 | MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL); | ||
585 | MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL); | ||
586 | MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL); | ||
587 | MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL); | ||
588 | MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL); | ||
589 | MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); | ||
590 | |||
591 | /* memory scrubber attribute file */ | ||
592 | MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show, | ||
593 | mci_sdram_scrub_rate_store); | ||
594 | |||
595 | static struct mcidev_sysfs_attribute *mci_attr[] = { | ||
596 | &mci_attr_reset_counters, | ||
597 | &mci_attr_mc_name, | ||
598 | &mci_attr_size_mb, | ||
599 | &mci_attr_seconds_since_reset, | ||
600 | &mci_attr_ue_noinfo_count, | ||
601 | &mci_attr_ce_noinfo_count, | ||
602 | &mci_attr_ue_count, | ||
603 | &mci_attr_ce_count, | ||
604 | &mci_attr_sdram_scrub_rate, | ||
605 | NULL | ||
606 | }; | ||
607 | |||
608 | |||
609 | /* | ||
610 | * Release of a MC controlling instance | ||
611 | * | ||
612 | * each MC control instance has the following resources upon entry: | ||
613 | * a) a ref count on the top memctl kobj | ||
614 | * b) a ref count on this module | ||
615 | * | ||
616 | * this function must decrement those ref counts and then | ||
617 | * issue a free on the instance's memory | ||
618 | */ | ||
619 | static void edac_mci_control_release(struct kobject *kobj) | ||
620 | { | ||
621 | struct mem_ctl_info *mci; | ||
622 | |||
623 | mci = to_mci(kobj); | ||
624 | |||
625 | debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx); | ||
626 | |||
627 | /* decrement the module ref count */ | ||
628 | module_put(mci->owner); | ||
629 | |||
630 | /* free the mci instance memory here */ | ||
631 | kfree(mci); | ||
632 | } | ||
633 | |||
634 | static struct kobj_type ktype_mci = { | ||
635 | .release = edac_mci_control_release, | ||
636 | .sysfs_ops = &mci_ops, | ||
637 | .default_attrs = (struct attribute **)mci_attr, | ||
638 | }; | ||
639 | |||
640 | /* show/store, tables, etc for the MC kset */ | ||
641 | |||
642 | |||
643 | struct memctrl_dev_attribute { | ||
644 | struct attribute attr; | ||
645 | void *value; | ||
646 | ssize_t(*show) (void *, char *); | ||
647 | ssize_t(*store) (void *, const char *, size_t); | ||
648 | }; | ||
649 | |||
650 | /* Set of show/store abstract level functions for memory control object */ | ||
651 | static ssize_t memctrl_dev_show(struct kobject *kobj, | ||
652 | struct attribute *attr, char *buffer) | ||
653 | { | ||
654 | struct memctrl_dev_attribute *memctrl_dev; | ||
655 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
656 | |||
657 | if (memctrl_dev->show) | ||
658 | return memctrl_dev->show(memctrl_dev->value, buffer); | ||
659 | |||
660 | return -EIO; | ||
661 | } | ||
662 | |||
663 | static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, | ||
664 | const char *buffer, size_t count) | ||
665 | { | ||
666 | struct memctrl_dev_attribute *memctrl_dev; | ||
667 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
668 | |||
669 | if (memctrl_dev->store) | ||
670 | return memctrl_dev->store(memctrl_dev->value, buffer, count); | ||
671 | |||
672 | return -EIO; | ||
673 | } | ||
674 | |||
675 | static struct sysfs_ops memctrlfs_ops = { | ||
676 | .show = memctrl_dev_show, | ||
677 | .store = memctrl_dev_store | ||
678 | }; | ||
679 | |||
680 | #define MEMCTRL_ATTR(_name, _mode, _show, _store) \ | ||
681 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
682 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
683 | .value = &_name, \ | ||
684 | .show = _show, \ | ||
685 | .store = _store, \ | ||
686 | }; | ||
687 | |||
688 | #define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store) \ | ||
689 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
690 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
691 | .value = _data, \ | ||
692 | .show = _show, \ | ||
693 | .store = _store, \ | ||
694 | }; | ||
695 | |||
696 | /* csrow<id> control files */ | ||
697 | MEMCTRL_ATTR(edac_mc_panic_on_ue, | ||
698 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
699 | |||
700 | MEMCTRL_ATTR(edac_mc_log_ue, | ||
701 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
702 | |||
703 | MEMCTRL_ATTR(edac_mc_log_ce, | ||
704 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
705 | |||
706 | MEMCTRL_ATTR(edac_mc_poll_msec, | ||
707 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
708 | |||
709 | /* Base Attributes of the memory ECC object */ | ||
710 | static struct memctrl_dev_attribute *memctrl_attr[] = { | ||
711 | &attr_edac_mc_panic_on_ue, | ||
712 | &attr_edac_mc_log_ue, | ||
713 | &attr_edac_mc_log_ce, | ||
714 | &attr_edac_mc_poll_msec, | ||
715 | NULL, | ||
716 | }; | ||
717 | |||
718 | |||
719 | /* the ktype for the mc_kset internal kobj */ | ||
720 | static struct kobj_type ktype_mc_set_attribs = { | ||
721 | .sysfs_ops = &memctrlfs_ops, | ||
722 | .default_attrs = (struct attribute **)memctrl_attr, | ||
723 | }; | ||
724 | |||
725 | /* EDAC memory controller sysfs kset: | ||
726 | * /sys/devices/system/edac/mc | ||
727 | */ | ||
728 | static struct kset mc_kset = { | ||
729 | .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, | ||
730 | .ktype = &ktype_mci, | ||
731 | }; | ||
732 | |||
733 | |||
734 | /* | ||
735 | * edac_mc_register_sysfs_main_kobj | ||
736 | * | ||
737 | * setups and registers the main kobject for each mci | ||
738 | */ | ||
739 | int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) | ||
740 | { | ||
741 | struct kobject *kobj_mci; | ||
742 | int err; | ||
743 | |||
744 | debugf1("%s()\n", __func__); | ||
745 | |||
746 | kobj_mci = &mci->edac_mci_kobj; | ||
747 | |||
748 | /* Init the mci's kobject */ | ||
749 | memset(kobj_mci, 0, sizeof(*kobj_mci)); | ||
750 | |||
751 | /* this instance become part of the mc_kset */ | ||
752 | kobj_mci->kset = &mc_kset; | ||
753 | |||
754 | /* set the name of the mc<id> object */ | ||
755 | err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx); | ||
756 | if (err) | ||
757 | goto fail_out; | ||
758 | |||
759 | /* Record which module 'owns' this control structure | ||
760 | * and bump the ref count of the module | ||
761 | */ | ||
762 | mci->owner = THIS_MODULE; | ||
763 | |||
764 | /* bump ref count on this module */ | ||
765 | if (!try_module_get(mci->owner)) { | ||
766 | err = -ENODEV; | ||
767 | goto fail_out; | ||
768 | } | ||
769 | |||
770 | /* register the mc<id> kobject to the mc_kset */ | ||
771 | err = kobject_register(kobj_mci); | ||
772 | if (err) { | ||
773 | debugf1("%s()Failed to register '.../edac/mc%d'\n", | ||
774 | __func__, mci->mc_idx); | ||
775 | goto kobj_reg_fail; | ||
776 | } | ||
777 | |||
778 | /* At this point, to 'free' the control struct, | ||
779 | * edac_mc_unregister_sysfs_main_kobj() must be used | ||
780 | */ | ||
781 | |||
782 | debugf1("%s() Registered '.../edac/mc%d' kobject\n", | ||
783 | __func__, mci->mc_idx); | ||
784 | |||
785 | return 0; | ||
786 | |||
787 | /* Error exit stack */ | ||
788 | |||
789 | kobj_reg_fail: | ||
790 | module_put(mci->owner); | ||
791 | |||
792 | fail_out: | ||
793 | return err; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * edac_mc_register_sysfs_main_kobj | ||
798 | * | ||
799 | * tears down and the main mci kobject from the mc_kset | ||
800 | */ | ||
801 | void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) | ||
802 | { | ||
803 | /* delete the kobj from the mc_kset */ | ||
804 | kobject_unregister(&mci->edac_mci_kobj); | ||
805 | } | ||
806 | |||
807 | #define EDAC_DEVICE_SYMLINK "device" | ||
808 | |||
809 | /* | ||
810 | * edac_create_mci_instance_attributes | ||
811 | * create MC driver specific attributes at the topmost level | ||
812 | * directory of this mci instance. | ||
813 | */ | ||
814 | static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) | ||
815 | { | ||
816 | int err; | ||
817 | struct mcidev_sysfs_attribute *sysfs_attrib; | ||
818 | |||
819 | /* point to the start of the array and iterate over it | ||
820 | * adding each attribute listed to this mci instance's kobject | ||
821 | */ | ||
822 | sysfs_attrib = mci->mc_driver_sysfs_attributes; | ||
823 | |||
824 | while (sysfs_attrib && sysfs_attrib->attr.name) { | ||
825 | err = sysfs_create_file(&mci->edac_mci_kobj, | ||
826 | (struct attribute*) sysfs_attrib); | ||
827 | if (err) { | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | sysfs_attrib++; | ||
832 | } | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | /* | ||
838 | * edac_remove_mci_instance_attributes | ||
839 | * remove MC driver specific attributes at the topmost level | ||
840 | * directory of this mci instance. | ||
841 | */ | ||
842 | static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci) | ||
843 | { | ||
844 | struct mcidev_sysfs_attribute *sysfs_attrib; | ||
845 | |||
846 | /* point to the start of the array and iterate over it | ||
847 | * adding each attribute listed to this mci instance's kobject | ||
848 | */ | ||
849 | sysfs_attrib = mci->mc_driver_sysfs_attributes; | ||
850 | |||
851 | /* loop if there are attributes and until we hit a NULL entry */ | ||
852 | while (sysfs_attrib && sysfs_attrib->attr.name) { | ||
853 | sysfs_remove_file(&mci->edac_mci_kobj, | ||
854 | (struct attribute *) sysfs_attrib); | ||
855 | sysfs_attrib++; | ||
856 | } | ||
857 | } | ||
858 | |||
859 | |||
860 | /* | ||
861 | * Create a new Memory Controller kobject instance, | ||
862 | * mc<id> under the 'mc' directory | ||
863 | * | ||
864 | * Return: | ||
865 | * 0 Success | ||
866 | * !0 Failure | ||
867 | */ | ||
868 | int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | ||
869 | { | ||
870 | int i; | ||
871 | int err; | ||
872 | struct csrow_info *csrow; | ||
873 | struct kobject *kobj_mci = &mci->edac_mci_kobj; | ||
874 | |||
875 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | ||
876 | |||
877 | /* create a symlink for the device */ | ||
878 | err = sysfs_create_link(kobj_mci, &mci->dev->kobj, | ||
879 | EDAC_DEVICE_SYMLINK); | ||
880 | if (err) { | ||
881 | debugf1("%s() failure to create symlink\n", __func__); | ||
882 | goto fail0; | ||
883 | } | ||
884 | |||
885 | /* If the low level driver desires some attributes, | ||
886 | * then create them now for the driver. | ||
887 | */ | ||
888 | if (mci->mc_driver_sysfs_attributes) { | ||
889 | err = edac_create_mci_instance_attributes(mci); | ||
890 | if (err) { | ||
891 | debugf1("%s() failure to create mci attributes\n", | ||
892 | __func__); | ||
893 | goto fail0; | ||
894 | } | ||
895 | } | ||
896 | |||
897 | /* Make directories for each CSROW object under the mc<id> kobject | ||
898 | */ | ||
899 | for (i = 0; i < mci->nr_csrows; i++) { | ||
900 | csrow = &mci->csrows[i]; | ||
901 | |||
902 | /* Only expose populated CSROWs */ | ||
903 | if (csrow->nr_pages > 0) { | ||
904 | err = edac_create_csrow_object(mci, csrow, i); | ||
905 | if (err) { | ||
906 | debugf1("%s() failure: create csrow %d obj\n", | ||
907 | __func__, i); | ||
908 | goto fail1; | ||
909 | } | ||
910 | } | ||
911 | } | ||
912 | |||
913 | return 0; | ||
914 | |||
915 | /* CSROW error: backout what has already been registered, */ | ||
916 | fail1: | ||
917 | for (i--; i >= 0; i--) { | ||
918 | if (csrow->nr_pages > 0) { | ||
919 | kobject_unregister(&mci->csrows[i].kobj); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | /* remove the mci instance's attributes, if any */ | ||
924 | edac_remove_mci_instance_attributes(mci); | ||
925 | |||
926 | /* remove the symlink */ | ||
927 | sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); | ||
928 | |||
929 | fail0: | ||
930 | return err; | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * remove a Memory Controller instance | ||
935 | */ | ||
936 | void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | ||
937 | { | ||
938 | int i; | ||
939 | |||
940 | debugf0("%s()\n", __func__); | ||
941 | |||
942 | /* remove all csrow kobjects */ | ||
943 | for (i = 0; i < mci->nr_csrows; i++) { | ||
944 | if (mci->csrows[i].nr_pages > 0) { | ||
945 | debugf0("%s() unreg csrow-%d\n", __func__, i); | ||
946 | kobject_unregister(&mci->csrows[i].kobj); | ||
947 | } | ||
948 | } | ||
949 | |||
950 | debugf0("%s() remove_link\n", __func__); | ||
951 | |||
952 | /* remove the symlink */ | ||
953 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | ||
954 | |||
955 | debugf0("%s() remove_mci_instance\n", __func__); | ||
956 | |||
957 | /* remove this mci instance's attribtes */ | ||
958 | edac_remove_mci_instance_attributes(mci); | ||
959 | |||
960 | debugf0("%s() unregister this mci kobj\n", __func__); | ||
961 | |||
962 | /* unregister this instance's kobject */ | ||
963 | kobject_unregister(&mci->edac_mci_kobj); | ||
964 | } | ||
965 | |||
966 | |||
967 | |||
968 | |||
969 | /* | ||
970 | * edac_setup_sysfs_mc_kset(void) | ||
971 | * | ||
972 | * Initialize the mc_kset for the 'mc' entry | ||
973 | * This requires creating the top 'mc' directory with a kset | ||
974 | * and its controls/attributes. | ||
975 | * | ||
976 | * To this 'mc' kset, instance 'mci' will be grouped as children. | ||
977 | * | ||
978 | * Return: 0 SUCCESS | ||
979 | * !0 FAILURE error code | ||
980 | */ | ||
981 | int edac_sysfs_setup_mc_kset(void) | ||
982 | { | ||
983 | int err = 0; | ||
984 | struct sysdev_class *edac_class; | ||
985 | |||
986 | debugf1("%s()\n", __func__); | ||
987 | |||
988 | /* get the /sys/devices/system/edac class reference */ | ||
989 | edac_class = edac_get_edac_class(); | ||
990 | if (edac_class == NULL) { | ||
991 | debugf1("%s() no edac_class error=%d\n", __func__, err); | ||
992 | goto fail_out; | ||
993 | } | ||
994 | |||
995 | /* Init the MC's kobject */ | ||
996 | mc_kset.kobj.parent = &edac_class->kset.kobj; | ||
997 | |||
998 | /* register the mc_kset */ | ||
999 | err = kset_register(&mc_kset); | ||
1000 | if (err) { | ||
1001 | debugf1("%s() Failed to register '.../edac/mc'\n", __func__); | ||
1002 | goto fail_out; | ||
1003 | } | ||
1004 | |||
1005 | debugf1("%s() Registered '.../edac/mc' kobject\n", __func__); | ||
1006 | |||
1007 | return 0; | ||
1008 | |||
1009 | |||
1010 | /* error unwind stack */ | ||
1011 | fail_out: | ||
1012 | return err; | ||
1013 | } | ||
1014 | |||
1015 | /* | ||
1016 | * edac_sysfs_teardown_mc_kset | ||
1017 | * | ||
1018 | * deconstruct the mc_ket for memory controllers | ||
1019 | */ | ||
1020 | void edac_sysfs_teardown_mc_kset(void) | ||
1021 | { | ||
1022 | kset_unregister(&mc_kset); | ||
1023 | } | ||
1024 | |||
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c new file mode 100644 index 000000000000..e0c4a4086055 --- /dev/null +++ b/drivers/edac/edac_module.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * edac_module.c | ||
3 | * | ||
4 | * (C) 2007 www.softwarebitmaker.com | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | * | ||
10 | * Author: Doug Thompson <dougthompson@xmission.com> | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/edac.h> | ||
14 | |||
15 | #include "edac_core.h" | ||
16 | #include "edac_module.h" | ||
17 | |||
18 | #define EDAC_VERSION "Ver: 2.1.0 " __DATE__ | ||
19 | |||
20 | #ifdef CONFIG_EDAC_DEBUG | ||
21 | /* Values of 0 to 4 will generate output */ | ||
22 | int edac_debug_level = 2; | ||
23 | EXPORT_SYMBOL_GPL(edac_debug_level); | ||
24 | #endif | ||
25 | |||
26 | /* scope is to module level only */ | ||
27 | struct workqueue_struct *edac_workqueue; | ||
28 | |||
29 | /* | ||
30 | * sysfs object: /sys/devices/system/edac | ||
31 | * need to export to other files in this modules | ||
32 | */ | ||
33 | static struct sysdev_class edac_class = { | ||
34 | set_kset_name("edac"), | ||
35 | }; | ||
36 | static int edac_class_valid; | ||
37 | |||
38 | /* | ||
39 | * edac_op_state_to_string() | ||
40 | */ | ||
41 | char *edac_op_state_to_string(int opstate) | ||
42 | { | ||
43 | if (opstate == OP_RUNNING_POLL) | ||
44 | return "POLLED"; | ||
45 | else if (opstate == OP_RUNNING_INTERRUPT) | ||
46 | return "INTERRUPT"; | ||
47 | else if (opstate == OP_RUNNING_POLL_INTR) | ||
48 | return "POLL-INTR"; | ||
49 | else if (opstate == OP_ALLOC) | ||
50 | return "ALLOC"; | ||
51 | else if (opstate == OP_OFFLINE) | ||
52 | return "OFFLINE"; | ||
53 | |||
54 | return "UNKNOWN"; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * edac_get_edac_class() | ||
59 | * | ||
60 | * return pointer to the edac class of 'edac' | ||
61 | */ | ||
62 | struct sysdev_class *edac_get_edac_class(void) | ||
63 | { | ||
64 | struct sysdev_class *classptr = NULL; | ||
65 | |||
66 | if (edac_class_valid) | ||
67 | classptr = &edac_class; | ||
68 | |||
69 | return classptr; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * edac_register_sysfs_edac_name() | ||
74 | * | ||
75 | * register the 'edac' into /sys/devices/system | ||
76 | * | ||
77 | * return: | ||
78 | * 0 success | ||
79 | * !0 error | ||
80 | */ | ||
81 | static int edac_register_sysfs_edac_name(void) | ||
82 | { | ||
83 | int err; | ||
84 | |||
85 | /* create the /sys/devices/system/edac directory */ | ||
86 | err = sysdev_class_register(&edac_class); | ||
87 | |||
88 | if (err) { | ||
89 | debugf1("%s() error=%d\n", __func__, err); | ||
90 | return err; | ||
91 | } | ||
92 | |||
93 | edac_class_valid = 1; | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * sysdev_class_unregister() | ||
99 | * | ||
100 | * unregister the 'edac' from /sys/devices/system | ||
101 | */ | ||
102 | static void edac_unregister_sysfs_edac_name(void) | ||
103 | { | ||
104 | /* only if currently registered, then unregister it */ | ||
105 | if (edac_class_valid) | ||
106 | sysdev_class_unregister(&edac_class); | ||
107 | |||
108 | edac_class_valid = 0; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * edac_workqueue_setup | ||
113 | * initialize the edac work queue for polling operations | ||
114 | */ | ||
115 | static int edac_workqueue_setup(void) | ||
116 | { | ||
117 | edac_workqueue = create_singlethread_workqueue("edac-poller"); | ||
118 | if (edac_workqueue == NULL) | ||
119 | return -ENODEV; | ||
120 | else | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * edac_workqueue_teardown | ||
126 | * teardown the edac workqueue | ||
127 | */ | ||
128 | static void edac_workqueue_teardown(void) | ||
129 | { | ||
130 | if (edac_workqueue) { | ||
131 | flush_workqueue(edac_workqueue); | ||
132 | destroy_workqueue(edac_workqueue); | ||
133 | edac_workqueue = NULL; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * edac_init | ||
139 | * module initialization entry point | ||
140 | */ | ||
141 | static int __init edac_init(void) | ||
142 | { | ||
143 | int err = 0; | ||
144 | |||
145 | edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); | ||
146 | |||
147 | /* | ||
148 | * Harvest and clear any boot/initialization PCI parity errors | ||
149 | * | ||
150 | * FIXME: This only clears errors logged by devices present at time of | ||
151 | * module initialization. We should also do an initial clear | ||
152 | * of each newly hotplugged device. | ||
153 | */ | ||
154 | edac_pci_clear_parity_errors(); | ||
155 | |||
156 | /* | ||
157 | * perform the registration of the /sys/devices/system/edac class object | ||
158 | */ | ||
159 | if (edac_register_sysfs_edac_name()) { | ||
160 | edac_printk(KERN_ERR, EDAC_MC, | ||
161 | "Error initializing 'edac' kobject\n"); | ||
162 | err = -ENODEV; | ||
163 | goto error; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * now set up the mc_kset under the edac class object | ||
168 | */ | ||
169 | err = edac_sysfs_setup_mc_kset(); | ||
170 | if (err) | ||
171 | goto sysfs_setup_fail; | ||
172 | |||
173 | /* Setup/Initialize the workq for this core */ | ||
174 | err = edac_workqueue_setup(); | ||
175 | if (err) { | ||
176 | edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n"); | ||
177 | goto workq_fail; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | |||
182 | /* Error teardown stack */ | ||
183 | workq_fail: | ||
184 | edac_sysfs_teardown_mc_kset(); | ||
185 | |||
186 | sysfs_setup_fail: | ||
187 | edac_unregister_sysfs_edac_name(); | ||
188 | |||
189 | error: | ||
190 | return err; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * edac_exit() | ||
195 | * module exit/termination function | ||
196 | */ | ||
197 | static void __exit edac_exit(void) | ||
198 | { | ||
199 | debugf0("%s()\n", __func__); | ||
200 | |||
201 | /* tear down the various subsystems */ | ||
202 | edac_workqueue_teardown(); | ||
203 | edac_sysfs_teardown_mc_kset(); | ||
204 | edac_unregister_sysfs_edac_name(); | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * Inform the kernel of our entry and exit points | ||
209 | */ | ||
210 | module_init(edac_init); | ||
211 | module_exit(edac_exit); | ||
212 | |||
213 | MODULE_LICENSE("GPL"); | ||
214 | MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al"); | ||
215 | MODULE_DESCRIPTION("Core library routines for EDAC reporting"); | ||
216 | |||
217 | /* refer to *_sysfs.c files for parameters that are exported via sysfs */ | ||
218 | |||
219 | #ifdef CONFIG_EDAC_DEBUG | ||
220 | module_param(edac_debug_level, int, 0644); | ||
221 | MODULE_PARM_DESC(edac_debug_level, "Debug level"); | ||
222 | #endif | ||
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h new file mode 100644 index 000000000000..a2134dfc3cc6 --- /dev/null +++ b/drivers/edac/edac_module.h | |||
@@ -0,0 +1,77 @@ | |||
1 | |||
2 | /* | ||
3 | * edac_module.h | ||
4 | * | ||
5 | * For defining functions/data for within the EDAC_CORE module only | ||
6 | * | ||
7 | * written by doug thompson <norsk5@xmission.h> | ||
8 | */ | ||
9 | |||
10 | #ifndef __EDAC_MODULE_H__ | ||
11 | #define __EDAC_MODULE_H__ | ||
12 | |||
13 | #include <linux/sysdev.h> | ||
14 | |||
15 | #include "edac_core.h" | ||
16 | |||
17 | /* | ||
18 | * INTERNAL EDAC MODULE: | ||
19 | * EDAC memory controller sysfs create/remove functions | ||
20 | * and setup/teardown functions | ||
21 | * | ||
22 | * edac_mc objects | ||
23 | */ | ||
24 | extern int edac_sysfs_setup_mc_kset(void); | ||
25 | extern void edac_sysfs_teardown_mc_kset(void); | ||
26 | extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci); | ||
27 | extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci); | ||
28 | extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); | ||
29 | extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); | ||
30 | extern void edac_check_mc_devices(void); | ||
31 | extern int edac_get_log_ue(void); | ||
32 | extern int edac_get_log_ce(void); | ||
33 | extern int edac_get_panic_on_ue(void); | ||
34 | extern int edac_mc_get_log_ue(void); | ||
35 | extern int edac_mc_get_log_ce(void); | ||
36 | extern int edac_mc_get_panic_on_ue(void); | ||
37 | extern int edac_get_poll_msec(void); | ||
38 | extern int edac_mc_get_poll_msec(void); | ||
39 | |||
40 | extern int edac_device_register_sysfs_main_kobj( | ||
41 | struct edac_device_ctl_info *edac_dev); | ||
42 | extern void edac_device_unregister_sysfs_main_kobj( | ||
43 | struct edac_device_ctl_info *edac_dev); | ||
44 | extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); | ||
45 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); | ||
46 | extern struct sysdev_class *edac_get_edac_class(void); | ||
47 | |||
48 | /* edac core workqueue: single CPU mode */ | ||
49 | extern struct workqueue_struct *edac_workqueue; | ||
50 | extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | ||
51 | unsigned msec); | ||
52 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); | ||
53 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info | ||
54 | *edac_dev, unsigned long value); | ||
55 | extern void *edac_align_ptr(void *ptr, unsigned size); | ||
56 | |||
57 | /* | ||
58 | * EDAC PCI functions | ||
59 | */ | ||
60 | #ifdef CONFIG_PCI | ||
61 | extern void edac_pci_do_parity_check(void); | ||
62 | extern void edac_pci_clear_parity_errors(void); | ||
63 | extern int edac_sysfs_pci_setup(void); | ||
64 | extern void edac_sysfs_pci_teardown(void); | ||
65 | extern int edac_pci_get_check_errors(void); | ||
66 | extern int edac_pci_get_poll_msec(void); | ||
67 | #else /* CONFIG_PCI */ | ||
68 | /* pre-process these away */ | ||
69 | #define edac_pci_do_parity_check() | ||
70 | #define edac_pci_clear_parity_errors() | ||
71 | #define edac_sysfs_pci_setup() (0) | ||
72 | #define edac_sysfs_pci_teardown() | ||
73 | #define edac_pci_get_check_errors() | ||
74 | #define edac_pci_get_poll_msec() | ||
75 | #endif /* CONFIG_PCI */ | ||
76 | |||
77 | #endif /* __EDAC_MODULE_H__ */ | ||
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c new file mode 100644 index 000000000000..d9cd5e048cee --- /dev/null +++ b/drivers/edac/edac_pci.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * EDAC PCI component | ||
3 | * | ||
4 | * Author: Dave Jiang <djiang@mvista.com> | ||
5 | * | ||
6 | * 2007 (c) MontaVista Software, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | * | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/sysctl.h> | ||
17 | #include <linux/highmem.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/sysdev.h> | ||
23 | #include <linux/ctype.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/page.h> | ||
27 | |||
28 | #include "edac_core.h" | ||
29 | #include "edac_module.h" | ||
30 | |||
31 | static DEFINE_MUTEX(edac_pci_ctls_mutex); | ||
32 | static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list); | ||
33 | |||
34 | static inline void edac_lock_pci_list(void) | ||
35 | { | ||
36 | mutex_lock(&edac_pci_ctls_mutex); | ||
37 | } | ||
38 | |||
39 | static inline void edac_unlock_pci_list(void) | ||
40 | { | ||
41 | mutex_unlock(&edac_pci_ctls_mutex); | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * The alloc() and free() functions for the 'edac_pci' control info | ||
46 | * structure. The chip driver will allocate one of these for each | ||
47 | * edac_pci it is going to control/register with the EDAC CORE. | ||
48 | */ | ||
49 | struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, | ||
50 | const char *edac_pci_name) | ||
51 | { | ||
52 | struct edac_pci_ctl_info *pci; | ||
53 | void *pvt; | ||
54 | unsigned int size; | ||
55 | |||
56 | pci = (struct edac_pci_ctl_info *)0; | ||
57 | pvt = edac_align_ptr(&pci[1], sz_pvt); | ||
58 | size = ((unsigned long)pvt) + sz_pvt; | ||
59 | |||
60 | if ((pci = kzalloc(size, GFP_KERNEL)) == NULL) | ||
61 | return NULL; | ||
62 | |||
63 | pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL; | ||
64 | |||
65 | pci->pvt_info = pvt; | ||
66 | |||
67 | pci->op_state = OP_ALLOC; | ||
68 | |||
69 | snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name); | ||
70 | |||
71 | return pci; | ||
72 | } | ||
73 | |||
74 | EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info); | ||
75 | |||
76 | /* | ||
77 | * edac_pci_free_ctl_info() | ||
78 | * frees the memory allocated by edac_pci_alloc_ctl_info() function | ||
79 | */ | ||
80 | void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci) | ||
81 | { | ||
82 | kfree(pci); | ||
83 | } | ||
84 | |||
85 | EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info); | ||
86 | |||
87 | /* | ||
88 | * find_edac_pci_by_dev() | ||
89 | * scans the edac_pci list for a specific 'struct device *' | ||
90 | */ | ||
91 | static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev) | ||
92 | { | ||
93 | struct edac_pci_ctl_info *pci; | ||
94 | struct list_head *item; | ||
95 | |||
96 | debugf3("%s()\n", __func__); | ||
97 | |||
98 | list_for_each(item, &edac_pci_list) { | ||
99 | pci = list_entry(item, struct edac_pci_ctl_info, link); | ||
100 | |||
101 | if (pci->dev == dev) | ||
102 | return pci; | ||
103 | } | ||
104 | |||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * add_edac_pci_to_global_list | ||
110 | * Before calling this function, caller must assign a unique value to | ||
111 | * edac_dev->pci_idx. | ||
112 | * Return: | ||
113 | * 0 on success | ||
114 | * 1 on failure | ||
115 | */ | ||
116 | static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci) | ||
117 | { | ||
118 | struct list_head *item, *insert_before; | ||
119 | struct edac_pci_ctl_info *rover; | ||
120 | |||
121 | insert_before = &edac_pci_list; | ||
122 | |||
123 | /* Determine if already on the list */ | ||
124 | if (unlikely((rover = find_edac_pci_by_dev(pci->dev)) != NULL)) | ||
125 | goto fail0; | ||
126 | |||
127 | /* Insert in ascending order by 'pci_idx', so find position */ | ||
128 | list_for_each(item, &edac_pci_list) { | ||
129 | rover = list_entry(item, struct edac_pci_ctl_info, link); | ||
130 | |||
131 | if (rover->pci_idx >= pci->pci_idx) { | ||
132 | if (unlikely(rover->pci_idx == pci->pci_idx)) | ||
133 | goto fail1; | ||
134 | |||
135 | insert_before = item; | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | list_add_tail_rcu(&pci->link, insert_before); | ||
141 | return 0; | ||
142 | |||
143 | fail0: | ||
144 | edac_printk(KERN_WARNING, EDAC_PCI, | ||
145 | "%s (%s) %s %s already assigned %d\n", | ||
146 | rover->dev->bus_id, dev_name(rover), | ||
147 | rover->mod_name, rover->ctl_name, rover->pci_idx); | ||
148 | return 1; | ||
149 | |||
150 | fail1: | ||
151 | edac_printk(KERN_WARNING, EDAC_PCI, | ||
152 | "but in low-level driver: attempt to assign\n" | ||
153 | "\tduplicate pci_idx %d in %s()\n", rover->pci_idx, | ||
154 | __func__); | ||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * complete_edac_pci_list_del | ||
160 | */ | ||
161 | static void complete_edac_pci_list_del(struct rcu_head *head) | ||
162 | { | ||
163 | struct edac_pci_ctl_info *pci; | ||
164 | |||
165 | pci = container_of(head, struct edac_pci_ctl_info, rcu); | ||
166 | INIT_LIST_HEAD(&pci->link); | ||
167 | complete(&pci->complete); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * del_edac_pci_from_global_list | ||
172 | */ | ||
173 | static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) | ||
174 | { | ||
175 | list_del_rcu(&pci->link); | ||
176 | init_completion(&pci->complete); | ||
177 | call_rcu(&pci->rcu, complete_edac_pci_list_del); | ||
178 | wait_for_completion(&pci->complete); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * edac_pci_find() | ||
183 | * Search for an edac_pci_ctl_info structure whose index is 'idx' | ||
184 | * | ||
185 | * If found, return a pointer to the structure | ||
186 | * Else return NULL. | ||
187 | * | ||
188 | * Caller must hold pci_ctls_mutex. | ||
189 | */ | ||
190 | struct edac_pci_ctl_info *edac_pci_find(int idx) | ||
191 | { | ||
192 | struct list_head *item; | ||
193 | struct edac_pci_ctl_info *pci; | ||
194 | |||
195 | /* Iterage over list, looking for exact match of ID */ | ||
196 | list_for_each(item, &edac_pci_list) { | ||
197 | pci = list_entry(item, struct edac_pci_ctl_info, link); | ||
198 | |||
199 | if (pci->pci_idx >= idx) { | ||
200 | if (pci->pci_idx == idx) | ||
201 | return pci; | ||
202 | |||
203 | /* not on list, so terminate early */ | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | EXPORT_SYMBOL_GPL(edac_pci_find); | ||
212 | |||
213 | /* | ||
214 | * edac_pci_workq_function() | ||
215 | * performs the operation scheduled by a workq request | ||
216 | */ | ||
217 | static void edac_pci_workq_function(struct work_struct *work_req) | ||
218 | { | ||
219 | struct delayed_work *d_work = (struct delayed_work *)work_req; | ||
220 | struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work); | ||
221 | |||
222 | edac_lock_pci_list(); | ||
223 | |||
224 | if ((pci->op_state == OP_RUNNING_POLL) && | ||
225 | (pci->edac_check != NULL) && (edac_pci_get_check_errors())) | ||
226 | pci->edac_check(pci); | ||
227 | |||
228 | edac_unlock_pci_list(); | ||
229 | |||
230 | /* Reschedule */ | ||
231 | queue_delayed_work(edac_workqueue, &pci->work, | ||
232 | msecs_to_jiffies(edac_pci_get_poll_msec())); | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * edac_pci_workq_setup() | ||
237 | * initialize a workq item for this edac_pci instance | ||
238 | * passing in the new delay period in msec | ||
239 | */ | ||
240 | static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, | ||
241 | unsigned int msec) | ||
242 | { | ||
243 | debugf0("%s()\n", __func__); | ||
244 | |||
245 | INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); | ||
246 | queue_delayed_work(edac_workqueue, &pci->work, | ||
247 | msecs_to_jiffies(edac_pci_get_poll_msec())); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * edac_pci_workq_teardown() | ||
252 | * stop the workq processing on this edac_pci instance | ||
253 | */ | ||
254 | static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) | ||
255 | { | ||
256 | int status; | ||
257 | |||
258 | status = cancel_delayed_work(&pci->work); | ||
259 | if (status == 0) | ||
260 | flush_workqueue(edac_workqueue); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * edac_pci_reset_delay_period | ||
265 | */ | ||
266 | void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, | ||
267 | unsigned long value) | ||
268 | { | ||
269 | edac_lock_pci_list(); | ||
270 | |||
271 | edac_pci_workq_teardown(pci); | ||
272 | |||
273 | edac_pci_workq_setup(pci, value); | ||
274 | |||
275 | edac_unlock_pci_list(); | ||
276 | } | ||
277 | |||
278 | EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); | ||
279 | |||
280 | /* | ||
281 | * edac_pci_add_device: Insert the 'edac_dev' structure into the | ||
282 | * edac_pci global list and create sysfs entries associated with | ||
283 | * edac_pci structure. | ||
284 | * @pci: pointer to the edac_device structure to be added to the list | ||
285 | * @edac_idx: A unique numeric identifier to be assigned to the | ||
286 | * 'edac_pci' structure. | ||
287 | * | ||
288 | * Return: | ||
289 | * 0 Success | ||
290 | * !0 Failure | ||
291 | */ | ||
292 | int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx) | ||
293 | { | ||
294 | debugf0("%s()\n", __func__); | ||
295 | |||
296 | pci->pci_idx = edac_idx; | ||
297 | |||
298 | edac_lock_pci_list(); | ||
299 | |||
300 | if (add_edac_pci_to_global_list(pci)) | ||
301 | goto fail0; | ||
302 | |||
303 | pci->start_time = jiffies; | ||
304 | |||
305 | if (edac_pci_create_sysfs(pci)) { | ||
306 | edac_pci_printk(pci, KERN_WARNING, | ||
307 | "failed to create sysfs pci\n"); | ||
308 | goto fail1; | ||
309 | } | ||
310 | |||
311 | if (pci->edac_check != NULL) { | ||
312 | pci->op_state = OP_RUNNING_POLL; | ||
313 | |||
314 | edac_pci_workq_setup(pci, 1000); | ||
315 | } else { | ||
316 | pci->op_state = OP_RUNNING_INTERRUPT; | ||
317 | } | ||
318 | |||
319 | edac_pci_printk(pci, KERN_INFO, | ||
320 | "Giving out device to module '%s' controller '%s':" | ||
321 | " DEV '%s' (%s)\n", | ||
322 | pci->mod_name, | ||
323 | pci->ctl_name, | ||
324 | dev_name(pci), edac_op_state_to_string(pci->op_state)); | ||
325 | |||
326 | edac_unlock_pci_list(); | ||
327 | return 0; | ||
328 | |||
329 | fail1: | ||
330 | del_edac_pci_from_global_list(pci); | ||
331 | fail0: | ||
332 | edac_unlock_pci_list(); | ||
333 | return 1; | ||
334 | } | ||
335 | |||
336 | EXPORT_SYMBOL_GPL(edac_pci_add_device); | ||
337 | |||
338 | /* | ||
339 | * edac_pci_del_device() | ||
340 | * Remove sysfs entries for specified edac_pci structure and | ||
341 | * then remove edac_pci structure from global list | ||
342 | * | ||
343 | * @dev: | ||
344 | * Pointer to 'struct device' representing edac_pci structure | ||
345 | * to remove | ||
346 | * | ||
347 | * Return: | ||
348 | * Pointer to removed edac_pci structure, | ||
349 | * or NULL if device not found | ||
350 | */ | ||
351 | struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev) | ||
352 | { | ||
353 | struct edac_pci_ctl_info *pci; | ||
354 | |||
355 | debugf0("%s()\n", __func__); | ||
356 | |||
357 | edac_lock_pci_list(); | ||
358 | |||
359 | if ((pci = find_edac_pci_by_dev(dev)) == NULL) { | ||
360 | edac_unlock_pci_list(); | ||
361 | return NULL; | ||
362 | } | ||
363 | |||
364 | pci->op_state = OP_OFFLINE; | ||
365 | |||
366 | edac_pci_workq_teardown(pci); | ||
367 | |||
368 | edac_pci_remove_sysfs(pci); | ||
369 | |||
370 | del_edac_pci_from_global_list(pci); | ||
371 | |||
372 | edac_unlock_pci_list(); | ||
373 | |||
374 | edac_printk(KERN_INFO, EDAC_PCI, | ||
375 | "Removed device %d for %s %s: DEV %s\n", | ||
376 | pci->pci_idx, pci->mod_name, pci->ctl_name, dev_name(pci)); | ||
377 | |||
378 | return pci; | ||
379 | } | ||
380 | |||
381 | EXPORT_SYMBOL_GPL(edac_pci_del_device); | ||
382 | |||
383 | void edac_pci_generic_check(struct edac_pci_ctl_info *pci) | ||
384 | { | ||
385 | edac_pci_do_parity_check(); | ||
386 | } | ||
387 | |||
388 | static int edac_pci_idx; | ||
389 | #define EDAC_PCI_GENCTL_NAME "EDAC PCI controller" | ||
390 | |||
391 | struct edac_pci_gen_data { | ||
392 | int edac_idx; | ||
393 | }; | ||
394 | |||
395 | struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, | ||
396 | const char *mod_name) | ||
397 | { | ||
398 | struct edac_pci_ctl_info *pci; | ||
399 | struct edac_pci_gen_data *pdata; | ||
400 | |||
401 | pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME); | ||
402 | if (!pci) | ||
403 | return NULL; | ||
404 | |||
405 | pdata = pci->pvt_info; | ||
406 | pci->dev = dev; | ||
407 | dev_set_drvdata(pci->dev, pci); | ||
408 | pci->dev_name = pci_name(to_pci_dev(dev)); | ||
409 | |||
410 | pci->mod_name = mod_name; | ||
411 | pci->ctl_name = EDAC_PCI_GENCTL_NAME; | ||
412 | pci->edac_check = edac_pci_generic_check; | ||
413 | |||
414 | pdata->edac_idx = edac_pci_idx++; | ||
415 | |||
416 | if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { | ||
417 | debugf3("%s(): failed edac_pci_add_device()\n", __func__); | ||
418 | edac_pci_free_ctl_info(pci); | ||
419 | return NULL; | ||
420 | } | ||
421 | |||
422 | return pci; | ||
423 | } | ||
424 | |||
425 | EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl); | ||
426 | |||
427 | void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci) | ||
428 | { | ||
429 | edac_pci_del_device(pci->dev); | ||
430 | edac_pci_free_ctl_info(pci); | ||
431 | } | ||
432 | |||
433 | EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl); | ||
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c new file mode 100644 index 000000000000..fac94cae2c3d --- /dev/null +++ b/drivers/edac/edac_pci_sysfs.c | |||
@@ -0,0 +1,620 @@ | |||
1 | /* | ||
2 | * (C) 2005, 2006 Linux Networx (http://lnxi.com) | ||
3 | * This file may be distributed under the terms of the | ||
4 | * GNU General Public License. | ||
5 | * | ||
6 | * Written Doug Thompson <norsk5@xmission.com> | ||
7 | * | ||
8 | */ | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/sysdev.h> | ||
11 | #include <linux/ctype.h> | ||
12 | |||
13 | #include "edac_core.h" | ||
14 | #include "edac_module.h" | ||
15 | |||
16 | #ifdef CONFIG_PCI | ||
17 | |||
18 | #define EDAC_PCI_SYMLINK "device" | ||
19 | |||
20 | static int check_pci_errors; /* default YES check PCI parity */ | ||
21 | static int edac_pci_panic_on_pe; /* default no panic on PCI Parity */ | ||
22 | static int edac_pci_log_pe = 1; /* log PCI parity errors */ | ||
23 | static int edac_pci_log_npe = 1; /* log PCI non-parity error errors */ | ||
24 | static atomic_t pci_parity_count = ATOMIC_INIT(0); | ||
25 | static atomic_t pci_nonparity_count = ATOMIC_INIT(0); | ||
26 | static int edac_pci_poll_msec = 1000; | ||
27 | |||
28 | static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ | ||
29 | static struct completion edac_pci_kobj_complete; | ||
30 | static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0); | ||
31 | |||
32 | int edac_pci_get_check_errors(void) | ||
33 | { | ||
34 | return check_pci_errors; | ||
35 | } | ||
36 | |||
37 | int edac_pci_get_log_pe(void) | ||
38 | { | ||
39 | return edac_pci_log_pe; | ||
40 | } | ||
41 | |||
42 | int edac_pci_get_log_npe(void) | ||
43 | { | ||
44 | return edac_pci_log_npe; | ||
45 | } | ||
46 | |||
47 | int edac_pci_get_panic_on_pe(void) | ||
48 | { | ||
49 | return edac_pci_panic_on_pe; | ||
50 | } | ||
51 | |||
52 | int edac_pci_get_poll_msec(void) | ||
53 | { | ||
54 | return edac_pci_poll_msec; | ||
55 | } | ||
56 | |||
57 | /**************************** EDAC PCI sysfs instance *******************/ | ||
58 | static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data) | ||
59 | { | ||
60 | return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count)); | ||
61 | } | ||
62 | |||
63 | static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci, | ||
64 | char *data) | ||
65 | { | ||
66 | return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count)); | ||
67 | } | ||
68 | |||
69 | #define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj) | ||
70 | #define to_instance_attr(a) container_of(a, struct instance_attribute, attr) | ||
71 | |||
72 | /* DEVICE instance kobject release() function */ | ||
73 | static void edac_pci_instance_release(struct kobject *kobj) | ||
74 | { | ||
75 | struct edac_pci_ctl_info *pci; | ||
76 | |||
77 | debugf1("%s()\n", __func__); | ||
78 | |||
79 | pci = to_instance(kobj); | ||
80 | complete(&pci->kobj_complete); | ||
81 | } | ||
82 | |||
83 | /* instance specific attribute structure */ | ||
84 | struct instance_attribute { | ||
85 | struct attribute attr; | ||
86 | ssize_t(*show) (struct edac_pci_ctl_info *, char *); | ||
87 | ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t); | ||
88 | }; | ||
89 | |||
90 | /* Function to 'show' fields from the edac_pci 'instance' structure */ | ||
91 | static ssize_t edac_pci_instance_show(struct kobject *kobj, | ||
92 | struct attribute *attr, char *buffer) | ||
93 | { | ||
94 | struct edac_pci_ctl_info *pci = to_instance(kobj); | ||
95 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
96 | |||
97 | if (instance_attr->show) | ||
98 | return instance_attr->show(pci, buffer); | ||
99 | return -EIO; | ||
100 | } | ||
101 | |||
102 | /* Function to 'store' fields into the edac_pci 'instance' structure */ | ||
103 | static ssize_t edac_pci_instance_store(struct kobject *kobj, | ||
104 | struct attribute *attr, | ||
105 | const char *buffer, size_t count) | ||
106 | { | ||
107 | struct edac_pci_ctl_info *pci = to_instance(kobj); | ||
108 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
109 | |||
110 | if (instance_attr->store) | ||
111 | return instance_attr->store(pci, buffer, count); | ||
112 | return -EIO; | ||
113 | } | ||
114 | |||
115 | static struct sysfs_ops pci_instance_ops = { | ||
116 | .show = edac_pci_instance_show, | ||
117 | .store = edac_pci_instance_store | ||
118 | }; | ||
119 | |||
120 | #define INSTANCE_ATTR(_name, _mode, _show, _store) \ | ||
121 | static struct instance_attribute attr_instance_##_name = { \ | ||
122 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
123 | .show = _show, \ | ||
124 | .store = _store, \ | ||
125 | }; | ||
126 | |||
127 | INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL); | ||
128 | INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL); | ||
129 | |||
130 | /* pci instance attributes */ | ||
131 | static struct instance_attribute *pci_instance_attr[] = { | ||
132 | &attr_instance_pe_count, | ||
133 | &attr_instance_npe_count, | ||
134 | NULL | ||
135 | }; | ||
136 | |||
137 | /* the ktype for pci instance */ | ||
138 | static struct kobj_type ktype_pci_instance = { | ||
139 | .release = edac_pci_instance_release, | ||
140 | .sysfs_ops = &pci_instance_ops, | ||
141 | .default_attrs = (struct attribute **)pci_instance_attr, | ||
142 | }; | ||
143 | |||
144 | static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) | ||
145 | { | ||
146 | int err; | ||
147 | |||
148 | pci->kobj.parent = &edac_pci_kobj; | ||
149 | pci->kobj.ktype = &ktype_pci_instance; | ||
150 | |||
151 | err = kobject_set_name(&pci->kobj, "pci%d", idx); | ||
152 | if (err) | ||
153 | return err; | ||
154 | |||
155 | err = kobject_register(&pci->kobj); | ||
156 | if (err != 0) { | ||
157 | debugf2("%s() failed to register instance pci%d\n", | ||
158 | __func__, idx); | ||
159 | return err; | ||
160 | } | ||
161 | |||
162 | debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static void | ||
168 | edac_pci_delete_instance_kobj(struct edac_pci_ctl_info *pci, int idx) | ||
169 | { | ||
170 | init_completion(&pci->kobj_complete); | ||
171 | kobject_unregister(&pci->kobj); | ||
172 | wait_for_completion(&pci->kobj_complete); | ||
173 | } | ||
174 | |||
175 | /***************************** EDAC PCI sysfs root **********************/ | ||
176 | #define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj) | ||
177 | #define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr) | ||
178 | |||
179 | static ssize_t edac_pci_int_show(void *ptr, char *buffer) | ||
180 | { | ||
181 | int *value = ptr; | ||
182 | return sprintf(buffer, "%d\n", *value); | ||
183 | } | ||
184 | |||
185 | static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count) | ||
186 | { | ||
187 | int *value = ptr; | ||
188 | |||
189 | if (isdigit(*buffer)) | ||
190 | *value = simple_strtoul(buffer, NULL, 0); | ||
191 | |||
192 | return count; | ||
193 | } | ||
194 | |||
195 | struct edac_pci_dev_attribute { | ||
196 | struct attribute attr; | ||
197 | void *value; | ||
198 | ssize_t(*show) (void *, char *); | ||
199 | ssize_t(*store) (void *, const char *, size_t); | ||
200 | }; | ||
201 | |||
202 | /* Set of show/store abstract level functions for PCI Parity object */ | ||
203 | static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, | ||
204 | char *buffer) | ||
205 | { | ||
206 | struct edac_pci_dev_attribute *edac_pci_dev; | ||
207 | edac_pci_dev = (struct edac_pci_dev_attribute *)attr; | ||
208 | |||
209 | if (edac_pci_dev->show) | ||
210 | return edac_pci_dev->show(edac_pci_dev->value, buffer); | ||
211 | return -EIO; | ||
212 | } | ||
213 | |||
214 | static ssize_t edac_pci_dev_store(struct kobject *kobj, | ||
215 | struct attribute *attr, const char *buffer, | ||
216 | size_t count) | ||
217 | { | ||
218 | struct edac_pci_dev_attribute *edac_pci_dev; | ||
219 | edac_pci_dev = (struct edac_pci_dev_attribute *)attr; | ||
220 | |||
221 | if (edac_pci_dev->show) | ||
222 | return edac_pci_dev->store(edac_pci_dev->value, buffer, count); | ||
223 | return -EIO; | ||
224 | } | ||
225 | |||
226 | static struct sysfs_ops edac_pci_sysfs_ops = { | ||
227 | .show = edac_pci_dev_show, | ||
228 | .store = edac_pci_dev_store | ||
229 | }; | ||
230 | |||
231 | #define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ | ||
232 | static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | ||
233 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
234 | .value = &_name, \ | ||
235 | .show = _show, \ | ||
236 | .store = _store, \ | ||
237 | }; | ||
238 | |||
239 | #define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \ | ||
240 | static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | ||
241 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
242 | .value = _data, \ | ||
243 | .show = _show, \ | ||
244 | .store = _store, \ | ||
245 | }; | ||
246 | |||
247 | /* PCI Parity control files */ | ||
248 | EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show, | ||
249 | edac_pci_int_store); | ||
250 | EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show, | ||
251 | edac_pci_int_store); | ||
252 | EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show, | ||
253 | edac_pci_int_store); | ||
254 | EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show, | ||
255 | edac_pci_int_store); | ||
256 | EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); | ||
257 | EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL); | ||
258 | |||
259 | /* Base Attributes of the memory ECC object */ | ||
260 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { | ||
261 | &edac_pci_attr_check_pci_errors, | ||
262 | &edac_pci_attr_edac_pci_log_pe, | ||
263 | &edac_pci_attr_edac_pci_log_npe, | ||
264 | &edac_pci_attr_edac_pci_panic_on_pe, | ||
265 | &edac_pci_attr_pci_parity_count, | ||
266 | &edac_pci_attr_pci_nonparity_count, | ||
267 | NULL, | ||
268 | }; | ||
269 | |||
270 | /* No memory to release */ | ||
271 | static void edac_pci_release(struct kobject *kobj) | ||
272 | { | ||
273 | struct edac_pci_ctl_info *pci; | ||
274 | |||
275 | pci = to_edacpci(kobj); | ||
276 | |||
277 | debugf1("%s()\n", __func__); | ||
278 | complete(&pci->kobj_complete); | ||
279 | } | ||
280 | |||
281 | static struct kobj_type ktype_edac_pci = { | ||
282 | .release = edac_pci_release, | ||
283 | .sysfs_ops = &edac_pci_sysfs_ops, | ||
284 | .default_attrs = (struct attribute **)edac_pci_attr, | ||
285 | }; | ||
286 | |||
287 | /** | ||
288 | * edac_sysfs_pci_setup() | ||
289 | * | ||
290 | * setup the sysfs for EDAC PCI attributes | ||
291 | * assumes edac_class has already been initialized | ||
292 | */ | ||
293 | int edac_pci_register_main_kobj(void) | ||
294 | { | ||
295 | int err; | ||
296 | struct sysdev_class *edac_class; | ||
297 | |||
298 | debugf1("%s()\n", __func__); | ||
299 | |||
300 | edac_class = edac_get_edac_class(); | ||
301 | if (edac_class == NULL) { | ||
302 | debugf1("%s() no edac_class\n", __func__); | ||
303 | return -ENODEV; | ||
304 | } | ||
305 | |||
306 | edac_pci_kobj.ktype = &ktype_edac_pci; | ||
307 | |||
308 | edac_pci_kobj.parent = &edac_class->kset.kobj; | ||
309 | |||
310 | err = kobject_set_name(&edac_pci_kobj, "pci"); | ||
311 | if (err) | ||
312 | return err; | ||
313 | |||
314 | /* Instanstiate the pci object */ | ||
315 | /* FIXME: maybe new sysdev_create_subdir() */ | ||
316 | err = kobject_register(&edac_pci_kobj); | ||
317 | |||
318 | if (err) { | ||
319 | debugf1("Failed to register '.../edac/pci'\n"); | ||
320 | return err; | ||
321 | } | ||
322 | |||
323 | debugf1("Registered '.../edac/pci' kobject\n"); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * edac_pci_unregister_main_kobj() | ||
330 | * | ||
331 | * perform the sysfs teardown for the PCI attributes | ||
332 | */ | ||
333 | void edac_pci_unregister_main_kobj(void) | ||
334 | { | ||
335 | debugf0("%s()\n", __func__); | ||
336 | init_completion(&edac_pci_kobj_complete); | ||
337 | kobject_unregister(&edac_pci_kobj); | ||
338 | wait_for_completion(&edac_pci_kobj_complete); | ||
339 | } | ||
340 | |||
341 | int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci) | ||
342 | { | ||
343 | int err; | ||
344 | struct kobject *edac_kobj = &pci->kobj; | ||
345 | |||
346 | if (atomic_inc_return(&edac_pci_sysfs_refcount) == 1) { | ||
347 | err = edac_pci_register_main_kobj(); | ||
348 | if (err) { | ||
349 | atomic_dec(&edac_pci_sysfs_refcount); | ||
350 | return err; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | err = edac_pci_create_instance_kobj(pci, pci->pci_idx); | ||
355 | if (err) { | ||
356 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) | ||
357 | edac_pci_unregister_main_kobj(); | ||
358 | } | ||
359 | |||
360 | debugf0("%s() idx=%d\n", __func__, pci->pci_idx); | ||
361 | |||
362 | err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK); | ||
363 | if (err) { | ||
364 | debugf0("%s() sysfs_create_link() returned err= %d\n", | ||
365 | __func__, err); | ||
366 | return err; | ||
367 | } | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci) | ||
373 | { | ||
374 | debugf0("%s()\n", __func__); | ||
375 | |||
376 | edac_pci_delete_instance_kobj(pci, pci->pci_idx); | ||
377 | |||
378 | sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK); | ||
379 | |||
380 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) | ||
381 | edac_pci_unregister_main_kobj(); | ||
382 | } | ||
383 | |||
384 | /************************ PCI error handling *************************/ | ||
385 | static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) | ||
386 | { | ||
387 | int where; | ||
388 | u16 status; | ||
389 | |||
390 | where = secondary ? PCI_SEC_STATUS : PCI_STATUS; | ||
391 | pci_read_config_word(dev, where, &status); | ||
392 | |||
393 | /* If we get back 0xFFFF then we must suspect that the card has been | ||
394 | * pulled but the Linux PCI layer has not yet finished cleaning up. | ||
395 | * We don't want to report on such devices | ||
396 | */ | ||
397 | |||
398 | if (status == 0xFFFF) { | ||
399 | u32 sanity; | ||
400 | |||
401 | pci_read_config_dword(dev, 0, &sanity); | ||
402 | |||
403 | if (sanity == 0xFFFFFFFF) | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | | ||
408 | PCI_STATUS_PARITY; | ||
409 | |||
410 | if (status) | ||
411 | /* reset only the bits we are interested in */ | ||
412 | pci_write_config_word(dev, where, status); | ||
413 | |||
414 | return status; | ||
415 | } | ||
416 | |||
417 | typedef void (*pci_parity_check_fn_t) (struct pci_dev * dev); | ||
418 | |||
419 | /* Clear any PCI parity errors logged by this device. */ | ||
420 | static void edac_pci_dev_parity_clear(struct pci_dev *dev) | ||
421 | { | ||
422 | u8 header_type; | ||
423 | |||
424 | get_pci_parity_status(dev, 0); | ||
425 | |||
426 | /* read the device TYPE, looking for bridges */ | ||
427 | pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); | ||
428 | |||
429 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) | ||
430 | get_pci_parity_status(dev, 1); | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * PCI Parity polling | ||
435 | * | ||
436 | */ | ||
437 | static void edac_pci_dev_parity_test(struct pci_dev *dev) | ||
438 | { | ||
439 | u16 status; | ||
440 | u8 header_type; | ||
441 | |||
442 | /* read the STATUS register on this device | ||
443 | */ | ||
444 | status = get_pci_parity_status(dev, 0); | ||
445 | |||
446 | debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id); | ||
447 | |||
448 | /* check the status reg for errors */ | ||
449 | if (status) { | ||
450 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) { | ||
451 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
452 | "Signaled System Error on %s\n", | ||
453 | pci_name(dev)); | ||
454 | atomic_inc(&pci_nonparity_count); | ||
455 | } | ||
456 | |||
457 | if (status & (PCI_STATUS_PARITY)) { | ||
458 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
459 | "Master Data Parity Error on %s\n", | ||
460 | pci_name(dev)); | ||
461 | |||
462 | atomic_inc(&pci_parity_count); | ||
463 | } | ||
464 | |||
465 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | ||
466 | edac_printk(KERN_CRIT, EDAC_PCI, | ||
467 | "Detected Parity Error on %s\n", | ||
468 | pci_name(dev)); | ||
469 | |||
470 | atomic_inc(&pci_parity_count); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /* read the device TYPE, looking for bridges */ | ||
475 | pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); | ||
476 | |||
477 | debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id); | ||
478 | |||
479 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | ||
480 | /* On bridges, need to examine secondary status register */ | ||
481 | status = get_pci_parity_status(dev, 1); | ||
482 | |||
483 | debugf2("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id); | ||
484 | |||
485 | /* check the secondary status reg for errors */ | ||
486 | if (status) { | ||
487 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) { | ||
488 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
489 | "Signaled System Error on %s\n", | ||
490 | pci_name(dev)); | ||
491 | atomic_inc(&pci_nonparity_count); | ||
492 | } | ||
493 | |||
494 | if (status & (PCI_STATUS_PARITY)) { | ||
495 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
496 | "Master Data Parity Error on " | ||
497 | "%s\n", pci_name(dev)); | ||
498 | |||
499 | atomic_inc(&pci_parity_count); | ||
500 | } | ||
501 | |||
502 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | ||
503 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | ||
504 | "Detected Parity Error on %s\n", | ||
505 | pci_name(dev)); | ||
506 | |||
507 | atomic_inc(&pci_parity_count); | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | /* | ||
514 | * pci_dev parity list iterator | ||
515 | * Scan the PCI device list for one iteration, looking for SERRORs | ||
516 | * Master Parity ERRORS or Parity ERRORs on primary or secondary devices | ||
517 | */ | ||
518 | static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) | ||
519 | { | ||
520 | struct pci_dev *dev = NULL; | ||
521 | |||
522 | /* request for kernel access to the next PCI device, if any, | ||
523 | * and while we are looking at it have its reference count | ||
524 | * bumped until we are done with it | ||
525 | */ | ||
526 | while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | ||
527 | fn(dev); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * edac_pci_do_parity_check | ||
533 | * | ||
534 | * performs the actual PCI parity check operation | ||
535 | */ | ||
536 | void edac_pci_do_parity_check(void) | ||
537 | { | ||
538 | unsigned long flags; | ||
539 | int before_count; | ||
540 | |||
541 | debugf3("%s()\n", __func__); | ||
542 | |||
543 | if (!check_pci_errors) | ||
544 | return; | ||
545 | |||
546 | before_count = atomic_read(&pci_parity_count); | ||
547 | |||
548 | /* scan all PCI devices looking for a Parity Error on devices and | ||
549 | * bridges | ||
550 | */ | ||
551 | local_irq_save(flags); | ||
552 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); | ||
553 | local_irq_restore(flags); | ||
554 | |||
555 | /* Only if operator has selected panic on PCI Error */ | ||
556 | if (edac_pci_get_panic_on_pe()) { | ||
557 | /* If the count is different 'after' from 'before' */ | ||
558 | if (before_count != atomic_read(&pci_parity_count)) | ||
559 | panic("EDAC: PCI Parity Error"); | ||
560 | } | ||
561 | } | ||
562 | |||
563 | void edac_pci_clear_parity_errors(void) | ||
564 | { | ||
565 | /* Clear any PCI bus parity errors that devices initially have logged | ||
566 | * in their registers. | ||
567 | */ | ||
568 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); | ||
569 | } | ||
570 | void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg) | ||
571 | { | ||
572 | |||
573 | /* global PE counter incremented by edac_pci_do_parity_check() */ | ||
574 | atomic_inc(&pci->counters.pe_count); | ||
575 | |||
576 | if (edac_pci_get_log_pe()) | ||
577 | edac_pci_printk(pci, KERN_WARNING, | ||
578 | "Parity Error ctl: %s %d: %s\n", | ||
579 | pci->ctl_name, pci->pci_idx, msg); | ||
580 | |||
581 | /* | ||
582 | * poke all PCI devices and see which one is the troublemaker | ||
583 | * panic() is called if set | ||
584 | */ | ||
585 | edac_pci_do_parity_check(); | ||
586 | } | ||
587 | |||
588 | EXPORT_SYMBOL_GPL(edac_pci_handle_pe); | ||
589 | |||
590 | void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg) | ||
591 | { | ||
592 | |||
593 | /* global NPE counter incremented by edac_pci_do_parity_check() */ | ||
594 | atomic_inc(&pci->counters.npe_count); | ||
595 | |||
596 | if (edac_pci_get_log_npe()) | ||
597 | edac_pci_printk(pci, KERN_WARNING, | ||
598 | "Non-Parity Error ctl: %s %d: %s\n", | ||
599 | pci->ctl_name, pci->pci_idx, msg); | ||
600 | |||
601 | /* | ||
602 | * poke all PCI devices and see which one is the troublemaker | ||
603 | * panic() is called if set | ||
604 | */ | ||
605 | edac_pci_do_parity_check(); | ||
606 | } | ||
607 | |||
608 | EXPORT_SYMBOL_GPL(edac_pci_handle_npe); | ||
609 | |||
610 | /* | ||
611 | * Define the PCI parameter to the module | ||
612 | */ | ||
613 | module_param(check_pci_errors, int, 0644); | ||
614 | MODULE_PARM_DESC(check_pci_errors, | ||
615 | "Check for PCI bus parity errors: 0=off 1=on"); | ||
616 | module_param(edac_pci_panic_on_pe, int, 0644); | ||
617 | MODULE_PARM_DESC(edac_pci_panic_on_pe, | ||
618 | "Panic on PCI Bus Parity error: 0=off 1=on"); | ||
619 | |||
620 | #endif /* CONFIG_PCI */ | ||
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c new file mode 100644 index 000000000000..20b428aa155e --- /dev/null +++ b/drivers/edac/edac_stub.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * common EDAC components that must be in kernel | ||
3 | * | ||
4 | * Author: Dave Jiang <djiang@mvista.com> | ||
5 | * | ||
6 | * 2007 (c) MontaVista Software, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | * | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/edac.h> | ||
14 | #include <asm/atomic.h> | ||
15 | #include <asm/edac.h> | ||
16 | |||
17 | int edac_op_state = EDAC_OPSTATE_INVAL; | ||
18 | EXPORT_SYMBOL_GPL(edac_op_state); | ||
19 | |||
20 | atomic_t edac_handlers = ATOMIC_INIT(0); | ||
21 | EXPORT_SYMBOL_GPL(edac_handlers); | ||
22 | |||
23 | int edac_err_assert = 0; | ||
24 | EXPORT_SYMBOL_GPL(edac_err_assert); | ||
25 | |||
26 | /* | ||
27 | * called to determine if there is an EDAC driver interested in | ||
28 | * knowing an event (such as NMI) occurred | ||
29 | */ | ||
30 | int edac_handler_set(void) | ||
31 | { | ||
32 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
33 | return 0; | ||
34 | |||
35 | return atomic_read(&edac_handlers); | ||
36 | } | ||
37 | EXPORT_SYMBOL_GPL(edac_handler_set); | ||
38 | |||
39 | /* | ||
40 | * handler for NMI type of interrupts to assert error | ||
41 | */ | ||
42 | void edac_atomic_assert_error(void) | ||
43 | { | ||
44 | edac_err_assert++; | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(edac_atomic_assert_error); | ||
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c new file mode 100644 index 000000000000..0ecfdc432f87 --- /dev/null +++ b/drivers/edac/i3000_edac.c | |||
@@ -0,0 +1,506 @@ | |||
1 | /* | ||
2 | * Intel 3000/3010 Memory Controller kernel module | ||
3 | * Copyright (C) 2007 Akamai Technologies, Inc. | ||
4 | * Shamelessly copied from: | ||
5 | * Intel D82875P Memory Controller kernel module | ||
6 | * (C) 2003 Linux Networx (http://lnxi.com) | ||
7 | * | ||
8 | * This file may be distributed under the terms of the | ||
9 | * GNU General Public License. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/pci_ids.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include "edac_core.h" | ||
18 | |||
19 | #define I3000_REVISION "1.1" | ||
20 | |||
21 | #define EDAC_MOD_STR "i3000_edac" | ||
22 | |||
23 | #define I3000_RANKS 8 | ||
24 | #define I3000_RANKS_PER_CHANNEL 4 | ||
25 | #define I3000_CHANNELS 2 | ||
26 | |||
27 | /* Intel 3000 register addresses - device 0 function 0 - DRAM Controller */ | ||
28 | |||
29 | #define I3000_MCHBAR 0x44 /* MCH Memory Mapped Register BAR */ | ||
30 | #define I3000_MCHBAR_MASK 0xffffc000 | ||
31 | #define I3000_MMR_WINDOW_SIZE 16384 | ||
32 | |||
33 | #define I3000_EDEAP 0x70 /* Extended DRAM Error Address Pointer (8b) | ||
34 | * | ||
35 | * 7:1 reserved | ||
36 | * 0 bit 32 of address | ||
37 | */ | ||
38 | #define I3000_DEAP 0x58 /* DRAM Error Address Pointer (32b) | ||
39 | * | ||
40 | * 31:7 address | ||
41 | * 6:1 reserved | ||
42 | * 0 Error channel 0/1 | ||
43 | */ | ||
44 | #define I3000_DEAP_GRAIN (1 << 7) | ||
45 | #define I3000_DEAP_PFN(edeap, deap) ((((edeap) & 1) << (32 - PAGE_SHIFT)) | \ | ||
46 | ((deap) >> PAGE_SHIFT)) | ||
47 | #define I3000_DEAP_OFFSET(deap) ((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK) | ||
48 | #define I3000_DEAP_CHANNEL(deap) ((deap) & 1) | ||
49 | |||
50 | #define I3000_DERRSYN 0x5c /* DRAM Error Syndrome (8b) | ||
51 | * | ||
52 | * 7:0 DRAM ECC Syndrome | ||
53 | */ | ||
54 | |||
55 | #define I3000_ERRSTS 0xc8 /* Error Status Register (16b) | ||
56 | * | ||
57 | * 15:12 reserved | ||
58 | * 11 MCH Thermal Sensor Event for SMI/SCI/SERR | ||
59 | * 10 reserved | ||
60 | * 9 LOCK to non-DRAM Memory Flag (LCKF) | ||
61 | * 8 Received Refresh Timeout Flag (RRTOF) | ||
62 | * 7:2 reserved | ||
63 | * 1 Multiple-bit DRAM ECC Error Flag (DMERR) | ||
64 | * 0 Single-bit DRAM ECC Error Flag (DSERR) | ||
65 | */ | ||
66 | #define I3000_ERRSTS_BITS 0x0b03 /* bits which indicate errors */ | ||
67 | #define I3000_ERRSTS_UE 0x0002 | ||
68 | #define I3000_ERRSTS_CE 0x0001 | ||
69 | |||
70 | #define I3000_ERRCMD 0xca /* Error Command (16b) | ||
71 | * | ||
72 | * 15:12 reserved | ||
73 | * 11 SERR on MCH Thermal Sensor Event (TSESERR) | ||
74 | * 10 reserved | ||
75 | * 9 SERR on LOCK to non-DRAM Memory (LCKERR) | ||
76 | * 8 SERR on DRAM Refresh Timeout (DRTOERR) | ||
77 | * 7:2 reserved | ||
78 | * 1 SERR Multiple-Bit DRAM ECC Error (DMERR) | ||
79 | * 0 SERR on Single-Bit ECC Error (DSERR) | ||
80 | */ | ||
81 | |||
82 | /* Intel MMIO register space - device 0 function 0 - MMR space */ | ||
83 | |||
84 | #define I3000_DRB_SHIFT 25 /* 32MiB grain */ | ||
85 | |||
86 | #define I3000_C0DRB 0x100 /* Channel 0 DRAM Rank Boundary (8b x 4) | ||
87 | * | ||
88 | * 7:0 Channel 0 DRAM Rank Boundary Address | ||
89 | */ | ||
90 | #define I3000_C1DRB 0x180 /* Channel 1 DRAM Rank Boundary (8b x 4) | ||
91 | * | ||
92 | * 7:0 Channel 1 DRAM Rank Boundary Address | ||
93 | */ | ||
94 | |||
95 | #define I3000_C0DRA 0x108 /* Channel 0 DRAM Rank Attribute (8b x 2) | ||
96 | * | ||
97 | * 7 reserved | ||
98 | * 6:4 DRAM odd Rank Attribute | ||
99 | * 3 reserved | ||
100 | * 2:0 DRAM even Rank Attribute | ||
101 | * | ||
102 | * Each attribute defines the page | ||
103 | * size of the corresponding rank: | ||
104 | * 000: unpopulated | ||
105 | * 001: reserved | ||
106 | * 010: 4 KB | ||
107 | * 011: 8 KB | ||
108 | * 100: 16 KB | ||
109 | * Others: reserved | ||
110 | */ | ||
111 | #define I3000_C1DRA 0x188 /* Channel 1 DRAM Rank Attribute (8b x 2) */ | ||
112 | #define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4) | ||
113 | #define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07) | ||
114 | |||
115 | #define I3000_C0DRC0 0x120 /* DRAM Controller Mode 0 (32b) | ||
116 | * | ||
117 | * 31:30 reserved | ||
118 | * 29 Initialization Complete (IC) | ||
119 | * 28:11 reserved | ||
120 | * 10:8 Refresh Mode Select (RMS) | ||
121 | * 7 reserved | ||
122 | * 6:4 Mode Select (SMS) | ||
123 | * 3:2 reserved | ||
124 | * 1:0 DRAM Type (DT) | ||
125 | */ | ||
126 | |||
127 | #define I3000_C0DRC1 0x124 /* DRAM Controller Mode 1 (32b) | ||
128 | * | ||
129 | * 31 Enhanced Addressing Enable (ENHADE) | ||
130 | * 30:0 reserved | ||
131 | */ | ||
132 | |||
133 | enum i3000p_chips { | ||
134 | I3000 = 0, | ||
135 | }; | ||
136 | |||
137 | struct i3000_dev_info { | ||
138 | const char *ctl_name; | ||
139 | }; | ||
140 | |||
141 | struct i3000_error_info { | ||
142 | u16 errsts; | ||
143 | u8 derrsyn; | ||
144 | u8 edeap; | ||
145 | u32 deap; | ||
146 | u16 errsts2; | ||
147 | }; | ||
148 | |||
149 | static const struct i3000_dev_info i3000_devs[] = { | ||
150 | [I3000] = { | ||
151 | .ctl_name = "i3000"}, | ||
152 | }; | ||
153 | |||
154 | static struct pci_dev *mci_pdev; | ||
155 | static int i3000_registered = 1; | ||
156 | static struct edac_pci_ctl_info *i3000_pci; | ||
157 | |||
158 | static void i3000_get_error_info(struct mem_ctl_info *mci, | ||
159 | struct i3000_error_info *info) | ||
160 | { | ||
161 | struct pci_dev *pdev; | ||
162 | |||
163 | pdev = to_pci_dev(mci->dev); | ||
164 | |||
165 | /* | ||
166 | * This is a mess because there is no atomic way to read all the | ||
167 | * registers at once and the registers can transition from CE being | ||
168 | * overwritten by UE. | ||
169 | */ | ||
170 | pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts); | ||
171 | if (!(info->errsts & I3000_ERRSTS_BITS)) | ||
172 | return; | ||
173 | pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap); | ||
174 | pci_read_config_dword(pdev, I3000_DEAP, &info->deap); | ||
175 | pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn); | ||
176 | pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts2); | ||
177 | |||
178 | /* | ||
179 | * If the error is the same for both reads then the first set | ||
180 | * of reads is valid. If there is a change then there is a CE | ||
181 | * with no info and the second set of reads is valid and | ||
182 | * should be UE info. | ||
183 | */ | ||
184 | if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) { | ||
185 | pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap); | ||
186 | pci_read_config_dword(pdev, I3000_DEAP, &info->deap); | ||
187 | pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn); | ||
188 | } | ||
189 | |||
190 | /* Clear any error bits. | ||
191 | * (Yes, we really clear bits by writing 1 to them.) | ||
192 | */ | ||
193 | pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS, | ||
194 | I3000_ERRSTS_BITS); | ||
195 | } | ||
196 | |||
197 | static int i3000_process_error_info(struct mem_ctl_info *mci, | ||
198 | struct i3000_error_info *info, | ||
199 | int handle_errors) | ||
200 | { | ||
201 | int row, multi_chan; | ||
202 | int pfn, offset, channel; | ||
203 | |||
204 | multi_chan = mci->csrows[0].nr_channels - 1; | ||
205 | |||
206 | if (!(info->errsts & I3000_ERRSTS_BITS)) | ||
207 | return 0; | ||
208 | |||
209 | if (!handle_errors) | ||
210 | return 1; | ||
211 | |||
212 | if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) { | ||
213 | edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); | ||
214 | info->errsts = info->errsts2; | ||
215 | } | ||
216 | |||
217 | pfn = I3000_DEAP_PFN(info->edeap, info->deap); | ||
218 | offset = I3000_DEAP_OFFSET(info->deap); | ||
219 | channel = I3000_DEAP_CHANNEL(info->deap); | ||
220 | |||
221 | row = edac_mc_find_csrow_by_page(mci, pfn); | ||
222 | |||
223 | if (info->errsts & I3000_ERRSTS_UE) | ||
224 | edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE"); | ||
225 | else | ||
226 | edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row, | ||
227 | multi_chan ? channel : 0, "i3000 CE"); | ||
228 | |||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | static void i3000_check(struct mem_ctl_info *mci) | ||
233 | { | ||
234 | struct i3000_error_info info; | ||
235 | |||
236 | debugf1("MC%d: %s()\n", mci->mc_idx, __func__); | ||
237 | i3000_get_error_info(mci, &info); | ||
238 | i3000_process_error_info(mci, &info, 1); | ||
239 | } | ||
240 | |||
241 | static int i3000_is_interleaved(const unsigned char *c0dra, | ||
242 | const unsigned char *c1dra, | ||
243 | const unsigned char *c0drb, | ||
244 | const unsigned char *c1drb) | ||
245 | { | ||
246 | int i; | ||
247 | |||
248 | /* If the channels aren't populated identically then | ||
249 | * we're not interleaved. | ||
250 | */ | ||
251 | for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++) | ||
252 | if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) || | ||
253 | EVEN_RANK_ATTRIB(c0dra[i]) != | ||
254 | EVEN_RANK_ATTRIB(c1dra[i])) | ||
255 | return 0; | ||
256 | |||
257 | /* If the rank boundaries for the two channels are different | ||
258 | * then we're not interleaved. | ||
259 | */ | ||
260 | for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) | ||
261 | if (c0drb[i] != c1drb[i]) | ||
262 | return 0; | ||
263 | |||
264 | return 1; | ||
265 | } | ||
266 | |||
267 | static int i3000_probe1(struct pci_dev *pdev, int dev_idx) | ||
268 | { | ||
269 | int rc; | ||
270 | int i; | ||
271 | struct mem_ctl_info *mci = NULL; | ||
272 | unsigned long last_cumul_size; | ||
273 | int interleaved, nr_channels; | ||
274 | unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS]; | ||
275 | unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2]; | ||
276 | unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL]; | ||
277 | unsigned long mchbar; | ||
278 | void *window; | ||
279 | |||
280 | debugf0("MC: %s()\n", __func__); | ||
281 | |||
282 | pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar); | ||
283 | mchbar &= I3000_MCHBAR_MASK; | ||
284 | window = ioremap_nocache(mchbar, I3000_MMR_WINDOW_SIZE); | ||
285 | if (!window) { | ||
286 | printk(KERN_ERR "i3000: cannot map mmio space at 0x%lx\n", | ||
287 | mchbar); | ||
288 | return -ENODEV; | ||
289 | } | ||
290 | |||
291 | c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */ | ||
292 | c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */ | ||
293 | c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */ | ||
294 | c1dra[1] = readb(window + I3000_C1DRA + 1); /* ranks 2,3 */ | ||
295 | |||
296 | for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) { | ||
297 | c0drb[i] = readb(window + I3000_C0DRB + i); | ||
298 | c1drb[i] = readb(window + I3000_C1DRB + i); | ||
299 | } | ||
300 | |||
301 | iounmap(window); | ||
302 | |||
303 | /* Figure out how many channels we have. | ||
304 | * | ||
305 | * If we have what the datasheet calls "asymmetric channels" | ||
306 | * (essentially the same as what was called "virtual single | ||
307 | * channel mode" in the i82875) then it's a single channel as | ||
308 | * far as EDAC is concerned. | ||
309 | */ | ||
310 | interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb); | ||
311 | nr_channels = interleaved ? 2 : 1; | ||
312 | mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0); | ||
313 | if (!mci) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | debugf3("MC: %s(): init mci\n", __func__); | ||
317 | |||
318 | mci->dev = &pdev->dev; | ||
319 | mci->mtype_cap = MEM_FLAG_DDR2; | ||
320 | |||
321 | mci->edac_ctl_cap = EDAC_FLAG_SECDED; | ||
322 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
323 | |||
324 | mci->mod_name = EDAC_MOD_STR; | ||
325 | mci->mod_ver = I3000_REVISION; | ||
326 | mci->ctl_name = i3000_devs[dev_idx].ctl_name; | ||
327 | mci->dev_name = pci_name(pdev); | ||
328 | mci->edac_check = i3000_check; | ||
329 | mci->ctl_page_to_phys = NULL; | ||
330 | |||
331 | /* | ||
332 | * The dram rank boundary (DRB) reg values are boundary addresses | ||
333 | * for each DRAM rank with a granularity of 32MB. DRB regs are | ||
334 | * cumulative; the last one will contain the total memory | ||
335 | * contained in all ranks. | ||
336 | * | ||
337 | * If we're in interleaved mode then we're only walking through | ||
338 | * the ranks of controller 0, so we double all the values we see. | ||
339 | */ | ||
340 | for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) { | ||
341 | u8 value; | ||
342 | u32 cumul_size; | ||
343 | struct csrow_info *csrow = &mci->csrows[i]; | ||
344 | |||
345 | value = drb[i]; | ||
346 | cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT); | ||
347 | if (interleaved) | ||
348 | cumul_size <<= 1; | ||
349 | debugf3("MC: %s(): (%d) cumul_size 0x%x\n", | ||
350 | __func__, i, cumul_size); | ||
351 | if (cumul_size == last_cumul_size) { | ||
352 | csrow->mtype = MEM_EMPTY; | ||
353 | continue; | ||
354 | } | ||
355 | |||
356 | csrow->first_page = last_cumul_size; | ||
357 | csrow->last_page = cumul_size - 1; | ||
358 | csrow->nr_pages = cumul_size - last_cumul_size; | ||
359 | last_cumul_size = cumul_size; | ||
360 | csrow->grain = I3000_DEAP_GRAIN; | ||
361 | csrow->mtype = MEM_DDR2; | ||
362 | csrow->dtype = DEV_UNKNOWN; | ||
363 | csrow->edac_mode = EDAC_UNKNOWN; | ||
364 | } | ||
365 | |||
366 | /* Clear any error bits. | ||
367 | * (Yes, we really clear bits by writing 1 to them.) | ||
368 | */ | ||
369 | pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS, | ||
370 | I3000_ERRSTS_BITS); | ||
371 | |||
372 | rc = -ENODEV; | ||
373 | if (edac_mc_add_mc(mci)) { | ||
374 | debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__); | ||
375 | goto fail; | ||
376 | } | ||
377 | |||
378 | /* allocating generic PCI control info */ | ||
379 | i3000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
380 | if (!i3000_pci) { | ||
381 | printk(KERN_WARNING | ||
382 | "%s(): Unable to create PCI control\n", | ||
383 | __func__); | ||
384 | printk(KERN_WARNING | ||
385 | "%s(): PCI error report via EDAC not setup\n", | ||
386 | __func__); | ||
387 | } | ||
388 | |||
389 | /* get this far and it's successful */ | ||
390 | debugf3("MC: %s(): success\n", __func__); | ||
391 | return 0; | ||
392 | |||
393 | fail: | ||
394 | if (mci) | ||
395 | edac_mc_free(mci); | ||
396 | |||
397 | return rc; | ||
398 | } | ||
399 | |||
400 | /* returns count (>= 0), or negative on error */ | ||
401 | static int __devinit i3000_init_one(struct pci_dev *pdev, | ||
402 | const struct pci_device_id *ent) | ||
403 | { | ||
404 | int rc; | ||
405 | |||
406 | debugf0("MC: %s()\n", __func__); | ||
407 | |||
408 | if (pci_enable_device(pdev) < 0) | ||
409 | return -EIO; | ||
410 | |||
411 | rc = i3000_probe1(pdev, ent->driver_data); | ||
412 | if (mci_pdev == NULL) | ||
413 | mci_pdev = pci_dev_get(pdev); | ||
414 | |||
415 | return rc; | ||
416 | } | ||
417 | |||
418 | static void __devexit i3000_remove_one(struct pci_dev *pdev) | ||
419 | { | ||
420 | struct mem_ctl_info *mci; | ||
421 | |||
422 | debugf0("%s()\n", __func__); | ||
423 | |||
424 | if (i3000_pci) | ||
425 | edac_pci_release_generic_ctl(i3000_pci); | ||
426 | |||
427 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | ||
428 | return; | ||
429 | |||
430 | edac_mc_free(mci); | ||
431 | } | ||
432 | |||
433 | static const struct pci_device_id i3000_pci_tbl[] __devinitdata = { | ||
434 | { | ||
435 | PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
436 | I3000}, | ||
437 | { | ||
438 | 0, | ||
439 | } /* 0 terminated list. */ | ||
440 | }; | ||
441 | |||
442 | MODULE_DEVICE_TABLE(pci, i3000_pci_tbl); | ||
443 | |||
444 | static struct pci_driver i3000_driver = { | ||
445 | .name = EDAC_MOD_STR, | ||
446 | .probe = i3000_init_one, | ||
447 | .remove = __devexit_p(i3000_remove_one), | ||
448 | .id_table = i3000_pci_tbl, | ||
449 | }; | ||
450 | |||
451 | static int __init i3000_init(void) | ||
452 | { | ||
453 | int pci_rc; | ||
454 | |||
455 | debugf3("MC: %s()\n", __func__); | ||
456 | pci_rc = pci_register_driver(&i3000_driver); | ||
457 | if (pci_rc < 0) | ||
458 | goto fail0; | ||
459 | |||
460 | if (mci_pdev == NULL) { | ||
461 | i3000_registered = 0; | ||
462 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
463 | PCI_DEVICE_ID_INTEL_3000_HB, NULL); | ||
464 | if (!mci_pdev) { | ||
465 | debugf0("i3000 pci_get_device fail\n"); | ||
466 | pci_rc = -ENODEV; | ||
467 | goto fail1; | ||
468 | } | ||
469 | |||
470 | pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl); | ||
471 | if (pci_rc < 0) { | ||
472 | debugf0("i3000 init fail\n"); | ||
473 | pci_rc = -ENODEV; | ||
474 | goto fail1; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | |||
480 | fail1: | ||
481 | pci_unregister_driver(&i3000_driver); | ||
482 | |||
483 | fail0: | ||
484 | if (mci_pdev) | ||
485 | pci_dev_put(mci_pdev); | ||
486 | |||
487 | return pci_rc; | ||
488 | } | ||
489 | |||
490 | static void __exit i3000_exit(void) | ||
491 | { | ||
492 | debugf3("MC: %s()\n", __func__); | ||
493 | |||
494 | pci_unregister_driver(&i3000_driver); | ||
495 | if (!i3000_registered) { | ||
496 | i3000_remove_one(mci_pdev); | ||
497 | pci_dev_put(mci_pdev); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | module_init(i3000_init); | ||
502 | module_exit(i3000_exit); | ||
503 | |||
504 | MODULE_LICENSE("GPL"); | ||
505 | MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott"); | ||
506 | MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers"); | ||
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c new file mode 100644 index 000000000000..96f7e63e3996 --- /dev/null +++ b/drivers/edac/i5000_edac.c | |||
@@ -0,0 +1,1505 @@ | |||
1 | /* | ||
2 | * Intel 5000(P/V/X) class Memory Controllers kernel module | ||
3 | * | ||
4 | * This file may be distributed under the terms of the | ||
5 | * GNU General Public License. | ||
6 | * | ||
7 | * Written by Douglas Thompson Linux Networx (http://lnxi.com) | ||
8 | * norsk5@xmission.com | ||
9 | * | ||
10 | * This module is based on the following document: | ||
11 | * | ||
12 | * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet | ||
13 | * http://developer.intel.com/design/chipsets/datashts/313070.htm | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/pci_ids.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/edac.h> | ||
23 | #include <asm/mmzone.h> | ||
24 | |||
25 | #include "edac_core.h" | ||
26 | |||
27 | /* | ||
28 | * Alter this version for the I5000 module when modifications are made | ||
29 | */ | ||
30 | #define I5000_REVISION " Ver: 2.0.12 " __DATE__ | ||
31 | #define EDAC_MOD_STR "i5000_edac" | ||
32 | |||
33 | #define i5000_printk(level, fmt, arg...) \ | ||
34 | edac_printk(level, "i5000", fmt, ##arg) | ||
35 | |||
36 | #define i5000_mc_printk(mci, level, fmt, arg...) \ | ||
37 | edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg) | ||
38 | |||
39 | #ifndef PCI_DEVICE_ID_INTEL_FBD_0 | ||
40 | #define PCI_DEVICE_ID_INTEL_FBD_0 0x25F5 | ||
41 | #endif | ||
42 | #ifndef PCI_DEVICE_ID_INTEL_FBD_1 | ||
43 | #define PCI_DEVICE_ID_INTEL_FBD_1 0x25F6 | ||
44 | #endif | ||
45 | |||
46 | /* Device 16, | ||
47 | * Function 0: System Address | ||
48 | * Function 1: Memory Branch Map, Control, Errors Register | ||
49 | * Function 2: FSB Error Registers | ||
50 | * | ||
51 | * All 3 functions of Device 16 (0,1,2) share the SAME DID | ||
52 | */ | ||
53 | #define PCI_DEVICE_ID_INTEL_I5000_DEV16 0x25F0 | ||
54 | |||
55 | /* OFFSETS for Function 0 */ | ||
56 | |||
57 | /* OFFSETS for Function 1 */ | ||
58 | #define AMBASE 0x48 | ||
59 | #define MAXCH 0x56 | ||
60 | #define MAXDIMMPERCH 0x57 | ||
61 | #define TOLM 0x6C | ||
62 | #define REDMEMB 0x7C | ||
63 | #define RED_ECC_LOCATOR(x) ((x) & 0x3FFFF) | ||
64 | #define REC_ECC_LOCATOR_EVEN(x) ((x) & 0x001FF) | ||
65 | #define REC_ECC_LOCATOR_ODD(x) ((x) & 0x3FE00) | ||
66 | #define MIR0 0x80 | ||
67 | #define MIR1 0x84 | ||
68 | #define MIR2 0x88 | ||
69 | #define AMIR0 0x8C | ||
70 | #define AMIR1 0x90 | ||
71 | #define AMIR2 0x94 | ||
72 | |||
73 | #define FERR_FAT_FBD 0x98 | ||
74 | #define NERR_FAT_FBD 0x9C | ||
75 | #define EXTRACT_FBDCHAN_INDX(x) (((x)>>28) & 0x3) | ||
76 | #define FERR_FAT_FBDCHAN 0x30000000 | ||
77 | #define FERR_FAT_M3ERR 0x00000004 | ||
78 | #define FERR_FAT_M2ERR 0x00000002 | ||
79 | #define FERR_FAT_M1ERR 0x00000001 | ||
80 | #define FERR_FAT_MASK (FERR_FAT_M1ERR | \ | ||
81 | FERR_FAT_M2ERR | \ | ||
82 | FERR_FAT_M3ERR) | ||
83 | |||
84 | #define FERR_NF_FBD 0xA0 | ||
85 | |||
86 | /* Thermal and SPD or BFD errors */ | ||
87 | #define FERR_NF_M28ERR 0x01000000 | ||
88 | #define FERR_NF_M27ERR 0x00800000 | ||
89 | #define FERR_NF_M26ERR 0x00400000 | ||
90 | #define FERR_NF_M25ERR 0x00200000 | ||
91 | #define FERR_NF_M24ERR 0x00100000 | ||
92 | #define FERR_NF_M23ERR 0x00080000 | ||
93 | #define FERR_NF_M22ERR 0x00040000 | ||
94 | #define FERR_NF_M21ERR 0x00020000 | ||
95 | |||
96 | /* Correctable errors */ | ||
97 | #define FERR_NF_M20ERR 0x00010000 | ||
98 | #define FERR_NF_M19ERR 0x00008000 | ||
99 | #define FERR_NF_M18ERR 0x00004000 | ||
100 | #define FERR_NF_M17ERR 0x00002000 | ||
101 | |||
102 | /* Non-Retry or redundant Retry errors */ | ||
103 | #define FERR_NF_M16ERR 0x00001000 | ||
104 | #define FERR_NF_M15ERR 0x00000800 | ||
105 | #define FERR_NF_M14ERR 0x00000400 | ||
106 | #define FERR_NF_M13ERR 0x00000200 | ||
107 | |||
108 | /* Uncorrectable errors */ | ||
109 | #define FERR_NF_M12ERR 0x00000100 | ||
110 | #define FERR_NF_M11ERR 0x00000080 | ||
111 | #define FERR_NF_M10ERR 0x00000040 | ||
112 | #define FERR_NF_M9ERR 0x00000020 | ||
113 | #define FERR_NF_M8ERR 0x00000010 | ||
114 | #define FERR_NF_M7ERR 0x00000008 | ||
115 | #define FERR_NF_M6ERR 0x00000004 | ||
116 | #define FERR_NF_M5ERR 0x00000002 | ||
117 | #define FERR_NF_M4ERR 0x00000001 | ||
118 | |||
119 | #define FERR_NF_UNCORRECTABLE (FERR_NF_M12ERR | \ | ||
120 | FERR_NF_M11ERR | \ | ||
121 | FERR_NF_M10ERR | \ | ||
122 | FERR_NF_M8ERR | \ | ||
123 | FERR_NF_M7ERR | \ | ||
124 | FERR_NF_M6ERR | \ | ||
125 | FERR_NF_M5ERR | \ | ||
126 | FERR_NF_M4ERR) | ||
127 | #define FERR_NF_CORRECTABLE (FERR_NF_M20ERR | \ | ||
128 | FERR_NF_M19ERR | \ | ||
129 | FERR_NF_M18ERR | \ | ||
130 | FERR_NF_M17ERR) | ||
131 | #define FERR_NF_DIMM_SPARE (FERR_NF_M27ERR | \ | ||
132 | FERR_NF_M28ERR) | ||
133 | #define FERR_NF_THERMAL (FERR_NF_M26ERR | \ | ||
134 | FERR_NF_M25ERR | \ | ||
135 | FERR_NF_M24ERR | \ | ||
136 | FERR_NF_M23ERR) | ||
137 | #define FERR_NF_SPD_PROTOCOL (FERR_NF_M22ERR) | ||
138 | #define FERR_NF_NORTH_CRC (FERR_NF_M21ERR) | ||
139 | #define FERR_NF_NON_RETRY (FERR_NF_M13ERR | \ | ||
140 | FERR_NF_M14ERR | \ | ||
141 | FERR_NF_M15ERR) | ||
142 | |||
143 | #define NERR_NF_FBD 0xA4 | ||
144 | #define FERR_NF_MASK (FERR_NF_UNCORRECTABLE | \ | ||
145 | FERR_NF_CORRECTABLE | \ | ||
146 | FERR_NF_DIMM_SPARE | \ | ||
147 | FERR_NF_THERMAL | \ | ||
148 | FERR_NF_SPD_PROTOCOL | \ | ||
149 | FERR_NF_NORTH_CRC | \ | ||
150 | FERR_NF_NON_RETRY) | ||
151 | |||
152 | #define EMASK_FBD 0xA8 | ||
153 | #define EMASK_FBD_M28ERR 0x08000000 | ||
154 | #define EMASK_FBD_M27ERR 0x04000000 | ||
155 | #define EMASK_FBD_M26ERR 0x02000000 | ||
156 | #define EMASK_FBD_M25ERR 0x01000000 | ||
157 | #define EMASK_FBD_M24ERR 0x00800000 | ||
158 | #define EMASK_FBD_M23ERR 0x00400000 | ||
159 | #define EMASK_FBD_M22ERR 0x00200000 | ||
160 | #define EMASK_FBD_M21ERR 0x00100000 | ||
161 | #define EMASK_FBD_M20ERR 0x00080000 | ||
162 | #define EMASK_FBD_M19ERR 0x00040000 | ||
163 | #define EMASK_FBD_M18ERR 0x00020000 | ||
164 | #define EMASK_FBD_M17ERR 0x00010000 | ||
165 | |||
166 | #define EMASK_FBD_M15ERR 0x00004000 | ||
167 | #define EMASK_FBD_M14ERR 0x00002000 | ||
168 | #define EMASK_FBD_M13ERR 0x00001000 | ||
169 | #define EMASK_FBD_M12ERR 0x00000800 | ||
170 | #define EMASK_FBD_M11ERR 0x00000400 | ||
171 | #define EMASK_FBD_M10ERR 0x00000200 | ||
172 | #define EMASK_FBD_M9ERR 0x00000100 | ||
173 | #define EMASK_FBD_M8ERR 0x00000080 | ||
174 | #define EMASK_FBD_M7ERR 0x00000040 | ||
175 | #define EMASK_FBD_M6ERR 0x00000020 | ||
176 | #define EMASK_FBD_M5ERR 0x00000010 | ||
177 | #define EMASK_FBD_M4ERR 0x00000008 | ||
178 | #define EMASK_FBD_M3ERR 0x00000004 | ||
179 | #define EMASK_FBD_M2ERR 0x00000002 | ||
180 | #define EMASK_FBD_M1ERR 0x00000001 | ||
181 | |||
182 | #define ENABLE_EMASK_FBD_FATAL_ERRORS (EMASK_FBD_M1ERR | \ | ||
183 | EMASK_FBD_M2ERR | \ | ||
184 | EMASK_FBD_M3ERR) | ||
185 | |||
186 | #define ENABLE_EMASK_FBD_UNCORRECTABLE (EMASK_FBD_M4ERR | \ | ||
187 | EMASK_FBD_M5ERR | \ | ||
188 | EMASK_FBD_M6ERR | \ | ||
189 | EMASK_FBD_M7ERR | \ | ||
190 | EMASK_FBD_M8ERR | \ | ||
191 | EMASK_FBD_M9ERR | \ | ||
192 | EMASK_FBD_M10ERR | \ | ||
193 | EMASK_FBD_M11ERR | \ | ||
194 | EMASK_FBD_M12ERR) | ||
195 | #define ENABLE_EMASK_FBD_CORRECTABLE (EMASK_FBD_M17ERR | \ | ||
196 | EMASK_FBD_M18ERR | \ | ||
197 | EMASK_FBD_M19ERR | \ | ||
198 | EMASK_FBD_M20ERR) | ||
199 | #define ENABLE_EMASK_FBD_DIMM_SPARE (EMASK_FBD_M27ERR | \ | ||
200 | EMASK_FBD_M28ERR) | ||
201 | #define ENABLE_EMASK_FBD_THERMALS (EMASK_FBD_M26ERR | \ | ||
202 | EMASK_FBD_M25ERR | \ | ||
203 | EMASK_FBD_M24ERR | \ | ||
204 | EMASK_FBD_M23ERR) | ||
205 | #define ENABLE_EMASK_FBD_SPD_PROTOCOL (EMASK_FBD_M22ERR) | ||
206 | #define ENABLE_EMASK_FBD_NORTH_CRC (EMASK_FBD_M21ERR) | ||
207 | #define ENABLE_EMASK_FBD_NON_RETRY (EMASK_FBD_M15ERR | \ | ||
208 | EMASK_FBD_M14ERR | \ | ||
209 | EMASK_FBD_M13ERR) | ||
210 | |||
211 | #define ENABLE_EMASK_ALL (ENABLE_EMASK_FBD_NON_RETRY | \ | ||
212 | ENABLE_EMASK_FBD_NORTH_CRC | \ | ||
213 | ENABLE_EMASK_FBD_SPD_PROTOCOL | \ | ||
214 | ENABLE_EMASK_FBD_THERMALS | \ | ||
215 | ENABLE_EMASK_FBD_DIMM_SPARE | \ | ||
216 | ENABLE_EMASK_FBD_FATAL_ERRORS | \ | ||
217 | ENABLE_EMASK_FBD_CORRECTABLE | \ | ||
218 | ENABLE_EMASK_FBD_UNCORRECTABLE) | ||
219 | |||
220 | #define ERR0_FBD 0xAC | ||
221 | #define ERR1_FBD 0xB0 | ||
222 | #define ERR2_FBD 0xB4 | ||
223 | #define MCERR_FBD 0xB8 | ||
224 | #define NRECMEMA 0xBE | ||
225 | #define NREC_BANK(x) (((x)>>12) & 0x7) | ||
226 | #define NREC_RDWR(x) (((x)>>11) & 1) | ||
227 | #define NREC_RANK(x) (((x)>>8) & 0x7) | ||
228 | #define NRECMEMB 0xC0 | ||
229 | #define NREC_CAS(x) (((x)>>16) & 0xFFFFFF) | ||
230 | #define NREC_RAS(x) ((x) & 0x7FFF) | ||
231 | #define NRECFGLOG 0xC4 | ||
232 | #define NREEECFBDA 0xC8 | ||
233 | #define NREEECFBDB 0xCC | ||
234 | #define NREEECFBDC 0xD0 | ||
235 | #define NREEECFBDD 0xD4 | ||
236 | #define NREEECFBDE 0xD8 | ||
237 | #define REDMEMA 0xDC | ||
238 | #define RECMEMA 0xE2 | ||
239 | #define REC_BANK(x) (((x)>>12) & 0x7) | ||
240 | #define REC_RDWR(x) (((x)>>11) & 1) | ||
241 | #define REC_RANK(x) (((x)>>8) & 0x7) | ||
242 | #define RECMEMB 0xE4 | ||
243 | #define REC_CAS(x) (((x)>>16) & 0xFFFFFF) | ||
244 | #define REC_RAS(x) ((x) & 0x7FFF) | ||
245 | #define RECFGLOG 0xE8 | ||
246 | #define RECFBDA 0xEC | ||
247 | #define RECFBDB 0xF0 | ||
248 | #define RECFBDC 0xF4 | ||
249 | #define RECFBDD 0xF8 | ||
250 | #define RECFBDE 0xFC | ||
251 | |||
252 | /* OFFSETS for Function 2 */ | ||
253 | |||
254 | /* | ||
255 | * Device 21, | ||
256 | * Function 0: Memory Map Branch 0 | ||
257 | * | ||
258 | * Device 22, | ||
259 | * Function 0: Memory Map Branch 1 | ||
260 | */ | ||
261 | #define PCI_DEVICE_ID_I5000_BRANCH_0 0x25F5 | ||
262 | #define PCI_DEVICE_ID_I5000_BRANCH_1 0x25F6 | ||
263 | |||
264 | #define AMB_PRESENT_0 0x64 | ||
265 | #define AMB_PRESENT_1 0x66 | ||
266 | #define MTR0 0x80 | ||
267 | #define MTR1 0x84 | ||
268 | #define MTR2 0x88 | ||
269 | #define MTR3 0x8C | ||
270 | |||
271 | #define NUM_MTRS 4 | ||
272 | #define CHANNELS_PER_BRANCH (2) | ||
273 | |||
274 | /* Defines to extract the vaious fields from the | ||
275 | * MTRx - Memory Technology Registers | ||
276 | */ | ||
277 | #define MTR_DIMMS_PRESENT(mtr) ((mtr) & (0x1 << 8)) | ||
278 | #define MTR_DRAM_WIDTH(mtr) ((((mtr) >> 6) & 0x1) ? 8 : 4) | ||
279 | #define MTR_DRAM_BANKS(mtr) ((((mtr) >> 5) & 0x1) ? 8 : 4) | ||
280 | #define MTR_DRAM_BANKS_ADDR_BITS(mtr) ((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2) | ||
281 | #define MTR_DIMM_RANK(mtr) (((mtr) >> 4) & 0x1) | ||
282 | #define MTR_DIMM_RANK_ADDR_BITS(mtr) (MTR_DIMM_RANK(mtr) ? 2 : 1) | ||
283 | #define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) | ||
284 | #define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) | ||
285 | #define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) | ||
286 | #define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) | ||
287 | |||
288 | #ifdef CONFIG_EDAC_DEBUG | ||
289 | static char *numrow_toString[] = { | ||
290 | "8,192 - 13 rows", | ||
291 | "16,384 - 14 rows", | ||
292 | "32,768 - 15 rows", | ||
293 | "reserved" | ||
294 | }; | ||
295 | |||
296 | static char *numcol_toString[] = { | ||
297 | "1,024 - 10 columns", | ||
298 | "2,048 - 11 columns", | ||
299 | "4,096 - 12 columns", | ||
300 | "reserved" | ||
301 | }; | ||
302 | #endif | ||
303 | |||
304 | /* Enumeration of supported devices */ | ||
305 | enum i5000_chips { | ||
306 | I5000P = 0, | ||
307 | I5000V = 1, /* future */ | ||
308 | I5000X = 2 /* future */ | ||
309 | }; | ||
310 | |||
311 | /* Device name and register DID (Device ID) */ | ||
312 | struct i5000_dev_info { | ||
313 | const char *ctl_name; /* name for this device */ | ||
314 | u16 fsb_mapping_errors; /* DID for the branchmap,control */ | ||
315 | }; | ||
316 | |||
317 | /* Table of devices attributes supported by this driver */ | ||
318 | static const struct i5000_dev_info i5000_devs[] = { | ||
319 | [I5000P] = { | ||
320 | .ctl_name = "I5000", | ||
321 | .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16, | ||
322 | }, | ||
323 | }; | ||
324 | |||
325 | struct i5000_dimm_info { | ||
326 | int megabytes; /* size, 0 means not present */ | ||
327 | int dual_rank; | ||
328 | }; | ||
329 | |||
330 | #define MAX_CHANNELS 6 /* max possible channels */ | ||
331 | #define MAX_CSROWS (8*2) /* max possible csrows per channel */ | ||
332 | |||
333 | /* driver private data structure */ | ||
334 | struct i5000_pvt { | ||
335 | struct pci_dev *system_address; /* 16.0 */ | ||
336 | struct pci_dev *branchmap_werrors; /* 16.1 */ | ||
337 | struct pci_dev *fsb_error_regs; /* 16.2 */ | ||
338 | struct pci_dev *branch_0; /* 21.0 */ | ||
339 | struct pci_dev *branch_1; /* 22.0 */ | ||
340 | |||
341 | u16 tolm; /* top of low memory */ | ||
342 | u64 ambase; /* AMB BAR */ | ||
343 | |||
344 | u16 mir0, mir1, mir2; | ||
345 | |||
346 | u16 b0_mtr[NUM_MTRS]; /* Memory Technlogy Reg */ | ||
347 | u16 b0_ambpresent0; /* Branch 0, Channel 0 */ | ||
348 | u16 b0_ambpresent1; /* Brnach 0, Channel 1 */ | ||
349 | |||
350 | u16 b1_mtr[NUM_MTRS]; /* Memory Technlogy Reg */ | ||
351 | u16 b1_ambpresent0; /* Branch 1, Channel 8 */ | ||
352 | u16 b1_ambpresent1; /* Branch 1, Channel 1 */ | ||
353 | |||
354 | /* DIMM infomation matrix, allocating architecture maximums */ | ||
355 | struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS]; | ||
356 | |||
357 | /* Actual values for this controller */ | ||
358 | int maxch; /* Max channels */ | ||
359 | int maxdimmperch; /* Max DIMMs per channel */ | ||
360 | }; | ||
361 | |||
362 | /* I5000 MCH error information retrieved from Hardware */ | ||
363 | struct i5000_error_info { | ||
364 | |||
365 | /* These registers are always read from the MC */ | ||
366 | u32 ferr_fat_fbd; /* First Errors Fatal */ | ||
367 | u32 nerr_fat_fbd; /* Next Errors Fatal */ | ||
368 | u32 ferr_nf_fbd; /* First Errors Non-Fatal */ | ||
369 | u32 nerr_nf_fbd; /* Next Errors Non-Fatal */ | ||
370 | |||
371 | /* These registers are input ONLY if there was a Recoverable Error */ | ||
372 | u32 redmemb; /* Recoverable Mem Data Error log B */ | ||
373 | u16 recmema; /* Recoverable Mem Error log A */ | ||
374 | u32 recmemb; /* Recoverable Mem Error log B */ | ||
375 | |||
376 | /* These registers are input ONLY if there was a | ||
377 | * Non-Recoverable Error */ | ||
378 | u16 nrecmema; /* Non-Recoverable Mem log A */ | ||
379 | u16 nrecmemb; /* Non-Recoverable Mem log B */ | ||
380 | |||
381 | }; | ||
382 | |||
383 | static struct edac_pci_ctl_info *i5000_pci; | ||
384 | |||
385 | /* | ||
386 | * i5000_get_error_info Retrieve the hardware error information from | ||
387 | * the hardware and cache it in the 'info' | ||
388 | * structure | ||
389 | */ | ||
390 | static void i5000_get_error_info(struct mem_ctl_info *mci, | ||
391 | struct i5000_error_info *info) | ||
392 | { | ||
393 | struct i5000_pvt *pvt; | ||
394 | u32 value; | ||
395 | |||
396 | pvt = mci->pvt_info; | ||
397 | |||
398 | /* read in the 1st FATAL error register */ | ||
399 | pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value); | ||
400 | |||
401 | /* Mask only the bits that the doc says are valid | ||
402 | */ | ||
403 | value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK); | ||
404 | |||
405 | /* If there is an error, then read in the */ | ||
406 | /* NEXT FATAL error register and the Memory Error Log Register A */ | ||
407 | if (value & FERR_FAT_MASK) { | ||
408 | info->ferr_fat_fbd = value; | ||
409 | |||
410 | /* harvest the various error data we need */ | ||
411 | pci_read_config_dword(pvt->branchmap_werrors, | ||
412 | NERR_FAT_FBD, &info->nerr_fat_fbd); | ||
413 | pci_read_config_word(pvt->branchmap_werrors, | ||
414 | NRECMEMA, &info->nrecmema); | ||
415 | pci_read_config_word(pvt->branchmap_werrors, | ||
416 | NRECMEMB, &info->nrecmemb); | ||
417 | |||
418 | /* Clear the error bits, by writing them back */ | ||
419 | pci_write_config_dword(pvt->branchmap_werrors, | ||
420 | FERR_FAT_FBD, value); | ||
421 | } else { | ||
422 | info->ferr_fat_fbd = 0; | ||
423 | info->nerr_fat_fbd = 0; | ||
424 | info->nrecmema = 0; | ||
425 | info->nrecmemb = 0; | ||
426 | } | ||
427 | |||
428 | /* read in the 1st NON-FATAL error register */ | ||
429 | pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value); | ||
430 | |||
431 | /* If there is an error, then read in the 1st NON-FATAL error | ||
432 | * register as well */ | ||
433 | if (value & FERR_NF_MASK) { | ||
434 | info->ferr_nf_fbd = value; | ||
435 | |||
436 | /* harvest the various error data we need */ | ||
437 | pci_read_config_dword(pvt->branchmap_werrors, | ||
438 | NERR_NF_FBD, &info->nerr_nf_fbd); | ||
439 | pci_read_config_word(pvt->branchmap_werrors, | ||
440 | RECMEMA, &info->recmema); | ||
441 | pci_read_config_dword(pvt->branchmap_werrors, | ||
442 | RECMEMB, &info->recmemb); | ||
443 | pci_read_config_dword(pvt->branchmap_werrors, | ||
444 | REDMEMB, &info->redmemb); | ||
445 | |||
446 | /* Clear the error bits, by writing them back */ | ||
447 | pci_write_config_dword(pvt->branchmap_werrors, | ||
448 | FERR_NF_FBD, value); | ||
449 | } else { | ||
450 | info->ferr_nf_fbd = 0; | ||
451 | info->nerr_nf_fbd = 0; | ||
452 | info->recmema = 0; | ||
453 | info->recmemb = 0; | ||
454 | info->redmemb = 0; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * i5000_process_fatal_error_info(struct mem_ctl_info *mci, | ||
460 | * struct i5000_error_info *info, | ||
461 | * int handle_errors); | ||
462 | * | ||
463 | * handle the Intel FATAL errors, if any | ||
464 | */ | ||
465 | static void i5000_process_fatal_error_info(struct mem_ctl_info *mci, | ||
466 | struct i5000_error_info *info, | ||
467 | int handle_errors) | ||
468 | { | ||
469 | char msg[EDAC_MC_LABEL_LEN + 1 + 90]; | ||
470 | u32 allErrors; | ||
471 | int branch; | ||
472 | int channel; | ||
473 | int bank; | ||
474 | int rank; | ||
475 | int rdwr; | ||
476 | int ras, cas; | ||
477 | |||
478 | /* mask off the Error bits that are possible */ | ||
479 | allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK); | ||
480 | if (!allErrors) | ||
481 | return; /* if no error, return now */ | ||
482 | |||
483 | /* ONLY ONE of the possible error bits will be set, as per the docs */ | ||
484 | i5000_mc_printk(mci, KERN_ERR, | ||
485 | "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n", | ||
486 | allErrors); | ||
487 | |||
488 | branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd); | ||
489 | channel = branch; | ||
490 | |||
491 | /* Use the NON-Recoverable macros to extract data */ | ||
492 | bank = NREC_BANK(info->nrecmema); | ||
493 | rank = NREC_RANK(info->nrecmema); | ||
494 | rdwr = NREC_RDWR(info->nrecmema); | ||
495 | ras = NREC_RAS(info->nrecmemb); | ||
496 | cas = NREC_CAS(info->nrecmemb); | ||
497 | |||
498 | debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " | ||
499 | "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", | ||
500 | rank, channel, channel + 1, branch >> 1, bank, | ||
501 | rdwr ? "Write" : "Read", ras, cas); | ||
502 | |||
503 | /* Only 1 bit will be on */ | ||
504 | if (allErrors & FERR_FAT_M1ERR) { | ||
505 | i5000_mc_printk(mci, KERN_ERR, | ||
506 | "Alert on non-redundant retry or fast " | ||
507 | "reset timeout\n"); | ||
508 | |||
509 | } else if (allErrors & FERR_FAT_M2ERR) { | ||
510 | i5000_mc_printk(mci, KERN_ERR, | ||
511 | "Northbound CRC error on non-redundant " | ||
512 | "retry\n"); | ||
513 | |||
514 | } else if (allErrors & FERR_FAT_M3ERR) { | ||
515 | i5000_mc_printk(mci, KERN_ERR, | ||
516 | ">Tmid Thermal event with intelligent " | ||
517 | "throttling disabled\n"); | ||
518 | } | ||
519 | |||
520 | /* Form out message */ | ||
521 | snprintf(msg, sizeof(msg), | ||
522 | "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d " | ||
523 | "FATAL Err=0x%x)", | ||
524 | branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas, | ||
525 | allErrors); | ||
526 | |||
527 | /* Call the helper to output message */ | ||
528 | edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * i5000_process_fatal_error_info(struct mem_ctl_info *mci, | ||
533 | * struct i5000_error_info *info, | ||
534 | * int handle_errors); | ||
535 | * | ||
536 | * handle the Intel NON-FATAL errors, if any | ||
537 | */ | ||
538 | static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci, | ||
539 | struct i5000_error_info *info, | ||
540 | int handle_errors) | ||
541 | { | ||
542 | char msg[EDAC_MC_LABEL_LEN + 1 + 90]; | ||
543 | u32 allErrors; | ||
544 | u32 ue_errors; | ||
545 | u32 ce_errors; | ||
546 | u32 misc_errors; | ||
547 | int branch; | ||
548 | int channel; | ||
549 | int bank; | ||
550 | int rank; | ||
551 | int rdwr; | ||
552 | int ras, cas; | ||
553 | |||
554 | /* mask off the Error bits that are possible */ | ||
555 | allErrors = (info->ferr_nf_fbd & FERR_NF_MASK); | ||
556 | if (!allErrors) | ||
557 | return; /* if no error, return now */ | ||
558 | |||
559 | /* ONLY ONE of the possible error bits will be set, as per the docs */ | ||
560 | i5000_mc_printk(mci, KERN_WARNING, | ||
561 | "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err " | ||
562 | "Reg= 0x%x\n", allErrors); | ||
563 | |||
564 | ue_errors = allErrors & FERR_NF_UNCORRECTABLE; | ||
565 | if (ue_errors) { | ||
566 | debugf0("\tUncorrected bits= 0x%x\n", ue_errors); | ||
567 | |||
568 | branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd); | ||
569 | channel = branch; | ||
570 | bank = NREC_BANK(info->nrecmema); | ||
571 | rank = NREC_RANK(info->nrecmema); | ||
572 | rdwr = NREC_RDWR(info->nrecmema); | ||
573 | ras = NREC_RAS(info->nrecmemb); | ||
574 | cas = NREC_CAS(info->nrecmemb); | ||
575 | |||
576 | debugf0 | ||
577 | ("\t\tCSROW= %d Channels= %d,%d (Branch= %d " | ||
578 | "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", | ||
579 | rank, channel, channel + 1, branch >> 1, bank, | ||
580 | rdwr ? "Write" : "Read", ras, cas); | ||
581 | |||
582 | /* Form out message */ | ||
583 | snprintf(msg, sizeof(msg), | ||
584 | "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d " | ||
585 | "CAS=%d, UE Err=0x%x)", | ||
586 | branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas, | ||
587 | ue_errors); | ||
588 | |||
589 | /* Call the helper to output message */ | ||
590 | edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); | ||
591 | } | ||
592 | |||
593 | /* Check correctable errors */ | ||
594 | ce_errors = allErrors & FERR_NF_CORRECTABLE; | ||
595 | if (ce_errors) { | ||
596 | debugf0("\tCorrected bits= 0x%x\n", ce_errors); | ||
597 | |||
598 | branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd); | ||
599 | |||
600 | channel = 0; | ||
601 | if (REC_ECC_LOCATOR_ODD(info->redmemb)) | ||
602 | channel = 1; | ||
603 | |||
604 | /* Convert channel to be based from zero, instead of | ||
605 | * from branch base of 0 */ | ||
606 | channel += branch; | ||
607 | |||
608 | bank = REC_BANK(info->recmema); | ||
609 | rank = REC_RANK(info->recmema); | ||
610 | rdwr = REC_RDWR(info->recmema); | ||
611 | ras = REC_RAS(info->recmemb); | ||
612 | cas = REC_CAS(info->recmemb); | ||
613 | |||
614 | debugf0("\t\tCSROW= %d Channel= %d (Branch %d " | ||
615 | "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", | ||
616 | rank, channel, branch >> 1, bank, | ||
617 | rdwr ? "Write" : "Read", ras, cas); | ||
618 | |||
619 | /* Form out message */ | ||
620 | snprintf(msg, sizeof(msg), | ||
621 | "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d " | ||
622 | "CAS=%d, CE Err=0x%x)", branch >> 1, bank, | ||
623 | rdwr ? "Write" : "Read", ras, cas, ce_errors); | ||
624 | |||
625 | /* Call the helper to output message */ | ||
626 | edac_mc_handle_fbd_ce(mci, rank, channel, msg); | ||
627 | } | ||
628 | |||
629 | /* See if any of the thermal errors have fired */ | ||
630 | misc_errors = allErrors & FERR_NF_THERMAL; | ||
631 | if (misc_errors) { | ||
632 | i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n", | ||
633 | misc_errors); | ||
634 | } | ||
635 | |||
636 | /* See if any of the thermal errors have fired */ | ||
637 | misc_errors = allErrors & FERR_NF_NON_RETRY; | ||
638 | if (misc_errors) { | ||
639 | i5000_printk(KERN_WARNING, "\tNON-Retry Errors, bits= 0x%x\n", | ||
640 | misc_errors); | ||
641 | } | ||
642 | |||
643 | /* See if any of the thermal errors have fired */ | ||
644 | misc_errors = allErrors & FERR_NF_NORTH_CRC; | ||
645 | if (misc_errors) { | ||
646 | i5000_printk(KERN_WARNING, | ||
647 | "\tNORTHBOUND CRC Error, bits= 0x%x\n", | ||
648 | misc_errors); | ||
649 | } | ||
650 | |||
651 | /* See if any of the thermal errors have fired */ | ||
652 | misc_errors = allErrors & FERR_NF_SPD_PROTOCOL; | ||
653 | if (misc_errors) { | ||
654 | i5000_printk(KERN_WARNING, | ||
655 | "\tSPD Protocol Error, bits= 0x%x\n", | ||
656 | misc_errors); | ||
657 | } | ||
658 | |||
659 | /* See if any of the thermal errors have fired */ | ||
660 | misc_errors = allErrors & FERR_NF_DIMM_SPARE; | ||
661 | if (misc_errors) { | ||
662 | i5000_printk(KERN_WARNING, "\tDIMM-Spare Error, bits= 0x%x\n", | ||
663 | misc_errors); | ||
664 | } | ||
665 | } | ||
666 | |||
667 | /* | ||
668 | * i5000_process_error_info Process the error info that is | ||
669 | * in the 'info' structure, previously retrieved from hardware | ||
670 | */ | ||
671 | static void i5000_process_error_info(struct mem_ctl_info *mci, | ||
672 | struct i5000_error_info *info, | ||
673 | int handle_errors) | ||
674 | { | ||
675 | /* First handle any fatal errors that occurred */ | ||
676 | i5000_process_fatal_error_info(mci, info, handle_errors); | ||
677 | |||
678 | /* now handle any non-fatal errors that occurred */ | ||
679 | i5000_process_nonfatal_error_info(mci, info, handle_errors); | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * i5000_clear_error Retrieve any error from the hardware | ||
684 | * but do NOT process that error. | ||
685 | * Used for 'clearing' out of previous errors | ||
686 | * Called by the Core module. | ||
687 | */ | ||
688 | static void i5000_clear_error(struct mem_ctl_info *mci) | ||
689 | { | ||
690 | struct i5000_error_info info; | ||
691 | |||
692 | i5000_get_error_info(mci, &info); | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * i5000_check_error Retrieve and process errors reported by the | ||
697 | * hardware. Called by the Core module. | ||
698 | */ | ||
699 | static void i5000_check_error(struct mem_ctl_info *mci) | ||
700 | { | ||
701 | struct i5000_error_info info; | ||
702 | debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | ||
703 | i5000_get_error_info(mci, &info); | ||
704 | i5000_process_error_info(mci, &info, 1); | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * i5000_get_devices Find and perform 'get' operation on the MCH's | ||
709 | * device/functions we want to reference for this driver | ||
710 | * | ||
711 | * Need to 'get' device 16 func 1 and func 2 | ||
712 | */ | ||
713 | static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx) | ||
714 | { | ||
715 | //const struct i5000_dev_info *i5000_dev = &i5000_devs[dev_idx]; | ||
716 | struct i5000_pvt *pvt; | ||
717 | struct pci_dev *pdev; | ||
718 | |||
719 | pvt = mci->pvt_info; | ||
720 | |||
721 | /* Attempt to 'get' the MCH register we want */ | ||
722 | pdev = NULL; | ||
723 | while (1) { | ||
724 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
725 | PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev); | ||
726 | |||
727 | /* End of list, leave */ | ||
728 | if (pdev == NULL) { | ||
729 | i5000_printk(KERN_ERR, | ||
730 | "'system address,Process Bus' " | ||
731 | "device not found:" | ||
732 | "vendor 0x%x device 0x%x FUNC 1 " | ||
733 | "(broken BIOS?)\n", | ||
734 | PCI_VENDOR_ID_INTEL, | ||
735 | PCI_DEVICE_ID_INTEL_I5000_DEV16); | ||
736 | |||
737 | return 1; | ||
738 | } | ||
739 | |||
740 | /* Scan for device 16 func 1 */ | ||
741 | if (PCI_FUNC(pdev->devfn) == 1) | ||
742 | break; | ||
743 | } | ||
744 | |||
745 | pvt->branchmap_werrors = pdev; | ||
746 | |||
747 | /* Attempt to 'get' the MCH register we want */ | ||
748 | pdev = NULL; | ||
749 | while (1) { | ||
750 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
751 | PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev); | ||
752 | |||
753 | if (pdev == NULL) { | ||
754 | i5000_printk(KERN_ERR, | ||
755 | "MC: 'branchmap,control,errors' " | ||
756 | "device not found:" | ||
757 | "vendor 0x%x device 0x%x Func 2 " | ||
758 | "(broken BIOS?)\n", | ||
759 | PCI_VENDOR_ID_INTEL, | ||
760 | PCI_DEVICE_ID_INTEL_I5000_DEV16); | ||
761 | |||
762 | pci_dev_put(pvt->branchmap_werrors); | ||
763 | return 1; | ||
764 | } | ||
765 | |||
766 | /* Scan for device 16 func 1 */ | ||
767 | if (PCI_FUNC(pdev->devfn) == 2) | ||
768 | break; | ||
769 | } | ||
770 | |||
771 | pvt->fsb_error_regs = pdev; | ||
772 | |||
773 | debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", | ||
774 | pci_name(pvt->system_address), | ||
775 | pvt->system_address->vendor, pvt->system_address->device); | ||
776 | debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", | ||
777 | pci_name(pvt->branchmap_werrors), | ||
778 | pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device); | ||
779 | debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", | ||
780 | pci_name(pvt->fsb_error_regs), | ||
781 | pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device); | ||
782 | |||
783 | pdev = NULL; | ||
784 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
785 | PCI_DEVICE_ID_I5000_BRANCH_0, pdev); | ||
786 | |||
787 | if (pdev == NULL) { | ||
788 | i5000_printk(KERN_ERR, | ||
789 | "MC: 'BRANCH 0' device not found:" | ||
790 | "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", | ||
791 | PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I5000_BRANCH_0); | ||
792 | |||
793 | pci_dev_put(pvt->branchmap_werrors); | ||
794 | pci_dev_put(pvt->fsb_error_regs); | ||
795 | return 1; | ||
796 | } | ||
797 | |||
798 | pvt->branch_0 = pdev; | ||
799 | |||
800 | /* If this device claims to have more than 2 channels then | ||
801 | * fetch Branch 1's information | ||
802 | */ | ||
803 | if (pvt->maxch >= CHANNELS_PER_BRANCH) { | ||
804 | pdev = NULL; | ||
805 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
806 | PCI_DEVICE_ID_I5000_BRANCH_1, pdev); | ||
807 | |||
808 | if (pdev == NULL) { | ||
809 | i5000_printk(KERN_ERR, | ||
810 | "MC: 'BRANCH 1' device not found:" | ||
811 | "vendor 0x%x device 0x%x Func 0 " | ||
812 | "(broken BIOS?)\n", | ||
813 | PCI_VENDOR_ID_INTEL, | ||
814 | PCI_DEVICE_ID_I5000_BRANCH_1); | ||
815 | |||
816 | pci_dev_put(pvt->branchmap_werrors); | ||
817 | pci_dev_put(pvt->fsb_error_regs); | ||
818 | pci_dev_put(pvt->branch_0); | ||
819 | return 1; | ||
820 | } | ||
821 | |||
822 | pvt->branch_1 = pdev; | ||
823 | } | ||
824 | |||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * i5000_put_devices 'put' all the devices that we have | ||
830 | * reserved via 'get' | ||
831 | */ | ||
832 | static void i5000_put_devices(struct mem_ctl_info *mci) | ||
833 | { | ||
834 | struct i5000_pvt *pvt; | ||
835 | |||
836 | pvt = mci->pvt_info; | ||
837 | |||
838 | pci_dev_put(pvt->branchmap_werrors); /* FUNC 1 */ | ||
839 | pci_dev_put(pvt->fsb_error_regs); /* FUNC 2 */ | ||
840 | pci_dev_put(pvt->branch_0); /* DEV 21 */ | ||
841 | |||
842 | /* Only if more than 2 channels do we release the second branch */ | ||
843 | if (pvt->maxch >= CHANNELS_PER_BRANCH) | ||
844 | pci_dev_put(pvt->branch_1); /* DEV 22 */ | ||
845 | } | ||
846 | |||
847 | /* | ||
848 | * determine_amb_resent | ||
849 | * | ||
850 | * the information is contained in NUM_MTRS different registers | ||
851 | * determineing which of the NUM_MTRS requires knowing | ||
852 | * which channel is in question | ||
853 | * | ||
854 | * 2 branches, each with 2 channels | ||
855 | * b0_ambpresent0 for channel '0' | ||
856 | * b0_ambpresent1 for channel '1' | ||
857 | * b1_ambpresent0 for channel '2' | ||
858 | * b1_ambpresent1 for channel '3' | ||
859 | */ | ||
860 | static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel) | ||
861 | { | ||
862 | int amb_present; | ||
863 | |||
864 | if (channel < CHANNELS_PER_BRANCH) { | ||
865 | if (channel & 0x1) | ||
866 | amb_present = pvt->b0_ambpresent1; | ||
867 | else | ||
868 | amb_present = pvt->b0_ambpresent0; | ||
869 | } else { | ||
870 | if (channel & 0x1) | ||
871 | amb_present = pvt->b1_ambpresent1; | ||
872 | else | ||
873 | amb_present = pvt->b1_ambpresent0; | ||
874 | } | ||
875 | |||
876 | return amb_present; | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * determine_mtr(pvt, csrow, channel) | ||
881 | * | ||
882 | * return the proper MTR register as determine by the csrow and channel desired | ||
883 | */ | ||
884 | static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel) | ||
885 | { | ||
886 | int mtr; | ||
887 | |||
888 | if (channel < CHANNELS_PER_BRANCH) | ||
889 | mtr = pvt->b0_mtr[csrow >> 1]; | ||
890 | else | ||
891 | mtr = pvt->b1_mtr[csrow >> 1]; | ||
892 | |||
893 | return mtr; | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | */ | ||
898 | static void decode_mtr(int slot_row, u16 mtr) | ||
899 | { | ||
900 | int ans; | ||
901 | |||
902 | ans = MTR_DIMMS_PRESENT(mtr); | ||
903 | |||
904 | debugf2("\tMTR%d=0x%x: DIMMs are %s\n", slot_row, mtr, | ||
905 | ans ? "Present" : "NOT Present"); | ||
906 | if (!ans) | ||
907 | return; | ||
908 | |||
909 | debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); | ||
910 | debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); | ||
911 | debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single"); | ||
912 | debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); | ||
913 | debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); | ||
914 | } | ||
915 | |||
916 | static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel, | ||
917 | struct i5000_dimm_info *dinfo) | ||
918 | { | ||
919 | int mtr; | ||
920 | int amb_present_reg; | ||
921 | int addrBits; | ||
922 | |||
923 | mtr = determine_mtr(pvt, csrow, channel); | ||
924 | if (MTR_DIMMS_PRESENT(mtr)) { | ||
925 | amb_present_reg = determine_amb_present_reg(pvt, channel); | ||
926 | |||
927 | /* Determine if there is a DIMM present in this DIMM slot */ | ||
928 | if (amb_present_reg & (1 << (csrow >> 1))) { | ||
929 | dinfo->dual_rank = MTR_DIMM_RANK(mtr); | ||
930 | |||
931 | if (!((dinfo->dual_rank == 0) && | ||
932 | ((csrow & 0x1) == 0x1))) { | ||
933 | /* Start with the number of bits for a Bank | ||
934 | * on the DRAM */ | ||
935 | addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); | ||
936 | /* Add thenumber of ROW bits */ | ||
937 | addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); | ||
938 | /* add the number of COLUMN bits */ | ||
939 | addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); | ||
940 | |||
941 | addrBits += 6; /* add 64 bits per DIMM */ | ||
942 | addrBits -= 20; /* divide by 2^^20 */ | ||
943 | addrBits -= 3; /* 8 bits per bytes */ | ||
944 | |||
945 | dinfo->megabytes = 1 << addrBits; | ||
946 | } | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * calculate_dimm_size | ||
953 | * | ||
954 | * also will output a DIMM matrix map, if debug is enabled, for viewing | ||
955 | * how the DIMMs are populated | ||
956 | */ | ||
957 | static void calculate_dimm_size(struct i5000_pvt *pvt) | ||
958 | { | ||
959 | struct i5000_dimm_info *dinfo; | ||
960 | int csrow, max_csrows; | ||
961 | char *p, *mem_buffer; | ||
962 | int space, n; | ||
963 | int channel; | ||
964 | |||
965 | /* ================= Generate some debug output ================= */ | ||
966 | space = PAGE_SIZE; | ||
967 | mem_buffer = p = kmalloc(space, GFP_KERNEL); | ||
968 | if (p == NULL) { | ||
969 | i5000_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n", | ||
970 | __FILE__, __func__); | ||
971 | return; | ||
972 | } | ||
973 | |||
974 | n = snprintf(p, space, "\n"); | ||
975 | p += n; | ||
976 | space -= n; | ||
977 | |||
978 | /* Scan all the actual CSROWS (which is # of DIMMS * 2) | ||
979 | * and calculate the information for each DIMM | ||
980 | * Start with the highest csrow first, to display it first | ||
981 | * and work toward the 0th csrow | ||
982 | */ | ||
983 | max_csrows = pvt->maxdimmperch * 2; | ||
984 | for (csrow = max_csrows - 1; csrow >= 0; csrow--) { | ||
985 | |||
986 | /* on an odd csrow, first output a 'boundary' marker, | ||
987 | * then reset the message buffer */ | ||
988 | if (csrow & 0x1) { | ||
989 | n = snprintf(p, space, "---------------------------" | ||
990 | "--------------------------------"); | ||
991 | p += n; | ||
992 | space -= n; | ||
993 | debugf2("%s\n", mem_buffer); | ||
994 | p = mem_buffer; | ||
995 | space = PAGE_SIZE; | ||
996 | } | ||
997 | n = snprintf(p, space, "csrow %2d ", csrow); | ||
998 | p += n; | ||
999 | space -= n; | ||
1000 | |||
1001 | for (channel = 0; channel < pvt->maxch; channel++) { | ||
1002 | dinfo = &pvt->dimm_info[csrow][channel]; | ||
1003 | handle_channel(pvt, csrow, channel, dinfo); | ||
1004 | n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); | ||
1005 | p += n; | ||
1006 | space -= n; | ||
1007 | } | ||
1008 | n = snprintf(p, space, "\n"); | ||
1009 | p += n; | ||
1010 | space -= n; | ||
1011 | } | ||
1012 | |||
1013 | /* Output the last bottom 'boundary' marker */ | ||
1014 | n = snprintf(p, space, "---------------------------" | ||
1015 | "--------------------------------\n"); | ||
1016 | p += n; | ||
1017 | space -= n; | ||
1018 | |||
1019 | /* now output the 'channel' labels */ | ||
1020 | n = snprintf(p, space, " "); | ||
1021 | p += n; | ||
1022 | space -= n; | ||
1023 | for (channel = 0; channel < pvt->maxch; channel++) { | ||
1024 | n = snprintf(p, space, "channel %d | ", channel); | ||
1025 | p += n; | ||
1026 | space -= n; | ||
1027 | } | ||
1028 | n = snprintf(p, space, "\n"); | ||
1029 | p += n; | ||
1030 | space -= n; | ||
1031 | |||
1032 | /* output the last message and free buffer */ | ||
1033 | debugf2("%s\n", mem_buffer); | ||
1034 | kfree(mem_buffer); | ||
1035 | } | ||
1036 | |||
1037 | /* | ||
1038 | * i5000_get_mc_regs read in the necessary registers and | ||
1039 | * cache locally | ||
1040 | * | ||
1041 | * Fills in the private data members | ||
1042 | */ | ||
1043 | static void i5000_get_mc_regs(struct mem_ctl_info *mci) | ||
1044 | { | ||
1045 | struct i5000_pvt *pvt; | ||
1046 | u32 actual_tolm; | ||
1047 | u16 limit; | ||
1048 | int slot_row; | ||
1049 | int maxch; | ||
1050 | int maxdimmperch; | ||
1051 | int way0, way1; | ||
1052 | |||
1053 | pvt = mci->pvt_info; | ||
1054 | |||
1055 | pci_read_config_dword(pvt->system_address, AMBASE, | ||
1056 | (u32 *) & pvt->ambase); | ||
1057 | pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32), | ||
1058 | ((u32 *) & pvt->ambase) + sizeof(u32)); | ||
1059 | |||
1060 | maxdimmperch = pvt->maxdimmperch; | ||
1061 | maxch = pvt->maxch; | ||
1062 | |||
1063 | debugf2("AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n", | ||
1064 | (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch); | ||
1065 | |||
1066 | /* Get the Branch Map regs */ | ||
1067 | pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm); | ||
1068 | pvt->tolm >>= 12; | ||
1069 | debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, | ||
1070 | pvt->tolm); | ||
1071 | |||
1072 | actual_tolm = pvt->tolm << 28; | ||
1073 | debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm); | ||
1074 | |||
1075 | pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0); | ||
1076 | pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1); | ||
1077 | pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir2); | ||
1078 | |||
1079 | /* Get the MIR[0-2] regs */ | ||
1080 | limit = (pvt->mir0 >> 4) & 0x0FFF; | ||
1081 | way0 = pvt->mir0 & 0x1; | ||
1082 | way1 = pvt->mir0 & 0x2; | ||
1083 | debugf2("MIR0: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); | ||
1084 | limit = (pvt->mir1 >> 4) & 0x0FFF; | ||
1085 | way0 = pvt->mir1 & 0x1; | ||
1086 | way1 = pvt->mir1 & 0x2; | ||
1087 | debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); | ||
1088 | limit = (pvt->mir2 >> 4) & 0x0FFF; | ||
1089 | way0 = pvt->mir2 & 0x1; | ||
1090 | way1 = pvt->mir2 & 0x2; | ||
1091 | debugf2("MIR2: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); | ||
1092 | |||
1093 | /* Get the MTR[0-3] regs */ | ||
1094 | for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) { | ||
1095 | int where = MTR0 + (slot_row * sizeof(u32)); | ||
1096 | |||
1097 | pci_read_config_word(pvt->branch_0, where, | ||
1098 | &pvt->b0_mtr[slot_row]); | ||
1099 | |||
1100 | debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where, | ||
1101 | pvt->b0_mtr[slot_row]); | ||
1102 | |||
1103 | if (pvt->maxch >= CHANNELS_PER_BRANCH) { | ||
1104 | pci_read_config_word(pvt->branch_1, where, | ||
1105 | &pvt->b1_mtr[slot_row]); | ||
1106 | debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row, | ||
1107 | where, pvt->b0_mtr[slot_row]); | ||
1108 | } else { | ||
1109 | pvt->b1_mtr[slot_row] = 0; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | /* Read and dump branch 0's MTRs */ | ||
1114 | debugf2("\nMemory Technology Registers:\n"); | ||
1115 | debugf2(" Branch 0:\n"); | ||
1116 | for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) { | ||
1117 | decode_mtr(slot_row, pvt->b0_mtr[slot_row]); | ||
1118 | } | ||
1119 | pci_read_config_word(pvt->branch_0, AMB_PRESENT_0, | ||
1120 | &pvt->b0_ambpresent0); | ||
1121 | debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0); | ||
1122 | pci_read_config_word(pvt->branch_0, AMB_PRESENT_1, | ||
1123 | &pvt->b0_ambpresent1); | ||
1124 | debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1); | ||
1125 | |||
1126 | /* Only if we have 2 branchs (4 channels) */ | ||
1127 | if (pvt->maxch < CHANNELS_PER_BRANCH) { | ||
1128 | pvt->b1_ambpresent0 = 0; | ||
1129 | pvt->b1_ambpresent1 = 0; | ||
1130 | } else { | ||
1131 | /* Read and dump branch 1's MTRs */ | ||
1132 | debugf2(" Branch 1:\n"); | ||
1133 | for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) { | ||
1134 | decode_mtr(slot_row, pvt->b1_mtr[slot_row]); | ||
1135 | } | ||
1136 | pci_read_config_word(pvt->branch_1, AMB_PRESENT_0, | ||
1137 | &pvt->b1_ambpresent0); | ||
1138 | debugf2("\t\tAMB-Branch 1-present0 0x%x:\n", | ||
1139 | pvt->b1_ambpresent0); | ||
1140 | pci_read_config_word(pvt->branch_1, AMB_PRESENT_1, | ||
1141 | &pvt->b1_ambpresent1); | ||
1142 | debugf2("\t\tAMB-Branch 1-present1 0x%x:\n", | ||
1143 | pvt->b1_ambpresent1); | ||
1144 | } | ||
1145 | |||
1146 | /* Go and determine the size of each DIMM and place in an | ||
1147 | * orderly matrix */ | ||
1148 | calculate_dimm_size(pvt); | ||
1149 | } | ||
1150 | |||
1151 | /* | ||
1152 | * i5000_init_csrows Initialize the 'csrows' table within | ||
1153 | * the mci control structure with the | ||
1154 | * addressing of memory. | ||
1155 | * | ||
1156 | * return: | ||
1157 | * 0 success | ||
1158 | * 1 no actual memory found on this MC | ||
1159 | */ | ||
1160 | static int i5000_init_csrows(struct mem_ctl_info *mci) | ||
1161 | { | ||
1162 | struct i5000_pvt *pvt; | ||
1163 | struct csrow_info *p_csrow; | ||
1164 | int empty, channel_count; | ||
1165 | int max_csrows; | ||
1166 | int mtr; | ||
1167 | int csrow_megs; | ||
1168 | int channel; | ||
1169 | int csrow; | ||
1170 | |||
1171 | pvt = mci->pvt_info; | ||
1172 | |||
1173 | channel_count = pvt->maxch; | ||
1174 | max_csrows = pvt->maxdimmperch * 2; | ||
1175 | |||
1176 | empty = 1; /* Assume NO memory */ | ||
1177 | |||
1178 | for (csrow = 0; csrow < max_csrows; csrow++) { | ||
1179 | p_csrow = &mci->csrows[csrow]; | ||
1180 | |||
1181 | p_csrow->csrow_idx = csrow; | ||
1182 | |||
1183 | /* use branch 0 for the basis */ | ||
1184 | mtr = pvt->b0_mtr[csrow >> 1]; | ||
1185 | |||
1186 | /* if no DIMMS on this row, continue */ | ||
1187 | if (!MTR_DIMMS_PRESENT(mtr)) | ||
1188 | continue; | ||
1189 | |||
1190 | /* FAKE OUT VALUES, FIXME */ | ||
1191 | p_csrow->first_page = 0 + csrow * 20; | ||
1192 | p_csrow->last_page = 9 + csrow * 20; | ||
1193 | p_csrow->page_mask = 0xFFF; | ||
1194 | |||
1195 | p_csrow->grain = 8; | ||
1196 | |||
1197 | csrow_megs = 0; | ||
1198 | for (channel = 0; channel < pvt->maxch; channel++) { | ||
1199 | csrow_megs += pvt->dimm_info[csrow][channel].megabytes; | ||
1200 | } | ||
1201 | |||
1202 | p_csrow->nr_pages = csrow_megs << 8; | ||
1203 | |||
1204 | /* Assume DDR2 for now */ | ||
1205 | p_csrow->mtype = MEM_FB_DDR2; | ||
1206 | |||
1207 | /* ask what device type on this row */ | ||
1208 | if (MTR_DRAM_WIDTH(mtr)) | ||
1209 | p_csrow->dtype = DEV_X8; | ||
1210 | else | ||
1211 | p_csrow->dtype = DEV_X4; | ||
1212 | |||
1213 | p_csrow->edac_mode = EDAC_S8ECD8ED; | ||
1214 | |||
1215 | empty = 0; | ||
1216 | } | ||
1217 | |||
1218 | return empty; | ||
1219 | } | ||
1220 | |||
1221 | /* | ||
1222 | * i5000_enable_error_reporting | ||
1223 | * Turn on the memory reporting features of the hardware | ||
1224 | */ | ||
1225 | static void i5000_enable_error_reporting(struct mem_ctl_info *mci) | ||
1226 | { | ||
1227 | struct i5000_pvt *pvt; | ||
1228 | u32 fbd_error_mask; | ||
1229 | |||
1230 | pvt = mci->pvt_info; | ||
1231 | |||
1232 | /* Read the FBD Error Mask Register */ | ||
1233 | pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD, | ||
1234 | &fbd_error_mask); | ||
1235 | |||
1236 | /* Enable with a '0' */ | ||
1237 | fbd_error_mask &= ~(ENABLE_EMASK_ALL); | ||
1238 | |||
1239 | pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD, | ||
1240 | fbd_error_mask); | ||
1241 | } | ||
1242 | |||
1243 | /* | ||
1244 | * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels) | ||
1245 | * | ||
1246 | * ask the device how many channels are present and how many CSROWS | ||
1247 | * as well | ||
1248 | */ | ||
1249 | static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev, | ||
1250 | int *num_dimms_per_channel, | ||
1251 | int *num_channels) | ||
1252 | { | ||
1253 | u8 value; | ||
1254 | |||
1255 | /* Need to retrieve just how many channels and dimms per channel are | ||
1256 | * supported on this memory controller | ||
1257 | */ | ||
1258 | pci_read_config_byte(pdev, MAXDIMMPERCH, &value); | ||
1259 | *num_dimms_per_channel = (int)value *2; | ||
1260 | |||
1261 | pci_read_config_byte(pdev, MAXCH, &value); | ||
1262 | *num_channels = (int)value; | ||
1263 | } | ||
1264 | |||
1265 | /* | ||
1266 | * i5000_probe1 Probe for ONE instance of device to see if it is | ||
1267 | * present. | ||
1268 | * return: | ||
1269 | * 0 for FOUND a device | ||
1270 | * < 0 for error code | ||
1271 | */ | ||
1272 | static int i5000_probe1(struct pci_dev *pdev, int dev_idx) | ||
1273 | { | ||
1274 | struct mem_ctl_info *mci; | ||
1275 | struct i5000_pvt *pvt; | ||
1276 | int num_channels; | ||
1277 | int num_dimms_per_channel; | ||
1278 | int num_csrows; | ||
1279 | |||
1280 | debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", | ||
1281 | __func__, | ||
1282 | pdev->bus->number, | ||
1283 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | ||
1284 | |||
1285 | /* We only are looking for func 0 of the set */ | ||
1286 | if (PCI_FUNC(pdev->devfn) != 0) | ||
1287 | return -ENODEV; | ||
1288 | |||
1289 | /* make sure error reporting method is sane */ | ||
1290 | switch (edac_op_state) { | ||
1291 | case EDAC_OPSTATE_POLL: | ||
1292 | case EDAC_OPSTATE_NMI: | ||
1293 | break; | ||
1294 | default: | ||
1295 | edac_op_state = EDAC_OPSTATE_POLL; | ||
1296 | break; | ||
1297 | } | ||
1298 | |||
1299 | /* Ask the devices for the number of CSROWS and CHANNELS so | ||
1300 | * that we can calculate the memory resources, etc | ||
1301 | * | ||
1302 | * The Chipset will report what it can handle which will be greater | ||
1303 | * or equal to what the motherboard manufacturer will implement. | ||
1304 | * | ||
1305 | * As we don't have a motherboard identification routine to determine | ||
1306 | * actual number of slots/dimms per channel, we thus utilize the | ||
1307 | * resource as specified by the chipset. Thus, we might have | ||
1308 | * have more DIMMs per channel than actually on the mobo, but this | ||
1309 | * allows the driver to support upto the chipset max, without | ||
1310 | * some fancy mobo determination. | ||
1311 | */ | ||
1312 | i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel, | ||
1313 | &num_channels); | ||
1314 | num_csrows = num_dimms_per_channel * 2; | ||
1315 | |||
1316 | debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", | ||
1317 | __func__, num_channels, num_dimms_per_channel, num_csrows); | ||
1318 | |||
1319 | /* allocate a new MC control structure */ | ||
1320 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); | ||
1321 | |||
1322 | if (mci == NULL) | ||
1323 | return -ENOMEM; | ||
1324 | |||
1325 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | ||
1326 | |||
1327 | mci->dev = &pdev->dev; /* record ptr to the generic device */ | ||
1328 | |||
1329 | pvt = mci->pvt_info; | ||
1330 | pvt->system_address = pdev; /* Record this device in our private */ | ||
1331 | pvt->maxch = num_channels; | ||
1332 | pvt->maxdimmperch = num_dimms_per_channel; | ||
1333 | |||
1334 | /* 'get' the pci devices we want to reserve for our use */ | ||
1335 | if (i5000_get_devices(mci, dev_idx)) | ||
1336 | goto fail0; | ||
1337 | |||
1338 | /* Time to get serious */ | ||
1339 | i5000_get_mc_regs(mci); /* retrieve the hardware registers */ | ||
1340 | |||
1341 | mci->mc_idx = 0; | ||
1342 | mci->mtype_cap = MEM_FLAG_FB_DDR2; | ||
1343 | mci->edac_ctl_cap = EDAC_FLAG_NONE; | ||
1344 | mci->edac_cap = EDAC_FLAG_NONE; | ||
1345 | mci->mod_name = "i5000_edac.c"; | ||
1346 | mci->mod_ver = I5000_REVISION; | ||
1347 | mci->ctl_name = i5000_devs[dev_idx].ctl_name; | ||
1348 | mci->dev_name = pci_name(pdev); | ||
1349 | mci->ctl_page_to_phys = NULL; | ||
1350 | |||
1351 | /* Set the function pointer to an actual operation function */ | ||
1352 | mci->edac_check = i5000_check_error; | ||
1353 | |||
1354 | /* initialize the MC control structure 'csrows' table | ||
1355 | * with the mapping and control information */ | ||
1356 | if (i5000_init_csrows(mci)) { | ||
1357 | debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" | ||
1358 | " because i5000_init_csrows() returned nonzero " | ||
1359 | "value\n"); | ||
1360 | mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ | ||
1361 | } else { | ||
1362 | debugf1("MC: Enable error reporting now\n"); | ||
1363 | i5000_enable_error_reporting(mci); | ||
1364 | } | ||
1365 | |||
1366 | /* add this new MC control structure to EDAC's list of MCs */ | ||
1367 | if (edac_mc_add_mc(mci)) { | ||
1368 | debugf0("MC: " __FILE__ | ||
1369 | ": %s(): failed edac_mc_add_mc()\n", __func__); | ||
1370 | /* FIXME: perhaps some code should go here that disables error | ||
1371 | * reporting if we just enabled it | ||
1372 | */ | ||
1373 | goto fail1; | ||
1374 | } | ||
1375 | |||
1376 | i5000_clear_error(mci); | ||
1377 | |||
1378 | /* allocating generic PCI control info */ | ||
1379 | i5000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
1380 | if (!i5000_pci) { | ||
1381 | printk(KERN_WARNING | ||
1382 | "%s(): Unable to create PCI control\n", | ||
1383 | __func__); | ||
1384 | printk(KERN_WARNING | ||
1385 | "%s(): PCI error report via EDAC not setup\n", | ||
1386 | __func__); | ||
1387 | } | ||
1388 | |||
1389 | return 0; | ||
1390 | |||
1391 | /* Error exit unwinding stack */ | ||
1392 | fail1: | ||
1393 | |||
1394 | i5000_put_devices(mci); | ||
1395 | |||
1396 | fail0: | ||
1397 | edac_mc_free(mci); | ||
1398 | return -ENODEV; | ||
1399 | } | ||
1400 | |||
1401 | /* | ||
1402 | * i5000_init_one constructor for one instance of device | ||
1403 | * | ||
1404 | * returns: | ||
1405 | * negative on error | ||
1406 | * count (>= 0) | ||
1407 | */ | ||
1408 | static int __devinit i5000_init_one(struct pci_dev *pdev, | ||
1409 | const struct pci_device_id *id) | ||
1410 | { | ||
1411 | int rc; | ||
1412 | |||
1413 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
1414 | |||
1415 | /* wake up device */ | ||
1416 | rc = pci_enable_device(pdev); | ||
1417 | if (rc == -EIO) | ||
1418 | return rc; | ||
1419 | |||
1420 | /* now probe and enable the device */ | ||
1421 | return i5000_probe1(pdev, id->driver_data); | ||
1422 | } | ||
1423 | |||
1424 | /* | ||
1425 | * i5000_remove_one destructor for one instance of device | ||
1426 | * | ||
1427 | */ | ||
1428 | static void __devexit i5000_remove_one(struct pci_dev *pdev) | ||
1429 | { | ||
1430 | struct mem_ctl_info *mci; | ||
1431 | |||
1432 | debugf0(__FILE__ ": %s()\n", __func__); | ||
1433 | |||
1434 | if (i5000_pci) | ||
1435 | edac_pci_release_generic_ctl(i5000_pci); | ||
1436 | |||
1437 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | ||
1438 | return; | ||
1439 | |||
1440 | /* retrieve references to resources, and free those resources */ | ||
1441 | i5000_put_devices(mci); | ||
1442 | |||
1443 | edac_mc_free(mci); | ||
1444 | } | ||
1445 | |||
1446 | /* | ||
1447 | * pci_device_id table for which devices we are looking for | ||
1448 | * | ||
1449 | * The "E500P" device is the first device supported. | ||
1450 | */ | ||
1451 | static const struct pci_device_id i5000_pci_tbl[] __devinitdata = { | ||
1452 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16), | ||
1453 | .driver_data = I5000P}, | ||
1454 | |||
1455 | {0,} /* 0 terminated list. */ | ||
1456 | }; | ||
1457 | |||
1458 | MODULE_DEVICE_TABLE(pci, i5000_pci_tbl); | ||
1459 | |||
1460 | /* | ||
1461 | * i5000_driver pci_driver structure for this module | ||
1462 | * | ||
1463 | */ | ||
1464 | static struct pci_driver i5000_driver = { | ||
1465 | .name = __stringify(KBUILD_BASENAME), | ||
1466 | .probe = i5000_init_one, | ||
1467 | .remove = __devexit_p(i5000_remove_one), | ||
1468 | .id_table = i5000_pci_tbl, | ||
1469 | }; | ||
1470 | |||
1471 | /* | ||
1472 | * i5000_init Module entry function | ||
1473 | * Try to initialize this module for its devices | ||
1474 | */ | ||
1475 | static int __init i5000_init(void) | ||
1476 | { | ||
1477 | int pci_rc; | ||
1478 | |||
1479 | debugf2("MC: " __FILE__ ": %s()\n", __func__); | ||
1480 | |||
1481 | pci_rc = pci_register_driver(&i5000_driver); | ||
1482 | |||
1483 | return (pci_rc < 0) ? pci_rc : 0; | ||
1484 | } | ||
1485 | |||
1486 | /* | ||
1487 | * i5000_exit() Module exit function | ||
1488 | * Unregister the driver | ||
1489 | */ | ||
1490 | static void __exit i5000_exit(void) | ||
1491 | { | ||
1492 | debugf2("MC: " __FILE__ ": %s()\n", __func__); | ||
1493 | pci_unregister_driver(&i5000_driver); | ||
1494 | } | ||
1495 | |||
1496 | module_init(i5000_init); | ||
1497 | module_exit(i5000_exit); | ||
1498 | |||
1499 | MODULE_LICENSE("GPL"); | ||
1500 | MODULE_AUTHOR | ||
1501 | ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); | ||
1502 | MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " | ||
1503 | I5000_REVISION); | ||
1504 | module_param(edac_op_state, int, 0444); | ||
1505 | MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); | ||
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c new file mode 100644 index 000000000000..83bfe37c4bbb --- /dev/null +++ b/drivers/edac/i82443bxgx_edac.c | |||
@@ -0,0 +1,402 @@ | |||
1 | /* | ||
2 | * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel | ||
3 | * module (C) 2006 Tim Small | ||
4 | * | ||
5 | * This file may be distributed under the terms of the GNU General | ||
6 | * Public License. | ||
7 | * | ||
8 | * Written by Tim Small <tim@buttersideup.com>, based on work by Linux | ||
9 | * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and | ||
10 | * others. | ||
11 | * | ||
12 | * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>. | ||
13 | * | ||
14 | * Written with reference to 82443BX Host Bridge Datasheet: | ||
15 | * http://www.intel.com/design/chipsets/440/documentation.htm | ||
16 | * references to this document given in []. | ||
17 | * | ||
18 | * This module doesn't support the 440LX, but it may be possible to | ||
19 | * make it do so (the 440LX's register definitions are different, but | ||
20 | * not completely so - I haven't studied them in enough detail to know | ||
21 | * how easy this would be). | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | #include <linux/pci_ids.h> | ||
29 | |||
30 | #include <linux/slab.h> | ||
31 | |||
32 | #include "edac_core.h" | ||
33 | |||
34 | #define I82443_REVISION "0.1" | ||
35 | |||
36 | #define EDAC_MOD_STR "i82443bxgx_edac" | ||
37 | |||
38 | /* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory | ||
39 | * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory | ||
40 | * rows" "The 82443BX supports multiple-bit error detection and | ||
41 | * single-bit error correction when ECC mode is enabled and | ||
42 | * single/multi-bit error detection when correction is disabled. | ||
43 | * During writes to the DRAM, the 82443BX generates ECC for the data | ||
44 | * on a QWord basis. Partial QWord writes require a read-modify-write | ||
45 | * cycle when ECC is enabled." | ||
46 | */ | ||
47 | |||
48 | /* "Additionally, the 82443BX ensures that the data is corrected in | ||
49 | * main memory so that accumulation of errors is prevented. Another | ||
50 | * error within the same QWord would result in a double-bit error | ||
51 | * which is unrecoverable. This is known as hardware scrubbing since | ||
52 | * it requires no software intervention to correct the data in memory." | ||
53 | */ | ||
54 | |||
55 | /* [Also see page 100 (section 4.3), "DRAM Interface"] | ||
56 | * [Also see page 112 (section 4.6.1.4), ECC] | ||
57 | */ | ||
58 | |||
59 | #define I82443BXGX_NR_CSROWS 8 | ||
60 | #define I82443BXGX_NR_CHANS 1 | ||
61 | #define I82443BXGX_NR_DIMMS 4 | ||
62 | |||
63 | /* 82443 PCI Device 0 */ | ||
64 | #define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI | ||
65 | * config space offset */ | ||
66 | #define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if | ||
67 | * row is non-ECC */ | ||
68 | #define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */ | ||
69 | |||
70 | #define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */ | ||
71 | #define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */ | ||
72 | #define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */ | ||
73 | #define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */ | ||
74 | #define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */ | ||
75 | |||
76 | #define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6 | ||
77 | |||
78 | /* 82443 PCI Device 0 */ | ||
79 | #define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI | ||
80 | * config space offset, Error Address | ||
81 | * Pointer Register */ | ||
82 | #define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */ | ||
83 | #define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */ | ||
84 | #define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */ | ||
85 | |||
86 | #define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI | ||
87 | * config space offset. */ | ||
88 | #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */ | ||
89 | #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */ | ||
90 | |||
91 | #define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI | ||
92 | * config space offset. */ | ||
93 | #define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */ | ||
94 | #define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */ | ||
95 | #define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */ | ||
96 | #define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */ | ||
97 | |||
98 | #define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI | ||
99 | * config space offset. */ | ||
100 | #define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */ | ||
101 | #define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */ | ||
102 | #define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */ | ||
103 | #define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */ | ||
104 | |||
105 | #define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI | ||
106 | * config space offset. */ | ||
107 | |||
108 | /* FIXME - don't poll when ECC disabled? */ | ||
109 | |||
110 | struct i82443bxgx_edacmc_error_info { | ||
111 | u32 eap; | ||
112 | }; | ||
113 | |||
114 | static struct edac_pci_ctl_info *i82443bxgx_pci; | ||
115 | |||
116 | static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci, | ||
117 | struct i82443bxgx_edacmc_error_info | ||
118 | *info) | ||
119 | { | ||
120 | struct pci_dev *pdev; | ||
121 | pdev = to_pci_dev(mci->dev); | ||
122 | pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap); | ||
123 | if (info->eap & I82443BXGX_EAP_OFFSET_SBE) | ||
124 | /* Clear error to allow next error to be reported [p.61] */ | ||
125 | pci_write_bits32(pdev, I82443BXGX_EAP, | ||
126 | I82443BXGX_EAP_OFFSET_SBE, | ||
127 | I82443BXGX_EAP_OFFSET_SBE); | ||
128 | |||
129 | if (info->eap & I82443BXGX_EAP_OFFSET_MBE) | ||
130 | /* Clear error to allow next error to be reported [p.61] */ | ||
131 | pci_write_bits32(pdev, I82443BXGX_EAP, | ||
132 | I82443BXGX_EAP_OFFSET_MBE, | ||
133 | I82443BXGX_EAP_OFFSET_MBE); | ||
134 | } | ||
135 | |||
136 | static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci, | ||
137 | struct | ||
138 | i82443bxgx_edacmc_error_info | ||
139 | *info, int handle_errors) | ||
140 | { | ||
141 | int error_found = 0; | ||
142 | u32 eapaddr, page, pageoffset; | ||
143 | |||
144 | /* bits 30:12 hold the 4kb block in which the error occurred | ||
145 | * [p.61] */ | ||
146 | eapaddr = (info->eap & 0xfffff000); | ||
147 | page = eapaddr >> PAGE_SHIFT; | ||
148 | pageoffset = eapaddr - (page << PAGE_SHIFT); | ||
149 | |||
150 | if (info->eap & I82443BXGX_EAP_OFFSET_SBE) { | ||
151 | error_found = 1; | ||
152 | if (handle_errors) | ||
153 | edac_mc_handle_ce(mci, page, pageoffset, | ||
154 | /* 440BX/GX don't make syndrome information | ||
155 | * available */ | ||
156 | 0, edac_mc_find_csrow_by_page(mci, page), 0, | ||
157 | mci->ctl_name); | ||
158 | } | ||
159 | |||
160 | if (info->eap & I82443BXGX_EAP_OFFSET_MBE) { | ||
161 | error_found = 1; | ||
162 | if (handle_errors) | ||
163 | edac_mc_handle_ue(mci, page, pageoffset, | ||
164 | edac_mc_find_csrow_by_page(mci, page), | ||
165 | mci->ctl_name); | ||
166 | } | ||
167 | |||
168 | return error_found; | ||
169 | } | ||
170 | |||
171 | static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci) | ||
172 | { | ||
173 | struct i82443bxgx_edacmc_error_info info; | ||
174 | |||
175 | debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | ||
176 | i82443bxgx_edacmc_get_error_info(mci, &info); | ||
177 | i82443bxgx_edacmc_process_error_info(mci, &info, 1); | ||
178 | } | ||
179 | |||
180 | static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, | ||
181 | struct pci_dev *pdev, | ||
182 | enum edac_type edac_mode, | ||
183 | enum mem_type mtype) | ||
184 | { | ||
185 | struct csrow_info *csrow; | ||
186 | int index; | ||
187 | u8 drbar, dramc; | ||
188 | u32 row_base, row_high_limit, row_high_limit_last; | ||
189 | |||
190 | pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); | ||
191 | row_high_limit_last = 0; | ||
192 | for (index = 0; index < mci->nr_csrows; index++) { | ||
193 | csrow = &mci->csrows[index]; | ||
194 | pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar); | ||
195 | debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n", | ||
196 | mci->mc_idx, __func__, index, drbar); | ||
197 | row_high_limit = ((u32) drbar << 23); | ||
198 | /* find the DRAM Chip Select Base address and mask */ | ||
199 | debugf1("MC%d: " __FILE__ ": %s() Row=%d, " | ||
200 | "Boundry Address=%#0x, Last = %#0x \n", | ||
201 | mci->mc_idx, __func__, index, row_high_limit, | ||
202 | row_high_limit_last); | ||
203 | |||
204 | /* 440GX goes to 2GB, represented with a DRB of 0. */ | ||
205 | if (row_high_limit_last && !row_high_limit) | ||
206 | row_high_limit = 1UL << 31; | ||
207 | |||
208 | /* This row is empty [p.49] */ | ||
209 | if (row_high_limit == row_high_limit_last) | ||
210 | continue; | ||
211 | row_base = row_high_limit_last; | ||
212 | csrow->first_page = row_base >> PAGE_SHIFT; | ||
213 | csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; | ||
214 | csrow->nr_pages = csrow->last_page - csrow->first_page + 1; | ||
215 | /* EAP reports in 4kilobyte granularity [61] */ | ||
216 | csrow->grain = 1 << 12; | ||
217 | csrow->mtype = mtype; | ||
218 | /* I don't think 440BX can tell you device type? FIXME? */ | ||
219 | csrow->dtype = DEV_UNKNOWN; | ||
220 | /* Mode is global to all rows on 440BX */ | ||
221 | csrow->edac_mode = edac_mode; | ||
222 | row_high_limit_last = row_high_limit; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) | ||
227 | { | ||
228 | struct mem_ctl_info *mci; | ||
229 | u8 dramc; | ||
230 | u32 nbxcfg, ecc_mode; | ||
231 | enum mem_type mtype; | ||
232 | enum edac_type edac_mode; | ||
233 | |||
234 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
235 | |||
236 | /* Something is really hosed if PCI config space reads from | ||
237 | * the MC aren't working. | ||
238 | */ | ||
239 | if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg)) | ||
240 | return -EIO; | ||
241 | |||
242 | mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0); | ||
243 | |||
244 | if (mci == NULL) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | ||
248 | mci->dev = &pdev->dev; | ||
249 | mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR; | ||
250 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | ||
251 | pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); | ||
252 | switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) { | ||
253 | case I82443BXGX_DRAMC_DRAM_IS_EDO: | ||
254 | mtype = MEM_EDO; | ||
255 | break; | ||
256 | case I82443BXGX_DRAMC_DRAM_IS_SDRAM: | ||
257 | mtype = MEM_SDR; | ||
258 | break; | ||
259 | case I82443BXGX_DRAMC_DRAM_IS_RSDRAM: | ||
260 | mtype = MEM_RDR; | ||
261 | break; | ||
262 | default: | ||
263 | debugf0("Unknown/reserved DRAM type value " | ||
264 | "in DRAMC register!\n"); | ||
265 | mtype = -MEM_UNKNOWN; | ||
266 | } | ||
267 | |||
268 | if ((mtype == MEM_SDR) || (mtype == MEM_RDR)) | ||
269 | mci->edac_cap = mci->edac_ctl_cap; | ||
270 | else | ||
271 | mci->edac_cap = EDAC_FLAG_NONE; | ||
272 | |||
273 | mci->scrub_cap = SCRUB_FLAG_HW_SRC; | ||
274 | pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg); | ||
275 | ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) & | ||
276 | (BIT(0) | BIT(1))); | ||
277 | |||
278 | mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB) | ||
279 | ? SCRUB_HW_SRC : SCRUB_NONE; | ||
280 | |||
281 | switch (ecc_mode) { | ||
282 | case I82443BXGX_NBXCFG_INTEGRITY_NONE: | ||
283 | edac_mode = EDAC_NONE; | ||
284 | break; | ||
285 | case I82443BXGX_NBXCFG_INTEGRITY_EC: | ||
286 | edac_mode = EDAC_EC; | ||
287 | break; | ||
288 | case I82443BXGX_NBXCFG_INTEGRITY_ECC: | ||
289 | case I82443BXGX_NBXCFG_INTEGRITY_SCRUB: | ||
290 | edac_mode = EDAC_SECDED; | ||
291 | break; | ||
292 | default: | ||
293 | debugf0("%s(): Unknown/reserved ECC state " | ||
294 | "in NBXCFG register!\n", __func__); | ||
295 | edac_mode = EDAC_UNKNOWN; | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype); | ||
300 | |||
301 | /* Many BIOSes don't clear error flags on boot, so do this | ||
302 | * here, or we get "phantom" errors occuring at module-load | ||
303 | * time. */ | ||
304 | pci_write_bits32(pdev, I82443BXGX_EAP, | ||
305 | (I82443BXGX_EAP_OFFSET_SBE | | ||
306 | I82443BXGX_EAP_OFFSET_MBE), | ||
307 | (I82443BXGX_EAP_OFFSET_SBE | | ||
308 | I82443BXGX_EAP_OFFSET_MBE)); | ||
309 | |||
310 | mci->mod_name = EDAC_MOD_STR; | ||
311 | mci->mod_ver = I82443_REVISION; | ||
312 | mci->ctl_name = "I82443BXGX"; | ||
313 | mci->dev_name = pci_name(pdev); | ||
314 | mci->edac_check = i82443bxgx_edacmc_check; | ||
315 | mci->ctl_page_to_phys = NULL; | ||
316 | |||
317 | if (edac_mc_add_mc(mci)) { | ||
318 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | ||
319 | goto fail; | ||
320 | } | ||
321 | |||
322 | /* allocating generic PCI control info */ | ||
323 | i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
324 | if (!i82443bxgx_pci) { | ||
325 | printk(KERN_WARNING | ||
326 | "%s(): Unable to create PCI control\n", | ||
327 | __func__); | ||
328 | printk(KERN_WARNING | ||
329 | "%s(): PCI error report via EDAC not setup\n", | ||
330 | __func__); | ||
331 | } | ||
332 | |||
333 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | ||
334 | return 0; | ||
335 | |||
336 | fail: | ||
337 | edac_mc_free(mci); | ||
338 | return -ENODEV; | ||
339 | } | ||
340 | |||
341 | EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1); | ||
342 | |||
343 | /* returns count (>= 0), or negative on error */ | ||
344 | static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev, | ||
345 | const struct pci_device_id *ent) | ||
346 | { | ||
347 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
348 | |||
349 | /* don't need to call pci_device_enable() */ | ||
350 | return i82443bxgx_edacmc_probe1(pdev, ent->driver_data); | ||
351 | } | ||
352 | |||
353 | static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev) | ||
354 | { | ||
355 | struct mem_ctl_info *mci; | ||
356 | |||
357 | debugf0(__FILE__ ": %s()\n", __func__); | ||
358 | |||
359 | if (i82443bxgx_pci) | ||
360 | edac_pci_release_generic_ctl(i82443bxgx_pci); | ||
361 | |||
362 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | ||
363 | return; | ||
364 | |||
365 | edac_mc_free(mci); | ||
366 | } | ||
367 | |||
368 | EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one); | ||
369 | |||
370 | static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = { | ||
371 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)}, | ||
372 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)}, | ||
373 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)}, | ||
374 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)}, | ||
375 | {0,} /* 0 terminated list. */ | ||
376 | }; | ||
377 | |||
378 | MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl); | ||
379 | |||
380 | static struct pci_driver i82443bxgx_edacmc_driver = { | ||
381 | .name = EDAC_MOD_STR, | ||
382 | .probe = i82443bxgx_edacmc_init_one, | ||
383 | .remove = __devexit_p(i82443bxgx_edacmc_remove_one), | ||
384 | .id_table = i82443bxgx_pci_tbl, | ||
385 | }; | ||
386 | |||
387 | static int __init i82443bxgx_edacmc_init(void) | ||
388 | { | ||
389 | return pci_register_driver(&i82443bxgx_edacmc_driver); | ||
390 | } | ||
391 | |||
392 | static void __exit i82443bxgx_edacmc_exit(void) | ||
393 | { | ||
394 | pci_unregister_driver(&i82443bxgx_edacmc_driver); | ||
395 | } | ||
396 | |||
397 | module_init(i82443bxgx_edacmc_init); | ||
398 | module_exit(i82443bxgx_edacmc_exit); | ||
399 | |||
400 | MODULE_LICENSE("GPL"); | ||
401 | MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD"); | ||
402 | MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); | ||
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index e4bb298e613f..f5ecd2c4d813 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c | |||
@@ -14,9 +14,9 @@ | |||
14 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
15 | #include <linux/pci_ids.h> | 15 | #include <linux/pci_ids.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include "edac_mc.h" | 17 | #include "edac_core.h" |
18 | 18 | ||
19 | #define I82860_REVISION " Ver: 2.0.1 " __DATE__ | 19 | #define I82860_REVISION " Ver: 2.0.2 " __DATE__ |
20 | #define EDAC_MOD_STR "i82860_edac" | 20 | #define EDAC_MOD_STR "i82860_edac" |
21 | 21 | ||
22 | #define i82860_printk(level, fmt, arg...) \ | 22 | #define i82860_printk(level, fmt, arg...) \ |
@@ -54,16 +54,16 @@ struct i82860_error_info { | |||
54 | 54 | ||
55 | static const struct i82860_dev_info i82860_devs[] = { | 55 | static const struct i82860_dev_info i82860_devs[] = { |
56 | [I82860] = { | 56 | [I82860] = { |
57 | .ctl_name = "i82860" | 57 | .ctl_name = "i82860"}, |
58 | }, | ||
59 | }; | 58 | }; |
60 | 59 | ||
61 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code | 60 | static struct pci_dev *mci_pdev; /* init dev: in case that AGP code |
62 | * has already registered driver | 61 | * has already registered driver |
63 | */ | 62 | */ |
63 | static struct edac_pci_ctl_info *i82860_pci; | ||
64 | 64 | ||
65 | static void i82860_get_error_info(struct mem_ctl_info *mci, | 65 | static void i82860_get_error_info(struct mem_ctl_info *mci, |
66 | struct i82860_error_info *info) | 66 | struct i82860_error_info *info) |
67 | { | 67 | { |
68 | struct pci_dev *pdev; | 68 | struct pci_dev *pdev; |
69 | 69 | ||
@@ -91,13 +91,13 @@ static void i82860_get_error_info(struct mem_ctl_info *mci, | |||
91 | 91 | ||
92 | if ((info->errsts ^ info->errsts2) & 0x0003) { | 92 | if ((info->errsts ^ info->errsts2) & 0x0003) { |
93 | pci_read_config_dword(pdev, I82860_EAP, &info->eap); | 93 | pci_read_config_dword(pdev, I82860_EAP, &info->eap); |
94 | pci_read_config_word(pdev, I82860_DERRCTL_STS, | 94 | pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn); |
95 | &info->derrsyn); | ||
96 | } | 95 | } |
97 | } | 96 | } |
98 | 97 | ||
99 | static int i82860_process_error_info(struct mem_ctl_info *mci, | 98 | static int i82860_process_error_info(struct mem_ctl_info *mci, |
100 | struct i82860_error_info *info, int handle_errors) | 99 | struct i82860_error_info *info, |
100 | int handle_errors) | ||
101 | { | 101 | { |
102 | int row; | 102 | int row; |
103 | 103 | ||
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci) | |||
136 | static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) | 136 | static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) |
137 | { | 137 | { |
138 | unsigned long last_cumul_size; | 138 | unsigned long last_cumul_size; |
139 | u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ | 139 | u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ |
140 | u16 value; | 140 | u16 value; |
141 | u32 cumul_size; | 141 | u32 cumul_size; |
142 | struct csrow_info *csrow; | 142 | struct csrow_info *csrow; |
@@ -155,7 +155,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) | |||
155 | csrow = &mci->csrows[index]; | 155 | csrow = &mci->csrows[index]; |
156 | pci_read_config_word(pdev, I82860_GBA + index * 2, &value); | 156 | pci_read_config_word(pdev, I82860_GBA + index * 2, &value); |
157 | cumul_size = (value & I82860_GBA_MASK) << | 157 | cumul_size = (value & I82860_GBA_MASK) << |
158 | (I82860_GBA_SHIFT - PAGE_SHIFT); | 158 | (I82860_GBA_SHIFT - PAGE_SHIFT); |
159 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, | 159 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
160 | cumul_size); | 160 | cumul_size); |
161 | 161 | ||
@@ -186,7 +186,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
186 | the channel and the GRA registers map to physical devices so we are | 186 | the channel and the GRA registers map to physical devices so we are |
187 | going to make 1 channel for group. | 187 | going to make 1 channel for group. |
188 | */ | 188 | */ |
189 | mci = edac_mc_alloc(0, 16, 1); | 189 | mci = edac_mc_alloc(0, 16, 1, 0); |
190 | 190 | ||
191 | if (!mci) | 191 | if (!mci) |
192 | return -ENOMEM; | 192 | return -ENOMEM; |
@@ -200,19 +200,31 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
200 | mci->mod_name = EDAC_MOD_STR; | 200 | mci->mod_name = EDAC_MOD_STR; |
201 | mci->mod_ver = I82860_REVISION; | 201 | mci->mod_ver = I82860_REVISION; |
202 | mci->ctl_name = i82860_devs[dev_idx].ctl_name; | 202 | mci->ctl_name = i82860_devs[dev_idx].ctl_name; |
203 | mci->dev_name = pci_name(pdev); | ||
203 | mci->edac_check = i82860_check; | 204 | mci->edac_check = i82860_check; |
204 | mci->ctl_page_to_phys = NULL; | 205 | mci->ctl_page_to_phys = NULL; |
205 | i82860_init_csrows(mci, pdev); | 206 | i82860_init_csrows(mci, pdev); |
206 | i82860_get_error_info(mci, &discard); /* clear counters */ | 207 | i82860_get_error_info(mci, &discard); /* clear counters */ |
207 | 208 | ||
208 | /* Here we assume that we will never see multiple instances of this | 209 | /* Here we assume that we will never see multiple instances of this |
209 | * type of memory controller. The ID is therefore hardcoded to 0. | 210 | * type of memory controller. The ID is therefore hardcoded to 0. |
210 | */ | 211 | */ |
211 | if (edac_mc_add_mc(mci,0)) { | 212 | if (edac_mc_add_mc(mci)) { |
212 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 213 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
213 | goto fail; | 214 | goto fail; |
214 | } | 215 | } |
215 | 216 | ||
217 | /* allocating generic PCI control info */ | ||
218 | i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
219 | if (!i82860_pci) { | ||
220 | printk(KERN_WARNING | ||
221 | "%s(): Unable to create PCI control\n", | ||
222 | __func__); | ||
223 | printk(KERN_WARNING | ||
224 | "%s(): PCI error report via EDAC not setup\n", | ||
225 | __func__); | ||
226 | } | ||
227 | |||
216 | /* get this far and it's successful */ | 228 | /* get this far and it's successful */ |
217 | debugf3("%s(): success\n", __func__); | 229 | debugf3("%s(): success\n", __func__); |
218 | 230 | ||
@@ -225,7 +237,7 @@ fail: | |||
225 | 237 | ||
226 | /* returns count (>= 0), or negative on error */ | 238 | /* returns count (>= 0), or negative on error */ |
227 | static int __devinit i82860_init_one(struct pci_dev *pdev, | 239 | static int __devinit i82860_init_one(struct pci_dev *pdev, |
228 | const struct pci_device_id *ent) | 240 | const struct pci_device_id *ent) |
229 | { | 241 | { |
230 | int rc; | 242 | int rc; |
231 | 243 | ||
@@ -249,6 +261,9 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev) | |||
249 | 261 | ||
250 | debugf0("%s()\n", __func__); | 262 | debugf0("%s()\n", __func__); |
251 | 263 | ||
264 | if (i82860_pci) | ||
265 | edac_pci_release_generic_ctl(i82860_pci); | ||
266 | |||
252 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 267 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
253 | return; | 268 | return; |
254 | 269 | ||
@@ -257,12 +272,11 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev) | |||
257 | 272 | ||
258 | static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { | 273 | static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { |
259 | { | 274 | { |
260 | PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 275 | PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
261 | I82860 | 276 | I82860}, |
262 | }, | ||
263 | { | 277 | { |
264 | 0, | 278 | 0, |
265 | } /* 0 terminated list. */ | 279 | } /* 0 terminated list. */ |
266 | }; | 280 | }; |
267 | 281 | ||
268 | MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); | 282 | MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); |
@@ -329,5 +343,5 @@ module_exit(i82860_exit); | |||
329 | 343 | ||
330 | MODULE_LICENSE("GPL"); | 344 | MODULE_LICENSE("GPL"); |
331 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " | 345 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " |
332 | "Ben Woodard <woodard@redhat.com>"); | 346 | "Ben Woodard <woodard@redhat.com>"); |
333 | MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); | 347 | MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); |
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 2800b3e614a9..031abadc439a 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c | |||
@@ -18,9 +18,9 @@ | |||
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/pci_ids.h> | 19 | #include <linux/pci_ids.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include "edac_mc.h" | 21 | #include "edac_core.h" |
22 | 22 | ||
23 | #define I82875P_REVISION " Ver: 2.0.1 " __DATE__ | 23 | #define I82875P_REVISION " Ver: 2.0.2 " __DATE__ |
24 | #define EDAC_MOD_STR "i82875p_edac" | 24 | #define EDAC_MOD_STR "i82875p_edac" |
25 | 25 | ||
26 | #define i82875p_printk(level, fmt, arg...) \ | 26 | #define i82875p_printk(level, fmt, arg...) \ |
@@ -174,18 +174,19 @@ struct i82875p_error_info { | |||
174 | 174 | ||
175 | static const struct i82875p_dev_info i82875p_devs[] = { | 175 | static const struct i82875p_dev_info i82875p_devs[] = { |
176 | [I82875P] = { | 176 | [I82875P] = { |
177 | .ctl_name = "i82875p" | 177 | .ctl_name = "i82875p"}, |
178 | }, | ||
179 | }; | 178 | }; |
180 | 179 | ||
181 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code has | 180 | static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has |
182 | * already registered driver | 181 | * already registered driver |
183 | */ | 182 | */ |
184 | 183 | ||
185 | static int i82875p_registered = 1; | 184 | static int i82875p_registered = 1; |
186 | 185 | ||
186 | static struct edac_pci_ctl_info *i82875p_pci; | ||
187 | |||
187 | static void i82875p_get_error_info(struct mem_ctl_info *mci, | 188 | static void i82875p_get_error_info(struct mem_ctl_info *mci, |
188 | struct i82875p_error_info *info) | 189 | struct i82875p_error_info *info) |
189 | { | 190 | { |
190 | struct pci_dev *pdev; | 191 | struct pci_dev *pdev; |
191 | 192 | ||
@@ -197,38 +198,39 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci, | |||
197 | * overwritten by UE. | 198 | * overwritten by UE. |
198 | */ | 199 | */ |
199 | pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts); | 200 | pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts); |
201 | |||
202 | if (!(info->errsts & 0x0081)) | ||
203 | return; | ||
204 | |||
200 | pci_read_config_dword(pdev, I82875P_EAP, &info->eap); | 205 | pci_read_config_dword(pdev, I82875P_EAP, &info->eap); |
201 | pci_read_config_byte(pdev, I82875P_DES, &info->des); | 206 | pci_read_config_byte(pdev, I82875P_DES, &info->des); |
202 | pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn); | 207 | pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn); |
203 | pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2); | 208 | pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2); |
204 | 209 | ||
205 | pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081); | ||
206 | |||
207 | /* | 210 | /* |
208 | * If the error is the same then we can for both reads then | 211 | * If the error is the same then we can for both reads then |
209 | * the first set of reads is valid. If there is a change then | 212 | * the first set of reads is valid. If there is a change then |
210 | * there is a CE no info and the second set of reads is valid | 213 | * there is a CE no info and the second set of reads is valid |
211 | * and should be UE info. | 214 | * and should be UE info. |
212 | */ | 215 | */ |
213 | if (!(info->errsts2 & 0x0081)) | ||
214 | return; | ||
215 | |||
216 | if ((info->errsts ^ info->errsts2) & 0x0081) { | 216 | if ((info->errsts ^ info->errsts2) & 0x0081) { |
217 | pci_read_config_dword(pdev, I82875P_EAP, &info->eap); | 217 | pci_read_config_dword(pdev, I82875P_EAP, &info->eap); |
218 | pci_read_config_byte(pdev, I82875P_DES, &info->des); | 218 | pci_read_config_byte(pdev, I82875P_DES, &info->des); |
219 | pci_read_config_byte(pdev, I82875P_DERRSYN, | 219 | pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn); |
220 | &info->derrsyn); | ||
221 | } | 220 | } |
221 | |||
222 | pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081); | ||
222 | } | 223 | } |
223 | 224 | ||
224 | static int i82875p_process_error_info(struct mem_ctl_info *mci, | 225 | static int i82875p_process_error_info(struct mem_ctl_info *mci, |
225 | struct i82875p_error_info *info, int handle_errors) | 226 | struct i82875p_error_info *info, |
227 | int handle_errors) | ||
226 | { | 228 | { |
227 | int row, multi_chan; | 229 | int row, multi_chan; |
228 | 230 | ||
229 | multi_chan = mci->csrows[0].nr_channels - 1; | 231 | multi_chan = mci->csrows[0].nr_channels - 1; |
230 | 232 | ||
231 | if (!(info->errsts2 & 0x0081)) | 233 | if (!(info->errsts & 0x0081)) |
232 | return 0; | 234 | return 0; |
233 | 235 | ||
234 | if (!handle_errors) | 236 | if (!handle_errors) |
@@ -263,10 +265,12 @@ static void i82875p_check(struct mem_ctl_info *mci) | |||
263 | 265 | ||
264 | /* Return 0 on success or 1 on failure. */ | 266 | /* Return 0 on success or 1 on failure. */ |
265 | static int i82875p_setup_overfl_dev(struct pci_dev *pdev, | 267 | static int i82875p_setup_overfl_dev(struct pci_dev *pdev, |
266 | struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window) | 268 | struct pci_dev **ovrfl_pdev, |
269 | void __iomem **ovrfl_window) | ||
267 | { | 270 | { |
268 | struct pci_dev *dev; | 271 | struct pci_dev *dev; |
269 | void __iomem *window; | 272 | void __iomem *window; |
273 | int err; | ||
270 | 274 | ||
271 | *ovrfl_pdev = NULL; | 275 | *ovrfl_pdev = NULL; |
272 | *ovrfl_window = NULL; | 276 | *ovrfl_window = NULL; |
@@ -284,14 +288,19 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, | |||
284 | if (dev == NULL) | 288 | if (dev == NULL) |
285 | return 1; | 289 | return 1; |
286 | 290 | ||
287 | pci_bus_add_device(dev); | 291 | err = pci_bus_add_device(dev); |
292 | if (err) { | ||
293 | i82875p_printk(KERN_ERR, | ||
294 | "%s(): pci_bus_add_device() Failed\n", | ||
295 | __func__); | ||
296 | } | ||
288 | } | 297 | } |
289 | 298 | ||
290 | *ovrfl_pdev = dev; | 299 | *ovrfl_pdev = dev; |
291 | 300 | ||
292 | if (pci_enable_device(dev)) { | 301 | if (pci_enable_device(dev)) { |
293 | i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow " | 302 | i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow " |
294 | "device\n", __func__); | 303 | "device\n", __func__); |
295 | return 1; | 304 | return 1; |
296 | } | 305 | } |
297 | 306 | ||
@@ -307,7 +316,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, | |||
307 | 316 | ||
308 | if (window == NULL) { | 317 | if (window == NULL) { |
309 | i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n", | 318 | i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n", |
310 | __func__); | 319 | __func__); |
311 | goto fail1; | 320 | goto fail1; |
312 | } | 321 | } |
313 | 322 | ||
@@ -325,21 +334,20 @@ fail0: | |||
325 | return 1; | 334 | return 1; |
326 | } | 335 | } |
327 | 336 | ||
328 | |||
329 | /* Return 1 if dual channel mode is active. Else return 0. */ | 337 | /* Return 1 if dual channel mode is active. Else return 0. */ |
330 | static inline int dual_channel_active(u32 drc) | 338 | static inline int dual_channel_active(u32 drc) |
331 | { | 339 | { |
332 | return (drc >> 21) & 0x1; | 340 | return (drc >> 21) & 0x1; |
333 | } | 341 | } |
334 | 342 | ||
335 | |||
336 | static void i82875p_init_csrows(struct mem_ctl_info *mci, | 343 | static void i82875p_init_csrows(struct mem_ctl_info *mci, |
337 | struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc) | 344 | struct pci_dev *pdev, |
345 | void __iomem * ovrfl_window, u32 drc) | ||
338 | { | 346 | { |
339 | struct csrow_info *csrow; | 347 | struct csrow_info *csrow; |
340 | unsigned long last_cumul_size; | 348 | unsigned long last_cumul_size; |
341 | u8 value; | 349 | u8 value; |
342 | u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | 350 | u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ |
343 | u32 cumul_size; | 351 | u32 cumul_size; |
344 | int index; | 352 | int index; |
345 | 353 | ||
@@ -392,7 +400,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
392 | drc = readl(ovrfl_window + I82875P_DRC); | 400 | drc = readl(ovrfl_window + I82875P_DRC); |
393 | nr_chans = dual_channel_active(drc) + 1; | 401 | nr_chans = dual_channel_active(drc) + 1; |
394 | mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), | 402 | mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), |
395 | nr_chans); | 403 | nr_chans, 0); |
396 | 404 | ||
397 | if (!mci) { | 405 | if (!mci) { |
398 | rc = -ENOMEM; | 406 | rc = -ENOMEM; |
@@ -407,23 +415,35 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
407 | mci->mod_name = EDAC_MOD_STR; | 415 | mci->mod_name = EDAC_MOD_STR; |
408 | mci->mod_ver = I82875P_REVISION; | 416 | mci->mod_ver = I82875P_REVISION; |
409 | mci->ctl_name = i82875p_devs[dev_idx].ctl_name; | 417 | mci->ctl_name = i82875p_devs[dev_idx].ctl_name; |
418 | mci->dev_name = pci_name(pdev); | ||
410 | mci->edac_check = i82875p_check; | 419 | mci->edac_check = i82875p_check; |
411 | mci->ctl_page_to_phys = NULL; | 420 | mci->ctl_page_to_phys = NULL; |
412 | debugf3("%s(): init pvt\n", __func__); | 421 | debugf3("%s(): init pvt\n", __func__); |
413 | pvt = (struct i82875p_pvt *) mci->pvt_info; | 422 | pvt = (struct i82875p_pvt *)mci->pvt_info; |
414 | pvt->ovrfl_pdev = ovrfl_pdev; | 423 | pvt->ovrfl_pdev = ovrfl_pdev; |
415 | pvt->ovrfl_window = ovrfl_window; | 424 | pvt->ovrfl_window = ovrfl_window; |
416 | i82875p_init_csrows(mci, pdev, ovrfl_window, drc); | 425 | i82875p_init_csrows(mci, pdev, ovrfl_window, drc); |
417 | i82875p_get_error_info(mci, &discard); /* clear counters */ | 426 | i82875p_get_error_info(mci, &discard); /* clear counters */ |
418 | 427 | ||
419 | /* Here we assume that we will never see multiple instances of this | 428 | /* Here we assume that we will never see multiple instances of this |
420 | * type of memory controller. The ID is therefore hardcoded to 0. | 429 | * type of memory controller. The ID is therefore hardcoded to 0. |
421 | */ | 430 | */ |
422 | if (edac_mc_add_mc(mci,0)) { | 431 | if (edac_mc_add_mc(mci)) { |
423 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 432 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
424 | goto fail1; | 433 | goto fail1; |
425 | } | 434 | } |
426 | 435 | ||
436 | /* allocating generic PCI control info */ | ||
437 | i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
438 | if (!i82875p_pci) { | ||
439 | printk(KERN_WARNING | ||
440 | "%s(): Unable to create PCI control\n", | ||
441 | __func__); | ||
442 | printk(KERN_WARNING | ||
443 | "%s(): PCI error report via EDAC not setup\n", | ||
444 | __func__); | ||
445 | } | ||
446 | |||
427 | /* get this far and it's successful */ | 447 | /* get this far and it's successful */ |
428 | debugf3("%s(): success\n", __func__); | 448 | debugf3("%s(): success\n", __func__); |
429 | return 0; | 449 | return 0; |
@@ -442,7 +462,7 @@ fail0: | |||
442 | 462 | ||
443 | /* returns count (>= 0), or negative on error */ | 463 | /* returns count (>= 0), or negative on error */ |
444 | static int __devinit i82875p_init_one(struct pci_dev *pdev, | 464 | static int __devinit i82875p_init_one(struct pci_dev *pdev, |
445 | const struct pci_device_id *ent) | 465 | const struct pci_device_id *ent) |
446 | { | 466 | { |
447 | int rc; | 467 | int rc; |
448 | 468 | ||
@@ -467,10 +487,13 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev) | |||
467 | 487 | ||
468 | debugf0("%s()\n", __func__); | 488 | debugf0("%s()\n", __func__); |
469 | 489 | ||
490 | if (i82875p_pci) | ||
491 | edac_pci_release_generic_ctl(i82875p_pci); | ||
492 | |||
470 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 493 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
471 | return; | 494 | return; |
472 | 495 | ||
473 | pvt = (struct i82875p_pvt *) mci->pvt_info; | 496 | pvt = (struct i82875p_pvt *)mci->pvt_info; |
474 | 497 | ||
475 | if (pvt->ovrfl_window) | 498 | if (pvt->ovrfl_window) |
476 | iounmap(pvt->ovrfl_window); | 499 | iounmap(pvt->ovrfl_window); |
@@ -488,12 +511,11 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev) | |||
488 | 511 | ||
489 | static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { | 512 | static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { |
490 | { | 513 | { |
491 | PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 514 | PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
492 | I82875P | 515 | I82875P}, |
493 | }, | ||
494 | { | 516 | { |
495 | 0, | 517 | 0, |
496 | } /* 0 terminated list. */ | 518 | } /* 0 terminated list. */ |
497 | }; | 519 | }; |
498 | 520 | ||
499 | MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); | 521 | MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); |
@@ -517,7 +539,7 @@ static int __init i82875p_init(void) | |||
517 | 539 | ||
518 | if (mci_pdev == NULL) { | 540 | if (mci_pdev == NULL) { |
519 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 541 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
520 | PCI_DEVICE_ID_INTEL_82875_0, NULL); | 542 | PCI_DEVICE_ID_INTEL_82875_0, NULL); |
521 | 543 | ||
522 | if (!mci_pdev) { | 544 | if (!mci_pdev) { |
523 | debugf0("875p pci_get_device fail\n"); | 545 | debugf0("875p pci_get_device fail\n"); |
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c new file mode 100644 index 000000000000..0ee888456932 --- /dev/null +++ b/drivers/edac/i82975x_edac.c | |||
@@ -0,0 +1,666 @@ | |||
1 | /* | ||
2 | * Intel 82975X Memory Controller kernel module | ||
3 | * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com) | ||
4 | * (C) 2007 jetzbroadband (http://jetzbroadband.com) | ||
5 | * This file may be distributed under the terms of the | ||
6 | * GNU General Public License. | ||
7 | * | ||
8 | * Written by Arvind R. | ||
9 | * Copied from i82875p_edac.c source: | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/pci_ids.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include "edac_core.h" | ||
19 | |||
20 | #define I82975X_REVISION " Ver: 1.0.0 " __DATE__ | ||
21 | #define EDAC_MOD_STR "i82975x_edac" | ||
22 | |||
23 | #define i82975x_printk(level, fmt, arg...) \ | ||
24 | edac_printk(level, "i82975x", fmt, ##arg) | ||
25 | |||
26 | #define i82975x_mc_printk(mci, level, fmt, arg...) \ | ||
27 | edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg) | ||
28 | |||
29 | #ifndef PCI_DEVICE_ID_INTEL_82975_0 | ||
30 | #define PCI_DEVICE_ID_INTEL_82975_0 0x277c | ||
31 | #endif /* PCI_DEVICE_ID_INTEL_82975_0 */ | ||
32 | |||
33 | #define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans)) | ||
34 | |||
35 | /* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */ | ||
36 | #define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b) | ||
37 | * | ||
38 | * 31:7 128 byte cache-line address | ||
39 | * 6:1 reserved | ||
40 | * 0 0: CH0; 1: CH1 | ||
41 | */ | ||
42 | |||
43 | #define I82975X_DERRSYN 0x5c /* Dram Error SYNdrome (8b) | ||
44 | * | ||
45 | * 7:0 DRAM ECC Syndrome | ||
46 | */ | ||
47 | |||
48 | #define I82975X_DES 0x5d /* Dram ERRor DeSTination (8b) | ||
49 | * 0h: Processor Memory Reads | ||
50 | * 1h:7h reserved | ||
51 | * More - See Page 65 of Intel DocSheet. | ||
52 | */ | ||
53 | |||
54 | #define I82975X_ERRSTS 0xc8 /* Error Status Register (16b) | ||
55 | * | ||
56 | * 15:12 reserved | ||
57 | * 11 Thermal Sensor Event | ||
58 | * 10 reserved | ||
59 | * 9 non-DRAM lock error (ndlock) | ||
60 | * 8 Refresh Timeout | ||
61 | * 7:2 reserved | ||
62 | * 1 ECC UE (multibit DRAM error) | ||
63 | * 0 ECC CE (singlebit DRAM error) | ||
64 | */ | ||
65 | |||
66 | /* Error Reporting is supported by 3 mechanisms: | ||
67 | 1. DMI SERR generation ( ERRCMD ) | ||
68 | 2. SMI DMI generation ( SMICMD ) | ||
69 | 3. SCI DMI generation ( SCICMD ) | ||
70 | NOTE: Only ONE of the three must be enabled | ||
71 | */ | ||
72 | #define I82975X_ERRCMD 0xca /* Error Command (16b) | ||
73 | * | ||
74 | * 15:12 reserved | ||
75 | * 11 Thermal Sensor Event | ||
76 | * 10 reserved | ||
77 | * 9 non-DRAM lock error (ndlock) | ||
78 | * 8 Refresh Timeout | ||
79 | * 7:2 reserved | ||
80 | * 1 ECC UE (multibit DRAM error) | ||
81 | * 0 ECC CE (singlebit DRAM error) | ||
82 | */ | ||
83 | |||
84 | #define I82975X_SMICMD 0xcc /* Error Command (16b) | ||
85 | * | ||
86 | * 15:2 reserved | ||
87 | * 1 ECC UE (multibit DRAM error) | ||
88 | * 0 ECC CE (singlebit DRAM error) | ||
89 | */ | ||
90 | |||
91 | #define I82975X_SCICMD 0xce /* Error Command (16b) | ||
92 | * | ||
93 | * 15:2 reserved | ||
94 | * 1 ECC UE (multibit DRAM error) | ||
95 | * 0 ECC CE (singlebit DRAM error) | ||
96 | */ | ||
97 | |||
98 | #define I82975X_XEAP 0xfc /* Extended Dram Error Address Pointer (8b) | ||
99 | * | ||
100 | * 7:1 reserved | ||
101 | * 0 Bit32 of the Dram Error Address | ||
102 | */ | ||
103 | |||
104 | #define I82975X_MCHBAR 0x44 /* | ||
105 | * | ||
106 | * 31:14 Base Addr of 16K memory-mapped | ||
107 | * configuration space | ||
108 | * 13:1 reserverd | ||
109 | * 0 mem-mapped config space enable | ||
110 | */ | ||
111 | |||
112 | /* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */ | ||
113 | /* Intel 82975x memory mapped register space */ | ||
114 | |||
115 | #define I82975X_DRB_SHIFT 25 /* fixed 32MiB grain */ | ||
116 | |||
117 | #define I82975X_DRB 0x100 /* DRAM Row Boundary (8b x 8) | ||
118 | * | ||
119 | * 7 set to 1 in highest DRB of | ||
120 | * channel if 4GB in ch. | ||
121 | * 6:2 upper boundary of rank in | ||
122 | * 32MB grains | ||
123 | * 1:0 set to 0 | ||
124 | */ | ||
125 | #define I82975X_DRB_CH0R0 0x100 | ||
126 | #define I82975X_DRB_CH0R1 0x101 | ||
127 | #define I82975X_DRB_CH0R2 0x102 | ||
128 | #define I82975X_DRB_CH0R3 0x103 | ||
129 | #define I82975X_DRB_CH1R0 0x180 | ||
130 | #define I82975X_DRB_CH1R1 0x181 | ||
131 | #define I82975X_DRB_CH1R2 0x182 | ||
132 | #define I82975X_DRB_CH1R3 0x183 | ||
133 | |||
134 | |||
135 | #define I82975X_DRA 0x108 /* DRAM Row Attribute (4b x 8) | ||
136 | * defines the PAGE SIZE to be used | ||
137 | * for the rank | ||
138 | * 7 reserved | ||
139 | * 6:4 row attr of odd rank, i.e. 1 | ||
140 | * 3 reserved | ||
141 | * 2:0 row attr of even rank, i.e. 0 | ||
142 | * | ||
143 | * 000 = unpopulated | ||
144 | * 001 = reserved | ||
145 | * 010 = 4KiB | ||
146 | * 011 = 8KiB | ||
147 | * 100 = 16KiB | ||
148 | * others = reserved | ||
149 | */ | ||
150 | #define I82975X_DRA_CH0R01 0x108 | ||
151 | #define I82975X_DRA_CH0R23 0x109 | ||
152 | #define I82975X_DRA_CH1R01 0x188 | ||
153 | #define I82975X_DRA_CH1R23 0x189 | ||
154 | |||
155 | |||
156 | #define I82975X_BNKARC 0x10e /* Type of device in each rank - Bank Arch (16b) | ||
157 | * | ||
158 | * 15:8 reserved | ||
159 | * 7:6 Rank 3 architecture | ||
160 | * 5:4 Rank 2 architecture | ||
161 | * 3:2 Rank 1 architecture | ||
162 | * 1:0 Rank 0 architecture | ||
163 | * | ||
164 | * 00 => x16 devices; i.e 4 banks | ||
165 | * 01 => x8 devices; i.e 8 banks | ||
166 | */ | ||
167 | #define I82975X_C0BNKARC 0x10e | ||
168 | #define I82975X_C1BNKARC 0x18e | ||
169 | |||
170 | |||
171 | |||
172 | #define I82975X_DRC 0x120 /* DRAM Controller Mode0 (32b) | ||
173 | * | ||
174 | * 31:30 reserved | ||
175 | * 29 init complete | ||
176 | * 28:11 reserved, according to Intel | ||
177 | * 22:21 number of channels | ||
178 | * 00=1 01=2 in 82875 | ||
179 | * seems to be ECC mode | ||
180 | * bits in 82975 in Asus | ||
181 | * P5W | ||
182 | * 19:18 Data Integ Mode | ||
183 | * 00=none 01=ECC in 82875 | ||
184 | * 10:8 refresh mode | ||
185 | * 7 reserved | ||
186 | * 6:4 mode select | ||
187 | * 3:2 reserved | ||
188 | * 1:0 DRAM type 10=Second Revision | ||
189 | * DDR2 SDRAM | ||
190 | * 00, 01, 11 reserved | ||
191 | */ | ||
192 | #define I82975X_DRC_CH0M0 0x120 | ||
193 | #define I82975X_DRC_CH1M0 0x1A0 | ||
194 | |||
195 | |||
196 | #define I82975X_DRC_M1 0x124 /* DRAM Controller Mode1 (32b) | ||
197 | * 31 0=Standard Address Map | ||
198 | * 1=Enhanced Address Map | ||
199 | * 30:0 reserved | ||
200 | */ | ||
201 | |||
202 | #define I82975X_DRC_CH0M1 0x124 | ||
203 | #define I82975X_DRC_CH1M1 0x1A4 | ||
204 | |||
205 | enum i82975x_chips { | ||
206 | I82975X = 0, | ||
207 | }; | ||
208 | |||
209 | struct i82975x_pvt { | ||
210 | void __iomem *mch_window; | ||
211 | }; | ||
212 | |||
213 | struct i82975x_dev_info { | ||
214 | const char *ctl_name; | ||
215 | }; | ||
216 | |||
217 | struct i82975x_error_info { | ||
218 | u16 errsts; | ||
219 | u32 eap; | ||
220 | u8 des; | ||
221 | u8 derrsyn; | ||
222 | u16 errsts2; | ||
223 | u8 chan; /* the channel is bit 0 of EAP */ | ||
224 | u8 xeap; /* extended eap bit */ | ||
225 | }; | ||
226 | |||
227 | static const struct i82975x_dev_info i82975x_devs[] = { | ||
228 | [I82975X] = { | ||
229 | .ctl_name = "i82975x" | ||
230 | }, | ||
231 | }; | ||
232 | |||
233 | static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has | ||
234 | * already registered driver | ||
235 | */ | ||
236 | |||
237 | static int i82975x_registered = 1; | ||
238 | |||
239 | static void i82975x_get_error_info(struct mem_ctl_info *mci, | ||
240 | struct i82975x_error_info *info) | ||
241 | { | ||
242 | struct pci_dev *pdev; | ||
243 | |||
244 | pdev = to_pci_dev(mci->dev); | ||
245 | |||
246 | /* | ||
247 | * This is a mess because there is no atomic way to read all the | ||
248 | * registers at once and the registers can transition from CE being | ||
249 | * overwritten by UE. | ||
250 | */ | ||
251 | pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts); | ||
252 | pci_read_config_dword(pdev, I82975X_EAP, &info->eap); | ||
253 | pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap); | ||
254 | pci_read_config_byte(pdev, I82975X_DES, &info->des); | ||
255 | pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn); | ||
256 | pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2); | ||
257 | |||
258 | pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003); | ||
259 | |||
260 | /* | ||
261 | * If the error is the same then we can for both reads then | ||
262 | * the first set of reads is valid. If there is a change then | ||
263 | * there is a CE no info and the second set of reads is valid | ||
264 | * and should be UE info. | ||
265 | */ | ||
266 | if (!(info->errsts2 & 0x0003)) | ||
267 | return; | ||
268 | |||
269 | if ((info->errsts ^ info->errsts2) & 0x0003) { | ||
270 | pci_read_config_dword(pdev, I82975X_EAP, &info->eap); | ||
271 | pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap); | ||
272 | pci_read_config_byte(pdev, I82975X_DES, &info->des); | ||
273 | pci_read_config_byte(pdev, I82975X_DERRSYN, | ||
274 | &info->derrsyn); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | static int i82975x_process_error_info(struct mem_ctl_info *mci, | ||
279 | struct i82975x_error_info *info, int handle_errors) | ||
280 | { | ||
281 | int row, multi_chan, chan; | ||
282 | |||
283 | multi_chan = mci->csrows[0].nr_channels - 1; | ||
284 | |||
285 | if (!(info->errsts2 & 0x0003)) | ||
286 | return 0; | ||
287 | |||
288 | if (!handle_errors) | ||
289 | return 1; | ||
290 | |||
291 | if ((info->errsts ^ info->errsts2) & 0x0003) { | ||
292 | edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); | ||
293 | info->errsts = info->errsts2; | ||
294 | } | ||
295 | |||
296 | chan = info->eap & 1; | ||
297 | info->eap >>= 1; | ||
298 | if (info->xeap ) | ||
299 | info->eap |= 0x80000000; | ||
300 | info->eap >>= PAGE_SHIFT; | ||
301 | row = edac_mc_find_csrow_by_page(mci, info->eap); | ||
302 | |||
303 | if (info->errsts & 0x0002) | ||
304 | edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE"); | ||
305 | else | ||
306 | edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, | ||
307 | multi_chan ? chan : 0, | ||
308 | "i82975x CE"); | ||
309 | |||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | static void i82975x_check(struct mem_ctl_info *mci) | ||
314 | { | ||
315 | struct i82975x_error_info info; | ||
316 | |||
317 | debugf1("MC%d: %s()\n", mci->mc_idx, __func__); | ||
318 | i82975x_get_error_info(mci, &info); | ||
319 | i82975x_process_error_info(mci, &info, 1); | ||
320 | } | ||
321 | |||
322 | /* Return 1 if dual channel mode is active. Else return 0. */ | ||
323 | static int dual_channel_active(void __iomem *mch_window) | ||
324 | { | ||
325 | /* | ||
326 | * We treat interleaved-symmetric configuration as dual-channel - EAP's | ||
327 | * bit-0 giving the channel of the error location. | ||
328 | * | ||
329 | * All other configurations are treated as single channel - the EAP's | ||
330 | * bit-0 will resolve ok in symmetric area of mixed | ||
331 | * (symmetric/asymmetric) configurations | ||
332 | */ | ||
333 | u8 drb[4][2]; | ||
334 | int row; | ||
335 | int dualch; | ||
336 | |||
337 | for (dualch = 1, row = 0; dualch && (row < 4); row++) { | ||
338 | drb[row][0] = readb(mch_window + I82975X_DRB + row); | ||
339 | drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80); | ||
340 | dualch = dualch && (drb[row][0] == drb[row][1]); | ||
341 | } | ||
342 | return dualch; | ||
343 | } | ||
344 | |||
345 | static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank) | ||
346 | { | ||
347 | /* | ||
348 | * ASUS P5W DH either does not program this register or programs | ||
349 | * it wrong! | ||
350 | * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val' | ||
351 | * for each rank should be 01b - the LSB of the word should be 0x55; | ||
352 | * but it reads 0! | ||
353 | */ | ||
354 | return DEV_X8; | ||
355 | } | ||
356 | |||
357 | static void i82975x_init_csrows(struct mem_ctl_info *mci, | ||
358 | struct pci_dev *pdev, void __iomem *mch_window) | ||
359 | { | ||
360 | struct csrow_info *csrow; | ||
361 | unsigned long last_cumul_size; | ||
362 | u8 value; | ||
363 | u32 cumul_size; | ||
364 | int index; | ||
365 | |||
366 | last_cumul_size = 0; | ||
367 | |||
368 | /* | ||
369 | * 82875 comment: | ||
370 | * The dram row boundary (DRB) reg values are boundary address | ||
371 | * for each DRAM row with a granularity of 32 or 64MB (single/dual | ||
372 | * channel operation). DRB regs are cumulative; therefore DRB7 will | ||
373 | * contain the total memory contained in all eight rows. | ||
374 | * | ||
375 | * FIXME: | ||
376 | * EDAC currently works for Dual-channel Interleaved configuration. | ||
377 | * Other configurations, which the chip supports, need fixing/testing. | ||
378 | * | ||
379 | */ | ||
380 | |||
381 | for (index = 0; index < mci->nr_csrows; index++) { | ||
382 | csrow = &mci->csrows[index]; | ||
383 | |||
384 | value = readb(mch_window + I82975X_DRB + index + | ||
385 | ((index >= 4) ? 0x80 : 0)); | ||
386 | cumul_size = value; | ||
387 | cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT); | ||
388 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, | ||
389 | cumul_size); | ||
390 | if (cumul_size == last_cumul_size) | ||
391 | continue; /* not populated */ | ||
392 | |||
393 | csrow->first_page = last_cumul_size; | ||
394 | csrow->last_page = cumul_size - 1; | ||
395 | csrow->nr_pages = cumul_size - last_cumul_size; | ||
396 | last_cumul_size = cumul_size; | ||
397 | csrow->grain = 1 << 7; /* I82975X_EAP has 128B resolution */ | ||
398 | csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */ | ||
399 | csrow->dtype = i82975x_dram_type(mch_window, index); | ||
400 | csrow->edac_mode = EDAC_SECDED; /* only supported */ | ||
401 | } | ||
402 | } | ||
403 | |||
404 | /* #define i82975x_DEBUG_IOMEM */ | ||
405 | |||
406 | #ifdef i82975x_DEBUG_IOMEM | ||
407 | static void i82975x_print_dram_timings(void __iomem *mch_window) | ||
408 | { | ||
409 | /* | ||
410 | * The register meanings are from Intel specs; | ||
411 | * (shows 13-5-5-5 for 800-DDR2) | ||
412 | * Asus P5W Bios reports 15-5-4-4 | ||
413 | * What's your religion? | ||
414 | */ | ||
415 | static const int caslats[4] = { 5, 4, 3, 6 }; | ||
416 | u32 dtreg[2]; | ||
417 | |||
418 | dtreg[0] = readl(mch_window + 0x114); | ||
419 | dtreg[1] = readl(mch_window + 0x194); | ||
420 | i82975x_printk(KERN_INFO, "DRAM Timings : Ch0 Ch1\n" | ||
421 | " RAS Active Min = %d %d\n" | ||
422 | " CAS latency = %d %d\n" | ||
423 | " RAS to CAS = %d %d\n" | ||
424 | " RAS precharge = %d %d\n", | ||
425 | (dtreg[0] >> 19 ) & 0x0f, | ||
426 | (dtreg[1] >> 19) & 0x0f, | ||
427 | caslats[(dtreg[0] >> 8) & 0x03], | ||
428 | caslats[(dtreg[1] >> 8) & 0x03], | ||
429 | ((dtreg[0] >> 4) & 0x07) + 2, | ||
430 | ((dtreg[1] >> 4) & 0x07) + 2, | ||
431 | (dtreg[0] & 0x07) + 2, | ||
432 | (dtreg[1] & 0x07) + 2 | ||
433 | ); | ||
434 | |||
435 | } | ||
436 | #endif | ||
437 | |||
438 | static int i82975x_probe1(struct pci_dev *pdev, int dev_idx) | ||
439 | { | ||
440 | int rc = -ENODEV; | ||
441 | struct mem_ctl_info *mci; | ||
442 | struct i82975x_pvt *pvt; | ||
443 | void __iomem *mch_window; | ||
444 | u32 mchbar; | ||
445 | u32 drc[2]; | ||
446 | struct i82975x_error_info discard; | ||
447 | int chans; | ||
448 | #ifdef i82975x_DEBUG_IOMEM | ||
449 | u8 c0drb[4]; | ||
450 | u8 c1drb[4]; | ||
451 | #endif | ||
452 | |||
453 | debugf0("%s()\n", __func__); | ||
454 | |||
455 | pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar); | ||
456 | if (!(mchbar & 1)) { | ||
457 | debugf3("%s(): failed, MCHBAR disabled!\n", __func__); | ||
458 | goto fail0; | ||
459 | } | ||
460 | mchbar &= 0xffffc000; /* bits 31:14 used for 16K window */ | ||
461 | mch_window = ioremap_nocache(mchbar, 0x1000); | ||
462 | |||
463 | #ifdef i82975x_DEBUG_IOMEM | ||
464 | i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n", | ||
465 | mchbar, mch_window); | ||
466 | |||
467 | c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0); | ||
468 | c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1); | ||
469 | c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2); | ||
470 | c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3); | ||
471 | c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0); | ||
472 | c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1); | ||
473 | c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2); | ||
474 | c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3); | ||
475 | i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]); | ||
476 | i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]); | ||
477 | i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]); | ||
478 | i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]); | ||
479 | i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]); | ||
480 | i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]); | ||
481 | i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]); | ||
482 | i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]); | ||
483 | #endif | ||
484 | |||
485 | drc[0] = readl(mch_window + I82975X_DRC_CH0M0); | ||
486 | drc[1] = readl(mch_window + I82975X_DRC_CH1M0); | ||
487 | #ifdef i82975x_DEBUG_IOMEM | ||
488 | i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0], | ||
489 | ((drc[0] >> 21) & 3) == 1 ? | ||
490 | "ECC enabled" : "ECC disabled"); | ||
491 | i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1], | ||
492 | ((drc[1] >> 21) & 3) == 1 ? | ||
493 | "ECC enabled" : "ECC disabled"); | ||
494 | |||
495 | i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n", | ||
496 | readw(mch_window + I82975X_C0BNKARC)); | ||
497 | i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n", | ||
498 | readw(mch_window + I82975X_C1BNKARC)); | ||
499 | i82975x_print_dram_timings(mch_window); | ||
500 | goto fail1; | ||
501 | #endif | ||
502 | if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) { | ||
503 | i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n"); | ||
504 | goto fail1; | ||
505 | } | ||
506 | |||
507 | chans = dual_channel_active(mch_window) + 1; | ||
508 | |||
509 | /* assuming only one controller, index thus is 0 */ | ||
510 | mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans), | ||
511 | chans, 0); | ||
512 | if (!mci) { | ||
513 | rc = -ENOMEM; | ||
514 | goto fail1; | ||
515 | } | ||
516 | |||
517 | debugf3("%s(): init mci\n", __func__); | ||
518 | mci->dev = &pdev->dev; | ||
519 | mci->mtype_cap = MEM_FLAG_DDR; | ||
520 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
521 | mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
522 | mci->mod_name = EDAC_MOD_STR; | ||
523 | mci->mod_ver = I82975X_REVISION; | ||
524 | mci->ctl_name = i82975x_devs[dev_idx].ctl_name; | ||
525 | mci->edac_check = i82975x_check; | ||
526 | mci->ctl_page_to_phys = NULL; | ||
527 | debugf3("%s(): init pvt\n", __func__); | ||
528 | pvt = (struct i82975x_pvt *) mci->pvt_info; | ||
529 | pvt->mch_window = mch_window; | ||
530 | i82975x_init_csrows(mci, pdev, mch_window); | ||
531 | i82975x_get_error_info(mci, &discard); /* clear counters */ | ||
532 | |||
533 | /* finalize this instance of memory controller with edac core */ | ||
534 | if (edac_mc_add_mc(mci)) { | ||
535 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | ||
536 | goto fail2; | ||
537 | } | ||
538 | |||
539 | /* get this far and it's successful */ | ||
540 | debugf3("%s(): success\n", __func__); | ||
541 | return 0; | ||
542 | |||
543 | fail2: | ||
544 | edac_mc_free(mci); | ||
545 | |||
546 | fail1: | ||
547 | iounmap(mch_window); | ||
548 | fail0: | ||
549 | return rc; | ||
550 | } | ||
551 | |||
552 | /* returns count (>= 0), or negative on error */ | ||
553 | static int __devinit i82975x_init_one(struct pci_dev *pdev, | ||
554 | const struct pci_device_id *ent) | ||
555 | { | ||
556 | int rc; | ||
557 | |||
558 | debugf0("%s()\n", __func__); | ||
559 | |||
560 | if (pci_enable_device(pdev) < 0) | ||
561 | return -EIO; | ||
562 | |||
563 | rc = i82975x_probe1(pdev, ent->driver_data); | ||
564 | |||
565 | if (mci_pdev == NULL) | ||
566 | mci_pdev = pci_dev_get(pdev); | ||
567 | |||
568 | return rc; | ||
569 | } | ||
570 | |||
571 | static void __devexit i82975x_remove_one(struct pci_dev *pdev) | ||
572 | { | ||
573 | struct mem_ctl_info *mci; | ||
574 | struct i82975x_pvt *pvt; | ||
575 | |||
576 | debugf0("%s()\n", __func__); | ||
577 | |||
578 | mci = edac_mc_del_mc(&pdev->dev); | ||
579 | if (mci == NULL) | ||
580 | return; | ||
581 | |||
582 | pvt = mci->pvt_info; | ||
583 | if (pvt->mch_window) | ||
584 | iounmap( pvt->mch_window ); | ||
585 | |||
586 | edac_mc_free(mci); | ||
587 | } | ||
588 | |||
589 | static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = { | ||
590 | { | ||
591 | PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
592 | I82975X | ||
593 | }, | ||
594 | { | ||
595 | 0, | ||
596 | } /* 0 terminated list. */ | ||
597 | }; | ||
598 | |||
599 | MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl); | ||
600 | |||
601 | static struct pci_driver i82975x_driver = { | ||
602 | .name = EDAC_MOD_STR, | ||
603 | .probe = i82975x_init_one, | ||
604 | .remove = __devexit_p(i82975x_remove_one), | ||
605 | .id_table = i82975x_pci_tbl, | ||
606 | }; | ||
607 | |||
608 | static int __init i82975x_init(void) | ||
609 | { | ||
610 | int pci_rc; | ||
611 | |||
612 | debugf3("%s()\n", __func__); | ||
613 | |||
614 | pci_rc = pci_register_driver(&i82975x_driver); | ||
615 | if (pci_rc < 0) | ||
616 | goto fail0; | ||
617 | |||
618 | if (mci_pdev == NULL) { | ||
619 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
620 | PCI_DEVICE_ID_INTEL_82975_0, NULL); | ||
621 | |||
622 | if (!mci_pdev) { | ||
623 | debugf0("i82975x pci_get_device fail\n"); | ||
624 | pci_rc = -ENODEV; | ||
625 | goto fail1; | ||
626 | } | ||
627 | |||
628 | pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl); | ||
629 | |||
630 | if (pci_rc < 0) { | ||
631 | debugf0("i82975x init fail\n"); | ||
632 | pci_rc = -ENODEV; | ||
633 | goto fail1; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | return 0; | ||
638 | |||
639 | fail1: | ||
640 | pci_unregister_driver(&i82975x_driver); | ||
641 | |||
642 | fail0: | ||
643 | if (mci_pdev != NULL) | ||
644 | pci_dev_put(mci_pdev); | ||
645 | |||
646 | return pci_rc; | ||
647 | } | ||
648 | |||
649 | static void __exit i82975x_exit(void) | ||
650 | { | ||
651 | debugf3("%s()\n", __func__); | ||
652 | |||
653 | pci_unregister_driver(&i82975x_driver); | ||
654 | |||
655 | if (!i82975x_registered) { | ||
656 | i82975x_remove_one(mci_pdev); | ||
657 | pci_dev_put(mci_pdev); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | module_init(i82975x_init); | ||
662 | module_exit(i82975x_exit); | ||
663 | |||
664 | MODULE_LICENSE("GPL"); | ||
665 | MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>"); | ||
666 | MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers"); | ||
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c new file mode 100644 index 000000000000..e66cdd42a392 --- /dev/null +++ b/drivers/edac/pasemi_edac.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2007 PA Semi, Inc | ||
3 | * | ||
4 | * Author: Egor Martovetsky <egor@pasemi.com> | ||
5 | * Maintained by: Olof Johansson <olof@lixom.net> | ||
6 | * | ||
7 | * Driver for the PWRficient onchip memory controllers | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/pci_ids.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include "edac_core.h" | ||
30 | |||
31 | #define MODULE_NAME "pasemi_edac" | ||
32 | |||
33 | #define MCCFG_MCEN 0x300 | ||
34 | #define MCCFG_MCEN_MMC_EN 0x00000001 | ||
35 | #define MCCFG_ERRCOR 0x388 | ||
36 | #define MCCFG_ERRCOR_RNK_FAIL_DET_EN 0x00000100 | ||
37 | #define MCCFG_ERRCOR_ECC_GEN_EN 0x00000010 | ||
38 | #define MCCFG_ERRCOR_ECC_CRR_EN 0x00000001 | ||
39 | #define MCCFG_SCRUB 0x384 | ||
40 | #define MCCFG_SCRUB_RGLR_SCRB_EN 0x00000001 | ||
41 | #define MCDEBUG_ERRCTL1 0x728 | ||
42 | #define MCDEBUG_ERRCTL1_RFL_LOG_EN 0x00080000 | ||
43 | #define MCDEBUG_ERRCTL1_MBE_LOG_EN 0x00040000 | ||
44 | #define MCDEBUG_ERRCTL1_SBE_LOG_EN 0x00020000 | ||
45 | #define MCDEBUG_ERRSTA 0x730 | ||
46 | #define MCDEBUG_ERRSTA_RFL_STATUS 0x00000004 | ||
47 | #define MCDEBUG_ERRSTA_MBE_STATUS 0x00000002 | ||
48 | #define MCDEBUG_ERRSTA_SBE_STATUS 0x00000001 | ||
49 | #define MCDEBUG_ERRCNT1 0x734 | ||
50 | #define MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO 0x00000080 | ||
51 | #define MCDEBUG_ERRLOG1A 0x738 | ||
52 | #define MCDEBUG_ERRLOG1A_MERR_TYPE_M 0x30000000 | ||
53 | #define MCDEBUG_ERRLOG1A_MERR_TYPE_NONE 0x00000000 | ||
54 | #define MCDEBUG_ERRLOG1A_MERR_TYPE_SBE 0x10000000 | ||
55 | #define MCDEBUG_ERRLOG1A_MERR_TYPE_MBE 0x20000000 | ||
56 | #define MCDEBUG_ERRLOG1A_MERR_TYPE_RFL 0x30000000 | ||
57 | #define MCDEBUG_ERRLOG1A_MERR_BA_M 0x00700000 | ||
58 | #define MCDEBUG_ERRLOG1A_MERR_BA_S 20 | ||
59 | #define MCDEBUG_ERRLOG1A_MERR_CS_M 0x00070000 | ||
60 | #define MCDEBUG_ERRLOG1A_MERR_CS_S 16 | ||
61 | #define MCDEBUG_ERRLOG1A_SYNDROME_M 0x0000ffff | ||
62 | #define MCDRAM_RANKCFG 0x114 | ||
63 | #define MCDRAM_RANKCFG_EN 0x00000001 | ||
64 | #define MCDRAM_RANKCFG_TYPE_SIZE_M 0x000001c0 | ||
65 | #define MCDRAM_RANKCFG_TYPE_SIZE_S 6 | ||
66 | |||
67 | #define PASEMI_EDAC_NR_CSROWS 8 | ||
68 | #define PASEMI_EDAC_NR_CHANS 1 | ||
69 | #define PASEMI_EDAC_ERROR_GRAIN 64 | ||
70 | |||
71 | static int last_page_in_mmc; | ||
72 | static int system_mmc_id; | ||
73 | |||
74 | |||
75 | static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci) | ||
76 | { | ||
77 | struct pci_dev *pdev = to_pci_dev(mci->dev); | ||
78 | u32 tmp; | ||
79 | |||
80 | pci_read_config_dword(pdev, MCDEBUG_ERRSTA, | ||
81 | &tmp); | ||
82 | |||
83 | tmp &= (MCDEBUG_ERRSTA_RFL_STATUS | MCDEBUG_ERRSTA_MBE_STATUS | ||
84 | | MCDEBUG_ERRSTA_SBE_STATUS); | ||
85 | |||
86 | if (tmp) { | ||
87 | if (tmp & MCDEBUG_ERRSTA_SBE_STATUS) | ||
88 | pci_write_config_dword(pdev, MCDEBUG_ERRCNT1, | ||
89 | MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO); | ||
90 | pci_write_config_dword(pdev, MCDEBUG_ERRSTA, tmp); | ||
91 | } | ||
92 | |||
93 | return tmp; | ||
94 | } | ||
95 | |||
96 | static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta) | ||
97 | { | ||
98 | struct pci_dev *pdev = to_pci_dev(mci->dev); | ||
99 | u32 errlog1a; | ||
100 | u32 cs; | ||
101 | |||
102 | if (!errsta) | ||
103 | return; | ||
104 | |||
105 | pci_read_config_dword(pdev, MCDEBUG_ERRLOG1A, &errlog1a); | ||
106 | |||
107 | cs = (errlog1a & MCDEBUG_ERRLOG1A_MERR_CS_M) >> | ||
108 | MCDEBUG_ERRLOG1A_MERR_CS_S; | ||
109 | |||
110 | /* uncorrectable/multi-bit errors */ | ||
111 | if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS | | ||
112 | MCDEBUG_ERRSTA_RFL_STATUS)) { | ||
113 | edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0, | ||
114 | cs, mci->ctl_name); | ||
115 | } | ||
116 | |||
117 | /* correctable/single-bit errors */ | ||
118 | if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) { | ||
119 | edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0, | ||
120 | 0, cs, 0, mci->ctl_name); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static void pasemi_edac_check(struct mem_ctl_info *mci) | ||
125 | { | ||
126 | u32 errsta; | ||
127 | |||
128 | errsta = pasemi_edac_get_error_info(mci); | ||
129 | if (errsta) | ||
130 | pasemi_edac_process_error_info(mci, errsta); | ||
131 | } | ||
132 | |||
133 | static int pasemi_edac_init_csrows(struct mem_ctl_info *mci, | ||
134 | struct pci_dev *pdev, | ||
135 | enum edac_type edac_mode) | ||
136 | { | ||
137 | struct csrow_info *csrow; | ||
138 | u32 rankcfg; | ||
139 | int index; | ||
140 | |||
141 | for (index = 0; index < mci->nr_csrows; index++) { | ||
142 | csrow = &mci->csrows[index]; | ||
143 | |||
144 | pci_read_config_dword(pdev, | ||
145 | MCDRAM_RANKCFG + (index * 12), | ||
146 | &rankcfg); | ||
147 | |||
148 | if (!(rankcfg & MCDRAM_RANKCFG_EN)) | ||
149 | continue; | ||
150 | |||
151 | switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >> | ||
152 | MCDRAM_RANKCFG_TYPE_SIZE_S) { | ||
153 | case 0: | ||
154 | csrow->nr_pages = 128 << (20 - PAGE_SHIFT); | ||
155 | break; | ||
156 | case 1: | ||
157 | csrow->nr_pages = 256 << (20 - PAGE_SHIFT); | ||
158 | break; | ||
159 | case 2: | ||
160 | case 3: | ||
161 | csrow->nr_pages = 512 << (20 - PAGE_SHIFT); | ||
162 | break; | ||
163 | case 4: | ||
164 | csrow->nr_pages = 1024 << (20 - PAGE_SHIFT); | ||
165 | break; | ||
166 | case 5: | ||
167 | csrow->nr_pages = 2048 << (20 - PAGE_SHIFT); | ||
168 | break; | ||
169 | default: | ||
170 | edac_mc_printk(mci, KERN_ERR, | ||
171 | "Unrecognized Rank Config. rankcfg=%u\n", | ||
172 | rankcfg); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | csrow->first_page = last_page_in_mmc; | ||
177 | csrow->last_page = csrow->first_page + csrow->nr_pages - 1; | ||
178 | last_page_in_mmc += csrow->nr_pages; | ||
179 | csrow->page_mask = 0; | ||
180 | csrow->grain = PASEMI_EDAC_ERROR_GRAIN; | ||
181 | csrow->mtype = MEM_DDR; | ||
182 | csrow->dtype = DEV_UNKNOWN; | ||
183 | csrow->edac_mode = edac_mode; | ||
184 | } | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int __devinit pasemi_edac_probe(struct pci_dev *pdev, | ||
189 | const struct pci_device_id *ent) | ||
190 | { | ||
191 | struct mem_ctl_info *mci = NULL; | ||
192 | u32 errctl1, errcor, scrub, mcen; | ||
193 | |||
194 | pci_read_config_dword(pdev, MCCFG_MCEN, &mcen); | ||
195 | if (!(mcen & MCCFG_MCEN_MMC_EN)) | ||
196 | return -ENODEV; | ||
197 | |||
198 | /* | ||
199 | * We should think about enabling other error detection later on | ||
200 | */ | ||
201 | |||
202 | pci_read_config_dword(pdev, MCDEBUG_ERRCTL1, &errctl1); | ||
203 | errctl1 |= MCDEBUG_ERRCTL1_SBE_LOG_EN | | ||
204 | MCDEBUG_ERRCTL1_MBE_LOG_EN | | ||
205 | MCDEBUG_ERRCTL1_RFL_LOG_EN; | ||
206 | pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1); | ||
207 | |||
208 | mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS, | ||
209 | system_mmc_id++); | ||
210 | |||
211 | if (mci == NULL) | ||
212 | return -ENOMEM; | ||
213 | |||
214 | pci_read_config_dword(pdev, MCCFG_ERRCOR, &errcor); | ||
215 | errcor |= MCCFG_ERRCOR_RNK_FAIL_DET_EN | | ||
216 | MCCFG_ERRCOR_ECC_GEN_EN | | ||
217 | MCCFG_ERRCOR_ECC_CRR_EN; | ||
218 | |||
219 | mci->dev = &pdev->dev; | ||
220 | mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR; | ||
221 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | ||
222 | mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ? | ||
223 | ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? | ||
224 | (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_EC) : | ||
225 | EDAC_FLAG_NONE; | ||
226 | mci->mod_name = MODULE_NAME; | ||
227 | mci->dev_name = pci_name(pdev); | ||
228 | mci->ctl_name = "pasemi,1682m-mc"; | ||
229 | mci->edac_check = pasemi_edac_check; | ||
230 | mci->ctl_page_to_phys = NULL; | ||
231 | pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub); | ||
232 | mci->scrub_cap = SCRUB_FLAG_HW_PROG | SCRUB_FLAG_HW_SRC; | ||
233 | mci->scrub_mode = | ||
234 | ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? SCRUB_FLAG_HW_SRC : 0) | | ||
235 | ((scrub & MCCFG_SCRUB_RGLR_SCRB_EN) ? SCRUB_FLAG_HW_PROG : 0); | ||
236 | |||
237 | if (pasemi_edac_init_csrows(mci, pdev, | ||
238 | (mci->edac_cap & EDAC_FLAG_SECDED) ? | ||
239 | EDAC_SECDED : | ||
240 | ((mci->edac_cap & EDAC_FLAG_EC) ? | ||
241 | EDAC_EC : EDAC_NONE))) | ||
242 | goto fail; | ||
243 | |||
244 | /* | ||
245 | * Clear status | ||
246 | */ | ||
247 | pasemi_edac_get_error_info(mci); | ||
248 | |||
249 | if (edac_mc_add_mc(mci)) | ||
250 | goto fail; | ||
251 | |||
252 | /* get this far and it's successful */ | ||
253 | return 0; | ||
254 | |||
255 | fail: | ||
256 | edac_mc_free(mci); | ||
257 | return -ENODEV; | ||
258 | } | ||
259 | |||
260 | static void __devexit pasemi_edac_remove(struct pci_dev *pdev) | ||
261 | { | ||
262 | struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev); | ||
263 | |||
264 | if (!mci) | ||
265 | return; | ||
266 | |||
267 | edac_mc_free(mci); | ||
268 | } | ||
269 | |||
270 | |||
271 | static const struct pci_device_id pasemi_edac_pci_tbl[] = { | ||
272 | { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) }, | ||
273 | }; | ||
274 | |||
275 | MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl); | ||
276 | |||
277 | static struct pci_driver pasemi_edac_driver = { | ||
278 | .name = MODULE_NAME, | ||
279 | .probe = pasemi_edac_probe, | ||
280 | .remove = __devexit_p(pasemi_edac_remove), | ||
281 | .id_table = pasemi_edac_pci_tbl, | ||
282 | }; | ||
283 | |||
284 | static int __init pasemi_edac_init(void) | ||
285 | { | ||
286 | return pci_register_driver(&pasemi_edac_driver); | ||
287 | } | ||
288 | |||
289 | static void __exit pasemi_edac_exit(void) | ||
290 | { | ||
291 | pci_unregister_driver(&pasemi_edac_driver); | ||
292 | } | ||
293 | |||
294 | module_init(pasemi_edac_init); | ||
295 | module_exit(pasemi_edac_exit); | ||
296 | |||
297 | MODULE_LICENSE("GPL"); | ||
298 | MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); | ||
299 | MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller"); | ||
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index a49cf0a39398..e25f712f2dc3 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | * Written with reference to 82600 High Integration Dual PCI System | 12 | * Written with reference to 82600 High Integration Dual PCI System |
13 | * Controller Data Book: | 13 | * Controller Data Book: |
14 | * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf | 14 | * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf |
15 | * references to this document given in [] | 15 | * references to this document given in [] |
16 | */ | 16 | */ |
17 | 17 | ||
@@ -20,9 +20,9 @@ | |||
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/pci_ids.h> | 21 | #include <linux/pci_ids.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include "edac_mc.h" | 23 | #include "edac_core.h" |
24 | 24 | ||
25 | #define R82600_REVISION " Ver: 2.0.1 " __DATE__ | 25 | #define R82600_REVISION " Ver: 2.0.2 " __DATE__ |
26 | #define EDAC_MOD_STR "r82600_edac" | 26 | #define EDAC_MOD_STR "r82600_edac" |
27 | 27 | ||
28 | #define r82600_printk(level, fmt, arg...) \ | 28 | #define r82600_printk(level, fmt, arg...) \ |
@@ -131,10 +131,12 @@ struct r82600_error_info { | |||
131 | u32 eapr; | 131 | u32 eapr; |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static unsigned int disable_hardware_scrub = 0; | 134 | static unsigned int disable_hardware_scrub; |
135 | 135 | ||
136 | static void r82600_get_error_info (struct mem_ctl_info *mci, | 136 | static struct edac_pci_ctl_info *r82600_pci; |
137 | struct r82600_error_info *info) | 137 | |
138 | static void r82600_get_error_info(struct mem_ctl_info *mci, | ||
139 | struct r82600_error_info *info) | ||
138 | { | 140 | { |
139 | struct pci_dev *pdev; | 141 | struct pci_dev *pdev; |
140 | 142 | ||
@@ -144,18 +146,19 @@ static void r82600_get_error_info (struct mem_ctl_info *mci, | |||
144 | if (info->eapr & BIT(0)) | 146 | if (info->eapr & BIT(0)) |
145 | /* Clear error to allow next error to be reported [p.62] */ | 147 | /* Clear error to allow next error to be reported [p.62] */ |
146 | pci_write_bits32(pdev, R82600_EAP, | 148 | pci_write_bits32(pdev, R82600_EAP, |
147 | ((u32) BIT(0) & (u32) BIT(1)), | 149 | ((u32) BIT(0) & (u32) BIT(1)), |
148 | ((u32) BIT(0) & (u32) BIT(1))); | 150 | ((u32) BIT(0) & (u32) BIT(1))); |
149 | 151 | ||
150 | if (info->eapr & BIT(1)) | 152 | if (info->eapr & BIT(1)) |
151 | /* Clear error to allow next error to be reported [p.62] */ | 153 | /* Clear error to allow next error to be reported [p.62] */ |
152 | pci_write_bits32(pdev, R82600_EAP, | 154 | pci_write_bits32(pdev, R82600_EAP, |
153 | ((u32) BIT(0) & (u32) BIT(1)), | 155 | ((u32) BIT(0) & (u32) BIT(1)), |
154 | ((u32) BIT(0) & (u32) BIT(1))); | 156 | ((u32) BIT(0) & (u32) BIT(1))); |
155 | } | 157 | } |
156 | 158 | ||
157 | static int r82600_process_error_info (struct mem_ctl_info *mci, | 159 | static int r82600_process_error_info(struct mem_ctl_info *mci, |
158 | struct r82600_error_info *info, int handle_errors) | 160 | struct r82600_error_info *info, |
161 | int handle_errors) | ||
159 | { | 162 | { |
160 | int error_found; | 163 | int error_found; |
161 | u32 eapaddr, page; | 164 | u32 eapaddr, page; |
@@ -172,25 +175,24 @@ static int r82600_process_error_info (struct mem_ctl_info *mci, | |||
172 | * granularity (upper 19 bits only) */ | 175 | * granularity (upper 19 bits only) */ |
173 | page = eapaddr >> PAGE_SHIFT; | 176 | page = eapaddr >> PAGE_SHIFT; |
174 | 177 | ||
175 | if (info->eapr & BIT(0)) { /* CE? */ | 178 | if (info->eapr & BIT(0)) { /* CE? */ |
176 | error_found = 1; | 179 | error_found = 1; |
177 | 180 | ||
178 | if (handle_errors) | 181 | if (handle_errors) |
179 | edac_mc_handle_ce(mci, page, 0, /* not avail */ | 182 | edac_mc_handle_ce(mci, page, 0, /* not avail */ |
180 | syndrome, | 183 | syndrome, |
181 | edac_mc_find_csrow_by_page(mci, page), | 184 | edac_mc_find_csrow_by_page(mci, page), |
182 | 0, /* channel */ | 185 | 0, mci->ctl_name); |
183 | mci->ctl_name); | ||
184 | } | 186 | } |
185 | 187 | ||
186 | if (info->eapr & BIT(1)) { /* UE? */ | 188 | if (info->eapr & BIT(1)) { /* UE? */ |
187 | error_found = 1; | 189 | error_found = 1; |
188 | 190 | ||
189 | if (handle_errors) | 191 | if (handle_errors) |
190 | /* 82600 doesn't give enough info */ | 192 | /* 82600 doesn't give enough info */ |
191 | edac_mc_handle_ue(mci, page, 0, | 193 | edac_mc_handle_ue(mci, page, 0, |
192 | edac_mc_find_csrow_by_page(mci, page), | 194 | edac_mc_find_csrow_by_page(mci, page), |
193 | mci->ctl_name); | 195 | mci->ctl_name); |
194 | } | 196 | } |
195 | 197 | ||
196 | return error_found; | 198 | return error_found; |
@@ -211,11 +213,11 @@ static inline int ecc_enabled(u8 dramcr) | |||
211 | } | 213 | } |
212 | 214 | ||
213 | static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | 215 | static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
214 | u8 dramcr) | 216 | u8 dramcr) |
215 | { | 217 | { |
216 | struct csrow_info *csrow; | 218 | struct csrow_info *csrow; |
217 | int index; | 219 | int index; |
218 | u8 drbar; /* SDRAM Row Boundry Address Register */ | 220 | u8 drbar; /* SDRAM Row Boundry Address Register */ |
219 | u32 row_high_limit, row_high_limit_last; | 221 | u32 row_high_limit, row_high_limit_last; |
220 | u32 reg_sdram, ecc_on, row_base; | 222 | u32 reg_sdram, ecc_on, row_base; |
221 | 223 | ||
@@ -276,7 +278,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
276 | debugf2("%s(): sdram refresh rate = %#0x\n", __func__, | 278 | debugf2("%s(): sdram refresh rate = %#0x\n", __func__, |
277 | sdram_refresh_rate); | 279 | sdram_refresh_rate); |
278 | debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); | 280 | debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); |
279 | mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); | 281 | mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0); |
280 | 282 | ||
281 | if (mci == NULL) | 283 | if (mci == NULL) |
282 | return -ENOMEM; | 284 | return -ENOMEM; |
@@ -305,15 +307,16 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
305 | mci->mod_name = EDAC_MOD_STR; | 307 | mci->mod_name = EDAC_MOD_STR; |
306 | mci->mod_ver = R82600_REVISION; | 308 | mci->mod_ver = R82600_REVISION; |
307 | mci->ctl_name = "R82600"; | 309 | mci->ctl_name = "R82600"; |
310 | mci->dev_name = pci_name(pdev); | ||
308 | mci->edac_check = r82600_check; | 311 | mci->edac_check = r82600_check; |
309 | mci->ctl_page_to_phys = NULL; | 312 | mci->ctl_page_to_phys = NULL; |
310 | r82600_init_csrows(mci, pdev, dramcr); | 313 | r82600_init_csrows(mci, pdev, dramcr); |
311 | r82600_get_error_info(mci, &discard); /* clear counters */ | 314 | r82600_get_error_info(mci, &discard); /* clear counters */ |
312 | 315 | ||
313 | /* Here we assume that we will never see multiple instances of this | 316 | /* Here we assume that we will never see multiple instances of this |
314 | * type of memory controller. The ID is therefore hardcoded to 0. | 317 | * type of memory controller. The ID is therefore hardcoded to 0. |
315 | */ | 318 | */ |
316 | if (edac_mc_add_mc(mci,0)) { | 319 | if (edac_mc_add_mc(mci)) { |
317 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 320 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
318 | goto fail; | 321 | goto fail; |
319 | } | 322 | } |
@@ -326,6 +329,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
326 | pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); | 329 | pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); |
327 | } | 330 | } |
328 | 331 | ||
332 | /* allocating generic PCI control info */ | ||
333 | r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | ||
334 | if (!r82600_pci) { | ||
335 | printk(KERN_WARNING | ||
336 | "%s(): Unable to create PCI control\n", | ||
337 | __func__); | ||
338 | printk(KERN_WARNING | ||
339 | "%s(): PCI error report via EDAC not setup\n", | ||
340 | __func__); | ||
341 | } | ||
342 | |||
329 | debugf3("%s(): success\n", __func__); | 343 | debugf3("%s(): success\n", __func__); |
330 | return 0; | 344 | return 0; |
331 | 345 | ||
@@ -336,7 +350,7 @@ fail: | |||
336 | 350 | ||
337 | /* returns count (>= 0), or negative on error */ | 351 | /* returns count (>= 0), or negative on error */ |
338 | static int __devinit r82600_init_one(struct pci_dev *pdev, | 352 | static int __devinit r82600_init_one(struct pci_dev *pdev, |
339 | const struct pci_device_id *ent) | 353 | const struct pci_device_id *ent) |
340 | { | 354 | { |
341 | debugf0("%s()\n", __func__); | 355 | debugf0("%s()\n", __func__); |
342 | 356 | ||
@@ -350,6 +364,9 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev) | |||
350 | 364 | ||
351 | debugf0("%s()\n", __func__); | 365 | debugf0("%s()\n", __func__); |
352 | 366 | ||
367 | if (r82600_pci) | ||
368 | edac_pci_release_generic_ctl(r82600_pci); | ||
369 | |||
353 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) | 370 | if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
354 | return; | 371 | return; |
355 | 372 | ||
@@ -358,11 +375,11 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev) | |||
358 | 375 | ||
359 | static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { | 376 | static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { |
360 | { | 377 | { |
361 | PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) | 378 | PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) |
362 | }, | 379 | }, |
363 | { | 380 | { |
364 | 0, | 381 | 0, |
365 | } /* 0 terminated list. */ | 382 | } /* 0 terminated list. */ |
366 | }; | 383 | }; |
367 | 384 | ||
368 | MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); | 385 | MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); |
@@ -389,7 +406,7 @@ module_exit(r82600_exit); | |||
389 | 406 | ||
390 | MODULE_LICENSE("GPL"); | 407 | MODULE_LICENSE("GPL"); |
391 | MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " | 408 | MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " |
392 | "on behalf of EADS Astrium"); | 409 | "on behalf of EADS Astrium"); |
393 | MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); | 410 | MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); |
394 | 411 | ||
395 | module_param(disable_hardware_scrub, bool, 0644); | 412 | module_param(disable_hardware_scrub, bool, 0644); |
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 41476abc0693..db703758db98 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr, | |||
224 | u32 val, old; | 224 | u32 val, old; |
225 | 225 | ||
226 | reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); | 226 | reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); |
227 | flush_writes(ohci); | ||
227 | msleep(2); | 228 | msleep(2); |
228 | val = reg_read(ohci, OHCI1394_PhyControl); | 229 | val = reg_read(ohci, OHCI1394_PhyControl); |
229 | if ((val & OHCI1394_PhyControl_ReadDone) == 0) { | 230 | if ((val & OHCI1394_PhyControl_ReadDone) == 0) { |
@@ -586,7 +587,7 @@ static void context_stop(struct context *ctx) | |||
586 | break; | 587 | break; |
587 | 588 | ||
588 | fw_notify("context_stop: still active (0x%08x)\n", reg); | 589 | fw_notify("context_stop: still active (0x%08x)\n", reg); |
589 | msleep(1); | 590 | mdelay(1); |
590 | } | 591 | } |
591 | } | 592 | } |
592 | 593 | ||
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 7c53be0387fb..fc984474162c 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -840,7 +840,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
840 | container_of(base_orb, struct sbp2_command_orb, base); | 840 | container_of(base_orb, struct sbp2_command_orb, base); |
841 | struct fw_unit *unit = orb->unit; | 841 | struct fw_unit *unit = orb->unit; |
842 | struct fw_device *device = fw_device(unit->device.parent); | 842 | struct fw_device *device = fw_device(unit->device.parent); |
843 | struct scatterlist *sg; | ||
844 | int result; | 843 | int result; |
845 | 844 | ||
846 | if (status != NULL) { | 845 | if (status != NULL) { |
@@ -876,11 +875,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
876 | dma_unmap_single(device->card->device, orb->base.request_bus, | 875 | dma_unmap_single(device->card->device, orb->base.request_bus, |
877 | sizeof(orb->request), DMA_TO_DEVICE); | 876 | sizeof(orb->request), DMA_TO_DEVICE); |
878 | 877 | ||
879 | if (orb->cmd->use_sg > 0) { | 878 | if (scsi_sg_count(orb->cmd) > 0) |
880 | sg = (struct scatterlist *)orb->cmd->request_buffer; | 879 | dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd), |
881 | dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, | 880 | scsi_sg_count(orb->cmd), |
882 | orb->cmd->sc_data_direction); | 881 | orb->cmd->sc_data_direction); |
883 | } | ||
884 | 882 | ||
885 | if (orb->page_table_bus != 0) | 883 | if (orb->page_table_bus != 0) |
886 | dma_unmap_single(device->card->device, orb->page_table_bus, | 884 | dma_unmap_single(device->card->device, orb->page_table_bus, |
@@ -901,8 +899,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) | |||
901 | int sg_len, l, i, j, count; | 899 | int sg_len, l, i, j, count; |
902 | dma_addr_t sg_addr; | 900 | dma_addr_t sg_addr; |
903 | 901 | ||
904 | sg = (struct scatterlist *)orb->cmd->request_buffer; | 902 | sg = scsi_sglist(orb->cmd); |
905 | count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg, | 903 | count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd), |
906 | orb->cmd->sc_data_direction); | 904 | orb->cmd->sc_data_direction); |
907 | if (count == 0) | 905 | if (count == 0) |
908 | goto fail; | 906 | goto fail; |
@@ -971,7 +969,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) | |||
971 | return 0; | 969 | return 0; |
972 | 970 | ||
973 | fail_page_table: | 971 | fail_page_table: |
974 | dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg, | 972 | dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd), |
975 | orb->cmd->sc_data_direction); | 973 | orb->cmd->sc_data_direction); |
976 | fail: | 974 | fail: |
977 | return -ENOMEM; | 975 | return -ENOMEM; |
@@ -1031,7 +1029,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
1031 | orb->request.misc |= | 1029 | orb->request.misc |= |
1032 | COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); | 1030 | COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); |
1033 | 1031 | ||
1034 | if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0) | 1032 | if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0) |
1035 | goto fail_mapping; | 1033 | goto fail_mapping; |
1036 | 1034 | ||
1037 | fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); | 1035 | fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); |
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 80d0121463d0..3ce8e2fbe15f 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) | |||
605 | * check is sufficient to ensure we don't send response to | 605 | * check is sufficient to ensure we don't send response to |
606 | * broadcast packets or posted writes. | 606 | * broadcast packets or posted writes. |
607 | */ | 607 | */ |
608 | if (request->ack != ACK_PENDING) | 608 | if (request->ack != ACK_PENDING) { |
609 | kfree(request); | ||
609 | return; | 610 | return; |
611 | } | ||
610 | 612 | ||
611 | if (rcode == RCODE_COMPLETE) | 613 | if (rcode == RCODE_COMPLETE) |
612 | fw_fill_response(&request->response, request->request_header, | 614 | fw_fill_response(&request->response, request->request_header, |
@@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p) | |||
628 | unsigned long flags; | 630 | unsigned long flags; |
629 | int tcode, destination, source; | 631 | int tcode, destination, source; |
630 | 632 | ||
631 | if (p->payload_length > 2048) { | ||
632 | /* FIXME: send error response. */ | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) | 633 | if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) |
637 | return; | 634 | return; |
638 | 635 | ||
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 5abed193f4a6..5ceaccd10564 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
@@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode, | |||
123 | size_t length, | 123 | size_t length, |
124 | void *callback_data); | 124 | void *callback_data); |
125 | 125 | ||
126 | /* | ||
127 | * Important note: The callback must guarantee that either fw_send_response() | ||
128 | * or kfree() is called on the @request. | ||
129 | */ | ||
126 | typedef void (*fw_address_callback_t)(struct fw_card *card, | 130 | typedef void (*fw_address_callback_t)(struct fw_card *card, |
127 | struct fw_request *request, | 131 | struct fw_request *request, |
128 | int tcode, int destination, int source, | 132 | int tcode, int destination, int source, |
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index c5b5011da56e..f9de79844418 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
@@ -55,7 +55,7 @@ | |||
55 | #include <asm/bitops.h> | 55 | #include <asm/bitops.h> |
56 | 56 | ||
57 | static int __ide_end_request(ide_drive_t *drive, struct request *rq, | 57 | static int __ide_end_request(ide_drive_t *drive, struct request *rq, |
58 | int uptodate, int nr_sectors) | 58 | int uptodate, unsigned int nr_bytes) |
59 | { | 59 | { |
60 | int ret = 1; | 60 | int ret = 1; |
61 | 61 | ||
@@ -64,7 +64,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, | |||
64 | * complete the whole request right now | 64 | * complete the whole request right now |
65 | */ | 65 | */ |
66 | if (blk_noretry_request(rq) && end_io_error(uptodate)) | 66 | if (blk_noretry_request(rq) && end_io_error(uptodate)) |
67 | nr_sectors = rq->hard_nr_sectors; | 67 | nr_bytes = rq->hard_nr_sectors << 9; |
68 | 68 | ||
69 | if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) | 69 | if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) |
70 | rq->errors = -EIO; | 70 | rq->errors = -EIO; |
@@ -78,7 +78,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, | |||
78 | HWGROUP(drive)->hwif->ide_dma_on(drive); | 78 | HWGROUP(drive)->hwif->ide_dma_on(drive); |
79 | } | 79 | } |
80 | 80 | ||
81 | if (!end_that_request_first(rq, uptodate, nr_sectors)) { | 81 | if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { |
82 | add_disk_randomness(rq->rq_disk); | 82 | add_disk_randomness(rq->rq_disk); |
83 | if (!list_empty(&rq->queuelist)) | 83 | if (!list_empty(&rq->queuelist)) |
84 | blkdev_dequeue_request(rq); | 84 | blkdev_dequeue_request(rq); |
@@ -103,6 +103,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, | |||
103 | 103 | ||
104 | int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) | 104 | int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) |
105 | { | 105 | { |
106 | unsigned int nr_bytes = nr_sectors << 9; | ||
106 | struct request *rq; | 107 | struct request *rq; |
107 | unsigned long flags; | 108 | unsigned long flags; |
108 | int ret = 1; | 109 | int ret = 1; |
@@ -114,10 +115,14 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) | |||
114 | spin_lock_irqsave(&ide_lock, flags); | 115 | spin_lock_irqsave(&ide_lock, flags); |
115 | rq = HWGROUP(drive)->rq; | 116 | rq = HWGROUP(drive)->rq; |
116 | 117 | ||
117 | if (!nr_sectors) | 118 | if (!nr_bytes) { |
118 | nr_sectors = rq->hard_cur_sectors; | 119 | if (blk_pc_request(rq)) |
120 | nr_bytes = rq->data_len; | ||
121 | else | ||
122 | nr_bytes = rq->hard_cur_sectors << 9; | ||
123 | } | ||
119 | 124 | ||
120 | ret = __ide_end_request(drive, rq, uptodate, nr_sectors); | 125 | ret = __ide_end_request(drive, rq, uptodate, nr_bytes); |
121 | 126 | ||
122 | spin_unlock_irqrestore(&ide_lock, flags); | 127 | spin_unlock_irqrestore(&ide_lock, flags); |
123 | return ret; | 128 | return ret; |
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 6e935d7c63fd..c2e29571b007 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c | |||
@@ -165,12 +165,11 @@ static int __devinit swarm_ide_init_module(void) | |||
165 | goto out; | 165 | goto out; |
166 | } | 166 | } |
167 | 167 | ||
168 | if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) { | 168 | if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) { |
169 | err = -ENOMEM; | 169 | err = -ENOMEM; |
170 | goto out_unregister_driver; | 170 | goto out_unregister_driver; |
171 | } | 171 | } |
172 | 172 | ||
173 | memset (pldev, 0, sizeof (*pldev)); | ||
174 | pldev->name = swarm_ide_string; | 173 | pldev->name = swarm_ide_string; |
175 | pldev->id = 0; | 174 | pldev->id = 0; |
176 | pldev->dev.release = swarm_ide_platform_release; | 175 | pldev->dev.release = swarm_ide_platform_release; |
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index a91001c59b69..c5c33d35f87d 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c | |||
@@ -295,10 +295,9 @@ int rdma_resolve_ip(struct rdma_addr_client *client, | |||
295 | struct addr_req *req; | 295 | struct addr_req *req; |
296 | int ret = 0; | 296 | int ret = 0; |
297 | 297 | ||
298 | req = kmalloc(sizeof *req, GFP_KERNEL); | 298 | req = kzalloc(sizeof *req, GFP_KERNEL); |
299 | if (!req) | 299 | if (!req) |
300 | return -ENOMEM; | 300 | return -ENOMEM; |
301 | memset(req, 0, sizeof *req); | ||
302 | 301 | ||
303 | if (src_addr) | 302 | if (src_addr) |
304 | memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); | 303 | memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); |
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 9820c67ba47d..4df269f5d9ac 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -3374,7 +3374,7 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id, | |||
3374 | } | 3374 | } |
3375 | EXPORT_SYMBOL(ib_cm_init_qp_attr); | 3375 | EXPORT_SYMBOL(ib_cm_init_qp_attr); |
3376 | 3376 | ||
3377 | void cm_get_ack_delay(struct cm_device *cm_dev) | 3377 | static void cm_get_ack_delay(struct cm_device *cm_dev) |
3378 | { | 3378 | { |
3379 | struct ib_device_attr attr; | 3379 | struct ib_device_attr attr; |
3380 | 3380 | ||
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 23af7a032a03..9ffb9987450a 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c | |||
@@ -573,7 +573,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, | |||
573 | break; | 573 | break; |
574 | case RDMA_TRANSPORT_IWARP: | 574 | case RDMA_TRANSPORT_IWARP: |
575 | if (!id_priv->cm_id.iw) { | 575 | if (!id_priv->cm_id.iw) { |
576 | qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; | 576 | qp_attr->qp_access_flags = 0; |
577 | *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; | 577 | *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; |
578 | } else | 578 | } else |
579 | ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, | 579 | ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3b41dc0c39dd..9574088f0d4e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c | |||
@@ -229,9 +229,8 @@ static void *alloc_ep(int size, gfp_t gfp) | |||
229 | { | 229 | { |
230 | struct iwch_ep_common *epc; | 230 | struct iwch_ep_common *epc; |
231 | 231 | ||
232 | epc = kmalloc(size, gfp); | 232 | epc = kzalloc(size, gfp); |
233 | if (epc) { | 233 | if (epc) { |
234 | memset(epc, 0, size); | ||
235 | kref_init(&epc->kref); | 234 | kref_init(&epc->kref); |
236 | spin_lock_init(&epc->lock); | 235 | spin_lock_init(&epc->lock); |
237 | init_waitqueue_head(&epc->waitq); | 236 | init_waitqueue_head(&epc->waitq); |
@@ -1914,6 +1913,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog) | |||
1914 | fail3: | 1913 | fail3: |
1915 | cxgb3_free_stid(ep->com.tdev, ep->stid); | 1914 | cxgb3_free_stid(ep->com.tdev, ep->stid); |
1916 | fail2: | 1915 | fail2: |
1916 | cm_id->rem_ref(cm_id); | ||
1917 | put_ep(&ep->com); | 1917 | put_ep(&ep->com); |
1918 | fail1: | 1918 | fail1: |
1919 | out: | 1919 | out: |
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c index 3cd6bf3402d1..e53a97af1260 100644 --- a/drivers/infiniband/hw/ehca/ehca_av.c +++ b/drivers/infiniband/hw/ehca/ehca_av.c | |||
@@ -79,7 +79,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | |||
79 | av->av.ipd = (ah_mult > 0) ? | 79 | av->av.ipd = (ah_mult > 0) ? |
80 | ((ehca_mult - 1) / ah_mult) : 0; | 80 | ((ehca_mult - 1) / ah_mult) : 0; |
81 | } else | 81 | } else |
82 | av->av.ipd = ehca_static_rate; | 82 | av->av.ipd = ehca_static_rate; |
83 | 83 | ||
84 | av->av.lnh = ah_attr->ah_flags; | 84 | av->av.lnh = ah_attr->ah_flags; |
85 | av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6); | 85 | av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6); |
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index daf823ea1ace..043e4fb23fb0 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
@@ -204,11 +204,11 @@ struct ehca_mr { | |||
204 | spinlock_t mrlock; | 204 | spinlock_t mrlock; |
205 | 205 | ||
206 | enum ehca_mr_flag flags; | 206 | enum ehca_mr_flag flags; |
207 | u32 num_pages; /* number of MR pages */ | 207 | u32 num_kpages; /* number of kernel pages */ |
208 | u32 num_4k; /* number of 4k "page" portions to form MR */ | 208 | u32 num_hwpages; /* number of hw pages to form MR */ |
209 | int acl; /* ACL (stored here for usage in reregister) */ | 209 | int acl; /* ACL (stored here for usage in reregister) */ |
210 | u64 *start; /* virtual start address (stored here for */ | 210 | u64 *start; /* virtual start address (stored here for */ |
211 | /* usage in reregister) */ | 211 | /* usage in reregister) */ |
212 | u64 size; /* size (stored here for usage in reregister) */ | 212 | u64 size; /* size (stored here for usage in reregister) */ |
213 | u32 fmr_page_size; /* page size for FMR */ | 213 | u32 fmr_page_size; /* page size for FMR */ |
214 | u32 fmr_max_pages; /* max pages for FMR */ | 214 | u32 fmr_max_pages; /* max pages for FMR */ |
@@ -217,9 +217,6 @@ struct ehca_mr { | |||
217 | /* fw specific data */ | 217 | /* fw specific data */ |
218 | struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */ | 218 | struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */ |
219 | struct h_galpas galpas; | 219 | struct h_galpas galpas; |
220 | /* data for userspace bridge */ | ||
221 | u32 nr_of_pages; | ||
222 | void *pagearray; | ||
223 | }; | 220 | }; |
224 | 221 | ||
225 | struct ehca_mw { | 222 | struct ehca_mw { |
@@ -241,26 +238,29 @@ enum ehca_mr_pgi_type { | |||
241 | 238 | ||
242 | struct ehca_mr_pginfo { | 239 | struct ehca_mr_pginfo { |
243 | enum ehca_mr_pgi_type type; | 240 | enum ehca_mr_pgi_type type; |
244 | u64 num_pages; | 241 | u64 num_kpages; |
245 | u64 page_cnt; | 242 | u64 kpage_cnt; |
246 | u64 num_4k; /* number of 4k "page" portions */ | 243 | u64 num_hwpages; /* number of hw pages */ |
247 | u64 page_4k_cnt; /* counter for 4k "page" portions */ | 244 | u64 hwpage_cnt; /* counter for hw pages */ |
248 | u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */ | 245 | u64 next_hwpage; /* next hw page in buffer/chunk/listelem */ |
249 | 246 | ||
250 | /* type EHCA_MR_PGI_PHYS section */ | 247 | union { |
251 | int num_phys_buf; | 248 | struct { /* type EHCA_MR_PGI_PHYS section */ |
252 | struct ib_phys_buf *phys_buf_array; | 249 | int num_phys_buf; |
253 | u64 next_buf; | 250 | struct ib_phys_buf *phys_buf_array; |
254 | 251 | u64 next_buf; | |
255 | /* type EHCA_MR_PGI_USER section */ | 252 | } phy; |
256 | struct ib_umem *region; | 253 | struct { /* type EHCA_MR_PGI_USER section */ |
257 | struct ib_umem_chunk *next_chunk; | 254 | struct ib_umem *region; |
258 | u64 next_nmap; | 255 | struct ib_umem_chunk *next_chunk; |
259 | 256 | u64 next_nmap; | |
260 | /* type EHCA_MR_PGI_FMR section */ | 257 | } usr; |
261 | u64 *page_list; | 258 | struct { /* type EHCA_MR_PGI_FMR section */ |
262 | u64 next_listelem; | 259 | u64 fmr_pgsize; |
263 | /* next_4k also used within EHCA_MR_PGI_FMR */ | 260 | u64 *page_list; |
261 | u64 next_listelem; | ||
262 | } fmr; | ||
263 | } u; | ||
264 | }; | 264 | }; |
265 | 265 | ||
266 | /* output parameters for MR/FMR hipz calls */ | 266 | /* output parameters for MR/FMR hipz calls */ |
@@ -391,6 +391,6 @@ struct ehca_alloc_qp_parms { | |||
391 | 391 | ||
392 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp); | 392 | int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp); |
393 | int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num); | 393 | int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num); |
394 | struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num); | 394 | struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num); |
395 | 395 | ||
396 | #endif | 396 | #endif |
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h index fb3df5c271e7..1798e6466bd0 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h +++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h | |||
@@ -154,83 +154,83 @@ struct hcp_modify_qp_control_block { | |||
154 | u32 reserved_70_127[58]; /* 70 */ | 154 | u32 reserved_70_127[58]; /* 70 */ |
155 | }; | 155 | }; |
156 | 156 | ||
157 | #define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0) | 157 | #define MQPCB_MASK_QKEY EHCA_BMASK_IBM( 0, 0) |
158 | #define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2) | 158 | #define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM( 2, 2) |
159 | #define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3) | 159 | #define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM( 3, 3) |
160 | #define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4) | 160 | #define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM( 4, 4) |
161 | #define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31) | 161 | #define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24, 31) |
162 | #define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5) | 162 | #define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM( 5, 5) |
163 | #define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6) | 163 | #define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM( 6, 6) |
164 | #define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31) | 164 | #define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24, 31) |
165 | #define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7) | 165 | #define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM( 7, 7) |
166 | #define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8) | 166 | #define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM( 8, 8) |
167 | #define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9) | 167 | #define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM( 9, 9) |
168 | #define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31) | 168 | #define MQPCB_QP_STATE EHCA_BMASK_IBM(24, 31) |
169 | #define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11) | 169 | #define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11, 11) |
170 | #define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12) | 170 | #define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12, 12) |
171 | #define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13) | 171 | #define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13, 13) |
172 | #define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14) | 172 | #define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14, 14) |
173 | #define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15) | 173 | #define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15, 15) |
174 | #define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16) | 174 | #define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16, 16) |
175 | #define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17) | 175 | #define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17, 17) |
176 | #define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18) | 176 | #define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18, 18) |
177 | #define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19) | 177 | #define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19, 19) |
178 | #define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20) | 178 | #define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20, 20) |
179 | #define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31) | 179 | #define MQPCB_PATH_MTU EHCA_BMASK_IBM(24, 31) |
180 | #define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21) | 180 | #define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21, 21) |
181 | #define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31) | 181 | #define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24, 31) |
182 | #define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22) | 182 | #define MQPCB_MASK_DLID EHCA_BMASK_IBM(22, 22) |
183 | #define MQPCB_DLID EHCA_BMASK_IBM(16,31) | 183 | #define MQPCB_DLID EHCA_BMASK_IBM(16, 31) |
184 | #define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23) | 184 | #define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23, 23) |
185 | #define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31) | 185 | #define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29, 31) |
186 | #define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24) | 186 | #define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24, 24) |
187 | #define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31) | 187 | #define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25, 31) |
188 | #define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25) | 188 | #define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25, 25) |
189 | #define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31) | 189 | #define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24, 31) |
190 | #define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26) | 190 | #define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26, 26) |
191 | #define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31) | 191 | #define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24, 31) |
192 | #define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27) | 192 | #define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27, 27) |
193 | #define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31) | 193 | #define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24, 31) |
194 | #define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28) | 194 | #define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28, 28) |
195 | #define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31) | 195 | #define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12, 31) |
196 | #define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30) | 196 | #define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30, 30) |
197 | #define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31) | 197 | #define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31, 31) |
198 | #define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31) | 198 | #define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28, 31) |
199 | #define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32) | 199 | #define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32, 32) |
200 | #define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31) | 200 | #define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31, 31) |
201 | #define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33) | 201 | #define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33, 33) |
202 | #define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31) | 202 | #define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31) |
203 | #define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34) | 203 | #define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34, 34) |
204 | #define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31) | 204 | #define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27, 31) |
205 | #define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35) | 205 | #define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35, 35) |
206 | #define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31) | 206 | #define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24, 31) |
207 | #define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36) | 207 | #define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36, 36) |
208 | #define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31) | 208 | #define MQPCB_DLID_AL EHCA_BMASK_IBM(16, 31) |
209 | #define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37) | 209 | #define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37, 37) |
210 | #define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31) | 210 | #define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31) |
211 | #define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38) | 211 | #define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38, 38) |
212 | #define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31) | 212 | #define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25, 31) |
213 | #define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39) | 213 | #define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39, 39) |
214 | #define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31) | 214 | #define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24, 31) |
215 | #define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40) | 215 | #define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40, 40) |
216 | #define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31) | 216 | #define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24, 31) |
217 | #define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41) | 217 | #define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41, 41) |
218 | #define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31) | 218 | #define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24, 31) |
219 | #define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42) | 219 | #define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42, 42) |
220 | #define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31) | 220 | #define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12, 31) |
221 | #define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44) | 221 | #define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44, 44) |
222 | #define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45) | 222 | #define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45, 45) |
223 | #define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31) | 223 | #define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31) |
224 | #define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46) | 224 | #define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46, 46) |
225 | #define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31) | 225 | #define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31) |
226 | #define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47) | 226 | #define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47, 47) |
227 | #define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31) | 227 | #define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31, 31) |
228 | #define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31) | 228 | #define MQPCB_QP_NUMBER EHCA_BMASK_IBM( 8, 31) |
229 | #define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48) | 229 | #define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48, 48) |
230 | #define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31) | 230 | #define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31, 31) |
231 | #define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49,49) | 231 | #define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49, 49) |
232 | #define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16,31) | 232 | #define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16, 31) |
233 | #define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50) | 233 | #define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50, 50) |
234 | #define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51) | 234 | #define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51, 51) |
235 | 235 | ||
236 | #endif /* __EHCA_CLASSES_PSERIES_H__ */ | 236 | #endif /* __EHCA_CLASSES_PSERIES_H__ */ |
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 01d4a148bd71..9e87883b561a 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c | |||
@@ -97,7 +97,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num) | |||
97 | return ret; | 97 | return ret; |
98 | } | 98 | } |
99 | 99 | ||
100 | struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num) | 100 | struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num) |
101 | { | 101 | { |
102 | struct ehca_qp *ret = NULL; | 102 | struct ehca_qp *ret = NULL; |
103 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); | 103 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); |
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 4961eb88827c..4825975f88cf 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c | |||
@@ -96,7 +96,8 @@ int ehca_create_eq(struct ehca_shca *shca, | |||
96 | for (i = 0; i < nr_pages; i++) { | 96 | for (i = 0; i < nr_pages; i++) { |
97 | u64 rpage; | 97 | u64 rpage; |
98 | 98 | ||
99 | if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) { | 99 | vpage = ipz_qpageit_get_inc(&eq->ipz_queue); |
100 | if (!vpage) { | ||
100 | ret = H_RESOURCE; | 101 | ret = H_RESOURCE; |
101 | goto create_eq_exit2; | 102 | goto create_eq_exit2; |
102 | } | 103 | } |
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index bbd3c6a5822f..fc19ef9fd963 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c | |||
@@ -127,6 +127,7 @@ int ehca_query_port(struct ib_device *ibdev, | |||
127 | u8 port, struct ib_port_attr *props) | 127 | u8 port, struct ib_port_attr *props) |
128 | { | 128 | { |
129 | int ret = 0; | 129 | int ret = 0; |
130 | u64 h_ret; | ||
130 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, | 131 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, |
131 | ib_device); | 132 | ib_device); |
132 | struct hipz_query_port *rblock; | 133 | struct hipz_query_port *rblock; |
@@ -137,7 +138,8 @@ int ehca_query_port(struct ib_device *ibdev, | |||
137 | return -ENOMEM; | 138 | return -ENOMEM; |
138 | } | 139 | } |
139 | 140 | ||
140 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | 141 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock); |
142 | if (h_ret != H_SUCCESS) { | ||
141 | ehca_err(&shca->ib_device, "Can't query port properties"); | 143 | ehca_err(&shca->ib_device, "Can't query port properties"); |
142 | ret = -EINVAL; | 144 | ret = -EINVAL; |
143 | goto query_port1; | 145 | goto query_port1; |
@@ -197,6 +199,7 @@ int ehca_query_sma_attr(struct ehca_shca *shca, | |||
197 | u8 port, struct ehca_sma_attr *attr) | 199 | u8 port, struct ehca_sma_attr *attr) |
198 | { | 200 | { |
199 | int ret = 0; | 201 | int ret = 0; |
202 | u64 h_ret; | ||
200 | struct hipz_query_port *rblock; | 203 | struct hipz_query_port *rblock; |
201 | 204 | ||
202 | rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); | 205 | rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); |
@@ -205,7 +208,8 @@ int ehca_query_sma_attr(struct ehca_shca *shca, | |||
205 | return -ENOMEM; | 208 | return -ENOMEM; |
206 | } | 209 | } |
207 | 210 | ||
208 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | 211 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock); |
212 | if (h_ret != H_SUCCESS) { | ||
209 | ehca_err(&shca->ib_device, "Can't query port properties"); | 213 | ehca_err(&shca->ib_device, "Can't query port properties"); |
210 | ret = -EINVAL; | 214 | ret = -EINVAL; |
211 | goto query_sma_attr1; | 215 | goto query_sma_attr1; |
@@ -230,9 +234,11 @@ query_sma_attr1: | |||
230 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) | 234 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) |
231 | { | 235 | { |
232 | int ret = 0; | 236 | int ret = 0; |
233 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); | 237 | u64 h_ret; |
238 | struct ehca_shca *shca; | ||
234 | struct hipz_query_port *rblock; | 239 | struct hipz_query_port *rblock; |
235 | 240 | ||
241 | shca = container_of(ibdev, struct ehca_shca, ib_device); | ||
236 | if (index > 16) { | 242 | if (index > 16) { |
237 | ehca_err(&shca->ib_device, "Invalid index: %x.", index); | 243 | ehca_err(&shca->ib_device, "Invalid index: %x.", index); |
238 | return -EINVAL; | 244 | return -EINVAL; |
@@ -244,7 +250,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) | |||
244 | return -ENOMEM; | 250 | return -ENOMEM; |
245 | } | 251 | } |
246 | 252 | ||
247 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | 253 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock); |
254 | if (h_ret != H_SUCCESS) { | ||
248 | ehca_err(&shca->ib_device, "Can't query port properties"); | 255 | ehca_err(&shca->ib_device, "Can't query port properties"); |
249 | ret = -EINVAL; | 256 | ret = -EINVAL; |
250 | goto query_pkey1; | 257 | goto query_pkey1; |
@@ -262,6 +269,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, | |||
262 | int index, union ib_gid *gid) | 269 | int index, union ib_gid *gid) |
263 | { | 270 | { |
264 | int ret = 0; | 271 | int ret = 0; |
272 | u64 h_ret; | ||
265 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, | 273 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, |
266 | ib_device); | 274 | ib_device); |
267 | struct hipz_query_port *rblock; | 275 | struct hipz_query_port *rblock; |
@@ -277,7 +285,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, | |||
277 | return -ENOMEM; | 285 | return -ENOMEM; |
278 | } | 286 | } |
279 | 287 | ||
280 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | 288 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock); |
289 | if (h_ret != H_SUCCESS) { | ||
281 | ehca_err(&shca->ib_device, "Can't query port properties"); | 290 | ehca_err(&shca->ib_device, "Can't query port properties"); |
282 | ret = -EINVAL; | 291 | ret = -EINVAL; |
283 | goto query_gid1; | 292 | goto query_gid1; |
@@ -302,11 +311,12 @@ int ehca_modify_port(struct ib_device *ibdev, | |||
302 | struct ib_port_modify *props) | 311 | struct ib_port_modify *props) |
303 | { | 312 | { |
304 | int ret = 0; | 313 | int ret = 0; |
305 | struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); | 314 | struct ehca_shca *shca; |
306 | struct hipz_query_port *rblock; | 315 | struct hipz_query_port *rblock; |
307 | u32 cap; | 316 | u32 cap; |
308 | u64 hret; | 317 | u64 hret; |
309 | 318 | ||
319 | shca = container_of(ibdev, struct ehca_shca, ib_device); | ||
310 | if ((props->set_port_cap_mask | props->clr_port_cap_mask) | 320 | if ((props->set_port_cap_mask | props->clr_port_cap_mask) |
311 | & ~allowed_port_caps) { | 321 | & ~allowed_port_caps) { |
312 | ehca_err(&shca->ib_device, "Non-changeable bits set in masks " | 322 | ehca_err(&shca->ib_device, "Non-changeable bits set in masks " |
@@ -325,7 +335,8 @@ int ehca_modify_port(struct ib_device *ibdev, | |||
325 | goto modify_port1; | 335 | goto modify_port1; |
326 | } | 336 | } |
327 | 337 | ||
328 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | 338 | hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock); |
339 | if (hret != H_SUCCESS) { | ||
329 | ehca_err(&shca->ib_device, "Can't query port properties"); | 340 | ehca_err(&shca->ib_device, "Can't query port properties"); |
330 | ret = -EINVAL; | 341 | ret = -EINVAL; |
331 | goto modify_port2; | 342 | goto modify_port2; |
@@ -337,7 +348,8 @@ int ehca_modify_port(struct ib_device *ibdev, | |||
337 | hret = hipz_h_modify_port(shca->ipz_hca_handle, port, | 348 | hret = hipz_h_modify_port(shca->ipz_hca_handle, port, |
338 | cap, props->init_type, port_modify_mask); | 349 | cap, props->init_type, port_modify_mask); |
339 | if (hret != H_SUCCESS) { | 350 | if (hret != H_SUCCESS) { |
340 | ehca_err(&shca->ib_device, "Modify port failed hret=%lx", hret); | 351 | ehca_err(&shca->ib_device, "Modify port failed hret=%lx", |
352 | hret); | ||
341 | ret = -EINVAL; | 353 | ret = -EINVAL; |
342 | } | 354 | } |
343 | 355 | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 96eba3830754..4fb01fcb63ae 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c | |||
@@ -49,26 +49,26 @@ | |||
49 | #include "hipz_fns.h" | 49 | #include "hipz_fns.h" |
50 | #include "ipz_pt_fn.h" | 50 | #include "ipz_pt_fn.h" |
51 | 51 | ||
52 | #define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1) | 52 | #define EQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1) |
53 | #define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31) | 53 | #define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM( 8, 31) |
54 | #define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7) | 54 | #define EQE_EE_IDENTIFIER EHCA_BMASK_IBM( 2, 7) |
55 | #define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31) | 55 | #define EQE_CQ_NUMBER EHCA_BMASK_IBM( 8, 31) |
56 | #define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31) | 56 | #define EQE_QP_NUMBER EHCA_BMASK_IBM( 8, 31) |
57 | #define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63) | 57 | #define EQE_QP_TOKEN EHCA_BMASK_IBM(32, 63) |
58 | #define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63) | 58 | #define EQE_CQ_TOKEN EHCA_BMASK_IBM(32, 63) |
59 | 59 | ||
60 | #define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1) | 60 | #define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1) |
61 | #define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) | 61 | #define NEQE_EVENT_CODE EHCA_BMASK_IBM( 2, 7) |
62 | #define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) | 62 | #define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15) |
63 | #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) | 63 | #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16) |
64 | #define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16,16) | 64 | #define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16) |
65 | 65 | ||
66 | #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) | 66 | #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63) |
67 | #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) | 67 | #define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7) |
68 | 68 | ||
69 | static void queue_comp_task(struct ehca_cq *__cq); | 69 | static void queue_comp_task(struct ehca_cq *__cq); |
70 | 70 | ||
71 | static struct ehca_comp_pool* pool; | 71 | static struct ehca_comp_pool *pool; |
72 | #ifdef CONFIG_HOTPLUG_CPU | 72 | #ifdef CONFIG_HOTPLUG_CPU |
73 | static struct notifier_block comp_pool_callback_nb; | 73 | static struct notifier_block comp_pool_callback_nb; |
74 | #endif | 74 | #endif |
@@ -85,8 +85,8 @@ static inline void comp_event_callback(struct ehca_cq *cq) | |||
85 | return; | 85 | return; |
86 | } | 86 | } |
87 | 87 | ||
88 | static void print_error_data(struct ehca_shca * shca, void* data, | 88 | static void print_error_data(struct ehca_shca *shca, void *data, |
89 | u64* rblock, int length) | 89 | u64 *rblock, int length) |
90 | { | 90 | { |
91 | u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]); | 91 | u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]); |
92 | u64 resource = rblock[1]; | 92 | u64 resource = rblock[1]; |
@@ -94,7 +94,7 @@ static void print_error_data(struct ehca_shca * shca, void* data, | |||
94 | switch (type) { | 94 | switch (type) { |
95 | case 0x1: /* Queue Pair */ | 95 | case 0x1: /* Queue Pair */ |
96 | { | 96 | { |
97 | struct ehca_qp *qp = (struct ehca_qp*)data; | 97 | struct ehca_qp *qp = (struct ehca_qp *)data; |
98 | 98 | ||
99 | /* only print error data if AER is set */ | 99 | /* only print error data if AER is set */ |
100 | if (rblock[6] == 0) | 100 | if (rblock[6] == 0) |
@@ -107,7 +107,7 @@ static void print_error_data(struct ehca_shca * shca, void* data, | |||
107 | } | 107 | } |
108 | case 0x4: /* Completion Queue */ | 108 | case 0x4: /* Completion Queue */ |
109 | { | 109 | { |
110 | struct ehca_cq *cq = (struct ehca_cq*)data; | 110 | struct ehca_cq *cq = (struct ehca_cq *)data; |
111 | 111 | ||
112 | ehca_err(&shca->ib_device, | 112 | ehca_err(&shca->ib_device, |
113 | "CQ 0x%x (resource=%lx) has errors.", | 113 | "CQ 0x%x (resource=%lx) has errors.", |
@@ -572,7 +572,7 @@ void ehca_tasklet_eq(unsigned long data) | |||
572 | ehca_process_eq((struct ehca_shca*)data, 1); | 572 | ehca_process_eq((struct ehca_shca*)data, 1); |
573 | } | 573 | } |
574 | 574 | ||
575 | static inline int find_next_online_cpu(struct ehca_comp_pool* pool) | 575 | static inline int find_next_online_cpu(struct ehca_comp_pool *pool) |
576 | { | 576 | { |
577 | int cpu; | 577 | int cpu; |
578 | unsigned long flags; | 578 | unsigned long flags; |
@@ -636,7 +636,7 @@ static void queue_comp_task(struct ehca_cq *__cq) | |||
636 | __queue_comp_task(__cq, cct); | 636 | __queue_comp_task(__cq, cct); |
637 | } | 637 | } |
638 | 638 | ||
639 | static void run_comp_task(struct ehca_cpu_comp_task* cct) | 639 | static void run_comp_task(struct ehca_cpu_comp_task *cct) |
640 | { | 640 | { |
641 | struct ehca_cq *cq; | 641 | struct ehca_cq *cq; |
642 | unsigned long flags; | 642 | unsigned long flags; |
@@ -666,12 +666,12 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct) | |||
666 | 666 | ||
667 | static int comp_task(void *__cct) | 667 | static int comp_task(void *__cct) |
668 | { | 668 | { |
669 | struct ehca_cpu_comp_task* cct = __cct; | 669 | struct ehca_cpu_comp_task *cct = __cct; |
670 | int cql_empty; | 670 | int cql_empty; |
671 | DECLARE_WAITQUEUE(wait, current); | 671 | DECLARE_WAITQUEUE(wait, current); |
672 | 672 | ||
673 | set_current_state(TASK_INTERRUPTIBLE); | 673 | set_current_state(TASK_INTERRUPTIBLE); |
674 | while(!kthread_should_stop()) { | 674 | while (!kthread_should_stop()) { |
675 | add_wait_queue(&cct->wait_queue, &wait); | 675 | add_wait_queue(&cct->wait_queue, &wait); |
676 | 676 | ||
677 | spin_lock_irq(&cct->task_lock); | 677 | spin_lock_irq(&cct->task_lock); |
@@ -745,7 +745,7 @@ static void take_over_work(struct ehca_comp_pool *pool, | |||
745 | 745 | ||
746 | list_splice_init(&cct->cq_list, &list); | 746 | list_splice_init(&cct->cq_list, &list); |
747 | 747 | ||
748 | while(!list_empty(&list)) { | 748 | while (!list_empty(&list)) { |
749 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); | 749 | cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); |
750 | 750 | ||
751 | list_del(&cq->entry); | 751 | list_del(&cq->entry); |
@@ -768,7 +768,7 @@ static int comp_pool_callback(struct notifier_block *nfb, | |||
768 | case CPU_UP_PREPARE: | 768 | case CPU_UP_PREPARE: |
769 | case CPU_UP_PREPARE_FROZEN: | 769 | case CPU_UP_PREPARE_FROZEN: |
770 | ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu); | 770 | ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu); |
771 | if(!create_comp_task(pool, cpu)) { | 771 | if (!create_comp_task(pool, cpu)) { |
772 | ehca_gen_err("Can't create comp_task for cpu: %x", cpu); | 772 | ehca_gen_err("Can't create comp_task for cpu: %x", cpu); |
773 | return NOTIFY_BAD; | 773 | return NOTIFY_BAD; |
774 | } | 774 | } |
@@ -838,7 +838,7 @@ int ehca_create_comp_pool(void) | |||
838 | 838 | ||
839 | #ifdef CONFIG_HOTPLUG_CPU | 839 | #ifdef CONFIG_HOTPLUG_CPU |
840 | comp_pool_callback_nb.notifier_call = comp_pool_callback; | 840 | comp_pool_callback_nb.notifier_call = comp_pool_callback; |
841 | comp_pool_callback_nb.priority =0; | 841 | comp_pool_callback_nb.priority = 0; |
842 | register_cpu_notifier(&comp_pool_callback_nb); | 842 | register_cpu_notifier(&comp_pool_callback_nb); |
843 | #endif | 843 | #endif |
844 | 844 | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index 77aeca6a2c2f..dce503bb7d6b 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h | |||
@@ -81,8 +81,9 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | |||
81 | int num_phys_buf, | 81 | int num_phys_buf, |
82 | int mr_access_flags, u64 *iova_start); | 82 | int mr_access_flags, u64 *iova_start); |
83 | 83 | ||
84 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt, | 84 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
85 | int mr_access_flags, struct ib_udata *udata); | 85 | u64 virt, int mr_access_flags, |
86 | struct ib_udata *udata); | ||
86 | 87 | ||
87 | int ehca_rereg_phys_mr(struct ib_mr *mr, | 88 | int ehca_rereg_phys_mr(struct ib_mr *mr, |
88 | int mr_rereg_mask, | 89 | int mr_rereg_mask, |
@@ -192,7 +193,7 @@ void ehca_poll_eqs(unsigned long data); | |||
192 | void *ehca_alloc_fw_ctrlblock(gfp_t flags); | 193 | void *ehca_alloc_fw_ctrlblock(gfp_t flags); |
193 | void ehca_free_fw_ctrlblock(void *ptr); | 194 | void ehca_free_fw_ctrlblock(void *ptr); |
194 | #else | 195 | #else |
195 | #define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags)) | 196 | #define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags)) |
196 | #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) | 197 | #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) |
197 | #endif | 198 | #endif |
198 | 199 | ||
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 28ba2dd24216..36377c6db3d4 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c | |||
@@ -107,7 +107,7 @@ static DEFINE_SPINLOCK(shca_list_lock); | |||
107 | static struct timer_list poll_eqs_timer; | 107 | static struct timer_list poll_eqs_timer; |
108 | 108 | ||
109 | #ifdef CONFIG_PPC_64K_PAGES | 109 | #ifdef CONFIG_PPC_64K_PAGES |
110 | static struct kmem_cache *ctblk_cache = NULL; | 110 | static struct kmem_cache *ctblk_cache; |
111 | 111 | ||
112 | void *ehca_alloc_fw_ctrlblock(gfp_t flags) | 112 | void *ehca_alloc_fw_ctrlblock(gfp_t flags) |
113 | { | 113 | { |
@@ -200,8 +200,8 @@ static void ehca_destroy_slab_caches(void) | |||
200 | #endif | 200 | #endif |
201 | } | 201 | } |
202 | 202 | ||
203 | #define EHCA_HCAAVER EHCA_BMASK_IBM(32,39) | 203 | #define EHCA_HCAAVER EHCA_BMASK_IBM(32, 39) |
204 | #define EHCA_REVID EHCA_BMASK_IBM(40,63) | 204 | #define EHCA_REVID EHCA_BMASK_IBM(40, 63) |
205 | 205 | ||
206 | static struct cap_descr { | 206 | static struct cap_descr { |
207 | u64 mask; | 207 | u64 mask; |
@@ -263,22 +263,27 @@ int ehca_sense_attributes(struct ehca_shca *shca) | |||
263 | 263 | ||
264 | ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid); | 264 | ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid); |
265 | 265 | ||
266 | if ((hcaaver == 1) && (revid == 0)) | 266 | if (hcaaver == 1) { |
267 | shca->hw_level = 0x11; | 267 | if (revid <= 3) |
268 | else if ((hcaaver == 1) && (revid == 1)) | 268 | shca->hw_level = 0x10 | (revid + 1); |
269 | shca->hw_level = 0x12; | 269 | else |
270 | else if ((hcaaver == 1) && (revid == 2)) | 270 | shca->hw_level = 0x14; |
271 | shca->hw_level = 0x13; | 271 | } else if (hcaaver == 2) { |
272 | else if ((hcaaver == 2) && (revid == 0)) | 272 | if (revid == 0) |
273 | shca->hw_level = 0x21; | 273 | shca->hw_level = 0x21; |
274 | else if ((hcaaver == 2) && (revid == 0x10)) | 274 | else if (revid == 0x10) |
275 | shca->hw_level = 0x22; | 275 | shca->hw_level = 0x22; |
276 | else { | 276 | else if (revid == 0x20 || revid == 0x21) |
277 | shca->hw_level = 0x23; | ||
278 | } | ||
279 | |||
280 | if (!shca->hw_level) { | ||
277 | ehca_gen_warn("unknown hardware version" | 281 | ehca_gen_warn("unknown hardware version" |
278 | " - assuming default level"); | 282 | " - assuming default level"); |
279 | shca->hw_level = 0x22; | 283 | shca->hw_level = 0x22; |
280 | } | 284 | } |
281 | } | 285 | } else |
286 | shca->hw_level = ehca_hw_level; | ||
282 | ehca_gen_dbg(" ... hardware level=%x", shca->hw_level); | 287 | ehca_gen_dbg(" ... hardware level=%x", shca->hw_level); |
283 | 288 | ||
284 | shca->sport[0].rate = IB_RATE_30_GBPS; | 289 | shca->sport[0].rate = IB_RATE_30_GBPS; |
@@ -290,7 +295,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) | |||
290 | if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap)) | 295 | if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap)) |
291 | ehca_gen_dbg(" %s", hca_cap_descr[i].descr); | 296 | ehca_gen_dbg(" %s", hca_cap_descr[i].descr); |
292 | 297 | ||
293 | port = (struct hipz_query_port *) rblock; | 298 | port = (struct hipz_query_port *)rblock; |
294 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); | 299 | h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); |
295 | if (h_ret != H_SUCCESS) { | 300 | if (h_ret != H_SUCCESS) { |
296 | ehca_gen_err("Cannot query port properties. h_ret=%lx", | 301 | ehca_gen_err("Cannot query port properties. h_ret=%lx", |
@@ -439,7 +444,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) | |||
439 | return -EPERM; | 444 | return -EPERM; |
440 | } | 445 | } |
441 | 446 | ||
442 | ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0); | 447 | ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0); |
443 | if (IS_ERR(ibcq)) { | 448 | if (IS_ERR(ibcq)) { |
444 | ehca_err(&shca->ib_device, "Cannot create AQP1 CQ."); | 449 | ehca_err(&shca->ib_device, "Cannot create AQP1 CQ."); |
445 | return PTR_ERR(ibcq); | 450 | return PTR_ERR(ibcq); |
@@ -666,7 +671,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, | |||
666 | } | 671 | } |
667 | 672 | ||
668 | /* create internal protection domain */ | 673 | /* create internal protection domain */ |
669 | ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL); | 674 | ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL); |
670 | if (IS_ERR(ibpd)) { | 675 | if (IS_ERR(ibpd)) { |
671 | ehca_err(&shca->ib_device, "Cannot create internal PD."); | 676 | ehca_err(&shca->ib_device, "Cannot create internal PD."); |
672 | ret = PTR_ERR(ibpd); | 677 | ret = PTR_ERR(ibpd); |
@@ -863,18 +868,21 @@ int __init ehca_module_init(void) | |||
863 | printk(KERN_INFO "eHCA Infiniband Device Driver " | 868 | printk(KERN_INFO "eHCA Infiniband Device Driver " |
864 | "(Rel.: SVNEHCA_0023)\n"); | 869 | "(Rel.: SVNEHCA_0023)\n"); |
865 | 870 | ||
866 | if ((ret = ehca_create_comp_pool())) { | 871 | ret = ehca_create_comp_pool(); |
872 | if (ret) { | ||
867 | ehca_gen_err("Cannot create comp pool."); | 873 | ehca_gen_err("Cannot create comp pool."); |
868 | return ret; | 874 | return ret; |
869 | } | 875 | } |
870 | 876 | ||
871 | if ((ret = ehca_create_slab_caches())) { | 877 | ret = ehca_create_slab_caches(); |
878 | if (ret) { | ||
872 | ehca_gen_err("Cannot create SLAB caches"); | 879 | ehca_gen_err("Cannot create SLAB caches"); |
873 | ret = -ENOMEM; | 880 | ret = -ENOMEM; |
874 | goto module_init1; | 881 | goto module_init1; |
875 | } | 882 | } |
876 | 883 | ||
877 | if ((ret = ibmebus_register_driver(&ehca_driver))) { | 884 | ret = ibmebus_register_driver(&ehca_driver); |
885 | if (ret) { | ||
878 | ehca_gen_err("Cannot register eHCA device driver"); | 886 | ehca_gen_err("Cannot register eHCA device driver"); |
879 | ret = -EINVAL; | 887 | ret = -EINVAL; |
880 | goto module_init2; | 888 | goto module_init2; |
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index add79bd44e39..6262c5462d50 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c | |||
@@ -48,6 +48,11 @@ | |||
48 | #include "hcp_if.h" | 48 | #include "hcp_if.h" |
49 | #include "hipz_hw.h" | 49 | #include "hipz_hw.h" |
50 | 50 | ||
51 | #define NUM_CHUNKS(length, chunk_size) \ | ||
52 | (((length) + (chunk_size - 1)) / (chunk_size)) | ||
53 | /* max number of rpages (per hcall register_rpages) */ | ||
54 | #define MAX_RPAGES 512 | ||
55 | |||
51 | static struct kmem_cache *mr_cache; | 56 | static struct kmem_cache *mr_cache; |
52 | static struct kmem_cache *mw_cache; | 57 | static struct kmem_cache *mw_cache; |
53 | 58 | ||
@@ -56,9 +61,9 @@ static struct ehca_mr *ehca_mr_new(void) | |||
56 | struct ehca_mr *me; | 61 | struct ehca_mr *me; |
57 | 62 | ||
58 | me = kmem_cache_zalloc(mr_cache, GFP_KERNEL); | 63 | me = kmem_cache_zalloc(mr_cache, GFP_KERNEL); |
59 | if (me) { | 64 | if (me) |
60 | spin_lock_init(&me->mrlock); | 65 | spin_lock_init(&me->mrlock); |
61 | } else | 66 | else |
62 | ehca_gen_err("alloc failed"); | 67 | ehca_gen_err("alloc failed"); |
63 | 68 | ||
64 | return me; | 69 | return me; |
@@ -74,9 +79,9 @@ static struct ehca_mw *ehca_mw_new(void) | |||
74 | struct ehca_mw *me; | 79 | struct ehca_mw *me; |
75 | 80 | ||
76 | me = kmem_cache_zalloc(mw_cache, GFP_KERNEL); | 81 | me = kmem_cache_zalloc(mw_cache, GFP_KERNEL); |
77 | if (me) { | 82 | if (me) |
78 | spin_lock_init(&me->mwlock); | 83 | spin_lock_init(&me->mwlock); |
79 | } else | 84 | else |
80 | ehca_gen_err("alloc failed"); | 85 | ehca_gen_err("alloc failed"); |
81 | 86 | ||
82 | return me; | 87 | return me; |
@@ -106,11 +111,12 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags) | |||
106 | goto get_dma_mr_exit0; | 111 | goto get_dma_mr_exit0; |
107 | } | 112 | } |
108 | 113 | ||
109 | ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE, | 114 | ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE, |
110 | mr_access_flags, e_pd, | 115 | mr_access_flags, e_pd, |
111 | &e_maxmr->ib.ib_mr.lkey, | 116 | &e_maxmr->ib.ib_mr.lkey, |
112 | &e_maxmr->ib.ib_mr.rkey); | 117 | &e_maxmr->ib.ib_mr.rkey); |
113 | if (ret) { | 118 | if (ret) { |
119 | ehca_mr_delete(e_maxmr); | ||
114 | ib_mr = ERR_PTR(ret); | 120 | ib_mr = ERR_PTR(ret); |
115 | goto get_dma_mr_exit0; | 121 | goto get_dma_mr_exit0; |
116 | } | 122 | } |
@@ -144,9 +150,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | |||
144 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | 150 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); |
145 | 151 | ||
146 | u64 size; | 152 | u64 size; |
147 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | ||
148 | u32 num_pages_mr; | ||
149 | u32 num_pages_4k; /* 4k portion "pages" */ | ||
150 | 153 | ||
151 | if ((num_phys_buf <= 0) || !phys_buf_array) { | 154 | if ((num_phys_buf <= 0) || !phys_buf_array) { |
152 | ehca_err(pd->device, "bad input values: num_phys_buf=%x " | 155 | ehca_err(pd->device, "bad input values: num_phys_buf=%x " |
@@ -190,12 +193,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | |||
190 | goto reg_phys_mr_exit0; | 193 | goto reg_phys_mr_exit0; |
191 | } | 194 | } |
192 | 195 | ||
193 | /* determine number of MR pages */ | ||
194 | num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size + | ||
195 | PAGE_SIZE - 1) / PAGE_SIZE); | ||
196 | num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size + | ||
197 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | ||
198 | |||
199 | /* register MR on HCA */ | 196 | /* register MR on HCA */ |
200 | if (ehca_mr_is_maxmr(size, iova_start)) { | 197 | if (ehca_mr_is_maxmr(size, iova_start)) { |
201 | e_mr->flags |= EHCA_MR_FLAG_MAXMR; | 198 | e_mr->flags |= EHCA_MR_FLAG_MAXMR; |
@@ -207,13 +204,22 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, | |||
207 | goto reg_phys_mr_exit1; | 204 | goto reg_phys_mr_exit1; |
208 | } | 205 | } |
209 | } else { | 206 | } else { |
210 | pginfo.type = EHCA_MR_PGI_PHYS; | 207 | struct ehca_mr_pginfo pginfo; |
211 | pginfo.num_pages = num_pages_mr; | 208 | u32 num_kpages; |
212 | pginfo.num_4k = num_pages_4k; | 209 | u32 num_hwpages; |
213 | pginfo.num_phys_buf = num_phys_buf; | 210 | |
214 | pginfo.phys_buf_array = phys_buf_array; | 211 | num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size, |
215 | pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) / | 212 | PAGE_SIZE); |
216 | EHCA_PAGESIZE); | 213 | num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) + |
214 | size, EHCA_PAGESIZE); | ||
215 | memset(&pginfo, 0, sizeof(pginfo)); | ||
216 | pginfo.type = EHCA_MR_PGI_PHYS; | ||
217 | pginfo.num_kpages = num_kpages; | ||
218 | pginfo.num_hwpages = num_hwpages; | ||
219 | pginfo.u.phy.num_phys_buf = num_phys_buf; | ||
220 | pginfo.u.phy.phys_buf_array = phys_buf_array; | ||
221 | pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) / | ||
222 | EHCA_PAGESIZE); | ||
217 | 223 | ||
218 | ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags, | 224 | ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags, |
219 | e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, | 225 | e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, |
@@ -240,18 +246,19 @@ reg_phys_mr_exit0: | |||
240 | 246 | ||
241 | /*----------------------------------------------------------------------*/ | 247 | /*----------------------------------------------------------------------*/ |
242 | 248 | ||
243 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt, | 249 | struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
244 | int mr_access_flags, struct ib_udata *udata) | 250 | u64 virt, int mr_access_flags, |
251 | struct ib_udata *udata) | ||
245 | { | 252 | { |
246 | struct ib_mr *ib_mr; | 253 | struct ib_mr *ib_mr; |
247 | struct ehca_mr *e_mr; | 254 | struct ehca_mr *e_mr; |
248 | struct ehca_shca *shca = | 255 | struct ehca_shca *shca = |
249 | container_of(pd->device, struct ehca_shca, ib_device); | 256 | container_of(pd->device, struct ehca_shca, ib_device); |
250 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | 257 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); |
251 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 258 | struct ehca_mr_pginfo pginfo; |
252 | int ret; | 259 | int ret; |
253 | u32 num_pages_mr; | 260 | u32 num_kpages; |
254 | u32 num_pages_4k; /* 4k portion "pages" */ | 261 | u32 num_hwpages; |
255 | 262 | ||
256 | if (!pd) { | 263 | if (!pd) { |
257 | ehca_gen_err("bad pd=%p", pd); | 264 | ehca_gen_err("bad pd=%p", pd); |
@@ -289,7 +296,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt | |||
289 | e_mr->umem = ib_umem_get(pd->uobject->context, start, length, | 296 | e_mr->umem = ib_umem_get(pd->uobject->context, start, length, |
290 | mr_access_flags); | 297 | mr_access_flags); |
291 | if (IS_ERR(e_mr->umem)) { | 298 | if (IS_ERR(e_mr->umem)) { |
292 | ib_mr = (void *) e_mr->umem; | 299 | ib_mr = (void *)e_mr->umem; |
293 | goto reg_user_mr_exit1; | 300 | goto reg_user_mr_exit1; |
294 | } | 301 | } |
295 | 302 | ||
@@ -301,23 +308,24 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt | |||
301 | } | 308 | } |
302 | 309 | ||
303 | /* determine number of MR pages */ | 310 | /* determine number of MR pages */ |
304 | num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) / | 311 | num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE); |
305 | PAGE_SIZE); | 312 | num_hwpages = NUM_CHUNKS((virt % EHCA_PAGESIZE) + length, |
306 | num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) / | 313 | EHCA_PAGESIZE); |
307 | EHCA_PAGESIZE); | ||
308 | 314 | ||
309 | /* register MR on HCA */ | 315 | /* register MR on HCA */ |
310 | pginfo.type = EHCA_MR_PGI_USER; | 316 | memset(&pginfo, 0, sizeof(pginfo)); |
311 | pginfo.num_pages = num_pages_mr; | 317 | pginfo.type = EHCA_MR_PGI_USER; |
312 | pginfo.num_4k = num_pages_4k; | 318 | pginfo.num_kpages = num_kpages; |
313 | pginfo.region = e_mr->umem; | 319 | pginfo.num_hwpages = num_hwpages; |
314 | pginfo.next_4k = e_mr->umem->offset / EHCA_PAGESIZE; | 320 | pginfo.u.usr.region = e_mr->umem; |
315 | pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk, | 321 | pginfo.next_hwpage = e_mr->umem->offset / EHCA_PAGESIZE; |
316 | (&e_mr->umem->chunk_list), | 322 | pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk, |
317 | list); | 323 | (&e_mr->umem->chunk_list), |
318 | 324 | list); | |
319 | ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd, | 325 | |
320 | &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey); | 326 | ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags, |
327 | e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, | ||
328 | &e_mr->ib.ib_mr.rkey); | ||
321 | if (ret) { | 329 | if (ret) { |
322 | ib_mr = ERR_PTR(ret); | 330 | ib_mr = ERR_PTR(ret); |
323 | goto reg_user_mr_exit2; | 331 | goto reg_user_mr_exit2; |
@@ -360,9 +368,9 @@ int ehca_rereg_phys_mr(struct ib_mr *mr, | |||
360 | struct ehca_pd *new_pd; | 368 | struct ehca_pd *new_pd; |
361 | u32 tmp_lkey, tmp_rkey; | 369 | u32 tmp_lkey, tmp_rkey; |
362 | unsigned long sl_flags; | 370 | unsigned long sl_flags; |
363 | u32 num_pages_mr = 0; | 371 | u32 num_kpages = 0; |
364 | u32 num_pages_4k = 0; /* 4k portion "pages" */ | 372 | u32 num_hwpages = 0; |
365 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 373 | struct ehca_mr_pginfo pginfo; |
366 | u32 cur_pid = current->tgid; | 374 | u32 cur_pid = current->tgid; |
367 | 375 | ||
368 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | 376 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && |
@@ -414,7 +422,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr, | |||
414 | goto rereg_phys_mr_exit0; | 422 | goto rereg_phys_mr_exit0; |
415 | } | 423 | } |
416 | if (!phys_buf_array || num_phys_buf <= 0) { | 424 | if (!phys_buf_array || num_phys_buf <= 0) { |
417 | ehca_err(mr->device, "bad input values: mr_rereg_mask=%x" | 425 | ehca_err(mr->device, "bad input values mr_rereg_mask=%x" |
418 | " phys_buf_array=%p num_phys_buf=%x", | 426 | " phys_buf_array=%p num_phys_buf=%x", |
419 | mr_rereg_mask, phys_buf_array, num_phys_buf); | 427 | mr_rereg_mask, phys_buf_array, num_phys_buf); |
420 | ret = -EINVAL; | 428 | ret = -EINVAL; |
@@ -438,10 +446,10 @@ int ehca_rereg_phys_mr(struct ib_mr *mr, | |||
438 | 446 | ||
439 | /* set requested values dependent on rereg request */ | 447 | /* set requested values dependent on rereg request */ |
440 | spin_lock_irqsave(&e_mr->mrlock, sl_flags); | 448 | spin_lock_irqsave(&e_mr->mrlock, sl_flags); |
441 | new_start = e_mr->start; /* new == old address */ | 449 | new_start = e_mr->start; |
442 | new_size = e_mr->size; /* new == old length */ | 450 | new_size = e_mr->size; |
443 | new_acl = e_mr->acl; /* new == old access control */ | 451 | new_acl = e_mr->acl; |
444 | new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/ | 452 | new_pd = container_of(mr->pd, struct ehca_pd, ib_pd); |
445 | 453 | ||
446 | if (mr_rereg_mask & IB_MR_REREG_TRANS) { | 454 | if (mr_rereg_mask & IB_MR_REREG_TRANS) { |
447 | new_start = iova_start; /* change address */ | 455 | new_start = iova_start; /* change address */ |
@@ -458,17 +466,18 @@ int ehca_rereg_phys_mr(struct ib_mr *mr, | |||
458 | ret = -EINVAL; | 466 | ret = -EINVAL; |
459 | goto rereg_phys_mr_exit1; | 467 | goto rereg_phys_mr_exit1; |
460 | } | 468 | } |
461 | num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size + | 469 | num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) + |
462 | PAGE_SIZE - 1) / PAGE_SIZE); | 470 | new_size, PAGE_SIZE); |
463 | num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size + | 471 | num_hwpages = NUM_CHUNKS(((u64)new_start % EHCA_PAGESIZE) + |
464 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | 472 | new_size, EHCA_PAGESIZE); |
465 | pginfo.type = EHCA_MR_PGI_PHYS; | 473 | memset(&pginfo, 0, sizeof(pginfo)); |
466 | pginfo.num_pages = num_pages_mr; | 474 | pginfo.type = EHCA_MR_PGI_PHYS; |
467 | pginfo.num_4k = num_pages_4k; | 475 | pginfo.num_kpages = num_kpages; |
468 | pginfo.num_phys_buf = num_phys_buf; | 476 | pginfo.num_hwpages = num_hwpages; |
469 | pginfo.phys_buf_array = phys_buf_array; | 477 | pginfo.u.phy.num_phys_buf = num_phys_buf; |
470 | pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) / | 478 | pginfo.u.phy.phys_buf_array = phys_buf_array; |
471 | EHCA_PAGESIZE); | 479 | pginfo.next_hwpage = (((u64)iova_start & ~PAGE_MASK) / |
480 | EHCA_PAGESIZE); | ||
472 | } | 481 | } |
473 | if (mr_rereg_mask & IB_MR_REREG_ACCESS) | 482 | if (mr_rereg_mask & IB_MR_REREG_ACCESS) |
474 | new_acl = mr_access_flags; | 483 | new_acl = mr_access_flags; |
@@ -510,7 +519,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) | |||
510 | struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd); | 519 | struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd); |
511 | u32 cur_pid = current->tgid; | 520 | u32 cur_pid = current->tgid; |
512 | unsigned long sl_flags; | 521 | unsigned long sl_flags; |
513 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 522 | struct ehca_mr_hipzout_parms hipzout; |
514 | 523 | ||
515 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | 524 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && |
516 | (my_pd->ownpid != cur_pid)) { | 525 | (my_pd->ownpid != cur_pid)) { |
@@ -536,14 +545,14 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) | |||
536 | "hca_hndl=%lx mr_hndl=%lx lkey=%x", | 545 | "hca_hndl=%lx mr_hndl=%lx lkey=%x", |
537 | h_ret, mr, shca->ipz_hca_handle.handle, | 546 | h_ret, mr, shca->ipz_hca_handle.handle, |
538 | e_mr->ipz_mr_handle.handle, mr->lkey); | 547 | e_mr->ipz_mr_handle.handle, mr->lkey); |
539 | ret = ehca_mrmw_map_hrc_query_mr(h_ret); | 548 | ret = ehca2ib_return_code(h_ret); |
540 | goto query_mr_exit1; | 549 | goto query_mr_exit1; |
541 | } | 550 | } |
542 | mr_attr->pd = mr->pd; | 551 | mr_attr->pd = mr->pd; |
543 | mr_attr->device_virt_addr = hipzout.vaddr; | 552 | mr_attr->device_virt_addr = hipzout.vaddr; |
544 | mr_attr->size = hipzout.len; | 553 | mr_attr->size = hipzout.len; |
545 | mr_attr->lkey = hipzout.lkey; | 554 | mr_attr->lkey = hipzout.lkey; |
546 | mr_attr->rkey = hipzout.rkey; | 555 | mr_attr->rkey = hipzout.rkey; |
547 | ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags); | 556 | ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags); |
548 | 557 | ||
549 | query_mr_exit1: | 558 | query_mr_exit1: |
@@ -596,7 +605,7 @@ int ehca_dereg_mr(struct ib_mr *mr) | |||
596 | "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x", | 605 | "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x", |
597 | h_ret, shca, e_mr, shca->ipz_hca_handle.handle, | 606 | h_ret, shca, e_mr, shca->ipz_hca_handle.handle, |
598 | e_mr->ipz_mr_handle.handle, mr->lkey); | 607 | e_mr->ipz_mr_handle.handle, mr->lkey); |
599 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | 608 | ret = ehca2ib_return_code(h_ret); |
600 | goto dereg_mr_exit0; | 609 | goto dereg_mr_exit0; |
601 | } | 610 | } |
602 | 611 | ||
@@ -622,7 +631,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd) | |||
622 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); | 631 | struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd); |
623 | struct ehca_shca *shca = | 632 | struct ehca_shca *shca = |
624 | container_of(pd->device, struct ehca_shca, ib_device); | 633 | container_of(pd->device, struct ehca_shca, ib_device); |
625 | struct ehca_mw_hipzout_parms hipzout = {{0},0}; | 634 | struct ehca_mw_hipzout_parms hipzout; |
626 | 635 | ||
627 | e_mw = ehca_mw_new(); | 636 | e_mw = ehca_mw_new(); |
628 | if (!e_mw) { | 637 | if (!e_mw) { |
@@ -636,7 +645,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd) | |||
636 | ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx " | 645 | ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx " |
637 | "shca=%p hca_hndl=%lx mw=%p", | 646 | "shca=%p hca_hndl=%lx mw=%p", |
638 | h_ret, shca, shca->ipz_hca_handle.handle, e_mw); | 647 | h_ret, shca, shca->ipz_hca_handle.handle, e_mw); |
639 | ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret)); | 648 | ib_mw = ERR_PTR(ehca2ib_return_code(h_ret)); |
640 | goto alloc_mw_exit1; | 649 | goto alloc_mw_exit1; |
641 | } | 650 | } |
642 | /* successful MW allocation */ | 651 | /* successful MW allocation */ |
@@ -679,7 +688,7 @@ int ehca_dealloc_mw(struct ib_mw *mw) | |||
679 | "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx", | 688 | "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx", |
680 | h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle, | 689 | h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle, |
681 | e_mw->ipz_mw_handle.handle); | 690 | e_mw->ipz_mw_handle.handle); |
682 | return ehca_mrmw_map_hrc_free_mw(h_ret); | 691 | return ehca2ib_return_code(h_ret); |
683 | } | 692 | } |
684 | /* successful deallocation */ | 693 | /* successful deallocation */ |
685 | ehca_mw_delete(e_mw); | 694 | ehca_mw_delete(e_mw); |
@@ -699,7 +708,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, | |||
699 | struct ehca_mr *e_fmr; | 708 | struct ehca_mr *e_fmr; |
700 | int ret; | 709 | int ret; |
701 | u32 tmp_lkey, tmp_rkey; | 710 | u32 tmp_lkey, tmp_rkey; |
702 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 711 | struct ehca_mr_pginfo pginfo; |
703 | 712 | ||
704 | /* check other parameters */ | 713 | /* check other parameters */ |
705 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && | 714 | if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) && |
@@ -745,6 +754,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, | |||
745 | e_fmr->flags |= EHCA_MR_FLAG_FMR; | 754 | e_fmr->flags |= EHCA_MR_FLAG_FMR; |
746 | 755 | ||
747 | /* register MR on HCA */ | 756 | /* register MR on HCA */ |
757 | memset(&pginfo, 0, sizeof(pginfo)); | ||
748 | ret = ehca_reg_mr(shca, e_fmr, NULL, | 758 | ret = ehca_reg_mr(shca, e_fmr, NULL, |
749 | fmr_attr->max_pages * (1 << fmr_attr->page_shift), | 759 | fmr_attr->max_pages * (1 << fmr_attr->page_shift), |
750 | mr_access_flags, e_pd, &pginfo, | 760 | mr_access_flags, e_pd, &pginfo, |
@@ -783,7 +793,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr, | |||
783 | container_of(fmr->device, struct ehca_shca, ib_device); | 793 | container_of(fmr->device, struct ehca_shca, ib_device); |
784 | struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr); | 794 | struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr); |
785 | struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd); | 795 | struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd); |
786 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 796 | struct ehca_mr_pginfo pginfo; |
787 | u32 tmp_lkey, tmp_rkey; | 797 | u32 tmp_lkey, tmp_rkey; |
788 | 798 | ||
789 | if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) { | 799 | if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) { |
@@ -809,14 +819,16 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr, | |||
809 | fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps); | 819 | fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps); |
810 | } | 820 | } |
811 | 821 | ||
812 | pginfo.type = EHCA_MR_PGI_FMR; | 822 | memset(&pginfo, 0, sizeof(pginfo)); |
813 | pginfo.num_pages = list_len; | 823 | pginfo.type = EHCA_MR_PGI_FMR; |
814 | pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE); | 824 | pginfo.num_kpages = list_len; |
815 | pginfo.page_list = page_list; | 825 | pginfo.num_hwpages = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE); |
816 | pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) / | 826 | pginfo.u.fmr.page_list = page_list; |
817 | EHCA_PAGESIZE); | 827 | pginfo.next_hwpage = ((iova & (e_fmr->fmr_page_size-1)) / |
828 | EHCA_PAGESIZE); | ||
829 | pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size; | ||
818 | 830 | ||
819 | ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova, | 831 | ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova, |
820 | list_len * e_fmr->fmr_page_size, | 832 | list_len * e_fmr->fmr_page_size, |
821 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey); | 833 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey); |
822 | if (ret) | 834 | if (ret) |
@@ -831,8 +843,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr, | |||
831 | map_phys_fmr_exit0: | 843 | map_phys_fmr_exit0: |
832 | if (ret) | 844 | if (ret) |
833 | ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x " | 845 | ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x " |
834 | "iova=%lx", | 846 | "iova=%lx", ret, fmr, page_list, list_len, iova); |
835 | ret, fmr, page_list, list_len, iova); | ||
836 | return ret; | 847 | return ret; |
837 | } /* end ehca_map_phys_fmr() */ | 848 | } /* end ehca_map_phys_fmr() */ |
838 | 849 | ||
@@ -922,7 +933,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr) | |||
922 | "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x", | 933 | "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x", |
923 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | 934 | h_ret, e_fmr, shca->ipz_hca_handle.handle, |
924 | e_fmr->ipz_mr_handle.handle, fmr->lkey); | 935 | e_fmr->ipz_mr_handle.handle, fmr->lkey); |
925 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | 936 | ret = ehca2ib_return_code(h_ret); |
926 | goto free_fmr_exit0; | 937 | goto free_fmr_exit0; |
927 | } | 938 | } |
928 | /* successful deregistration */ | 939 | /* successful deregistration */ |
@@ -950,12 +961,12 @@ int ehca_reg_mr(struct ehca_shca *shca, | |||
950 | int ret; | 961 | int ret; |
951 | u64 h_ret; | 962 | u64 h_ret; |
952 | u32 hipz_acl; | 963 | u32 hipz_acl; |
953 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 964 | struct ehca_mr_hipzout_parms hipzout; |
954 | 965 | ||
955 | ehca_mrmw_map_acl(acl, &hipz_acl); | 966 | ehca_mrmw_map_acl(acl, &hipz_acl); |
956 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | 967 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); |
957 | if (ehca_use_hp_mr == 1) | 968 | if (ehca_use_hp_mr == 1) |
958 | hipz_acl |= 0x00000001; | 969 | hipz_acl |= 0x00000001; |
959 | 970 | ||
960 | h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr, | 971 | h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr, |
961 | (u64)iova_start, size, hipz_acl, | 972 | (u64)iova_start, size, hipz_acl, |
@@ -963,7 +974,7 @@ int ehca_reg_mr(struct ehca_shca *shca, | |||
963 | if (h_ret != H_SUCCESS) { | 974 | if (h_ret != H_SUCCESS) { |
964 | ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx " | 975 | ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx " |
965 | "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle); | 976 | "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle); |
966 | ret = ehca_mrmw_map_hrc_alloc(h_ret); | 977 | ret = ehca2ib_return_code(h_ret); |
967 | goto ehca_reg_mr_exit0; | 978 | goto ehca_reg_mr_exit0; |
968 | } | 979 | } |
969 | 980 | ||
@@ -974,11 +985,11 @@ int ehca_reg_mr(struct ehca_shca *shca, | |||
974 | goto ehca_reg_mr_exit1; | 985 | goto ehca_reg_mr_exit1; |
975 | 986 | ||
976 | /* successful registration */ | 987 | /* successful registration */ |
977 | e_mr->num_pages = pginfo->num_pages; | 988 | e_mr->num_kpages = pginfo->num_kpages; |
978 | e_mr->num_4k = pginfo->num_4k; | 989 | e_mr->num_hwpages = pginfo->num_hwpages; |
979 | e_mr->start = iova_start; | 990 | e_mr->start = iova_start; |
980 | e_mr->size = size; | 991 | e_mr->size = size; |
981 | e_mr->acl = acl; | 992 | e_mr->acl = acl; |
982 | *lkey = hipzout.lkey; | 993 | *lkey = hipzout.lkey; |
983 | *rkey = hipzout.rkey; | 994 | *rkey = hipzout.rkey; |
984 | return 0; | 995 | return 0; |
@@ -988,10 +999,10 @@ ehca_reg_mr_exit1: | |||
988 | if (h_ret != H_SUCCESS) { | 999 | if (h_ret != H_SUCCESS) { |
989 | ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p " | 1000 | ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p " |
990 | "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x " | 1001 | "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x " |
991 | "pginfo=%p num_pages=%lx num_4k=%lx ret=%x", | 1002 | "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x", |
992 | h_ret, shca, e_mr, iova_start, size, acl, e_pd, | 1003 | h_ret, shca, e_mr, iova_start, size, acl, e_pd, |
993 | hipzout.lkey, pginfo, pginfo->num_pages, | 1004 | hipzout.lkey, pginfo, pginfo->num_kpages, |
994 | pginfo->num_4k, ret); | 1005 | pginfo->num_hwpages, ret); |
995 | ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, " | 1006 | ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, " |
996 | "not recoverable"); | 1007 | "not recoverable"); |
997 | } | 1008 | } |
@@ -999,9 +1010,9 @@ ehca_reg_mr_exit0: | |||
999 | if (ret) | 1010 | if (ret) |
1000 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " | 1011 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " |
1001 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " | 1012 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " |
1002 | "num_pages=%lx num_4k=%lx", | 1013 | "num_kpages=%lx num_hwpages=%lx", |
1003 | ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo, | 1014 | ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo, |
1004 | pginfo->num_pages, pginfo->num_4k); | 1015 | pginfo->num_kpages, pginfo->num_hwpages); |
1005 | return ret; | 1016 | return ret; |
1006 | } /* end ehca_reg_mr() */ | 1017 | } /* end ehca_reg_mr() */ |
1007 | 1018 | ||
@@ -1026,24 +1037,24 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, | |||
1026 | } | 1037 | } |
1027 | 1038 | ||
1028 | /* max 512 pages per shot */ | 1039 | /* max 512 pages per shot */ |
1029 | for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) { | 1040 | for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) { |
1030 | 1041 | ||
1031 | if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) { | 1042 | if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) { |
1032 | rnum = pginfo->num_4k % 512; /* last shot */ | 1043 | rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */ |
1033 | if (rnum == 0) | 1044 | if (rnum == 0) |
1034 | rnum = 512; /* last shot is full */ | 1045 | rnum = MAX_RPAGES; /* last shot is full */ |
1035 | } else | 1046 | } else |
1036 | rnum = 512; | 1047 | rnum = MAX_RPAGES; |
1037 | 1048 | ||
1038 | if (rnum > 1) { | 1049 | ret = ehca_set_pagebuf(pginfo, rnum, kpage); |
1039 | ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage); | 1050 | if (ret) { |
1040 | if (ret) { | 1051 | ehca_err(&shca->ib_device, "ehca_set_pagebuf " |
1041 | ehca_err(&shca->ib_device, "ehca_set_pagebuf " | ||
1042 | "bad rc, ret=%x rnum=%x kpage=%p", | 1052 | "bad rc, ret=%x rnum=%x kpage=%p", |
1043 | ret, rnum, kpage); | 1053 | ret, rnum, kpage); |
1044 | ret = -EFAULT; | 1054 | goto ehca_reg_mr_rpages_exit1; |
1045 | goto ehca_reg_mr_rpages_exit1; | 1055 | } |
1046 | } | 1056 | |
1057 | if (rnum > 1) { | ||
1047 | rpage = virt_to_abs(kpage); | 1058 | rpage = virt_to_abs(kpage); |
1048 | if (!rpage) { | 1059 | if (!rpage) { |
1049 | ehca_err(&shca->ib_device, "kpage=%p i=%x", | 1060 | ehca_err(&shca->ib_device, "kpage=%p i=%x", |
@@ -1051,21 +1062,14 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, | |||
1051 | ret = -EFAULT; | 1062 | ret = -EFAULT; |
1052 | goto ehca_reg_mr_rpages_exit1; | 1063 | goto ehca_reg_mr_rpages_exit1; |
1053 | } | 1064 | } |
1054 | } else { /* rnum==1 */ | 1065 | } else |
1055 | ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage); | 1066 | rpage = *kpage; |
1056 | if (ret) { | ||
1057 | ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 " | ||
1058 | "bad rc, ret=%x i=%x", ret, i); | ||
1059 | ret = -EFAULT; | ||
1060 | goto ehca_reg_mr_rpages_exit1; | ||
1061 | } | ||
1062 | } | ||
1063 | 1067 | ||
1064 | h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr, | 1068 | h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr, |
1065 | 0, /* pagesize 4k */ | 1069 | 0, /* pagesize 4k */ |
1066 | 0, rpage, rnum); | 1070 | 0, rpage, rnum); |
1067 | 1071 | ||
1068 | if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) { | 1072 | if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) { |
1069 | /* | 1073 | /* |
1070 | * check for 'registration complete'==H_SUCCESS | 1074 | * check for 'registration complete'==H_SUCCESS |
1071 | * and for 'page registered'==H_PAGE_REGISTERED | 1075 | * and for 'page registered'==H_PAGE_REGISTERED |
@@ -1078,7 +1082,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, | |||
1078 | shca->ipz_hca_handle.handle, | 1082 | shca->ipz_hca_handle.handle, |
1079 | e_mr->ipz_mr_handle.handle, | 1083 | e_mr->ipz_mr_handle.handle, |
1080 | e_mr->ib.ib_mr.lkey); | 1084 | e_mr->ib.ib_mr.lkey); |
1081 | ret = ehca_mrmw_map_hrc_rrpg_last(h_ret); | 1085 | ret = ehca2ib_return_code(h_ret); |
1082 | break; | 1086 | break; |
1083 | } else | 1087 | } else |
1084 | ret = 0; | 1088 | ret = 0; |
@@ -1089,7 +1093,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, | |||
1089 | e_mr->ib.ib_mr.lkey, | 1093 | e_mr->ib.ib_mr.lkey, |
1090 | shca->ipz_hca_handle.handle, | 1094 | shca->ipz_hca_handle.handle, |
1091 | e_mr->ipz_mr_handle.handle); | 1095 | e_mr->ipz_mr_handle.handle); |
1092 | ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret); | 1096 | ret = ehca2ib_return_code(h_ret); |
1093 | break; | 1097 | break; |
1094 | } else | 1098 | } else |
1095 | ret = 0; | 1099 | ret = 0; |
@@ -1101,8 +1105,8 @@ ehca_reg_mr_rpages_exit1: | |||
1101 | ehca_reg_mr_rpages_exit0: | 1105 | ehca_reg_mr_rpages_exit0: |
1102 | if (ret) | 1106 | if (ret) |
1103 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " | 1107 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " |
1104 | "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo, | 1108 | "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr, |
1105 | pginfo->num_pages, pginfo->num_4k); | 1109 | pginfo, pginfo->num_kpages, pginfo->num_hwpages); |
1106 | return ret; | 1110 | return ret; |
1107 | } /* end ehca_reg_mr_rpages() */ | 1111 | } /* end ehca_reg_mr_rpages() */ |
1108 | 1112 | ||
@@ -1124,7 +1128,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, | |||
1124 | u64 *kpage; | 1128 | u64 *kpage; |
1125 | u64 rpage; | 1129 | u64 rpage; |
1126 | struct ehca_mr_pginfo pginfo_save; | 1130 | struct ehca_mr_pginfo pginfo_save; |
1127 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 1131 | struct ehca_mr_hipzout_parms hipzout; |
1128 | 1132 | ||
1129 | ehca_mrmw_map_acl(acl, &hipz_acl); | 1133 | ehca_mrmw_map_acl(acl, &hipz_acl); |
1130 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | 1134 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); |
@@ -1137,12 +1141,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, | |||
1137 | } | 1141 | } |
1138 | 1142 | ||
1139 | pginfo_save = *pginfo; | 1143 | pginfo_save = *pginfo; |
1140 | ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage); | 1144 | ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage); |
1141 | if (ret) { | 1145 | if (ret) { |
1142 | ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p " | 1146 | ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p " |
1143 | "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p", | 1147 | "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx " |
1144 | e_mr, pginfo, pginfo->type, pginfo->num_pages, | 1148 | "kpage=%p", e_mr, pginfo, pginfo->type, |
1145 | pginfo->num_4k,kpage); | 1149 | pginfo->num_kpages, pginfo->num_hwpages, kpage); |
1146 | goto ehca_rereg_mr_rereg1_exit1; | 1150 | goto ehca_rereg_mr_rereg1_exit1; |
1147 | } | 1151 | } |
1148 | rpage = virt_to_abs(kpage); | 1152 | rpage = virt_to_abs(kpage); |
@@ -1164,7 +1168,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, | |||
1164 | "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr); | 1168 | "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr); |
1165 | *pginfo = pginfo_save; | 1169 | *pginfo = pginfo_save; |
1166 | ret = -EAGAIN; | 1170 | ret = -EAGAIN; |
1167 | } else if ((u64*)hipzout.vaddr != iova_start) { | 1171 | } else if ((u64 *)hipzout.vaddr != iova_start) { |
1168 | ehca_err(&shca->ib_device, "PHYP changed iova_start in " | 1172 | ehca_err(&shca->ib_device, "PHYP changed iova_start in " |
1169 | "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p " | 1173 | "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p " |
1170 | "mr_handle=%lx lkey=%x lkey_out=%x", iova_start, | 1174 | "mr_handle=%lx lkey=%x lkey_out=%x", iova_start, |
@@ -1176,11 +1180,11 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, | |||
1176 | * successful reregistration | 1180 | * successful reregistration |
1177 | * note: start and start_out are identical for eServer HCAs | 1181 | * note: start and start_out are identical for eServer HCAs |
1178 | */ | 1182 | */ |
1179 | e_mr->num_pages = pginfo->num_pages; | 1183 | e_mr->num_kpages = pginfo->num_kpages; |
1180 | e_mr->num_4k = pginfo->num_4k; | 1184 | e_mr->num_hwpages = pginfo->num_hwpages; |
1181 | e_mr->start = iova_start; | 1185 | e_mr->start = iova_start; |
1182 | e_mr->size = size; | 1186 | e_mr->size = size; |
1183 | e_mr->acl = acl; | 1187 | e_mr->acl = acl; |
1184 | *lkey = hipzout.lkey; | 1188 | *lkey = hipzout.lkey; |
1185 | *rkey = hipzout.rkey; | 1189 | *rkey = hipzout.rkey; |
1186 | } | 1190 | } |
@@ -1190,9 +1194,9 @@ ehca_rereg_mr_rereg1_exit1: | |||
1190 | ehca_rereg_mr_rereg1_exit0: | 1194 | ehca_rereg_mr_rereg1_exit0: |
1191 | if ( ret && (ret != -EAGAIN) ) | 1195 | if ( ret && (ret != -EAGAIN) ) |
1192 | ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " | 1196 | ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " |
1193 | "pginfo=%p num_pages=%lx num_4k=%lx", | 1197 | "pginfo=%p num_kpages=%lx num_hwpages=%lx", |
1194 | ret, *lkey, *rkey, pginfo, pginfo->num_pages, | 1198 | ret, *lkey, *rkey, pginfo, pginfo->num_kpages, |
1195 | pginfo->num_4k); | 1199 | pginfo->num_hwpages); |
1196 | return ret; | 1200 | return ret; |
1197 | } /* end ehca_rereg_mr_rereg1() */ | 1201 | } /* end ehca_rereg_mr_rereg1() */ |
1198 | 1202 | ||
@@ -1214,10 +1218,12 @@ int ehca_rereg_mr(struct ehca_shca *shca, | |||
1214 | int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */ | 1218 | int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */ |
1215 | 1219 | ||
1216 | /* first determine reregistration hCall(s) */ | 1220 | /* first determine reregistration hCall(s) */ |
1217 | if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) || | 1221 | if ((pginfo->num_hwpages > MAX_RPAGES) || |
1218 | (pginfo->num_4k > e_mr->num_4k)) { | 1222 | (e_mr->num_hwpages > MAX_RPAGES) || |
1219 | ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx " | 1223 | (pginfo->num_hwpages > e_mr->num_hwpages)) { |
1220 | "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k); | 1224 | ehca_dbg(&shca->ib_device, "Rereg3 case, " |
1225 | "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x", | ||
1226 | pginfo->num_hwpages, e_mr->num_hwpages); | ||
1221 | rereg_1_hcall = 0; | 1227 | rereg_1_hcall = 0; |
1222 | rereg_3_hcall = 1; | 1228 | rereg_3_hcall = 1; |
1223 | } | 1229 | } |
@@ -1253,7 +1259,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, | |||
1253 | h_ret, e_mr, shca->ipz_hca_handle.handle, | 1259 | h_ret, e_mr, shca->ipz_hca_handle.handle, |
1254 | e_mr->ipz_mr_handle.handle, | 1260 | e_mr->ipz_mr_handle.handle, |
1255 | e_mr->ib.ib_mr.lkey); | 1261 | e_mr->ib.ib_mr.lkey); |
1256 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | 1262 | ret = ehca2ib_return_code(h_ret); |
1257 | goto ehca_rereg_mr_exit0; | 1263 | goto ehca_rereg_mr_exit0; |
1258 | } | 1264 | } |
1259 | /* clean ehca_mr_t, without changing struct ib_mr and lock */ | 1265 | /* clean ehca_mr_t, without changing struct ib_mr and lock */ |
@@ -1281,9 +1287,9 @@ ehca_rereg_mr_exit0: | |||
1281 | if (ret) | 1287 | if (ret) |
1282 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " | 1288 | ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " |
1283 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " | 1289 | "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " |
1284 | "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x " | 1290 | "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x " |
1285 | "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size, | 1291 | "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size, |
1286 | acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey, | 1292 | acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey, |
1287 | rereg_1_hcall, rereg_3_hcall); | 1293 | rereg_1_hcall, rereg_3_hcall); |
1288 | return ret; | 1294 | return ret; |
1289 | } /* end ehca_rereg_mr() */ | 1295 | } /* end ehca_rereg_mr() */ |
@@ -1295,97 +1301,86 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, | |||
1295 | { | 1301 | { |
1296 | int ret = 0; | 1302 | int ret = 0; |
1297 | u64 h_ret; | 1303 | u64 h_ret; |
1298 | int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */ | ||
1299 | int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */ | ||
1300 | struct ehca_pd *e_pd = | 1304 | struct ehca_pd *e_pd = |
1301 | container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd); | 1305 | container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd); |
1302 | struct ehca_mr save_fmr; | 1306 | struct ehca_mr save_fmr; |
1303 | u32 tmp_lkey, tmp_rkey; | 1307 | u32 tmp_lkey, tmp_rkey; |
1304 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 1308 | struct ehca_mr_pginfo pginfo; |
1305 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 1309 | struct ehca_mr_hipzout_parms hipzout; |
1310 | struct ehca_mr save_mr; | ||
1306 | 1311 | ||
1307 | /* first check if reregistration hCall can be used for unmap */ | 1312 | if (e_fmr->fmr_max_pages <= MAX_RPAGES) { |
1308 | if (e_fmr->fmr_max_pages > 512) { | ||
1309 | rereg_1_hcall = 0; | ||
1310 | rereg_3_hcall = 1; | ||
1311 | } | ||
1312 | |||
1313 | if (rereg_1_hcall) { | ||
1314 | /* | 1313 | /* |
1315 | * note: after using rereg hcall with len=0, | 1314 | * note: after using rereg hcall with len=0, |
1316 | * rereg hcall must be used again for registering pages | 1315 | * rereg hcall must be used again for registering pages |
1317 | */ | 1316 | */ |
1318 | h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0, | 1317 | h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0, |
1319 | 0, 0, e_pd->fw_pd, 0, &hipzout); | 1318 | 0, 0, e_pd->fw_pd, 0, &hipzout); |
1320 | if (h_ret != H_SUCCESS) { | 1319 | if (h_ret == H_SUCCESS) { |
1321 | /* | ||
1322 | * should not happen, because length checked above, | ||
1323 | * FMRs are not shared and no MW bound to FMRs | ||
1324 | */ | ||
1325 | ehca_err(&shca->ib_device, "hipz_reregister_pmr failed " | ||
1326 | "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx " | ||
1327 | "mr_hndl=%lx lkey=%x lkey_out=%x", | ||
1328 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | ||
1329 | e_fmr->ipz_mr_handle.handle, | ||
1330 | e_fmr->ib.ib_fmr.lkey, hipzout.lkey); | ||
1331 | rereg_3_hcall = 1; | ||
1332 | } else { | ||
1333 | /* successful reregistration */ | 1320 | /* successful reregistration */ |
1334 | e_fmr->start = NULL; | 1321 | e_fmr->start = NULL; |
1335 | e_fmr->size = 0; | 1322 | e_fmr->size = 0; |
1336 | tmp_lkey = hipzout.lkey; | 1323 | tmp_lkey = hipzout.lkey; |
1337 | tmp_rkey = hipzout.rkey; | 1324 | tmp_rkey = hipzout.rkey; |
1325 | return 0; | ||
1338 | } | 1326 | } |
1327 | /* | ||
1328 | * should not happen, because length checked above, | ||
1329 | * FMRs are not shared and no MW bound to FMRs | ||
1330 | */ | ||
1331 | ehca_err(&shca->ib_device, "hipz_reregister_pmr failed " | ||
1332 | "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx " | ||
1333 | "mr_hndl=%lx lkey=%x lkey_out=%x", | ||
1334 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | ||
1335 | e_fmr->ipz_mr_handle.handle, | ||
1336 | e_fmr->ib.ib_fmr.lkey, hipzout.lkey); | ||
1337 | /* try free and rereg */ | ||
1339 | } | 1338 | } |
1340 | 1339 | ||
1341 | if (rereg_3_hcall) { | 1340 | /* first free old FMR */ |
1342 | struct ehca_mr save_mr; | 1341 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); |
1343 | 1342 | if (h_ret != H_SUCCESS) { | |
1344 | /* first free old FMR */ | 1343 | ehca_err(&shca->ib_device, "hipz_free_mr failed, " |
1345 | h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); | 1344 | "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx " |
1346 | if (h_ret != H_SUCCESS) { | 1345 | "lkey=%x", |
1347 | ehca_err(&shca->ib_device, "hipz_free_mr failed, " | 1346 | h_ret, e_fmr, shca->ipz_hca_handle.handle, |
1348 | "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx " | 1347 | e_fmr->ipz_mr_handle.handle, |
1349 | "lkey=%x", | 1348 | e_fmr->ib.ib_fmr.lkey); |
1350 | h_ret, e_fmr, shca->ipz_hca_handle.handle, | 1349 | ret = ehca2ib_return_code(h_ret); |
1351 | e_fmr->ipz_mr_handle.handle, | 1350 | goto ehca_unmap_one_fmr_exit0; |
1352 | e_fmr->ib.ib_fmr.lkey); | 1351 | } |
1353 | ret = ehca_mrmw_map_hrc_free_mr(h_ret); | 1352 | /* clean ehca_mr_t, without changing lock */ |
1354 | goto ehca_unmap_one_fmr_exit0; | 1353 | save_fmr = *e_fmr; |
1355 | } | 1354 | ehca_mr_deletenew(e_fmr); |
1356 | /* clean ehca_mr_t, without changing lock */ | 1355 | |
1357 | save_fmr = *e_fmr; | 1356 | /* set some MR values */ |
1358 | ehca_mr_deletenew(e_fmr); | 1357 | e_fmr->flags = save_fmr.flags; |
1359 | 1358 | e_fmr->fmr_page_size = save_fmr.fmr_page_size; | |
1360 | /* set some MR values */ | 1359 | e_fmr->fmr_max_pages = save_fmr.fmr_max_pages; |
1361 | e_fmr->flags = save_fmr.flags; | 1360 | e_fmr->fmr_max_maps = save_fmr.fmr_max_maps; |
1362 | e_fmr->fmr_page_size = save_fmr.fmr_page_size; | 1361 | e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt; |
1363 | e_fmr->fmr_max_pages = save_fmr.fmr_max_pages; | 1362 | e_fmr->acl = save_fmr.acl; |
1364 | e_fmr->fmr_max_maps = save_fmr.fmr_max_maps; | 1363 | |
1365 | e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt; | 1364 | memset(&pginfo, 0, sizeof(pginfo)); |
1366 | e_fmr->acl = save_fmr.acl; | 1365 | pginfo.type = EHCA_MR_PGI_FMR; |
1367 | 1366 | pginfo.num_kpages = 0; | |
1368 | pginfo.type = EHCA_MR_PGI_FMR; | 1367 | pginfo.num_hwpages = 0; |
1369 | pginfo.num_pages = 0; | 1368 | ret = ehca_reg_mr(shca, e_fmr, NULL, |
1370 | pginfo.num_4k = 0; | 1369 | (e_fmr->fmr_max_pages * e_fmr->fmr_page_size), |
1371 | ret = ehca_reg_mr(shca, e_fmr, NULL, | 1370 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, |
1372 | (e_fmr->fmr_max_pages * e_fmr->fmr_page_size), | 1371 | &tmp_rkey); |
1373 | e_fmr->acl, e_pd, &pginfo, &tmp_lkey, | 1372 | if (ret) { |
1374 | &tmp_rkey); | 1373 | u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr; |
1375 | if (ret) { | 1374 | memcpy(&e_fmr->flags, &(save_mr.flags), |
1376 | u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr; | 1375 | sizeof(struct ehca_mr) - offset); |
1377 | memcpy(&e_fmr->flags, &(save_mr.flags), | 1376 | goto ehca_unmap_one_fmr_exit0; |
1378 | sizeof(struct ehca_mr) - offset); | ||
1379 | goto ehca_unmap_one_fmr_exit0; | ||
1380 | } | ||
1381 | } | 1377 | } |
1382 | 1378 | ||
1383 | ehca_unmap_one_fmr_exit0: | 1379 | ehca_unmap_one_fmr_exit0: |
1384 | if (ret) | 1380 | if (ret) |
1385 | ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x " | 1381 | ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x " |
1386 | "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x", | 1382 | "fmr_max_pages=%x", |
1387 | ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages, | 1383 | ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages); |
1388 | rereg_1_hcall, rereg_3_hcall); | ||
1389 | return ret; | 1384 | return ret; |
1390 | } /* end ehca_unmap_one_fmr() */ | 1385 | } /* end ehca_unmap_one_fmr() */ |
1391 | 1386 | ||
@@ -1403,7 +1398,7 @@ int ehca_reg_smr(struct ehca_shca *shca, | |||
1403 | int ret = 0; | 1398 | int ret = 0; |
1404 | u64 h_ret; | 1399 | u64 h_ret; |
1405 | u32 hipz_acl; | 1400 | u32 hipz_acl; |
1406 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 1401 | struct ehca_mr_hipzout_parms hipzout; |
1407 | 1402 | ||
1408 | ehca_mrmw_map_acl(acl, &hipz_acl); | 1403 | ehca_mrmw_map_acl(acl, &hipz_acl); |
1409 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | 1404 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); |
@@ -1419,15 +1414,15 @@ int ehca_reg_smr(struct ehca_shca *shca, | |||
1419 | shca->ipz_hca_handle.handle, | 1414 | shca->ipz_hca_handle.handle, |
1420 | e_origmr->ipz_mr_handle.handle, | 1415 | e_origmr->ipz_mr_handle.handle, |
1421 | e_origmr->ib.ib_mr.lkey); | 1416 | e_origmr->ib.ib_mr.lkey); |
1422 | ret = ehca_mrmw_map_hrc_reg_smr(h_ret); | 1417 | ret = ehca2ib_return_code(h_ret); |
1423 | goto ehca_reg_smr_exit0; | 1418 | goto ehca_reg_smr_exit0; |
1424 | } | 1419 | } |
1425 | /* successful registration */ | 1420 | /* successful registration */ |
1426 | e_newmr->num_pages = e_origmr->num_pages; | 1421 | e_newmr->num_kpages = e_origmr->num_kpages; |
1427 | e_newmr->num_4k = e_origmr->num_4k; | 1422 | e_newmr->num_hwpages = e_origmr->num_hwpages; |
1428 | e_newmr->start = iova_start; | 1423 | e_newmr->start = iova_start; |
1429 | e_newmr->size = e_origmr->size; | 1424 | e_newmr->size = e_origmr->size; |
1430 | e_newmr->acl = acl; | 1425 | e_newmr->acl = acl; |
1431 | e_newmr->ipz_mr_handle = hipzout.handle; | 1426 | e_newmr->ipz_mr_handle = hipzout.handle; |
1432 | *lkey = hipzout.lkey; | 1427 | *lkey = hipzout.lkey; |
1433 | *rkey = hipzout.rkey; | 1428 | *rkey = hipzout.rkey; |
@@ -1453,10 +1448,10 @@ int ehca_reg_internal_maxmr( | |||
1453 | struct ehca_mr *e_mr; | 1448 | struct ehca_mr *e_mr; |
1454 | u64 *iova_start; | 1449 | u64 *iova_start; |
1455 | u64 size_maxmr; | 1450 | u64 size_maxmr; |
1456 | struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0}; | 1451 | struct ehca_mr_pginfo pginfo; |
1457 | struct ib_phys_buf ib_pbuf; | 1452 | struct ib_phys_buf ib_pbuf; |
1458 | u32 num_pages_mr; | 1453 | u32 num_kpages; |
1459 | u32 num_pages_4k; /* 4k portion "pages" */ | 1454 | u32 num_hwpages; |
1460 | 1455 | ||
1461 | e_mr = ehca_mr_new(); | 1456 | e_mr = ehca_mr_new(); |
1462 | if (!e_mr) { | 1457 | if (!e_mr) { |
@@ -1468,28 +1463,29 @@ int ehca_reg_internal_maxmr( | |||
1468 | 1463 | ||
1469 | /* register internal max-MR on HCA */ | 1464 | /* register internal max-MR on HCA */ |
1470 | size_maxmr = (u64)high_memory - PAGE_OFFSET; | 1465 | size_maxmr = (u64)high_memory - PAGE_OFFSET; |
1471 | iova_start = (u64*)KERNELBASE; | 1466 | iova_start = (u64 *)KERNELBASE; |
1472 | ib_pbuf.addr = 0; | 1467 | ib_pbuf.addr = 0; |
1473 | ib_pbuf.size = size_maxmr; | 1468 | ib_pbuf.size = size_maxmr; |
1474 | num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr + | 1469 | num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr, |
1475 | PAGE_SIZE - 1) / PAGE_SIZE); | 1470 | PAGE_SIZE); |
1476 | num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr + | 1471 | num_hwpages = NUM_CHUNKS(((u64)iova_start % EHCA_PAGESIZE) + size_maxmr, |
1477 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE); | 1472 | EHCA_PAGESIZE); |
1478 | 1473 | ||
1479 | pginfo.type = EHCA_MR_PGI_PHYS; | 1474 | memset(&pginfo, 0, sizeof(pginfo)); |
1480 | pginfo.num_pages = num_pages_mr; | 1475 | pginfo.type = EHCA_MR_PGI_PHYS; |
1481 | pginfo.num_4k = num_pages_4k; | 1476 | pginfo.num_kpages = num_kpages; |
1482 | pginfo.num_phys_buf = 1; | 1477 | pginfo.num_hwpages = num_hwpages; |
1483 | pginfo.phys_buf_array = &ib_pbuf; | 1478 | pginfo.u.phy.num_phys_buf = 1; |
1479 | pginfo.u.phy.phys_buf_array = &ib_pbuf; | ||
1484 | 1480 | ||
1485 | ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd, | 1481 | ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd, |
1486 | &pginfo, &e_mr->ib.ib_mr.lkey, | 1482 | &pginfo, &e_mr->ib.ib_mr.lkey, |
1487 | &e_mr->ib.ib_mr.rkey); | 1483 | &e_mr->ib.ib_mr.rkey); |
1488 | if (ret) { | 1484 | if (ret) { |
1489 | ehca_err(&shca->ib_device, "reg of internal max MR failed, " | 1485 | ehca_err(&shca->ib_device, "reg of internal max MR failed, " |
1490 | "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x " | 1486 | "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x " |
1491 | "num_pages_4k=%x", e_mr, iova_start, size_maxmr, | 1487 | "num_hwpages=%x", e_mr, iova_start, size_maxmr, |
1492 | num_pages_mr, num_pages_4k); | 1488 | num_kpages, num_hwpages); |
1493 | goto ehca_reg_internal_maxmr_exit1; | 1489 | goto ehca_reg_internal_maxmr_exit1; |
1494 | } | 1490 | } |
1495 | 1491 | ||
@@ -1524,7 +1520,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca, | |||
1524 | u64 h_ret; | 1520 | u64 h_ret; |
1525 | struct ehca_mr *e_origmr = shca->maxmr; | 1521 | struct ehca_mr *e_origmr = shca->maxmr; |
1526 | u32 hipz_acl; | 1522 | u32 hipz_acl; |
1527 | struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0}; | 1523 | struct ehca_mr_hipzout_parms hipzout; |
1528 | 1524 | ||
1529 | ehca_mrmw_map_acl(acl, &hipz_acl); | 1525 | ehca_mrmw_map_acl(acl, &hipz_acl); |
1530 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); | 1526 | ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl); |
@@ -1538,14 +1534,14 @@ int ehca_reg_maxmr(struct ehca_shca *shca, | |||
1538 | h_ret, e_origmr, shca->ipz_hca_handle.handle, | 1534 | h_ret, e_origmr, shca->ipz_hca_handle.handle, |
1539 | e_origmr->ipz_mr_handle.handle, | 1535 | e_origmr->ipz_mr_handle.handle, |
1540 | e_origmr->ib.ib_mr.lkey); | 1536 | e_origmr->ib.ib_mr.lkey); |
1541 | return ehca_mrmw_map_hrc_reg_smr(h_ret); | 1537 | return ehca2ib_return_code(h_ret); |
1542 | } | 1538 | } |
1543 | /* successful registration */ | 1539 | /* successful registration */ |
1544 | e_newmr->num_pages = e_origmr->num_pages; | 1540 | e_newmr->num_kpages = e_origmr->num_kpages; |
1545 | e_newmr->num_4k = e_origmr->num_4k; | 1541 | e_newmr->num_hwpages = e_origmr->num_hwpages; |
1546 | e_newmr->start = iova_start; | 1542 | e_newmr->start = iova_start; |
1547 | e_newmr->size = e_origmr->size; | 1543 | e_newmr->size = e_origmr->size; |
1548 | e_newmr->acl = acl; | 1544 | e_newmr->acl = acl; |
1549 | e_newmr->ipz_mr_handle = hipzout.handle; | 1545 | e_newmr->ipz_mr_handle = hipzout.handle; |
1550 | *lkey = hipzout.lkey; | 1546 | *lkey = hipzout.lkey; |
1551 | *rkey = hipzout.rkey; | 1547 | *rkey = hipzout.rkey; |
@@ -1677,299 +1673,187 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr, | |||
1677 | 1673 | ||
1678 | /*----------------------------------------------------------------------*/ | 1674 | /*----------------------------------------------------------------------*/ |
1679 | 1675 | ||
1680 | /* setup page buffer from page info */ | 1676 | /* PAGE_SIZE >= pginfo->hwpage_size */ |
1681 | int ehca_set_pagebuf(struct ehca_mr *e_mr, | 1677 | static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo, |
1682 | struct ehca_mr_pginfo *pginfo, | 1678 | u32 number, |
1683 | u32 number, | 1679 | u64 *kpage) |
1684 | u64 *kpage) | ||
1685 | { | 1680 | { |
1686 | int ret = 0; | 1681 | int ret = 0; |
1687 | struct ib_umem_chunk *prev_chunk; | 1682 | struct ib_umem_chunk *prev_chunk; |
1688 | struct ib_umem_chunk *chunk; | 1683 | struct ib_umem_chunk *chunk; |
1689 | struct ib_phys_buf *pbuf; | 1684 | u64 pgaddr; |
1690 | u64 *fmrlist; | ||
1691 | u64 num4k, pgaddr, offs4k; | ||
1692 | u32 i = 0; | 1685 | u32 i = 0; |
1693 | u32 j = 0; | 1686 | u32 j = 0; |
1694 | 1687 | ||
1695 | if (pginfo->type == EHCA_MR_PGI_PHYS) { | 1688 | /* loop over desired chunk entries */ |
1696 | /* loop over desired phys_buf_array entries */ | 1689 | chunk = pginfo->u.usr.next_chunk; |
1697 | while (i < number) { | 1690 | prev_chunk = pginfo->u.usr.next_chunk; |
1698 | pbuf = pginfo->phys_buf_array + pginfo->next_buf; | 1691 | list_for_each_entry_continue( |
1699 | num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size + | 1692 | chunk, (&(pginfo->u.usr.region->chunk_list)), list) { |
1700 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE; | 1693 | for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) { |
1701 | offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE; | 1694 | pgaddr = page_to_pfn(chunk->page_list[i].page) |
1702 | while (pginfo->next_4k < offs4k + num4k) { | 1695 | << PAGE_SHIFT ; |
1703 | /* sanity check */ | 1696 | *kpage = phys_to_abs(pgaddr + |
1704 | if ((pginfo->page_cnt >= pginfo->num_pages) || | 1697 | (pginfo->next_hwpage * |
1705 | (pginfo->page_4k_cnt >= pginfo->num_4k)) { | 1698 | EHCA_PAGESIZE)); |
1706 | ehca_gen_err("page_cnt >= num_pages, " | ||
1707 | "page_cnt=%lx " | ||
1708 | "num_pages=%lx " | ||
1709 | "page_4k_cnt=%lx " | ||
1710 | "num_4k=%lx i=%x", | ||
1711 | pginfo->page_cnt, | ||
1712 | pginfo->num_pages, | ||
1713 | pginfo->page_4k_cnt, | ||
1714 | pginfo->num_4k, i); | ||
1715 | ret = -EFAULT; | ||
1716 | goto ehca_set_pagebuf_exit0; | ||
1717 | } | ||
1718 | *kpage = phys_to_abs( | ||
1719 | (pbuf->addr & EHCA_PAGEMASK) | ||
1720 | + (pginfo->next_4k * EHCA_PAGESIZE)); | ||
1721 | if ( !(*kpage) && pbuf->addr ) { | ||
1722 | ehca_gen_err("pbuf->addr=%lx " | ||
1723 | "pbuf->size=%lx " | ||
1724 | "next_4k=%lx", pbuf->addr, | ||
1725 | pbuf->size, | ||
1726 | pginfo->next_4k); | ||
1727 | ret = -EFAULT; | ||
1728 | goto ehca_set_pagebuf_exit0; | ||
1729 | } | ||
1730 | (pginfo->page_4k_cnt)++; | ||
1731 | (pginfo->next_4k)++; | ||
1732 | if (pginfo->next_4k % | ||
1733 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) | ||
1734 | (pginfo->page_cnt)++; | ||
1735 | kpage++; | ||
1736 | i++; | ||
1737 | if (i >= number) break; | ||
1738 | } | ||
1739 | if (pginfo->next_4k >= offs4k + num4k) { | ||
1740 | (pginfo->next_buf)++; | ||
1741 | pginfo->next_4k = 0; | ||
1742 | } | ||
1743 | } | ||
1744 | } else if (pginfo->type == EHCA_MR_PGI_USER) { | ||
1745 | /* loop over desired chunk entries */ | ||
1746 | chunk = pginfo->next_chunk; | ||
1747 | prev_chunk = pginfo->next_chunk; | ||
1748 | list_for_each_entry_continue(chunk, | ||
1749 | (&(pginfo->region->chunk_list)), | ||
1750 | list) { | ||
1751 | for (i = pginfo->next_nmap; i < chunk->nmap; ) { | ||
1752 | pgaddr = ( page_to_pfn(chunk->page_list[i].page) | ||
1753 | << PAGE_SHIFT ); | ||
1754 | *kpage = phys_to_abs(pgaddr + | ||
1755 | (pginfo->next_4k * | ||
1756 | EHCA_PAGESIZE)); | ||
1757 | if ( !(*kpage) ) { | ||
1758 | ehca_gen_err("pgaddr=%lx " | ||
1759 | "chunk->page_list[i]=%lx " | ||
1760 | "i=%x next_4k=%lx mr=%p", | ||
1761 | pgaddr, | ||
1762 | (u64)sg_dma_address( | ||
1763 | &chunk-> | ||
1764 | page_list[i]), | ||
1765 | i, pginfo->next_4k, e_mr); | ||
1766 | ret = -EFAULT; | ||
1767 | goto ehca_set_pagebuf_exit0; | ||
1768 | } | ||
1769 | (pginfo->page_4k_cnt)++; | ||
1770 | (pginfo->next_4k)++; | ||
1771 | kpage++; | ||
1772 | if (pginfo->next_4k % | ||
1773 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) { | ||
1774 | (pginfo->page_cnt)++; | ||
1775 | (pginfo->next_nmap)++; | ||
1776 | pginfo->next_4k = 0; | ||
1777 | i++; | ||
1778 | } | ||
1779 | j++; | ||
1780 | if (j >= number) break; | ||
1781 | } | ||
1782 | if ((pginfo->next_nmap >= chunk->nmap) && | ||
1783 | (j >= number)) { | ||
1784 | pginfo->next_nmap = 0; | ||
1785 | prev_chunk = chunk; | ||
1786 | break; | ||
1787 | } else if (pginfo->next_nmap >= chunk->nmap) { | ||
1788 | pginfo->next_nmap = 0; | ||
1789 | prev_chunk = chunk; | ||
1790 | } else if (j >= number) | ||
1791 | break; | ||
1792 | else | ||
1793 | prev_chunk = chunk; | ||
1794 | } | ||
1795 | pginfo->next_chunk = | ||
1796 | list_prepare_entry(prev_chunk, | ||
1797 | (&(pginfo->region->chunk_list)), | ||
1798 | list); | ||
1799 | } else if (pginfo->type == EHCA_MR_PGI_FMR) { | ||
1800 | /* loop over desired page_list entries */ | ||
1801 | fmrlist = pginfo->page_list + pginfo->next_listelem; | ||
1802 | for (i = 0; i < number; i++) { | ||
1803 | *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) + | ||
1804 | pginfo->next_4k * EHCA_PAGESIZE); | ||
1805 | if ( !(*kpage) ) { | 1699 | if ( !(*kpage) ) { |
1806 | ehca_gen_err("*fmrlist=%lx fmrlist=%p " | 1700 | ehca_gen_err("pgaddr=%lx " |
1807 | "next_listelem=%lx next_4k=%lx", | 1701 | "chunk->page_list[i]=%lx " |
1808 | *fmrlist, fmrlist, | 1702 | "i=%x next_hwpage=%lx", |
1809 | pginfo->next_listelem, | 1703 | pgaddr, (u64)sg_dma_address( |
1810 | pginfo->next_4k); | 1704 | &chunk->page_list[i]), |
1811 | ret = -EFAULT; | 1705 | i, pginfo->next_hwpage); |
1812 | goto ehca_set_pagebuf_exit0; | 1706 | return -EFAULT; |
1813 | } | 1707 | } |
1814 | (pginfo->page_4k_cnt)++; | 1708 | (pginfo->hwpage_cnt)++; |
1815 | (pginfo->next_4k)++; | 1709 | (pginfo->next_hwpage)++; |
1816 | kpage++; | 1710 | kpage++; |
1817 | if (pginfo->next_4k % | 1711 | if (pginfo->next_hwpage % |
1818 | (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) { | 1712 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) { |
1819 | (pginfo->page_cnt)++; | 1713 | (pginfo->kpage_cnt)++; |
1820 | (pginfo->next_listelem)++; | 1714 | (pginfo->u.usr.next_nmap)++; |
1821 | fmrlist++; | 1715 | pginfo->next_hwpage = 0; |
1822 | pginfo->next_4k = 0; | 1716 | i++; |
1823 | } | 1717 | } |
1718 | j++; | ||
1719 | if (j >= number) break; | ||
1824 | } | 1720 | } |
1825 | } else { | 1721 | if ((pginfo->u.usr.next_nmap >= chunk->nmap) && |
1826 | ehca_gen_err("bad pginfo->type=%x", pginfo->type); | 1722 | (j >= number)) { |
1827 | ret = -EFAULT; | 1723 | pginfo->u.usr.next_nmap = 0; |
1828 | goto ehca_set_pagebuf_exit0; | 1724 | prev_chunk = chunk; |
1725 | break; | ||
1726 | } else if (pginfo->u.usr.next_nmap >= chunk->nmap) { | ||
1727 | pginfo->u.usr.next_nmap = 0; | ||
1728 | prev_chunk = chunk; | ||
1729 | } else if (j >= number) | ||
1730 | break; | ||
1731 | else | ||
1732 | prev_chunk = chunk; | ||
1829 | } | 1733 | } |
1830 | 1734 | pginfo->u.usr.next_chunk = | |
1831 | ehca_set_pagebuf_exit0: | 1735 | list_prepare_entry(prev_chunk, |
1832 | if (ret) | 1736 | (&(pginfo->u.usr.region->chunk_list)), |
1833 | ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx " | 1737 | list); |
1834 | "num_4k=%lx next_buf=%lx next_4k=%lx number=%x " | ||
1835 | "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x " | ||
1836 | "next_listelem=%lx region=%p next_chunk=%p " | ||
1837 | "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type, | ||
1838 | pginfo->num_pages, pginfo->num_4k, | ||
1839 | pginfo->next_buf, pginfo->next_4k, number, kpage, | ||
1840 | pginfo->page_cnt, pginfo->page_4k_cnt, i, | ||
1841 | pginfo->next_listelem, pginfo->region, | ||
1842 | pginfo->next_chunk, pginfo->next_nmap); | ||
1843 | return ret; | 1738 | return ret; |
1844 | } /* end ehca_set_pagebuf() */ | 1739 | } |
1845 | |||
1846 | /*----------------------------------------------------------------------*/ | ||
1847 | 1740 | ||
1848 | /* setup 1 page from page info page buffer */ | 1741 | int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo, |
1849 | int ehca_set_pagebuf_1(struct ehca_mr *e_mr, | 1742 | u32 number, |
1850 | struct ehca_mr_pginfo *pginfo, | 1743 | u64 *kpage) |
1851 | u64 *rpage) | ||
1852 | { | 1744 | { |
1853 | int ret = 0; | 1745 | int ret = 0; |
1854 | struct ib_phys_buf *tmp_pbuf; | 1746 | struct ib_phys_buf *pbuf; |
1855 | u64 *fmrlist; | 1747 | u64 num_hw, offs_hw; |
1856 | struct ib_umem_chunk *chunk; | 1748 | u32 i = 0; |
1857 | struct ib_umem_chunk *prev_chunk; | 1749 | |
1858 | u64 pgaddr, num4k, offs4k; | 1750 | /* loop over desired phys_buf_array entries */ |
1859 | 1751 | while (i < number) { | |
1860 | if (pginfo->type == EHCA_MR_PGI_PHYS) { | 1752 | pbuf = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf; |
1861 | /* sanity check */ | 1753 | num_hw = NUM_CHUNKS((pbuf->addr % EHCA_PAGESIZE) + |
1862 | if ((pginfo->page_cnt >= pginfo->num_pages) || | 1754 | pbuf->size, EHCA_PAGESIZE); |
1863 | (pginfo->page_4k_cnt >= pginfo->num_4k)) { | 1755 | offs_hw = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE; |
1864 | ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx " | 1756 | while (pginfo->next_hwpage < offs_hw + num_hw) { |
1865 | "num_pages=%lx page_4k_cnt=%lx num_4k=%lx", | 1757 | /* sanity check */ |
1866 | pginfo->page_cnt, pginfo->num_pages, | 1758 | if ((pginfo->kpage_cnt >= pginfo->num_kpages) || |
1867 | pginfo->page_4k_cnt, pginfo->num_4k); | 1759 | (pginfo->hwpage_cnt >= pginfo->num_hwpages)) { |
1868 | ret = -EFAULT; | 1760 | ehca_gen_err("kpage_cnt >= num_kpages, " |
1869 | goto ehca_set_pagebuf_1_exit0; | 1761 | "kpage_cnt=%lx num_kpages=%lx " |
1870 | } | 1762 | "hwpage_cnt=%lx " |
1871 | tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf; | 1763 | "num_hwpages=%lx i=%x", |
1872 | num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size + | 1764 | pginfo->kpage_cnt, |
1873 | EHCA_PAGESIZE - 1) / EHCA_PAGESIZE; | 1765 | pginfo->num_kpages, |
1874 | offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE; | 1766 | pginfo->hwpage_cnt, |
1875 | *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) + | 1767 | pginfo->num_hwpages, i); |
1876 | (pginfo->next_4k * EHCA_PAGESIZE)); | 1768 | return -EFAULT; |
1877 | if ( !(*rpage) && tmp_pbuf->addr ) { | ||
1878 | ehca_gen_err("tmp_pbuf->addr=%lx" | ||
1879 | " tmp_pbuf->size=%lx next_4k=%lx", | ||
1880 | tmp_pbuf->addr, tmp_pbuf->size, | ||
1881 | pginfo->next_4k); | ||
1882 | ret = -EFAULT; | ||
1883 | goto ehca_set_pagebuf_1_exit0; | ||
1884 | } | ||
1885 | (pginfo->page_4k_cnt)++; | ||
1886 | (pginfo->next_4k)++; | ||
1887 | if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0) | ||
1888 | (pginfo->page_cnt)++; | ||
1889 | if (pginfo->next_4k >= offs4k + num4k) { | ||
1890 | (pginfo->next_buf)++; | ||
1891 | pginfo->next_4k = 0; | ||
1892 | } | ||
1893 | } else if (pginfo->type == EHCA_MR_PGI_USER) { | ||
1894 | chunk = pginfo->next_chunk; | ||
1895 | prev_chunk = pginfo->next_chunk; | ||
1896 | list_for_each_entry_continue(chunk, | ||
1897 | (&(pginfo->region->chunk_list)), | ||
1898 | list) { | ||
1899 | pgaddr = ( page_to_pfn(chunk->page_list[ | ||
1900 | pginfo->next_nmap].page) | ||
1901 | << PAGE_SHIFT); | ||
1902 | *rpage = phys_to_abs(pgaddr + | ||
1903 | (pginfo->next_4k * EHCA_PAGESIZE)); | ||
1904 | if ( !(*rpage) ) { | ||
1905 | ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx" | ||
1906 | " next_nmap=%lx next_4k=%lx mr=%p", | ||
1907 | pgaddr, (u64)sg_dma_address( | ||
1908 | &chunk->page_list[ | ||
1909 | pginfo-> | ||
1910 | next_nmap]), | ||
1911 | pginfo->next_nmap, pginfo->next_4k, | ||
1912 | e_mr); | ||
1913 | ret = -EFAULT; | ||
1914 | goto ehca_set_pagebuf_1_exit0; | ||
1915 | } | ||
1916 | (pginfo->page_4k_cnt)++; | ||
1917 | (pginfo->next_4k)++; | ||
1918 | if (pginfo->next_4k % | ||
1919 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) { | ||
1920 | (pginfo->page_cnt)++; | ||
1921 | (pginfo->next_nmap)++; | ||
1922 | pginfo->next_4k = 0; | ||
1923 | } | 1769 | } |
1924 | if (pginfo->next_nmap >= chunk->nmap) { | 1770 | *kpage = phys_to_abs( |
1925 | pginfo->next_nmap = 0; | 1771 | (pbuf->addr & EHCA_PAGEMASK) |
1926 | prev_chunk = chunk; | 1772 | + (pginfo->next_hwpage * EHCA_PAGESIZE)); |
1773 | if ( !(*kpage) && pbuf->addr ) { | ||
1774 | ehca_gen_err("pbuf->addr=%lx " | ||
1775 | "pbuf->size=%lx " | ||
1776 | "next_hwpage=%lx", pbuf->addr, | ||
1777 | pbuf->size, | ||
1778 | pginfo->next_hwpage); | ||
1779 | return -EFAULT; | ||
1927 | } | 1780 | } |
1928 | break; | 1781 | (pginfo->hwpage_cnt)++; |
1782 | (pginfo->next_hwpage)++; | ||
1783 | if (pginfo->next_hwpage % | ||
1784 | (PAGE_SIZE / EHCA_PAGESIZE) == 0) | ||
1785 | (pginfo->kpage_cnt)++; | ||
1786 | kpage++; | ||
1787 | i++; | ||
1788 | if (i >= number) break; | ||
1789 | } | ||
1790 | if (pginfo->next_hwpage >= offs_hw + num_hw) { | ||
1791 | (pginfo->u.phy.next_buf)++; | ||
1792 | pginfo->next_hwpage = 0; | ||
1929 | } | 1793 | } |
1930 | pginfo->next_chunk = | 1794 | } |
1931 | list_prepare_entry(prev_chunk, | 1795 | return ret; |
1932 | (&(pginfo->region->chunk_list)), | 1796 | } |
1933 | list); | 1797 | |
1934 | } else if (pginfo->type == EHCA_MR_PGI_FMR) { | 1798 | int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo, |
1935 | fmrlist = pginfo->page_list + pginfo->next_listelem; | 1799 | u32 number, |
1936 | *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) + | 1800 | u64 *kpage) |
1937 | pginfo->next_4k * EHCA_PAGESIZE); | 1801 | { |
1938 | if ( !(*rpage) ) { | 1802 | int ret = 0; |
1803 | u64 *fmrlist; | ||
1804 | u32 i; | ||
1805 | |||
1806 | /* loop over desired page_list entries */ | ||
1807 | fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem; | ||
1808 | for (i = 0; i < number; i++) { | ||
1809 | *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) + | ||
1810 | pginfo->next_hwpage * EHCA_PAGESIZE); | ||
1811 | if ( !(*kpage) ) { | ||
1939 | ehca_gen_err("*fmrlist=%lx fmrlist=%p " | 1812 | ehca_gen_err("*fmrlist=%lx fmrlist=%p " |
1940 | "next_listelem=%lx next_4k=%lx", | 1813 | "next_listelem=%lx next_hwpage=%lx", |
1941 | *fmrlist, fmrlist, pginfo->next_listelem, | 1814 | *fmrlist, fmrlist, |
1942 | pginfo->next_4k); | 1815 | pginfo->u.fmr.next_listelem, |
1943 | ret = -EFAULT; | 1816 | pginfo->next_hwpage); |
1944 | goto ehca_set_pagebuf_1_exit0; | 1817 | return -EFAULT; |
1945 | } | 1818 | } |
1946 | (pginfo->page_4k_cnt)++; | 1819 | (pginfo->hwpage_cnt)++; |
1947 | (pginfo->next_4k)++; | 1820 | (pginfo->next_hwpage)++; |
1948 | if (pginfo->next_4k % | 1821 | kpage++; |
1949 | (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) { | 1822 | if (pginfo->next_hwpage % |
1950 | (pginfo->page_cnt)++; | 1823 | (pginfo->u.fmr.fmr_pgsize / EHCA_PAGESIZE) == 0) { |
1951 | (pginfo->next_listelem)++; | 1824 | (pginfo->kpage_cnt)++; |
1952 | pginfo->next_4k = 0; | 1825 | (pginfo->u.fmr.next_listelem)++; |
1826 | fmrlist++; | ||
1827 | pginfo->next_hwpage = 0; | ||
1953 | } | 1828 | } |
1954 | } else { | 1829 | } |
1830 | return ret; | ||
1831 | } | ||
1832 | |||
1833 | /* setup page buffer from page info */ | ||
1834 | int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo, | ||
1835 | u32 number, | ||
1836 | u64 *kpage) | ||
1837 | { | ||
1838 | int ret; | ||
1839 | |||
1840 | switch (pginfo->type) { | ||
1841 | case EHCA_MR_PGI_PHYS: | ||
1842 | ret = ehca_set_pagebuf_phys(pginfo, number, kpage); | ||
1843 | break; | ||
1844 | case EHCA_MR_PGI_USER: | ||
1845 | ret = ehca_set_pagebuf_user1(pginfo, number, kpage); | ||
1846 | break; | ||
1847 | case EHCA_MR_PGI_FMR: | ||
1848 | ret = ehca_set_pagebuf_fmr(pginfo, number, kpage); | ||
1849 | break; | ||
1850 | default: | ||
1955 | ehca_gen_err("bad pginfo->type=%x", pginfo->type); | 1851 | ehca_gen_err("bad pginfo->type=%x", pginfo->type); |
1956 | ret = -EFAULT; | 1852 | ret = -EFAULT; |
1957 | goto ehca_set_pagebuf_1_exit0; | 1853 | break; |
1958 | } | 1854 | } |
1959 | |||
1960 | ehca_set_pagebuf_1_exit0: | ||
1961 | if (ret) | ||
1962 | ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx " | ||
1963 | "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p " | ||
1964 | "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx " | ||
1965 | "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr, | ||
1966 | pginfo, pginfo->type, pginfo->num_pages, | ||
1967 | pginfo->num_4k, pginfo->next_buf, pginfo->next_4k, | ||
1968 | rpage, pginfo->page_cnt, pginfo->page_4k_cnt, | ||
1969 | pginfo->next_listelem, pginfo->region, | ||
1970 | pginfo->next_chunk, pginfo->next_nmap); | ||
1971 | return ret; | 1855 | return ret; |
1972 | } /* end ehca_set_pagebuf_1() */ | 1856 | } /* end ehca_set_pagebuf() */ |
1973 | 1857 | ||
1974 | /*----------------------------------------------------------------------*/ | 1858 | /*----------------------------------------------------------------------*/ |
1975 | 1859 | ||
@@ -1982,7 +1866,7 @@ int ehca_mr_is_maxmr(u64 size, | |||
1982 | { | 1866 | { |
1983 | /* a MR is treated as max-MR only if it fits following: */ | 1867 | /* a MR is treated as max-MR only if it fits following: */ |
1984 | if ((size == ((u64)high_memory - PAGE_OFFSET)) && | 1868 | if ((size == ((u64)high_memory - PAGE_OFFSET)) && |
1985 | (iova_start == (void*)KERNELBASE)) { | 1869 | (iova_start == (void *)KERNELBASE)) { |
1986 | ehca_gen_dbg("this is a max-MR"); | 1870 | ehca_gen_dbg("this is a max-MR"); |
1987 | return 1; | 1871 | return 1; |
1988 | } else | 1872 | } else |
@@ -2042,196 +1926,23 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, | |||
2042 | /*----------------------------------------------------------------------*/ | 1926 | /*----------------------------------------------------------------------*/ |
2043 | 1927 | ||
2044 | /* | 1928 | /* |
2045 | * map HIPZ rc to IB retcodes for MR/MW allocations | ||
2046 | * Used for hipz_mr_reg_alloc and hipz_mw_alloc. | ||
2047 | */ | ||
2048 | int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc) | ||
2049 | { | ||
2050 | switch (hipz_rc) { | ||
2051 | case H_SUCCESS: /* successful completion */ | ||
2052 | return 0; | ||
2053 | case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ | ||
2054 | case H_CONSTRAINED: /* resource constraint */ | ||
2055 | case H_NO_MEM: | ||
2056 | return -ENOMEM; | ||
2057 | case H_BUSY: /* long busy */ | ||
2058 | return -EBUSY; | ||
2059 | default: | ||
2060 | return -EINVAL; | ||
2061 | } | ||
2062 | } /* end ehca_mrmw_map_hrc_alloc() */ | ||
2063 | |||
2064 | /*----------------------------------------------------------------------*/ | ||
2065 | |||
2066 | /* | ||
2067 | * map HIPZ rc to IB retcodes for MR register rpage | ||
2068 | * Used for hipz_h_register_rpage_mr at registering last page | ||
2069 | */ | ||
2070 | int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc) | ||
2071 | { | ||
2072 | switch (hipz_rc) { | ||
2073 | case H_SUCCESS: /* registration complete */ | ||
2074 | return 0; | ||
2075 | case H_PAGE_REGISTERED: /* page registered */ | ||
2076 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2077 | case H_RH_PARM: /* invalid resource handle */ | ||
2078 | /* case H_QT_PARM: invalid queue type */ | ||
2079 | case H_PARAMETER: /* | ||
2080 | * invalid logical address, | ||
2081 | * or count zero or greater 512 | ||
2082 | */ | ||
2083 | case H_TABLE_FULL: /* page table full */ | ||
2084 | case H_HARDWARE: /* HCA not operational */ | ||
2085 | return -EINVAL; | ||
2086 | case H_BUSY: /* long busy */ | ||
2087 | return -EBUSY; | ||
2088 | default: | ||
2089 | return -EINVAL; | ||
2090 | } | ||
2091 | } /* end ehca_mrmw_map_hrc_rrpg_last() */ | ||
2092 | |||
2093 | /*----------------------------------------------------------------------*/ | ||
2094 | |||
2095 | /* | ||
2096 | * map HIPZ rc to IB retcodes for MR register rpage | ||
2097 | * Used for hipz_h_register_rpage_mr at registering one page, but not last page | ||
2098 | */ | ||
2099 | int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc) | ||
2100 | { | ||
2101 | switch (hipz_rc) { | ||
2102 | case H_PAGE_REGISTERED: /* page registered */ | ||
2103 | return 0; | ||
2104 | case H_SUCCESS: /* registration complete */ | ||
2105 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2106 | case H_RH_PARM: /* invalid resource handle */ | ||
2107 | /* case H_QT_PARM: invalid queue type */ | ||
2108 | case H_PARAMETER: /* | ||
2109 | * invalid logical address, | ||
2110 | * or count zero or greater 512 | ||
2111 | */ | ||
2112 | case H_TABLE_FULL: /* page table full */ | ||
2113 | case H_HARDWARE: /* HCA not operational */ | ||
2114 | return -EINVAL; | ||
2115 | case H_BUSY: /* long busy */ | ||
2116 | return -EBUSY; | ||
2117 | default: | ||
2118 | return -EINVAL; | ||
2119 | } | ||
2120 | } /* end ehca_mrmw_map_hrc_rrpg_notlast() */ | ||
2121 | |||
2122 | /*----------------------------------------------------------------------*/ | ||
2123 | |||
2124 | /* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */ | ||
2125 | int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc) | ||
2126 | { | ||
2127 | switch (hipz_rc) { | ||
2128 | case H_SUCCESS: /* successful completion */ | ||
2129 | return 0; | ||
2130 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2131 | case H_RH_PARM: /* invalid resource handle */ | ||
2132 | return -EINVAL; | ||
2133 | case H_BUSY: /* long busy */ | ||
2134 | return -EBUSY; | ||
2135 | default: | ||
2136 | return -EINVAL; | ||
2137 | } | ||
2138 | } /* end ehca_mrmw_map_hrc_query_mr() */ | ||
2139 | |||
2140 | /*----------------------------------------------------------------------*/ | ||
2141 | /*----------------------------------------------------------------------*/ | ||
2142 | |||
2143 | /* | ||
2144 | * map HIPZ rc to IB retcodes for freeing MR resource | ||
2145 | * Used for hipz_h_free_resource_mr | ||
2146 | */ | ||
2147 | int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc) | ||
2148 | { | ||
2149 | switch (hipz_rc) { | ||
2150 | case H_SUCCESS: /* resource freed */ | ||
2151 | return 0; | ||
2152 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2153 | case H_RH_PARM: /* invalid resource handle */ | ||
2154 | case H_R_STATE: /* invalid resource state */ | ||
2155 | case H_HARDWARE: /* HCA not operational */ | ||
2156 | return -EINVAL; | ||
2157 | case H_RESOURCE: /* Resource in use */ | ||
2158 | case H_BUSY: /* long busy */ | ||
2159 | return -EBUSY; | ||
2160 | default: | ||
2161 | return -EINVAL; | ||
2162 | } | ||
2163 | } /* end ehca_mrmw_map_hrc_free_mr() */ | ||
2164 | |||
2165 | /*----------------------------------------------------------------------*/ | ||
2166 | |||
2167 | /* | ||
2168 | * map HIPZ rc to IB retcodes for freeing MW resource | ||
2169 | * Used for hipz_h_free_resource_mw | ||
2170 | */ | ||
2171 | int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc) | ||
2172 | { | ||
2173 | switch (hipz_rc) { | ||
2174 | case H_SUCCESS: /* resource freed */ | ||
2175 | return 0; | ||
2176 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2177 | case H_RH_PARM: /* invalid resource handle */ | ||
2178 | case H_R_STATE: /* invalid resource state */ | ||
2179 | case H_HARDWARE: /* HCA not operational */ | ||
2180 | return -EINVAL; | ||
2181 | case H_RESOURCE: /* Resource in use */ | ||
2182 | case H_BUSY: /* long busy */ | ||
2183 | return -EBUSY; | ||
2184 | default: | ||
2185 | return -EINVAL; | ||
2186 | } | ||
2187 | } /* end ehca_mrmw_map_hrc_free_mw() */ | ||
2188 | |||
2189 | /*----------------------------------------------------------------------*/ | ||
2190 | |||
2191 | /* | ||
2192 | * map HIPZ rc to IB retcodes for SMR registrations | ||
2193 | * Used for hipz_h_register_smr. | ||
2194 | */ | ||
2195 | int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc) | ||
2196 | { | ||
2197 | switch (hipz_rc) { | ||
2198 | case H_SUCCESS: /* successful completion */ | ||
2199 | return 0; | ||
2200 | case H_ADAPTER_PARM: /* invalid adapter handle */ | ||
2201 | case H_RH_PARM: /* invalid resource handle */ | ||
2202 | case H_MEM_PARM: /* invalid MR virtual address */ | ||
2203 | case H_MEM_ACCESS_PARM: /* invalid access controls */ | ||
2204 | case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ | ||
2205 | return -EINVAL; | ||
2206 | case H_BUSY: /* long busy */ | ||
2207 | return -EBUSY; | ||
2208 | default: | ||
2209 | return -EINVAL; | ||
2210 | } | ||
2211 | } /* end ehca_mrmw_map_hrc_reg_smr() */ | ||
2212 | |||
2213 | /*----------------------------------------------------------------------*/ | ||
2214 | |||
2215 | /* | ||
2216 | * MR destructor and constructor | 1929 | * MR destructor and constructor |
2217 | * used in Reregister MR verb, sets all fields in ehca_mr_t to 0, | 1930 | * used in Reregister MR verb, sets all fields in ehca_mr_t to 0, |
2218 | * except struct ib_mr and spinlock | 1931 | * except struct ib_mr and spinlock |
2219 | */ | 1932 | */ |
2220 | void ehca_mr_deletenew(struct ehca_mr *mr) | 1933 | void ehca_mr_deletenew(struct ehca_mr *mr) |
2221 | { | 1934 | { |
2222 | mr->flags = 0; | 1935 | mr->flags = 0; |
2223 | mr->num_pages = 0; | 1936 | mr->num_kpages = 0; |
2224 | mr->num_4k = 0; | 1937 | mr->num_hwpages = 0; |
2225 | mr->acl = 0; | 1938 | mr->acl = 0; |
2226 | mr->start = NULL; | 1939 | mr->start = NULL; |
2227 | mr->fmr_page_size = 0; | 1940 | mr->fmr_page_size = 0; |
2228 | mr->fmr_max_pages = 0; | 1941 | mr->fmr_max_pages = 0; |
2229 | mr->fmr_max_maps = 0; | 1942 | mr->fmr_max_maps = 0; |
2230 | mr->fmr_map_cnt = 0; | 1943 | mr->fmr_map_cnt = 0; |
2231 | memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle)); | 1944 | memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle)); |
2232 | memset(&mr->galpas, 0, sizeof(mr->galpas)); | 1945 | memset(&mr->galpas, 0, sizeof(mr->galpas)); |
2233 | mr->nr_of_pages = 0; | ||
2234 | mr->pagearray = NULL; | ||
2235 | } /* end ehca_mr_deletenew() */ | 1946 | } /* end ehca_mr_deletenew() */ |
2236 | 1947 | ||
2237 | int ehca_init_mrmw_cache(void) | 1948 | int ehca_init_mrmw_cache(void) |
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h index d936e40a5748..24f13fe3708b 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.h +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h | |||
@@ -101,15 +101,10 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr, | |||
101 | u64 *page_list, | 101 | u64 *page_list, |
102 | int list_len); | 102 | int list_len); |
103 | 103 | ||
104 | int ehca_set_pagebuf(struct ehca_mr *e_mr, | 104 | int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo, |
105 | struct ehca_mr_pginfo *pginfo, | ||
106 | u32 number, | 105 | u32 number, |
107 | u64 *kpage); | 106 | u64 *kpage); |
108 | 107 | ||
109 | int ehca_set_pagebuf_1(struct ehca_mr *e_mr, | ||
110 | struct ehca_mr_pginfo *pginfo, | ||
111 | u64 *rpage); | ||
112 | |||
113 | int ehca_mr_is_maxmr(u64 size, | 108 | int ehca_mr_is_maxmr(u64 size, |
114 | u64 *iova_start); | 109 | u64 *iova_start); |
115 | 110 | ||
@@ -121,20 +116,6 @@ void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl); | |||
121 | void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, | 116 | void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, |
122 | int *ib_acl); | 117 | int *ib_acl); |
123 | 118 | ||
124 | int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc); | ||
125 | |||
126 | int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc); | ||
127 | |||
128 | int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc); | ||
129 | |||
130 | int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc); | ||
131 | |||
132 | int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc); | ||
133 | |||
134 | int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc); | ||
135 | |||
136 | int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc); | ||
137 | |||
138 | void ehca_mr_deletenew(struct ehca_mr *mr); | 119 | void ehca_mr_deletenew(struct ehca_mr *mr); |
139 | 120 | ||
140 | #endif /*_EHCA_MRMW_H_*/ | 121 | #endif /*_EHCA_MRMW_H_*/ |
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h index 8707d297ce4c..818803057ebf 100644 --- a/drivers/infiniband/hw/ehca/ehca_qes.h +++ b/drivers/infiniband/hw/ehca/ehca_qes.h | |||
@@ -53,13 +53,13 @@ struct ehca_vsgentry { | |||
53 | u32 length; | 53 | u32 length; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | #define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7) | 56 | #define GRH_FLAG_MASK EHCA_BMASK_IBM( 7, 7) |
57 | #define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3) | 57 | #define GRH_IPVERSION_MASK EHCA_BMASK_IBM( 0, 3) |
58 | #define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12) | 58 | #define GRH_TCLASS_MASK EHCA_BMASK_IBM( 4, 12) |
59 | #define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31) | 59 | #define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13, 31) |
60 | #define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47) | 60 | #define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32, 47) |
61 | #define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55) | 61 | #define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48, 55) |
62 | #define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63) | 62 | #define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56, 63) |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Unreliable Datagram Address Vector Format | 65 | * Unreliable Datagram Address Vector Format |
@@ -206,10 +206,10 @@ struct ehca_wqe { | |||
206 | 206 | ||
207 | }; | 207 | }; |
208 | 208 | ||
209 | #define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0) | 209 | #define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0) |
210 | #define WC_IMM_DATA EHCA_BMASK_IBM(1,1) | 210 | #define WC_IMM_DATA EHCA_BMASK_IBM(1, 1) |
211 | #define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2) | 211 | #define WC_GRH_PRESENT EHCA_BMASK_IBM(2, 2) |
212 | #define WC_SE_BIT EHCA_BMASK_IBM(3,3) | 212 | #define WC_SE_BIT EHCA_BMASK_IBM(3, 3) |
213 | #define WC_STATUS_ERROR_BIT 0x80000000 | 213 | #define WC_STATUS_ERROR_BIT 0x80000000 |
214 | #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 | 214 | #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800 |
215 | #define WC_STATUS_PURGE_BIT 0x10 | 215 | #define WC_STATUS_PURGE_BIT 0x10 |
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 74671250303f..48e9ceacd6fa 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c | |||
@@ -602,10 +602,10 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd, | |||
602 | /* UD circumvention */ | 602 | /* UD circumvention */ |
603 | parms.act_nr_send_sges -= 2; | 603 | parms.act_nr_send_sges -= 2; |
604 | parms.act_nr_recv_sges -= 2; | 604 | parms.act_nr_recv_sges -= 2; |
605 | swqe_size = offsetof(struct ehca_wqe, | 605 | swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[ |
606 | u.ud_av.sg_list[parms.act_nr_send_sges]); | 606 | parms.act_nr_send_sges]); |
607 | rwqe_size = offsetof(struct ehca_wqe, | 607 | rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[ |
608 | u.ud_av.sg_list[parms.act_nr_recv_sges]); | 608 | parms.act_nr_recv_sges]); |
609 | } | 609 | } |
610 | 610 | ||
611 | if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) { | 611 | if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) { |
@@ -690,8 +690,8 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd, | |||
690 | if (my_qp->send_cq) { | 690 | if (my_qp->send_cq) { |
691 | ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp); | 691 | ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp); |
692 | if (ret) { | 692 | if (ret) { |
693 | ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x", | 693 | ehca_err(pd->device, |
694 | ret); | 694 | "Couldn't assign qp to send_cq ret=%x", ret); |
695 | goto create_qp_exit4; | 695 | goto create_qp_exit4; |
696 | } | 696 | } |
697 | } | 697 | } |
@@ -749,7 +749,7 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd, | |||
749 | struct ehca_qp *ret; | 749 | struct ehca_qp *ret; |
750 | 750 | ||
751 | ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0); | 751 | ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0); |
752 | return IS_ERR(ret) ? (struct ib_qp *) ret : &ret->ib_qp; | 752 | return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp; |
753 | } | 753 | } |
754 | 754 | ||
755 | int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, | 755 | int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, |
@@ -780,7 +780,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, | |||
780 | 780 | ||
781 | my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1); | 781 | my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1); |
782 | if (IS_ERR(my_qp)) | 782 | if (IS_ERR(my_qp)) |
783 | return (struct ib_srq *) my_qp; | 783 | return (struct ib_srq *)my_qp; |
784 | 784 | ||
785 | /* copy back return values */ | 785 | /* copy back return values */ |
786 | srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr; | 786 | srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr; |
@@ -875,7 +875,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, | |||
875 | my_qp, qp_num, h_ret); | 875 | my_qp, qp_num, h_ret); |
876 | return ehca2ib_return_code(h_ret); | 876 | return ehca2ib_return_code(h_ret); |
877 | } | 877 | } |
878 | bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63))); | 878 | bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63))); |
879 | ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p", | 879 | ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p", |
880 | qp_num, bad_send_wqe_p); | 880 | qp_num, bad_send_wqe_p); |
881 | /* convert wqe pointer to vadr */ | 881 | /* convert wqe pointer to vadr */ |
@@ -890,7 +890,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, | |||
890 | } | 890 | } |
891 | 891 | ||
892 | /* loop sets wqe's purge bit */ | 892 | /* loop sets wqe's purge bit */ |
893 | wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs); | 893 | wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs); |
894 | *bad_wqe_cnt = 0; | 894 | *bad_wqe_cnt = 0; |
895 | while (wqe->optype != 0xff && wqe->wqef != 0xff) { | 895 | while (wqe->optype != 0xff && wqe->wqef != 0xff) { |
896 | if (ehca_debug_level) | 896 | if (ehca_debug_level) |
@@ -898,7 +898,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, | |||
898 | wqe->nr_of_data_seg = 0; /* suppress data access */ | 898 | wqe->nr_of_data_seg = 0; /* suppress data access */ |
899 | wqe->wqef = WQEF_PURGE; /* WQE to be purged */ | 899 | wqe->wqef = WQEF_PURGE; /* WQE to be purged */ |
900 | q_ofs = ipz_queue_advance_offset(squeue, q_ofs); | 900 | q_ofs = ipz_queue_advance_offset(squeue, q_ofs); |
901 | wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs); | 901 | wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs); |
902 | *bad_wqe_cnt = (*bad_wqe_cnt)+1; | 902 | *bad_wqe_cnt = (*bad_wqe_cnt)+1; |
903 | } | 903 | } |
904 | /* | 904 | /* |
@@ -1003,7 +1003,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, | |||
1003 | goto modify_qp_exit1; | 1003 | goto modify_qp_exit1; |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x " | 1006 | ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x " |
1007 | "new qp_state=%x attribute_mask=%x", | 1007 | "new qp_state=%x attribute_mask=%x", |
1008 | my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask); | 1008 | my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask); |
1009 | 1009 | ||
@@ -1019,7 +1019,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, | |||
1019 | goto modify_qp_exit1; | 1019 | goto modify_qp_exit1; |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state))) | 1022 | mqpcb->qp_state = ib2ehca_qp_state(qp_new_state); |
1023 | if (mqpcb->qp_state) | ||
1023 | update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1); | 1024 | update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1); |
1024 | else { | 1025 | else { |
1025 | ret = -EINVAL; | 1026 | ret = -EINVAL; |
@@ -1077,7 +1078,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, | |||
1077 | spin_lock_irqsave(&my_qp->spinlock_s, flags); | 1078 | spin_lock_irqsave(&my_qp->spinlock_s, flags); |
1078 | squeue_locked = 1; | 1079 | squeue_locked = 1; |
1079 | /* mark next free wqe */ | 1080 | /* mark next free wqe */ |
1080 | wqe = (struct ehca_wqe*) | 1081 | wqe = (struct ehca_wqe *) |
1081 | ipz_qeit_get(&my_qp->ipz_squeue); | 1082 | ipz_qeit_get(&my_qp->ipz_squeue); |
1082 | wqe->optype = wqe->wqef = 0xff; | 1083 | wqe->optype = wqe->wqef = 0xff; |
1083 | ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p", | 1084 | ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p", |
@@ -1312,7 +1313,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, | |||
1312 | if (h_ret != H_SUCCESS) { | 1313 | if (h_ret != H_SUCCESS) { |
1313 | ret = ehca2ib_return_code(h_ret); | 1314 | ret = ehca2ib_return_code(h_ret); |
1314 | ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx " | 1315 | ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx " |
1315 | "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num); | 1316 | "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num); |
1316 | goto modify_qp_exit2; | 1317 | goto modify_qp_exit2; |
1317 | } | 1318 | } |
1318 | 1319 | ||
@@ -1411,7 +1412,7 @@ int ehca_query_qp(struct ib_qp *qp, | |||
1411 | } | 1412 | } |
1412 | 1413 | ||
1413 | if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) { | 1414 | if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) { |
1414 | ehca_err(qp->device,"Invalid attribute mask " | 1415 | ehca_err(qp->device, "Invalid attribute mask " |
1415 | "ehca_qp=%p qp_num=%x qp_attr_mask=%x ", | 1416 | "ehca_qp=%p qp_num=%x qp_attr_mask=%x ", |
1416 | my_qp, qp->qp_num, qp_attr_mask); | 1417 | my_qp, qp->qp_num, qp_attr_mask); |
1417 | return -EINVAL; | 1418 | return -EINVAL; |
@@ -1419,7 +1420,7 @@ int ehca_query_qp(struct ib_qp *qp, | |||
1419 | 1420 | ||
1420 | qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); | 1421 | qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); |
1421 | if (!qpcb) { | 1422 | if (!qpcb) { |
1422 | ehca_err(qp->device,"Out of memory for qpcb " | 1423 | ehca_err(qp->device, "Out of memory for qpcb " |
1423 | "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num); | 1424 | "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num); |
1424 | return -ENOMEM; | 1425 | return -ENOMEM; |
1425 | } | 1426 | } |
@@ -1431,7 +1432,7 @@ int ehca_query_qp(struct ib_qp *qp, | |||
1431 | 1432 | ||
1432 | if (h_ret != H_SUCCESS) { | 1433 | if (h_ret != H_SUCCESS) { |
1433 | ret = ehca2ib_return_code(h_ret); | 1434 | ret = ehca2ib_return_code(h_ret); |
1434 | ehca_err(qp->device,"hipz_h_query_qp() failed " | 1435 | ehca_err(qp->device, "hipz_h_query_qp() failed " |
1435 | "ehca_qp=%p qp_num=%x h_ret=%lx", | 1436 | "ehca_qp=%p qp_num=%x h_ret=%lx", |
1436 | my_qp, qp->qp_num, h_ret); | 1437 | my_qp, qp->qp_num, h_ret); |
1437 | goto query_qp_exit1; | 1438 | goto query_qp_exit1; |
@@ -1442,7 +1443,7 @@ int ehca_query_qp(struct ib_qp *qp, | |||
1442 | 1443 | ||
1443 | if (qp_attr->cur_qp_state == -EINVAL) { | 1444 | if (qp_attr->cur_qp_state == -EINVAL) { |
1444 | ret = -EINVAL; | 1445 | ret = -EINVAL; |
1445 | ehca_err(qp->device,"Got invalid ehca_qp_state=%x " | 1446 | ehca_err(qp->device, "Got invalid ehca_qp_state=%x " |
1446 | "ehca_qp=%p qp_num=%x", | 1447 | "ehca_qp=%p qp_num=%x", |
1447 | qpcb->qp_state, my_qp, qp->qp_num); | 1448 | qpcb->qp_state, my_qp, qp->qp_num); |
1448 | goto query_qp_exit1; | 1449 | goto query_qp_exit1; |
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 61da65e6e5e0..94eed70fedf5 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c | |||
@@ -79,7 +79,8 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, | |||
79 | } | 79 | } |
80 | 80 | ||
81 | if (ehca_debug_level) { | 81 | if (ehca_debug_level) { |
82 | ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue); | 82 | ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", |
83 | ipz_rqueue); | ||
83 | ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); | 84 | ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); |
84 | } | 85 | } |
85 | 86 | ||
@@ -99,7 +100,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) | |||
99 | struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr; | 100 | struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr; |
100 | struct ib_sge *sge = send_wr->sg_list; | 101 | struct ib_sge *sge = send_wr->sg_list; |
101 | ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x " | 102 | ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x " |
102 | "send_flags=%x opcode=%x",idx, send_wr->wr_id, | 103 | "send_flags=%x opcode=%x", idx, send_wr->wr_id, |
103 | send_wr->num_sge, send_wr->send_flags, | 104 | send_wr->num_sge, send_wr->send_flags, |
104 | send_wr->opcode); | 105 | send_wr->opcode); |
105 | if (mad_hdr) { | 106 | if (mad_hdr) { |
@@ -116,7 +117,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) | |||
116 | mad_hdr->attr_mod); | 117 | mad_hdr->attr_mod); |
117 | } | 118 | } |
118 | for (j = 0; j < send_wr->num_sge; j++) { | 119 | for (j = 0; j < send_wr->num_sge; j++) { |
119 | u8 *data = (u8 *) abs_to_virt(sge->addr); | 120 | u8 *data = (u8 *)abs_to_virt(sge->addr); |
120 | ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x " | 121 | ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x " |
121 | "lkey=%x", | 122 | "lkey=%x", |
122 | idx, j, data, sge->length, sge->lkey); | 123 | idx, j, data, sge->length, sge->lkey); |
@@ -534,9 +535,11 @@ poll_cq_one_read_cqe: | |||
534 | 535 | ||
535 | cqe_count++; | 536 | cqe_count++; |
536 | if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) { | 537 | if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) { |
537 | struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number); | 538 | struct ehca_qp *qp; |
538 | int purgeflag; | 539 | int purgeflag; |
539 | unsigned long flags; | 540 | unsigned long flags; |
541 | |||
542 | qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number); | ||
540 | if (!qp) { | 543 | if (!qp) { |
541 | ehca_err(cq->device, "cq_num=%x qp_num=%x " | 544 | ehca_err(cq->device, "cq_num=%x qp_num=%x " |
542 | "could not find qp -> ignore cqe", | 545 | "could not find qp -> ignore cqe", |
@@ -551,8 +554,8 @@ poll_cq_one_read_cqe: | |||
551 | spin_unlock_irqrestore(&qp->spinlock_s, flags); | 554 | spin_unlock_irqrestore(&qp->spinlock_s, flags); |
552 | 555 | ||
553 | if (purgeflag) { | 556 | if (purgeflag) { |
554 | ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x " | 557 | ehca_dbg(cq->device, |
555 | "src_qp=%x", | 558 | "Got CQE with purged bit qp_num=%x src_qp=%x", |
556 | cqe->local_qp_number, cqe->remote_qp_number); | 559 | cqe->local_qp_number, cqe->remote_qp_number); |
557 | if (ehca_debug_level) | 560 | if (ehca_debug_level) |
558 | ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x", | 561 | ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x", |
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index 03b185f873da..678b81391861 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h | |||
@@ -93,14 +93,14 @@ extern int ehca_debug_level; | |||
93 | #define ehca_gen_dbg(format, arg...) \ | 93 | #define ehca_gen_dbg(format, arg...) \ |
94 | do { \ | 94 | do { \ |
95 | if (unlikely(ehca_debug_level)) \ | 95 | if (unlikely(ehca_debug_level)) \ |
96 | printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\ | 96 | printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \ |
97 | get_paca()->paca_index, __FUNCTION__, ## arg); \ | 97 | get_paca()->paca_index, __FUNCTION__, ## arg); \ |
98 | } while (0) | 98 | } while (0) |
99 | 99 | ||
100 | #define ehca_gen_warn(format, arg...) \ | 100 | #define ehca_gen_warn(format, arg...) \ |
101 | do { \ | 101 | do { \ |
102 | if (unlikely(ehca_debug_level)) \ | 102 | if (unlikely(ehca_debug_level)) \ |
103 | printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\ | 103 | printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ |
104 | get_paca()->paca_index, __FUNCTION__, ## arg); \ | 104 | get_paca()->paca_index, __FUNCTION__, ## arg); \ |
105 | } while (0) | 105 | } while (0) |
106 | 106 | ||
@@ -114,12 +114,12 @@ extern int ehca_debug_level; | |||
114 | * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex> | 114 | * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex> |
115 | */ | 115 | */ |
116 | #define ehca_dmp(adr, len, format, args...) \ | 116 | #define ehca_dmp(adr, len, format, args...) \ |
117 | do { \ | 117 | do { \ |
118 | unsigned int x; \ | 118 | unsigned int x; \ |
119 | unsigned int l = (unsigned int)(len); \ | 119 | unsigned int l = (unsigned int)(len); \ |
120 | unsigned char *deb = (unsigned char*)(adr); \ | 120 | unsigned char *deb = (unsigned char *)(adr); \ |
121 | for (x = 0; x < l; x += 16) { \ | 121 | for (x = 0; x < l; x += 16) { \ |
122 | printk("EHCA_DMP:%s " format \ | 122 | printk(KERN_INFO "EHCA_DMP:%s " format \ |
123 | " adr=%p ofs=%04x %016lx %016lx\n", \ | 123 | " adr=%p ofs=%04x %016lx %016lx\n", \ |
124 | __FUNCTION__, ##args, deb, x, \ | 124 | __FUNCTION__, ##args, deb, x, \ |
125 | *((u64 *)&deb[0]), *((u64 *)&deb[8])); \ | 125 | *((u64 *)&deb[0]), *((u64 *)&deb[8])); \ |
@@ -128,16 +128,16 @@ extern int ehca_debug_level; | |||
128 | } while (0) | 128 | } while (0) |
129 | 129 | ||
130 | /* define a bitmask, little endian version */ | 130 | /* define a bitmask, little endian version */ |
131 | #define EHCA_BMASK(pos,length) (((pos)<<16)+(length)) | 131 | #define EHCA_BMASK(pos, length) (((pos) << 16) + (length)) |
132 | 132 | ||
133 | /* define a bitmask, the ibm way... */ | 133 | /* define a bitmask, the ibm way... */ |
134 | #define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1)) | 134 | #define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1)) |
135 | 135 | ||
136 | /* internal function, don't use */ | 136 | /* internal function, don't use */ |
137 | #define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff) | 137 | #define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff) |
138 | 138 | ||
139 | /* internal function, don't use */ | 139 | /* internal function, don't use */ |
140 | #define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff)) | 140 | #define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff)) |
141 | 141 | ||
142 | /** | 142 | /** |
143 | * EHCA_BMASK_SET - return value shifted and masked by mask | 143 | * EHCA_BMASK_SET - return value shifted and masked by mask |
@@ -145,14 +145,14 @@ extern int ehca_debug_level; | |||
145 | * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask | 145 | * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask |
146 | * in variable | 146 | * in variable |
147 | */ | 147 | */ |
148 | #define EHCA_BMASK_SET(mask,value) \ | 148 | #define EHCA_BMASK_SET(mask, value) \ |
149 | ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask)) | 149 | ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask)) |
150 | 150 | ||
151 | /** | 151 | /** |
152 | * EHCA_BMASK_GET - extract a parameter from value by mask | 152 | * EHCA_BMASK_GET - extract a parameter from value by mask |
153 | */ | 153 | */ |
154 | #define EHCA_BMASK_GET(mask,value) \ | 154 | #define EHCA_BMASK_GET(mask, value) \ |
155 | (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask))) | 155 | (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask))) |
156 | 156 | ||
157 | 157 | ||
158 | /* Converts ehca to ib return code */ | 158 | /* Converts ehca to ib return code */ |
@@ -161,8 +161,11 @@ static inline int ehca2ib_return_code(u64 ehca_rc) | |||
161 | switch (ehca_rc) { | 161 | switch (ehca_rc) { |
162 | case H_SUCCESS: | 162 | case H_SUCCESS: |
163 | return 0; | 163 | return 0; |
164 | case H_RESOURCE: /* Resource in use */ | ||
164 | case H_BUSY: | 165 | case H_BUSY: |
165 | return -EBUSY; | 166 | return -EBUSY; |
167 | case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */ | ||
168 | case H_CONSTRAINED: /* resource constraint */ | ||
166 | case H_NO_MEM: | 169 | case H_NO_MEM: |
167 | return -ENOMEM; | 170 | return -ENOMEM; |
168 | default: | 171 | default: |
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 3031b3bb56f9..05c415744e3b 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c | |||
@@ -70,7 +70,7 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context) | |||
70 | 70 | ||
71 | static void ehca_mm_open(struct vm_area_struct *vma) | 71 | static void ehca_mm_open(struct vm_area_struct *vma) |
72 | { | 72 | { |
73 | u32 *count = (u32*)vma->vm_private_data; | 73 | u32 *count = (u32 *)vma->vm_private_data; |
74 | if (!count) { | 74 | if (!count) { |
75 | ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", | 75 | ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", |
76 | vma->vm_start, vma->vm_end); | 76 | vma->vm_start, vma->vm_end); |
@@ -86,7 +86,7 @@ static void ehca_mm_open(struct vm_area_struct *vma) | |||
86 | 86 | ||
87 | static void ehca_mm_close(struct vm_area_struct *vma) | 87 | static void ehca_mm_close(struct vm_area_struct *vma) |
88 | { | 88 | { |
89 | u32 *count = (u32*)vma->vm_private_data; | 89 | u32 *count = (u32 *)vma->vm_private_data; |
90 | if (!count) { | 90 | if (!count) { |
91 | ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", | 91 | ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", |
92 | vma->vm_start, vma->vm_end); | 92 | vma->vm_start, vma->vm_end); |
@@ -215,7 +215,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, | |||
215 | case 2: /* qp rqueue_addr */ | 215 | case 2: /* qp rqueue_addr */ |
216 | ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", | 216 | ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", |
217 | qp->ib_qp.qp_num); | 217 | qp->ib_qp.qp_num); |
218 | ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue); | 218 | ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, |
219 | &qp->mm_count_rqueue); | ||
219 | if (unlikely(ret)) { | 220 | if (unlikely(ret)) { |
220 | ehca_err(qp->ib_qp.device, | 221 | ehca_err(qp->ib_qp.device, |
221 | "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", | 222 | "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", |
@@ -227,7 +228,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, | |||
227 | case 3: /* qp squeue_addr */ | 228 | case 3: /* qp squeue_addr */ |
228 | ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", | 229 | ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", |
229 | qp->ib_qp.qp_num); | 230 | qp->ib_qp.qp_num); |
230 | ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue); | 231 | ret = ehca_mmap_queue(vma, &qp->ipz_squeue, |
232 | &qp->mm_count_squeue); | ||
231 | if (unlikely(ret)) { | 233 | if (unlikely(ret)) { |
232 | ehca_err(qp->ib_qp.device, | 234 | ehca_err(qp->ib_qp.device, |
233 | "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", | 235 | "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", |
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 4776a8b0feec..3394e05f4b4f 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c | |||
@@ -501,8 +501,8 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle, | |||
501 | return H_PARAMETER; | 501 | return H_PARAMETER; |
502 | } | 502 | } |
503 | 503 | ||
504 | return hipz_h_register_rpage(adapter_handle,pagesize,queue_type, | 504 | return hipz_h_register_rpage(adapter_handle, pagesize, queue_type, |
505 | qp_handle.handle,logical_address_of_page, | 505 | qp_handle.handle, logical_address_of_page, |
506 | count); | 506 | count); |
507 | } | 507 | } |
508 | 508 | ||
@@ -522,9 +522,9 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle, | |||
522 | qp_handle.handle, /* r6 */ | 522 | qp_handle.handle, /* r6 */ |
523 | 0, 0, 0, 0, 0, 0); | 523 | 0, 0, 0, 0, 0, 0); |
524 | if (log_addr_next_sq_wqe2processed) | 524 | if (log_addr_next_sq_wqe2processed) |
525 | *log_addr_next_sq_wqe2processed = (void*)outs[0]; | 525 | *log_addr_next_sq_wqe2processed = (void *)outs[0]; |
526 | if (log_addr_next_rq_wqe2processed) | 526 | if (log_addr_next_rq_wqe2processed) |
527 | *log_addr_next_rq_wqe2processed = (void*)outs[1]; | 527 | *log_addr_next_rq_wqe2processed = (void *)outs[1]; |
528 | 528 | ||
529 | return ret; | 529 | return ret; |
530 | } | 530 | } |
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c index 0b1a4772c78a..214821095cb1 100644 --- a/drivers/infiniband/hw/ehca/hcp_phyp.c +++ b/drivers/infiniband/hw/ehca/hcp_phyp.c | |||
@@ -50,7 +50,7 @@ int hcall_map_page(u64 physaddr, u64 *mapaddr) | |||
50 | 50 | ||
51 | int hcall_unmap_page(u64 mapaddr) | 51 | int hcall_unmap_page(u64 mapaddr) |
52 | { | 52 | { |
53 | iounmap((volatile void __iomem*)mapaddr); | 53 | iounmap((volatile void __iomem *) mapaddr); |
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h index 20898a153446..868735fd3187 100644 --- a/drivers/infiniband/hw/ehca/hipz_fns_core.h +++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h | |||
@@ -53,10 +53,10 @@ | |||
53 | #define hipz_galpa_load_cq(gal, offset) \ | 53 | #define hipz_galpa_load_cq(gal, offset) \ |
54 | hipz_galpa_load(gal, CQTEMM_OFFSET(offset)) | 54 | hipz_galpa_load(gal, CQTEMM_OFFSET(offset)) |
55 | 55 | ||
56 | #define hipz_galpa_store_qp(gal,offset, value) \ | 56 | #define hipz_galpa_store_qp(gal, offset, value) \ |
57 | hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value) | 57 | hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value) |
58 | #define hipz_galpa_load_qp(gal, offset) \ | 58 | #define hipz_galpa_load_qp(gal, offset) \ |
59 | hipz_galpa_load(gal,QPTEMM_OFFSET(offset)) | 59 | hipz_galpa_load(gal, QPTEMM_OFFSET(offset)) |
60 | 60 | ||
61 | static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes) | 61 | static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes) |
62 | { | 62 | { |
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h index dad6dea5636b..d9739e554515 100644 --- a/drivers/infiniband/hw/ehca/hipz_hw.h +++ b/drivers/infiniband/hw/ehca/hipz_hw.h | |||
@@ -161,11 +161,11 @@ struct hipz_qptemm { | |||
161 | /* 0x1000 */ | 161 | /* 0x1000 */ |
162 | }; | 162 | }; |
163 | 163 | ||
164 | #define QPX_SQADDER EHCA_BMASK_IBM(48,63) | 164 | #define QPX_SQADDER EHCA_BMASK_IBM(48, 63) |
165 | #define QPX_RQADDER EHCA_BMASK_IBM(48,63) | 165 | #define QPX_RQADDER EHCA_BMASK_IBM(48, 63) |
166 | #define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3,3) | 166 | #define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3) |
167 | 167 | ||
168 | #define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x) | 168 | #define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x) |
169 | 169 | ||
170 | /* MRMWPT Entry Memory Map */ | 170 | /* MRMWPT Entry Memory Map */ |
171 | struct hipz_mrmwmm { | 171 | struct hipz_mrmwmm { |
@@ -187,7 +187,7 @@ struct hipz_mrmwmm { | |||
187 | 187 | ||
188 | }; | 188 | }; |
189 | 189 | ||
190 | #define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x) | 190 | #define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x) |
191 | 191 | ||
192 | struct hipz_qpedmm { | 192 | struct hipz_qpedmm { |
193 | /* 0x00 */ | 193 | /* 0x00 */ |
@@ -238,7 +238,7 @@ struct hipz_qpedmm { | |||
238 | u64 qpedx_rrva3; | 238 | u64 qpedx_rrva3; |
239 | }; | 239 | }; |
240 | 240 | ||
241 | #define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x) | 241 | #define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x) |
242 | 242 | ||
243 | /* CQ Table Entry Memory Map */ | 243 | /* CQ Table Entry Memory Map */ |
244 | struct hipz_cqtemm { | 244 | struct hipz_cqtemm { |
@@ -263,12 +263,12 @@ struct hipz_cqtemm { | |||
263 | /* 0x1000 */ | 263 | /* 0x1000 */ |
264 | }; | 264 | }; |
265 | 265 | ||
266 | #define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63) | 266 | #define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32, 63) |
267 | #define CQX_FECADDER EHCA_BMASK_IBM(32,63) | 267 | #define CQX_FECADDER EHCA_BMASK_IBM(32, 63) |
268 | #define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0) | 268 | #define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0) |
269 | #define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0) | 269 | #define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0) |
270 | 270 | ||
271 | #define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x) | 271 | #define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x) |
272 | 272 | ||
273 | /* EQ Table Entry Memory Map */ | 273 | /* EQ Table Entry Memory Map */ |
274 | struct hipz_eqtemm { | 274 | struct hipz_eqtemm { |
@@ -293,7 +293,7 @@ struct hipz_eqtemm { | |||
293 | 293 | ||
294 | }; | 294 | }; |
295 | 295 | ||
296 | #define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x) | 296 | #define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x) |
297 | 297 | ||
298 | /* access control defines for MR/MW */ | 298 | /* access control defines for MR/MW */ |
299 | #define HIPZ_ACCESSCTRL_L_WRITE 0x00800000 | 299 | #define HIPZ_ACCESSCTRL_L_WRITE 0x00800000 |
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index bf7a40088f61..9606f13ed092 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c | |||
@@ -114,7 +114,7 @@ int ipz_queue_ctor(struct ipz_queue *queue, | |||
114 | */ | 114 | */ |
115 | f = 0; | 115 | f = 0; |
116 | while (f < nr_of_pages) { | 116 | while (f < nr_of_pages) { |
117 | u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL); | 117 | u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL); |
118 | int k; | 118 | int k; |
119 | if (!kpage) | 119 | if (!kpage) |
120 | goto ipz_queue_ctor_exit0; /*NOMEM*/ | 120 | goto ipz_queue_ctor_exit0; /*NOMEM*/ |
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h index 007f0882fd40..39a4f64aff41 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h | |||
@@ -240,7 +240,7 @@ void *ipz_qeit_eq_get_inc(struct ipz_queue *queue); | |||
240 | static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) | 240 | static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) |
241 | { | 241 | { |
242 | void *ret = ipz_qeit_get(queue); | 242 | void *ret = ipz_qeit_get(queue); |
243 | u32 qe = *(u8 *) ret; | 243 | u32 qe = *(u8 *)ret; |
244 | if ((qe >> 7) != (queue->toggle_state & 1)) | 244 | if ((qe >> 7) != (queue->toggle_state & 1)) |
245 | return NULL; | 245 | return NULL; |
246 | ipz_qeit_eq_get_inc(queue); /* this is a good one */ | 246 | ipz_qeit_eq_get_inc(queue); /* this is a good one */ |
@@ -250,7 +250,7 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) | |||
250 | static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue) | 250 | static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue) |
251 | { | 251 | { |
252 | void *ret = ipz_qeit_get(queue); | 252 | void *ret = ipz_qeit_get(queue); |
253 | u32 qe = *(u8 *) ret; | 253 | u32 qe = *(u8 *)ret; |
254 | if ((qe >> 7) != (queue->toggle_state & 1)) | 254 | if ((qe >> 7) != (queue->toggle_state & 1)) |
255 | return NULL; | 255 | return NULL; |
256 | return ret; | 256 | return ret; |
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 9361f5ab8bd6..09c5fd84b1e3 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -1889,7 +1889,7 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno, | |||
1889 | /* Below is "non-zero" to force override, but both actual LEDs are off */ | 1889 | /* Below is "non-zero" to force override, but both actual LEDs are off */ |
1890 | #define LED_OVER_BOTH_OFF (8) | 1890 | #define LED_OVER_BOTH_OFF (8) |
1891 | 1891 | ||
1892 | void ipath_run_led_override(unsigned long opaque) | 1892 | static void ipath_run_led_override(unsigned long opaque) |
1893 | { | 1893 | { |
1894 | struct ipath_devdata *dd = (struct ipath_devdata *)opaque; | 1894 | struct ipath_devdata *dd = (struct ipath_devdata *)opaque; |
1895 | int timeoff; | 1895 | int timeoff; |
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c index 6b9147964a4f..b4503e9c1e95 100644 --- a/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c | |||
@@ -426,8 +426,8 @@ bail: | |||
426 | * @buffer: data to write | 426 | * @buffer: data to write |
427 | * @len: number of bytes to write | 427 | * @len: number of bytes to write |
428 | */ | 428 | */ |
429 | int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset, | 429 | static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset, |
430 | const void *buffer, int len) | 430 | const void *buffer, int len) |
431 | { | 431 | { |
432 | u8 single_byte; | 432 | u8 single_byte; |
433 | int sub_len; | 433 | int sub_len; |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 47aa43428fbf..1fd91c59f246 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum) | |||
70 | * If rewrite is true, and bits are set in the sendbufferror registers, | 70 | * If rewrite is true, and bits are set in the sendbufferror registers, |
71 | * we'll write to the buffer, for error recovery on parity errors. | 71 | * we'll write to the buffer, for error recovery on parity errors. |
72 | */ | 72 | */ |
73 | void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite) | 73 | static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite) |
74 | { | 74 | { |
75 | u32 piobcnt; | 75 | u32 piobcnt; |
76 | unsigned long sbuf[4]; | 76 | unsigned long sbuf[4]; |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 3105005fc9d2..ace63ef78e6f 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -776,7 +776,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *); | |||
776 | int ipath_update_eeprom_log(struct ipath_devdata *dd); | 776 | int ipath_update_eeprom_log(struct ipath_devdata *dd); |
777 | void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); | 777 | void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); |
778 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); | 778 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); |
779 | void ipath_disarm_senderrbufs(struct ipath_devdata *, int); | ||
780 | 779 | ||
781 | /* | 780 | /* |
782 | * Set LED override, only the two LSBs have "public" meaning, but | 781 | * Set LED override, only the two LSBs have "public" meaning, but |
@@ -820,7 +819,6 @@ static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data) | |||
820 | #define IPATH_MDIO_CTRL_8355_REG_10 0x1D | 819 | #define IPATH_MDIO_CTRL_8355_REG_10 0x1D |
821 | 820 | ||
822 | int ipath_get_user_pages(unsigned long, size_t, struct page **); | 821 | int ipath_get_user_pages(unsigned long, size_t, struct page **); |
823 | int ipath_get_user_pages_nocopy(unsigned long, struct page **); | ||
824 | void ipath_release_user_pages(struct page **, size_t); | 822 | void ipath_release_user_pages(struct page **, size_t); |
825 | void ipath_release_user_pages_on_close(struct page **, size_t); | 823 | void ipath_release_user_pages_on_close(struct page **, size_t); |
826 | int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int); | 824 | int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int); |
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index 85256747d8a1..c69c25239443 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c | |||
@@ -507,7 +507,7 @@ static int want_buffer(struct ipath_devdata *dd) | |||
507 | * | 507 | * |
508 | * Called when we run out of PIO buffers. | 508 | * Called when we run out of PIO buffers. |
509 | */ | 509 | */ |
510 | void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) | 510 | static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) |
511 | { | 511 | { |
512 | unsigned long flags; | 512 | unsigned long flags; |
513 | 513 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c index 27034d38b3dd..0190edc8044e 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c | |||
@@ -171,32 +171,6 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages, | |||
171 | return ret; | 171 | return ret; |
172 | } | 172 | } |
173 | 173 | ||
174 | /** | ||
175 | * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared | ||
176 | * @start_page: the page to lock | ||
177 | * @p: the output page structure | ||
178 | * | ||
179 | * This is similar to ipath_get_user_pages, but it's always one page, and we | ||
180 | * mark the page as locked for I/O, and shared. This is used for the user | ||
181 | * process page that contains the destination address for the rcvhdrq tail | ||
182 | * update, so we need to have the vma. If we don't do this, the page can be | ||
183 | * taken away from us on fork, even if the child never touches it, and then | ||
184 | * the user process never sees the tail register updates. | ||
185 | */ | ||
186 | int ipath_get_user_pages_nocopy(unsigned long page, struct page **p) | ||
187 | { | ||
188 | struct vm_area_struct *vma; | ||
189 | int ret; | ||
190 | |||
191 | down_write(¤t->mm->mmap_sem); | ||
192 | |||
193 | ret = __get_user_pages(page, 1, p, &vma); | ||
194 | |||
195 | up_write(¤t->mm->mmap_sem); | ||
196 | |||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | void ipath_release_user_pages(struct page **p, size_t num_pages) | 174 | void ipath_release_user_pages(struct page **p, size_t num_pages) |
201 | { | 175 | { |
202 | down_write(¤t->mm->mmap_sem); | 176 | down_write(¤t->mm->mmap_sem); |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 65f7181e9cf8..16aa61fd8085 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -488,7 +488,7 @@ bail:; | |||
488 | * This is called from ipath_do_rcv_timer() at interrupt level to check for | 488 | * This is called from ipath_do_rcv_timer() at interrupt level to check for |
489 | * QPs which need retransmits and to collect performance numbers. | 489 | * QPs which need retransmits and to collect performance numbers. |
490 | */ | 490 | */ |
491 | void ipath_ib_timer(struct ipath_ibdev *dev) | 491 | static void ipath_ib_timer(struct ipath_ibdev *dev) |
492 | { | 492 | { |
493 | struct ipath_qp *resend = NULL; | 493 | struct ipath_qp *resend = NULL; |
494 | struct list_head *last; | 494 | struct list_head *last; |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index f3d1f2cee6f8..9bbe81967f14 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h | |||
@@ -782,8 +782,6 @@ void ipath_update_mmap_info(struct ipath_ibdev *dev, | |||
782 | 782 | ||
783 | int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); | 783 | int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); |
784 | 784 | ||
785 | void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev); | ||
786 | |||
787 | void ipath_insert_rnr_queue(struct ipath_qp *qp); | 785 | void ipath_insert_rnr_queue(struct ipath_qp *qp); |
788 | 786 | ||
789 | int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only); | 787 | int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only); |
@@ -807,8 +805,6 @@ void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32); | |||
807 | 805 | ||
808 | int ipath_ib_piobufavail(struct ipath_ibdev *); | 806 | int ipath_ib_piobufavail(struct ipath_ibdev *); |
809 | 807 | ||
810 | void ipath_ib_timer(struct ipath_ibdev *); | ||
811 | |||
812 | unsigned ipath_get_npkeys(struct ipath_devdata *); | 808 | unsigned ipath_get_npkeys(struct ipath_devdata *); |
813 | 809 | ||
814 | u32 ipath_get_cr_errpkey(struct ipath_devdata *); | 810 | u32 ipath_get_cr_errpkey(struct ipath_devdata *); |
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 40042184ad58..b5a24fbef70d 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c | |||
@@ -1183,6 +1183,43 @@ static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq | |||
1183 | return cur + nreq >= wq->max_post; | 1183 | return cur + nreq >= wq->max_post; |
1184 | } | 1184 | } |
1185 | 1185 | ||
1186 | static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, | ||
1187 | u64 remote_addr, u32 rkey) | ||
1188 | { | ||
1189 | rseg->raddr = cpu_to_be64(remote_addr); | ||
1190 | rseg->rkey = cpu_to_be32(rkey); | ||
1191 | rseg->reserved = 0; | ||
1192 | } | ||
1193 | |||
1194 | static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr) | ||
1195 | { | ||
1196 | if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { | ||
1197 | aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); | ||
1198 | aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); | ||
1199 | } else { | ||
1200 | aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); | ||
1201 | aseg->compare = 0; | ||
1202 | } | ||
1203 | |||
1204 | } | ||
1205 | |||
1206 | static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, | ||
1207 | struct ib_send_wr *wr) | ||
1208 | { | ||
1209 | memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); | ||
1210 | dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); | ||
1211 | dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); | ||
1212 | |||
1213 | } | ||
1214 | |||
1215 | static void set_data_seg(struct mlx4_wqe_data_seg *dseg, | ||
1216 | struct ib_sge *sg) | ||
1217 | { | ||
1218 | dseg->byte_count = cpu_to_be32(sg->length); | ||
1219 | dseg->lkey = cpu_to_be32(sg->lkey); | ||
1220 | dseg->addr = cpu_to_be64(sg->addr); | ||
1221 | } | ||
1222 | |||
1186 | int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | 1223 | int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, |
1187 | struct ib_send_wr **bad_wr) | 1224 | struct ib_send_wr **bad_wr) |
1188 | { | 1225 | { |
@@ -1238,26 +1275,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1238 | switch (wr->opcode) { | 1275 | switch (wr->opcode) { |
1239 | case IB_WR_ATOMIC_CMP_AND_SWP: | 1276 | case IB_WR_ATOMIC_CMP_AND_SWP: |
1240 | case IB_WR_ATOMIC_FETCH_AND_ADD: | 1277 | case IB_WR_ATOMIC_FETCH_AND_ADD: |
1241 | ((struct mlx4_wqe_raddr_seg *) wqe)->raddr = | 1278 | set_raddr_seg(wqe, wr->wr.atomic.remote_addr, |
1242 | cpu_to_be64(wr->wr.atomic.remote_addr); | 1279 | wr->wr.atomic.rkey); |
1243 | ((struct mlx4_wqe_raddr_seg *) wqe)->rkey = | ||
1244 | cpu_to_be32(wr->wr.atomic.rkey); | ||
1245 | ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0; | ||
1246 | |||
1247 | wqe += sizeof (struct mlx4_wqe_raddr_seg); | 1280 | wqe += sizeof (struct mlx4_wqe_raddr_seg); |
1248 | 1281 | ||
1249 | if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { | 1282 | set_atomic_seg(wqe, wr); |
1250 | ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add = | ||
1251 | cpu_to_be64(wr->wr.atomic.swap); | ||
1252 | ((struct mlx4_wqe_atomic_seg *) wqe)->compare = | ||
1253 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
1254 | } else { | ||
1255 | ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add = | ||
1256 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
1257 | ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0; | ||
1258 | } | ||
1259 | |||
1260 | wqe += sizeof (struct mlx4_wqe_atomic_seg); | 1283 | wqe += sizeof (struct mlx4_wqe_atomic_seg); |
1284 | |||
1261 | size += (sizeof (struct mlx4_wqe_raddr_seg) + | 1285 | size += (sizeof (struct mlx4_wqe_raddr_seg) + |
1262 | sizeof (struct mlx4_wqe_atomic_seg)) / 16; | 1286 | sizeof (struct mlx4_wqe_atomic_seg)) / 16; |
1263 | 1287 | ||
@@ -1266,15 +1290,10 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1266 | case IB_WR_RDMA_READ: | 1290 | case IB_WR_RDMA_READ: |
1267 | case IB_WR_RDMA_WRITE: | 1291 | case IB_WR_RDMA_WRITE: |
1268 | case IB_WR_RDMA_WRITE_WITH_IMM: | 1292 | case IB_WR_RDMA_WRITE_WITH_IMM: |
1269 | ((struct mlx4_wqe_raddr_seg *) wqe)->raddr = | 1293 | set_raddr_seg(wqe, wr->wr.rdma.remote_addr, |
1270 | cpu_to_be64(wr->wr.rdma.remote_addr); | 1294 | wr->wr.rdma.rkey); |
1271 | ((struct mlx4_wqe_raddr_seg *) wqe)->rkey = | ||
1272 | cpu_to_be32(wr->wr.rdma.rkey); | ||
1273 | ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0; | ||
1274 | |||
1275 | wqe += sizeof (struct mlx4_wqe_raddr_seg); | 1295 | wqe += sizeof (struct mlx4_wqe_raddr_seg); |
1276 | size += sizeof (struct mlx4_wqe_raddr_seg) / 16; | 1296 | size += sizeof (struct mlx4_wqe_raddr_seg) / 16; |
1277 | |||
1278 | break; | 1297 | break; |
1279 | 1298 | ||
1280 | default: | 1299 | default: |
@@ -1284,13 +1303,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1284 | break; | 1303 | break; |
1285 | 1304 | ||
1286 | case IB_QPT_UD: | 1305 | case IB_QPT_UD: |
1287 | memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av, | 1306 | set_datagram_seg(wqe, wr); |
1288 | &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); | ||
1289 | ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn = | ||
1290 | cpu_to_be32(wr->wr.ud.remote_qpn); | ||
1291 | ((struct mlx4_wqe_datagram_seg *) wqe)->qkey = | ||
1292 | cpu_to_be32(wr->wr.ud.remote_qkey); | ||
1293 | |||
1294 | wqe += sizeof (struct mlx4_wqe_datagram_seg); | 1307 | wqe += sizeof (struct mlx4_wqe_datagram_seg); |
1295 | size += sizeof (struct mlx4_wqe_datagram_seg) / 16; | 1308 | size += sizeof (struct mlx4_wqe_datagram_seg) / 16; |
1296 | break; | 1309 | break; |
@@ -1313,12 +1326,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1313 | } | 1326 | } |
1314 | 1327 | ||
1315 | for (i = 0; i < wr->num_sge; ++i) { | 1328 | for (i = 0; i < wr->num_sge; ++i) { |
1316 | ((struct mlx4_wqe_data_seg *) wqe)->byte_count = | 1329 | set_data_seg(wqe, wr->sg_list + i); |
1317 | cpu_to_be32(wr->sg_list[i].length); | ||
1318 | ((struct mlx4_wqe_data_seg *) wqe)->lkey = | ||
1319 | cpu_to_be32(wr->sg_list[i].lkey); | ||
1320 | ((struct mlx4_wqe_data_seg *) wqe)->addr = | ||
1321 | cpu_to_be64(wr->sg_list[i].addr); | ||
1322 | 1330 | ||
1323 | wqe += sizeof (struct mlx4_wqe_data_seg); | 1331 | wqe += sizeof (struct mlx4_wqe_data_seg); |
1324 | size += sizeof (struct mlx4_wqe_data_seg) / 16; | 1332 | size += sizeof (struct mlx4_wqe_data_seg) / 16; |
@@ -1498,7 +1506,7 @@ static int to_ib_qp_access_flags(int mlx4_flags) | |||
1498 | static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr, | 1506 | static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr, |
1499 | struct mlx4_qp_path *path) | 1507 | struct mlx4_qp_path *path) |
1500 | { | 1508 | { |
1501 | memset(ib_ah_attr, 0, sizeof *path); | 1509 | memset(ib_ah_attr, 0, sizeof *ib_ah_attr); |
1502 | ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1; | 1510 | ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1; |
1503 | 1511 | ||
1504 | if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) | 1512 | if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) |
@@ -1515,7 +1523,7 @@ static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr, | |||
1515 | ib_ah_attr->grh.traffic_class = | 1523 | ib_ah_attr->grh.traffic_class = |
1516 | (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff; | 1524 | (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff; |
1517 | ib_ah_attr->grh.flow_label = | 1525 | ib_ah_attr->grh.flow_label = |
1518 | be32_to_cpu(path->tclass_flowlabel) & 0xffffff; | 1526 | be32_to_cpu(path->tclass_flowlabel) & 0xfffff; |
1519 | memcpy(ib_ah_attr->grh.dgid.raw, | 1527 | memcpy(ib_ah_attr->grh.dgid.raw, |
1520 | path->rgid, sizeof ib_ah_attr->grh.dgid.raw); | 1528 | path->rgid, sizeof ib_ah_attr->grh.dgid.raw); |
1521 | } | 1529 | } |
@@ -1560,7 +1568,10 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr | |||
1560 | } | 1568 | } |
1561 | 1569 | ||
1562 | qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; | 1570 | qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; |
1563 | qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; | 1571 | if (qp_attr->qp_state == IB_QPS_INIT) |
1572 | qp_attr->port_num = qp->port; | ||
1573 | else | ||
1574 | qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; | ||
1564 | 1575 | ||
1565 | /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ | 1576 | /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ |
1566 | qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING; | 1577 | qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING; |
@@ -1578,17 +1589,25 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr | |||
1578 | 1589 | ||
1579 | done: | 1590 | done: |
1580 | qp_attr->cur_qp_state = qp_attr->qp_state; | 1591 | qp_attr->cur_qp_state = qp_attr->qp_state; |
1592 | qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; | ||
1593 | qp_attr->cap.max_recv_sge = qp->rq.max_gs; | ||
1594 | |||
1581 | if (!ibqp->uobject) { | 1595 | if (!ibqp->uobject) { |
1582 | qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; | 1596 | qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; |
1583 | qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; | 1597 | qp_attr->cap.max_send_sge = qp->sq.max_gs; |
1584 | qp_attr->cap.max_send_sge = qp->sq.max_gs; | 1598 | } else { |
1585 | qp_attr->cap.max_recv_sge = qp->rq.max_gs; | 1599 | qp_attr->cap.max_send_wr = 0; |
1586 | qp_attr->cap.max_inline_data = (1 << qp->sq.wqe_shift) - | 1600 | qp_attr->cap.max_send_sge = 0; |
1587 | send_wqe_overhead(qp->ibqp.qp_type) - | ||
1588 | sizeof (struct mlx4_wqe_inline_seg); | ||
1589 | qp_init_attr->cap = qp_attr->cap; | ||
1590 | } | 1601 | } |
1591 | 1602 | ||
1603 | /* | ||
1604 | * We don't support inline sends for kernel QPs (yet), and we | ||
1605 | * don't know what userspace's value should be. | ||
1606 | */ | ||
1607 | qp_attr->cap.max_inline_data = 0; | ||
1608 | |||
1609 | qp_init_attr->cap = qp_attr->cap; | ||
1610 | |||
1592 | return 0; | 1611 | return 0; |
1593 | } | 1612 | } |
1594 | 1613 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index aa563e61de65..76fed7545c53 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c | |||
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); | |||
67 | 67 | ||
68 | static int msi = 0; | 68 | static int msi = 0; |
69 | module_param(msi, int, 0444); | 69 | module_param(msi, int, 0444); |
70 | MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero"); | 70 | MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)"); |
71 | 71 | ||
72 | #else /* CONFIG_PCI_MSI */ | 72 | #else /* CONFIG_PCI_MSI */ |
73 | 73 | ||
@@ -1117,9 +1117,21 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) | |||
1117 | 1117 | ||
1118 | if (msi_x && !mthca_enable_msi_x(mdev)) | 1118 | if (msi_x && !mthca_enable_msi_x(mdev)) |
1119 | mdev->mthca_flags |= MTHCA_FLAG_MSI_X; | 1119 | mdev->mthca_flags |= MTHCA_FLAG_MSI_X; |
1120 | if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) && | 1120 | else if (msi) { |
1121 | !pci_enable_msi(pdev)) | 1121 | static int warned; |
1122 | mdev->mthca_flags |= MTHCA_FLAG_MSI; | 1122 | |
1123 | if (!warned) { | ||
1124 | printk(KERN_WARNING PFX "WARNING: MSI support will be " | ||
1125 | "removed from the ib_mthca driver in January 2008.\n"); | ||
1126 | printk(KERN_WARNING " If you are using MSI and cannot " | ||
1127 | "switch to MSI-X, please tell " | ||
1128 | "<general@lists.openfabrics.org>.\n"); | ||
1129 | ++warned; | ||
1130 | } | ||
1131 | |||
1132 | if (!pci_enable_msi(pdev)) | ||
1133 | mdev->mthca_flags |= MTHCA_FLAG_MSI; | ||
1134 | } | ||
1123 | 1135 | ||
1124 | if (mthca_cmd_init(mdev)) { | 1136 | if (mthca_cmd_init(mdev)) { |
1125 | mthca_err(mdev, "Failed to init command interface, aborting.\n"); | 1137 | mthca_err(mdev, "Failed to init command interface, aborting.\n"); |
@@ -1135,7 +1147,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) | |||
1135 | goto err_cmd; | 1147 | goto err_cmd; |
1136 | 1148 | ||
1137 | if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { | 1149 | if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { |
1138 | mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n", | 1150 | mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n", |
1139 | (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, | 1151 | (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, |
1140 | (int) (mdev->fw_ver & 0xffff), | 1152 | (int) (mdev->fw_ver & 0xffff), |
1141 | (int) (mthca_hca_table[hca_type].latest_fw >> 32), | 1153 | (int) (mthca_hca_table[hca_type].latest_fw >> 32), |
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 11f1d99db40b..df01b2026a64 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c | |||
@@ -1578,6 +1578,45 @@ static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq, | |||
1578 | return cur + nreq >= wq->max; | 1578 | return cur + nreq >= wq->max; |
1579 | } | 1579 | } |
1580 | 1580 | ||
1581 | static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg, | ||
1582 | u64 remote_addr, u32 rkey) | ||
1583 | { | ||
1584 | rseg->raddr = cpu_to_be64(remote_addr); | ||
1585 | rseg->rkey = cpu_to_be32(rkey); | ||
1586 | rseg->reserved = 0; | ||
1587 | } | ||
1588 | |||
1589 | static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg, | ||
1590 | struct ib_send_wr *wr) | ||
1591 | { | ||
1592 | if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { | ||
1593 | aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); | ||
1594 | aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); | ||
1595 | } else { | ||
1596 | aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); | ||
1597 | aseg->compare = 0; | ||
1598 | } | ||
1599 | |||
1600 | } | ||
1601 | |||
1602 | static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg, | ||
1603 | struct ib_send_wr *wr) | ||
1604 | { | ||
1605 | useg->lkey = cpu_to_be32(to_mah(wr->wr.ud.ah)->key); | ||
1606 | useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma); | ||
1607 | useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); | ||
1608 | useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); | ||
1609 | |||
1610 | } | ||
1611 | |||
1612 | static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg, | ||
1613 | struct ib_send_wr *wr) | ||
1614 | { | ||
1615 | memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE); | ||
1616 | useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); | ||
1617 | useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); | ||
1618 | } | ||
1619 | |||
1581 | int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | 1620 | int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, |
1582 | struct ib_send_wr **bad_wr) | 1621 | struct ib_send_wr **bad_wr) |
1583 | { | 1622 | { |
@@ -1590,8 +1629,15 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1590 | int nreq; | 1629 | int nreq; |
1591 | int i; | 1630 | int i; |
1592 | int size; | 1631 | int size; |
1593 | int size0 = 0; | 1632 | /* |
1594 | u32 f0 = 0; | 1633 | * f0 and size0 are only used if nreq != 0, and they will |
1634 | * always be initialized the first time through the main loop | ||
1635 | * before nreq is incremented. So nreq cannot become non-zero | ||
1636 | * without initializing f0 and size0, and they are in fact | ||
1637 | * never used uninitialized. | ||
1638 | */ | ||
1639 | int uninitialized_var(size0); | ||
1640 | u32 uninitialized_var(f0); | ||
1595 | int ind; | 1641 | int ind; |
1596 | u8 op0 = 0; | 1642 | u8 op0 = 0; |
1597 | 1643 | ||
@@ -1636,25 +1682,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1636 | switch (wr->opcode) { | 1682 | switch (wr->opcode) { |
1637 | case IB_WR_ATOMIC_CMP_AND_SWP: | 1683 | case IB_WR_ATOMIC_CMP_AND_SWP: |
1638 | case IB_WR_ATOMIC_FETCH_AND_ADD: | 1684 | case IB_WR_ATOMIC_FETCH_AND_ADD: |
1639 | ((struct mthca_raddr_seg *) wqe)->raddr = | 1685 | set_raddr_seg(wqe, wr->wr.atomic.remote_addr, |
1640 | cpu_to_be64(wr->wr.atomic.remote_addr); | 1686 | wr->wr.atomic.rkey); |
1641 | ((struct mthca_raddr_seg *) wqe)->rkey = | ||
1642 | cpu_to_be32(wr->wr.atomic.rkey); | ||
1643 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
1644 | |||
1645 | wqe += sizeof (struct mthca_raddr_seg); | 1687 | wqe += sizeof (struct mthca_raddr_seg); |
1646 | 1688 | ||
1647 | if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { | 1689 | set_atomic_seg(wqe, wr); |
1648 | ((struct mthca_atomic_seg *) wqe)->swap_add = | ||
1649 | cpu_to_be64(wr->wr.atomic.swap); | ||
1650 | ((struct mthca_atomic_seg *) wqe)->compare = | ||
1651 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
1652 | } else { | ||
1653 | ((struct mthca_atomic_seg *) wqe)->swap_add = | ||
1654 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
1655 | ((struct mthca_atomic_seg *) wqe)->compare = 0; | ||
1656 | } | ||
1657 | |||
1658 | wqe += sizeof (struct mthca_atomic_seg); | 1690 | wqe += sizeof (struct mthca_atomic_seg); |
1659 | size += (sizeof (struct mthca_raddr_seg) + | 1691 | size += (sizeof (struct mthca_raddr_seg) + |
1660 | sizeof (struct mthca_atomic_seg)) / 16; | 1692 | sizeof (struct mthca_atomic_seg)) / 16; |
@@ -1663,12 +1695,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1663 | case IB_WR_RDMA_WRITE: | 1695 | case IB_WR_RDMA_WRITE: |
1664 | case IB_WR_RDMA_WRITE_WITH_IMM: | 1696 | case IB_WR_RDMA_WRITE_WITH_IMM: |
1665 | case IB_WR_RDMA_READ: | 1697 | case IB_WR_RDMA_READ: |
1666 | ((struct mthca_raddr_seg *) wqe)->raddr = | 1698 | set_raddr_seg(wqe, wr->wr.rdma.remote_addr, |
1667 | cpu_to_be64(wr->wr.rdma.remote_addr); | 1699 | wr->wr.rdma.rkey); |
1668 | ((struct mthca_raddr_seg *) wqe)->rkey = | 1700 | wqe += sizeof (struct mthca_raddr_seg); |
1669 | cpu_to_be32(wr->wr.rdma.rkey); | ||
1670 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
1671 | wqe += sizeof (struct mthca_raddr_seg); | ||
1672 | size += sizeof (struct mthca_raddr_seg) / 16; | 1701 | size += sizeof (struct mthca_raddr_seg) / 16; |
1673 | break; | 1702 | break; |
1674 | 1703 | ||
@@ -1683,12 +1712,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1683 | switch (wr->opcode) { | 1712 | switch (wr->opcode) { |
1684 | case IB_WR_RDMA_WRITE: | 1713 | case IB_WR_RDMA_WRITE: |
1685 | case IB_WR_RDMA_WRITE_WITH_IMM: | 1714 | case IB_WR_RDMA_WRITE_WITH_IMM: |
1686 | ((struct mthca_raddr_seg *) wqe)->raddr = | 1715 | set_raddr_seg(wqe, wr->wr.rdma.remote_addr, |
1687 | cpu_to_be64(wr->wr.rdma.remote_addr); | 1716 | wr->wr.rdma.rkey); |
1688 | ((struct mthca_raddr_seg *) wqe)->rkey = | 1717 | wqe += sizeof (struct mthca_raddr_seg); |
1689 | cpu_to_be32(wr->wr.rdma.rkey); | ||
1690 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
1691 | wqe += sizeof (struct mthca_raddr_seg); | ||
1692 | size += sizeof (struct mthca_raddr_seg) / 16; | 1718 | size += sizeof (struct mthca_raddr_seg) / 16; |
1693 | break; | 1719 | break; |
1694 | 1720 | ||
@@ -1700,16 +1726,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1700 | break; | 1726 | break; |
1701 | 1727 | ||
1702 | case UD: | 1728 | case UD: |
1703 | ((struct mthca_tavor_ud_seg *) wqe)->lkey = | 1729 | set_tavor_ud_seg(wqe, wr); |
1704 | cpu_to_be32(to_mah(wr->wr.ud.ah)->key); | 1730 | wqe += sizeof (struct mthca_tavor_ud_seg); |
1705 | ((struct mthca_tavor_ud_seg *) wqe)->av_addr = | ||
1706 | cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma); | ||
1707 | ((struct mthca_tavor_ud_seg *) wqe)->dqpn = | ||
1708 | cpu_to_be32(wr->wr.ud.remote_qpn); | ||
1709 | ((struct mthca_tavor_ud_seg *) wqe)->qkey = | ||
1710 | cpu_to_be32(wr->wr.ud.remote_qkey); | ||
1711 | |||
1712 | wqe += sizeof (struct mthca_tavor_ud_seg); | ||
1713 | size += sizeof (struct mthca_tavor_ud_seg) / 16; | 1731 | size += sizeof (struct mthca_tavor_ud_seg) / 16; |
1714 | break; | 1732 | break; |
1715 | 1733 | ||
@@ -1734,13 +1752,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1734 | } | 1752 | } |
1735 | 1753 | ||
1736 | for (i = 0; i < wr->num_sge; ++i) { | 1754 | for (i = 0; i < wr->num_sge; ++i) { |
1737 | ((struct mthca_data_seg *) wqe)->byte_count = | 1755 | mthca_set_data_seg(wqe, wr->sg_list + i); |
1738 | cpu_to_be32(wr->sg_list[i].length); | 1756 | wqe += sizeof (struct mthca_data_seg); |
1739 | ((struct mthca_data_seg *) wqe)->lkey = | ||
1740 | cpu_to_be32(wr->sg_list[i].lkey); | ||
1741 | ((struct mthca_data_seg *) wqe)->addr = | ||
1742 | cpu_to_be64(wr->sg_list[i].addr); | ||
1743 | wqe += sizeof (struct mthca_data_seg); | ||
1744 | size += sizeof (struct mthca_data_seg) / 16; | 1757 | size += sizeof (struct mthca_data_seg) / 16; |
1745 | } | 1758 | } |
1746 | 1759 | ||
@@ -1768,11 +1781,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1768 | mthca_opcode[wr->opcode]); | 1781 | mthca_opcode[wr->opcode]); |
1769 | wmb(); | 1782 | wmb(); |
1770 | ((struct mthca_next_seg *) prev_wqe)->ee_nds = | 1783 | ((struct mthca_next_seg *) prev_wqe)->ee_nds = |
1771 | cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size | | 1784 | cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size | |
1772 | ((wr->send_flags & IB_SEND_FENCE) ? | 1785 | ((wr->send_flags & IB_SEND_FENCE) ? |
1773 | MTHCA_NEXT_FENCE : 0)); | 1786 | MTHCA_NEXT_FENCE : 0)); |
1774 | 1787 | ||
1775 | if (!size0) { | 1788 | if (!nreq) { |
1776 | size0 = size; | 1789 | size0 = size; |
1777 | op0 = mthca_opcode[wr->opcode]; | 1790 | op0 = mthca_opcode[wr->opcode]; |
1778 | f0 = wr->send_flags & IB_SEND_FENCE ? | 1791 | f0 = wr->send_flags & IB_SEND_FENCE ? |
@@ -1822,7 +1835,14 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1822 | int nreq; | 1835 | int nreq; |
1823 | int i; | 1836 | int i; |
1824 | int size; | 1837 | int size; |
1825 | int size0 = 0; | 1838 | /* |
1839 | * size0 is only used if nreq != 0, and it will always be | ||
1840 | * initialized the first time through the main loop before | ||
1841 | * nreq is incremented. So nreq cannot become non-zero | ||
1842 | * without initializing size0, and it is in fact never used | ||
1843 | * uninitialized. | ||
1844 | */ | ||
1845 | int uninitialized_var(size0); | ||
1826 | int ind; | 1846 | int ind; |
1827 | void *wqe; | 1847 | void *wqe; |
1828 | void *prev_wqe; | 1848 | void *prev_wqe; |
@@ -1863,13 +1883,8 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1863 | } | 1883 | } |
1864 | 1884 | ||
1865 | for (i = 0; i < wr->num_sge; ++i) { | 1885 | for (i = 0; i < wr->num_sge; ++i) { |
1866 | ((struct mthca_data_seg *) wqe)->byte_count = | 1886 | mthca_set_data_seg(wqe, wr->sg_list + i); |
1867 | cpu_to_be32(wr->sg_list[i].length); | 1887 | wqe += sizeof (struct mthca_data_seg); |
1868 | ((struct mthca_data_seg *) wqe)->lkey = | ||
1869 | cpu_to_be32(wr->sg_list[i].lkey); | ||
1870 | ((struct mthca_data_seg *) wqe)->addr = | ||
1871 | cpu_to_be64(wr->sg_list[i].addr); | ||
1872 | wqe += sizeof (struct mthca_data_seg); | ||
1873 | size += sizeof (struct mthca_data_seg) / 16; | 1888 | size += sizeof (struct mthca_data_seg) / 16; |
1874 | } | 1889 | } |
1875 | 1890 | ||
@@ -1881,7 +1896,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1881 | ((struct mthca_next_seg *) prev_wqe)->ee_nds = | 1896 | ((struct mthca_next_seg *) prev_wqe)->ee_nds = |
1882 | cpu_to_be32(MTHCA_NEXT_DBD | size); | 1897 | cpu_to_be32(MTHCA_NEXT_DBD | size); |
1883 | 1898 | ||
1884 | if (!size0) | 1899 | if (!nreq) |
1885 | size0 = size; | 1900 | size0 = size; |
1886 | 1901 | ||
1887 | ++ind; | 1902 | ++ind; |
@@ -1903,7 +1918,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
1903 | 1918 | ||
1904 | qp->rq.next_ind = ind; | 1919 | qp->rq.next_ind = ind; |
1905 | qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; | 1920 | qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; |
1906 | size0 = 0; | ||
1907 | } | 1921 | } |
1908 | } | 1922 | } |
1909 | 1923 | ||
@@ -1945,8 +1959,15 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1945 | int nreq; | 1959 | int nreq; |
1946 | int i; | 1960 | int i; |
1947 | int size; | 1961 | int size; |
1948 | int size0 = 0; | 1962 | /* |
1949 | u32 f0 = 0; | 1963 | * f0 and size0 are only used if nreq != 0, and they will |
1964 | * always be initialized the first time through the main loop | ||
1965 | * before nreq is incremented. So nreq cannot become non-zero | ||
1966 | * without initializing f0 and size0, and they are in fact | ||
1967 | * never used uninitialized. | ||
1968 | */ | ||
1969 | int uninitialized_var(size0); | ||
1970 | u32 uninitialized_var(f0); | ||
1950 | int ind; | 1971 | int ind; |
1951 | u8 op0 = 0; | 1972 | u8 op0 = 0; |
1952 | 1973 | ||
@@ -1966,7 +1987,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
1966 | doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0); | 1987 | doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0); |
1967 | 1988 | ||
1968 | qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; | 1989 | qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; |
1969 | size0 = 0; | ||
1970 | 1990 | ||
1971 | /* | 1991 | /* |
1972 | * Make sure that descriptors are written before | 1992 | * Make sure that descriptors are written before |
@@ -2017,26 +2037,12 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2017 | switch (wr->opcode) { | 2037 | switch (wr->opcode) { |
2018 | case IB_WR_ATOMIC_CMP_AND_SWP: | 2038 | case IB_WR_ATOMIC_CMP_AND_SWP: |
2019 | case IB_WR_ATOMIC_FETCH_AND_ADD: | 2039 | case IB_WR_ATOMIC_FETCH_AND_ADD: |
2020 | ((struct mthca_raddr_seg *) wqe)->raddr = | 2040 | set_raddr_seg(wqe, wr->wr.atomic.remote_addr, |
2021 | cpu_to_be64(wr->wr.atomic.remote_addr); | 2041 | wr->wr.atomic.rkey); |
2022 | ((struct mthca_raddr_seg *) wqe)->rkey = | ||
2023 | cpu_to_be32(wr->wr.atomic.rkey); | ||
2024 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
2025 | |||
2026 | wqe += sizeof (struct mthca_raddr_seg); | 2042 | wqe += sizeof (struct mthca_raddr_seg); |
2027 | 2043 | ||
2028 | if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { | 2044 | set_atomic_seg(wqe, wr); |
2029 | ((struct mthca_atomic_seg *) wqe)->swap_add = | 2045 | wqe += sizeof (struct mthca_atomic_seg); |
2030 | cpu_to_be64(wr->wr.atomic.swap); | ||
2031 | ((struct mthca_atomic_seg *) wqe)->compare = | ||
2032 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
2033 | } else { | ||
2034 | ((struct mthca_atomic_seg *) wqe)->swap_add = | ||
2035 | cpu_to_be64(wr->wr.atomic.compare_add); | ||
2036 | ((struct mthca_atomic_seg *) wqe)->compare = 0; | ||
2037 | } | ||
2038 | |||
2039 | wqe += sizeof (struct mthca_atomic_seg); | ||
2040 | size += (sizeof (struct mthca_raddr_seg) + | 2046 | size += (sizeof (struct mthca_raddr_seg) + |
2041 | sizeof (struct mthca_atomic_seg)) / 16; | 2047 | sizeof (struct mthca_atomic_seg)) / 16; |
2042 | break; | 2048 | break; |
@@ -2044,12 +2050,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2044 | case IB_WR_RDMA_READ: | 2050 | case IB_WR_RDMA_READ: |
2045 | case IB_WR_RDMA_WRITE: | 2051 | case IB_WR_RDMA_WRITE: |
2046 | case IB_WR_RDMA_WRITE_WITH_IMM: | 2052 | case IB_WR_RDMA_WRITE_WITH_IMM: |
2047 | ((struct mthca_raddr_seg *) wqe)->raddr = | 2053 | set_raddr_seg(wqe, wr->wr.rdma.remote_addr, |
2048 | cpu_to_be64(wr->wr.rdma.remote_addr); | 2054 | wr->wr.rdma.rkey); |
2049 | ((struct mthca_raddr_seg *) wqe)->rkey = | 2055 | wqe += sizeof (struct mthca_raddr_seg); |
2050 | cpu_to_be32(wr->wr.rdma.rkey); | ||
2051 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
2052 | wqe += sizeof (struct mthca_raddr_seg); | ||
2053 | size += sizeof (struct mthca_raddr_seg) / 16; | 2056 | size += sizeof (struct mthca_raddr_seg) / 16; |
2054 | break; | 2057 | break; |
2055 | 2058 | ||
@@ -2064,12 +2067,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2064 | switch (wr->opcode) { | 2067 | switch (wr->opcode) { |
2065 | case IB_WR_RDMA_WRITE: | 2068 | case IB_WR_RDMA_WRITE: |
2066 | case IB_WR_RDMA_WRITE_WITH_IMM: | 2069 | case IB_WR_RDMA_WRITE_WITH_IMM: |
2067 | ((struct mthca_raddr_seg *) wqe)->raddr = | 2070 | set_raddr_seg(wqe, wr->wr.rdma.remote_addr, |
2068 | cpu_to_be64(wr->wr.rdma.remote_addr); | 2071 | wr->wr.rdma.rkey); |
2069 | ((struct mthca_raddr_seg *) wqe)->rkey = | 2072 | wqe += sizeof (struct mthca_raddr_seg); |
2070 | cpu_to_be32(wr->wr.rdma.rkey); | ||
2071 | ((struct mthca_raddr_seg *) wqe)->reserved = 0; | ||
2072 | wqe += sizeof (struct mthca_raddr_seg); | ||
2073 | size += sizeof (struct mthca_raddr_seg) / 16; | 2073 | size += sizeof (struct mthca_raddr_seg) / 16; |
2074 | break; | 2074 | break; |
2075 | 2075 | ||
@@ -2081,14 +2081,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2081 | break; | 2081 | break; |
2082 | 2082 | ||
2083 | case UD: | 2083 | case UD: |
2084 | memcpy(((struct mthca_arbel_ud_seg *) wqe)->av, | 2084 | set_arbel_ud_seg(wqe, wr); |
2085 | to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE); | 2085 | wqe += sizeof (struct mthca_arbel_ud_seg); |
2086 | ((struct mthca_arbel_ud_seg *) wqe)->dqpn = | ||
2087 | cpu_to_be32(wr->wr.ud.remote_qpn); | ||
2088 | ((struct mthca_arbel_ud_seg *) wqe)->qkey = | ||
2089 | cpu_to_be32(wr->wr.ud.remote_qkey); | ||
2090 | |||
2091 | wqe += sizeof (struct mthca_arbel_ud_seg); | ||
2092 | size += sizeof (struct mthca_arbel_ud_seg) / 16; | 2086 | size += sizeof (struct mthca_arbel_ud_seg) / 16; |
2093 | break; | 2087 | break; |
2094 | 2088 | ||
@@ -2113,13 +2107,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2113 | } | 2107 | } |
2114 | 2108 | ||
2115 | for (i = 0; i < wr->num_sge; ++i) { | 2109 | for (i = 0; i < wr->num_sge; ++i) { |
2116 | ((struct mthca_data_seg *) wqe)->byte_count = | 2110 | mthca_set_data_seg(wqe, wr->sg_list + i); |
2117 | cpu_to_be32(wr->sg_list[i].length); | 2111 | wqe += sizeof (struct mthca_data_seg); |
2118 | ((struct mthca_data_seg *) wqe)->lkey = | ||
2119 | cpu_to_be32(wr->sg_list[i].lkey); | ||
2120 | ((struct mthca_data_seg *) wqe)->addr = | ||
2121 | cpu_to_be64(wr->sg_list[i].addr); | ||
2122 | wqe += sizeof (struct mthca_data_seg); | ||
2123 | size += sizeof (struct mthca_data_seg) / 16; | 2112 | size += sizeof (struct mthca_data_seg) / 16; |
2124 | } | 2113 | } |
2125 | 2114 | ||
@@ -2151,7 +2140,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | |||
2151 | ((wr->send_flags & IB_SEND_FENCE) ? | 2140 | ((wr->send_flags & IB_SEND_FENCE) ? |
2152 | MTHCA_NEXT_FENCE : 0)); | 2141 | MTHCA_NEXT_FENCE : 0)); |
2153 | 2142 | ||
2154 | if (!size0) { | 2143 | if (!nreq) { |
2155 | size0 = size; | 2144 | size0 = size; |
2156 | op0 = mthca_opcode[wr->opcode]; | 2145 | op0 = mthca_opcode[wr->opcode]; |
2157 | f0 = wr->send_flags & IB_SEND_FENCE ? | 2146 | f0 = wr->send_flags & IB_SEND_FENCE ? |
@@ -2241,20 +2230,12 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | |||
2241 | } | 2230 | } |
2242 | 2231 | ||
2243 | for (i = 0; i < wr->num_sge; ++i) { | 2232 | for (i = 0; i < wr->num_sge; ++i) { |
2244 | ((struct mthca_data_seg *) wqe)->byte_count = | 2233 | mthca_set_data_seg(wqe, wr->sg_list + i); |
2245 | cpu_to_be32(wr->sg_list[i].length); | ||
2246 | ((struct mthca_data_seg *) wqe)->lkey = | ||
2247 | cpu_to_be32(wr->sg_list[i].lkey); | ||
2248 | ((struct mthca_data_seg *) wqe)->addr = | ||
2249 | cpu_to_be64(wr->sg_list[i].addr); | ||
2250 | wqe += sizeof (struct mthca_data_seg); | 2234 | wqe += sizeof (struct mthca_data_seg); |
2251 | } | 2235 | } |
2252 | 2236 | ||
2253 | if (i < qp->rq.max_gs) { | 2237 | if (i < qp->rq.max_gs) |
2254 | ((struct mthca_data_seg *) wqe)->byte_count = 0; | 2238 | mthca_set_data_seg_inval(wqe); |
2255 | ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); | ||
2256 | ((struct mthca_data_seg *) wqe)->addr = 0; | ||
2257 | } | ||
2258 | 2239 | ||
2259 | qp->wrid[ind] = wr->wr_id; | 2240 | qp->wrid[ind] = wr->wr_id; |
2260 | 2241 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index b8f05a526673..88d219e730ad 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c | |||
@@ -543,20 +543,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
543 | } | 543 | } |
544 | 544 | ||
545 | for (i = 0; i < wr->num_sge; ++i) { | 545 | for (i = 0; i < wr->num_sge; ++i) { |
546 | ((struct mthca_data_seg *) wqe)->byte_count = | 546 | mthca_set_data_seg(wqe, wr->sg_list + i); |
547 | cpu_to_be32(wr->sg_list[i].length); | ||
548 | ((struct mthca_data_seg *) wqe)->lkey = | ||
549 | cpu_to_be32(wr->sg_list[i].lkey); | ||
550 | ((struct mthca_data_seg *) wqe)->addr = | ||
551 | cpu_to_be64(wr->sg_list[i].addr); | ||
552 | wqe += sizeof (struct mthca_data_seg); | 547 | wqe += sizeof (struct mthca_data_seg); |
553 | } | 548 | } |
554 | 549 | ||
555 | if (i < srq->max_gs) { | 550 | if (i < srq->max_gs) |
556 | ((struct mthca_data_seg *) wqe)->byte_count = 0; | 551 | mthca_set_data_seg_inval(wqe); |
557 | ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); | ||
558 | ((struct mthca_data_seg *) wqe)->addr = 0; | ||
559 | } | ||
560 | 552 | ||
561 | ((struct mthca_next_seg *) prev_wqe)->nda_op = | 553 | ((struct mthca_next_seg *) prev_wqe)->nda_op = |
562 | cpu_to_be32((ind << srq->wqe_shift) | 1); | 554 | cpu_to_be32((ind << srq->wqe_shift) | 1); |
@@ -662,20 +654,12 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, | |||
662 | } | 654 | } |
663 | 655 | ||
664 | for (i = 0; i < wr->num_sge; ++i) { | 656 | for (i = 0; i < wr->num_sge; ++i) { |
665 | ((struct mthca_data_seg *) wqe)->byte_count = | 657 | mthca_set_data_seg(wqe, wr->sg_list + i); |
666 | cpu_to_be32(wr->sg_list[i].length); | ||
667 | ((struct mthca_data_seg *) wqe)->lkey = | ||
668 | cpu_to_be32(wr->sg_list[i].lkey); | ||
669 | ((struct mthca_data_seg *) wqe)->addr = | ||
670 | cpu_to_be64(wr->sg_list[i].addr); | ||
671 | wqe += sizeof (struct mthca_data_seg); | 658 | wqe += sizeof (struct mthca_data_seg); |
672 | } | 659 | } |
673 | 660 | ||
674 | if (i < srq->max_gs) { | 661 | if (i < srq->max_gs) |
675 | ((struct mthca_data_seg *) wqe)->byte_count = 0; | 662 | mthca_set_data_seg_inval(wqe); |
676 | ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); | ||
677 | ((struct mthca_data_seg *) wqe)->addr = 0; | ||
678 | } | ||
679 | 663 | ||
680 | srq->wrid[ind] = wr->wr_id; | 664 | srq->wrid[ind] = wr->wr_id; |
681 | srq->first_free = next_ind; | 665 | srq->first_free = next_ind; |
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h index e7d2c1e86199..f6a66fe78e48 100644 --- a/drivers/infiniband/hw/mthca/mthca_wqe.h +++ b/drivers/infiniband/hw/mthca/mthca_wqe.h | |||
@@ -113,4 +113,19 @@ struct mthca_mlx_seg { | |||
113 | __be16 vcrc; | 113 | __be16 vcrc; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg, | ||
117 | struct ib_sge *sg) | ||
118 | { | ||
119 | dseg->byte_count = cpu_to_be32(sg->length); | ||
120 | dseg->lkey = cpu_to_be32(sg->lkey); | ||
121 | dseg->addr = cpu_to_be64(sg->addr); | ||
122 | } | ||
123 | |||
124 | static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg) | ||
125 | { | ||
126 | dseg->byte_count = 0; | ||
127 | dseg->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); | ||
128 | dseg->addr = 0; | ||
129 | } | ||
130 | |||
116 | #endif /* MTHCA_WQE_H */ | 131 | #endif /* MTHCA_WQE_H */ |
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index e2353701e8bb..1ee867b1b341 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h | |||
@@ -310,8 +310,6 @@ int iser_conn_init(struct iser_conn **ib_conn); | |||
310 | 310 | ||
311 | void iser_conn_terminate(struct iser_conn *ib_conn); | 311 | void iser_conn_terminate(struct iser_conn *ib_conn); |
312 | 312 | ||
313 | void iser_conn_release(struct iser_conn *ib_conn); | ||
314 | |||
315 | void iser_rcv_completion(struct iser_desc *desc, | 313 | void iser_rcv_completion(struct iser_desc *desc, |
316 | unsigned long dto_xfer_len); | 314 | unsigned long dto_xfer_len); |
317 | 315 | ||
@@ -329,9 +327,6 @@ void iser_reg_single(struct iser_device *device, | |||
329 | struct iser_regd_buf *regd_buf, | 327 | struct iser_regd_buf *regd_buf, |
330 | enum dma_data_direction direction); | 328 | enum dma_data_direction direction); |
331 | 329 | ||
332 | int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask, | ||
333 | enum iser_data_dir cmd_dir); | ||
334 | |||
335 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask, | 330 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask, |
336 | enum iser_data_dir cmd_dir); | 331 | enum iser_data_dir cmd_dir); |
337 | 332 | ||
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index fc9f1fd0ae54..36cdf77ae92a 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c | |||
@@ -103,8 +103,8 @@ void iser_reg_single(struct iser_device *device, | |||
103 | /** | 103 | /** |
104 | * iser_start_rdma_unaligned_sg | 104 | * iser_start_rdma_unaligned_sg |
105 | */ | 105 | */ |
106 | int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | 106 | static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, |
107 | enum iser_data_dir cmd_dir) | 107 | enum iser_data_dir cmd_dir) |
108 | { | 108 | { |
109 | int dma_nents; | 109 | int dma_nents; |
110 | struct ib_device *dev; | 110 | struct ib_device *dev; |
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 2044de1164ac..d42ec0156eec 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c | |||
@@ -311,6 +311,29 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn, | |||
311 | } | 311 | } |
312 | 312 | ||
313 | /** | 313 | /** |
314 | * Frees all conn objects and deallocs conn descriptor | ||
315 | */ | ||
316 | static void iser_conn_release(struct iser_conn *ib_conn) | ||
317 | { | ||
318 | struct iser_device *device = ib_conn->device; | ||
319 | |||
320 | BUG_ON(ib_conn->state != ISER_CONN_DOWN); | ||
321 | |||
322 | mutex_lock(&ig.connlist_mutex); | ||
323 | list_del(&ib_conn->conn_list); | ||
324 | mutex_unlock(&ig.connlist_mutex); | ||
325 | |||
326 | iser_free_ib_conn_res(ib_conn); | ||
327 | ib_conn->device = NULL; | ||
328 | /* on EVENT_ADDR_ERROR there's no device yet for this conn */ | ||
329 | if (device != NULL) | ||
330 | iser_device_try_release(device); | ||
331 | if (ib_conn->iser_conn) | ||
332 | ib_conn->iser_conn->ib_conn = NULL; | ||
333 | kfree(ib_conn); | ||
334 | } | ||
335 | |||
336 | /** | ||
314 | * triggers start of the disconnect procedures and wait for them to be done | 337 | * triggers start of the disconnect procedures and wait for them to be done |
315 | */ | 338 | */ |
316 | void iser_conn_terminate(struct iser_conn *ib_conn) | 339 | void iser_conn_terminate(struct iser_conn *ib_conn) |
@@ -550,30 +573,6 @@ connect_failure: | |||
550 | } | 573 | } |
551 | 574 | ||
552 | /** | 575 | /** |
553 | * Frees all conn objects and deallocs conn descriptor | ||
554 | */ | ||
555 | void iser_conn_release(struct iser_conn *ib_conn) | ||
556 | { | ||
557 | struct iser_device *device = ib_conn->device; | ||
558 | |||
559 | BUG_ON(ib_conn->state != ISER_CONN_DOWN); | ||
560 | |||
561 | mutex_lock(&ig.connlist_mutex); | ||
562 | list_del(&ib_conn->conn_list); | ||
563 | mutex_unlock(&ig.connlist_mutex); | ||
564 | |||
565 | iser_free_ib_conn_res(ib_conn); | ||
566 | ib_conn->device = NULL; | ||
567 | /* on EVENT_ADDR_ERROR there's no device yet for this conn */ | ||
568 | if (device != NULL) | ||
569 | iser_device_try_release(device); | ||
570 | if (ib_conn->iser_conn) | ||
571 | ib_conn->iser_conn->ib_conn = NULL; | ||
572 | kfree(ib_conn); | ||
573 | } | ||
574 | |||
575 | |||
576 | /** | ||
577 | * iser_reg_page_vec - Register physical memory | 576 | * iser_reg_page_vec - Register physical memory |
578 | * | 577 | * |
579 | * returns: 0 on success, errno code on failure | 578 | * returns: 0 on success, errno code on failure |
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 5a7b49c35539..b10ffae7c39b 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c | |||
@@ -117,15 +117,13 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) | |||
117 | if (ret) | 117 | if (ret) |
118 | return ret; | 118 | return ret; |
119 | 119 | ||
120 | kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); | 120 | kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); |
121 | io = kmalloc(sizeof(struct serio), GFP_KERNEL); | 121 | io = kzalloc(sizeof(struct serio), GFP_KERNEL); |
122 | if (!kmi || !io) { | 122 | if (!kmi || !io) { |
123 | ret = -ENOMEM; | 123 | ret = -ENOMEM; |
124 | goto out; | 124 | goto out; |
125 | } | 125 | } |
126 | 126 | ||
127 | memset(kmi, 0, sizeof(struct amba_kmi_port)); | ||
128 | memset(io, 0, sizeof(struct serio)); | ||
129 | 127 | ||
130 | io->id.type = SERIO_8042; | 128 | io->id.type = SERIO_8042; |
131 | io->write = amba_kmi_write; | 129 | io->write = amba_kmi_write; |
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index ea5e3c6ddb62..1b404f9e3bff 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c | |||
@@ -140,15 +140,13 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i | |||
140 | if (ret) | 140 | if (ret) |
141 | goto disable; | 141 | goto disable; |
142 | 142 | ||
143 | ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); | 143 | ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL); |
144 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | 144 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); |
145 | if (!ps2if || !serio) { | 145 | if (!ps2if || !serio) { |
146 | ret = -ENOMEM; | 146 | ret = -ENOMEM; |
147 | goto release; | 147 | goto release; |
148 | } | 148 | } |
149 | 149 | ||
150 | memset(ps2if, 0, sizeof(struct pcips2_data)); | ||
151 | memset(serio, 0, sizeof(struct serio)); | ||
152 | 150 | ||
153 | serio->id.type = SERIO_8042; | 151 | serio->id.type = SERIO_8042; |
154 | serio->write = pcips2_write; | 152 | serio->write = pcips2_write; |
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index d31ece8f68e9..2ad88780a170 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c | |||
@@ -234,15 +234,13 @@ static int __devinit ps2_probe(struct sa1111_dev *dev) | |||
234 | struct serio *serio; | 234 | struct serio *serio; |
235 | int ret; | 235 | int ret; |
236 | 236 | ||
237 | ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); | 237 | ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL); |
238 | serio = kmalloc(sizeof(struct serio), GFP_KERNEL); | 238 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); |
239 | if (!ps2if || !serio) { | 239 | if (!ps2if || !serio) { |
240 | ret = -ENOMEM; | 240 | ret = -ENOMEM; |
241 | goto free; | 241 | goto free; |
242 | } | 242 | } |
243 | 243 | ||
244 | memset(ps2if, 0, sizeof(struct ps2if)); | ||
245 | memset(serio, 0, sizeof(struct serio)); | ||
246 | 244 | ||
247 | serio->id.type = SERIO_8042; | 245 | serio->id.type = SERIO_8042; |
248 | serio->write = ps2_write; | 246 | serio->write = ps2_write; |
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 5f7907e57090..97097ef3491e 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c | |||
@@ -1146,14 +1146,12 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card, | |||
1146 | } | 1146 | } |
1147 | if (ret) { | 1147 | if (ret) { |
1148 | closecard(cardnr); | 1148 | closecard(cardnr); |
1149 | ret = 0; | ||
1150 | goto outf_cs; | 1149 | goto outf_cs; |
1151 | } | 1150 | } |
1152 | init_tei(cs, cs->protocol); | 1151 | init_tei(cs, cs->protocol); |
1153 | ret = CallcNewChan(cs); | 1152 | ret = CallcNewChan(cs); |
1154 | if (ret) { | 1153 | if (ret) { |
1155 | closecard(cardnr); | 1154 | closecard(cardnr); |
1156 | ret = 0; | ||
1157 | goto outf_cs; | 1155 | goto outf_cs; |
1158 | } | 1156 | } |
1159 | /* ISAR needs firmware download first */ | 1157 | /* ISAR needs firmware download first */ |
@@ -1165,7 +1163,7 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card, | |||
1165 | outf_cs: | 1163 | outf_cs: |
1166 | kfree(cs); | 1164 | kfree(cs); |
1167 | card->cs = NULL; | 1165 | card->cs = NULL; |
1168 | return ret; | 1166 | return 0; |
1169 | } | 1167 | } |
1170 | 1168 | ||
1171 | static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner) | 1169 | static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner) |
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h index 4fbfa825c3a2..5992f63c383e 100644 --- a/drivers/isdn/sc/card.h +++ b/drivers/isdn/sc/card.h | |||
@@ -125,7 +125,7 @@ int sendmessage(int card, unsigned int procid, unsigned int type, | |||
125 | int receivemessage(int card, RspMessage *rspmsg); | 125 | int receivemessage(int card, RspMessage *rspmsg); |
126 | int sc_ioctl(int card, scs_ioctl *data); | 126 | int sc_ioctl(int card, scs_ioctl *data); |
127 | int setup_buffers(int card, int c); | 127 | int setup_buffers(int card, int c); |
128 | void check_reset(unsigned long data); | 128 | void sc_check_reset(unsigned long data); |
129 | void check_phystat(unsigned long data); | 129 | void check_phystat(unsigned long data); |
130 | 130 | ||
131 | #endif /* CARD_H */ | 131 | #endif /* CARD_H */ |
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c index b7bb7cbcf503..0e4969c2ef95 100644 --- a/drivers/isdn/sc/command.c +++ b/drivers/isdn/sc/command.c | |||
@@ -344,7 +344,7 @@ int reset(int card) | |||
344 | 344 | ||
345 | spin_lock_irqsave(&sc_adapter[card]->lock, flags); | 345 | spin_lock_irqsave(&sc_adapter[card]->lock, flags); |
346 | init_timer(&sc_adapter[card]->reset_timer); | 346 | init_timer(&sc_adapter[card]->reset_timer); |
347 | sc_adapter[card]->reset_timer.function = check_reset; | 347 | sc_adapter[card]->reset_timer.function = sc_check_reset; |
348 | sc_adapter[card]->reset_timer.data = card; | 348 | sc_adapter[card]->reset_timer.data = card; |
349 | sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; | 349 | sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; |
350 | add_timer(&sc_adapter[card]->reset_timer); | 350 | add_timer(&sc_adapter[card]->reset_timer); |
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c index cc1b8861be2a..91fbe0dc28ec 100644 --- a/drivers/isdn/sc/timer.c +++ b/drivers/isdn/sc/timer.c | |||
@@ -43,7 +43,7 @@ static void setup_ports(int card) | |||
43 | * Then, check to see if the signate has been set. Next, set the | 43 | * Then, check to see if the signate has been set. Next, set the |
44 | * signature to a known value and issue a startproc if needed. | 44 | * signature to a known value and issue a startproc if needed. |
45 | */ | 45 | */ |
46 | void check_reset(unsigned long data) | 46 | void sc_check_reset(unsigned long data) |
47 | { | 47 | { |
48 | unsigned long flags; | 48 | unsigned long flags; |
49 | unsigned long sig; | 49 | unsigned long sig; |
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig new file mode 100644 index 000000000000..43d901fdc77f --- /dev/null +++ b/drivers/lguest/Kconfig | |||
@@ -0,0 +1,20 @@ | |||
1 | config LGUEST | ||
2 | tristate "Linux hypervisor example code" | ||
3 | depends on X86 && PARAVIRT && NET && EXPERIMENTAL && !X86_PAE | ||
4 | select LGUEST_GUEST | ||
5 | select HVC_DRIVER | ||
6 | ---help--- | ||
7 | This is a very simple module which allows you to run | ||
8 | multiple instances of the same Linux kernel, using the | ||
9 | "lguest" command found in the Documentation/lguest directory. | ||
10 | Note that "lguest" is pronounced to rhyme with "fell quest", | ||
11 | not "rustyvisor". See Documentation/lguest/lguest.txt. | ||
12 | |||
13 | If unsure, say N. If curious, say M. If masochistic, say Y. | ||
14 | |||
15 | config LGUEST_GUEST | ||
16 | bool | ||
17 | help | ||
18 | The guest needs code built-in, even if the host has lguest | ||
19 | support as a module. The drivers are tiny, so we build them | ||
20 | in too. | ||
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile new file mode 100644 index 000000000000..55382c7d799c --- /dev/null +++ b/drivers/lguest/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # Guest requires the paravirt_ops replacement and the bus driver. | ||
2 | obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o | ||
3 | |||
4 | # Host requires the other files, which can be a module. | ||
5 | obj-$(CONFIG_LGUEST) += lg.o | ||
6 | lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \ | ||
7 | segments.o io.o lguest_user.o switcher.o | ||
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c new file mode 100644 index 000000000000..ce909ec57499 --- /dev/null +++ b/drivers/lguest/core.c | |||
@@ -0,0 +1,462 @@ | |||
1 | /* World's simplest hypervisor, to test paravirt_ops and show | ||
2 | * unbelievers that virtualization is the future. Plus, it's fun! */ | ||
3 | #include <linux/module.h> | ||
4 | #include <linux/stringify.h> | ||
5 | #include <linux/stddef.h> | ||
6 | #include <linux/io.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/vmalloc.h> | ||
9 | #include <linux/cpu.h> | ||
10 | #include <linux/freezer.h> | ||
11 | #include <asm/paravirt.h> | ||
12 | #include <asm/desc.h> | ||
13 | #include <asm/pgtable.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/poll.h> | ||
16 | #include <asm/highmem.h> | ||
17 | #include <asm/asm-offsets.h> | ||
18 | #include <asm/i387.h> | ||
19 | #include "lg.h" | ||
20 | |||
21 | /* Found in switcher.S */ | ||
22 | extern char start_switcher_text[], end_switcher_text[], switch_to_guest[]; | ||
23 | extern unsigned long default_idt_entries[]; | ||
24 | |||
25 | /* Every guest maps the core switcher code. */ | ||
26 | #define SHARED_SWITCHER_PAGES \ | ||
27 | DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE) | ||
28 | /* Pages for switcher itself, then two pages per cpu */ | ||
29 | #define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS) | ||
30 | |||
31 | /* We map at -4M for ease of mapping into the guest (one PTE page). */ | ||
32 | #define SWITCHER_ADDR 0xFFC00000 | ||
33 | |||
34 | static struct vm_struct *switcher_vma; | ||
35 | static struct page **switcher_page; | ||
36 | |||
37 | static int cpu_had_pge; | ||
38 | static struct { | ||
39 | unsigned long offset; | ||
40 | unsigned short segment; | ||
41 | } lguest_entry; | ||
42 | |||
43 | /* This One Big lock protects all inter-guest data structures. */ | ||
44 | DEFINE_MUTEX(lguest_lock); | ||
45 | static DEFINE_PER_CPU(struct lguest *, last_guest); | ||
46 | |||
47 | /* FIXME: Make dynamic. */ | ||
48 | #define MAX_LGUEST_GUESTS 16 | ||
49 | struct lguest lguests[MAX_LGUEST_GUESTS]; | ||
50 | |||
51 | /* Offset from where switcher.S was compiled to where we've copied it */ | ||
52 | static unsigned long switcher_offset(void) | ||
53 | { | ||
54 | return SWITCHER_ADDR - (unsigned long)start_switcher_text; | ||
55 | } | ||
56 | |||
57 | /* This cpu's struct lguest_pages. */ | ||
58 | static struct lguest_pages *lguest_pages(unsigned int cpu) | ||
59 | { | ||
60 | return &(((struct lguest_pages *) | ||
61 | (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]); | ||
62 | } | ||
63 | |||
64 | static __init int map_switcher(void) | ||
65 | { | ||
66 | int i, err; | ||
67 | struct page **pagep; | ||
68 | |||
69 | switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES, | ||
70 | GFP_KERNEL); | ||
71 | if (!switcher_page) { | ||
72 | err = -ENOMEM; | ||
73 | goto out; | ||
74 | } | ||
75 | |||
76 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { | ||
77 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
78 | if (!addr) { | ||
79 | err = -ENOMEM; | ||
80 | goto free_some_pages; | ||
81 | } | ||
82 | switcher_page[i] = virt_to_page(addr); | ||
83 | } | ||
84 | |||
85 | switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, | ||
86 | VM_ALLOC, SWITCHER_ADDR, VMALLOC_END); | ||
87 | if (!switcher_vma) { | ||
88 | err = -ENOMEM; | ||
89 | printk("lguest: could not map switcher pages high\n"); | ||
90 | goto free_pages; | ||
91 | } | ||
92 | |||
93 | pagep = switcher_page; | ||
94 | err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep); | ||
95 | if (err) { | ||
96 | printk("lguest: map_vm_area failed: %i\n", err); | ||
97 | goto free_vma; | ||
98 | } | ||
99 | memcpy(switcher_vma->addr, start_switcher_text, | ||
100 | end_switcher_text - start_switcher_text); | ||
101 | |||
102 | /* Fix up IDT entries to point into copied text. */ | ||
103 | for (i = 0; i < IDT_ENTRIES; i++) | ||
104 | default_idt_entries[i] += switcher_offset(); | ||
105 | |||
106 | for_each_possible_cpu(i) { | ||
107 | struct lguest_pages *pages = lguest_pages(i); | ||
108 | struct lguest_ro_state *state = &pages->state; | ||
109 | |||
110 | /* These fields are static: rest done in copy_in_guest_info */ | ||
111 | state->host_gdt_desc.size = GDT_SIZE-1; | ||
112 | state->host_gdt_desc.address = (long)get_cpu_gdt_table(i); | ||
113 | store_idt(&state->host_idt_desc); | ||
114 | state->guest_idt_desc.size = sizeof(state->guest_idt)-1; | ||
115 | state->guest_idt_desc.address = (long)&state->guest_idt; | ||
116 | state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1; | ||
117 | state->guest_gdt_desc.address = (long)&state->guest_gdt; | ||
118 | state->guest_tss.esp0 = (long)(&pages->regs + 1); | ||
119 | state->guest_tss.ss0 = LGUEST_DS; | ||
120 | /* No I/O for you! */ | ||
121 | state->guest_tss.io_bitmap_base = sizeof(state->guest_tss); | ||
122 | setup_default_gdt_entries(state); | ||
123 | setup_default_idt_entries(state, default_idt_entries); | ||
124 | |||
125 | /* Setup LGUEST segments on all cpus */ | ||
126 | get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT; | ||
127 | get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT; | ||
128 | } | ||
129 | |||
130 | /* Initialize entry point into switcher. */ | ||
131 | lguest_entry.offset = (long)switch_to_guest + switcher_offset(); | ||
132 | lguest_entry.segment = LGUEST_CS; | ||
133 | |||
134 | printk(KERN_INFO "lguest: mapped switcher at %p\n", | ||
135 | switcher_vma->addr); | ||
136 | return 0; | ||
137 | |||
138 | free_vma: | ||
139 | vunmap(switcher_vma->addr); | ||
140 | free_pages: | ||
141 | i = TOTAL_SWITCHER_PAGES; | ||
142 | free_some_pages: | ||
143 | for (--i; i >= 0; i--) | ||
144 | __free_pages(switcher_page[i], 0); | ||
145 | kfree(switcher_page); | ||
146 | out: | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | static void unmap_switcher(void) | ||
151 | { | ||
152 | unsigned int i; | ||
153 | |||
154 | vunmap(switcher_vma->addr); | ||
155 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) | ||
156 | __free_pages(switcher_page[i], 0); | ||
157 | } | ||
158 | |||
159 | /* IN/OUT insns: enough to get us past boot-time probing. */ | ||
160 | static int emulate_insn(struct lguest *lg) | ||
161 | { | ||
162 | u8 insn; | ||
163 | unsigned int insnlen = 0, in = 0, shift = 0; | ||
164 | unsigned long physaddr = guest_pa(lg, lg->regs->eip); | ||
165 | |||
166 | /* This only works for addresses in linear mapping... */ | ||
167 | if (lg->regs->eip < lg->page_offset) | ||
168 | return 0; | ||
169 | lgread(lg, &insn, physaddr, 1); | ||
170 | |||
171 | /* Operand size prefix means it's actually for ax. */ | ||
172 | if (insn == 0x66) { | ||
173 | shift = 16; | ||
174 | insnlen = 1; | ||
175 | lgread(lg, &insn, physaddr + insnlen, 1); | ||
176 | } | ||
177 | |||
178 | switch (insn & 0xFE) { | ||
179 | case 0xE4: /* in <next byte>,%al */ | ||
180 | insnlen += 2; | ||
181 | in = 1; | ||
182 | break; | ||
183 | case 0xEC: /* in (%dx),%al */ | ||
184 | insnlen += 1; | ||
185 | in = 1; | ||
186 | break; | ||
187 | case 0xE6: /* out %al,<next byte> */ | ||
188 | insnlen += 2; | ||
189 | break; | ||
190 | case 0xEE: /* out %al,(%dx) */ | ||
191 | insnlen += 1; | ||
192 | break; | ||
193 | default: | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | if (in) { | ||
198 | /* Lower bit tells is whether it's a 16 or 32 bit access */ | ||
199 | if (insn & 0x1) | ||
200 | lg->regs->eax = 0xFFFFFFFF; | ||
201 | else | ||
202 | lg->regs->eax |= (0xFFFF << shift); | ||
203 | } | ||
204 | lg->regs->eip += insnlen; | ||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | int lguest_address_ok(const struct lguest *lg, | ||
209 | unsigned long addr, unsigned long len) | ||
210 | { | ||
211 | return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr); | ||
212 | } | ||
213 | |||
214 | /* Just like get_user, but don't let guest access lguest binary. */ | ||
215 | u32 lgread_u32(struct lguest *lg, unsigned long addr) | ||
216 | { | ||
217 | u32 val = 0; | ||
218 | |||
219 | /* Don't let them access lguest binary */ | ||
220 | if (!lguest_address_ok(lg, addr, sizeof(val)) | ||
221 | || get_user(val, (u32 __user *)addr) != 0) | ||
222 | kill_guest(lg, "bad read address %#lx", addr); | ||
223 | return val; | ||
224 | } | ||
225 | |||
226 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val) | ||
227 | { | ||
228 | if (!lguest_address_ok(lg, addr, sizeof(val)) | ||
229 | || put_user(val, (u32 __user *)addr) != 0) | ||
230 | kill_guest(lg, "bad write address %#lx", addr); | ||
231 | } | ||
232 | |||
233 | void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) | ||
234 | { | ||
235 | if (!lguest_address_ok(lg, addr, bytes) | ||
236 | || copy_from_user(b, (void __user *)addr, bytes) != 0) { | ||
237 | /* copy_from_user should do this, but as we rely on it... */ | ||
238 | memset(b, 0, bytes); | ||
239 | kill_guest(lg, "bad read address %#lx len %u", addr, bytes); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | void lgwrite(struct lguest *lg, unsigned long addr, const void *b, | ||
244 | unsigned bytes) | ||
245 | { | ||
246 | if (!lguest_address_ok(lg, addr, bytes) | ||
247 | || copy_to_user((void __user *)addr, b, bytes) != 0) | ||
248 | kill_guest(lg, "bad write address %#lx len %u", addr, bytes); | ||
249 | } | ||
250 | |||
251 | static void set_ts(void) | ||
252 | { | ||
253 | u32 cr0; | ||
254 | |||
255 | cr0 = read_cr0(); | ||
256 | if (!(cr0 & 8)) | ||
257 | write_cr0(cr0|8); | ||
258 | } | ||
259 | |||
260 | static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) | ||
261 | { | ||
262 | if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) { | ||
263 | __get_cpu_var(last_guest) = lg; | ||
264 | lg->last_pages = pages; | ||
265 | lg->changed = CHANGED_ALL; | ||
266 | } | ||
267 | |||
268 | /* These are pretty cheap, so we do them unconditionally. */ | ||
269 | pages->state.host_cr3 = __pa(current->mm->pgd); | ||
270 | map_switcher_in_guest(lg, pages); | ||
271 | pages->state.guest_tss.esp1 = lg->esp1; | ||
272 | pages->state.guest_tss.ss1 = lg->ss1; | ||
273 | |||
274 | /* Copy direct trap entries. */ | ||
275 | if (lg->changed & CHANGED_IDT) | ||
276 | copy_traps(lg, pages->state.guest_idt, default_idt_entries); | ||
277 | |||
278 | /* Copy all GDT entries but the TSS. */ | ||
279 | if (lg->changed & CHANGED_GDT) | ||
280 | copy_gdt(lg, pages->state.guest_gdt); | ||
281 | /* If only the TLS entries have changed, copy them. */ | ||
282 | else if (lg->changed & CHANGED_GDT_TLS) | ||
283 | copy_gdt_tls(lg, pages->state.guest_gdt); | ||
284 | |||
285 | lg->changed = 0; | ||
286 | } | ||
287 | |||
288 | static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) | ||
289 | { | ||
290 | unsigned int clobber; | ||
291 | |||
292 | copy_in_guest_info(lg, pages); | ||
293 | |||
294 | /* Put eflags on stack, lcall does rest: suitable for iret return. */ | ||
295 | asm volatile("pushf; lcall *lguest_entry" | ||
296 | : "=a"(clobber), "=b"(clobber) | ||
297 | : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir)) | ||
298 | : "memory", "%edx", "%ecx", "%edi", "%esi"); | ||
299 | } | ||
300 | |||
301 | int run_guest(struct lguest *lg, unsigned long __user *user) | ||
302 | { | ||
303 | while (!lg->dead) { | ||
304 | unsigned int cr2 = 0; /* Damn gcc */ | ||
305 | |||
306 | /* Hypercalls first: we might have been out to userspace */ | ||
307 | do_hypercalls(lg); | ||
308 | if (lg->dma_is_pending) { | ||
309 | if (put_user(lg->pending_dma, user) || | ||
310 | put_user(lg->pending_key, user+1)) | ||
311 | return -EFAULT; | ||
312 | return sizeof(unsigned long)*2; | ||
313 | } | ||
314 | |||
315 | if (signal_pending(current)) | ||
316 | return -ERESTARTSYS; | ||
317 | |||
318 | /* If Waker set break_out, return to Launcher. */ | ||
319 | if (lg->break_out) | ||
320 | return -EAGAIN; | ||
321 | |||
322 | maybe_do_interrupt(lg); | ||
323 | |||
324 | try_to_freeze(); | ||
325 | |||
326 | if (lg->dead) | ||
327 | break; | ||
328 | |||
329 | if (lg->halted) { | ||
330 | set_current_state(TASK_INTERRUPTIBLE); | ||
331 | schedule(); | ||
332 | continue; | ||
333 | } | ||
334 | |||
335 | local_irq_disable(); | ||
336 | |||
337 | /* Even if *we* don't want FPU trap, guest might... */ | ||
338 | if (lg->ts) | ||
339 | set_ts(); | ||
340 | |||
341 | /* Don't let Guest do SYSENTER: we can't handle it. */ | ||
342 | if (boot_cpu_has(X86_FEATURE_SEP)) | ||
343 | wrmsr(MSR_IA32_SYSENTER_CS, 0, 0); | ||
344 | |||
345 | run_guest_once(lg, lguest_pages(raw_smp_processor_id())); | ||
346 | |||
347 | /* Save cr2 now if we page-faulted. */ | ||
348 | if (lg->regs->trapnum == 14) | ||
349 | cr2 = read_cr2(); | ||
350 | else if (lg->regs->trapnum == 7) | ||
351 | math_state_restore(); | ||
352 | |||
353 | if (boot_cpu_has(X86_FEATURE_SEP)) | ||
354 | wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); | ||
355 | local_irq_enable(); | ||
356 | |||
357 | switch (lg->regs->trapnum) { | ||
358 | case 13: /* We've intercepted a GPF. */ | ||
359 | if (lg->regs->errcode == 0) { | ||
360 | if (emulate_insn(lg)) | ||
361 | continue; | ||
362 | } | ||
363 | break; | ||
364 | case 14: /* We've intercepted a page fault. */ | ||
365 | if (demand_page(lg, cr2, lg->regs->errcode)) | ||
366 | continue; | ||
367 | |||
368 | /* If lguest_data is NULL, this won't hurt. */ | ||
369 | if (put_user(cr2, &lg->lguest_data->cr2)) | ||
370 | kill_guest(lg, "Writing cr2"); | ||
371 | break; | ||
372 | case 7: /* We've intercepted a Device Not Available fault. */ | ||
373 | /* If they don't want to know, just absorb it. */ | ||
374 | if (!lg->ts) | ||
375 | continue; | ||
376 | break; | ||
377 | case 32 ... 255: /* Real interrupt, fall thru */ | ||
378 | cond_resched(); | ||
379 | case LGUEST_TRAP_ENTRY: /* Handled at top of loop */ | ||
380 | continue; | ||
381 | } | ||
382 | |||
383 | if (deliver_trap(lg, lg->regs->trapnum)) | ||
384 | continue; | ||
385 | |||
386 | kill_guest(lg, "unhandled trap %li at %#lx (%#lx)", | ||
387 | lg->regs->trapnum, lg->regs->eip, | ||
388 | lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode); | ||
389 | } | ||
390 | return -ENOENT; | ||
391 | } | ||
392 | |||
393 | int find_free_guest(void) | ||
394 | { | ||
395 | unsigned int i; | ||
396 | for (i = 0; i < MAX_LGUEST_GUESTS; i++) | ||
397 | if (!lguests[i].tsk) | ||
398 | return i; | ||
399 | return -1; | ||
400 | } | ||
401 | |||
402 | static void adjust_pge(void *on) | ||
403 | { | ||
404 | if (on) | ||
405 | write_cr4(read_cr4() | X86_CR4_PGE); | ||
406 | else | ||
407 | write_cr4(read_cr4() & ~X86_CR4_PGE); | ||
408 | } | ||
409 | |||
410 | static int __init init(void) | ||
411 | { | ||
412 | int err; | ||
413 | |||
414 | if (paravirt_enabled()) { | ||
415 | printk("lguest is afraid of %s\n", paravirt_ops.name); | ||
416 | return -EPERM; | ||
417 | } | ||
418 | |||
419 | err = map_switcher(); | ||
420 | if (err) | ||
421 | return err; | ||
422 | |||
423 | err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES); | ||
424 | if (err) { | ||
425 | unmap_switcher(); | ||
426 | return err; | ||
427 | } | ||
428 | lguest_io_init(); | ||
429 | |||
430 | err = lguest_device_init(); | ||
431 | if (err) { | ||
432 | free_pagetables(); | ||
433 | unmap_switcher(); | ||
434 | return err; | ||
435 | } | ||
436 | lock_cpu_hotplug(); | ||
437 | if (cpu_has_pge) { /* We have a broader idea of "global". */ | ||
438 | cpu_had_pge = 1; | ||
439 | on_each_cpu(adjust_pge, (void *)0, 0, 1); | ||
440 | clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); | ||
441 | } | ||
442 | unlock_cpu_hotplug(); | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static void __exit fini(void) | ||
447 | { | ||
448 | lguest_device_remove(); | ||
449 | free_pagetables(); | ||
450 | unmap_switcher(); | ||
451 | lock_cpu_hotplug(); | ||
452 | if (cpu_had_pge) { | ||
453 | set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); | ||
454 | on_each_cpu(adjust_pge, (void *)1, 0, 1); | ||
455 | } | ||
456 | unlock_cpu_hotplug(); | ||
457 | } | ||
458 | |||
459 | module_init(init); | ||
460 | module_exit(fini); | ||
461 | MODULE_LICENSE("GPL"); | ||
462 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c new file mode 100644 index 000000000000..ea52ca451f74 --- /dev/null +++ b/drivers/lguest/hypercalls.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* Actual hypercalls, which allow guests to actually do something. | ||
2 | Copyright (C) 2006 Rusty Russell IBM Corporation | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include <linux/uaccess.h> | ||
19 | #include <linux/syscalls.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/pgtable.h> | ||
23 | #include <irq_vectors.h> | ||
24 | #include "lg.h" | ||
25 | |||
26 | static void do_hcall(struct lguest *lg, struct lguest_regs *regs) | ||
27 | { | ||
28 | switch (regs->eax) { | ||
29 | case LHCALL_FLUSH_ASYNC: | ||
30 | break; | ||
31 | case LHCALL_LGUEST_INIT: | ||
32 | kill_guest(lg, "already have lguest_data"); | ||
33 | break; | ||
34 | case LHCALL_CRASH: { | ||
35 | char msg[128]; | ||
36 | lgread(lg, msg, regs->edx, sizeof(msg)); | ||
37 | msg[sizeof(msg)-1] = '\0'; | ||
38 | kill_guest(lg, "CRASH: %s", msg); | ||
39 | break; | ||
40 | } | ||
41 | case LHCALL_FLUSH_TLB: | ||
42 | if (regs->edx) | ||
43 | guest_pagetable_clear_all(lg); | ||
44 | else | ||
45 | guest_pagetable_flush_user(lg); | ||
46 | break; | ||
47 | case LHCALL_GET_WALLCLOCK: { | ||
48 | struct timespec ts; | ||
49 | ktime_get_real_ts(&ts); | ||
50 | regs->eax = ts.tv_sec; | ||
51 | break; | ||
52 | } | ||
53 | case LHCALL_BIND_DMA: | ||
54 | regs->eax = bind_dma(lg, regs->edx, regs->ebx, | ||
55 | regs->ecx >> 8, regs->ecx & 0xFF); | ||
56 | break; | ||
57 | case LHCALL_SEND_DMA: | ||
58 | send_dma(lg, regs->edx, regs->ebx); | ||
59 | break; | ||
60 | case LHCALL_LOAD_GDT: | ||
61 | load_guest_gdt(lg, regs->edx, regs->ebx); | ||
62 | break; | ||
63 | case LHCALL_LOAD_IDT_ENTRY: | ||
64 | load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx); | ||
65 | break; | ||
66 | case LHCALL_NEW_PGTABLE: | ||
67 | guest_new_pagetable(lg, regs->edx); | ||
68 | break; | ||
69 | case LHCALL_SET_STACK: | ||
70 | guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx); | ||
71 | break; | ||
72 | case LHCALL_SET_PTE: | ||
73 | guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx)); | ||
74 | break; | ||
75 | case LHCALL_SET_PMD: | ||
76 | guest_set_pmd(lg, regs->edx, regs->ebx); | ||
77 | break; | ||
78 | case LHCALL_LOAD_TLS: | ||
79 | guest_load_tls(lg, regs->edx); | ||
80 | break; | ||
81 | case LHCALL_SET_CLOCKEVENT: | ||
82 | guest_set_clockevent(lg, regs->edx); | ||
83 | break; | ||
84 | case LHCALL_TS: | ||
85 | lg->ts = regs->edx; | ||
86 | break; | ||
87 | case LHCALL_HALT: | ||
88 | lg->halted = 1; | ||
89 | break; | ||
90 | default: | ||
91 | kill_guest(lg, "Bad hypercall %li\n", regs->eax); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* We always do queued calls before actual hypercall. */ | ||
96 | static void do_async_hcalls(struct lguest *lg) | ||
97 | { | ||
98 | unsigned int i; | ||
99 | u8 st[LHCALL_RING_SIZE]; | ||
100 | |||
101 | if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) | ||
102 | return; | ||
103 | |||
104 | for (i = 0; i < ARRAY_SIZE(st); i++) { | ||
105 | struct lguest_regs regs; | ||
106 | unsigned int n = lg->next_hcall; | ||
107 | |||
108 | if (st[n] == 0xFF) | ||
109 | break; | ||
110 | |||
111 | if (++lg->next_hcall == LHCALL_RING_SIZE) | ||
112 | lg->next_hcall = 0; | ||
113 | |||
114 | if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax) | ||
115 | || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx) | ||
116 | || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx) | ||
117 | || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) { | ||
118 | kill_guest(lg, "Fetching async hypercalls"); | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | do_hcall(lg, ®s); | ||
123 | if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { | ||
124 | kill_guest(lg, "Writing result for async hypercall"); | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | if (lg->dma_is_pending) | ||
129 | break; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void initialize(struct lguest *lg) | ||
134 | { | ||
135 | u32 tsc_speed; | ||
136 | |||
137 | if (lg->regs->eax != LHCALL_LGUEST_INIT) { | ||
138 | kill_guest(lg, "hypercall %li before LGUEST_INIT", | ||
139 | lg->regs->eax); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | /* We only tell the guest to use the TSC if it's reliable. */ | ||
144 | if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable()) | ||
145 | tsc_speed = tsc_khz; | ||
146 | else | ||
147 | tsc_speed = 0; | ||
148 | |||
149 | lg->lguest_data = (struct lguest_data __user *)lg->regs->edx; | ||
150 | /* We check here so we can simply copy_to_user/from_user */ | ||
151 | if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) { | ||
152 | kill_guest(lg, "bad guest page %p", lg->lguest_data); | ||
153 | return; | ||
154 | } | ||
155 | if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) | ||
156 | || get_user(lg->noirq_end, &lg->lguest_data->noirq_end) | ||
157 | /* We reserve the top pgd entry. */ | ||
158 | || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem) | ||
159 | || put_user(tsc_speed, &lg->lguest_data->tsc_khz) | ||
160 | || put_user(lg->guestid, &lg->lguest_data->guestid)) | ||
161 | kill_guest(lg, "bad guest page %p", lg->lguest_data); | ||
162 | |||
163 | /* This is the one case where the above accesses might have | ||
164 | * been the first write to a Guest page. This may have caused | ||
165 | * a copy-on-write fault, but the Guest might be referring to | ||
166 | * the old (read-only) page. */ | ||
167 | guest_pagetable_clear_all(lg); | ||
168 | } | ||
169 | |||
170 | /* Even if we go out to userspace and come back, we don't want to do | ||
171 | * the hypercall again. */ | ||
172 | static void clear_hcall(struct lguest *lg) | ||
173 | { | ||
174 | lg->regs->trapnum = 255; | ||
175 | } | ||
176 | |||
177 | void do_hypercalls(struct lguest *lg) | ||
178 | { | ||
179 | if (unlikely(!lg->lguest_data)) { | ||
180 | if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) { | ||
181 | initialize(lg); | ||
182 | clear_hcall(lg); | ||
183 | } | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | do_async_hcalls(lg); | ||
188 | if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) { | ||
189 | do_hcall(lg, lg->regs); | ||
190 | clear_hcall(lg); | ||
191 | } | ||
192 | } | ||
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c new file mode 100644 index 000000000000..d9de5bbc613f --- /dev/null +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -0,0 +1,268 @@ | |||
1 | #include <linux/uaccess.h> | ||
2 | #include "lg.h" | ||
3 | |||
4 | static unsigned long idt_address(u32 lo, u32 hi) | ||
5 | { | ||
6 | return (lo & 0x0000FFFF) | (hi & 0xFFFF0000); | ||
7 | } | ||
8 | |||
9 | static int idt_type(u32 lo, u32 hi) | ||
10 | { | ||
11 | return (hi >> 8) & 0xF; | ||
12 | } | ||
13 | |||
14 | static int idt_present(u32 lo, u32 hi) | ||
15 | { | ||
16 | return (hi & 0x8000); | ||
17 | } | ||
18 | |||
19 | static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) | ||
20 | { | ||
21 | *gstack -= 4; | ||
22 | lgwrite_u32(lg, *gstack, val); | ||
23 | } | ||
24 | |||
25 | static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | ||
26 | { | ||
27 | unsigned long gstack; | ||
28 | u32 eflags, ss, irq_enable; | ||
29 | |||
30 | /* If they want a ring change, we use new stack and push old ss/esp */ | ||
31 | if ((lg->regs->ss&0x3) != GUEST_PL) { | ||
32 | gstack = guest_pa(lg, lg->esp1); | ||
33 | ss = lg->ss1; | ||
34 | push_guest_stack(lg, &gstack, lg->regs->ss); | ||
35 | push_guest_stack(lg, &gstack, lg->regs->esp); | ||
36 | } else { | ||
37 | gstack = guest_pa(lg, lg->regs->esp); | ||
38 | ss = lg->regs->ss; | ||
39 | } | ||
40 | |||
41 | /* We use IF bit in eflags to indicate whether irqs were disabled | ||
42 | (it's always 0, since irqs are enabled when guest is running). */ | ||
43 | eflags = lg->regs->eflags; | ||
44 | if (get_user(irq_enable, &lg->lguest_data->irq_enabled)) | ||
45 | irq_enable = 0; | ||
46 | eflags |= (irq_enable & X86_EFLAGS_IF); | ||
47 | |||
48 | push_guest_stack(lg, &gstack, eflags); | ||
49 | push_guest_stack(lg, &gstack, lg->regs->cs); | ||
50 | push_guest_stack(lg, &gstack, lg->regs->eip); | ||
51 | |||
52 | if (has_err) | ||
53 | push_guest_stack(lg, &gstack, lg->regs->errcode); | ||
54 | |||
55 | /* Change the real stack so switcher returns to trap handler */ | ||
56 | lg->regs->ss = ss; | ||
57 | lg->regs->esp = gstack + lg->page_offset; | ||
58 | lg->regs->cs = (__KERNEL_CS|GUEST_PL); | ||
59 | lg->regs->eip = idt_address(lo, hi); | ||
60 | |||
61 | /* Disable interrupts for an interrupt gate. */ | ||
62 | if (idt_type(lo, hi) == 0xE) | ||
63 | if (put_user(0, &lg->lguest_data->irq_enabled)) | ||
64 | kill_guest(lg, "Disabling interrupts"); | ||
65 | } | ||
66 | |||
67 | void maybe_do_interrupt(struct lguest *lg) | ||
68 | { | ||
69 | unsigned int irq; | ||
70 | DECLARE_BITMAP(blk, LGUEST_IRQS); | ||
71 | struct desc_struct *idt; | ||
72 | |||
73 | if (!lg->lguest_data) | ||
74 | return; | ||
75 | |||
76 | /* Mask out any interrupts they have blocked. */ | ||
77 | if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts, | ||
78 | sizeof(blk))) | ||
79 | return; | ||
80 | |||
81 | bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS); | ||
82 | |||
83 | irq = find_first_bit(blk, LGUEST_IRQS); | ||
84 | if (irq >= LGUEST_IRQS) | ||
85 | return; | ||
86 | |||
87 | if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end) | ||
88 | return; | ||
89 | |||
90 | /* If they're halted, we re-enable interrupts. */ | ||
91 | if (lg->halted) { | ||
92 | /* Re-enable interrupts. */ | ||
93 | if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled)) | ||
94 | kill_guest(lg, "Re-enabling interrupts"); | ||
95 | lg->halted = 0; | ||
96 | } else { | ||
97 | /* Maybe they have interrupts disabled? */ | ||
98 | u32 irq_enabled; | ||
99 | if (get_user(irq_enabled, &lg->lguest_data->irq_enabled)) | ||
100 | irq_enabled = 0; | ||
101 | if (!irq_enabled) | ||
102 | return; | ||
103 | } | ||
104 | |||
105 | idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq]; | ||
106 | if (idt_present(idt->a, idt->b)) { | ||
107 | clear_bit(irq, lg->irqs_pending); | ||
108 | set_guest_interrupt(lg, idt->a, idt->b, 0); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static int has_err(unsigned int trap) | ||
113 | { | ||
114 | return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17); | ||
115 | } | ||
116 | |||
117 | int deliver_trap(struct lguest *lg, unsigned int num) | ||
118 | { | ||
119 | u32 lo = lg->idt[num].a, hi = lg->idt[num].b; | ||
120 | |||
121 | if (!idt_present(lo, hi)) | ||
122 | return 0; | ||
123 | set_guest_interrupt(lg, lo, hi, has_err(num)); | ||
124 | return 1; | ||
125 | } | ||
126 | |||
127 | static int direct_trap(const struct lguest *lg, | ||
128 | const struct desc_struct *trap, | ||
129 | unsigned int num) | ||
130 | { | ||
131 | /* Hardware interrupts don't go to guest (except syscall). */ | ||
132 | if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR) | ||
133 | return 0; | ||
134 | |||
135 | /* We intercept page fault (demand shadow paging & cr2 saving) | ||
136 | protection fault (in/out emulation) and device not | ||
137 | available (TS handling), and hypercall */ | ||
138 | if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY) | ||
139 | return 0; | ||
140 | |||
141 | /* Interrupt gates (0xE) or not present (0x0) can't go direct. */ | ||
142 | return idt_type(trap->a, trap->b) == 0xF; | ||
143 | } | ||
144 | |||
145 | void pin_stack_pages(struct lguest *lg) | ||
146 | { | ||
147 | unsigned int i; | ||
148 | |||
149 | for (i = 0; i < lg->stack_pages; i++) | ||
150 | pin_page(lg, lg->esp1 - i * PAGE_SIZE); | ||
151 | } | ||
152 | |||
153 | void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) | ||
154 | { | ||
155 | /* You cannot have a stack segment with priv level 0. */ | ||
156 | if ((seg & 0x3) != GUEST_PL) | ||
157 | kill_guest(lg, "bad stack segment %i", seg); | ||
158 | if (pages > 2) | ||
159 | kill_guest(lg, "bad stack pages %u", pages); | ||
160 | lg->ss1 = seg; | ||
161 | lg->esp1 = esp; | ||
162 | lg->stack_pages = pages; | ||
163 | pin_stack_pages(lg); | ||
164 | } | ||
165 | |||
166 | /* Set up trap in IDT. */ | ||
167 | static void set_trap(struct lguest *lg, struct desc_struct *trap, | ||
168 | unsigned int num, u32 lo, u32 hi) | ||
169 | { | ||
170 | u8 type = idt_type(lo, hi); | ||
171 | |||
172 | if (!idt_present(lo, hi)) { | ||
173 | trap->a = trap->b = 0; | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | if (type != 0xE && type != 0xF) | ||
178 | kill_guest(lg, "bad IDT type %i", type); | ||
179 | |||
180 | trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF); | ||
181 | trap->b = (hi&0xFFFFEF00); | ||
182 | } | ||
183 | |||
184 | void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) | ||
185 | { | ||
186 | /* Guest never handles: NMI, doublefault, hypercall, spurious irq. */ | ||
187 | if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY) | ||
188 | return; | ||
189 | |||
190 | lg->changed |= CHANGED_IDT; | ||
191 | if (num < ARRAY_SIZE(lg->idt)) | ||
192 | set_trap(lg, &lg->idt[num], num, lo, hi); | ||
193 | else if (num == SYSCALL_VECTOR) | ||
194 | set_trap(lg, &lg->syscall_idt, num, lo, hi); | ||
195 | } | ||
196 | |||
197 | static void default_idt_entry(struct desc_struct *idt, | ||
198 | int trap, | ||
199 | const unsigned long handler) | ||
200 | { | ||
201 | u32 flags = 0x8e00; | ||
202 | |||
203 | /* They can't "int" into any of them except hypercall. */ | ||
204 | if (trap == LGUEST_TRAP_ENTRY) | ||
205 | flags |= (GUEST_PL << 13); | ||
206 | |||
207 | idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); | ||
208 | idt->b = (handler&0xFFFF0000) | flags; | ||
209 | } | ||
210 | |||
211 | void setup_default_idt_entries(struct lguest_ro_state *state, | ||
212 | const unsigned long *def) | ||
213 | { | ||
214 | unsigned int i; | ||
215 | |||
216 | for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) | ||
217 | default_idt_entry(&state->guest_idt[i], i, def[i]); | ||
218 | } | ||
219 | |||
220 | void copy_traps(const struct lguest *lg, struct desc_struct *idt, | ||
221 | const unsigned long *def) | ||
222 | { | ||
223 | unsigned int i; | ||
224 | |||
225 | /* All hardware interrupts are same whatever the guest: only the | ||
226 | * traps might be different. */ | ||
227 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) { | ||
228 | if (direct_trap(lg, &lg->idt[i], i)) | ||
229 | idt[i] = lg->idt[i]; | ||
230 | else | ||
231 | default_idt_entry(&idt[i], i, def[i]); | ||
232 | } | ||
233 | i = SYSCALL_VECTOR; | ||
234 | if (direct_trap(lg, &lg->syscall_idt, i)) | ||
235 | idt[i] = lg->syscall_idt; | ||
236 | else | ||
237 | default_idt_entry(&idt[i], i, def[i]); | ||
238 | } | ||
239 | |||
240 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) | ||
241 | { | ||
242 | ktime_t expires; | ||
243 | |||
244 | if (unlikely(delta == 0)) { | ||
245 | /* Clock event device is shutting down. */ | ||
246 | hrtimer_cancel(&lg->hrt); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | expires = ktime_add_ns(ktime_get_real(), delta); | ||
251 | hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); | ||
252 | } | ||
253 | |||
254 | static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) | ||
255 | { | ||
256 | struct lguest *lg = container_of(timer, struct lguest, hrt); | ||
257 | |||
258 | set_bit(0, lg->irqs_pending); | ||
259 | if (lg->halted) | ||
260 | wake_up_process(lg->tsk); | ||
261 | return HRTIMER_NORESTART; | ||
262 | } | ||
263 | |||
264 | void init_clockdev(struct lguest *lg) | ||
265 | { | ||
266 | hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); | ||
267 | lg->hrt.function = clockdev_fn; | ||
268 | } | ||
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c new file mode 100644 index 000000000000..06bdba2337ef --- /dev/null +++ b/drivers/lguest/io.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* Simple I/O model for guests, based on shared memory. | ||
2 | * Copyright (C) 2006 Rusty Russell IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/futex.h> | ||
20 | #include <linux/jhash.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/highmem.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include "lg.h" | ||
25 | |||
26 | static struct list_head dma_hash[61]; | ||
27 | |||
28 | void lguest_io_init(void) | ||
29 | { | ||
30 | unsigned int i; | ||
31 | |||
32 | for (i = 0; i < ARRAY_SIZE(dma_hash); i++) | ||
33 | INIT_LIST_HEAD(&dma_hash[i]); | ||
34 | } | ||
35 | |||
36 | /* FIXME: allow multi-page lengths. */ | ||
37 | static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma) | ||
38 | { | ||
39 | unsigned int i; | ||
40 | |||
41 | for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) { | ||
42 | if (!dma->len[i]) | ||
43 | return 1; | ||
44 | if (!lguest_address_ok(lg, dma->addr[i], dma->len[i])) | ||
45 | goto kill; | ||
46 | if (dma->len[i] > PAGE_SIZE) | ||
47 | goto kill; | ||
48 | /* We could do over a page, but is it worth it? */ | ||
49 | if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE) | ||
50 | goto kill; | ||
51 | } | ||
52 | return 1; | ||
53 | |||
54 | kill: | ||
55 | kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static unsigned int hash(const union futex_key *key) | ||
60 | { | ||
61 | return jhash2((u32*)&key->both.word, | ||
62 | (sizeof(key->both.word)+sizeof(key->both.ptr))/4, | ||
63 | key->both.offset) | ||
64 | % ARRAY_SIZE(dma_hash); | ||
65 | } | ||
66 | |||
67 | static inline int key_eq(const union futex_key *a, const union futex_key *b) | ||
68 | { | ||
69 | return (a->both.word == b->both.word | ||
70 | && a->both.ptr == b->both.ptr | ||
71 | && a->both.offset == b->both.offset); | ||
72 | } | ||
73 | |||
74 | /* Must hold read lock on dmainfo owner's current->mm->mmap_sem */ | ||
75 | static void unlink_dma(struct lguest_dma_info *dmainfo) | ||
76 | { | ||
77 | BUG_ON(!mutex_is_locked(&lguest_lock)); | ||
78 | dmainfo->interrupt = 0; | ||
79 | list_del(&dmainfo->list); | ||
80 | drop_futex_key_refs(&dmainfo->key); | ||
81 | } | ||
82 | |||
83 | static int unbind_dma(struct lguest *lg, | ||
84 | const union futex_key *key, | ||
85 | unsigned long dmas) | ||
86 | { | ||
87 | int i, ret = 0; | ||
88 | |||
89 | for (i = 0; i < LGUEST_MAX_DMA; i++) { | ||
90 | if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) { | ||
91 | unlink_dma(&lg->dma[i]); | ||
92 | ret = 1; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | int bind_dma(struct lguest *lg, | ||
100 | unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt) | ||
101 | { | ||
102 | unsigned int i; | ||
103 | int ret = 0; | ||
104 | union futex_key key; | ||
105 | struct rw_semaphore *fshared = ¤t->mm->mmap_sem; | ||
106 | |||
107 | if (interrupt >= LGUEST_IRQS) | ||
108 | return 0; | ||
109 | |||
110 | mutex_lock(&lguest_lock); | ||
111 | down_read(fshared); | ||
112 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | ||
113 | kill_guest(lg, "bad dma key %#lx", ukey); | ||
114 | goto unlock; | ||
115 | } | ||
116 | get_futex_key_refs(&key); | ||
117 | |||
118 | if (interrupt == 0) | ||
119 | ret = unbind_dma(lg, &key, dmas); | ||
120 | else { | ||
121 | for (i = 0; i < LGUEST_MAX_DMA; i++) { | ||
122 | if (lg->dma[i].interrupt) | ||
123 | continue; | ||
124 | |||
125 | lg->dma[i].dmas = dmas; | ||
126 | lg->dma[i].num_dmas = numdmas; | ||
127 | lg->dma[i].next_dma = 0; | ||
128 | lg->dma[i].key = key; | ||
129 | lg->dma[i].guestid = lg->guestid; | ||
130 | lg->dma[i].interrupt = interrupt; | ||
131 | list_add(&lg->dma[i].list, &dma_hash[hash(&key)]); | ||
132 | ret = 1; | ||
133 | goto unlock; | ||
134 | } | ||
135 | } | ||
136 | drop_futex_key_refs(&key); | ||
137 | unlock: | ||
138 | up_read(fshared); | ||
139 | mutex_unlock(&lguest_lock); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | /* lgread from another guest */ | ||
144 | static int lgread_other(struct lguest *lg, | ||
145 | void *buf, u32 addr, unsigned bytes) | ||
146 | { | ||
147 | if (!lguest_address_ok(lg, addr, bytes) | ||
148 | || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) { | ||
149 | memset(buf, 0, bytes); | ||
150 | kill_guest(lg, "bad address in registered DMA struct"); | ||
151 | return 0; | ||
152 | } | ||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | /* lgwrite to another guest */ | ||
157 | static int lgwrite_other(struct lguest *lg, u32 addr, | ||
158 | const void *buf, unsigned bytes) | ||
159 | { | ||
160 | if (!lguest_address_ok(lg, addr, bytes) | ||
161 | || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1) | ||
162 | != bytes)) { | ||
163 | kill_guest(lg, "bad address writing to registered DMA"); | ||
164 | return 0; | ||
165 | } | ||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | static u32 copy_data(struct lguest *srclg, | ||
170 | const struct lguest_dma *src, | ||
171 | const struct lguest_dma *dst, | ||
172 | struct page *pages[]) | ||
173 | { | ||
174 | unsigned int totlen, si, di, srcoff, dstoff; | ||
175 | void *maddr = NULL; | ||
176 | |||
177 | totlen = 0; | ||
178 | si = di = 0; | ||
179 | srcoff = dstoff = 0; | ||
180 | while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si] | ||
181 | && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) { | ||
182 | u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff); | ||
183 | |||
184 | if (!maddr) | ||
185 | maddr = kmap(pages[di]); | ||
186 | |||
187 | /* FIXME: This is not completely portable, since | ||
188 | archs do different things for copy_to_user_page. */ | ||
189 | if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE, | ||
190 | (void *__user)src->addr[si], len) != 0) { | ||
191 | kill_guest(srclg, "bad address in sending DMA"); | ||
192 | totlen = 0; | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | totlen += len; | ||
197 | srcoff += len; | ||
198 | dstoff += len; | ||
199 | if (srcoff == src->len[si]) { | ||
200 | si++; | ||
201 | srcoff = 0; | ||
202 | } | ||
203 | if (dstoff == dst->len[di]) { | ||
204 | kunmap(pages[di]); | ||
205 | maddr = NULL; | ||
206 | di++; | ||
207 | dstoff = 0; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (maddr) | ||
212 | kunmap(pages[di]); | ||
213 | |||
214 | return totlen; | ||
215 | } | ||
216 | |||
217 | /* Src is us, ie. current. */ | ||
218 | static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src, | ||
219 | struct lguest *dstlg, const struct lguest_dma *dst) | ||
220 | { | ||
221 | int i; | ||
222 | u32 ret; | ||
223 | struct page *pages[LGUEST_MAX_DMA_SECTIONS]; | ||
224 | |||
225 | if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src)) | ||
226 | return 0; | ||
227 | |||
228 | /* First get the destination pages */ | ||
229 | for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) { | ||
230 | if (dst->len[i] == 0) | ||
231 | break; | ||
232 | if (get_user_pages(dstlg->tsk, dstlg->mm, | ||
233 | dst->addr[i], 1, 1, 1, pages+i, NULL) | ||
234 | != 1) { | ||
235 | kill_guest(dstlg, "Error mapping DMA pages"); | ||
236 | ret = 0; | ||
237 | goto drop_pages; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* Now copy until we run out of src or dst. */ | ||
242 | ret = copy_data(srclg, src, dst, pages); | ||
243 | |||
244 | drop_pages: | ||
245 | while (--i >= 0) | ||
246 | put_page(pages[i]); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static int dma_transfer(struct lguest *srclg, | ||
251 | unsigned long udma, | ||
252 | struct lguest_dma_info *dst) | ||
253 | { | ||
254 | struct lguest_dma dst_dma, src_dma; | ||
255 | struct lguest *dstlg; | ||
256 | u32 i, dma = 0; | ||
257 | |||
258 | dstlg = &lguests[dst->guestid]; | ||
259 | /* Get our dma list. */ | ||
260 | lgread(srclg, &src_dma, udma, sizeof(src_dma)); | ||
261 | |||
262 | /* We can't deadlock against them dmaing to us, because this | ||
263 | * is all under the lguest_lock. */ | ||
264 | down_read(&dstlg->mm->mmap_sem); | ||
265 | |||
266 | for (i = 0; i < dst->num_dmas; i++) { | ||
267 | dma = (dst->next_dma + i) % dst->num_dmas; | ||
268 | if (!lgread_other(dstlg, &dst_dma, | ||
269 | dst->dmas + dma * sizeof(struct lguest_dma), | ||
270 | sizeof(dst_dma))) { | ||
271 | goto fail; | ||
272 | } | ||
273 | if (!dst_dma.used_len) | ||
274 | break; | ||
275 | } | ||
276 | if (i != dst->num_dmas) { | ||
277 | unsigned long used_lenp; | ||
278 | unsigned int ret; | ||
279 | |||
280 | ret = do_dma(srclg, &src_dma, dstlg, &dst_dma); | ||
281 | /* Put used length in src. */ | ||
282 | lgwrite_u32(srclg, | ||
283 | udma+offsetof(struct lguest_dma, used_len), ret); | ||
284 | if (ret == 0 && src_dma.len[0] != 0) | ||
285 | goto fail; | ||
286 | |||
287 | /* Make sure destination sees contents before length. */ | ||
288 | wmb(); | ||
289 | used_lenp = dst->dmas | ||
290 | + dma * sizeof(struct lguest_dma) | ||
291 | + offsetof(struct lguest_dma, used_len); | ||
292 | lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret)); | ||
293 | dst->next_dma++; | ||
294 | } | ||
295 | up_read(&dstlg->mm->mmap_sem); | ||
296 | |||
297 | /* Do this last so dst doesn't simply sleep on lock. */ | ||
298 | set_bit(dst->interrupt, dstlg->irqs_pending); | ||
299 | wake_up_process(dstlg->tsk); | ||
300 | return i == dst->num_dmas; | ||
301 | |||
302 | fail: | ||
303 | up_read(&dstlg->mm->mmap_sem); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma) | ||
308 | { | ||
309 | union futex_key key; | ||
310 | int empty = 0; | ||
311 | struct rw_semaphore *fshared = ¤t->mm->mmap_sem; | ||
312 | |||
313 | again: | ||
314 | mutex_lock(&lguest_lock); | ||
315 | down_read(fshared); | ||
316 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | ||
317 | kill_guest(lg, "bad sending DMA key"); | ||
318 | goto unlock; | ||
319 | } | ||
320 | /* Shared mapping? Look for other guests... */ | ||
321 | if (key.shared.offset & 1) { | ||
322 | struct lguest_dma_info *i; | ||
323 | list_for_each_entry(i, &dma_hash[hash(&key)], list) { | ||
324 | if (i->guestid == lg->guestid) | ||
325 | continue; | ||
326 | if (!key_eq(&key, &i->key)) | ||
327 | continue; | ||
328 | |||
329 | empty += dma_transfer(lg, udma, i); | ||
330 | break; | ||
331 | } | ||
332 | if (empty == 1) { | ||
333 | /* Give any recipients one chance to restock. */ | ||
334 | up_read(¤t->mm->mmap_sem); | ||
335 | mutex_unlock(&lguest_lock); | ||
336 | empty++; | ||
337 | goto again; | ||
338 | } | ||
339 | } else { | ||
340 | /* Private mapping: tell our userspace. */ | ||
341 | lg->dma_is_pending = 1; | ||
342 | lg->pending_dma = udma; | ||
343 | lg->pending_key = ukey; | ||
344 | } | ||
345 | unlock: | ||
346 | up_read(fshared); | ||
347 | mutex_unlock(&lguest_lock); | ||
348 | } | ||
349 | |||
350 | void release_all_dma(struct lguest *lg) | ||
351 | { | ||
352 | unsigned int i; | ||
353 | |||
354 | BUG_ON(!mutex_is_locked(&lguest_lock)); | ||
355 | |||
356 | down_read(&lg->mm->mmap_sem); | ||
357 | for (i = 0; i < LGUEST_MAX_DMA; i++) { | ||
358 | if (lg->dma[i].interrupt) | ||
359 | unlink_dma(&lg->dma[i]); | ||
360 | } | ||
361 | up_read(&lg->mm->mmap_sem); | ||
362 | } | ||
363 | |||
364 | /* Userspace wants a dma buffer from this guest. */ | ||
365 | unsigned long get_dma_buffer(struct lguest *lg, | ||
366 | unsigned long ukey, unsigned long *interrupt) | ||
367 | { | ||
368 | unsigned long ret = 0; | ||
369 | union futex_key key; | ||
370 | struct lguest_dma_info *i; | ||
371 | struct rw_semaphore *fshared = ¤t->mm->mmap_sem; | ||
372 | |||
373 | mutex_lock(&lguest_lock); | ||
374 | down_read(fshared); | ||
375 | if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) { | ||
376 | kill_guest(lg, "bad registered DMA buffer"); | ||
377 | goto unlock; | ||
378 | } | ||
379 | list_for_each_entry(i, &dma_hash[hash(&key)], list) { | ||
380 | if (key_eq(&key, &i->key) && i->guestid == lg->guestid) { | ||
381 | unsigned int j; | ||
382 | for (j = 0; j < i->num_dmas; j++) { | ||
383 | struct lguest_dma dma; | ||
384 | |||
385 | ret = i->dmas + j * sizeof(struct lguest_dma); | ||
386 | lgread(lg, &dma, ret, sizeof(dma)); | ||
387 | if (dma.used_len == 0) | ||
388 | break; | ||
389 | } | ||
390 | *interrupt = i->interrupt; | ||
391 | break; | ||
392 | } | ||
393 | } | ||
394 | unlock: | ||
395 | up_read(fshared); | ||
396 | mutex_unlock(&lguest_lock); | ||
397 | return ret; | ||
398 | } | ||
399 | |||
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h new file mode 100644 index 000000000000..3e2ddfbc816e --- /dev/null +++ b/drivers/lguest/lg.h | |||
@@ -0,0 +1,261 @@ | |||
1 | #ifndef _LGUEST_H | ||
2 | #define _LGUEST_H | ||
3 | |||
4 | #include <asm/desc.h> | ||
5 | |||
6 | #define GDT_ENTRY_LGUEST_CS 10 | ||
7 | #define GDT_ENTRY_LGUEST_DS 11 | ||
8 | #define LGUEST_CS (GDT_ENTRY_LGUEST_CS * 8) | ||
9 | #define LGUEST_DS (GDT_ENTRY_LGUEST_DS * 8) | ||
10 | |||
11 | #ifndef __ASSEMBLY__ | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/stringify.h> | ||
15 | #include <linux/binfmts.h> | ||
16 | #include <linux/futex.h> | ||
17 | #include <linux/lguest.h> | ||
18 | #include <linux/lguest_launcher.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <asm/semaphore.h> | ||
22 | #include "irq_vectors.h" | ||
23 | |||
24 | #define GUEST_PL 1 | ||
25 | |||
26 | struct lguest_regs | ||
27 | { | ||
28 | /* Manually saved part. */ | ||
29 | unsigned long ebx, ecx, edx; | ||
30 | unsigned long esi, edi, ebp; | ||
31 | unsigned long gs; | ||
32 | unsigned long eax; | ||
33 | unsigned long fs, ds, es; | ||
34 | unsigned long trapnum, errcode; | ||
35 | /* Trap pushed part */ | ||
36 | unsigned long eip; | ||
37 | unsigned long cs; | ||
38 | unsigned long eflags; | ||
39 | unsigned long esp; | ||
40 | unsigned long ss; | ||
41 | }; | ||
42 | |||
43 | void free_pagetables(void); | ||
44 | int init_pagetables(struct page **switcher_page, unsigned int pages); | ||
45 | |||
46 | /* Full 4G segment descriptors, suitable for CS and DS. */ | ||
47 | #define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00}) | ||
48 | #define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300}) | ||
49 | |||
50 | struct lguest_dma_info | ||
51 | { | ||
52 | struct list_head list; | ||
53 | union futex_key key; | ||
54 | unsigned long dmas; | ||
55 | u16 next_dma; | ||
56 | u16 num_dmas; | ||
57 | u16 guestid; | ||
58 | u8 interrupt; /* 0 when not registered */ | ||
59 | }; | ||
60 | |||
61 | /* We have separate types for the guest's ptes & pgds and the shadow ptes & | ||
62 | * pgds. Since this host might use three-level pagetables and the guest and | ||
63 | * shadow pagetables don't, we can't use the normal pte_t/pgd_t. */ | ||
64 | typedef union { | ||
65 | struct { unsigned flags:12, pfn:20; }; | ||
66 | struct { unsigned long val; } raw; | ||
67 | } spgd_t; | ||
68 | typedef union { | ||
69 | struct { unsigned flags:12, pfn:20; }; | ||
70 | struct { unsigned long val; } raw; | ||
71 | } spte_t; | ||
72 | typedef union { | ||
73 | struct { unsigned flags:12, pfn:20; }; | ||
74 | struct { unsigned long val; } raw; | ||
75 | } gpgd_t; | ||
76 | typedef union { | ||
77 | struct { unsigned flags:12, pfn:20; }; | ||
78 | struct { unsigned long val; } raw; | ||
79 | } gpte_t; | ||
80 | #define mkgpte(_val) ((gpte_t){.raw.val = _val}) | ||
81 | #define mkgpgd(_val) ((gpgd_t){.raw.val = _val}) | ||
82 | |||
83 | struct pgdir | ||
84 | { | ||
85 | unsigned long cr3; | ||
86 | spgd_t *pgdir; | ||
87 | }; | ||
88 | |||
89 | /* This is a guest-specific page (mapped ro) into the guest. */ | ||
90 | struct lguest_ro_state | ||
91 | { | ||
92 | /* Host information we need to restore when we switch back. */ | ||
93 | u32 host_cr3; | ||
94 | struct Xgt_desc_struct host_idt_desc; | ||
95 | struct Xgt_desc_struct host_gdt_desc; | ||
96 | u32 host_sp; | ||
97 | |||
98 | /* Fields which are used when guest is running. */ | ||
99 | struct Xgt_desc_struct guest_idt_desc; | ||
100 | struct Xgt_desc_struct guest_gdt_desc; | ||
101 | struct i386_hw_tss guest_tss; | ||
102 | struct desc_struct guest_idt[IDT_ENTRIES]; | ||
103 | struct desc_struct guest_gdt[GDT_ENTRIES]; | ||
104 | }; | ||
105 | |||
106 | /* We have two pages shared with guests, per cpu. */ | ||
107 | struct lguest_pages | ||
108 | { | ||
109 | /* This is the stack page mapped rw in guest */ | ||
110 | char spare[PAGE_SIZE - sizeof(struct lguest_regs)]; | ||
111 | struct lguest_regs regs; | ||
112 | |||
113 | /* This is the host state & guest descriptor page, ro in guest */ | ||
114 | struct lguest_ro_state state; | ||
115 | } __attribute__((aligned(PAGE_SIZE))); | ||
116 | |||
117 | #define CHANGED_IDT 1 | ||
118 | #define CHANGED_GDT 2 | ||
119 | #define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */ | ||
120 | #define CHANGED_ALL 3 | ||
121 | |||
122 | /* The private info the thread maintains about the guest. */ | ||
123 | struct lguest | ||
124 | { | ||
125 | /* At end of a page shared mapped over lguest_pages in guest. */ | ||
126 | unsigned long regs_page; | ||
127 | struct lguest_regs *regs; | ||
128 | struct lguest_data __user *lguest_data; | ||
129 | struct task_struct *tsk; | ||
130 | struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */ | ||
131 | u16 guestid; | ||
132 | u32 pfn_limit; | ||
133 | u32 page_offset; | ||
134 | u32 cr2; | ||
135 | int halted; | ||
136 | int ts; | ||
137 | u32 next_hcall; | ||
138 | u32 esp1; | ||
139 | u8 ss1; | ||
140 | |||
141 | /* Do we need to stop what we're doing and return to userspace? */ | ||
142 | int break_out; | ||
143 | wait_queue_head_t break_wq; | ||
144 | |||
145 | /* Bitmap of what has changed: see CHANGED_* above. */ | ||
146 | int changed; | ||
147 | struct lguest_pages *last_pages; | ||
148 | |||
149 | /* We keep a small number of these. */ | ||
150 | u32 pgdidx; | ||
151 | struct pgdir pgdirs[4]; | ||
152 | |||
153 | /* Cached wakeup: we hold a reference to this task. */ | ||
154 | struct task_struct *wake; | ||
155 | |||
156 | unsigned long noirq_start, noirq_end; | ||
157 | int dma_is_pending; | ||
158 | unsigned long pending_dma; /* struct lguest_dma */ | ||
159 | unsigned long pending_key; /* address they're sending to */ | ||
160 | |||
161 | unsigned int stack_pages; | ||
162 | u32 tsc_khz; | ||
163 | |||
164 | struct lguest_dma_info dma[LGUEST_MAX_DMA]; | ||
165 | |||
166 | /* Dead? */ | ||
167 | const char *dead; | ||
168 | |||
169 | /* The GDT entries copied into lguest_ro_state when running. */ | ||
170 | struct desc_struct gdt[GDT_ENTRIES]; | ||
171 | |||
172 | /* The IDT entries: some copied into lguest_ro_state when running. */ | ||
173 | struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS]; | ||
174 | struct desc_struct syscall_idt; | ||
175 | |||
176 | /* Virtual clock device */ | ||
177 | struct hrtimer hrt; | ||
178 | |||
179 | /* Pending virtual interrupts */ | ||
180 | DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); | ||
181 | }; | ||
182 | |||
183 | extern struct lguest lguests[]; | ||
184 | extern struct mutex lguest_lock; | ||
185 | |||
186 | /* core.c: */ | ||
187 | u32 lgread_u32(struct lguest *lg, unsigned long addr); | ||
188 | void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val); | ||
189 | void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len); | ||
190 | void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len); | ||
191 | int find_free_guest(void); | ||
192 | int lguest_address_ok(const struct lguest *lg, | ||
193 | unsigned long addr, unsigned long len); | ||
194 | int run_guest(struct lguest *lg, unsigned long __user *user); | ||
195 | |||
196 | |||
197 | /* interrupts_and_traps.c: */ | ||
198 | void maybe_do_interrupt(struct lguest *lg); | ||
199 | int deliver_trap(struct lguest *lg, unsigned int num); | ||
200 | void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi); | ||
201 | void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages); | ||
202 | void pin_stack_pages(struct lguest *lg); | ||
203 | void setup_default_idt_entries(struct lguest_ro_state *state, | ||
204 | const unsigned long *def); | ||
205 | void copy_traps(const struct lguest *lg, struct desc_struct *idt, | ||
206 | const unsigned long *def); | ||
207 | void guest_set_clockevent(struct lguest *lg, unsigned long delta); | ||
208 | void init_clockdev(struct lguest *lg); | ||
209 | |||
210 | /* segments.c: */ | ||
211 | void setup_default_gdt_entries(struct lguest_ro_state *state); | ||
212 | void setup_guest_gdt(struct lguest *lg); | ||
213 | void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num); | ||
214 | void guest_load_tls(struct lguest *lg, unsigned long tls_array); | ||
215 | void copy_gdt(const struct lguest *lg, struct desc_struct *gdt); | ||
216 | void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt); | ||
217 | |||
218 | /* page_tables.c: */ | ||
219 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); | ||
220 | void free_guest_pagetable(struct lguest *lg); | ||
221 | void guest_new_pagetable(struct lguest *lg, unsigned long pgtable); | ||
222 | void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i); | ||
223 | void guest_pagetable_clear_all(struct lguest *lg); | ||
224 | void guest_pagetable_flush_user(struct lguest *lg); | ||
225 | void guest_set_pte(struct lguest *lg, unsigned long cr3, | ||
226 | unsigned long vaddr, gpte_t val); | ||
227 | void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages); | ||
228 | int demand_page(struct lguest *info, unsigned long cr2, int errcode); | ||
229 | void pin_page(struct lguest *lg, unsigned long vaddr); | ||
230 | |||
231 | /* lguest_user.c: */ | ||
232 | int lguest_device_init(void); | ||
233 | void lguest_device_remove(void); | ||
234 | |||
235 | /* io.c: */ | ||
236 | void lguest_io_init(void); | ||
237 | int bind_dma(struct lguest *lg, | ||
238 | unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt); | ||
239 | void send_dma(struct lguest *info, unsigned long key, unsigned long udma); | ||
240 | void release_all_dma(struct lguest *lg); | ||
241 | unsigned long get_dma_buffer(struct lguest *lg, unsigned long key, | ||
242 | unsigned long *interrupt); | ||
243 | |||
244 | /* hypercalls.c: */ | ||
245 | void do_hypercalls(struct lguest *lg); | ||
246 | |||
247 | #define kill_guest(lg, fmt...) \ | ||
248 | do { \ | ||
249 | if (!(lg)->dead) { \ | ||
250 | (lg)->dead = kasprintf(GFP_ATOMIC, fmt); \ | ||
251 | if (!(lg)->dead) \ | ||
252 | (lg)->dead = ERR_PTR(-ENOMEM); \ | ||
253 | } \ | ||
254 | } while(0) | ||
255 | |||
256 | static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) | ||
257 | { | ||
258 | return vaddr - lg->page_offset; | ||
259 | } | ||
260 | #endif /* __ASSEMBLY__ */ | ||
261 | #endif /* _LGUEST_H */ | ||
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c new file mode 100644 index 000000000000..b9a58b78c990 --- /dev/null +++ b/drivers/lguest/lguest.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* | ||
2 | * Lguest specific paravirt-ops implementation | ||
3 | * | ||
4 | * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
14 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
15 | * details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/start_kernel.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/console.h> | ||
25 | #include <linux/screen_info.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/clocksource.h> | ||
29 | #include <linux/clockchips.h> | ||
30 | #include <linux/lguest.h> | ||
31 | #include <linux/lguest_launcher.h> | ||
32 | #include <linux/lguest_bus.h> | ||
33 | #include <asm/paravirt.h> | ||
34 | #include <asm/param.h> | ||
35 | #include <asm/page.h> | ||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/desc.h> | ||
38 | #include <asm/setup.h> | ||
39 | #include <asm/e820.h> | ||
40 | #include <asm/mce.h> | ||
41 | #include <asm/io.h> | ||
42 | //#include <asm/sched-clock.h> | ||
43 | |||
44 | /* Declarations for definitions in lguest_guest.S */ | ||
45 | extern char lguest_noirq_start[], lguest_noirq_end[]; | ||
46 | extern const char lgstart_cli[], lgend_cli[]; | ||
47 | extern const char lgstart_sti[], lgend_sti[]; | ||
48 | extern const char lgstart_popf[], lgend_popf[]; | ||
49 | extern const char lgstart_pushf[], lgend_pushf[]; | ||
50 | extern const char lgstart_iret[], lgend_iret[]; | ||
51 | extern void lguest_iret(void); | ||
52 | |||
53 | struct lguest_data lguest_data = { | ||
54 | .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF }, | ||
55 | .noirq_start = (u32)lguest_noirq_start, | ||
56 | .noirq_end = (u32)lguest_noirq_end, | ||
57 | .blocked_interrupts = { 1 }, /* Block timer interrupts */ | ||
58 | }; | ||
59 | struct lguest_device_desc *lguest_devices; | ||
60 | |||
61 | static enum paravirt_lazy_mode lazy_mode; | ||
62 | static void lguest_lazy_mode(enum paravirt_lazy_mode mode) | ||
63 | { | ||
64 | if (mode == PARAVIRT_LAZY_FLUSH) { | ||
65 | if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE)) | ||
66 | hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0); | ||
67 | } else { | ||
68 | lazy_mode = mode; | ||
69 | if (mode == PARAVIRT_LAZY_NONE) | ||
70 | hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static void lazy_hcall(unsigned long call, | ||
75 | unsigned long arg1, | ||
76 | unsigned long arg2, | ||
77 | unsigned long arg3) | ||
78 | { | ||
79 | if (lazy_mode == PARAVIRT_LAZY_NONE) | ||
80 | hcall(call, arg1, arg2, arg3); | ||
81 | else | ||
82 | async_hcall(call, arg1, arg2, arg3); | ||
83 | } | ||
84 | |||
85 | void async_hcall(unsigned long call, | ||
86 | unsigned long arg1, unsigned long arg2, unsigned long arg3) | ||
87 | { | ||
88 | /* Note: This code assumes we're uniprocessor. */ | ||
89 | static unsigned int next_call; | ||
90 | unsigned long flags; | ||
91 | |||
92 | local_irq_save(flags); | ||
93 | if (lguest_data.hcall_status[next_call] != 0xFF) { | ||
94 | /* Table full, so do normal hcall which will flush table. */ | ||
95 | hcall(call, arg1, arg2, arg3); | ||
96 | } else { | ||
97 | lguest_data.hcalls[next_call].eax = call; | ||
98 | lguest_data.hcalls[next_call].edx = arg1; | ||
99 | lguest_data.hcalls[next_call].ebx = arg2; | ||
100 | lguest_data.hcalls[next_call].ecx = arg3; | ||
101 | /* Make sure host sees arguments before "valid" flag. */ | ||
102 | wmb(); | ||
103 | lguest_data.hcall_status[next_call] = 0; | ||
104 | if (++next_call == LHCALL_RING_SIZE) | ||
105 | next_call = 0; | ||
106 | } | ||
107 | local_irq_restore(flags); | ||
108 | } | ||
109 | |||
110 | void lguest_send_dma(unsigned long key, struct lguest_dma *dma) | ||
111 | { | ||
112 | dma->used_len = 0; | ||
113 | hcall(LHCALL_SEND_DMA, key, __pa(dma), 0); | ||
114 | } | ||
115 | |||
116 | int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas, | ||
117 | unsigned int num, u8 irq) | ||
118 | { | ||
119 | if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq)) | ||
120 | return -ENOMEM; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas) | ||
125 | { | ||
126 | hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0); | ||
127 | } | ||
128 | |||
129 | /* For guests, device memory can be used as normal memory, so we cast away the | ||
130 | * __iomem to quieten sparse. */ | ||
131 | void *lguest_map(unsigned long phys_addr, unsigned long pages) | ||
132 | { | ||
133 | return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages); | ||
134 | } | ||
135 | |||
136 | void lguest_unmap(void *addr) | ||
137 | { | ||
138 | iounmap((__force void __iomem *)addr); | ||
139 | } | ||
140 | |||
141 | static unsigned long save_fl(void) | ||
142 | { | ||
143 | return lguest_data.irq_enabled; | ||
144 | } | ||
145 | |||
146 | static void restore_fl(unsigned long flags) | ||
147 | { | ||
148 | /* FIXME: Check if interrupt pending... */ | ||
149 | lguest_data.irq_enabled = flags; | ||
150 | } | ||
151 | |||
152 | static void irq_disable(void) | ||
153 | { | ||
154 | lguest_data.irq_enabled = 0; | ||
155 | } | ||
156 | |||
157 | static void irq_enable(void) | ||
158 | { | ||
159 | /* FIXME: Check if interrupt pending... */ | ||
160 | lguest_data.irq_enabled = X86_EFLAGS_IF; | ||
161 | } | ||
162 | |||
163 | static void lguest_write_idt_entry(struct desc_struct *dt, | ||
164 | int entrynum, u32 low, u32 high) | ||
165 | { | ||
166 | write_dt_entry(dt, entrynum, low, high); | ||
167 | hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high); | ||
168 | } | ||
169 | |||
170 | static void lguest_load_idt(const struct Xgt_desc_struct *desc) | ||
171 | { | ||
172 | unsigned int i; | ||
173 | struct desc_struct *idt = (void *)desc->address; | ||
174 | |||
175 | for (i = 0; i < (desc->size+1)/8; i++) | ||
176 | hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); | ||
177 | } | ||
178 | |||
179 | static void lguest_load_gdt(const struct Xgt_desc_struct *desc) | ||
180 | { | ||
181 | BUG_ON((desc->size+1)/8 != GDT_ENTRIES); | ||
182 | hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0); | ||
183 | } | ||
184 | |||
185 | static void lguest_write_gdt_entry(struct desc_struct *dt, | ||
186 | int entrynum, u32 low, u32 high) | ||
187 | { | ||
188 | write_dt_entry(dt, entrynum, low, high); | ||
189 | hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0); | ||
190 | } | ||
191 | |||
192 | static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) | ||
193 | { | ||
194 | lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0); | ||
195 | } | ||
196 | |||
197 | static void lguest_set_ldt(const void *addr, unsigned entries) | ||
198 | { | ||
199 | } | ||
200 | |||
201 | static void lguest_load_tr_desc(void) | ||
202 | { | ||
203 | } | ||
204 | |||
205 | static void lguest_cpuid(unsigned int *eax, unsigned int *ebx, | ||
206 | unsigned int *ecx, unsigned int *edx) | ||
207 | { | ||
208 | int function = *eax; | ||
209 | |||
210 | native_cpuid(eax, ebx, ecx, edx); | ||
211 | switch (function) { | ||
212 | case 1: /* Basic feature request. */ | ||
213 | /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */ | ||
214 | *ecx &= 0x00002201; | ||
215 | /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */ | ||
216 | *edx &= 0x07808101; | ||
217 | /* Host wants to know when we flush kernel pages: set PGE. */ | ||
218 | *edx |= 0x00002000; | ||
219 | break; | ||
220 | case 0x80000000: | ||
221 | /* Futureproof this a little: if they ask how much extended | ||
222 | * processor information, limit it to known fields. */ | ||
223 | if (*eax > 0x80000008) | ||
224 | *eax = 0x80000008; | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static unsigned long current_cr0, current_cr3; | ||
230 | static void lguest_write_cr0(unsigned long val) | ||
231 | { | ||
232 | lazy_hcall(LHCALL_TS, val & 8, 0, 0); | ||
233 | current_cr0 = val; | ||
234 | } | ||
235 | |||
236 | static unsigned long lguest_read_cr0(void) | ||
237 | { | ||
238 | return current_cr0; | ||
239 | } | ||
240 | |||
241 | static void lguest_clts(void) | ||
242 | { | ||
243 | lazy_hcall(LHCALL_TS, 0, 0, 0); | ||
244 | current_cr0 &= ~8U; | ||
245 | } | ||
246 | |||
247 | static unsigned long lguest_read_cr2(void) | ||
248 | { | ||
249 | return lguest_data.cr2; | ||
250 | } | ||
251 | |||
252 | static void lguest_write_cr3(unsigned long cr3) | ||
253 | { | ||
254 | lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0); | ||
255 | current_cr3 = cr3; | ||
256 | } | ||
257 | |||
258 | static unsigned long lguest_read_cr3(void) | ||
259 | { | ||
260 | return current_cr3; | ||
261 | } | ||
262 | |||
263 | /* Used to enable/disable PGE, but we don't care. */ | ||
264 | static unsigned long lguest_read_cr4(void) | ||
265 | { | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static void lguest_write_cr4(unsigned long val) | ||
270 | { | ||
271 | } | ||
272 | |||
273 | static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
274 | pte_t *ptep, pte_t pteval) | ||
275 | { | ||
276 | *ptep = pteval; | ||
277 | lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low); | ||
278 | } | ||
279 | |||
280 | /* We only support two-level pagetables at the moment. */ | ||
281 | static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) | ||
282 | { | ||
283 | *pmdp = pmdval; | ||
284 | lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK, | ||
285 | (__pa(pmdp)&(PAGE_SIZE-1))/4, 0); | ||
286 | } | ||
287 | |||
288 | /* FIXME: Eliminate all callers of this. */ | ||
289 | static void lguest_set_pte(pte_t *ptep, pte_t pteval) | ||
290 | { | ||
291 | *ptep = pteval; | ||
292 | /* Don't bother with hypercall before initial setup. */ | ||
293 | if (current_cr3) | ||
294 | lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); | ||
295 | } | ||
296 | |||
297 | static void lguest_flush_tlb_single(unsigned long addr) | ||
298 | { | ||
299 | /* Simply set it to zero, and it will fault back in. */ | ||
300 | lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0); | ||
301 | } | ||
302 | |||
303 | static void lguest_flush_tlb_user(void) | ||
304 | { | ||
305 | lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0); | ||
306 | } | ||
307 | |||
308 | static void lguest_flush_tlb_kernel(void) | ||
309 | { | ||
310 | lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); | ||
311 | } | ||
312 | |||
313 | static void disable_lguest_irq(unsigned int irq) | ||
314 | { | ||
315 | set_bit(irq, lguest_data.blocked_interrupts); | ||
316 | } | ||
317 | |||
318 | static void enable_lguest_irq(unsigned int irq) | ||
319 | { | ||
320 | clear_bit(irq, lguest_data.blocked_interrupts); | ||
321 | /* FIXME: If it's pending? */ | ||
322 | } | ||
323 | |||
324 | static struct irq_chip lguest_irq_controller = { | ||
325 | .name = "lguest", | ||
326 | .mask = disable_lguest_irq, | ||
327 | .mask_ack = disable_lguest_irq, | ||
328 | .unmask = enable_lguest_irq, | ||
329 | }; | ||
330 | |||
331 | static void __init lguest_init_IRQ(void) | ||
332 | { | ||
333 | unsigned int i; | ||
334 | |||
335 | for (i = 0; i < LGUEST_IRQS; i++) { | ||
336 | int vector = FIRST_EXTERNAL_VECTOR + i; | ||
337 | if (vector != SYSCALL_VECTOR) { | ||
338 | set_intr_gate(vector, interrupt[i]); | ||
339 | set_irq_chip_and_handler(i, &lguest_irq_controller, | ||
340 | handle_level_irq); | ||
341 | } | ||
342 | } | ||
343 | irq_ctx_init(smp_processor_id()); | ||
344 | } | ||
345 | |||
346 | static unsigned long lguest_get_wallclock(void) | ||
347 | { | ||
348 | return hcall(LHCALL_GET_WALLCLOCK, 0, 0, 0); | ||
349 | } | ||
350 | |||
351 | static cycle_t lguest_clock_read(void) | ||
352 | { | ||
353 | if (lguest_data.tsc_khz) | ||
354 | return native_read_tsc(); | ||
355 | else | ||
356 | return jiffies; | ||
357 | } | ||
358 | |||
359 | /* This is what we tell the kernel is our clocksource. */ | ||
360 | static struct clocksource lguest_clock = { | ||
361 | .name = "lguest", | ||
362 | .rating = 400, | ||
363 | .read = lguest_clock_read, | ||
364 | }; | ||
365 | |||
366 | /* We also need a "struct clock_event_device": Linux asks us to set it to go | ||
367 | * off some time in the future. Actually, James Morris figured all this out, I | ||
368 | * just applied the patch. */ | ||
369 | static int lguest_clockevent_set_next_event(unsigned long delta, | ||
370 | struct clock_event_device *evt) | ||
371 | { | ||
372 | if (delta < LG_CLOCK_MIN_DELTA) { | ||
373 | if (printk_ratelimit()) | ||
374 | printk(KERN_DEBUG "%s: small delta %lu ns\n", | ||
375 | __FUNCTION__, delta); | ||
376 | return -ETIME; | ||
377 | } | ||
378 | hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static void lguest_clockevent_set_mode(enum clock_event_mode mode, | ||
383 | struct clock_event_device *evt) | ||
384 | { | ||
385 | switch (mode) { | ||
386 | case CLOCK_EVT_MODE_UNUSED: | ||
387 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
388 | /* A 0 argument shuts the clock down. */ | ||
389 | hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0); | ||
390 | break; | ||
391 | case CLOCK_EVT_MODE_ONESHOT: | ||
392 | /* This is what we expect. */ | ||
393 | break; | ||
394 | case CLOCK_EVT_MODE_PERIODIC: | ||
395 | BUG(); | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /* This describes our primitive timer chip. */ | ||
400 | static struct clock_event_device lguest_clockevent = { | ||
401 | .name = "lguest", | ||
402 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
403 | .set_next_event = lguest_clockevent_set_next_event, | ||
404 | .set_mode = lguest_clockevent_set_mode, | ||
405 | .rating = INT_MAX, | ||
406 | .mult = 1, | ||
407 | .shift = 0, | ||
408 | .min_delta_ns = LG_CLOCK_MIN_DELTA, | ||
409 | .max_delta_ns = LG_CLOCK_MAX_DELTA, | ||
410 | }; | ||
411 | |||
412 | /* This is the Guest timer interrupt handler (hardware interrupt 0). We just | ||
413 | * call the clockevent infrastructure and it does whatever needs doing. */ | ||
414 | static void lguest_time_irq(unsigned int irq, struct irq_desc *desc) | ||
415 | { | ||
416 | unsigned long flags; | ||
417 | |||
418 | /* Don't interrupt us while this is running. */ | ||
419 | local_irq_save(flags); | ||
420 | lguest_clockevent.event_handler(&lguest_clockevent); | ||
421 | local_irq_restore(flags); | ||
422 | } | ||
423 | |||
424 | static void lguest_time_init(void) | ||
425 | { | ||
426 | set_irq_handler(0, lguest_time_irq); | ||
427 | |||
428 | /* We use the TSC if the Host tells us we can, otherwise a dumb | ||
429 | * jiffies-based clock. */ | ||
430 | if (lguest_data.tsc_khz) { | ||
431 | lguest_clock.shift = 22; | ||
432 | lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz, | ||
433 | lguest_clock.shift); | ||
434 | lguest_clock.mask = CLOCKSOURCE_MASK(64); | ||
435 | lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
436 | } else { | ||
437 | /* To understand this, start at kernel/time/jiffies.c... */ | ||
438 | lguest_clock.shift = 8; | ||
439 | lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8; | ||
440 | lguest_clock.mask = CLOCKSOURCE_MASK(32); | ||
441 | } | ||
442 | clocksource_register(&lguest_clock); | ||
443 | |||
444 | /* We can't set cpumask in the initializer: damn C limitations! */ | ||
445 | lguest_clockevent.cpumask = cpumask_of_cpu(0); | ||
446 | clockevents_register_device(&lguest_clockevent); | ||
447 | |||
448 | enable_lguest_irq(0); | ||
449 | } | ||
450 | |||
451 | static void lguest_load_esp0(struct tss_struct *tss, | ||
452 | struct thread_struct *thread) | ||
453 | { | ||
454 | lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0, | ||
455 | THREAD_SIZE/PAGE_SIZE); | ||
456 | } | ||
457 | |||
458 | static void lguest_set_debugreg(int regno, unsigned long value) | ||
459 | { | ||
460 | /* FIXME: Implement */ | ||
461 | } | ||
462 | |||
463 | static void lguest_wbinvd(void) | ||
464 | { | ||
465 | } | ||
466 | |||
467 | #ifdef CONFIG_X86_LOCAL_APIC | ||
468 | static void lguest_apic_write(unsigned long reg, unsigned long v) | ||
469 | { | ||
470 | } | ||
471 | |||
472 | static unsigned long lguest_apic_read(unsigned long reg) | ||
473 | { | ||
474 | return 0; | ||
475 | } | ||
476 | #endif | ||
477 | |||
478 | static void lguest_safe_halt(void) | ||
479 | { | ||
480 | hcall(LHCALL_HALT, 0, 0, 0); | ||
481 | } | ||
482 | |||
483 | static void lguest_power_off(void) | ||
484 | { | ||
485 | hcall(LHCALL_CRASH, __pa("Power down"), 0, 0); | ||
486 | } | ||
487 | |||
488 | static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) | ||
489 | { | ||
490 | hcall(LHCALL_CRASH, __pa(p), 0, 0); | ||
491 | return NOTIFY_DONE; | ||
492 | } | ||
493 | |||
494 | static struct notifier_block paniced = { | ||
495 | .notifier_call = lguest_panic | ||
496 | }; | ||
497 | |||
498 | static __init char *lguest_memory_setup(void) | ||
499 | { | ||
500 | /* We do this here because lockcheck barfs if before start_kernel */ | ||
501 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
502 | |||
503 | add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type); | ||
504 | return "LGUEST"; | ||
505 | } | ||
506 | |||
507 | static const struct lguest_insns | ||
508 | { | ||
509 | const char *start, *end; | ||
510 | } lguest_insns[] = { | ||
511 | [PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli }, | ||
512 | [PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti }, | ||
513 | [PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf }, | ||
514 | [PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf }, | ||
515 | }; | ||
516 | static unsigned lguest_patch(u8 type, u16 clobber, void *insns, unsigned len) | ||
517 | { | ||
518 | unsigned int insn_len; | ||
519 | |||
520 | /* Don't touch it if we don't have a replacement */ | ||
521 | if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start) | ||
522 | return paravirt_patch_default(type, clobber, insns, len); | ||
523 | |||
524 | insn_len = lguest_insns[type].end - lguest_insns[type].start; | ||
525 | |||
526 | /* Similarly if we can't fit replacement. */ | ||
527 | if (len < insn_len) | ||
528 | return paravirt_patch_default(type, clobber, insns, len); | ||
529 | |||
530 | memcpy(insns, lguest_insns[type].start, insn_len); | ||
531 | return insn_len; | ||
532 | } | ||
533 | |||
534 | __init void lguest_init(void *boot) | ||
535 | { | ||
536 | /* Copy boot parameters first. */ | ||
537 | memcpy(&boot_params, boot, PARAM_SIZE); | ||
538 | memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr), | ||
539 | COMMAND_LINE_SIZE); | ||
540 | |||
541 | paravirt_ops.name = "lguest"; | ||
542 | paravirt_ops.paravirt_enabled = 1; | ||
543 | paravirt_ops.kernel_rpl = 1; | ||
544 | |||
545 | paravirt_ops.save_fl = save_fl; | ||
546 | paravirt_ops.restore_fl = restore_fl; | ||
547 | paravirt_ops.irq_disable = irq_disable; | ||
548 | paravirt_ops.irq_enable = irq_enable; | ||
549 | paravirt_ops.load_gdt = lguest_load_gdt; | ||
550 | paravirt_ops.memory_setup = lguest_memory_setup; | ||
551 | paravirt_ops.cpuid = lguest_cpuid; | ||
552 | paravirt_ops.write_cr3 = lguest_write_cr3; | ||
553 | paravirt_ops.flush_tlb_user = lguest_flush_tlb_user; | ||
554 | paravirt_ops.flush_tlb_single = lguest_flush_tlb_single; | ||
555 | paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel; | ||
556 | paravirt_ops.set_pte = lguest_set_pte; | ||
557 | paravirt_ops.set_pte_at = lguest_set_pte_at; | ||
558 | paravirt_ops.set_pmd = lguest_set_pmd; | ||
559 | #ifdef CONFIG_X86_LOCAL_APIC | ||
560 | paravirt_ops.apic_write = lguest_apic_write; | ||
561 | paravirt_ops.apic_write_atomic = lguest_apic_write; | ||
562 | paravirt_ops.apic_read = lguest_apic_read; | ||
563 | #endif | ||
564 | paravirt_ops.load_idt = lguest_load_idt; | ||
565 | paravirt_ops.iret = lguest_iret; | ||
566 | paravirt_ops.load_esp0 = lguest_load_esp0; | ||
567 | paravirt_ops.load_tr_desc = lguest_load_tr_desc; | ||
568 | paravirt_ops.set_ldt = lguest_set_ldt; | ||
569 | paravirt_ops.load_tls = lguest_load_tls; | ||
570 | paravirt_ops.set_debugreg = lguest_set_debugreg; | ||
571 | paravirt_ops.clts = lguest_clts; | ||
572 | paravirt_ops.read_cr0 = lguest_read_cr0; | ||
573 | paravirt_ops.write_cr0 = lguest_write_cr0; | ||
574 | paravirt_ops.init_IRQ = lguest_init_IRQ; | ||
575 | paravirt_ops.read_cr2 = lguest_read_cr2; | ||
576 | paravirt_ops.read_cr3 = lguest_read_cr3; | ||
577 | paravirt_ops.read_cr4 = lguest_read_cr4; | ||
578 | paravirt_ops.write_cr4 = lguest_write_cr4; | ||
579 | paravirt_ops.write_gdt_entry = lguest_write_gdt_entry; | ||
580 | paravirt_ops.write_idt_entry = lguest_write_idt_entry; | ||
581 | paravirt_ops.patch = lguest_patch; | ||
582 | paravirt_ops.safe_halt = lguest_safe_halt; | ||
583 | paravirt_ops.get_wallclock = lguest_get_wallclock; | ||
584 | paravirt_ops.time_init = lguest_time_init; | ||
585 | paravirt_ops.set_lazy_mode = lguest_lazy_mode; | ||
586 | paravirt_ops.wbinvd = lguest_wbinvd; | ||
587 | |||
588 | hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0); | ||
589 | |||
590 | /* We use top of mem for initial pagetables. */ | ||
591 | init_pg_tables_end = __pa(pg0); | ||
592 | |||
593 | asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory"); | ||
594 | |||
595 | reserve_top_address(lguest_data.reserve_mem); | ||
596 | |||
597 | lockdep_init(); | ||
598 | |||
599 | paravirt_disable_iospace(); | ||
600 | |||
601 | cpu_detect(&new_cpu_data); | ||
602 | /* head.S usually sets up the first capability word, so do it here. */ | ||
603 | new_cpu_data.x86_capability[0] = cpuid_edx(1); | ||
604 | |||
605 | /* Math is always hard! */ | ||
606 | new_cpu_data.hard_math = 1; | ||
607 | |||
608 | #ifdef CONFIG_X86_MCE | ||
609 | mce_disabled = 1; | ||
610 | #endif | ||
611 | |||
612 | #ifdef CONFIG_ACPI | ||
613 | acpi_disabled = 1; | ||
614 | acpi_ht = 0; | ||
615 | #endif | ||
616 | |||
617 | add_preferred_console("hvc", 0, NULL); | ||
618 | |||
619 | pm_power_off = lguest_power_off; | ||
620 | start_kernel(); | ||
621 | } | ||
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S new file mode 100644 index 000000000000..00046c57b5ba --- /dev/null +++ b/drivers/lguest/lguest_asm.S | |||
@@ -0,0 +1,56 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <linux/lguest.h> | ||
3 | #include <asm/asm-offsets.h> | ||
4 | #include <asm/thread_info.h> | ||
5 | |||
6 | /* FIXME: Once asm/processor-flags.h goes in, include that */ | ||
7 | #define X86_EFLAGS_IF 0x00000200 | ||
8 | |||
9 | /* | ||
10 | * This is where we begin: we have a magic signature which the launcher looks | ||
11 | * for. The plan is that the Linux boot protocol will be extended with a | ||
12 | * "platform type" field which will guide us here from the normal entry point, | ||
13 | * but for the moment this suffices. We pass the virtual address of the boot | ||
14 | * info to lguest_init(). | ||
15 | * | ||
16 | * We put it in .init.text will be discarded after boot. | ||
17 | */ | ||
18 | .section .init.text, "ax", @progbits | ||
19 | .ascii "GenuineLguest" | ||
20 | /* Set up initial stack. */ | ||
21 | movl $(init_thread_union+THREAD_SIZE),%esp | ||
22 | movl %esi, %eax | ||
23 | addl $__PAGE_OFFSET, %eax | ||
24 | jmp lguest_init | ||
25 | |||
26 | /* The templates for inline patching. */ | ||
27 | #define LGUEST_PATCH(name, insns...) \ | ||
28 | lgstart_##name: insns; lgend_##name:; \ | ||
29 | .globl lgstart_##name; .globl lgend_##name | ||
30 | |||
31 | LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled) | ||
32 | LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled) | ||
33 | LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled) | ||
34 | LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax) | ||
35 | |||
36 | .text | ||
37 | /* These demark the EIP range where host should never deliver interrupts. */ | ||
38 | .global lguest_noirq_start | ||
39 | .global lguest_noirq_end | ||
40 | |||
41 | /* | ||
42 | * We move eflags word to lguest_data.irq_enabled to restore interrupt state. | ||
43 | * For page faults, gpfs and virtual interrupts, the hypervisor has saved | ||
44 | * eflags manually, otherwise it was delivered directly and so eflags reflects | ||
45 | * the real machine IF state, ie. interrupts on. Since the kernel always dies | ||
46 | * if it takes such a trap with interrupts disabled anyway, turning interrupts | ||
47 | * back on unconditionally here is OK. | ||
48 | */ | ||
49 | ENTRY(lguest_iret) | ||
50 | pushl %eax | ||
51 | movl 12(%esp), %eax | ||
52 | lguest_noirq_start: | ||
53 | movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled | ||
54 | popl %eax | ||
55 | iret | ||
56 | lguest_noirq_end: | ||
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c new file mode 100644 index 000000000000..18d6ab21a43b --- /dev/null +++ b/drivers/lguest/lguest_bus.c | |||
@@ -0,0 +1,148 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/bootmem.h> | ||
3 | #include <linux/lguest_bus.h> | ||
4 | #include <asm/io.h> | ||
5 | |||
6 | static ssize_t type_show(struct device *_dev, | ||
7 | struct device_attribute *attr, char *buf) | ||
8 | { | ||
9 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
10 | return sprintf(buf, "%hu", lguest_devices[dev->index].type); | ||
11 | } | ||
12 | static ssize_t features_show(struct device *_dev, | ||
13 | struct device_attribute *attr, char *buf) | ||
14 | { | ||
15 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
16 | return sprintf(buf, "%hx", lguest_devices[dev->index].features); | ||
17 | } | ||
18 | static ssize_t pfn_show(struct device *_dev, | ||
19 | struct device_attribute *attr, char *buf) | ||
20 | { | ||
21 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
22 | return sprintf(buf, "%u", lguest_devices[dev->index].pfn); | ||
23 | } | ||
24 | static ssize_t status_show(struct device *_dev, | ||
25 | struct device_attribute *attr, char *buf) | ||
26 | { | ||
27 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
28 | return sprintf(buf, "%hx", lguest_devices[dev->index].status); | ||
29 | } | ||
30 | static ssize_t status_store(struct device *_dev, struct device_attribute *attr, | ||
31 | const char *buf, size_t count) | ||
32 | { | ||
33 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
34 | if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1) | ||
35 | return -EINVAL; | ||
36 | return count; | ||
37 | } | ||
38 | static struct device_attribute lguest_dev_attrs[] = { | ||
39 | __ATTR_RO(type), | ||
40 | __ATTR_RO(features), | ||
41 | __ATTR_RO(pfn), | ||
42 | __ATTR(status, 0644, status_show, status_store), | ||
43 | __ATTR_NULL | ||
44 | }; | ||
45 | |||
46 | static int lguest_dev_match(struct device *_dev, struct device_driver *_drv) | ||
47 | { | ||
48 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
49 | struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv); | ||
50 | |||
51 | return (drv->device_type == lguest_devices[dev->index].type); | ||
52 | } | ||
53 | |||
54 | struct lguest_bus { | ||
55 | struct bus_type bus; | ||
56 | struct device dev; | ||
57 | }; | ||
58 | |||
59 | static struct lguest_bus lguest_bus = { | ||
60 | .bus = { | ||
61 | .name = "lguest", | ||
62 | .match = lguest_dev_match, | ||
63 | .dev_attrs = lguest_dev_attrs, | ||
64 | }, | ||
65 | .dev = { | ||
66 | .parent = NULL, | ||
67 | .bus_id = "lguest", | ||
68 | } | ||
69 | }; | ||
70 | |||
71 | static int lguest_dev_probe(struct device *_dev) | ||
72 | { | ||
73 | int ret; | ||
74 | struct lguest_device *dev = container_of(_dev,struct lguest_device,dev); | ||
75 | struct lguest_driver *drv = container_of(dev->dev.driver, | ||
76 | struct lguest_driver, drv); | ||
77 | |||
78 | lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER; | ||
79 | ret = drv->probe(dev); | ||
80 | if (ret == 0) | ||
81 | lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK; | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | int register_lguest_driver(struct lguest_driver *drv) | ||
86 | { | ||
87 | if (!lguest_devices) | ||
88 | return 0; | ||
89 | |||
90 | drv->drv.bus = &lguest_bus.bus; | ||
91 | drv->drv.name = drv->name; | ||
92 | drv->drv.owner = drv->owner; | ||
93 | drv->drv.probe = lguest_dev_probe; | ||
94 | |||
95 | return driver_register(&drv->drv); | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(register_lguest_driver); | ||
98 | |||
99 | static void add_lguest_device(unsigned int index) | ||
100 | { | ||
101 | struct lguest_device *new; | ||
102 | |||
103 | lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE; | ||
104 | new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL); | ||
105 | if (!new) { | ||
106 | printk(KERN_EMERG "Cannot allocate lguest device %u\n", index); | ||
107 | lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED; | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | new->index = index; | ||
112 | new->private = NULL; | ||
113 | memset(&new->dev, 0, sizeof(new->dev)); | ||
114 | new->dev.parent = &lguest_bus.dev; | ||
115 | new->dev.bus = &lguest_bus.bus; | ||
116 | sprintf(new->dev.bus_id, "%u", index); | ||
117 | if (device_register(&new->dev) != 0) { | ||
118 | printk(KERN_EMERG "Cannot register lguest device %u\n", index); | ||
119 | lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED; | ||
120 | kfree(new); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static void scan_devices(void) | ||
125 | { | ||
126 | unsigned int i; | ||
127 | |||
128 | for (i = 0; i < LGUEST_MAX_DEVICES; i++) | ||
129 | if (lguest_devices[i].type) | ||
130 | add_lguest_device(i); | ||
131 | } | ||
132 | |||
133 | static int __init lguest_bus_init(void) | ||
134 | { | ||
135 | if (strcmp(paravirt_ops.name, "lguest") != 0) | ||
136 | return 0; | ||
137 | |||
138 | /* Devices are in page above top of "normal" mem. */ | ||
139 | lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1); | ||
140 | |||
141 | if (bus_register(&lguest_bus.bus) != 0 | ||
142 | || device_register(&lguest_bus.dev) != 0) | ||
143 | panic("lguest bus registration failed"); | ||
144 | |||
145 | scan_devices(); | ||
146 | return 0; | ||
147 | } | ||
148 | postcore_initcall(lguest_bus_init); | ||
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c new file mode 100644 index 000000000000..e90d7a783daf --- /dev/null +++ b/drivers/lguest/lguest_user.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* Userspace control of the guest, via /dev/lguest. */ | ||
2 | #include <linux/uaccess.h> | ||
3 | #include <linux/miscdevice.h> | ||
4 | #include <linux/fs.h> | ||
5 | #include "lg.h" | ||
6 | |||
7 | static void setup_regs(struct lguest_regs *regs, unsigned long start) | ||
8 | { | ||
9 | /* Write out stack in format lguest expects, so we can switch to it. */ | ||
10 | regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL; | ||
11 | regs->cs = __KERNEL_CS|GUEST_PL; | ||
12 | regs->eflags = 0x202; /* Interrupts enabled. */ | ||
13 | regs->eip = start; | ||
14 | /* esi points to our boot information (physical address 0) */ | ||
15 | } | ||
16 | |||
17 | /* + addr */ | ||
18 | static long user_get_dma(struct lguest *lg, const u32 __user *input) | ||
19 | { | ||
20 | unsigned long key, udma, irq; | ||
21 | |||
22 | if (get_user(key, input) != 0) | ||
23 | return -EFAULT; | ||
24 | udma = get_dma_buffer(lg, key, &irq); | ||
25 | if (!udma) | ||
26 | return -ENOENT; | ||
27 | |||
28 | /* We put irq number in udma->used_len. */ | ||
29 | lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq); | ||
30 | return udma; | ||
31 | } | ||
32 | |||
33 | /* To force the Guest to stop running and return to the Launcher, the | ||
34 | * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The | ||
35 | * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */ | ||
36 | static int break_guest_out(struct lguest *lg, const u32 __user *input) | ||
37 | { | ||
38 | unsigned long on; | ||
39 | |||
40 | /* Fetch whether they're turning break on or off.. */ | ||
41 | if (get_user(on, input) != 0) | ||
42 | return -EFAULT; | ||
43 | |||
44 | if (on) { | ||
45 | lg->break_out = 1; | ||
46 | /* Pop it out (may be running on different CPU) */ | ||
47 | wake_up_process(lg->tsk); | ||
48 | /* Wait for them to reset it */ | ||
49 | return wait_event_interruptible(lg->break_wq, !lg->break_out); | ||
50 | } else { | ||
51 | lg->break_out = 0; | ||
52 | wake_up(&lg->break_wq); | ||
53 | return 0; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | /* + irq */ | ||
58 | static int user_send_irq(struct lguest *lg, const u32 __user *input) | ||
59 | { | ||
60 | u32 irq; | ||
61 | |||
62 | if (get_user(irq, input) != 0) | ||
63 | return -EFAULT; | ||
64 | if (irq >= LGUEST_IRQS) | ||
65 | return -EINVAL; | ||
66 | set_bit(irq, lg->irqs_pending); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) | ||
71 | { | ||
72 | struct lguest *lg = file->private_data; | ||
73 | |||
74 | if (!lg) | ||
75 | return -EINVAL; | ||
76 | |||
77 | /* If you're not the task which owns the guest, go away. */ | ||
78 | if (current != lg->tsk) | ||
79 | return -EPERM; | ||
80 | |||
81 | if (lg->dead) { | ||
82 | size_t len; | ||
83 | |||
84 | if (IS_ERR(lg->dead)) | ||
85 | return PTR_ERR(lg->dead); | ||
86 | |||
87 | len = min(size, strlen(lg->dead)+1); | ||
88 | if (copy_to_user(user, lg->dead, len) != 0) | ||
89 | return -EFAULT; | ||
90 | return len; | ||
91 | } | ||
92 | |||
93 | if (lg->dma_is_pending) | ||
94 | lg->dma_is_pending = 0; | ||
95 | |||
96 | return run_guest(lg, (unsigned long __user *)user); | ||
97 | } | ||
98 | |||
99 | /* Take: pfnlimit, pgdir, start, pageoffset. */ | ||
100 | static int initialize(struct file *file, const u32 __user *input) | ||
101 | { | ||
102 | struct lguest *lg; | ||
103 | int err, i; | ||
104 | u32 args[4]; | ||
105 | |||
106 | /* We grab the Big Lguest lock, which protects the global array | ||
107 | * "lguests" and multiple simultaneous initializations. */ | ||
108 | mutex_lock(&lguest_lock); | ||
109 | |||
110 | if (file->private_data) { | ||
111 | err = -EBUSY; | ||
112 | goto unlock; | ||
113 | } | ||
114 | |||
115 | if (copy_from_user(args, input, sizeof(args)) != 0) { | ||
116 | err = -EFAULT; | ||
117 | goto unlock; | ||
118 | } | ||
119 | |||
120 | i = find_free_guest(); | ||
121 | if (i < 0) { | ||
122 | err = -ENOSPC; | ||
123 | goto unlock; | ||
124 | } | ||
125 | lg = &lguests[i]; | ||
126 | lg->guestid = i; | ||
127 | lg->pfn_limit = args[0]; | ||
128 | lg->page_offset = args[3]; | ||
129 | lg->regs_page = get_zeroed_page(GFP_KERNEL); | ||
130 | if (!lg->regs_page) { | ||
131 | err = -ENOMEM; | ||
132 | goto release_guest; | ||
133 | } | ||
134 | lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs); | ||
135 | |||
136 | err = init_guest_pagetable(lg, args[1]); | ||
137 | if (err) | ||
138 | goto free_regs; | ||
139 | |||
140 | setup_regs(lg->regs, args[2]); | ||
141 | setup_guest_gdt(lg); | ||
142 | init_clockdev(lg); | ||
143 | lg->tsk = current; | ||
144 | lg->mm = get_task_mm(lg->tsk); | ||
145 | init_waitqueue_head(&lg->break_wq); | ||
146 | lg->last_pages = NULL; | ||
147 | file->private_data = lg; | ||
148 | |||
149 | mutex_unlock(&lguest_lock); | ||
150 | |||
151 | return sizeof(args); | ||
152 | |||
153 | free_regs: | ||
154 | free_page(lg->regs_page); | ||
155 | release_guest: | ||
156 | memset(lg, 0, sizeof(*lg)); | ||
157 | unlock: | ||
158 | mutex_unlock(&lguest_lock); | ||
159 | return err; | ||
160 | } | ||
161 | |||
162 | static ssize_t write(struct file *file, const char __user *input, | ||
163 | size_t size, loff_t *off) | ||
164 | { | ||
165 | struct lguest *lg = file->private_data; | ||
166 | u32 req; | ||
167 | |||
168 | if (get_user(req, input) != 0) | ||
169 | return -EFAULT; | ||
170 | input += sizeof(req); | ||
171 | |||
172 | if (req != LHREQ_INITIALIZE && !lg) | ||
173 | return -EINVAL; | ||
174 | if (lg && lg->dead) | ||
175 | return -ENOENT; | ||
176 | |||
177 | /* If you're not the task which owns the Guest, you can only break */ | ||
178 | if (lg && current != lg->tsk && req != LHREQ_BREAK) | ||
179 | return -EPERM; | ||
180 | |||
181 | switch (req) { | ||
182 | case LHREQ_INITIALIZE: | ||
183 | return initialize(file, (const u32 __user *)input); | ||
184 | case LHREQ_GETDMA: | ||
185 | return user_get_dma(lg, (const u32 __user *)input); | ||
186 | case LHREQ_IRQ: | ||
187 | return user_send_irq(lg, (const u32 __user *)input); | ||
188 | case LHREQ_BREAK: | ||
189 | return break_guest_out(lg, (const u32 __user *)input); | ||
190 | default: | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static int close(struct inode *inode, struct file *file) | ||
196 | { | ||
197 | struct lguest *lg = file->private_data; | ||
198 | |||
199 | if (!lg) | ||
200 | return 0; | ||
201 | |||
202 | mutex_lock(&lguest_lock); | ||
203 | /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ | ||
204 | hrtimer_cancel(&lg->hrt); | ||
205 | release_all_dma(lg); | ||
206 | free_guest_pagetable(lg); | ||
207 | mmput(lg->mm); | ||
208 | if (!IS_ERR(lg->dead)) | ||
209 | kfree(lg->dead); | ||
210 | free_page(lg->regs_page); | ||
211 | memset(lg, 0, sizeof(*lg)); | ||
212 | mutex_unlock(&lguest_lock); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static struct file_operations lguest_fops = { | ||
217 | .owner = THIS_MODULE, | ||
218 | .release = close, | ||
219 | .write = write, | ||
220 | .read = read, | ||
221 | }; | ||
222 | static struct miscdevice lguest_dev = { | ||
223 | .minor = MISC_DYNAMIC_MINOR, | ||
224 | .name = "lguest", | ||
225 | .fops = &lguest_fops, | ||
226 | }; | ||
227 | |||
228 | int __init lguest_device_init(void) | ||
229 | { | ||
230 | return misc_register(&lguest_dev); | ||
231 | } | ||
232 | |||
233 | void __exit lguest_device_remove(void) | ||
234 | { | ||
235 | misc_deregister(&lguest_dev); | ||
236 | } | ||
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c new file mode 100644 index 000000000000..1b0ba09b1269 --- /dev/null +++ b/drivers/lguest/page_tables.c | |||
@@ -0,0 +1,411 @@ | |||
1 | /* Shadow page table operations. | ||
2 | * Copyright (C) Rusty Russell IBM Corporation 2006. | ||
3 | * GPL v2 and any later version */ | ||
4 | #include <linux/mm.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/spinlock.h> | ||
7 | #include <linux/random.h> | ||
8 | #include <linux/percpu.h> | ||
9 | #include <asm/tlbflush.h> | ||
10 | #include "lg.h" | ||
11 | |||
12 | #define PTES_PER_PAGE_SHIFT 10 | ||
13 | #define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT) | ||
14 | #define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1) | ||
15 | |||
16 | static DEFINE_PER_CPU(spte_t *, switcher_pte_pages); | ||
17 | #define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu) | ||
18 | |||
19 | static unsigned vaddr_to_pgd_index(unsigned long vaddr) | ||
20 | { | ||
21 | return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT); | ||
22 | } | ||
23 | |||
24 | /* These access the shadow versions (ie. the ones used by the CPU). */ | ||
25 | static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr) | ||
26 | { | ||
27 | unsigned int index = vaddr_to_pgd_index(vaddr); | ||
28 | |||
29 | if (index >= SWITCHER_PGD_INDEX) { | ||
30 | kill_guest(lg, "attempt to access switcher pages"); | ||
31 | index = 0; | ||
32 | } | ||
33 | return &lg->pgdirs[i].pgdir[index]; | ||
34 | } | ||
35 | |||
36 | static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr) | ||
37 | { | ||
38 | spte_t *page = __va(spgd.pfn << PAGE_SHIFT); | ||
39 | BUG_ON(!(spgd.flags & _PAGE_PRESENT)); | ||
40 | return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE]; | ||
41 | } | ||
42 | |||
43 | /* These access the guest versions. */ | ||
44 | static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr) | ||
45 | { | ||
46 | unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT); | ||
47 | return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t); | ||
48 | } | ||
49 | |||
50 | static unsigned long gpte_addr(struct lguest *lg, | ||
51 | gpgd_t gpgd, unsigned long vaddr) | ||
52 | { | ||
53 | unsigned long gpage = gpgd.pfn << PAGE_SHIFT; | ||
54 | BUG_ON(!(gpgd.flags & _PAGE_PRESENT)); | ||
55 | return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t); | ||
56 | } | ||
57 | |||
58 | /* Do a virtual -> physical mapping on a user page. */ | ||
59 | static unsigned long get_pfn(unsigned long virtpfn, int write) | ||
60 | { | ||
61 | struct page *page; | ||
62 | unsigned long ret = -1UL; | ||
63 | |||
64 | down_read(¤t->mm->mmap_sem); | ||
65 | if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT, | ||
66 | 1, write, 1, &page, NULL) == 1) | ||
67 | ret = page_to_pfn(page); | ||
68 | up_read(¤t->mm->mmap_sem); | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write) | ||
73 | { | ||
74 | spte_t spte; | ||
75 | unsigned long pfn; | ||
76 | |||
77 | /* We ignore the global flag. */ | ||
78 | spte.flags = (gpte.flags & ~_PAGE_GLOBAL); | ||
79 | pfn = get_pfn(gpte.pfn, write); | ||
80 | if (pfn == -1UL) { | ||
81 | kill_guest(lg, "failed to get page %u", gpte.pfn); | ||
82 | /* Must not put_page() bogus page on cleanup. */ | ||
83 | spte.flags = 0; | ||
84 | } | ||
85 | spte.pfn = pfn; | ||
86 | return spte; | ||
87 | } | ||
88 | |||
89 | static void release_pte(spte_t pte) | ||
90 | { | ||
91 | if (pte.flags & _PAGE_PRESENT) | ||
92 | put_page(pfn_to_page(pte.pfn)); | ||
93 | } | ||
94 | |||
95 | static void check_gpte(struct lguest *lg, gpte_t gpte) | ||
96 | { | ||
97 | if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit) | ||
98 | kill_guest(lg, "bad page table entry"); | ||
99 | } | ||
100 | |||
101 | static void check_gpgd(struct lguest *lg, gpgd_t gpgd) | ||
102 | { | ||
103 | if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit) | ||
104 | kill_guest(lg, "bad page directory entry"); | ||
105 | } | ||
106 | |||
107 | /* FIXME: We hold reference to pages, which prevents them from being | ||
108 | swapped. It'd be nice to have a callback when Linux wants to swap out. */ | ||
109 | |||
110 | /* We fault pages in, which allows us to update accessed/dirty bits. | ||
111 | * Return true if we got page. */ | ||
112 | int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) | ||
113 | { | ||
114 | gpgd_t gpgd; | ||
115 | spgd_t *spgd; | ||
116 | unsigned long gpte_ptr; | ||
117 | gpte_t gpte; | ||
118 | spte_t *spte; | ||
119 | |||
120 | gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr))); | ||
121 | if (!(gpgd.flags & _PAGE_PRESENT)) | ||
122 | return 0; | ||
123 | |||
124 | spgd = spgd_addr(lg, lg->pgdidx, vaddr); | ||
125 | if (!(spgd->flags & _PAGE_PRESENT)) { | ||
126 | /* Get a page of PTEs for them. */ | ||
127 | unsigned long ptepage = get_zeroed_page(GFP_KERNEL); | ||
128 | /* FIXME: Steal from self in this case? */ | ||
129 | if (!ptepage) { | ||
130 | kill_guest(lg, "out of memory allocating pte page"); | ||
131 | return 0; | ||
132 | } | ||
133 | check_gpgd(lg, gpgd); | ||
134 | spgd->raw.val = (__pa(ptepage) | gpgd.flags); | ||
135 | } | ||
136 | |||
137 | gpte_ptr = gpte_addr(lg, gpgd, vaddr); | ||
138 | gpte = mkgpte(lgread_u32(lg, gpte_ptr)); | ||
139 | |||
140 | /* No page? */ | ||
141 | if (!(gpte.flags & _PAGE_PRESENT)) | ||
142 | return 0; | ||
143 | |||
144 | /* Write to read-only page? */ | ||
145 | if ((errcode & 2) && !(gpte.flags & _PAGE_RW)) | ||
146 | return 0; | ||
147 | |||
148 | /* User access to a non-user page? */ | ||
149 | if ((errcode & 4) && !(gpte.flags & _PAGE_USER)) | ||
150 | return 0; | ||
151 | |||
152 | check_gpte(lg, gpte); | ||
153 | gpte.flags |= _PAGE_ACCESSED; | ||
154 | if (errcode & 2) | ||
155 | gpte.flags |= _PAGE_DIRTY; | ||
156 | |||
157 | /* We're done with the old pte. */ | ||
158 | spte = spte_addr(lg, *spgd, vaddr); | ||
159 | release_pte(*spte); | ||
160 | |||
161 | /* We don't make it writable if this isn't a write: later | ||
162 | * write will fault so we can set dirty bit in guest. */ | ||
163 | if (gpte.flags & _PAGE_DIRTY) | ||
164 | *spte = gpte_to_spte(lg, gpte, 1); | ||
165 | else { | ||
166 | gpte_t ro_gpte = gpte; | ||
167 | ro_gpte.flags &= ~_PAGE_RW; | ||
168 | *spte = gpte_to_spte(lg, ro_gpte, 0); | ||
169 | } | ||
170 | |||
171 | /* Now we update dirty/accessed on guest. */ | ||
172 | lgwrite_u32(lg, gpte_ptr, gpte.raw.val); | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | /* This is much faster than the full demand_page logic. */ | ||
177 | static int page_writable(struct lguest *lg, unsigned long vaddr) | ||
178 | { | ||
179 | spgd_t *spgd; | ||
180 | unsigned long flags; | ||
181 | |||
182 | spgd = spgd_addr(lg, lg->pgdidx, vaddr); | ||
183 | if (!(spgd->flags & _PAGE_PRESENT)) | ||
184 | return 0; | ||
185 | |||
186 | flags = spte_addr(lg, *spgd, vaddr)->flags; | ||
187 | return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); | ||
188 | } | ||
189 | |||
190 | void pin_page(struct lguest *lg, unsigned long vaddr) | ||
191 | { | ||
192 | if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2)) | ||
193 | kill_guest(lg, "bad stack page %#lx", vaddr); | ||
194 | } | ||
195 | |||
196 | static void release_pgd(struct lguest *lg, spgd_t *spgd) | ||
197 | { | ||
198 | if (spgd->flags & _PAGE_PRESENT) { | ||
199 | unsigned int i; | ||
200 | spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT); | ||
201 | for (i = 0; i < PTES_PER_PAGE; i++) | ||
202 | release_pte(ptepage[i]); | ||
203 | free_page((long)ptepage); | ||
204 | spgd->raw.val = 0; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static void flush_user_mappings(struct lguest *lg, int idx) | ||
209 | { | ||
210 | unsigned int i; | ||
211 | for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++) | ||
212 | release_pgd(lg, lg->pgdirs[idx].pgdir + i); | ||
213 | } | ||
214 | |||
215 | void guest_pagetable_flush_user(struct lguest *lg) | ||
216 | { | ||
217 | flush_user_mappings(lg, lg->pgdidx); | ||
218 | } | ||
219 | |||
220 | static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable) | ||
221 | { | ||
222 | unsigned int i; | ||
223 | for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) | ||
224 | if (lg->pgdirs[i].cr3 == pgtable) | ||
225 | break; | ||
226 | return i; | ||
227 | } | ||
228 | |||
229 | static unsigned int new_pgdir(struct lguest *lg, | ||
230 | unsigned long cr3, | ||
231 | int *blank_pgdir) | ||
232 | { | ||
233 | unsigned int next; | ||
234 | |||
235 | next = random32() % ARRAY_SIZE(lg->pgdirs); | ||
236 | if (!lg->pgdirs[next].pgdir) { | ||
237 | lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL); | ||
238 | if (!lg->pgdirs[next].pgdir) | ||
239 | next = lg->pgdidx; | ||
240 | else | ||
241 | /* There are no mappings: you'll need to re-pin */ | ||
242 | *blank_pgdir = 1; | ||
243 | } | ||
244 | lg->pgdirs[next].cr3 = cr3; | ||
245 | /* Release all the non-kernel mappings. */ | ||
246 | flush_user_mappings(lg, next); | ||
247 | |||
248 | return next; | ||
249 | } | ||
250 | |||
251 | void guest_new_pagetable(struct lguest *lg, unsigned long pgtable) | ||
252 | { | ||
253 | int newpgdir, repin = 0; | ||
254 | |||
255 | newpgdir = find_pgdir(lg, pgtable); | ||
256 | if (newpgdir == ARRAY_SIZE(lg->pgdirs)) | ||
257 | newpgdir = new_pgdir(lg, pgtable, &repin); | ||
258 | lg->pgdidx = newpgdir; | ||
259 | if (repin) | ||
260 | pin_stack_pages(lg); | ||
261 | } | ||
262 | |||
263 | static void release_all_pagetables(struct lguest *lg) | ||
264 | { | ||
265 | unsigned int i, j; | ||
266 | |||
267 | for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) | ||
268 | if (lg->pgdirs[i].pgdir) | ||
269 | for (j = 0; j < SWITCHER_PGD_INDEX; j++) | ||
270 | release_pgd(lg, lg->pgdirs[i].pgdir + j); | ||
271 | } | ||
272 | |||
273 | void guest_pagetable_clear_all(struct lguest *lg) | ||
274 | { | ||
275 | release_all_pagetables(lg); | ||
276 | pin_stack_pages(lg); | ||
277 | } | ||
278 | |||
279 | static void do_set_pte(struct lguest *lg, int idx, | ||
280 | unsigned long vaddr, gpte_t gpte) | ||
281 | { | ||
282 | spgd_t *spgd = spgd_addr(lg, idx, vaddr); | ||
283 | if (spgd->flags & _PAGE_PRESENT) { | ||
284 | spte_t *spte = spte_addr(lg, *spgd, vaddr); | ||
285 | release_pte(*spte); | ||
286 | if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) { | ||
287 | check_gpte(lg, gpte); | ||
288 | *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY); | ||
289 | } else | ||
290 | spte->raw.val = 0; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | void guest_set_pte(struct lguest *lg, | ||
295 | unsigned long cr3, unsigned long vaddr, gpte_t gpte) | ||
296 | { | ||
297 | /* Kernel mappings must be changed on all top levels. */ | ||
298 | if (vaddr >= lg->page_offset) { | ||
299 | unsigned int i; | ||
300 | for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) | ||
301 | if (lg->pgdirs[i].pgdir) | ||
302 | do_set_pte(lg, i, vaddr, gpte); | ||
303 | } else { | ||
304 | int pgdir = find_pgdir(lg, cr3); | ||
305 | if (pgdir != ARRAY_SIZE(lg->pgdirs)) | ||
306 | do_set_pte(lg, pgdir, vaddr, gpte); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx) | ||
311 | { | ||
312 | int pgdir; | ||
313 | |||
314 | if (idx >= SWITCHER_PGD_INDEX) | ||
315 | return; | ||
316 | |||
317 | pgdir = find_pgdir(lg, cr3); | ||
318 | if (pgdir < ARRAY_SIZE(lg->pgdirs)) | ||
319 | release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx); | ||
320 | } | ||
321 | |||
322 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) | ||
323 | { | ||
324 | /* We assume this in flush_user_mappings, so check now */ | ||
325 | if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX) | ||
326 | return -EINVAL; | ||
327 | lg->pgdidx = 0; | ||
328 | lg->pgdirs[lg->pgdidx].cr3 = pgtable; | ||
329 | lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL); | ||
330 | if (!lg->pgdirs[lg->pgdidx].pgdir) | ||
331 | return -ENOMEM; | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | void free_guest_pagetable(struct lguest *lg) | ||
336 | { | ||
337 | unsigned int i; | ||
338 | |||
339 | release_all_pagetables(lg); | ||
340 | for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) | ||
341 | free_page((long)lg->pgdirs[i].pgdir); | ||
342 | } | ||
343 | |||
344 | /* Caller must be preempt-safe */ | ||
345 | void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages) | ||
346 | { | ||
347 | spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages); | ||
348 | spgd_t switcher_pgd; | ||
349 | spte_t regs_pte; | ||
350 | |||
351 | /* Since switcher less that 4MB, we simply mug top pte page. */ | ||
352 | switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT; | ||
353 | switcher_pgd.flags = _PAGE_KERNEL; | ||
354 | lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; | ||
355 | |||
356 | /* Map our regs page over stack page. */ | ||
357 | regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT; | ||
358 | regs_pte.flags = _PAGE_KERNEL; | ||
359 | switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE] | ||
360 | = regs_pte; | ||
361 | } | ||
362 | |||
363 | static void free_switcher_pte_pages(void) | ||
364 | { | ||
365 | unsigned int i; | ||
366 | |||
367 | for_each_possible_cpu(i) | ||
368 | free_page((long)switcher_pte_page(i)); | ||
369 | } | ||
370 | |||
371 | static __init void populate_switcher_pte_page(unsigned int cpu, | ||
372 | struct page *switcher_page[], | ||
373 | unsigned int pages) | ||
374 | { | ||
375 | unsigned int i; | ||
376 | spte_t *pte = switcher_pte_page(cpu); | ||
377 | |||
378 | for (i = 0; i < pages; i++) { | ||
379 | pte[i].pfn = page_to_pfn(switcher_page[i]); | ||
380 | pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED; | ||
381 | } | ||
382 | |||
383 | /* We only map this CPU's pages, so guest can't see others. */ | ||
384 | i = pages + cpu*2; | ||
385 | |||
386 | /* First page (regs) is rw, second (state) is ro. */ | ||
387 | pte[i].pfn = page_to_pfn(switcher_page[i]); | ||
388 | pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW; | ||
389 | pte[i+1].pfn = page_to_pfn(switcher_page[i+1]); | ||
390 | pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED; | ||
391 | } | ||
392 | |||
393 | __init int init_pagetables(struct page **switcher_page, unsigned int pages) | ||
394 | { | ||
395 | unsigned int i; | ||
396 | |||
397 | for_each_possible_cpu(i) { | ||
398 | switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL); | ||
399 | if (!switcher_pte_page(i)) { | ||
400 | free_switcher_pte_pages(); | ||
401 | return -ENOMEM; | ||
402 | } | ||
403 | populate_switcher_pte_page(i, switcher_page, pages); | ||
404 | } | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | void free_pagetables(void) | ||
409 | { | ||
410 | free_switcher_pte_pages(); | ||
411 | } | ||
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c new file mode 100644 index 000000000000..1b2cfe89dcd5 --- /dev/null +++ b/drivers/lguest/segments.c | |||
@@ -0,0 +1,125 @@ | |||
1 | #include "lg.h" | ||
2 | |||
3 | static int desc_ok(const struct desc_struct *gdt) | ||
4 | { | ||
5 | /* MBZ=0, P=1, DT=1 */ | ||
6 | return ((gdt->b & 0x00209000) == 0x00009000); | ||
7 | } | ||
8 | |||
9 | static int segment_present(const struct desc_struct *gdt) | ||
10 | { | ||
11 | return gdt->b & 0x8000; | ||
12 | } | ||
13 | |||
14 | static int ignored_gdt(unsigned int num) | ||
15 | { | ||
16 | return (num == GDT_ENTRY_TSS | ||
17 | || num == GDT_ENTRY_LGUEST_CS | ||
18 | || num == GDT_ENTRY_LGUEST_DS | ||
19 | || num == GDT_ENTRY_DOUBLEFAULT_TSS); | ||
20 | } | ||
21 | |||
22 | /* We don't allow removal of CS, DS or SS; it doesn't make sense. */ | ||
23 | static void check_segment_use(struct lguest *lg, unsigned int desc) | ||
24 | { | ||
25 | if (lg->regs->gs / 8 == desc) | ||
26 | lg->regs->gs = 0; | ||
27 | if (lg->regs->fs / 8 == desc) | ||
28 | lg->regs->fs = 0; | ||
29 | if (lg->regs->es / 8 == desc) | ||
30 | lg->regs->es = 0; | ||
31 | if (lg->regs->ds / 8 == desc | ||
32 | || lg->regs->cs / 8 == desc | ||
33 | || lg->regs->ss / 8 == desc) | ||
34 | kill_guest(lg, "Removed live GDT entry %u", desc); | ||
35 | } | ||
36 | |||
37 | static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) | ||
38 | { | ||
39 | unsigned int i; | ||
40 | |||
41 | for (i = start; i < end; i++) { | ||
42 | /* We never copy these ones to real gdt */ | ||
43 | if (ignored_gdt(i)) | ||
44 | continue; | ||
45 | |||
46 | /* We could fault in switch_to_guest if they are using | ||
47 | * a removed segment. */ | ||
48 | if (!segment_present(&lg->gdt[i])) { | ||
49 | check_segment_use(lg, i); | ||
50 | continue; | ||
51 | } | ||
52 | |||
53 | if (!desc_ok(&lg->gdt[i])) | ||
54 | kill_guest(lg, "Bad GDT descriptor %i", i); | ||
55 | |||
56 | /* DPL 0 presumably means "for use by guest". */ | ||
57 | if ((lg->gdt[i].b & 0x00006000) == 0) | ||
58 | lg->gdt[i].b |= (GUEST_PL << 13); | ||
59 | |||
60 | /* Set accessed bit, since gdt isn't writable. */ | ||
61 | lg->gdt[i].b |= 0x00000100; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | void setup_default_gdt_entries(struct lguest_ro_state *state) | ||
66 | { | ||
67 | struct desc_struct *gdt = state->guest_gdt; | ||
68 | unsigned long tss = (unsigned long)&state->guest_tss; | ||
69 | |||
70 | /* Hypervisor segments. */ | ||
71 | gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT; | ||
72 | gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT; | ||
73 | |||
74 | /* This is the one which we *cannot* copy from guest, since tss | ||
75 | is depended on this lguest_ro_state, ie. this cpu. */ | ||
76 | gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16); | ||
77 | gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000) | ||
78 | | ((tss >> 16) & 0x000000FF); | ||
79 | } | ||
80 | |||
81 | void setup_guest_gdt(struct lguest *lg) | ||
82 | { | ||
83 | lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; | ||
84 | lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; | ||
85 | lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); | ||
86 | lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); | ||
87 | } | ||
88 | |||
89 | /* This is a fast version for the common case where only the three TLS entries | ||
90 | * have changed. */ | ||
91 | void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt) | ||
92 | { | ||
93 | unsigned int i; | ||
94 | |||
95 | for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) | ||
96 | gdt[i] = lg->gdt[i]; | ||
97 | } | ||
98 | |||
99 | void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) | ||
100 | { | ||
101 | unsigned int i; | ||
102 | |||
103 | for (i = 0; i < GDT_ENTRIES; i++) | ||
104 | if (!ignored_gdt(i)) | ||
105 | gdt[i] = lg->gdt[i]; | ||
106 | } | ||
107 | |||
108 | void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) | ||
109 | { | ||
110 | if (num > ARRAY_SIZE(lg->gdt)) | ||
111 | kill_guest(lg, "too many gdt entries %i", num); | ||
112 | |||
113 | lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0])); | ||
114 | fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt)); | ||
115 | lg->changed |= CHANGED_GDT; | ||
116 | } | ||
117 | |||
118 | void guest_load_tls(struct lguest *lg, unsigned long gtls) | ||
119 | { | ||
120 | struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN]; | ||
121 | |||
122 | lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); | ||
123 | fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); | ||
124 | lg->changed |= CHANGED_GDT_TLS; | ||
125 | } | ||
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S new file mode 100644 index 000000000000..eadd4cc299d2 --- /dev/null +++ b/drivers/lguest/switcher.S | |||
@@ -0,0 +1,159 @@ | |||
1 | /* This code sits at 0xFFC00000 to do the low-level guest<->host switch. | ||
2 | |||
3 | There is are two pages above us for this CPU (struct lguest_pages). | ||
4 | The second page (struct lguest_ro_state) becomes read-only after the | ||
5 | context switch. The first page (the stack for traps) remains writable, | ||
6 | but while we're in here, the guest cannot be running. | ||
7 | */ | ||
8 | #include <linux/linkage.h> | ||
9 | #include <asm/asm-offsets.h> | ||
10 | #include "lg.h" | ||
11 | |||
12 | .text | ||
13 | ENTRY(start_switcher_text) | ||
14 | |||
15 | /* %eax points to lguest pages for this CPU. %ebx contains cr3 value. | ||
16 | All normal registers can be clobbered! */ | ||
17 | ENTRY(switch_to_guest) | ||
18 | /* Save host segments on host stack. */ | ||
19 | pushl %es | ||
20 | pushl %ds | ||
21 | pushl %gs | ||
22 | pushl %fs | ||
23 | /* With CONFIG_FRAME_POINTER, gcc doesn't let us clobber this! */ | ||
24 | pushl %ebp | ||
25 | /* Save host stack. */ | ||
26 | movl %esp, LGUEST_PAGES_host_sp(%eax) | ||
27 | /* Switch to guest stack: if we get NMI we expect to be there. */ | ||
28 | movl %eax, %edx | ||
29 | addl $LGUEST_PAGES_regs, %edx | ||
30 | movl %edx, %esp | ||
31 | /* Switch to guest's GDT, IDT. */ | ||
32 | lgdt LGUEST_PAGES_guest_gdt_desc(%eax) | ||
33 | lidt LGUEST_PAGES_guest_idt_desc(%eax) | ||
34 | /* Switch to guest's TSS while GDT still writable. */ | ||
35 | movl $(GDT_ENTRY_TSS*8), %edx | ||
36 | ltr %dx | ||
37 | /* Set host's TSS GDT entry to available (clear byte 5 bit 2). */ | ||
38 | movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx | ||
39 | andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx) | ||
40 | /* Switch to guest page tables: lguest_pages->state now read-only. */ | ||
41 | movl %ebx, %cr3 | ||
42 | /* Restore guest regs */ | ||
43 | popl %ebx | ||
44 | popl %ecx | ||
45 | popl %edx | ||
46 | popl %esi | ||
47 | popl %edi | ||
48 | popl %ebp | ||
49 | popl %gs | ||
50 | popl %eax | ||
51 | popl %fs | ||
52 | popl %ds | ||
53 | popl %es | ||
54 | /* Skip error code and trap number */ | ||
55 | addl $8, %esp | ||
56 | iret | ||
57 | |||
58 | #define SWITCH_TO_HOST \ | ||
59 | /* Save guest state */ \ | ||
60 | pushl %es; \ | ||
61 | pushl %ds; \ | ||
62 | pushl %fs; \ | ||
63 | pushl %eax; \ | ||
64 | pushl %gs; \ | ||
65 | pushl %ebp; \ | ||
66 | pushl %edi; \ | ||
67 | pushl %esi; \ | ||
68 | pushl %edx; \ | ||
69 | pushl %ecx; \ | ||
70 | pushl %ebx; \ | ||
71 | /* Load lguest ds segment for convenience. */ \ | ||
72 | movl $(LGUEST_DS), %eax; \ | ||
73 | movl %eax, %ds; \ | ||
74 | /* Figure out where we are, based on stack (at top of regs). */ \ | ||
75 | movl %esp, %eax; \ | ||
76 | subl $LGUEST_PAGES_regs, %eax; \ | ||
77 | /* Put trap number in %ebx before we switch cr3 and lose it. */ \ | ||
78 | movl LGUEST_PAGES_regs_trapnum(%eax), %ebx; \ | ||
79 | /* Switch to host page tables (host GDT, IDT and stack are in host \ | ||
80 | mem, so need this first) */ \ | ||
81 | movl LGUEST_PAGES_host_cr3(%eax), %edx; \ | ||
82 | movl %edx, %cr3; \ | ||
83 | /* Set guest's TSS to available (clear byte 5 bit 2). */ \ | ||
84 | andb $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \ | ||
85 | /* Switch to host's GDT & IDT. */ \ | ||
86 | lgdt LGUEST_PAGES_host_gdt_desc(%eax); \ | ||
87 | lidt LGUEST_PAGES_host_idt_desc(%eax); \ | ||
88 | /* Switch to host's stack. */ \ | ||
89 | movl LGUEST_PAGES_host_sp(%eax), %esp; \ | ||
90 | /* Switch to host's TSS */ \ | ||
91 | movl $(GDT_ENTRY_TSS*8), %edx; \ | ||
92 | ltr %dx; \ | ||
93 | popl %ebp; \ | ||
94 | popl %fs; \ | ||
95 | popl %gs; \ | ||
96 | popl %ds; \ | ||
97 | popl %es | ||
98 | |||
99 | /* Return to run_guest_once. */ | ||
100 | return_to_host: | ||
101 | SWITCH_TO_HOST | ||
102 | iret | ||
103 | |||
104 | deliver_to_host: | ||
105 | SWITCH_TO_HOST | ||
106 | /* Decode IDT and jump to hosts' irq handler. When that does iret, it | ||
107 | * will return to run_guest_once. This is a feature. */ | ||
108 | movl (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx | ||
109 | leal (%edx,%ebx,8), %eax | ||
110 | movzwl (%eax),%edx | ||
111 | movl 4(%eax), %eax | ||
112 | xorw %ax, %ax | ||
113 | orl %eax, %edx | ||
114 | jmp *%edx | ||
115 | |||
116 | /* Real hardware interrupts are delivered straight to the host. Others | ||
117 | cause us to return to run_guest_once so it can decide what to do. Note | ||
118 | that some of these are overridden by the guest to deliver directly, and | ||
119 | never enter here (see load_guest_idt_entry). */ | ||
120 | .macro IRQ_STUB N TARGET | ||
121 | .data; .long 1f; .text; 1: | ||
122 | /* Make an error number for most traps, which don't have one. */ | ||
123 | .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17) | ||
124 | pushl $0 | ||
125 | .endif | ||
126 | pushl $\N | ||
127 | jmp \TARGET | ||
128 | ALIGN | ||
129 | .endm | ||
130 | |||
131 | .macro IRQ_STUBS FIRST LAST TARGET | ||
132 | irq=\FIRST | ||
133 | .rept \LAST-\FIRST+1 | ||
134 | IRQ_STUB irq \TARGET | ||
135 | irq=irq+1 | ||
136 | .endr | ||
137 | .endm | ||
138 | |||
139 | /* We intercept every interrupt, because we may need to switch back to | ||
140 | * host. Unfortunately we can't tell them apart except by entry | ||
141 | * point, so we need 256 entry points. | ||
142 | */ | ||
143 | .data | ||
144 | .global default_idt_entries | ||
145 | default_idt_entries: | ||
146 | .text | ||
147 | IRQ_STUBS 0 1 return_to_host /* First two traps */ | ||
148 | IRQ_STUB 2 handle_nmi /* NMI */ | ||
149 | IRQ_STUBS 3 31 return_to_host /* Rest of traps */ | ||
150 | IRQ_STUBS 32 127 deliver_to_host /* Real interrupts */ | ||
151 | IRQ_STUB 128 return_to_host /* System call (overridden) */ | ||
152 | IRQ_STUBS 129 255 deliver_to_host /* Other real interrupts */ | ||
153 | |||
154 | /* We ignore NMI and return. */ | ||
155 | handle_nmi: | ||
156 | addl $8, %esp | ||
157 | iret | ||
158 | |||
159 | ENTRY(end_switcher_text) | ||
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index c96b7fe882a4..ec9e5f32f0ae 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c | |||
@@ -365,10 +365,9 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, | |||
365 | if (np == NULL) | 365 | if (np == NULL) |
366 | return NULL; | 366 | return NULL; |
367 | 367 | ||
368 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | 368 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
369 | if (!dev) | 369 | if (!dev) |
370 | return NULL; | 370 | return NULL; |
371 | memset(dev, 0, sizeof(*dev)); | ||
372 | 371 | ||
373 | dev->bus = &chip->lbus; | 372 | dev->bus = &chip->lbus; |
374 | dev->media_bay = in_bay; | 373 | dev->media_bay = in_bay; |
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index f8e1a135bf9d..d409f6759482 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c | |||
@@ -1053,10 +1053,9 @@ static int smu_open(struct inode *inode, struct file *file) | |||
1053 | struct smu_private *pp; | 1053 | struct smu_private *pp; |
1054 | unsigned long flags; | 1054 | unsigned long flags; |
1055 | 1055 | ||
1056 | pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL); | 1056 | pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL); |
1057 | if (pp == 0) | 1057 | if (pp == 0) |
1058 | return -ENOMEM; | 1058 | return -ENOMEM; |
1059 | memset(pp, 0, sizeof(struct smu_private)); | ||
1060 | spin_lock_init(&pp->lock); | 1059 | spin_lock_init(&pp->lock); |
1061 | pp->mode = smu_file_commands; | 1060 | pp->mode = smu_file_commands; |
1062 | init_waitqueue_head(&pp->wait); | 1061 | init_waitqueue_head(&pp->wait); |
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 3d90fc002097..e43554e754a4 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c | |||
@@ -318,10 +318,9 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) | |||
318 | if (adap == NULL) | 318 | if (adap == NULL) |
319 | return NULL; | 319 | return NULL; |
320 | 320 | ||
321 | clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | 321 | clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); |
322 | if (clt == NULL) | 322 | if (clt == NULL) |
323 | return NULL; | 323 | return NULL; |
324 | memset(clt, 0, sizeof(struct i2c_client)); | ||
325 | 324 | ||
326 | clt->addr = (id >> 1) & 0x7f; | 325 | clt->addr = (id >> 1) & 0x7f; |
327 | clt->adapter = adap; | 326 | clt->adapter = adap; |
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3d0354e96a97..5452da1bb1a5 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c | |||
@@ -431,9 +431,8 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind ) | |||
431 | | I2C_FUNC_SMBUS_WRITE_BYTE) ) | 431 | | I2C_FUNC_SMBUS_WRITE_BYTE) ) |
432 | return 0; | 432 | return 0; |
433 | 433 | ||
434 | if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) ) | 434 | if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) ) |
435 | return -ENOMEM; | 435 | return -ENOMEM; |
436 | memset( cl, 0, sizeof(struct i2c_client) ); | ||
437 | 436 | ||
438 | cl->addr = addr; | 437 | cl->addr = addr; |
439 | cl->adapter = adapter; | 438 | cl->adapter = adapter; |
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index a0fabf3c2008..7e10c3ab4d50 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c | |||
@@ -117,10 +117,9 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, | |||
117 | DBG("wf_lm75: creating %s device at address 0x%02x\n", | 117 | DBG("wf_lm75: creating %s device at address 0x%02x\n", |
118 | ds1775 ? "ds1775" : "lm75", addr); | 118 | ds1775 ? "ds1775" : "lm75", addr); |
119 | 119 | ||
120 | lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); | 120 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); |
121 | if (lm == NULL) | 121 | if (lm == NULL) |
122 | return NULL; | 122 | return NULL; |
123 | memset(lm, 0, sizeof(struct wf_lm75_sensor)); | ||
124 | 123 | ||
125 | /* Usual rant about sensor names not beeing very consistent in | 124 | /* Usual rant about sensor names not beeing very consistent in |
126 | * the device-tree, oh well ... | 125 | * the device-tree, oh well ... |
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 1a876f9965e0..144071e70a93 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -951,13 +951,12 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
951 | 951 | ||
952 | len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors); | 952 | len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors); |
953 | 953 | ||
954 | ms = kmalloc(len, GFP_KERNEL); | 954 | ms = kzalloc(len, GFP_KERNEL); |
955 | if (!ms) { | 955 | if (!ms) { |
956 | ti->error = "Cannot allocate mirror context"; | 956 | ti->error = "Cannot allocate mirror context"; |
957 | return NULL; | 957 | return NULL; |
958 | } | 958 | } |
959 | 959 | ||
960 | memset(ms, 0, len); | ||
961 | spin_lock_init(&ms->lock); | 960 | spin_lock_init(&ms->lock); |
962 | 961 | ||
963 | ms->ti = ti; | 962 | ms->ti = ti; |
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 5a1449f485cf..28929b618e20 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c | |||
@@ -905,12 +905,11 @@ static int cinergyt2_probe (struct usb_interface *intf, | |||
905 | struct cinergyt2 *cinergyt2; | 905 | struct cinergyt2 *cinergyt2; |
906 | int err; | 906 | int err; |
907 | 907 | ||
908 | if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { | 908 | if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { |
909 | dprintk(1, "out of memory?!?\n"); | 909 | dprintk(1, "out of memory?!?\n"); |
910 | return -ENOMEM; | 910 | return -ENOMEM; |
911 | } | 911 | } |
912 | 912 | ||
913 | memset (cinergyt2, 0, sizeof (struct cinergyt2)); | ||
914 | usb_set_intfdata (intf, (void *) cinergyt2); | 913 | usb_set_intfdata (intf, (void *) cinergyt2); |
915 | 914 | ||
916 | mutex_init(&cinergyt2->sem); | 915 | mutex_init(&cinergyt2->sem); |
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c index 55aab8d38880..a76bd786cf13 100644 --- a/drivers/media/video/cpia2/cpia2_core.c +++ b/drivers/media/video/cpia2/cpia2_core.c | |||
@@ -2224,15 +2224,13 @@ struct camera_data *cpia2_init_camera_struct(void) | |||
2224 | { | 2224 | { |
2225 | struct camera_data *cam; | 2225 | struct camera_data *cam; |
2226 | 2226 | ||
2227 | cam = kmalloc(sizeof(*cam), GFP_KERNEL); | 2227 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); |
2228 | 2228 | ||
2229 | if (!cam) { | 2229 | if (!cam) { |
2230 | ERR("couldn't kmalloc cpia2 struct\n"); | 2230 | ERR("couldn't kmalloc cpia2 struct\n"); |
2231 | return NULL; | 2231 | return NULL; |
2232 | } | 2232 | } |
2233 | 2233 | ||
2234 | /* Default everything to 0 */ | ||
2235 | memset(cam, 0, sizeof(struct camera_data)); | ||
2236 | 2234 | ||
2237 | cam->present = 1; | 2235 | cam->present = 1; |
2238 | mutex_init(&cam->busy_lock); | 2236 | mutex_init(&cam->busy_lock); |
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 507b1d4260ed..11cfcf18ec34 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -812,10 +812,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | |||
812 | int msp_product, msp_prod_hi, msp_prod_lo; | 812 | int msp_product, msp_prod_hi, msp_prod_lo; |
813 | int msp_rom; | 813 | int msp_rom; |
814 | 814 | ||
815 | client = kmalloc(sizeof(*client), GFP_KERNEL); | 815 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
816 | if (client == NULL) | 816 | if (client == NULL) |
817 | return -ENOMEM; | 817 | return -ENOMEM; |
818 | memset(client, 0, sizeof(*client)); | ||
819 | client->addr = address; | 818 | client->addr = address; |
820 | client->adapter = adapter; | 819 | client->adapter = adapter; |
821 | client->driver = &i2c_driver; | 820 | client->driver = &i2c_driver; |
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 1455a8f4e930..4ab1af74a970 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c | |||
@@ -353,9 +353,8 @@ static int planb_prepare_open(struct planb *pb) | |||
353 | * PLANB_DUMMY)*sizeof(struct dbdma_cmd) | 353 | * PLANB_DUMMY)*sizeof(struct dbdma_cmd) |
354 | +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 | 354 | +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 |
355 | +MAX_GBUFFERS*sizeof(unsigned int); | 355 | +MAX_GBUFFERS*sizeof(unsigned int); |
356 | if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0) | 356 | if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0) |
357 | return -ENOMEM; | 357 | return -ENOMEM; |
358 | memset ((void *) pb->priv_space, 0, size); | ||
359 | pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) | 358 | pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) |
360 | DBDMA_ALIGN (pb->priv_space); | 359 | DBDMA_ALIGN (pb->priv_space); |
361 | pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; | 360 | pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; |
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 2d9c0dd3b733..ff555129c82f 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c | |||
@@ -1130,13 +1130,12 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) | |||
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | if ((cam = | 1132 | if ((cam = |
1133 | kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { | 1133 | kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { |
1134 | printk(KERN_WARNING | 1134 | printk(KERN_WARNING |
1135 | "could not allocate kernel memory for vicam_camera struct\n"); | 1135 | "could not allocate kernel memory for vicam_camera struct\n"); |
1136 | return -ENOMEM; | 1136 | return -ENOMEM; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | memset(cam, 0, sizeof (struct vicam_camera)); | ||
1140 | 1139 | ||
1141 | cam->shutter_speed = 15; | 1140 | cam->shutter_speed = 15; |
1142 | 1141 | ||
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 75f401d52fda..b4ed57e02729 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c | |||
@@ -200,9 +200,8 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) | |||
200 | { | 200 | { |
201 | struct mcp *mcp; | 201 | struct mcp *mcp; |
202 | 202 | ||
203 | mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL); | 203 | mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL); |
204 | if (mcp) { | 204 | if (mcp) { |
205 | memset(mcp, 0, sizeof(struct mcp) + size); | ||
206 | spin_lock_init(&mcp->lock); | 205 | spin_lock_init(&mcp->lock); |
207 | mcp->attached_device.parent = parent; | 206 | mcp->attached_device.parent = parent; |
208 | mcp->attached_device.bus = &mcp_bus_type; | 207 | mcp->attached_device.bus = &mcp_bus_type; |
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 149810a084f5..e03f1bcd4f9f 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c | |||
@@ -484,12 +484,11 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
484 | goto err_disable; | 484 | goto err_disable; |
485 | } | 485 | } |
486 | 486 | ||
487 | ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); | 487 | ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL); |
488 | ret = -ENOMEM; | 488 | ret = -ENOMEM; |
489 | if (!ucb) | 489 | if (!ucb) |
490 | goto err_disable; | 490 | goto err_disable; |
491 | 491 | ||
492 | memset(ucb, 0, sizeof(struct ucb1x00)); | ||
493 | 492 | ||
494 | ucb->cdev.class = &ucb1x00_class; | 493 | ucb->cdev.class = &ucb1x00_class; |
495 | ucb->cdev.dev = &mcp->attached_device; | 494 | ucb->cdev.dev = &mcp->attached_device; |
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 7798f590e5aa..f75306059971 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c | |||
@@ -979,10 +979,9 @@ static int asus_hotk_add(struct acpi_device *device) | |||
979 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", | 979 | printk(ASUS_NOTICE "Asus Laptop Support version %s\n", |
980 | ASUS_LAPTOP_VERSION); | 980 | ASUS_LAPTOP_VERSION); |
981 | 981 | ||
982 | hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); | 982 | hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); |
983 | if (!hotk) | 983 | if (!hotk) |
984 | return -ENOMEM; | 984 | return -ENOMEM; |
985 | memset(hotk, 0, sizeof(struct asus_hotk)); | ||
986 | 985 | ||
987 | hotk->handle = device->handle; | 986 | hotk->handle = device->handle; |
988 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); | 987 | strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); |
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index b5df347c81b9..6497872df524 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c | |||
@@ -41,18 +41,16 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s | |||
41 | if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE) | 41 | if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE) |
42 | return NULL; | 42 | return NULL; |
43 | 43 | ||
44 | cmd = kmalloc(sizeof(struct command), GFP_KERNEL); | 44 | cmd = kzalloc(sizeof(struct command), GFP_KERNEL); |
45 | if (cmd == NULL) | 45 | if (cmd == NULL) |
46 | return NULL; | 46 | return NULL; |
47 | 47 | ||
48 | memset(cmd, 0, sizeof(*cmd)); | ||
49 | 48 | ||
50 | cmd->buffer = kmalloc(buffer_size, GFP_KERNEL); | 49 | cmd->buffer = kzalloc(buffer_size, GFP_KERNEL); |
51 | if (cmd->buffer == NULL) { | 50 | if (cmd->buffer == NULL) { |
52 | kfree(cmd); | 51 | kfree(cmd); |
53 | return NULL; | 52 | return NULL; |
54 | } | 53 | } |
55 | memset(cmd->buffer, 0, buffer_size); | ||
56 | cmd->buffer_size = buffer_size; | 54 | cmd->buffer_size = buffer_size; |
57 | 55 | ||
58 | kobject_init(&cmd->kobj); | 56 | kobject_init(&cmd->kobj); |
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index eb7b073734b8..22a7e8ba211d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c | |||
@@ -563,11 +563,10 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user * | |||
563 | if (*offset != 0) | 563 | if (*offset != 0) |
564 | return 0; | 564 | return 0; |
565 | 565 | ||
566 | buff = kmalloc (count + 1, GFP_KERNEL); | 566 | buff = kzalloc (count + 1, GFP_KERNEL); |
567 | if (!buff) | 567 | if (!buff) |
568 | return -ENOMEM; | 568 | return -ENOMEM; |
569 | 569 | ||
570 | memset(buff, 0x0, count + 1); | ||
571 | 570 | ||
572 | if (copy_from_user(buff, ubuff, count)) { | 571 | if (copy_from_user(buff, ubuff, count)) { |
573 | kfree(buff); | 572 | kfree(buff); |
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index fb03a853fac4..4f9d4a9da983 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c | |||
@@ -77,13 +77,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi | |||
77 | /* vnc client won't work without bus-mastering */ | 77 | /* vnc client won't work without bus-mastering */ |
78 | pci_set_master(pdev); | 78 | pci_set_master(pdev); |
79 | 79 | ||
80 | sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL); | 80 | sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL); |
81 | if (sp == NULL) { | 81 | if (sp == NULL) { |
82 | dev_err(&pdev->dev, "Failed to allocate memory\n"); | 82 | dev_err(&pdev->dev, "Failed to allocate memory\n"); |
83 | result = -ENOMEM; | 83 | result = -ENOMEM; |
84 | goto error_kmalloc; | 84 | goto error_kmalloc; |
85 | } | 85 | } |
86 | memset(sp, 0, sizeof(struct service_processor)); | ||
87 | 86 | ||
88 | spin_lock_init(&sp->lock); | 87 | spin_lock_init(&sp->lock); |
89 | INIT_LIST_HEAD(&sp->command_queue); | 88 | INIT_LIST_HEAD(&sp->command_queue); |
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index cbd4b6e3e17c..93fe2e5dd616 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -414,13 +414,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) | |||
414 | return ERR_PTR(-ENOSPC); | 414 | return ERR_PTR(-ENOSPC); |
415 | __set_bit(devidx, dev_use); | 415 | __set_bit(devidx, dev_use); |
416 | 416 | ||
417 | md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); | 417 | md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); |
418 | if (!md) { | 418 | if (!md) { |
419 | ret = -ENOMEM; | 419 | ret = -ENOMEM; |
420 | goto out; | 420 | goto out; |
421 | } | 421 | } |
422 | 422 | ||
423 | memset(md, 0, sizeof(struct mmc_blk_data)); | ||
424 | 423 | ||
425 | /* | 424 | /* |
426 | * Set the read-only status based on the supported commands | 425 | * Set the read-only status based on the supported commands |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5fb659f8b20e..3073f679584b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -838,6 +838,50 @@ config ULTRA32 | |||
838 | <file:Documentation/networking/net-modules.txt>. The module | 838 | <file:Documentation/networking/net-modules.txt>. The module |
839 | will be called smc-ultra32. | 839 | will be called smc-ultra32. |
840 | 840 | ||
841 | config BFIN_MAC | ||
842 | tristate "Blackfin 536/537 on-chip mac support" | ||
843 | depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H) | ||
844 | select CRC32 | ||
845 | select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE | ||
846 | help | ||
847 | This is the driver for blackfin on-chip mac device. Say Y if you want it | ||
848 | compiled into the kernel. This driver is also available as a module | ||
849 | ( = code which can be inserted in and removed from the running kernel | ||
850 | whenever you want). The module will be called bfin_mac. | ||
851 | |||
852 | config BFIN_MAC_USE_L1 | ||
853 | bool "Use L1 memory for rx/tx packets" | ||
854 | depends on BFIN_MAC && BF537 | ||
855 | default y | ||
856 | help | ||
857 | To get maximum network performace, you should use L1 memory as rx/tx buffers. | ||
858 | Say N here if you want to reserve L1 memory for other uses. | ||
859 | |||
860 | config BFIN_TX_DESC_NUM | ||
861 | int "Number of transmit buffer packets" | ||
862 | depends on BFIN_MAC | ||
863 | range 6 10 if BFIN_MAC_USE_L1 | ||
864 | range 10 100 | ||
865 | default "10" | ||
866 | help | ||
867 | Set the number of buffer packets used in driver. | ||
868 | |||
869 | config BFIN_RX_DESC_NUM | ||
870 | int "Number of receive buffer packets" | ||
871 | depends on BFIN_MAC | ||
872 | range 20 100 if BFIN_MAC_USE_L1 | ||
873 | range 20 800 | ||
874 | default "20" | ||
875 | help | ||
876 | Set the number of buffer packets used in driver. | ||
877 | |||
878 | config BFIN_MAC_RMII | ||
879 | bool "RMII PHY Interface (EXPERIMENTAL)" | ||
880 | depends on BFIN_MAC && EXPERIMENTAL | ||
881 | default n | ||
882 | help | ||
883 | Use Reduced PHY MII Interface | ||
884 | |||
841 | config SMC9194 | 885 | config SMC9194 |
842 | tristate "SMC 9194 support" | 886 | tristate "SMC 9194 support" |
843 | depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) | 887 | depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0e286ab8855a..336af0635df8 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -177,6 +177,7 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o | |||
177 | obj-$(CONFIG_HPLANCE) += hplance.o 7990.o | 177 | obj-$(CONFIG_HPLANCE) += hplance.o 7990.o |
178 | obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o | 178 | obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o |
179 | obj-$(CONFIG_EQUALIZER) += eql.o | 179 | obj-$(CONFIG_EQUALIZER) += eql.o |
180 | obj-$(CONFIG_LGUEST_GUEST) += lguest_net.o | ||
180 | obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o | 181 | obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o |
181 | obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o | 182 | obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o |
182 | obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o | 183 | obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o |
@@ -200,6 +201,7 @@ obj-$(CONFIG_S2IO) += s2io.o | |||
200 | obj-$(CONFIG_MYRI10GE) += myri10ge/ | 201 | obj-$(CONFIG_MYRI10GE) += myri10ge/ |
201 | obj-$(CONFIG_SMC91X) += smc91x.o | 202 | obj-$(CONFIG_SMC91X) += smc91x.o |
202 | obj-$(CONFIG_SMC911X) += smc911x.o | 203 | obj-$(CONFIG_SMC911X) += smc911x.o |
204 | obj-$(CONFIG_BFIN_MAC) += bfin_mac.o | ||
203 | obj-$(CONFIG_DM9000) += dm9000.o | 205 | obj-$(CONFIG_DM9000) += dm9000.o |
204 | obj-$(CONFIG_FEC_8XX) += fec_8xx/ | 206 | obj-$(CONFIG_FEC_8XX) += fec_8xx/ |
205 | obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o | 207 | obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o |
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index da713500654d..a7cac695a9bd 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c | |||
@@ -464,7 +464,7 @@ static void ether3_setmulticastlist(struct net_device *dev) | |||
464 | if (dev->flags & IFF_PROMISC) { | 464 | if (dev->flags & IFF_PROMISC) { |
465 | /* promiscuous mode */ | 465 | /* promiscuous mode */ |
466 | priv(dev)->regs.config1 |= CFG1_RECVPROMISC; | 466 | priv(dev)->regs.config1 |= CFG1_RECVPROMISC; |
467 | } else if (dev->flags & IFF_ALLMULTI) { | 467 | } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) { |
468 | priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; | 468 | priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; |
469 | } else | 469 | } else |
470 | priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; | 470 | priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; |
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 96fb0ec905a7..37f1b6ff5c12 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c | |||
@@ -1519,14 +1519,13 @@ static void b44_setup_pseudo_magicp(struct b44 *bp) | |||
1519 | u8 *pwol_pattern; | 1519 | u8 *pwol_pattern; |
1520 | u8 pwol_mask[B44_PMASK_SIZE]; | 1520 | u8 pwol_mask[B44_PMASK_SIZE]; |
1521 | 1521 | ||
1522 | pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL); | 1522 | pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL); |
1523 | if (!pwol_pattern) { | 1523 | if (!pwol_pattern) { |
1524 | printk(KERN_ERR PFX "Memory not available for WOL\n"); | 1524 | printk(KERN_ERR PFX "Memory not available for WOL\n"); |
1525 | return; | 1525 | return; |
1526 | } | 1526 | } |
1527 | 1527 | ||
1528 | /* Ipv4 magic packet pattern - pattern 0.*/ | 1528 | /* Ipv4 magic packet pattern - pattern 0.*/ |
1529 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
1530 | memset(pwol_mask, 0, B44_PMASK_SIZE); | 1529 | memset(pwol_mask, 0, B44_PMASK_SIZE); |
1531 | plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | 1530 | plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, |
1532 | B44_ETHIPV4UDP_HLEN); | 1531 | B44_ETHIPV4UDP_HLEN); |
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c new file mode 100644 index 000000000000..9a08d656f1ce --- /dev/null +++ b/drivers/net/bfin_mac.c | |||
@@ -0,0 +1,1009 @@ | |||
1 | /* | ||
2 | * File: drivers/net/bfin_mac.c | ||
3 | * Based on: | ||
4 | * Maintainer: | ||
5 | * Bryan Wu <bryan.wu@analog.com> | ||
6 | * | ||
7 | * Original author: | ||
8 | * Luke Yang <luke.yang@analog.com> | ||
9 | * | ||
10 | * Created: | ||
11 | * Description: | ||
12 | * | ||
13 | * Modified: | ||
14 | * Copyright 2004-2006 Analog Devices Inc. | ||
15 | * | ||
16 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
17 | * | ||
18 | * This program is free software ; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation ; either version 2, or (at your option) | ||
21 | * any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY ; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program ; see the file COPYING. | ||
30 | * If not, write to the Free Software Foundation, | ||
31 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
32 | */ | ||
33 | |||
34 | #include <linux/init.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/irq.h> | ||
43 | #include <linux/io.h> | ||
44 | #include <linux/ioport.h> | ||
45 | #include <linux/crc32.h> | ||
46 | #include <linux/device.h> | ||
47 | #include <linux/spinlock.h> | ||
48 | #include <linux/ethtool.h> | ||
49 | #include <linux/mii.h> | ||
50 | |||
51 | #include <linux/netdevice.h> | ||
52 | #include <linux/etherdevice.h> | ||
53 | #include <linux/skbuff.h> | ||
54 | |||
55 | #include <linux/platform_device.h> | ||
56 | #include <linux/netdevice.h> | ||
57 | #include <linux/etherdevice.h> | ||
58 | #include <linux/skbuff.h> | ||
59 | |||
60 | #include <asm/dma.h> | ||
61 | #include <linux/dma-mapping.h> | ||
62 | |||
63 | #include <asm/blackfin.h> | ||
64 | #include <asm/cacheflush.h> | ||
65 | #include <asm/portmux.h> | ||
66 | |||
67 | #include "bfin_mac.h" | ||
68 | |||
69 | #define DRV_NAME "bfin_mac" | ||
70 | #define DRV_VERSION "1.1" | ||
71 | #define DRV_AUTHOR "Bryan Wu, Luke Yang" | ||
72 | #define DRV_DESC "Blackfin BF53[67] on-chip Ethernet MAC driver" | ||
73 | |||
74 | MODULE_AUTHOR(DRV_AUTHOR); | ||
75 | MODULE_LICENSE("GPL"); | ||
76 | MODULE_DESCRIPTION(DRV_DESC); | ||
77 | |||
78 | #if defined(CONFIG_BFIN_MAC_USE_L1) | ||
79 | # define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size) | ||
80 | # define bfin_mac_free(dma_handle, ptr) l1_data_sram_free(ptr) | ||
81 | #else | ||
82 | # define bfin_mac_alloc(dma_handle, size) \ | ||
83 | dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL) | ||
84 | # define bfin_mac_free(dma_handle, ptr) \ | ||
85 | dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle) | ||
86 | #endif | ||
87 | |||
88 | #define PKT_BUF_SZ 1580 | ||
89 | |||
90 | #define MAX_TIMEOUT_CNT 500 | ||
91 | |||
92 | /* pointers to maintain transmit list */ | ||
93 | static struct net_dma_desc_tx *tx_list_head; | ||
94 | static struct net_dma_desc_tx *tx_list_tail; | ||
95 | static struct net_dma_desc_rx *rx_list_head; | ||
96 | static struct net_dma_desc_rx *rx_list_tail; | ||
97 | static struct net_dma_desc_rx *current_rx_ptr; | ||
98 | static struct net_dma_desc_tx *current_tx_ptr; | ||
99 | static struct net_dma_desc_tx *tx_desc; | ||
100 | static struct net_dma_desc_rx *rx_desc; | ||
101 | |||
102 | static void desc_list_free(void) | ||
103 | { | ||
104 | struct net_dma_desc_rx *r; | ||
105 | struct net_dma_desc_tx *t; | ||
106 | int i; | ||
107 | #if !defined(CONFIG_BFIN_MAC_USE_L1) | ||
108 | dma_addr_t dma_handle = 0; | ||
109 | #endif | ||
110 | |||
111 | if (tx_desc) { | ||
112 | t = tx_list_head; | ||
113 | for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) { | ||
114 | if (t) { | ||
115 | if (t->skb) { | ||
116 | dev_kfree_skb(t->skb); | ||
117 | t->skb = NULL; | ||
118 | } | ||
119 | t = t->next; | ||
120 | } | ||
121 | } | ||
122 | bfin_mac_free(dma_handle, tx_desc); | ||
123 | } | ||
124 | |||
125 | if (rx_desc) { | ||
126 | r = rx_list_head; | ||
127 | for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) { | ||
128 | if (r) { | ||
129 | if (r->skb) { | ||
130 | dev_kfree_skb(r->skb); | ||
131 | r->skb = NULL; | ||
132 | } | ||
133 | r = r->next; | ||
134 | } | ||
135 | } | ||
136 | bfin_mac_free(dma_handle, rx_desc); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static int desc_list_init(void) | ||
141 | { | ||
142 | int i; | ||
143 | struct sk_buff *new_skb; | ||
144 | #if !defined(CONFIG_BFIN_MAC_USE_L1) | ||
145 | /* | ||
146 | * This dma_handle is useless in Blackfin dma_alloc_coherent(). | ||
147 | * The real dma handler is the return value of dma_alloc_coherent(). | ||
148 | */ | ||
149 | dma_addr_t dma_handle; | ||
150 | #endif | ||
151 | |||
152 | tx_desc = bfin_mac_alloc(&dma_handle, | ||
153 | sizeof(struct net_dma_desc_tx) * | ||
154 | CONFIG_BFIN_TX_DESC_NUM); | ||
155 | if (tx_desc == NULL) | ||
156 | goto init_error; | ||
157 | |||
158 | rx_desc = bfin_mac_alloc(&dma_handle, | ||
159 | sizeof(struct net_dma_desc_rx) * | ||
160 | CONFIG_BFIN_RX_DESC_NUM); | ||
161 | if (rx_desc == NULL) | ||
162 | goto init_error; | ||
163 | |||
164 | /* init tx_list */ | ||
165 | tx_list_head = tx_list_tail = tx_desc; | ||
166 | |||
167 | for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) { | ||
168 | struct net_dma_desc_tx *t = tx_desc + i; | ||
169 | struct dma_descriptor *a = &(t->desc_a); | ||
170 | struct dma_descriptor *b = &(t->desc_b); | ||
171 | |||
172 | /* | ||
173 | * disable DMA | ||
174 | * read from memory WNR = 0 | ||
175 | * wordsize is 32 bits | ||
176 | * 6 half words is desc size | ||
177 | * large desc flow | ||
178 | */ | ||
179 | a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE; | ||
180 | a->start_addr = (unsigned long)t->packet; | ||
181 | a->x_count = 0; | ||
182 | a->next_dma_desc = b; | ||
183 | |||
184 | /* | ||
185 | * enabled DMA | ||
186 | * write to memory WNR = 1 | ||
187 | * wordsize is 32 bits | ||
188 | * disable interrupt | ||
189 | * 6 half words is desc size | ||
190 | * large desc flow | ||
191 | */ | ||
192 | b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE; | ||
193 | b->start_addr = (unsigned long)(&(t->status)); | ||
194 | b->x_count = 0; | ||
195 | |||
196 | t->skb = NULL; | ||
197 | tx_list_tail->desc_b.next_dma_desc = a; | ||
198 | tx_list_tail->next = t; | ||
199 | tx_list_tail = t; | ||
200 | } | ||
201 | tx_list_tail->next = tx_list_head; /* tx_list is a circle */ | ||
202 | tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a); | ||
203 | current_tx_ptr = tx_list_head; | ||
204 | |||
205 | /* init rx_list */ | ||
206 | rx_list_head = rx_list_tail = rx_desc; | ||
207 | |||
208 | for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) { | ||
209 | struct net_dma_desc_rx *r = rx_desc + i; | ||
210 | struct dma_descriptor *a = &(r->desc_a); | ||
211 | struct dma_descriptor *b = &(r->desc_b); | ||
212 | |||
213 | /* allocate a new skb for next time receive */ | ||
214 | new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); | ||
215 | if (!new_skb) { | ||
216 | printk(KERN_NOTICE DRV_NAME | ||
217 | ": init: low on mem - packet dropped\n"); | ||
218 | goto init_error; | ||
219 | } | ||
220 | skb_reserve(new_skb, 2); | ||
221 | r->skb = new_skb; | ||
222 | |||
223 | /* | ||
224 | * enabled DMA | ||
225 | * write to memory WNR = 1 | ||
226 | * wordsize is 32 bits | ||
227 | * disable interrupt | ||
228 | * 6 half words is desc size | ||
229 | * large desc flow | ||
230 | */ | ||
231 | a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE; | ||
232 | /* since RXDWA is enabled */ | ||
233 | a->start_addr = (unsigned long)new_skb->data - 2; | ||
234 | a->x_count = 0; | ||
235 | a->next_dma_desc = b; | ||
236 | |||
237 | /* | ||
238 | * enabled DMA | ||
239 | * write to memory WNR = 1 | ||
240 | * wordsize is 32 bits | ||
241 | * enable interrupt | ||
242 | * 6 half words is desc size | ||
243 | * large desc flow | ||
244 | */ | ||
245 | b->config = DMAEN | WNR | WDSIZE_32 | DI_EN | | ||
246 | NDSIZE_6 | DMAFLOW_LARGE; | ||
247 | b->start_addr = (unsigned long)(&(r->status)); | ||
248 | b->x_count = 0; | ||
249 | |||
250 | rx_list_tail->desc_b.next_dma_desc = a; | ||
251 | rx_list_tail->next = r; | ||
252 | rx_list_tail = r; | ||
253 | } | ||
254 | rx_list_tail->next = rx_list_head; /* rx_list is a circle */ | ||
255 | rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a); | ||
256 | current_rx_ptr = rx_list_head; | ||
257 | |||
258 | return 0; | ||
259 | |||
260 | init_error: | ||
261 | desc_list_free(); | ||
262 | printk(KERN_ERR DRV_NAME ": kmalloc failed\n"); | ||
263 | return -ENOMEM; | ||
264 | } | ||
265 | |||
266 | |||
267 | /*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ | ||
268 | |||
269 | /* Set FER regs to MUX in Ethernet pins */ | ||
270 | static int setup_pin_mux(int action) | ||
271 | { | ||
272 | #if defined(CONFIG_BFIN_MAC_RMII) | ||
273 | u16 pin_req[] = P_RMII0; | ||
274 | #else | ||
275 | u16 pin_req[] = P_MII0; | ||
276 | #endif | ||
277 | |||
278 | if (action) { | ||
279 | if (peripheral_request_list(pin_req, DRV_NAME)) { | ||
280 | printk(KERN_ERR DRV_NAME | ||
281 | ": Requesting Peripherals failed\n"); | ||
282 | return -EFAULT; | ||
283 | } | ||
284 | } else | ||
285 | peripheral_free_list(pin_req); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* Wait until the previous MDC/MDIO transaction has completed */ | ||
291 | static void poll_mdc_done(void) | ||
292 | { | ||
293 | int timeout_cnt = MAX_TIMEOUT_CNT; | ||
294 | |||
295 | /* poll the STABUSY bit */ | ||
296 | while ((bfin_read_EMAC_STAADD()) & STABUSY) { | ||
297 | mdelay(10); | ||
298 | if (timeout_cnt-- < 0) { | ||
299 | printk(KERN_ERR DRV_NAME | ||
300 | ": wait MDC/MDIO transaction to complete timeout\n"); | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* Read an off-chip register in a PHY through the MDC/MDIO port */ | ||
307 | static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr) | ||
308 | { | ||
309 | poll_mdc_done(); | ||
310 | /* read mode */ | ||
311 | bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | | ||
312 | SET_REGAD(RegAddr) | | ||
313 | STABUSY); | ||
314 | poll_mdc_done(); | ||
315 | |||
316 | return (u16) bfin_read_EMAC_STADAT(); | ||
317 | } | ||
318 | |||
319 | /* Write an off-chip register in a PHY through the MDC/MDIO port */ | ||
320 | static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) | ||
321 | { | ||
322 | bfin_write_EMAC_STADAT(Data); | ||
323 | |||
324 | /* write mode */ | ||
325 | bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | | ||
326 | SET_REGAD(RegAddr) | | ||
327 | STAOP | | ||
328 | STABUSY); | ||
329 | |||
330 | poll_mdc_done(); | ||
331 | } | ||
332 | |||
333 | static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) | ||
334 | { | ||
335 | poll_mdc_done(); | ||
336 | raw_write_phy_reg(PHYAddr, RegAddr, Data); | ||
337 | } | ||
338 | |||
339 | /* set up the phy */ | ||
340 | static void bf537mac_setphy(struct net_device *dev) | ||
341 | { | ||
342 | u16 phydat; | ||
343 | struct bf537mac_local *lp = netdev_priv(dev); | ||
344 | |||
345 | /* Program PHY registers */ | ||
346 | pr_debug("start setting up phy\n"); | ||
347 | |||
348 | /* issue a reset */ | ||
349 | raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000); | ||
350 | |||
351 | /* wait half a second */ | ||
352 | msleep(500); | ||
353 | |||
354 | phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); | ||
355 | |||
356 | /* advertise flow control supported */ | ||
357 | phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR); | ||
358 | phydat |= (1 << 10); | ||
359 | write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat); | ||
360 | |||
361 | phydat = 0; | ||
362 | if (lp->Negotiate) | ||
363 | phydat |= 0x1000; /* enable auto negotiation */ | ||
364 | else { | ||
365 | if (lp->FullDuplex) | ||
366 | phydat |= (1 << 8); /* full duplex */ | ||
367 | else | ||
368 | phydat &= (~(1 << 8)); /* half duplex */ | ||
369 | |||
370 | if (!lp->Port10) | ||
371 | phydat |= (1 << 13); /* 100 Mbps */ | ||
372 | else | ||
373 | phydat &= (~(1 << 13)); /* 10 Mbps */ | ||
374 | } | ||
375 | |||
376 | if (lp->Loopback) | ||
377 | phydat |= (1 << 14); /* enable TX->RX loopback */ | ||
378 | |||
379 | write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat); | ||
380 | msleep(500); | ||
381 | |||
382 | phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); | ||
383 | /* check for SMSC PHY */ | ||
384 | if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) && | ||
385 | ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) { | ||
386 | /* | ||
387 | * we have SMSC PHY so reqest interrupt | ||
388 | * on link down condition | ||
389 | */ | ||
390 | |||
391 | /* enable interrupts */ | ||
392 | write_phy_reg(lp->PhyAddr, 30, 0x0ff); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | /**************************************************************************/ | ||
397 | void setup_system_regs(struct net_device *dev) | ||
398 | { | ||
399 | int phyaddr; | ||
400 | unsigned short sysctl, phydat; | ||
401 | u32 opmode; | ||
402 | struct bf537mac_local *lp = netdev_priv(dev); | ||
403 | int count = 0; | ||
404 | |||
405 | phyaddr = lp->PhyAddr; | ||
406 | |||
407 | /* Enable PHY output */ | ||
408 | if (!(bfin_read_VR_CTL() & PHYCLKOE)) | ||
409 | bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); | ||
410 | |||
411 | /* MDC = 2.5 MHz */ | ||
412 | sysctl = SET_MDCDIV(24); | ||
413 | /* Odd word alignment for Receive Frame DMA word */ | ||
414 | /* Configure checksum support and rcve frame word alignment */ | ||
415 | #if defined(BFIN_MAC_CSUM_OFFLOAD) | ||
416 | sysctl |= RXDWA | RXCKS; | ||
417 | #else | ||
418 | sysctl |= RXDWA; | ||
419 | #endif | ||
420 | bfin_write_EMAC_SYSCTL(sysctl); | ||
421 | /* auto negotiation on */ | ||
422 | /* full duplex */ | ||
423 | /* 100 Mbps */ | ||
424 | phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; | ||
425 | write_phy_reg(phyaddr, PHYREG_MODECTL, phydat); | ||
426 | |||
427 | /* test if full duplex supported */ | ||
428 | do { | ||
429 | msleep(100); | ||
430 | phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT); | ||
431 | if (count > 30) { | ||
432 | printk(KERN_NOTICE DRV_NAME ": Link is down\n"); | ||
433 | printk(KERN_NOTICE DRV_NAME | ||
434 | "please check your network connection\n"); | ||
435 | break; | ||
436 | } | ||
437 | count++; | ||
438 | } while (!(phydat & 0x0004)); | ||
439 | |||
440 | phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR); | ||
441 | |||
442 | if ((phydat & 0x0100) || (phydat & 0x0040)) { | ||
443 | opmode = FDMODE; | ||
444 | } else { | ||
445 | opmode = 0; | ||
446 | printk(KERN_INFO DRV_NAME | ||
447 | ": Network is set to half duplex\n"); | ||
448 | } | ||
449 | |||
450 | #if defined(CONFIG_BFIN_MAC_RMII) | ||
451 | opmode |= RMII; /* For Now only 100MBit are supported */ | ||
452 | #endif | ||
453 | |||
454 | bfin_write_EMAC_OPMODE(opmode); | ||
455 | |||
456 | bfin_write_EMAC_MMC_CTL(RSTC | CROLL); | ||
457 | |||
458 | /* Initialize the TX DMA channel registers */ | ||
459 | bfin_write_DMA2_X_COUNT(0); | ||
460 | bfin_write_DMA2_X_MODIFY(4); | ||
461 | bfin_write_DMA2_Y_COUNT(0); | ||
462 | bfin_write_DMA2_Y_MODIFY(0); | ||
463 | |||
464 | /* Initialize the RX DMA channel registers */ | ||
465 | bfin_write_DMA1_X_COUNT(0); | ||
466 | bfin_write_DMA1_X_MODIFY(4); | ||
467 | bfin_write_DMA1_Y_COUNT(0); | ||
468 | bfin_write_DMA1_Y_MODIFY(0); | ||
469 | } | ||
470 | |||
471 | void setup_mac_addr(u8 * mac_addr) | ||
472 | { | ||
473 | u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]); | ||
474 | u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]); | ||
475 | |||
476 | /* this depends on a little-endian machine */ | ||
477 | bfin_write_EMAC_ADDRLO(addr_low); | ||
478 | bfin_write_EMAC_ADDRHI(addr_hi); | ||
479 | } | ||
480 | |||
481 | static void adjust_tx_list(void) | ||
482 | { | ||
483 | int timeout_cnt = MAX_TIMEOUT_CNT; | ||
484 | |||
485 | if (tx_list_head->status.status_word != 0 | ||
486 | && current_tx_ptr != tx_list_head) { | ||
487 | goto adjust_head; /* released something, just return; */ | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * if nothing released, check wait condition | ||
492 | * current's next can not be the head, | ||
493 | * otherwise the dma will not stop as we want | ||
494 | */ | ||
495 | if (current_tx_ptr->next->next == tx_list_head) { | ||
496 | while (tx_list_head->status.status_word == 0) { | ||
497 | mdelay(10); | ||
498 | if (tx_list_head->status.status_word != 0 | ||
499 | || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) { | ||
500 | goto adjust_head; | ||
501 | } | ||
502 | if (timeout_cnt-- < 0) { | ||
503 | printk(KERN_ERR DRV_NAME | ||
504 | ": wait for adjust tx list head timeout\n"); | ||
505 | break; | ||
506 | } | ||
507 | } | ||
508 | if (tx_list_head->status.status_word != 0) { | ||
509 | goto adjust_head; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | return; | ||
514 | |||
515 | adjust_head: | ||
516 | do { | ||
517 | tx_list_head->desc_a.config &= ~DMAEN; | ||
518 | tx_list_head->status.status_word = 0; | ||
519 | if (tx_list_head->skb) { | ||
520 | dev_kfree_skb(tx_list_head->skb); | ||
521 | tx_list_head->skb = NULL; | ||
522 | } else { | ||
523 | printk(KERN_ERR DRV_NAME | ||
524 | ": no sk_buff in a transmitted frame!\n"); | ||
525 | } | ||
526 | tx_list_head = tx_list_head->next; | ||
527 | } while (tx_list_head->status.status_word != 0 | ||
528 | && current_tx_ptr != tx_list_head); | ||
529 | return; | ||
530 | |||
531 | } | ||
532 | |||
533 | static int bf537mac_hard_start_xmit(struct sk_buff *skb, | ||
534 | struct net_device *dev) | ||
535 | { | ||
536 | struct bf537mac_local *lp = netdev_priv(dev); | ||
537 | unsigned int data; | ||
538 | |||
539 | current_tx_ptr->skb = skb; | ||
540 | |||
541 | /* | ||
542 | * Is skb->data always 16-bit aligned? | ||
543 | * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)? | ||
544 | */ | ||
545 | if ((((unsigned int)(skb->data)) & 0x02) == 2) { | ||
546 | /* move skb->data to current_tx_ptr payload */ | ||
547 | data = (unsigned int)(skb->data) - 2; | ||
548 | *((unsigned short *)data) = (unsigned short)(skb->len); | ||
549 | current_tx_ptr->desc_a.start_addr = (unsigned long)data; | ||
550 | /* this is important! */ | ||
551 | blackfin_dcache_flush_range(data, (data + (skb->len)) + 2); | ||
552 | |||
553 | } else { | ||
554 | *((unsigned short *)(current_tx_ptr->packet)) = | ||
555 | (unsigned short)(skb->len); | ||
556 | memcpy((char *)(current_tx_ptr->packet + 2), skb->data, | ||
557 | (skb->len)); | ||
558 | current_tx_ptr->desc_a.start_addr = | ||
559 | (unsigned long)current_tx_ptr->packet; | ||
560 | if (current_tx_ptr->status.status_word != 0) | ||
561 | current_tx_ptr->status.status_word = 0; | ||
562 | blackfin_dcache_flush_range((unsigned int)current_tx_ptr-> | ||
563 | packet, | ||
564 | (unsigned int)(current_tx_ptr-> | ||
565 | packet + skb->len) + | ||
566 | 2); | ||
567 | } | ||
568 | |||
569 | /* enable this packet's dma */ | ||
570 | current_tx_ptr->desc_a.config |= DMAEN; | ||
571 | |||
572 | /* tx dma is running, just return */ | ||
573 | if (bfin_read_DMA2_IRQ_STATUS() & 0x08) | ||
574 | goto out; | ||
575 | |||
576 | /* tx dma is not running */ | ||
577 | bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a)); | ||
578 | /* dma enabled, read from memory, size is 6 */ | ||
579 | bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config); | ||
580 | /* Turn on the EMAC tx */ | ||
581 | bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); | ||
582 | |||
583 | out: | ||
584 | adjust_tx_list(); | ||
585 | current_tx_ptr = current_tx_ptr->next; | ||
586 | dev->trans_start = jiffies; | ||
587 | lp->stats.tx_packets++; | ||
588 | lp->stats.tx_bytes += (skb->len); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static void bf537mac_rx(struct net_device *dev) | ||
593 | { | ||
594 | struct sk_buff *skb, *new_skb; | ||
595 | struct bf537mac_local *lp = netdev_priv(dev); | ||
596 | unsigned short len; | ||
597 | |||
598 | /* allocate a new skb for next time receive */ | ||
599 | skb = current_rx_ptr->skb; | ||
600 | new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); | ||
601 | if (!new_skb) { | ||
602 | printk(KERN_NOTICE DRV_NAME | ||
603 | ": rx: low on mem - packet dropped\n"); | ||
604 | lp->stats.rx_dropped++; | ||
605 | goto out; | ||
606 | } | ||
607 | /* reserve 2 bytes for RXDWA padding */ | ||
608 | skb_reserve(new_skb, 2); | ||
609 | current_rx_ptr->skb = new_skb; | ||
610 | current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; | ||
611 | |||
612 | len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN); | ||
613 | skb_put(skb, len); | ||
614 | blackfin_dcache_invalidate_range((unsigned long)skb->head, | ||
615 | (unsigned long)skb->tail); | ||
616 | |||
617 | dev->last_rx = jiffies; | ||
618 | skb->dev = dev; | ||
619 | skb->protocol = eth_type_trans(skb, dev); | ||
620 | #if defined(BFIN_MAC_CSUM_OFFLOAD) | ||
621 | skb->csum = current_rx_ptr->status.ip_payload_csum; | ||
622 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
623 | #endif | ||
624 | |||
625 | netif_rx(skb); | ||
626 | lp->stats.rx_packets++; | ||
627 | lp->stats.rx_bytes += len; | ||
628 | current_rx_ptr->status.status_word = 0x00000000; | ||
629 | current_rx_ptr = current_rx_ptr->next; | ||
630 | |||
631 | out: | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | /* interrupt routine to handle rx and error signal */ | ||
636 | static irqreturn_t bf537mac_interrupt(int irq, void *dev_id) | ||
637 | { | ||
638 | struct net_device *dev = dev_id; | ||
639 | int number = 0; | ||
640 | |||
641 | get_one_packet: | ||
642 | if (current_rx_ptr->status.status_word == 0) { | ||
643 | /* no more new packet received */ | ||
644 | if (number == 0) { | ||
645 | if (current_rx_ptr->next->status.status_word != 0) { | ||
646 | current_rx_ptr = current_rx_ptr->next; | ||
647 | goto real_rx; | ||
648 | } | ||
649 | } | ||
650 | bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() | | ||
651 | DMA_DONE | DMA_ERR); | ||
652 | return IRQ_HANDLED; | ||
653 | } | ||
654 | |||
655 | real_rx: | ||
656 | bf537mac_rx(dev); | ||
657 | number++; | ||
658 | goto get_one_packet; | ||
659 | } | ||
660 | |||
661 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
662 | static void bf537mac_poll(struct net_device *dev) | ||
663 | { | ||
664 | disable_irq(IRQ_MAC_RX); | ||
665 | bf537mac_interrupt(IRQ_MAC_RX, dev); | ||
666 | enable_irq(IRQ_MAC_RX); | ||
667 | } | ||
668 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | ||
669 | |||
670 | static void bf537mac_reset(void) | ||
671 | { | ||
672 | unsigned int opmode; | ||
673 | |||
674 | opmode = bfin_read_EMAC_OPMODE(); | ||
675 | opmode &= (~RE); | ||
676 | opmode &= (~TE); | ||
677 | /* Turn off the EMAC */ | ||
678 | bfin_write_EMAC_OPMODE(opmode); | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * Enable Interrupts, Receive, and Transmit | ||
683 | */ | ||
684 | static int bf537mac_enable(struct net_device *dev) | ||
685 | { | ||
686 | u32 opmode; | ||
687 | |||
688 | pr_debug("%s: %s\n", dev->name, __FUNCTION__); | ||
689 | |||
690 | /* Set RX DMA */ | ||
691 | bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a)); | ||
692 | bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config); | ||
693 | |||
694 | /* Wait MII done */ | ||
695 | poll_mdc_done(); | ||
696 | |||
697 | /* We enable only RX here */ | ||
698 | /* ASTP : Enable Automatic Pad Stripping | ||
699 | PR : Promiscuous Mode for test | ||
700 | PSF : Receive frames with total length less than 64 bytes. | ||
701 | FDMODE : Full Duplex Mode | ||
702 | LB : Internal Loopback for test | ||
703 | RE : Receiver Enable */ | ||
704 | opmode = bfin_read_EMAC_OPMODE(); | ||
705 | if (opmode & FDMODE) | ||
706 | opmode |= PSF; | ||
707 | else | ||
708 | opmode |= DRO | DC | PSF; | ||
709 | opmode |= RE; | ||
710 | |||
711 | #if defined(CONFIG_BFIN_MAC_RMII) | ||
712 | opmode |= RMII; /* For Now only 100MBit are supported */ | ||
713 | #ifdef CONFIG_BF_REV_0_2 | ||
714 | opmode |= TE; | ||
715 | #endif | ||
716 | #endif | ||
717 | /* Turn on the EMAC rx */ | ||
718 | bfin_write_EMAC_OPMODE(opmode); | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | /* Our watchdog timed out. Called by the networking layer */ | ||
724 | static void bf537mac_timeout(struct net_device *dev) | ||
725 | { | ||
726 | pr_debug("%s: %s\n", dev->name, __FUNCTION__); | ||
727 | |||
728 | bf537mac_reset(); | ||
729 | |||
730 | /* reset tx queue */ | ||
731 | tx_list_tail = tx_list_head->next; | ||
732 | |||
733 | bf537mac_enable(dev); | ||
734 | |||
735 | /* We can accept TX packets again */ | ||
736 | dev->trans_start = jiffies; | ||
737 | netif_wake_queue(dev); | ||
738 | } | ||
739 | |||
740 | /* | ||
741 | * Get the current statistics. | ||
742 | * This may be called with the card open or closed. | ||
743 | */ | ||
744 | static struct net_device_stats *bf537mac_query_statistics(struct net_device | ||
745 | *dev) | ||
746 | { | ||
747 | struct bf537mac_local *lp = netdev_priv(dev); | ||
748 | |||
749 | pr_debug("%s: %s\n", dev->name, __FUNCTION__); | ||
750 | |||
751 | return &lp->stats; | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * This routine will, depending on the values passed to it, | ||
756 | * either make it accept multicast packets, go into | ||
757 | * promiscuous mode (for TCPDUMP and cousins) or accept | ||
758 | * a select set of multicast packets | ||
759 | */ | ||
760 | static void bf537mac_set_multicast_list(struct net_device *dev) | ||
761 | { | ||
762 | u32 sysctl; | ||
763 | |||
764 | if (dev->flags & IFF_PROMISC) { | ||
765 | printk(KERN_INFO "%s: set to promisc mode\n", dev->name); | ||
766 | sysctl = bfin_read_EMAC_OPMODE(); | ||
767 | sysctl |= RAF; | ||
768 | bfin_write_EMAC_OPMODE(sysctl); | ||
769 | } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) { | ||
770 | /* accept all multicast */ | ||
771 | sysctl = bfin_read_EMAC_OPMODE(); | ||
772 | sysctl |= PAM; | ||
773 | bfin_write_EMAC_OPMODE(sysctl); | ||
774 | } else { | ||
775 | /* clear promisc or multicast mode */ | ||
776 | sysctl = bfin_read_EMAC_OPMODE(); | ||
777 | sysctl &= ~(RAF | PAM); | ||
778 | bfin_write_EMAC_OPMODE(sysctl); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /* | ||
783 | * this puts the device in an inactive state | ||
784 | */ | ||
785 | static void bf537mac_shutdown(struct net_device *dev) | ||
786 | { | ||
787 | /* Turn off the EMAC */ | ||
788 | bfin_write_EMAC_OPMODE(0x00000000); | ||
789 | /* Turn off the EMAC RX DMA */ | ||
790 | bfin_write_DMA1_CONFIG(0x0000); | ||
791 | bfin_write_DMA2_CONFIG(0x0000); | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * Open and Initialize the interface | ||
796 | * | ||
797 | * Set up everything, reset the card, etc.. | ||
798 | */ | ||
799 | static int bf537mac_open(struct net_device *dev) | ||
800 | { | ||
801 | pr_debug("%s: %s\n", dev->name, __FUNCTION__); | ||
802 | |||
803 | /* | ||
804 | * Check that the address is valid. If its not, refuse | ||
805 | * to bring the device up. The user must specify an | ||
806 | * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx | ||
807 | */ | ||
808 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
809 | printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n"); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | /* initial rx and tx list */ | ||
814 | desc_list_init(); | ||
815 | |||
816 | bf537mac_setphy(dev); | ||
817 | setup_system_regs(dev); | ||
818 | bf537mac_reset(); | ||
819 | bf537mac_enable(dev); | ||
820 | |||
821 | pr_debug("hardware init finished\n"); | ||
822 | netif_start_queue(dev); | ||
823 | netif_carrier_on(dev); | ||
824 | |||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * | ||
830 | * this makes the board clean up everything that it can | ||
831 | * and not talk to the outside world. Caused by | ||
832 | * an 'ifconfig ethX down' | ||
833 | */ | ||
834 | static int bf537mac_close(struct net_device *dev) | ||
835 | { | ||
836 | pr_debug("%s: %s\n", dev->name, __FUNCTION__); | ||
837 | |||
838 | netif_stop_queue(dev); | ||
839 | netif_carrier_off(dev); | ||
840 | |||
841 | /* clear everything */ | ||
842 | bf537mac_shutdown(dev); | ||
843 | |||
844 | /* free the rx/tx buffers */ | ||
845 | desc_list_free(); | ||
846 | |||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | static int __init bf537mac_probe(struct net_device *dev) | ||
851 | { | ||
852 | struct bf537mac_local *lp = netdev_priv(dev); | ||
853 | int retval; | ||
854 | |||
855 | /* Grab the MAC address in the MAC */ | ||
856 | *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO()); | ||
857 | *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI()); | ||
858 | |||
859 | /* probe mac */ | ||
860 | /*todo: how to proble? which is revision_register */ | ||
861 | bfin_write_EMAC_ADDRLO(0x12345678); | ||
862 | if (bfin_read_EMAC_ADDRLO() != 0x12345678) { | ||
863 | pr_debug("can't detect bf537 mac!\n"); | ||
864 | retval = -ENODEV; | ||
865 | goto err_out; | ||
866 | } | ||
867 | |||
868 | /* set the GPIO pins to Ethernet mode */ | ||
869 | retval = setup_pin_mux(1); | ||
870 | |||
871 | if (retval) | ||
872 | return retval; | ||
873 | |||
874 | /*Is it valid? (Did bootloader initialize it?) */ | ||
875 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
876 | /* Grab the MAC from the board somehow - this is done in the | ||
877 | arch/blackfin/mach-bf537/boards/eth_mac.c */ | ||
878 | get_bf537_ether_addr(dev->dev_addr); | ||
879 | } | ||
880 | |||
881 | /* If still not valid, get a random one */ | ||
882 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
883 | random_ether_addr(dev->dev_addr); | ||
884 | } | ||
885 | |||
886 | setup_mac_addr(dev->dev_addr); | ||
887 | |||
888 | /* Fill in the fields of the device structure with ethernet values. */ | ||
889 | ether_setup(dev); | ||
890 | |||
891 | dev->open = bf537mac_open; | ||
892 | dev->stop = bf537mac_close; | ||
893 | dev->hard_start_xmit = bf537mac_hard_start_xmit; | ||
894 | dev->tx_timeout = bf537mac_timeout; | ||
895 | dev->get_stats = bf537mac_query_statistics; | ||
896 | dev->set_multicast_list = bf537mac_set_multicast_list; | ||
897 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
898 | dev->poll_controller = bf537mac_poll; | ||
899 | #endif | ||
900 | |||
901 | /* fill in some of the fields */ | ||
902 | lp->version = 1; | ||
903 | lp->PhyAddr = 0x01; | ||
904 | lp->CLKIN = 25; | ||
905 | lp->FullDuplex = 0; | ||
906 | lp->Negotiate = 1; | ||
907 | lp->FlowControl = 0; | ||
908 | spin_lock_init(&lp->lock); | ||
909 | |||
910 | /* now, enable interrupts */ | ||
911 | /* register irq handler */ | ||
912 | if (request_irq | ||
913 | (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED, | ||
914 | "BFIN537_MAC_RX", dev)) { | ||
915 | printk(KERN_WARNING DRV_NAME | ||
916 | ": Unable to attach BlackFin MAC RX interrupt\n"); | ||
917 | return -EBUSY; | ||
918 | } | ||
919 | |||
920 | /* Enable PHY output early */ | ||
921 | if (!(bfin_read_VR_CTL() & PHYCLKOE)) | ||
922 | bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); | ||
923 | |||
924 | retval = register_netdev(dev); | ||
925 | if (retval == 0) { | ||
926 | /* now, print out the card info, in a short format.. */ | ||
927 | printk(KERN_INFO "%s: Version %s, %s\n", | ||
928 | DRV_NAME, DRV_VERSION, DRV_DESC); | ||
929 | } | ||
930 | |||
931 | err_out: | ||
932 | return retval; | ||
933 | } | ||
934 | |||
935 | static int bfin_mac_probe(struct platform_device *pdev) | ||
936 | { | ||
937 | struct net_device *ndev; | ||
938 | |||
939 | ndev = alloc_etherdev(sizeof(struct bf537mac_local)); | ||
940 | if (!ndev) { | ||
941 | printk(KERN_WARNING DRV_NAME ": could not allocate device\n"); | ||
942 | return -ENOMEM; | ||
943 | } | ||
944 | |||
945 | SET_MODULE_OWNER(ndev); | ||
946 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
947 | |||
948 | platform_set_drvdata(pdev, ndev); | ||
949 | |||
950 | if (bf537mac_probe(ndev) != 0) { | ||
951 | platform_set_drvdata(pdev, NULL); | ||
952 | free_netdev(ndev); | ||
953 | printk(KERN_WARNING DRV_NAME ": not found\n"); | ||
954 | return -ENODEV; | ||
955 | } | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int bfin_mac_remove(struct platform_device *pdev) | ||
961 | { | ||
962 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
963 | |||
964 | platform_set_drvdata(pdev, NULL); | ||
965 | |||
966 | unregister_netdev(ndev); | ||
967 | |||
968 | free_irq(IRQ_MAC_RX, ndev); | ||
969 | |||
970 | free_netdev(ndev); | ||
971 | |||
972 | setup_pin_mux(0); | ||
973 | |||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state) | ||
978 | { | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int bfin_mac_resume(struct platform_device *pdev) | ||
983 | { | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static struct platform_driver bfin_mac_driver = { | ||
988 | .probe = bfin_mac_probe, | ||
989 | .remove = bfin_mac_remove, | ||
990 | .resume = bfin_mac_resume, | ||
991 | .suspend = bfin_mac_suspend, | ||
992 | .driver = { | ||
993 | .name = DRV_NAME, | ||
994 | }, | ||
995 | }; | ||
996 | |||
997 | static int __init bfin_mac_init(void) | ||
998 | { | ||
999 | return platform_driver_register(&bfin_mac_driver); | ||
1000 | } | ||
1001 | |||
1002 | module_init(bfin_mac_init); | ||
1003 | |||
1004 | static void __exit bfin_mac_cleanup(void) | ||
1005 | { | ||
1006 | platform_driver_unregister(&bfin_mac_driver); | ||
1007 | } | ||
1008 | |||
1009 | module_exit(bfin_mac_cleanup); | ||
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h new file mode 100644 index 000000000000..af87189b85fa --- /dev/null +++ b/drivers/net/bfin_mac.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * File: drivers/net/bfin_mac.c | ||
3 | * Based on: | ||
4 | * Maintainer: | ||
5 | * Bryan Wu <bryan.wu@analog.com> | ||
6 | * | ||
7 | * Original author: | ||
8 | * Luke Yang <luke.yang@analog.com> | ||
9 | * | ||
10 | * Created: | ||
11 | * Description: | ||
12 | * | ||
13 | * Modified: | ||
14 | * Copyright 2004-2006 Analog Devices Inc. | ||
15 | * | ||
16 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
17 | * | ||
18 | * This program is free software ; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation ; either version 2, or (at your option) | ||
21 | * any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY ; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program ; see the file COPYING. | ||
30 | * If not, write to the Free Software Foundation, | ||
31 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
32 | */ | ||
33 | |||
34 | /* | ||
35 | * PHY REGISTER NAMES | ||
36 | */ | ||
37 | #define PHYREG_MODECTL 0x0000 | ||
38 | #define PHYREG_MODESTAT 0x0001 | ||
39 | #define PHYREG_PHYID1 0x0002 | ||
40 | #define PHYREG_PHYID2 0x0003 | ||
41 | #define PHYREG_ANAR 0x0004 | ||
42 | #define PHYREG_ANLPAR 0x0005 | ||
43 | #define PHYREG_ANER 0x0006 | ||
44 | #define PHYREG_NSR 0x0010 | ||
45 | #define PHYREG_LBREMR 0x0011 | ||
46 | #define PHYREG_REC 0x0012 | ||
47 | #define PHYREG_10CFG 0x0013 | ||
48 | #define PHYREG_PHY1_1 0x0014 | ||
49 | #define PHYREG_PHY1_2 0x0015 | ||
50 | #define PHYREG_PHY2 0x0016 | ||
51 | #define PHYREG_TW_1 0x0017 | ||
52 | #define PHYREG_TW_2 0x0018 | ||
53 | #define PHYREG_TEST 0x0019 | ||
54 | |||
55 | #define PHY_RESET 0x8000 | ||
56 | #define PHY_ANEG_EN 0x1000 | ||
57 | #define PHY_DUPLEX 0x0100 | ||
58 | #define PHY_SPD_SET 0x2000 | ||
59 | |||
60 | #define BFIN_MAC_CSUM_OFFLOAD | ||
61 | |||
62 | struct dma_descriptor { | ||
63 | struct dma_descriptor *next_dma_desc; | ||
64 | unsigned long start_addr; | ||
65 | unsigned short config; | ||
66 | unsigned short x_count; | ||
67 | }; | ||
68 | |||
69 | struct status_area_rx { | ||
70 | #if defined(BFIN_MAC_CSUM_OFFLOAD) | ||
71 | unsigned short ip_hdr_csum; /* ip header checksum */ | ||
72 | /* ip payload(udp or tcp or others) checksum */ | ||
73 | unsigned short ip_payload_csum; | ||
74 | #endif | ||
75 | unsigned long status_word; /* the frame status word */ | ||
76 | }; | ||
77 | |||
78 | struct status_area_tx { | ||
79 | unsigned long status_word; /* the frame status word */ | ||
80 | }; | ||
81 | |||
82 | /* use two descriptors for a packet */ | ||
83 | struct net_dma_desc_rx { | ||
84 | struct net_dma_desc_rx *next; | ||
85 | struct sk_buff *skb; | ||
86 | struct dma_descriptor desc_a; | ||
87 | struct dma_descriptor desc_b; | ||
88 | struct status_area_rx status; | ||
89 | }; | ||
90 | |||
91 | /* use two descriptors for a packet */ | ||
92 | struct net_dma_desc_tx { | ||
93 | struct net_dma_desc_tx *next; | ||
94 | struct sk_buff *skb; | ||
95 | struct dma_descriptor desc_a; | ||
96 | struct dma_descriptor desc_b; | ||
97 | unsigned char packet[1560]; | ||
98 | struct status_area_tx status; | ||
99 | }; | ||
100 | |||
101 | struct bf537mac_local { | ||
102 | /* | ||
103 | * these are things that the kernel wants me to keep, so users | ||
104 | * can find out semi-useless statistics of how well the card is | ||
105 | * performing | ||
106 | */ | ||
107 | struct net_device_stats stats; | ||
108 | |||
109 | int version; | ||
110 | |||
111 | int FlowEnabled; /* record if data flow is active */ | ||
112 | int EtherIntIVG; /* IVG for the ethernet interrupt */ | ||
113 | int RXIVG; /* IVG for the RX completion */ | ||
114 | int TXIVG; /* IVG for the TX completion */ | ||
115 | int PhyAddr; /* PHY address */ | ||
116 | int OpMode; /* set these bits n the OPMODE regs */ | ||
117 | int Port10; /* set port speed to 10 Mbit/s */ | ||
118 | int GenChksums; /* IP checksums to be calculated */ | ||
119 | int NoRcveLnth; /* dont insert recv length at start of buffer */ | ||
120 | int StripPads; /* remove trailing pad bytes */ | ||
121 | int FullDuplex; /* set full duplex mode */ | ||
122 | int Negotiate; /* enable auto negotiation */ | ||
123 | int Loopback; /* loopback at the PHY */ | ||
124 | int Cache; /* Buffers may be cached */ | ||
125 | int FlowControl; /* flow control active */ | ||
126 | int CLKIN; /* clock in value in MHZ */ | ||
127 | unsigned short IntMask; /* interrupt mask */ | ||
128 | unsigned char Mac[6]; /* MAC address of the board */ | ||
129 | spinlock_t lock; | ||
130 | }; | ||
131 | |||
132 | extern void get_bf537_ether_addr(char *addr); | ||
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c index 7845eaf6f29f..202d4a4ef751 100644 --- a/drivers/net/bsd_comp.c +++ b/drivers/net/bsd_comp.c | |||
@@ -395,14 +395,13 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) | |||
395 | * Allocate the main control structure for this instance. | 395 | * Allocate the main control structure for this instance. |
396 | */ | 396 | */ |
397 | maxmaxcode = MAXCODE(bits); | 397 | maxmaxcode = MAXCODE(bits); |
398 | db = kmalloc(sizeof (struct bsd_db), | 398 | db = kzalloc(sizeof (struct bsd_db), |
399 | GFP_KERNEL); | 399 | GFP_KERNEL); |
400 | if (!db) | 400 | if (!db) |
401 | { | 401 | { |
402 | return NULL; | 402 | return NULL; |
403 | } | 403 | } |
404 | 404 | ||
405 | memset (db, 0, sizeof(struct bsd_db)); | ||
406 | /* | 405 | /* |
407 | * Allocate space for the dictionary. This may be more than one page in | 406 | * Allocate space for the dictionary. This may be more than one page in |
408 | * length. | 407 | * length. |
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 6628fa622e2c..489c8b260dd8 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | 40 | ||
41 | #define DRV_NAME "ehea" | 41 | #define DRV_NAME "ehea" |
42 | #define DRV_VERSION "EHEA_0070" | 42 | #define DRV_VERSION "EHEA_0071" |
43 | 43 | ||
44 | /* eHEA capability flags */ | 44 | /* eHEA capability flags */ |
45 | #define DLPAR_PORT_ADD_REM 1 | 45 | #define DLPAR_PORT_ADD_REM 1 |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 1d1571cf322e..4c70a9301c1b 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -466,6 +466,8 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, | |||
466 | cqe->vlan_tag); | 466 | cqe->vlan_tag); |
467 | else | 467 | else |
468 | netif_receive_skb(skb); | 468 | netif_receive_skb(skb); |
469 | |||
470 | dev->last_rx = jiffies; | ||
469 | } else { | 471 | } else { |
470 | pr->p_stats.poll_receive_errors++; | 472 | pr->p_stats.poll_receive_errors++; |
471 | port_reset = ehea_treat_poll_error(pr, rq, cqe, | 473 | port_reset = ehea_treat_poll_error(pr, rq, cqe, |
@@ -1433,7 +1435,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid) | |||
1433 | port->logical_port_id, | 1435 | port->logical_port_id, |
1434 | reg_type, port->mac_addr, 0, hcallid); | 1436 | reg_type, port->mac_addr, 0, hcallid); |
1435 | if (hret != H_SUCCESS) { | 1437 | if (hret != H_SUCCESS) { |
1436 | ehea_error("reg_dereg_bcmc failed (tagged)"); | 1438 | ehea_error("%sregistering bc address failed (tagged)", |
1439 | hcallid == H_REG_BCMC ? "" : "de"); | ||
1437 | ret = -EIO; | 1440 | ret = -EIO; |
1438 | goto out_herr; | 1441 | goto out_herr; |
1439 | } | 1442 | } |
@@ -1444,7 +1447,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid) | |||
1444 | port->logical_port_id, | 1447 | port->logical_port_id, |
1445 | reg_type, port->mac_addr, 0, hcallid); | 1448 | reg_type, port->mac_addr, 0, hcallid); |
1446 | if (hret != H_SUCCESS) { | 1449 | if (hret != H_SUCCESS) { |
1447 | ehea_error("reg_dereg_bcmc failed (vlan)"); | 1450 | ehea_error("%sregistering bc address failed (vlan)", |
1451 | hcallid == H_REG_BCMC ? "" : "de"); | ||
1448 | ret = -EIO; | 1452 | ret = -EIO; |
1449 | } | 1453 | } |
1450 | out_herr: | 1454 | out_herr: |
@@ -2170,7 +2174,6 @@ static int ehea_up(struct net_device *dev) | |||
2170 | { | 2174 | { |
2171 | int ret, i; | 2175 | int ret, i; |
2172 | struct ehea_port *port = netdev_priv(dev); | 2176 | struct ehea_port *port = netdev_priv(dev); |
2173 | u64 mac_addr = 0; | ||
2174 | 2177 | ||
2175 | if (port->state == EHEA_PORT_UP) | 2178 | if (port->state == EHEA_PORT_UP) |
2176 | return 0; | 2179 | return 0; |
@@ -2189,18 +2192,10 @@ static int ehea_up(struct net_device *dev) | |||
2189 | goto out_clean_pr; | 2192 | goto out_clean_pr; |
2190 | } | 2193 | } |
2191 | 2194 | ||
2192 | ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); | ||
2193 | if (ret) { | ||
2194 | ret = -EIO; | ||
2195 | ehea_error("out_clean_pr"); | ||
2196 | goto out_clean_pr; | ||
2197 | } | ||
2198 | mac_addr = (*(u64*)dev->dev_addr) >> 16; | ||
2199 | |||
2200 | ret = ehea_reg_interrupts(dev); | 2195 | ret = ehea_reg_interrupts(dev); |
2201 | if (ret) { | 2196 | if (ret) { |
2202 | ehea_error("out_dereg_bc"); | 2197 | ehea_error("reg_interrupts failed. ret:%d", ret); |
2203 | goto out_dereg_bc; | 2198 | goto out_clean_pr; |
2204 | } | 2199 | } |
2205 | 2200 | ||
2206 | for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { | 2201 | for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { |
@@ -2226,9 +2221,6 @@ static int ehea_up(struct net_device *dev) | |||
2226 | out_free_irqs: | 2221 | out_free_irqs: |
2227 | ehea_free_interrupts(dev); | 2222 | ehea_free_interrupts(dev); |
2228 | 2223 | ||
2229 | out_dereg_bc: | ||
2230 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); | ||
2231 | |||
2232 | out_clean_pr: | 2224 | out_clean_pr: |
2233 | ehea_clean_all_portres(port); | 2225 | ehea_clean_all_portres(port); |
2234 | out: | 2226 | out: |
@@ -2273,7 +2265,6 @@ static int ehea_down(struct net_device *dev) | |||
2273 | &port->port_res[i].d_netdev->state)) | 2265 | &port->port_res[i].d_netdev->state)) |
2274 | msleep(1); | 2266 | msleep(1); |
2275 | 2267 | ||
2276 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); | ||
2277 | port->state = EHEA_PORT_DOWN; | 2268 | port->state = EHEA_PORT_DOWN; |
2278 | 2269 | ||
2279 | ret = ehea_clean_all_portres(port); | 2270 | ret = ehea_clean_all_portres(port); |
@@ -2655,12 +2646,18 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | |||
2655 | 2646 | ||
2656 | INIT_WORK(&port->reset_task, ehea_reset_port); | 2647 | INIT_WORK(&port->reset_task, ehea_reset_port); |
2657 | 2648 | ||
2649 | ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); | ||
2650 | if (ret) { | ||
2651 | ret = -EIO; | ||
2652 | goto out_unreg_port; | ||
2653 | } | ||
2654 | |||
2658 | ehea_set_ethtool_ops(dev); | 2655 | ehea_set_ethtool_ops(dev); |
2659 | 2656 | ||
2660 | ret = register_netdev(dev); | 2657 | ret = register_netdev(dev); |
2661 | if (ret) { | 2658 | if (ret) { |
2662 | ehea_error("register_netdev failed. ret=%d", ret); | 2659 | ehea_error("register_netdev failed. ret=%d", ret); |
2663 | goto out_unreg_port; | 2660 | goto out_dereg_bc; |
2664 | } | 2661 | } |
2665 | 2662 | ||
2666 | ret = ehea_get_jumboframe_status(port, &jumbo); | 2663 | ret = ehea_get_jumboframe_status(port, &jumbo); |
@@ -2675,6 +2672,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | |||
2675 | 2672 | ||
2676 | return port; | 2673 | return port; |
2677 | 2674 | ||
2675 | out_dereg_bc: | ||
2676 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); | ||
2677 | |||
2678 | out_unreg_port: | 2678 | out_unreg_port: |
2679 | ehea_unregister_port(port); | 2679 | ehea_unregister_port(port); |
2680 | 2680 | ||
@@ -2694,6 +2694,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port) | |||
2694 | { | 2694 | { |
2695 | unregister_netdev(port->netdev); | 2695 | unregister_netdev(port->netdev); |
2696 | ehea_unregister_port(port); | 2696 | ehea_unregister_port(port); |
2697 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); | ||
2697 | kfree(port->mc_list); | 2698 | kfree(port->mc_list); |
2698 | free_netdev(port->netdev); | 2699 | free_netdev(port->netdev); |
2699 | port->adapter->active_ports--; | 2700 | port->adapter->active_ports--; |
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 136827f8dc2e..6d1d50a19783 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -5137,12 +5137,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5137 | goto out_unmap; | 5137 | goto out_unmap; |
5138 | np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; | 5138 | np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; |
5139 | } | 5139 | } |
5140 | np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL); | 5140 | np->rx_skb = kcalloc(np->rx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL); |
5141 | np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL); | 5141 | np->tx_skb = kcalloc(np->tx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL); |
5142 | if (!np->rx_skb || !np->tx_skb) | 5142 | if (!np->rx_skb || !np->tx_skb) |
5143 | goto out_freering; | 5143 | goto out_freering; |
5144 | memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size); | ||
5145 | memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size); | ||
5146 | 5144 | ||
5147 | dev->open = nv_open; | 5145 | dev->open = nv_open; |
5148 | dev->stop = nv_close; | 5146 | dev->stop = nv_close; |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index d7a1a58de766..f92690555dd9 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -420,8 +420,18 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) | |||
420 | if (ecntrl & ECNTRL_REDUCED_MODE) { | 420 | if (ecntrl & ECNTRL_REDUCED_MODE) { |
421 | if (ecntrl & ECNTRL_REDUCED_MII_MODE) | 421 | if (ecntrl & ECNTRL_REDUCED_MII_MODE) |
422 | return PHY_INTERFACE_MODE_RMII; | 422 | return PHY_INTERFACE_MODE_RMII; |
423 | else | 423 | else { |
424 | phy_interface_t interface = priv->einfo->interface; | ||
425 | |||
426 | /* | ||
427 | * This isn't autodetected right now, so it must | ||
428 | * be set by the device tree or platform code. | ||
429 | */ | ||
430 | if (interface == PHY_INTERFACE_MODE_RGMII_ID) | ||
431 | return PHY_INTERFACE_MODE_RGMII_ID; | ||
432 | |||
424 | return PHY_INTERFACE_MODE_RGMII; | 433 | return PHY_INTERFACE_MODE_RGMII; |
434 | } | ||
425 | } | 435 | } |
426 | 436 | ||
427 | if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) | 437 | if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) |
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 3be8c5047599..205f09672492 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c | |||
@@ -453,8 +453,8 @@ static int __init setup_adapter(int card_base, int type, int n) | |||
453 | int scc_base = card_base + hw[type].scc_offset; | 453 | int scc_base = card_base + hw[type].scc_offset; |
454 | char *chipnames[] = CHIPNAMES; | 454 | char *chipnames[] = CHIPNAMES; |
455 | 455 | ||
456 | /* Allocate memory */ | 456 | /* Initialize what is necessary for write_scc and write_scc_data */ |
457 | info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); | 457 | info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); |
458 | if (!info) { | 458 | if (!info) { |
459 | printk(KERN_ERR "dmascc: " | 459 | printk(KERN_ERR "dmascc: " |
460 | "could not allocate memory for %s at %#3x\n", | 460 | "could not allocate memory for %s at %#3x\n", |
@@ -462,8 +462,6 @@ static int __init setup_adapter(int card_base, int type, int n) | |||
462 | goto out; | 462 | goto out; |
463 | } | 463 | } |
464 | 464 | ||
465 | /* Initialize what is necessary for write_scc and write_scc_data */ | ||
466 | memset(info, 0, sizeof(struct scc_info)); | ||
467 | 465 | ||
468 | info->dev[0] = alloc_netdev(0, "", dev_setup); | 466 | info->dev[0] = alloc_netdev(0, "", dev_setup); |
469 | if (!info->dev[0]) { | 467 | if (!info->dev[0]) { |
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 3078c419cb02..20732458f5ac 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c | |||
@@ -164,14 +164,13 @@ irport_open(int i, unsigned int iobase, unsigned int irq) | |||
164 | 164 | ||
165 | /* Allocate memory if needed */ | 165 | /* Allocate memory if needed */ |
166 | if (self->tx_buff.truesize > 0) { | 166 | if (self->tx_buff.truesize > 0) { |
167 | self->tx_buff.head = kmalloc(self->tx_buff.truesize, | 167 | self->tx_buff.head = kzalloc(self->tx_buff.truesize, |
168 | GFP_KERNEL); | 168 | GFP_KERNEL); |
169 | if (self->tx_buff.head == NULL) { | 169 | if (self->tx_buff.head == NULL) { |
170 | IRDA_ERROR("%s(), can't allocate memory for " | 170 | IRDA_ERROR("%s(), can't allocate memory for " |
171 | "transmit buffer!\n", __FUNCTION__); | 171 | "transmit buffer!\n", __FUNCTION__); |
172 | goto err_out4; | 172 | goto err_out4; |
173 | } | 173 | } |
174 | memset(self->tx_buff.head, 0, self->tx_buff.truesize); | ||
175 | } | 174 | } |
176 | self->tx_buff.data = self->tx_buff.head; | 175 | self->tx_buff.data = self->tx_buff.head; |
177 | 176 | ||
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index ad1857364d51..6f5f697ec9f8 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c | |||
@@ -505,10 +505,9 @@ static int irtty_open(struct tty_struct *tty) | |||
505 | } | 505 | } |
506 | 506 | ||
507 | /* allocate private device info block */ | 507 | /* allocate private device info block */ |
508 | priv = kmalloc(sizeof(*priv), GFP_KERNEL); | 508 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
509 | if (!priv) | 509 | if (!priv) |
510 | goto out_put; | 510 | goto out_put; |
511 | memset(priv, 0, sizeof(*priv)); | ||
512 | 511 | ||
513 | priv->magic = IRTTY_MAGIC; | 512 | priv->magic = IRTTY_MAGIC; |
514 | priv->tty = tty; | 513 | priv->tty = tty; |
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 347d50cd77d4..0433c41f9029 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c | |||
@@ -822,10 +822,9 @@ static int veth_init_connection(u8 rlp) | |||
822 | || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) | 822 | || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) |
823 | return 0; | 823 | return 0; |
824 | 824 | ||
825 | cnx = kmalloc(sizeof(*cnx), GFP_KERNEL); | 825 | cnx = kzalloc(sizeof(*cnx), GFP_KERNEL); |
826 | if (! cnx) | 826 | if (! cnx) |
827 | return -ENOMEM; | 827 | return -ENOMEM; |
828 | memset(cnx, 0, sizeof(*cnx)); | ||
829 | 828 | ||
830 | cnx->remote_lp = rlp; | 829 | cnx->remote_lp = rlp; |
831 | spin_lock_init(&cnx->lock); | 830 | spin_lock_init(&cnx->lock); |
@@ -852,14 +851,13 @@ static int veth_init_connection(u8 rlp) | |||
852 | if (rc != 0) | 851 | if (rc != 0) |
853 | return rc; | 852 | return rc; |
854 | 853 | ||
855 | msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL); | 854 | msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL); |
856 | if (! msgs) { | 855 | if (! msgs) { |
857 | veth_error("Can't allocate buffers for LPAR %d.\n", rlp); | 856 | veth_error("Can't allocate buffers for LPAR %d.\n", rlp); |
858 | return -ENOMEM; | 857 | return -ENOMEM; |
859 | } | 858 | } |
860 | 859 | ||
861 | cnx->msgs = msgs; | 860 | cnx->msgs = msgs; |
862 | memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg)); | ||
863 | 861 | ||
864 | for (i = 0; i < VETH_NUMBUFFERS; i++) { | 862 | for (i = 0; i < VETH_NUMBUFFERS; i++) { |
865 | msgs[i].token = i; | 863 | msgs[i].token = i; |
diff --git a/drivers/net/lance.c b/drivers/net/lance.c index a2f37e52b928..a4e5fab12628 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c | |||
@@ -533,11 +533,10 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int | |||
533 | dev->base_addr = ioaddr; | 533 | dev->base_addr = ioaddr; |
534 | /* Make certain the data structures used by the LANCE are aligned and DMAble. */ | 534 | /* Make certain the data structures used by the LANCE are aligned and DMAble. */ |
535 | 535 | ||
536 | lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); | 536 | lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL); |
537 | if(lp==NULL) | 537 | if(lp==NULL) |
538 | return -ENODEV; | 538 | return -ENODEV; |
539 | if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); | 539 | if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); |
540 | memset(lp, 0, sizeof(*lp)); | ||
541 | dev->priv = lp; | 540 | dev->priv = lp; |
542 | lp->name = chipname; | 541 | lp->name = chipname; |
543 | lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, | 542 | lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, |
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c new file mode 100644 index 000000000000..112778652f7d --- /dev/null +++ b/drivers/net/lguest_net.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* A simple network driver for lguest. | ||
2 | * | ||
3 | * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | //#define DEBUG | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/etherdevice.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/mm_types.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/lguest_bus.h> | ||
26 | |||
27 | #define SHARED_SIZE PAGE_SIZE | ||
28 | #define MAX_LANS 4 | ||
29 | #define NUM_SKBS 8 | ||
30 | |||
31 | struct lguestnet_info | ||
32 | { | ||
33 | /* The shared page(s). */ | ||
34 | struct lguest_net *peer; | ||
35 | unsigned long peer_phys; | ||
36 | unsigned long mapsize; | ||
37 | |||
38 | /* The lguest_device I come from */ | ||
39 | struct lguest_device *lgdev; | ||
40 | |||
41 | /* My peerid. */ | ||
42 | unsigned int me; | ||
43 | |||
44 | /* Receive queue. */ | ||
45 | struct sk_buff *skb[NUM_SKBS]; | ||
46 | struct lguest_dma dma[NUM_SKBS]; | ||
47 | }; | ||
48 | |||
49 | /* How many bytes left in this page. */ | ||
50 | static unsigned int rest_of_page(void *data) | ||
51 | { | ||
52 | return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE); | ||
53 | } | ||
54 | |||
55 | /* Simple convention: offset 4 * peernum. */ | ||
56 | static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum) | ||
57 | { | ||
58 | return info->peer_phys + 4 * peernum; | ||
59 | } | ||
60 | |||
61 | static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen, | ||
62 | struct lguest_dma *dma) | ||
63 | { | ||
64 | unsigned int i, seg; | ||
65 | |||
66 | for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) { | ||
67 | dma->addr[seg] = virt_to_phys(skb->data + i); | ||
68 | dma->len[seg] = min((unsigned)(headlen - i), | ||
69 | rest_of_page(skb->data + i)); | ||
70 | } | ||
71 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) { | ||
72 | const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; | ||
73 | /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */ | ||
74 | if (seg == LGUEST_MAX_DMA_SECTIONS) { | ||
75 | printk("Woah dude! Megapacket!\n"); | ||
76 | break; | ||
77 | } | ||
78 | dma->addr[seg] = page_to_phys(f->page) + f->page_offset; | ||
79 | dma->len[seg] = f->size; | ||
80 | } | ||
81 | if (seg < LGUEST_MAX_DMA_SECTIONS) | ||
82 | dma->len[seg] = 0; | ||
83 | } | ||
84 | |||
85 | /* We overload multicast bit to show promiscuous mode. */ | ||
86 | #define PROMISC_BIT 0x01 | ||
87 | |||
88 | static void lguestnet_set_multicast(struct net_device *dev) | ||
89 | { | ||
90 | struct lguestnet_info *info = netdev_priv(dev); | ||
91 | |||
92 | if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count) | ||
93 | info->peer[info->me].mac[0] |= PROMISC_BIT; | ||
94 | else | ||
95 | info->peer[info->me].mac[0] &= ~PROMISC_BIT; | ||
96 | } | ||
97 | |||
98 | static int promisc(struct lguestnet_info *info, unsigned int peer) | ||
99 | { | ||
100 | return info->peer[peer].mac[0] & PROMISC_BIT; | ||
101 | } | ||
102 | |||
103 | static int mac_eq(const unsigned char mac[ETH_ALEN], | ||
104 | struct lguestnet_info *info, unsigned int peer) | ||
105 | { | ||
106 | /* Ignore multicast bit, which peer turns on to mean promisc. */ | ||
107 | if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0]) | ||
108 | return 0; | ||
109 | return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0; | ||
110 | } | ||
111 | |||
112 | static void transfer_packet(struct net_device *dev, | ||
113 | struct sk_buff *skb, | ||
114 | unsigned int peernum) | ||
115 | { | ||
116 | struct lguestnet_info *info = netdev_priv(dev); | ||
117 | struct lguest_dma dma; | ||
118 | |||
119 | skb_to_dma(skb, skb_headlen(skb), &dma); | ||
120 | pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len); | ||
121 | |||
122 | lguest_send_dma(peer_key(info, peernum), &dma); | ||
123 | if (dma.used_len != skb->len) { | ||
124 | dev->stats.tx_carrier_errors++; | ||
125 | pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n", | ||
126 | peernum, dma.used_len, skb->len, | ||
127 | (void *)dma.addr[0], dma.len[0]); | ||
128 | } else { | ||
129 | dev->stats.tx_bytes += skb->len; | ||
130 | dev->stats.tx_packets++; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static int unused_peer(const struct lguest_net peer[], unsigned int num) | ||
135 | { | ||
136 | return peer[num].mac[0] == 0; | ||
137 | } | ||
138 | |||
139 | static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
140 | { | ||
141 | unsigned int i; | ||
142 | int broadcast; | ||
143 | struct lguestnet_info *info = netdev_priv(dev); | ||
144 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | ||
145 | |||
146 | pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
147 | dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]); | ||
148 | |||
149 | broadcast = is_multicast_ether_addr(dest); | ||
150 | for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) { | ||
151 | if (i == info->me || unused_peer(info->peer, i)) | ||
152 | continue; | ||
153 | |||
154 | if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i)) | ||
155 | continue; | ||
156 | |||
157 | pr_debug("lguestnet %s: sending from %i to %i\n", | ||
158 | dev->name, info->me, i); | ||
159 | transfer_packet(dev, skb, i); | ||
160 | } | ||
161 | dev_kfree_skb(skb); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /* Find a new skb to put in this slot in shared mem. */ | ||
166 | static int fill_slot(struct net_device *dev, unsigned int slot) | ||
167 | { | ||
168 | struct lguestnet_info *info = netdev_priv(dev); | ||
169 | /* Try to create and register a new one. */ | ||
170 | info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN); | ||
171 | if (!info->skb[slot]) { | ||
172 | printk("%s: could not fill slot %i\n", dev->name, slot); | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | |||
176 | skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]); | ||
177 | wmb(); | ||
178 | /* Now we tell hypervisor it can use the slot. */ | ||
179 | info->dma[slot].used_len = 0; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static irqreturn_t lguestnet_rcv(int irq, void *dev_id) | ||
184 | { | ||
185 | struct net_device *dev = dev_id; | ||
186 | struct lguestnet_info *info = netdev_priv(dev); | ||
187 | unsigned int i, done = 0; | ||
188 | |||
189 | for (i = 0; i < ARRAY_SIZE(info->dma); i++) { | ||
190 | unsigned int length; | ||
191 | struct sk_buff *skb; | ||
192 | |||
193 | length = info->dma[i].used_len; | ||
194 | if (length == 0) | ||
195 | continue; | ||
196 | |||
197 | done++; | ||
198 | skb = info->skb[i]; | ||
199 | fill_slot(dev, i); | ||
200 | |||
201 | if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) { | ||
202 | pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n", | ||
203 | dev->name, length); | ||
204 | dev_kfree_skb(skb); | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | skb_put(skb, length); | ||
209 | skb->protocol = eth_type_trans(skb, dev); | ||
210 | /* This is a reliable transport. */ | ||
211 | if (dev->features & NETIF_F_NO_CSUM) | ||
212 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
213 | pr_debug("Receiving skb proto 0x%04x len %i type %i\n", | ||
214 | ntohs(skb->protocol), skb->len, skb->pkt_type); | ||
215 | |||
216 | dev->stats.rx_bytes += skb->len; | ||
217 | dev->stats.rx_packets++; | ||
218 | netif_rx(skb); | ||
219 | } | ||
220 | return done ? IRQ_HANDLED : IRQ_NONE; | ||
221 | } | ||
222 | |||
223 | static int lguestnet_open(struct net_device *dev) | ||
224 | { | ||
225 | int i; | ||
226 | struct lguestnet_info *info = netdev_priv(dev); | ||
227 | |||
228 | /* Set up our MAC address */ | ||
229 | memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN); | ||
230 | |||
231 | /* Turn on promisc mode if needed */ | ||
232 | lguestnet_set_multicast(dev); | ||
233 | |||
234 | for (i = 0; i < ARRAY_SIZE(info->dma); i++) { | ||
235 | if (fill_slot(dev, i) != 0) | ||
236 | goto cleanup; | ||
237 | } | ||
238 | if (lguest_bind_dma(peer_key(info,info->me), info->dma, | ||
239 | NUM_SKBS, lgdev_irq(info->lgdev)) != 0) | ||
240 | goto cleanup; | ||
241 | return 0; | ||
242 | |||
243 | cleanup: | ||
244 | while (--i >= 0) | ||
245 | dev_kfree_skb(info->skb[i]); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | |||
249 | static int lguestnet_close(struct net_device *dev) | ||
250 | { | ||
251 | unsigned int i; | ||
252 | struct lguestnet_info *info = netdev_priv(dev); | ||
253 | |||
254 | /* Clear all trace: others might deliver packets, we'll ignore it. */ | ||
255 | memset(&info->peer[info->me], 0, sizeof(info->peer[info->me])); | ||
256 | |||
257 | /* Deregister sg lists. */ | ||
258 | lguest_unbind_dma(peer_key(info, info->me), info->dma); | ||
259 | for (i = 0; i < ARRAY_SIZE(info->dma); i++) | ||
260 | dev_kfree_skb(info->skb[i]); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int lguestnet_probe(struct lguest_device *lgdev) | ||
265 | { | ||
266 | int err, irqf = IRQF_SHARED; | ||
267 | struct net_device *dev; | ||
268 | struct lguestnet_info *info; | ||
269 | struct lguest_device_desc *desc = &lguest_devices[lgdev->index]; | ||
270 | |||
271 | pr_debug("lguest_net: probing for device %i\n", lgdev->index); | ||
272 | |||
273 | dev = alloc_etherdev(sizeof(struct lguestnet_info)); | ||
274 | if (!dev) | ||
275 | return -ENOMEM; | ||
276 | |||
277 | SET_MODULE_OWNER(dev); | ||
278 | |||
279 | /* Ethernet defaults with some changes */ | ||
280 | ether_setup(dev); | ||
281 | dev->set_mac_address = NULL; | ||
282 | |||
283 | dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */ | ||
284 | dev->dev_addr[1] = 0x00; | ||
285 | memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2); | ||
286 | dev->dev_addr[4] = 0x00; | ||
287 | dev->dev_addr[5] = 0x00; | ||
288 | |||
289 | dev->open = lguestnet_open; | ||
290 | dev->stop = lguestnet_close; | ||
291 | dev->hard_start_xmit = lguestnet_start_xmit; | ||
292 | |||
293 | /* Turning on/off promisc will call dev->set_multicast_list. | ||
294 | * We don't actually support multicast yet */ | ||
295 | dev->set_multicast_list = lguestnet_set_multicast; | ||
296 | SET_NETDEV_DEV(dev, &lgdev->dev); | ||
297 | if (desc->features & LGUEST_NET_F_NOCSUM) | ||
298 | dev->features = NETIF_F_SG|NETIF_F_NO_CSUM; | ||
299 | |||
300 | info = netdev_priv(dev); | ||
301 | info->mapsize = PAGE_SIZE * desc->num_pages; | ||
302 | info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT); | ||
303 | info->lgdev = lgdev; | ||
304 | info->peer = lguest_map(info->peer_phys, desc->num_pages); | ||
305 | if (!info->peer) { | ||
306 | err = -ENOMEM; | ||
307 | goto free; | ||
308 | } | ||
309 | |||
310 | /* This stores our peerid (upper bits reserved for future). */ | ||
311 | info->me = (desc->features & (info->mapsize-1)); | ||
312 | |||
313 | err = register_netdev(dev); | ||
314 | if (err) { | ||
315 | pr_debug("lguestnet: registering device failed\n"); | ||
316 | goto unmap; | ||
317 | } | ||
318 | |||
319 | if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS) | ||
320 | irqf |= IRQF_SAMPLE_RANDOM; | ||
321 | if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet", | ||
322 | dev) != 0) { | ||
323 | pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev)); | ||
324 | goto unregister; | ||
325 | } | ||
326 | |||
327 | pr_debug("lguestnet: registered device %s\n", dev->name); | ||
328 | lgdev->private = dev; | ||
329 | return 0; | ||
330 | |||
331 | unregister: | ||
332 | unregister_netdev(dev); | ||
333 | unmap: | ||
334 | lguest_unmap(info->peer); | ||
335 | free: | ||
336 | free_netdev(dev); | ||
337 | return err; | ||
338 | } | ||
339 | |||
340 | static struct lguest_driver lguestnet_drv = { | ||
341 | .name = "lguestnet", | ||
342 | .owner = THIS_MODULE, | ||
343 | .device_type = LGUEST_DEVICE_T_NET, | ||
344 | .probe = lguestnet_probe, | ||
345 | }; | ||
346 | |||
347 | static __init int lguestnet_init(void) | ||
348 | { | ||
349 | return register_lguest_driver(&lguestnet_drv); | ||
350 | } | ||
351 | module_init(lguestnet_init); | ||
352 | |||
353 | MODULE_DESCRIPTION("Lguest network driver"); | ||
354 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c index 1bb088aeaf71..6b32ec94b3a8 100644 --- a/drivers/net/mlx4/catas.c +++ b/drivers/net/mlx4/catas.c | |||
@@ -30,41 +30,133 @@ | |||
30 | * SOFTWARE. | 30 | * SOFTWARE. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/workqueue.h> | ||
34 | |||
33 | #include "mlx4.h" | 35 | #include "mlx4.h" |
34 | 36 | ||
35 | void mlx4_handle_catas_err(struct mlx4_dev *dev) | 37 | enum { |
38 | MLX4_CATAS_POLL_INTERVAL = 5 * HZ, | ||
39 | }; | ||
40 | |||
41 | static DEFINE_SPINLOCK(catas_lock); | ||
42 | |||
43 | static LIST_HEAD(catas_list); | ||
44 | static struct workqueue_struct *catas_wq; | ||
45 | static struct work_struct catas_work; | ||
46 | |||
47 | static int internal_err_reset = 1; | ||
48 | module_param(internal_err_reset, int, 0644); | ||
49 | MODULE_PARM_DESC(internal_err_reset, | ||
50 | "Reset device on internal errors if non-zero (default 1)"); | ||
51 | |||
52 | static void dump_err_buf(struct mlx4_dev *dev) | ||
36 | { | 53 | { |
37 | struct mlx4_priv *priv = mlx4_priv(dev); | 54 | struct mlx4_priv *priv = mlx4_priv(dev); |
38 | 55 | ||
39 | int i; | 56 | int i; |
40 | 57 | ||
41 | mlx4_err(dev, "Catastrophic error detected:\n"); | 58 | mlx4_err(dev, "Internal error detected:\n"); |
42 | for (i = 0; i < priv->fw.catas_size; ++i) | 59 | for (i = 0; i < priv->fw.catas_size; ++i) |
43 | mlx4_err(dev, " buf[%02x]: %08x\n", | 60 | mlx4_err(dev, " buf[%02x]: %08x\n", |
44 | i, swab32(readl(priv->catas_err.map + i))); | 61 | i, swab32(readl(priv->catas_err.map + i))); |
62 | } | ||
45 | 63 | ||
46 | mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0); | 64 | static void poll_catas(unsigned long dev_ptr) |
65 | { | ||
66 | struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; | ||
67 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
68 | |||
69 | if (readl(priv->catas_err.map)) { | ||
70 | dump_err_buf(dev); | ||
71 | |||
72 | mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0); | ||
73 | |||
74 | if (internal_err_reset) { | ||
75 | spin_lock(&catas_lock); | ||
76 | list_add(&priv->catas_err.list, &catas_list); | ||
77 | spin_unlock(&catas_lock); | ||
78 | |||
79 | queue_work(catas_wq, &catas_work); | ||
80 | } | ||
81 | } else | ||
82 | mod_timer(&priv->catas_err.timer, | ||
83 | round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); | ||
47 | } | 84 | } |
48 | 85 | ||
49 | void mlx4_map_catas_buf(struct mlx4_dev *dev) | 86 | static void catas_reset(struct work_struct *work) |
87 | { | ||
88 | struct mlx4_priv *priv, *tmppriv; | ||
89 | struct mlx4_dev *dev; | ||
90 | |||
91 | LIST_HEAD(tlist); | ||
92 | int ret; | ||
93 | |||
94 | spin_lock_irq(&catas_lock); | ||
95 | list_splice_init(&catas_list, &tlist); | ||
96 | spin_unlock_irq(&catas_lock); | ||
97 | |||
98 | list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { | ||
99 | ret = mlx4_restart_one(priv->dev.pdev); | ||
100 | dev = &priv->dev; | ||
101 | if (ret) | ||
102 | mlx4_err(dev, "Reset failed (%d)\n", ret); | ||
103 | else | ||
104 | mlx4_dbg(dev, "Reset succeeded\n"); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | void mlx4_start_catas_poll(struct mlx4_dev *dev) | ||
50 | { | 109 | { |
51 | struct mlx4_priv *priv = mlx4_priv(dev); | 110 | struct mlx4_priv *priv = mlx4_priv(dev); |
52 | unsigned long addr; | 111 | unsigned long addr; |
53 | 112 | ||
113 | INIT_LIST_HEAD(&priv->catas_err.list); | ||
114 | init_timer(&priv->catas_err.timer); | ||
115 | priv->catas_err.map = NULL; | ||
116 | |||
54 | addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + | 117 | addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + |
55 | priv->fw.catas_offset; | 118 | priv->fw.catas_offset; |
56 | 119 | ||
57 | priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); | 120 | priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); |
58 | if (!priv->catas_err.map) | 121 | if (!priv->catas_err.map) { |
59 | mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n", | 122 | mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n", |
60 | addr); | 123 | addr); |
124 | return; | ||
125 | } | ||
61 | 126 | ||
127 | priv->catas_err.timer.data = (unsigned long) dev; | ||
128 | priv->catas_err.timer.function = poll_catas; | ||
129 | priv->catas_err.timer.expires = | ||
130 | round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL); | ||
131 | add_timer(&priv->catas_err.timer); | ||
62 | } | 132 | } |
63 | 133 | ||
64 | void mlx4_unmap_catas_buf(struct mlx4_dev *dev) | 134 | void mlx4_stop_catas_poll(struct mlx4_dev *dev) |
65 | { | 135 | { |
66 | struct mlx4_priv *priv = mlx4_priv(dev); | 136 | struct mlx4_priv *priv = mlx4_priv(dev); |
67 | 137 | ||
138 | del_timer_sync(&priv->catas_err.timer); | ||
139 | |||
68 | if (priv->catas_err.map) | 140 | if (priv->catas_err.map) |
69 | iounmap(priv->catas_err.map); | 141 | iounmap(priv->catas_err.map); |
142 | |||
143 | spin_lock_irq(&catas_lock); | ||
144 | list_del(&priv->catas_err.list); | ||
145 | spin_unlock_irq(&catas_lock); | ||
146 | } | ||
147 | |||
148 | int __init mlx4_catas_init(void) | ||
149 | { | ||
150 | INIT_WORK(&catas_work, catas_reset); | ||
151 | |||
152 | catas_wq = create_singlethread_workqueue("mlx4_err"); | ||
153 | if (!catas_wq) | ||
154 | return -ENOMEM; | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | void mlx4_catas_cleanup(void) | ||
160 | { | ||
161 | destroy_workqueue(catas_wq); | ||
70 | } | 162 | } |
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 27a82cecd693..2095c843fa15 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c | |||
@@ -89,14 +89,12 @@ struct mlx4_eq_context { | |||
89 | (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ | 89 | (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ |
90 | (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ | 90 | (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ |
91 | (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ | 91 | (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ |
92 | (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR) | \ | ||
93 | (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ | 92 | (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ |
94 | (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ | 93 | (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ |
95 | (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ | 94 | (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ |
96 | (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ | 95 | (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ |
97 | (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ | 96 | (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ |
98 | (1ull << MLX4_EVENT_TYPE_CMD)) | 97 | (1ull << MLX4_EVENT_TYPE_CMD)) |
99 | #define MLX4_CATAS_EVENT_MASK (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR) | ||
100 | 98 | ||
101 | struct mlx4_eqe { | 99 | struct mlx4_eqe { |
102 | u8 reserved1; | 100 | u8 reserved1; |
@@ -264,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) | |||
264 | 262 | ||
265 | writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); | 263 | writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); |
266 | 264 | ||
267 | for (i = 0; i < MLX4_EQ_CATAS; ++i) | 265 | for (i = 0; i < MLX4_NUM_EQ; ++i) |
268 | work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); | 266 | work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); |
269 | 267 | ||
270 | return IRQ_RETVAL(work); | 268 | return IRQ_RETVAL(work); |
@@ -281,14 +279,6 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) | |||
281 | return IRQ_HANDLED; | 279 | return IRQ_HANDLED; |
282 | } | 280 | } |
283 | 281 | ||
284 | static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr) | ||
285 | { | ||
286 | mlx4_handle_catas_err(dev_ptr); | ||
287 | |||
288 | /* MSI-X vectors always belong to us */ | ||
289 | return IRQ_HANDLED; | ||
290 | } | ||
291 | |||
292 | static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, | 282 | static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, |
293 | int eq_num) | 283 | int eq_num) |
294 | { | 284 | { |
@@ -490,11 +480,9 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) | |||
490 | 480 | ||
491 | if (eq_table->have_irq) | 481 | if (eq_table->have_irq) |
492 | free_irq(dev->pdev->irq, dev); | 482 | free_irq(dev->pdev->irq, dev); |
493 | for (i = 0; i < MLX4_EQ_CATAS; ++i) | 483 | for (i = 0; i < MLX4_NUM_EQ; ++i) |
494 | if (eq_table->eq[i].have_irq) | 484 | if (eq_table->eq[i].have_irq) |
495 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); | 485 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); |
496 | if (eq_table->eq[MLX4_EQ_CATAS].have_irq) | ||
497 | free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev); | ||
498 | } | 486 | } |
499 | 487 | ||
500 | static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev) | 488 | static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev) |
@@ -598,32 +586,19 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev) | |||
598 | if (dev->flags & MLX4_FLAG_MSI_X) { | 586 | if (dev->flags & MLX4_FLAG_MSI_X) { |
599 | static const char *eq_name[] = { | 587 | static const char *eq_name[] = { |
600 | [MLX4_EQ_COMP] = DRV_NAME " (comp)", | 588 | [MLX4_EQ_COMP] = DRV_NAME " (comp)", |
601 | [MLX4_EQ_ASYNC] = DRV_NAME " (async)", | 589 | [MLX4_EQ_ASYNC] = DRV_NAME " (async)" |
602 | [MLX4_EQ_CATAS] = DRV_NAME " (catas)" | ||
603 | }; | 590 | }; |
604 | 591 | ||
605 | err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS, | 592 | for (i = 0; i < MLX4_NUM_EQ; ++i) { |
606 | &priv->eq_table.eq[MLX4_EQ_CATAS]); | ||
607 | if (err) | ||
608 | goto err_out_async; | ||
609 | |||
610 | for (i = 0; i < MLX4_EQ_CATAS; ++i) { | ||
611 | err = request_irq(priv->eq_table.eq[i].irq, | 593 | err = request_irq(priv->eq_table.eq[i].irq, |
612 | mlx4_msi_x_interrupt, | 594 | mlx4_msi_x_interrupt, |
613 | 0, eq_name[i], priv->eq_table.eq + i); | 595 | 0, eq_name[i], priv->eq_table.eq + i); |
614 | if (err) | 596 | if (err) |
615 | goto err_out_catas; | 597 | goto err_out_async; |
616 | 598 | ||
617 | priv->eq_table.eq[i].have_irq = 1; | 599 | priv->eq_table.eq[i].have_irq = 1; |
618 | } | 600 | } |
619 | 601 | ||
620 | err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq, | ||
621 | mlx4_catas_interrupt, 0, | ||
622 | eq_name[MLX4_EQ_CATAS], dev); | ||
623 | if (err) | ||
624 | goto err_out_catas; | ||
625 | |||
626 | priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1; | ||
627 | } else { | 602 | } else { |
628 | err = request_irq(dev->pdev->irq, mlx4_interrupt, | 603 | err = request_irq(dev->pdev->irq, mlx4_interrupt, |
629 | IRQF_SHARED, DRV_NAME, dev); | 604 | IRQF_SHARED, DRV_NAME, dev); |
@@ -639,22 +614,11 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev) | |||
639 | mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", | 614 | mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", |
640 | priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err); | 615 | priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err); |
641 | 616 | ||
642 | for (i = 0; i < MLX4_EQ_CATAS; ++i) | 617 | for (i = 0; i < MLX4_NUM_EQ; ++i) |
643 | eq_set_ci(&priv->eq_table.eq[i], 1); | 618 | eq_set_ci(&priv->eq_table.eq[i], 1); |
644 | 619 | ||
645 | if (dev->flags & MLX4_FLAG_MSI_X) { | ||
646 | err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0, | ||
647 | priv->eq_table.eq[MLX4_EQ_CATAS].eqn); | ||
648 | if (err) | ||
649 | mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n", | ||
650 | priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err); | ||
651 | } | ||
652 | |||
653 | return 0; | 620 | return 0; |
654 | 621 | ||
655 | err_out_catas: | ||
656 | mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]); | ||
657 | |||
658 | err_out_async: | 622 | err_out_async: |
659 | mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]); | 623 | mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]); |
660 | 624 | ||
@@ -675,19 +639,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) | |||
675 | struct mlx4_priv *priv = mlx4_priv(dev); | 639 | struct mlx4_priv *priv = mlx4_priv(dev); |
676 | int i; | 640 | int i; |
677 | 641 | ||
678 | if (dev->flags & MLX4_FLAG_MSI_X) | ||
679 | mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1, | ||
680 | priv->eq_table.eq[MLX4_EQ_CATAS].eqn); | ||
681 | |||
682 | mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, | 642 | mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, |
683 | priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); | 643 | priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); |
684 | 644 | ||
685 | mlx4_free_irqs(dev); | 645 | mlx4_free_irqs(dev); |
686 | 646 | ||
687 | for (i = 0; i < MLX4_EQ_CATAS; ++i) | 647 | for (i = 0; i < MLX4_NUM_EQ; ++i) |
688 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); | 648 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); |
689 | if (dev->flags & MLX4_FLAG_MSI_X) | ||
690 | mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]); | ||
691 | 649 | ||
692 | mlx4_unmap_clr_int(dev); | 650 | mlx4_unmap_clr_int(dev); |
693 | 651 | ||
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c index 9ae951bf6aa6..be5d9e90ccf2 100644 --- a/drivers/net/mlx4/intf.c +++ b/drivers/net/mlx4/intf.c | |||
@@ -142,6 +142,7 @@ int mlx4_register_device(struct mlx4_dev *dev) | |||
142 | mlx4_add_device(intf, priv); | 142 | mlx4_add_device(intf, priv); |
143 | 143 | ||
144 | mutex_unlock(&intf_mutex); | 144 | mutex_unlock(&intf_mutex); |
145 | mlx4_start_catas_poll(dev); | ||
145 | 146 | ||
146 | return 0; | 147 | return 0; |
147 | } | 148 | } |
@@ -151,6 +152,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev) | |||
151 | struct mlx4_priv *priv = mlx4_priv(dev); | 152 | struct mlx4_priv *priv = mlx4_priv(dev); |
152 | struct mlx4_interface *intf; | 153 | struct mlx4_interface *intf; |
153 | 154 | ||
155 | mlx4_stop_catas_poll(dev); | ||
154 | mutex_lock(&intf_mutex); | 156 | mutex_lock(&intf_mutex); |
155 | 157 | ||
156 | list_for_each_entry(intf, &intf_list, list) | 158 | list_for_each_entry(intf, &intf_list, list) |
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index a4f2e0475a71..4dc9dc19b716 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
@@ -78,7 +78,7 @@ static const char mlx4_version[] __devinitdata = | |||
78 | static struct mlx4_profile default_profile = { | 78 | static struct mlx4_profile default_profile = { |
79 | .num_qp = 1 << 16, | 79 | .num_qp = 1 << 16, |
80 | .num_srq = 1 << 16, | 80 | .num_srq = 1 << 16, |
81 | .rdmarc_per_qp = 4, | 81 | .rdmarc_per_qp = 1 << 4, |
82 | .num_cq = 1 << 16, | 82 | .num_cq = 1 << 16, |
83 | .num_mcg = 1 << 13, | 83 | .num_mcg = 1 << 13, |
84 | .num_mpt = 1 << 17, | 84 | .num_mpt = 1 << 17, |
@@ -583,13 +583,11 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev) | |||
583 | goto err_pd_table_free; | 583 | goto err_pd_table_free; |
584 | } | 584 | } |
585 | 585 | ||
586 | mlx4_map_catas_buf(dev); | ||
587 | |||
588 | err = mlx4_init_eq_table(dev); | 586 | err = mlx4_init_eq_table(dev); |
589 | if (err) { | 587 | if (err) { |
590 | mlx4_err(dev, "Failed to initialize " | 588 | mlx4_err(dev, "Failed to initialize " |
591 | "event queue table, aborting.\n"); | 589 | "event queue table, aborting.\n"); |
592 | goto err_catas_buf; | 590 | goto err_mr_table_free; |
593 | } | 591 | } |
594 | 592 | ||
595 | err = mlx4_cmd_use_events(dev); | 593 | err = mlx4_cmd_use_events(dev); |
@@ -659,8 +657,7 @@ err_cmd_poll: | |||
659 | err_eq_table_free: | 657 | err_eq_table_free: |
660 | mlx4_cleanup_eq_table(dev); | 658 | mlx4_cleanup_eq_table(dev); |
661 | 659 | ||
662 | err_catas_buf: | 660 | err_mr_table_free: |
663 | mlx4_unmap_catas_buf(dev); | ||
664 | mlx4_cleanup_mr_table(dev); | 661 | mlx4_cleanup_mr_table(dev); |
665 | 662 | ||
666 | err_pd_table_free: | 663 | err_pd_table_free: |
@@ -836,9 +833,6 @@ err_cleanup: | |||
836 | mlx4_cleanup_cq_table(dev); | 833 | mlx4_cleanup_cq_table(dev); |
837 | mlx4_cmd_use_polling(dev); | 834 | mlx4_cmd_use_polling(dev); |
838 | mlx4_cleanup_eq_table(dev); | 835 | mlx4_cleanup_eq_table(dev); |
839 | |||
840 | mlx4_unmap_catas_buf(dev); | ||
841 | |||
842 | mlx4_cleanup_mr_table(dev); | 836 | mlx4_cleanup_mr_table(dev); |
843 | mlx4_cleanup_pd_table(dev); | 837 | mlx4_cleanup_pd_table(dev); |
844 | mlx4_cleanup_uar_table(dev); | 838 | mlx4_cleanup_uar_table(dev); |
@@ -885,9 +879,6 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev) | |||
885 | mlx4_cleanup_cq_table(dev); | 879 | mlx4_cleanup_cq_table(dev); |
886 | mlx4_cmd_use_polling(dev); | 880 | mlx4_cmd_use_polling(dev); |
887 | mlx4_cleanup_eq_table(dev); | 881 | mlx4_cleanup_eq_table(dev); |
888 | |||
889 | mlx4_unmap_catas_buf(dev); | ||
890 | |||
891 | mlx4_cleanup_mr_table(dev); | 882 | mlx4_cleanup_mr_table(dev); |
892 | mlx4_cleanup_pd_table(dev); | 883 | mlx4_cleanup_pd_table(dev); |
893 | 884 | ||
@@ -908,6 +899,12 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev) | |||
908 | } | 899 | } |
909 | } | 900 | } |
910 | 901 | ||
902 | int mlx4_restart_one(struct pci_dev *pdev) | ||
903 | { | ||
904 | mlx4_remove_one(pdev); | ||
905 | return mlx4_init_one(pdev, NULL); | ||
906 | } | ||
907 | |||
911 | static struct pci_device_id mlx4_pci_table[] = { | 908 | static struct pci_device_id mlx4_pci_table[] = { |
912 | { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */ | 909 | { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */ |
913 | { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */ | 910 | { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */ |
@@ -930,6 +927,10 @@ static int __init mlx4_init(void) | |||
930 | { | 927 | { |
931 | int ret; | 928 | int ret; |
932 | 929 | ||
930 | ret = mlx4_catas_init(); | ||
931 | if (ret) | ||
932 | return ret; | ||
933 | |||
933 | ret = pci_register_driver(&mlx4_driver); | 934 | ret = pci_register_driver(&mlx4_driver); |
934 | return ret < 0 ? ret : 0; | 935 | return ret < 0 ? ret : 0; |
935 | } | 936 | } |
@@ -937,6 +938,7 @@ static int __init mlx4_init(void) | |||
937 | static void __exit mlx4_cleanup(void) | 938 | static void __exit mlx4_cleanup(void) |
938 | { | 939 | { |
939 | pci_unregister_driver(&mlx4_driver); | 940 | pci_unregister_driver(&mlx4_driver); |
941 | mlx4_catas_cleanup(); | ||
940 | } | 942 | } |
941 | 943 | ||
942 | module_init(mlx4_init); | 944 | module_init(mlx4_init); |
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index d9c91a71fc87..be304a7c2c91 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | #include <linux/mutex.h> | 40 | #include <linux/mutex.h> |
41 | #include <linux/radix-tree.h> | 41 | #include <linux/radix-tree.h> |
42 | #include <linux/timer.h> | ||
42 | 43 | ||
43 | #include <linux/mlx4/device.h> | 44 | #include <linux/mlx4/device.h> |
44 | #include <linux/mlx4/doorbell.h> | 45 | #include <linux/mlx4/doorbell.h> |
@@ -67,7 +68,6 @@ enum { | |||
67 | enum { | 68 | enum { |
68 | MLX4_EQ_ASYNC, | 69 | MLX4_EQ_ASYNC, |
69 | MLX4_EQ_COMP, | 70 | MLX4_EQ_COMP, |
70 | MLX4_EQ_CATAS, | ||
71 | MLX4_NUM_EQ | 71 | MLX4_NUM_EQ |
72 | }; | 72 | }; |
73 | 73 | ||
@@ -248,7 +248,8 @@ struct mlx4_mcg_table { | |||
248 | 248 | ||
249 | struct mlx4_catas_err { | 249 | struct mlx4_catas_err { |
250 | u32 __iomem *map; | 250 | u32 __iomem *map; |
251 | int size; | 251 | struct timer_list timer; |
252 | struct list_head list; | ||
252 | }; | 253 | }; |
253 | 254 | ||
254 | struct mlx4_priv { | 255 | struct mlx4_priv { |
@@ -311,9 +312,11 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev); | |||
311 | void mlx4_cleanup_srq_table(struct mlx4_dev *dev); | 312 | void mlx4_cleanup_srq_table(struct mlx4_dev *dev); |
312 | void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); | 313 | void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); |
313 | 314 | ||
314 | void mlx4_map_catas_buf(struct mlx4_dev *dev); | 315 | void mlx4_start_catas_poll(struct mlx4_dev *dev); |
315 | void mlx4_unmap_catas_buf(struct mlx4_dev *dev); | 316 | void mlx4_stop_catas_poll(struct mlx4_dev *dev); |
316 | 317 | int mlx4_catas_init(void); | |
318 | void mlx4_catas_cleanup(void); | ||
319 | int mlx4_restart_one(struct pci_dev *pdev); | ||
317 | int mlx4_register_device(struct mlx4_dev *dev); | 320 | int mlx4_register_device(struct mlx4_dev *dev); |
318 | void mlx4_unregister_device(struct mlx4_dev *dev); | 321 | void mlx4_unregister_device(struct mlx4_dev *dev); |
319 | void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, | 322 | void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type, |
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 3d5b4232f65f..22a3b3dc7d89 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c | |||
@@ -670,14 +670,10 @@ static void ni5010_set_multicast_list(struct net_device *dev) | |||
670 | 670 | ||
671 | PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); | 671 | PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); |
672 | 672 | ||
673 | if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) { | 673 | if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) { |
674 | dev->flags |= IFF_PROMISC; | 674 | dev->flags |= IFF_PROMISC; |
675 | outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ | 675 | outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ |
676 | PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); | 676 | PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); |
677 | } else if (dev->mc_list) { | ||
678 | /* Sorry, multicast not supported */ | ||
679 | PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name)); | ||
680 | outb(RMD_BROADCAST, EDLC_RMODE); | ||
681 | } else { | 677 | } else { |
682 | PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name)); | 678 | PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name)); |
683 | outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */ | 679 | outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */ |
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 104aab3c957f..ea80e6cb3dec 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c | |||
@@ -1582,7 +1582,7 @@ static void ns83820_set_multicast(struct net_device *ndev) | |||
1582 | else | 1582 | else |
1583 | and_mask &= ~(RFCR_AAU | RFCR_AAM); | 1583 | and_mask &= ~(RFCR_AAU | RFCR_AAM); |
1584 | 1584 | ||
1585 | if (ndev->flags & IFF_ALLMULTI) | 1585 | if (ndev->flags & IFF_ALLMULTI || ndev->mc_count) |
1586 | or_mask |= RFCR_AAM; | 1586 | or_mask |= RFCR_AAM; |
1587 | else | 1587 | else |
1588 | and_mask &= ~RFCR_AAM; | 1588 | and_mask &= ~RFCR_AAM; |
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 0d1c7a41c9c6..ea9414c4d900 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c | |||
@@ -147,7 +147,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) | |||
147 | DEBUG(0, "com20020_attach()\n"); | 147 | DEBUG(0, "com20020_attach()\n"); |
148 | 148 | ||
149 | /* Create new network device */ | 149 | /* Create new network device */ |
150 | info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); | 150 | info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); |
151 | if (!info) | 151 | if (!info) |
152 | goto fail_alloc_info; | 152 | goto fail_alloc_info; |
153 | 153 | ||
@@ -155,7 +155,6 @@ static int com20020_probe(struct pcmcia_device *p_dev) | |||
155 | if (!dev) | 155 | if (!dev) |
156 | goto fail_alloc_dev; | 156 | goto fail_alloc_dev; |
157 | 157 | ||
158 | memset(info, 0, sizeof(struct com20020_dev_t)); | ||
159 | lp = dev->priv; | 158 | lp = dev->priv; |
160 | lp->timeout = timeout; | 159 | lp->timeout = timeout; |
161 | lp->backplane = backplane; | 160 | lp->backplane = backplane; |
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 4ecb8ca5a992..4eafa4f42cff 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c | |||
@@ -146,9 +146,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link) | |||
146 | DEBUG(0, "ibmtr_attach()\n"); | 146 | DEBUG(0, "ibmtr_attach()\n"); |
147 | 147 | ||
148 | /* Create new token-ring device */ | 148 | /* Create new token-ring device */ |
149 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 149 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
150 | if (!info) return -ENOMEM; | 150 | if (!info) return -ENOMEM; |
151 | memset(info,0,sizeof(*info)); | ||
152 | dev = alloc_trdev(sizeof(struct tok_info)); | 151 | dev = alloc_trdev(sizeof(struct tok_info)); |
153 | if (!dev) { | 152 | if (!dev) { |
154 | kfree(info); | 153 | kfree(info); |
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 596222b260d6..6a5385647911 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c | |||
@@ -21,6 +21,10 @@ | |||
21 | /* Vitesse Extended Control Register 1 */ | 21 | /* Vitesse Extended Control Register 1 */ |
22 | #define MII_VSC8244_EXT_CON1 0x17 | 22 | #define MII_VSC8244_EXT_CON1 0x17 |
23 | #define MII_VSC8244_EXTCON1_INIT 0x0000 | 23 | #define MII_VSC8244_EXTCON1_INIT 0x0000 |
24 | #define MII_VSC8244_EXTCON1_TX_SKEW_MASK 0x0c00 | ||
25 | #define MII_VSC8244_EXTCON1_RX_SKEW_MASK 0x0300 | ||
26 | #define MII_VSC8244_EXTCON1_TX_SKEW 0x0800 | ||
27 | #define MII_VSC8244_EXTCON1_RX_SKEW 0x0200 | ||
24 | 28 | ||
25 | /* Vitesse Interrupt Mask Register */ | 29 | /* Vitesse Interrupt Mask Register */ |
26 | #define MII_VSC8244_IMASK 0x19 | 30 | #define MII_VSC8244_IMASK 0x19 |
@@ -39,7 +43,7 @@ | |||
39 | 43 | ||
40 | /* Vitesse Auxiliary Control/Status Register */ | 44 | /* Vitesse Auxiliary Control/Status Register */ |
41 | #define MII_VSC8244_AUX_CONSTAT 0x1c | 45 | #define MII_VSC8244_AUX_CONSTAT 0x1c |
42 | #define MII_VSC8244_AUXCONSTAT_INIT 0x0004 | 46 | #define MII_VSC8244_AUXCONSTAT_INIT 0x0000 |
43 | #define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020 | 47 | #define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020 |
44 | #define MII_VSC8244_AUXCONSTAT_SPEED 0x0018 | 48 | #define MII_VSC8244_AUXCONSTAT_SPEED 0x0018 |
45 | #define MII_VSC8244_AUXCONSTAT_GBIT 0x0010 | 49 | #define MII_VSC8244_AUXCONSTAT_GBIT 0x0010 |
@@ -51,6 +55,7 @@ MODULE_LICENSE("GPL"); | |||
51 | 55 | ||
52 | static int vsc824x_config_init(struct phy_device *phydev) | 56 | static int vsc824x_config_init(struct phy_device *phydev) |
53 | { | 57 | { |
58 | int extcon; | ||
54 | int err; | 59 | int err; |
55 | 60 | ||
56 | err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, | 61 | err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, |
@@ -58,14 +63,34 @@ static int vsc824x_config_init(struct phy_device *phydev) | |||
58 | if (err < 0) | 63 | if (err < 0) |
59 | return err; | 64 | return err; |
60 | 65 | ||
61 | err = phy_write(phydev, MII_VSC8244_EXT_CON1, | 66 | extcon = phy_read(phydev, MII_VSC8244_EXT_CON1); |
62 | MII_VSC8244_EXTCON1_INIT); | 67 | |
68 | if (extcon < 0) | ||
69 | return err; | ||
70 | |||
71 | extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK | | ||
72 | MII_VSC8244_EXTCON1_RX_SKEW_MASK); | ||
73 | |||
74 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) | ||
75 | extcon |= (MII_VSC8244_EXTCON1_TX_SKEW | | ||
76 | MII_VSC8244_EXTCON1_RX_SKEW); | ||
77 | |||
78 | err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon); | ||
79 | |||
63 | return err; | 80 | return err; |
64 | } | 81 | } |
65 | 82 | ||
66 | static int vsc824x_ack_interrupt(struct phy_device *phydev) | 83 | static int vsc824x_ack_interrupt(struct phy_device *phydev) |
67 | { | 84 | { |
68 | int err = phy_read(phydev, MII_VSC8244_ISTAT); | 85 | int err = 0; |
86 | |||
87 | /* | ||
88 | * Don't bother to ACK the interrupts if interrupts | ||
89 | * are disabled. The 824x cannot clear the interrupts | ||
90 | * if they are disabled. | ||
91 | */ | ||
92 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
93 | err = phy_read(phydev, MII_VSC8244_ISTAT); | ||
69 | 94 | ||
70 | return (err < 0) ? err : 0; | 95 | return (err < 0) ? err : 0; |
71 | } | 96 | } |
@@ -77,8 +102,19 @@ static int vsc824x_config_intr(struct phy_device *phydev) | |||
77 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | 102 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) |
78 | err = phy_write(phydev, MII_VSC8244_IMASK, | 103 | err = phy_write(phydev, MII_VSC8244_IMASK, |
79 | MII_VSC8244_IMASK_MASK); | 104 | MII_VSC8244_IMASK_MASK); |
80 | else | 105 | else { |
106 | /* | ||
107 | * The Vitesse PHY cannot clear the interrupt | ||
108 | * once it has disabled them, so we clear them first | ||
109 | */ | ||
110 | err = phy_read(phydev, MII_VSC8244_ISTAT); | ||
111 | |||
112 | if (err) | ||
113 | return err; | ||
114 | |||
81 | err = phy_write(phydev, MII_VSC8244_IMASK, 0); | 115 | err = phy_write(phydev, MII_VSC8244_IMASK, 0); |
116 | } | ||
117 | |||
82 | return err; | 118 | return err; |
83 | } | 119 | } |
84 | 120 | ||
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index caabbc408c34..27f5b904f48e 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c | |||
@@ -159,12 +159,11 @@ ppp_asynctty_open(struct tty_struct *tty) | |||
159 | int err; | 159 | int err; |
160 | 160 | ||
161 | err = -ENOMEM; | 161 | err = -ENOMEM; |
162 | ap = kmalloc(sizeof(*ap), GFP_KERNEL); | 162 | ap = kzalloc(sizeof(*ap), GFP_KERNEL); |
163 | if (ap == 0) | 163 | if (ap == 0) |
164 | goto out; | 164 | goto out; |
165 | 165 | ||
166 | /* initialize the asyncppp structure */ | 166 | /* initialize the asyncppp structure */ |
167 | memset(ap, 0, sizeof(*ap)); | ||
168 | ap->tty = tty; | 167 | ap->tty = tty; |
169 | ap->mru = PPP_MRU; | 168 | ap->mru = PPP_MRU; |
170 | spin_lock_init(&ap->xmit_lock); | 169 | spin_lock_init(&ap->xmit_lock); |
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 72c8d6628f58..eb98b661efba 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c | |||
@@ -121,12 +121,11 @@ static void *z_comp_alloc(unsigned char *options, int opt_len) | |||
121 | if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) | 121 | if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) |
122 | return NULL; | 122 | return NULL; |
123 | 123 | ||
124 | state = kmalloc(sizeof(*state), | 124 | state = kzalloc(sizeof(*state), |
125 | GFP_KERNEL); | 125 | GFP_KERNEL); |
126 | if (state == NULL) | 126 | if (state == NULL) |
127 | return NULL; | 127 | return NULL; |
128 | 128 | ||
129 | memset (state, 0, sizeof (struct ppp_deflate_state)); | ||
130 | state->strm.next_in = NULL; | 129 | state->strm.next_in = NULL; |
131 | state->w_size = w_size; | 130 | state->w_size = w_size; |
132 | state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); | 131 | state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); |
@@ -341,11 +340,10 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len) | |||
341 | if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) | 340 | if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) |
342 | return NULL; | 341 | return NULL; |
343 | 342 | ||
344 | state = kmalloc(sizeof(*state), GFP_KERNEL); | 343 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
345 | if (state == NULL) | 344 | if (state == NULL) |
346 | return NULL; | 345 | return NULL; |
347 | 346 | ||
348 | memset (state, 0, sizeof (struct ppp_deflate_state)); | ||
349 | state->w_size = w_size; | 347 | state->w_size = w_size; |
350 | state->strm.next_out = NULL; | 348 | state->strm.next_out = NULL; |
351 | state->strm.workspace = kmalloc(zlib_inflate_workspacesize(), | 349 | state->strm.workspace = kmalloc(zlib_inflate_workspacesize(), |
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 3ef0092dc09c..ef3325b69233 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -2684,8 +2684,7 @@ static void __exit ppp_cleanup(void) | |||
2684 | if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) | 2684 | if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) |
2685 | printk(KERN_ERR "PPP: removing module but units remain!\n"); | 2685 | printk(KERN_ERR "PPP: removing module but units remain!\n"); |
2686 | cardmap_destroy(&all_ppp_units); | 2686 | cardmap_destroy(&all_ppp_units); |
2687 | if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) | 2687 | unregister_chrdev(PPP_MAJOR, "ppp"); |
2688 | printk(KERN_ERR "PPP: failed to unregister PPP device\n"); | ||
2689 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); | 2688 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); |
2690 | class_destroy(ppp_class); | 2689 | class_destroy(ppp_class); |
2691 | } | 2690 | } |
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c index d5bdd2574659..f79cf87a2bff 100644 --- a/drivers/net/ppp_mppe.c +++ b/drivers/net/ppp_mppe.c | |||
@@ -200,11 +200,10 @@ static void *mppe_alloc(unsigned char *options, int optlen) | |||
200 | || options[0] != CI_MPPE || options[1] != CILEN_MPPE) | 200 | || options[0] != CI_MPPE || options[1] != CILEN_MPPE) |
201 | goto out; | 201 | goto out; |
202 | 202 | ||
203 | state = kmalloc(sizeof(*state), GFP_KERNEL); | 203 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
204 | if (state == NULL) | 204 | if (state == NULL) |
205 | goto out; | 205 | goto out; |
206 | 206 | ||
207 | memset(state, 0, sizeof(*state)); | ||
208 | 207 | ||
209 | state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); | 208 | state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); |
210 | if (IS_ERR(state->arc4)) { | 209 | if (IS_ERR(state->arc4)) { |
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 5918fab38349..ce64032a465a 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c | |||
@@ -207,13 +207,12 @@ ppp_sync_open(struct tty_struct *tty) | |||
207 | struct syncppp *ap; | 207 | struct syncppp *ap; |
208 | int err; | 208 | int err; |
209 | 209 | ||
210 | ap = kmalloc(sizeof(*ap), GFP_KERNEL); | 210 | ap = kzalloc(sizeof(*ap), GFP_KERNEL); |
211 | err = -ENOMEM; | 211 | err = -ENOMEM; |
212 | if (ap == 0) | 212 | if (ap == 0) |
213 | goto out; | 213 | goto out; |
214 | 214 | ||
215 | /* initialize the syncppp structure */ | 215 | /* initialize the syncppp structure */ |
216 | memset(ap, 0, sizeof(*ap)); | ||
217 | ap->tty = tty; | 216 | ap->tty = tty; |
218 | ap->mru = PPP_MRU; | 217 | ap->mru = PPP_MRU; |
219 | spin_lock_init(&ap->xmit_lock); | 218 | spin_lock_init(&ap->xmit_lock); |
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 451486b32f23..7dae4d404978 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c | |||
@@ -940,15 +940,14 @@ static void lan_saa9730_set_multicast(struct net_device *dev) | |||
940 | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, | 940 | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, |
941 | &lp->lan_saa9730_regs->CamCtl); | 941 | &lp->lan_saa9730_regs->CamCtl); |
942 | } else { | 942 | } else { |
943 | if (dev->flags & IFF_ALLMULTI) { | 943 | if (dev->flags & IFF_ALLMULTI || dev->mc_count) { |
944 | /* accept all multicast packets */ | 944 | /* accept all multicast packets */ |
945 | writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | | ||
946 | CAM_CONTROL_BROAD_ACC, | ||
947 | &lp->lan_saa9730_regs->CamCtl); | ||
948 | } else { | ||
949 | /* | 945 | /* |
950 | * Will handle the multicast stuff later. -carstenl | 946 | * Will handle the multicast stuff later. -carstenl |
951 | */ | 947 | */ |
948 | writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | | ||
949 | CAM_CONTROL_BROAD_ACC, | ||
950 | &lp->lan_saa9730_regs->CamCtl); | ||
952 | } | 951 | } |
953 | } | 952 | } |
954 | 953 | ||
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index e886e8d7cfdf..4c3d98ff4cd4 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c | |||
@@ -600,10 +600,9 @@ static int __init shaper_init(void) | |||
600 | return -ENODEV; | 600 | return -ENODEV; |
601 | 601 | ||
602 | alloc_size = sizeof(*dev) * shapers; | 602 | alloc_size = sizeof(*dev) * shapers; |
603 | devs = kmalloc(alloc_size, GFP_KERNEL); | 603 | devs = kzalloc(alloc_size, GFP_KERNEL); |
604 | if (!devs) | 604 | if (!devs) |
605 | return -ENOMEM; | 605 | return -ENOMEM; |
606 | memset(devs, 0, alloc_size); | ||
607 | 606 | ||
608 | for (i = 0; i < shapers; i++) { | 607 | for (i = 0; i < shapers; i++) { |
609 | 608 | ||
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 75655add3f34..7f94ca930988 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
@@ -626,7 +626,7 @@ static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev) | |||
626 | return -ENODEV; | 626 | return -ENODEV; |
627 | } | 627 | } |
628 | #else | 628 | #else |
629 | static int __devinit tc35815_read_plat_dev_addr(struct device *dev) | 629 | static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev) |
630 | { | 630 | { |
631 | return -ENODEV; | 631 | return -ENODEV; |
632 | } | 632 | } |
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 6b63b350cd52..8ead774d14c8 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c | |||
@@ -315,12 +315,11 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) | |||
315 | return -ENODEV; | 315 | return -ENODEV; |
316 | } | 316 | } |
317 | 317 | ||
318 | card = kmalloc(sizeof(card_t), GFP_KERNEL); | 318 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
319 | if (card == NULL) { | 319 | if (card == NULL) { |
320 | printk(KERN_ERR "c101: unable to allocate memory\n"); | 320 | printk(KERN_ERR "c101: unable to allocate memory\n"); |
321 | return -ENOBUFS; | 321 | return -ENOBUFS; |
322 | } | 322 | } |
323 | memset(card, 0, sizeof(card_t)); | ||
324 | 323 | ||
325 | card->dev = alloc_hdlcdev(card); | 324 | card->dev = alloc_hdlcdev(card); |
326 | if (!card->dev) { | 325 | if (!card->dev) { |
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 9ef49ce148b2..26058b4f8f36 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c | |||
@@ -572,13 +572,11 @@ static int cosa_probe(int base, int irq, int dma) | |||
572 | sprintf(cosa->name, "cosa%d", cosa->num); | 572 | sprintf(cosa->name, "cosa%d", cosa->num); |
573 | 573 | ||
574 | /* Initialize the per-channel data */ | 574 | /* Initialize the per-channel data */ |
575 | cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels, | 575 | cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL); |
576 | GFP_KERNEL); | ||
577 | if (!cosa->chan) { | 576 | if (!cosa->chan) { |
578 | err = -ENOMEM; | 577 | err = -ENOMEM; |
579 | goto err_out3; | 578 | goto err_out3; |
580 | } | 579 | } |
581 | memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels); | ||
582 | for (i=0; i<cosa->nchannels; i++) { | 580 | for (i=0; i<cosa->nchannels; i++) { |
583 | cosa->chan[i].cosa = cosa; | 581 | cosa->chan[i].cosa = cosa; |
584 | cosa->chan[i].num = i; | 582 | cosa->chan[i].num = i; |
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 6e5f1c898517..a0e8611ad8e8 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c | |||
@@ -113,12 +113,10 @@ static int __init cycx_init(void) | |||
113 | /* Verify number of cards and allocate adapter data space */ | 113 | /* Verify number of cards and allocate adapter data space */ |
114 | cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS); | 114 | cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS); |
115 | cycx_ncards = max_t(int, cycx_ncards, 1); | 115 | cycx_ncards = max_t(int, cycx_ncards, 1); |
116 | cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards, | 116 | cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL); |
117 | GFP_KERNEL); | ||
118 | if (!cycx_card_array) | 117 | if (!cycx_card_array) |
119 | goto out; | 118 | goto out; |
120 | 119 | ||
121 | memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards); | ||
122 | 120 | ||
123 | /* Register adapters with WAN router */ | 121 | /* Register adapters with WAN router */ |
124 | for (cnt = 0; cnt < cycx_ncards; ++cnt) { | 122 | for (cnt = 0; cnt < cycx_ncards; ++cnt) { |
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 016b3ff3ea5e..a8af28b273d3 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c | |||
@@ -376,11 +376,10 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, | |||
376 | } | 376 | } |
377 | 377 | ||
378 | /* allocate and initialize private data */ | 378 | /* allocate and initialize private data */ |
379 | chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL); | 379 | chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL); |
380 | if (!chan) | 380 | if (!chan) |
381 | return -ENOMEM; | 381 | return -ENOMEM; |
382 | 382 | ||
383 | memset(chan, 0, sizeof(*chan)); | ||
384 | strcpy(chan->name, conf->name); | 383 | strcpy(chan->name, conf->name); |
385 | chan->card = card; | 384 | chan->card = card; |
386 | chan->link = conf->port; | 385 | chan->link = conf->port; |
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index dca024471455..50d2f9108dca 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c | |||
@@ -890,12 +890,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr) | |||
890 | struct dscc4_dev_priv *root; | 890 | struct dscc4_dev_priv *root; |
891 | int i, ret = -ENOMEM; | 891 | int i, ret = -ENOMEM; |
892 | 892 | ||
893 | root = kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL); | 893 | root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL); |
894 | if (!root) { | 894 | if (!root) { |
895 | printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME); | 895 | printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME); |
896 | goto err_out; | 896 | goto err_out; |
897 | } | 897 | } |
898 | memset(root, 0, dev_per_card*sizeof(*root)); | ||
899 | 898 | ||
900 | for (i = 0; i < dev_per_card; i++) { | 899 | for (i = 0; i < dev_per_card; i++) { |
901 | root[i].dev = alloc_hdlcdev(root + i); | 900 | root[i].dev = alloc_hdlcdev(root + i); |
@@ -903,12 +902,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr) | |||
903 | goto err_free_dev; | 902 | goto err_free_dev; |
904 | } | 903 | } |
905 | 904 | ||
906 | ppriv = kmalloc(sizeof(*ppriv), GFP_KERNEL); | 905 | ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL); |
907 | if (!ppriv) { | 906 | if (!ppriv) { |
908 | printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME); | 907 | printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME); |
909 | goto err_free_dev; | 908 | goto err_free_dev; |
910 | } | 909 | } |
911 | memset(ppriv, 0, sizeof(struct dscc4_pci_priv)); | ||
912 | 910 | ||
913 | ppriv->root = root; | 911 | ppriv->root = root; |
914 | spin_lock_init(&ppriv->lock); | 912 | spin_lock_init(&ppriv->lock); |
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 58a53b6d9b42..12dae8e24844 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c | |||
@@ -2476,13 +2476,12 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2476 | } | 2476 | } |
2477 | 2477 | ||
2478 | /* Allocate driver private data */ | 2478 | /* Allocate driver private data */ |
2479 | card = kmalloc(sizeof (struct fst_card_info), GFP_KERNEL); | 2479 | card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL); |
2480 | if (card == NULL) { | 2480 | if (card == NULL) { |
2481 | printk_err("FarSync card found but insufficient memory for" | 2481 | printk_err("FarSync card found but insufficient memory for" |
2482 | " driver storage\n"); | 2482 | " driver storage\n"); |
2483 | return -ENOMEM; | 2483 | return -ENOMEM; |
2484 | } | 2484 | } |
2485 | memset(card, 0, sizeof (struct fst_card_info)); | ||
2486 | 2485 | ||
2487 | /* Try to enable the device */ | 2486 | /* Try to enable the device */ |
2488 | if ((err = pci_enable_device(pdev)) != 0) { | 2487 | if ((err = pci_enable_device(pdev)) != 0) { |
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 9ba3e4ee6ec7..bf5f8d9b5c83 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c | |||
@@ -231,11 +231,10 @@ static struct sv11_device *sv11_init(int iobase, int irq) | |||
231 | return NULL; | 231 | return NULL; |
232 | } | 232 | } |
233 | 233 | ||
234 | sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL); | 234 | sv = kzalloc(sizeof(struct sv11_device), GFP_KERNEL); |
235 | if(!sv) | 235 | if(!sv) |
236 | goto fail3; | 236 | goto fail3; |
237 | 237 | ||
238 | memset(sv, 0, sizeof(*sv)); | ||
239 | sv->if_ptr=&sv->netdev; | 238 | sv->if_ptr=&sv->netdev; |
240 | 239 | ||
241 | sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup); | 240 | sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup); |
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 5c322dfb79f6..cbdf0b748bde 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c | |||
@@ -351,12 +351,11 @@ static int __init n2_run(unsigned long io, unsigned long irq, | |||
351 | return -ENODEV; | 351 | return -ENODEV; |
352 | } | 352 | } |
353 | 353 | ||
354 | card = kmalloc(sizeof(card_t), GFP_KERNEL); | 354 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
355 | if (card == NULL) { | 355 | if (card == NULL) { |
356 | printk(KERN_ERR "n2: unable to allocate memory\n"); | 356 | printk(KERN_ERR "n2: unable to allocate memory\n"); |
357 | return -ENOBUFS; | 357 | return -ENOBUFS; |
358 | } | 358 | } |
359 | memset(card, 0, sizeof(card_t)); | ||
360 | 359 | ||
361 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); | 360 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); |
362 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); | 361 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); |
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 5d8c78ee2cd9..99fee2f1d019 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c | |||
@@ -3456,7 +3456,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3456 | if ((err = pci_enable_device(pdev)) < 0) | 3456 | if ((err = pci_enable_device(pdev)) < 0) |
3457 | return err; | 3457 | return err; |
3458 | 3458 | ||
3459 | card = kmalloc(sizeof(pc300_t), GFP_KERNEL); | 3459 | card = kzalloc(sizeof(pc300_t), GFP_KERNEL); |
3460 | if (card == NULL) { | 3460 | if (card == NULL) { |
3461 | printk("PC300 found at RAM 0x%016llx, " | 3461 | printk("PC300 found at RAM 0x%016llx, " |
3462 | "but could not allocate card structure.\n", | 3462 | "but could not allocate card structure.\n", |
@@ -3464,7 +3464,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3464 | err = -ENOMEM; | 3464 | err = -ENOMEM; |
3465 | goto err_disable_dev; | 3465 | goto err_disable_dev; |
3466 | } | 3466 | } |
3467 | memset(card, 0, sizeof(pc300_t)); | ||
3468 | 3467 | ||
3469 | err = -ENODEV; | 3468 | err = -ENODEV; |
3470 | 3469 | ||
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index dfbd3b00f03b..6353cb5c658d 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c | |||
@@ -334,14 +334,13 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, | |||
334 | return i; | 334 | return i; |
335 | } | 335 | } |
336 | 336 | ||
337 | card = kmalloc(sizeof(card_t), GFP_KERNEL); | 337 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
338 | if (card == NULL) { | 338 | if (card == NULL) { |
339 | printk(KERN_ERR "pc300: unable to allocate memory\n"); | 339 | printk(KERN_ERR "pc300: unable to allocate memory\n"); |
340 | pci_release_regions(pdev); | 340 | pci_release_regions(pdev); |
341 | pci_disable_device(pdev); | 341 | pci_disable_device(pdev); |
342 | return -ENOBUFS; | 342 | return -ENOBUFS; |
343 | } | 343 | } |
344 | memset(card, 0, sizeof(card_t)); | ||
345 | pci_set_drvdata(pdev, card); | 344 | pci_set_drvdata(pdev, card); |
346 | 345 | ||
347 | if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || | 346 | if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || |
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index 7f720de2e9f0..092e51d89036 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c | |||
@@ -312,14 +312,13 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, | |||
312 | return i; | 312 | return i; |
313 | } | 313 | } |
314 | 314 | ||
315 | card = kmalloc(sizeof(card_t), GFP_KERNEL); | 315 | card = kzalloc(sizeof(card_t), GFP_KERNEL); |
316 | if (card == NULL) { | 316 | if (card == NULL) { |
317 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); | 317 | printk(KERN_ERR "pci200syn: unable to allocate memory\n"); |
318 | pci_release_regions(pdev); | 318 | pci_release_regions(pdev); |
319 | pci_disable_device(pdev); | 319 | pci_disable_device(pdev); |
320 | return -ENOBUFS; | 320 | return -ENOBUFS; |
321 | } | 321 | } |
322 | memset(card, 0, sizeof(card_t)); | ||
323 | pci_set_drvdata(pdev, card); | 322 | pci_set_drvdata(pdev, card); |
324 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); | 323 | card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); |
325 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); | 324 | card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); |
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 6a485f0556f4..792e588d7d61 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c | |||
@@ -1196,10 +1196,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r | |||
1196 | 1196 | ||
1197 | if (read) | 1197 | if (read) |
1198 | { | 1198 | { |
1199 | temp = kmalloc(mem.len, GFP_KERNEL); | 1199 | temp = kzalloc(mem.len, GFP_KERNEL); |
1200 | if (!temp) | 1200 | if (!temp) |
1201 | return(-ENOMEM); | 1201 | return(-ENOMEM); |
1202 | memset(temp, 0, mem.len); | ||
1203 | sdla_read(dev, mem.addr, temp, mem.len); | 1202 | sdla_read(dev, mem.addr, temp, mem.len); |
1204 | if(copy_to_user(mem.data, temp, mem.len)) | 1203 | if(copy_to_user(mem.data, temp, mem.len)) |
1205 | { | 1204 | { |
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 131358108c5a..11276bf3149f 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c | |||
@@ -270,11 +270,10 @@ static __init struct slvl_board *slvl_init(int iobase, int irq, | |||
270 | return NULL; | 270 | return NULL; |
271 | } | 271 | } |
272 | 272 | ||
273 | b = kmalloc(sizeof(struct slvl_board), GFP_KERNEL); | 273 | b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL); |
274 | if(!b) | 274 | if(!b) |
275 | goto fail3; | 275 | goto fail3; |
276 | 276 | ||
277 | memset(b, 0, sizeof(*b)); | ||
278 | if (!(b->dev[0]= slvl_alloc(iobase, irq))) | 277 | if (!(b->dev[0]= slvl_alloc(iobase, irq))) |
279 | goto fail2; | 278 | goto fail2; |
280 | 279 | ||
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index c73601574334..3c78f9856380 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c | |||
@@ -599,7 +599,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, | |||
599 | } | 599 | } |
600 | 600 | ||
601 | alloc_size = sizeof(card_t) + ports * sizeof(port_t); | 601 | alloc_size = sizeof(card_t) + ports * sizeof(port_t); |
602 | card = kmalloc(alloc_size, GFP_KERNEL); | 602 | card = kzalloc(alloc_size, GFP_KERNEL); |
603 | if (card == NULL) { | 603 | if (card == NULL) { |
604 | printk(KERN_ERR "wanXL %s: unable to allocate memory\n", | 604 | printk(KERN_ERR "wanXL %s: unable to allocate memory\n", |
605 | pci_name(pdev)); | 605 | pci_name(pdev)); |
@@ -607,7 +607,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, | |||
607 | pci_disable_device(pdev); | 607 | pci_disable_device(pdev); |
608 | return -ENOBUFS; | 608 | return -ENOBUFS; |
609 | } | 609 | } |
610 | memset(card, 0, alloc_size); | ||
611 | 610 | ||
612 | pci_set_drvdata(pdev, card); | 611 | pci_set_drvdata(pdev, card); |
613 | card->pdev = pdev; | 612 | card->pdev = pdev; |
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 1c9edd97accd..c48b1cc63fd5 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c | |||
@@ -786,14 +786,12 @@ static int __init init_x25_asy(void) | |||
786 | printk(KERN_INFO "X.25 async: version 0.00 ALPHA " | 786 | printk(KERN_INFO "X.25 async: version 0.00 ALPHA " |
787 | "(dynamic channels, max=%d).\n", x25_asy_maxdev ); | 787 | "(dynamic channels, max=%d).\n", x25_asy_maxdev ); |
788 | 788 | ||
789 | x25_asy_devs = kmalloc(sizeof(struct net_device *)*x25_asy_maxdev, | 789 | x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL); |
790 | GFP_KERNEL); | ||
791 | if (!x25_asy_devs) { | 790 | if (!x25_asy_devs) { |
792 | printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] " | 791 | printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] " |
793 | "array! Uaargh! (-> No X.25 available)\n"); | 792 | "array! Uaargh! (-> No X.25 available)\n"); |
794 | return -ENOMEM; | 793 | return -ENOMEM; |
795 | } | 794 | } |
796 | memset(x25_asy_devs, 0, sizeof(struct net_device *)*x25_asy_maxdev); | ||
797 | 795 | ||
798 | return tty_register_ldisc(N_X25, &x25_ldisc); | 796 | return tty_register_ldisc(N_X25, &x25_ldisc); |
799 | } | 797 | } |
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 072ede71e575..8990585bd228 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
@@ -7868,10 +7868,10 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, | |||
7868 | goto done; | 7868 | goto done; |
7869 | } | 7869 | } |
7870 | 7870 | ||
7871 | if ((mode < 1) || (mode > POWER_MODES)) | 7871 | if ((mode < 0) || (mode > POWER_MODES)) |
7872 | mode = IPW_POWER_AUTO; | 7872 | mode = IPW_POWER_AUTO; |
7873 | 7873 | ||
7874 | if (priv->power_mode != mode) | 7874 | if (IPW_POWER_LEVEL(priv->power_mode) != mode) |
7875 | err = ipw2100_set_power_mode(priv, mode); | 7875 | err = ipw2100_set_power_mode(priv, mode); |
7876 | done: | 7876 | done: |
7877 | mutex_unlock(&priv->action_mutex); | 7877 | mutex_unlock(&priv->action_mutex); |
@@ -7902,7 +7902,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, | |||
7902 | break; | 7902 | break; |
7903 | case IPW_POWER_AUTO: | 7903 | case IPW_POWER_AUTO: |
7904 | snprintf(extra, MAX_POWER_STRING, | 7904 | snprintf(extra, MAX_POWER_STRING, |
7905 | "Power save level: %d (Auto)", 0); | 7905 | "Power save level: %d (Auto)", level); |
7906 | break; | 7906 | break; |
7907 | default: | 7907 | default: |
7908 | timeout = timeout_duration[level - 1] / 1000; | 7908 | timeout = timeout_duration[level - 1] / 1000; |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index aa32a97380ec..61497c467467 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -70,7 +70,7 @@ | |||
70 | #define VQ | 70 | #define VQ |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | #define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ | 73 | #define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ |
74 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" | 74 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" |
75 | #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" | 75 | #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" |
76 | #define DRV_VERSION IPW2200_VERSION | 76 | #define DRV_VERSION IPW2200_VERSION |
@@ -2506,7 +2506,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) | |||
2506 | break; | 2506 | break; |
2507 | } | 2507 | } |
2508 | 2508 | ||
2509 | param = cpu_to_le32(mode); | 2509 | param = cpu_to_le32(param); |
2510 | return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), | 2510 | return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), |
2511 | ¶m); | 2511 | ¶m); |
2512 | } | 2512 | } |
@@ -9568,6 +9568,7 @@ static int ipw_wx_set_power(struct net_device *dev, | |||
9568 | priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; | 9568 | priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; |
9569 | else | 9569 | else |
9570 | priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; | 9570 | priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; |
9571 | |||
9571 | err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); | 9572 | err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); |
9572 | if (err) { | 9573 | if (err) { |
9573 | IPW_DEBUG_WX("failed setting power mode.\n"); | 9574 | IPW_DEBUG_WX("failed setting power mode.\n"); |
@@ -9604,22 +9605,19 @@ static int ipw_wx_set_powermode(struct net_device *dev, | |||
9604 | struct ipw_priv *priv = ieee80211_priv(dev); | 9605 | struct ipw_priv *priv = ieee80211_priv(dev); |
9605 | int mode = *(int *)extra; | 9606 | int mode = *(int *)extra; |
9606 | int err; | 9607 | int err; |
9608 | |||
9607 | mutex_lock(&priv->mutex); | 9609 | mutex_lock(&priv->mutex); |
9608 | if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { | 9610 | if ((mode < 1) || (mode > IPW_POWER_LIMIT)) |
9609 | mode = IPW_POWER_AC; | 9611 | mode = IPW_POWER_AC; |
9610 | priv->power_mode = mode; | ||
9611 | } else { | ||
9612 | priv->power_mode = IPW_POWER_ENABLED | mode; | ||
9613 | } | ||
9614 | 9612 | ||
9615 | if (priv->power_mode != mode) { | 9613 | if (IPW_POWER_LEVEL(priv->power_mode) != mode) { |
9616 | err = ipw_send_power_mode(priv, mode); | 9614 | err = ipw_send_power_mode(priv, mode); |
9617 | |||
9618 | if (err) { | 9615 | if (err) { |
9619 | IPW_DEBUG_WX("failed setting power mode.\n"); | 9616 | IPW_DEBUG_WX("failed setting power mode.\n"); |
9620 | mutex_unlock(&priv->mutex); | 9617 | mutex_unlock(&priv->mutex); |
9621 | return err; | 9618 | return err; |
9622 | } | 9619 | } |
9620 | priv->power_mode = IPW_POWER_ENABLED | mode; | ||
9623 | } | 9621 | } |
9624 | mutex_unlock(&priv->mutex); | 9622 | mutex_unlock(&priv->mutex); |
9625 | return 0; | 9623 | return 0; |
@@ -10555,7 +10553,7 @@ static irqreturn_t ipw_isr(int irq, void *data) | |||
10555 | spin_lock(&priv->irq_lock); | 10553 | spin_lock(&priv->irq_lock); |
10556 | 10554 | ||
10557 | if (!(priv->status & STATUS_INT_ENABLED)) { | 10555 | if (!(priv->status & STATUS_INT_ENABLED)) { |
10558 | /* Shared IRQ */ | 10556 | /* IRQ is disabled */ |
10559 | goto none; | 10557 | goto none; |
10560 | } | 10558 | } |
10561 | 10559 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 28d41a29d7b1..a9c339ef116a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -72,6 +72,8 @@ static struct usb_device_id usb_ids[] = { | |||
72 | { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, | 72 | { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, |
73 | { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, | 73 | { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, |
74 | { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, | 74 | { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, |
75 | { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, | ||
76 | { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, | ||
75 | /* "Driverless" devices that need ejecting */ | 77 | /* "Driverless" devices that need ejecting */ |
76 | { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, | 78 | { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, |
77 | { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, | 79 | { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, |
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index 3a0a3a734933..e503c9c98032 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c | |||
@@ -466,9 +466,8 @@ static struct nubus_dev* __init | |||
466 | parent->base, dir.base); | 466 | parent->base, dir.base); |
467 | 467 | ||
468 | /* Actually we should probably panic if this fails */ | 468 | /* Actually we should probably panic if this fails */ |
469 | if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) | 469 | if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) |
470 | return NULL; | 470 | return NULL; |
471 | memset(dev, 0, sizeof(*dev)); | ||
472 | dev->resid = parent->type; | 471 | dev->resid = parent->type; |
473 | dev->directory = dir.base; | 472 | dev->directory = dir.base; |
474 | dev->board = board; | 473 | dev->board = board; |
@@ -800,9 +799,8 @@ static struct nubus_board* __init nubus_add_board(int slot, int bytelanes) | |||
800 | nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes); | 799 | nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes); |
801 | 800 | ||
802 | /* Actually we should probably panic if this fails */ | 801 | /* Actually we should probably panic if this fails */ |
803 | if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL) | 802 | if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL) |
804 | return NULL; | 803 | return NULL; |
805 | memset(board, 0, sizeof(*board)); | ||
806 | board->fblock = rp; | 804 | board->fblock = rp; |
807 | 805 | ||
808 | /* Dump the format block for debugging purposes */ | 806 | /* Dump the format block for debugging purposes */ |
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 8b7d84eca05d..802a81d47367 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c | |||
@@ -105,9 +105,8 @@ static int parport_probe(struct pcmcia_device *link) | |||
105 | DEBUG(0, "parport_attach()\n"); | 105 | DEBUG(0, "parport_attach()\n"); |
106 | 106 | ||
107 | /* Create new parport device */ | 107 | /* Create new parport device */ |
108 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 108 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
109 | if (!info) return -ENOMEM; | 109 | if (!info) return -ENOMEM; |
110 | memset(info, 0, sizeof(*info)); | ||
111 | link->priv = info; | 110 | link->priv = info; |
112 | info->p_dev = link; | 111 | info->p_dev = link; |
113 | 112 | ||
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 90ea3b8b99b0..bd6ad8b38168 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c | |||
@@ -324,10 +324,9 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev, | |||
324 | struct parport_serial_private *priv; | 324 | struct parport_serial_private *priv; |
325 | int err; | 325 | int err; |
326 | 326 | ||
327 | priv = kmalloc (sizeof *priv, GFP_KERNEL); | 327 | priv = kzalloc (sizeof *priv, GFP_KERNEL); |
328 | if (!priv) | 328 | if (!priv) |
329 | return -ENOMEM; | 329 | return -ENOMEM; |
330 | memset(priv, 0, sizeof(struct parport_serial_private)); | ||
331 | pci_set_drvdata (dev, priv); | 330 | pci_set_drvdata (dev, priv); |
332 | 331 | ||
333 | err = pci_enable_device (dev); | 332 | err = pci_enable_device (dev); |
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 6846fb42b399..ad90a01b0dfc 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -148,11 +148,10 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) | |||
148 | { | 148 | { |
149 | struct aer_rpc *rpc; | 149 | struct aer_rpc *rpc; |
150 | 150 | ||
151 | if (!(rpc = kmalloc(sizeof(struct aer_rpc), | 151 | if (!(rpc = kzalloc(sizeof(struct aer_rpc), |
152 | GFP_KERNEL))) | 152 | GFP_KERNEL))) |
153 | return NULL; | 153 | return NULL; |
154 | 154 | ||
155 | memset(rpc, 0, sizeof(struct aer_rpc)); | ||
156 | /* | 155 | /* |
157 | * Initialize Root lock access, e_lock, to Root Error Status Reg, | 156 | * Initialize Root lock access, e_lock, to Root Error Status Reg, |
158 | * Root Error ID Reg, and Root error producer/consumer index. | 157 | * Root Error ID Reg, and Root error producer/consumer index. |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 143c6efc478a..a99607142fc8 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -1127,6 +1127,34 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, | |||
1127 | 1127 | ||
1128 | #endif | 1128 | #endif |
1129 | 1129 | ||
1130 | /************************ runtime PM support ***************************/ | ||
1131 | |||
1132 | static int pcmcia_dev_suspend(struct device *dev, pm_message_t state); | ||
1133 | static int pcmcia_dev_resume(struct device *dev); | ||
1134 | |||
1135 | static int runtime_suspend(struct device *dev) | ||
1136 | { | ||
1137 | int rc; | ||
1138 | |||
1139 | down(&dev->sem); | ||
1140 | rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND); | ||
1141 | up(&dev->sem); | ||
1142 | if (!rc) | ||
1143 | dev->power.power_state.event = PM_EVENT_SUSPEND; | ||
1144 | return rc; | ||
1145 | } | ||
1146 | |||
1147 | static void runtime_resume(struct device *dev) | ||
1148 | { | ||
1149 | int rc; | ||
1150 | |||
1151 | down(&dev->sem); | ||
1152 | rc = pcmcia_dev_resume(dev); | ||
1153 | up(&dev->sem); | ||
1154 | if (!rc) | ||
1155 | dev->power.power_state.event = PM_EVENT_ON; | ||
1156 | } | ||
1157 | |||
1130 | /************************ per-device sysfs output ***************************/ | 1158 | /************************ per-device sysfs output ***************************/ |
1131 | 1159 | ||
1132 | #define pcmcia_device_attr(field, test, format) \ | 1160 | #define pcmcia_device_attr(field, test, format) \ |
@@ -1173,9 +1201,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute | |||
1173 | return -EINVAL; | 1201 | return -EINVAL; |
1174 | 1202 | ||
1175 | if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) | 1203 | if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) |
1176 | ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); | 1204 | ret = runtime_suspend(dev); |
1177 | else if (p_dev->suspended && !strncmp(buf, "on", 2)) | 1205 | else if (p_dev->suspended && !strncmp(buf, "on", 2)) |
1178 | dpm_runtime_resume(dev); | 1206 | runtime_resume(dev); |
1179 | 1207 | ||
1180 | return ret ? ret : count; | 1208 | return ret ? ret : count; |
1181 | } | 1209 | } |
@@ -1312,10 +1340,10 @@ static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) | |||
1312 | struct pcmcia_socket *skt = _data; | 1340 | struct pcmcia_socket *skt = _data; |
1313 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1341 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1314 | 1342 | ||
1315 | if (p_dev->socket != skt) | 1343 | if (p_dev->socket != skt || p_dev->suspended) |
1316 | return 0; | 1344 | return 0; |
1317 | 1345 | ||
1318 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); | 1346 | return runtime_suspend(dev); |
1319 | } | 1347 | } |
1320 | 1348 | ||
1321 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | 1349 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) |
@@ -1323,10 +1351,10 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | |||
1323 | struct pcmcia_socket *skt = _data; | 1351 | struct pcmcia_socket *skt = _data; |
1324 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1352 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1325 | 1353 | ||
1326 | if (p_dev->socket != skt) | 1354 | if (p_dev->socket != skt || !p_dev->suspended) |
1327 | return 0; | 1355 | return 0; |
1328 | 1356 | ||
1329 | dpm_runtime_resume(dev); | 1357 | runtime_resume(dev); |
1330 | 1358 | ||
1331 | return 0; | 1359 | return 0; |
1332 | } | 1360 | } |
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 3e20b1cc7778..8e7b2dd38810 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c | |||
@@ -35,12 +35,11 @@ void *pnp_alloc(long size) | |||
35 | { | 35 | { |
36 | void *result; | 36 | void *result; |
37 | 37 | ||
38 | result = kmalloc(size, GFP_KERNEL); | 38 | result = kzalloc(size, GFP_KERNEL); |
39 | if (!result){ | 39 | if (!result){ |
40 | printk(KERN_ERR "pnp: Out of Memory\n"); | 40 | printk(KERN_ERR "pnp: Out of Memory\n"); |
41 | return NULL; | 41 | return NULL; |
42 | } | 42 | } |
43 | memset(result, 0, size); | ||
44 | return result; | 43 | return result; |
45 | } | 44 | } |
46 | 45 | ||
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index f935c1f71a58..44420723a359 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -297,11 +297,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, | |||
297 | struct rio_switch *rswitch; | 297 | struct rio_switch *rswitch; |
298 | int result, rdid; | 298 | int result, rdid; |
299 | 299 | ||
300 | rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL); | 300 | rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); |
301 | if (!rdev) | 301 | if (!rdev) |
302 | goto out; | 302 | goto out; |
303 | 303 | ||
304 | memset(rdev, 0, sizeof(struct rio_dev)); | ||
305 | rdev->net = net; | 304 | rdev->net = net; |
306 | rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, | 305 | rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, |
307 | &result); | 306 | &result); |
@@ -801,9 +800,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) | |||
801 | { | 800 | { |
802 | struct rio_net *net; | 801 | struct rio_net *net; |
803 | 802 | ||
804 | net = kmalloc(sizeof(struct rio_net), GFP_KERNEL); | 803 | net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); |
805 | if (net) { | 804 | if (net) { |
806 | memset(net, 0, sizeof(struct rio_net)); | ||
807 | INIT_LIST_HEAD(&net->node); | 805 | INIT_LIST_HEAD(&net->node); |
808 | INIT_LIST_HEAD(&net->devices); | 806 | INIT_LIST_HEAD(&net->devices); |
809 | INIT_LIST_HEAD(&net->mports); | 807 | INIT_LIST_HEAD(&net->mports); |
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index e24ea82dc35b..5d760bb6c2cd 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -235,7 +235,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
235 | return 0; | 235 | return 0; |
236 | } | 236 | } |
237 | 237 | ||
238 | static int cmos_set_freq(struct device *dev, int freq) | 238 | static int cmos_irq_set_freq(struct device *dev, int freq) |
239 | { | 239 | { |
240 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 240 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
241 | int f; | 241 | int f; |
@@ -259,6 +259,34 @@ static int cmos_set_freq(struct device *dev, int freq) | |||
259 | return 0; | 259 | return 0; |
260 | } | 260 | } |
261 | 261 | ||
262 | static int cmos_irq_set_state(struct device *dev, int enabled) | ||
263 | { | ||
264 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | ||
265 | unsigned char rtc_control, rtc_intr; | ||
266 | unsigned long flags; | ||
267 | |||
268 | if (!is_valid_irq(cmos->irq)) | ||
269 | return -ENXIO; | ||
270 | |||
271 | spin_lock_irqsave(&rtc_lock, flags); | ||
272 | rtc_control = CMOS_READ(RTC_CONTROL); | ||
273 | |||
274 | if (enabled) | ||
275 | rtc_control |= RTC_PIE; | ||
276 | else | ||
277 | rtc_control &= ~RTC_PIE; | ||
278 | |||
279 | CMOS_WRITE(rtc_control, RTC_CONTROL); | ||
280 | |||
281 | rtc_intr = CMOS_READ(RTC_INTR_FLAGS); | ||
282 | rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; | ||
283 | if (is_intr(rtc_intr)) | ||
284 | rtc_update_irq(cmos->rtc, 1, rtc_intr); | ||
285 | |||
286 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
262 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) | 290 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) |
263 | 291 | ||
264 | static int | 292 | static int |
@@ -360,7 +388,8 @@ static const struct rtc_class_ops cmos_rtc_ops = { | |||
360 | .read_alarm = cmos_read_alarm, | 388 | .read_alarm = cmos_read_alarm, |
361 | .set_alarm = cmos_set_alarm, | 389 | .set_alarm = cmos_set_alarm, |
362 | .proc = cmos_procfs, | 390 | .proc = cmos_procfs, |
363 | .irq_set_freq = cmos_set_freq, | 391 | .irq_set_freq = cmos_irq_set_freq, |
392 | .irq_set_state = cmos_irq_set_state, | ||
364 | }; | 393 | }; |
365 | 394 | ||
366 | /*----------------------------------------------------------------*/ | 395 | /*----------------------------------------------------------------*/ |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index e765875e8db2..80e7a537e7d2 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -131,10 +131,9 @@ tape_34xx_schedule_work(struct tape_device *device, enum tape_op op) | |||
131 | { | 131 | { |
132 | struct tape_34xx_work *p; | 132 | struct tape_34xx_work *p; |
133 | 133 | ||
134 | if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL) | 134 | if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) |
135 | return -ENOMEM; | 135 | return -ENOMEM; |
136 | 136 | ||
137 | memset(p, 0, sizeof(*p)); | ||
138 | INIT_WORK(&p->work, tape_34xx_work_handler); | 137 | INIT_WORK(&p->work, tape_34xx_work_handler); |
139 | 138 | ||
140 | p->device = tape_get_device_reference(device); | 139 | p->device = tape_get_device_reference(device); |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 348bb7b82771..023455a0b34a 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -317,8 +317,8 @@ claw_probe(struct ccwgroup_device *cgdev) | |||
317 | CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); | 317 | CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); |
318 | return -ENOMEM; | 318 | return -ENOMEM; |
319 | } | 319 | } |
320 | privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL); | 320 | privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL); |
321 | privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL); | 321 | privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL); |
322 | if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) { | 322 | if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) { |
323 | probe_error(cgdev); | 323 | probe_error(cgdev); |
324 | put_device(&cgdev->dev); | 324 | put_device(&cgdev->dev); |
@@ -327,8 +327,6 @@ claw_probe(struct ccwgroup_device *cgdev) | |||
327 | CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); | 327 | CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM); |
328 | return -ENOMEM; | 328 | return -ENOMEM; |
329 | } | 329 | } |
330 | memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE); | ||
331 | memset(privptr->p_env, 0x00, sizeof(struct claw_env)); | ||
332 | memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8); | 330 | memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8); |
333 | memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8); | 331 | memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8); |
334 | memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8); | 332 | memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8); |
@@ -3924,7 +3922,7 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr) | |||
3924 | snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id); | 3922 | snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id); |
3925 | ccw_device_get_id(cdev, &dev_id); | 3923 | ccw_device_get_id(cdev, &dev_id); |
3926 | p_ch->devno = dev_id.devno; | 3924 | p_ch->devno = dev_id.devno; |
3927 | if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) { | 3925 | if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) { |
3928 | printk(KERN_WARNING "%s Out of memory in %s for irb\n", | 3926 | printk(KERN_WARNING "%s Out of memory in %s for irb\n", |
3929 | p_ch->id,__FUNCTION__); | 3927 | p_ch->id,__FUNCTION__); |
3930 | #ifdef FUNCTRACE | 3928 | #ifdef FUNCTRACE |
@@ -3933,7 +3931,6 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr) | |||
3933 | #endif | 3931 | #endif |
3934 | return -ENOMEM; | 3932 | return -ENOMEM; |
3935 | } | 3933 | } |
3936 | memset(p_ch->irb, 0, sizeof (struct irb)); | ||
3937 | #ifdef FUNCTRACE | 3934 | #ifdef FUNCTRACE |
3938 | printk(KERN_INFO "%s:%s Exit on line %d\n", | 3935 | printk(KERN_INFO "%s:%s Exit on line %d\n", |
3939 | cdev->dev.bus_id,__FUNCTION__,__LINE__); | 3936 | cdev->dev.bus_id,__FUNCTION__,__LINE__); |
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 178155bf9db6..fbadd4d761f3 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c | |||
@@ -156,10 +156,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) | |||
156 | 156 | ||
157 | if (!bp) | 157 | if (!bp) |
158 | return NULL; | 158 | return NULL; |
159 | client = kmalloc(sizeof(*client), GFP_KERNEL); | 159 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
160 | if (!client) | 160 | if (!client) |
161 | return NULL; | 161 | return NULL; |
162 | memset(client, 0, sizeof(*client)); | ||
163 | client->bp = bp; | 162 | client->bp = bp; |
164 | client->echild = echild; | 163 | client->echild = echild; |
165 | client->bus = echild->resource[0].start; | 164 | client->bus = echild->resource[0].start; |
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 6afc7e5df0d4..26b1d2a17ed2 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c | |||
@@ -656,12 +656,9 @@ static int vfc_probe(void) | |||
656 | if (!cards) | 656 | if (!cards) |
657 | return -ENODEV; | 657 | return -ENODEV; |
658 | 658 | ||
659 | vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) * | 659 | vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL); |
660 | (cards+1), | ||
661 | GFP_KERNEL); | ||
662 | if (vfc_dev_lst == NULL) | 660 | if (vfc_dev_lst == NULL) |
663 | return -ENOMEM; | 661 | return -ENOMEM; |
664 | memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1)); | ||
665 | vfc_dev_lst[cards] = NULL; | 662 | vfc_dev_lst[cards] = NULL; |
666 | 663 | ||
667 | ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops); | 664 | ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops); |
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 76c09097175f..6b49f6a2524d 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c | |||
@@ -1160,13 +1160,12 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev) | |||
1160 | } | 1160 | } |
1161 | 1161 | ||
1162 | /* Allocate event info space */ | 1162 | /* Allocate event info space */ |
1163 | tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL); | 1163 | tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); |
1164 | if (!tw_dev->event_queue[0]) { | 1164 | if (!tw_dev->event_queue[0]) { |
1165 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); | 1165 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); |
1166 | goto out; | 1166 | goto out; |
1167 | } | 1167 | } |
1168 | 1168 | ||
1169 | memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH); | ||
1170 | 1169 | ||
1171 | for (i = 0; i < TW_Q_LENGTH; i++) { | 1170 | for (i = 0; i < TW_Q_LENGTH; i++) { |
1172 | tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); | 1171 | tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); |
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 8b5334c56f0a..773d11dd9953 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c | |||
@@ -3606,11 +3606,10 @@ out: | |||
3606 | int esp_slave_alloc(struct scsi_device *SDptr) | 3606 | int esp_slave_alloc(struct scsi_device *SDptr) |
3607 | { | 3607 | { |
3608 | struct esp_device *esp_dev = | 3608 | struct esp_device *esp_dev = |
3609 | kmalloc(sizeof(struct esp_device), GFP_ATOMIC); | 3609 | kzalloc(sizeof(struct esp_device), GFP_ATOMIC); |
3610 | 3610 | ||
3611 | if (!esp_dev) | 3611 | if (!esp_dev) |
3612 | return -ENOMEM; | 3612 | return -ENOMEM; |
3613 | memset(esp_dev, 0, sizeof(struct esp_device)); | ||
3614 | SDptr->hostdata = esp_dev; | 3613 | SDptr->hostdata = esp_dev; |
3615 | return 0; | 3614 | return 0; |
3616 | } | 3615 | } |
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index f12864abed2f..3a8089705feb 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c | |||
@@ -181,13 +181,12 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq, | |||
181 | struct Scsi_Host *host; | 181 | struct Scsi_Host *host; |
182 | int ret; | 182 | int ret; |
183 | 183 | ||
184 | hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL); | 184 | hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); |
185 | if (!hostdata) { | 185 | if (!hostdata) { |
186 | printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host" | 186 | printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host" |
187 | "data, detatching\n", siop); | 187 | "data, detatching\n", siop); |
188 | return -ENOMEM; | 188 | return -ENOMEM; |
189 | } | 189 | } |
190 | memset(hostdata, 0, sizeof(*hostdata)); | ||
191 | 190 | ||
192 | if (!request_region(region, 64, "NCR_D700")) { | 191 | if (!request_region(region, 64, "NCR_D700")) { |
193 | printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", | 192 | printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", |
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c index 778844c3544a..a8bbdc2273b8 100644 --- a/drivers/scsi/NCR_Q720.c +++ b/drivers/scsi/NCR_Q720.c | |||
@@ -148,11 +148,10 @@ NCR_Q720_probe(struct device *dev) | |||
148 | __u32 base_addr, mem_size; | 148 | __u32 base_addr, mem_size; |
149 | void __iomem *mem_base; | 149 | void __iomem *mem_base; |
150 | 150 | ||
151 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 151 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
152 | if (!p) | 152 | if (!p) |
153 | return -ENOMEM; | 153 | return -ENOMEM; |
154 | 154 | ||
155 | memset(p, 0, sizeof(*p)); | ||
156 | pos2 = mca_device_read_pos(mca_dev, 2); | 155 | pos2 = mca_device_read_pos(mca_dev, 2); |
157 | /* enable device */ | 156 | /* enable device */ |
158 | pos2 |= NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE; | 157 | pos2 |= NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE; |
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 0464c182c577..005d2b05f32d 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c | |||
@@ -1159,11 +1159,10 @@ static int __imm_attach(struct parport *pb) | |||
1159 | 1159 | ||
1160 | init_waitqueue_head(&waiting); | 1160 | init_waitqueue_head(&waiting); |
1161 | 1161 | ||
1162 | dev = kmalloc(sizeof(imm_struct), GFP_KERNEL); | 1162 | dev = kzalloc(sizeof(imm_struct), GFP_KERNEL); |
1163 | if (!dev) | 1163 | if (!dev) |
1164 | return -ENOMEM; | 1164 | return -ENOMEM; |
1165 | 1165 | ||
1166 | memset(dev, 0, sizeof(imm_struct)); | ||
1167 | 1166 | ||
1168 | dev->base = -1; | 1167 | dev->base = -1; |
1169 | dev->mode = IMM_AUTODETECT; | 1168 | dev->mode = IMM_AUTODETECT; |
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 9f8ed6b81576..492a51bd6aa8 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c | |||
@@ -7068,14 +7068,13 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) | |||
7068 | subdevice_id = pci_dev->subsystem_device; | 7068 | subdevice_id = pci_dev->subsystem_device; |
7069 | 7069 | ||
7070 | /* found a controller */ | 7070 | /* found a controller */ |
7071 | ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL); | 7071 | ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); |
7072 | if (ha == NULL) { | 7072 | if (ha == NULL) { |
7073 | IPS_PRINTK(KERN_WARNING, pci_dev, | 7073 | IPS_PRINTK(KERN_WARNING, pci_dev, |
7074 | "Unable to allocate temporary ha struct\n"); | 7074 | "Unable to allocate temporary ha struct\n"); |
7075 | return -1; | 7075 | return -1; |
7076 | } | 7076 | } |
7077 | 7077 | ||
7078 | memset(ha, 0, sizeof (ips_ha_t)); | ||
7079 | 7078 | ||
7080 | ips_sh[index] = NULL; | 7079 | ips_sh[index] = NULL; |
7081 | ips_ha[index] = ha; | 7080 | ips_ha[index] = ha; |
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 5c32a69e41ba..3126824da36d 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c | |||
@@ -101,13 +101,12 @@ lasi700_probe(struct parisc_device *dev) | |||
101 | struct NCR_700_Host_Parameters *hostdata; | 101 | struct NCR_700_Host_Parameters *hostdata; |
102 | struct Scsi_Host *host; | 102 | struct Scsi_Host *host; |
103 | 103 | ||
104 | hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL); | 104 | hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); |
105 | if (!hostdata) { | 105 | if (!hostdata) { |
106 | printk(KERN_ERR "%s: Failed to allocate host data\n", | 106 | printk(KERN_ERR "%s: Failed to allocate host data\n", |
107 | dev->dev.bus_id); | 107 | dev->dev.bus_id); |
108 | return -ENOMEM; | 108 | return -ENOMEM; |
109 | } | 109 | } |
110 | memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); | ||
111 | 110 | ||
112 | hostdata->dev = &dev->dev; | 111 | hostdata->dev = &dev->dev; |
113 | dma_set_mask(&dev->dev, DMA_32BIT_MASK); | 112 | dma_set_mask(&dev->dev, DMA_32BIT_MASK); |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f81f85ee190f..07bd0dcdf0d6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -1830,7 +1830,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1830 | /* Initialize and populate the iocb list per host. */ | 1830 | /* Initialize and populate the iocb list per host. */ |
1831 | INIT_LIST_HEAD(&phba->lpfc_iocb_list); | 1831 | INIT_LIST_HEAD(&phba->lpfc_iocb_list); |
1832 | for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) { | 1832 | for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) { |
1833 | iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); | 1833 | iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); |
1834 | if (iocbq_entry == NULL) { | 1834 | if (iocbq_entry == NULL) { |
1835 | printk(KERN_ERR "%s: only allocated %d iocbs of " | 1835 | printk(KERN_ERR "%s: only allocated %d iocbs of " |
1836 | "expected %d count. Unloading driver.\n", | 1836 | "expected %d count. Unloading driver.\n", |
@@ -1839,7 +1839,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1839 | goto out_free_iocbq; | 1839 | goto out_free_iocbq; |
1840 | } | 1840 | } |
1841 | 1841 | ||
1842 | memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq)); | ||
1843 | iotag = lpfc_sli_next_iotag(phba, iocbq_entry); | 1842 | iotag = lpfc_sli_next_iotag(phba, iocbq_entry); |
1844 | if (iotag == 0) { | 1843 | if (iotag == 0) { |
1845 | kfree (iocbq_entry); | 1844 | kfree (iocbq_entry); |
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c46685a03a9f..c6a53dccc16a 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c | |||
@@ -454,7 +454,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
454 | pci_set_master(pdev); | 454 | pci_set_master(pdev); |
455 | 455 | ||
456 | // Allocate the per driver initialization structure | 456 | // Allocate the per driver initialization structure |
457 | adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL); | 457 | adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); |
458 | 458 | ||
459 | if (adapter == NULL) { | 459 | if (adapter == NULL) { |
460 | con_log(CL_ANN, (KERN_WARNING | 460 | con_log(CL_ANN, (KERN_WARNING |
@@ -462,7 +462,6 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
462 | 462 | ||
463 | goto out_probe_one; | 463 | goto out_probe_one; |
464 | } | 464 | } |
465 | memset(adapter, 0, sizeof(adapter_t)); | ||
466 | 465 | ||
467 | 466 | ||
468 | // set up PCI related soft state and other pre-known parameters | 467 | // set up PCI related soft state and other pre-known parameters |
@@ -746,10 +745,9 @@ megaraid_init_mbox(adapter_t *adapter) | |||
746 | * Allocate and initialize the init data structure for mailbox | 745 | * Allocate and initialize the init data structure for mailbox |
747 | * controllers | 746 | * controllers |
748 | */ | 747 | */ |
749 | raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL); | 748 | raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); |
750 | if (raid_dev == NULL) return -1; | 749 | if (raid_dev == NULL) return -1; |
751 | 750 | ||
752 | memset(raid_dev, 0, sizeof(mraid_device_t)); | ||
753 | 751 | ||
754 | /* | 752 | /* |
755 | * Attach the adapter soft state to raid device soft state | 753 | * Attach the adapter soft state to raid device soft state |
@@ -1050,8 +1048,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
1050 | * since the calling routine does not yet know the number of available | 1048 | * since the calling routine does not yet know the number of available |
1051 | * commands. | 1049 | * commands. |
1052 | */ | 1050 | */ |
1053 | adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS, | 1051 | adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); |
1054 | GFP_KERNEL); | ||
1055 | 1052 | ||
1056 | if (adapter->kscb_list == NULL) { | 1053 | if (adapter->kscb_list == NULL) { |
1057 | con_log(CL_ANN, (KERN_WARNING | 1054 | con_log(CL_ANN, (KERN_WARNING |
@@ -1059,7 +1056,6 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
1059 | __LINE__)); | 1056 | __LINE__)); |
1060 | goto out_free_ibuf; | 1057 | goto out_free_ibuf; |
1061 | } | 1058 | } |
1062 | memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS); | ||
1063 | 1059 | ||
1064 | // memory allocation for our command packets | 1060 | // memory allocation for our command packets |
1065 | if (megaraid_mbox_setup_dma_pools(adapter) != 0) { | 1061 | if (megaraid_mbox_setup_dma_pools(adapter) != 0) { |
@@ -3495,8 +3491,7 @@ megaraid_cmm_register(adapter_t *adapter) | |||
3495 | int i; | 3491 | int i; |
3496 | 3492 | ||
3497 | // Allocate memory for the base list of scb for management module. | 3493 | // Allocate memory for the base list of scb for management module. |
3498 | adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS, | 3494 | adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL); |
3499 | GFP_KERNEL); | ||
3500 | 3495 | ||
3501 | if (adapter->uscb_list == NULL) { | 3496 | if (adapter->uscb_list == NULL) { |
3502 | con_log(CL_ANN, (KERN_WARNING | 3497 | con_log(CL_ANN, (KERN_WARNING |
@@ -3504,7 +3499,6 @@ megaraid_cmm_register(adapter_t *adapter) | |||
3504 | __LINE__)); | 3499 | __LINE__)); |
3505 | return -1; | 3500 | return -1; |
3506 | } | 3501 | } |
3507 | memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS); | ||
3508 | 3502 | ||
3509 | 3503 | ||
3510 | // Initialize the synchronization parameters for resources for | 3504 | // Initialize the synchronization parameters for resources for |
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 84d9c27133d4..b6587a6d8486 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c | |||
@@ -890,12 +890,11 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) | |||
890 | if (lld_adp->drvr_type != DRVRTYPE_MBOX) | 890 | if (lld_adp->drvr_type != DRVRTYPE_MBOX) |
891 | return (-EINVAL); | 891 | return (-EINVAL); |
892 | 892 | ||
893 | adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); | 893 | adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); |
894 | 894 | ||
895 | if (!adapter) | 895 | if (!adapter) |
896 | return -ENOMEM; | 896 | return -ENOMEM; |
897 | 897 | ||
898 | memset(adapter, 0, sizeof(mraid_mmadp_t)); | ||
899 | 898 | ||
900 | adapter->unique_id = lld_adp->unique_id; | 899 | adapter->unique_id = lld_adp->unique_id; |
901 | adapter->drvr_type = lld_adp->drvr_type; | 900 | adapter->drvr_type = lld_adp->drvr_type; |
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index b7f2e613c903..ebb948c016bb 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c | |||
@@ -1636,15 +1636,13 @@ static int megasas_alloc_cmds(struct megasas_instance *instance) | |||
1636 | * Allocate the dynamic array first and then allocate individual | 1636 | * Allocate the dynamic array first and then allocate individual |
1637 | * commands. | 1637 | * commands. |
1638 | */ | 1638 | */ |
1639 | instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd, | 1639 | instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL); |
1640 | GFP_KERNEL); | ||
1641 | 1640 | ||
1642 | if (!instance->cmd_list) { | 1641 | if (!instance->cmd_list) { |
1643 | printk(KERN_DEBUG "megasas: out of memory\n"); | 1642 | printk(KERN_DEBUG "megasas: out of memory\n"); |
1644 | return -ENOMEM; | 1643 | return -ENOMEM; |
1645 | } | 1644 | } |
1646 | 1645 | ||
1647 | memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd); | ||
1648 | 1646 | ||
1649 | for (i = 0; i < max_cmd; i++) { | 1647 | for (i = 0; i < max_cmd; i++) { |
1650 | instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), | 1648 | instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), |
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 370802d24acd..2dd0dc9a9aed 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c | |||
@@ -106,9 +106,8 @@ static int aha152x_probe(struct pcmcia_device *link) | |||
106 | DEBUG(0, "aha152x_attach()\n"); | 106 | DEBUG(0, "aha152x_attach()\n"); |
107 | 107 | ||
108 | /* Create new SCSI device */ | 108 | /* Create new SCSI device */ |
109 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 109 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
110 | if (!info) return -ENOMEM; | 110 | if (!info) return -ENOMEM; |
111 | memset(info, 0, sizeof(*info)); | ||
112 | info->p_dev = link; | 111 | info->p_dev = link; |
113 | link->priv = info; | 112 | link->priv = info; |
114 | 113 | ||
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index c6f8c6e65e05..445cfbbca9b3 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c | |||
@@ -1602,9 +1602,8 @@ static int nsp_cs_probe(struct pcmcia_device *link) | |||
1602 | nsp_dbg(NSP_DEBUG_INIT, "in"); | 1602 | nsp_dbg(NSP_DEBUG_INIT, "in"); |
1603 | 1603 | ||
1604 | /* Create new SCSI device */ | 1604 | /* Create new SCSI device */ |
1605 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 1605 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
1606 | if (info == NULL) { return -ENOMEM; } | 1606 | if (info == NULL) { return -ENOMEM; } |
1607 | memset(info, 0, sizeof(*info)); | ||
1608 | info->p_dev = link; | 1607 | info->p_dev = link; |
1609 | link->priv = info; | 1608 | link->priv = info; |
1610 | data->ScsiInfo = info; | 1609 | data->ScsiInfo = info; |
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 697cfb76c3a4..67c5a58d17df 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c | |||
@@ -162,10 +162,9 @@ static int qlogic_probe(struct pcmcia_device *link) | |||
162 | DEBUG(0, "qlogic_attach()\n"); | 162 | DEBUG(0, "qlogic_attach()\n"); |
163 | 163 | ||
164 | /* Create new SCSI device */ | 164 | /* Create new SCSI device */ |
165 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 165 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
166 | if (!info) | 166 | if (!info) |
167 | return -ENOMEM; | 167 | return -ENOMEM; |
168 | memset(info, 0, sizeof(*info)); | ||
169 | info->p_dev = link; | 168 | info->p_dev = link; |
170 | link->priv = info; | 169 | link->priv = info; |
171 | link->io.NumPorts1 = 16; | 170 | link->io.NumPorts1 = 16; |
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 2695b7187b2f..961839ecfe86 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c | |||
@@ -875,10 +875,9 @@ SYM53C500_probe(struct pcmcia_device *link) | |||
875 | DEBUG(0, "SYM53C500_attach()\n"); | 875 | DEBUG(0, "SYM53C500_attach()\n"); |
876 | 876 | ||
877 | /* Create new SCSI device */ | 877 | /* Create new SCSI device */ |
878 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 878 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
879 | if (!info) | 879 | if (!info) |
880 | return -ENOMEM; | 880 | return -ENOMEM; |
881 | memset(info, 0, sizeof(*info)); | ||
882 | info->p_dev = link; | 881 | info->p_dev = link; |
883 | link->priv = info; | 882 | link->priv = info; |
884 | link->io.NumPorts1 = 16; | 883 | link->io.NumPorts1 = 16; |
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 2f1fa1eb7e90..67b6d76a6c8d 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c | |||
@@ -1014,10 +1014,9 @@ static int __ppa_attach(struct parport *pb) | |||
1014 | int modes, ppb, ppb_hi; | 1014 | int modes, ppb, ppb_hi; |
1015 | int err = -ENOMEM; | 1015 | int err = -ENOMEM; |
1016 | 1016 | ||
1017 | dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL); | 1017 | dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL); |
1018 | if (!dev) | 1018 | if (!dev) |
1019 | return -ENOMEM; | 1019 | return -ENOMEM; |
1020 | memset(dev, 0, sizeof(ppa_struct)); | ||
1021 | dev->base = -1; | 1020 | dev->base = -1; |
1022 | dev->mode = PPA_AUTODETECT; | 1021 | dev->mode = PPA_AUTODETECT; |
1023 | dev->recon_tmo = PPA_RECON_TMO; | 1022 | dev->recon_tmo = PPA_RECON_TMO; |
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 018c65f73ac4..710f19de3d40 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c | |||
@@ -100,7 +100,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, | |||
100 | { | 100 | { |
101 | struct Scsi_Host * host = NULL; | 101 | struct Scsi_Host * host = NULL; |
102 | struct NCR_700_Host_Parameters *hostdata = | 102 | struct NCR_700_Host_Parameters *hostdata = |
103 | kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); | 103 | kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); |
104 | 104 | ||
105 | printk(KERN_NOTICE "sim710: %s\n", dev->bus_id); | 105 | printk(KERN_NOTICE "sim710: %s\n", dev->bus_id); |
106 | printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", | 106 | printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", |
@@ -110,7 +110,6 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, | |||
110 | printk(KERN_ERR "sim710: Failed to allocate host data\n"); | 110 | printk(KERN_ERR "sim710: Failed to allocate host data\n"); |
111 | goto out; | 111 | goto out; |
112 | } | 112 | } |
113 | memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); | ||
114 | 113 | ||
115 | if(request_region(base_addr, 64, "sim710") == NULL) { | 114 | if(request_region(base_addr, 64, "sim710") == NULL) { |
116 | printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n", | 115 | printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n", |
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 14cba1ca38b3..5db1520f8ba9 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c | |||
@@ -2082,10 +2082,9 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device) | |||
2082 | uint id = scsi_device->id; | 2082 | uint id = scsi_device->id; |
2083 | uint lun = scsi_device->lun; | 2083 | uint lun = scsi_device->lun; |
2084 | 2084 | ||
2085 | pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL); | 2085 | pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL); |
2086 | if (!pDCB) | 2086 | if (!pDCB) |
2087 | return -ENOMEM; | 2087 | return -ENOMEM; |
2088 | memset(pDCB, 0, sizeof(struct dc390_dcb)); | ||
2089 | 2088 | ||
2090 | if (!pACB->DCBCnt++) { | 2089 | if (!pACB->DCBCnt++) { |
2091 | pACB->pLinkDCB = pDCB; | 2090 | pACB->pLinkDCB = pDCB; |
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 954073c6ce3a..72229df9dc11 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -716,7 +716,7 @@ static int pl011_probe(struct amba_device *dev, void *id) | |||
716 | goto out; | 716 | goto out; |
717 | } | 717 | } |
718 | 718 | ||
719 | uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL); | 719 | uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); |
720 | if (uap == NULL) { | 720 | if (uap == NULL) { |
721 | ret = -ENOMEM; | 721 | ret = -ENOMEM; |
722 | goto out; | 722 | goto out; |
@@ -728,7 +728,6 @@ static int pl011_probe(struct amba_device *dev, void *id) | |||
728 | goto free; | 728 | goto free; |
729 | } | 729 | } |
730 | 730 | ||
731 | memset(uap, 0, sizeof(struct uart_amba_port)); | ||
732 | uap->clk = clk_get(&dev->dev, "UARTCLK"); | 731 | uap->clk = clk_get(&dev->dev, "UARTCLK"); |
733 | if (IS_ERR(uap->clk)) { | 732 | if (IS_ERR(uap->clk)) { |
734 | ret = PTR_ERR(uap->clk); | 733 | ret = PTR_ERR(uap->clk); |
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c index 94b229031198..7d873b3b0513 100644 --- a/drivers/sh/superhyway/superhyway.c +++ b/drivers/sh/superhyway/superhyway.c | |||
@@ -56,11 +56,10 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev, | |||
56 | struct superhyway_device *dev = sdev; | 56 | struct superhyway_device *dev = sdev; |
57 | 57 | ||
58 | if (!dev) { | 58 | if (!dev) { |
59 | dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); | 59 | dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL); |
60 | if (!dev) | 60 | if (!dev) |
61 | return -ENOMEM; | 61 | return -ENOMEM; |
62 | 62 | ||
63 | memset(dev, 0, sizeof(struct superhyway_device)); | ||
64 | } | 63 | } |
65 | 64 | ||
66 | dev->bus = bus; | 65 | dev->bus = bus; |
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 2dd6eed50aa0..29fcd6d0301d 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c | |||
@@ -629,7 +629,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | |||
629 | #endif | 629 | #endif |
630 | 630 | ||
631 | /* Set up per-IOC3 data */ | 631 | /* Set up per-IOC3 data */ |
632 | idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL); | 632 | idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL); |
633 | if (!idd) { | 633 | if (!idd) { |
634 | printk(KERN_WARNING | 634 | printk(KERN_WARNING |
635 | "%s: Failed to allocate IOC3 data for pci_dev %s.\n", | 635 | "%s: Failed to allocate IOC3 data for pci_dev %s.\n", |
@@ -637,7 +637,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | |||
637 | ret = -ENODEV; | 637 | ret = -ENODEV; |
638 | goto out_idd; | 638 | goto out_idd; |
639 | } | 639 | } |
640 | memset(idd, 0, sizeof(struct ioc3_driver_data)); | ||
641 | spin_lock_init(&idd->ir_lock); | 640 | spin_lock_init(&idd->ir_lock); |
642 | spin_lock_init(&idd->gpio_lock); | 641 | spin_lock_init(&idd->gpio_lock); |
643 | idd->pdev = pdev; | 642 | idd->pdev = pdev; |
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 3e658dc7c2d8..ff9a29b76336 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c | |||
@@ -45,11 +45,10 @@ static int ixj_probe(struct pcmcia_device *p_dev) | |||
45 | p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; | 45 | p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; |
46 | p_dev->io.IOAddrLines = 3; | 46 | p_dev->io.IOAddrLines = 3; |
47 | p_dev->conf.IntType = INT_MEMORY_AND_IO; | 47 | p_dev->conf.IntType = INT_MEMORY_AND_IO; |
48 | p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); | 48 | p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL); |
49 | if (!p_dev->priv) { | 49 | if (!p_dev->priv) { |
50 | return -ENOMEM; | 50 | return -ENOMEM; |
51 | } | 51 | } |
52 | memset(p_dev->priv, 0, sizeof(struct ixj_info_t)); | ||
53 | 52 | ||
54 | return ixj_config(p_dev); | 53 | return ixj_config(p_dev); |
55 | } | 54 | } |
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig new file mode 100644 index 000000000000..b778ed71f636 --- /dev/null +++ b/drivers/uio/Kconfig | |||
@@ -0,0 +1,29 @@ | |||
1 | menu "Userspace I/O" | ||
2 | depends on !S390 | ||
3 | |||
4 | config UIO | ||
5 | tristate "Userspace I/O drivers" | ||
6 | default n | ||
7 | help | ||
8 | Enable this to allow the userspace driver core code to be | ||
9 | built. This code allows userspace programs easy access to | ||
10 | kernel interrupts and memory locations, allowing some drivers | ||
11 | to be written in userspace. Note that a small kernel driver | ||
12 | is also required for interrupt handling to work properly. | ||
13 | |||
14 | If you don't know what to do here, say N. | ||
15 | |||
16 | config UIO_CIF | ||
17 | tristate "generic Hilscher CIF Card driver" | ||
18 | depends on UIO && PCI | ||
19 | default n | ||
20 | help | ||
21 | Driver for Hilscher CIF DeviceNet and Profibus cards. This | ||
22 | driver requires a userspace component that handles all of the | ||
23 | heavy lifting and can be found at: | ||
24 | http://www.osadl.org/projects/downloads/UIO/user/cif-* | ||
25 | |||
26 | To compile this driver as a module, choose M here: the module | ||
27 | will be called uio_cif. | ||
28 | |||
29 | endmenu | ||
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile new file mode 100644 index 000000000000..7fecfb459da5 --- /dev/null +++ b/drivers/uio/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_UIO) += uio.o | ||
2 | obj-$(CONFIG_UIO_CIF) += uio_cif.o | ||
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c new file mode 100644 index 000000000000..865f32b63b5c --- /dev/null +++ b/drivers/uio/uio.c | |||
@@ -0,0 +1,701 @@ | |||
1 | /* | ||
2 | * drivers/uio/uio.c | ||
3 | * | ||
4 | * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> | ||
5 | * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> | ||
6 | * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de> | ||
7 | * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> | ||
8 | * | ||
9 | * Userspace IO | ||
10 | * | ||
11 | * Base Functions | ||
12 | * | ||
13 | * Licensed under the GPLv2 only. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/poll.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/idr.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/kobject.h> | ||
24 | #include <linux/uio_driver.h> | ||
25 | |||
26 | #define UIO_MAX_DEVICES 255 | ||
27 | |||
28 | struct uio_device { | ||
29 | struct module *owner; | ||
30 | struct device *dev; | ||
31 | int minor; | ||
32 | atomic_t event; | ||
33 | struct fasync_struct *async_queue; | ||
34 | wait_queue_head_t wait; | ||
35 | int vma_count; | ||
36 | struct uio_info *info; | ||
37 | struct kset map_attr_kset; | ||
38 | }; | ||
39 | |||
40 | static int uio_major; | ||
41 | static DEFINE_IDR(uio_idr); | ||
42 | static struct file_operations uio_fops; | ||
43 | |||
44 | /* UIO class infrastructure */ | ||
45 | static struct uio_class { | ||
46 | struct kref kref; | ||
47 | struct class *class; | ||
48 | } *uio_class; | ||
49 | |||
50 | /* | ||
51 | * attributes | ||
52 | */ | ||
53 | |||
54 | static struct attribute attr_addr = { | ||
55 | .name = "addr", | ||
56 | .mode = S_IRUGO, | ||
57 | }; | ||
58 | |||
59 | static struct attribute attr_size = { | ||
60 | .name = "size", | ||
61 | .mode = S_IRUGO, | ||
62 | }; | ||
63 | |||
64 | static struct attribute* map_attrs[] = { | ||
65 | &attr_addr, &attr_size, NULL | ||
66 | }; | ||
67 | |||
68 | static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, | ||
69 | char *buf) | ||
70 | { | ||
71 | struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj); | ||
72 | |||
73 | if (strncmp(attr->name,"addr",4) == 0) | ||
74 | return sprintf(buf, "0x%lx\n", mem->addr); | ||
75 | |||
76 | if (strncmp(attr->name,"size",4) == 0) | ||
77 | return sprintf(buf, "0x%lx\n", mem->size); | ||
78 | |||
79 | return -ENODEV; | ||
80 | } | ||
81 | |||
82 | static void map_attr_release(struct kobject *kobj) | ||
83 | { | ||
84 | /* TODO ??? */ | ||
85 | } | ||
86 | |||
87 | static struct sysfs_ops map_attr_ops = { | ||
88 | .show = map_attr_show, | ||
89 | }; | ||
90 | |||
91 | static struct kobj_type map_attr_type = { | ||
92 | .release = map_attr_release, | ||
93 | .sysfs_ops = &map_attr_ops, | ||
94 | .default_attrs = map_attrs, | ||
95 | }; | ||
96 | |||
97 | static ssize_t show_name(struct device *dev, | ||
98 | struct device_attribute *attr, char *buf) | ||
99 | { | ||
100 | struct uio_device *idev = dev_get_drvdata(dev); | ||
101 | if (idev) | ||
102 | return sprintf(buf, "%s\n", idev->info->name); | ||
103 | else | ||
104 | return -ENODEV; | ||
105 | } | ||
106 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
107 | |||
108 | static ssize_t show_version(struct device *dev, | ||
109 | struct device_attribute *attr, char *buf) | ||
110 | { | ||
111 | struct uio_device *idev = dev_get_drvdata(dev); | ||
112 | if (idev) | ||
113 | return sprintf(buf, "%s\n", idev->info->version); | ||
114 | else | ||
115 | return -ENODEV; | ||
116 | } | ||
117 | static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); | ||
118 | |||
119 | static ssize_t show_event(struct device *dev, | ||
120 | struct device_attribute *attr, char *buf) | ||
121 | { | ||
122 | struct uio_device *idev = dev_get_drvdata(dev); | ||
123 | if (idev) | ||
124 | return sprintf(buf, "%u\n", | ||
125 | (unsigned int)atomic_read(&idev->event)); | ||
126 | else | ||
127 | return -ENODEV; | ||
128 | } | ||
129 | static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); | ||
130 | |||
131 | static struct attribute *uio_attrs[] = { | ||
132 | &dev_attr_name.attr, | ||
133 | &dev_attr_version.attr, | ||
134 | &dev_attr_event.attr, | ||
135 | NULL, | ||
136 | }; | ||
137 | |||
138 | static struct attribute_group uio_attr_grp = { | ||
139 | .attrs = uio_attrs, | ||
140 | }; | ||
141 | |||
142 | /* | ||
143 | * device functions | ||
144 | */ | ||
145 | static int uio_dev_add_attributes(struct uio_device *idev) | ||
146 | { | ||
147 | int ret; | ||
148 | int mi; | ||
149 | int map_found = 0; | ||
150 | struct uio_mem *mem; | ||
151 | |||
152 | ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); | ||
153 | if (ret) | ||
154 | goto err_group; | ||
155 | |||
156 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { | ||
157 | mem = &idev->info->mem[mi]; | ||
158 | if (mem->size == 0) | ||
159 | break; | ||
160 | if (!map_found) { | ||
161 | map_found = 1; | ||
162 | kobject_set_name(&idev->map_attr_kset.kobj,"maps"); | ||
163 | idev->map_attr_kset.ktype = &map_attr_type; | ||
164 | idev->map_attr_kset.kobj.parent = &idev->dev->kobj; | ||
165 | ret = kset_register(&idev->map_attr_kset); | ||
166 | if (ret) | ||
167 | goto err_remove_group; | ||
168 | } | ||
169 | kobject_init(&mem->kobj); | ||
170 | kobject_set_name(&mem->kobj,"map%d",mi); | ||
171 | mem->kobj.parent = &idev->map_attr_kset.kobj; | ||
172 | mem->kobj.kset = &idev->map_attr_kset; | ||
173 | ret = kobject_add(&mem->kobj); | ||
174 | if (ret) | ||
175 | goto err_remove_maps; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | |||
180 | err_remove_maps: | ||
181 | for (mi--; mi>=0; mi--) { | ||
182 | mem = &idev->info->mem[mi]; | ||
183 | kobject_unregister(&mem->kobj); | ||
184 | } | ||
185 | kset_unregister(&idev->map_attr_kset); /* Needed ? */ | ||
186 | err_remove_group: | ||
187 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | ||
188 | err_group: | ||
189 | dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static void uio_dev_del_attributes(struct uio_device *idev) | ||
194 | { | ||
195 | int mi; | ||
196 | struct uio_mem *mem; | ||
197 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { | ||
198 | mem = &idev->info->mem[mi]; | ||
199 | if (mem->size == 0) | ||
200 | break; | ||
201 | kobject_unregister(&mem->kobj); | ||
202 | } | ||
203 | kset_unregister(&idev->map_attr_kset); | ||
204 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | ||
205 | } | ||
206 | |||
207 | static int uio_get_minor(struct uio_device *idev) | ||
208 | { | ||
209 | static DEFINE_MUTEX(minor_lock); | ||
210 | int retval = -ENOMEM; | ||
211 | int id; | ||
212 | |||
213 | mutex_lock(&minor_lock); | ||
214 | if (idr_pre_get(&uio_idr, GFP_KERNEL) == 0) | ||
215 | goto exit; | ||
216 | |||
217 | retval = idr_get_new(&uio_idr, idev, &id); | ||
218 | if (retval < 0) { | ||
219 | if (retval == -EAGAIN) | ||
220 | retval = -ENOMEM; | ||
221 | goto exit; | ||
222 | } | ||
223 | idev->minor = id & MAX_ID_MASK; | ||
224 | exit: | ||
225 | mutex_unlock(&minor_lock); | ||
226 | return retval; | ||
227 | } | ||
228 | |||
229 | static void uio_free_minor(struct uio_device *idev) | ||
230 | { | ||
231 | idr_remove(&uio_idr, idev->minor); | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * uio_event_notify - trigger an interrupt event | ||
236 | * @info: UIO device capabilities | ||
237 | */ | ||
238 | void uio_event_notify(struct uio_info *info) | ||
239 | { | ||
240 | struct uio_device *idev = info->uio_dev; | ||
241 | |||
242 | atomic_inc(&idev->event); | ||
243 | wake_up_interruptible(&idev->wait); | ||
244 | kill_fasync(&idev->async_queue, SIGIO, POLL_IN); | ||
245 | } | ||
246 | EXPORT_SYMBOL_GPL(uio_event_notify); | ||
247 | |||
248 | /** | ||
249 | * uio_interrupt - hardware interrupt handler | ||
250 | * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer | ||
251 | * @dev_id: Pointer to the devices uio_device structure | ||
252 | */ | ||
253 | static irqreturn_t uio_interrupt(int irq, void *dev_id) | ||
254 | { | ||
255 | struct uio_device *idev = (struct uio_device *)dev_id; | ||
256 | irqreturn_t ret = idev->info->handler(irq, idev->info); | ||
257 | |||
258 | if (ret == IRQ_HANDLED) | ||
259 | uio_event_notify(idev->info); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | struct uio_listener { | ||
265 | struct uio_device *dev; | ||
266 | s32 event_count; | ||
267 | }; | ||
268 | |||
269 | static int uio_open(struct inode *inode, struct file *filep) | ||
270 | { | ||
271 | struct uio_device *idev; | ||
272 | struct uio_listener *listener; | ||
273 | int ret = 0; | ||
274 | |||
275 | idev = idr_find(&uio_idr, iminor(inode)); | ||
276 | if (!idev) | ||
277 | return -ENODEV; | ||
278 | |||
279 | listener = kmalloc(sizeof(*listener), GFP_KERNEL); | ||
280 | if (!listener) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | listener->dev = idev; | ||
284 | listener->event_count = atomic_read(&idev->event); | ||
285 | filep->private_data = listener; | ||
286 | |||
287 | if (idev->info->open) { | ||
288 | if (!try_module_get(idev->owner)) | ||
289 | return -ENODEV; | ||
290 | ret = idev->info->open(idev->info, inode); | ||
291 | module_put(idev->owner); | ||
292 | } | ||
293 | |||
294 | if (ret) | ||
295 | kfree(listener); | ||
296 | |||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static int uio_fasync(int fd, struct file *filep, int on) | ||
301 | { | ||
302 | struct uio_listener *listener = filep->private_data; | ||
303 | struct uio_device *idev = listener->dev; | ||
304 | |||
305 | return fasync_helper(fd, filep, on, &idev->async_queue); | ||
306 | } | ||
307 | |||
308 | static int uio_release(struct inode *inode, struct file *filep) | ||
309 | { | ||
310 | int ret = 0; | ||
311 | struct uio_listener *listener = filep->private_data; | ||
312 | struct uio_device *idev = listener->dev; | ||
313 | |||
314 | if (idev->info->release) { | ||
315 | if (!try_module_get(idev->owner)) | ||
316 | return -ENODEV; | ||
317 | ret = idev->info->release(idev->info, inode); | ||
318 | module_put(idev->owner); | ||
319 | } | ||
320 | if (filep->f_flags & FASYNC) | ||
321 | ret = uio_fasync(-1, filep, 0); | ||
322 | kfree(listener); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | static unsigned int uio_poll(struct file *filep, poll_table *wait) | ||
327 | { | ||
328 | struct uio_listener *listener = filep->private_data; | ||
329 | struct uio_device *idev = listener->dev; | ||
330 | |||
331 | if (idev->info->irq == UIO_IRQ_NONE) | ||
332 | return -EIO; | ||
333 | |||
334 | poll_wait(filep, &idev->wait, wait); | ||
335 | if (listener->event_count != atomic_read(&idev->event)) | ||
336 | return POLLIN | POLLRDNORM; | ||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static ssize_t uio_read(struct file *filep, char __user *buf, | ||
341 | size_t count, loff_t *ppos) | ||
342 | { | ||
343 | struct uio_listener *listener = filep->private_data; | ||
344 | struct uio_device *idev = listener->dev; | ||
345 | DECLARE_WAITQUEUE(wait, current); | ||
346 | ssize_t retval; | ||
347 | s32 event_count; | ||
348 | |||
349 | if (idev->info->irq == UIO_IRQ_NONE) | ||
350 | return -EIO; | ||
351 | |||
352 | if (count != sizeof(s32)) | ||
353 | return -EINVAL; | ||
354 | |||
355 | add_wait_queue(&idev->wait, &wait); | ||
356 | |||
357 | do { | ||
358 | set_current_state(TASK_INTERRUPTIBLE); | ||
359 | |||
360 | event_count = atomic_read(&idev->event); | ||
361 | if (event_count != listener->event_count) { | ||
362 | if (copy_to_user(buf, &event_count, count)) | ||
363 | retval = -EFAULT; | ||
364 | else { | ||
365 | listener->event_count = event_count; | ||
366 | retval = count; | ||
367 | } | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | if (filep->f_flags & O_NONBLOCK) { | ||
372 | retval = -EAGAIN; | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | if (signal_pending(current)) { | ||
377 | retval = -ERESTARTSYS; | ||
378 | break; | ||
379 | } | ||
380 | schedule(); | ||
381 | } while (1); | ||
382 | |||
383 | __set_current_state(TASK_RUNNING); | ||
384 | remove_wait_queue(&idev->wait, &wait); | ||
385 | |||
386 | return retval; | ||
387 | } | ||
388 | |||
389 | static int uio_find_mem_index(struct vm_area_struct *vma) | ||
390 | { | ||
391 | int mi; | ||
392 | struct uio_device *idev = vma->vm_private_data; | ||
393 | |||
394 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { | ||
395 | if (idev->info->mem[mi].size == 0) | ||
396 | return -1; | ||
397 | if (vma->vm_pgoff == mi) | ||
398 | return mi; | ||
399 | } | ||
400 | return -1; | ||
401 | } | ||
402 | |||
403 | static void uio_vma_open(struct vm_area_struct *vma) | ||
404 | { | ||
405 | struct uio_device *idev = vma->vm_private_data; | ||
406 | idev->vma_count++; | ||
407 | } | ||
408 | |||
409 | static void uio_vma_close(struct vm_area_struct *vma) | ||
410 | { | ||
411 | struct uio_device *idev = vma->vm_private_data; | ||
412 | idev->vma_count--; | ||
413 | } | ||
414 | |||
415 | static struct page *uio_vma_nopage(struct vm_area_struct *vma, | ||
416 | unsigned long address, int *type) | ||
417 | { | ||
418 | struct uio_device *idev = vma->vm_private_data; | ||
419 | struct page* page = NOPAGE_SIGBUS; | ||
420 | |||
421 | int mi = uio_find_mem_index(vma); | ||
422 | if (mi < 0) | ||
423 | return page; | ||
424 | |||
425 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) | ||
426 | page = virt_to_page(idev->info->mem[mi].addr); | ||
427 | else | ||
428 | page = vmalloc_to_page((void*)idev->info->mem[mi].addr); | ||
429 | get_page(page); | ||
430 | if (type) | ||
431 | *type = VM_FAULT_MINOR; | ||
432 | return page; | ||
433 | } | ||
434 | |||
435 | static struct vm_operations_struct uio_vm_ops = { | ||
436 | .open = uio_vma_open, | ||
437 | .close = uio_vma_close, | ||
438 | .nopage = uio_vma_nopage, | ||
439 | }; | ||
440 | |||
441 | static int uio_mmap_physical(struct vm_area_struct *vma) | ||
442 | { | ||
443 | struct uio_device *idev = vma->vm_private_data; | ||
444 | int mi = uio_find_mem_index(vma); | ||
445 | if (mi < 0) | ||
446 | return -EINVAL; | ||
447 | |||
448 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
449 | |||
450 | return remap_pfn_range(vma, | ||
451 | vma->vm_start, | ||
452 | idev->info->mem[mi].addr >> PAGE_SHIFT, | ||
453 | vma->vm_end - vma->vm_start, | ||
454 | vma->vm_page_prot); | ||
455 | } | ||
456 | |||
457 | static int uio_mmap_logical(struct vm_area_struct *vma) | ||
458 | { | ||
459 | vma->vm_flags |= VM_RESERVED; | ||
460 | vma->vm_ops = &uio_vm_ops; | ||
461 | uio_vma_open(vma); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int uio_mmap(struct file *filep, struct vm_area_struct *vma) | ||
466 | { | ||
467 | struct uio_listener *listener = filep->private_data; | ||
468 | struct uio_device *idev = listener->dev; | ||
469 | int mi; | ||
470 | unsigned long requested_pages, actual_pages; | ||
471 | int ret = 0; | ||
472 | |||
473 | if (vma->vm_end < vma->vm_start) | ||
474 | return -EINVAL; | ||
475 | |||
476 | vma->vm_private_data = idev; | ||
477 | |||
478 | mi = uio_find_mem_index(vma); | ||
479 | if (mi < 0) | ||
480 | return -EINVAL; | ||
481 | |||
482 | requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
483 | actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT; | ||
484 | if (requested_pages > actual_pages) | ||
485 | return -EINVAL; | ||
486 | |||
487 | if (idev->info->mmap) { | ||
488 | if (!try_module_get(idev->owner)) | ||
489 | return -ENODEV; | ||
490 | ret = idev->info->mmap(idev->info, vma); | ||
491 | module_put(idev->owner); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | switch (idev->info->mem[mi].memtype) { | ||
496 | case UIO_MEM_PHYS: | ||
497 | return uio_mmap_physical(vma); | ||
498 | case UIO_MEM_LOGICAL: | ||
499 | case UIO_MEM_VIRTUAL: | ||
500 | return uio_mmap_logical(vma); | ||
501 | default: | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | static struct file_operations uio_fops = { | ||
507 | .owner = THIS_MODULE, | ||
508 | .open = uio_open, | ||
509 | .release = uio_release, | ||
510 | .read = uio_read, | ||
511 | .mmap = uio_mmap, | ||
512 | .poll = uio_poll, | ||
513 | .fasync = uio_fasync, | ||
514 | }; | ||
515 | |||
516 | static int uio_major_init(void) | ||
517 | { | ||
518 | uio_major = register_chrdev(0, "uio", &uio_fops); | ||
519 | if (uio_major < 0) | ||
520 | return uio_major; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static void uio_major_cleanup(void) | ||
525 | { | ||
526 | unregister_chrdev(uio_major, "uio"); | ||
527 | } | ||
528 | |||
529 | static int init_uio_class(void) | ||
530 | { | ||
531 | int ret = 0; | ||
532 | |||
533 | if (uio_class != NULL) { | ||
534 | kref_get(&uio_class->kref); | ||
535 | goto exit; | ||
536 | } | ||
537 | |||
538 | /* This is the first time in here, set everything up properly */ | ||
539 | ret = uio_major_init(); | ||
540 | if (ret) | ||
541 | goto exit; | ||
542 | |||
543 | uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); | ||
544 | if (!uio_class) { | ||
545 | ret = -ENOMEM; | ||
546 | goto err_kzalloc; | ||
547 | } | ||
548 | |||
549 | kref_init(&uio_class->kref); | ||
550 | uio_class->class = class_create(THIS_MODULE, "uio"); | ||
551 | if (IS_ERR(uio_class->class)) { | ||
552 | ret = IS_ERR(uio_class->class); | ||
553 | printk(KERN_ERR "class_create failed for uio\n"); | ||
554 | goto err_class_create; | ||
555 | } | ||
556 | return 0; | ||
557 | |||
558 | err_class_create: | ||
559 | kfree(uio_class); | ||
560 | uio_class = NULL; | ||
561 | err_kzalloc: | ||
562 | uio_major_cleanup(); | ||
563 | exit: | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | static void release_uio_class(struct kref *kref) | ||
568 | { | ||
569 | /* Ok, we cheat as we know we only have one uio_class */ | ||
570 | class_destroy(uio_class->class); | ||
571 | kfree(uio_class); | ||
572 | uio_major_cleanup(); | ||
573 | uio_class = NULL; | ||
574 | } | ||
575 | |||
576 | static void uio_class_destroy(void) | ||
577 | { | ||
578 | if (uio_class) | ||
579 | kref_put(&uio_class->kref, release_uio_class); | ||
580 | } | ||
581 | |||
582 | /** | ||
583 | * uio_register_device - register a new userspace IO device | ||
584 | * @owner: module that creates the new device | ||
585 | * @parent: parent device | ||
586 | * @info: UIO device capabilities | ||
587 | * | ||
588 | * returns zero on success or a negative error code. | ||
589 | */ | ||
590 | int __uio_register_device(struct module *owner, | ||
591 | struct device *parent, | ||
592 | struct uio_info *info) | ||
593 | { | ||
594 | struct uio_device *idev; | ||
595 | int ret = 0; | ||
596 | |||
597 | if (!parent || !info || !info->name || !info->version) | ||
598 | return -EINVAL; | ||
599 | |||
600 | info->uio_dev = NULL; | ||
601 | |||
602 | ret = init_uio_class(); | ||
603 | if (ret) | ||
604 | return ret; | ||
605 | |||
606 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | ||
607 | if (!idev) { | ||
608 | ret = -ENOMEM; | ||
609 | goto err_kzalloc; | ||
610 | } | ||
611 | |||
612 | idev->owner = owner; | ||
613 | idev->info = info; | ||
614 | init_waitqueue_head(&idev->wait); | ||
615 | atomic_set(&idev->event, 0); | ||
616 | |||
617 | ret = uio_get_minor(idev); | ||
618 | if (ret) | ||
619 | goto err_get_minor; | ||
620 | |||
621 | idev->dev = device_create(uio_class->class, parent, | ||
622 | MKDEV(uio_major, idev->minor), | ||
623 | "uio%d", idev->minor); | ||
624 | if (IS_ERR(idev->dev)) { | ||
625 | printk(KERN_ERR "UIO: device register failed\n"); | ||
626 | ret = PTR_ERR(idev->dev); | ||
627 | goto err_device_create; | ||
628 | } | ||
629 | dev_set_drvdata(idev->dev, idev); | ||
630 | |||
631 | ret = uio_dev_add_attributes(idev); | ||
632 | if (ret) | ||
633 | goto err_uio_dev_add_attributes; | ||
634 | |||
635 | info->uio_dev = idev; | ||
636 | |||
637 | if (idev->info->irq >= 0) { | ||
638 | ret = request_irq(idev->info->irq, uio_interrupt, | ||
639 | idev->info->irq_flags, idev->info->name, idev); | ||
640 | if (ret) | ||
641 | goto err_request_irq; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | |||
646 | err_request_irq: | ||
647 | uio_dev_del_attributes(idev); | ||
648 | err_uio_dev_add_attributes: | ||
649 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | ||
650 | err_device_create: | ||
651 | uio_free_minor(idev); | ||
652 | err_get_minor: | ||
653 | kfree(idev); | ||
654 | err_kzalloc: | ||
655 | uio_class_destroy(); | ||
656 | return ret; | ||
657 | } | ||
658 | EXPORT_SYMBOL_GPL(__uio_register_device); | ||
659 | |||
660 | /** | ||
661 | * uio_unregister_device - unregister a industrial IO device | ||
662 | * @info: UIO device capabilities | ||
663 | * | ||
664 | */ | ||
665 | void uio_unregister_device(struct uio_info *info) | ||
666 | { | ||
667 | struct uio_device *idev; | ||
668 | |||
669 | if (!info || !info->uio_dev) | ||
670 | return; | ||
671 | |||
672 | idev = info->uio_dev; | ||
673 | |||
674 | uio_free_minor(idev); | ||
675 | |||
676 | if (info->irq >= 0) | ||
677 | free_irq(info->irq, idev); | ||
678 | |||
679 | uio_dev_del_attributes(idev); | ||
680 | |||
681 | dev_set_drvdata(idev->dev, NULL); | ||
682 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | ||
683 | kfree(idev); | ||
684 | uio_class_destroy(); | ||
685 | |||
686 | return; | ||
687 | } | ||
688 | EXPORT_SYMBOL_GPL(uio_unregister_device); | ||
689 | |||
690 | static int __init uio_init(void) | ||
691 | { | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static void __exit uio_exit(void) | ||
696 | { | ||
697 | } | ||
698 | |||
699 | module_init(uio_init) | ||
700 | module_exit(uio_exit) | ||
701 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c new file mode 100644 index 000000000000..838bae460831 --- /dev/null +++ b/drivers/uio/uio_cif.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * UIO Hilscher CIF card driver | ||
3 | * | ||
4 | * (C) 2007 Hans J. Koch <hjk@linutronix.de> | ||
5 | * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de> | ||
6 | * | ||
7 | * Licensed under GPL version 2 only. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/uio_driver.h> | ||
15 | |||
16 | #include <asm/io.h> | ||
17 | |||
18 | #ifndef PCI_DEVICE_ID_PLX_9030 | ||
19 | #define PCI_DEVICE_ID_PLX_9030 0x9030 | ||
20 | #endif | ||
21 | |||
22 | #define PLX9030_INTCSR 0x4C | ||
23 | #define INTSCR_INT1_ENABLE 0x01 | ||
24 | #define INTSCR_INT1_STATUS 0x04 | ||
25 | #define INT1_ENABLED_AND_ACTIVE (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS) | ||
26 | |||
27 | #define PCI_SUBVENDOR_ID_PEP 0x1518 | ||
28 | #define CIF_SUBDEVICE_PROFIBUS 0x430 | ||
29 | #define CIF_SUBDEVICE_DEVICENET 0x432 | ||
30 | |||
31 | |||
32 | static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info) | ||
33 | { | ||
34 | void __iomem *plx_intscr = dev_info->mem[0].internal_addr | ||
35 | + PLX9030_INTCSR; | ||
36 | |||
37 | if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE) | ||
38 | != INT1_ENABLED_AND_ACTIVE) | ||
39 | return IRQ_NONE; | ||
40 | |||
41 | /* Disable interrupt */ | ||
42 | iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr); | ||
43 | return IRQ_HANDLED; | ||
44 | } | ||
45 | |||
46 | static int __devinit hilscher_pci_probe(struct pci_dev *dev, | ||
47 | const struct pci_device_id *id) | ||
48 | { | ||
49 | struct uio_info *info; | ||
50 | |||
51 | info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); | ||
52 | if (!info) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | if (pci_enable_device(dev)) | ||
56 | goto out_free; | ||
57 | |||
58 | if (pci_request_regions(dev, "hilscher")) | ||
59 | goto out_disable; | ||
60 | |||
61 | info->mem[0].addr = pci_resource_start(dev, 0); | ||
62 | if (!info->mem[0].addr) | ||
63 | goto out_release; | ||
64 | info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0), | ||
65 | pci_resource_len(dev, 0)); | ||
66 | if (!info->mem[0].internal_addr) | ||
67 | goto out_release; | ||
68 | |||
69 | info->mem[0].size = pci_resource_len(dev, 0); | ||
70 | info->mem[0].memtype = UIO_MEM_PHYS; | ||
71 | info->mem[1].addr = pci_resource_start(dev, 2); | ||
72 | info->mem[1].size = pci_resource_len(dev, 2); | ||
73 | info->mem[1].memtype = UIO_MEM_PHYS; | ||
74 | switch (id->subdevice) { | ||
75 | case CIF_SUBDEVICE_PROFIBUS: | ||
76 | info->name = "CIF_Profibus"; | ||
77 | break; | ||
78 | case CIF_SUBDEVICE_DEVICENET: | ||
79 | info->name = "CIF_Devicenet"; | ||
80 | break; | ||
81 | default: | ||
82 | info->name = "CIF_???"; | ||
83 | } | ||
84 | info->version = "0.0.1"; | ||
85 | info->irq = dev->irq; | ||
86 | info->irq_flags = IRQF_DISABLED | IRQF_SHARED; | ||
87 | info->handler = hilscher_handler; | ||
88 | |||
89 | if (uio_register_device(&dev->dev, info)) | ||
90 | goto out_unmap; | ||
91 | |||
92 | pci_set_drvdata(dev, info); | ||
93 | |||
94 | return 0; | ||
95 | out_unmap: | ||
96 | iounmap(info->mem[0].internal_addr); | ||
97 | out_release: | ||
98 | pci_release_regions(dev); | ||
99 | out_disable: | ||
100 | pci_disable_device(dev); | ||
101 | out_free: | ||
102 | kfree (info); | ||
103 | return -ENODEV; | ||
104 | } | ||
105 | |||
106 | static void hilscher_pci_remove(struct pci_dev *dev) | ||
107 | { | ||
108 | struct uio_info *info = pci_get_drvdata(dev); | ||
109 | |||
110 | uio_unregister_device(info); | ||
111 | pci_release_regions(dev); | ||
112 | pci_disable_device(dev); | ||
113 | pci_set_drvdata(dev, NULL); | ||
114 | iounmap(info->mem[0].internal_addr); | ||
115 | |||
116 | kfree (info); | ||
117 | } | ||
118 | |||
119 | static struct pci_device_id hilscher_pci_ids[] = { | ||
120 | { | ||
121 | .vendor = PCI_VENDOR_ID_PLX, | ||
122 | .device = PCI_DEVICE_ID_PLX_9030, | ||
123 | .subvendor = PCI_SUBVENDOR_ID_PEP, | ||
124 | .subdevice = CIF_SUBDEVICE_PROFIBUS, | ||
125 | }, | ||
126 | { | ||
127 | .vendor = PCI_VENDOR_ID_PLX, | ||
128 | .device = PCI_DEVICE_ID_PLX_9030, | ||
129 | .subvendor = PCI_SUBVENDOR_ID_PEP, | ||
130 | .subdevice = CIF_SUBDEVICE_DEVICENET, | ||
131 | }, | ||
132 | { 0, } | ||
133 | }; | ||
134 | |||
135 | static struct pci_driver hilscher_pci_driver = { | ||
136 | .name = "hilscher", | ||
137 | .id_table = hilscher_pci_ids, | ||
138 | .probe = hilscher_pci_probe, | ||
139 | .remove = hilscher_pci_remove, | ||
140 | }; | ||
141 | |||
142 | static int __init hilscher_init_module(void) | ||
143 | { | ||
144 | return pci_register_driver(&hilscher_pci_driver); | ||
145 | } | ||
146 | |||
147 | static void __exit hilscher_exit_module(void) | ||
148 | { | ||
149 | pci_unregister_driver(&hilscher_pci_driver); | ||
150 | } | ||
151 | |||
152 | module_init(hilscher_init_module); | ||
153 | module_exit(hilscher_exit_module); | ||
154 | |||
155 | MODULE_LICENSE("GPL v2"); | ||
156 | MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger"); | ||
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 73c49362cd47..654857493a82 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -29,13 +29,6 @@ | |||
29 | #include "hcd.h" | 29 | #include "hcd.h" |
30 | #include "usb.h" | 30 | #include "usb.h" |
31 | 31 | ||
32 | #define VERBOSE_DEBUG 0 | ||
33 | |||
34 | #if VERBOSE_DEBUG | ||
35 | #define dev_vdbg dev_dbg | ||
36 | #else | ||
37 | #define dev_vdbg(dev, fmt, args...) do { } while (0) | ||
38 | #endif | ||
39 | 32 | ||
40 | #ifdef CONFIG_HOTPLUG | 33 | #ifdef CONFIG_HOTPLUG |
41 | 34 | ||
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index d6c5f1150ae7..349b8166f34a 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c | |||
@@ -1777,14 +1777,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1777 | } | 1777 | } |
1778 | 1778 | ||
1779 | /* alloc, and start init */ | 1779 | /* alloc, and start init */ |
1780 | dev = kmalloc (sizeof *dev, GFP_KERNEL); | 1780 | dev = kzalloc (sizeof *dev, GFP_KERNEL); |
1781 | if (dev == NULL){ | 1781 | if (dev == NULL){ |
1782 | pr_debug("enomem %s\n", pci_name(pdev)); | 1782 | pr_debug("enomem %s\n", pci_name(pdev)); |
1783 | retval = -ENOMEM; | 1783 | retval = -ENOMEM; |
1784 | goto done; | 1784 | goto done; |
1785 | } | 1785 | } |
1786 | 1786 | ||
1787 | memset(dev, 0, sizeof *dev); | ||
1788 | spin_lock_init(&dev->lock); | 1787 | spin_lock_init(&dev->lock); |
1789 | dev->pdev = pdev; | 1788 | dev->pdev = pdev; |
1790 | dev->gadget.ops = &goku_ops; | 1789 | dev->gadget.ops = &goku_ops; |
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index dd33ff0ae4ce..38138bb9ddb0 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c | |||
@@ -1427,7 +1427,7 @@ static int __init gs_bind(struct usb_gadget *gadget) | |||
1427 | gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; | 1427 | gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; |
1428 | } | 1428 | } |
1429 | 1429 | ||
1430 | gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); | 1430 | gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL); |
1431 | if (dev == NULL) | 1431 | if (dev == NULL) |
1432 | return -ENOMEM; | 1432 | return -ENOMEM; |
1433 | 1433 | ||
@@ -1435,7 +1435,6 @@ static int __init gs_bind(struct usb_gadget *gadget) | |||
1435 | init_utsname()->sysname, init_utsname()->release, | 1435 | init_utsname()->sysname, init_utsname()->release, |
1436 | gadget->name); | 1436 | gadget->name); |
1437 | 1437 | ||
1438 | memset(dev, 0, sizeof(struct gs_dev)); | ||
1439 | dev->dev_gadget = gadget; | 1438 | dev->dev_gadget = gadget; |
1440 | spin_lock_init(&dev->dev_lock); | 1439 | spin_lock_init(&dev->dev_lock); |
1441 | INIT_LIST_HEAD(&dev->dev_req_list); | 1440 | INIT_LIST_HEAD(&dev->dev_req_list); |
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2038125b7f8c..6edf4097d2d2 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -171,11 +171,10 @@ static int ohci_urb_enqueue ( | |||
171 | } | 171 | } |
172 | 172 | ||
173 | /* allocate the private part of the URB */ | 173 | /* allocate the private part of the URB */ |
174 | urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), | 174 | urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), |
175 | mem_flags); | 175 | mem_flags); |
176 | if (!urb_priv) | 176 | if (!urb_priv) |
177 | return -ENOMEM; | 177 | return -ENOMEM; |
178 | memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); | ||
179 | INIT_LIST_HEAD (&urb_priv->pending); | 178 | INIT_LIST_HEAD (&urb_priv->pending); |
180 | urb_priv->length = size; | 179 | urb_priv->length = size; |
181 | urb_priv->ed = ed; | 180 | urb_priv->ed = ed; |
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 2d0e73b20099..5da63f535005 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c | |||
@@ -278,10 +278,9 @@ static int sl811_cs_probe(struct pcmcia_device *link) | |||
278 | { | 278 | { |
279 | local_info_t *local; | 279 | local_info_t *local; |
280 | 280 | ||
281 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 281 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); |
282 | if (!local) | 282 | if (!local) |
283 | return -ENOMEM; | 283 | return -ENOMEM; |
284 | memset(local, 0, sizeof(local_info_t)); | ||
285 | local->p_dev = link; | 284 | local->p_dev = link; |
286 | link->priv = local; | 285 | link->priv = local; |
287 | 286 | ||
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 6c9dc2e69c82..a7a1c891bfa2 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c | |||
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id) | |||
447 | goto out; | 447 | goto out; |
448 | } | 448 | } |
449 | 449 | ||
450 | fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); | 450 | fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL); |
451 | if (!fb) { | 451 | if (!fb) { |
452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); | 452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); |
453 | ret = -ENOMEM; | 453 | ret = -ENOMEM; |
454 | goto free_region; | 454 | goto free_region; |
455 | } | 455 | } |
456 | memset(fb, 0, sizeof(struct clcd_fb)); | ||
457 | 456 | ||
458 | fb->dev = dev; | 457 | fb->dev = dev; |
459 | fb->board = board; | 458 | fb->board = board; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index ef330e34d031..0c7bf75732ea 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -2937,12 +2937,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, | |||
2937 | /* nothing */ ; | 2937 | /* nothing */ ; |
2938 | j = i + 4; | 2938 | j = i + 4; |
2939 | 2939 | ||
2940 | par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC); | 2940 | par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC); |
2941 | if (!par->mmap_map) { | 2941 | if (!par->mmap_map) { |
2942 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); | 2942 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); |
2943 | return -ENOMEM; | 2943 | return -ENOMEM; |
2944 | } | 2944 | } |
2945 | memset(par->mmap_map, 0, j * sizeof(*par->mmap_map)); | ||
2946 | 2945 | ||
2947 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { | 2946 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { |
2948 | struct resource *rp = &pdev->resource[i]; | 2947 | struct resource *rp = &pdev->resource[i]; |
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index dbf4ec3f6d57..03e57ef88378 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c | |||
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) | |||
1589 | return -EFAULT; | 1589 | return -EFAULT; |
1590 | } | 1590 | } |
1591 | 1591 | ||
1592 | fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | 1592 | fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL); |
1593 | if (!fbi->pseudo_palette) { | 1593 | if (!fbi->pseudo_palette) { |
1594 | return -ENOMEM; | 1594 | return -ENOMEM; |
1595 | } | 1595 | } |
1596 | memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); | ||
1597 | 1596 | ||
1598 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | 1597 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { |
1599 | print_err("Fail to allocate colormap (%d entries)", | 1598 | print_err("Fail to allocate colormap (%d entries)", |
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 50b78af0fa24..dea6579941b7 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void) | |||
366 | if (fb_get_options("clps711xfb", NULL)) | 366 | if (fb_get_options("clps711xfb", NULL)) |
367 | return -ENODEV; | 367 | return -ENODEV; |
368 | 368 | ||
369 | cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); | 369 | cfb = kzalloc(sizeof(*cfb), GFP_KERNEL); |
370 | if (!cfb) | 370 | if (!cfb) |
371 | goto out; | 371 | goto out; |
372 | 372 | ||
373 | memset(cfb, 0, sizeof(*cfb)); | ||
374 | strcpy(cfb->fix.id, "clps711x"); | 373 | strcpy(cfb->fix.id, "clps711x"); |
375 | 374 | ||
376 | cfb->fbops = &clps7111fb_ops; | 375 | cfb->fbops = &clps7111fb_ops; |
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 7a6eeda5ae9a..30ede6e8830f 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) | |||
1221 | { | 1221 | { |
1222 | struct cfb_info *cfb; | 1222 | struct cfb_info *cfb; |
1223 | 1223 | ||
1224 | cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL); | 1224 | cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL); |
1225 | if (!cfb) | 1225 | if (!cfb) |
1226 | return NULL; | 1226 | return NULL; |
1227 | 1227 | ||
1228 | memset(cfb, 0, sizeof(struct cfb_info)); | ||
1229 | 1228 | ||
1230 | cfb->id = id; | 1229 | cfb->id = id; |
1231 | 1230 | ||
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 0f88c30f94f8..f9300266044d 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c | |||
@@ -1082,13 +1082,12 @@ static int __init pvr2fb_init(void) | |||
1082 | #endif | 1082 | #endif |
1083 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); | 1083 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); |
1084 | 1084 | ||
1085 | fb_info = kmalloc(size, GFP_KERNEL); | 1085 | fb_info = kzalloc(size, GFP_KERNEL); |
1086 | if (!fb_info) { | 1086 | if (!fb_info) { |
1087 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); | 1087 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); |
1088 | return -ENOMEM; | 1088 | return -ENOMEM; |
1089 | } | 1089 | } |
1090 | 1090 | ||
1091 | memset(fb_info, 0, size); | ||
1092 | 1091 | ||
1093 | currentpar = (struct pvr2fb_par *)(fb_info + 1); | 1092 | currentpar = (struct pvr2fb_par *)(fb_info + 1); |
1094 | 1093 | ||
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 3d7507ad55f6..b855f4a34afe 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info, | |||
2174 | 2174 | ||
2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
2176 | /* FIFO size + padding for commands */ | 2176 | /* FIFO size + padding for commands */ |
2177 | info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL); | 2177 | info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL); |
2178 | 2178 | ||
2179 | err = -ENOMEM; | 2179 | err = -ENOMEM; |
2180 | if (info->pixmap.addr) { | 2180 | if (info->pixmap.addr) { |
2181 | memset(info->pixmap.addr, 0, 8*1024); | ||
2182 | info->pixmap.size = 8*1024; | 2181 | info->pixmap.size = 8*1024; |
2183 | info->pixmap.scan_align = 4; | 2182 | info->pixmap.scan_align = 4; |
2184 | info->pixmap.buf_align = 4; | 2183 | info->pixmap.buf_align = 4; |
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index ad66f070acb8..7b0cef9ca8f9 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c | |||
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void) | |||
356 | } | 356 | } |
357 | #endif /* ppc (!CONFIG_MAC) */ | 357 | #endif /* ppc (!CONFIG_MAC) */ |
358 | 358 | ||
359 | p = kmalloc(sizeof(*p), GFP_ATOMIC); | 359 | p = kzalloc(sizeof(*p), GFP_ATOMIC); |
360 | if (p == 0) | 360 | if (p == 0) |
361 | return -ENOMEM; | 361 | return -ENOMEM; |
362 | memset(p, 0, sizeof(*p)); | ||
363 | 362 | ||
364 | /* Map in frame buffer and registers */ | 363 | /* Map in frame buffer and registers */ |
365 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { | 364 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { |
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 6f9d880ab2e9..d356da5709fc 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c | |||
@@ -164,7 +164,7 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi | |||
164 | if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400) | 164 | if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400) |
165 | return -ENODEV; | 165 | return -ENODEV; |
166 | 166 | ||
167 | dev = kmalloc(sizeof(struct matrox_device) + | 167 | dev = kzalloc(sizeof(struct matrox_device) + |
168 | sizeof(struct w1_bus_master), GFP_KERNEL); | 168 | sizeof(struct w1_bus_master), GFP_KERNEL); |
169 | if (!dev) { | 169 | if (!dev) { |
170 | dev_err(&pdev->dev, | 170 | dev_err(&pdev->dev, |
@@ -173,7 +173,6 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi | |||
173 | return -ENOMEM; | 173 | return -ENOMEM; |
174 | } | 174 | } |
175 | 175 | ||
176 | memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master)); | ||
177 | 176 | ||
178 | dev->bus_master = (struct w1_bus_master *)(dev + 1); | 177 | dev->bus_master = (struct w1_bus_master *)(dev + 1); |
179 | 178 | ||
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index cab56005dd49..858c16a544c2 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c | |||
@@ -266,10 +266,9 @@ static int w1_f23_add_slave(struct w1_slave *sl) | |||
266 | #ifdef CONFIG_W1_SLAVE_DS2433_CRC | 266 | #ifdef CONFIG_W1_SLAVE_DS2433_CRC |
267 | struct w1_f23_data *data; | 267 | struct w1_f23_data *data; |
268 | 268 | ||
269 | data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL); | 269 | data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL); |
270 | if (!data) | 270 | if (!data) |
271 | return -ENOMEM; | 271 | return -ENOMEM; |
272 | memset(data, 0, sizeof(struct w1_f23_data)); | ||
273 | sl->family_data = data; | 272 | sl->family_data = data; |
274 | 273 | ||
275 | #endif /* CONFIG_W1_SLAVE_DS2433_CRC */ | 274 | #endif /* CONFIG_W1_SLAVE_DS2433_CRC */ |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c6332108f1c5..8d7ab74170d5 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -520,7 +520,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
520 | int err; | 520 | int err; |
521 | struct w1_netlink_msg msg; | 521 | struct w1_netlink_msg msg; |
522 | 522 | ||
523 | sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL); | 523 | sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL); |
524 | if (!sl) { | 524 | if (!sl) { |
525 | dev_err(&dev->dev, | 525 | dev_err(&dev->dev, |
526 | "%s: failed to allocate new slave device.\n", | 526 | "%s: failed to allocate new slave device.\n", |
@@ -528,7 +528,6 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
528 | return -ENOMEM; | 528 | return -ENOMEM; |
529 | } | 529 | } |
530 | 530 | ||
531 | memset(sl, 0, sizeof(*sl)); | ||
532 | 531 | ||
533 | sl->owner = THIS_MODULE; | 532 | sl->owner = THIS_MODULE; |
534 | sl->master = dev; | 533 | sl->master = dev; |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 258defdb2efd..2fbd8dd16df5 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -41,7 +41,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
41 | /* | 41 | /* |
42 | * We are in process context(kernel thread), so can sleep. | 42 | * We are in process context(kernel thread), so can sleep. |
43 | */ | 43 | */ |
44 | dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL); | 44 | dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL); |
45 | if (!dev) { | 45 | if (!dev) { |
46 | printk(KERN_ERR | 46 | printk(KERN_ERR |
47 | "Failed to allocate %zd bytes for new w1 device.\n", | 47 | "Failed to allocate %zd bytes for new w1 device.\n", |
@@ -49,7 +49,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
49 | return NULL; | 49 | return NULL; |
50 | } | 50 | } |
51 | 51 | ||
52 | memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | ||
53 | 52 | ||
54 | dev->bus_master = (struct w1_bus_master *)(dev + 1); | 53 | dev->bus_master = (struct w1_bus_master *)(dev + 1); |
55 | 54 | ||