From 03fed4d1c8b29648079e98e7e5369d9be556f19e Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 4 Oct 2017 09:11:26 +0900 Subject: [PATCH] automatically generate hfi structs from dwarf info --- .gitignore | 1 + kernel/chip.c | 2 +- kernel/file_ops.c | 2 +- kernel/include/hfi1/hfi.h | 423 +------------ kernel/include/hfi1/hfi1_generated_structs.h | 100 +++ kernel/script/dwarf-extract-struct.c | 614 +++++++++++++++++++ kernel/script/regenerate_hfi1_header.sh | 38 ++ kernel/user_sdma.c | 4 +- 8 files changed, 780 insertions(+), 404 deletions(-) create mode 100644 kernel/include/hfi1/hfi1_generated_structs.h create mode 100644 kernel/script/dwarf-extract-struct.c create mode 100755 kernel/script/regenerate_hfi1_header.sh diff --git a/.gitignore b/.gitignore index c304f0c6..c30cdcff 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ elfboot/elfboot_test linux/executer/mcexec linux/mod_test* linux/target +kernel/script/dwarf-extract-struct diff --git a/kernel/chip.c b/kernel/chip.c index c4a1b4c4..2da2a048 100644 --- a/kernel/chip.c +++ b/kernel/chip.c @@ -71,7 +71,7 @@ void hfi1_put_tid(struct hfi1_devdata *dd, u32 index, { u64 reg; void __iomem *base = (dd->rcvarray_wc ? dd->rcvarray_wc : - (dd->kregbase + RCV_ARRAY)); + (dd->kregbase1 + RCV_ARRAY)); if (!(dd->flags & HFI1_PRESENT)) goto done; diff --git a/kernel/file_ops.c b/kernel/file_ops.c index 26c5d163..ce65e2d1 100644 --- a/kernel/file_ops.c +++ b/kernel/file_ops.c @@ -1187,7 +1187,7 @@ static int find_shared_ctxt(struct file *fp, for (ndev = 0; ndev < devmax; ndev++) { struct hfi1_devdata *dd = hfi1_lookup(ndev); - if (!(dd && (dd->flags & HFI1_PRESENT) && dd->kregbase)) + if (!(dd && (dd->flags & HFI1_PRESENT) && dd->kregbase1)) continue; for (i = dd->first_user_ctxt; i < dd->num_rcv_contexts; i++) { struct hfi1_ctxtdata *uctxt = dd->rcd[i]; diff --git a/kernel/include/hfi1/hfi.h b/kernel/include/hfi1/hfi.h index 727f8693..b7c4ab6b 100644 --- a/kernel/include/hfi1/hfi.h +++ b/kernel/include/hfi1/hfi.h @@ -137,30 +137,6 @@ struct exp_tid_set { u32 count; }; -//TODO: Fix hfi1_ctxtdata and pport -#ifndef __HFI1_ORIG__ -struct hfi1_ctxtdata { - char __padding0[144]; - unsigned ctxt; - char __padding1[172-148]; - /* number of RcvArray groups for this context. */ - u32 rcv_array_groups; - /* index of first eager TID entry. */ - u32 eager_base; - /* number of expected TID entries */ - u32 expected_count; - /* index of first expected TID entry. */ - u32 expected_base; - - struct exp_tid_set tid_group_list; - struct exp_tid_set tid_used_list; - struct exp_tid_set tid_full_list; - - char __padding2[432-264]; - struct hfi1_devdata *dd; -}; -#endif /* !__HFI1_ORIG__ */ - /* * Get/Set IB link-level config parameters for f_get/set_ib_cfg() * Mostly for MADs that set or query link parameters, also ipath @@ -301,24 +277,6 @@ static inline void incr_cntr32(u32 *cntr) #define MAX_NAME_SIZE 64 -#ifndef __HFI1_ORIG__ -struct hfi1_pportdata { - char _padding[1907]; // TODO: compute this offset automatically from kernel we're basing off -/* -$ objdump --dwarf $(modinfo -n hfi1) | \ -awk '/DW_AT_name.*: vls_operational/ { - while (getline) { - if (/DW_AT_data_member_location/) { - print $NF; exit; - } - } -}' --> 1899 - */ - u8 vls_operational; -}; -#endif /* __HFI1_ORIG__ */ - struct rcv_array_data { u8 group_size; u16 ngroups; @@ -333,347 +291,7 @@ struct rcv_array_data { #define BOARD_VERS_MAX 96 /* how long the version string can be */ #define SERIAL_MAX 16 /* length of the serial number */ -/* Size on Linux side is 7360 Bytes */ -struct hfi1_devdata { - char verbs_dev[2624]; //struct hfi1_ibdev verbs_dev - struct list_head list; - /* pointers to related structs for this device */ - /* pci access data structure */ - void *pcidev; // struct pci_dev *pcidev; - char user_cdev[104]; //struct cdev user_cdev - char diag_cdev[104]; //struct cdev diag_cdev - char ui_cdev[104]; //struct cdev ui_cdev - void *user_device; //struct device *user_device; - void *diag_device; //struct device *diag_device; - void *ui_device; //struct device *ui_device; - - - u8 __iomem *kregbase; - resource_size_t physaddr; - - /* second uncached mapping from RcvArray to pio send buffers */ - u8 __iomem *kregend; - /* for detecting offset above kregbase2 address */ - u32 base2_start; - /* Per VL data. Enough for all VLs but not all elements are set/used. */ - char vld[16 * PER_VL_SEND_CONTEXTS]; //struct per_vl_data vld[PER_VL_SEND_CONTEXTS] - /* send context data */ - void *send_contexts; //struct send_context_info *send_contexts; - - /* map hardware send contexts to software index */ - u8 *hw_to_sw; - /* spinlock for allocating and releasing send context resources */ - spinlock_t sc_lock; - /* lock for pio_map */ - spinlock_t pio_map_lock; - /* Send Context initialization lock. */ - spinlock_t sc_init_lock; - /* lock for sdma_map */ - spinlock_t sde_map_lock; - /* array of kernel send contexts */ - void **kernel_send_context; //struct send_context **kernel_send_context; - - void __rcu *pio_map; //struct pio_vl_map __rcu *pio_map - /* default flags to last descriptor */ - u64 default_desc1; - - /* fields common to all SDMA engines */ - - volatile __le64 *sdma_heads_dma; /* DMA'ed by chip */ - dma_addr_t sdma_heads_phys; - void *sdma_pad_dma; /* DMA'ed by chip */ - dma_addr_t sdma_pad_phys; - /* for deallocation */ - size_t sdma_heads_size; - /* number from the chip */ - u32 chip_sdma_engines; - /* num used */ - u32 num_sdma; - /* array of engines sized by num_sdma */ - struct sdma_engine *per_sdma; - /* array of vl maps */ - struct sdma_vl_map __rcu *sdma_map; //struct sdma_vl_map __rc *sdma_map - /* SPC freeze waitqueue and variable */ - wait_queue_head_t sdma_unfreeze_wq; - atomic_t sdma_unfreeze_count; - - u32 lcb_access_count; - - - void *asic_data; //struct hfi1_asic_data *asic_data; - - - /* mem-mapped pointer to base of PIO buffers */ - void __iomem *piobase; - /* - * write-combining mem-mapped pointer to base of RcvArray - * memory. - */ - void __iomem *rcvarray_wc; - /* - * credit return base - a per-NUMA range of DMA address that - * the chip will use to update the per-context free counter - */ - void *cr_base; //struct credit_return_base *cr_base; - - char sc_sizes[4 * SC_MAX]; //struct sc_config_sizes sc_sizes[SC_MAX] - - char *boardname; - - - u64 z_int_counter; - u64 z_rcv_limit; - u64 z_send_schedule; - - u64 __percpu *send_schedule; - /* number of receive contexts in use by the driver */ - - u32 num_rcv_contexts; - /* number of pio send contexts in use by the driver */ - - u32 num_send_contexts; - /* - * number of ctxts available for PSM open - */ - u32 freectxts; - /* total number of available user/PSM contexts */ - u32 num_user_contexts; - /* base receive interrupt timeout, in CSR units */ - u32 rcv_intr_timeout_csr; - - u32 freezelen; /* max length of freezemsg */ - u64 __iomem *egrtidbase; - spinlock_t sendctrl_lock; - spinlock_t rcvctrl_lock; - - spinlock_t uctxt_lock; - - char dc8051_lock[40]; // struct mutex dc8051_lock; /* exclusive access to 8051 */ - struct workqueue_struct *update_cntr_wq; - char update_cntr_work[32]; // struct work_struct update_cntr_work; - - spinlock_t dc8051_memlock; - int dc8051_timed_out; - unsigned long *events; - void *status; //struct hfi1_status *status; - - - u64 revision; - - u64 base_guid; - - - - - u32 rcvhdrsize; - - u32 chip_rcv_contexts; - - u32 chip_rcv_array_count; - - u32 chip_send_contexts; - - u32 chip_pio_mem_size; - - u32 chip_sdma_mem_size; - - - u32 rcvegrbufsize; - - u16 rcvegrbufsize_shift; - - u8 link_gen3_capable; - - u8 link_default; - - u32 lbus_width; - - u32 lbus_speed; - int unit; - int node; - - - u32 pcibar0; - u32 pcibar1; - u32 pci_rom; - u16 pci_command; - u16 pcie_devctl; - u16 pcie_lnkctl; - u16 pcie_devctl2; - u32 pci_msix0; - u32 pci_lnkctl3; - u32 pci_tph2; - u8 serial[SERIAL_MAX]; - - u8 boardversion[BOARD_VERS_MAX]; - u8 lbus_info[32]; - - u8 majrev; - - u8 minrev; - - u8 hfi1_id; - - u8 icode; - - u8 vau; - - u8 vcu; - - u16 link_credits; - /* initial vl15 credits to use */ - u16 vl15_init; - /* - * Cached value for vl15buf, read during verify cap interrupt. VL15 - * credits are to be kept at 0 and set when handling the link-up - * interrupt. This removes the possibility of receiving VL15 MAD - * packets before this HFI is ready. - */ - u16 vl15buf_cached; - - - u8 n_krcv_queues; - u8 qos_shift; - - u16 irev; - u32 dc8051_ver; /* 8051 firmware version */ - - spinlock_t hfi1_diag_trans_lock; - char platform_config[16]; //struct platform_config platform_config - char pcfg_cache[176]; //struct platform_config_cache pcfg_cache - - void *diag_client; //struct diag_client *diag_client; - - - void *msix_entries; //struct hfi1_msix_entry *msix_entries; - u32 num_msix_entries; - - /* INTx information */ - u32 requested_intx_irq; - char intx_name[MAX_NAME_SIZE]; - - /* general interrupt: mask of handled interrupts */ - u64 gi_mask[CCE_NUM_INT_CSRS]; - - struct rcv_array_data rcv_entries; - - - u16 psxmitwait_check_rate; - char synth_stats_timer[80]; //struct timer_list synth_stats_timer - char *cntrnames; - size_t cntrnameslen; - size_t ndevcntrs; - u64 *cntrs; - u64 *scntrs; - u64 last_tx; - u64 last_rx; - size_t nportcntrs; - char *portcntrnames; - size_t portcntrnameslen; - - char hfi1_snoop[192]; //struct hfi1_snoop_data hfi1_snoop - - char err_info_rcvport[24]; //struct err_info_rcvport err_info_rcvport - char err_info_rcv_constraint[8]; //struct err_info_constraint err_info_rcv_constraint - char err_info_xmit_constraint[8]; //struct err_info_constraint err_info_xmit_constraint - - atomic_t drop_packet; - u8 do_drop; - u8 err_info_uncorrectable; - u8 err_info_fmconfig; - u64 cce_err_status_cnt[NUM_CCE_ERR_STATUS_COUNTERS]; - u64 rcv_err_status_cnt[NUM_RCV_ERR_STATUS_COUNTERS]; - u64 misc_err_status_cnt[NUM_MISC_ERR_STATUS_COUNTERS]; - u64 send_pio_err_status_cnt[NUM_SEND_PIO_ERR_STATUS_COUNTERS]; - u64 send_dma_err_status_cnt[NUM_SEND_DMA_ERR_STATUS_COUNTERS]; - u64 send_egress_err_status_cnt[NUM_SEND_EGRESS_ERR_STATUS_COUNTERS]; - u64 send_err_status_cnt[NUM_SEND_ERR_STATUS_COUNTERS]; - - - u64 sw_ctxt_err_status_cnt[NUM_SEND_CTXT_ERR_STATUS_COUNTERS]; - - u64 sw_send_dma_eng_err_status_cnt[ - NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS]; - - u64 sw_cce_err_status_aggregate; - - u64 sw_rcv_bypass_packet_errors; - - void *rnormal_rhf_rcv_functions[8]; //hf_rcv_function_ptr normal_rhf_rcv_functions[8] - - u64 lcb_err_en; - send_routine process_pio_send ____cacheline_aligned_in_smp; - send_routine process_dma_send; - void *pio_inline_send; //void (*pio_inline_send)(struct hfi1_devdata *dd, struct pio_buf *pbuf,u64 pbc, const void *from, size_t count); - struct hfi1_pportdata *pport; - - void **rcd; //struct hfi1_ctxtdata **rcd; - u64 __percpu *int_counter; - - u16 flags; - - u8 num_pports; - - u8 first_user_ctxt; - - - - seqlock_t sc2vl_lock ____cacheline_aligned_in_smp; - u64 sc2vl[4]; - - void *rhf_rcv_function_map; //rhf_rcv_function_ptr *rhf_rcv_function_map - u64 __percpu *rcv_limit; - u16 rhf_offset; - - - - u8 oui1; - u8 oui2; - u8 oui3; - u8 dc_shutdown; - - - char rcverr_timer[80]; //struct timer_list rcverr_timer - - wait_queue_head_t event_queue; - - - __le64 *rcvhdrtail_dummy_kvaddr; - dma_addr_t rcvhdrtail_dummy_dma; - - u32 rcv_ovfl_cnt; - - spinlock_t aspm_lock; - - atomic_t aspm_disabled_cnt; - - atomic_t user_refcount; - - struct completion user_comp; - bool eprom_available; - bool aspm_supported; - bool aspm_enabled; - void *sdma_rht; //struct rhashtable sdma_rht - - char kobj[64]; //struct kobject kobj -}; - -/* USED FILEDS */ -// struct hfi1_devdata { -// struct list_head list; //used -// /* pointers to related structs for this device */ -// /* pci access data structure */ -// struct pci_dev *pcidev; //used -// /* lock for sdma_map */ -// spinlock_t sde_map_lock; //used -// /* array of vl maps */ -// struct sdma_vl_map __rcu *sdma_map; //used -// dma_addr_t sdma_pad_phys; //used -// /* array of engines sized by num_sdma */ -// struct sdma_engine *per_sdma; //used -// struct hfi1_pportdata *pport; //used -// }; -#endif /* __HFI1_ORIG__ */ +#endif /* !__HFI1_ORIG__ */ /* 8051 firmware version helper */ #define dc8051_ver(a, b) ((a) << 8 | (b)) @@ -892,23 +510,6 @@ static inline void pause_for_credit_return(struct hfi1_devdata *dd) udelay(usec ? usec : 1); } -#endif /* __HFI1_ORIG__ */ - -#define OPA_MAX_SCS 32 // from opa_smi.h - -/** - * sc_to_vlt() reverse lookup sc to vl - * @dd - devdata - * @sc5 - 5 bit sc - */ -static inline u8 sc_to_vlt(struct hfi1_devdata *dd, u8 sc5) -{ - if (sc5 >= OPA_MAX_SCS) - return (u8)(0xff); - - return *(((u8 *)dd->sc2vl) + sc5); -} -#ifdef __HFI1_ORIG__ #define PKEY_MEMBER_MASK 0x8000 #define PKEY_LOW_15_MASK 0x7fff @@ -1619,4 +1220,26 @@ __print_symbolic(opcode, \ ib_opcode_name(CNP)) #endif /* __HFI1_ORIG__ */ + +/* This include is at the end of this file on purpose, + * because it needs other structs defined here. + * Except for static inlines that need these types. + */ +#include + +#define OPA_MAX_SCS 32 // from opa_smi.h + +/** + * sc_to_vlt() reverse lookup sc to vl + * @dd - devdata + * @sc5 - 5 bit sc + */ +static inline u8 sc_to_vlt(struct hfi1_devdata *dd, u8 sc5) +{ + if (sc5 >= OPA_MAX_SCS) + return (u8)(0xff); + + return *(((u8 *)dd->sc2vl) + sc5); +} + #endif /* _HFI1_KERNEL_H */ diff --git a/kernel/include/hfi1/hfi1_generated_structs.h b/kernel/include/hfi1/hfi1_generated_structs.h new file mode 100644 index 00000000..25a04116 --- /dev/null +++ b/kernel/include/hfi1/hfi1_generated_structs.h @@ -0,0 +1,100 @@ +struct hfi1_pportdata { + union { + struct { + char padding0[1907]; + u8 vls_operational; + }; + }; +}; +struct hfi1_ctxtdata { + union { + struct { + char padding0[144]; + unsigned int ctxt; + }; + struct { + char padding1[172]; + u32 rcv_array_groups; + }; + struct { + char padding2[176]; + u32 eager_base; + }; + struct { + char padding3[180]; + u32 expected_count; + }; + struct { + char padding4[184]; + u32 expected_base; + }; + struct { + char padding5[192]; + struct exp_tid_set tid_group_list; + }; + struct { + char padding6[216]; + struct exp_tid_set tid_used_list; + }; + struct { + char padding7[240]; + struct exp_tid_set tid_full_list; + }; + struct { + char padding8[432]; + struct hfi1_devdata *dd; + }; + }; +}; +struct hfi1_devdata { + union { + struct { + char padding0[2984]; + u8 *kregbase1; + }; + struct { + char padding1[2992]; + resource_size_t physaddr; + }; + struct { + char padding2[3320]; + u64 default_desc1; + }; + struct { + char padding3[3352]; + dma_addr_t sdma_pad_phys; + }; + struct { + char padding4[3376]; + struct sdma_engine *per_sdma; + }; + struct { + char padding5[3384]; + struct sdma_vl_map *sdma_map; + }; + struct { + char padding6[3432]; + void *piobase; + }; + struct { + char padding7[3440]; + void *rcvarray_wc; + }; + struct { + char padding8[3688]; + u32 chip_rcv_array_count; + }; + struct { + char padding9[6872]; + struct hfi1_pportdata *pport; + }; + struct { + char padding10[6896]; + u16 flags; + }; + struct { + char padding11[6920]; + u64 sc2vl[4]; + }; + }; +}; diff --git a/kernel/script/dwarf-extract-struct.c b/kernel/script/dwarf-extract-struct.c new file mode 100644 index 00000000..1ade375e --- /dev/null +++ b/kernel/script/dwarf-extract-struct.c @@ -0,0 +1,614 @@ +/* + * Trivial dwarf parser to extract part of a struct from debug infos + * + * Author: Dominique Martinet + * License: WTFPLv2 + * + * Canonical source: http://cgit.notk.org/asmadeus/dwarf-extract-struct.git + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libdwarf/dwarf.h" +#include "libdwarf/libdwarf.h" + + +static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, + const char *field_names[], int field_count); +static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, + const char *field_names[], int field_count, int level); +static void find_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, + const char *field_names[], int field_count, int level); +static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name, + int pad_num); + +int debug = 0; + +void usage(const char *argv[]) { + fprintf(stderr, "%s debug_file struct_name field [field...]\n", + argv[0]); +} + +int main(int argc, const char *argv[]) { + Dwarf_Debug dbg = 0; + int fd = -1; + const char *filepath; + const char *struct_name; + int res = DW_DLV_ERROR; + Dwarf_Error error; + Dwarf_Handler errhand = 0; + Dwarf_Ptr errarg = 0; + + if(argc < 4) { + usage(argv); + exit(1); + } + + filepath = argv[1]; + struct_name = argv[2]; + + fd = open(filepath,O_RDONLY); + if(fd < 0) { + fprintf(stderr, "Failure attempting to open %s\n",filepath); + } + res = dwarf_init(fd, DW_DLC_READ, errhand, errarg, &dbg, &error); + if(res != DW_DLV_OK) { + fprintf(stderr, "Giving up, cannot do DWARF processing\n"); + exit(1); + } + + parse_dwarf(dbg, struct_name, argv + 3, argc - 3); + + res = dwarf_finish(dbg,&error); + if(res != DW_DLV_OK) { + fprintf(stderr, "dwarf_finish failed!\n"); + } + close(fd); + return 0; +} + +static void parse_dwarf(Dwarf_Debug dbg, const char *struct_name, + const char *field_names[], int field_count) { + Dwarf_Bool is_info = 1; + Dwarf_Unsigned cu_length; + Dwarf_Half cu_version; + Dwarf_Off cu_abbrev_offset; + Dwarf_Half cu_pointer_size; + Dwarf_Half cu_offset_size; + Dwarf_Half cu_extension_size; + Dwarf_Sig8 type_signature; + Dwarf_Unsigned type_offset; + Dwarf_Unsigned cu_next_offset; + Dwarf_Error err; + int rc; + + + while (1) { + Dwarf_Die die; + + rc = dwarf_next_cu_header_c(dbg, is_info, &cu_length, + &cu_version, &cu_abbrev_offset, &cu_pointer_size, + &cu_offset_size, &cu_extension_size, &type_signature, + &type_offset, &cu_next_offset, &err); + + if (rc == DW_DLV_NO_ENTRY) + break; + if (rc != DW_DLV_OK) { + fprintf(stderr, "error dwarf_next_cu_header_c: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + + rc = dwarf_siblingof(dbg, NULL, &die, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, "first dwarf_siblingof failed: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + find_struct(dbg, die, struct_name, field_names, field_count, 0); + } + + fprintf(stderr, "struct %s not found\n", struct_name); + exit(2); +} + +static void find_struct(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, + const char *field_names[], int field_count, int level) { + Dwarf_Die next; + Dwarf_Error err; + int rc; + + if (level > 1) + return; + + do { + char *name; + const char *tag_name; + Dwarf_Half tag; + + rc = dwarf_diename(die, &name, &err); + if (rc == DW_DLV_NO_ENTRY) { + name = NULL; + } else if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_diename error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + rc = dwarf_tag(die, &tag, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_tag error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + if (debug) { + rc = dwarf_get_TAG_name(tag, &tag_name); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "dwarf_get_TAG_name error: %d\n", rc); + exit(1); + } + + printf("<%d> %p <%d> %s: %s\n", level, die, tag, + tag_name, name ? name : ""); + } + + rc = dwarf_child(die, &next, &err); + if (rc == DW_DLV_ERROR) { + fprintf(stderr, "dwarf_child error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + if (rc == DW_DLV_OK) { + if (tag == DW_TAG_structure_type + && name && strcasecmp(name, struct_name) == 0) { + find_fields(dbg, next, struct_name, field_names, + field_count, level + 1); + fprintf(stderr, + "Found struct %s but it did not have all members given!\nMissing:\n", + struct_name); + for (rc = 0; rc < field_count; rc++) { + if (field_names[rc]) + fprintf(stderr, "%s\n", + field_names[rc]); + } + exit(3); + } + find_struct(dbg, next, struct_name, field_names, + field_count, level + 1); + dwarf_dealloc(dbg, next, DW_DLA_DIE); + } + + + rc = dwarf_siblingof(dbg, die, &next, &err); + dwarf_dealloc(dbg, die, DW_DLA_DIE); + if (name) + dwarf_dealloc(dbg, name, DW_DLA_STRING); + + if (rc != DW_DLV_OK) + break; + + die = next; + } while (die); +} + +static void find_fields(Dwarf_Debug dbg, Dwarf_Die die, const char *struct_name, + const char *field_names[], int field_count, int level) { + Dwarf_Die next; + Dwarf_Error err; + int rc, i, printed_count = 0; + + printf("struct %s {\n\tunion {\n", + struct_name); + + do { + char *name; + const char *tag_name; + Dwarf_Half tag; + + rc = dwarf_diename(die, &name, &err); + if (rc == DW_DLV_NO_ENTRY) { + name = NULL; + } else if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_diename error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + rc = dwarf_tag(die, &tag, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_tag error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(1); + } + + if (debug) { + rc = dwarf_get_TAG_name(tag, &tag_name); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "dwarf_get_TAG_name error: %d\n", rc); + exit(1); + } + + printf("<%d> %p <%d> %s: %s\n", level, die, tag, + tag_name, name ? name : ""); + } + + if (tag == DW_TAG_member && name) { + for (i = 0; i < field_count; i++) { + if (!field_names[i]) + continue; + if (strcasecmp(name, field_names[i]) == 0) { + print_field(dbg, die, field_names[i], + printed_count); + field_names[i] = NULL; + printed_count++; + break; + } + } + if (printed_count == field_count) { + printf("\t};\n};\n"); + exit(0); + } + } + + rc = dwarf_siblingof(dbg, die, &next, &err); + dwarf_dealloc(dbg, die, DW_DLA_DIE); + if (name) + dwarf_dealloc(dbg, name, DW_DLA_STRING); + + if (rc != DW_DLV_OK) + break; + + die = next; + } while (die); +} + + +static int dwarf_get_offset(Dwarf_Debug dbg, Dwarf_Die die, + int *poffset, Dwarf_Error *perr) { + Dwarf_Attribute attr; + Dwarf_Unsigned offset; + int rc; + + rc = dwarf_attr(die, DW_AT_data_member_location, &attr, perr); + if (rc != DW_DLV_OK) { + return rc; + } + Dwarf_Half form; + rc = dwarf_whatform(attr, &form, perr); + if (rc != DW_DLV_OK) { + fprintf(stderr, "Error getting whatform: %s\n", + dwarf_errmsg(*perr)); + exit(5); + } + if (form == DW_FORM_data1 || form == DW_FORM_data2 + || form == DW_FORM_data2 || form == DW_FORM_data4 + || form == DW_FORM_data8 || form == DW_FORM_udata) { + dwarf_formudata(attr, &offset, 0); + } else if (form == DW_FORM_sdata) { + Dwarf_Signed soffset; + dwarf_formsdata(attr, &soffset, 0); + if (soffset < 0) { + fprintf(stderr, + "unsupported negative offset\n"); + exit(5); + } + offset = (Dwarf_Unsigned) soffset; + } else { + Dwarf_Locdesc **locdescs; + Dwarf_Signed len; + if (dwarf_loclist_n(attr, &locdescs, &len, perr) + == DW_DLV_ERROR) { + fprintf(stderr, "unsupported member offset\n"); + exit(5); + } + if (len != 1 + || locdescs[0]->ld_cents != 1 + || (locdescs[0]->ld_s[0]).lr_atom + != DW_OP_plus_uconst) { + fprintf(stderr, + "unsupported location expression\n"); + exit(5); + } + offset = (locdescs[0]->ld_s[0]).lr_number; + } + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + + *poffset = (int) offset; + return DW_DLV_OK; +} + +static int dwarf_get_size(Dwarf_Debug dbg, Dwarf_Die die, + int *psize, Dwarf_Error *perr) { + Dwarf_Attribute attr; + Dwarf_Unsigned size; + int rc; + + rc = dwarf_attr(die, DW_AT_byte_size, &attr, perr); + if (rc != DW_DLV_OK) { + return rc; + } + Dwarf_Half form; + rc = dwarf_whatform(attr, &form, perr); + if (rc != DW_DLV_OK) { + fprintf(stderr, "Error getting whatform: %s\n", + dwarf_errmsg(*perr)); + exit(5); + } + if (form == DW_FORM_data1 || form == DW_FORM_data2 + || form == DW_FORM_data2 || form == DW_FORM_data4 + || form == DW_FORM_data8 || form == DW_FORM_udata) { + dwarf_formudata(attr, &size, 0); + } else if (form == DW_FORM_sdata) { + Dwarf_Signed ssize; + dwarf_formsdata(attr, &ssize, 0); + if (ssize < 0) { + fprintf(stderr, + "unsupported negative size\n"); + exit(5); + } + size = (Dwarf_Unsigned) ssize; + } else { + Dwarf_Locdesc **locdescs; + Dwarf_Signed len; + if (dwarf_loclist_n(attr, &locdescs, &len, perr) + == DW_DLV_ERROR) { + fprintf(stderr, "unsupported member size\n"); + exit(5); + } + if (len != 1 + || locdescs[0]->ld_cents != 1 + || (locdescs[0]->ld_s[0]).lr_atom + != DW_OP_plus_uconst) { + fprintf(stderr, + "unsupported location expression\n"); + exit(5); + } + size = (locdescs[0]->ld_s[0]).lr_number; + } + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + + *psize = (int) size; + return DW_DLV_OK; +} + +static int deref_type(Dwarf_Debug dbg, Dwarf_Die type_die, + Dwarf_Die *new_type_die, Dwarf_Half *ptype_tag, + Dwarf_Error *perr) { + Dwarf_Attribute pointer_attr; + Dwarf_Off pointer_off; + int rc; + + rc = dwarf_attr(type_die, DW_AT_type, &pointer_attr, + perr); + if (rc != DW_DLV_OK) + return rc; + + rc = dwarf_global_formref(pointer_attr, &pointer_off, + perr); + if (rc != DW_DLV_OK) + return rc; + + rc = dwarf_offdie_b(dbg, pointer_off, 1, new_type_die, + perr); + if (rc != DW_DLV_OK) + return rc; + + dwarf_dealloc(dbg, pointer_attr, DW_DLA_ATTR); + + if (ptype_tag) + rc = dwarf_tag(*new_type_die, ptype_tag, perr); + + return rc; +} + +static void print_field(Dwarf_Debug dbg, Dwarf_Die die, const char *field_name, + int padnum) { + Dwarf_Attribute attr; + Dwarf_Error err; + int offset = 0; + char type_buf[1024]; + char array_buf[128] = ""; + int rc; + + rc = dwarf_get_offset(dbg, die, &offset, &err); + if (rc == DW_DLV_NO_ENTRY) { + fprintf(stderr, "Found %s but no offset, assuming 0\n", + field_name); + } else if (rc != DW_DLV_OK) { + fprintf(stderr, "Error getting dwarf attr offset: %s\n", + dwarf_errmsg(err)); + exit(4); + } + + rc = dwarf_attr(die, DW_AT_type, &attr, &err); + if (rc == DW_DLV_NO_ENTRY) { + fprintf(stderr, + "Found %s but no type, can't assume that one out..\n", + field_name); + exit(6); + } else if (rc != DW_DLV_OK) { + fprintf(stderr, "Error getting dwarf attrlist: %s\n", + dwarf_errmsg(err)); + exit(6); + } else { + Dwarf_Die type_die, next; + Dwarf_Off type_off; + Dwarf_Half type_tag; + char *type_name; + int pointer = 0; + + rc = dwarf_global_formref(attr, &type_off, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Error getting ref offset for type: %s\n", + dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_offdie_b(dbg, type_off, 1, &type_die, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Error getting die from offset for type: %s\n", + dwarf_errmsg(err)); + exit(7); + } + + rc = dwarf_tag(type_die, &type_tag, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_tag error: %d %s\n", + rc, dwarf_errmsg(err)); + exit(7); + } + + if (type_tag == DW_TAG_pointer_type) { + rc = deref_type(dbg, type_die, &next, + &type_tag, &err); + /* No entry here means void* */ + if (rc != DW_DLV_NO_ENTRY) { + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not deref type for %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + + dwarf_dealloc(dbg, type_die, DW_DLA_DIE); + type_die = next; + } + + pointer++; + } + if (type_tag == DW_TAG_array_type) { + int next_offset, size; + + rc = deref_type(dbg, type_die, &next, + &type_tag, &err); + if (rc == DW_DLV_NO_ENTRY) { + fprintf(stderr, + "Could not deref array type for %s: no entry\n", + field_name); + exit(7); + } + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not deref type for %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + + dwarf_dealloc(dbg, type_die, DW_DLA_DIE); + type_die = next; + + /* get next pos */ + rc = dwarf_siblingof(dbg, die, &next, &err); + if (rc == DW_DLV_NO_ENTRY) { + fprintf(stderr, + "Need to get sibling for array size but none left, please implement through whole struct size instead. field %s\n", + field_name); + exit(7); + } + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not get sibling of field %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + rc = dwarf_get_offset(dbg, next, &next_offset, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not get neighbor's offset for field %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + dwarf_dealloc(dbg, next, DW_DLA_DIE); + + /* get type size */ + next = type_die; + if (type_tag == DW_TAG_typedef) { + rc = deref_type(dbg, type_die, &next, NULL, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not deref array typedef type for %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + } + rc = dwarf_get_size(dbg, next, &size, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "Could not get size for type for %s: %s\n", + field_name, dwarf_errmsg(err)); + exit(7); + } + if (next != type_die) + dwarf_dealloc(dbg, next, DW_DLA_DIE); + + snprintf(array_buf, 128, "[%d]", (next_offset - offset) / size); + } + + /* If it's still pointer at this point, it's void * */ + if (type_tag != DW_TAG_pointer_type) { + rc = dwarf_diename(type_die, &type_name, &err); + if (rc != DW_DLV_OK) { + fprintf(stderr, "dwarf_diename error: %s\n", + rc == DW_DLV_NO_ENTRY ? + "no name" : dwarf_errmsg(err)); + const char *tag_name; + + rc = dwarf_get_TAG_name(type_tag, &tag_name); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "dwarf_get_TAG_name error: %d\n", + rc); + } + + fprintf(stderr, "Bad tag %s (%d)?\n", + tag_name, type_tag); + exit(7); + } + } + + if (type_tag == DW_TAG_structure_type) { + snprintf(type_buf, 1024, "struct %s %s", + type_name, pointer ? "*" : ""); + } else if (type_tag == DW_TAG_base_type + || type_tag == DW_TAG_typedef) { + snprintf(type_buf, 1024, "%s %s", type_name, + pointer ? "*" : ""); + } else if (type_tag == DW_TAG_pointer_type) { + snprintf(type_buf, 1024, "void *"); + } else { + const char *tag_name; + + rc = dwarf_get_TAG_name(type_tag, &tag_name); + if (rc != DW_DLV_OK) { + fprintf(stderr, + "dwarf_get_TAG_name error: %d\n", rc); + } + + fprintf(stderr, + "Type tag %s (%d) is not implemented, please add it\n", + tag_name, type_tag); + exit(7); + } + + dwarf_dealloc(dbg, type_name, DW_DLA_STRING); + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); + dwarf_dealloc(dbg, type_die, DW_DLA_DIE); + } + + printf("\t\tstruct {\n\t\t\tchar padding%i[%u];\n\t\t\t%s%s%s;\n\t\t};\n", + padnum, (unsigned int) offset, + type_buf, field_name, array_buf); +} diff --git a/kernel/script/regenerate_hfi1_header.sh b/kernel/script/regenerate_hfi1_header.sh new file mode 100755 index 00000000..b61dc1a8 --- /dev/null +++ b/kernel/script/regenerate_hfi1_header.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# usage: +# /path/to/regenerate_hfi1_header.sh [hfi1.ko] + +SCRIPT_PATH="${BASH_SOURCE[0]}" +ROOTDIR=$(readlink -m "$SCRIPT_PATH") +ROOTDIR=$(dirname "$ROOTDIR") +set -e + +# static configuration-ish +declare -r DES_BIN="${ROOTDIR}/dwarf-extract-struct" +declare -r DES_SRC="${DES_BIN}.c" +declare -r HDR="${ROOTDIR}/../include/hfi1/hfi1_generated_structs.h" + +error() { + echo "$@" >&2 + exit 1 +} + +HFI1_KO="${1-$(modprobe -n hfi1)}" || \ + error "Could not find hfi1 module and no argument given. Usage: $0 [hfi1.ko]" + + +[[ "$DES_BIN" -nt "$DES_SRC" ]] || \ + gcc -o "$DES_BIN" -g -ldwarf "$DES_SRC" || \ + error "Could not compile, install libdwarf-devel ?" + +"$DES_BIN" "$HFI1_KO" hfi1_pportdata vls_operational > "$HDR" + +"$DES_BIN" "$HFI1_KO" hfi1_ctxtdata \ + ctxt rcv_array_groups eager_base expected_count expected_base \ + tid_group_list tid_used_list tid_full_list dd >> "$HDR" + +"$DES_BIN" "$HFI1_KO" hfi1_devdata \ + per_sdma sdma_pad_phys sdma_map pport chip_rcv_array_count \ + kregbase1 piobase physaddr rcvarray_wc default_desc1 flags \ + sc2vl >> "$HDR" diff --git a/kernel/user_sdma.c b/kernel/user_sdma.c index b3c31c0d..adc28f03 100644 --- a/kernel/user_sdma.c +++ b/kernel/user_sdma.c @@ -573,8 +573,8 @@ int hfi1_map_device_addresses(struct hfi1_filedata *fd) /* * Map device addresses if not mapped or mapping changed. */ - if (proc->hfi1_kregbase != dd->kregbase) { - void *hfi1_kregbase = dd->kregbase; + if (proc->hfi1_kregbase != dd->kregbase1) { + void *hfi1_kregbase = dd->kregbase1; phys = dd->physaddr; attr = PTATTR_UNCACHABLE | PTATTR_WRITABLE;