diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-09-23 00:56:09 -0400 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2005-09-23 00:56:09 -0400 |
commit | c0a59491daca7db11d49edad1a1cefaaa7120a9e (patch) | |
tree | ea7947639fd442a15f57962f4350998b3c2ccbb3 /arch/ppc64 | |
parent | f6ab9c68406dfcd1fcd0a5352244fcb932b113b1 (diff) |
ppc64 iSeries: Create a fake flat device tree on iSeries
This patch adds infrastructure for creating a fake flattened device tree
on iSeries.
We also need to build prom.o for iSeries which means we'll always need it.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Diffstat (limited to 'arch/ppc64')
-rw-r--r-- | arch/ppc64/kernel/iSeries_setup.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index 49d0f9999682..99e4307affd6 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c | |||
@@ -912,7 +912,144 @@ struct machdep_calls __initdata iseries_md = { | |||
912 | /* XXX Implement enable_pmcs for iSeries */ | 912 | /* XXX Implement enable_pmcs for iSeries */ |
913 | }; | 913 | }; |
914 | 914 | ||
915 | struct blob { | ||
916 | unsigned char data[PAGE_SIZE]; | ||
917 | unsigned long next; | ||
918 | }; | ||
919 | |||
920 | struct iseries_flat_dt { | ||
921 | struct boot_param_header header; | ||
922 | u64 reserve_map[2]; | ||
923 | struct blob dt; | ||
924 | struct blob strings; | ||
925 | }; | ||
926 | |||
927 | struct iseries_flat_dt iseries_dt; | ||
928 | |||
929 | void dt_init(struct iseries_flat_dt *dt) | ||
930 | { | ||
931 | dt->header.off_mem_rsvmap = | ||
932 | offsetof(struct iseries_flat_dt, reserve_map); | ||
933 | dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt); | ||
934 | dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings); | ||
935 | dt->header.totalsize = sizeof(struct iseries_flat_dt); | ||
936 | dt->header.dt_strings_size = sizeof(struct blob); | ||
937 | |||
938 | /* There is no notion of hardware cpu id on iSeries */ | ||
939 | dt->header.boot_cpuid_phys = smp_processor_id(); | ||
940 | |||
941 | dt->dt.next = (unsigned long)&dt->dt.data; | ||
942 | dt->strings.next = (unsigned long)&dt->strings.data; | ||
943 | |||
944 | dt->header.magic = OF_DT_HEADER; | ||
945 | dt->header.version = 0x10; | ||
946 | dt->header.last_comp_version = 0x10; | ||
947 | |||
948 | dt->reserve_map[0] = 0; | ||
949 | dt->reserve_map[1] = 0; | ||
950 | } | ||
951 | |||
952 | void dt_check_blob(struct blob *b) | ||
953 | { | ||
954 | if (b->next >= (unsigned long)&b->next) { | ||
955 | DBG("Ran out of space in flat device tree blob!\n"); | ||
956 | BUG(); | ||
957 | } | ||
958 | } | ||
959 | |||
960 | void dt_push_u32(struct iseries_flat_dt *dt, u32 value) | ||
961 | { | ||
962 | *((u32*)dt->dt.next) = value; | ||
963 | dt->dt.next += sizeof(u32); | ||
964 | |||
965 | dt_check_blob(&dt->dt); | ||
966 | } | ||
967 | |||
968 | void dt_push_u64(struct iseries_flat_dt *dt, u64 value) | ||
969 | { | ||
970 | *((u64*)dt->dt.next) = value; | ||
971 | dt->dt.next += sizeof(u64); | ||
972 | |||
973 | dt_check_blob(&dt->dt); | ||
974 | } | ||
975 | |||
976 | unsigned long dt_push_bytes(struct blob *blob, char *data, int len) | ||
977 | { | ||
978 | unsigned long start = blob->next - (unsigned long)blob->data; | ||
979 | |||
980 | memcpy((char *)blob->next, data, len); | ||
981 | blob->next = _ALIGN(blob->next + len, 4); | ||
982 | |||
983 | dt_check_blob(blob); | ||
984 | |||
985 | return start; | ||
986 | } | ||
987 | |||
988 | void dt_start_node(struct iseries_flat_dt *dt, char *name) | ||
989 | { | ||
990 | dt_push_u32(dt, OF_DT_BEGIN_NODE); | ||
991 | dt_push_bytes(&dt->dt, name, strlen(name) + 1); | ||
992 | } | ||
993 | |||
994 | #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) | ||
995 | |||
996 | void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len) | ||
997 | { | ||
998 | unsigned long offset; | ||
999 | |||
1000 | dt_push_u32(dt, OF_DT_PROP); | ||
1001 | |||
1002 | /* Length of the data */ | ||
1003 | dt_push_u32(dt, len); | ||
1004 | |||
1005 | /* Put the property name in the string blob. */ | ||
1006 | offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1); | ||
1007 | |||
1008 | /* The offset of the properties name in the string blob. */ | ||
1009 | dt_push_u32(dt, (u32)offset); | ||
1010 | |||
1011 | /* The actual data. */ | ||
1012 | dt_push_bytes(&dt->dt, data, len); | ||
1013 | } | ||
1014 | |||
1015 | void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data) | ||
1016 | { | ||
1017 | dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */ | ||
1018 | } | ||
1019 | |||
1020 | void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data) | ||
1021 | { | ||
1022 | dt_prop(dt, name, (char *)&data, sizeof(u32)); | ||
1023 | } | ||
1024 | |||
1025 | void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data) | ||
1026 | { | ||
1027 | dt_prop(dt, name, (char *)&data, sizeof(u64)); | ||
1028 | } | ||
1029 | |||
1030 | void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n) | ||
1031 | { | ||
1032 | dt_prop(dt, name, (char *)data, sizeof(u64) * n); | ||
1033 | } | ||
1034 | |||
1035 | void dt_prop_empty(struct iseries_flat_dt *dt, char *name) | ||
1036 | { | ||
1037 | dt_prop(dt, name, NULL, 0); | ||
1038 | } | ||
1039 | |||
1040 | void build_flat_dt(struct iseries_flat_dt *dt) | ||
1041 | { | ||
1042 | dt_init(dt); | ||
1043 | |||
1044 | dt_start_node(dt, ""); | ||
1045 | dt_end_node(dt); | ||
1046 | |||
1047 | dt_push_u32(dt, OF_DT_END); | ||
1048 | } | ||
1049 | |||
915 | void __init iSeries_early_setup(void) | 1050 | void __init iSeries_early_setup(void) |
916 | { | 1051 | { |
917 | iSeries_fixup_klimit(); | 1052 | iSeries_fixup_klimit(); |
1053 | |||
1054 | build_flat_dt(&iseries_dt); | ||
918 | } | 1055 | } |