master/domain.c
changeset 2635 42b62867574d
parent 2627 04c83089bac2
equal deleted inserted replaced
2634:f859d567f94e 2635:42b62867574d
    44 #include "datagram_pair.h"
    44 #include "datagram_pair.h"
    45 
    45 
    46 /** Extra debug output for redundancy functions.
    46 /** Extra debug output for redundancy functions.
    47  */
    47  */
    48 #define DEBUG_REDUNDANCY 0
    48 #define DEBUG_REDUNDANCY 0
       
    49 
       
    50 #ifndef list_next_entry
       
    51 #define list_next_entry(pos, member) \
       
    52     list_entry((pos)->member.next, typeof(*(pos)), member)
       
    53 #endif
    49 
    54 
    50 /*****************************************************************************/
    55 /*****************************************************************************/
    51 
    56 
    52 void ec_domain_clear_data(ec_domain_t *);
    57 void ec_domain_clear_data(ec_domain_t *);
    53 
    58 
    77     }
    82     }
    78     domain->expected_working_counter = 0x0000;
    83     domain->expected_working_counter = 0x0000;
    79     domain->working_counter_changes = 0;
    84     domain->working_counter_changes = 0;
    80     domain->redundancy_active = 0;
    85     domain->redundancy_active = 0;
    81     domain->notify_jiffies = 0;
    86     domain->notify_jiffies = 0;
       
    87 
       
    88     /* Used by ec_domain_add_fmmu_config */
       
    89     memset(domain->offset_used, 0, sizeof(domain->offset_used));
       
    90     domain->sc_in_work = 0;
    82 }
    91 }
    83 
    92 
    84 /*****************************************************************************/
    93 /*****************************************************************************/
    85 
    94 
    86 /** Domain destructor.
    95 /** Domain destructor.
   122 void ec_domain_add_fmmu_config(
   131 void ec_domain_add_fmmu_config(
   123         ec_domain_t *domain, /**< EtherCAT domain. */
   132         ec_domain_t *domain, /**< EtherCAT domain. */
   124         ec_fmmu_config_t *fmmu /**< FMMU configuration. */
   133         ec_fmmu_config_t *fmmu /**< FMMU configuration. */
   125         )
   134         )
   126 {
   135 {
       
   136     const ec_slave_config_t *sc;
       
   137     uint32_t logical_domain_offset;
       
   138     unsigned fmmu_data_size;
       
   139 
   127     fmmu->domain = domain;
   140     fmmu->domain = domain;
   128 
   141     sc = fmmu->sc;
   129     domain->data_size += fmmu->data_size;
   142 
       
   143     fmmu_data_size = ec_pdo_list_total_size(
       
   144         &sc->sync_configs[fmmu->sync_index].pdos);
       
   145 
       
   146     if (sc->allow_overlapping_pdos && (sc == domain->sc_in_work)) {
       
   147         // If we permit overlapped PDOs, and we already have an allocated FMMU
       
   148         // for this slave, allocate the subsequent FMMU offsets by direction
       
   149         logical_domain_offset = domain->offset_used[fmmu->dir];
       
   150     } else {
       
   151         // otherwise, allocate to the furthest extent of any allocated
       
   152         // FMMU on this domain.
       
   153         logical_domain_offset = max(domain->offset_used[EC_DIR_INPUT],
       
   154             domain->offset_used[EC_DIR_OUTPUT]);
       
   155         // rebase the free offsets to the current position
       
   156         domain->offset_used[EC_DIR_INPUT] = logical_domain_offset;
       
   157         domain->offset_used[EC_DIR_OUTPUT] = logical_domain_offset;
       
   158     }
       
   159     domain->sc_in_work = sc;
       
   160 
       
   161     // consume the offset space for this FMMU's direction
       
   162     domain->offset_used[fmmu->dir] += fmmu_data_size;
       
   163 
       
   164     ec_fmmu_set_domain_offset_size(fmmu, logical_domain_offset, fmmu_data_size);
       
   165 
   130     list_add_tail(&fmmu->list, &domain->fmmu_configs);
   166     list_add_tail(&fmmu->list, &domain->fmmu_configs);
   131 
   167 
       
   168     // Determine domain size from furthest extent of FMMU data
       
   169     domain->data_size = max(domain->offset_used[EC_DIR_INPUT],
       
   170             domain->offset_used[EC_DIR_OUTPUT]);
       
   171 
   132     EC_MASTER_DBG(domain->master, 1, "Domain %u:"
   172     EC_MASTER_DBG(domain->master, 1, "Domain %u:"
   133             " Added %u bytes, total %zu.\n",
   173             " Added %u bytes at %u.\n",
   134             domain->index, fmmu->data_size, domain->data_size);
   174             domain->index, fmmu->data_size, logical_domain_offset);
   135 }
   175 }
   136 
   176 
   137 /*****************************************************************************/
   177 /*****************************************************************************/
   138 
   178 
   139 /** Allocates a domain datagram pair and appends it to the list.
   179 /** Allocates a domain datagram pair and appends it to the list.
   190  * Walks through the list of all FMMU configurations for the current datagram
   230  * Walks through the list of all FMMU configurations for the current datagram
   191  * and ends before the current datagram.
   231  * and ends before the current datagram.
   192  *
   232  *
   193  * \return Non-zero if slave connfig was already counted.
   233  * \return Non-zero if slave connfig was already counted.
   194  */
   234  */
   195 int shall_count(
   235 static int shall_count(
   196         const ec_fmmu_config_t *cur_fmmu, /**< Current FMMU with direction to
   236         const ec_fmmu_config_t *cur_fmmu, /**< Current FMMU with direction to
   197                                             search for. */
   237                                             search for. */
   198         const ec_fmmu_config_t *first_fmmu /**< Datagram's first FMMU. */
   238         const ec_fmmu_config_t *first_fmmu /**< Datagram's first FMMU. */
   199         )
   239         )
   200 {
   240 {
   211     return 1;
   251     return 1;
   212 }
   252 }
   213 
   253 
   214 /*****************************************************************************/
   254 /*****************************************************************************/
   215 
   255 
       
   256 /** Domain finish helper function.
       
   257  *
       
   258  * Known boundaries for a datagram have been identified. Scans the datagram
       
   259  * FMMU boundaries for WKC counters and then creates the datagram_pair.
       
   260  *
       
   261  * \param domain The parent domain
       
   262  * \param datagram_begin_offset Datagram's logical beginning offset
       
   263  * \param datagram_end_offset Logical end offset (one past last byte)
       
   264  * \param datagram_first_fmmu The begin FMMU in the datagram
       
   265  * \param datagram_end_fmmu The end (one past last) FMMU
       
   266  *
       
   267  * \return Non-zero if error emplacing domain
       
   268  */
       
   269 static int emplace_datagram(ec_domain_t *domain,
       
   270         uint32_t datagram_begin_offset,
       
   271         uint32_t datagram_end_offset,
       
   272         const ec_fmmu_config_t *datagram_first_fmmu,
       
   273         const ec_fmmu_config_t *datagram_end_fmmu
       
   274         )
       
   275 {
       
   276     unsigned int datagram_used[EC_DIR_COUNT];
       
   277     const ec_fmmu_config_t *curr_fmmu;
       
   278     size_t data_size;
       
   279 
       
   280     data_size = datagram_end_offset - datagram_begin_offset;
       
   281 
       
   282     memset(datagram_used, 0, sizeof(datagram_used));
       
   283     for (curr_fmmu = datagram_first_fmmu;
       
   284             &curr_fmmu->list != &datagram_end_fmmu->list;
       
   285             curr_fmmu = list_next_entry(curr_fmmu, list)) {
       
   286         if (shall_count(curr_fmmu, datagram_first_fmmu)) {
       
   287             datagram_used[curr_fmmu->dir]++;
       
   288         }
       
   289     }
       
   290 
       
   291     return ec_domain_add_datagram_pair(domain,
       
   292             domain->logical_base_address + datagram_begin_offset,
       
   293             data_size,
       
   294             domain->data + datagram_begin_offset,
       
   295             datagram_used);
       
   296 }
       
   297 
       
   298 /*****************************************************************************/
       
   299 
   216 /** Finishes a domain.
   300 /** Finishes a domain.
   217  *
   301  *
   218  * This allocates the necessary datagrams and writes the correct logical
   302  * This allocates the necessary datagrams and writes the correct logical
   219  * addresses to every configured FMMU.
   303  * addresses to every configured FMMU.
   220  *
       
   221  * \todo Check for FMMUs that do not fit into any datagram.
       
   222  *
   304  *
   223  * \retval  0 Success
   305  * \retval  0 Success
   224  * \retval <0 Error code.
   306  * \retval <0 Error code.
   225  */
   307  */
   226 int ec_domain_finish(
   308 int ec_domain_finish(
   227         ec_domain_t *domain, /**< EtherCAT domain. */
   309         ec_domain_t *domain, /**< EtherCAT domain. */
   228         uint32_t base_address /**< Logical base address. */
   310         uint32_t base_address /**< Logical base address. */
   229         )
   311         )
   230 {
   312 {
   231     uint32_t datagram_offset;
   313     uint32_t datagram_offset = 0;
   232     size_t datagram_size;
   314     unsigned int datagram_count = 0;
   233     unsigned int datagram_count;
       
   234     unsigned int datagram_used[EC_DIR_COUNT];
       
   235     ec_fmmu_config_t *fmmu;
   315     ec_fmmu_config_t *fmmu;
   236     const ec_fmmu_config_t *datagram_first_fmmu = NULL;
   316     const ec_fmmu_config_t *datagram_first_fmmu = NULL;
       
   317     const ec_fmmu_config_t *valid_fmmu = NULL;
       
   318     unsigned candidate_start = 0;
       
   319     unsigned valid_start = 0;
   237     const ec_datagram_pair_t *datagram_pair;
   320     const ec_datagram_pair_t *datagram_pair;
   238     int ret;
   321     int ret;
   239 
   322 
   240     domain->logical_base_address = base_address;
   323     domain->logical_base_address = base_address;
   241 
   324 
   251 
   334 
   252     // Cycle through all domain FMMUs and
   335     // Cycle through all domain FMMUs and
   253     // - correct the logical base addresses
   336     // - correct the logical base addresses
   254     // - set up the datagrams to carry the process data
   337     // - set up the datagrams to carry the process data
   255     // - calculate the datagrams' expected working counters
   338     // - calculate the datagrams' expected working counters
   256     datagram_offset = 0;
       
   257     datagram_size = 0;
       
   258     datagram_count = 0;
       
   259     datagram_used[EC_DIR_OUTPUT] = 0;
       
   260     datagram_used[EC_DIR_INPUT] = 0;
       
   261 
       
   262     if (!list_empty(&domain->fmmu_configs)) {
   339     if (!list_empty(&domain->fmmu_configs)) {
   263         datagram_first_fmmu =
   340         datagram_first_fmmu =
   264             list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list);
   341             list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list);
   265     }
   342     }
   266 
   343 
   267     list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
   344     list_for_each_entry(fmmu, &domain->fmmu_configs, list) {
   268 
   345         if (fmmu->data_size > EC_MAX_DATA_SIZE) {
   269         // Correct logical FMMU address
   346             EC_MASTER_ERR(domain->master,
   270         fmmu->logical_start_address += base_address;
   347                 "FMMU size %u bytes exceeds maximum data size %u",
   271 
   348                 fmmu->data_size, EC_MAX_DATA_SIZE);
   272         // Increment Input/Output counter to determine datagram types
   349             return -EINVAL;
   273         // and calculate expected working counters
   350         }
   274         if (shall_count(fmmu, datagram_first_fmmu)) {
   351         if (fmmu->logical_domain_offset >= candidate_start) {
   275             datagram_used[fmmu->dir]++;
   352             // As FMMU offsets increase monotonically, and candidate start
   276         }
   353             // offset has never been contradicted, it can now never be
   277 
   354             // contradicted, as no future FMMU can cross it.
   278         // If the current FMMU's data do not fit in the current datagram,
   355             // All FMMUs prior to this point approved for next datagram
   279         // allocate a new one.
   356             valid_fmmu = fmmu;
   280         if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) {
   357             valid_start = candidate_start;
   281             ret = ec_domain_add_datagram_pair(domain,
   358             if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset
   282                     domain->logical_base_address + datagram_offset,
   359                     > EC_MAX_DATA_SIZE) {
   283                     datagram_size, domain->data + datagram_offset,
   360                 // yet the new candidate exceeds the datagram size, so we
   284                     datagram_used);
   361                 // use the last known valid candidate to create the datagram
   285             if (ret < 0)
   362                 ret = emplace_datagram(domain, datagram_offset, valid_start,
   286                 return ret;
   363                     datagram_first_fmmu, valid_fmmu);
   287 
   364                 if (ret < 0)
   288             datagram_offset += datagram_size;
   365                     return ret;
   289             datagram_size = 0;
   366 
   290             datagram_count++;
   367                 datagram_offset = valid_start;
   291             datagram_used[EC_DIR_OUTPUT] = 0;
   368                 datagram_count++;
   292             datagram_used[EC_DIR_INPUT] = 0;
   369                 datagram_first_fmmu = fmmu;
   293             datagram_first_fmmu = fmmu;
   370             }
   294         }
   371         }
   295 
   372         if (fmmu->logical_domain_offset + fmmu->data_size > candidate_start) {
   296         datagram_size += fmmu->data_size;
   373             candidate_start = fmmu->logical_domain_offset + fmmu->data_size;
       
   374         }
   297     }
   375     }
   298 
   376 
   299     /* Allocate last datagram pair, if data are left (this is also the case if
   377     /* Allocate last datagram pair, if data are left (this is also the case if
   300      * the process data fit into a single datagram) */
   378      * the process data fit into a single datagram) */
   301     if (datagram_size) {
   379     if (domain->data_size > datagram_offset) {
   302         ret = ec_domain_add_datagram_pair(domain,
   380         ret = emplace_datagram(domain, datagram_offset, domain->data_size,
   303                 domain->logical_base_address + datagram_offset,
   381             datagram_first_fmmu, fmmu);
   304                 datagram_size, domain->data + datagram_offset,
       
   305                 datagram_used);
       
   306         if (ret < 0)
   382         if (ret < 0)
   307             return ret;
   383             return ret;
   308         datagram_count++;
   384         datagram_count++;
   309     }
   385     }
   310 
   386 
   315 
   391 
   316     list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
   392     list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) {
   317         const ec_datagram_t *datagram =
   393         const ec_datagram_t *datagram =
   318             &datagram_pair->datagrams[EC_DEVICE_MAIN];
   394             &datagram_pair->datagrams[EC_DEVICE_MAIN];
   319         EC_MASTER_INFO(domain->master, "  Datagram %s: Logical offset 0x%08x,"
   395         EC_MASTER_INFO(domain->master, "  Datagram %s: Logical offset 0x%08x,"
   320                 " %zu byte, type %s.\n", datagram->name,
   396                 " %zu byte, type %s at %p.\n", datagram->name,
   321                 EC_READ_U32(datagram->address), datagram->data_size,
   397                 EC_READ_U32(datagram->address), datagram->data_size,
   322                 ec_datagram_type_string(datagram));
   398                 ec_datagram_type_string(datagram), datagram);
   323     }
   399     }
   324 
   400 
   325     return 0;
   401     return 0;
   326 }
   402 }
   327 
   403 
   501 
   577 
   502                 if (fmmu->dir != EC_DIR_INPUT) {
   578                 if (fmmu->dir != EC_DIR_INPUT) {
   503                     continue;
   579                     continue;
   504                 }
   580                 }
   505 
   581 
   506                 if (fmmu->logical_start_address >=
   582                 if (fmmu->logical_domain_offset >= datagram_size) {
   507                         logical_datagram_address + datagram_size) {
       
   508                     // fmmu data contained in next datagram pair
   583                     // fmmu data contained in next datagram pair
   509                     break;
   584                     break;
   510                 }
   585                 }
   511 
   586 
   512                 datagram_offset =
   587                 datagram_offset = fmmu->logical_domain_offset;
   513                     fmmu->logical_start_address - logical_datagram_address;
       
   514 
   588 
   515 #if DEBUG_REDUNDANCY
   589 #if DEBUG_REDUNDANCY
   516                 EC_MASTER_DBG(domain->master, 1,
   590                 EC_MASTER_DBG(domain->master, 1,
   517                         "input fmmu log=%u size=%u offset=%u\n",
   591                         "input fmmu log_off=%u size=%u offset=%u\n",
   518                         fmmu->logical_start_address, fmmu->data_size,
   592                         fmmu->logical_domain_offset, fmmu->data_size,
   519                         datagram_offset);
   593                         datagram_offset);
   520                 if (domain->master->debug_level > 0) {
   594                 if (domain->master->debug_level > 0) {
   521                     ec_print_data(pair->send_buffer + datagram_offset,
   595                     ec_print_data(pair->send_buffer + datagram_offset,
   522                             fmmu->data_size);
   596                             fmmu->data_size);
   523                     ec_print_data(main_datagram->data + datagram_offset,
   597                     ec_print_data(main_datagram->data + datagram_offset,