diff options
99 files changed, 8875 insertions, 6551 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index e1cf152a..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,361 +0,0 @@ -Guidelines for Developing and Contributing Code -=============================================== - -Introduction ------------- - -This guide aims to help developing and contributing code to the libbsd. One -goal of the libbsd is to stay in synchronization with FreeBSD. This is only -feasible if certain rules are in place. Otherwise, managing more than a -thousand imported source files will become too labour intensive eventually. - -What is in the Git Repository ------------------------------ - -The libbsd a self-contained kit with FreeBSD and RTEMS components -pre-merged. The Waf wscript in libbsd automatically generates the build when -you run waf by reading the modules and module's source, header, defines and -special flags from `libbsd.py`. This is the same module data used to manage -the FreeBSD source. - -Any changes to source in the `freebsd` directories will need to be merged -upstream into our master FreeBSD checkout, the `freebsd-org` submodule. - -The repository contains two FreeBSD source trees. In the `freebsd` directory -are the so called *managed* FreeBSD sources used to build the BSD library. -The FreeBSD source in `freebsd-org` is the *master* version. The -`freebsd-to-rtems.py` script is used to transfer files between the two trees -using the module defnitions in `libbsd.py`. In general terms, if you have -modified managed FreeBSD sources, you will need to run the script in *revert* -or *reverse* mode using the `-R` switch. This will copy the source back to -your local copy of the master FreeBSD source so you can run `git diff` against -the upstream FreeBSD source. If you want to transfer source files from the -master FreeBSD source to the manged FreeBSD sources, then you must run the -script in *forward* mode (the default). - -Kernel and User Space ---------------------- - -FreeBSD uses virtual memory to run separate address spaces. The kernel is one -address space and each process the kernel runs is another separate address -space. The FreeBSD build system understands the separation and separately -linked executable for the kernel and user land maintains the separation. - -RTEMS is a single address space operating system and that means the kernel and -user space code have to be linked to together and be able to run side by -side. This creates additional complexity when working with the FreeBSD code, -for example the FreeBSD kernel has a `malloc` call with a different signature -to the user land `malloc` call. The RTEMS LibBSD support code provides -structured ways to manage the separation. - -LibBSD manages the integration of kernel and user code by knowing the context -of the source code. This lets the merge process handle specific changes each -type of file needs. The build system also uses this information to control the -include paths a source file sees. The kernel code sees the kernel, CPU -specific and build system generated include paths in that order. User code -sees the user include paths then the kernel, CPU specific and build system -generated include paths in that order. The FreeBSD OS include path -`/usr/include` has a mix of kernel and user space header files. The kernel -headers let user space code cleanly access structures the kernel exports. If a -user header file has the same name as a kernel header file the user file will -be used in the user code rather than the kernel file. If the user code -includes a kernel header that file will be found and included. - -Organization ------------- - -The top level directory contains a few directories and files. The following -are important to understand - -* `freebsd-to-rtems.py` - script to convert to and free FreeBSD and RTEMS trees, -* `create-kernel-namespace.sh` - script to create the kernel namespace header `<machine/rtems-bsd-kernel-namespace.h>`, -* `wscript` - automatically generates the build from libbsd.py, -* `libbsd.py` - modules, sources, compile flags, and dependencies -* `freebsd/` - from FreeBSD by script, -* `rtemsbsd/` - RTEMS specific implementations of FreeBSD kernel support routines, -* `testsuite/` - RTEMS specific tests, and -* `libbsd.txt` - documentation in Asciidoc. - -Moving Code Between Managed and Master FreeBSD Source ------------------------------------------------------ - -The script `freebsd-to-rtems.py` is used to copy code from FreeBSD to the -rtems-libbsd tree and to reverse this process. This script attempts to -automate this process as much as possible and performs some transformations -on the FreeBSD code. Its command line arguments are shown below: - -``` -freebsd-to-rtems.py [args] - -?|-h|--help print this and exit - -d|--dry-run run program but no modifications - -D|--diff provide diff of files between trees - -e|--early-exit evaluate arguments, print results, and exit - -m|--makefile Warning: depreciated and will be removed - -b|--buildscripts just generate the build scripts - -S|--stats Print a statistics report - -R|--reverse default FreeBSD -> RTEMS, reverse that - -r|--rtems RTEMS Libbsd directory (default: '.') - -f|--freebsd FreeBSD SVN directory (default: 'freebsd-org') - -c|--config Output the configuration then exit - -v|--verbose enable verbose output mode -``` - -In its default mode of operation, `freebsd-to-rtems.py` is used to copy code -from FreeBSD to the rtems-libbsd tree and perform transformations. - -In *reverse mode*, this script undoes those transformations and copies -the source code back to the *master* FreeBSD tree. This allows us to do -'git diff', evaluate changes made by the RTEMS Project, and report changes -back to FreeBSD upstream. - -In either mode, the script may be asked to perform a dry-run or be verbose. -Also, in either mode, the script is also smart enough to avoid copying over -files which have not changed. This means that the timestamps of files are -not changed unless the contents change. The script will also report the -number of files which changed. In verbose mode, the script will print -the name of the files which are changed. - -To add or update files in the RTEMS FreeBSD tree first run the *reverse mode* -and move the current set of patches FreeBSD. The script may warn you if a file -is not present at the destination for the direction. This can happen as files -not avaliable at the FreeBSD snapshot point have been specially added to the -RTEMS FreeBSD tree. Warnings can also appear if you have changed the list of -files in libbsd.py. The reverse mode will result in the FreeBSD having -uncommitted changes. You can ignore these. Once the reverse process has -finished edit libbsd.py and add any new files then run the forwad mode to bring -those files into the RTEMS FreeBSD tree. - -The following is an example forward run with no changes. - -``` -$ ./freebsd-to-rtems.py -v -Verbose: yes (1) -Dry Run: no -Diff Mode Enabled: no -Only Generate Build Scripts: no -RTEMS Libbsd Directory: . -FreeBSD SVN Directory: freebsd-org -Direction: forward -Forward from FreeBSD GIT into . -0 file(s) were changed: -``` - -The script may also be used to generate a diff in either forward or reverse -direction. - -You can add more than one verbose option (-v) to the command line and get more -detail and debug level information from the command. - -FreeBSD Baseline ----------------- - -Use -``` -$ git log freebsd-org -``` -to figure out the current FreeBSD baseline. - -How to Import Code from FreeBSD -------------------------------- - -* In case you import files from a special FreeBSD version, then update the list above. -* Run `git status` and make sure your working directory is clean. -* Run `./freebsd-to-rtems.py -R` -* Run `./freebsd-to-rtems.py` -* Run `git status` and make sure your working directory is clean. If you see modified files, then the `freebsd-to-rtems.py` script needs to be fixed first. -* Add the files to import to `libbsd.py` and your intended build set (for example `buildset/default.ini`. -* Run `./freebsd-to-rtems.py` -* Immediately check in the imported files without the changes to `libbsd.py` and the buildsets. Do not touch the imported files yourself at this point. -* Port the imported files to RTEMS. See 'Rules for Modifying FreeBSD Source'. -* Add a test to the testsuite if possible. -* Run `./create-kernel-namespace.sh` if you imported kernel space headers. Add only your new defines via `git add -p rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h`. -* Create one commit from this. - -The -S or --stats option generates reports the changes we have made to -FreeBSD. If the code has been reserved into the original FreeBSD tree it will -show nothing has changed. To see what we have change: - -``` -$ cd freebsd-org -$ git checkout -- . -$ cd .. -$ ./freebsd-to-rtems.py -R -S -d - ``` - -The report lists the files change based on the opacity level. The opacity is a -measure on how much of a file differs from the original FreeBSD source. The -lower the value the more transparent the source file it. - -Porting of User-Space Utilities ------------------------------- - -The theory behind the described method is to put all BSS and initialized data -objects into a named section. This section then will be saved before the code is -executed and restored after it has finished. This method limits to a single -threaded execution of the application but minimizes the necessary changes to the -original FreeBSD code. - -* Import and commit the unchanged source files like described above. -* Add the files to the [libbsd.py](libbsd.py) and build them. -* Check the sources for everything that can be made const. This type of patches - should go back to the upstream FreeBSD sources. -* Move static variables out of functions if necessary (search for - "\tstatic"). These patches most likely will not be accepted into FreeBSD. -* Add a rtems_bsd_command_PROGNAME() wrapper function to the source file - containing the main function (e.g. PROGNAME = pfctl). For an example look at - `rtems_bsd_command_pfctl()` in [pfctl.c](freebsd/sbin/pfctl/pfctl.c). -* You probably have to use getopt_r() instead of getopt(). Have a look at - [pfctl.c](freebsd/sbin/pfctl/pfctl.c). -* Build the libbsd without optimization. -* Use the `userspace-header-gen.py` to generate some necessary header - files. It will generate one `rtems-bsd-PROGNAME-MODULE-data.h` per object file, one - `rtems-bsd-PROGNAME-namespace.h` and one `rtems-bsd-PROGNAME-data.h`. To call - the script, you have to compile the objects and afterwards run the helper - script with a call similar to this one: - `python ./userspace-header-gen.py build/arm-rtems4.12-xilinx_zynq_a9_qemu/freebsd/sbin/pfctl/*.o -p pfctl` - Replace the name (given via -p option) by the name of the userspace tool. It - has to match the name that is used in the RTEMS linker set further below. - `Note:` the script `userspace-header-gen.py` depends on pyelftools. It can be - installed using pip: - `pip install --user pyelftools` -* If you regenerated files that have already been generated, you may have to - remove RTEMS-specific names from the namespace. The defaults (linker set names - and rtems_bsd_program_.*) should already be filtered. -* Put the generated header files into the same folder like the source files. -* At the top of each source file place the following right after the user-space header: - ```c - #ifdef __rtems__ - #include <machine/rtems-bsd-program.h> - #include "rtems-bsd-PROGNAME-namespace.h" - #endif /* __rtems__ */ - ``` - The following command may be useful: - ``` - sed -i 's%#include <machine/rtems-bsd-user-space.h>%#include <machine/rtems-bsd-user-space.h>\n\n#ifdef __rtems__\n#include <machine/rtems-bsd-program.h>\n#include "rtems-bsd-PROGNAME-namespace.h"\n#endif /* __rtems__ */%' *.c - ``` -* At the bottom of each source file place the follwing: - ```c - #ifdef __rtems__ - #include "rtems-bsd-PROGNAME-FILE-data.h" - #endif /* __rtems__ */ - ``` - The following command may be useful: - ``` - for i in *.c ; do n=$(basename $i .c) ; echo -e "#ifdef __rtems__\n#include \"rtems-bsd-PROGNAME-$n-data.h\"\n#endif /* __rtems__ */" >> $i ; done - ``` -* Create one compilable commit. - -Rules for Modifying FreeBSD Source ----------------------------------- - -Changes in FreeBSD files must be done using `__rtems__` C pre-processor guards. -This makes synchronization with the FreeBSD upstream easier and is very -important. Patches which do not follow these rules will be rejected. Only add -lines. If your patch contains lines starting with a `-`, then this is wrong. -Subtract code by added `#ifndef __rtems__`. For example: - -```c -/* Global variables for the kernel. */ - -#ifndef __rtems__ -/* 1.1 */ -extern char kernelname[MAXPATHLEN]; -#endif /* __rtems__ */ - -extern int tick; /* usec per tick (1000000 / hz) */ -``` - -```c -#if defined(_KERNEL) || defined(_WANT_FILE) -#ifdef __rtems__ -#include <rtems/libio_.h> -#include <sys/fcntl.h> -#endif /* __rtems__ */ -/* - * Kernel descriptor table. - * One entry for each open kernel vnode and socket. - * - * Below is the list of locks that protects members in struct file. - * - * (f) protected with mtx_lock(mtx_pool_find(fp)) - * (d) cdevpriv_mtx - * none not locked - */ -``` - -```c -extern int profprocs; /* number of process's profiling */ -#ifndef __rtems__ -extern volatile int ticks; -#else /* __rtems__ */ -#include <rtems/score/watchdogimpl.h> -#define ticks _Watchdog_Ticks_since_boot -#endif /* __rtems__ */ - -#endif /* _KERNEL */ -``` - -Add nothing (even blank lines) before or after the `__rtems__` guards. Always -include a `__rtems__` in the guards to make searches easy, so use - -* `#ifndef __rtems__`, -* `#ifdef __rtems__`, -* `#else /* __rtems__ */`, and -* `#endif /* __rtems__ */`. - -The guards must start at the begin of the line. Examples for wrong guards: - -```c -static void -guards_must_start_at_the_begin_of_the_line(int j) -{ - - /* WRONG */ - #ifdef __rtems__ - return (j + 1); - #else /* __rtems__ */ - return (j + 2); - #endif /* __rtems__ */ -} - -static void -missing_rtems_comments_in_the_guards(int j) -{ - -#ifdef __rtems__ - return (j + 3); -/* WRONG */ -#else - return (j + 4); -#endif -} -``` - -The FreeBSD build and configuration system uses option header files, e.g. -`#include "opt_xyz.h"` in an unmodified FreeBSD file. This include is -transformed by the import script into `#include <rtems/bsd/local/opt_xyz.h>`. Do -not disable option header includes via guards. Instead, add an empty option -header, e.g. `touch rtemsbsd/include/rtems/bsd/local/opt_xyz.h`. -```c -/* WRONG */ -#ifndef __rtems__ -#include <rtems/bsd/local/opt_xyz.h> -#endif /* __rtems__ */ -``` - -In general, provide empty header files and do not guard includes. - -For new code use -[STYLE(9)](http://www.freebsd.org/cgi/man.cgi?query=style&apropos=0&sektion=9). - -Do not format original FreeBSD code. Do not perform white space changes even -if you get git commit warnings. - -Automatically Generated FreeBSD Files -------------------------------------- - -Some source and header files are automatically generated during the FreeBSD -build process. The `Makefile.todo` file performs this manually. The should be -included in `freebsd-to-rtems.py` script some time in the future. For details, -see also -[KOBJ(9)](http://www.freebsd.org/cgi/man.cgi?query=kobj&sektion=9&apropos=0). diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 00000000..0b6fc7a0 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,736 @@ +Guidelines for Developing and Contributing Code +*********************************************** + +Introduction +============ + +This guide aims to help developing and contributing code to the LibBSD. One +goal of the LibBSD is to stay in synchronization with FreeBSD. This is only +feasible if certain rules are in place. Otherwise, managing more than a +thousand imported source files will become too labour intensive eventually. + +The LibBSD makes FreeBSD subsystems like TCP/IP, USB, SD/MMC, PCIe, and some +more usable for RTEMS. It tries to follow the FreeBSD development as close as +possible and therefore is updated to the latest FreeBSD HEAD revision of the +associated FreeBSD branch from time to time. To find out which version of +FreeBSD is currently used as the base version for LibBSD please take a look at +the ``freebsd-org`` submodule. + +This guide captures information on the process of merging code from FreeBSD, +RTEMS specific support files, general guidelines on what modifications to the +FreeBSD source are permitted, and some other topics. For building the library, +see the `README <README.rst>`_. + +Goals of the LibBSD activity are + +* provide functionality from FreeBSD to RTEMS, +* ease updating to future FreeBSD versions, +* ease tracking changes in FreeBSD code, +* minimize manual changes in FreeBSD code. + +We will work to push our changes upstream to the FreeBSD Project and minimize +changes required at each update point. + +What is in the Git Repository +============================= + +The LibBSD a self-contained kit with FreeBSD and RTEMS components +pre-merged. The Waf wscript in LibBSD automatically generates the build when +you run waf by reading the modules and module's source, header, defines and +special flags from ``libbsd.py``. This is the same module data used to manage +the FreeBSD source. + +Any changes to source in the ``freebsd`` directories will need to be merged +upstream into our master FreeBSD checkout, the ``freebsd-org`` submodule. + +The repository contains two FreeBSD source trees. In the ``freebsd`` directory +are the so called *managed* FreeBSD sources used to build the BSD library. +The FreeBSD source in ``freebsd-org`` is the *master* version. The +``freebsd-to-rtems.py`` script is used to transfer files between the two trees +using the module defnitions in ``libbsd.py``. In general terms, if you have +modified managed FreeBSD sources, you will need to run the script in *revert* +or *reverse* mode using the ``-R`` switch. This will copy the source back to +your local copy of the master FreeBSD source so you can run ``git diff`` against +the upstream FreeBSD source. If you want to transfer source files from the +master FreeBSD source to the manged FreeBSD sources, then you must run the +script in *forward* mode (the default). + +Kernel and User Space +===================== + +FreeBSD uses virtual memory to run separate address spaces. The kernel is one +address space and each process the kernel runs is another separate address +space. The FreeBSD build system understands the separation and separately +linked executable for the kernel and user land maintains the separation. + +RTEMS is a single address space operating system and that means the kernel and +user space code have to be linked to together and be able to run side by +side. This creates additional complexity when working with the FreeBSD code, +for example the FreeBSD kernel has a ``malloc`` call with a different signature +to the user land ``malloc`` call. The RTEMS LibBSD support code provides +structured ways to manage the separation. + +LibBSD manages the integration of kernel and user code by knowing the context +of the source code. This lets the merge process handle specific changes each +type of file needs. The build system also uses this information to control the +include paths a source file sees. The kernel code sees the kernel, CPU +specific and build system generated include paths in that order. User code +sees the user include paths then the kernel, CPU specific and build system +generated include paths in that order. The FreeBSD OS include path +``/usr/include`` has a mix of kernel and user space header files. The kernel +headers let user space code cleanly access structures the kernel exports. If a +user header file has the same name as a kernel header file the user file will +be used in the user code rather than the kernel file. If the user code +includes a kernel header that file will be found and included. + +Organization +============ + +The top level directory contains a few directories and files. The following +are important to understand + +* ``freebsd-to-rtems.py`` - script to convert to and free FreeBSD and RTEMS trees, +* ``create-kernel-namespace.sh`` - script to create the kernel namespace header ``<machine/rtems-bsd-kernel-namespace.h>``, +* ``wscript`` - automatically generates the build from libbsd.py, +* ``libbsd.py`` - modules, sources, compile flags, and dependencies +* ``freebsd/`` - from FreeBSD by script, +* ``rtemsbsd/`` - RTEMS specific implementations of FreeBSD kernel support routines, +* ``testsuite/`` - RTEMS specific tests, and +* ``libbsd.txt`` - documentation in Asciidoc. + +Moving Code Between Managed and Master FreeBSD Source +===================================================== + +The script ``freebsd-to-rtems.py`` is used to copy code from FreeBSD to the +rtems-libbsd tree and to reverse this process. This script attempts to +automate this process as much as possible and performs some transformations +on the FreeBSD code. Its command line arguments are shown below: + +.. code-block:: none + + freebsd-to-rtems.py [args] + -?|-h|--help print this and exit + -d|--dry-run run program but no modifications + -D|--diff provide diff of files between trees + -e|--early-exit evaluate arguments, print results, and exit + -m|--makefile Warning: depreciated and will be removed + -b|--buildscripts just generate the build scripts + -S|--stats Print a statistics report + -R|--reverse default FreeBSD -> RTEMS, reverse that + -r|--rtems RTEMS Libbsd directory (default: '.') + -f|--freebsd FreeBSD SVN directory (default: 'freebsd-org') + -c|--config Output the configuration then exit + -v|--verbose enable verbose output mode + +In its default mode of operation, ``freebsd-to-rtems.py`` is used to copy code +from FreeBSD to the rtems-libbsd tree and perform transformations. + +In *reverse mode*, this script undoes those transformations and copies +the source code back to the *master* FreeBSD tree. This allows us to do +'git diff', evaluate changes made by the RTEMS Project, and report changes +back to FreeBSD upstream. + +In either mode, the script may be asked to perform a dry-run or be verbose. +Also, in either mode, the script is also smart enough to avoid copying over +files which have not changed. This means that the timestamps of files are +not changed unless the contents change. The script will also report the +number of files which changed. In verbose mode, the script will print +the name of the files which are changed. + +To add or update files in the RTEMS FreeBSD tree first run the *reverse mode* +and move the current set of patches FreeBSD. The script may warn you if a file +is not present at the destination for the direction. This can happen as files +not avaliable at the FreeBSD snapshot point have been specially added to the +RTEMS FreeBSD tree. Warnings can also appear if you have changed the list of +files in libbsd.py. The reverse mode will result in the FreeBSD having +uncommitted changes. You can ignore these. Once the reverse process has +finished edit libbsd.py and add any new files then run the forwad mode to bring +those files into the RTEMS FreeBSD tree. + +The following is an example forward run with no changes. + +.. code-block:: none + + $ ./freebsd-to-rtems.py -v + Verbose: yes (1) + Dry Run: no + Diff Mode Enabled: no + Only Generate Build Scripts: no + RTEMS Libbsd Directory: . + FreeBSD SVN Directory: freebsd-org + Direction: forward + Forward from FreeBSD GIT into . + 0 file(s) were changed: + +The script may also be used to generate a diff in either forward or reverse +direction. + +You can add more than one verbose option (-v) to the command line and get more +detail and debug level information from the command. + +FreeBSD Baseline +================ + +Use + +.. code-block:: none + + $ git log freebsd-org + +to figure out the current FreeBSD baseline. + +How to Import Code from FreeBSD +=============================== + +* In case you import files from a special FreeBSD version, then update the list above. +* Run ``git status`` and make sure your working directory is clean. +* Run ``./freebsd-to-rtems.py -R`` +* Run ``./freebsd-to-rtems.py`` +* Run ``git status`` and make sure your working directory is clean. If you see modified files, then the ``freebsd-to-rtems.py`` script needs to be fixed first. +* Add the files to import to ``libbsd.py`` and your intended build set (for example ``buildset/default.ini``. +* Run ``./freebsd-to-rtems.py`` +* Immediately check in the imported files without the changes to ``libbsd.py`` and the buildsets. Do not touch the imported files yourself at this point. +* Port the imported files to RTEMS. See 'Rules for Modifying FreeBSD Source'. +* Add a test to the testsuite if possible. +* Run ``./create-kernel-namespace.sh`` if you imported kernel space headers. Add only your new defines via ``git add -p rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h``. +* Create one commit from this. + +The -S or --stats option generates reports the changes we have made to +FreeBSD. If the code has been reserved into the original FreeBSD tree it will +show nothing has changed. To see what we have change: + +.. code-block:: none + + $ cd freebsd-org + $ git checkout -- . + $ cd .. + $ ./freebsd-to-rtems.py -R -S -d + +The report lists the files change based on the opacity level. The opacity is a +measure on how much of a file differs from the original FreeBSD source. The +lower the value the more transparent the source file it. + +Porting of User-Space Utilities +=============================== + +The theory behind the described method is to put all BSS and initialized data +objects into a named section. This section then will be saved before the code is +executed and restored after it has finished. This method limits to a single +threaded execution of the application but minimizes the necessary changes to the +original FreeBSD code. + +* Import and commit the unchanged source files like described above. +* Add the files to the `<libbsd.py>`_ and build them. +* Check the sources for everything that can be made const. This type of patches + should go back to the upstream FreeBSD sources. +* Move static variables out of functions if necessary (search for + "\tstatic"). These patches most likely will not be accepted into FreeBSD. +* Add a rtems_bsd_command_PROGNAME() wrapper function to the source file + containing the main function (e.g. PROGNAME = pfctl). For an example look at + ``rtems_bsd_command_pfctl()`` in `pfctl.c <freebsd/sbin/pfctl/pfctl.c>`_. +* You probably have to use getopt_r() instead of getopt(). Have a look at + `pfctl.c <freebsd/sbin/pfctl/pfctl.c>`_. +* Build the LibBSD without optimization. +* Use the ``userspace-header-gen.py`` to generate some necessary header + files. It will generate one ``rtems-bsd-PROGNAME-MODULE-data.h`` per object file, one + ``rtems-bsd-PROGNAME-namespace.h`` and one ``rtems-bsd-PROGNAME-data.h``. To call + the script, you have to compile the objects and afterwards run the helper + script with a call similar to this one: + ``python ./userspace-header-gen.py build/arm-rtems4.12-xilinx_zynq_a9_qemu/freebsd/sbin/pfctl/*.o -p pfctl`` + Replace the name (given via -p option) by the name of the userspace tool. It + has to match the name that is used in the RTEMS linker set further below. + ``Note:`` the script ``userspace-header-gen.py`` depends on pyelftools. It can be + installed using pip: + ``pip install --user pyelftools`` +* If you regenerated files that have already been generated, you may have to + remove RTEMS-specific names from the namespace. The defaults (linker set names + and rtems_bsd_program_.*) should already be filtered. +* Put the generated header files into the same folder like the source files. +* At the top of each source file place the following right after the user-space header: + + .. code-block:: c + + #ifdef __rtems__ + #include <machine/rtems-bsd-program.h> + #include "rtems-bsd-PROGNAME-namespace.h" + #endif /* __rtems__ */ + + The following command may be useful: + + .. code-block:: none + + sed -i 's%#include <machine/rtems-bsd-user-space.h>%#include <machine/rtems-bsd-user-space.h>\n\n#ifdef __rtems__\n#include <machine/rtems-bsd-program.h>\n#include "rtems-bsd-PROGNAME-namespace.h"\n#endif /* __rtems__ */%' *.c + +* At the bottom of each source file place the follwing: + + .. code-block:: c + + #ifdef __rtems__ + #include "rtems-bsd-PROGNAME-FILE-data.h" + #endif /* __rtems__ */ + + The following command may be useful: + + .. code-block:: none + + for i in *.c ; do n=$(basename $i .c) ; echo -e "#ifdef __rtems__\n#include \"rtems-bsd-PROGNAME-$n-data.h\"\n#endif /* __rtems__ */" >> $i ; done +* Create one compilable commit. + +Rules for Modifying FreeBSD Source +================================== + +Do not reformat original FreeBSD code. Do not perform white space changes even +if you get git commit warnings. **Check your editor settings so that it does +not perform white space changes automatically**, for example adding a newline +to the end of the file. White space changes may result in conflicts during +updates, especially changes at the end of a file. + +Changes in FreeBSD files must be done using ``__rtems__`` C pre-processor guards. +This makes synchronization with the FreeBSD upstream easier and is very +important. Patches which do not follow these rules will be rejected. Only add +lines. If your patch contains lines starting with a ``-``, then this is wrong. +Subtract code by added ``#ifndef __rtems__``. For example: + +.. code-block:: c + + /* Global variables for the kernel. */ + + #ifndef __rtems__ + /* 1.1 */ + extern char kernelname[MAXPATHLEN]; + #endif /* __rtems__ */ + + extern int tick; /* usec per tick (1000000 / hz) */ + +.. code-block:: c + + #if defined(_KERNEL) || defined(_WANT_FILE) + #ifdef __rtems__ + #include <rtems/libio_.h> + #include <sys/fcntl.h> + #endif /* __rtems__ */ + /* + * Kernel descriptor table. + * One entry for each open kernel vnode and socket. + * + * Below is the list of locks that protects members in struct file. + * + * (f) protected with mtx_lock(mtx_pool_find(fp)) + * (d) cdevpriv_mtx + * none not locked + */ + +.. code-block:: c + + extern int profprocs; /* number of process's profiling */ + #ifndef __rtems__ + extern volatile int ticks; + #else /* __rtems__ */ + #include <rtems/score/watchdogimpl.h> + #define ticks _Watchdog_Ticks_since_boot + #endif /* __rtems__ */ + + #endif /* _KERNEL */ + +Add nothing (even blank lines) before or after the ``__rtems__`` guards. Always +include a ``__rtems__`` in the guards to make searches easy, so use + +* ``#ifndef __rtems__``, +* ``#ifdef __rtems__``, +* ``#else /* __rtems__ */``, and +* ``#endif /* __rtems__ */``. + +The guards must start at the begin of the line. Examples for wrong guards: + +.. code-block:: c + + static void + guards_must_start_at_the_begin_of_the_line(int j) + { + + /* WRONG */ + #ifdef __rtems__ + return (j + 1); + #else /* __rtems__ */ + return (j + 2); + #endif /* __rtems__ */ + } + + static void + missing_rtems_comments_in_the_guards(int j) + { + + #ifdef __rtems__ + return (j + 3); + /* WRONG */ + #else + return (j + 4); + #endif + } + +The FreeBSD build and configuration system uses option header files, e.g. +``#include "opt_xyz.h"`` in an unmodified FreeBSD file. This include is +transformed by the import script into ``#include <rtems/bsd/local/opt_xyz.h>``. Do +not disable option header includes via guards. Instead, add an empty option +header, e.g. ``touch rtemsbsd/include/rtems/bsd/local/opt_xyz.h``. + +.. code-block:: c + + /* WRONG */ + #ifndef __rtems__ + #include <rtems/bsd/local/opt_xyz.h> + #endif /* __rtems__ */ + +In general, provide empty header files and do not guard includes. + +For new code use +`STYLE(9) <http://www.freebsd.org/cgi/man.cgi?query=style&apropos=0&sektion=9>`_. + +Update FreeBSD Baseline +======================= + +Perform the following steps to do a FreeBSD baseline update: + +* Update ``__FreeBSD_version`` in ``rtemsbsd/include/machine/rtems-bsd-version.h`` + +* Update the namespace header file. + +* Review all code blocks with the ``REVIEW-AFTER-FREEBSD-BASELINE-UPDATE`` tag. + +Automatically Generated FreeBSD Files +===================================== + +Some source and header files are automatically generated during the FreeBSD +build process. The ``Makefile.todo`` file performs this manually. The should be +included in ``freebsd-to-rtems.py`` script some time in the future. For details, +see also +`KOBJ(9) <http://www.freebsd.org/cgi/man.cgi?query=kobj&sektion=9&apropos=0>`_. + +Reference Board Support Package +=============================== + +The reference BSP for LibBSD development is ``arm/xilinx_zynq_a9_qemu``. All +patches shall be tested for this BSP. The BSP runs on the Qemu simulator which +has some benefits for development and test of the LibBSD + +* ``NULL`` pointer read and write protection, +* Qemu is a fast simulator, +* Qemu provides support for GDB watchpoints, +* Qemu provides support for virtual Ethernet networks, e.g. TUN and bridge + devices (you can run multiple test instances on one virtual network). + +Board Support Package Requirements +================================== + +In FreeBSD, interrupt handler may use mutexes. In RTEMS, using mutexes from +within interrupt context is not allowed, so the Board Support Package (BSP) +should support the +`Interrupt Manager <https://docs.rtems.org/branches/master/c-user/interrupt/directives.html#rtems-interrupt-server-handler-install>`_ +in general. + +Network Interface Drivers Hints +=============================== + +Link Up/Down Events +------------------- + +You can notifiy the application space of link up/down events in your network +interface driver via the +``if_link_state_change(LINK_STATE_UP/LINK_STATE_DOWN)`` function. The +DHCPCD(8) client is a consumer of these events for example. Make sure that the +interface flag ``IFF_UP`` and the interface driver flag ``IFF_DRV_RUNNING`` is +set in case the link is up, otherwise ``ether_output()`` will return the error +status ``ENETDOWN``. + +FreeBSD Kernel Features Ported to LibBSD +======================================== + +All lock based synchronization primitives are implemented through mutexes using +the priority inheritance protocol. + +* `BUS_DMA(9) <http://www.freebsd.org/cgi/man.cgi?query=bus_dma&sektion=9>`_: Bus and Machine Independent DMA Mapping Interface +* `BUS_SPACE(9) <http://www.freebsd.org/cgi/man.cgi?query=bus_space&sektion=9>`_: Bus space manipulation functions +* `CALLOUT(9) <http://www.freebsd.org/cgi/man.cgi?query=callout&sektion=9>`_: Execute a function after a specified length of time +* `CONDVAR(9) <http://www.freebsd.org/cgi/man.cgi?query=condvar&sektion=9>`_: Kernel condition variable +* `DEVICE(9) <http://www.freebsd.org/cgi/man.cgi?query=device&sektion=9>`_: An abstract representation of a device +* `DRIVER(9) <http://www.freebsd.org/cgi/man.cgi?query=driver&sektion=9>`_: Structure describing a device driver +* `EPOCH(9) <http://www.freebsd.org/cgi/man.cgi?query=epoch&sektion=9>`_: Kernel epoch based reclamation +* `MUTEX(9) <http://www.freebsd.org/cgi/man.cgi?query=mutex&sektion=9>`_: Kernel synchronization primitives +* `RMAN(9) <http://www.freebsd.org/cgi/man.cgi?query=rman&sektion=9>`_: Resource management functions +* `RMLOCK(9) <http://www.freebsd.org/cgi/man.cgi?query=rmlock&sektion=9>`_: Kernel reader/writer lock optimized for read-mostly access patterns +* `RWLOCK(9) <http://www.freebsd.org/cgi/man.cgi?query=rwlock&sektion=9>`_: Kernel reader/writer lock +* `SX(9) <http://www.freebsd.org/cgi/man.cgi?query=sx&sektion=9>`_: Kernel shared/exclusive lock +* `SYSCTL(9) <http://www.freebsd.org/cgi/man.cgi?query=SYSCTL_DECL&sektion=9>`_: Dynamic and static sysctl MIB creation functions +* `SYSINIT(9) <http://www.freebsd.org/cgi/man.cgi?query=sysinit&sektion=9>`_: A framework for dynamic kernel initialization +* `TASKQUEUE(9) <http://www.freebsd.org/cgi/man.cgi?query=taskqueue&sektion=9>`_: Asynchronous task execution +* `UMA(9) <http://www.freebsd.org/cgi/man.cgi?query=uma&sektion=9>`_: General-purpose kernel object allocator + +LibBSD Initialization Details +============================= + +The initialization of LibBSD is based on the FreeBSD +`SYSINIT(9) <http://www.freebsd.org/cgi/man.cgi?query=sysinit&sektion=9>`_ +infrastructure. The key to initializing a system is to ensure that the desired +device drivers are explicitly pulled into the linked application. This plus +linking against the LibBSD (``libbsd.a``) will pull in the necessary FreeBSD +infrastructure. + +The FreeBSD kernel is not a library like the RTEMS kernel. It is a bunch of +object files linked together. If we have a library, then creating the +executable is simple. We begin with a start symbol and recursively resolve all +references. With a bunch of object files linked together we need a different +mechanism. Most object files don't know each other. Lets say we have a driver +module. The rest of the system has no references to this driver module. The +driver module needs a way to tell the rest of the system: Hey, kernel I am +here, please use my services! + +This registration of independent components is performed by SYSINIT(9) and +specializations + +The SYSINIT(9) uses some global data structures that are placed in a certain +section. In the linker command file we need this: + +.. code-block:: none + + .rtemsroset : { + KEEP (*(SORT(.rtemsroset.*))) + } + + .rtemsrwset : { + KEEP (*(SORT(.rtemsrwset.*))) + } + +This results for example in this executable layout: + +.. code-block:: none + + [...] + *(SORT(.rtemsroset.*)) + .rtemsroset.bsd.modmetadata_set.begin + 0x000000000025fe00 0x0 libbsd.a(rtems-bsd-init.o) + 0x000000000025fe00 _bsd__start_set_modmetadata_set + .rtemsroset.bsd.modmetadata_set.content + 0x000000000025fe00 0x8 libbsd.a(rtems-bsd-nexus.o) + .rtemsroset.bsd.modmetadata_set.content + 0x000000000025fe08 0x4 libbsd.a(kern_module.o) + [...] + .rtemsroset.bsd.modmetadata_set.content + 0x000000000025fe68 0x4 libbsd.a(mii.o) + .rtemsroset.bsd.modmetadata_set.content + 0x000000000025fe6c 0x4 libbsd.a(mii_bitbang.o) + .rtemsroset.bsd.modmetadata_set.end + 0x000000000025fe70 0x0 libbsd.a(rtems-bsd-init.o) + 0x000000000025fe70 _bsd__stop_set_modmetadata_set + [...] + .rtemsrwset 0x000000000030bad0 0x290 + *(SORT(.rtemsrwset.*)) + .rtemsrwset.bsd.sysinit_set.begin + 0x000000000030bad0 0x0 libbsd.a(rtems-bsd-init.o) + 0x000000000030bad0 _bsd__start_set_sysinit_set + .rtemsrwset.bsd.sysinit_set.content + 0x000000000030bad0 0x4 libbsd.a(rtems-bsd-nexus.o) + .rtemsrwset.bsd.sysinit_set.content + 0x000000000030bad4 0x8 libbsd.a(rtems-bsd-thread.o) + .rtemsrwset.bsd.sysinit_set.content + 0x000000000030badc 0x4 libbsd.a(init_main.o) + [...] + .rtemsrwset.bsd.sysinit_set.content + 0x000000000030bd54 0x4 libbsd.a(frag6.o) + .rtemsrwset.bsd.sysinit_set.content + 0x000000000030bd58 0x8 libbsd.a(uipc_accf.o) + .rtemsrwset.bsd.sysinit_set.end + 0x000000000030bd60 0x0 libbsd.a(rtems-bsd-init.o) + 0x000000000030bd60 _bsd__stop_set_sysinit_set + [...] + +Here you can see, that some global data structures are collected into +continuous memory areas. This memory area can be identified by start and stop +symbols. This constructs a table of uniform items. + +The low level FreeBSD code calls at some time during the initialization the +mi_startup() function (machine independent startup). This function will sort +the SYSINIT(9) set and call handler functions which perform further +initialization. The last step is the scheduler invocation. + +The SYSINIT(9) routines are run in ``mi_startup()`` which is called by +``rtems_bsd_initialize()``. This is also explained in "The Design and +Implementation of the FreeBSD Operating System" section 14.3 "Kernel +Initialization". + +In RTEMS, we have a library and not a bunch of object files. Thus we need a +way to pull-in the desired services out of the libbsd. Here the +``rtems-bsd-sysinit.h`` comes into play. The SYSINIT(9) macros have been +modified and extended for RTEMS in ``<sys/kernel.h>``: + +.. code-block:: none + + #ifndef __rtems__ + #define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ + static struct sysinit uniquifier ## _sys_init = { \ + subsystem, \ + order, \ + func, \ + (ident) \ + }; \ + DATA_SET(sysinit_set,uniquifier ## _sys_init) + #else /* __rtems__ */ + #define SYSINIT_ENTRY_NAME(uniquifier) \ + _bsd_ ## uniquifier ## _sys_init + #define SYSINIT_REFERENCE_NAME(uniquifier) \ + _bsd_ ## uniquifier ## _sys_init_ref + #define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ + struct sysinit SYSINIT_ENTRY_NAME(uniquifier) = { \ + subsystem, \ + order, \ + func, \ + (ident) \ + }; \ + RWDATA_SET(sysinit_set,SYSINIT_ENTRY_NAME(uniquifier)) + #define SYSINIT_REFERENCE(uniquifier) \ + extern struct sysinit SYSINIT_ENTRY_NAME(uniquifier); \ + static struct sysinit const * const \ + SYSINIT_REFERENCE_NAME(uniquifier) __used \ + = &SYSINIT_ENTRY_NAME(uniquifier) + #define SYSINIT_MODULE_REFERENCE(mod) \ + SYSINIT_REFERENCE(mod ## module) + #define SYSINIT_DRIVER_REFERENCE(driver, bus) \ + SYSINIT_MODULE_REFERENCE(driver ## _ ## bus) + #define SYSINIT_DOMAIN_REFERENCE(dom) \ + SYSINIT_REFERENCE(domain_add_ ## dom) + #endif /* __rtems__ */ + +Here you see that the SYSINIT(9) entries are no longer static. The +``*_REFERENCE()`` macros will create references to the corresponding modules +which are later resolved by the linker. The application has to provide an +object file with references to all required FreeBSD modules. + +System Control Hints +==================== + +If you get undefined references to ``_bsd_sysctl_*`` symbols, then you have to +locate and add the associated system control node, see +`SYSCTL(9) <http://www.freebsd.org/cgi/man.cgi?query=SYSCTL_DECL&sektion=9>`_. + +Issues and TODO +=============== + +* PCI support on x86 uses a quick and dirty hack, see pci_reserve_map(). + +* Priority queues are broken with clustered scheduling. + +* Per-CPU data should be enabled once the new stack is ready for SMP. + +* Per-CPU NETISR(9) should be enabled onece the new stack is ready for SMP. + +* Multiple routing tables are not supported. Every FIB value is set to zero + (= BSD_DEFAULT_FIB). + +* Process identifiers are not supported. Every PID value is set to zero + (= BSD_DEFAULT_PID). + +* User credentials are not supported. The following functions allow the + operation for everyone + + * prison_equal_ip4(), + * chgsbsize(), + * cr_cansee(), + * cr_canseesocket() and + * cr_canseeinpcb(). + +* A basic USB functionality test that is known to work on Qemu is desirable. + +* Adapt generic IRQ PIC interface code to Simple Vectored Interrupt Model + so that those architectures can use new TCP/IP and USB code. + +* freebsd-userspace/rtems/include/sys/syslog.h is a copy from the old + RTEMS TCP/IP stack. For some reason, the __printflike markers do not + compile in this environment. We may want to use the FreeBSD syslog.h + and get this addressed. + +* in_cksum implementations for architectures not supported by FreeBSD. + This will require figuring out where to put implementations that do + not originate from FreeBSD and are populated via the script. + +* MAC support functions are not thread-safe ("freebsd/lib/libc/posix1e/mac.c"). + +* IFCONFIG(8): IEEE80211 support is disabled. This module depends on a XML + parser and mmap(). + +* get_cyclecount(): The implementation is a security problem. + +* What to do with the priority parameter present in the FreeBSD synchronization + primitives and the thread creation functions? + +* TASKQUEUE(9): Support spin mutexes. + +* ZONE(9): Review allocator lock usage in rtems-bsd-chunk.c. + +* KQUEUE(2): Choose proper lock for global kqueue list. + +* TIMEOUT(9): Maybe use special task instead of timer server to call + callout_tick(). + +* sysctl_handle_opaque(): Implement reliable snapshots. + +* PING6(8): What to do with SIGALARM? + +* <sys/param.h>: Update Newlib to use a MSIZE of 256. + +* BPF(4): Add support for zero-copy buffers. + +* UNIX(4): Fix race conditions in the area of socket object and file node + destruction. Add support for file descriptor transmission via control + messages. + +* PRINTF(9): Add support for log(), the %D format specifier is missing in the + normal printf() family. + +* Why is the interrupt server used? The BSD interrupt handlers can block on + synchronization primitives like mutexes. This is in contrast to RTEMS + interrupt service routines. The BSPs using the generic interrupt support + must implement the ``bsp_interrupt_vector_enable()`` and + ``bsp_interrupt_vector_disable()`` routines. They normally enable/disable a + particular interrupt source at the interrupt controller. This can be used to + implement the interrupt server. The interrupt server is a task that wakes-up + in case an associated interrupt happens. The interrupt source is disabled in + a generic interrupt handler that wakes-up the interrupt server task. Once + the postponed interrupt processing is performed in the interrupt server the + interrupt source is enabled again. + +* Convert all BSP linkcmds to use a linkcmds.base so the sections are + easier to insert. + +* NIC Device Drivers +* Only common PCI NIC drivers have been included in the initial set. These + do not include any system on chip or ISA drivers. +* PCI configuration probe does not appear to happen to determine if a + NIC is in I/O or memory space. We have worked around this by using a + static hint to tell the fxp driver the correct mode. But this needs to + be addressed. +* The ISA drivers require more BSD infrastructure to be addressed. This was + outside the scope of the initial porting effort. + +* devfs (Device file system): There is a minimal implementation based on IMFS. + The mount point is fixed to "/dev". Note that the devfs is only used by the + cdev subsystem. cdev has been adapted so that the full path (including the + leading "/dev") is given to devfs. This saves some copy operations. + + devfs_create() first creates the full path and then creates an IMFS generic + node for the device. + + TBD: remove empty paths on devfs_destroy(). + +* altq_subr.c - Arbitrary choices were made in this file that RTEMS would not + support tsc frequency change. Additionally, the clock frequency for + machclk_freq is always measured for RTEMS. + +* conf.h - In order to add make_dev and destroy_dev, variables in the cdev + structure that were not being used were conditionally compiled out. The + capability of supporting children did not appear to be needed and was not + implemented in the rtems version of these routines. + +* Problem to report to FreeBSD: The MMAP_NOT_AVAILABLE define is inverted on + its usage. When it is defined the mmap method is called. Additionally, it is + not used thoroughly. It is not used in the unmap portion of the source. The + file rec_open.c uses the define MMAP_NOT_AVAILABLE to wrap the call to mmap + and file rec_close.c uses the munmap method. diff --git a/README.md b/README.md deleted file mode 100644 index 19c9023e..00000000 --- a/README.md +++ /dev/null @@ -1,295 +0,0 @@ -RTEMS LibBSD -============ - -Welcome to building LibBSD for RTEMS using Waf. This package is a library -containing various parts of the FreeBSD kernel ported to RTEMS. The library -replaces the networking port of FreeBSD in the RTEMS kernel sources. This -package is designed to be updated from the FreeBSD kernel sources and contains -more than just the networking code. - -To build this package you need a current RTEMS tool set for your architecture, -and a recent RTEMS kernel for your BSP configured with networking disabled -built and installed. If you already have this you can skip to step 3 of the -build procedure. - -Building and Installing LibBSD ------------------------------- - -The following instructions show you how to build and install RTEMS Tools and -RTEMS kernel for your BSP in separate paths. Using separate paths for the tools -and BSPs lets you manage what you have installed. If you are happy with a -single path you can use the same path in each stage. - -The Waf build support for RTEMS requires you provide your BSP name as an -architecture and BSP pair. You must provide both or Waf will generate an error -message during the configure phase. - -We will build an Xilinx Zynq QEMU BSP using the name -*arm/xilinx_zynq_a9_qemu*. You can copy and paste the shell commands below to -do this. The individual steps are explained afterwards. - -``` -sandbox="$PWD/sandbox" -mkdir sandbox -cd "$sandbox" -git clone git://git.rtems.org/rtems-source-builder.git -git clone git://git.rtems.org/rtems.git -git clone git://git.rtems.org/rtems-libbsd.git -cd "$sandbox" -cd rtems-source-builder/rtems -../source-builder/sb-set-builder --prefix="$sandbox/rtems/5" 5/rtems-arm -cd "$sandbox" -cd rtems -PATH="$sandbox/rtems/5/bin:$PATH" ./bootstrap -cd "$sandbox" -mkdir b-xilinx_zynq_a9_qemu -cd b-xilinx_zynq_a9_qemu -PATH="$sandbox/rtems/5/bin:$PATH" "$sandbox/rtems/configure" \ - --target=arm-rtems5 --prefix="$sandbox/rtems/5" \ - --disable-networking --enable-rtemsbsp=xilinx_zynq_a9_qemu -PATH="$sandbox/rtems/5/bin:$PATH" make -PATH="$sandbox/rtems/5/bin:$PATH" make install -cd "$sandbox" -cd rtems-libbsd -git submodule init -git submodule update rtems_waf -./waf configure --prefix="$sandbox/rtems/5" \ - --rtems-bsps=arm/xilinx_zynq_a9_qemu \ - --buildset=buildset/default.ini -./waf -./waf install -qemu-system-arm -no-reboot -serial null -serial mon:stdio -net none \ - -nographic -M xilinx-zynq-a9 -m 256M \ - -kernel build/arm-rtems5-xilinx_zynq_a9_qemu-default/selectpollkqueue01.exe -``` - -1. Create a sandbox directory: - -``` -$ sandbox="$PWD/sandbox" -$ mkdir sandbox -``` - -2. Clone the repositories: - -``` -$ cd "$sandbox" -$ git clone git://git.rtems.org/rtems-source-builder.git -$ git clone git://git.rtems.org/rtems.git -$ git clone git://git.rtems.org/rtems-libbsd.git -``` - -3. Build and install the tools: - -``` -$ cd "$sandbox" -$ cd rtems-source-builder/rtems -$ ../source-builder/sb-set-builder --prefix="$sandbox/rtems/5" 5/rtems-arm -``` - -4. Bootstrap the RTEMS sources: - -``` -$ cd "$sandbox" -$ cd rtems -$ PATH="$sandbox/rtems/5/bin:$PATH" ./bootstrap -``` - -5. Build and install the RTEMS Board Support Packages (BSP) you want to use: - -``` -$ cd "$sandbox" -$ mkdir b-xilinx_zynq_a9_qemu -$ cd b-xilinx_zynq_a9_qemu -$ PATH="$sandbox/rtems/5/bin:$PATH" "$sandbox/rtems/configure" \ - --target=arm-rtems5 --prefix="$sandbox/rtems/5" \ - --disable-networking --enable-rtemsbsp=xilinx_zynq_a9_qemu -$ PATH="$sandbox/rtems/5/bin:$PATH" make -$ PATH="$sandbox/rtems/5/bin:$PATH" make install -``` - -6. Populate the rtems_waf git submodule. Note, make sure you specify - 'rtems_waf' or the FreeBSD kernel source will be cloned: - -``` -$ cd "$sandbox" -$ cd rtems-libbsd -$ git submodule init -$ git submodule update rtems_waf -``` - -7. Run Waf's configure with your specific settings. In this case the path to - the tools and RTEMS are provided on the command line and so do not need to - be in your path or environment [1]. You can use - '--rtems-archs=arm,sparc,i386' or - '--rtems-bsps=arm/xilinx_zynq_a9_qemu,sparc/sis,i386/pc586' to build for - more than BSP at a time. Note, you must provide the architecture and BSP as - a pair. Providing just the BSP name will fail. This call also explicitly - provides a buildset via the '--buildset=buildset/default.ini' option. If no - buildset is provided the default one (which is the same as the one provided - explicitly here) will be used. You can also provide multiple buildsets as a - coma separated list or via multiple '--buildset=x' options. - -``` -$ cd "$sandbox" -$ cd rtems-libbsd -$ ./waf configure --prefix="$sandbox/rtems/5" \ - --rtems-bsps=arm/xilinx_zynq_a9_qemu \ - --buildset=buildset/default.ini -``` - -8. Build and install. The LibBSD package will be installed into the prefix - provided to configure: - -``` -$ cd "$sandbox" -$ cd rtems-libbsd -$ ./waf -$ ./waf install -``` - -9. Run the tests on QEMU, for example using VDE: - -``` -$ qemu-system-arm -no-reboot -serial null -serial mon:stdio \ - -net nic,model=cadence_gem -net vde,id=vde0,sock=/tmp/vde1 \ - -nographic -M xilinx-zynq-a9 -m 256M \ - -kernel build/arm-rtems5-xilinx_zynq_a9_qemu/selectpollkqueue01.exe -``` - -[1] It is good practice to keep your environment as empty as possible. Setting - paths to tools or specific values to configure or control a build is - dangerous because settings can leak between different builds and change - what you expect a build to do. The Waf tool used here lets you specify on - the command line the tools and RTEMS paths and this is embedded in Waf's - configuration information. If you have a few source trees working at any - one time with different tool sets or configurations you can easly move - between them safe in the knowledge that one build will not infect another. - -Branches --------- - -* master - branch intended for the RTEMS master which tracks the FreeBSD master - branch. This branch must be used for libbsd development. Back ports to the - 6-freebsd-12 are allowed. - -* 6-freebsd-12 - branch intended for RTEMS 6 which tracks the FreeBSD stable/12 - branch. This branch is maintained and regular updates from FreeBSD are - planned. It is recommended for production systems. - -* 5-freebsd-12 - branch belongs to the RTEMS 5 release. It is based on FreeBSD - stable/12 branch. It is recommended for production systems that use RTEMS 5. - -* 5 - branch belongs to the RTEMS 5 release. It is based on a FreeBSD - development version. - -* freebsd-9.3 - branch for some RTEMS version with a FreeBSD 9.3 baseline. - This branch is unmaintained. It is recommended to update to RTEMS 5 or 6. - -* 4.11 - branch for the RTEMS 4.11 release series. This branch is - unmaintained. It is recommended to update to RTEMS 5 or 6. - -Updating RTEMS Waf Support --------------------------- - -If you have a working libbsd repository and new changes to the `rtems_waf` -submodule has been made, you will need update. A `git status` will indicate -there are new commits with: - -``` -$ git status - [ snip output ] - modified: rtems_waf (new commits) - [ snip output ] -``` - -To update: - -``` -$ git submodule update rtems_waf -``` - -Please make sure you use the exact command or you might find you are cloning -the whole of the FreeBSD source tree. If that happens simply git ^C and try -again. - -FreeBSD Kernel Options ----------------------- - -You can set FreeBSD kernel options during build configuration with the ---freebsd-option=a,b,c,... configuration command option. This is an advanced -option and should only be used if you are familiar with the internals of the -FreeBSD kernel and what these options do. Each of the comma separated options -is converted to uppercase and passed as a compiler command line define (-D). - -The options are listed in: - -https://github.com/freebsd/freebsd/blob/master/sys/conf/NOTES - -An example to turn on a verbose kernel boot, verbose sysinit and bus debugging -configure with: - -``` ---freebsd-options=bootverbose,verbose_sysinit,bus_debug -``` - -To enable kernel internal consistency checking use: - -``` ---freebsd-options=invariants,invariant_support -``` - -Qemu and Networking -------------------- - -You can use the Qemu simulator to run a LibBSD based application and connect it -to a virtual network on your host. You have to create a TAP virtual Ethernet -interface for this: - -``` -sudo tunctl -p -t qtap -u $(whoami) -sudo ip link set dev qtap up -sudo ip addr add 169.254.1.1/16 dev qtap -``` - -You can show the interface state with the following command: - -``` -$ ip addr show qtap -27: qtap: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000 - link/ether 8e:50:a2:fb:e1:3b brd ff:ff:ff:ff:ff:ff - inet 169.254.1.1/16 scope global qtap - valid_lft forever preferred_lft forever -``` - -You may have to assign the interface to a firewall zone. - -The Qemu command line varies by board support package, here is an example for -the arm/xilinx_zynq_a9_qemu BSP: - -``` -qemu-system-arm -serial null -serial mon:stdio -nographic \ - -M xilinx-zynq-a9 -m 256M \ - -net tap,ifname=qtap,script=no,downscript=no \ - -net nic,model=cadence_gem,macaddr=0e:b0:ba:5e:ba:12 \ - -kernel build/arm-rtems5-xilinx_zynq_a9_qemu-default/media01.exe -``` - -After some seconds it will acquire a IPv4 link-local address, e.g. - -``` -info: cgem0: probing for an IPv4LL address -debug: cgem0: checking for 169.254.159.156 -``` - -You can connect to the target via telnet for example: - -``` -$ telnet 169.254.159.156 -Trying 169.254.159.156... -Connected to 169.254.159.156. -Escape character is '^]'. - -RTEMS Shell on /dev/pty4. Use 'help' to list commands. -TLNT [/] # -``` diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..9b328078 --- /dev/null +++ b/README.rst @@ -0,0 +1,853 @@ +RTEMS LibBSD +************ + +Welcome to building LibBSD for RTEMS using Waf. This package is a library +containing various parts of the FreeBSD kernel ported to RTEMS. The library +replaces the networking port of FreeBSD in the RTEMS kernel sources. This +package is designed to be updated from the FreeBSD kernel sources and contains +more than just the networking code. + +To build this package you need a current RTEMS tool set for your architecture, +and a recent RTEMS kernel for your BSP installed. If you already have this, you +can skip to step 5 of the build procedure. + +Building and Installing LibBSD +============================== + +The following instructions show you how to build and install the RTEMS Tool +Suite for the ``arm`` target, the RTEMS kernel using the +``arm/xilinx_zynq_a9_qemu`` Board Support Package (BSP), and the LibBSD for this +BSP. + +The Waf build support for RTEMS requires you provide your BSP name as an +architecture and BSP pair. You must provide both or Waf will generate an error +message during the configure phase. + +We will build an Xilinx Zynq Qemu BSP using the name +``arm/xilinx_zynq_a9_qemu``. You can copy and paste the shell commands below to +do this. The individual steps are explained afterwards. + +.. code-block:: none + + sandbox="$PWD/sandbox" + mkdir sandbox + cd "$sandbox" + git clone git://git.rtems.org/rtems-source-builder.git + git clone git://git.rtems.org/rtems.git + git clone git://git.rtems.org/rtems-libbsd.git + cd "$sandbox" + cd rtems-source-builder/rtems + ../source-builder/sb-set-builder --prefix="$sandbox/rtems/6" 6/rtems-arm + cd "$sandbox" + cd rtems + echo -e "[arm/xilinx_zynq_a9_qemu]" > config.ini + ./waf configure --prefix "$sandbox/rtems/6" + ./waf + ./waf install + cd "$sandbox" + cd rtems-libbsd + git submodule init + git submodule update rtems_waf + ./waf configure --prefix="$sandbox/rtems/6" \ + --rtems-bsps=arm/xilinx_zynq_a9_qemu \ + --buildset=buildset/default.ini + ./waf + ./waf install + ../rtems/6/bin/rtems-test --rtems-bsp=xilinx_zynq_a9_qemu build + +1. Create a sandbox directory: + + .. code-block:: none + + $ sandbox="$PWD/sandbox" + $ mkdir sandbox + +2. Clone the repositories: + + .. code-block:: none + + $ cd "$sandbox" + $ git clone git://git.rtems.org/rtems-source-builder.git + $ git clone git://git.rtems.org/rtems.git + $ git clone git://git.rtems.org/rtems-libbsd.git + +3. Build and install the tools: + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems-source-builder/rtems + $ ../source-builder/sb-set-builder --prefix="$sandbox/rtems/6" 6/rtems-arm + +4. Build and install the RTEMS Board Support Packages (BSP) you want to use: + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems + $ echo -e "[arm/xilinx_zynq_a9_qemu]" > config.ini + $ ./waf configure --prefix "$sandbox/rtems/6" + $ ./waf + $ ./waf install + +5. Populate the ``rtems_waf`` git submodule. Note, make sure you specify + ``rtems_waf`` or the FreeBSD kernel source will be cloned: + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems-libbsd + $ git submodule init + $ git submodule update rtems_waf + +6. Run Waf's configure with your specific settings. In this case the path to + the tools and RTEMS are provided on the command line and so do not need to + be in your path or environment, see comment below. You can use + ``--rtems-archs=arm,sparc,i386`` or + ``--rtems-bsps=arm/xilinx_zynq_a9_qemu,sparc/sis,i386/pc586`` to build for + more than BSP at a time. Note, you must provide the architecture and BSP as + a pair. Providing just the BSP name will fail. This call also explicitly + provides a buildset via the ``--buildset=buildset/default.ini`` option. If no + buildset is provided the default one (which is the same as the one provided + explicitly here) will be used. You can also provide multiple buildsets as a + coma separated list or via multiple ``--buildset=x`` options. + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems-libbsd + $ ./waf configure --prefix="$sandbox/rtems/6" \ + --rtems-bsps=arm/xilinx_zynq_a9_qemu \ + --buildset=buildset/default.ini + +7. Build and install. The LibBSD package will be installed into the prefix + provided to configure: + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems-libbsd + $ ./waf + $ ./waf install + +9. Run the tests: + + .. code-block:: none + + $ cd "$sandbox" + $ cd rtems-libbsd + $ ../rtems/6/bin/rtems-test --rtems-bsp=xilinx_zynq_a9_qemu build + +It is good practice to keep your environment as empty as possible. Setting +paths to tools or specific values to configure or control a build is dangerous +because settings can leak between different builds and change what you expect a +build to do. The Waf tool used here lets you specify on the command line the +tools and RTEMS paths and this is embedded in Waf's configuration information. +If you have a few source trees working at any one time with different tool sets +or configurations you can easly move between them safe in the knowledge that +one build will not infect another. + +Buildsets +========= + +Note that the LibBSD supports different buildsets. These can be selected with +the ``--buildset=some.ini`` option during the configure phase. Take a look at +the comments in ``buildset/*.ini`` to see which build sets are officially +supported. + +You can also create and provide your own buildset configuration. But remember +that it's quite easy to break something by disabling the wrong modules. Only +the configurations in the ``buildset`` directory are officially maintained. + +Initialization +============== + +To initialise the LibBSD create a suitable ``rc.conf`` file. The FreeBSD man +page `RC.CONF(5) <https://www.freebsd.org/cgi/man.cgi?rc.conf>`_ provides the +details needed to create a suitable format file + +You can call one of three functions to run the initialisation once LibBSD has +initialised: + +* ``rtems_bsd_run_etc_rc_conf()``: Run ``/etc/rc.conf``. +* ``rtems_bsd_run_rc_conf()``: Run a user supplied file. +* ``rtems_bsd_run_rc_conf_script()``: Run the in memory line feed separated text string. + +For exapmle: + +.. code-block:: c + + void + network_init(void) + { + rtems_status_code sc; + + sc = rtems_bsd_initialize(); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_bsd_run_etc_rc_conf(true); /* verbose = true */ + } + +By default the networking support is builtin. Other directives can be added and +are found in ``machine/rtems-bsd-rc-conf-directives.h``. Please check the file +for the list. + +The following network names are supported: + +.. code-block:: none + + cloned_interfaces + ifconfig_'interface' + defaultrouter + hostname + +For example: + +.. code-block:: none + + # + # My BSD initialisation. + # + hostname="myhost" + cloned_interfaces="vlan0 vlan1" + ifconfig_re0="inet inet 10.10.10.10 netmask 255.255.255.0" + fconfig_vlan0="inet 10.11.10.10 255.255.255.0 vlan 101 vlandev re0" + defaultrouter="10.10.10.1" + +You can also intialise the LibBSD using code. The following code to +initialize the LibBSD: + +.. code-block:: c + + #include <assert.h> + #include <sysexits.h> + + #include <rtems/bsd/bsd.h> + + void + network_init(void) + { + rtems_status_code sc; + int exit_code; + + sc = rtems_bsd_initialize(); + assert(sc == RTEMS_SUCCESSFUL); + + exit_code = rtems_bsd_ifconfig_lo0(); + assert(exit_code == EX_OK); + } + +This performs the basic network stack initialization with a loopback interface. +Further initialization must be done using the standard FreeBSD network +configuration commands +`IFCONFIG(8) <http://www.freebsd.org/cgi/man.cgi?query=ifconfig&sektion=8>`_ +using ``rtems_bsd_command_ifconfig()`` and +`ROUTE(8) <http://www.freebsd.org/cgi/man.cgi?query=route&sektion=8>`_ +using ``rtems_bsd_command_route()``. For an example, please have a look at +`default-network-init.h <testsuite/include/rtems/bsd/test/default-network-init.h>`_. + +Task Priorities and Stack Size +============================== + +The default task priority is 96 for the interrupt server task (name "IRQS"), 98 +for the timer server task (name "TIME") and 100 for all other tasks. The +application may provide their own implementation of the +``rtems_bsd_get_task_priority()`` function if different values are desired (for +example in the translation unit which calls ``rtems_bsd_initialize()``). + +The task stack size is determined by the ``rtems_bsd_get_task_stack_size()`` +function which may be provided by the application in case the default is not +appropriate. + +Size for Allocator Domains +========================== + +The size for an allocator domain can be specified via the +``rtems_bsd_get_allocator_domain_size()`` function. The application may provide +their own implementation of the ``rtems_bsd_get_allocator_domain_size()`` +function (for example in the module which calls ``rtems_bsd_initialize()``) if +different values are desired. The default size is 8MiB for all domains. + +Redirecting or Disabling the Output +=================================== + +A lot of system messages are printed to the ``stdout`` by default. If you want to +redirect them you can overwrite the default print handler. That can even be done +before the libbsd initialization to catch all messages. An example would look +like follows: + +.. code-block:: c + + int my_vprintf_handler(int level, const char *fmt, va_list ap) { + /* Do something with the messages. */ + + return number_of_printed_chars; + } + + ... + /* In your initialization: */ + rtems_bsd_vprintf_handler old; + old = rtems_bsd_set_vprintf_handler(my_vprintf_handler); + ... + +As a special case, you can set the ``rtems_bsd_vprintf_handler_mute(...)`` +provided by LibBSD to suppress all output. + +Branches +======== + +master + This branch is intended for the RTEMS master which tracks the FreeBSD + master branch. This branch must be used for libbsd development. Back + ports to the 6-freebsd-12 are allowed. + +6-freebsd-12 + This branch is intended for RTEMS 6 which tracks the FreeBSD stable/12 + branch. This branch is maintained and regular updates from FreeBSD are + planned. It is recommended for production systems. + +5-freebsd-12 + This branch belongs to the RTEMS 5 release. It is based on FreeBSD + stable/12 branch. It is recommended for production systems that use + RTEMS 5. + +5 + This branch belongs to the RTEMS 5 release. It is based on a FreeBSD + development version. This branch is unmaintained. Use 5-freebsd-12 for + RTEMS 5. + +freebsd-9.3 + Is the branch for some RTEMS version with a FreeBSD 9.3 baseline. This + branch is unmaintained. It is recommended to update to RTEMS 5 or 6. + +4.11 + Is the branch for the RTEMS 4.11 release series. This branch is + unmaintained. It is recommended to update to RTEMS 5 or 6. + +Features +======== + +The following features are available in LibBSD. Some features need device +driver support for a particular target platform. + +* `BPF(4) <http://www.freebsd.org/cgi/man.cgi?query=bpf&sektion=4>`_: Berkeley Packet Filter +* `DHCPCD(8) <http://roy.marples.name/projects/dhcpcd/index>`_: DHCP client +* `dns_sd.h <mDNSResponder/mDNSShared/dns_sd.h>`_: DNS Service Discovery +* `GETHOSTBYNAME(3) <http://www.freebsd.org/cgi/man.cgi?query=gethostbyname&sektion=3>`_: Get network host entry +* `IF_BRIDGE(4) <http://www.freebsd.org/cgi/man.cgi?query=if_bridge&sektion=4>`_: Network bridge device +* `INET(4) <http://www.freebsd.org/cgi/man.cgi?query=inet&sektion=4>`_: Internet protocol family +* `INET6(4) <http://www.freebsd.org/cgi/man.cgi?query=inet6&sektion=4>`_: Internet protocol version 6 family +* `IPSEC(4) <http://www.freebsd.org/cgi/man.cgi?query=ipsec&sektion=4>`_: Internet Protocol Security protocol +* `KQUEUE(2) <http://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2>`_: Kernel event notification mechanism +* `LAGG(4) <http://www.freebsd.org/cgi/man.cgi?query=lagg&sektion=4>`_: Link aggregation and link failover interface +* `mDNSEmbeddedAPI.h <mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h>`_: Multi-Cast DNS +* `MMC(4) <http://www.freebsd.org/cgi/man.cgi?query=mmc&sektion=4>`_: MultiMediaCard and SD Card bus driver +* `NET80211(4) <http://www.freebsd.org/cgi/man.cgi?query=net80211&sektion=4>`_: Standard interface to IEEE 802.11 devices +* `NVME(4) <http://www.freebsd.org/cgi/man.cgi?query=nvme&sektion=4>`_: NVM Express core driver +* `PCI(4) <http://www.freebsd.org/cgi/man.cgi?query=pci&sektion=4>`_: Generic PCI/PCIe bus driver +* `PF(4) <http://www.freebsd.org/cgi/man.cgi?query=pf&sektion=4>`_: Packet filter +* `POLL(2) <http://www.freebsd.org/cgi/man.cgi?query=poll&sektion=2>`_: Synchronous I/O multiplexing +* `RESOLVER(3) <http://www.freebsd.org/cgi/man.cgi?query=resolver&sektion=3>`_: Resolver routines +* `ROUTE(4) <http://www.freebsd.org/cgi/man.cgi?query=route&sektion=4>`_: Kernel packet forwarding database +* `SELECT(2) <http://www.freebsd.org/cgi/man.cgi?query=select&sektion=2>`_: Synchronous I/O multiplexing +* `SOCKET(2) <http://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2>`_: Create an endpoint for communication +* `SSL(7) <http://www.freebsd.org/cgi/man.cgi?query=ssl&sektion=7>`_: OpenSSL SSL/TLS library +* `SYSCTL(3) <http://www.freebsd.org/cgi/man.cgi?query=sysctl&sektion=3>`_: Get or set system information +* `TCP(4) <http://www.freebsd.org/cgi/man.cgi?query=tcp&sektion=4>`_: Internet Transmission Control Protocol +* `UDP(4) <http://www.freebsd.org/cgi/man.cgi?query=udp&sektion=4>`_: Internet User Datagram Protocol +* `UMASS(4) <http://www.freebsd.org/cgi/man.cgi?query=umass&sektion=4>`_: USB Mass Storage Devices driver +* `UNIX(4) <http://www.freebsd.org/cgi/man.cgi?query=unix&sektion=4>`_: UNIX-domain protocol family +* `USB(4) <http://www.freebsd.org/cgi/man.cgi?query=usb&sektion=4>`_: Universal Serial Bus +* `VLAN(4) <http://www.freebsd.org/cgi/man.cgi?query=vlan&sektion=4>`_: IEEE 802.1Q VLAN network interface + +Commands +======== + +In LibBSD the following ports of FreeBSD command line tools are available. You +can invoke the commands in the RTEMS Shell or through function calls, for +example ``rtems_bsd_command_ifconfig()``. The functions declarations are +available through +`#include <machine/rtems-bsd-commands.h> <rtemsbsd/include/machine/rtems-bsd-commands.h>`_. + +* `ARP(8) <http://www.freebsd.org/cgi/man.cgi?query=arp&sektion=8>`_: Address resolution display and control +* `HOSTNAME(1) <http://www.freebsd.org/cgi/man.cgi?query=hostname&sektion=1>`_: Set or print name of current host system +* `IFCONFIG(8) <http://www.freebsd.org/cgi/man.cgi?query=ifconfig&sektion=8>`_: Configure network interface parameters +* `IFMCSTAT(8) <http://www.freebsd.org/cgi/man.cgi?query=ifmcstat&sektion=8>`_: Dump multicast group management statistics per interface +* `NETSTAT(1) <http://www.freebsd.org/cgi/man.cgi?query=netstat&sektion=1>`_: Show network status +* `NVMECONTROL(8) <http://www.freebsd.org/cgi/man.cgi?query=nvmecontrol&sektion=8>`_: NVM Express control utility +* `OPENSSL(1) <http://www.freebsd.org/cgi/man.cgi?query=openssl&sektion=1>`_: OpenSSL command line tool +* `PFCTL(8) <http://www.freebsd.org/cgi/man.cgi?query=pfctl&sektion=8>`_: Control the packet filter (PF) device +* `PING6(8) <http://www.freebsd.org/cgi/man.cgi?query=ping6&sektion=8>`_: Send ICMPv6 ECHO_REQUEST packets to network hosts +* `PING(8) <http://www.freebsd.org/cgi/man.cgi?query=ping&sektion=8>`_: Send ICMP ECHO_REQUEST packets to network hosts +* `RACOON(8) <http://www.freebsd.org/cgi/man.cgi?query=racoon&sektion=8>`_: IKE (ISAKMP/Oakley) key management daemon +* `ROUTE(8) <http://www.freebsd.org/cgi/man.cgi?query=route&sektion=8>`_: Manually manipulate the routing tables +* `SETKEY(8) <http://www.freebsd.org/cgi/man.cgi?query=setkey&sektion=8>`_: Manually manipulate the IPsec SA/SP database +* `STTY(1) <http://www.freebsd.org/cgi/man.cgi?query=stty&sektion=1>`_: Set the options for a terminal device interface +* `SYSCTL(8) <http://www.freebsd.org/cgi/man.cgi?query=sysctl&sektion=8>`_: Get or set kernel state +* `TCPDUMP(1) <http://www.freebsd.org/cgi/man.cgi?query=tcpdump&sektion=1>`_: Dump traffic on a network +* `VMSTAT(8) <http://www.freebsd.org/cgi/man.cgi?query=vmstat&sektion=8>`_: Report virtual memory statistics +* `WPA_SUPPLICANT(8) <http://www.freebsd.org/cgi/man.cgi?query=wpa_supplicant&sektion=8>`_: WPA/802.11i Supplicant for wireless network devices + +Command specific notes are listed below. + +HOSTNAME(1) + In addition to the standard options the RTEMS version of the HOSTNAME(1) + command supports the -m flag to set/get the multicast hostname of the mDNS + resolver instance. See also ``rtems_mdns_sethostname()`` and + ``rtems_mdns_gethostname()``. + +Packet Filter (PF, Firewall) +============================ + +It is possible to use PF as a firewall. See the +`FreeBSD Handbook <https://docs.freebsd.org/en/books/handbook/firewalls/#firewalls-pf>`_ +for details on the range of functions and for how to configure the firewall. + +Configuration +------------- + +The following is necessary to use PF on RTEMS: + +* You have to provide a ``/etc/pf.os`` file. The firewall can use it for passive + OS fingerprinting. If you don't want to use this feature, the file may contain + nothing except a line of comment (for example "# empty"). + +* If some filters use protocol names (like ``tcp`` or ``udp``) you have to provide a + ``/etc/protocols`` file. + +* If some filters use service names (like ``http`` or ``https``) you have to provide a + ``/etc/services`` file. + +* Create a rule file (normally ``/etc/pf.conf``). See the FreeBSD manual for the + syntax. + +* Load the rule file using the + `pfctl <http://www.freebsd.org/cgi/man.cgi?query=pfctl&sektion=8>`_ + command and enable PF. Please note that the pfctl command needs a lot of + stack. You should use at least RTEMS_MINIMUM_STACK_SIZE + 8192 Bytes of + stack. An example initialisation can look like follows: + + .. code-block:: c + + int exit_code; + char *argv[] = { + "pfctl", + "-f", + "/etc/pf.conf", + "-e", + NULL + }; + + exit_code = rtems_bsd_command_pfctl(ARGC(argv), argv); + assert(exit_code == EXIT_SUCCSESS); + +Known Restrictions +------------------ + +Currently, PF on RTEMS always uses the configuration for memory restricted +systems (on FreeBSD that means systems with less than 100 MB RAM). This is +fixed in ``pfctl_init_options()``. + +Wireless Network (WLAN) +======================= + +The LibBSD provides a basic support for WLAN. Note that currently this support +is still in an early state. The WLAN support is _not_ enabled in the default +buildset. You have to configure LibBSD with the +``--buildset=buildset/everything.ini`` to enable that feature. + +Configuration +------------- + +The following gives a rough overview over the necessary steps to connect to an +encrypted network with an RTL8188EU based WiFi dongle: + +* Reference all necessary module for your BSP. For some BSPs this is already + done in the ``nexus-devices.h``: + + .. code-block:: none + + SYSINIT_MODULE_REFERENCE(wlan_ratectl_none); + SYSINIT_MODULE_REFERENCE(wlan_sta); + SYSINIT_MODULE_REFERENCE(wlan_amrr); + SYSINIT_MODULE_REFERENCE(wlan_wep); + SYSINIT_MODULE_REFERENCE(wlan_tkip); + SYSINIT_MODULE_REFERENCE(wlan_ccmp); + SYSINIT_DRIVER_REFERENCE(rtwn_usb, uhub); + +* Create your wlan device using ifconfig: + + .. code-block:: none + + ifconfig wlan0 create wlandev rtwn0 up + +* Start a ``wpa_supplicant`` instance for that device: + + .. code-block:: none + + wpa_supplicant_fork -Dbsd -iwlan0 -c/media/mmcsd-0-0/wpa_supplicant.conf + +Note that the wpa_supplicant will only be active till the device goes down. A +workaround is to just restart it every time it exits. + +Known Restrictions +------------------ + +* The network interface (e.g. wlan0) is currently not automatically created. It + would be nice, if some service would create it as soon as for example a USB + device is connected. In FreeBSD the names are assigned via rc.conf with lines + like ``wlans_rtwn0="wlan0"``. + +* ``wpa_supplicant`` hast to be started after the device is created. It has to be + restarted every time the connection goes down. Instead of this behaviour, + there should be some service that starts and restarts ``wpa_supplicant`` + automatically if a interface is ready. Probably the dhcpcd hooks could be used + for that. + +* The current ``wpa_supplicant`` implementation is protected with a lock so it can't + be started more than one time. If multiple interface should be used, all have + to be handled by that single instance. That makes it hard to add interfaces + dynamically. ``wpa_supplicant`` should be reviewed thoroughly whether multiple + instances could be started in parallel. + +* The control interface of ``wpa_supplicant`` most likely doesn't work. The wpa_cli + application is not ported. + +IPSec +===== + +The IPSec support is optional in LibBSD. It is disabled in the default build +set. Please make sure to use a build set with ``netipsec = on``. + +Configuration +------------- + +To use IPSec the following configuration is necessary: + +.. code-block:: none + + SYSINIT_MODULE_REFERENCE(if_gif); + SYSINIT_MODULE_REFERENCE(cryptodev); + RTEMS_BSD_RC_CONF_SYSINT(rc_conf_ipsec) + RTEMS_BSD_DEFINE_NEXUS_DEVICE(cryptosoft, 0, 0, NULL); + +Alternatively, you can use the ``RTEMS_BSD_CONFIG_IPSEC`` which also includes the +rc.conf support for ipsec. It's still necessary to include a crypto device in +your config (``cryptosoft`` in the above sample). + +The necessary initialization steps for a IPSec connection are similar to the +steps on a FreeBSD-System. The example assumes the following setup: + +- RTEMS external IP: 192.168.10.1/24 +- RTEMS internal IP: 10.10.1.1/24 +- remote external IP: 192.168.10.10/24 +- remote internal IP: 172.24.0.1/24 +- shared key: "mysecretkey" + +With this the following steps are necessary: + +* Create a gif0 device: + + .. code-block:: none + + ifconfig gif0 create + +* Configure the gif0 device: + + .. code-block:: none + + ifconfig gif0 10.10.1.1 172.24.0.1 + ifconfig gif0 tunnel 192.168.10.1 192.168.10.10 + +* Add a route to the remote net via the remote IP: + + .. code-block:: none + + route add 172.24.0.0/24 172.24.0.1 + +* Create a correct rule set in ``/etc/setkey.conf``: + + .. code-block:: none + + flush; + spdflush; + spdadd 10.10.1.0/24 172.24.0.0/24 any -P out ipsec esp/tunnel/192.168.10.1-192.168.10.10/use; + spdadd 172.24.0.0/24 10.10.1.0/24 any -P in ipsec esp/tunnel/192.168.10.10-192.168.10.1/use; + +* Call ``setkey``: + + .. code-block:: none + + setkey -f /etc/setkey.conf + +* Create a correct configuration in ``/etc/racoon.conf``: + + .. code-block:: none + + path pre_shared_key "/etc/racoon_psk.txt"; + log info; + + padding # options are not to be changed + { + maximum_length 20; + randomize off; + strict_check off; + exclusive_tail off; + } + + listen # address [port] that racoon will listen on + { + isakmp 192.168.10.1[500]; + } + + remote 192.168.10.10 [500] + { + exchange_mode main; + my_identifier address 192.168.10.1; + peers_identifier address 192.168.10.10; + proposal_check obey; + proposal { + encryption_algorithm 3des; + hash_algorithm md5; + authentication_method pre_shared_key; + lifetime time 3600 sec; + dh_group 2; + } + } + + sainfo (address 10.10.1.0/24 any address 172.24.0.0/24 any) + { + pfs_group 2; + lifetime time 28800 sec; + encryption_algorithm 3des; + authentication_algorithm hmac_md5; + compression_algorithm deflate; + } + +* Create a correct configuration in ``/etc/racoon_psk.txt``: + + .. code-block:: none + + 192.168.10.10 mysecretkey + +* Start a ike-daemon (racoon): + + .. code-block:: none + + racoon -F -f /etc/racoon.conf +---- + +All commands can be called via the respective API functions. For racoon there is +a ``rtems_bsd_racoon_daemon()`` function that forks of racoon as a task. + +Alternatively, IPSec can also be configured via rc.conf entries: + +.. code-block:: none + + cloned_interfaces="gif0" + ifconfig_gif0="10.10.1.1 172.24.0.1 tunnel 192.168.10.1 192.168.10.10" + ike_enable="YES" + ike_program="racoon" + ike_flags="-F -f /etc/racoon.conf" + ike_priority="250" + + ipsec_enable="YES" + ipsec_file="/etc/setkey.conf" + +ATTENTION: It is possible that the first packets slip through the tunnel without +encryption (true for FreeBSD as well as RTEMS). You might want to set up a +firewall rule to prevent that. + +Updating RTEMS Waf Support +========================== + +If you have a working libbsd repository and new changes to the ``rtems_waf`` +submodule has been made, you will need update. A ``git status`` will indicate +there are new commits with: + +.. code-block:: none + + $ git status + [ snip output ] + modified: rtems_waf (new commits) + [ snip output ] + +To update: + +.. code-block:: none + + $ git submodule update rtems_waf + +Please make sure you use the exact command or you might find you are cloning +the whole of the FreeBSD source tree. If that happens simply git ^C and try +again. + +FreeBSD Kernel Options +====================== + +You can set FreeBSD kernel options during build configuration with the +--freebsd-option=a,b,c,... configuration command option. This is an advanced +option and should only be used if you are familiar with the internals of the +FreeBSD kernel and what these options do. Each of the comma separated options +is converted to uppercase and passed as a compiler command line define (-D). + +The options are listed in the FreeBSD +`NOTES <https://github.com/freebsd/freebsd/blob/master/sys/conf/NOTES>`_ +file. + +An example to turn on a verbose kernel boot, verbose sysinit and bus debugging +configure with: + +.. code-block:: none + + --freebsd-options=bootverbose,verbose_sysinit,bus_debug + +To enable kernel internal consistency checking use: + +.. code-block:: none + + --freebsd-options=invariants,invariant_support + +SMP Requirements +================ + +In order to support +`EPOCH(9) <https://www.freebsd.org/cgi/man.cgi?query=epoch&apropos=0&sektion=9>`_ +a scheduler with thread pinning support is required. This is the case if you +use the default scheduler configuration. EPOCH(9) is a central synchronization +mechanism of the network stack. + +Configuration for Network Tests +=============================== + +If you need some other IP configuration for the network tests that use a fixed +IP config you can copy ``config.inc`` to a location outside to the source tree and +adapt it. Then use the option ``--net-test-config=NET_CONFIG`` to pass the file to +Waf's configure command. + +.. code-block:: none + + NET_CFG_SELF_IP = 10.0.0.2 + NET_CFG_NETMASK = 255.255.0.0 + NET_CFG_PEER_IP = 10.0.0.1 + NET_CFG_GATEWAY_IP = 10.0.0.1 + +Qemu and Networking +=================== + +You can use the Qemu simulator to run a LibBSD based application and connect it +to a virtual network on your host. + +Networking with TAP Interface +----------------------------- + +One option for networking with Qemu is using a TAP interface (virtual +Ethernet). You can create a TAP interface with these commands on Linux: + +.. code-block:: none + + sudo ip tuntap add qtap mode tap user $(whoami) + sudo ip link set dev qtap up + sudo ip addr add 169.254.1.1/16 dev qtap + +You can show the interface state with the following command: + +.. code-block:: none + + $ ip addr show qtap + 27: qtap: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000 + link/ether 8e:50:a2:fb:e1:3b brd ff:ff:ff:ff:ff:ff + inet 169.254.1.1/16 scope global qtap + valid_lft forever preferred_lft forever + +You may have to assign the interface to a firewall zone. + +The Qemu command line varies by board support package, here is an example for +the arm/xilinx_zynq_a9_qemu BSP: + +.. code-block:: none + + qemu-system-arm -serial null -serial mon:stdio -nographic \ + -M xilinx-zynq-a9 -m 256M \ + -net nic,model=cadence_gem \ + -net tap,ifname=qtap,script=no,downscript=no \ + -kernel build/arm-rtems6-xilinx_zynq_a9_qemu-default/media01.exe + +Make sure that each Qemu instance uses its own MAC address to avoid an address +conflict (or otherwise use it as a test). After some seconds it will acquire a +IPv4 link-local address, for example: + +.. code-block:: none + + info: cgem0: probing for an IPv4LL address + debug: cgem0: checking for 169.254.159.156 + +You can connect to the target via telnet, for example: + +.. code-block:: none + + $ telnet 169.254.159.156 + Trying 169.254.159.156... + Connected to 169.254.159.156. + Escape character is '^]'. + + RTEMS Shell on /dev/pty4. Use 'help' to list commands. + TLNT [/] # + +Virtual Distributed Ethernet (VDE) +---------------------------------- + +You can use a Virtual Distributed Ethernet (VDE) to create a network +environment that does not need to run Qemu as root or needing to drop the tap's +privileges to run Qemu. + +VDE creates a software switch with a default of 32 ports which means a single +kernel tap can support 32 Qemu networking sessions. + +To use VDE you need to build Qemu with VDE support. The RSB can detect a VDE +plug and enable VDE support in Qemu when building. On FreeBSD install the VDE +support with: + +.. code-block:: none + + pkg install -u vde2 + +Build Qemu with the RSB. + +To network create a bridge and a tap. The network is 10.10.1.0/24. On FreeBSD +add to your ``/etc/rc.conf``: + +.. code-block:: none + + cloned_interfaces="bridge0 tap0" + autobridge_interfaces="bridge0" + autobridge_bridge0="re0 tap0" + ifconfig_re0="up" + ifconfig_tap0="up" + ifconfig_bridge0="inet 10.1.1.2 netmask 255.255.255.0" + defaultrouter="10.10.1.1" + +Start the VDE switch as root: + +.. code-block:: none + + sysctl net.link.tap.user_open=1 + sysctl net.link.tap.up_on_open=1 + vde_switch -d -s /tmp/vde1 -M /tmp/mgmt1 -tap tap0 -m 660 --mgmtmode 660 + chmod 660 /dev/tap0 + +You can connect to the VDE switch's management channel using: + +.. code-block:: none + + vdeterm /tmp/mgmt1 + +To run Qemu: + +.. code-block:: none + + qemu-system-arm -serial null -serial mon:stdio -nographic \ + -M xilinx-zynq-a9 -m 256M \ + -net nic,model=cadence_gem \ + -net vde,id=vde0,sock=/tmp/vde1 + -kernel build/arm-rtems6-xilinx_zynq_a9_qemu-default/rcconf02.exe @@ -883,7 +883,7 @@ class Module(object): ] return files - def addPlainTextFile(self, files): + def addPlainTextFiles(self, files): self.files += self.addFiles('user', files, FreeBSDPathComposer(), Converter(), Converter(), assertNothing) @@ -1062,7 +1062,8 @@ class ModuleManager(object): def _checkDependencies(self): enabled_modules = self.getEnabledModules() - enabled_modules.remove('tests') + if 'tests' in enabled_modules: + enabled_modules.remove('tests') for mod in enabled_modules: if mod not in self.modules: raise KeyError('enabled module not found: %s' % (mod)) diff --git a/buildset/default.ini b/buildset/default.ini index 472c535d..88379a96 100644 --- a/buildset/default.ini +++ b/buildset/default.ini @@ -43,6 +43,7 @@ dhcpcd = on dpaa = on evdev = on fdt = on +if_mve = on imx = on in_cksum = on mdnsresponder = on diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c index b7839d49..93620727 100644 --- a/dhcpcd/dhcpcd.c +++ b/dhcpcd/dhcpcd.c @@ -1155,7 +1155,7 @@ dhcpcd_task(rtems_task_argument arg) (*config->destroy)(config, exit_code); } - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } rtems_status_code diff --git a/freebsd-org b/freebsd-org -Subproject 6b0307a0a5184339393f555d5d424190d8a8277 +Subproject 5d85e12f44ccb0e5728344a002c108ddc105e03 diff --git a/freebsd/contrib/tcpdump/rtems-bsd-tcpdump-data.h b/freebsd/contrib/tcpdump/rtems-bsd-tcpdump-data.h index d021ae99..2c8ff3b8 100644 --- a/freebsd/contrib/tcpdump/rtems-bsd-tcpdump-data.h +++ b/freebsd/contrib/tcpdump/rtems-bsd-tcpdump-data.h @@ -139,7 +139,7 @@ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_tcpdump, extern int nd_smi_module_loaded); /* print-sll.c */ /* print-slow.c */ /* print-smb.c */ -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_tcpdump, extern u_char const *startbuf); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_tcpdump, extern unsigned char const *startbuf); /* print-smtp.c */ /* print-snmp.c */ /* print-stp.c */ diff --git a/freebsd/contrib/tcpdump/tcpdump.c b/freebsd/contrib/tcpdump/tcpdump.c index 3b68ed51..24c6a29c 100644 --- a/freebsd/contrib/tcpdump/tcpdump.c +++ b/freebsd/contrib/tcpdump/tcpdump.c @@ -143,6 +143,7 @@ The Regents of the University of California. All rights reserved.\n"; #include <sys/sysctl.h> #include <machine/rtems-bsd-commands.h> #include <assert.h> +#include <sched.h> #include <rtems.h> #include <rtems/linkersets.h> #define setpriority(a, b, c) @@ -210,8 +211,10 @@ cap_channel_t *capdns; static void error(FORMAT_STRING(const char *), ...) NORETURN PRINTFLIKE(1, 2); static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); static void exit_tcpdump(int) NORETURN; +#ifndef __rtems__ static RETSIGTYPE cleanup(int); static RETSIGTYPE child_cleanup(int); +#endif /* __rtems__ */ static void print_version(void); static void print_usage(void); static void show_tstamp_types_and_exit(pcap_t *, const char *device) NORETURN; @@ -223,6 +226,7 @@ static void show_devices_and_exit (void) NORETURN; static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); +#ifndef __rtems__ static void droproot(const char *, const char *); #ifdef SIGNAL_REQ_INFO @@ -236,6 +240,7 @@ RETSIGTYPE requestinfo(int); #elif defined(HAVE_ALARM) static void verbose_stats_dump(int sig); #endif +#endif /* __rtems__ */ static void info(int); static u_int packets_captured; @@ -627,6 +632,7 @@ static const struct option longopts[] = { { NULL, 0, NULL, 0 } }; +#ifndef __rtems__ #ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void @@ -659,7 +665,6 @@ droproot(const char *username, const char *chroot_dir) } } #else -#ifndef __rtems__ if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { fprintf(stderr, "%s: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", @@ -672,7 +677,6 @@ droproot(const char *username, const char *chroot_dir) else { fprintf(stderr, "dropped privs to %s\n", username); } -#endif /* __rtems__ */ #endif /* HAVE_LIBCAP_NG */ } else { @@ -694,6 +698,7 @@ droproot(const char *username, const char *chroot_dir) } #endif /* _WIN32 */ +#endif /* __rtems__ */ static int getWflagChars(int x) @@ -1219,26 +1224,22 @@ typedef struct { FILE *in; pcap_t *pd; rtems_id master; + bool terminate; } pcap_loop_context; static void pcap_loop_monitor(rtems_task_argument arg) { - pcap_loop_context *ctx; + const pcap_loop_context *ctx; FILE *in; pcap_t *pd; - rtems_id master; rtems_status_code sc; - ctx = (pcap_loop_context *)arg; + ctx = (const pcap_loop_context *)arg; in = ctx->in; pd = ctx->pd; - master = ctx->master; - - sc = rtems_event_transient_send(master); - assert(sc == RTEMS_SUCCESSFUL); - while (true) { + while (!ctx->terminate) { int c; c = fgetc(in); @@ -1247,19 +1248,22 @@ pcap_loop_monitor(rtems_task_argument arg) pcap_breakloop(pd); break; } + + sched_yield(); } - rtems_task_delete(RTEMS_SELF); - assert(0); + sc = rtems_event_transient_send(ctx->master); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_task_exit(); } -static int -pcap_loop_wrapper(pcap_t *pd, int cnt, pcap_handler cb, u_char *ud) +static void +pcap_create_loop_monitor(pcap_loop_context *ctx, pcap_t *pd) { rtems_status_code sc; rtems_task_priority priority; rtems_id id; - pcap_loop_context ctx; sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); @@ -1269,27 +1273,38 @@ pcap_loop_wrapper(pcap_t *pd, int cnt, pcap_handler cb, u_char *ud) RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &id); if (sc != RTEMS_SUCCESSFUL) { - fprintf(stderr, "tcpdump: cannot create helper thread: %s\n", + error("cannot create pcap loop monitor thread: %s\n", rtems_status_text(sc)); - return (-1); } fprintf(stdout, "tcpdump: press <ENTER> or 'q' or 'Q' to quit\n"); - ctx.in = stdin; - ctx.pd = pd; - ctx.master = rtems_task_self(); + ctx->in = stdin; + ctx->pd = pd; + ctx->master = rtems_task_self(); + ctx->terminate = false; sc = rtems_task_start(id, pcap_loop_monitor, - (rtems_task_argument)&ctx); + (rtems_task_argument)ctx); assert(sc == RTEMS_SUCCESSFUL); +} + +static void +pcap_terminate_loop_monitor(pcap_loop_context *ctx) +{ + rtems_status_code sc; + + ctx->terminate = true; sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); assert(sc == RTEMS_SUCCESSFUL); - - return (pcap_loop(pd, cnt, cb, ud)); } -#define pcap_loop(pd, cnt, cb, ud) pcap_loop_wrapper(pd, cnt, cb, ud) +static void +destroy_pcap_dumper(void *arg) +{ + + pcap_dump_close(arg); +} #endif /* __rtems__ */ int #ifndef __rtems__ @@ -1306,15 +1321,19 @@ main(int argc, char **argv) int dlt; const char *dlt_name; struct bpf_program fcode; +#ifndef __rtems__ #ifndef _WIN32 RETSIGTYPE (*oldhandler)(int); #endif +#endif /* __rtems__ */ struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; char VFileLine[PATH_MAX + 1]; +#ifndef __rtems__ char *username = NULL; char *chroot_dir = NULL; +#endif /* __rtems__ */ char *ret = NULL; char *end; #ifdef HAVE_PCAP_FINDALLDEVS @@ -1686,9 +1705,11 @@ main(int argc, char **argv) zflag = optarg; break; +#ifndef __rtems__ case 'Z': username = optarg; break; +#endif /* __rtems__ */ case '#': ndo->ndo_packet_number = 1; @@ -1985,6 +2006,7 @@ main(int argc, char **argv) init_print(ndo, localnet, netmask, timezone_offset); +#ifndef __rtems__ #ifndef _WIN32 (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); @@ -2052,6 +2074,7 @@ main(int argc, char **argv) } #endif /* _WIN32 */ +#endif /* __rtems__ */ if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); @@ -2146,6 +2169,12 @@ main(int argc, char **argv) if (Uflag) pcap_dump_flush(p); #endif +#ifdef __rtems__ + if (rtems_bsd_program_add_destructor(destroy_pcap_dumper, p) == + NULL) { + error("cannot add destructor"); + } +#endif /* __rtems__ */ } else { dlt = pcap_datalink(pd); ndo->ndo_if_printer = get_if_printer(ndo, dlt); @@ -2153,6 +2182,7 @@ main(int argc, char **argv) pcap_userdata = (u_char *)ndo; } +#ifndef __rtems__ #ifdef SIGNAL_REQ_INFO /* * We can't get statistics when reading from a file rather @@ -2177,6 +2207,7 @@ main(int argc, char **argv) alarm(1); #endif } +#endif /* __rtems__ */ if (RFileName == NULL) { /* @@ -2219,7 +2250,19 @@ main(int argc, char **argv) #endif /* HAVE_CAPSICUM */ do { +#ifdef __rtems__ + pcap_loop_context ctx; + + if (RFileName == NULL) { + pcap_create_loop_monitor(&ctx, pd); + } +#endif /* __rtems__ */ status = pcap_loop(pd, cnt, callback, pcap_userdata); +#ifdef __rtems__ + if (RFileName == NULL) { + pcap_terminate_loop_monitor(&ctx); + } +#endif /* __rtems__ */ if (WFileName == NULL) { /* * We're printing packets. Flush the printed output, @@ -2338,6 +2381,7 @@ main(int argc, char **argv) exit_tcpdump(status == -1 ? 1 : 0); } +#ifndef __rtems__ /* make a clean exit on interrupts */ static RETSIGTYPE cleanup(int signo _U_) @@ -2390,6 +2434,7 @@ child_cleanup(int signo _U_) wait(NULL); } #endif /* HAVE_FORK && HAVE_VFORK */ +#endif /* __rtems__ */ static void info(register int verbose) @@ -2750,6 +2795,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) char Wpcap_version[]="3.1"; #endif +#ifndef __rtems__ #ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int signo _U_) { @@ -2778,6 +2824,7 @@ static void verbose_stats_dump(int sig _U_) alarm(1); } #endif +#endif /* __rtems__ */ USES_APPLE_DEPRECATED_API static void diff --git a/freebsd/contrib/wpa/src/utils/eloop.c b/freebsd/contrib/wpa/src/utils/eloop.c index 41de0f79..09493b89 100644 --- a/freebsd/contrib/wpa/src/utils/eloop.c +++ b/freebsd/contrib/wpa/src/utils/eloop.c @@ -16,6 +16,9 @@ #include "list.h" #include "eloop.h" +#ifdef __rtems__ +#define CONFIG_ELOOP_KQUEUE +#endif /* __rtems__ */ #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL) #error Do not define both of poll and epoll #endif @@ -955,6 +958,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, } +#ifndef __rtems__ #ifndef CONFIG_NATIVE_WINDOWS static void eloop_handle_alarm(int sig) { @@ -966,8 +970,10 @@ static void eloop_handle_alarm(int sig) exit(1); } #endif /* CONFIG_NATIVE_WINDOWS */ +#endif /* __rtems__ */ +#ifndef __rtems__ static void eloop_handle_signal(int sig) { int i; @@ -990,6 +996,7 @@ static void eloop_handle_signal(int sig) } } } +#endif /* __rtems__ */ static void eloop_process_pending_signals(void) @@ -1001,9 +1008,11 @@ static void eloop_process_pending_signals(void) eloop.signaled = 0; if (eloop.pending_terminate) { +#ifndef __rtems__ #ifndef CONFIG_NATIVE_WINDOWS alarm(0); #endif /* CONFIG_NATIVE_WINDOWS */ +#endif /* __rtems__ */ eloop.pending_terminate = 0; } @@ -1017,6 +1026,7 @@ static void eloop_process_pending_signals(void) } +#ifndef __rtems__ int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data) { @@ -1037,26 +1047,35 @@ int eloop_register_signal(int sig, eloop_signal_handler handler, return 0; } +#endif /* __rtems__ */ int eloop_register_signal_terminate(eloop_signal_handler handler, void *user_data) { +#ifndef __rtems__ int ret = eloop_register_signal(SIGINT, handler, user_data); if (ret == 0) ret = eloop_register_signal(SIGTERM, handler, user_data); return ret; +#else /* __rtems__ */ + return 0; +#endif /* __rtems__ */ } int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data) { +#ifndef __rtems__ #ifdef CONFIG_NATIVE_WINDOWS return 0; #else /* CONFIG_NATIVE_WINDOWS */ return eloop_register_signal(SIGHUP, handler, user_data); #endif /* CONFIG_NATIVE_WINDOWS */ +#else /* __rtems__ */ + return 0; +#endif /* __rtems__ */ } diff --git a/freebsd/crypto/openssl/apps/ocsp.c b/freebsd/crypto/openssl/apps/ocsp.c index 7ff6a20c..dba8e6a9 100644 --- a/freebsd/crypto/openssl/apps/ocsp.c +++ b/freebsd/crypto/openssl/apps/ocsp.c @@ -58,7 +58,7 @@ NON_EMPTY_TRANSLATION_UNIT #endif # if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \ - && !defined(OPENSSL_NO_POSIX_IO) + && !defined(OPENSSL_NO_POSIX_IO) && !defined(__rtems__) # define OCSP_DAEMON # include <sys/types.h> # include <sys/wait.h> diff --git a/freebsd/crypto/openssl/apps/openssl.c b/freebsd/crypto/openssl/apps/openssl.c index 31ec58d8..cdbb262b 100644 --- a/freebsd/crypto/openssl/apps/openssl.c +++ b/freebsd/crypto/openssl/apps/openssl.c @@ -89,9 +89,11 @@ static void calculate_columns(DISPLAY_COLUMNS *dc) static int apps_startup(void) { +#ifndef __rtems__ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif +#endif /* __rtems__ */ /* Set non-default library initialisation settings */ if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN diff --git a/freebsd/crypto/openssl/apps/rtems-bsd-openssl-ocsp-data.h b/freebsd/crypto/openssl/apps/rtems-bsd-openssl-ocsp-data.h index 2c2b926e..90043fb0 100644 --- a/freebsd/crypto/openssl/apps/rtems-bsd-openssl-ocsp-data.h +++ b/freebsd/crypto/openssl/apps/rtems-bsd-openssl-ocsp-data.h @@ -3,6 +3,4 @@ #include "rtems-bsd-openssl-data.h" /* ocsp.c */ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_openssl, static char *prog); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_openssl, static int acfd); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_openssl, static int multi); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_openssl, static int termsig); diff --git a/freebsd/crypto/openssl/crypto/ui/ui_openssl.c b/freebsd/crypto/openssl/crypto/ui/ui_openssl.c index 03596eee..6a040553 100644 --- a/freebsd/crypto/openssl/crypto/ui/ui_openssl.c +++ b/freebsd/crypto/openssl/crypto/ui/ui_openssl.c @@ -158,11 +158,13 @@ struct IOSB { # endif /* Define globals. They are protected by a lock */ +#ifndef __rtems__ # ifdef SIGACTION static struct sigaction savsig[NX509_SIG]; # else static void (*savsig[NX509_SIG]) (int); # endif +#endif /* __rtems__ */ # ifdef OPENSSL_SYS_VMS static struct IOSB iosb; @@ -185,7 +187,9 @@ static int is_a_tty; /* Declare static functions */ # if !defined(OPENSSL_SYS_WINCE) static int read_till_nl(FILE *); +#ifndef __rtems__ static void recsig(int); +#endif /* __rtems__ */ static void pushsig(void); static void popsig(void); # endif @@ -588,6 +592,7 @@ static int close_console(UI *ui) /* Internal functions to handle signals and act on them */ static void pushsig(void) { +#ifndef __rtems__ # ifndef OPENSSL_SYS_WIN32 int i; # endif @@ -630,10 +635,12 @@ static void pushsig(void) # ifdef SIGWINCH signal(SIGWINCH, SIG_DFL); # endif +#endif /* __rtems__ */ } static void popsig(void) { +#ifndef __rtems__ # ifdef OPENSSL_SYS_WIN32 signal(SIGABRT, savsig[SIGABRT]); signal(SIGFPE, savsig[SIGFPE]); @@ -659,12 +666,15 @@ static void popsig(void) # endif } # endif +#endif /* __rtems__ */ } +#ifndef __rtems__ static void recsig(int i) { intr_signal = i; } +#endif /* __rtems__ */ # endif /* Internal functions specific for Windows */ diff --git a/freebsd/lib/libc/include/libc_private.h b/freebsd/lib/libc/include/libc_private.h index fb3a4bb2..4a699e93 100644 --- a/freebsd/lib/libc/include/libc_private.h +++ b/freebsd/lib/libc/include/libc_private.h @@ -36,8 +36,12 @@ #ifndef _LIBC_PRIVATE_H_ #define _LIBC_PRIVATE_H_ +#ifndef __rtems__ #include <sys/_types.h> #include <sys/_pthreadtypes.h> +#else /* __rtems__ */ +#include <sys/types.h> +#endif /* __rtems__ */ /* * This global flag is non-zero when a process has created one diff --git a/freebsd/lib/libc/stdio/local.h b/freebsd/lib/libc/stdio/local.h index bed0b232..5ec1d3f5 100644 --- a/freebsd/lib/libc/stdio/local.h +++ b/freebsd/lib/libc/stdio/local.h @@ -78,13 +78,15 @@ extern int __srefill(FILE *); */ extern int __srefill_r(struct _reent *,FILE *); -#define __srefill(_x) __srefill_r(__getreent(), _x) +#define __srefill(_x) __srefill_r(_REENT, _x) #endif /* __rtems__ */ extern int __sread(void *, char *, int); extern int __swrite(void *, char const *, int); extern fpos_t __sseek(void *, fpos_t, int); extern int __sclose(void *); +#ifndef __rtems__ extern void __sinit(void); +#endif /* __rtems__ */ extern void _cleanup(void); extern void __smakebuf(FILE *); extern int __swhatbuf(FILE *, size_t *, int *); diff --git a/freebsd/sbin/pfctl/pfctl_altq.c b/freebsd/sbin/pfctl/pfctl_altq.c index 7cf72b43..05c7da22 100644 --- a/freebsd/sbin/pfctl/pfctl_altq.c +++ b/freebsd/sbin/pfctl/pfctl_altq.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #define PFIOC_USE_LATEST +#define _WANT_FREEBSD_BITSET #include <sys/types.h> #include <sys/bitset.h> diff --git a/freebsd/sbin/pfctl/pfctl_parser.c b/freebsd/sbin/pfctl/pfctl_parser.c index f339d972..9d752d26 100644 --- a/freebsd/sbin/pfctl/pfctl_parser.c +++ b/freebsd/sbin/pfctl/pfctl_parser.c @@ -1351,10 +1351,17 @@ get_socket_domain(void) return (sdom); } +#ifdef __rtems__ +static int pfctl_s = -1; +#endif /* __rtems__ */ int get_query_socket(void) { +#ifndef __rtems__ static int s = -1; +#else /* __rtems__ */ +#define s pfctl_s +#endif /* __rtems__ */ if (s == -1) { if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) @@ -1362,6 +1369,9 @@ get_query_socket(void) } return (s); +#ifdef __rtems__ +#undef s +#endif /* __rtems__ */ } /* diff --git a/freebsd/sbin/pfctl/pfctl_parser.h b/freebsd/sbin/pfctl/pfctl_parser.h index aa6d98d7..7d92b1db 100644 --- a/freebsd/sbin/pfctl/pfctl_parser.h +++ b/freebsd/sbin/pfctl/pfctl_parser.h @@ -178,7 +178,7 @@ struct node_queue_opt { }; #define QPRI_BITSET_SIZE 256 -BITSET_DEFINE(qpri_bitset, QPRI_BITSET_SIZE); +__BITSET_DEFINE(qpri_bitset, QPRI_BITSET_SIZE); LIST_HEAD(gen_sc, segment); struct pfctl_altq { diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h index 1712b9e6..2f7fb828 100644 --- a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h @@ -35,6 +35,7 @@ #define parseport _bsd_pfctl_parseport #define pfctl_cmdline_symset _bsd_pfctl_pfctl_cmdline_symset #define pfctl_load_anchors _bsd_pfctl_pfctl_load_anchors +#define pfctl_s _bsd_pfctl_s #define pfctlychar _bsd_pfctl_pfctlychar #define pfctlydebug _bsd_pfctl_pfctlydebug #define pfctlyerrflag _bsd_pfctl_pfctlyerrflag diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h index bb8832ac..9bbec579 100644 --- a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h @@ -3,3 +3,4 @@ #include "rtems-bsd-pfctl-data.h" /* pfctl_parser.c */ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pfctl_s); diff --git a/freebsd/sbin/ping/ping.c b/freebsd/sbin/ping/ping.c index e31941b8..fae24e53 100644 --- a/freebsd/sbin/ping/ping.c +++ b/freebsd/sbin/ping/ping.c @@ -307,7 +307,9 @@ main(int argc, char *const *argv) #endif struct sockaddr_in *to; double t; +#ifndef __rtems__ u_long alarmtimeout; +#endif /* __rtems__ */ long ltmp; int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; int ssend_errno, srecv_errno, tos, ttl; @@ -370,7 +372,9 @@ main(int argc, char *const *argv) err(EX_OSERR, "srecv socket"); } +#ifndef __rtems__ alarmtimeout = df = preload = tos = 0; +#endif /* __rtems__ */ outpack = outpackhdr + sizeof(struct ip); while ((ch = getopt(argc, argv, @@ -572,6 +576,7 @@ main(int argc, char *const *argv) mttl = ltmp; options |= F_MTTL; break; +#ifndef __rtems__ case 't': alarmtimeout = strtoul(optarg, &ep, 0); if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) @@ -582,6 +587,7 @@ main(int argc, char *const *argv) optarg, MAXALARM); alarm((int)alarmtimeout); break; +#endif /* __rtems__ */ case 'v': options |= F_VERBOSE; break; @@ -1518,8 +1524,10 @@ static void finish(void) { +#ifndef __rtems__ (void)signal(SIGINT, SIG_IGN); (void)signal(SIGALRM, SIG_IGN); +#endif /* __rtems__ */ (void)putchar('\n'); (void)fflush(stdout); (void)printf("--- %s ping statistics ---\n", hostname); diff --git a/freebsd/sbin/ping6/ping6.c b/freebsd/sbin/ping6/ping6.c index 2d6e5ade..921797d0 100644 --- a/freebsd/sbin/ping6/ping6.c +++ b/freebsd/sbin/ping6/ping6.c @@ -287,7 +287,9 @@ static void fill(char *, char *); static int get_hoplim(struct msghdr *); static int get_pathmtu(struct msghdr *); static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *); +#ifndef __rtems__ static void onsignal(int); +#endif /* __rtems__ */ static void onint(int); static size_t pingerlen(void); static int pinger(void); @@ -347,7 +349,9 @@ main(int argc, char *argv[]) struct timespec last, intvl; struct sockaddr_in6 from, *sin6; struct addrinfo hints, *res; +#ifndef __rtems__ struct sigaction si_sa; +#endif /* __rtems__ */ int cc, i; int almost_done, ch, hold, packlen, preload, optval, error; int nig_oldmcprefix = -1; @@ -374,7 +378,9 @@ main(int argc, char *argv[]) char *policy_out = NULL; #endif double t; +#ifndef __rtems__ u_long alarmtimeout; +#endif /* __rtems__ */ size_t rthlen; #ifdef IPV6_USE_MIN_MTU int mflag = 0; @@ -400,7 +406,9 @@ main(int argc, char *argv[]) intvl.tv_sec = interval / 1000; intvl.tv_nsec = interval % 1000 * 1000000; +#ifndef __rtems__ alarmtimeout = preload = 0; +#endif /* __rtems__ */ datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; capdns = capdns_setup(); #ifndef IPSEC @@ -628,6 +636,7 @@ main(int argc, char *argv[]) options |= F_WAITTIME; waittime = (int)t; break; +#ifndef __rtems__ case 't': alarmtimeout = strtoul(optarg, &e, 0); if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) @@ -638,6 +647,7 @@ main(int argc, char *argv[]) optarg, MAXALARM); alarm((int)alarmtimeout); break; +#endif /* __rtems__ */ #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC case 'P': @@ -1174,6 +1184,7 @@ main(int argc, char *argv[]) } clock_gettime(CLOCK_MONOTONIC, &last); +#ifndef __rtems__ sigemptyset(&si_sa.sa_mask); si_sa.sa_flags = 0; si_sa.sa_handler = onsignal; @@ -1189,6 +1200,7 @@ main(int argc, char *argv[]) if (sigaction(SIGALRM, &si_sa, 0) == -1) err(EX_OSERR, "sigaction SIGALRM"); } +#endif /* __rtems__ */ if (options & F_FLOOD) { intvl.tv_sec = 0; intvl.tv_nsec = 10000000; @@ -1310,11 +1322,13 @@ main(int argc, char *argv[]) } } } +#ifndef __rtems__ sigemptyset(&si_sa.sa_mask); si_sa.sa_flags = 0; si_sa.sa_handler = SIG_IGN; sigaction(SIGINT, &si_sa, 0); sigaction(SIGALRM, &si_sa, 0); +#endif /* __rtems__ */ summary(); if(packet != NULL) @@ -1323,6 +1337,7 @@ main(int argc, char *argv[]) exit(nreceived == 0 ? 2 : 0); } +#ifndef __rtems__ static void onsignal(int sig) { @@ -1339,6 +1354,7 @@ onsignal(int sig) #endif } } +#endif /* __rtems__ */ /* * pinger -- diff --git a/freebsd/sys/arm/freescale/imx/imx6_ccm.c b/freebsd/sys/arm/freescale/imx/imx6_ccm.c index 78bbd5c1..7fdb69b8 100644 --- a/freebsd/sys/arm/freescale/imx/imx6_ccm.c +++ b/freebsd/sys/arm/freescale/imx/imx6_ccm.c @@ -368,6 +368,7 @@ imx6_ccm_sata_enable(void) return 0; } +#ifndef __rtems__ uint32_t imx_ccm_ecspi_hz(void) { @@ -408,6 +409,7 @@ imx_ccm_ahb_hz(void) { return (132000000); } +#endif /* __rtems__ */ void imx_ccm_ipu_enable(int ipu) diff --git a/freebsd/sys/arm64/include/machine/in_cksum.h b/freebsd/sys/arm64/include/machine/in_cksum.h index d55b838b..522ba005 100644 --- a/freebsd/sys/arm64/include/machine/in_cksum.h +++ b/freebsd/sys/arm64/include/machine/in_cksum.h @@ -1,6 +1,4 @@ /*- - * SPDX-License-Identifier: BSD-3-Clause - * * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * @@ -31,7 +29,6 @@ * from tahoe: in_cksum.c 1.2 86/01/05 * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 * from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp - * from: src/sys/alpha/include/in_cksum.h,v 1.7 2005/03/02 21:33:20 joerg * $FreeBSD$ */ @@ -40,44 +37,16 @@ #include <sys/cdefs.h> +#ifdef _KERNEL #define in_cksum(m, len) in_cksum_skip(m, len, 0) - +u_short in_addword(u_short sum, u_short b); +u_short in_cksum_skip(struct mbuf *m, int len, int skip); +u_int do_cksum(const void *, int); #if defined(IPVERSION) && (IPVERSION == 4) -/* - * It it useful to have an Internet checksum routine which is inlineable - * and optimized specifically for the task of computing IP header checksums - * in the normal case (where there are no options and the header length is - * therefore always exactly five 32-bit words. - */ -#ifdef __CC_SUPPORTS___INLINE - -static __inline void -in_cksum_update(struct ip *ip) -{ - int __tmpsum; - __tmpsum = (int)ntohs(ip->ip_sum) + 256; - ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); -} - -#else - -#define in_cksum_update(ip) \ - do { \ - int __tmpsum; \ - __tmpsum = (int)ntohs(ip->ip_sum) + 256; \ - ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \ - } while(0) - -#endif +u_int in_cksum_hdr(const struct ip *); #endif -#ifdef _KERNEL -#if defined(IPVERSION) && (IPVERSION == 4) -u_int in_cksum_hdr(const struct ip *ip); -#endif -u_short in_addword(u_short sum, u_short b); u_short in_pseudo(u_int sum, u_int b, u_int c); -u_short in_cksum_skip(struct mbuf *m, int len, int skip); -#endif +#endif /* _KERNEL */ #endif /* _MACHINE_IN_CKSUM_H_ */ diff --git a/freebsd/sys/dev/ffec/if_ffec.c b/freebsd/sys/dev/ffec/if_ffec.c index 47c0f770..316e077c 100644 --- a/freebsd/sys/dev/ffec/if_ffec.c +++ b/freebsd/sys/dev/ffec/if_ffec.c @@ -139,9 +139,17 @@ static struct ofw_compat_data compat_data[] = { /* * Driver data and defines. The descriptor counts must be a power of two. */ +#ifndef __rtems__ #define RX_DESC_COUNT 512 +#else /* __rtems__ */ +#define RX_DESC_COUNT 64 +#endif /* __rtems__ */ #define RX_DESC_SIZE (sizeof(struct ffec_hwdesc) * RX_DESC_COUNT) +#ifndef __rtems__ #define TX_DESC_COUNT 512 +#else /* __rtems__ */ +#define TX_DESC_COUNT 64 +#endif /* __rtems__ */ #define TX_DESC_SIZE (sizeof(struct ffec_hwdesc) * TX_DESC_COUNT) #define TX_MAX_DMA_SEGS 8 @@ -201,6 +209,11 @@ struct ffec_softc { int rx_ic_count; /* RW, valid values 0..255 */ int tx_ic_time; int tx_ic_count; +#ifdef __rtems__ + + device_t mdio_device; + struct mtx mdio_mtx; +#endif /* __rtems__ */ }; static struct resource_spec irq_res_spec[MAX_IRQ_COUNT + 1] = { @@ -368,6 +381,13 @@ ffec_miibus_readreg(device_t dev, int phy, int reg) int val; sc = device_get_softc(dev); +#ifdef __rtems__ + if (sc->mdio_device) { + return (MIIBUS_READREG(sc->mdio_device, phy, reg)); + } + + mtx_lock(&sc->mdio_mtx); +#endif /* __rtems__ */ WR4(sc, FEC_IER_REG, FEC_IER_MII); @@ -378,11 +398,17 @@ ffec_miibus_readreg(device_t dev, int phy, int reg) if (!ffec_miibus_iowait(sc)) { device_printf(dev, "timeout waiting for mii read\n"); +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (-1); /* All-ones is a symptom of bad mdio. */ } val = RD4(sc, FEC_MMFR_REG) & FEC_MMFR_DATA_MASK; +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (val); } @@ -392,6 +418,13 @@ ffec_miibus_writereg(device_t dev, int phy, int reg, int val) struct ffec_softc *sc; sc = device_get_softc(dev); +#ifdef __rtems__ + if (sc->mdio_device) { + return (MIIBUS_WRITEREG(sc->mdio_device, phy, reg, val)); + } + + mtx_lock(&sc->mdio_mtx); +#endif /* __rtems__ */ WR4(sc, FEC_IER_REG, FEC_IER_MII); @@ -403,9 +436,15 @@ ffec_miibus_writereg(device_t dev, int phy, int reg, int val) if (!ffec_miibus_iowait(sc)) { device_printf(dev, "timeout waiting for mii write\n"); +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (-1); } +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (0); } @@ -1569,6 +1608,9 @@ ffec_detach(device_t dev) if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); +#ifdef __rtems__ + mtx_destroy(&sc->mtx); +#endif /* __rtems__ */ FFEC_LOCK_DESTROY(sc); return (0); } @@ -1718,6 +1760,80 @@ ffec_set_txic(struct ffec_softc *sc) ffec_set_ic(sc, FEC_TXIC0_REG, sc->tx_ic_count, sc->tx_ic_time); } +#ifdef __rtems__ +int +ffec_get_phy_information( + struct ffec_softc *sc, + phandle_t node, + device_t dev, + int *phy_addr +) +{ + phandle_t phy_node; + phandle_t parent_node; + pcell_t phy_handle, phy_reg; + device_t other; + phandle_t xref; + + /* Search for the phy-handle and get the address */ + + if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, + sizeof(phy_handle)) <= 0) + return (ENXIO); + + phy_node = OF_node_from_xref(phy_handle); + + if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, + sizeof(phy_reg)) <= 0) + return (ENXIO); + + *phy_addr = phy_reg; + + /* Detect whether PHY handle is connected to this or another FFEC. */ + parent_node = phy_node; + + while (parent_node != 0) { + if (parent_node == node) { + /* PHY is directly connected. That's easy. */ + sc->mdio_device = NULL; + return 0; + } + + /* + * Check whether the node is also an Ethernet controller. Do + * that by just assuming that every Ethernet controller has a + * PHY attached to it. + */ + if (OF_getencprop(parent_node, "phy-handle", + (void *)&phy_handle, sizeof(phy_handle)) > 0) { + /* + * Try to find the device of the other Ethernet + * controller and use that for MDIO communication. + * Note: This is not really a nice workaround but it + * works. + */ + xref = OF_xref_from_node(parent_node); + if (xref == 0) { + device_printf(dev, + "Couldn't get device that handles PHY\n"); + return (ENXIO); + } + other = OF_device_from_xref(xref); + if (other == 0) { + device_printf(dev, + "Couldn't get device that handles PHY\n"); + return (ENXIO); + } + sc->mdio_device = other; + return 0; + } + + parent_node = OF_parent(parent_node); + } + return (ENXIO); +} + +#endif /* __rtems__ */ static int ffec_attach(device_t dev) { @@ -1735,6 +1851,10 @@ ffec_attach(device_t dev) sc->dev = dev; FFEC_LOCK_INIT(sc); +#ifdef __rtems__ + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), + MTX_NETWORK_LOCK, MTX_DEF); +#endif /* __rtems__ */ /* * There are differences in the implementation and features of the FEC @@ -2039,9 +2159,17 @@ ffec_attach(device_t dev) ffec_miigasket_setup(sc); /* Attach the mii driver. */ +#ifdef __rtems__ + OF_device_register_xref(OF_xref_from_node(ofw_node), dev); + if (ffec_get_phy_information(sc, ofw_node, dev, &phynum) != 0) { + phynum = MII_PHY_ANY; + } + (void) dummy; +#else /* __rtems__ */ if (fdt_get_phyaddr(ofw_node, dev, &phynum, &dummy) != 0) { phynum = MII_PHY_ANY; } +#endif /* __rtems__ */ error = mii_attach(dev, &sc->miibus, ifp, ffec_media_change, ffec_media_status, BMSR_DEFCAPMASK, phynum, MII_OFFSET_ANY, (sc->fecflags & FECTYPE_MVF) ? MIIF_FORCEANEG : 0); diff --git a/freebsd/sys/dev/mmc/mmcsd.c b/freebsd/sys/dev/mmc/mmcsd.c index 11cf945f..ff517abc 100644 --- a/freebsd/sys/dev/mmc/mmcsd.c +++ b/freebsd/sys/dev/mmc/mmcsd.c @@ -546,6 +546,11 @@ mmcsd_attach(device_t dev) */ rev = ext_csd[EXT_CSD_REV]; +/* + * Cache flush functions are currently not available. Use of on-device cache can + * cause data loss. + */ +#ifndef __rtems__ /* * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take * advantage of the device R/W cache if present and useage is not @@ -567,6 +572,7 @@ mmcsd_attach(device_t dev) sc->flags |= MMCSD_FLUSH_CACHE; } } +#endif /* * Ignore user-creatable enhanced user data area and general purpose diff --git a/freebsd/sys/i386/include/machine/intr_machdep.h b/freebsd/sys/i386/include/machine/intr_machdep.h deleted file mode 100644 index a0b28387..00000000 --- a/freebsd/sys/i386/include/machine/intr_machdep.h +++ /dev/null @@ -1,6 +0,0 @@ -/*- - * This file is in the public domain. - */ -/* $FreeBSD$ */ - -#include <x86/intr_machdep.h> diff --git a/freebsd/sys/sys/_domainset.h b/freebsd/sys/sys/_domainset.h index 5685d532..443c68fd 100644 --- a/freebsd/sys/sys/_domainset.h +++ b/freebsd/sys/sys/_domainset.h @@ -43,7 +43,7 @@ #define DOMAINSET_SETSIZE DOMAINSET_MAXSIZE #endif -BITSET_DEFINE(_domainset, DOMAINSET_SETSIZE); +__BITSET_DEFINE(_domainset, DOMAINSET_SETSIZE); typedef struct _domainset domainset_t; /* diff --git a/freebsd/sys/sys/domainset.h b/freebsd/sys/sys/domainset.h index 5a00347f..e028f3e9 100644 --- a/freebsd/sys/sys/domainset.h +++ b/freebsd/sys/sys/domainset.h @@ -44,34 +44,34 @@ sizeof(__XSTRING(MAXMEMDOM))) -#define DOMAINSET_CLR(n, p) BIT_CLR(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_COPY(f, t) BIT_COPY(DOMAINSET_SETSIZE, f, t) -#define DOMAINSET_ISSET(n, p) BIT_ISSET(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_SET(n, p) BIT_SET(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_ZERO(p) BIT_ZERO(DOMAINSET_SETSIZE, p) -#define DOMAINSET_FILL(p) BIT_FILL(DOMAINSET_SETSIZE, p) -#define DOMAINSET_SETOF(n, p) BIT_SETOF(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_EMPTY(p) BIT_EMPTY(DOMAINSET_SETSIZE, p) -#define DOMAINSET_ISFULLSET(p) BIT_ISFULLSET(DOMAINSET_SETSIZE, p) -#define DOMAINSET_SUBSET(p, c) BIT_SUBSET(DOMAINSET_SETSIZE, p, c) -#define DOMAINSET_OVERLAP(p, c) BIT_OVERLAP(DOMAINSET_SETSIZE, p, c) -#define DOMAINSET_CMP(p, c) BIT_CMP(DOMAINSET_SETSIZE, p, c) -#define DOMAINSET_OR(d, s) BIT_OR(DOMAINSET_SETSIZE, d, s) -#define DOMAINSET_AND(d, s) BIT_AND(DOMAINSET_SETSIZE, d, s) -#define DOMAINSET_NAND(d, s) BIT_NAND(DOMAINSET_SETSIZE, d, s) -#define DOMAINSET_CLR_ATOMIC(n, p) BIT_CLR_ATOMIC(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_SET_ATOMIC(n, p) BIT_SET_ATOMIC(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_CLR(n, p) __BIT_CLR(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_COPY(f, t) __BIT_COPY(DOMAINSET_SETSIZE, f, t) +#define DOMAINSET_ISSET(n, p) __BIT_ISSET(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_SET(n, p) __BIT_SET(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_ZERO(p) __BIT_ZERO(DOMAINSET_SETSIZE, p) +#define DOMAINSET_FILL(p) __BIT_FILL(DOMAINSET_SETSIZE, p) +#define DOMAINSET_SETOF(n, p) __BIT_SETOF(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_EMPTY(p) __BIT_EMPTY(DOMAINSET_SETSIZE, p) +#define DOMAINSET_ISFULLSET(p) __BIT_ISFULLSET(DOMAINSET_SETSIZE, p) +#define DOMAINSET_SUBSET(p, c) __BIT_SUBSET(DOMAINSET_SETSIZE, p, c) +#define DOMAINSET_OVERLAP(p, c) __BIT_OVERLAP(DOMAINSET_SETSIZE, p, c) +#define DOMAINSET_CMP(p, c) __BIT_CMP(DOMAINSET_SETSIZE, p, c) +#define DOMAINSET_OR(d, s) __BIT_OR(DOMAINSET_SETSIZE, d, s) +#define DOMAINSET_AND(d, s) __BIT_AND(DOMAINSET_SETSIZE, d, s) +#define DOMAINSET_NAND(d, s) __BIT_NAND(DOMAINSET_SETSIZE, d, s) +#define DOMAINSET_CLR_ATOMIC(n, p) __BIT_CLR_ATOMIC(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_SET_ATOMIC(n, p) __BIT_SET_ATOMIC(DOMAINSET_SETSIZE, n, p) #define DOMAINSET_SET_ATOMIC_ACQ(n, p) \ - BIT_SET_ATOMIC_ACQ(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_AND_ATOMIC(n, p) BIT_AND_ATOMIC(DOMAINSET_SETSIZE, n, p) -#define DOMAINSET_OR_ATOMIC(d, s) BIT_OR_ATOMIC(DOMAINSET_SETSIZE, d, s) + __BIT_SET_ATOMIC_ACQ(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_AND_ATOMIC(n, p) __BIT_AND_ATOMIC(DOMAINSET_SETSIZE, n, p) +#define DOMAINSET_OR_ATOMIC(d, s) __BIT_OR_ATOMIC(DOMAINSET_SETSIZE, d, s) #define DOMAINSET_COPY_STORE_REL(f, t) \ - BIT_COPY_STORE_REL(DOMAINSET_SETSIZE, f, t) -#define DOMAINSET_FFS(p) BIT_FFS(DOMAINSET_SETSIZE, p) -#define DOMAINSET_FLS(p) BIT_FLS(DOMAINSET_SETSIZE, p) -#define DOMAINSET_COUNT(p) BIT_COUNT(DOMAINSET_SETSIZE, p) -#define DOMAINSET_FSET BITSET_FSET(_NDOMAINSETWORDS) -#define DOMAINSET_T_INITIALIZER BITSET_T_INITIALIZER + __BIT_COPY_STORE_REL(DOMAINSET_SETSIZE, f, t) +#define DOMAINSET_FFS(p) __BIT_FFS(DOMAINSET_SETSIZE, p) +#define DOMAINSET_FLS(p) __BIT_FLS(DOMAINSET_SETSIZE, p) +#define DOMAINSET_COUNT(p) __BIT_COUNT(DOMAINSET_SETSIZE, p) +#define DOMAINSET_FSET __BITSET_FSET(_NDOMAINSETWORDS) +#define DOMAINSET_T_INITIALIZER __BITSET_T_INITIALIZER #define DOMAINSET_POLICY_INVALID 0 #define DOMAINSET_POLICY_ROUNDROBIN 1 diff --git a/freebsd/tools/tools/net80211/wlanstats/main.c b/freebsd/tools/tools/net80211/wlanstats/main.c index 3a6fd204..ef2caf56 100644 --- a/freebsd/tools/tools/net80211/wlanstats/main.c +++ b/freebsd/tools/tools/net80211/wlanstats/main.c @@ -43,6 +43,7 @@ #ifdef __rtems__ #define __need_getopt_newlib #include <getopt.h> +#include <string.h> #include <machine/rtems-bsd-program.h> #include <machine/rtems-bsd-commands.h> #endif /* __rtems__ */ @@ -96,6 +97,7 @@ getfmt(const char *tag) return tag; } +#ifndef __rtems__ static int signalled; static void @@ -103,6 +105,7 @@ catchalarm(int signo __unused) { signalled = 1; } +#endif /* __rtems__ */ #if 0 static void @@ -262,6 +265,7 @@ main(int argc, char *argv[]) wf->setstamac(wf, mac); if (argc > 0) { +#ifndef __rtems__ u_long interval = strtoul(argv[0], NULL, 0); int line, omask; @@ -283,24 +287,10 @@ main(int argc, char *argv[]) wf->print_total(wf, stdout); } fflush(stdout); -#ifndef __rtems__ omask = sigblock(sigmask(SIGALRM)); if (!signalled) sigpause(0); sigsetmask(omask); -#else /* __rtems__ */ - { - sigset_t oldmask, desired, empty; - - sigemptyset(&empty); - sigemptyset(&desired); - sigaddset(&desired, SIGALRM); - sigprocmask(SIG_BLOCK, &desired, &oldmask); - while (!signalled) - sigsuspend(&desired); - sigprocmask(SIG_SETMASK, &oldmask, NULL); - } -#endif /* __rtems__ */ signalled = 0; alarm(interval); line++; @@ -346,6 +336,10 @@ main(int argc, char *argv[]) } while (len >= sizeof(struct ieee80211req_sta_info)); } #endif +#else /* __rtems__ */ + (void)mode; + printf("wlanstats: not implemented\n"); +#endif /* __rtems__ */ } else { wf->collect_tot(wf); wf->print_verbose(wf, stdout); diff --git a/freebsd/tools/tools/net80211/wlanstats/rtems-bsd-wlanstats-main-data.h b/freebsd/tools/tools/net80211/wlanstats/rtems-bsd-wlanstats-main-data.h index f88c5834..afb145be 100644 --- a/freebsd/tools/tools/net80211/wlanstats/rtems-bsd-wlanstats-main-data.h +++ b/freebsd/tools/tools/net80211/wlanstats/rtems-bsd-wlanstats-main-data.h @@ -1,5 +1,3 @@ /* generated by userspace-header-gen.py */ #include <rtems/linkersets.h> #include "rtems-bsd-wlanstats-data.h" -/* main.c */ -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_wlanstats, static int signalled); diff --git a/freebsd/usr.bin/netstat/if.c b/freebsd/usr.bin/netstat/if.c index c578629e..ffb639c6 100644 --- a/freebsd/usr.bin/netstat/if.c +++ b/freebsd/usr.bin/netstat/if.c @@ -512,6 +512,7 @@ intpr(void (*pfunc)(char *), int af) freeifmaddrs(ifmap); } +#ifndef __rtems__ struct iftot { u_long ift_ip; /* input packets */ u_long ift_ie; /* input errors */ @@ -575,6 +576,7 @@ catchalarm(int signo __unused) { signalled = true; } +#endif /* __rtems__ */ /* * Print a running summary of interface statistics. @@ -585,6 +587,7 @@ catchalarm(int signo __unused) static void sidewaysintpr(void) { +#ifndef __rtems__ struct iftot ift[2], *new, *old; struct itimerval interval_it; int oldmask, line; @@ -619,26 +622,11 @@ loop: xo_close_list("interface-statistics"); return; } -#ifdef __rtems__ - { - sigset_t oldmask, desired, empty; - - sigemptyset(&empty); - sigemptyset(&desired); - sigaddset(&desired, SIGALRM); - sigprocmask(SIG_BLOCK, &desired, &oldmask); - while (!signalled) - sigsuspend(&desired); - signalled = false; - sigprocmask(SIG_SETMASK, &oldmask, NULL); - } -#else /* __rtems__ */ oldmask = sigblock(sigmask(SIGALRM)); while (!signalled) sigpause(0); signalled = false; sigsetmask(oldmask); -#endif /* __rtems__ */ line++; fill_iftot(new); @@ -681,4 +669,5 @@ loop: goto loop; /* NOTREACHED */ +#endif /* __rtems__ */ } diff --git a/freebsd/usr.bin/netstat/rtems-bsd-netstat-if-data.h b/freebsd/usr.bin/netstat/rtems-bsd-netstat-if-data.h index 9e12b65e..9a685f33 100644 --- a/freebsd/usr.bin/netstat/rtems-bsd-netstat-if-data.h +++ b/freebsd/usr.bin/netstat/rtems-bsd-netstat-if-data.h @@ -1,5 +1,3 @@ /* generated by userspace-header-gen.py */ #include <rtems/linkersets.h> #include "rtems-bsd-netstat-data.h" -/* if.c */ -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_netstat, static sig_atomic_t signalled); diff --git a/ipsec-tools/src/libipsec/pfkey.c b/ipsec-tools/src/libipsec/pfkey.c index a621be12..cc6ad816 100644 --- a/ipsec-tools/src/libipsec/pfkey.c +++ b/ipsec-tools/src/libipsec/pfkey.c @@ -1,5 +1,12 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +/* Only need socket from rtems-bsd-program wrappers! */ +int +rtems_bsd_program_socket(int domain, int type, int protocol); +#define socket(domain, type, protocol) \ + rtems_bsd_program_socket(domain, type, protocol) +#endif /* __rtems__ */ /* $NetBSD: pfkey.c,v 1.21.2.1 2011/11/14 13:25:06 tteras Exp $ */ /* $KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $ */ @@ -1829,8 +1836,18 @@ pfkey_open(void) (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz_wanted, sizeof(bufsiz_wanted)); +#ifndef __rtems__ /* Try to have have at least 2MB. If we have more, do not lower it. */ bufsiz_wanted = 2 * 1024 * 1024; +#else /* __rtems__ */ + /* + * The bufsize_wanted has an influence on the maximum number of SPDs. We + * don't really need that much of them on an embedded system. If some + * application really needs it, this can be overwritten with the + * pfkey_buffer option in the config file. + */ + bufsiz_wanted = 128 * 1024; +#endif /* __rtems__ */ len = sizeof(bufsiz_current); ret = getsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz_current, &len); diff --git a/ipsec-tools/src/racoon/privsep.c b/ipsec-tools/src/racoon/privsep.c index 8efdae84..914d8a44 100644 --- a/ipsec-tools/src/racoon/privsep.c +++ b/ipsec-tools/src/racoon/privsep.c @@ -80,7 +80,9 @@ static int privsep_sock[2] = { -1, -1 }; static int privsep_recv(int, struct privsep_com_msg **, size_t *); static int privsep_send(int, struct privsep_com_msg *, size_t); static int safety_check(struct privsep_com_msg *, int i); +#ifndef __rtems__ static int port_check(int); +#endif /* __rtems__ */ static int unsafe_env(char *const *); static int unknown_name(int); static int unsafe_path(char *, int); @@ -321,7 +323,6 @@ privsep_init(void) #if defined(__NetBSD__) || defined(__FreeBSD__) setproctitle("[priv]"); #endif -#endif /* __rtems__ */ /* * Don't catch any signal @@ -334,13 +335,16 @@ privsep_init(void) signal(SIGUSR1, SIG_DFL); signal(SIGUSR2, SIG_DFL); signal(SIGCHLD, SIG_DFL); +#endif /* __rtems__ */ while (1) { size_t len; struct privsep_com_msg *combuf; struct privsep_com_msg *reply; char *data; +#ifndef __rtems__ size_t *buflen; +#endif /* __rtems__ */ size_t totallen; char *bufs[PRIVSEP_NBUF_MAX]; int i; @@ -1067,7 +1071,9 @@ privsep_getpsk(str, keylen) vchar_t *psk; struct privsep_com_msg *msg; size_t len; +#ifndef __rtems__ int *keylenp; +#endif /* __rtems__ */ char *data; if (geteuid() == 0) @@ -1129,7 +1135,11 @@ privsep_socket(domain, type, protocol) size_t len; char *data; struct socket_args socket_args; +#ifndef __rtems__ int s, saved_errno = 0; +#else /* __rtems__ */ + int s; +#endif /* __rtems__ */ if (geteuid() == 0) return socket(domain, type, protocol); diff --git a/ipsec-tools/src/racoon/rtems-bsd-racoon-data.h b/ipsec-tools/src/racoon/rtems-bsd-racoon-data.h index 7f1e9247..6867269e 100644 --- a/ipsec-tools/src/racoon/rtems-bsd-racoon-data.h +++ b/ipsec-tools/src/racoon/rtems-bsd-racoon-data.h @@ -56,7 +56,7 @@ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern struct dhgroup dh_modp8192); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern char *pname); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern int f_foreground); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern int print_location); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern u_int32_t loglevel); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, extern __uint32_t loglevel); /* policy.c */ /* privsep.c */ /* proposal.c */ diff --git a/ipsec-tools/src/racoon/rtems-bsd-racoon-session-data.h b/ipsec-tools/src/racoon/rtems-bsd-racoon-session-data.h index 196107a3..51b67d2e 100644 --- a/ipsec-tools/src/racoon/rtems-bsd-racoon-session-data.h +++ b/ipsec-tools/src/racoon/rtems-bsd-racoon-session-data.h @@ -2,11 +2,8 @@ #include <rtems/linkersets.h> #include "rtems-bsd-racoon-data.h" /* session.c */ -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static _types_fd_set *allocated_active_mask); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static _types_fd_set *allocated_preset_mask); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static fd_set *allocated_active_mask); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static fd_set *allocated_preset_mask); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static int nfds); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static int signals[]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static sig_atomic_t volatile volatile sigreq[]); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static struct fd_monitor *allocated_fd_monitors); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static struct fd_monitor_list fd_monitor_tree[]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_racoon, static struct sched scflushsa); diff --git a/ipsec-tools/src/racoon/session.c b/ipsec-tools/src/racoon/session.c index 90120c76..bd2bd316 100644 --- a/ipsec-tools/src/racoon/session.c +++ b/ipsec-tools/src/racoon/session.c @@ -119,6 +119,7 @@ struct fd_monitor { #define NUM_PRIORITIES 2 +#ifndef __rtems__ static void close_session __P((void)); static void initfds __P((void)); static void init_signal __P((void)); @@ -126,6 +127,7 @@ static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int)))); static void check_sigreq __P((void)); static void check_flushsa __P((void)); static int close_sockets __P((void)); +#endif /* __rtems__ */ #ifndef __rtems__ static fd_set preset_mask, active_mask; @@ -140,8 +142,10 @@ static struct fd_monitor *allocated_fd_monitors; static TAILQ_HEAD(fd_monitor_list, fd_monitor) fd_monitor_tree[NUM_PRIORITIES]; static int nfds = 0; +#ifndef __rtems__ static volatile sig_atomic_t sigreq[NSIG + 1]; static struct sched scflushsa = SCHED_INITIALIZER(); +#endif /* __rtems__ */ void monitor_fd(int fd, int (*callback)(void *, int), void *ctx, int priority) @@ -199,9 +203,11 @@ session(void) { struct timeval *timeout; int error; +#ifndef __rtems__ char pid_file[MAXPATHLEN]; FILE *fp; pid_t racoon_pid = 0; +#endif /* __rtems__ */ int i, count; struct fd_monitor *fdm; @@ -209,6 +215,8 @@ session(void) #ifndef __rtems__ FD_ZERO(&preset_mask); #else /* __rtems__ */ + size_t allocated_mask_size = sizeof(fd_set) * + howmany(rtems_libio_number_iops, sizeof(fd_set) * 8); allocated_preset_mask = calloc(sizeof(fd_set), howmany(rtems_libio_number_iops, sizeof(fd_set) * 8)); if (allocated_preset_mask == NULL) @@ -228,7 +236,9 @@ session(void) /* initialize schedular */ sched_init(); +#ifndef __rtems__ init_signal(); +#endif /* __rtems__ */ if (pfkey_init() < 0) errx(1, "failed to initialize pfkey socket"); @@ -325,24 +335,31 @@ session(void) racoon_pid = getpid(); fprintf(fp, "%ld\n", (long)racoon_pid); fclose(fp); -#endif /* __rtems__ */ for (i = 0; i <= NSIG; i++) sigreq[i] = 0; +#endif /* __rtems__ */ while (1) { +#ifndef __rtems__ /* * asynchronous requests via signal. * make sure to reset sigreq to 0. */ check_sigreq(); +#endif /* __rtems__ */ /* scheduling */ timeout = schedular(); /* schedular can change select() mask, so we reset * the working copy here */ +#ifndef __rtems__ active_mask = preset_mask; +#else /* __rtems__ */ + memcpy(allocated_active_mask, allocated_preset_mask, + allocated_mask_size); +#endif /* __rtems__ */ error = select(nfds + 1, &active_mask, NULL, NULL, timeout); if (error < 0) { @@ -379,6 +396,7 @@ session(void) } } +#ifndef __rtems__ /* clear all status and exit program. */ static void close_session() @@ -391,11 +409,6 @@ close_session() flushsainfo(); close_sockets(); backupsa_clean(); -#ifdef __rtems__ - free(allocated_preset_mask); allocated_preset_mask = NULL; - free(allocated_active_mask); allocated_active_mask = NULL; - free(allocated_fd_monitors); allocated_fd_monitors = NULL; -#endif /* __rtems__ */ plog(LLV_INFO, LOCATION, NULL, "racoon process %d shutdown\n", getpid()); @@ -565,11 +578,7 @@ set_signal(sig, func) memset((caddr_t)&sa, 0, sizeof(sa)); sa.sa_handler = func; -#ifndef __rtems__ sa.sa_flags = SA_RESTART; -#else /* __rtems__ */ - sa.sa_flags = 0; -#endif /* __rtems__ */ if (sigemptyset(&sa.sa_mask) < 0) return -1; @@ -590,6 +599,7 @@ close_sockets() #endif return 0; } +#endif /* __rtems__ */ #ifdef __rtems__ #include "rtems-bsd-racoon-session-data.h" @@ -144,6 +144,7 @@ _defaults = { ('freebsd/sys/dev/pci', '**/*.h', 'dev/pci'), ('freebsd/sys/dev/nvme', '**/*.h', 'dev/nvme'), ('freebsd/sys/dev/evdev', '**/*.h', 'dev/evdev'), + ('freebsd/sys/@CPU@/include', '**/*.h', ''), ('linux/include', '**/*.h', ''), ('mDNSResponder/mDNSCore', 'mDNSDebug.h', ''), ('mDNSResponder/mDNSCore', 'mDNSEmbeddedAPI.h', ''), @@ -552,7 +553,7 @@ class base(builder.Module): ], mm.generator['source']() ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'COPYRIGHT' ] @@ -890,6 +891,24 @@ class pinmux(builder.Module): ) # +# MV643XX Ethernet driver +# +class if_mve(builder.Module): + + def __init__(self, manager): + super(if_mve, self).__init__(manager, type(self).__name__) + + def generate(self): + mm = self.manager + self.addRTEMSKernelSourceFiles( + [ + 'sys/dev/mve/if_mve.c', + 'sys/dev/mve/if_mve_nexus.c', + ], + mm.generator['source']() + ) + +# # USB # class dev_usb(builder.Module): @@ -1585,7 +1604,6 @@ class dev_nic(builder.Module): 'sys/arm64/include/cpu.h', 'sys/arm/include/cpufunc.h', 'sys/i386/include/md_var.h', - 'sys/i386/include/intr_machdep.h', 'sys/x86/include/intr_machdep.h', 'sys/i386/include/cpufunc.h', 'sys/x86/include/intr_machdep.h', @@ -1714,7 +1732,7 @@ class dev_nic_e1000(builder.Module): ], mm.generator['source']() ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'sys/dev/e1000/LICENSE' ] @@ -2594,7 +2612,7 @@ class opencrypto(builder.Module): ], mm.generator['source']() ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'sys/contrib/libsodium/LICENSE' ] @@ -3250,7 +3268,7 @@ class user_space(builder.Module): ], mm.generator['source'](['-DINET']) ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'contrib/libxo/LICENSE' ] @@ -4257,7 +4275,7 @@ class crypto_openssl(builder.Module): mm.generator['from-FreeBSD-to-RTEMS-UserSpaceSourceConverter'](), mm.generator['from-RTEMS-To-FreeBSD-SourceConverter'](), mm.generator['buildSystemComposer']())) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'crypto/openssl/LICENSE' ] @@ -4395,7 +4413,7 @@ class contrib_expat(builder.Module): ], mm.generator['source'](cflags) ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'contrib/expat/COPYING' ] @@ -4500,7 +4518,7 @@ class contrib_libpcap(builder.Module): ], mm.generator['source'](cflags) ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'contrib/libpcap/LICENSE' ] @@ -4745,7 +4763,7 @@ class usr_sbin_tcpdump(builder.Module): ['freebsd/contrib/tcpdump', 'freebsd/usr.sbin/tcpdump/tcpdump']) ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'contrib/tcpdump/LICENSE' ] @@ -5064,7 +5082,7 @@ class usr_sbin_wpa_supplicant(builder.Module): ], mm.generator['source']() ) - self.addPlainTextFile( + self.addPlainTextFiles( [ 'contrib/wpa/COPYING' ] @@ -5316,6 +5334,12 @@ class imx(builder.Module): ], mm.generator['source']() ) + self.addRTEMSKernelSourceFiles( + [ + 'sys/arm/freescale/imx/imxrt1166_usbphy.c', + ], + mm.generator['source']() + ) class regulator(builder.Module): def __init__(self, manager): @@ -5407,7 +5431,7 @@ class tests(builder.Module): self.addTest(mm.generator['test']('smp01', ['test_main'], extraLibs = ['rtemstest'])) self.addTest(mm.generator['test']('media01', ['test_main', 'pattern-test'], runTest = False, - extraLibs = ['ftpd', 'telnetd'])) + extraLibs = ['tftpfs', 'ftpd', 'telnetd'])) self.addTest(mm.generator['test']('mcast01', ['test_main'])) self.addTest(mm.generator['test']('vlan01', ['test_main'], netTest = True)) self.addTest(mm.generator['test']('lagg01', ['test_main'], netTest = True)) @@ -5449,6 +5473,7 @@ class tests(builder.Module): self.addTest(mm.generator['test']('ipsec01', ['test_main'])) self.addTest(mm.generator['test']('openssl01', ['test_main'])) self.addTest(mm.generator['test']('openssl02', ['test_main'])) + self.addTest(mm.generator['test']('tcpdump01', ['test_main'])) def load(mm): @@ -5466,6 +5491,7 @@ def load(mm): mm.addModule(evdev(mm)) mm.addModule(iic(mm)) mm.addModule(pinmux(mm)) + mm.addModule(if_mve(mm)) mm.addModule(display(mm)) mm.addModule(dev_usb(mm)) diff --git a/libbsd.txt b/libbsd.txt deleted file mode 100644 index 3d665500..00000000 --- a/libbsd.txt +++ /dev/null @@ -1,1331 +0,0 @@ -RTEMS BSD Library Guide -======================= -:toc: -:icons: -:numbered: -:website: http://www.rtems.org/ - -The libbsd makes FreeBSD subsystems like TCP/IP, USB, SD and some more usable -for RTEMS. It tries to follow the FreeBSD development as close as possible and -therefore is updated to the latest FreeBSD HEAD revision from time to time. -To find out which version of FreeBSD is currently used as the base version for -libbsd please take a look at the -https://git.rtems.org/rtems-libbsd/log/freebsd-org[freebsd-org] submodule. - -This is a guide which captures information on the -process of merging code from FreeBSD, building this library, -RTEMS specific support files, and general guidelines on what -modifications to the FreeBSD source are permitted. - -Goals of this effort are - -* update TCP/IP and provide USB in RTEMS, -* ease updating to future FreeBSD versions, -* ease tracking changes in FreeBSD code, -* minimize manual changes in FreeBSD code, and -* define stable kernel/device driver API which is implemented -by both RTEMS and FreeBSD. This is the foundation of the port. - -We will work to push our changes upstream to the FreeBSD Project -and minimize changes required at each update point. - -******************************************************************************* -This is a work in progress and is very likely to be incomplete. -Please help by adding to it. -******************************************************************************* - -== Getting Started - -=== Tool Chain === - -You need a tool chain for RTEMS based on the latest RTEMS Source Builder (RSB). - -=== Installation Overview === - -. You must configure your BSP with the +--disable-networking+ option to disable -the old network stack. Make sure no header files of the old network stack are -installed. - -. Clone the Git repository +git clone git://git.rtems.org/rtems-libbsd.git+. -. Change into the RTEMS BSD library root directory. -. If you want to run tests with a custom IP configuration instead of the default - one you can use an adjusted `config.inc` configuration file. -. Run +waf configure ...+. -. Run +waf+. -. Run +waf install+. - -Refer to the README.waf for Waf building instructions. - -Make sure the submodules have been initialised and are updated. If a 'git -status' says `rtems_waf` need updating run the submodule update command: - - $ git submodule sync - $ git submodule rtems_waf update - -=== Board Support Package Requirements === - -You need the latest RTEMS version to build the libbsd master. The Board -Support Package (BSP) must support the -http://www.rtems.org/onlinedocs/doxygen/cpukit/html/group\__rtems\__interrupt__extension.html[Interrupt Manager Extension] -// The first underscores have to be masked to stop asciidoc interpreting them -to make use of generic FreeBSD based drivers. - -=== Board Support Package Configuration and Build === - -You need to configure RTEMS for the desired BSP and install it. The BSP must -be configured with a disabled network stack. The BSD library containing the -new network stack is a separate package. Using a BSP installation containing -the old network stack may lead to confusion and unpredictable results. - -The following script is used to build the `arm/xilinx_zynq_a9_qemu` BSP for -our internal testing purposes: - -------------------------------------------------------------------------------- -#!/bin/sh - -cd ${HOME}/sandbox -rm -rf b-xilinx_zynq_a9_qemu -mkdir b-xilinx_zynq_a9_qemu -cd b-xilinx_zynq_a9_qemu -${HOME}/git-rtems/configure \ - --prefix=${HOME}/sandbox/install \ - --target=arm-rtems5 \ - --enable-rtemsbsp=xilinx_zynq_a9_qemu \ - --disable-networking && \ - make && \ - make install -------------------------------------------------------------------------------- - -The `arm/xilinx_zynq_a9_qemu` BSP running on the Qemu simulator has some -benefits for development and test of the BSD library - -* it offers a NULL pointer read and write protection, -* Qemu is a fast simulator, -* Qemu provides support for GDB watchpoints, -* Qemu provides support for virtual Ethernet networks, e.g. TUN and bridge -devices (you can run multiple test instances on one virtual network). - -=== BSD Library Configuration and Build === - -The build system based on the Waf build system. To build with Waf please refer -to the README.waf file. - -Note that the libbsd supports different buildsets. These can be selected with -the `--buildset=xxx.ini` option during the configure phase. Take a look at the -comments in `buildset/*.ini` to see which build sets are officially supported. - -You can also create and provide your own buildset configuration. But remember -that it's quite easy to break something by disabling the wrong modules. Only the -configurations in the `buildset` directory are officially maintained. - -===== Example Configuration for Network Tests ===== - -If you need some other IP configuration for the network tests that use a fixed -IP config you can copy `config.inc` to a location outside to the source tree and -adapt it. Then use the option `--net-test-config=NET_CONFIG` to pass the file to -waf's configure command. - -------------------------------------------------------------------------------- -NET_CFG_SELF_IP = 10.0.0.2 -NET_CFG_NETMASK = 255.255.0.0 -NET_CFG_PEER_IP = 10.0.0.1 -NET_CFG_GATEWAY_IP = 10.0.0.1 -------------------------------------------------------------------------------- - -=== BSD Library Initialization === - -To initialise the BSD Library create a suitable rc.conf file. The FreeBSD man -page rc.conf(5) provides the details needed to create a suitable format file: - - https://www.freebsd.org/cgi/man.cgi?rc.conf - -You can call one of three functions to run the initialisation once BSD has -initialised: - - - rtems_bsd_run_etc_rc_conf: Run /etc/rc.conf. - - rtems_bsd_run_rc_conf: Run a user supplied file. - - rtems_bsd_run_rc_conf_script: Run the in memory line feed separated text string. - -For exapmle: - - void - network_init(void) - { - rtems_status_code sc; - - sc = rtems_bsd_initialize(); - assert(sc == RTEMS_SUCCESSFUL); - - rtems_bsd_run_etc_rc_conf(true); /* verbose = true */ - -} - -By default the networking support is builtin. Other directives can be added and -are found in 'machine/rtems-bsd-rc-conf-directives.h'. Please check the file -for the list. - -The following network names are supported: - - cloned_interfaces - ifconfig_'interface' - defaultrouter - hostname - -For example: - - # - # My BSD initialisation. - # - hostname="myhost" - cloned_interfaces="vlan0 vlan1" - ifconfig_re0="inet inet 10.10.10.10 netmask 255.255.255.0" - fconfig_vlan0="inet 10.11.10.10 255.255.255.0 vlan 101 vlandev re0" - defaultrouter="10.10.10.1" - -You can also intialise the BSD library using code. The following code to -initialize the BSD library: - -------------------------------------------------------------------------------- -#include <assert.h> -#include <sysexits.h> - -#include <rtems/bsd/bsd.h> - -void -network_init(void) -{ - rtems_status_code sc; - int exit_code; - - sc = rtems_bsd_initialize(); - assert(sc == RTEMS_SUCCESSFUL); - - exit_code = rtems_bsd_ifconfig_lo0(); - assert(exit_code == EX_OK); -} -------------------------------------------------------------------------------- - -This performs the basic network stack initialization with a loopback interface. -Further initialization must be done using the standard BSD network -configuration commands -http://www.freebsd.org/cgi/man.cgi?query=ifconfig&sektion=8[IFCONFIG(8)] -using `rtems_bsd_command_ifconfig()` and -http://www.freebsd.org/cgi/man.cgi?query=route&sektion=8[ROUTE(8)] -using `rtems_bsd_command_route()`. For an example please have a look at -`testsuite/include/rtems/bsd/test/default-network-init.h`. - -=== Task Priorities and Stack Size === - -The default task priority is 96 for the interrupt server task (name "IRQS"), 98 -for the timer server task (name "TIME") and 100 for all other tasks. The -application may provide their own implementation of the -`rtems_bsd_get_task_priority()` function (for example in the module which calls -`rtems_bsd_initialize()`) if different values are desired. - -The task stack size is determined by the `rtems_bsd_get_task_stack_size()` -function which may be provided by the application in case the default is not -appropriate. - -=== Size for Allocator Domains === - -The size for an allocator domain can be specified via the -`rtems_bsd_get_allocator_domain_size()` function. The application may provide -their own implementation of the `rtems_bsd_get_allocator_domain_size()` -function (for example in the module which calls `rtems_bsd_initialize()`) if -different values are desired. The default size is 8MiB for all domains. - -=== Redirecting or Disabling the Output === - -A lot of system messages are printed to the stdout by default. If you want to -redirect them you can overwrite the default print handler. That can even be done -before the libbsd initialization to catch all messages. An example would look -like follows: - -------------------------------------------------------------------------------- -int my_vprintf_handler(int level, const char *fmt, va_list ap) { - /* Do something with the messages. */ - - return number_of_printed_chars; -} - -... - /* In your initialization: */ - rtems_bsd_vprintf_handler old; - old = rtems_bsd_set_vprintf_handler(my_vprintf_handler); -... -------------------------------------------------------------------------------- - -As a special case, you can set the `rtems_bsd_vprintf_handler_mute(...)` -provided by libbsd to suppress all output. - -== Network Stack Features - -http://roy.marples.name/projects/dhcpcd/index[DHCPCD(8)]:: DHCP client - -https://developer.apple.com/library/mac/documentation/Networking/Reference/DNSServiceDiscovery_CRef/Reference/reference.html[dns_sd.h]:: DNS Service Discovery - -http://www.opensource.apple.com/source/mDNSResponder/mDNSResponder-320.10/mDNSCore/mDNSEmbeddedAPI.h[mDNS]:: Multi-Cast DNS - -http://www.freebsd.org/cgi/man.cgi?query=unix&sektion=4[UNIX(4)]:: UNIX-domain protocol family - -http://www.freebsd.org/cgi/man.cgi?query=inet&sektion=4[INET(4)]:: Internet protocol family - -http://www.freebsd.org/cgi/man.cgi?query=inet6&sektion=4[INET6(4)]:: Internet protocol version 6 family - -http://www.freebsd.org/cgi/man.cgi?query=tcp&sektion=4[TCP(4)]:: Internet Transmission Control Protocol - -http://www.freebsd.org/cgi/man.cgi?query=udp&sektion=4[UDP(4)]:: Internet User Datagram Protocol - -http://www.freebsd.org/cgi/man.cgi?query=route&sektion=4[ROUTE(4)]:: Kernel packet forwarding database - -http://www.freebsd.org/cgi/man.cgi?query=bpf&sektion=4[BPF(4)]:: Berkeley Packet Filter - -http://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2[SOCKET(2)]:: Create an endpoint for communication - -http://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2[KQUEUE(2)]:: Kernel event notification mechanism - -http://www.freebsd.org/cgi/man.cgi?query=select&sektion=2[SELECT(2)]:: Synchronous I/O multiplexing - -http://www.freebsd.org/cgi/man.cgi?query=poll&sektion=2[POLL(2)]:: Synchronous I/O multiplexing - -http://www.freebsd.org/cgi/man.cgi?query=route&sektion=8[ROUTE(8)]:: Manually manipulate the routing tables - -http://www.freebsd.org/cgi/man.cgi?query=ifconfig&sektion=8[IFCONFIG(8)]:: Configure network interface parameters - -http://www.freebsd.org/cgi/man.cgi?query=netstat&sektion=1[NETSTAT(1)]:: Show network status - -http://www.freebsd.org/cgi/man.cgi?query=ping&sektion=8[PING(8)]:: Send ICMP ECHO_REQUEST packets to network hosts - -http://www.freebsd.org/cgi/man.cgi?query=ping6&sektion=8[PING6(8)]:: Send ICMPv6 ECHO_REQUEST packets to network hosts - -http://www.freebsd.org/cgi/man.cgi?query=sysctl&sektion=3[SYSCTL(3)]:: Get or set system information - -http://www.freebsd.org/cgi/man.cgi?query=resolver&sektion=3[RESOLVER(3)]:: Resolver routines - -http://www.freebsd.org/cgi/man.cgi?query=gethostbyname&sektion=3[GETHOSTBYNAME(3)]:: Get network host entry - -== Network Interface Drivers - -=== Link Up/Down Events - -You can notifiy the application space of link up/down events in your network -interface driver via the if_link_state_change(LINK_STATE_UP/LINK_STATE_DOWN) -function. The DHCPCD(8) client is a consumer of these events for example. -Make sure that the interface flag IFF_UP and the interface driver flag -IFF_DRV_RUNNING is set in case the link is up, otherwise ether_output() will -return the error status ENETDOWN. - -== Shell Commands - -=== HOSTNAME(1) - -In addition to the standard options the RTEMS version of the HOSTNAME(1) -command supports the -m flag to set/get the multicast hostname of the -mDNS resolver instance. See also rtems_mdns_sethostname() and -rtems_mdns_gethostname(). - -== Qemu - -Use the following script to set up a virtual network with three tap devices -connected via one bridge device. - -------------------------------------------------------------------------------- -#!/bin/sh -x - -user=`whoami` -interfaces=(1 2 3) - -tap=qtap -bri=qbri - -case $1 in - up) - sudo -i brctl addbr $bri - for i in ${interfaces[@]} ; do - sudo -i tunctl -t $tap$i -u $user ; - sudo -i ifconfig $tap$i up ; - sudo -i brctl addif $bri $tap$i ; - done - sudo -i ifconfig $bri up - ;; - down) - for i in ${interfaces[@]} ; do - sudo -i ifconfig $tap$i down ; - sudo -i tunctl -d $tap$i ; - done - sudo -i ifconfig $bri down - sudo -i brctl delbr $bri - ;; -esac -------------------------------------------------------------------------------- - -Connect your Qemu instance to one of the tap devices, e.g. - -------------------------------------------------------------------------------- -qemu-system-i386 -m 512 -boot a -cpu pentium3 \ - -drive file=$HOME/qemu/pc386_fda,index=0,if=floppy,format=raw \ - -drive file=fat:$HOME/qemu/hd,format=raw \ - -net nic,model=e1000,macaddr=0e:b0:ba:5e:ba:11 \ - -net tap,ifname=qtap1,script=no,downscript=no \ - -nodefaults -nographic -serial stdio -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -qemu-system-arm \ - -serial null \ - -serial mon:stdio \ - -nographic \ - -M xilinx-zynq-a9 \ - -net nic,model=cadence_gem,macaddr=0e:b0:ba:5e:ba:11 \ - -net tap,ifname=qtap1,script=no,downscript=no \ - -m 256M \ - -kernel build/arm-rtems5-xilinx_zynq_a9_qemu/media01.exe -------------------------------------------------------------------------------- - -Make sure that each Qemu instance uses its own MAC address to avoid an address -conflict (or otherwise use it as a test). - -To connect the Qemu instances with your local network use the following -(replace 'eth0' with the network interface of your host). - -------------------------------------------------------------------------------- -ifconfig eth0 0.0.0.0 -brctl addif qbri eth0 -dhclient qbri -------------------------------------------------------------------------------- - -=== VDE and QEMU - -On FreeBSD you can create VDE or the Virtual Distributed Ethernet to create a -network environment that does not need to run qemu as root or needing to drop -the tap's privileges to run qemu. - -VDE creates a software switch with a default of 32 ports which means a single -kernel tap can support 32 qemu networking sessions. - -To use VDE you need to build qemu with VDE support. The RSB can detect a VDE -plug and enable VDE support in qemu when building. On FreeBSD install the VDE -support with: - - # pkg install -u vde2 - -Build qemu with the RSB. - -To network create a bridge and a tap. The network is 10.10.1.0/24. On FreeBSD -add to your /etc/rc.conf: - - cloned_interfaces="bridge0 tap0" - autobridge_interfaces="bridge0" - autobridge_bridge0="re0 tap0" - ifconfig_re0="up" - ifconfig_tap0="up" - ifconfig_bridge0="inet 10.1.1.2 netmask 255.255.255.0" - defaultrouter="10.10.1.1" - -Start the VDE switch as root: - - # sysctl net.link.tap.user_open=1 - # sysctl net.link.tap.up_on_open=1 - # vde_switch -d -s /tmp/vde1 -M /tmp/mgmt1 -tap tap0 -m 660 --mgmtmode 660 - # chmod 660 /dev/tap0 - -You can connect to the VDE switch's management channel using: - - $ vdeterm /tmp/mgmt1 - -To run qemu: - - $ qemu-system-arm \ - -serial null \ - -serial mon:stdio \ - -nographic \ - -M xilinx-zynq-a9 \ - -net nic,model=cadence_gem,macaddr=0e:b0:ba:5e:ba:11 \ - -net vde,id=vde0,sock=/tmp/vde1 - -m 256M \ - -kernel build/arm-rtems5-xilinx_zynq_a9_qemu/rcconf02.exe - -== Issues and TODO - -* PCI support on x86 uses a quick and dirty hack, see pci_reserve_map(). - -* Priority queues are broken with clustered scheduling. - -* Per-CPU data should be enabled once the new stack is ready for SMP. - -* Per-CPU NETISR(9) should be enabled onece the new stack is ready for SMP. - -* Multiple routing tables are not supported. Every FIB value is set to zero - (= BSD_DEFAULT_FIB). - -* Process identifiers are not supported. Every PID value is set to zero - (= BSD_DEFAULT_PID). - -* User credentials are not supported. The following functions allow the - operation for everyone - - prison_equal_ip4(), - - chgsbsize(), - - cr_cansee(), - - cr_canseesocket() and - - cr_canseeinpcb(). - -* A basic USB functionality test that is known to work on Qemu is desirable. - -* Adapt generic IRQ PIC interface code to Simple Vectored Interrupt Model - so that those architectures can use new TCP/IP and USB code. - -* freebsd-userspace/rtems/include/sys/syslog.h is a copy from the old - RTEMS TCP/IP stack. For some reason, the __printflike markers do not - compile in this environment. We may want to use the FreeBSD syslog.h - and get this addressed. - -* in_cksum implementations for architectures not supported by FreeBSD. - This will require figuring out where to put implementations that do - not originate from FreeBSD and are populated via the script. - -* MAC support functions are not thread-safe ("freebsd/lib/libc/posix1e/mac.c"). - -* IFCONFIG(8): IEEE80211 support is disabled. This module depends on a XML - parser and mmap(). - -* get_cyclecount(): The implementation is a security problem. - -* What to do with the priority parameter present in the FreeBSD synchronization - primitives and the thread creation functions? - -* TASKQUEUE(9): Support spin mutexes. - -* ZONE(9): Review allocator lock usage in rtems-bsd-chunk.c. - -* KQUEUE(2): Choose proper lock for global kqueue list. - -* TIMEOUT(9): Maybe use special task instead of timer server to call - callout_tick(). - -* sysctl_handle_opaque(): Implement reliable snapshots. - -* PING6(8): What to do with SIGALARM? - -* <sys/param.h>: Update Newlib to use a MSIZE of 256. - -* BPF(4): Add support for zero-copy buffers. - -* UNIX(4): Fix race conditions in the area of socket object and file node - destruction. Add support for file descriptor transmission via control - messages. - -* PRINTF(9): Add support for log(), the %D format specifier is missing in the - normal printf() family. - -* Why is the interrupt server used? The BSD interrupt handlers can block on -synchronization primitives like mutexes. This is in contrast to RTEMS -interrupt service routines. The BSPs using the generic interrupt support must -implement the `bsp_interrupt_vector_enable()` and -`bsp_interrupt_vector_disable()` routines. They normally enable/disable a -particular interrupt source at the interrupt controller. This can be used to -implement the interrupt server. The interrupt server is a task that wakes-up -in case an associated interrupt happens. The interrupt source is disabled in -a generic interrupt handler that wakes-up the interrupt server task. Once the -postponed interrupt processing is performed in the interrupt server the -interrupt source is enabled again. - -* Convert all BSP linkcmds to use a linkcmds.base so the sections are -easier to insert. - -* NIC Device Drivers -- Only common PCI NIC drivers have been included in the initial set. These -do not include any system on chip or ISA drivers. -- PCI configuration probe does not appear to happen to determine if a -NIC is in I/O or memory space. We have worked around this by using a -static hint to tell the fxp driver the correct mode. But this needs to -be addressed. -- The ISA drivers require more BSD infrastructure to be addressed. This was -outside the scope of the initial porting effort. - -== FreeBSD Source - -You should be able to rely on FreebSD manual pages and documentation -for details on the code itself. - -== BSD Library Source - -== Initialization of the BSD Library - -The initialization of the BSD library is based on the FreeBSD SYSINIT(9) -infrastructure. The key to initializing a system is to ensure that the desired -device drivers are explicitly pulled into the linked application. This plus -linking against the BSD library (`libbsd.a`) will pull in the necessary FreeBSD -infrastructure. - -The FreeBSD kernel is not a library like the RTEMS kernel. It is a bunch of -object files linked together. If we have a library, then creating the -executable is simple. We begin with a start symbol and recursively resolve all -references. With a bunch of object files linked together we need a different -mechanism. Most object files don't know each other. Lets say we have a driver -module. The rest of the system has no references to this driver module. The -driver module needs a way to tell the rest of the system: Hey, kernel I am -here, please use my services! - -This registration of independent components is performed by SYSINIT(9) and -specializations: - -http://www.freebsd.org/cgi/man.cgi?query=SYSINIT - -The SYSINIT(9) uses some global data structures that are placed in a certain -section. In the linker command file we need this: - -------------------------------------------------------------------------------- -.rtemsroset : { - KEEP (*(SORT(.rtemsroset.*))) -} - -.rtemsrwset : { - KEEP (*(SORT(.rtemsrwset.*))) -} -------------------------------------------------------------------------------- - -This results for example in this executable layout: - -------------------------------------------------------------------------------- -[...] - *(SORT(.rtemsroset.*)) - .rtemsroset.bsd.modmetadata_set.begin - 0x000000000025fe00 0x0 libbsd.a(rtems-bsd-init.o) - 0x000000000025fe00 _bsd__start_set_modmetadata_set - .rtemsroset.bsd.modmetadata_set.content - 0x000000000025fe00 0x8 libbsd.a(rtems-bsd-nexus.o) - .rtemsroset.bsd.modmetadata_set.content - 0x000000000025fe08 0x4 libbsd.a(kern_module.o) -[...] - .rtemsroset.bsd.modmetadata_set.content - 0x000000000025fe68 0x4 libbsd.a(mii.o) - .rtemsroset.bsd.modmetadata_set.content - 0x000000000025fe6c 0x4 libbsd.a(mii_bitbang.o) - .rtemsroset.bsd.modmetadata_set.end - 0x000000000025fe70 0x0 libbsd.a(rtems-bsd-init.o) - 0x000000000025fe70 _bsd__stop_set_modmetadata_set -[...] -.rtemsrwset 0x000000000030bad0 0x290 - *(SORT(.rtemsrwset.*)) - .rtemsrwset.bsd.sysinit_set.begin - 0x000000000030bad0 0x0 libbsd.a(rtems-bsd-init.o) - 0x000000000030bad0 _bsd__start_set_sysinit_set - .rtemsrwset.bsd.sysinit_set.content - 0x000000000030bad0 0x4 libbsd.a(rtems-bsd-nexus.o) - .rtemsrwset.bsd.sysinit_set.content - 0x000000000030bad4 0x8 libbsd.a(rtems-bsd-thread.o) - .rtemsrwset.bsd.sysinit_set.content - 0x000000000030badc 0x4 libbsd.a(init_main.o) -[...] - .rtemsrwset.bsd.sysinit_set.content - 0x000000000030bd54 0x4 libbsd.a(frag6.o) - .rtemsrwset.bsd.sysinit_set.content - 0x000000000030bd58 0x8 libbsd.a(uipc_accf.o) - .rtemsrwset.bsd.sysinit_set.end - 0x000000000030bd60 0x0 libbsd.a(rtems-bsd-init.o) - 0x000000000030bd60 _bsd__stop_set_sysinit_set -[...] -------------------------------------------------------------------------------- - -Here you can see, that some global data structures are collected into -continuous memory areas. This memory area can be identified by start and stop -symbols. This constructs a table of uniform items. - -The low level FreeBSD code calls at some time during the initialization the -mi_startup() function (machine independent startup). This function will sort -the SYSINIT(9) set and call handler functions which perform further -initialization. The last step is the scheduler invocation. - -The SYSINIT(9) routines are run in mi_startup() which is called by -rtems_bsd_initialize(). - -This is also explained in "The Design and Implementation of the FreeBSD -Operating System" section 14.3 "Kernel Initialization". - -In RTEMS we have a library and not a bunch of object files. Thus we need a way -to pull-in the desired services out of the libbsd. Here the -`rtems-bsd-sysinit.h` comes into play. The SYSINIT(9) macros have been -modified and extended for RTEMS in `<sys/kernel.h>`: - -------------------------------------------------------------------------------- -#ifndef __rtems__ -#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ - static struct sysinit uniquifier ## _sys_init = { \ - subsystem, \ - order, \ - func, \ - (ident) \ - }; \ - DATA_SET(sysinit_set,uniquifier ## _sys_init) -#else /* __rtems__ */ -#define SYSINIT_ENTRY_NAME(uniquifier) \ - _bsd_ ## uniquifier ## _sys_init -#define SYSINIT_REFERENCE_NAME(uniquifier) \ - _bsd_ ## uniquifier ## _sys_init_ref -#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \ - struct sysinit SYSINIT_ENTRY_NAME(uniquifier) = { \ - subsystem, \ - order, \ - func, \ - (ident) \ - }; \ - RWDATA_SET(sysinit_set,SYSINIT_ENTRY_NAME(uniquifier)) -#define SYSINIT_REFERENCE(uniquifier) \ - extern struct sysinit SYSINIT_ENTRY_NAME(uniquifier); \ - static struct sysinit const * const \ - SYSINIT_REFERENCE_NAME(uniquifier) __used \ - = &SYSINIT_ENTRY_NAME(uniquifier) -#define SYSINIT_MODULE_REFERENCE(mod) \ - SYSINIT_REFERENCE(mod ## module) -#define SYSINIT_DRIVER_REFERENCE(driver, bus) \ - SYSINIT_MODULE_REFERENCE(driver ## _ ## bus) -#define SYSINIT_DOMAIN_REFERENCE(dom) \ - SYSINIT_REFERENCE(domain_add_ ## dom) -#endif /* __rtems__ */ -------------------------------------------------------------------------------- - -Here you see that the SYSINIT(9) entries are no longer static. The -\*_REFERENCE() macros will create references to the corresponding modules which -are later resolved by the linker. The application has to provide an object -file with references to all required FreeBSD modules. - -The FreeBSD device model is quite elaborated (with follow-ups): - -http://www.freebsd.org/cgi/man.cgi?query=driver - -The devices form a tree with the Nexus device at a high-level. This Nexus -device is architecture specific in FreeBSD. In RTEMS we have our own Nexus -device, see `rtemsbsd/bsp/bsp-bsd-nexus-devices.c`. - -=== SYSCTL_NODE Example - -During development, we had an undefined reference to -_bsd_sysctl__net_children that we had trouble tracking down. Thanks to -Chris Johns, we located it. He explained how to read SYSCTL_NODE -definitions. This line from freebsd/netinet/in_proto.c is attempting -to add the "inet" node to the parent node "_net". - ----- -SYSCTL_NODE(_net, PF_INET, inet, CTLFLAG_RW, 0, - "Internet Family"); ----- - -Our problem was that we could not find where _bsd_sysctl__net_children -was defined. Chris suggested that when in doubt compile with -save-temps -and look at the preprocessed .i files. But he did not need that. He -explained that this the symbol name _bsd_sysctl__net_children was -automatically generated by a SYSCTL_NODE as follows: - -* _bsd_ - added by RTEMS modifications to SYSCTL_NODE macro -* sysctl_ - boilerplace added by SYSCTL_NODE macro -* "" - empty string for parent node -* net - name of SYSCTL_NODE -* children - added by SYSCTL macros - -This was all generated by a support macro declaring the node as this: - ----- -struct sysctl_oid_list SYSCTL_NODE_CHILDREN(parent, name); ----- - -Given this information, we located this SYSCTL_NODE declaration in -kern/kern_mib.c - ----- -SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, - "High kernel, proc, limits &c"); ----- - -== Core FreeBSD APIs and RTEMS Replacements == - -=== SX(9) (Shared/exclusive locks) === - -http://www.freebsd.org/cgi/man.cgi?query=sx - -Binary semaphores (this neglects the ability to allow shared access). - -=== MUTEX(9) (Mutual exclusion) === - -http://www.freebsd.org/cgi/man.cgi?query=mutex - -Binary semaphores (not recursive mutexes are not supported this way). - -=== RWLOCK(9) (Reader/writer lock) === - -http://www.freebsd.org/cgi/man.cgi?query=rwlock - -POSIX r/w lock. - -=== RMLOCK(9) (Reader/writer lock optimized for mostly read access patterns) === - -Note: This object was implemented as a wrapper for RWLOCK in the rm_lock header file. - -http://www.freebsd.org/cgi/man.cgi?query=rmlock - -POSIX r/w lock. - -=== CONDVAR(9) (Condition variables) === - -http://www.freebsd.org/cgi/man.cgi?query=condvar - -POSIX condition variables with modifications (hack). - -=== CALLOUT(9) (Timer functions) === - -http://www.freebsd.org/cgi/man.cgi?query=callout - -Timer server. - -=== TASKQUEUE(9) (Asynchronous task execution) === - -http://www.freebsd.org/cgi/man.cgi?query=taskqueue - -TBD. - -=== KTHREAD(9), KPROC(9) (Tasks) === - -http://www.freebsd.org/cgi/man.cgi?query=kthread - -http://www.freebsd.org/cgi/man.cgi?query=kproc - -Tasks. - -=== ZONE(9) (Zone allocator) === - -http://www.freebsd.org/cgi/man.cgi?query=zone - -TBD. - -=== devfs (Device file system) === - -There is a minimal implementation based on IMFS. The mount point is fixed to -"/dev". Note that the devfs is only used by the cdev subsystem. cdev has been -adapted so that the full path (including the leading "/dev") is given to devfs. -This saves some copy operations. - -devfs_create() first creates the full path and then creates an IMFS generic node -for the device. - -TBD: remove empty paths on devfs_destroy(). - -=== psignal (Signals) === - -TBD. Seems to be not needed. - -=== poll, select === - -TBD. Seems to be not needed. - -=== RMAN(9) (Resource management) === - -http://www.freebsd.org/cgi/man.cgi?query=rman - -TBD. Seems to be not needed. - -=== DEVCLASS(9), DEVICE(9), DRIVER(9), MAKE_DEV(9) (Device management) === - -http://www.freebsd.org/cgi/man.cgi?query=devclass - -http://www.freebsd.org/cgi/man.cgi?query=device - -http://www.freebsd.org/cgi/man.cgi?query=driver - -http://www.freebsd.org/cgi/man.cgi?query=make_dev - -Use FreeBSD implementation as far as possible. FreeBSD has a nice API for -dynamic device handling. It may be interesting for RTEMS to use this API -internally in the future. - -=== BUS_SPACE(9), BUS_DMA(9) (Bus and DMA access) === - -http://www.freebsd.org/cgi/man.cgi?query=bus_space - -http://www.freebsd.org/cgi/man.cgi?query=bus_dma - -Likely BSP dependent. A default implementation for memory mapped linear access -is easy to provide. The current heap implementation supports all properties -demanded by bus_dma (including the boundary constraint). - -== RTEMS Replacements by File Description == - -Note: Files with a status of USB are used by the USB test and have at least -been partially tested. If they contain both USB and Nic, then they are used -by both and MAY contain methods that have not been tested yet. Files that -are only used by the Nic test are the most suspect. - ----- -rtems-libbsd File: rtems-bsd-assert.c -FreeBSD File: rtems-bsd-config.h redefines BSD_ASSERT. -Description: This file contains the support method rtems_bsd_assert_func(). -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-autoconf.c -FreeBSD File: FreeBSD has BSP specific autoconf.c -Description: This file contains configuration methods that are used to setup the system. -Status: USB - -rtems-libbsd File: rtems-bsd-bus-dma.c -FreeBSD File: FreeBSD has BSP specific busdma_machdep.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-bus-dma-mbuf.c -FreeBSD File: FreeBSD has BSP specific busdma_machdep.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-callout.c -FreeBSD File: kern/kern_timeout.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-cam.c -FreeBSD File: cam/cam_sim.c -Description: -Status: USB - -rtems-libbsd File: rtems-bsd-condvar.c -FreeBSD File: kern/kern_condvar.c -Description: -Status: USB - -rtems-libbsd File: rtems-bsd-copyinout.c -FreeBSD File: bsp specific copyinout.c ) -Description: Note: The FreeBSD file is split with some methods being in rtems-bsd-support -Status: Nic - -rtems-libbsd File: rtems-bsd-delay.c -FreeBSD File: bsp specific file with multiple names -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-descrip.c -FreeBSD File: kern/kern_descrip.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-generic.c -FreeBSD File: kern/sys_generic.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-init.c -FreeBSD File: N/A -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-init-with-irq.c -FreeBSD File: N/A -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-jail.c -FreeBSD File: kern/kern_jail.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-lock.c -FreeBSD File: kern/subr_lock.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-log.c -FreeBSD File: kern/subr_prf.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-malloc.c -FreeBSD File: kern/kern_malloc.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-mutex.c -FreeBSD File: kern/kern_mutex.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-newproc.c -FreeBSD File: N/A -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-nexus.c -FreeBSD File: bsp specific nexus.c -Description: -Status: USB - -rtems-libbsd File: rtems-bsd-panic.c -FreeBSD File: boot/common/panic.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-rwlock.c -FreeBSD File: kern_rwlock.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-shell.c -FreeBSD File: N/A -Description: -Status: USB - -rtems-libbsd File: rtems-bsd-signal.c -FreeBSD File: kern/kern_sig.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-smp.c -FreeBSD File: N/A -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-support.c -FreeBSD File: bsp specific copyinout.c -Description: Note: the FreeBSD file is split with some methods being in rtems-bsd-copyinout. -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-sx.c -FreeBSD File: kern/kern_sx.c -Description: Status: USB, Nic - -rtems-libbsd File: rtems-bsd-synch.c -FreeBSD File: kern/kern_synch.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-syscalls.c -FreeBSD File: User API for kern/uipc_syscalls.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-sysctlbyname.c -FreeBSD File: User API for sysctlbyname(3) -Description: -Status: - -rtems-libbsd File: rtems-bsd-sysctl.c -FreeBSD File: User API for sysctl(8) -Description: -Status: - -rtems-libbsd File: rtems-bsd-sysctlnametomib.c -FreeBSD File: User API for sysctlnametomib -Description: -Status: - -rtems-libbsd File: rtems-bsd-taskqueue.c -FreeBSD File: kern/subr_taskqueue.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-thread.c -FreeBSD File: kern/kern_kthread.c -Description: -Status: USB, Nic - -rtems-libbsd File: rtems-bsd-timeout.c -FreeBSD File: kern/kern_timeout.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-timesupport.c -FreeBSD File: kern/kern_clock.c -Description: -Status: Nic - -rtems-libbsd File: rtems-bsd-vm_glue.c -FreeBSD File: vm/vm_glue.c -Description: -Status: USB, Nic ----- - -== Notes by File == - -altq_subr.c - Arbitrary choices were made in this file that RTEMS would -not support tsc frequency change. Additionally, the clock frequency -for machclk_freq is always measured for RTEMS. - -conf.h - In order to add make_dev and destroy_dev, variables in the cdev -structure that were not being used were conditionally compiled out. The -capability of supporting children did not appear to be needed and was -not implemented in the rtems version of these routines. - -== NICs Status == - ----- -Driver Symbol Status -====== ====== ====== -RealTek _bsd_re_pcimodule_sys_init Links -EtherExpress _bsd_fxp_pcimodule_sys_init Links -DEC tulip _bsd_dc_pcimodule_sys_init Links -Broadcom BCM57xxx _bsd_bce_pcimodule_sys_init Links -Broadcom BCM4401 _bsd_bfe_pcimodule_sys_init Links -Broadcom BCM570x _bsd_bge_pcimodule_sys_init Needs Symbols (A) -E1000 IGB _bsd_igb_pcimodule_sys_init Links -E1000 EM _bsd_em_pcimodule_sys_init Links -Cadence ? Links, works. ----- - -To add a NIC edit rtemsbsd/include/bsp/nexus-devices.h and add the driver -reference to the architecture and/or BSP. For example to add the RealTek driver -add: - -SYSINIT_DRIVER_REFERENCE(re, pci); - -and to add the MII PHY driver add: - -SYSINIT_DRIVER_REFERENCE(rge, miibus); - -The PC BSP has these entries. - -Symbols (A) - pci_get_vpd_ident - -=== Cadence === - -The cadence driver works on the Xilinx Zynq platform. The hardware checksum -support works on real hardware but does not seem to be supported on qemu -therefore the default state is to disable TXCSUM and RXCSUM and this can be -enabled from the shell with: - - # ifconfig cgem0 rxcsum txcsum - -or with an ioctl call to the network interface driver with SIOCSIFCAP and the -mask IFCAP_TXCSUM and IFCAP_RXCSUM set. - -== PF (Firewall) == - -It is possible to use PF as a firewall. See -[https://www.freebsd.org/doc/handbook/firewalls-pf.html] for details on the -range of functions and for how to configure the firewall. - -The following is necessary to use PF on RTEMS: - -- You have to provide a +/etc/pf.os+ file. The firewall can use it for passive - OS fingerprinting. If you don't want to use this feature, the file may contain - nothing except a line of comment (for example "# empty"). - -- If some filters use protocol names (like tcp or udp) you have to provide a - +/etc/protocols+ file. - -- If some filters use service names (like ssh or http) you have to provide a - +/etc/services+ file. - -- Create a rule file (normally +/etc/pf.conf+). See the FreeBSD manual for the - syntax. - -- Load the rule file using the pfctl command and enable pf. Please note that the - pfctl command needs a lot of stack. You should use at least - RTEMS_MINIMUM_STACK_SIZE + 8192 Bytes of stack. An example initialisation can - look like follows: - ----- - int exit_code; - char *params[] = { - "pfctl", - "-f", - "/etc/pf.conf", - "-e", - NULL - }; - - exit_code = rtems_bsd_command_pfctl(ARGC(params), params); - assert(exit_code == EXIT_SUCCSESS); ----- - -=== Known restrictions === - -- Currently PF on RTEMS always uses the configuration for memory restricted - systems (on FreeBSD that means systems with less than 100 MB RAM). This is - fixed in +pfctl_init_options()+. - -== Wireless Network (WLAN) == - -The libbsd provides a basic support for WLAN. Note that currently this support -is still in an early state. The WLAN support is _not_ enabled in the default -buildset. You have to configure libbsd with the -`--buildset=buildset/everything.ini` to enable that feature. - -The following gives a rough overview over the necessary steps to connect to an -encrypted network with an RTL8188EU based WiFi dongle: - -- Reference all necessary module for your BSP. For some BSPs this is already - done in the nexus-devices.h: - ----- - SYSINIT_MODULE_REFERENCE(wlan_ratectl_none); - SYSINIT_MODULE_REFERENCE(wlan_sta); - SYSINIT_MODULE_REFERENCE(wlan_amrr); - SYSINIT_MODULE_REFERENCE(wlan_wep); - SYSINIT_MODULE_REFERENCE(wlan_tkip); - SYSINIT_MODULE_REFERENCE(wlan_ccmp); - SYSINIT_DRIVER_REFERENCE(rtwn_usb, uhub); - SYSINIT_REFERENCE(rtwn_rtl8188eufw); ----- - -- Create your wlan device using ifconfig: - +ifconfig wlan0 create wlandev rtwn0 up+ - -- Start a wpa_supplicant instance for that device: - + wpa_supplicant_fork -Dbsd -iwlan0 -c/media/mmcsd-0-0/wpa_supplicant.conf+ - -Note that the wpa_supplicant will only be active till the device goes down. A -workaround is to just restart it every time it exits. - -=== Known restrictions === - -- The network interface (e.g. wlan0) is currently not automatically created. It - would be nice, if some service would create it as soon as for example a USB - device is connected. In FreeBSD the names are assigned via rc.conf with lines - like +wlans_rtwn0="wlan0"+. - -- wpa_supplicant hast to be started after the device is created. It has to be - restarted every time the connection goes down. Instead of this behaviour, - there should be some service that starts and restarts wpa_supplicant - automatically if a interface is ready. Probably the dhcpcd hooks could be used - for that. - -- The current wpa_supplicant implementation is protected with a lock so it can't - be started more than one time. If multiple interface should be used, all have - to be handled by that single instance. That makes it hard to add interfaces - dynamically. wpa_supplicant should be reviewed thoroughly whether multiple - instances could be started in parallel. - -- The control interface of wpa_supplicant most likely doesn't work. The wpa_cli - application is not ported. - -== IPSec == - -The IPSec support is optional in libbsd. It is disabled in the default build -set. Please make sure to use a build set with +netipsec = on+. - -To use IPSec the following configuration is necessary: - ----- -SYSINIT_MODULE_REFERENCE(if_gif); -SYSINIT_MODULE_REFERENCE(cryptodev); -RTEMS_BSD_RC_CONF_SYSINT(rc_conf_ipsec) -RTEMS_BSD_DEFINE_NEXUS_DEVICE(cryptosoft, 0, 0, NULL); ----- - -Alternatively you can use the `RTEMS_BSD_CONFIG_IPSEC` which also includes the -rc.conf support for ipsec. It's still necessary to include a crypto device in -your config (`cryptosoft` in the above sample). - -The necessary initialization steps for a IPSec connection are similar to the -steps on a FreeBSD-System. The example assumes the following setup: - -- RTEMS external IP: 192.168.10.1/24 -- RTEMS internal IP: 10.10.1.1/24 -- remote external IP: 192.168.10.10/24 -- remote internal IP: 172.24.0.1/24 -- shared key: "mysecretkey" - -With this the following steps are necessary: - -- Create a gif0 device: - ----- -SHLL [/] # ifconfig gif0 create ----- - -- Configure the gif0 device: - ----- -SHLL [/] # ifconfig gif0 10.10.1.1 172.24.0.1 -SHLL [/] # ifconfig gif0 tunnel 192.168.10.1 192.168.10.10 ----- - -- Add a route to the remote net via the remote IP: - ----- -SHLL [/] # route add 172.24.0.0/24 172.24.0.1 ----- - -- Call `setkey` with a correct rule set: - ----- -SHLL [/] # cat /etc/setkey.conf -flush; -spdflush; -spdadd 10.10.1.0/24 172.24.0.0/24 any -P out ipsec esp/tunnel/192.168.10.1-192.168.10.10/use; -spdadd 172.24.0.0/24 10.10.1.0/24 any -P in ipsec esp/tunnel/192.168.10.10-192.168.10.1/use; -SHLL [/] # setkey -f /etc/setkey.conf ----- - -- Start a ike-daemon (racoon) with a correct configuration. ----- -SHLL [/] # cat /etc/racoon.conf -path pre_shared_key "/etc/racoon_psk.txt"; -log info; - -padding # options are not to be changed -{ - maximum_length 20; - randomize off; - strict_check off; - exclusive_tail off; -} - -listen # address [port] that racoon will listen on -{ - isakmp 192.168.10.1[500]; -} - -remote 192.168.10.10 [500] -{ - exchange_mode main; - my_identifier address 192.168.10.1; - peers_identifier address 192.168.10.10; - proposal_check obey; - - proposal { - encryption_algorithm 3des; - hash_algorithm md5; - authentication_method pre_shared_key; - lifetime time 3600 sec; - dh_group 2; - } -} - -sainfo (address 10.10.1.0/24 any address 172.24.0.0/24 any) -{ - pfs_group 2; - lifetime time 28800 sec; - encryption_algorithm 3des; - authentication_algorithm hmac_md5; - compression_algorithm deflate; -} -SHLL [/] # cat /etc/racoon_psk.txt -192.168.10.10 mysecretkey -SHLL [/] # racoon -F -f /etc/racoon.conf ----- - -All commands can be called via the respective API functions. For racoon there is -a `rtems_bsd_racoon_daemon()` function that forks of racoon as a task. - -Alternatively IPSec can also be configured via rc.conf entries: - ----- -cloned_interfaces="gif0" -ifconfig_gif0="10.10.1.1 172.24.0.1 tunnel 192.168.10.1 192.168.10.10" -ike_enable="YES" -ike_program="racoon" -ike_flags="-F -f /etc/racoon.conf" -ike_priority="250" - -ipsec_enable="YES" -ipsec_file="/etc/setkey.conf" ----- - -ATTENTION: It is possible that the first packets slip through the tunnel without -encryption (true for FreeBSD as well as RTEMS). You might want to set up a -firewall rule to prevent that. - -== Problems to report to FreeBSD == - -The MMAP_NOT_AVAILABLE define is inverted on its usage. When it is -defined the mmap method is called. Additionally, it is not used -thoroughly. It is not used in the unmap portion of the source. -The file rec_open.c uses the define MMAP_NOT_AVAILABLE to wrap -the call to mmap and file rec_close.c uses the munmap method. diff --git a/rtemsbsd/arm/include/arm/lpc/probe.h b/rtemsbsd/arm/include/arm/lpc/probe.h new file mode 100644 index 00000000..54f9ebda --- /dev/null +++ b/rtemsbsd/arm/include/arm/lpc/probe.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ARM_LPC_PROBE_H +#define _ARM_LPC_PROBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int lpc_eth_probe(int unit); + +int lpc_ohci_probe(int unit); + +#ifdef __cplusplus +} +#endif + +#endif /* _ARM_LPC_PROBE_H */ diff --git a/rtemsbsd/include/bsp/mv643xx_eth.h b/rtemsbsd/include/bsp/mv643xx_eth.h new file mode 100644 index 00000000..7d122cd6 --- /dev/null +++ b/rtemsbsd/include/bsp/mv643xx_eth.h @@ -0,0 +1,397 @@ +/* Acknowledgement: + * + * Valuable information for developing this driver was obtained + * from the linux open-source driver mv643xx_eth.c which was written + * by the following people and organizations: + * + * Matthew Dharm <mdharm@momenco.com> + * rabeeh@galileo.co.il + * PMC-Sierra, Inc., Manish Lachwani + * Ralf Baechle <ralf@linux-mips.org> + * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org> + * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com> + * + * Note however, that in spite of the identical name of this file + * (and some of the symbols used herein) this file provides a + * new implementation and is the original work by the author. + */ + +/* + * Authorship + * ---------- + * This software (mv643xx ethernet driver for RTEMS) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'mv643xx ethernet driver for RTEMS' was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#ifndef MV643XX_LOWLEVEL_DRIVER_H +#define MV643XX_LOWLEVEL_DRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MV643XXETH_NUM_DRIVER_SLOTS 2 + +struct mveth_private; + +/* Create interface. + * Allocates resources for descriptor rings and sets up the driver software structure. + * + * Arguments: + * unit: + * interface # (1..2). The interface must not be attached to BSD. + * + * driver_tid: + * optional driver task-id (can be retrieved with BSP_mve_get_tid()). + * Not used by the low-level driver. + * + * isr(isr_arg): + * user ISR. + * + * void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred): + * Pointer to user-supplied callback to release a buffer that had been sent + * by BSP_mve_send_buf() earlier. The callback is passed 'cleanup_txbuf_arg' + * and a flag indicating whether the send had been successful. + * The driver no longer accesses 'user_buf' after invoking this callback. + * CONTEXT: This callback is executed either by BSP_mve_swipe_tx() or + * BSP_mve_send_buf(), BSP_mve_init_hw(), BSP_mve_stop_hw() (the latter + * ones calling BSP_mve_swipe_tx()). + * void *cleanup_txbuf_arg: + * Closure argument that is passed on to 'cleanup_txbuf()' callback; + * + * void *(*alloc_rxbuf)(int *p_size, unsigned long *p_data_addr), + * Pointer to user-supplied callback to allocate a buffer for subsequent + * insertion into the RX ring by the driver. + * RETURNS: opaque handle to the buffer (which may be a more complex object + * such as an 'mbuf'). The handle is not used by the driver directly + * but passed back to the 'consume_rxbuf()' callback. + * Size of the available data area and pointer to buffer's data area + * in '*psize' and '*p_data_area', respectively. + * If no buffer is available, this routine should return NULL in which + * case the driver drops the last packet and re-uses the last buffer + * instead of handing it out to 'consume_rxbuf()'. + * CONTEXT: Called when initializing the RX ring (BSP_mve_init_hw()) or when + * swiping it (BSP_mve_swipe_rx()). + * + * + * void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len); + * Pointer to user-supplied callback to pass a received buffer back to + * the user. The driver no longer accesses the buffer after invoking this + * callback (with 'len'>0, see below). 'user_buf' is the buffer handle + * previously generated by 'alloc_rxbuf()'. + * The callback is passed 'cleanup_rxbuf_arg' and a 'len' + * argument giving the number of bytes that were received. + * 'len' may be <=0 in which case the 'user_buf' argument is NULL. + * 'len' == 0 means that the last 'alloc_rxbuf()' had failed, + * 'len' < 0 indicates a receiver error. In both cases, the last packet + * was dropped/missed and the last buffer will be re-used by the driver. + * NOTE: the data are 'prefixed' with two bytes, i.e., the ethernet packet header + * is stored at offset 2 in the buffer's data area. Also, the FCS (4 bytes) + * is appended. 'len' accounts for both. + * CONTEXT: Called from BSP_mve_swipe_rx(). + * void *cleanup_rxbuf_arg: + * Closure argument that is passed on to 'consume_rxbuf()' callback; + * + * rx_ring_size, tx_ring_size: + * How many big to make the RX and TX descriptor rings. Note that the sizes + * may be 0 in which case a reasonable default will be used. + * If either ring size is < 0 then the RX or TX will be disabled. + * Note that it is illegal in this case to use BSP_mve_swipe_rx() or + * BSP_mve_swipe_tx(), respectively. + * + * irq_mask: + * Interrupts to enable. OR of flags from above. + * + */ + +/* Direct assignment of MVE flags to user API relies on irqs and x-irqs not overlapping */ +#define MV643XX_ETH_IRQ_RX_DONE (1<<2) +#define MV643XX_ETH_EXT_IRQ_TX_DONE (1<<0) +#define MV643XX_ETH_EXT_IRQ_LINK_CHG (1<<16) + +struct mveth_private * +BSP_mve_create( + int unit, + rtems_id tid, + void (*isr)(void*isr_arg), + void *isr_arg, + void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), + void *cleanup_txbuf_arg, + void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr), + void (*consume_rxbuf)(void *user_buf, void *closure, int len), + void *consume_rxbuf_arg, + int rx_ring_size, + int tx_ring_size, + int irq_mask +); + +/* + * Clear multicast hash filter. No multicast frames are accepted + * after executing this routine (unless the hardware was initialized + * in 'promiscuous' mode). + */ +void +BSP_mve_mcast_filter_clear(struct mveth_private *mp); + +/* + * Program multicast filter to accept all multicast frames + */ +void +BSP_mve_mcast_filter_accept_all(struct mveth_private *mp); + +/* + * Add a MAC address to the multicast filter. + * Existing entries are not changed but note that + * the filter is imperfect, i.e., multiple MAC addresses + * may alias to a single filter entry. Hence software + * filtering must still be performed. + * + * If a higher-level driver implements IP multicasting + * then multiple IP addresses may alias to the same MAC + * address. This driver maintains a 'reference-count' + * which is incremented every time the same MAC-address + * is passed to this routine; the address is only removed + * from the filter if BSP_mve_mcast_filter_accept_del() + * is called the same number of times (or by BSP_mve_mcast_filter_clear). + */ +void +BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr); + +/* + * Remove a MAC address from the multicast filter. + * This routine decrements the reference count of the given + * MAC-address and removes it from the filter once the + * count reaches zero. + */ +void +BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr); + + +/* Enable/disable promiscuous mode */ +void +BSP_mve_promisc_set(struct mveth_private *mp, int promisc); + +/* calls BSP_mve_stop_hw(), releases all resources and marks the interface + * as unused. + * RETURNS 0 on success, nonzero on failure. + * NOTE: the handle MUST NOT be used after successful execution of this + * routine. + */ +int +BSP_mve_detach(struct mveth_private *mp); + +/* Enqueue a buffer chain for transmission. + * + * RETURN: #bytes sent or -1 if there are not enough descriptors + * -2 is returned if the caller should attempt to + * repackage the chain into a smaller one. + * + * Comments: software cache-flushing incurs a penalty if the + * packet cannot be queued since it is flushed anyways. + * The algorithm is slightly more efficient in the normal + * case, though. + */ + +typedef struct MveEthBufIter { + void *hdl; /* opaque handle for the iterator implementor */ + void *data; /* data to be sent */ + size_t len; /* data size (in octets) */ + void *uptr; /* user-pointer to go into the descriptor; + note: cleanup_txbuf is only called for desriptors + where this field is non-NULL (for historical + reasons) */ +} MveEthBufIter; + +typedef MveEthBufIter *(*MveEthBufIterNext)(MveEthBufIter*); + +int +BSP_mve_send_buf_chain(struct mveth_private *mp, MveEthBufIterNext next, MveEthBufIter *it); + + +/* Legacy entry point to send a header + a buffer */ +int +BSP_mve_send_buf_raw(struct mveth_private *mp, void *head_p, int h_len, void *data_p, int d_len); + +/* Descriptor scavenger; cleanup the TX ring, passing all buffers + * that have been sent to the cleanup_tx() callback. + * This routine is called from BSP_mve_send_buf(), BSP_mve_init_hw(), + * BSP_mve_stop_hw(). + * + * RETURNS: number of buffers processed. + */ +int +BSP_mve_swipe_tx(struct mveth_private *mp); + +/* Retrieve all received buffers from the RX ring, replacing them + * by fresh ones (obtained from the alloc_rxbuf() callback). The + * received buffers are passed to consume_rxbuf(). + * + * RETURNS: number of buffers processed. + */ +int +BSP_mve_swipe_rx(struct mveth_private *mp); + +/* read ethernet address from hw to buffer */ +void +BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr); + +/* Interrupt related routines */ + +/* Note: the BSP_mve_enable/disable/ack_irqs() entry points + * are deprecated. + * The newer API where the user passes a mask allows + * for more selective control. + */ + +/* Enable all supported interrupts at device */ +void +BSP_mve_enable_irqs(struct mveth_private *mp); + +/* Disable all supported interrupts at device */ +void +BSP_mve_disable_irqs(struct mveth_private *mp); + +/* Acknowledge (and clear) all supported interrupts. + * RETURNS: interrupts that were raised. + */ +uint32_t +BSP_mve_ack_irqs(struct mveth_private *mp); + +/* Enable interrupts included in 'mask' (leaving + * already enabled interrupts on). If the mask + * includes bits that were not passed to the 'setup' + * routine then the behavior is undefined. + */ +void +BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t irq_mask); + +/* Disable interrupts included in 'mask' (leaving + * other ones that are currently enabled on). If the + * mask includes bits that were not passed to the 'setup' + * routine then the behavior is undefined. + * + * RETURNS: Bitmask of interrupts that were enabled upon entry + * into this routine. This can be used to restore the + * previous state. + */ +uint32_t +BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t irq_mask); + +/* Acknowledge and clear selected interrupts. + * + * RETURNS: All pending interrupts. + * + * NOTE: Only pending interrupts contained in 'mask' + * are cleared. Others are left pending. + * + * This routine can be used to check for pending + * interrupts (pass mask == 0) or to clear all + * interrupts (pass mask == -1). + */ +uint32_t +BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask); + +/* Retrieve the driver daemon TID that was passed to + * BSP_mve_setup(). + */ + +rtems_id +BSP_mve_get_tid(struct mveth_private *mp); + +/* Dump statistics to file (stdout if NULL) + * + * NOTE: this routine is not thread safe + */ +void +BSP_mve_dump_stats(struct mveth_private *mp, FILE *f); + +#define MV643XX_MEDIA_LINK (1<<0) +#define MV643XX_MEDIA_FD (1<<1) +#define MV643XX_MEDIA_10 (1<<8) +#define MV643XX_MEDIA_100 (2<<8) +#define MV643XX_MEDIA_1000 (3<<8) +#define MV643XX_MEDIA_SPEED_MSK (0xff00) + +/* + * Initialize interface hardware + * + * 'mp' handle obtained by from BSP_mve_setup(). + * 'promisc' whether to set promiscuous flag. + * 'enaddr' pointer to six bytes with MAC address. Read + * from the device if NULL. + * 'speed' current speed and link status as read from the PHY. + * + * Note: Multicast filters are cleared by this routine. + * However, in promiscuous mode the mcast filters + * are programmed to accept all multicast frames. + */ +void +BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr, int speed); + +/* + * Update the serial port to a new speed (e.g., result of a PHY IRQ) + */ +void +BSP_mve_update_serial_port(struct mveth_private *mp, int speed); + +/* + * Shutdown hardware and clean out the rings + */ +void +BSP_mve_stop_hw(struct mveth_private *mp); + +unsigned +BSP_mve_mii_read(struct mveth_private *mp, unsigned addr); + +unsigned +BSP_mve_mii_write(struct mveth_private *mp, unsigned addr, unsigned v); + +unsigned +BSP_mve_mii_read_early(int port, unsigned addr); + +unsigned +BSP_mve_mii_write_early(int port, unsigned addr, unsigned v); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h index efe4fcb4..37008cc6 100644 --- a/rtemsbsd/include/bsp/nexus-devices.h +++ b/rtemsbsd/include/bsp/nexus-devices.h @@ -115,6 +115,13 @@ RTEMS_BSD_DRIVER_E1000PHY; RTEMS_BSD_DRIVER_XILINX_ZYNQMP_CGEM0(ZYNQMP_IRQ_ETHERNET_0); RTEMS_BSD_DRIVER_E1000PHY; +#elif defined(LIBBSP_AARCH64_XILINX_VERSAL_BSP_H) + +#include <bsp/irq.h> + +RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM0(VERSAL_IRQ_ETHERNET_0); +RTEMS_BSD_DRIVER_E1000PHY; + #elif defined(LIBBSP_ARM_ATSAM_BSP_H) RTEMS_BSD_DRIVER_USB; @@ -166,6 +173,14 @@ SYSINIT_DRIVER_REFERENCE(simplebus, ofwbus); SYSINIT_DRIVER_REFERENCE(ffec, simplebus); SYSINIT_DRIVER_REFERENCE(ksz8091rnb, miibus); +#if IMXRT_IS_MIMXRT11xx +SYSINIT_DRIVER_REFERENCE(ehci, simplebus); +SYSINIT_DRIVER_REFERENCE(imxrt1166_usbphy, simplebus); +SYSINIT_DRIVER_REFERENCE(usbus, ehci); +RTEMS_BSD_DRIVER_USB; +RTEMS_BSD_DRIVER_USB_MASS; +#endif /* IMXRT_IS_IMXRT11xx */ + #elif defined(LIBBSP_ARM_LPC24XX_BSP_H) RTEMS_BSD_DEFINE_NEXUS_DEVICE(ohci, 0, 0, NULL); @@ -244,6 +259,11 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus); RTEMS_BSD_DEFINE_NEXUS_DEVICE(fec, 0, 0, NULL); SYSINIT_DRIVER_REFERENCE(ukphy, miibus); +#elif defined(LIBBSP_BEATNIK_BSP_H) + +RTEMS_BSD_DEFINE_NEXUS_DEVICE(mve, 0, 0, NULL); +SYSINIT_DRIVER_REFERENCE(ukphy, miibus); + #elif defined(LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H) RTEMS_BSD_DRIVER_PC_LEGACY; diff --git a/rtemsbsd/include/machine/_kernel_if.h b/rtemsbsd/include/machine/_kernel_if.h index 08086658..16733fe3 100644 --- a/rtemsbsd/include/machine/_kernel_if.h +++ b/rtemsbsd/include/machine/_kernel_if.h @@ -41,6 +41,20 @@ MALLOC_DECLARE(M_IFADDR); MALLOC_DECLARE(M_IFMADDR); #endif +extern struct sx ifnet_detach_sxlock; + +struct nvlist; +struct ifcap_nv_bit_name; +int if_capnv_to_capint(const struct nvlist *nv, int *old_cap, + const struct ifcap_nv_bit_name *nn, bool all); +void if_capint_to_capnv(struct nvlist *nv, + const struct ifcap_nv_bit_name *nn, int ifr_cap, int ifr_req); +struct siocsifcapnv_driver_data { + int reqcap; + int reqcap2; + struct nvlist *nvcap; +}; + #define ifr_buffer ifr_ifru.ifru_buffer /* user supplied buffer with its length */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ diff --git a/rtemsbsd/include/machine/_kernel_socket.h b/rtemsbsd/include/machine/_kernel_socket.h index e9acc744..3acee460 100644 --- a/rtemsbsd/include/machine/_kernel_socket.h +++ b/rtemsbsd/include/machine/_kernel_socket.h @@ -46,6 +46,7 @@ #define MSG_SOCALLBCK 0x00010000 /* for use by socket callbacks - soreceive (TCP) */ #define MSG_MORETOCOME 0x00100000 /* additional data pending */ +#define MSG_TLSAPPDATA 0x00200000 /* do not soreceive() alert rec. (TLS) */ #define CMSG_ALIGN(n) _ALIGN(n) diff --git a/rtemsbsd/include/machine/rtems-bsd-cache.h b/rtemsbsd/include/machine/rtems-bsd-cache.h index 73b55e25..e292b216 100755 --- a/rtemsbsd/include/machine/rtems-bsd-cache.h +++ b/rtemsbsd/include/machine/rtems-bsd-cache.h @@ -45,7 +45,7 @@ #if defined(LIBBSP_ARM_LPC24XX_BSP_H) || (defined(LIBBSP_ARM_LPC32XX_BSP_H) && defined(LPC32XX_DISABLE_MMU)) /* No cache */ #elif defined(LIBBSP_ARM_ALTERA_CYCLONE_V_BSP_H) || \ - defined(LIBBSP_ARM_XILINX_ZYNQ_BSP_H) || (defined(LIBBSP_ARM_LPC32XX_BSP_H) && !defined(LPC32XX_DISABLE_MMU)) || defined(LIBBSP_ARM_IMX_BSP_H) + defined(LIBBSP_ARM_XILINX_ZYNQ_BSP_H) || (defined(LIBBSP_ARM_LPC32XX_BSP_H) && !defined(LPC32XX_DISABLE_MMU)) || defined(LIBBSP_ARM_IMX_BSP_H) || defined(LIBBSP_ARM_IMXRT_BSP_H) /* With cache, no coherency support in hardware */ #define CPU_DATA_CACHE_ALIGNMENT 32 #elif defined(__GEN83xx_BSP_h) diff --git a/rtemsbsd/include/machine/rtems-bsd-kernel-space.h b/rtemsbsd/include/machine/rtems-bsd-kernel-space.h index 09bcecf1..f2f1b91f 100644 --- a/rtemsbsd/include/machine/rtems-bsd-kernel-space.h +++ b/rtemsbsd/include/machine/rtems-bsd-kernel-space.h @@ -55,6 +55,12 @@ /* General define to activate BSD kernel parts */ #define _KERNEL 1 +/* REVIEW-AFTER-FREEBSD-BASELINE-UPDATE */ +#define IN_HISTORICAL_NETS + +/* REVIEW-AFTER-FREEBSD-BASELINE-UPDATE */ +#define IFCAP_NOMAP 0x4000000 + #include <machine/rtems-bsd-version.h> #include <machine/rtems-bsd-kernel-namespace.h> diff --git a/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h b/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h index 5902c58c..50a43873 100644 --- a/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h +++ b/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h @@ -409,6 +409,17 @@ extern "C" { #define RTEMS_BSD_DRIVER_XILINX_ZYNQMP_CGEM3(_irq) \ RTEMS_BSD_DRIVER_XILINX_ZYNQ_CGEM(3, 0xff0e0000, _irq) #endif /* RTEMS_BSD_DRIVER_XILINX_ZYNQMP_CGEM3 */ +/* + * Versal has a similar GEM as the CGEM. This should work for now. + */ +#if !defined(RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM0) + #define RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM0(_irq) \ + RTEMS_BSD_DRIVER_XILINX_ZYNQ_CGEM(0, 0xff0c0000, _irq) +#endif /* RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM0 */ +#if !defined(RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM1) + #define RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM1(_irq) \ + RTEMS_BSD_DRIVER_XILINX_ZYNQ_CGEM(1, 0xff0d0000, _irq) +#endif /* RTEMS_BSD_DRIVER_XILINX_VERSAL_GEM1 */ /* * Designware/Synopsys Ethernet MAC Controller. diff --git a/rtemsbsd/include/machine/rtems-bsd-program.h b/rtemsbsd/include/machine/rtems-bsd-program.h index f71ac9cd..3062c1a2 100644 --- a/rtemsbsd/include/machine/rtems-bsd-program.h +++ b/rtemsbsd/include/machine/rtems-bsd-program.h @@ -60,6 +60,12 @@ rtems_bsd_program_call_main_with_data_restore(const char *name, int (*main)(int, char **), int argc, char **argv, void *data_buf, const size_t data_size); +void * +rtems_bsd_program_add_destructor(void (*destructor)(void *), void *arg); + +void +rtems_bsd_program_remove_destructor(void *cookie, bool call); + void rtems_bsd_program_exit(int exit_code) __dead2; @@ -198,7 +204,7 @@ rtems_bsd_program_free(void *ptr); #endif #ifndef RTEMS_BSD_PROGRAM_NO_FREE_WRAP - #define free(ptr) rtems_bsd_program_free(ptr); + #define free(ptr) rtems_bsd_program_free(ptr) #endif __END_DECLS diff --git a/rtemsbsd/include/machine/rtems-bsd-user-space.h b/rtemsbsd/include/machine/rtems-bsd-user-space.h index 28d5dd5a..93113b9c 100644 --- a/rtemsbsd/include/machine/rtems-bsd-user-space.h +++ b/rtemsbsd/include/machine/rtems-bsd-user-space.h @@ -41,6 +41,7 @@ #define _RTEMS_BSD_MACHINE_RTEMS_BSD_USER_SPACE_H_ #define __FreeBSD__ 1 +#define _WANT_FREEBSD_BITSET #include <rtems/bsd/local/opt_inet6.h> #include <machine/rtems-bsd-version.h> @@ -49,6 +50,9 @@ #include <stdio.h> +/* REVIEW-AFTER-FREEBSD-BASELINE-UPDATE */ +#define IFCAP_NOMAP 0x4000000 + #define O_CLOEXEC 0 #define O_DIRECTORY 0 diff --git a/rtemsbsd/include/rtems/bsd/bsd.h b/rtemsbsd/include/rtems/bsd/bsd.h index cec14ac4..9e524719 100755 --- a/rtemsbsd/include/rtems/bsd/bsd.h +++ b/rtemsbsd/include/rtems/bsd/bsd.h @@ -92,28 +92,6 @@ typedef struct { rtems_status_code rtems_bsd_initialize(void); /** - * @brief Initializes the libbsd and starts a DHCPCD task. - * - * The libbsd is initialized via rtems_bsd_initialize(). If this is - * successful, then the loop back interfaces are created. If this is - * successful, then a DHCPCD task is started at the least important priority. - * - * The default devices of the BSP are initialized. Support for - * - IF_BRIDGE(4), - * - LAGG(4), - * - multicast routing, - * - UNIX(4), and - * - VLAN(4), - * is enabled. - * - * No RTEMS shell commands are registered. - * - * @retval RTEMS_SUCCESSFUL Successful operation. - * @retval otherwise An error occurred. - */ -rtems_status_code rtems_bsd_initialize_dhcp(void); - -/** * @brief Configures the lo0 (loopback) interface. * * @return Returns an exit code, see also <sysexits.h>. diff --git a/rtemsbsd/include/x86/bus.h b/rtemsbsd/include/x86/bus.h deleted file mode 100644 index 2427ae51..00000000 --- a/rtemsbsd/include/x86/bus.h +++ /dev/null @@ -1,1109 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause-NetBSDE - * - * Copyright (c) KATO Takenori, 1999. - * - * All rights reserved. Unpublished rights reserved under the copyright - * laws of Japan. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer as - * the first lines of this file unmodified. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ - -/*- - * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, - * NASA Ames Research Center. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/*- - * Copyright (c) 1996 Charles M. Hannum. All rights reserved. - * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christopher G. Demetriou - * for the NetBSD Project. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _X86_BUS_H_ -#define _X86_BUS_H_ - -#include <machine/_bus.h> -#include <machine/cpufunc.h> - -#ifndef __GNUCLIKE_ASM -#error "no assembler code for your compiler" -#endif - -/* - * Values for the x86 bus space tag, not to be used directly by MI code. - */ -#define X86_BUS_SPACE_IO 0 /* space is i/o space */ -#define X86_BUS_SPACE_MEM 1 /* space is mem space */ - -#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF -#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF -#if defined(__amd64__) -#define BUS_SPACE_MAXSIZE 0xFFFFFFFFFFFFFFFFULL -#else -#define BUS_SPACE_MAXSIZE 0xFFFFFFFF -#endif -#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF -#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF -#if defined(__amd64__) || defined(PAE) -#define BUS_SPACE_MAXADDR_48BIT 0xFFFFFFFFFFFFULL -#define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFULL -#else -#define BUS_SPACE_MAXADDR 0xFFFFFFFF -#endif - -#define BUS_SPACE_INVALID_DATA (~0) -#define BUS_SPACE_UNRESTRICTED (~0) - -/* - * Map a region of device bus space into CPU virtual address space. - */ - -int bus_space_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, - int flags, bus_space_handle_t *bshp); - -/* - * Unmap a region of device bus space. - */ - -void bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t size); - -/* - * Get a new handle for a subregion of an already-mapped area of bus space. - */ - -static __inline int bus_space_subregion(bus_space_tag_t t, - bus_space_handle_t bsh, - bus_size_t offset, bus_size_t size, - bus_space_handle_t *nbshp); - -static __inline int -bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh, - bus_size_t offset, bus_size_t size __unused, - bus_space_handle_t *nbshp) -{ - - *nbshp = bsh + offset; - return (0); -} - -/* - * Allocate a region of memory that is accessible to devices in bus space. - */ - -int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, - bus_addr_t rend, bus_size_t size, bus_size_t align, - bus_size_t boundary, int flags, bus_addr_t *addrp, - bus_space_handle_t *bshp); - -/* - * Free a region of bus space accessible memory. - */ - -static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, - bus_size_t size); - -static __inline void -bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, - bus_size_t size __unused) -{ -} - - -/* - * Read a 1, 2, 4, or 8 byte quantity from bus space - * described by tag/handle/offset. - */ -static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, - bus_space_handle_t handle, - bus_size_t offset); - -static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, - bus_space_handle_t handle, - bus_size_t offset); - -static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, - bus_space_handle_t handle, - bus_size_t offset); - -#ifdef __amd64__ -static __inline uint64_t bus_space_read_8(bus_space_tag_t tag, - bus_space_handle_t handle, - bus_size_t offset); -#endif - -static __inline u_int8_t -bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - - if (tag == X86_BUS_SPACE_IO) - return (inb(handle + offset)); - return (*(volatile u_int8_t *)(handle + offset)); -} - -static __inline u_int16_t -bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - - if (tag == X86_BUS_SPACE_IO) - return (inw(handle + offset)); - return (*(volatile u_int16_t *)(handle + offset)); -} - -static __inline u_int32_t -bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - - if (tag == X86_BUS_SPACE_IO) - return (inl(handle + offset)); - return (*(volatile u_int32_t *)(handle + offset)); -} - -#ifdef __amd64__ -static __inline uint64_t -bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - - if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ - return (BUS_SPACE_INVALID_DATA); - return (*(volatile uint64_t *)(handle + offset)); -} -#endif - -/* - * Read `count' 1, 2, 4, or 8 byte quantities from bus space - * described by tag/handle/offset and copy into buffer provided. - */ -static __inline void bus_space_read_multi_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int8_t *addr, - size_t count); - -static __inline void bus_space_read_multi_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int16_t *addr, - size_t count); - -static __inline void bus_space_read_multi_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int32_t *addr, - size_t count); - -static __inline void -bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int8_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - insb(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: movb (%2),%%al \n\ - stosb \n\ - loop 1b" : - "=D" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory"); -#endif - } -} - -static __inline void -bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int16_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - insw(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: movw (%2),%%ax \n\ - stosw \n\ - loop 1b" : - "=D" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory"); -#endif - } -} - -static __inline void -bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int32_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - insl(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: movl (%2),%%eax \n\ - stosl \n\ - loop 1b" : - "=D" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory"); -#endif - } -} - -#if 0 /* Cause a link error for bus_space_read_multi_8 */ -#define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! -#endif - -/* - * Read `count' 1, 2, 4, or 8 byte quantities from bus space - * described by tag/handle and starting at `offset' and copy into - * buffer provided. - */ -static __inline void bus_space_read_region_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int8_t *addr, - size_t count); - -static __inline void bus_space_read_region_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int16_t *addr, - size_t count); - -static __inline void bus_space_read_region_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int32_t *addr, - size_t count); - - -static __inline void -bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int8_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: inb %w2,%%al \n\ - stosb \n\ - incl %2 \n\ - loop 1b" : - "=D" (addr), "=c" (count), "=d" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsb" : - "=D" (addr), "=c" (count), "=S" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int16_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: inw %w2,%%ax \n\ - stosw \n\ - addl $2,%2 \n\ - loop 1b" : - "=D" (addr), "=c" (count), "=d" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsw" : - "=D" (addr), "=c" (count), "=S" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int32_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: inl %w2,%%eax \n\ - stosl \n\ - addl $4,%2 \n\ - loop 1b" : - "=D" (addr), "=c" (count), "=d" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsl" : - "=D" (addr), "=c" (count), "=S" (_port_) : - "0" (addr), "1" (count), "2" (_port_) : - "memory", "cc"); -#endif - } -} - -#if 0 /* Cause a link error for bus_space_read_region_8 */ -#define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! -#endif - -/* - * Write the 1, 2, 4, or 8 byte value `value' to bus space - * described by tag/handle/offset. - */ - -static __inline void bus_space_write_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int8_t value); - -static __inline void bus_space_write_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int16_t value); - -static __inline void bus_space_write_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int32_t value); - -#ifdef __amd64__ -static __inline void bus_space_write_8(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, uint64_t value); -#endif - -static __inline void -bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int8_t value) -{ - - if (tag == X86_BUS_SPACE_IO) - outb(bsh + offset, value); - else - *(volatile u_int8_t *)(bsh + offset) = value; -} - -static __inline void -bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int16_t value) -{ - - if (tag == X86_BUS_SPACE_IO) - outw(bsh + offset, value); - else - *(volatile u_int16_t *)(bsh + offset) = value; -} - -static __inline void -bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int32_t value) -{ - - if (tag == X86_BUS_SPACE_IO) - outl(bsh + offset, value); - else - *(volatile u_int32_t *)(bsh + offset) = value; -} - -#ifdef __amd64__ -static __inline void -bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, uint64_t value) -{ - - if (tag == X86_BUS_SPACE_IO) /* No 8 byte IO space access on x86 */ - return; - else - *(volatile uint64_t *)(bsh + offset) = value; -} -#endif - -/* - * Write `count' 1, 2, 4, or 8 byte quantities from the buffer - * provided to bus space described by tag/handle/offset. - */ - -static __inline void bus_space_write_multi_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int8_t *addr, - size_t count); -static __inline void bus_space_write_multi_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int16_t *addr, - size_t count); - -static __inline void bus_space_write_multi_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int32_t *addr, - size_t count); - -static __inline void -bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int8_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - outsb(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsb \n\ - movb %%al,(%2) \n\ - loop 1b" : - "=S" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int16_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - outsw(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsw \n\ - movw %%ax,(%2) \n\ - loop 1b" : - "=S" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int32_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) - outsl(bsh + offset, addr, count); - else { -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsl \n\ - movl %%eax,(%2) \n\ - loop 1b" : - "=S" (addr), "=c" (count) : - "r" (bsh + offset), "0" (addr), "1" (count) : - "%eax", "memory", "cc"); -#endif - } -} - -#if 0 /* Cause a link error for bus_space_write_multi_8 */ -#define bus_space_write_multi_8(t, h, o, a, c) \ - !!! bus_space_write_multi_8 unimplemented !!! -#endif - -/* - * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided - * to bus space described by tag/handle starting at `offset'. - */ - -static __inline void bus_space_write_region_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int8_t *addr, - size_t count); -static __inline void bus_space_write_region_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int16_t *addr, - size_t count); -static __inline void bus_space_write_region_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - const u_int32_t *addr, - size_t count); - -static __inline void -bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int8_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsb \n\ - outb %%al,%w0 \n\ - incl %0 \n\ - loop 1b" : - "=d" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsb" : - "=D" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int16_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsw \n\ - outw %%ax,%w0 \n\ - addl $2,%0 \n\ - loop 1b" : - "=d" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsw" : - "=D" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "memory", "cc"); -#endif - } -} - -static __inline void -bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, const u_int32_t *addr, size_t count) -{ - - if (tag == X86_BUS_SPACE_IO) { - int _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - 1: lodsl \n\ - outl %%eax,%w0 \n\ - addl $4,%0 \n\ - loop 1b" : - "=d" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "%eax", "memory", "cc"); -#endif - } else { - bus_space_handle_t _port_ = bsh + offset; -#ifdef __GNUCLIKE_ASM - __asm __volatile(" \n\ - cld \n\ - repne \n\ - movsl" : - "=D" (_port_), "=S" (addr), "=c" (count) : - "0" (_port_), "1" (addr), "2" (count) : - "memory", "cc"); -#endif - } -} - -#if 0 /* Cause a link error for bus_space_write_region_8 */ -#define bus_space_write_region_8 \ - !!! bus_space_write_region_8 unimplemented !!! -#endif - -/* - * Write the 1, 2, 4, or 8 byte value `val' to bus space described - * by tag/handle/offset `count' times. - */ - -static __inline void bus_space_set_multi_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - u_int8_t value, size_t count); -static __inline void bus_space_set_multi_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - u_int16_t value, size_t count); -static __inline void bus_space_set_multi_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, - u_int32_t value, size_t count); - -static __inline void -bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int8_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - while (count--) - outb(addr, value); - else - while (count--) - *(volatile u_int8_t *)(addr) = value; -} - -static __inline void -bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int16_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - while (count--) - outw(addr, value); - else - while (count--) - *(volatile u_int16_t *)(addr) = value; -} - -static __inline void -bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int32_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - while (count--) - outl(addr, value); - else - while (count--) - *(volatile u_int32_t *)(addr) = value; -} - -#if 0 /* Cause a link error for bus_space_set_multi_8 */ -#define bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!! -#endif - -/* - * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described - * by tag/handle starting at `offset'. - */ - -static __inline void bus_space_set_region_1(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int8_t value, - size_t count); -static __inline void bus_space_set_region_2(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int16_t value, - size_t count); -static __inline void bus_space_set_region_4(bus_space_tag_t tag, - bus_space_handle_t bsh, - bus_size_t offset, u_int32_t value, - size_t count); - -static __inline void -bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int8_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - for (; count != 0; count--, addr++) - outb(addr, value); - else - for (; count != 0; count--, addr++) - *(volatile u_int8_t *)(addr) = value; -} - -static __inline void -bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int16_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - for (; count != 0; count--, addr += 2) - outw(addr, value); - else - for (; count != 0; count--, addr += 2) - *(volatile u_int16_t *)(addr) = value; -} - -static __inline void -bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, - bus_size_t offset, u_int32_t value, size_t count) -{ - bus_space_handle_t addr = bsh + offset; - - if (tag == X86_BUS_SPACE_IO) - for (; count != 0; count--, addr += 4) - outl(addr, value); - else - for (; count != 0; count--, addr += 4) - *(volatile u_int32_t *)(addr) = value; -} - -#if 0 /* Cause a link error for bus_space_set_region_8 */ -#define bus_space_set_region_8 !!! bus_space_set_region_8 unimplemented !!! -#endif - -/* - * Copy `count' 1, 2, 4, or 8 byte values from bus space starting - * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. - */ - -static __inline void bus_space_copy_region_1(bus_space_tag_t tag, - bus_space_handle_t bsh1, - bus_size_t off1, - bus_space_handle_t bsh2, - bus_size_t off2, size_t count); - -static __inline void bus_space_copy_region_2(bus_space_tag_t tag, - bus_space_handle_t bsh1, - bus_size_t off1, - bus_space_handle_t bsh2, - bus_size_t off2, size_t count); - -static __inline void bus_space_copy_region_4(bus_space_tag_t tag, - bus_space_handle_t bsh1, - bus_size_t off1, - bus_space_handle_t bsh2, - bus_size_t off2, size_t count); - -static __inline void -bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, - bus_size_t off1, bus_space_handle_t bsh2, - bus_size_t off2, size_t count) -{ - bus_space_handle_t addr1 = bsh1 + off1; - bus_space_handle_t addr2 = bsh2 + off2; - - if (tag == X86_BUS_SPACE_IO) { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1++, addr2++) - outb(addr2, inb(addr1)); - } else { - /* dest after src: copy backwards */ - for (addr1 += (count - 1), addr2 += (count - 1); - count != 0; count--, addr1--, addr2--) - outb(addr2, inb(addr1)); - } - } else { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1++, addr2++) - *(volatile u_int8_t *)(addr2) = - *(volatile u_int8_t *)(addr1); - } else { - /* dest after src: copy backwards */ - for (addr1 += (count - 1), addr2 += (count - 1); - count != 0; count--, addr1--, addr2--) - *(volatile u_int8_t *)(addr2) = - *(volatile u_int8_t *)(addr1); - } - } -} - -static __inline void -bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, - bus_size_t off1, bus_space_handle_t bsh2, - bus_size_t off2, size_t count) -{ - bus_space_handle_t addr1 = bsh1 + off1; - bus_space_handle_t addr2 = bsh2 + off2; - - if (tag == X86_BUS_SPACE_IO) { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1 += 2, addr2 += 2) - outw(addr2, inw(addr1)); - } else { - /* dest after src: copy backwards */ - for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); - count != 0; count--, addr1 -= 2, addr2 -= 2) - outw(addr2, inw(addr1)); - } - } else { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1 += 2, addr2 += 2) - *(volatile u_int16_t *)(addr2) = - *(volatile u_int16_t *)(addr1); - } else { - /* dest after src: copy backwards */ - for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); - count != 0; count--, addr1 -= 2, addr2 -= 2) - *(volatile u_int16_t *)(addr2) = - *(volatile u_int16_t *)(addr1); - } - } -} - -static __inline void -bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, - bus_size_t off1, bus_space_handle_t bsh2, - bus_size_t off2, size_t count) -{ - bus_space_handle_t addr1 = bsh1 + off1; - bus_space_handle_t addr2 = bsh2 + off2; - - if (tag == X86_BUS_SPACE_IO) { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1 += 4, addr2 += 4) - outl(addr2, inl(addr1)); - } else { - /* dest after src: copy backwards */ - for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); - count != 0; count--, addr1 -= 4, addr2 -= 4) - outl(addr2, inl(addr1)); - } - } else { - if (addr1 >= addr2) { - /* src after dest: copy forward */ - for (; count != 0; count--, addr1 += 4, addr2 += 4) - *(volatile u_int32_t *)(addr2) = - *(volatile u_int32_t *)(addr1); - } else { - /* dest after src: copy backwards */ - for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); - count != 0; count--, addr1 -= 4, addr2 -= 4) - *(volatile u_int32_t *)(addr2) = - *(volatile u_int32_t *)(addr1); - } - } -} - -#if 0 /* Cause a link error for bus_space_copy_8 */ -#define bus_space_copy_region_8 !!! bus_space_copy_region_8 unimplemented !!! -#endif - -/* - * Bus read/write barrier methods. - * - * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, - * bus_size_t offset, bus_size_t len, int flags); - * - * - * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than - * prevent reordering by the compiler; all Intel x86 processors currently - * retire operations outside the CPU in program order. - */ -#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ -#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ - -static __inline void -bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, - bus_size_t offset __unused, bus_size_t len __unused, int flags) -{ -#ifdef __GNUCLIKE_ASM - if (flags & BUS_SPACE_BARRIER_READ) -#ifdef __amd64__ - __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); -#else - __asm __volatile("lock; addl $0,0(%%esp)" : : : "memory"); -#endif - else - __compiler_membar(); -#endif -} - -#ifdef BUS_SPACE_NO_LEGACY -#undef inb -#undef outb -#define inb(a) compiler_error -#define inw(a) compiler_error -#define inl(a) compiler_error -#define outb(a, b) compiler_error -#define outw(a, b) compiler_error -#define outl(a, b) compiler_error -#endif - -#include <machine/bus_dma.h> - -/* - * Stream accesses are the same as normal accesses on x86; there are no - * supported bus systems with an endianess different from the host one. - */ -#define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) -#define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) -#define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) - -#define bus_space_read_multi_stream_1(t, h, o, a, c) \ - bus_space_read_multi_1((t), (h), (o), (a), (c)) -#define bus_space_read_multi_stream_2(t, h, o, a, c) \ - bus_space_read_multi_2((t), (h), (o), (a), (c)) -#define bus_space_read_multi_stream_4(t, h, o, a, c) \ - bus_space_read_multi_4((t), (h), (o), (a), (c)) - -#define bus_space_write_stream_1(t, h, o, v) \ - bus_space_write_1((t), (h), (o), (v)) -#define bus_space_write_stream_2(t, h, o, v) \ - bus_space_write_2((t), (h), (o), (v)) -#define bus_space_write_stream_4(t, h, o, v) \ - bus_space_write_4((t), (h), (o), (v)) - -#define bus_space_write_multi_stream_1(t, h, o, a, c) \ - bus_space_write_multi_1((t), (h), (o), (a), (c)) -#define bus_space_write_multi_stream_2(t, h, o, a, c) \ - bus_space_write_multi_2((t), (h), (o), (a), (c)) -#define bus_space_write_multi_stream_4(t, h, o, a, c) \ - bus_space_write_multi_4((t), (h), (o), (a), (c)) - -#define bus_space_set_multi_stream_1(t, h, o, v, c) \ - bus_space_set_multi_1((t), (h), (o), (v), (c)) -#define bus_space_set_multi_stream_2(t, h, o, v, c) \ - bus_space_set_multi_2((t), (h), (o), (v), (c)) -#define bus_space_set_multi_stream_4(t, h, o, v, c) \ - bus_space_set_multi_4((t), (h), (o), (v), (c)) - -#define bus_space_read_region_stream_1(t, h, o, a, c) \ - bus_space_read_region_1((t), (h), (o), (a), (c)) -#define bus_space_read_region_stream_2(t, h, o, a, c) \ - bus_space_read_region_2((t), (h), (o), (a), (c)) -#define bus_space_read_region_stream_4(t, h, o, a, c) \ - bus_space_read_region_4((t), (h), (o), (a), (c)) - -#define bus_space_write_region_stream_1(t, h, o, a, c) \ - bus_space_write_region_1((t), (h), (o), (a), (c)) -#define bus_space_write_region_stream_2(t, h, o, a, c) \ - bus_space_write_region_2((t), (h), (o), (a), (c)) -#define bus_space_write_region_stream_4(t, h, o, a, c) \ - bus_space_write_region_4((t), (h), (o), (a), (c)) - -#define bus_space_set_region_stream_1(t, h, o, v, c) \ - bus_space_set_region_1((t), (h), (o), (v), (c)) -#define bus_space_set_region_stream_2(t, h, o, v, c) \ - bus_space_set_region_2((t), (h), (o), (v), (c)) -#define bus_space_set_region_stream_4(t, h, o, v, c) \ - bus_space_set_region_4((t), (h), (o), (v), (c)) - -#define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ - bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) -#define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ - bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) -#define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ - bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) - -#endif /* _X86_BUS_H_ */ diff --git a/rtemsbsd/include/x86/specialreg.h b/rtemsbsd/include/x86/specialreg.h deleted file mode 100644 index f528bad5..00000000 --- a/rtemsbsd/include/x86/specialreg.h +++ /dev/null @@ -1,1143 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91 - * $FreeBSD$ - */ - -#ifndef _MACHINE_SPECIALREG_H_ -#define _MACHINE_SPECIALREG_H_ - -/* - * Bits in 386 special registers: - */ -#define CR0_PE 0x00000001 /* Protected mode Enable */ -#define CR0_MP 0x00000002 /* "Math" (fpu) Present */ -#define CR0_EM 0x00000004 /* EMulate FPU instructions. (trap ESC only) */ -#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */ -#define CR0_PG 0x80000000 /* PaGing enable */ - -/* - * Bits in 486 special registers: - */ -#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ -#define CR0_WP 0x00010000 /* Write Protect (honor page protect in - all modes) */ -#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */ -#define CR0_NW 0x20000000 /* Not Write-through */ -#define CR0_CD 0x40000000 /* Cache Disable */ - -#define CR3_PCID_SAVE 0x8000000000000000 -#define CR3_PCID_MASK 0xfff - -/* - * Bits in PPro special registers - */ -#define CR4_VME 0x00000001 /* Virtual 8086 mode extensions */ -#define CR4_PVI 0x00000002 /* Protected-mode virtual interrupts */ -#define CR4_TSD 0x00000004 /* Time stamp disable */ -#define CR4_DE 0x00000008 /* Debugging extensions */ -#define CR4_PSE 0x00000010 /* Page size extensions */ -#define CR4_PAE 0x00000020 /* Physical address extension */ -#define CR4_MCE 0x00000040 /* Machine check enable */ -#define CR4_PGE 0x00000080 /* Page global enable */ -#define CR4_PCE 0x00000100 /* Performance monitoring counter enable */ -#define CR4_FXSR 0x00000200 /* Fast FPU save/restore used by OS */ -#define CR4_XMM 0x00000400 /* enable SIMD/MMX2 to use except 16 */ -#define CR4_VMXE 0x00002000 /* enable VMX operation (Intel-specific) */ -#define CR4_FSGSBASE 0x00010000 /* Enable FS/GS BASE accessing instructions */ -#define CR4_PCIDE 0x00020000 /* Enable Context ID */ -#define CR4_XSAVE 0x00040000 /* XSETBV/XGETBV */ -#define CR4_SMEP 0x00100000 /* Supervisor-Mode Execution Prevention */ -#define CR4_SMAP 0x00200000 /* Supervisor-Mode Access Prevention */ -#define CR4_PKE 0x00400000 /* Protection Keys Enable */ - -/* - * Bits in AMD64 special registers. EFER is 64 bits wide. - */ -#define EFER_SCE 0x000000001 /* System Call Extensions (R/W) */ -#define EFER_LME 0x000000100 /* Long mode enable (R/W) */ -#define EFER_LMA 0x000000400 /* Long mode active (R) */ -#define EFER_NXE 0x000000800 /* PTE No-Execute bit enable (R/W) */ -#define EFER_SVM 0x000001000 /* SVM enable bit for AMD, reserved for Intel */ -#define EFER_LMSLE 0x000002000 /* Long Mode Segment Limit Enable */ -#define EFER_FFXSR 0x000004000 /* Fast FXSAVE/FSRSTOR */ -#define EFER_TCE 0x000008000 /* Translation Cache Extension */ - -/* - * Intel Extended Features registers - */ -#define XCR0 0 /* XFEATURE_ENABLED_MASK register */ - -#define XFEATURE_ENABLED_X87 0x00000001 -#define XFEATURE_ENABLED_SSE 0x00000002 -#define XFEATURE_ENABLED_YMM_HI128 0x00000004 -#define XFEATURE_ENABLED_AVX XFEATURE_ENABLED_YMM_HI128 -#define XFEATURE_ENABLED_BNDREGS 0x00000008 -#define XFEATURE_ENABLED_BNDCSR 0x00000010 -#define XFEATURE_ENABLED_OPMASK 0x00000020 -#define XFEATURE_ENABLED_ZMM_HI256 0x00000040 -#define XFEATURE_ENABLED_HI16_ZMM 0x00000080 - -#define XFEATURE_AVX \ - (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX) -#define XFEATURE_AVX512 \ - (XFEATURE_ENABLED_OPMASK | XFEATURE_ENABLED_ZMM_HI256 | \ - XFEATURE_ENABLED_HI16_ZMM) -#define XFEATURE_MPX \ - (XFEATURE_ENABLED_BNDREGS | XFEATURE_ENABLED_BNDCSR) - -/* - * CPUID instruction features register - */ -#define CPUID_FPU 0x00000001 -#define CPUID_VME 0x00000002 -#define CPUID_DE 0x00000004 -#define CPUID_PSE 0x00000008 -#define CPUID_TSC 0x00000010 -#define CPUID_MSR 0x00000020 -#define CPUID_PAE 0x00000040 -#define CPUID_MCE 0x00000080 -#define CPUID_CX8 0x00000100 -#define CPUID_APIC 0x00000200 -#define CPUID_B10 0x00000400 -#define CPUID_SEP 0x00000800 -#define CPUID_MTRR 0x00001000 -#define CPUID_PGE 0x00002000 -#define CPUID_MCA 0x00004000 -#define CPUID_CMOV 0x00008000 -#define CPUID_PAT 0x00010000 -#define CPUID_PSE36 0x00020000 -#define CPUID_PSN 0x00040000 -#define CPUID_CLFSH 0x00080000 -#define CPUID_B20 0x00100000 -#define CPUID_DS 0x00200000 -#define CPUID_ACPI 0x00400000 -#define CPUID_MMX 0x00800000 -#define CPUID_FXSR 0x01000000 -#define CPUID_SSE 0x02000000 -#define CPUID_XMM 0x02000000 -#define CPUID_SSE2 0x04000000 -#define CPUID_SS 0x08000000 -#define CPUID_HTT 0x10000000 -#define CPUID_TM 0x20000000 -#define CPUID_IA64 0x40000000 -#define CPUID_PBE 0x80000000 - -#define CPUID2_SSE3 0x00000001 -#define CPUID2_PCLMULQDQ 0x00000002 -#define CPUID2_DTES64 0x00000004 -#define CPUID2_MON 0x00000008 -#define CPUID2_DS_CPL 0x00000010 -#define CPUID2_VMX 0x00000020 -#define CPUID2_SMX 0x00000040 -#define CPUID2_EST 0x00000080 -#define CPUID2_TM2 0x00000100 -#define CPUID2_SSSE3 0x00000200 -#define CPUID2_CNXTID 0x00000400 -#define CPUID2_SDBG 0x00000800 -#define CPUID2_FMA 0x00001000 -#define CPUID2_CX16 0x00002000 -#define CPUID2_XTPR 0x00004000 -#define CPUID2_PDCM 0x00008000 -#define CPUID2_PCID 0x00020000 -#define CPUID2_DCA 0x00040000 -#define CPUID2_SSE41 0x00080000 -#define CPUID2_SSE42 0x00100000 -#define CPUID2_X2APIC 0x00200000 -#define CPUID2_MOVBE 0x00400000 -#define CPUID2_POPCNT 0x00800000 -#define CPUID2_TSCDLT 0x01000000 -#define CPUID2_AESNI 0x02000000 -#define CPUID2_XSAVE 0x04000000 -#define CPUID2_OSXSAVE 0x08000000 -#define CPUID2_AVX 0x10000000 -#define CPUID2_F16C 0x20000000 -#define CPUID2_RDRAND 0x40000000 -#define CPUID2_HV 0x80000000 - -/* - * Important bits in the Thermal and Power Management flags - * CPUID.6 EAX and ECX. - */ -#define CPUTPM1_SENSOR 0x00000001 -#define CPUTPM1_TURBO 0x00000002 -#define CPUTPM1_ARAT 0x00000004 -#define CPUTPM1_HWP 0x00000080 -#define CPUTPM1_HWP_NOTIFICATION 0x00000100 -#define CPUTPM1_HWP_ACTIVITY_WINDOW 0x00000200 -#define CPUTPM1_HWP_PERF_PREF 0x00000400 -#define CPUTPM1_HWP_PKG 0x00000800 -#define CPUTPM1_HWP_FLEXIBLE 0x00020000 -#define CPUTPM2_EFFREQ 0x00000001 - -/* Intel Processor Trace CPUID. */ - -/* Leaf 0 ebx. */ -#define CPUPT_CR3 (1 << 0) /* CR3 Filtering Support */ -#define CPUPT_PSB (1 << 1) /* Configurable PSB and Cycle-Accurate Mode Supported */ -#define CPUPT_IPF (1 << 2) /* IP Filtering and TraceStop supported */ -#define CPUPT_MTC (1 << 3) /* MTC Supported */ -#define CPUPT_PRW (1 << 4) /* PTWRITE Supported */ -#define CPUPT_PWR (1 << 5) /* Power Event Trace Supported */ - -/* Leaf 0 ecx. */ -#define CPUPT_TOPA (1 << 0) /* ToPA Output Supported */ -#define CPUPT_TOPA_MULTI (1 << 1) /* ToPA Tables Allow Multiple Output Entries */ -#define CPUPT_SINGLE (1 << 2) /* Single-Range Output Supported */ -#define CPUPT_TT_OUT (1 << 3) /* Output to Trace Transport Subsystem Supported */ -#define CPUPT_LINEAR_IP (1 << 31) /* IP Payloads are Linear IP, otherwise IP is effective */ - -/* Leaf 1 eax. */ -#define CPUPT_NADDR_S 0 /* Number of Address Ranges */ -#define CPUPT_NADDR_M (0x7 << CPUPT_NADDR_S) -#define CPUPT_MTC_BITMAP_S 16 /* Bitmap of supported MTC Period Encodings */ -#define CPUPT_MTC_BITMAP_M (0xffff << CPUPT_MTC_BITMAP_S) - -/* Leaf 1 ebx. */ -#define CPUPT_CT_BITMAP_S 0 /* Bitmap of supported Cycle Threshold values */ -#define CPUPT_CT_BITMAP_M (0xffff << CPUPT_CT_BITMAP_S) -#define CPUPT_PFE_BITMAP_S 16 /* Bitmap of supported Configurable PSB Frequency encoding */ -#define CPUPT_PFE_BITMAP_M (0xffff << CPUPT_PFE_BITMAP_S) - -/* - * Important bits in the AMD extended cpuid flags - */ -#define AMDID_SYSCALL 0x00000800 -#define AMDID_MP 0x00080000 -#define AMDID_NX 0x00100000 -#define AMDID_EXT_MMX 0x00400000 -#define AMDID_FFXSR 0x02000000 -#define AMDID_PAGE1GB 0x04000000 -#define AMDID_RDTSCP 0x08000000 -#define AMDID_LM 0x20000000 -#define AMDID_EXT_3DNOW 0x40000000 -#define AMDID_3DNOW 0x80000000 - -#define AMDID2_LAHF 0x00000001 -#define AMDID2_CMP 0x00000002 -#define AMDID2_SVM 0x00000004 -#define AMDID2_EXT_APIC 0x00000008 -#define AMDID2_CR8 0x00000010 -#define AMDID2_ABM 0x00000020 -#define AMDID2_SSE4A 0x00000040 -#define AMDID2_MAS 0x00000080 -#define AMDID2_PREFETCH 0x00000100 -#define AMDID2_OSVW 0x00000200 -#define AMDID2_IBS 0x00000400 -#define AMDID2_XOP 0x00000800 -#define AMDID2_SKINIT 0x00001000 -#define AMDID2_WDT 0x00002000 -#define AMDID2_LWP 0x00008000 -#define AMDID2_FMA4 0x00010000 -#define AMDID2_TCE 0x00020000 -#define AMDID2_NODE_ID 0x00080000 -#define AMDID2_TBM 0x00200000 -#define AMDID2_TOPOLOGY 0x00400000 -#define AMDID2_PCXC 0x00800000 -#define AMDID2_PNXC 0x01000000 -#define AMDID2_DBE 0x04000000 -#define AMDID2_PTSC 0x08000000 -#define AMDID2_PTSCEL2I 0x10000000 -#define AMDID2_MWAITX 0x20000000 - -/* - * CPUID instruction 1 eax info - */ -#define CPUID_STEPPING 0x0000000f -#define CPUID_MODEL 0x000000f0 -#define CPUID_FAMILY 0x00000f00 -#define CPUID_EXT_MODEL 0x000f0000 -#define CPUID_EXT_FAMILY 0x0ff00000 -#ifdef __i386__ -#define CPUID_TO_MODEL(id) \ - ((((id) & CPUID_MODEL) >> 4) | \ - ((((id) & CPUID_FAMILY) >= 0x600) ? \ - (((id) & CPUID_EXT_MODEL) >> 12) : 0)) -#define CPUID_TO_FAMILY(id) \ - ((((id) & CPUID_FAMILY) >> 8) + \ - ((((id) & CPUID_FAMILY) == 0xf00) ? \ - (((id) & CPUID_EXT_FAMILY) >> 20) : 0)) -#else -#define CPUID_TO_MODEL(id) \ - ((((id) & CPUID_MODEL) >> 4) | \ - (((id) & CPUID_EXT_MODEL) >> 12)) -#define CPUID_TO_FAMILY(id) \ - ((((id) & CPUID_FAMILY) >> 8) + \ - (((id) & CPUID_EXT_FAMILY) >> 20)) -#endif - -/* - * CPUID instruction 1 ebx info - */ -#define CPUID_BRAND_INDEX 0x000000ff -#define CPUID_CLFUSH_SIZE 0x0000ff00 -#define CPUID_HTT_CORES 0x00ff0000 -#define CPUID_LOCAL_APIC_ID 0xff000000 - -/* - * CPUID instruction 5 info - */ -#define CPUID5_MON_MIN_SIZE 0x0000ffff /* eax */ -#define CPUID5_MON_MAX_SIZE 0x0000ffff /* ebx */ -#define CPUID5_MON_MWAIT_EXT 0x00000001 /* ecx */ -#define CPUID5_MWAIT_INTRBREAK 0x00000002 /* ecx */ - -/* - * MWAIT cpu power states. Lower 4 bits are sub-states. - */ -#define MWAIT_C0 0xf0 -#define MWAIT_C1 0x00 -#define MWAIT_C2 0x10 -#define MWAIT_C3 0x20 -#define MWAIT_C4 0x30 - -/* - * MWAIT extensions. - */ -/* Interrupt breaks MWAIT even when masked. */ -#define MWAIT_INTRBREAK 0x00000001 - -/* - * CPUID instruction 6 ecx info - */ -#define CPUID_PERF_STAT 0x00000001 -#define CPUID_PERF_BIAS 0x00000008 - -/* - * CPUID instruction 0xb ebx info. - */ -#define CPUID_TYPE_INVAL 0 -#define CPUID_TYPE_SMT 1 -#define CPUID_TYPE_CORE 2 - -/* - * CPUID instruction 0xd Processor Extended State Enumeration Sub-leaf 1 - */ -#define CPUID_EXTSTATE_XSAVEOPT 0x00000001 -#define CPUID_EXTSTATE_XSAVEC 0x00000002 -#define CPUID_EXTSTATE_XINUSE 0x00000004 -#define CPUID_EXTSTATE_XSAVES 0x00000008 - -/* - * AMD extended function 8000_0007h ebx info - */ -#define AMDRAS_MCA_OF_RECOV 0x00000001 -#define AMDRAS_SUCCOR 0x00000002 -#define AMDRAS_HW_ASSERT 0x00000004 -#define AMDRAS_SCALABLE_MCA 0x00000008 -#define AMDRAS_PFEH_SUPPORT 0x00000010 - -/* - * AMD extended function 8000_0007h edx info - */ -#define AMDPM_TS 0x00000001 -#define AMDPM_FID 0x00000002 -#define AMDPM_VID 0x00000004 -#define AMDPM_TTP 0x00000008 -#define AMDPM_TM 0x00000010 -#define AMDPM_STC 0x00000020 -#define AMDPM_100MHZ_STEPS 0x00000040 -#define AMDPM_HW_PSTATE 0x00000080 -#define AMDPM_TSC_INVARIANT 0x00000100 -#define AMDPM_CPB 0x00000200 - -/* - * AMD extended function 8000_0008h ebx info (amd_extended_feature_extensions) - */ -#define AMDFEID_CLZERO 0x00000001 -#define AMDFEID_IRPERF 0x00000002 -#define AMDFEID_XSAVEERPTR 0x00000004 -#define AMDFEID_IBPB 0x00001000 -#define AMDFEID_IBRS 0x00004000 -#define AMDFEID_STIBP 0x00008000 -/* The below are only defined if the corresponding base feature above exists. */ -#define AMDFEID_IBRS_ALWAYSON 0x00010000 -#define AMDFEID_STIBP_ALWAYSON 0x00020000 -#define AMDFEID_PREFER_IBRS 0x00040000 -#define AMDFEID_SSBD 0x01000000 -/* SSBD via MSRC001_011F instead of MSR 0x48: */ -#define AMDFEID_VIRT_SSBD 0x02000000 -#define AMDFEID_SSB_NO 0x04000000 - -/* - * AMD extended function 8000_0008h ecx info - */ -#define AMDID_CMP_CORES 0x000000ff -#define AMDID_COREID_SIZE 0x0000f000 -#define AMDID_COREID_SIZE_SHIFT 12 - -/* - * CPUID instruction 7 Structured Extended Features, leaf 0 ebx info - */ -#define CPUID_STDEXT_FSGSBASE 0x00000001 -#define CPUID_STDEXT_TSC_ADJUST 0x00000002 -#define CPUID_STDEXT_SGX 0x00000004 -#define CPUID_STDEXT_BMI1 0x00000008 -#define CPUID_STDEXT_HLE 0x00000010 -#define CPUID_STDEXT_AVX2 0x00000020 -#define CPUID_STDEXT_FDP_EXC 0x00000040 -#define CPUID_STDEXT_SMEP 0x00000080 -#define CPUID_STDEXT_BMI2 0x00000100 -#define CPUID_STDEXT_ERMS 0x00000200 -#define CPUID_STDEXT_INVPCID 0x00000400 -#define CPUID_STDEXT_RTM 0x00000800 -#define CPUID_STDEXT_PQM 0x00001000 -#define CPUID_STDEXT_NFPUSG 0x00002000 -#define CPUID_STDEXT_MPX 0x00004000 -#define CPUID_STDEXT_PQE 0x00008000 -#define CPUID_STDEXT_AVX512F 0x00010000 -#define CPUID_STDEXT_AVX512DQ 0x00020000 -#define CPUID_STDEXT_RDSEED 0x00040000 -#define CPUID_STDEXT_ADX 0x00080000 -#define CPUID_STDEXT_SMAP 0x00100000 -#define CPUID_STDEXT_AVX512IFMA 0x00200000 -#define CPUID_STDEXT_PCOMMIT 0x00400000 -#define CPUID_STDEXT_CLFLUSHOPT 0x00800000 -#define CPUID_STDEXT_CLWB 0x01000000 -#define CPUID_STDEXT_PROCTRACE 0x02000000 -#define CPUID_STDEXT_AVX512PF 0x04000000 -#define CPUID_STDEXT_AVX512ER 0x08000000 -#define CPUID_STDEXT_AVX512CD 0x10000000 -#define CPUID_STDEXT_SHA 0x20000000 -#define CPUID_STDEXT_AVX512BW 0x40000000 -#define CPUID_STDEXT_AVX512VL 0x80000000 - -/* - * CPUID instruction 7 Structured Extended Features, leaf 0 ecx info - */ -#define CPUID_STDEXT2_PREFETCHWT1 0x00000001 -#define CPUID_STDEXT2_AVX512VBMI 0x00000002 -#define CPUID_STDEXT2_UMIP 0x00000004 -#define CPUID_STDEXT2_PKU 0x00000008 -#define CPUID_STDEXT2_OSPKE 0x00000010 -#define CPUID_STDEXT2_WAITPKG 0x00000020 -#define CPUID_STDEXT2_AVX512VBMI2 0x00000040 -#define CPUID_STDEXT2_GFNI 0x00000100 -#define CPUID_STDEXT2_VAES 0x00000200 -#define CPUID_STDEXT2_VPCLMULQDQ 0x00000400 -#define CPUID_STDEXT2_AVX512VNNI 0x00000800 -#define CPUID_STDEXT2_AVX512BITALG 0x00001000 -#define CPUID_STDEXT2_AVX512VPOPCNTDQ 0x00004000 -#define CPUID_STDEXT2_RDPID 0x00400000 -#define CPUID_STDEXT2_CLDEMOTE 0x02000000 -#define CPUID_STDEXT2_MOVDIRI 0x08000000 -#define CPUID_STDEXT2_MOVDIRI64B 0x10000000 -#define CPUID_STDEXT2_ENQCMD 0x20000000 -#define CPUID_STDEXT2_SGXLC 0x40000000 - -/* - * CPUID instruction 7 Structured Extended Features, leaf 0 edx info - */ -#define CPUID_STDEXT3_AVX5124VNNIW 0x00000004 -#define CPUID_STDEXT3_AVX5124FMAPS 0x00000008 -#define CPUID_STDEXT3_AVX512VP2INTERSECT 0x00000100 -#define CPUID_STDEXT3_MD_CLEAR 0x00000400 -#define CPUID_STDEXT3_TSXFA 0x00002000 -#define CPUID_STDEXT3_PCONFIG 0x00040000 -#define CPUID_STDEXT3_IBPB 0x04000000 -#define CPUID_STDEXT3_STIBP 0x08000000 -#define CPUID_STDEXT3_L1D_FLUSH 0x10000000 -#define CPUID_STDEXT3_ARCH_CAP 0x20000000 -#define CPUID_STDEXT3_CORE_CAP 0x40000000 -#define CPUID_STDEXT3_SSBD 0x80000000 - -/* MSR IA32_ARCH_CAP(ABILITIES) bits */ -#define IA32_ARCH_CAP_RDCL_NO 0x00000001 -#define IA32_ARCH_CAP_IBRS_ALL 0x00000002 -#define IA32_ARCH_CAP_RSBA 0x00000004 -#define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY 0x00000008 -#define IA32_ARCH_CAP_SSB_NO 0x00000010 -#define IA32_ARCH_CAP_MDS_NO 0x00000020 - -/* - * CPUID manufacturers identifiers - */ -#define AMD_VENDOR_ID "AuthenticAMD" -#define CENTAUR_VENDOR_ID "CentaurHauls" -#define CYRIX_VENDOR_ID "CyrixInstead" -#define INTEL_VENDOR_ID "GenuineIntel" -#define NEXGEN_VENDOR_ID "NexGenDriven" -#define NSC_VENDOR_ID "Geode by NSC" -#define RISE_VENDOR_ID "RiseRiseRise" -#define SIS_VENDOR_ID "SiS SiS SiS " -#define TRANSMETA_VENDOR_ID "GenuineTMx86" -#define UMC_VENDOR_ID "UMC UMC UMC " - -/* - * Model-specific registers for the i386 family - */ -#define MSR_P5_MC_ADDR 0x000 -#define MSR_P5_MC_TYPE 0x001 -#define MSR_TSC 0x010 -#define MSR_P5_CESR 0x011 -#define MSR_P5_CTR0 0x012 -#define MSR_P5_CTR1 0x013 -#define MSR_IA32_PLATFORM_ID 0x017 -#define MSR_APICBASE 0x01b -#define MSR_EBL_CR_POWERON 0x02a -#define MSR_TEST_CTL 0x033 -#define MSR_IA32_FEATURE_CONTROL 0x03a -#define MSR_IA32_SPEC_CTRL 0x048 -#define MSR_IA32_PRED_CMD 0x049 -#define MSR_BIOS_UPDT_TRIG 0x079 -#define MSR_BBL_CR_D0 0x088 -#define MSR_BBL_CR_D1 0x089 -#define MSR_BBL_CR_D2 0x08a -#define MSR_BIOS_SIGN 0x08b -#define MSR_PERFCTR0 0x0c1 -#define MSR_PERFCTR1 0x0c2 -#define MSR_PLATFORM_INFO 0x0ce -#define MSR_MPERF 0x0e7 -#define MSR_APERF 0x0e8 -#define MSR_IA32_EXT_CONFIG 0x0ee /* Undocumented. Core Solo/Duo only */ -#define MSR_MTRRcap 0x0fe -#define MSR_IA32_ARCH_CAP 0x10a -#define MSR_IA32_FLUSH_CMD 0x10b -#define MSR_TSX_FORCE_ABORT 0x10f -#define MSR_BBL_CR_ADDR 0x116 -#define MSR_BBL_CR_DECC 0x118 -#define MSR_BBL_CR_CTL 0x119 -#define MSR_BBL_CR_TRIG 0x11a -#define MSR_BBL_CR_BUSY 0x11b -#define MSR_BBL_CR_CTL3 0x11e -#define MSR_SYSENTER_CS_MSR 0x174 -#define MSR_SYSENTER_ESP_MSR 0x175 -#define MSR_SYSENTER_EIP_MSR 0x176 -#define MSR_MCG_CAP 0x179 -#define MSR_MCG_STATUS 0x17a -#define MSR_MCG_CTL 0x17b -#define MSR_EVNTSEL0 0x186 -#define MSR_EVNTSEL1 0x187 -#define MSR_THERM_CONTROL 0x19a -#define MSR_THERM_INTERRUPT 0x19b -#define MSR_THERM_STATUS 0x19c -#define MSR_IA32_MISC_ENABLE 0x1a0 -#define MSR_IA32_TEMPERATURE_TARGET 0x1a2 -#define MSR_TURBO_RATIO_LIMIT 0x1ad -#define MSR_TURBO_RATIO_LIMIT1 0x1ae -#define MSR_DEBUGCTLMSR 0x1d9 -#define MSR_LASTBRANCHFROMIP 0x1db -#define MSR_LASTBRANCHTOIP 0x1dc -#define MSR_LASTINTFROMIP 0x1dd -#define MSR_LASTINTTOIP 0x1de -#define MSR_ROB_CR_BKUPTMPDR6 0x1e0 -#define MSR_MTRRVarBase 0x200 -#define MSR_MTRR64kBase 0x250 -#define MSR_MTRR16kBase 0x258 -#define MSR_MTRR4kBase 0x268 -#define MSR_PAT 0x277 -#define MSR_MC0_CTL2 0x280 -#define MSR_MTRRdefType 0x2ff -#define MSR_MC0_CTL 0x400 -#define MSR_MC0_STATUS 0x401 -#define MSR_MC0_ADDR 0x402 -#define MSR_MC0_MISC 0x403 -#define MSR_MC1_CTL 0x404 -#define MSR_MC1_STATUS 0x405 -#define MSR_MC1_ADDR 0x406 -#define MSR_MC1_MISC 0x407 -#define MSR_MC2_CTL 0x408 -#define MSR_MC2_STATUS 0x409 -#define MSR_MC2_ADDR 0x40a -#define MSR_MC2_MISC 0x40b -#define MSR_MC3_CTL 0x40c -#define MSR_MC3_STATUS 0x40d -#define MSR_MC3_ADDR 0x40e -#define MSR_MC3_MISC 0x40f -#define MSR_MC4_CTL 0x410 -#define MSR_MC4_STATUS 0x411 -#define MSR_MC4_ADDR 0x412 -#define MSR_MC4_MISC 0x413 -#define MSR_RAPL_POWER_UNIT 0x606 -#define MSR_PKG_ENERGY_STATUS 0x611 -#define MSR_DRAM_ENERGY_STATUS 0x619 -#define MSR_PP0_ENERGY_STATUS 0x639 -#define MSR_PP1_ENERGY_STATUS 0x641 -#define MSR_PPERF 0x64e -#define MSR_TSC_DEADLINE 0x6e0 /* Writes are not serializing */ -#define MSR_IA32_PM_ENABLE 0x770 -#define MSR_IA32_HWP_CAPABILITIES 0x771 -#define MSR_IA32_HWP_REQUEST_PKG 0x772 -#define MSR_IA32_HWP_INTERRUPT 0x773 -#define MSR_IA32_HWP_REQUEST 0x774 -#define MSR_IA32_HWP_STATUS 0x777 - -/* - * VMX MSRs - */ -#define MSR_VMX_BASIC 0x480 -#define MSR_VMX_PINBASED_CTLS 0x481 -#define MSR_VMX_PROCBASED_CTLS 0x482 -#define MSR_VMX_EXIT_CTLS 0x483 -#define MSR_VMX_ENTRY_CTLS 0x484 -#define MSR_VMX_CR0_FIXED0 0x486 -#define MSR_VMX_CR0_FIXED1 0x487 -#define MSR_VMX_CR4_FIXED0 0x488 -#define MSR_VMX_CR4_FIXED1 0x489 -#define MSR_VMX_PROCBASED_CTLS2 0x48b -#define MSR_VMX_EPT_VPID_CAP 0x48c -#define MSR_VMX_TRUE_PINBASED_CTLS 0x48d -#define MSR_VMX_TRUE_PROCBASED_CTLS 0x48e -#define MSR_VMX_TRUE_EXIT_CTLS 0x48f -#define MSR_VMX_TRUE_ENTRY_CTLS 0x490 - -/* - * X2APIC MSRs. - * Writes are not serializing. - */ -#define MSR_APIC_000 0x800 -#define MSR_APIC_ID 0x802 -#define MSR_APIC_VERSION 0x803 -#define MSR_APIC_TPR 0x808 -#define MSR_APIC_EOI 0x80b -#define MSR_APIC_LDR 0x80d -#define MSR_APIC_SVR 0x80f -#define MSR_APIC_ISR0 0x810 -#define MSR_APIC_ISR1 0x811 -#define MSR_APIC_ISR2 0x812 -#define MSR_APIC_ISR3 0x813 -#define MSR_APIC_ISR4 0x814 -#define MSR_APIC_ISR5 0x815 -#define MSR_APIC_ISR6 0x816 -#define MSR_APIC_ISR7 0x817 -#define MSR_APIC_TMR0 0x818 -#define MSR_APIC_IRR0 0x820 -#define MSR_APIC_ESR 0x828 -#define MSR_APIC_LVT_CMCI 0x82F -#define MSR_APIC_ICR 0x830 -#define MSR_APIC_LVT_TIMER 0x832 -#define MSR_APIC_LVT_THERMAL 0x833 -#define MSR_APIC_LVT_PCINT 0x834 -#define MSR_APIC_LVT_LINT0 0x835 -#define MSR_APIC_LVT_LINT1 0x836 -#define MSR_APIC_LVT_ERROR 0x837 -#define MSR_APIC_ICR_TIMER 0x838 -#define MSR_APIC_CCR_TIMER 0x839 -#define MSR_APIC_DCR_TIMER 0x83e -#define MSR_APIC_SELF_IPI 0x83f - -#define MSR_IA32_XSS 0xda0 - -/* - * Intel Processor Trace (PT) MSRs. - */ -#define MSR_IA32_RTIT_OUTPUT_BASE 0x560 /* Trace Output Base Register (R/W) */ -#define MSR_IA32_RTIT_OUTPUT_MASK_PTRS 0x561 /* Trace Output Mask Pointers Register (R/W) */ -#define MSR_IA32_RTIT_CTL 0x570 /* Trace Control Register (R/W) */ -#define RTIT_CTL_TRACEEN (1 << 0) -#define RTIT_CTL_CYCEN (1 << 1) -#define RTIT_CTL_OS (1 << 2) -#define RTIT_CTL_USER (1 << 3) -#define RTIT_CTL_PWREVTEN (1 << 4) -#define RTIT_CTL_FUPONPTW (1 << 5) -#define RTIT_CTL_FABRICEN (1 << 6) -#define RTIT_CTL_CR3FILTER (1 << 7) -#define RTIT_CTL_TOPA (1 << 8) -#define RTIT_CTL_MTCEN (1 << 9) -#define RTIT_CTL_TSCEN (1 << 10) -#define RTIT_CTL_DISRETC (1 << 11) -#define RTIT_CTL_PTWEN (1 << 12) -#define RTIT_CTL_BRANCHEN (1 << 13) -#define RTIT_CTL_MTC_FREQ_S 14 -#define RTIT_CTL_MTC_FREQ(n) ((n) << RTIT_CTL_MTC_FREQ_S) -#define RTIT_CTL_MTC_FREQ_M (0xf << RTIT_CTL_MTC_FREQ_S) -#define RTIT_CTL_CYC_THRESH_S 19 -#define RTIT_CTL_CYC_THRESH_M (0xf << RTIT_CTL_CYC_THRESH_S) -#define RTIT_CTL_PSB_FREQ_S 24 -#define RTIT_CTL_PSB_FREQ_M (0xf << RTIT_CTL_PSB_FREQ_S) -#define RTIT_CTL_ADDR_CFG_S(n) (32 + (n) * 4) -#define RTIT_CTL_ADDR0_CFG_S 32 -#define RTIT_CTL_ADDR0_CFG_M (0xfULL << RTIT_CTL_ADDR0_CFG_S) -#define RTIT_CTL_ADDR1_CFG_S 36 -#define RTIT_CTL_ADDR1_CFG_M (0xfULL << RTIT_CTL_ADDR1_CFG_S) -#define RTIT_CTL_ADDR2_CFG_S 40 -#define RTIT_CTL_ADDR2_CFG_M (0xfULL << RTIT_CTL_ADDR2_CFG_S) -#define RTIT_CTL_ADDR3_CFG_S 44 -#define RTIT_CTL_ADDR3_CFG_M (0xfULL << RTIT_CTL_ADDR3_CFG_S) -#define MSR_IA32_RTIT_STATUS 0x571 /* Tracing Status Register (R/W) */ -#define RTIT_STATUS_FILTEREN (1 << 0) -#define RTIT_STATUS_CONTEXTEN (1 << 1) -#define RTIT_STATUS_TRIGGEREN (1 << 2) -#define RTIT_STATUS_ERROR (1 << 4) -#define RTIT_STATUS_STOPPED (1 << 5) -#define RTIT_STATUS_PACKETBYTECNT_S 32 -#define RTIT_STATUS_PACKETBYTECNT_M (0x1ffffULL << RTIT_STATUS_PACKETBYTECNT_S) -#define MSR_IA32_RTIT_CR3_MATCH 0x572 /* Trace Filter CR3 Match Register (R/W) */ -#define MSR_IA32_RTIT_ADDR_A(n) (0x580 + (n) * 2) -#define MSR_IA32_RTIT_ADDR_B(n) (0x581 + (n) * 2) -#define MSR_IA32_RTIT_ADDR0_A 0x580 /* Region 0 Start Address (R/W) */ -#define MSR_IA32_RTIT_ADDR0_B 0x581 /* Region 0 End Address (R/W) */ -#define MSR_IA32_RTIT_ADDR1_A 0x582 /* Region 1 Start Address (R/W) */ -#define MSR_IA32_RTIT_ADDR1_B 0x583 /* Region 1 End Address (R/W) */ -#define MSR_IA32_RTIT_ADDR2_A 0x584 /* Region 2 Start Address (R/W) */ -#define MSR_IA32_RTIT_ADDR2_B 0x585 /* Region 2 End Address (R/W) */ -#define MSR_IA32_RTIT_ADDR3_A 0x586 /* Region 3 Start Address (R/W) */ -#define MSR_IA32_RTIT_ADDR3_B 0x587 /* Region 3 End Address (R/W) */ - -/* Intel Processor Trace Table of Physical Addresses (ToPA). */ -#define TOPA_SIZE_S 6 -#define TOPA_SIZE_M (0xf << TOPA_SIZE_S) -#define TOPA_SIZE_4K (0 << TOPA_SIZE_S) -#define TOPA_SIZE_8K (1 << TOPA_SIZE_S) -#define TOPA_SIZE_16K (2 << TOPA_SIZE_S) -#define TOPA_SIZE_32K (3 << TOPA_SIZE_S) -#define TOPA_SIZE_64K (4 << TOPA_SIZE_S) -#define TOPA_SIZE_128K (5 << TOPA_SIZE_S) -#define TOPA_SIZE_256K (6 << TOPA_SIZE_S) -#define TOPA_SIZE_512K (7 << TOPA_SIZE_S) -#define TOPA_SIZE_1M (8 << TOPA_SIZE_S) -#define TOPA_SIZE_2M (9 << TOPA_SIZE_S) -#define TOPA_SIZE_4M (10 << TOPA_SIZE_S) -#define TOPA_SIZE_8M (11 << TOPA_SIZE_S) -#define TOPA_SIZE_16M (12 << TOPA_SIZE_S) -#define TOPA_SIZE_32M (13 << TOPA_SIZE_S) -#define TOPA_SIZE_64M (14 << TOPA_SIZE_S) -#define TOPA_SIZE_128M (15 << TOPA_SIZE_S) -#define TOPA_STOP (1 << 4) -#define TOPA_INT (1 << 2) -#define TOPA_END (1 << 0) - -/* - * Constants related to MSR's. - */ -#define APICBASE_RESERVED 0x000002ff -#define APICBASE_BSP 0x00000100 -#define APICBASE_X2APIC 0x00000400 -#define APICBASE_ENABLED 0x00000800 -#define APICBASE_ADDRESS 0xfffff000 - -/* MSR_IA32_FEATURE_CONTROL related */ -#define IA32_FEATURE_CONTROL_LOCK 0x01 /* lock bit */ -#define IA32_FEATURE_CONTROL_SMX_EN 0x02 /* enable VMX inside SMX */ -#define IA32_FEATURE_CONTROL_VMX_EN 0x04 /* enable VMX outside SMX */ - -/* MSR IA32_MISC_ENABLE */ -#define IA32_MISC_EN_FASTSTR 0x0000000000000001ULL -#define IA32_MISC_EN_ATCCE 0x0000000000000008ULL -#define IA32_MISC_EN_PERFMON 0x0000000000000080ULL -#define IA32_MISC_EN_PEBSU 0x0000000000001000ULL -#define IA32_MISC_EN_ESSTE 0x0000000000010000ULL -#define IA32_MISC_EN_MONE 0x0000000000040000ULL -#define IA32_MISC_EN_LIMCPUID 0x0000000000400000ULL -#define IA32_MISC_EN_xTPRD 0x0000000000800000ULL -#define IA32_MISC_EN_XDD 0x0000000400000000ULL - -/* - * IA32_SPEC_CTRL and IA32_PRED_CMD MSRs are described in the Intel' - * document 336996-001 Speculative Execution Side Channel Mitigations. - * - * AMD uses the same MSRs and bit definitions, as described in 111006-B - * "Indirect Branch Control Extension" and 124441 "Speculative Store Bypass - * Disable." - */ -/* MSR IA32_SPEC_CTRL */ -#define IA32_SPEC_CTRL_IBRS 0x00000001 -#define IA32_SPEC_CTRL_STIBP 0x00000002 -#define IA32_SPEC_CTRL_SSBD 0x00000004 - -/* MSR IA32_PRED_CMD */ -#define IA32_PRED_CMD_IBPB_BARRIER 0x0000000000000001ULL - -/* MSR IA32_FLUSH_CMD */ -#define IA32_FLUSH_CMD_L1D 0x00000001 - -/* MSR IA32_HWP_CAPABILITIES */ -#define IA32_HWP_CAPABILITIES_HIGHEST_PERFORMANCE(x) (((x) >> 0) & 0xff) -#define IA32_HWP_CAPABILITIES_GUARANTEED_PERFORMANCE(x) (((x) >> 8) & 0xff) -#define IA32_HWP_CAPABILITIES_EFFICIENT_PERFORMANCE(x) (((x) >> 16) & 0xff) -#define IA32_HWP_CAPABILITIES_LOWEST_PERFORMANCE(x) (((x) >> 24) & 0xff) - -/* MSR IA32_HWP_REQUEST */ -#define IA32_HWP_REQUEST_MINIMUM_VALID (1ULL << 63) -#define IA32_HWP_REQUEST_MAXIMUM_VALID (1ULL << 62) -#define IA32_HWP_REQUEST_DESIRED_VALID (1ULL << 61) -#define IA32_HWP_REQUEST_EPP_VALID (1ULL << 60) -#define IA32_HWP_REQUEST_ACTIVITY_WINDOW_VALID (1ULL << 59) -#define IA32_HWP_REQUEST_PACKAGE_CONTROL (1ULL << 42) -#define IA32_HWP_ACTIVITY_WINDOW (0x3ffULL << 32) -#define IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE (0xffULL << 24) -#define IA32_HWP_DESIRED_PERFORMANCE (0xffULL << 16) -#define IA32_HWP_REQUEST_MAXIMUM_PERFORMANCE (0xffULL << 8) -#define IA32_HWP_MINIMUM_PERFORMANCE (0xffULL << 0) - -/* - * PAT modes. - */ -#define PAT_UNCACHEABLE 0x00 -#define PAT_WRITE_COMBINING 0x01 -#define PAT_WRITE_THROUGH 0x04 -#define PAT_WRITE_PROTECTED 0x05 -#define PAT_WRITE_BACK 0x06 -#define PAT_UNCACHED 0x07 -#define PAT_VALUE(i, m) ((long long)(m) << (8 * (i))) -#define PAT_MASK(i) PAT_VALUE(i, 0xff) - -/* - * Constants related to MTRRs - */ -#define MTRR_UNCACHEABLE 0x00 -#define MTRR_WRITE_COMBINING 0x01 -#define MTRR_WRITE_THROUGH 0x04 -#define MTRR_WRITE_PROTECTED 0x05 -#define MTRR_WRITE_BACK 0x06 -#define MTRR_N64K 8 /* numbers of fixed-size entries */ -#define MTRR_N16K 16 -#define MTRR_N4K 64 -#define MTRR_CAP_WC 0x0000000000000400 -#define MTRR_CAP_FIXED 0x0000000000000100 -#define MTRR_CAP_VCNT 0x00000000000000ff -#define MTRR_DEF_ENABLE 0x0000000000000800 -#define MTRR_DEF_FIXED_ENABLE 0x0000000000000400 -#define MTRR_DEF_TYPE 0x00000000000000ff -#define MTRR_PHYSBASE_PHYSBASE 0x000ffffffffff000 -#define MTRR_PHYSBASE_TYPE 0x00000000000000ff -#define MTRR_PHYSMASK_PHYSMASK 0x000ffffffffff000 -#define MTRR_PHYSMASK_VALID 0x0000000000000800 - -/* - * Cyrix configuration registers, accessible as IO ports. - */ -#define CCR0 0xc0 /* Configuration control register 0 */ -#define CCR0_NC0 0x01 /* First 64K of each 1M memory region is - non-cacheable */ -#define CCR0_NC1 0x02 /* 640K-1M region is non-cacheable */ -#define CCR0_A20M 0x04 /* Enables A20M# input pin */ -#define CCR0_KEN 0x08 /* Enables KEN# input pin */ -#define CCR0_FLUSH 0x10 /* Enables FLUSH# input pin */ -#define CCR0_BARB 0x20 /* Flushes internal cache when entering hold - state */ -#define CCR0_CO 0x40 /* Cache org: 1=direct mapped, 0=2x set - assoc */ -#define CCR0_SUSPEND 0x80 /* Enables SUSP# and SUSPA# pins */ - -#define CCR1 0xc1 /* Configuration control register 1 */ -#define CCR1_RPL 0x01 /* Enables RPLSET and RPLVAL# pins */ -#define CCR1_SMI 0x02 /* Enables SMM pins */ -#define CCR1_SMAC 0x04 /* System management memory access */ -#define CCR1_MMAC 0x08 /* Main memory access */ -#define CCR1_NO_LOCK 0x10 /* Negate LOCK# */ -#define CCR1_SM3 0x80 /* SMM address space address region 3 */ - -#define CCR2 0xc2 -#define CCR2_WB 0x02 /* Enables WB cache interface pins */ -#define CCR2_SADS 0x02 /* Slow ADS */ -#define CCR2_LOCK_NW 0x04 /* LOCK NW Bit */ -#define CCR2_SUSP_HLT 0x08 /* Suspend on HALT */ -#define CCR2_WT1 0x10 /* WT region 1 */ -#define CCR2_WPR1 0x10 /* Write-protect region 1 */ -#define CCR2_BARB 0x20 /* Flushes write-back cache when entering - hold state. */ -#define CCR2_BWRT 0x40 /* Enables burst write cycles */ -#define CCR2_USE_SUSP 0x80 /* Enables suspend pins */ - -#define CCR3 0xc3 -#define CCR3_SMILOCK 0x01 /* SMM register lock */ -#define CCR3_NMI 0x02 /* Enables NMI during SMM */ -#define CCR3_LINBRST 0x04 /* Linear address burst cycles */ -#define CCR3_SMMMODE 0x08 /* SMM Mode */ -#define CCR3_MAPEN0 0x10 /* Enables Map0 */ -#define CCR3_MAPEN1 0x20 /* Enables Map1 */ -#define CCR3_MAPEN2 0x40 /* Enables Map2 */ -#define CCR3_MAPEN3 0x80 /* Enables Map3 */ - -#define CCR4 0xe8 -#define CCR4_IOMASK 0x07 -#define CCR4_MEM 0x08 /* Enables momory bypassing */ -#define CCR4_DTE 0x10 /* Enables directory table entry cache */ -#define CCR4_FASTFPE 0x20 /* Fast FPU exception */ -#define CCR4_CPUID 0x80 /* Enables CPUID instruction */ - -#define CCR5 0xe9 -#define CCR5_WT_ALLOC 0x01 /* Write-through allocate */ -#define CCR5_SLOP 0x02 /* LOOP instruction slowed down */ -#define CCR5_LBR1 0x10 /* Local bus region 1 */ -#define CCR5_ARREN 0x20 /* Enables ARR region */ - -#define CCR6 0xea - -#define CCR7 0xeb - -/* Performance Control Register (5x86 only). */ -#define PCR0 0x20 -#define PCR0_RSTK 0x01 /* Enables return stack */ -#define PCR0_BTB 0x02 /* Enables branch target buffer */ -#define PCR0_LOOP 0x04 /* Enables loop */ -#define PCR0_AIS 0x08 /* Enables all instrcutions stalled to - serialize pipe. */ -#define PCR0_MLR 0x10 /* Enables reordering of misaligned loads */ -#define PCR0_BTBRT 0x40 /* Enables BTB test register. */ -#define PCR0_LSSER 0x80 /* Disable reorder */ - -/* Device Identification Registers */ -#define DIR0 0xfe -#define DIR1 0xff - -/* - * Machine Check register constants. - */ -#define MCG_CAP_COUNT 0x000000ff -#define MCG_CAP_CTL_P 0x00000100 -#define MCG_CAP_EXT_P 0x00000200 -#define MCG_CAP_CMCI_P 0x00000400 -#define MCG_CAP_TES_P 0x00000800 -#define MCG_CAP_EXT_CNT 0x00ff0000 -#define MCG_CAP_SER_P 0x01000000 -#define MCG_STATUS_RIPV 0x00000001 -#define MCG_STATUS_EIPV 0x00000002 -#define MCG_STATUS_MCIP 0x00000004 -#define MCG_CTL_ENABLE 0xffffffffffffffff -#define MCG_CTL_DISABLE 0x0000000000000000 -#define MSR_MC_CTL(x) (MSR_MC0_CTL + (x) * 4) -#define MSR_MC_STATUS(x) (MSR_MC0_STATUS + (x) * 4) -#define MSR_MC_ADDR(x) (MSR_MC0_ADDR + (x) * 4) -#define MSR_MC_MISC(x) (MSR_MC0_MISC + (x) * 4) -#define MSR_MC_CTL2(x) (MSR_MC0_CTL2 + (x)) /* If MCG_CAP_CMCI_P */ -#define MC_STATUS_MCA_ERROR 0x000000000000ffff -#define MC_STATUS_MODEL_ERROR 0x00000000ffff0000 -#define MC_STATUS_OTHER_INFO 0x01ffffff00000000 -#define MC_STATUS_COR_COUNT 0x001fffc000000000 /* If MCG_CAP_CMCI_P */ -#define MC_STATUS_TES_STATUS 0x0060000000000000 /* If MCG_CAP_TES_P */ -#define MC_STATUS_AR 0x0080000000000000 /* If MCG_CAP_TES_P */ -#define MC_STATUS_S 0x0100000000000000 /* If MCG_CAP_TES_P */ -#define MC_STATUS_PCC 0x0200000000000000 -#define MC_STATUS_ADDRV 0x0400000000000000 -#define MC_STATUS_MISCV 0x0800000000000000 -#define MC_STATUS_EN 0x1000000000000000 -#define MC_STATUS_UC 0x2000000000000000 -#define MC_STATUS_OVER 0x4000000000000000 -#define MC_STATUS_VAL 0x8000000000000000 -#define MC_MISC_RA_LSB 0x000000000000003f /* If MCG_CAP_SER_P */ -#define MC_MISC_ADDRESS_MODE 0x00000000000001c0 /* If MCG_CAP_SER_P */ -#define MC_CTL2_THRESHOLD 0x0000000000007fff -#define MC_CTL2_CMCI_EN 0x0000000040000000 -#define MC_AMDNB_BANK 4 -#define MC_MISC_AMD_VAL 0x8000000000000000 /* Counter presence valid */ -#define MC_MISC_AMD_CNTP 0x4000000000000000 /* Counter present */ -#define MC_MISC_AMD_LOCK 0x2000000000000000 /* Register locked */ -#define MC_MISC_AMD_INTP 0x1000000000000000 /* Int. type can generate interrupts */ -#define MC_MISC_AMD_LVT_MASK 0x00f0000000000000 /* Extended LVT offset */ -#define MC_MISC_AMD_LVT_SHIFT 52 -#define MC_MISC_AMD_CNTEN 0x0008000000000000 /* Counter enabled */ -#define MC_MISC_AMD_INT_MASK 0x0006000000000000 /* Interrupt type */ -#define MC_MISC_AMD_INT_LVT 0x0002000000000000 /* Interrupt via Extended LVT */ -#define MC_MISC_AMD_INT_SMI 0x0004000000000000 /* SMI */ -#define MC_MISC_AMD_OVERFLOW 0x0001000000000000 /* Counter overflow */ -#define MC_MISC_AMD_CNT_MASK 0x00000fff00000000 /* Counter value */ -#define MC_MISC_AMD_CNT_SHIFT 32 -#define MC_MISC_AMD_CNT_MAX 0xfff -#define MC_MISC_AMD_PTR_MASK 0x00000000ff000000 /* Pointer to additional registers */ -#define MC_MISC_AMD_PTR_SHIFT 24 - -/* AMD Scalable MCA */ -#define MSR_SMCA_MC0_CTL 0xc0002000 -#define MSR_SMCA_MC0_STATUS 0xc0002001 -#define MSR_SMCA_MC0_ADDR 0xc0002002 -#define MSR_SMCA_MC0_MISC0 0xc0002003 -#define MSR_SMCA_MC_CTL(x) (MSR_SMCA_MC0_CTL + 0x10 * (x)) -#define MSR_SMCA_MC_STATUS(x) (MSR_SMCA_MC0_STATUS + 0x10 * (x)) -#define MSR_SMCA_MC_ADDR(x) (MSR_SMCA_MC0_ADDR + 0x10 * (x)) -#define MSR_SMCA_MC_MISC(x) (MSR_SMCA_MC0_MISC0 + 0x10 * (x)) - -/* - * The following four 3-byte registers control the non-cacheable regions. - * These registers must be written as three separate bytes. - * - * NCRx+0: A31-A24 of starting address - * NCRx+1: A23-A16 of starting address - * NCRx+2: A15-A12 of starting address | NCR_SIZE_xx. - * - * The non-cacheable region's starting address must be aligned to the - * size indicated by the NCR_SIZE_xx field. - */ -#define NCR1 0xc4 -#define NCR2 0xc7 -#define NCR3 0xca -#define NCR4 0xcd - -#define NCR_SIZE_0K 0 -#define NCR_SIZE_4K 1 -#define NCR_SIZE_8K 2 -#define NCR_SIZE_16K 3 -#define NCR_SIZE_32K 4 -#define NCR_SIZE_64K 5 -#define NCR_SIZE_128K 6 -#define NCR_SIZE_256K 7 -#define NCR_SIZE_512K 8 -#define NCR_SIZE_1M 9 -#define NCR_SIZE_2M 10 -#define NCR_SIZE_4M 11 -#define NCR_SIZE_8M 12 -#define NCR_SIZE_16M 13 -#define NCR_SIZE_32M 14 -#define NCR_SIZE_4G 15 - -/* - * The address region registers are used to specify the location and - * size for the eight address regions. - * - * ARRx + 0: A31-A24 of start address - * ARRx + 1: A23-A16 of start address - * ARRx + 2: A15-A12 of start address | ARR_SIZE_xx - */ -#define ARR0 0xc4 -#define ARR1 0xc7 -#define ARR2 0xca -#define ARR3 0xcd -#define ARR4 0xd0 -#define ARR5 0xd3 -#define ARR6 0xd6 -#define ARR7 0xd9 - -#define ARR_SIZE_0K 0 -#define ARR_SIZE_4K 1 -#define ARR_SIZE_8K 2 -#define ARR_SIZE_16K 3 -#define ARR_SIZE_32K 4 -#define ARR_SIZE_64K 5 -#define ARR_SIZE_128K 6 -#define ARR_SIZE_256K 7 -#define ARR_SIZE_512K 8 -#define ARR_SIZE_1M 9 -#define ARR_SIZE_2M 10 -#define ARR_SIZE_4M 11 -#define ARR_SIZE_8M 12 -#define ARR_SIZE_16M 13 -#define ARR_SIZE_32M 14 -#define ARR_SIZE_4G 15 - -/* - * The region control registers specify the attributes associated with - * the ARRx addres regions. - */ -#define RCR0 0xdc -#define RCR1 0xdd -#define RCR2 0xde -#define RCR3 0xdf -#define RCR4 0xe0 -#define RCR5 0xe1 -#define RCR6 0xe2 -#define RCR7 0xe3 - -#define RCR_RCD 0x01 /* Disables caching for ARRx (x = 0-6). */ -#define RCR_RCE 0x01 /* Enables caching for ARR7. */ -#define RCR_WWO 0x02 /* Weak write ordering. */ -#define RCR_WL 0x04 /* Weak locking. */ -#define RCR_WG 0x08 /* Write gathering. */ -#define RCR_WT 0x10 /* Write-through. */ -#define RCR_NLB 0x20 /* LBA# pin is not asserted. */ - -/* AMD Write Allocate Top-Of-Memory and Control Register */ -#define AMD_WT_ALLOC_TME 0x40000 /* top-of-memory enable */ -#define AMD_WT_ALLOC_PRE 0x20000 /* programmable range enable */ -#define AMD_WT_ALLOC_FRE 0x10000 /* fixed (A0000-FFFFF) range enable */ - -/* AMD64 MSR's */ -#define MSR_EFER 0xc0000080 /* extended features */ -#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target/cs/ss */ -#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target rip */ -#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target rip */ -#define MSR_SF_MASK 0xc0000084 /* syscall flags mask */ -#define MSR_FSBASE 0xc0000100 /* base address of the %fs "segment" */ -#define MSR_GSBASE 0xc0000101 /* base address of the %gs "segment" */ -#define MSR_KGSBASE 0xc0000102 /* base address of the kernel %gs */ -#define MSR_TSC_AUX 0xc0000103 -#define MSR_PERFEVSEL0 0xc0010000 -#define MSR_PERFEVSEL1 0xc0010001 -#define MSR_PERFEVSEL2 0xc0010002 -#define MSR_PERFEVSEL3 0xc0010003 -#define MSR_K7_PERFCTR0 0xc0010004 -#define MSR_K7_PERFCTR1 0xc0010005 -#define MSR_K7_PERFCTR2 0xc0010006 -#define MSR_K7_PERFCTR3 0xc0010007 -#define MSR_SYSCFG 0xc0010010 -#define MSR_HWCR 0xc0010015 -#define MSR_IORRBASE0 0xc0010016 -#define MSR_IORRMASK0 0xc0010017 -#define MSR_IORRBASE1 0xc0010018 -#define MSR_IORRMASK1 0xc0010019 -#define MSR_TOP_MEM 0xc001001a /* boundary for ram below 4G */ -#define MSR_TOP_MEM2 0xc001001d /* boundary for ram above 4G */ -#define MSR_NB_CFG1 0xc001001f /* NB configuration 1 */ -#define MSR_K8_UCODE_UPDATE 0xc0010020 /* update microcode */ -#define MSR_MC0_CTL_MASK 0xc0010044 -#define MSR_P_STATE_LIMIT 0xc0010061 /* P-state Current Limit Register */ -#define MSR_P_STATE_CONTROL 0xc0010062 /* P-state Control Register */ -#define MSR_P_STATE_STATUS 0xc0010063 /* P-state Status Register */ -#define MSR_P_STATE_CONFIG(n) (0xc0010064 + (n)) /* P-state Config */ -#define MSR_SMM_ADDR 0xc0010112 /* SMM TSEG base address */ -#define MSR_SMM_MASK 0xc0010113 /* SMM TSEG address mask */ -#define MSR_VM_CR 0xc0010114 /* SVM: feature control */ -#define MSR_VM_HSAVE_PA 0xc0010117 /* SVM: host save area address */ -#define MSR_AMD_CPUID07 0xc0011002 /* CPUID 07 %ebx override */ -#define MSR_EXTFEATURES 0xc0011005 /* Extended CPUID Features override */ -#define MSR_LS_CFG 0xc0011020 -#define MSR_IC_CFG 0xc0011021 /* Instruction Cache Configuration */ - -/* MSR_VM_CR related */ -#define VM_CR_SVMDIS 0x10 /* SVM: disabled by BIOS */ - -/* VIA ACE crypto featureset: for via_feature_rng */ -#define VIA_HAS_RNG 1 /* cpu has RNG */ - -/* VIA ACE crypto featureset: for via_feature_xcrypt */ -#define VIA_HAS_AES 1 /* cpu has AES */ -#define VIA_HAS_SHA 2 /* cpu has SHA1 & SHA256 */ -#define VIA_HAS_MM 4 /* cpu has RSA instructions */ -#define VIA_HAS_AESCTR 8 /* cpu has AES-CTR instructions */ - -/* Centaur Extended Feature flags */ -#define VIA_CPUID_HAS_RNG 0x000004 -#define VIA_CPUID_DO_RNG 0x000008 -#define VIA_CPUID_HAS_ACE 0x000040 -#define VIA_CPUID_DO_ACE 0x000080 -#define VIA_CPUID_HAS_ACE2 0x000100 -#define VIA_CPUID_DO_ACE2 0x000200 -#define VIA_CPUID_HAS_PHE 0x000400 -#define VIA_CPUID_DO_PHE 0x000800 -#define VIA_CPUID_HAS_PMM 0x001000 -#define VIA_CPUID_DO_PMM 0x002000 - -/* VIA ACE xcrypt-* instruction context control options */ -#define VIA_CRYPT_CWLO_ROUND_M 0x0000000f -#define VIA_CRYPT_CWLO_ALG_M 0x00000070 -#define VIA_CRYPT_CWLO_ALG_AES 0x00000000 -#define VIA_CRYPT_CWLO_KEYGEN_M 0x00000080 -#define VIA_CRYPT_CWLO_KEYGEN_HW 0x00000000 -#define VIA_CRYPT_CWLO_KEYGEN_SW 0x00000080 -#define VIA_CRYPT_CWLO_NORMAL 0x00000000 -#define VIA_CRYPT_CWLO_INTERMEDIATE 0x00000100 -#define VIA_CRYPT_CWLO_ENCRYPT 0x00000000 -#define VIA_CRYPT_CWLO_DECRYPT 0x00000200 -#define VIA_CRYPT_CWLO_KEY128 0x0000000a /* 128bit, 10 rds */ -#define VIA_CRYPT_CWLO_KEY192 0x0000040c /* 192bit, 12 rds */ -#define VIA_CRYPT_CWLO_KEY256 0x0000080e /* 256bit, 15 rds */ - -#endif /* !_MACHINE_SPECIALREG_H_ */ diff --git a/rtemsbsd/nfsclient/nfs.c b/rtemsbsd/nfsclient/nfs.c index 3b8a5925..e9e83abb 100644 --- a/rtemsbsd/nfsclient/nfs.c +++ b/rtemsbsd/nfsclient/nfs.c @@ -2058,19 +2058,19 @@ static int nfs_rmnod( return rv; } -static int nfs_utime( +static int nfs_utimens( const rtems_filesystem_location_info_t *pathloc, /* IN */ - time_t actime, /* IN */ - time_t modtime /* IN */ + struct timespec times[2] /* IN */ + ) { sattr arg; /* TODO: add rtems EPOCH - UNIX EPOCH seconds */ - arg.atime.seconds = actime; - arg.atime.useconds = 0; - arg.mtime.seconds = modtime; - arg.mtime.useconds = 0; + arg.atime.seconds = times[0].tv_sec; + arg.atime.useconds = times[0].tv_nsec / 1000; + arg.mtime.seconds = times[1].tv_sec; + arg.mtime.useconds = times[1].tv_nsec / 1000; return nfs_sattr(pathloc->node_access, &arg, SATTR_ATIME | SATTR_MTIME); } @@ -2262,25 +2262,25 @@ sattr arg; } const struct _rtems_filesystem_operations_table nfs_fs_ops = { - .lock_h = nfs_lock, - .unlock_h = nfs_unlock, - .eval_path_h = nfs_eval_path, - .link_h = nfs_link, + .lock_h = nfs_lock, + .unlock_h = nfs_unlock, + .eval_path_h = nfs_eval_path, + .link_h = nfs_link, .are_nodes_equal_h = nfs_are_nodes_equal, - .mknod_h = nfs_mknod, - .rmnod_h = nfs_rmnod, - .fchmod_h = nfs_fchmod, - .chown_h = nfs_chown, - .clonenod_h = nfs_clonenode, - .freenod_h = nfs_freenode, - .mount_h = rtems_filesystem_default_mount, - .unmount_h = rtems_filesystem_default_unmount, - .fsunmount_me_h = nfs_fsunmount_me, - .utime_h = nfs_utime, - .symlink_h = nfs_symlink, - .readlink_h = nfs_readlink, - .rename_h = nfs_rename, - .statvfs_h = rtems_filesystem_default_statvfs + .mknod_h = nfs_mknod, + .rmnod_h = nfs_rmnod, + .fchmod_h = nfs_fchmod, + .chown_h = nfs_chown, + .clonenod_h = nfs_clonenode, + .freenod_h = nfs_freenode, + .mount_h = rtems_filesystem_default_mount, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = nfs_fsunmount_me, + .utimens_h = nfs_utimens, + .symlink_h = nfs_symlink, + .readlink_h = nfs_readlink, + .rename_h = nfs_rename, + .statvfs_h = rtems_filesystem_default_statvfs }; /***************************************** @@ -3114,7 +3114,7 @@ rtems_filesystem_location_info_t old; rtems_filesystem_current->location = old; } rtems_semaphore_release(rpa->sync); - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } diff --git a/rtemsbsd/pppd/rtemspppd.c b/rtemsbsd/pppd/rtemspppd.c index cf237a81..c001eff5 100644 --- a/rtemsbsd/pppd/rtemspppd.c +++ b/rtemsbsd/pppd/rtemspppd.c @@ -71,7 +71,7 @@ static rtems_task pppTask(rtems_task_argument arg) /* terminate myself */ rtems_pppd_taskid = 0; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } int rtems_pppd_initialize(void) diff --git a/rtemsbsd/rtems/program-internal.h b/rtemsbsd/rtems/program-internal.h index da817130..2104c064 100644 --- a/rtemsbsd/rtems/program-internal.h +++ b/rtemsbsd/rtems/program-internal.h @@ -60,6 +60,12 @@ struct program_allocmem_item { LIST_ENTRY(program_allocmem_item) entries; }; +struct program_destructor { + void (*destructor)(void *); + void *arg; + LIST_ENTRY(program_destructor) link; +}; + struct rtems_bsd_program_control { void *context; int exit_code; @@ -68,6 +74,7 @@ struct rtems_bsd_program_control { LIST_HEAD(, program_fd_item) open_fd; LIST_HEAD(, program_file_item) open_file; LIST_HEAD(, program_allocmem_item) allocated_mem; + LIST_HEAD(, program_destructor) destructors; }; struct rtems_bsd_program_control *rtems_bsd_program_get_control_or_null(void); diff --git a/rtemsbsd/rtems/rtems-bsd-racoon.c b/rtemsbsd/rtems/rtems-bsd-racoon.c index c7ea3594..e6e6205c 100644 --- a/rtemsbsd/rtems/rtems-bsd-racoon.c +++ b/rtemsbsd/rtems/rtems-bsd-racoon.c @@ -75,7 +75,7 @@ racoon_task(rtems_task_argument arg) } clean_up_args(args); - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } rtems_status_code diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c index 23ee15db..8ffaa914 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf-net.c @@ -103,7 +103,9 @@ cloned_interfaces(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) "ifconfig", aa->argv[arg], "create", NULL }; rtems_bsd_rc_conf_print_cmd(rc_conf, "cloning_interfaces", 3, ifconfg_args); - rtems_bsd_command_ifconfig(3, (char**) ifconfg_args); + if (rtems_bsd_command_ifconfig(3, (char**) ifconfg_args)) { + return -1; + } } return 0; @@ -377,7 +379,7 @@ defaultrouter(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa, bool memset(&sin, 0, sizeof(sin)); memset(&rti_info[0], 0, sizeof(rti_info)); sin.sin_family = AF_INET; - inet_pton(AF_INET, "0.0.0.0", &sin.sin_addr); + (void) inet_pton(AF_INET, "0.0.0.0", &sin.sin_addr); r = rtems_get_route(&sin, rti_info); if (r == 0 && rti_info[RTAX_GATEWAY] != NULL) { @@ -710,9 +712,9 @@ run_dhcp(rtems_bsd_rc_conf* rc_conf, rtems_bsd_rc_conf_argc_argv* aa) } dd->config.priority = priority; - rtems_bsd_rc_conf_find(rc_conf, "dhcpcd_options", dd->argc_argv); + r = rtems_bsd_rc_conf_find(rc_conf, "dhcpcd_options", dd->argc_argv); - if (dd->argc_argv->argc > 0) { + if (r == 0 && dd->argc_argv->argc > 0) { dd->config.argc = dd->argc_argv->argc; dd->config.argv = dd->argc_argv->argv; } diff --git a/rtemsbsd/rtems/rtems-bsd-rc-conf.c b/rtemsbsd/rtems/rtems-bsd-rc-conf.c index 36f90a1d..88d98c3e 100644 --- a/rtemsbsd/rtems/rtems-bsd-rc-conf.c +++ b/rtemsbsd/rtems/rtems-bsd-rc-conf.c @@ -260,12 +260,14 @@ rc_conf_create(rtems_bsd_rc_conf** rc_conf, */ length = strnlen(text, RTEMS_BSD_RC_CONF_MAX_SIZE); if (length == RTEMS_BSD_RC_CONF_MAX_SIZE) { + free(_rc_conf); errno = E2BIG; return -1; } copy = strdup(text); if (copy == NULL) { + free(_rc_conf); errno = ENOMEM; return -1; } @@ -286,6 +288,7 @@ rc_conf_create(rtems_bsd_rc_conf** rc_conf, lines = malloc(sizeof(char*) * line_count); if (lines == NULL) { free(copy); + free(_rc_conf); errno = ENOMEM; return -1; } @@ -335,6 +338,13 @@ rc_conf_create(rtems_bsd_rc_conf** rc_conf, if (timeout >= 0) _rc_conf->waiter = rtems_task_self(); + if (_rc_conf->name == NULL) { + free((void*) _rc_conf->lines); + free((void*) _rc_conf->data); + free(_rc_conf); + return -1; + } + /* * Create the lock. */ @@ -343,6 +353,7 @@ rc_conf_create(rtems_bsd_rc_conf** rc_conf, free((void*) _rc_conf->name); free((void*) _rc_conf->lines); free((void*) _rc_conf->data); + free(_rc_conf); return -1; } @@ -714,6 +725,7 @@ rc_conf_worker(rtems_task_argument task_argument) rtems_chain_node* node = rtems_chain_first(&services); int r = 0; int error; + bool rc_conf_verbose; /* * Check for a syslog priority before any services are run. @@ -748,6 +760,8 @@ rc_conf_worker(rtems_task_argument task_argument) if (r < 0) rc_conf->error_code = error; + rc_conf_verbose = rc_conf->verbose; + /* * If there is a waiter signal else clean up because the waiter has gone. */ @@ -760,10 +774,10 @@ rc_conf_worker(rtems_task_argument task_argument) rc_conf_destroy(rc_conf); } - if (rc_conf->verbose) + if (rc_conf_verbose) printf("rc.conf: finished\n"); - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } int @@ -793,6 +807,7 @@ rtems_bsd_run_rc_conf_script(const char* name, if (sc != RTEMS_SUCCESSFUL) { fprintf(stderr, "error: %s: get priority: %s\n", name, rtems_status_text(sc)); + rc_conf_destroy(rc_conf); errno = EIO; return -1; } @@ -805,6 +820,7 @@ rtems_bsd_run_rc_conf_script(const char* name, &worker); if (sc != RTEMS_SUCCESSFUL) { fprintf (stderr, "error: worker create: %s", rtems_status_text(sc)); + rc_conf_destroy(rc_conf); errno = EIO; return -1; } @@ -814,6 +830,7 @@ rtems_bsd_run_rc_conf_script(const char* name, (rtems_task_argument) rc_conf); if (sc != RTEMS_SUCCESSFUL) { fprintf (stderr, "error: worker start: %s", rtems_status_text(sc)); + rc_conf_destroy(rc_conf); errno = EIO; return - 1; } @@ -869,7 +886,7 @@ rtems_bsd_run_rc_conf(const char* name, int timeout, bool verbose) if (r < 0) return r; - rc_conf = malloc(sb.st_size); + rc_conf = malloc(sb.st_size + 1); if (rc_conf == NULL) { errno = ENOMEM; return -1; @@ -892,6 +909,8 @@ rtems_bsd_run_rc_conf(const char* name, int timeout, bool verbose) fclose(file); + rc_conf[sb.st_size] = '\0'; + r = rtems_bsd_run_rc_conf_script(name, rc_conf, timeout, verbose); free(rc_conf); diff --git a/rtemsbsd/rtems/rtems-bsd-shell-wpa_supplicant_fork.c b/rtemsbsd/rtems/rtems-bsd-shell-wpa_supplicant_fork.c index 4af789cc..3f705975 100644 --- a/rtemsbsd/rtems/rtems-bsd-shell-wpa_supplicant_fork.c +++ b/rtemsbsd/rtems/rtems-bsd-shell-wpa_supplicant_fork.c @@ -53,7 +53,7 @@ new_wpa_supplicant_task(rtems_task_argument arg) free(params->argv); free(params); - rtems_task_delete( RTEMS_SELF ); + rtems_task_exit(); } int rtems_bsd_command_wpa_supplicant_fork(int argc, char **argv) diff --git a/rtemsbsd/rtems/rtems-kernel-epoch.c b/rtemsbsd/rtems/rtems-kernel-epoch.c index f4fff0ea..642b5854 100644 --- a/rtemsbsd/rtems/rtems-kernel-epoch.c +++ b/rtemsbsd/rtems/rtems-kernel-epoch.c @@ -60,6 +60,10 @@ struct epoch_pcpu { rtems_interrupt_server_request irq_srv_req; }; +#ifdef PER_CPU_DATA_NEED_INITIALIZATION +PER_CPU_DATA_NEED_INITIALIZATION(); +#endif + static PER_CPU_DATA_ITEM(struct epoch_pcpu, epoch); static SLIST_HEAD(, epoch) epoch_list = SLIST_HEAD_INITIALIZER(epoch_list); @@ -345,15 +349,29 @@ epoch_call(epoch_t epoch, epoch_context_t ctx, void (*callback) (epoch_context_t)) { Per_CPU_Control *cpu_self; - struct epoch_record *er; struct epoch_pcpu *epcpu; + struct epoch_record *er; +#ifdef RTEMS_SMP + ISR_Level level; + Thread_Control *executing; + + _ISR_Local_disable(level); + cpu_self = _Per_CPU_Get(); + executing = _Per_CPU_Get_executing(cpu_self); + _Thread_Pin(executing); + _ISR_Local_enable(level); +#endif - cpu_self = _Thread_Dispatch_disable(); epcpu = PER_CPU_DATA_GET(cpu_self, struct epoch_pcpu, epoch); epcpu->cb_count += 1; er = EPOCH_GET_RECORD(cpu_self, epoch); ck_epoch_call(&er->er_record, ctx, callback); + +#ifdef RTEMS_SMP + cpu_self = _Thread_Dispatch_disable(); + _Thread_Unpin(executing, cpu_self); _Thread_Dispatch_enable(cpu_self); +#endif } #ifdef INVARIANTS @@ -407,7 +425,7 @@ epoch_call_drain_cb(void *arg) struct epoch_record *er; epoch = arg; - cpu = _Per_CPU_Get(); + cpu = _Per_CPU_Get_snapshot(); er = EPOCH_GET_RECORD(cpu, epoch); epoch_call(epoch, &er->er_drain_ctx, epoch_drain_cb); } @@ -421,6 +439,7 @@ epoch_drain_callbacks(epoch_t epoch) uint32_t cpu_max; rtems_id id; rtems_status_code sc; + rtems_interrupt_server_request req[CPU_MAXIMUM_PROCESSORS]; #else struct epoch_record *er; #endif @@ -429,6 +448,7 @@ epoch_drain_callbacks(epoch_t epoch) mtx_lock(&epoch->e_drain_mtx); #ifdef RTEMS_SMP + memset(&req, 0, sizeof(req)); cpu_max = rtems_scheduler_get_processor_maximum(); for (cpu_index = 0; cpu_index <= cpu_max; ++cpu_index) { @@ -441,8 +461,15 @@ epoch_drain_callbacks(epoch_t epoch) for (cpu_index = 0; cpu_index <= cpu_max; ++cpu_index) { sc = rtems_scheduler_ident_by_processor(cpu_index, &id); if (sc == RTEMS_SUCCESSFUL) { - _SMP_Unicast_action(cpu_index, epoch_call_drain_cb, + sc = rtems_interrupt_server_request_initialize( + cpu_index, &req[cpu_index], epoch_call_drain_cb, epoch); + if (sc == RTEMS_SUCCESSFUL) { + rtems_interrupt_server_request_submit( + &req[cpu_index]); + } else { + panic("no interrupt server for epoch drain"); + } } } #else @@ -457,4 +484,12 @@ epoch_drain_callbacks(epoch_t epoch) mtx_unlock(&epoch->e_drain_mtx); sx_xunlock(&epoch->e_drain_sx); + +#ifdef RTEMS_SMP + for (cpu_index = 0; cpu_index <= cpu_max; ++cpu_index) { + if (req[cpu_index].action.handler != NULL) { + rtems_interrupt_server_request_destroy(&req[cpu_index]); + } + } +#endif } diff --git a/rtemsbsd/rtems/rtems-kernel-init.c b/rtemsbsd/rtems/rtems-kernel-init.c index 7112914e..b0779277 100644 --- a/rtemsbsd/rtems/rtems-kernel-init.c +++ b/rtemsbsd/rtems/rtems-kernel-init.c @@ -135,7 +135,9 @@ rtems_bsd_initialize(void) sbt_tickthreshold = bttosbt(bt_tickthreshold); maxid_maxcpus = (int) rtems_scheduler_get_processor_maximum(); - mkdir("/etc", S_IRWXU | S_IRWXG | S_IRWXO); + if (mkdir("/etc", S_IRWXU | S_IRWXG | S_IRWXO) != 0) { + return RTEMS_UNSATISFIED; + } sc = rtems_timer_initiate_server( rtems_bsd_get_task_priority(name), diff --git a/rtemsbsd/rtems/rtems-kernel-thread.c b/rtemsbsd/rtems/rtems-kernel-thread.c index 8e3344ef..f06999fb 100644 --- a/rtemsbsd/rtems/rtems-kernel-thread.c +++ b/rtemsbsd/rtems/rtems-kernel-thread.c @@ -280,13 +280,6 @@ rtems_bsd_thread_start(struct thread **td_ptr, void (*func)(void *), void *arg, return eno; } -static __dead2 void -rtems_bsd_thread_delete(void) -{ - rtems_task_delete(RTEMS_SELF); - BSD_PANIC("delete self failed"); -} - void kproc_start(const void *udata) { @@ -312,7 +305,7 @@ kproc_create(void (*func)(void *), void *arg, struct proc **newpp, int flags, in void kproc_exit(int ecode) { - rtems_bsd_thread_delete(); + rtems_task_exit(); } void @@ -340,7 +333,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p, struct thread **new void kthread_exit(void) { - rtems_bsd_thread_delete(); + rtems_task_exit(); } int diff --git a/rtemsbsd/rtems/rtems-program.c b/rtemsbsd/rtems/rtems-program.c index 204ed248..1ca8e3b9 100644 --- a/rtemsbsd/rtems/rtems-program.c +++ b/rtemsbsd/rtems/rtems-program.c @@ -224,6 +224,18 @@ allocmem_free_all(struct rtems_bsd_program_control *prog_ctrl) } } +static void +call_destructors(struct rtems_bsd_program_control *prog_ctrl) +{ + struct program_destructor *node; + struct program_destructor *tmp; + + LIST_FOREACH_SAFE(node, &prog_ctrl->destructors, link, tmp) { + (*node->destructor)(node->arg); + free(node); + } +} + int rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) { @@ -251,6 +263,7 @@ rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) LIST_INIT(&prog_ctrl->open_fd); LIST_INIT(&prog_ctrl->open_file); LIST_INIT(&prog_ctrl->allocated_mem); + LIST_INIT(&prog_ctrl->destructors); if (setjmp(prog_ctrl->return_context) == 0) { exit_code = (*prog)(context); @@ -262,10 +275,48 @@ rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) fd_close_all(prog_ctrl); file_close_all(prog_ctrl); allocmem_free_all(prog_ctrl); + call_destructors(prog_ctrl); free(prog_ctrl); return (exit_code); } +void * +rtems_bsd_program_add_destructor(void (*destructor)(void *), void *arg) +{ + struct rtems_bsd_program_control *prog_ctrl; + struct program_destructor *node; + + prog_ctrl = rtems_bsd_program_get_control_or_null(); + if (prog_ctrl == NULL) { + return (NULL); + } + + node = malloc(sizeof(*node)); + if (node == NULL) { + return (NULL); + } + + node->destructor = destructor; + node->arg = arg; + LIST_INSERT_HEAD(&prog_ctrl->destructors, node, link); + return (node); +} + +void +rtems_bsd_program_remove_destructor(void *cookie, bool call) +{ + struct program_destructor *node; + + node = cookie; + LIST_REMOVE(node, link); + + if (call) { + (*node->destructor)(node->arg); + } + + free(node); +} + void rtems_bsd_program_exit(int exit_code) { diff --git a/rtemsbsd/rtems/rtems-routes.c b/rtemsbsd/rtems/rtems-routes.c index 6663e8d4..0b5250f0 100644 --- a/rtemsbsd/rtems/rtems-routes.c +++ b/rtemsbsd/rtems/rtems-routes.c @@ -85,8 +85,10 @@ int rtems_get_route(const struct sockaddr_in* sin, struct sockaddr** rti_info) } s = socket(AF_ROUTE, SOCK_RAW, AF_UNSPEC); - if (s < 0) + if (s < 0) { + free(buf); return -1; + } rtm = (struct rt_msghdr *) buf; rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); diff --git a/rtemsbsd/sys/arm/freescale/imx/imx_rtems_gpio.c b/rtemsbsd/sys/arm/freescale/imx/imx_rtems_gpio.c index c24732cc..da64922f 100644 --- a/rtemsbsd/sys/arm/freescale/imx/imx_rtems_gpio.c +++ b/rtemsbsd/sys/arm/freescale/imx/imx_rtems_gpio.c @@ -27,7 +27,7 @@ */ #include <bsp.h> -#if defined(LIBBSP_ARM_IMX_BSP_H) +#if defined(LIBBSP_ARM_IMX_BSP_H) || defined(LIBBSP_ARM_IMXRT_BSP_H) #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -303,4 +303,4 @@ EARLY_DRIVER_MODULE(imx_rtems_gpio, simplebus, imx_rtems_gpio_driver, imx_rtems_gpio_devclass, NULL, NULL, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); -#endif /* LIBBSP_ARM_IMX_BSP_H */ +#endif /* LIBBSP_ARM_IMX_BSP_H || LIBBSP_ARM_IMXRT_BSP_H */ diff --git a/rtemsbsd/sys/arm/freescale/imx/imxrt1166_usbphy.c b/rtemsbsd/sys/arm/freescale/imx/imxrt1166_usbphy.c new file mode 100644 index 00000000..b8e3a188 --- /dev/null +++ b/rtemsbsd/sys/arm/freescale/imx/imxrt1166_usbphy.c @@ -0,0 +1,227 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> + * Copyright (C) 2023 embedded brains GmbH & Co. KG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <bsp.h> +#if defined(LIBBSP_ARM_IMXRT_BSP_H) + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * USBPHY driver for Freescale i.MXRT1166. Most likely works with the whole + * i.MXRT11xx family. + * + * Based on USBPHY driver for i.MX6. + */ + +#include <rtems/bsd/local/opt_bus.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <machine/bus.h> + +#include <dev/extres/regulator/regulator.h> + +#include <fsl_device_registers.h> +#include <fsl_clock.h> + +struct imxrt1166_usbphy_softc { + device_t dev; + struct resource *mem_res; + regulator_t supply_vbus; + USBPHY_Type *regs; +}; + +static struct ofw_compat_data compat_data[] = { + {"fsl,imxrt1166-usbphy", true}, + {NULL, false} +}; + +static int +imxrt1166_usbphy_detach(device_t dev) +{ + struct imxrt1166_usbphy_softc *sc; + + sc = device_get_softc(dev); + + if (sc->mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); + + return (0); +} + +#define BUS_SPACE_PHYSADDR(res, offs) \ + ((u_int)(rman_get_start(res)+(offs))) + +static int +enable_vbus_supply(device_t dev, struct imxrt1166_usbphy_softc *sc) +{ + int rv; + phandle_t node; + + node = ofw_bus_get_node(dev); + if (OF_hasprop(node, "vbus-supply")) { + rv = regulator_get_by_ofw_property(sc->dev, node, "vbus-supply", + &sc->supply_vbus); + if (rv != 0) { + device_printf(sc->dev, + "Cannot get \"vbus\" regulator\n"); + return ENXIO; + } + rv = regulator_enable(sc->supply_vbus); + if (rv != 0) { + device_printf(sc->dev, + "Cannot enable \"vbus\" regulator\n"); + return ENXIO; + } + } + + return 0; +} + +static int +imxrt1166_usbphy_attach(device_t dev) +{ + struct imxrt1166_usbphy_softc *sc; + int err, rid; +#if IMXRT_IS_MIMXRT11xx + uint32_t usbClockFreq; +#endif + + sc = device_get_softc(dev); + err = 0; + + /* Allocate bus_space resources. */ + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "Cannot allocate memory resources\n"); + err = ENXIO; + goto out; + } + + /* Enable VBUS Supply if a regulator is given */ + err = enable_vbus_supply(dev, sc); + if (err != 0) { + goto out; + } + + sc->regs = (USBPHY_Type *)BUS_SPACE_PHYSADDR(sc->mem_res, 0); + +#if IMXRT_IS_MIMXRT11xx + /* Enable register clock */ + CLOCK_EnableClock(kCLOCK_Usb); + + usbClockFreq = CLOCK_GetFreq(kCLOCK_Osc24M); + + /* + * Set the software reset bit. It will be implicitly cleared when + * setting up the clock in the next steps. + */ + sc->regs->CTRL_SET = USBPHY_CTRL_SFTRST_MASK; + + /* + * Enable PLLs. + * + * FIXME: Hacky way to find out the module. + */ + if (sc->regs == USBPHY1) { + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, usbClockFreq); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, usbClockFreq); + } else { + CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, usbClockFreq); + CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, usbClockFreq); + } +#else + /* Not implemented */ +#endif + + err = 0; + +out: + + if (err != 0) + imxrt1166_usbphy_detach(dev); + + return (err); +} + +static int +imxrt1166_usbphy_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Freescale i.MXRT1166 USB PHY"); + + return (BUS_PROBE_DEFAULT); +} + +static device_method_t imxrt1166_usbphy_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, imxrt1166_usbphy_probe), + DEVMETHOD(device_attach, imxrt1166_usbphy_attach), + DEVMETHOD(device_detach, imxrt1166_usbphy_detach), + + DEVMETHOD_END +}; + +static driver_t imxrt1166_usbphy_driver = { + "imxrt1166_usbphy", + imxrt1166_usbphy_methods, + sizeof(struct imxrt1166_usbphy_softc) +}; + +static devclass_t imxrt1166_usbphy_devclass; + +/* + * This driver needs to start before the ehci driver, but later than the usual + * "special" drivers like clocks and cpu. Ehci starts at DEFAULT so SUPPORTDEV + * is where this driver fits most. + */ +EARLY_DRIVER_MODULE(imxrt1166_usbphy, simplebus, imxrt1166_usbphy_driver, + imxrt1166_usbphy_devclass, 0, 0, + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); + +#endif /* LIBBSP_ARM_IMXRT_BSP_H */ diff --git a/rtemsbsd/sys/arm/lpc/if_lpe.c b/rtemsbsd/sys/arm/lpc/if_lpe.c index 40ac162e..87ca9ff7 100755 --- a/rtemsbsd/sys/arm/lpc/if_lpe.c +++ b/rtemsbsd/sys/arm/lpc/if_lpe.c @@ -1,1428 +1,1769 @@ -#include <machine/rtems-bsd-kernel-space.h> - -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD +/** + * @file * - * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> - * All rights reserved. + * @ingroup lpc_eth * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * @brief Ethernet driver. + */ + +/* + * Copyright (C) 2009, 2022 embedded brains GmbH * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); + +#include <machine/rtems-bsd-kernel-space.h> + +#include <bsp.h> + +#if defined(LIBBSP_ARM_LPC24XX_BSP_H) || defined(LIBBSP_ARM_LPC32XX_BSP_H) #include <sys/param.h> -#include <sys/endian.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> #include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> #include <sys/module.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/rman.h> -#include <sys/bus.h> #include <sys/socket.h> +#include <sys/sockio.h> + +#include <sys/bus.h> #include <machine/bus.h> -#ifndef __rtems__ -#include <machine/intr.h> -#endif /* __rtems__ */ #include <net/if.h> -#include <net/if_arp.h> #include <net/ethernet.h> +#include <net/if_arp.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> #include <net/if_var.h> -#include <net/bpf.h> +#include <dev/mii/mii.h> -#ifndef __rtems__ -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#endif /* __rtems__ */ +#include <rtems/bsd/bsd.h> -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> +#include <arm/lpc/probe.h> -#include <arm/lpc/lpcreg.h> -#include <arm/lpc/lpcvar.h> -#include <arm/lpc/if_lpereg.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/lpc-ethernet-config.h> +#include <bsp/utility.h> -#include <rtems/bsd/local/miibus_if.h> -#ifdef __rtems__ -#include <machine/rtems-bsd-cache.h> -#include <rtems/bsd/bsd.h> -#endif /* __rtems__ */ +#if MCLBYTES > (2 * 1024) + #error "MCLBYTES to large" +#endif -#ifdef DEBUG -#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ - printf(fmt,##args); } while (0) +#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + #define LPC_ETH_CONFIG_TX_BUF_SIZE sizeof(struct mbuf *) #else -#define debugf(fmt, args...) + #define LPC_ETH_CONFIG_TX_BUF_SIZE 1518U #endif -struct lpe_dmamap_arg { - bus_addr_t lpe_dma_busaddr; -}; +#define DEFAULT_PHY 0 +#define WATCHDOG_TIMEOUT 5 + +typedef struct { + uint32_t start; + uint32_t control; +} lpc_eth_transfer_descriptor; + +typedef struct { + uint32_t info; + uint32_t hash_crc; +} lpc_eth_receive_status; + +typedef struct { + uint32_t mac1; + uint32_t mac2; + uint32_t ipgt; + uint32_t ipgr; + uint32_t clrt; + uint32_t maxf; + uint32_t supp; + uint32_t test; + uint32_t mcfg; + uint32_t mcmd; + uint32_t madr; + uint32_t mwtd; + uint32_t mrdd; + uint32_t mind; + uint32_t reserved_0 [2]; + uint32_t sa0; + uint32_t sa1; + uint32_t sa2; + uint32_t reserved_1 [45]; + uint32_t command; + uint32_t status; + uint32_t rxdescriptor; + uint32_t rxstatus; + uint32_t rxdescriptornum; + uint32_t rxproduceindex; + uint32_t rxconsumeindex; + uint32_t txdescriptor; + uint32_t txstatus; + uint32_t txdescriptornum; + uint32_t txproduceindex; + uint32_t txconsumeindex; + uint32_t reserved_2 [10]; + uint32_t tsv0; + uint32_t tsv1; + uint32_t rsv; + uint32_t reserved_3 [3]; + uint32_t flowcontrolcnt; + uint32_t flowcontrolsts; + uint32_t reserved_4 [34]; + uint32_t rxfilterctrl; + uint32_t rxfilterwolsts; + uint32_t rxfilterwolclr; + uint32_t reserved_5 [1]; + uint32_t hashfilterl; + uint32_t hashfilterh; + uint32_t reserved_6 [882]; + uint32_t intstatus; + uint32_t intenable; + uint32_t intclear; + uint32_t intset; + uint32_t reserved_7 [1]; + uint32_t powerdown; +} lpc_eth_controller; + +#define LPE_LOCK(e) mtx_lock(&(e)->mtx) + +#define LPE_UNLOCK(e) mtx_unlock(&(e)->mtx) + +static volatile lpc_eth_controller *const lpc_eth = + (volatile lpc_eth_controller *) LPC_ETH_CONFIG_REG_BASE; + +/* ETH_RX_CTRL */ + +#define ETH_RX_CTRL_SIZE_MASK 0x000007ffU +#define ETH_RX_CTRL_INTERRUPT 0x80000000U + +/* ETH_RX_STAT */ + +#define ETH_RX_STAT_RXSIZE_MASK 0x000007ffU +#define ETH_RX_STAT_BYTES 0x00000100U +#define ETH_RX_STAT_CONTROL_FRAME 0x00040000U +#define ETH_RX_STAT_VLAN 0x00080000U +#define ETH_RX_STAT_FAIL_FILTER 0x00100000U +#define ETH_RX_STAT_MULTICAST 0x00200000U +#define ETH_RX_STAT_BROADCAST 0x00400000U +#define ETH_RX_STAT_CRC_ERROR 0x00800000U +#define ETH_RX_STAT_SYMBOL_ERROR 0x01000000U +#define ETH_RX_STAT_LENGTH_ERROR 0x02000000U +#define ETH_RX_STAT_RANGE_ERROR 0x04000000U +#define ETH_RX_STAT_ALIGNMENT_ERROR 0x08000000U +#define ETH_RX_STAT_OVERRUN 0x10000000U +#define ETH_RX_STAT_NO_DESCRIPTOR 0x20000000U +#define ETH_RX_STAT_LAST_FLAG 0x40000000U +#define ETH_RX_STAT_ERROR 0x80000000U + +/* ETH_TX_CTRL */ + +#define ETH_TX_CTRL_SIZE_MASK 0x7ffU +#define ETH_TX_CTRL_SIZE_SHIFT 0 +#define ETH_TX_CTRL_OVERRIDE 0x04000000U +#define ETH_TX_CTRL_HUGE 0x08000000U +#define ETH_TX_CTRL_PAD 0x10000000U +#define ETH_TX_CTRL_CRC 0x20000000U +#define ETH_TX_CTRL_LAST 0x40000000U +#define ETH_TX_CTRL_INTERRUPT 0x80000000U + +/* ETH_TX_STAT */ + +#define ETH_TX_STAT_COLLISION_COUNT_MASK 0x01e00000U +#define ETH_TX_STAT_DEFER 0x02000000U +#define ETH_TX_STAT_EXCESSIVE_DEFER 0x04000000U +#define ETH_TX_STAT_EXCESSIVE_COLLISION 0x08000000U +#define ETH_TX_STAT_LATE_COLLISION 0x10000000U +#define ETH_TX_STAT_UNDERRUN 0x20000000U +#define ETH_TX_STAT_NO_DESCRIPTOR 0x40000000U +#define ETH_TX_STAT_ERROR 0x80000000U + +/* ETH_INT */ + +#define ETH_INT_RX_OVERRUN 0x00000001U +#define ETH_INT_RX_ERROR 0x00000002U +#define ETH_INT_RX_FINISHED 0x00000004U +#define ETH_INT_RX_DONE 0x00000008U +#define ETH_INT_TX_UNDERRUN 0x00000010U +#define ETH_INT_TX_ERROR 0x00000020U +#define ETH_INT_TX_FINISHED 0x00000040U +#define ETH_INT_TX_DONE 0x00000080U +#define ETH_INT_SOFT 0x00001000U +#define ETH_INT_WAKEUP 0x00002000U + +/* ETH_RX_FIL_CTRL */ + +#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST 0x00000001U +#define ETH_RX_FIL_CTRL_ACCEPT_BROADCAST 0x00000002U +#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST 0x00000004U +#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST_HASH 0x00000008U +#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH 0x00000010U +#define ETH_RX_FIL_CTRL_ACCEPT_PERFECT 0x00000020U +#define ETH_RX_FIL_CTRL_MAGIC_PACKET_WOL 0x00001000U +#define ETH_RX_FIL_CTRL_RX_FILTER_WOL 0x00002000U + +/* ETH_CMD */ + +#define ETH_CMD_RX_ENABLE 0x00000001U +#define ETH_CMD_TX_ENABLE 0x00000002U +#define ETH_CMD_REG_RESET 0x00000008U +#define ETH_CMD_TX_RESET 0x00000010U +#define ETH_CMD_RX_RESET 0x00000020U +#define ETH_CMD_PASS_RUNT_FRAME 0x00000040U +#define ETH_CMD_PASS_RX_FILTER 0X00000080U +#define ETH_CMD_TX_FLOW_CONTROL 0x00000100U +#define ETH_CMD_RMII 0x00000200U +#define ETH_CMD_FULL_DUPLEX 0x00000400U -struct lpe_rxdesc { - struct mbuf * lpe_rxdesc_mbuf; -#ifndef __rtems__ - bus_dmamap_t lpe_rxdesc_dmamap; -#endif /* __rtems__ */ -}; +/* ETH_STAT */ -struct lpe_txdesc { - int lpe_txdesc_first; - struct mbuf * lpe_txdesc_mbuf; -#ifndef __rtems__ - bus_dmamap_t lpe_txdesc_dmamap; -#endif /* __rtems__ */ -}; +#define ETH_STAT_RX_ACTIVE 0x00000001U +#define ETH_STAT_TX_ACTIVE 0x00000002U -struct lpe_chain_data { - bus_dma_tag_t lpe_parent_tag; - bus_dma_tag_t lpe_tx_ring_tag; - bus_dmamap_t lpe_tx_ring_map; - bus_dma_tag_t lpe_tx_status_tag; - bus_dmamap_t lpe_tx_status_map; - bus_dma_tag_t lpe_tx_buf_tag; - bus_dma_tag_t lpe_rx_ring_tag; - bus_dmamap_t lpe_rx_ring_map; - bus_dma_tag_t lpe_rx_status_tag; - bus_dmamap_t lpe_rx_status_map; - bus_dma_tag_t lpe_rx_buf_tag; - struct lpe_rxdesc lpe_rx_desc[LPE_RXDESC_NUM]; - struct lpe_txdesc lpe_tx_desc[LPE_TXDESC_NUM]; - int lpe_tx_prod; - int lpe_tx_last; - int lpe_tx_used; -}; +/* ETH_MAC2 */ -struct lpe_ring_data { - struct lpe_hwdesc * lpe_rx_ring; - struct lpe_hwstatus * lpe_rx_status; - bus_addr_t lpe_rx_ring_phys; - bus_addr_t lpe_rx_status_phys; - struct lpe_hwdesc * lpe_tx_ring; - struct lpe_hwstatus * lpe_tx_status; - bus_addr_t lpe_tx_ring_phys; - bus_addr_t lpe_tx_status_phys; -}; +#define ETH_MAC2_FULL_DUPLEX BSP_BIT32(8) -struct lpe_softc { - struct ifnet * lpe_ifp; - struct mtx lpe_mtx; -#ifndef __rtems__ - phandle_t lpe_ofw; -#endif /* __rtems__ */ - device_t lpe_dev; - device_t lpe_miibus; - uint8_t lpe_enaddr[6]; - struct resource * lpe_mem_res; - struct resource * lpe_irq_res; - void * lpe_intrhand; - bus_space_tag_t lpe_bst; - bus_space_handle_t lpe_bsh; -#define LPE_FLAG_LINK (1 << 0) - uint32_t lpe_flags; - int lpe_watchdog_timer; - struct callout lpe_tick; - struct lpe_chain_data lpe_cdata; - struct lpe_ring_data lpe_rdata; -}; +/* ETH_SUPP */ -static int lpe_probe(device_t); -static int lpe_attach(device_t); -static int lpe_detach(device_t); -static int lpe_miibus_readreg(device_t, int, int); -static int lpe_miibus_writereg(device_t, int, int, int); -static void lpe_miibus_statchg(device_t); - -static void lpe_reset(struct lpe_softc *); -static void lpe_init(void *); -static void lpe_init_locked(struct lpe_softc *); -static void lpe_start(struct ifnet *); -static void lpe_start_locked(struct ifnet *); -static void lpe_stop(struct lpe_softc *); -static void lpe_stop_locked(struct lpe_softc *); -static int lpe_ioctl(struct ifnet *, u_long, caddr_t); -static void lpe_set_rxmode(struct lpe_softc *); -static void lpe_set_rxfilter(struct lpe_softc *); -static void lpe_intr(void *); -static void lpe_rxintr(struct lpe_softc *); -static void lpe_txintr(struct lpe_softc *); -static void lpe_tick(void *); -static void lpe_watchdog(struct lpe_softc *); -static int lpe_encap(struct lpe_softc *, struct mbuf **); -static int lpe_dma_alloc(struct lpe_softc *); -static int lpe_dma_alloc_rx(struct lpe_softc *); -static int lpe_dma_alloc_tx(struct lpe_softc *); -static int lpe_init_rx(struct lpe_softc *); -static int lpe_init_rxbuf(struct lpe_softc *, int); -static void lpe_discard_rxbuf(struct lpe_softc *, int); -static void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int); -static int lpe_ifmedia_upd(struct ifnet *); -static void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *); - -#define lpe_lock(_sc) mtx_lock(&(_sc)->lpe_mtx) -#define lpe_unlock(_sc) mtx_unlock(&(_sc)->lpe_mtx) -#define lpe_lock_assert(_sc) mtx_assert(&(_sc)->lpe_mtx, MA_OWNED) - -#define lpe_read_4(_sc, _reg) \ - bus_space_read_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg)) -#define lpe_write_4(_sc, _reg, _val) \ - bus_space_write_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg), (_val)) - -#define LPE_HWDESC_RXERRS (LPE_HWDESC_CRCERROR | LPE_HWDESC_SYMBOLERROR | \ - LPE_HWDESC_LENGTHERROR | LPE_HWDESC_ALIGNERROR | LPE_HWDESC_OVERRUN | \ - LPE_HWDESC_RXNODESCR) - -#define LPE_HWDESC_TXERRS (LPE_HWDESC_EXCDEFER | LPE_HWDESC_EXCCOLL | \ - LPE_HWDESC_LATECOLL | LPE_HWDESC_UNDERRUN | LPE_HWDESC_TXNODESCR) - -static int -lpe_probe(device_t dev) -{ - -#ifndef __rtems__ - if (!ofw_bus_status_okay(dev)) - return (ENXIO); +#define ETH_SUPP_SPEED BSP_BIT32(8) - if (!ofw_bus_is_compatible(dev, "lpc,ethernet")) - return (ENXIO); -#endif /* __rtems__ */ +/* ETH_MCFG */ - device_set_desc(dev, "LPC32x0 10/100 Ethernet"); - return (BUS_PROBE_DEFAULT); -} +#define ETH_MCFG_CLOCK_SELECT(val) BSP_FLD32(val, 2, 4) -static int -lpe_attach(device_t dev) -{ - struct lpe_softc *sc = device_get_softc(dev); - struct ifnet *ifp; -#ifndef __rtems__ - int rid, i; - uint32_t val; -#else /* __rtems__ */ - int rid; -#endif /* __rtems__ */ - - sc->lpe_dev = dev; -#ifndef __rtems__ - sc->lpe_ofw = ofw_bus_get_node(dev); - - i = OF_getprop(sc->lpe_ofw, "local-mac-address", (void *)&sc->lpe_enaddr, 6); - if (i != 6) { - sc->lpe_enaddr[0] = 0x00; - sc->lpe_enaddr[1] = 0x11; - sc->lpe_enaddr[2] = 0x22; - sc->lpe_enaddr[3] = 0x33; - sc->lpe_enaddr[4] = 0x44; - sc->lpe_enaddr[5] = 0x55; - } -#else /* __rtems__ */ - rtems_bsd_get_mac_address(device_get_name(sc->lpe_dev), device_get_unit(sc->lpe_dev), sc->lpe_enaddr); -#endif /* __rtems__ */ - - mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF); - - callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0); - - rid = 0; - sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->lpe_mem_res) { - device_printf(dev, "cannot allocate memory window\n"); - goto fail; - } - - sc->lpe_bst = rman_get_bustag(sc->lpe_mem_res); - sc->lpe_bsh = rman_get_bushandle(sc->lpe_mem_res); - - rid = 0; - sc->lpe_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); - if (!sc->lpe_irq_res) { - device_printf(dev, "cannot allocate interrupt\n"); - goto fail; - } - - sc->lpe_ifp = if_alloc(IFT_ETHER); - if (!sc->lpe_ifp) { - device_printf(dev, "cannot allocated ifnet\n"); - goto fail; - } - - ifp = sc->lpe_ifp; - - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_softc = sc; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_start = lpe_start; - ifp->if_ioctl = lpe_ioctl; - ifp->if_init = lpe_init; - IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); - ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; - IFQ_SET_READY(&ifp->if_snd); - - ether_ifattach(ifp, sc->lpe_enaddr); - - if (bus_setup_intr(dev, sc->lpe_irq_res, INTR_TYPE_NET, NULL, - lpe_intr, sc, &sc->lpe_intrhand)) { - device_printf(dev, "cannot establish interrupt handler\n"); - ether_ifdetach(ifp); - goto fail; - } - - /* Enable Ethernet clock */ -#ifndef __rtems__ - lpc_pwr_write(dev, LPC_CLKPWR_MACCLK_CTRL, - LPC_CLKPWR_MACCLK_CTRL_REG | - LPC_CLKPWR_MACCLK_CTRL_SLAVE | - LPC_CLKPWR_MACCLK_CTRL_MASTER | - LPC_CLKPWR_MACCLK_CTRL_HDWINF(3)); -#else /* __rtems__ */ -#ifdef LPC32XX_ETHERNET_RMII - lpc_pwr_write(dev, LPC_CLKPWR_MACCLK_CTRL, - LPC_CLKPWR_MACCLK_CTRL_REG | - LPC_CLKPWR_MACCLK_CTRL_SLAVE | - LPC_CLKPWR_MACCLK_CTRL_MASTER | - LPC_CLKPWR_MACCLK_CTRL_HDWINF(3)); -#else - lpc_pwr_write(dev, LPC_CLKPWR_MACCLK_CTRL, - LPC_CLKPWR_MACCLK_CTRL_REG | - LPC_CLKPWR_MACCLK_CTRL_SLAVE | - LPC_CLKPWR_MACCLK_CTRL_MASTER | - LPC_CLKPWR_MACCLK_CTRL_HDWINF(1)); -#endif -#endif /* __rtems__ */ - - /* Reset chip */ - lpe_reset(sc); - - /* Initialize MII */ -#ifndef __rtems__ - val = lpe_read_4(sc, LPE_COMMAND); - lpe_write_4(sc, LPE_COMMAND, val | LPE_COMMAND_RMII); - - if (mii_attach(dev, &sc->lpe_miibus, ifp, lpe_ifmedia_upd, - lpe_ifmedia_sts, BMSR_DEFCAPMASK, 0x01, - MII_OFFSET_ANY, 0)) { - device_printf(dev, "cannot find PHY\n"); - goto fail; - } -#else /* __rtems__ */ - if (mii_attach(dev, &sc->lpe_miibus, ifp, lpe_ifmedia_upd, - lpe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, - MII_OFFSET_ANY, 0)) { - device_printf(dev, "cannot find PHY\n"); - goto fail; - } -#endif /* __rtems__ */ - - lpe_dma_alloc(sc); - - return (0); - -fail: - if (sc->lpe_ifp) - if_free(sc->lpe_ifp); - if (sc->lpe_intrhand) - bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand); - if (sc->lpe_irq_res) - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res); - if (sc->lpe_mem_res) - bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res); - return (ENXIO); -} +#define ETH_MCFG_RESETMIIMGMT BSP_BIT32(15) -static int -lpe_detach(device_t dev) -{ - struct lpe_softc *sc = device_get_softc(dev); +/* ETH_MCMD */ - lpe_stop(sc); +#define ETH_MCMD_READ BSP_BIT32(0) +#define ETH_MCMD_SCAN BSP_BIT32(1) - if_free(sc->lpe_ifp); - bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res); - bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res); +/* ETH_MADR */ - return (0); -} +#define ETH_MADR_REG(val) BSP_FLD32(val, 0, 4) +#define ETH_MADR_PHY(val) BSP_FLD32(val, 8, 12) -static int -lpe_miibus_readreg(device_t dev, int phy, int reg) -{ - struct lpe_softc *sc = device_get_softc(dev); - uint32_t val; - int result; +/* ETH_MIND */ - lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ); - lpe_write_4(sc, LPE_MADR, - (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | - (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT); +#define ETH_MIND_BUSY BSP_BIT32(0) +#define ETH_MIND_SCANNING BSP_BIT32(1) +#define ETH_MIND_NOT_VALID BSP_BIT32(2) +#define ETH_MIND_MII_LINK_FAIL BSP_BIT32(3) - val = lpe_read_4(sc, LPE_MIND); +/* Events */ - /* Wait until request is completed */ - while (val & LPE_MIND_BUSY) { - val = lpe_read_4(sc, LPE_MIND); - DELAY(10); - } +#define LPC_ETH_EVENT_INIT_RX RTEMS_EVENT_0 - if (val & LPE_MIND_INVALID) - return (0); +#define LPC_ETH_EVENT_INIT_TX RTEMS_EVENT_1 - lpe_write_4(sc, LPE_MCMD, 0); - result = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); - debugf("phy=%d reg=%d result=0x%04x\n", phy, reg, result); +#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3 - return (result); -} +#define LPC_ETH_EVENT_STOP RTEMS_EVENT_4 -static int -lpe_miibus_writereg(device_t dev, int phy, int reg, int data) -{ - struct lpe_softc *sc = device_get_softc(dev); - uint32_t val; +/* Status */ - debugf("phy=%d reg=%d data=0x%04x\n", phy, reg, data); +#define LPC_ETH_INTERRUPT_RECEIVE \ + (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE) - lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE); - lpe_write_4(sc, LPE_MADR, - (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | - (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT); +#define LPC_ETH_RX_STAT_ERRORS \ + (ETH_RX_STAT_CRC_ERROR \ + | ETH_RX_STAT_SYMBOL_ERROR \ + | ETH_RX_STAT_LENGTH_ERROR \ + | ETH_RX_STAT_ALIGNMENT_ERROR \ + | ETH_RX_STAT_OVERRUN \ + | ETH_RX_STAT_NO_DESCRIPTOR) - lpe_write_4(sc, LPE_MWTD, (data & LPE_MWTD_DATAMASK)); +#define LPC_ETH_LAST_FRAGMENT_FLAGS \ + (ETH_TX_CTRL_OVERRIDE \ + | ETH_TX_CTRL_PAD \ + | ETH_TX_CTRL_CRC \ + | ETH_TX_CTRL_INTERRUPT \ + | ETH_TX_CTRL_LAST) - val = lpe_read_4(sc, LPE_MIND); +/* Debug */ - /* Wait until request is completed */ - while (val & LPE_MIND_BUSY) { - val = lpe_read_4(sc, LPE_MIND); - DELAY(10); - } +#ifdef DEBUG + #define LPC_ETH_PRINTF(...) printf(__VA_ARGS__) + #define LPC_ETH_PRINTK(...) printk(__VA_ARGS__) +#else + #define LPC_ETH_PRINTF(...) + #define LPC_ETH_PRINTK(...) +#endif - return (0); +typedef enum { + LPC_ETH_STATE_NOT_INITIALIZED = 0, + LPC_ETH_STATE_DOWN, + LPC_ETH_STATE_UP +} lpc_eth_state; + +typedef struct { + device_t dev; + struct ifnet *ifp; + struct mtx mtx; + lpc_eth_state state; + uint32_t anlpar; + struct callout watchdog_callout; + rtems_id receive_task; + unsigned rx_unit_count; + unsigned tx_unit_count; + volatile lpc_eth_transfer_descriptor *rx_desc_table; + volatile lpc_eth_receive_status *rx_status_table; + struct mbuf **rx_mbuf_table; + volatile lpc_eth_transfer_descriptor *tx_desc_table; + volatile uint32_t *tx_status_table; + void *tx_buf_table; + uint32_t tx_produce_index; + uint32_t tx_consume_index; + unsigned received_frames; + unsigned receive_interrupts; + unsigned transmitted_frames; + unsigned receive_drop_errors; + unsigned receive_overrun_errors; + unsigned receive_fragment_errors; + unsigned receive_crc_errors; + unsigned receive_symbol_errors; + unsigned receive_length_errors; + unsigned receive_alignment_errors; + unsigned receive_no_descriptor_errors; + unsigned receive_fatal_errors; + unsigned transmit_underrun_errors; + unsigned transmit_late_collision_errors; + unsigned transmit_excessive_collision_errors; + unsigned transmit_excessive_defer_errors; + unsigned transmit_no_descriptor_errors; + unsigned transmit_overflow_errors; + unsigned transmit_fatal_errors; + uint32_t phy_id; + int phy; + rtems_vector_number interrupt_number; + rtems_id control_task; + int if_flags; + struct ifmedia ifmedia; +} lpc_eth_driver_entry; + +static void lpc_eth_interface_watchdog(void *arg); + +static void lpc_eth_setup_rxfilter(lpc_eth_driver_entry *e); + +static void lpc_eth_control_request_complete(const lpc_eth_driver_entry *e) +{ + rtems_status_code sc = rtems_event_transient_send(e->control_task); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); } -static void -lpe_miibus_statchg(device_t dev) +static void lpc_eth_control_request( + lpc_eth_driver_entry *e, + rtems_id task, + rtems_event_set event +) { - struct lpe_softc *sc = device_get_softc(dev); - struct mii_data *mii = device_get_softc(sc->lpe_miibus); - -#ifndef __rtems__ - lpe_lock(sc); -#endif /* __rtems__ */ - - if ((mii->mii_media_status & IFM_ACTIVE) && - (mii->mii_media_status & IFM_AVALID)) - sc->lpe_flags |= LPE_FLAG_LINK; - else - sc->lpe_flags &= ~LPE_FLAG_LINK; - -#ifndef __rtems__ - lpe_unlock(sc); -#endif /* __rtems__ */ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + e->control_task = rtems_task_self(); + + sc = rtems_event_send(task, event); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); + + e->control_task = 0; } -static void -lpe_reset(struct lpe_softc *sc) +static inline uint32_t lpc_eth_increment( + uint32_t value, + uint32_t cycle +) { - uint32_t mac1; - -#ifndef __rtems__ - /* Enter soft reset mode */ - mac1 = lpe_read_4(sc, LPE_MAC1); - lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | - LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX); - - /* Reset registers, Tx path and Rx path */ - lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_REGRESET | - LPE_COMMAND_TXRESET | LPE_COMMAND_RXRESET); - - /* Set station address */ - lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[1] << 8 | sc->lpe_enaddr[0]); - lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[3] << 8 | sc->lpe_enaddr[2]); - lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[5] << 8 | sc->lpe_enaddr[4]); - - /* Leave soft reset mode */ - mac1 = lpe_read_4(sc, LPE_MAC1); - lpe_write_4(sc, LPE_MAC1, mac1 & ~(LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | - LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX)); -#else /* __rtems__ */ - /* Reset registers, Tx path and Rx path */ - lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_REGRESET | LPE_COMMAND_TXRESET | LPE_COMMAND_RXRESET); - - /* Enter soft reset mode */ - mac1 = lpe_read_4(sc, LPE_MAC1); - lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | - LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX); - - /* Leave soft reset mode */ - mac1 = lpe_read_4(sc, LPE_MAC1); - lpe_write_4(sc, LPE_MAC1, mac1 & ~(LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | - LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX)); - - /* Reinitialize registers */ - lpe_write_4(sc, LPE_MCFG, LPE_MCFG_CLKSEL(0x7)); - lpe_write_4(sc, LPE_MAC2, LPE_MAC2_PADCRCENABLE | LPE_MAC2_CRCENABLE | LPE_MAC2_FULLDUPLEX); - lpe_write_4(sc, LPE_IPGT, 0x15); - lpe_write_4(sc, LPE_IPGR, 0x12); - lpe_write_4(sc, LPE_CLRT, 0x370f); - lpe_write_4(sc, LPE_MAXF, 0x0600); - lpe_write_4(sc, LPE_SUPP, LPE_SUPP_SPEED); - lpe_write_4(sc, LPE_TEST, 0x0); -#ifdef LPC32XX_ETHERNET_RMII - lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_FULLDUPLEX | LPE_COMMAND_RMII); -#else - lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_FULLDUPLEX); -#endif - lpe_write_4(sc, LPE_INTENABLE, 0x0); - lpe_write_4(sc, LPE_INTCLEAR, 0x30ff); - lpe_write_4(sc, LPE_POWERDOWN, 0x0); - - /* Set station address */ - lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[1] << 8 | sc->lpe_enaddr[0]); - lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[3] << 8 | sc->lpe_enaddr[2]); - lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[5] << 8 | sc->lpe_enaddr[4]); -#endif /* __rtems__ */ + if (value < cycle) { + return ++value; + } else { + return 0; + } } -static void -lpe_init(void *arg) +static void lpc_eth_enable_promiscous_mode(bool enable) { - struct lpe_softc *sc = (struct lpe_softc *)arg; - - lpe_lock(sc); - lpe_init_locked(sc); - lpe_unlock(sc); + if (enable) { + lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_UNICAST + | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST + | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; + } else { + lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_PERFECT + | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH + | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; + } } -static void -lpe_init_locked(struct lpe_softc *sc) +static void lpc_eth_interrupt_handler(void *arg) { - struct ifnet *ifp = sc->lpe_ifp; - uint32_t cmd, mac1; - - lpe_lock_assert(sc); - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - return; + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; + rtems_event_set re = 0; + rtems_event_set te = 0; + uint32_t ie = 0; + + /* Get interrupt status */ + uint32_t im = lpc_eth->intenable; + uint32_t is = lpc_eth->intstatus & im; + + /* Check receive interrupts */ + if ((is & (ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN)) != 0) { + if ((is & ETH_INT_RX_OVERRUN) != 0) { + re = LPC_ETH_EVENT_INIT_RX; + ++e->receive_fatal_errors; + } + + if ((is & ETH_INT_TX_UNDERRUN) != 0) { + re = LPC_ETH_EVENT_INIT_TX; + ++e->transmit_fatal_errors; + } + } else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) { + re = LPC_ETH_EVENT_INTERRUPT; + ie |= LPC_ETH_INTERRUPT_RECEIVE; + ++e->receive_interrupts; + } + + /* Send events to receive task */ + if (re != 0) { + (void) rtems_event_send(e->receive_task, re); + } + + LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te); + + /* Update interrupt mask */ + lpc_eth->intenable = im & ~ie; + + /* Clear interrupts */ + lpc_eth->intclear = is; +} - /* Enable Tx and Rx */ - cmd = lpe_read_4(sc, LPE_COMMAND); - lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | - LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME); +static void lpc_eth_enable_receive_interrupts(void) +{ + rtems_interrupt_level level; - /* Enable receive */ - mac1 = lpe_read_4(sc, LPE_MAC1); -#ifdef __rtems__ - (void)mac1; -#endif /* __rtems__ */ - lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL); + rtems_interrupt_disable(level); + lpc_eth->intenable |= LPC_ETH_INTERRUPT_RECEIVE; + rtems_interrupt_enable(level); +} - lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE | - LPE_MAC2_FULLDUPLEX); +static void lpc_eth_disable_receive_interrupts(void) +{ + rtems_interrupt_level level; - lpe_write_4(sc, LPE_MCFG, LPE_MCFG_CLKSEL(7)); + rtems_interrupt_disable(level); + lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_RECEIVE; + rtems_interrupt_enable(level); +} - /* Set up Rx filter */ - lpe_set_rxmode(sc); +static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e) +{ + volatile uint32_t *const status = e->tx_status_table; + uint32_t const index_max = e->tx_unit_count - 1; + volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table; + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + struct mbuf **const mbufs = e->tx_buf_table; + #else + char *const buf = e->tx_buf_table; + #endif + uint32_t produce_index; + + /* Disable transmitter */ + lpc_eth->command &= ~ETH_CMD_TX_ENABLE; + + /* Wait for inactive status */ + while ((lpc_eth->status & ETH_STAT_TX_ACTIVE) != 0) { + /* Wait */ + } + + /* Reset */ + lpc_eth->command |= ETH_CMD_TX_RESET; + + /* Transmit descriptors */ + lpc_eth->txdescriptornum = index_max; + lpc_eth->txdescriptor = (uint32_t) desc; + lpc_eth->txstatus = (uint32_t) status; + + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Discard outstanding fragments (= data loss) */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + m_freem(mbufs [produce_index]); + mbufs [produce_index] = NULL; + } + #else + /* Initialize descriptor table */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + desc [produce_index].start = + (uint32_t) (buf + produce_index * LPC_ETH_CONFIG_TX_BUF_SIZE); + } + #endif + + /* Initialize indices */ + e->tx_produce_index = lpc_eth->txproduceindex; + e->tx_consume_index = lpc_eth->txconsumeindex; + + /* Enable transmitter */ + lpc_eth->command |= ETH_CMD_TX_ENABLE; +} - /* Enable interrupts */ - lpe_write_4(sc, LPE_INTENABLE, LPE_INT_RXOVERRUN | LPE_INT_RXERROR | - LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN | - LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE); +#define LPC_ETH_RX_DATA_OFFSET 2 - sc->lpe_cdata.lpe_tx_prod = 0; - sc->lpe_cdata.lpe_tx_last = 0; - sc->lpe_cdata.lpe_tx_used = 0; +static struct mbuf *lpc_eth_new_mbuf(struct ifnet *ifp, bool wait) +{ + struct mbuf *m = NULL; + int mw = wait ? M_WAITOK : M_NOWAIT; + + MGETHDR(m, mw, MT_DATA); + if (m != NULL) { + MCLGET(m, mw); + if ((m->m_flags & M_EXT) != 0) { + /* Set receive interface */ + m->m_pkthdr.rcvif = ifp; + + /* Adjust by two bytes for proper IP header alignment */ + m->m_data = mtod(m, char *) + LPC_ETH_RX_DATA_OFFSET; + + return m; + } else { + m_free(m); + } + } + + return NULL; +} - lpe_init_rx(sc); +static bool lpc_eth_add_new_mbuf( + struct ifnet *ifp, + volatile lpc_eth_transfer_descriptor *desc, + struct mbuf **mbufs, + uint32_t i, + bool wait +) +{ + /* New mbuf */ + struct mbuf *m = lpc_eth_new_mbuf(ifp, wait); + + /* Check mbuf */ + if (m != NULL) { + /* Cache invalidate */ + rtems_cache_invalidate_multiple_data_lines( + mtod(m, void *), + MCLBYTES - LPC_ETH_RX_DATA_OFFSET + ); + + /* Add mbuf to queue */ + desc [i].start = mtod(m, uint32_t); + desc [i].control = (MCLBYTES - LPC_ETH_RX_DATA_OFFSET - 1) + | ETH_RX_CTRL_INTERRUPT; + + /* Cache flush of descriptor */ + rtems_cache_flush_multiple_data_lines( + (void *) &desc [i], + sizeof(desc [0]) + ); + + /* Add mbuf to table */ + mbufs [i] = m; + + return true; + } else { + return false; + } +} - /* Initialize Rx packet and status descriptor heads */ - lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys); - lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys); - lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1); - lpe_write_4(sc, LPE_RXDESC_CONS, 0); +static void lpc_eth_receive_task(rtems_task_argument arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + lpc_eth_driver_entry *const e = (lpc_eth_driver_entry *) arg; + struct ifnet *const ifp = e->ifp; + volatile lpc_eth_transfer_descriptor *const desc = e->rx_desc_table; + volatile lpc_eth_receive_status *const status = e->rx_status_table; + struct mbuf **const mbufs = e->rx_mbuf_table; + uint32_t const index_max = e->rx_unit_count - 1; + uint32_t produce_index = 0; + uint32_t consume_index = 0; + + LPC_ETH_PRINTF("%s\n", __func__); + + /* Main event loop */ + while (true) { + /* Wait for events */ + sc = rtems_event_receive( + LPC_ETH_EVENT_INIT_RX + | LPC_ETH_EVENT_INIT_TX + | LPC_ETH_EVENT_STOP + | LPC_ETH_EVENT_INTERRUPT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); + + LPC_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events); + + /* Stop receiver? */ + if ((events & LPC_ETH_EVENT_STOP) != 0) { + lpc_eth_control_request_complete(e); + + /* Wait for events */ + continue; + } + + /* Initialize receiver or transmitter? */ + if ((events & (LPC_ETH_EVENT_INIT_RX | LPC_ETH_EVENT_INIT_TX)) != 0) { + if ((events & LPC_ETH_EVENT_INIT_RX) != 0) { + /* Disable receive interrupts */ + lpc_eth_disable_receive_interrupts(); + + /* Disable receiver */ + lpc_eth->command &= ~ETH_CMD_RX_ENABLE; + + /* Wait for inactive status */ + while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) { + /* Wait */ + } + + /* Reset */ + lpc_eth->command |= ETH_CMD_RX_RESET; + + /* Clear receive interrupts */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE; + + /* Move existing mbufs to the front */ + consume_index = 0; + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + if (mbufs [produce_index] != NULL) { + mbufs [consume_index] = mbufs [produce_index]; + ++consume_index; + } + } + + /* Fill receive queue */ + for ( + produce_index = consume_index; + produce_index <= index_max; + ++produce_index + ) { + lpc_eth_add_new_mbuf(ifp, desc, mbufs, produce_index, true); + } + + /* Receive descriptor table */ + lpc_eth->rxdescriptornum = index_max; + lpc_eth->rxdescriptor = (uint32_t) desc; + lpc_eth->rxstatus = (uint32_t) status; + + /* Initialize indices */ + produce_index = lpc_eth->rxproduceindex; + consume_index = lpc_eth->rxconsumeindex; + + /* Enable receiver */ + lpc_eth->command |= ETH_CMD_RX_ENABLE; + + /* Enable receive interrupts */ + lpc_eth_enable_receive_interrupts(); + + lpc_eth_control_request_complete(e); + } + + if ((events & LPC_ETH_EVENT_INIT_TX) != 0) { + LPE_LOCK(e); + lpc_eth_initialize_transmit(e); + LPE_UNLOCK(e); + } + + /* Wait for events */ + continue; + } + + while (true) { + /* Clear receive interrupt status */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE; + + /* Get current produce index */ + produce_index = lpc_eth->rxproduceindex; + + if (consume_index != produce_index) { + uint32_t stat = 0; + + /* Fragment status */ + rtems_cache_invalidate_multiple_data_lines( + (void *) &status [consume_index], + sizeof(status [0]) + ); + stat = status [consume_index].info; + + if ( + (stat & ETH_RX_STAT_LAST_FLAG) != 0 + && (stat & LPC_ETH_RX_STAT_ERRORS) == 0 + ) { + /* Received mbuf */ + struct mbuf *m = mbufs [consume_index]; + + if (lpc_eth_add_new_mbuf(ifp, desc, mbufs, consume_index, false)) { + /* Discard Ethernet CRC */ + int sz = (int) (stat & ETH_RX_STAT_RXSIZE_MASK) + 1 - ETHER_CRC_LEN; + + /* Update mbuf */ + m->m_len = sz; + m->m_pkthdr.len = sz; + + LPC_ETH_PRINTF("rx: %02" PRIu32 ": %u\n", consume_index, sz); + + /* Hand over */ + (*ifp->if_input)(ifp, m); + + /* Increment received frames counter */ + ++e->received_frames; + } else { + ++e->receive_drop_errors; + } + } else { + /* Update error counters */ + if ((stat & ETH_RX_STAT_OVERRUN) != 0) { + ++e->receive_overrun_errors; + } + if ((stat & ETH_RX_STAT_LAST_FLAG) == 0) { + ++e->receive_fragment_errors; + } + if ((stat & ETH_RX_STAT_CRC_ERROR) != 0) { + ++e->receive_crc_errors; + } + if ((stat & ETH_RX_STAT_SYMBOL_ERROR) != 0) { + ++e->receive_symbol_errors; + } + if ((stat & ETH_RX_STAT_LENGTH_ERROR) != 0) { + ++e->receive_length_errors; + } + if ((stat & ETH_RX_STAT_ALIGNMENT_ERROR) != 0) { + ++e->receive_alignment_errors; + } + if ((stat & ETH_RX_STAT_NO_DESCRIPTOR) != 0) { + ++e->receive_no_descriptor_errors; + } + } + + /* Increment and update consume index */ + consume_index = lpc_eth_increment(consume_index, index_max); + lpc_eth->rxconsumeindex = consume_index; + } else { + /* Nothing to do, enable receive interrupts */ + lpc_eth_enable_receive_interrupts(); + break; + } + } + } +} - /* Initialize Tx packet and status descriptor heads */ - lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys); - lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys); - lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1); - lpe_write_4(sc, LPE_TXDESC_PROD, 0); +static struct mbuf *lpc_eth_next_fragment( + struct ifnet *ifp, + struct mbuf *m, + uint32_t *ctrl +) +{ + struct mbuf *n; + int size; + + while (true) { + /* Get fragment size */ + size = m->m_len; + + if (size > 0) { + /* Now we have a not empty fragment */ + break; + } else { + /* Skip empty fragments */ + m = m->m_next; + + if (m == NULL) { + return NULL; + } + } + } + + /* Set fragment size */ + *ctrl = (uint32_t) (size - 1); + + /* Discard empty successive fragments */ + n = m->m_next; + while (n != NULL && n->m_len <= 0) { + n = m_free(n); + } + m->m_next = n; + + /* Is our fragment the last in the frame? */ + if (n == NULL) { + *ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS; + } + + return m; +} - ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; +static void lpc_eth_tx_reclaim(lpc_eth_driver_entry *e, struct ifnet *ifp) +{ + volatile uint32_t *const status = e->tx_status_table; + volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table; + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + struct mbuf **const mbufs = e->tx_buf_table; + #else + char *const buf = e->tx_buf_table; + #endif + uint32_t const index_max = e->tx_unit_count - 1; + uint32_t consume_index = e->tx_consume_index; + + /* Free consumed fragments */ + while (true) { + /* Save last known consume index */ + uint32_t c = consume_index; + + /* Get new consume index */ + consume_index = lpc_eth->txconsumeindex; + + /* Nothing consumed in the meantime? */ + if (c == consume_index) { + break; + } + + while (c != consume_index) { + uint32_t s = status [c]; + + /* Update error counters */ + if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) { + if ((s & ETH_TX_STAT_UNDERRUN) != 0) { + ++e->transmit_underrun_errors; + } + if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) { + ++e->transmit_late_collision_errors; + } + if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) { + ++e->transmit_excessive_collision_errors; + } + if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) { + ++e->transmit_excessive_defer_errors; + } + if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) { + ++e->transmit_no_descriptor_errors; + } + } + + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Release mbuf */ + m_freem(mbufs [c]); + mbufs [c] = NULL; + #endif + + /* Next consume index */ + c = lpc_eth_increment(c, index_max); + } + } + + e->tx_consume_index = consume_index; +} - callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); +static int lpc_eth_tx_enqueue( + lpc_eth_driver_entry *e, + struct ifnet *ifp, + struct mbuf *m0 +) +{ + volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table; + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + struct mbuf **const mbufs = e->tx_buf_table; + #else + char *const buf = e->tx_buf_table; + uint32_t frame_length; + char *frame_buffer; + #endif + uint32_t const index_max = e->tx_unit_count - 1; + uint32_t produce_index = e->tx_produce_index; + uint32_t consume_index = e->tx_consume_index; + struct mbuf *m = m0; + + while (true) { + uint32_t ctrl; + + /* Compute next produce index */ + uint32_t p = lpc_eth_increment(produce_index, index_max); + + /* Queue full? */ + if (p == consume_index) { + LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m); + + /* The queue is full */ + return ENOBUFS; + } + + /* Get next fragment and control value */ + m = lpc_eth_next_fragment(ifp, m, &ctrl); + + /* New fragment? */ + if (m != NULL) { + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Set the transfer data */ + rtems_cache_flush_multiple_data_lines( + mtod(m, const void *), + (size_t) m->m_len + ); + desc [produce_index].start = mtod(m, uint32_t); + desc [produce_index].control = ctrl; + rtems_cache_flush_multiple_data_lines( + (void *) &desc [produce_index], + sizeof(desc [0]) + ); + + LPC_ETH_PRINTF( + "tx: %02" PRIu32 ": %u %s\n", + produce_index, m->m_len, + (ctrl & ETH_TX_CTRL_LAST) != 0 ? "L" : "" + ); + + /* Next produce index */ + produce_index = p; + + /* Last fragment of a frame? */ + if ((ctrl & ETH_TX_CTRL_LAST) != 0) { + /* Update the produce index */ + lpc_eth->txproduceindex = produce_index; + e->tx_produce_index = produce_index; + + mbufs [produce_index] = m0; + + /* Increment transmitted frames counter */ + ++e->transmitted_frames; + + return 0; + } + + /* Next fragment of the frame */ + m = m->m_next; + #else + size_t fragment_length = (size_t) m->m_len; + void *fragment_start = mtod(m, void *); + uint32_t new_frame_length = frame_length + fragment_length; + + /* Check buffer size */ + if (new_frame_length > LPC_ETH_CONFIG_TX_BUF_SIZE) { + LPC_ETH_PRINTF("tx: overflow\n"); + + /* Discard overflow data */ + new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE; + fragment_length = new_frame_length - frame_length; + + /* Finalize frame */ + ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS; + + /* Update error counter */ + ++e->transmit_overflow_errors; + } + + LPC_ETH_PRINTF( + "tx: copy: %" PRIu32 "%s%s\n", + fragment_length, + (m->m_flags & M_EXT) != 0 ? ", E" : "", + (m->m_flags & M_PKTHDR) != 0 ? ", H" : "" + ); + + /* Copy fragment to buffer in Ethernet RAM */ + memcpy(frame_buffer, fragment_start, fragment_length); + + if ((ctrl & ETH_TX_CTRL_LAST) != 0) { + /* Finalize descriptor */ + desc [produce_index].control = (ctrl & ~ETH_TX_CTRL_SIZE_MASK) + | (new_frame_length - 1); + + LPC_ETH_PRINTF( + "tx: %02" PRIu32 ": %" PRIu32 "\n", + produce_index, + new_frame_length + ); + + /* Cache flush of data */ + rtems_cache_flush_multiple_data_lines( + (const void *) desc [produce_index].start, + new_frame_length + ); + + /* Cache flush of descriptor */ + rtems_cache_flush_multiple_data_lines( + (void *) &desc [produce_index], + sizeof(desc [0]) + ); + + /* Next produce index */ + produce_index = p; + + /* Update the produce index */ + lpc_eth->txproduceindex = produce_index; + + /* Fresh frame length and buffer start */ + frame_length = 0; + frame_buffer = (char *) desc [produce_index].start; + + /* Increment transmitted frames counter */ + ++e->transmitted_frames; + } else { + /* New frame length */ + frame_length = new_frame_length; + + /* Update current frame buffer start */ + frame_buffer += fragment_length; + } + + /* Free mbuf and get next */ + m = m_free(m); + #endif + } else { + /* Nothing to transmit */ + m_freem(m0); + return 0; + } + } } -static void -lpe_start(struct ifnet *ifp) +static int lpc_eth_mdio_wait_for_not_busy(void) { - struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc; + rtems_interval one_second = rtems_clock_get_ticks_per_second(); + rtems_interval i = 0; - lpe_lock(sc); - lpe_start_locked(ifp); - lpe_unlock(sc); + while ((lpc_eth->mind & ETH_MIND_BUSY) != 0 && i < one_second) { + rtems_task_wake_after(1); + ++i; + } + + LPC_ETH_PRINTK("tx: lpc_eth_mdio_wait %s after %d\n", + i != one_second? "succeed": "timeout", i); + + return i != one_second ? 0 : ETIMEDOUT; } -static void -lpe_start_locked(struct ifnet *ifp) +static uint32_t lpc_eth_mdio_read_anlpar(int phy) { - struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc; - struct mbuf *m_head; - int encap = 0; + uint32_t madr = ETH_MADR_REG(MII_ANLPAR) | ETH_MADR_PHY(phy); + uint32_t anlpar = 0; + int eno = 0; - lpe_lock_assert(sc); + if (lpc_eth->madr != madr) { + lpc_eth->madr = madr; + } - while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { - if (lpe_read_4(sc, LPE_TXDESC_PROD) == - lpe_read_4(sc, LPE_TXDESC_CONS) - 5) - break; + if (lpc_eth->mcmd != ETH_MCMD_READ) { + lpc_eth->mcmd = 0; + lpc_eth->mcmd = ETH_MCMD_READ; + } - /* Dequeue first packet */ - IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); - if (!m_head) - break; + eno = lpc_eth_mdio_wait_for_not_busy(); + if (eno == 0) { + anlpar = lpc_eth->mrdd; + } - lpe_encap(sc, &m_head); + /* Start next read */ + lpc_eth->mcmd = 0; + lpc_eth->mcmd = ETH_MCMD_READ; - encap++; - } - - /* Submit new descriptor list */ - if (encap) { - lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod); - sc->lpe_watchdog_timer = 5; - } - + return anlpar; } -#ifdef __rtems__ -static int -lpe_get_segs_for_tx(struct mbuf *m, bus_dma_segment_t segs[LPE_MAXFRAGS], - int *nsegs) +static int lpc_eth_mdio_read( + int phy, + void *arg RTEMS_UNUSED, + unsigned reg, + uint32_t *val +) { - int i = 0; - - do { - if (m->m_len > 0) { - segs[i].ds_addr = mtod(m, bus_addr_t); - segs[i].ds_len = m->m_len; -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_flush_multiple_data_lines(m->m_data, m->m_len); -#endif - ++i; - } - m = m->m_next; - if (m == NULL) { - *nsegs = i; - return (0); - } - } while (i < LPE_MAXFRAGS); - return (EFBIG); + int eno = 0; + + if (0 <= phy && phy <= 31) { + lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy); + lpc_eth->mcmd = 0; + lpc_eth->mcmd = ETH_MCMD_READ; + eno = lpc_eth_mdio_wait_for_not_busy(); + + if (eno == 0) { + *val = lpc_eth->mrdd; + } + } else { + eno = EINVAL; + } + + return eno; } -#endif /* __rtems__ */ -static int -lpe_encap(struct lpe_softc *sc, struct mbuf **m_head) -{ - struct lpe_txdesc *txd; - struct lpe_hwdesc *hwd; - bus_dma_segment_t segs[LPE_MAXFRAGS]; - int i, err, nsegs, prod; - - lpe_lock_assert(sc); - M_ASSERTPKTHDR((*m_head)); - - prod = sc->lpe_cdata.lpe_tx_prod; - txd = &sc->lpe_cdata.lpe_tx_desc[prod]; - - debugf("starting with prod=%d\n", prod); - -#ifndef __rtems__ - err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag, - txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT); -#else /* __rtems__ */ - err = lpe_get_segs_for_tx(*m_head, segs, &nsegs); -#endif /* __rtems__ */ - - if (err) - return (err); - - if (nsegs == 0) { - m_freem(*m_head); - *m_head = NULL; - return (EIO); - } - -#ifndef __rtems__ - bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, - BUS_DMASYNC_PREREAD); -#endif /* __rtems__ */ - bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - txd->lpe_txdesc_first = 1; - txd->lpe_txdesc_mbuf = *m_head; - - for (i = 0; i < nsegs; i++) { - hwd = &sc->lpe_rdata.lpe_tx_ring[prod]; - hwd->lhr_data = segs[i].ds_addr; - hwd->lhr_control = segs[i].ds_len - 1; - - if (i == nsegs - 1) { - hwd->lhr_control |= LPE_HWDESC_LASTFLAG; - hwd->lhr_control |= LPE_HWDESC_INTERRUPT; - hwd->lhr_control |= LPE_HWDESC_CRC; - hwd->lhr_control |= LPE_HWDESC_PAD; - } - -#ifdef __rtems__ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_flush_multiple_data_lines(hwd, sizeof(*hwd)); -#endif -#endif /* __rtems__ */ - LPE_INC(prod, LPE_TXDESC_NUM); - } - bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +static int lpc_eth_mdio_write( + int phy, + void *arg RTEMS_UNUSED, + unsigned reg, + uint32_t val +) +{ + int eno = 0; - sc->lpe_cdata.lpe_tx_used += nsegs; - sc->lpe_cdata.lpe_tx_prod = prod; + if (0 <= phy && phy <= 31) { + lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy); + lpc_eth->mwtd = val; + eno = lpc_eth_mdio_wait_for_not_busy(); + } else { + eno = EINVAL; + } - return (0); + return eno; } -static void -lpe_stop(struct lpe_softc *sc) +static int lpc_eth_phy_get_id(int phy, uint32_t *id) { - lpe_lock(sc); - lpe_stop_locked(sc); - lpe_unlock(sc); -} + uint32_t id1 = 0; + int eno = lpc_eth_mdio_read(phy, NULL, MII_PHYIDR1, &id1); -static void -lpe_stop_locked(struct lpe_softc *sc) -{ - lpe_lock_assert(sc); + if (eno == 0) { + uint32_t id2 = 0; - callout_stop(&sc->lpe_tick); + eno = lpc_eth_mdio_read(phy, NULL, MII_PHYIDR2, &id2); + if (eno == 0) { + *id = (id1 << 16) | (id2 & 0xfff0); + } + } - /* Disable interrupts */ - lpe_write_4(sc, LPE_INTCLEAR, 0xffffffff); + return eno; +} - /* Stop EMAC */ - lpe_write_4(sc, LPE_MAC1, 0); - lpe_write_4(sc, LPE_MAC2, 0); - lpe_write_4(sc, LPE_COMMAND, 0); +#define PHY_KSZ80X1RNL 0x221550 +#define PHY_DP83848 0x20005c90 - sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; -} +typedef struct { + unsigned reg; + uint32_t set; + uint32_t clear; +} lpc_eth_phy_action; -static int -lpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +static int lpc_eth_phy_set_and_clear( + lpc_eth_driver_entry *e, + const lpc_eth_phy_action *actions, + size_t n +) { - struct lpe_softc *sc = ifp->if_softc; - struct mii_data *mii = device_get_softc(sc->lpe_miibus); - struct ifreq *ifr = (struct ifreq *)data; - int err = 0; - - switch (cmd) { - case SIOCSIFFLAGS: - lpe_lock(sc); - if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - lpe_set_rxmode(sc); - lpe_set_rxfilter(sc); - } else - lpe_init_locked(sc); - } else - lpe_stop(sc); - lpe_unlock(sc); - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - lpe_lock(sc); - lpe_set_rxfilter(sc); - lpe_unlock(sc); - } - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); - break; - default: - err = ether_ioctl(ifp, cmd, data); - break; - } - - return (err); + int eno = 0; + size_t i; + + for (i = 0; eno == 0 && i < n; ++i) { + const lpc_eth_phy_action *action = &actions [i]; + uint32_t val; + + eno = lpc_eth_mdio_read(e->phy, NULL, action->reg, &val); + if (eno == 0) { + val |= action->set; + val &= ~action->clear; + eno = lpc_eth_mdio_write(e->phy, NULL, action->reg, val); + } + } + + return eno; } -static void lpe_set_rxmode(struct lpe_softc *sc) -{ - struct ifnet *ifp = sc->lpe_ifp; - uint32_t rxfilt; +static const lpc_eth_phy_action lpc_eth_phy_up_action_default [] = { + { MII_BMCR, 0, BMCR_PDOWN }, + { MII_BMCR, BMCR_RESET, 0 }, + { MII_BMCR, BMCR_AUTOEN, 0 } +}; - rxfilt = LPE_RXFILTER_UNIHASH | LPE_RXFILTER_MULTIHASH | LPE_RXFILTER_PERFECT; +static const lpc_eth_phy_action lpc_eth_phy_up_pre_action_KSZ80X1RNL [] = { + /* Disable slow oscillator mode */ + { 0x11, 0, 0x10 } +}; - if (ifp->if_flags & IFF_BROADCAST) - rxfilt |= LPE_RXFILTER_BROADCAST; +static const lpc_eth_phy_action lpc_eth_phy_up_post_action_KSZ80X1RNL [] = { + /* Enable energy detect power down (EDPD) mode */ + { 0x18, 0x0800, 0 }, + /* Turn PLL of automatically in EDPD mode */ + { 0x10, 0x10, 0 } +}; - if (ifp->if_flags & IFF_PROMISC) - rxfilt |= LPE_RXFILTER_UNICAST | LPE_RXFILTER_MULTICAST; +static int lpc_eth_phy_up(lpc_eth_driver_entry *e) +{ + int eno; + int retries = 64; + uint32_t val; + + e->phy = DEFAULT_PHY - 1; + while (true) { + e->phy = (e->phy + 1) % 32; + + --retries; + eno = lpc_eth_phy_get_id(e->phy, &e->phy_id); + if ( + (eno == 0 && e->phy_id != 0xfffffff0 && e->phy_id != 0) + || retries <= 0 + ) { + break; + } + + rtems_task_wake_after(1); + } + + LPC_ETH_PRINTF("lpc_eth_phy_get_id: 0x%08" PRIx32 " from phy %d retries %d\n", + e->phy_id, e->phy, retries); + + if (eno == 0) { + switch (e->phy_id) { + case PHY_KSZ80X1RNL: + eno = lpc_eth_phy_set_and_clear( + e, + &lpc_eth_phy_up_pre_action_KSZ80X1RNL [0], + RTEMS_ARRAY_SIZE(lpc_eth_phy_up_pre_action_KSZ80X1RNL) + ); + break; + case PHY_DP83848: + eno = lpc_eth_mdio_read(e->phy, NULL, 0x17, &val); + LPC_ETH_PRINTF("phy PHY_DP83848 RBR 0x%08" PRIx32 "\n", val); + /* val = 0x21; */ + val = 0x32 ; + eno = lpc_eth_mdio_write(e->phy, NULL, 0x17, val); + break; + case 0: + case 0xfffffff0: + eno = EIO; + e->phy = DEFAULT_PHY; + break; + default: + break; + } + + if (eno == 0) { + eno = lpc_eth_phy_set_and_clear( + e, + &lpc_eth_phy_up_action_default [0], + RTEMS_ARRAY_SIZE(lpc_eth_phy_up_action_default) + ); + } + + if (eno == 0) { + switch (e->phy_id) { + case PHY_KSZ80X1RNL: + eno = lpc_eth_phy_set_and_clear( + e, + &lpc_eth_phy_up_post_action_KSZ80X1RNL [0], + RTEMS_ARRAY_SIZE(lpc_eth_phy_up_post_action_KSZ80X1RNL) + ); + break; + default: + break; + } + } + } else { + e->phy_id = 0; + } + + return eno; +} - if (ifp->if_flags & IFF_ALLMULTI) - rxfilt |= LPE_RXFILTER_MULTICAST; +static const lpc_eth_phy_action lpc_eth_phy_down_action_default [] = { + { MII_BMCR, BMCR_PDOWN, 0 } +}; - lpe_write_4(sc, LPE_RXFILTER_CTRL, rxfilt); -} +static const lpc_eth_phy_action lpc_eth_phy_down_post_action_KSZ80X1RNL [] = { + /* Enable slow oscillator mode */ + { 0x11, 0x10, 0 } +}; -static void lpe_set_rxfilter(struct lpe_softc *sc) +static void lpc_eth_phy_down(lpc_eth_driver_entry *e) { - struct ifnet *ifp = sc->lpe_ifp; - struct ifmultiaddr *ifma; - int index; - uint32_t hashl, hashh; - - hashl = 0; - hashh = 0; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - index = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 23 & 0x3f; - - if (index > 31) - hashh |= (1 << (index - 32)); - else - hashl |= (1 << index); - } - if_maddr_runlock(ifp); - - /* Program new hash filter */ - lpe_write_4(sc, LPE_HASHFILTER_L, hashl); - lpe_write_4(sc, LPE_HASHFILTER_H, hashh); + int eno = lpc_eth_phy_set_and_clear( + e, + &lpc_eth_phy_down_action_default [0], + RTEMS_ARRAY_SIZE(lpc_eth_phy_down_action_default) + ); + + if (eno == 0) { + switch (e->phy_id) { + case PHY_KSZ80X1RNL: + eno = lpc_eth_phy_set_and_clear( + e, + &lpc_eth_phy_down_post_action_KSZ80X1RNL [0], + RTEMS_ARRAY_SIZE(lpc_eth_phy_down_post_action_KSZ80X1RNL) + ); + break; + default: + break; + } + } } -static void -lpe_intr(void *arg) +static void lpc_eth_soft_reset(void) { - struct lpe_softc *sc = (struct lpe_softc *)arg; - uint32_t intstatus; - - debugf("status=0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS)); - - lpe_lock(sc); - - while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) { - if (intstatus & LPE_INT_RXDONE) - lpe_rxintr(sc); - -#ifndef __rtems__ - if (intstatus & LPE_INT_TXDONE) - lpe_txintr(sc); - -#else /* __rtems__ */ - if (intstatus & LPE_INT_TXUNDERRUN) { - if_inc_counter(sc->lpe_ifp, IFCOUNTER_OERRORS, 1); - lpe_stop_locked(sc); - lpe_init_locked(sc); - } - else if (intstatus & (LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE)) - lpe_txintr(sc); -#endif /* __rtems__ */ - lpe_write_4(sc, LPE_INTCLEAR, 0xffff); - } - - lpe_unlock(sc); + lpc_eth->command = 0x38; + lpc_eth->mac1 = 0xcf00; + lpc_eth->mac1 = 0x0; } -static void -lpe_rxintr(struct lpe_softc *sc) +static int lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up) { - struct ifnet *ifp = sc->lpe_ifp; - struct lpe_hwdesc *hwd; - struct lpe_hwstatus *hws; - struct lpe_rxdesc *rxd; - struct mbuf *m; - int prod, cons; - - for (;;) { - prod = lpe_read_4(sc, LPE_RXDESC_PROD); - cons = lpe_read_4(sc, LPE_RXDESC_CONS); - - if (prod == cons) - break; - - rxd = &sc->lpe_cdata.lpe_rx_desc[cons]; - hwd = &sc->lpe_rdata.lpe_rx_ring[cons]; - hws = &sc->lpe_rdata.lpe_rx_status[cons]; -#ifdef __rtems__ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_invalidate_multiple_data_lines(rxd, sizeof(*rxd)); - rtems_cache_invalidate_multiple_data_lines(hwd, sizeof(*hwd)); - rtems_cache_invalidate_multiple_data_lines(hws, sizeof(*hws)); -#endif -#endif /* __rtems__ */ - - /* Check received frame for errors */ - if (hws->lhs_info & LPE_HWDESC_RXERRS) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - lpe_discard_rxbuf(sc, cons); - lpe_init_rxbuf(sc, cons); - goto skip; - } - - m = rxd->lpe_rxdesc_mbuf; -#ifdef __rtems__ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_invalidate_multiple_data_lines(m->m_data, m->m_len); -#endif -#endif /* __rtems__ */ - m->m_pkthdr.rcvif = ifp; - m->m_data += 2; - - if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); - - lpe_unlock(sc); - (*ifp->if_input)(ifp, m); - lpe_lock(sc); - - lpe_init_rxbuf(sc, cons); -skip: - LPE_INC(cons, LPE_RXDESC_NUM); - lpe_write_4(sc, LPE_RXDESC_CONS, cons); - } + int eno = 0; + rtems_status_code sc = RTEMS_SUCCESSFUL; + struct ifnet *ifp = e->ifp; + + if (up && e->state == LPC_ETH_STATE_DOWN) { + lpc_eth_config_module_enable(); + + /* Enable RX/TX reset and disable soft reset */ + lpc_eth->mac1 = 0xf00; + + /* Initialize PHY */ + /* Clock value 10 (divide by 44 ) is safe on LPC178x up to 100 MHz AHB clock */ + lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10) | ETH_MCFG_RESETMIIMGMT; + rtems_task_wake_after(1); + lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10); + rtems_task_wake_after(1); + eno = lpc_eth_phy_up(e); + + if (eno == 0) { + const uint8_t *eaddr; + + /* + * We must have a valid external clock from the PHY at this point, + * otherwise the system bus hangs and only a watchdog reset helps. + */ + lpc_eth_soft_reset(); + + /* Reinitialize registers */ + lpc_eth->mac2 = 0x31; + lpc_eth->ipgt = 0x15; + lpc_eth->ipgr = 0x12; + lpc_eth->clrt = 0x370f; + lpc_eth->maxf = 0x0600; + lpc_eth->supp = ETH_SUPP_SPEED; + lpc_eth->test = 0; + #ifdef LPC_ETH_CONFIG_RMII + lpc_eth->command = 0x0600; + #else + lpc_eth->command = 0x0400; + #endif + lpc_eth->intenable = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN; + lpc_eth->intclear = 0x30ff; + lpc_eth->powerdown = 0; + + /* MAC address */ + eaddr = IF_LLADDR(e->ifp); + lpc_eth->sa0 = ((uint32_t) eaddr [5] << 8) | (uint32_t) eaddr [4]; + lpc_eth->sa1 = ((uint32_t) eaddr [3] << 8) | (uint32_t) eaddr [2]; + lpc_eth->sa2 = ((uint32_t) eaddr [1] << 8) | (uint32_t) eaddr [0]; + + lpc_eth_setup_rxfilter(e); + + /* Enable receiver */ + lpc_eth->mac1 = 0x03; + + /* Initialize tasks */ + lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_INIT_RX); + lpc_eth_initialize_transmit(e); + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + e->interrupt_number, + "Ethernet", + RTEMS_INTERRUPT_UNIQUE, + lpc_eth_interrupt_handler, + e + ); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); + + /* Start watchdog timer */ + callout_reset(&e->watchdog_callout, hz, lpc_eth_interface_watchdog, e); + + /* Change state */ + ifp->if_drv_flags |= IFF_DRV_RUNNING; + e->state = LPC_ETH_STATE_UP; + } + } else if (!up && e->state == LPC_ETH_STATE_UP) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + + /* Remove interrupt handler */ + sc = rtems_interrupt_handler_remove( + e->interrupt_number, + lpc_eth_interrupt_handler, + e + ); + BSD_ASSERT(sc == RTEMS_SUCCESSFUL); + + /* Stop task */ + lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_STOP); + + lpc_eth_soft_reset(); + lpc_eth_phy_down(e); + lpc_eth_config_module_disable(); + + /* Stop watchdog timer */ + callout_stop(&e->watchdog_callout); + + /* Change state */ + e->state = LPC_ETH_STATE_DOWN; + } + + return eno; } -static void -lpe_txintr(struct lpe_softc *sc) +static void lpc_eth_interface_init(void *arg) { - struct ifnet *ifp = sc->lpe_ifp; - struct lpe_hwdesc *hwd; - struct lpe_hwstatus *hws; - struct lpe_txdesc *txd; - int cons, last; - - for (;;) { - cons = lpe_read_4(sc, LPE_TXDESC_CONS); - last = sc->lpe_cdata.lpe_tx_last; - - if (cons == last) - break; - - txd = &sc->lpe_cdata.lpe_tx_desc[last]; - hwd = &sc->lpe_rdata.lpe_tx_ring[last]; - hws = &sc->lpe_rdata.lpe_tx_status[last]; - -#ifndef __rtems__ - bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, - txd->lpe_txdesc_dmamap, BUS_DMASYNC_POSTWRITE); -#else /* __rtems__ */ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_invalidate_multiple_data_lines(txd, sizeof(*txd)); - rtems_cache_invalidate_multiple_data_lines(hwd, sizeof(*hwd)); - rtems_cache_invalidate_multiple_data_lines(hws, sizeof(*hws)); -#endif -#endif /* __rtems__ */ - - if_inc_counter(ifp, IFCOUNTER_COLLISIONS, LPE_HWDESC_COLLISIONS(hws->lhs_info)); + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; - if (hws->lhs_info & LPE_HWDESC_TXERRS) - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - else - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - - if (txd->lpe_txdesc_first) { -#ifndef __rtems__ - bus_dmamap_unload(sc->lpe_cdata.lpe_tx_buf_tag, - txd->lpe_txdesc_dmamap); -#endif /* __rtems__ */ - - m_freem(txd->lpe_txdesc_mbuf); - txd->lpe_txdesc_mbuf = NULL; - txd->lpe_txdesc_first = 0; - } + (void) lpc_eth_up_or_down(e, true); +} - sc->lpe_cdata.lpe_tx_used--; - LPE_INC(sc->lpe_cdata.lpe_tx_last, LPE_TXDESC_NUM); - } +static void lpc_eth_setup_rxfilter(lpc_eth_driver_entry *e) +{ + struct ifnet *ifp = e->ifp; + + lpc_eth_enable_promiscous_mode((ifp->if_flags & IFF_PROMISC) != 0); + + if ((ifp->if_flags & IFF_ALLMULTI)) { + lpc_eth->hashfilterl = 0xffffffff; + lpc_eth->hashfilterh = 0xffffffff; + } else { + struct ifmultiaddr *ifma; + + lpc_eth->hashfilterl = 0x0; + lpc_eth->hashfilterh = 0x0; + + if_maddr_rlock(ifp); + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + uint32_t crc; + uint32_t index; + + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + + /* XXX: ether_crc32_le() does not work, why? */ + crc = ether_crc32_be( + LLADDR((struct sockaddr_dl *) ifma->ifma_addr), + ETHER_ADDR_LEN + ); + index = (crc >> 23) & 0x3f; + + if (index < 32) { + lpc_eth->hashfilterl |= 1U << index; + } else { + lpc_eth->hashfilterh |= 1U << (index - 32); + } + } + if_maddr_runlock(ifp); + } +} - if (!sc->lpe_cdata.lpe_tx_used) - sc->lpe_watchdog_timer = 0; +static int lpc_eth_interface_ioctl( + struct ifnet *ifp, + ioctl_command_t cmd, + caddr_t data +) +{ + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int eno = 0; + + LPC_ETH_PRINTF("%s\n", __func__); + + switch (cmd) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + eno = ifmedia_ioctl(ifp, ifr, &e->ifmedia, cmd); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl(ifp, cmd, data); + break; + case SIOCSIFFLAGS: + LPE_LOCK(e); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ e->if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) { + lpc_eth_setup_rxfilter(e); + } + } else { + eno = lpc_eth_up_or_down(e, true); + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + eno = lpc_eth_up_or_down(e, false); + } + } + e->if_flags = ifp->if_flags; + LPE_UNLOCK(e); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + LPE_LOCK(e); + lpc_eth_setup_rxfilter(e); + LPE_UNLOCK(e); + } + break; + default: + eno = ether_ioctl(ifp, cmd, data); + break; + } + + return eno; } -static void -lpe_tick(void *arg) +static int lpc_eth_interface_transmit(struct ifnet *ifp, struct mbuf *m) { - struct lpe_softc *sc = (struct lpe_softc *)arg; - struct mii_data *mii = device_get_softc(sc->lpe_miibus); + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc; + int eno; - lpe_lock_assert(sc); - - mii_tick(mii); - lpe_watchdog(sc); + LPE_LOCK(e); - callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); -} + if (e->state == LPC_ETH_STATE_UP) { + eno = lpc_eth_tx_enqueue(e, ifp, m); + lpc_eth_tx_reclaim(e, ifp); -static void -lpe_watchdog(struct lpe_softc *sc) -{ - struct ifnet *ifp = sc->lpe_ifp; + if (__predict_false(eno != 0)) { + struct mbuf *n; - lpe_lock_assert(sc); + n = m_defrag(m, M_NOWAIT); + if (n != NULL) { + m = n; + } - if (sc->lpe_watchdog_timer == 0 || sc->lpe_watchdog_timer--) - return; + eno = lpc_eth_tx_enqueue(e, ifp, m); + } + } else { + eno = ENETDOWN; + } - /* Chip has stopped responding */ - device_printf(sc->lpe_dev, "WARNING: chip hangup, restarting...\n"); - lpe_stop_locked(sc); - lpe_init_locked(sc); + if (eno != 0) { + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); + } - /* Try to resend packets */ - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - lpe_start_locked(ifp); + LPE_UNLOCK(e); + return eno; } -static int -lpe_dma_alloc(struct lpe_softc *sc) +static void lpc_eth_interface_watchdog(void *arg) { - int err; - - /* Create parent DMA tag */ - err = bus_dma_tag_create( - bus_get_dma_tag(sc->lpe_dev), - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ - BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_parent_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create parent DMA tag\n"); - return (err); - } - - err = lpe_dma_alloc_rx(sc); - if (err) - return (err); - - err = lpe_dma_alloc_tx(sc); - if (err) - return (err); - - return (0); + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; + + if (e->state == LPC_ETH_STATE_UP) { + uint32_t anlpar = lpc_eth_mdio_read_anlpar(e->phy); + + if (e->anlpar != anlpar) { + bool full_duplex = false; + bool speed = false; + + e->anlpar = anlpar; + + if ((anlpar & ANLPAR_TX_FD) != 0) { + full_duplex = true; + speed = true; + } else if ((anlpar & ANLPAR_T4) != 0) { + speed = true; + } else if ((anlpar & ANLPAR_TX) != 0) { + speed = true; + } else if ((anlpar & ANLPAR_10_FD) != 0) { + full_duplex = true; + } + + if (full_duplex) { + lpc_eth->mac2 |= ETH_MAC2_FULL_DUPLEX; + } else { + lpc_eth->mac2 &= ~ETH_MAC2_FULL_DUPLEX; + } + + if (speed) { + lpc_eth->supp |= ETH_SUPP_SPEED; + } else { + lpc_eth->supp &= ~ETH_SUPP_SPEED; + } + } + + callout_reset(&e->watchdog_callout, WATCHDOG_TIMEOUT * hz, lpc_eth_interface_watchdog, e); + } } -static int -lpe_dma_alloc_rx(struct lpe_softc *sc) +static int lpc_eth_media_change(struct ifnet *ifp) { - struct lpe_rxdesc *rxd; - struct lpe_dmamap_arg ctx; - int err, i; - - /* Create tag for Rx ring */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - LPE_RXDESC_SIZE, 1, /* maxsize, nsegments */ - LPE_RXDESC_SIZE, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_rx_ring_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Rx ring DMA tag\n"); - goto fail; - } - - /* Create tag for Rx status ring */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - LPE_RXSTATUS_SIZE, 1, /* maxsize, nsegments */ - LPE_RXSTATUS_SIZE, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_rx_status_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Rx status ring DMA tag\n"); - goto fail; - } - - /* Create tag for Rx buffers */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES * LPE_RXDESC_NUM, /* maxsize */ - LPE_RXDESC_NUM, /* segments */ - MCLBYTES, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_rx_buf_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Rx buffers DMA tag\n"); - goto fail; - } - - /* Allocate Rx DMA ring */ - err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_ring_tag, - (void **)&sc->lpe_rdata.lpe_rx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | - BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_ring_map); - - err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_ring_tag, - sc->lpe_cdata.lpe_rx_ring_map, sc->lpe_rdata.lpe_rx_ring, - LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); - - sc->lpe_rdata.lpe_rx_ring_phys = ctx.lpe_dma_busaddr; - - /* Allocate Rx status ring */ - err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_status_tag, - (void **)&sc->lpe_rdata.lpe_rx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT | - BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_status_map); - - err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_status_tag, - sc->lpe_cdata.lpe_rx_status_map, sc->lpe_rdata.lpe_rx_status, - LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); - - sc->lpe_rdata.lpe_rx_status_phys = ctx.lpe_dma_busaddr; - - - /* Create Rx buffers DMA map */ - for (i = 0; i < LPE_RXDESC_NUM; i++) { - rxd = &sc->lpe_cdata.lpe_rx_desc[i]; - rxd->lpe_rxdesc_mbuf = NULL; -#ifndef __rtems__ - rxd->lpe_rxdesc_dmamap = NULL; - - err = bus_dmamap_create(sc->lpe_cdata.lpe_rx_buf_tag, 0, - &rxd->lpe_rxdesc_dmamap); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Rx DMA map\n"); - return (err); - } -#endif /* __rtems__ */ - } - - return (0); -fail: - return (err); + (void) ifp; + return EINVAL; } -static int -lpe_dma_alloc_tx(struct lpe_softc *sc) +static void lpc_eth_media_status(struct ifnet *ifp, struct ifmediareq *imr) { - struct lpe_txdesc *txd; - struct lpe_dmamap_arg ctx; - int err, i; - - /* Create tag for Tx ring */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - LPE_TXDESC_SIZE, 1, /* maxsize, nsegments */ - LPE_TXDESC_SIZE, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_tx_ring_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Tx ring DMA tag\n"); - goto fail; - } - - /* Create tag for Tx status ring */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - LPE_TXSTATUS_SIZE, 1, /* maxsize, nsegments */ - LPE_TXSTATUS_SIZE, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_tx_status_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Tx status ring DMA tag\n"); - goto fail; - } - - /* Create tag for Tx buffers */ - err = bus_dma_tag_create( - sc->lpe_cdata.lpe_parent_tag, - LPE_DESC_ALIGN, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES * LPE_TXDESC_NUM, /* maxsize */ - LPE_TXDESC_NUM, /* segments */ - MCLBYTES, 0, /* maxsegsize, flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->lpe_cdata.lpe_tx_buf_tag); - - if (err) { - device_printf(sc->lpe_dev, "cannot create Tx buffers DMA tag\n"); - goto fail; - } - - /* Allocate Tx DMA ring */ - err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_ring_tag, - (void **)&sc->lpe_rdata.lpe_tx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | - BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_ring_map); - - err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_ring_tag, - sc->lpe_cdata.lpe_tx_ring_map, sc->lpe_rdata.lpe_tx_ring, - LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); - - sc->lpe_rdata.lpe_tx_ring_phys = ctx.lpe_dma_busaddr; - - /* Allocate Tx status ring */ - err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_status_tag, - (void **)&sc->lpe_rdata.lpe_tx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT | - BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_status_map); - - err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_status_tag, - sc->lpe_cdata.lpe_tx_status_map, sc->lpe_rdata.lpe_tx_status, - LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); - - sc->lpe_rdata.lpe_tx_status_phys = ctx.lpe_dma_busaddr; - - - /* Create Tx buffers DMA map */ - for (i = 0; i < LPE_TXDESC_NUM; i++) { - txd = &sc->lpe_cdata.lpe_tx_desc[i]; - txd->lpe_txdesc_mbuf = NULL; -#ifndef __rtems__ - txd->lpe_txdesc_dmamap = NULL; -#endif /* __rtems__ */ - txd->lpe_txdesc_first = 0; - -#ifndef __rtems__ - err = bus_dmamap_create(sc->lpe_cdata.lpe_tx_buf_tag, 0, - &txd->lpe_txdesc_dmamap); -#endif /* __rtems__ */ - - if (err) { - device_printf(sc->lpe_dev, "cannot create Tx DMA map\n"); - return (err); - } - } - - return (0); -fail: - return (err); + (void) ifp; + + imr->ifm_status = IFM_AVALID | IFM_ACTIVE; + imr->ifm_active = IFM_ETHER; + + if ((lpc_eth->supp & ETH_SUPP_SPEED) != 0) { + imr->ifm_active |= IFM_100_TX; + } else { + imr->ifm_active |= IFM_10_T; + } + + if ((lpc_eth->mac2 & ETH_MAC2_FULL_DUPLEX) != 0) { + imr->ifm_active |= IFM_FDX; + } else { + imr->ifm_active |= IFM_HDX; + } } -static int -lpe_init_rx(struct lpe_softc *sc) +__weak_symbol int lpc_eth_probe(int unit) { - int i, err; + if (unit != 0) { + return ENXIO; + } - for (i = 0; i < LPE_RXDESC_NUM; i++) { - err = lpe_init_rxbuf(sc, i); - if (err) - return (err); - } - - return (0); + return BUS_PROBE_DEFAULT; } -static int -lpe_init_rxbuf(struct lpe_softc *sc, int n) +static int lpc_eth_do_probe(device_t dev) { - struct lpe_rxdesc *rxd; - struct lpe_hwdesc *hwd; -#ifndef __rtems__ - struct lpe_hwstatus *hws; -#endif /* __rtems__ */ - struct mbuf *m; - bus_dma_segment_t segs[1]; -#ifndef __rtems__ - int nsegs; -#endif /* __rtems__ */ - - rxd = &sc->lpe_cdata.lpe_rx_desc[n]; - hwd = &sc->lpe_rdata.lpe_rx_ring[n]; -#ifndef __rtems__ - hws = &sc->lpe_rdata.lpe_rx_status[n]; -#endif /* __rtems__ */ - m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); - - if (!m) { - device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n"); - return (ENOBUFS); - } - - m->m_len = m->m_pkthdr.len = MCLBYTES; - -#ifndef __rtems__ - bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); - - if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag, - rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) { - m_freem(m); - return (ENOBUFS); - } - - bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, - BUS_DMASYNC_PREREAD); -#else /* __rtems__ */ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_invalidate_multiple_data_lines(m->m_data, m->m_len); -#endif - segs[0].ds_addr = mtod(m, bus_addr_t); -#endif /* __rtems__ */ - - rxd->lpe_rxdesc_mbuf = m; - hwd->lhr_data = segs[0].ds_addr + 2; - hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT; -#ifdef __rtems__ -#ifdef CPU_DATA_CACHE_ALIGNMENT - rtems_cache_flush_multiple_data_lines(hwd, sizeof(*hwd)); -#endif -#endif /* __rtems__ */ - - return (0); + device_set_desc(dev, "LPC32x0 Ethernet controller"); + return lpc_eth_probe(device_get_unit(dev)); } -static void -lpe_discard_rxbuf(struct lpe_softc *sc, int n) +static int lpc_eth_attach(device_t dev) { - struct lpe_rxdesc *rxd; - struct lpe_hwdesc *hwd; - - rxd = &sc->lpe_cdata.lpe_rx_desc[n]; - hwd = &sc->lpe_rdata.lpe_rx_ring[n]; - -#ifndef __rtems__ - bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); -#endif /* __rtems__ */ - - hwd->lhr_data = 0; - hwd->lhr_control = 0; - - if (rxd->lpe_rxdesc_mbuf) { - m_freem(rxd->lpe_rxdesc_mbuf); - rxd->lpe_rxdesc_mbuf = NULL; - } + lpc_eth_driver_entry *e = device_get_softc(dev); + struct ifnet *ifp = NULL; + char *unit_name = NULL; + int unit_index = device_get_unit(dev); + size_t table_area_size = 0; + char *table_area = NULL; + char *table_location = NULL; + rtems_status_code status; + uint8_t eaddr[ETHER_ADDR_LEN]; + + BSD_ASSERT(e->state == LPC_ETH_STATE_NOT_INITIALIZED); + + mtx_init(&e->mtx, device_get_nameunit(e->dev), MTX_NETWORK_LOCK, MTX_DEF); + + ifmedia_init(&e->ifmedia, 0, lpc_eth_media_change, lpc_eth_media_status); + ifmedia_add(&e->ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&e->ifmedia, IFM_ETHER | IFM_AUTO); + + callout_init_mtx(&e->watchdog_callout, &e->mtx, 0); + + /* Receive unit count */ + e->rx_unit_count = LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT; + + /* Transmit unit count */ + e->tx_unit_count = LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT; + + /* Remember interrupt number */ + e->interrupt_number = LPC_ETH_CONFIG_INTERRUPT; + + /* Allocate and clear table area */ + table_area_size = + e->rx_unit_count + * (sizeof(lpc_eth_transfer_descriptor) + + sizeof(lpc_eth_receive_status) + + sizeof(struct mbuf *)) + + e->tx_unit_count + * (sizeof(lpc_eth_transfer_descriptor) + + sizeof(uint32_t) + + LPC_ETH_CONFIG_TX_BUF_SIZE); + table_area = lpc_eth_config_alloc_table_area(table_area_size); + if (table_area == NULL) { + return ENOMEM; + } + memset(table_area, 0, table_area_size); + + table_location = table_area; + + /* + * The receive status table must be the first one since it has the strictest + * alignment requirements. + */ + e->rx_status_table = (volatile lpc_eth_receive_status *) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_status_table [0]); + + e->rx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_desc_table [0]); + + e->rx_mbuf_table = (struct mbuf **) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_mbuf_table [0]); + + e->tx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location; + table_location += e->tx_unit_count * sizeof(e->tx_desc_table [0]); + + e->tx_status_table = (volatile uint32_t *) table_location; + table_location += e->tx_unit_count * sizeof(e->tx_status_table [0]); + + e->tx_buf_table = table_location; + + /* Set interface data */ + e->dev = dev; + e->ifp = ifp = if_alloc(IFT_ETHER); + ifp->if_softc = e; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_init = lpc_eth_interface_init; + ifp->if_ioctl = lpc_eth_interface_ioctl; + ifp->if_transmit = lpc_eth_interface_transmit; + ifp->if_qflush = if_qflush; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; + IFQ_SET_MAXLEN(&ifp->if_snd, LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX - 1); + ifp->if_snd.ifq_drv_maxlen = LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX - 1; + IFQ_SET_READY(&ifp->if_snd); + ifp->if_hdrlen = sizeof(struct ether_header); + + rtems_bsd_get_mac_address(device_get_name(e->dev), unit_index, eaddr); + + /* Create tasks */ + status = rtems_task_create( + rtems_build_name('n', 't', 'r', 'x'), + rtems_bsd_get_task_priority(device_get_name(e->dev)), + 4096, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &e->receive_task + ); + BSD_ASSERT(status == RTEMS_SUCCESSFUL); + status = rtems_task_start( + e->receive_task, + lpc_eth_receive_task, + (rtems_task_argument)e + ); + BSD_ASSERT(status == RTEMS_SUCCESSFUL); + + if_link_state_change(e->ifp, LINK_STATE_UP); + + /* Change status */ + e->state = LPC_ETH_STATE_DOWN; + + /* Attach the interface */ + ether_ifattach(ifp, eaddr); + + return 0; } -static void -lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +static int lpc_eth_detach(device_t dev) { - struct lpe_dmamap_arg *ctx; + /* FIXME: Detach the interface from the upper layers? */ - if (error) - return; + /* Module soft reset */ + lpc_eth->command = 0x38; + lpc_eth->mac1 = 0xcf00; - ctx = (struct lpe_dmamap_arg *)arg; - ctx->lpe_dma_busaddr = segs[0].ds_addr; -} + /* FIXME: More cleanup */ -static int -lpe_ifmedia_upd(struct ifnet *ifp) -{ - return (0); -} - -static void -lpe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) -{ - struct lpe_softc *sc = ifp->if_softc; - struct mii_data *mii = device_get_softc(sc->lpe_miibus); - - lpe_lock(sc); - mii_pollstat(mii); - ifmr->ifm_active = mii->mii_media_active; - ifmr->ifm_status = mii->mii_media_status; - lpe_unlock(sc); + return ENXIO; } static device_method_t lpe_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, lpe_probe), - DEVMETHOD(device_attach, lpe_attach), - DEVMETHOD(device_detach, lpe_detach), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - /* MII interface */ - DEVMETHOD(miibus_readreg, lpe_miibus_readreg), - DEVMETHOD(miibus_writereg, lpe_miibus_writereg), - DEVMETHOD(miibus_statchg, lpe_miibus_statchg), - { 0, 0 } + DEVMETHOD(device_probe, lpc_eth_do_probe), + DEVMETHOD(device_attach, lpc_eth_attach), + DEVMETHOD(device_detach, lpc_eth_detach), + DEVMETHOD_END }; -static driver_t lpe_driver = { - "lpe", - lpe_methods, - sizeof(struct lpe_softc), +static driver_t lpe_nexus_driver = { + "lpe", + lpe_methods, + sizeof(lpc_eth_driver_entry) }; static devclass_t lpe_devclass; - -#ifndef __rtems__ -DRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0); -#else /* __rtems__ */ -DRIVER_MODULE(lpe, nexus, lpe_driver, lpe_devclass, 0, 0); -#endif /* __rtems__ */ -DRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0); -MODULE_DEPEND(lpe, obio, 1, 1, 1); -MODULE_DEPEND(lpe, miibus, 1, 1, 1); +DRIVER_MODULE(lpe, nexus, lpe_nexus_driver, lpe_devclass, 0, 0); +MODULE_DEPEND(lpe, nexus, 1, 1, 1); MODULE_DEPEND(lpe, ether, 1, 1, 1); + +#endif /* LIBBSP_ARM_LPC24XX_BSP_H || LIBBSP_ARM_LPC32XX_BSP_H */ diff --git a/rtemsbsd/sys/arm/lpc/if_lpereg.h b/rtemsbsd/sys/arm/lpc/if_lpereg.h deleted file mode 100644 index a40bf8b5..00000000 --- a/rtemsbsd/sys/arm/lpc/if_lpereg.h +++ /dev/null @@ -1,210 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _ARM_LPC_IF_LPEREG_H -#define _ARM_LPC_IF_LPEREG_H - -#define LPE_MAC1 0x000 -#define LPE_MAC1_RXENABLE (1 << 0) -#define LPE_MAC1_PASSALL (1 << 1) -#define LPE_MAC1_RXFLOWCTRL (1 << 2) -#define LPE_MAC1_TXFLOWCTRL (1 << 3) -#define LPE_MAC1_LOOPBACK (1 << 4) -#define LPE_MAC1_RESETTX (1 << 8) -#define LPE_MAC1_RESETMCSTX (1 << 9) -#define LPE_MAC1_RESETRX (1 << 10) -#define LPE_MAC1_RESETMCSRX (1 << 11) -#define LPE_MAC1_SIMRESET (1 << 14) -#define LPE_MAC1_SOFTRESET (1 << 15) -#define LPE_MAC2 0x004 -#define LPE_MAC2_FULLDUPLEX (1 << 0) -#define LPE_MAC2_FRAMELENCHECK (1 << 1) -#define LPE_MAC2_HUGEFRAME (1 << 2) -#define LPE_MAC2_DELAYEDCRC (1 << 3) -#define LPE_MAC2_CRCENABLE (1 << 4) -#define LPE_MAC2_PADCRCENABLE (1 << 5) -#define LPE_MAC2_VLANPADENABLE (1 << 6) -#define LPE_MAC2_AUTOPADENABLE (1 << 7) -#define LPE_MAC2_PUREPREAMBLE (1 << 8) -#define LPE_MAC2_LONGPREAMBLE (1 << 9) -#define LPE_MAC2_NOBACKOFF (1 << 12) -#define LPE_MAC2_BACKPRESSURE (1 << 13) -#define LPE_MAC2_EXCESSDEFER (1 << 14) -#define LPE_IPGT 0x008 -#define LPE_IPGR 0x00c -#define LPE_CLRT 0x010 -#define LPE_MAXF 0x014 -#define LPE_SUPP 0x018 -#define LPE_SUPP_SPEED (1 << 8) -#define LPE_TEST 0x01c -#define LPE_MCFG 0x020 -#define LPE_MCFG_SCANINCR (1 << 0) -#define LPE_MCFG_SUPPREAMBLE (1 << 1) -#define LPE_MCFG_CLKSEL(_n) ((_n & 0x7) << 2) -#define LPC_MCFG_RESETMII (1 << 15) -#define LPE_MCMD 0x024 -#define LPE_MCMD_READ (1 << 0) -#define LPE_MCMD_WRITE (0 << 0) -#define LPE_MCMD_SCAN (1 << 1) -#define LPE_MADR 0x028 -#define LPE_MADR_REGMASK 0x1f -#define LPE_MADR_REGSHIFT 0 -#define LPE_MADR_PHYMASK 0x1f -#define LPE_MADR_PHYSHIFT 8 -#define LPE_MWTD 0x02c -#define LPE_MWTD_DATAMASK 0xffff -#define LPE_MRDD 0x030 -#define LPE_MRDD_DATAMASK 0xffff -#define LPE_MIND 0x034 -#define LPE_MIND_BUSY (1 << 0) -#define LPE_MIND_SCANNING (1 << 1) -#define LPE_MIND_INVALID (1 << 2) -#define LPE_MIND_MIIFAIL (1 << 3) -#define LPE_SA0 0x040 -#define LPE_SA1 0x044 -#define LPE_SA2 0x048 -#define LPE_COMMAND 0x100 -#define LPE_COMMAND_RXENABLE (1 << 0) -#define LPE_COMMAND_TXENABLE (1 << 1) -#define LPE_COMMAND_REGRESET (1 << 3) -#define LPE_COMMAND_TXRESET (1 << 4) -#define LPE_COMMAND_RXRESET (1 << 5) -#define LPE_COMMAND_PASSRUNTFRAME (1 << 6) -#define LPE_COMMAND_PASSRXFILTER (1 << 7) -#define LPE_COMMAND_TXFLOWCTL (1 << 8) -#define LPE_COMMAND_RMII (1 << 9) -#define LPE_COMMAND_FULLDUPLEX (1 << 10) -#define LPE_STATUS 0x104 -#define LPE_STATUS_RXACTIVE (1 << 0) -#define LPE_STATUS_TXACTIVE (1 << 1) -#define LPE_RXDESC 0x108 -#define LPE_RXSTATUS 0x10c -#define LPE_RXDESC_NUMBER 0x110 -#define LPE_RXDESC_PROD 0x114 -#define LPE_RXDESC_CONS 0x118 -#define LPE_TXDESC 0x11c -#define LPE_TXSTATUS 0x120 -#define LPE_TXDESC_NUMBER 0x124 -#define LPE_TXDESC_PROD 0x128 -#define LPE_TXDESC_CONS 0x12c -#define LPE_TSV0 0x158 -#define LPE_TSV1 0x15c -#define LPE_RSV 0x160 -#define LPE_FLOWCONTROL_COUNTER 0x170 -#define LPE_FLOWCONTROL_STATUS 0x174 -#define LPE_RXFILTER_CTRL 0x200 -#define LPE_RXFILTER_UNICAST (1 << 0) -#define LPE_RXFILTER_BROADCAST (1 << 1) -#define LPE_RXFILTER_MULTICAST (1 << 2) -#define LPE_RXFILTER_UNIHASH (1 << 3) -#define LPE_RXFILTER_MULTIHASH (1 << 4) -#define LPE_RXFILTER_PERFECT (1 << 5) -#define LPE_RXFILTER_WOL (1 << 12) -#define LPE_RXFILTER_FILTWOL (1 << 13) -#define LPE_RXFILTER_WOL_STATUS 0x204 -#define LPE_RXFILTER_WOL_CLEAR 0x208 -#define LPE_HASHFILTER_L 0x210 -#define LPE_HASHFILTER_H 0x214 -#define LPE_INTSTATUS 0xfe0 -#define LPE_INTENABLE 0xfe4 -#define LPE_INTCLEAR 0xfe8 -#define LPE_INTSET 0xfec -#define LPE_INT_RXOVERRUN (1 << 0) -#define LPE_INT_RXERROR (1 << 1) -#define LPE_INT_RXFINISH (1 << 2) -#define LPE_INT_RXDONE (1 << 3) -#define LPE_INT_TXUNDERRUN (1 << 4) -#define LPE_INT_TXERROR (1 << 5) -#define LPE_INT_TXFINISH (1 << 6) -#define LPE_INT_TXDONE (1 << 7) -#define LPE_INT_SOFTINT (1 << 12) -#define LPE_INTWAKEUPINT (1 << 13) -#define LPE_POWERDOWN 0xff4 - -#define LPE_DESC_ALIGN 8 -#define LPE_TXDESC_NUM 128 -#define LPE_RXDESC_NUM 128 -#define LPE_TXDESC_SIZE (LPE_TXDESC_NUM * sizeof(struct lpe_hwdesc)) -#define LPE_RXDESC_SIZE (LPE_RXDESC_NUM * sizeof(struct lpe_hwdesc)) -#define LPE_TXSTATUS_SIZE (LPE_TXDESC_NUM * sizeof(struct lpe_hwstatus)) -#define LPE_RXSTATUS_SIZE (LPE_RXDESC_NUM * sizeof(struct lpe_hwstatus)) -#define LPE_MAXFRAGS 8 - -struct lpe_hwdesc { - uint32_t lhr_data; - uint32_t lhr_control; -}; - -struct lpe_hwstatus { - uint32_t lhs_info; - uint32_t lhs_crc; -}; - -#define LPE_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1 - -/* These are valid for both Rx and Tx descriptors */ -#define LPE_HWDESC_SIZE_MASK (1 << 10) -#define LPE_HWDESC_INTERRUPT (1U << 31) - -/* These are valid for Tx descriptors */ -#define LPE_HWDESC_LAST (1 << 30) -#define LPE_HWDESC_CRC (1 << 29) -#define LPE_HWDESC_PAD (1 << 28) -#define LPE_HWDESC_HUGE (1 << 27) -#define LPE_HWDESC_OVERRIDE (1 << 26) - -/* These are valid for Tx status descriptors */ -#define LPE_HWDESC_COLLISIONS(_n) (((_n) >> 21) & 0x7) -#define LPE_HWDESC_DEFER (1 << 25) -#define LPE_HWDESC_EXCDEFER (1 << 26) -#define LPE_HWDESC_EXCCOLL (1 << 27) -#define LPE_HWDESC_LATECOLL (1 << 28) -#define LPE_HWDESC_UNDERRUN (1 << 29) -#define LPE_HWDESC_TXNODESCR (1 << 30) -#define LPE_HWDESC_ERROR (1U << 31) - -/* These are valid for Rx status descriptors */ -#define LPE_HWDESC_CONTROL (1 << 18) -#define LPE_HWDESC_VLAN (1 << 19) -#define LPE_HWDESC_FAILFILTER (1 << 20) -#define LPE_HWDESC_MULTICAST (1 << 21) -#define LPE_HWDESC_BROADCAST (1 << 22) -#define LPE_HWDESC_CRCERROR (1 << 23) -#define LPE_HWDESC_SYMBOLERROR (1 << 24) -#define LPE_HWDESC_LENGTHERROR (1 << 25) -#define LPE_HWDESC_RANGEERROR (1 << 26) -#define LPE_HWDESC_ALIGNERROR (1 << 27) -#define LPE_HWDESC_OVERRUN (1 << 28) -#define LPE_HWDESC_RXNODESCR (1 << 29) -#define LPE_HWDESC_LASTFLAG (1 << 30) -#define LPE_HWDESC_ERROR (1U << 31) - - -#endif /* _ARM_LPC_IF_LPEREG_H */ diff --git a/rtemsbsd/sys/dev/atsam/if_atsam.c b/rtemsbsd/sys/dev/atsam/if_atsam.c index ff8219f4..21a28fcd 100644 --- a/rtemsbsd/sys/dev/atsam/if_atsam.c +++ b/rtemsbsd/sys/dev/atsam/if_atsam.c @@ -42,6 +42,7 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/mbuf.h> +#include <sys/sbuf.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/kernel.h> @@ -49,7 +50,9 @@ #include <sys/bus.h> #include <sys/sysctl.h> +#include <net/bpf.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/if_var.h> #include <net/if_types.h> #include <net/if_media.h> @@ -66,6 +69,7 @@ #include <rtems/bsd/local/miibus_if.h> #include <rtems/bsd/if_atsam.h> +#include <rtems/bsd/bsd.h> /* * Number of interfaces supported by the driver @@ -90,46 +94,40 @@ /** The runtime pin configure list for GMAC */ #define BOARD_GMAC_RUN_PINS BOARD_GMAC_PINS -/** Multicast Enable */ -#define GMAC_MC_ENABLE (1u << 6) -#define HASH_INDEX_AMOUNT 6 -#define HASH_ELEMENTS_PER_INDEX 8 -#define MAC_ADDR_MASK 0x0000FFFFFFFFFFFF -#define MAC_IDX_MASK (1u << 0) - -/** Promiscuous Mode Enable */ -#define GMAC_PROM_ENABLE (1u << 4) - /** RX Defines */ #define GMAC_RX_BUFFER_SIZE 1536 #define GMAC_RX_BUF_DESC_ADDR_MASK 0xFFFFFFFC -#define GMAC_RX_SET_OFFSET (1u << 15) -#define GMAC_RX_SET_USED_WRAP ((1u << 1) | (1u << 0)) -#define GMAC_RX_SET_WRAP (1u << 1) -#define GMAC_RX_SET_USED (1u << 0) -/** TX Defines */ -#define GMAC_TX_SET_EOF (1u << 15) -#define GMAC_TX_SET_WRAP (1u << 30) -#define GMAC_TX_SET_USED (1u << 31) #define GMAC_DESCRIPTOR_ALIGNMENT 8 /** Events */ #define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1 -#define ATSAMV7_ETH_TX_EVENT_INTERRUPT RTEMS_EVENT_2 -#define ATSAMV7_ETH_START_TRANSMIT_EVENT RTEMS_EVENT_3 - -#define ATSAMV7_ETH_RX_DATA_OFFSET 2 - -#define WATCHDOG_TIMEOUT 5 /* FIXME: Make these configurable */ #define MDIO_RETRIES 10 #define MDIO_PHY MII_PHY_ANY -#define RXBUF_COUNT 8 -#define TXBUF_COUNT 64 #define IGNORE_RX_ERR false +#define RX_INTERRUPTS (GMAC_ISR_RCOMP | GMAC_ISR_RXUBR | GMAC_ISR_ROVR) + +#define RX_DESC_LOG2 3 +#define RX_DESC_COUNT (1U << RX_DESC_LOG2) +#define RX_DESC_WRAP(idx) \ + ((((idx) + 1) & RX_DESC_COUNT) >> (RX_DESC_LOG2 - 1)) +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 1) == + GMAC_RX_WRAP_BIT, rx_desc_wrap); +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 2) == + 0, rx_desc_no_wrap); + +#define TX_DESC_LOG2 6 +#define TX_DESC_COUNT (1U << TX_DESC_LOG2) +#define TX_DESC_WRAP(idx) \ + ((((idx) + 1) & TX_DESC_COUNT) << (30 - TX_DESC_LOG2)) +RTEMS_STATIC_ASSERT(TX_DESC_WRAP(TX_DESC_COUNT - 1) == + GMAC_TX_WRAP_BIT, tx_desc_wrap); +RTEMS_STATIC_ASSERT(TX_DESC_WRAP(TX_DESC_COUNT - 2) == + 0, tx_desc_no_wrap); + /** The PINs for GMAC */ static const Pin gmacPins[] = { BOARD_GMAC_RUN_PINS }; @@ -139,11 +137,13 @@ typedef struct if_atsam_gmac { uint32_t retries; } if_atsam_gmac; -typedef struct ring_buffer { - unsigned tx_bd_used; - unsigned tx_bd_free; - size_t length; -} ring_buffer; +struct if_atsam_tx_bds { + volatile sGmacTxDescriptor bds[TX_DESC_COUNT]; +}; + +struct if_atsam_rx_bds { + volatile sGmacRxDescriptor bds[RX_DESC_COUNT]; +}; /* * Per-device data @@ -156,17 +156,16 @@ typedef struct if_atsam_softc { struct ifnet *ifp; struct mtx mtx; if_atsam_gmac Gmac_inst; + size_t tx_idx_head; + size_t tx_idx_tail; + struct if_atsam_tx_bds *tx; + struct mbuf *tx_mbufs[TX_DESC_COUNT]; + size_t rx_idx_head; + struct if_atsam_rx_bds *rx; + struct mbuf *rx_mbufs[RX_DESC_COUNT]; uint8_t GMacAddress[6]; rtems_id rx_daemon_tid; - rtems_id tx_daemon_tid; rtems_vector_number interrupt_number; - struct mbuf **rx_mbuf; - struct mbuf **tx_mbuf; - volatile sGmacTxDescriptor *tx_bd_base; - size_t rx_bd_fill_idx; - size_t amount_rx_buf; - size_t amount_tx_buf; - ring_buffer tx_ring; struct callout tick_ch; /* @@ -190,13 +189,12 @@ typedef struct if_atsam_softc { struct if_atsam_stats { /* Software */ uint32_t rx_overrun_errors; + uint32_t rx_used_bit_reads; uint32_t rx_interrupts; - uint32_t tx_complete_int; uint32_t tx_tur_errors; uint32_t tx_rlex_errors; uint32_t tx_tfc_errors; uint32_t tx_hresp_errors; - uint32_t tx_interrupts; /* Hardware */ uint64_t octets_transm; @@ -243,6 +241,8 @@ typedef struct if_atsam_softc { uint32_t tcp_checksum_errors; uint32_t udp_checksum_errors; } stats; + + int if_flags; } if_atsam_softc; static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc); @@ -251,27 +251,6 @@ static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc); #define IF_ATSAM_UNLOCK(sc) mtx_unlock(&(sc)->mtx) -static void if_atsam_event_send(rtems_id task, rtems_event_set event) -{ - rtems_event_send(task, event); -} - - -static void if_atsam_event_receive(if_atsam_softc *sc, rtems_event_set in) -{ - rtems_event_set out; - - IF_ATSAM_UNLOCK(sc); - rtems_event_receive( - in, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &out - ); - IF_ATSAM_LOCK(sc); -} - - static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp) { struct mbuf *m; @@ -356,11 +335,10 @@ if_atsam_miibus_readreg(device_t dev, int phy, int reg) static int if_atsam_miibus_writereg(device_t dev, int phy, int reg, int data) { - uint8_t err; if_atsam_softc *sc = device_get_softc(dev); IF_ATSAM_LOCK(sc); - err = if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw, + (void)if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw, (uint8_t)phy, (uint8_t)reg, data, sc->Gmac_inst.retries); IF_ATSAM_UNLOCK(sc); @@ -403,63 +381,53 @@ if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck, static void if_atsam_interrupt_handler(void *arg) { if_atsam_softc *sc = (if_atsam_softc *)arg; - uint32_t irq_status_val; - rtems_event_set rx_event = 0; - rtems_event_set tx_event = 0; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + uint32_t is; /* Get interrupt status */ - irq_status_val = GMAC_GetItStatus(pHw, 0); + is = pHw->GMAC_ISR; - /* Check receive interrupts */ - if ((irq_status_val & GMAC_IER_ROVR) != 0) { - ++sc->stats.rx_overrun_errors; - rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_RCOMP) != 0) { - rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT; + if (__predict_false((is & GMAC_TX_ERR_BIT) != 0)) { + if ((is & GMAC_IER_TUR) != 0) { + ++sc->stats.tx_tur_errors; + } + if ((is & GMAC_IER_RLEX) != 0) { + ++sc->stats.tx_rlex_errors; + } + if ((is & GMAC_IER_TFC) != 0) { + ++sc->stats.tx_tfc_errors; + } + if ((is & GMAC_IER_HRESP) != 0) { + ++sc->stats.tx_hresp_errors; + } } - /* Send events to receive task and switch off rx interrupts */ - if (rx_event != 0) { + + /* Check receive interrupts */ + if (__predict_true((is & RX_INTERRUPTS) != 0)) { + if (__predict_false((is & GMAC_ISR_RXUBR) != 0)) { + ++sc->stats.rx_used_bit_reads; + } + + if (__predict_false((is & GMAC_ISR_ROVR) != 0)) { + ++sc->stats.rx_overrun_errors; + } + ++sc->stats.rx_interrupts; - /* Erase the interrupts for RX completion and errors */ - GMAC_DisableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); - (void)if_atsam_event_send(sc->rx_daemon_tid, rx_event); - } - if ((irq_status_val & GMAC_IER_TUR) != 0) { - ++sc->stats.tx_tur_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_RLEX) != 0) { - ++sc->stats.tx_rlex_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_TFC) != 0) { - ++sc->stats.tx_tfc_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_HRESP) != 0) { - ++sc->stats.tx_hresp_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_TCOMP) != 0) { - ++sc->stats.tx_complete_int; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - /* Send events to transmit task and switch off tx interrupts */ - if (tx_event != 0) { - ++sc->stats.tx_interrupts; - /* Erase the interrupts for TX completion and errors */ - GMAC_DisableIt(pHw, GMAC_INT_TX_BITS, 0); - (void)if_atsam_event_send(sc->tx_daemon_tid, tx_event); + + /* Disable RX interrupts */ + pHw->GMAC_IDR = RX_INTERRUPTS; + + (void)rtems_event_send(sc->rx_daemon_tid, + ATSAMV7_ETH_RX_EVENT_INTERRUPT); } } -static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) +static void +if_atsam_rx_update_mbuf(struct mbuf *m, uint32_t status) { int frame_len; - frame_len = (int) (buffer_desc->status.bm.len); + frame_len = (int)(status & GMAC_LENGTH_FRAME); m->m_data = mtod(m, char*)+ETHER_ALIGN; m->m_len = frame_len; @@ -467,7 +435,7 @@ static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) /* check checksum offload result */ m->m_pkthdr.csum_flags = 0; - switch (buffer_desc->status.bm.typeIDMatchOrCksumResult) { + switch ((status >> 22) & 0x3) { case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED: m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID; m->m_pkthdr.csum_data = 0xffff; @@ -481,21 +449,17 @@ static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) } } -/* - * Receive daemon - */ -static void if_atsam_rx_daemon(void *arg) +static void +if_atsam_rx_daemon(rtems_task_argument arg) { if_atsam_softc *sc = (if_atsam_softc *)arg; struct ifnet *ifp = sc->ifp; - rtems_event_set events = 0; - void *rx_bd_base; - struct mbuf *m; - struct mbuf *n; - volatile sGmacRxDescriptor *buffer_desc; - uint32_t tmp_rx_bd_address; - size_t i; + volatile sGmacRxDescriptor *base; + struct if_atsam_rx_bds *rx; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + size_t idx; + struct mbuf **mbufs; + struct mbuf *m; IF_ATSAM_LOCK(sc); @@ -506,47 +470,37 @@ static void if_atsam_rx_daemon(void *arg) } /* Allocate memory space for priority queue descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor), + base = rtems_cache_coherent_allocate(sizeof(*base), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); + assert(base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; - buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP; - buffer_desc->status.val = 0; + base->addr.val = GMAC_RX_OWNERSHIP_BIT | GMAC_RX_WRAP_BIT; + base->status.val = 0; - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2); + GMAC_SetRxQueue(pHw, (uint32_t)base, 1); + GMAC_SetRxQueue(pHw, (uint32_t)base, 2); /* Allocate memory space for buffer descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate( - sc->amount_rx_buf * sizeof(sGmacRxDescriptor), + rx = rtems_cache_coherent_allocate(sizeof(*rx), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; + assert(rx != NULL); + sc->rx = rx; + mbufs = &sc->rx_mbufs[0]; /* Create descriptor list and mark as empty */ - for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf; - ++sc->rx_bd_fill_idx) { + for (idx = 0; idx < RX_DESC_COUNT; ++idx) { m = if_atsam_new_mbuf(ifp); assert(m != NULL); - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - buffer_desc->addr.val = ((uint32_t)m->m_data) & - GMAC_RX_BUF_DESC_ADDR_MASK; - buffer_desc->status.val = 0; - if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) { - buffer_desc->addr.bm.bWrap = 1; - } else { - buffer_desc++; - } + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | RX_DESC_WRAP(idx); } - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; /* Set 2 Byte Receive Buffer Offset */ - pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET; + pHw->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(2); /* Write Buffer Queue Base Address Register */ GMAC_ReceiveEnable(pHw, 0); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0); + GMAC_SetRxQueue(pHw, (uint32_t)&rx->bds[0], 0); /* Set address for address matching */ GMAC_SetAddress(pHw, 0, sc->GMacAddress); @@ -554,306 +508,230 @@ static void if_atsam_rx_daemon(void *arg) /* Enable Receiving of data */ GMAC_ReceiveEnable(pHw, 1); - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); + IF_ATSAM_UNLOCK(sc); - sc->rx_bd_fill_idx = 0; + idx = 0; while (true) { - /* Wait for events */ - if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT); + rtems_event_set out; - /* - * Check for all packets with a set ownership bit - */ - while (buffer_desc->addr.bm.bOwnership == 1) { - if (buffer_desc->status.bm.bEof == 1) { - m = sc->rx_mbuf[sc->rx_bd_fill_idx]; + sc->rx_idx_head = idx; - /* New mbuf for desc */ - n = if_atsam_new_mbuf(ifp); - if (n != NULL) { - rx_update_mbuf(m, buffer_desc); + /* Enable RX interrupts */ + pHw->GMAC_IER = RX_INTERRUPTS; - IF_ATSAM_UNLOCK(sc); - sc->ifp->if_input(ifp, m); - IF_ATSAM_LOCK(sc); - m = n; - } else { - (void)if_atsam_event_send( - sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT); - } - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - tmp_rx_bd_address = (uint32_t)m->m_data & - GMAC_RX_BUF_DESC_ADDR_MASK; - - /* Switch pointer to next buffer descriptor */ - if (sc->rx_bd_fill_idx == - (sc->amount_rx_buf - 1)) { - tmp_rx_bd_address |= GMAC_RX_SET_WRAP; - sc->rx_bd_fill_idx = 0; - } else { - ++sc->rx_bd_fill_idx; - } + (void) rtems_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT, + RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &out); - /* - * Give ownership to GMAC for further processing - */ - tmp_rx_bd_address &= ~GMAC_RX_SET_USED; - _ARM_Data_synchronization_barrier(); - buffer_desc->addr.val = tmp_rx_bd_address; + while (true) { + uint32_t addr; + uint32_t status; - buffer_desc = (sGmacRxDescriptor *)rx_bd_base - + sc->rx_bd_fill_idx; + addr = rx->bds[idx].addr.val; + if ((addr & GMAC_RX_OWNERSHIP_BIT) == 0) { + break; } - } - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); - } -} -/* - * Update of current transmit buffer position. - */ -static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf) -{ - *pos = (*pos + 1) % amount_tx_buf; -} + status = rx->bds[idx].status.val; + m = mbufs[idx]; -/* - * Is RingBuffer empty - */ -static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer) -{ - return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free); -} + if (__predict_true((status & GMAC_RX_EOF_BIT) != 0)) { + struct mbuf *n; -/* - * Is RingBuffer full - */ -static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer) -{ - size_t tx_bd_used_next = ring_buffer->tx_bd_used; + n = if_atsam_new_mbuf(ifp); + if (n != NULL) { + if_atsam_rx_update_mbuf(m, status); + (*ifp->if_input)(ifp, m); + m = n; + } + } else { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + } - if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length); - return (tx_bd_used_next == ring_buffer->tx_bd_free); -} + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | + RX_DESC_WRAP(idx); -/* - * Cleanup transmit file descriptors by freeing mbufs which are not needed any - * longer due to correct transmission. - */ -static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc) -{ - struct mbuf *m; - volatile sGmacTxDescriptor *cur; - bool eof_needed = false; - - while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){ - cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free; - if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) { - eof_needed = true; - cur->status.val |= GMAC_TX_SET_USED; - m = sc->tx_mbuf[sc->tx_ring.tx_bd_free]; - m_free(m); - sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0; - if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free, - sc->tx_ring.length); - if (cur->status.bm.bLastBuffer) { - eof_needed = false; - } - } else { - break; + idx = (idx + 1) % RX_DESC_COUNT; } } } -/* - * Prepare Ethernet frame to start transmission. - */ -static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m) +static void +if_atsam_tx_reclaim(struct if_atsam_softc *sc, struct ifnet *ifp) { - volatile sGmacTxDescriptor *cur; - volatile sGmacTxDescriptor *start_packet_tx_bd = 0; - int pos = 0; - uint32_t tmp_val = 0; - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - bool success; - int csum_flags = m->m_pkthdr.csum_flags; + uint32_t head_idx; + uint32_t tail_idx; + volatile sGmacTxDescriptor *base; - if_atsam_tx_bd_cleanup(sc); - /* Wait for interrupt in case no buffer descriptors are available */ - /* Wait for events */ - while (true) { - if (if_atsam_ring_buffer_full(&sc->tx_ring)) { - /* Setup the interrupts for TX completion and errors */ - GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0); - success = false; + head_idx = sc->tx_idx_head; + tail_idx = sc->tx_idx_tail; + base = &sc->tx->bds[0]; + + while (head_idx != tail_idx) { + uint32_t status; + ift_counter cnt; + struct mbuf *m; + + status = base[tail_idx].status.val; + + if ((status & GMAC_TX_USED_BIT) == 0) { break; } - /* - * Get current mbuf for data fill - */ - cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used]; - /* Set the transfer data */ - if (m->m_len) { - uintptr_t cache_adjustment = mtod(m, uintptr_t) % 32; - - rtems_cache_flush_multiple_data_lines( - mtod(m, const char *) - cache_adjustment, - (size_t)(m->m_len + cache_adjustment)); - - cur->addr = mtod(m, uint32_t); - tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED; - if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) { - tmp_val |= GMAC_TX_SET_WRAP; - } - if (pos == 0) { - start_packet_tx_bd = cur; - } - sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m; - m = m->m_next; - if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used, - sc->tx_ring.length); + if (__predict_true((status & GMAC_TX_ERR_BITS) == 0)) { + cnt = IFCOUNTER_OPACKETS; } else { - /* Discard empty mbufs */ - m = m_free(m); + cnt = IFCOUNTER_OERRORS; } - /* - * Send out the buffer once the complete mbuf_chain has been - * processed - */ - if (m == NULL) { - tmp_val |= GMAC_TX_SET_EOF; - tmp_val &= ~GMAC_TX_SET_USED; - if ((csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | - CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0) { - start_packet_tx_bd->status.bm.bNoCRC = 0; - } else { - start_packet_tx_bd->status.bm.bNoCRC = 1; - } - _ARM_Data_synchronization_barrier(); - cur->status.val = tmp_val; - start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED; - _ARM_Data_synchronization_barrier(); - GMAC_TransmissionStart(pHw); - success = true; - break; - } else { - if (pos > 0) { - tmp_val &= ~GMAC_TX_SET_USED; + while ((m = sc->tx_mbufs[tail_idx]) == NULL ) { + base[tail_idx].status.val = status | GMAC_TX_USED_BIT; + tail_idx = (tail_idx + 1) % TX_DESC_COUNT; + status = base[tail_idx].status.val; + + if (__predict_false((status & GMAC_TX_ERR_BITS) != 0)) { + cnt = IFCOUNTER_OERRORS; } - pos++; - cur->status.val = tmp_val; } + + base[tail_idx].status.val = status | GMAC_TX_USED_BIT; + if_inc_counter(ifp, cnt, 1); + sc->tx_mbufs[tail_idx] = NULL; + m_freem(m); + + tail_idx = (tail_idx + 1) % TX_DESC_COUNT; } - return success; -} + sc->tx_idx_tail = tail_idx; +} -/* - * Transmit daemon - */ -static void if_atsam_tx_daemon(void *arg) +static void +if_atsam_cache_flush(uintptr_t begin, uintptr_t size) { - if_atsam_softc *sc = (if_atsam_softc *)arg; - rtems_event_set events = 0; - sGmacTxDescriptor *buffer_desc; - int bd_number; - void *tx_bd_base; - struct mbuf *m; - bool success; + uintptr_t end; + uintptr_t mask; + + /* Align begin and end of the data to a cache line */ + end = begin + size; + mask = CPU_CACHE_LINE_BYTES - 1; + begin &= ~mask; + end = (end + mask) & ~mask; + rtems_cache_flush_multiple_data_lines((void *)begin, end - begin); +} - IF_ATSAM_LOCK(sc); +static int +if_atsam_tx_enqueue(struct if_atsam_softc *sc, struct ifnet *ifp, struct mbuf *m) +{ + size_t head_idx; + size_t tail_idx; + size_t capacity; + size_t idx; + volatile sGmacTxDescriptor *base; + volatile sGmacTxDescriptor *desc; + size_t bufs; + uint32_t status; + struct mbuf *n; - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - struct ifnet *ifp = sc->ifp; + head_idx = sc->tx_idx_head; + tail_idx = sc->tx_idx_tail; + capacity = (tail_idx - head_idx - 1) % TX_DESC_COUNT; - GMAC_TransmitEnable(pHw, 0); + idx = head_idx; + base = &sc->tx->bds[0]; + bufs = 0; + n = m; - /* Allocate memory space for priority queue descriptor list */ - tx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacTxDescriptor), - GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(tx_bd_base != NULL); + do { + uint32_t size; - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; - buffer_desc->addr = 0; - buffer_desc->status.val = GMAC_TX_SET_USED | GMAC_TX_SET_WRAP; + desc = &base[idx]; - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 1); - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 2); + size = (uint32_t)n->m_len; + if (__predict_true(size > 0)) { + uintptr_t begin; - /* Allocate memory space for buffer descriptor list */ - tx_bd_base = rtems_cache_coherent_allocate( - sc->amount_tx_buf * sizeof(sGmacTxDescriptor), - GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(tx_bd_base != NULL); - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; + ++bufs; + if (__predict_false(bufs > capacity)) { + return (ENOBUFS); + } - /* Create descriptor list and mark as empty */ - for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) { - buffer_desc->addr = 0; - buffer_desc->status.val = GMAC_TX_SET_USED; - if (bd_number == (sc->amount_tx_buf - 1)) { - buffer_desc->status.bm.bWrap = 1; - } else { - buffer_desc++; + begin = mtod(n, uintptr_t); + desc->addr = (uint32_t)begin; + status = GMAC_TX_USED_BIT | TX_DESC_WRAP(idx) | size; + desc->status.val = status; + if_atsam_cache_flush(begin, size); + idx = (idx + 1) % TX_DESC_COUNT; } + + n = n->m_next; + } while (n != NULL); + + sc->tx_idx_head = idx; + + idx = (idx - 1) % TX_DESC_COUNT; + desc = &base[idx]; + sc->tx_mbufs[idx] = m; + status = GMAC_TX_LAST_BUFFER_BIT; + + while (idx != head_idx) { + desc->status.val = (desc->status.val & ~GMAC_TX_USED_BIT) | + status; + status = 0; + + idx = (idx - 1) % TX_DESC_COUNT; + desc = &base[idx]; } - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; - /* Write Buffer Queue Base Address Register */ - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 0); + desc->status.val = (desc->status.val & ~GMAC_TX_USED_BIT) | status; + _ARM_Data_synchronization_barrier(); + sc->Gmac_inst.gGmacd.pHw->GMAC_NCR |= GMAC_NCR_TSTART; + ETHER_BPF_MTAP(ifp, m); + return (0); +} - /* Enable Transmission of data */ - GMAC_TransmitEnable(pHw, 1); +static int +if_atsam_transmit(struct ifnet *ifp, struct mbuf *m) +{ + struct if_atsam_softc *sc; + int error; - /* Set variables in context */ - sc->tx_bd_base = tx_bd_base; + if (__predict_false((m->m_flags & M_VLANTAG) != 0)) { + struct mbuf *n; - while (true) { - /* Wait for events */ - if_atsam_event_receive(sc, - ATSAMV7_ETH_START_TRANSMIT_EVENT | - ATSAMV7_ETH_TX_EVENT_INTERRUPT); - //printf("TX Transmit Event received\n"); - - /* - * Send packets till queue is empty - */ - while (true) { - /* - * Get the mbuf chain to transmit - */ - if_atsam_tx_bd_cleanup(sc); - IF_DEQUEUE(&ifp->if_snd, m); - if (!m) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - break; - } - success = if_atsam_send_packet(sc, m); - if (!success){ - break; - } + n = ether_vlanencap(m, m->m_pkthdr.ether_vtag); + if (n == NULL) { + m_freem(m); + return (ENOBUFS); } + + m = n; } -} + sc = ifp->if_softc; + IF_ATSAM_LOCK(sc); -/* - * Send packet (caller provides header). - */ -static void if_atsam_enet_start(struct ifnet *ifp) -{ - if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc; + error = if_atsam_tx_enqueue(sc, ifp, m); + if_atsam_tx_reclaim(sc, ifp); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - if_atsam_event_send(sc->tx_daemon_tid, - ATSAMV7_ETH_START_TRANSMIT_EVENT); -} + if (__predict_false(error != 0)) { + struct mbuf *n; + n = m_defrag(m, M_NOWAIT); + if (n != NULL) { + m = n; + } + + error = if_atsam_tx_enqueue(sc, ifp, m); + if (error != 0) { + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); + } + } + + IF_ATSAM_UNLOCK(sc); + return (error); +} static uint8_t if_atsam_get_gmac_linkspeed_from_media(uint32_t media_subtype) { @@ -975,23 +853,55 @@ if_atsam_tick(void *context) callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc); } +static void +if_atsam_setup_tx(struct if_atsam_softc *sc) +{ + sGmacTxDescriptor *base; + struct if_atsam_tx_bds *tx; + size_t i; + Gmac *pHw; -/* - * Sets up the hardware and chooses the interface to be used - */ -static void if_atsam_init(void *arg) + pHw = sc->Gmac_inst.gGmacd.pHw; + GMAC_TransmitEnable(pHw, 0); + + /* Allocate memory space for priority queue descriptor list */ + base = rtems_cache_coherent_allocate(sizeof(base), + GMAC_DESCRIPTOR_ALIGNMENT, 0); + assert(base != NULL); + + base->addr = 0; + base->status.val = GMAC_TX_USED_BIT | GMAC_TX_WRAP_BIT; + + GMAC_SetTxQueue(pHw, (uint32_t)base, 1); + GMAC_SetTxQueue(pHw, (uint32_t)base, 2); + + /* Allocate memory space for buffer descriptor list */ + tx = rtems_cache_coherent_allocate(sizeof(*sc->tx), + GMAC_DESCRIPTOR_ALIGNMENT, 0); + assert(tx != NULL); + + /* Set variables in context */ + sc->tx = tx; + + /* Create descriptor list and mark as empty */ + for (i = 0; i < TX_DESC_COUNT; ++i) { + tx->bds[i].addr = 0; + tx->bds[i].status.val = GMAC_TX_USED_BIT | TX_DESC_WRAP(i); + } + + /* Write Buffer Queue Base Address Register */ + GMAC_SetTxQueue(pHw, (uint32_t)&tx->bds[0], 0); + + /* Enable Transmission of data */ + GMAC_TransmitEnable(pHw, 1); +} + +static void +if_atsam_init(if_atsam_softc *sc) { rtems_status_code status; - - if_atsam_softc *sc = (if_atsam_softc *)arg; - struct ifnet *ifp = sc->ifp; uint32_t dmac_cfg = 0; - uint32_t gmii_val = 0; - if (ifp->if_flags & IFF_DRV_RUNNING) { - return; - } - ifp->if_flags |= IFF_DRV_RUNNING; sc->interrupt_number = GMAC_IRQn; /* Enable Peripheral Clock */ @@ -1000,7 +910,6 @@ static void if_atsam_init(void *arg) } /* Setup interrupts */ NVIC_ClearPendingIRQ(GMAC_IRQn); - NVIC_EnableIRQ(GMAC_IRQn); /* Configuration of DMAC */ dmac_cfg = (GMAC_DCFGR_DRBS(GMAC_RX_BUFFER_SIZE >> 6)) | @@ -1011,20 +920,17 @@ static void if_atsam_init(void *arg) /* Enable hardware checksum offload for receive */ sc->Gmac_inst.gGmacd.pHw->GMAC_NCFGR |= GMAC_NCFGR_RXCOEN; + /* Use Multicast Hash Filter */ + sc->Gmac_inst.gGmacd.pHw->GMAC_NCFGR |= GMAC_NCFGR_MTIHEN; + sc->Gmac_inst.gGmacd.pHw->GMAC_HRB = 0; + sc->Gmac_inst.gGmacd.pHw->GMAC_HRT = 0; + /* Shut down Transmit and Receive */ GMAC_ReceiveEnable(sc->Gmac_inst.gGmacd.pHw, 0); GMAC_TransmitEnable(sc->Gmac_inst.gGmacd.pHw, 0); GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1); - /* - * Allocate mbuf pointers - */ - sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf, - M_TEMP, M_NOWAIT); - sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf, - M_TEMP, M_NOWAIT); - /* Install interrupt handler */ status = rtems_interrupt_handler_install(sc->interrupt_number, "Ethernet", @@ -1036,30 +942,143 @@ static void if_atsam_init(void *arg) /* * Start driver tasks */ - sc->rx_daemon_tid = rtems_bsdnet_newproc("SCrx", 4096, - if_atsam_rx_daemon, sc); - sc->tx_daemon_tid = rtems_bsdnet_newproc("SCtx", 4096, - if_atsam_tx_daemon, sc); + + status = rtems_task_create(rtems_build_name('S', 'C', 'r', 'x'), + rtems_bsd_get_task_priority(device_get_name(sc->dev)), 4096, + RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_MODES, &sc->rx_daemon_tid); + assert(status == RTEMS_SUCCESSFUL); + + status = rtems_task_start(sc->rx_daemon_tid, if_atsam_rx_daemon, + (rtems_task_argument)sc); + assert(status == RTEMS_SUCCESSFUL); callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc); + if_atsam_setup_tx(sc); +} + +static int +if_atsam_get_hash_index(const uint8_t *eaddr) +{ + uint64_t eaddr64; + int index; + int i; + + eaddr64 = eaddr[5]; + + for (i = 4; i >= 0; --i) { + eaddr64 <<= 8; + eaddr64 |= eaddr[i]; + } + + index = 0; + + for (i = 0; i < 6; ++i) { + uint64_t bits; + int j; + int hash; + + bits = eaddr64 >> i; + hash = bits & 1; + + for (j = 1; j < 8; ++j) { + bits >>= 6; + hash ^= bits & 1; + } + + index |= hash << i; + } + + return index; +} + +static void +if_atsam_setup_rxfilter(struct if_atsam_softc *sc) +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma; + uint64_t mhash; + Gmac *pHw; + + pHw = sc->Gmac_inst.gGmacd.pHw; + + if ((sc->ifp->if_flags & IFF_PROMISC) != 0) { + pHw->GMAC_NCFGR |= GMAC_NCFGR_CAF; + } else { + pHw->GMAC_NCFGR &= ~GMAC_NCFGR_CAF; + } + + ifp = sc->ifp; + + if ((ifp->if_flags & IFF_ALLMULTI)) + mhash = 0xffffffffffffffffLLU; + else { + mhash = 0; + if_maddr_rlock(ifp); + CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + mhash |= 1LLU << if_atsam_get_hash_index( + LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); + } + if_maddr_runlock(ifp); + } + + pHw->GMAC_HRB = (uint32_t)mhash; + pHw->GMAC_HRT = (uint32_t)(mhash >> 32); +} + +static void +if_atsam_start_locked(struct if_atsam_softc *sc) +{ + struct ifnet *ifp = sc->ifp; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + return; + } + ifp->if_drv_flags |= IFF_DRV_RUNNING; + + if_atsam_setup_rxfilter(sc); + + /* Enable TX/RX */ + pHw->GMAC_NCR |= GMAC_NCR_RXEN | GMAC_NCR_TXEN; } +static void +if_atsam_start(void *arg) +{ + struct if_atsam_softc *sc = arg; -/* - * Stop the device - */ -static void if_atsam_stop(struct if_atsam_softc *sc) + IF_ATSAM_LOCK(sc); + if_atsam_start_locked(sc); + IF_ATSAM_UNLOCK(sc); +} + +static void +if_atsam_stop_locked(struct if_atsam_softc *sc) { struct ifnet *ifp = sc->ifp; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + size_t i; - ifp->if_flags &= ~IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - /* Disable MDIO interface and TX/RX */ + /* Disable TX/RX */ pHw->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN); - pHw->GMAC_NCR &= ~GMAC_NCR_MPE; + + /* Reinitialize the TX descriptors */ + + sc->tx_idx_head = 0; + sc->tx_idx_tail = 0; + + for (i = 0; i < TX_DESC_COUNT; ++i) { + sc->tx->bds[i].addr = 0; + sc->tx->bds[i].status.val = GMAC_TX_USED_BIT | TX_DESC_WRAP(i); + m_freem(sc->tx_mbufs[i]); + sc->tx_mbufs[i] = NULL; + } } @@ -1070,7 +1089,7 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; octets = pHw->GMAC_OTLO; - octets |= pHw->GMAC_OTHI << 32; + octets |= (uint64_t)pHw->GMAC_OTHI << 32; sc->stats.octets_transm += octets; sc->stats.frames_transm += pHw->GMAC_FT; sc->stats.broadcast_frames_transm += pHw->GMAC_BCFT; @@ -1092,7 +1111,7 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) sc->stats.carrier_sense_errors += pHw->GMAC_CSE; octets = pHw->GMAC_ORLO; - octets |= pHw->GMAC_ORHI << 32; + octets |= (uint64_t)pHw->GMAC_ORHI << 32; sc->stats.octets_rec += octets; sc->stats.frames_rec += pHw->GMAC_FR; sc->stats.broadcast_frames_rec += pHw->GMAC_BCFR; @@ -1120,24 +1139,159 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) sc->stats.udp_checksum_errors += pHw->GMAC_UCE; } +static int +if_atsam_stats_reset(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + int value; + int error; + + value = 0; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) { + return (error); + } + + if (value != 0) { + IF_ATSAM_LOCK(sc); + if_atsam_poll_hw_stats(sc); + memset(&sc->stats, 0, sizeof(sc->stats)); + IF_ATSAM_UNLOCK(sc); + } + + return (0); +} + +static int +if_atsam_sysctl_reg(SYSCTL_HANDLER_ARGS) +{ + u_int value; + + value = *(uint32_t *)arg1; + return (sysctl_handle_int(oidp, &value, 0, req)); +} + +static int +if_atsam_sysctl_tx_desc(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + struct sbuf *sb; + int error; + size_t i; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) { + return (error); + } + + sb = sbuf_new_for_sysctl(NULL, NULL, 1024, req); + if (sb == NULL) { + return (ENOMEM); + } + + sbuf_printf(sb, "\n\tHead %u\n", sc->tx_idx_head); + sbuf_printf(sb, "\tTail %u\n", sc->tx_idx_tail); + sbuf_printf(sb, "\tDMA %u\n", + (pHw->GMAC_TBQB - (uintptr_t)&sc->tx->bds[0]) / 8); + + for (i = 0; i < TX_DESC_COUNT; ++i) { + sbuf_printf(sb, "\t[%2u] %08x %08x\n", i, + sc->tx->bds[i].status.val, sc->tx->bds[i].addr); + } + + error = sbuf_finish(sb); + sbuf_delete(sb); + return (error); +} + +static int +if_atsam_sysctl_rx_desc(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + struct sbuf *sb; + int error; + size_t i; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) { + return (error); + } + + sb = sbuf_new_for_sysctl(NULL, NULL, 1024, req); + if (sb == NULL) { + return (ENOMEM); + } + + sbuf_printf(sb, "\n\tHead %u\n", sc->rx_idx_head); + sbuf_printf(sb, "\tDMA %u\n", + (pHw->GMAC_RBQB - (uintptr_t)&sc->rx->bds[0]) / 8); + + for (i = 0; i < RX_DESC_COUNT; ++i) { + sbuf_printf(sb, "\t[%2u] %08x %08x\n", i, + sc->rx->bds[i].status.val, sc->rx->bds[i].addr); + } + + error = sbuf_finish(sb); + sbuf_delete(sb); + return (error); +} static void if_atsam_add_sysctls(device_t dev) { struct if_atsam_softc *sc = device_get_softc(dev); + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *base; struct sysctl_oid_list *statsnode; struct sysctl_oid_list *hwstatsnode; struct sysctl_oid_list *child; struct sysctl_oid *tree; ctx = device_get_sysctl_ctx(dev); - child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + base = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); - tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, + tree = SYSCTL_ADD_NODE(ctx, base, OID_AUTO, "regs", CTLFLAG_RD, + NULL, "if_atsam registers"); + child = SYSCTL_CHILDREN(tree); + + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdesc", CTLTYPE_STRING | + CTLFLAG_RD, sc, 0, if_atsam_sysctl_tx_desc, "A", + "Transmit Descriptors"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxdesc", CTLTYPE_STRING | + CTLFLAG_RD, sc, 0, if_atsam_sysctl_rx_desc, "A", + "Receive Descriptors"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "imr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_IMR), 0, + if_atsam_sysctl_reg, "I", "IMR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "isr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_ISR), 0, + if_atsam_sysctl_reg, "I", "ISR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_RSR), 0, + if_atsam_sysctl_reg, "I", "RSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_TSR), 0, + if_atsam_sysctl_reg, "I", "TSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "nsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NSR), 0, + if_atsam_sysctl_reg, "I", "NSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ncfgr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NCFGR), 0, + if_atsam_sysctl_reg, "I", "NCFGR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ncr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NCR), 0, + if_atsam_sysctl_reg, "I", "NCR"); + + tree = SYSCTL_ADD_NODE(ctx, base, OID_AUTO, "stats", CTLFLAG_RD, NULL, "if_atsam statistics"); statsnode = SYSCTL_CHILDREN(tree); + SYSCTL_ADD_PROC(ctx, statsnode, OID_AUTO, "reset", CTLTYPE_INT | + CTLFLAG_WR, sc, 0, if_atsam_stats_reset, "I", "Reset"); + tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "sw", CTLFLAG_RD, NULL, "if_atsam software statistics"); child = SYSCTL_CHILDREN(tree); @@ -1145,12 +1299,12 @@ if_atsam_add_sysctls(device_t dev) SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overrun_errors", CTLFLAG_RD, &sc->stats.rx_overrun_errors, 0, "RX overrun errors"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_used_bit_reads", + CTLFLAG_RD, &sc->stats.rx_used_bit_reads, 0, + "RX used bit reads"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_interrupts", CTLFLAG_RD, &sc->stats.rx_interrupts, 0, "Rx interrupts"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_complete_int", - CTLFLAG_RD, &sc->stats.tx_complete_int, 0, - "Tx complete interrupts"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tur_errors", CTLFLAG_RD, &sc->stats.tx_tur_errors, 0, "Error Tur Tx interrupts"); @@ -1163,9 +1317,6 @@ if_atsam_add_sysctls(device_t dev) SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_hresp_errors", CTLFLAG_RD, &sc->stats.tx_hresp_errors, 0, "Error Hresp Tx interrupts"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_interrupts", - CTLFLAG_RD, &sc->stats.tx_interrupts, 0, - "Tx interrupts"); tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "hw", CTLFLAG_RD, NULL, "if_atsam hardware statistics"); @@ -1175,40 +1326,40 @@ if_atsam_add_sysctls(device_t dev) NULL, "if_atsam hardware transmit statistics"); child = SYSCTL_CHILDREN(tree); - SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_transm", + SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets", CTLFLAG_RD, &sc->stats.octets_transm, "Octets Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames", CTLFLAG_RD, &sc->stats.frames_transm, 0, "Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames", CTLFLAG_RD, &sc->stats.broadcast_frames_transm, 0, "Broadcast Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames", CTLFLAG_RD, &sc->stats.multicast_frames_transm, 0, "Multicast Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames", CTLFLAG_RD, &sc->stats.pause_frames_transm, 0, "Pause Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_bytes", CTLFLAG_RD, &sc->stats.frames_64_byte_transm, 0, "64 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_bytes", CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_transm, 0, "65 to 127 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_bytes", CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_transm, 0, "128 to 255 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_bytes", CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_transm, 0, "256 to 511 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_bytes", CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_transm, 0, "512 to 1023 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_bytes", CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_transm, 0, "1024 to 1518 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_greater_1518_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_bytes", CTLFLAG_RD, &sc->stats.frames_greater_1518_byte_transm, 0, "Greater Than 1518 Byte Frames Transmitted"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "transmit_underruns", @@ -1237,49 +1388,49 @@ if_atsam_add_sysctls(device_t dev) NULL, "if_atsam hardware receive statistics"); child = SYSCTL_CHILDREN(tree); - SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_rec", + SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets", CTLFLAG_RD, &sc->stats.octets_rec, "Octets Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames", CTLFLAG_RD, &sc->stats.frames_rec, 0, "Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames", CTLFLAG_RD, &sc->stats.broadcast_frames_rec, 0, "Broadcast Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames", CTLFLAG_RD, &sc->stats.multicast_frames_rec, 0, "Multicast Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames", CTLFLAG_RD, &sc->stats.pause_frames_rec, 0, "Pause Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_bytes", CTLFLAG_RD, &sc->stats.frames_64_byte_rec, 0, "64 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_bytes", CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_rec, 0, "65 to 127 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_bytes", CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_rec, 0, "128 to 255 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_bytes", CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_rec, 0, "256 to 511 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_bytes", CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_rec, 0, "512 to 1023 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_bytes", CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_rec, 0, "1024 to 1518 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_bytes", CTLFLAG_RD, &sc->stats.frames_1519_to_maximum_byte_rec, 0, "1519 to Maximum Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames", CTLFLAG_RD, &sc->stats.undersize_frames_rec, 0, "Undersize Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames", CTLFLAG_RD, &sc->stats.oversize_frames_rec, 0, "Oversize Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers", CTLFLAG_RD, &sc->stats.jabbers_rec, 0, "Jabbers Received"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frame_check_sequence_errors", @@ -1311,49 +1462,6 @@ if_atsam_add_sysctls(device_t dev) "UDP Checksum Errors"); } - -/* - * Calculates the index that is to be sent into the hash registers - */ -static void if_atsam_get_hash_index(uint64_t addr, uint32_t *val) -{ - uint64_t tmp_val; - uint8_t i, j; - uint64_t idx; - int offset = 0; - - addr &= MAC_ADDR_MASK; - - for (i = 0; i < HASH_INDEX_AMOUNT; ++i) { - tmp_val = 0; - offset = 0; - for (j = 0; j < HASH_ELEMENTS_PER_INDEX; j++) { - idx = (addr >> (offset + i)) & MAC_IDX_MASK; - tmp_val ^= idx; - offset += HASH_INDEX_AMOUNT; - } - if (tmp_val > 0) { - *val |= (1u << i); - } - } -} - - -/* - * Dis/Enable promiscuous Mode - */ -static void if_atsam_promiscuous_mode(if_atsam_softc *sc, bool enable) -{ - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - - if (enable) { - pHw->GMAC_NCFGR |= GMAC_PROM_ENABLE; - } else { - pHw->GMAC_NCFGR &= ~GMAC_PROM_ENABLE; - } -} - - static int if_atsam_mediaioctl(if_atsam_softc *sc, struct ifreq *ifr, u_long command) { @@ -1380,8 +1488,6 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int rv = 0; - bool prom_enable; - struct mii_data *mii; switch (command) { case SIOCGIFMEDIA: @@ -1389,17 +1495,31 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) rv = if_atsam_mediaioctl(sc, ifr, command); break; case SIOCSIFFLAGS: + IF_ATSAM_LOCK(sc); if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if_atsam_init(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + if_atsam_setup_rxfilter(sc); + } + } else { + if_atsam_start_locked(sc); } - prom_enable = ((ifp->if_flags & IFF_PROMISC) != 0); - if_atsam_promiscuous_mode(sc, prom_enable); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if_atsam_stop(sc); + if_atsam_stop_locked(sc); } } + sc->if_flags = ifp->if_flags; + IF_ATSAM_UNLOCK(sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IF_ATSAM_LOCK(sc); + if_atsam_setup_rxfilter(sc); + IF_ATSAM_UNLOCK(sc); + } break; default: rv = ether_ioctl(ifp, command, data); @@ -1416,7 +1536,6 @@ static int if_atsam_driver_attach(device_t dev) if_atsam_softc *sc; struct ifnet *ifp; int unit; - char *unitName; uint8_t eaddr[ETHER_ADDR_LEN]; sc = device_get_softc(dev); @@ -1437,13 +1556,6 @@ static int if_atsam_driver_attach(device_t dev) memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN); - sc->amount_rx_buf = RXBUF_COUNT; - sc->amount_tx_buf = TXBUF_COUNT; - - sc->tx_ring.tx_bd_used = 0; - sc->tx_ring.tx_bd_free = 0; - sc->tx_ring.length = sc->amount_tx_buf; - /* Set Initial Link Speed */ sc->link_speed = GMAC_SPEED_100M; sc->link_duplex = GMAC_DUPLEX_FULL; @@ -1486,17 +1598,20 @@ static int if_atsam_driver_attach(device_t dev) */ ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_init = if_atsam_init; + ifp->if_init = if_atsam_start; ifp->if_ioctl = if_atsam_ioctl; - ifp->if_start = if_atsam_enet_start; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_transmit = if_atsam_transmit; + ifp->if_qflush = if_qflush; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | - IFCAP_VLAN_HWCSUM; + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTAGGING; + ifp->if_capenable = ifp->if_capabilities; ifp->if_hwassist = CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP; - IFQ_SET_MAXLEN(&ifp->if_snd, TXBUF_COUNT - 1); - ifp->if_snd.ifq_drv_maxlen = TXBUF_COUNT - 1; + IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); + ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* * Attach the interface @@ -1504,6 +1619,7 @@ static int if_atsam_driver_attach(device_t dev) ether_ifattach(ifp, eaddr); if_atsam_add_sysctls(dev); + if_atsam_init(sc); return (0); } diff --git a/rtemsbsd/sys/dev/mve/if_mve.c b/rtemsbsd/sys/dev/mve/if_mve.c new file mode 100644 index 00000000..517484ee --- /dev/null +++ b/rtemsbsd/sys/dev/mve/if_mve.c @@ -0,0 +1,2389 @@ +/* RTEMS driver for the mv643xx gigabit ethernet chip */ + +/* Acknowledgement: + * + * Valuable information for developing this driver was obtained + * from the linux open-source driver mv643xx_eth.c which was written + * by the following people and organizations: + * + * Matthew Dharm <mdharm@momenco.com> + * rabeeh@galileo.co.il + * PMC-Sierra, Inc., Manish Lachwani + * Ralf Baechle <ralf@linux-mips.org> + * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org> + * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com> + * + * Note however, that in spite of the identical name of this file + * (and some of the symbols used herein) this file provides a + * new implementation and is the original work by the author. + */ + +/* + * Authorship + * ---------- + * This software (mv643xx ethernet driver for RTEMS) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'mv643xx ethernet driver for RTEMS' was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +/* + * NOTE: Some register (e.g., the SMI register) are SHARED among the + * three devices. Concurrent access protection is provided by + * the global networking semaphore. + * If other drivers are running on a subset of IFs then proper + * locking of all shared registers must be implemented! + * + * Some things I learned about this hardware can be found + * further down... + */ + +/* +#ifndef KERNEL +#define KERNEL +#endif +#ifndef _KERNEL +#define _KERNEL +#endif +*/ + +#include <bsp.h> + +#ifdef LIBBSP_BEATNIK_BSP_H + +#include <rtems/bspIo.h> +#include <rtems/error.h> +#include <bsp/irq.h> +#include <bsp/gtreg.h> +#include <libcpu/byteorder.h> +#include <assert.h> +#include <stdio.h> +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> + +#include <bsp/mv643xx_eth.h> + +/* CONFIGURABLE PARAMETERS */ + +/* Enable Hardware Snooping; if this is disabled (undefined), + * cache coherency is maintained by software. + */ +#undef ENABLE_HW_SNOOPING + +/* Compile-time debugging features */ + +/* Enable paranoia assertions and checks; reduce # of descriptors to minimum for stressing */ +#define MVETH_TESTING + +/* Enable debugging messages and some support routines (dump rings etc.) */ +#undef MVETH_DEBUG + +#define TX_NUM_TAG_SLOTS 1 /* leave room for tag; must not be 0 */ + +/* This is REAL; chip reads from 64-bit down-aligned buffer + * if the buffer size is < 8 !!! for buffer sizes 8 and upwards + * alignment is not an issue. This was verified using the + * 'mve_smallbuf_test.c' + */ +#define ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM + +/* Chip register configuration values */ +#define MVETH_PORT_CONFIG_VAL (0 \ + | MV643XX_ETH_DFLT_RX_Q(0) \ + | MV643XX_ETH_DFLT_RX_ARP_Q(0) \ + | MV643XX_ETH_DFLT_RX_TCP_Q(0) \ + | MV643XX_ETH_DFLT_RX_UDP_Q(0) \ + | MV643XX_ETH_DFLT_RX_BPDU_Q(0) \ + ) + + +#define MVETH_PORT_XTEND_CONFIG_VAL 0 + +#ifdef OLDCONFIGVAL +#define MVETH_SERIAL_CTRL_CONFIG_VAL (0 \ + | MV643XX_ETH_FORCE_LINK_PASS \ + | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL \ + | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL \ + | MV643XX_ETH_BIT9_UNKNOWN \ + | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE \ + | MV643XX_ETH_SC_MAX_RX_1552 \ + | MV643XX_ETH_SET_FULL_DUPLEX \ + | MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD \ + ) +#endif +/* If we enable autoneg (duplex, speed, ...) then it seems + * that the chip automatically updates link settings + * (correct link settings are reflected in PORT_STATUS_R). + * However, when we disable aneg in the PHY then things + * can get messed up and the port doesn't work anymore. + * => we follow the linux driver in disabling all aneg + * in the serial config reg. and manually updating the + * speed & duplex bits when the phy link status changes. + * FIXME: don't know what to do about pause/flow-ctrl. + * It is best to just use ANEG anyways!!! + */ +#define MVETH_SERIAL_CTRL_CONFIG_VAL (0 \ + | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX \ + | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL \ + | MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL \ + | MV643XX_ETH_BIT9_UNKNOWN \ + | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE \ + | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII \ + | MV643XX_ETH_SC_MAX_RX_1552 \ + ) + +#define MVETH_SERIAL_CTRL_CONFIG_MSK (0 \ + | MV643XX_ETH_SERIAL_PORT_ENBL \ + | MV643XX_ETH_FORCE_LINK_PASS \ + | MV643XX_ETH_SC_MAX_RX_MASK \ + ) + + +#ifdef __PPC__ +#define MVETH_SDMA_CONFIG_VAL (0 \ + | MV643XX_ETH_RX_BURST_SZ_4_64BIT \ + | MV643XX_ETH_TX_BURST_SZ_4_64BIT \ + ) +#else +#define MVETH_SDMA_CONFIG_VAL (0 \ + | MV643XX_ETH_RX_BURST_SZ_16_64BIT \ + | MV643XX_ETH_TX_BURST_SZ_16_64BIT \ + ) +#endif + +/* minimal frame size we accept */ +#define MVETH_MIN_FRAMSZ_CONFIG_VAL 40 + +/* END OF CONFIGURABLE SECTION */ + +/* + * Here's stuff I learned about this chip: + * + * + * RX interrupt flags: + * + * broadcast packet RX: 0x00000005 + * last buf: 0x00000c05 + * overrun: 0x00000c00 + * unicast packet RX: 0x00000005 + * bad CRC received: 0x00000005 + * + * clearing 0x00000004 -> clears 0x00000001 + * clearing 0x00000400 -> clears 0x00000800 + * + * --> 0x0801 are probably some sort of summary bits. + * + * TX interrupt flags: + * + * broadcast packet in 1 buf: xcause: 0x00000001 (cause 0x00080000) + * into disconn. link: " " + * + * in some cases, I observed xcause: 0x00000101 (reason for 0x100 unknown + * but the linux driver accepts it also). + * + * + * Here a few more ugly things about this piece of hardware I learned + * (painfully, painfully; spending many many hours & nights :-() + * + * a) Especially in the case of 'chained' descriptors, the DMA keeps + * clobbering 'cmd_sts' long after it cleared the OWNership flag!!! + * Only after the whole chain is processed (OWN cleared on the + * last descriptor) it is safe to change cmd_sts. + * However, in the case of hardware snooping I found that the + * last descriptor in chain has its cmd_sts still clobbered *after* + * checking ownership!, I.e., + * if ( ! OWN & cmd_sts ) { + * cmd_sts = 0; + * } + * --> sometimes, cmd_sts is STILL != 0 here + * + * b) Sometimes, the OWNership flag is *not cleared*. + * + * c) Weird things happen if the chip finds a descriptor with 'OWN' + * still set (i.e., not properly loaded), i.e., corrupted packets + * are sent [with OK checksum since the chip calculates it]. + * + * Combine a+b+c and we end up with a real mess. + * + * The fact that the chip doesn't reliably reset OWN and that OTOH, + * it can't be reliably reset by the driver and still, the chip needs + * it for proper communication doesn't make things easy... + * + * Here the basic workarounds: + * + * - In addition to check OWN, the scavenger compares the "currently + * served desc" register to the descriptor it tries to recover and + * ignores OWN if they do not match. Hope this is OK. + * Otherwise, we could scan the list of used descriptors and proceed + * recycling descriptors if we find a !OWNed one behind the target... + * + * - Always keep an empty slot around to mark the end of the list of + * jobs. The driver clears the descriptor ahead when enqueueing a new + * packet. + */ + +#define DRVNAME "mve" +#define MAX_NUM_SLOTS 3 + +#if MV643XXETH_NUM_DRIVER_SLOTS > MAX_NUM_SLOTS +#error "mv643xxeth: only MAX_NUM_SLOTS supported" +#endif + +#ifdef NDEBUG +#error "Driver uses assert() statements with side-effects; MUST NOT define NDEBUG" +#endif + +#ifdef MVETH_DEBUG +#define STATIC +#else +#define STATIC static +#endif + +#define TX_AVAILABLE_RING_SIZE(mp) ((mp)->xbuf_count - (TX_NUM_TAG_SLOTS)) + +/* macros for ring alignment; proper alignment is a hardware req; . */ + +#ifdef ENABLE_HW_SNOOPING + +#define RING_ALIGNMENT 16 +/* rx buffers must be 64-bit aligned (chip requirement) */ +#define RX_BUF_ALIGNMENT 8 + +#else /* ENABLE_HW_SNOOPING */ + +/* Software cache management */ + +#ifndef __PPC__ +#error "Dont' know how to deal with cache on this CPU architecture" +#endif + +/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency + * management works for cache line sizes of 16 and 32 bytes only. If the line size + * is bigger, the descriptors could be padded... + */ +#if PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32 +#error "Cache line size must be 16 or 32" +#else +#define RING_ALIGNMENT PPC_CACHE_ALIGNMENT +#define RX_BUF_ALIGNMENT PPC_CACHE_ALIGNMENT +#endif + +#endif /* ENABLE_HW_SNOOPING */ + + +/* HELPER MACROS */ + +/* Align base to alignment 'a' */ +#define MV643XX_ALIGN(b, a) ((((uint32_t)(b)) + (a)-1) & (~((a)-1))) + +#define NOOP() do {} while(0) + +/* Function like macros */ +#define MV_READ(off) \ + ld_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off))) +#define MV_WRITE(off, data) \ + st_le32((volatile uint32_t *)(BSP_MV64x60_BASE + (off)), ((unsigned)data)) + + +/* ENET window mapped 1:1 to CPU addresses by our BSP/MotLoad + * -- if this is changed, we should think about caching the 'next' and 'buf' pointers. + */ +#define CPUADDR2ENET(a) ((Dma_addr_t)(a)) +#define ENET2CPUADDR(a) (a) + +#if 1 /* Whether to automatically try to reclaim descriptors when enqueueing new packets */ +#define MVETH_CLEAN_ON_SEND(mp) (BSP_mve_swipe_tx(mp)) +#else +#define MVETH_CLEAN_ON_SEND(mp) (-1) +#endif + +#define NEXT_TXD(d) (d)->next +#define NEXT_RXD(d) (d)->next + +/* REGISTER AND DESCRIPTOR OFFSET AND BIT DEFINITIONS */ + +/* Descriptor Definitions */ +/* Rx descriptor */ +#define RDESC_ERROR (1<< 0) /* Error summary */ + +/* Error code (bit 1&2) is only valid if summary bit is set */ +#define RDESC_CRC_ERROR ( 1) +#define RDESC_OVERRUN_ERROR ( 3) +#define RDESC_MAX_FRAMELENGTH_ERROR ( 5) +#define RDESC_RESOURCE_ERROR ( 7) + +#define RDESC_LAST (1<<26) /* Last Descriptor */ +#define RDESC_FRST (1<<27) /* First Descriptor */ +#define RDESC_INT_ENA (1<<29) /* Enable Interrupts */ +#define RDESC_DMA_OWNED (1<<31) + +/* Tx descriptor */ +#define TDESC_ERROR (1<< 0) /* Error summary */ +#define TDESC_ZERO_PAD (1<<19) +#define TDESC_LAST (1<<20) /* Last Descriptor */ +#define TDESC_FRST (1<<21) /* First Descriptor */ +#define TDESC_GEN_CRC (1<<22) +#define TDESC_INT_ENA (1<<23) /* Enable Interrupts */ +#define TDESC_DMA_OWNED (1<<31) + + + +/* Register Definitions */ +#define MV643XX_ETH_PHY_ADDR_R (0x2000) +#define MV643XX_ETH_SMI_R (0x2004) +#define MV643XX_ETH_SMI_BUSY (1<<28) +#define MV643XX_ETH_SMI_VALID (1<<27) +#define MV643XX_ETH_SMI_OP_WR (0<<26) +#define MV643XX_ETH_SMI_OP_RD (1<<26) + +#define MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port) (0x2448 + ((port)<<10)) +#define MV643XX_ETH_TX_START(queue) (0x0001<<(queue)) +#define MV643XX_ETH_TX_STOP(queue) (0x0100<<(queue)) +#define MV643XX_ETH_TX_START_M(queues) ((queues)&0xff) +#define MV643XX_ETH_TX_STOP_M(queues) (((queues)&0xff)<<8) +#define MV643XX_ETH_TX_STOP_ALL (0xff00) +#define MV643XX_ETH_TX_ANY_RUNNING (0x00ff) + +#define MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(port) (0x2680 + ((port)<<10)) +#define MV643XX_ETH_RX_START(queue) (0x0001<<(queue)) +#define MV643XX_ETH_RX_STOP(queue) (0x0100<<(queue)) +#define MV643XX_ETH_RX_STOP_ALL (0xff00) +#define MV643XX_ETH_RX_ANY_RUNNING (0x00ff) + +#define MV643XX_ETH_CURRENT_SERVED_TX_DESC(port) (0x2684 + ((port)<<10)) + +/* The chip puts the ethernet header at offset 2 into the buffer so + * that the payload is aligned + */ +#define ETH_RX_OFFSET 2 +#define ETH_CRC_LEN 4 /* strip FCS at end of packet */ + + +#define MV643XX_ETH_INTERRUPT_CAUSE_R(port) (0x2460 + ((port)<<10)) +/* not fully understood; RX seems to raise 0x0005 or 0x0c05 if last buffer is filled and 0x0c00 + * if there are no buffers + */ +#define MV643XX_ETH_ALL_IRQS (0x07ffffff) +#define MV643XX_ETH_KNOWN_IRQS (0x00080c07) +#define MV643XX_ETH_IRQ_EXT_ENA (1<<1) +/* defined in public header +#define MV643XX_ETH_IRQ_RX_DONE (1<<2) + */ +#define MV643XX_ETH_IRQ_RX_NO_DESC (1<<10) +#define MV643XX_ETH_TX_Q_N_END(n) (1<<((n)+19)) +/* We just use queue 0 */ +#define MV643XX_ETH_TX_Q_END MV643XX_ETH_TX_Q_N_END(0) + +#define MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(port) (0x2464 + ((port)<<10)) +/* not fully understood; TX seems to raise 0x0001 and link change is 0x00010000 + * if there are no buffers + */ +#define MV643XX_ETH_ALL_EXT_IRQS (0x0011ffff) +/* Recent (2013) linux driver mentions both bits 0x00110000 as 'link change' causes */ +#define MV643XX_ETH_KNOWN_EXT_IRQS (0x00110101) +/* TX queues 0..7 */ +#define MV643XX_ETH_EXT_IRQ_TXN_DONE(n) (1<<(n)) +/* We just use queue 0 */ +/* defined in public header +#define MV643XX_ETH_EXT_IRQ_TX_DONE MV643XX_ETH_EXT_IRQ_TXN_DONE(0) +#define MV643XX_ETH_EXT_IRQ_LINK_CHG (1<<16) + */ +#define MV643XX_ETH_INTERRUPT_ENBL_R(port) (0x2468 + ((port)<<10)) +#define MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(port) (0x246c + ((port)<<10)) + +/* port configuration */ +#define MV643XX_ETH_PORT_CONFIG_R(port) (0x2400 + ((port)<<10)) +#define MV643XX_ETH_UNICAST_PROMISC_MODE (1<<0) +#define MV643XX_ETH_DFLT_RX_Q(q) ((q)<<1) +#define MV643XX_ETH_DFLT_RX_ARP_Q(q) ((q)<<4) +#define MV643XX_ETH_REJ_BCAST_IF_NOT_IP_OR_ARP (1<<7) +#define MV643XX_ETH_REJ_BCAST_IF_IP (1<<8) +#define MV643XX_ETH_REJ_BCAST_IF_ARP (1<<9) +#define MV643XX_ETH_TX_AM_NO_UPDATE_ERR_SUMMARY (1<<12) +#define MV643XX_ETH_CAPTURE_TCP_FRAMES_ENBL (1<<14) +#define MV643XX_ETH_CAPTURE_UDP_FRAMES_ENBL (1<<15) +#define MV643XX_ETH_DFLT_RX_TCP_Q(q) ((q)<<16) +#define MV643XX_ETH_DFLT_RX_UDP_Q(q) ((q)<<19) +#define MV643XX_ETH_DFLT_RX_BPDU_Q(q) ((q)<<22) + + + +#define MV643XX_ETH_PORT_CONFIG_XTEND_R(port) (0x2404 + ((port)<<10)) +#define MV643XX_ETH_CLASSIFY_ENBL (1<<0) +#define MV643XX_ETH_SPAN_BPDU_PACKETS_AS_NORMAL (0<<1) +#define MV643XX_ETH_SPAN_BPDU_PACKETS_2_Q7 (1<<1) +#define MV643XX_ETH_PARTITION_DISBL (0<<2) +#define MV643XX_ETH_PARTITION_ENBL (1<<2) + +#define MV643XX_ETH_SDMA_CONFIG_R(port) (0x241c + ((port)<<10)) +#define MV643XX_ETH_SDMA_RIFB (1<<0) +#define MV643XX_ETH_RX_BURST_SZ_1_64BIT (0<<1) +#define MV643XX_ETH_RX_BURST_SZ_2_64BIT (1<<1) +#define MV643XX_ETH_RX_BURST_SZ_4_64BIT (2<<1) +#define MV643XX_ETH_RX_BURST_SZ_8_64BIT (3<<1) +#define MV643XX_ETH_RX_BURST_SZ_16_64BIT (4<<1) +#define MV643XX_ETH_SMDA_BLM_RX_NO_SWAP (1<<4) +#define MV643XX_ETH_SMDA_BLM_TX_NO_SWAP (1<<5) +#define MV643XX_ETH_SMDA_DESC_BYTE_SWAP (1<<6) +#define MV643XX_ETH_TX_BURST_SZ_1_64BIT (0<<22) +#define MV643XX_ETH_TX_BURST_SZ_2_64BIT (1<<22) +#define MV643XX_ETH_TX_BURST_SZ_4_64BIT (2<<22) +#define MV643XX_ETH_TX_BURST_SZ_8_64BIT (3<<22) +#define MV643XX_ETH_TX_BURST_SZ_16_64BIT (4<<22) + +#define MV643XX_ETH_RX_MIN_FRAME_SIZE_R(port) (0x247c + ((port)<<10)) + + +#define MV643XX_ETH_SERIAL_CONTROL_R(port) (0x243c + ((port)<<10)) +#define MV643XX_ETH_SERIAL_PORT_ENBL (1<<0) /* Enable serial port */ +#define MV643XX_ETH_FORCE_LINK_PASS (1<<1) +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLEX (1<<2) +#define MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOWCTL (1<<3) +#define MV643XX_ETH_ADVERTISE_SYMMETRIC_FLOWCTL (1<<4) +#define MV643XX_ETH_FORCE_FC_MODE_TX_PAUSE_DIS (1<<5) +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX (1<<7) +#define MV643XX_ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR (1<<8) +#define MV643XX_ETH_BIT9_UNKNOWN (1<<9) /* unknown purpose; linux sets this */ +#define MV643XX_ETH_FORCE_LINK_FAIL_DISABLE (1<<10) +#define MV643XX_ETH_RETRANSMIT_FOREVER (1<<11) /* limit to 16 attempts if clear */ +#define MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII (1<<13) +#define MV643XX_ETH_DTE_ADV_1 (1<<14) +#define MV643XX_ETH_AUTO_NEG_BYPASS_ENBL (1<<15) +#define MV643XX_ETH_RESTART_AUTO_NEG (1<<16) +#define MV643XX_ETH_SC_MAX_RX_1518 (0<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_1522 (1<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_1552 (2<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_9022 (3<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_9192 (4<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_9700 (5<<17) /* Limit RX packet size */ +#define MV643XX_ETH_SC_MAX_RX_MASK (7<<17) /* bitmask */ +#define MV643XX_ETH_SET_EXT_LOOPBACK (1<<20) +#define MV643XX_ETH_SET_FULL_DUPLEX (1<<21) +#define MV643XX_ETH_ENBL_FLOWCTL_TX_RX_IN_FD (1<<22) /* enable flow ctrl on rx and tx in full-duplex */ +#define MV643XX_ETH_SET_GMII_SPEED_1000 (1<<23) /* 10/100 if clear */ +#define MV643XX_ETH_SET_MII_SPEED_100 (1<<24) /* 10 if clear */ + +#define MV643XX_ETH_PORT_STATUS_R(port) (0x2444 + ((port)<<10)) + +#define MV643XX_ETH_PORT_STATUS_MODE_10_BIT (1<<0) +#define MV643XX_ETH_PORT_STATUS_LINK_UP (1<<1) +#define MV643XX_ETH_PORT_STATUS_FDX (1<<2) +#define MV643XX_ETH_PORT_STATUS_FC (1<<3) +#define MV643XX_ETH_PORT_STATUS_1000 (1<<4) +#define MV643XX_ETH_PORT_STATUS_100 (1<<5) +/* PSR bit 6 unknown */ +#define MV643XX_ETH_PORT_STATUS_TX_IN_PROGRESS (1<<7) +#define MV643XX_ETH_PORT_STATUS_ANEG_BYPASSED (1<<8) +#define MV643XX_ETH_PORT_STATUS_PARTITION (1<<9) +#define MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY (1<<10) + +#define MV643XX_ETH_MIB_COUNTERS(port) (0x3000 + ((port)<<7)) +#define MV643XX_ETH_NUM_MIB_COUNTERS 32 + +#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO (0) +#define MV643XX_ETH_MIB_GOOD_OCTS_RCVD_HI (1<<2) +#define MV643XX_ETH_MIB_BAD_OCTS_RCVD (2<<2) +#define MV643XX_ETH_MIB_INTERNAL_MAC_TX_ERR (3<<2) +#define MV643XX_ETH_MIB_GOOD_FRAMES_RCVD (4<<2) +#define MV643XX_ETH_MIB_BAD_FRAMES_RCVD (5<<2) +#define MV643XX_ETH_MIB_BCAST_FRAMES_RCVD (6<<2) +#define MV643XX_ETH_MIB_MCAST_FRAMES_RCVD (7<<2) +#define MV643XX_ETH_MIB_FRAMES_64_OCTS (8<<2) +#define MV643XX_ETH_MIB_FRAMES_65_127_OCTS (9<<2) +#define MV643XX_ETH_MIB_FRAMES_128_255_OCTS (10<<2) +#define MV643XX_ETH_MIB_FRAMES_256_511_OCTS (11<<2) +#define MV643XX_ETH_MIB_FRAMES_512_1023_OCTS (12<<2) +#define MV643XX_ETH_MIB_FRAMES_1024_MAX_OCTS (13<<2) +#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO (14<<2) +#define MV643XX_ETH_MIB_GOOD_OCTS_SENT_HI (15<<2) +#define MV643XX_ETH_MIB_GOOD_FRAMES_SENT (16<<2) +#define MV643XX_ETH_MIB_EXCESSIVE_COLL (17<<2) +#define MV643XX_ETH_MIB_MCAST_FRAMES_SENT (18<<2) +#define MV643XX_ETH_MIB_BCAST_FRAMES_SENT (19<<2) +#define MV643XX_ETH_MIB_UNREC_MAC_CTRL_RCVD (20<<2) +#define MV643XX_ETH_MIB_FC_SENT (21<<2) +#define MV643XX_ETH_MIB_GOOD_FC_RCVD (22<<2) +#define MV643XX_ETH_MIB_BAD_FC_RCVD (23<<2) +#define MV643XX_ETH_MIB_UNDERSIZE_RCVD (24<<2) +#define MV643XX_ETH_MIB_FRAGMENTS_RCVD (25<<2) +#define MV643XX_ETH_MIB_OVERSIZE_RCVD (26<<2) +#define MV643XX_ETH_MIB_JABBER_RCVD (27<<2) +#define MV643XX_ETH_MIB_MAC_RX_ERR (28<<2) +#define MV643XX_ETH_MIB_BAD_CRC_EVENT (29<<2) +#define MV643XX_ETH_MIB_COLL (30<<2) +#define MV643XX_ETH_MIB_LATE_COLL (31<<2) + +#define MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(port) (0x3400+((port)<<10)) +#define MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(port) (0x3500+((port)<<10)) +#define MV643XX_ETH_DA_FILTER_UNICAST_TBL(port) (0x3600+((port)<<10)) +#define MV643XX_ETH_NUM_MCAST_ENTRIES 64 +#define MV643XX_ETH_NUM_UNICAST_ENTRIES 4 + +#define MV643XX_ETH_BAR_0 (0x2200) +#define MV643XX_ETH_SIZE_R_0 (0x2204) +#define MV643XX_ETH_BAR_1 (0x2208) +#define MV643XX_ETH_SIZE_R_1 (0x220c) +#define MV643XX_ETH_BAR_2 (0x2210) +#define MV643XX_ETH_SIZE_R_2 (0x2214) +#define MV643XX_ETH_BAR_3 (0x2218) +#define MV643XX_ETH_SIZE_R_3 (0x221c) +#define MV643XX_ETH_BAR_4 (0x2220) +#define MV643XX_ETH_SIZE_R_4 (0x2224) +#define MV643XX_ETH_BAR_5 (0x2228) +#define MV643XX_ETH_SIZE_R_5 (0x222c) +#define MV643XX_ETH_NUM_BARS 6 + +/* Bits in the BAR reg to program cache snooping */ +#define MV64360_ENET2MEM_SNOOP_NONE 0x0000 +#define MV64360_ENET2MEM_SNOOP_WT 0x1000 +#define MV64360_ENET2MEM_SNOOP_WB 0x2000 +#define MV64360_ENET2MEM_SNOOP_MSK 0x3000 + + +#define MV643XX_ETH_BAR_ENBL_R (0x2290) +#define MV643XX_ETH_BAR_DISABLE(bar) (1<<(bar)) +#define MV643XX_ETH_BAR_DISBL_ALL 0x3f + +#define MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(port) (0x260c+((port)<<10)) +#define MV643XX_ETH_RX_Q1_CURRENT_DESC_PTR(port) (0x261c+((port)<<10)) +#define MV643XX_ETH_RX_Q2_CURRENT_DESC_PTR(port) (0x262c+((port)<<10)) +#define MV643XX_ETH_RX_Q3_CURRENT_DESC_PTR(port) (0x263c+((port)<<10)) +#define MV643XX_ETH_RX_Q4_CURRENT_DESC_PTR(port) (0x264c+((port)<<10)) +#define MV643XX_ETH_RX_Q5_CURRENT_DESC_PTR(port) (0x265c+((port)<<10)) +#define MV643XX_ETH_RX_Q6_CURRENT_DESC_PTR(port) (0x266c+((port)<<10)) +#define MV643XX_ETH_RX_Q7_CURRENT_DESC_PTR(port) (0x267c+((port)<<10)) + +#define MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(port) (0x26c0+((port)<<10)) +#define MV643XX_ETH_TX_Q1_CURRENT_DESC_PTR(port) (0x26c4+((port)<<10)) +#define MV643XX_ETH_TX_Q2_CURRENT_DESC_PTR(port) (0x26c8+((port)<<10)) +#define MV643XX_ETH_TX_Q3_CURRENT_DESC_PTR(port) (0x26cc+((port)<<10)) +#define MV643XX_ETH_TX_Q4_CURRENT_DESC_PTR(port) (0x26d0+((port)<<10)) +#define MV643XX_ETH_TX_Q5_CURRENT_DESC_PTR(port) (0x26d4+((port)<<10)) +#define MV643XX_ETH_TX_Q6_CURRENT_DESC_PTR(port) (0x26d8+((port)<<10)) +#define MV643XX_ETH_TX_Q7_CURRENT_DESC_PTR(port) (0x26dc+((port)<<10)) + +#define MV643XX_ETH_MAC_ADDR_LO(port) (0x2414+((port)<<10)) +#define MV643XX_ETH_MAC_ADDR_HI(port) (0x2418+((port)<<10)) + +/* TYPE DEFINITIONS */ + +/* just to make the purpose explicit; vars of this + * type may need CPU-dependent address translation, + * endian conversion etc. + */ +typedef uint32_t Dma_addr_t; + +typedef volatile struct mveth_rx_desc { +#ifndef __BIG_ENDIAN__ +#error "descriptor declaration not implemented for little endian machines" +#endif + uint16_t byte_cnt; + uint16_t buf_size; + uint32_t cmd_sts; /* control and status */ + Dma_addr_t next_desc_ptr; /* next descriptor (as seen from DMA) */ + Dma_addr_t buf_ptr; + /* fields below here are not used by the chip */ + void *u_buf; /* user buffer */ + volatile struct mveth_rx_desc *next; /* next descriptor (CPU address; next_desc_ptr is a DMA address) */ + uint32_t pad[2]; +} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthRxDescRec, *MvEthRxDesc; + +typedef volatile struct mveth_tx_desc { +#ifndef __BIG_ENDIAN__ +#error "descriptor declaration not implemented for little endian machines" +#endif + uint16_t byte_cnt; + uint16_t l4i_chk; + uint32_t cmd_sts; /* control and status */ + Dma_addr_t next_desc_ptr; /* next descriptor (as seen from DMA) */ + Dma_addr_t buf_ptr; + /* fields below here are not used by the chip */ + uint32_t workaround[2]; /* use this space to work around the 8byte problem (is this real?) */ + void *u_buf; /* user buffer */ + volatile struct mveth_tx_desc *next; /* next descriptor (CPU address; next_desc_ptr is a DMA address) */ +} __attribute__(( aligned(RING_ALIGNMENT) )) MvEthTxDescRec, *MvEthTxDesc; + +/* Assume there are never more then 64k aliasing entries */ +typedef uint16_t Mc_Refcnt[MV643XX_ETH_NUM_MCAST_ENTRIES*4]; + +/* driver private data and bsdnet interface structure */ +struct mveth_private { + MvEthRxDesc rx_ring; /* pointers to aligned ring area */ + MvEthTxDesc tx_ring; /* pointers to aligned ring area */ + MvEthRxDesc ring_area; /* allocated ring area */ + int rbuf_count, xbuf_count; /* saved ring sizes from ifconfig */ + int port_num; + int phy; + MvEthRxDesc d_rx_t; /* tail of the RX ring; next received packet */ + MvEthTxDesc d_tx_t, d_tx_h; + uint32_t rx_desc_dma, tx_desc_dma; /* ring address as seen by DMA; (1:1 on this BSP) */ + int avail; + void (*isr)(void*); + void *isr_arg; + /* Callbacks to handle buffers */ + void (*cleanup_txbuf)(void*, void*, int); /* callback to cleanup TX buffer */ + void *cleanup_txbuf_arg; + void *(*alloc_rxbuf)(int *psize, uintptr_t *paddr); /* allocate RX buffer */ + void (*consume_rxbuf)(void*, void*, int); /* callback to consume RX buffer */ + void *consume_rxbuf_arg; + rtems_id tid; + uint32_t irq_mask; /* IRQs we use */ + uint32_t xirq_mask; + int promisc; + struct { + unsigned irqs; + unsigned maxchain; + unsigned repack; + unsigned packet; + unsigned idrops; /* no counter in core code */ + struct { + uint64_t good_octs_rcvd; /* 64-bit */ + uint32_t bad_octs_rcvd; + uint32_t internal_mac_tx_err; + uint32_t good_frames_rcvd; + uint32_t bad_frames_rcvd; + uint32_t bcast_frames_rcvd; + uint32_t mcast_frames_rcvd; + uint32_t frames_64_octs; + uint32_t frames_65_127_octs; + uint32_t frames_128_255_octs; + uint32_t frames_256_511_octs; + uint32_t frames_512_1023_octs; + uint32_t frames_1024_max_octs; + uint64_t good_octs_sent; /* 64-bit */ + uint32_t good_frames_sent; + uint32_t excessive_coll; + uint32_t mcast_frames_sent; + uint32_t bcast_frames_sent; + uint32_t unrec_mac_ctrl_rcvd; + uint32_t fc_sent; + uint32_t good_fc_rcvd; + uint32_t bad_fc_rcvd; + uint32_t undersize_rcvd; + uint32_t fragments_rcvd; + uint32_t oversize_rcvd; + uint32_t jabber_rcvd; + uint32_t mac_rx_err; + uint32_t bad_crc_event; + uint32_t coll; + uint32_t late_coll; + } mib; + } stats; + struct { + Mc_Refcnt specl, other; + } mc_refcnt; +}; + +/* GLOBAL VARIABLES */ + +/* Format strings for statistics messages */ +static const char *mibfmt[] = { + " GOOD_OCTS_RCVD: %"PRIu64"\n", + 0, + " BAD_OCTS_RCVD: %"PRIu32"\n", + " INTERNAL_MAC_TX_ERR: %"PRIu32"\n", + " GOOD_FRAMES_RCVD: %"PRIu32"\n", + " BAD_FRAMES_RCVD: %"PRIu32"\n", + " BCAST_FRAMES_RCVD: %"PRIu32"\n", + " MCAST_FRAMES_RCVD: %"PRIu32"\n", + " FRAMES_64_OCTS: %"PRIu32"\n", + " FRAMES_65_127_OCTS: %"PRIu32"\n", + " FRAMES_128_255_OCTS: %"PRIu32"\n", + " FRAMES_256_511_OCTS: %"PRIu32"\n", + " FRAMES_512_1023_OCTS:%"PRIu32"\n", + " FRAMES_1024_MAX_OCTS:%"PRIu32"\n", + " GOOD_OCTS_SENT: %"PRIu64"\n", + 0, + " GOOD_FRAMES_SENT: %"PRIu32"\n", + " EXCESSIVE_COLL: %"PRIu32"\n", + " MCAST_FRAMES_SENT: %"PRIu32"\n", + " BCAST_FRAMES_SENT: %"PRIu32"\n", + " UNREC_MAC_CTRL_RCVD: %"PRIu32"\n", + " FC_SENT: %"PRIu32"\n", + " GOOD_FC_RCVD: %"PRIu32"\n", + " BAD_FC_RCVD: %"PRIu32"\n", + " UNDERSIZE_RCVD: %"PRIu32"\n", + " FRAGMENTS_RCVD: %"PRIu32"\n", + " OVERSIZE_RCVD: %"PRIu32"\n", + " JABBER_RCVD: %"PRIu32"\n", + " MAC_RX_ERR: %"PRIu32"\n", + " BAD_CRC_EVENT: %"PRIu32"\n", + " COLL: %"PRIu32"\n", + " LATE_COLL: %"PRIu32"\n", +}; + +/* Interrupt Handler Connection */ + +/* forward decls + implementation for IRQ API funcs */ + +STATIC int +mveth_init_rx_desc_ring(struct mveth_private *mp); + +STATIC int +mveth_init_tx_desc_ring(struct mveth_private *mp); + +int +BSP_mve_dring_nonsync(struct mveth_private *mp); + +static void mveth_isr(rtems_irq_hdl_param unit); +static void noop(const rtems_irq_connect_data *unused) {} +static int noop1(const rtems_irq_connect_data *unused) { return 0; } + +static rtems_irq_connect_data irq_data[MAX_NUM_SLOTS] = { + { + BSP_IRQ_ETH0, + 0, + (rtems_irq_hdl_param)0, + noop, + noop, + noop1 + }, + { + BSP_IRQ_ETH1, + 0, + (rtems_irq_hdl_param)1, + noop, + noop, + noop1 + }, + { + BSP_IRQ_ETH2, + 0, + (rtems_irq_hdl_param)2, + noop, + noop, + noop1 + }, +}; + +/* LOW LEVEL SUPPORT ROUTINES */ + +/* Software Cache Coherency */ +#ifndef ENABLE_HW_SNOOPING +#ifndef __PPC__ +#error "Software cache coherency maintenance is not implemented for your CPU architecture" +#endif + +static inline unsigned INVAL_DESC(volatile void *d) +{ +typedef const char cache_line[PPC_CACHE_ALIGNMENT]; + asm volatile("dcbi 0, %1":"=m"(*(cache_line*)d):"r"(d)); + return (unsigned)d; /* so this can be used in comma expression */ +} + +static inline void FLUSH_DESC(volatile void *d) +{ +typedef const char cache_line[PPC_CACHE_ALIGNMENT]; + asm volatile("dcbf 0, %0"::"r"(d),"m"(*(cache_line*)d)); +} + +static inline void FLUSH_BARRIER(void) +{ + asm volatile("eieio"); +} + +/* RX buffers are always cache-line aligned + * ASSUMPTIONS: + * - 'addr' is cache aligned + * - len is a multiple >0 of cache lines + */ +static inline void INVAL_BUF(register uintptr_t addr, register int len) +{ +typedef char maxbuf[2048]; /* more than an ethernet packet */ + do { + len -= RX_BUF_ALIGNMENT; + asm volatile("dcbi %0, %1"::"b"(addr),"r"(len)); + } while (len > 0); + asm volatile("":"=m"(*(maxbuf*)addr)); +} + +/* Flushing TX buffers is a little bit trickier; we don't really know their + * alignment but *assume* adjacent addresses are covering 'ordinary' memory + * so that flushing them does no harm! + */ +static inline void FLUSH_BUF(register uintptr_t addr, register int len) +{ + asm volatile("":::"memory"); + len = MV643XX_ALIGN(len, RX_BUF_ALIGNMENT); + do { + asm volatile("dcbf %0, %1"::"b"(addr),"r"(len)); + len -= RX_BUF_ALIGNMENT; + } while ( len >= 0 ); +} + +#else /* hardware snooping enabled */ + +/* inline this to silence compiler warnings */ +static inline int INVAL_DESC(volatile void *d) +{ return 0; } + +#define FLUSH_DESC(d) NOOP() +#define INVAL_BUF(b,l) NOOP() +#define FLUSH_BUF(b,l) NOOP() +#define FLUSH_BARRIER() NOOP() + +#endif /* cache coherency support */ + +/* Synchronize memory access */ +#ifdef __PPC__ +static inline void membarrier(void) +{ + asm volatile("sync":::"memory"); +} +#else +#error "memory barrier instruction not defined (yet) for this CPU" +#endif + +/* Enable and disable interrupts at the device */ +static inline void +mveth_enable_irqs(struct mveth_private *mp, uint32_t mask) +{ +rtems_interrupt_level l; +uint32_t val; + rtems_interrupt_disable(l); + + val = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num)); + val = (val | mask | MV643XX_ETH_IRQ_EXT_ENA) & mp->irq_mask; + + MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), val); + + val = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num)); + val = (val | mask) & mp->xirq_mask; + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), val); + + rtems_interrupt_enable(l); +} + +static inline uint32_t +mveth_disable_irqs(struct mveth_private *mp, uint32_t mask) +{ +rtems_interrupt_level l; +uint32_t val,xval,tmp; + rtems_interrupt_disable(l); + + val = MV_READ(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num)); + tmp = ( (val & ~mask) | MV643XX_ETH_IRQ_EXT_ENA ) & mp->irq_mask; + MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), tmp); + + xval = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num)); + tmp = (xval & ~mask) & mp->xirq_mask; + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), tmp); + + rtems_interrupt_enable(l); + + return (val | xval); +} + +/* This should be safe even w/o turning off interrupts if multiple + * threads ack different bits in the cause register (and ignore + * other ones) since writing 'ones' into the cause register doesn't + * 'stick'. + */ + +static inline uint32_t +mveth_ack_irqs(struct mveth_private *mp, uint32_t mask) +{ +register uint32_t x,xe,p; +register uint32_t rval; + + p = mp->port_num; + /* Get cause */ + x = MV_READ(MV643XX_ETH_INTERRUPT_CAUSE_R(p)); + + /* Ack interrupts filtering the ones we're interested in */ + + /* Note: EXT_IRQ bit clears by itself if EXT interrupts are cleared */ + MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(p), ~ (x & mp->irq_mask & mask)); + + /* linux driver tests 1<<1 as a summary bit for extended interrupts; + * the mv64360 seems to use 1<<19 for that purpose; for the moment, + * I just check both. + * Update: link status irq (1<<16 in xe) doesn't set (1<<19) in x! + */ + if ( 1 /* x & 2 */ ) + { + xe = MV_READ(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p)); + + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(p), ~ (xe & mp->xirq_mask & mask)); + } else { + xe = 0; + } +#ifdef MVETH_TESTING + if ( ((x & MV643XX_ETH_ALL_IRQS) & ~MV643XX_ETH_KNOWN_IRQS) + || ((xe & MV643XX_ETH_ALL_EXT_IRQS) & ~MV643XX_ETH_KNOWN_EXT_IRQS) ) { + fprintf(stderr, "Unknown IRQs detected; leaving all disabled for debugging:\n"); + fprintf(stderr, "Cause reg was 0x%08x, ext cause 0x%08x\n", x, xe); +/* + mp->irq_mask = 0; + mp->xirq_mask = 0; +*/ + } +#endif + /* luckily, the extended and 'normal' interrupts we use don't overlap so + * we can just OR them into a single word + */ + rval = (xe & mp->xirq_mask) | (x & mp->irq_mask); + +#ifdef MVETH_DEBUG + printk(DRVNAME"%i: mveth_ack_irqs 0x%08x\n", rval); +#endif + return rval; +} + +static void mveth_isr(rtems_irq_hdl_param arg) +{ +struct mveth_private *mp = (struct mveth_private*) arg; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mveth_isr\n"); +#endif + mp->stats.irqs++; + mp->isr(mp->isr_arg); +} + +static void +mveth_clear_mib_counters(struct mveth_private *mp) +{ +register int i; +register uint32_t b; + /* reading the counters resets them */ + b = MV643XX_ETH_MIB_COUNTERS(mp->port_num); + for (i=0; i< MV643XX_ETH_NUM_MIB_COUNTERS; i++, b+=4) + (void)MV_READ(b); +} + +/* Reading a MIB register also clears it. Hence we read the lo + * register first, then the hi one. Correct reading is guaranteed since + * the 'lo' register cannot overflow after it is read since it had + * been reset to 0. + */ +static unsigned long long +read_long_mib_counter(int port_num, int idx) +{ +unsigned long lo; +unsigned long long hi; + lo = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2)); + idx++; + hi = MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2)); + return (hi<<32) | lo; +} + +static inline unsigned long +read_mib_counter(int port_num, int idx) +{ + return MV_READ(MV643XX_ETH_MIB_COUNTERS(port_num)+(idx<<2)); +} + + +/* write ethernet address from buffer to hardware (need to change unicast filter after this) */ +static void +mveth_write_eaddr(struct mveth_private *mp, unsigned char *eaddr) +{ +int i; +uint32_t x; + + /* build hi word */ + for (i=4,x=0; i; i--, eaddr++) { + x = (x<<8) | *eaddr; + } + MV_WRITE(MV643XX_ETH_MAC_ADDR_HI(mp->port_num), x); + + /* build lo word */ + for (i=2,x=0; i; i--, eaddr++) { + x = (x<<8) | *eaddr; + } + MV_WRITE(MV643XX_ETH_MAC_ADDR_LO(mp->port_num), x); +} + +static inline int +port2phy(int port) +{ + port &= 0x1f; + /* during early init we may not know the phy and we are given a port number instead! */ + return ( (MV_READ(MV643XX_ETH_PHY_ADDR_R) >> (5*port)) & 0x1f ); +} + +/* PHY/MII Interface + * + * Read/write a PHY register; + * + * NOTE: The SMI register is shared among the three devices. + * Protection is provided by the global networking semaphore. + * If non-bsd drivers are running on a subset of IFs proper + * locking of all shared registers must be implemented! + */ +static unsigned +do_mii_read(int phy, unsigned addr) +{ +unsigned v; +unsigned wc = 0; + + addr &= 0x1f; + + /* wait until not busy */ + do { + v = MV_READ(MV643XX_ETH_SMI_R); + wc++; + } while ( MV643XX_ETH_SMI_BUSY & v ); + + MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (phy<<16) | MV643XX_ETH_SMI_OP_RD ); + + do { + v = MV_READ(MV643XX_ETH_SMI_R); + wc++; + } while ( MV643XX_ETH_SMI_BUSY & v ); + + if (wc>0xffff) + wc = 0xffff; + return (wc<<16) | (v & 0xffff); +} + +unsigned +BSP_mve_mii_read(struct mveth_private *mp, unsigned addr) +{ +unsigned rval = do_mii_read(mp->phy, addr); +#ifdef MVETH_DEBUG + printk(DRVNAME": BSP_mve_mii_read(%d): 0x%08x\n", addr, rval); +#endif + return rval; +} + +unsigned +BSP_mve_mii_read_early(int port, unsigned addr) +{ + return do_mii_read(port2phy(port), addr); +} + +static unsigned +do_mii_write(int phy, unsigned addr, unsigned v) +{ +unsigned wc = 0; + + addr &= 0x1f; + v &= 0xffff; + + /* busywait is ugly but not preventing ISRs or high priority tasks from + * preempting us + */ + + /* wait until not busy */ + while ( MV643XX_ETH_SMI_BUSY & MV_READ(MV643XX_ETH_SMI_R) ) + wc++ /* wait */; + + MV_WRITE(MV643XX_ETH_SMI_R, (addr <<21 ) | (phy<<16) | MV643XX_ETH_SMI_OP_WR | v ); + + return wc; +} + +unsigned +BSP_mve_mii_write(struct mveth_private *mp, unsigned addr, unsigned v) +{ +#ifdef MVETH_DEBUG + printk(DRVNAME": BSP_mve_mii_write(%d): 0x%08x\n", addr, v); +#endif + return do_mii_write( mp->phy, addr, v ); +} + +unsigned +BSP_mve_mii_write_early(int port, unsigned addr, unsigned v) +{ + return do_mii_write(port2phy(port), addr, v); +} + + +/* MID-LAYER SUPPORT ROUTINES */ + +/* Start TX if descriptors are exhausted */ +static __inline__ void +mveth_start_tx(struct mveth_private *mp) +{ +uint32_t running; + if ( mp->avail <= 0 ) { + running = MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num)); + if ( ! (running & MV643XX_ETH_TX_START(0)) ) { + MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0)); + } + } +} + +/* Stop TX and wait for the command queues to stop and the fifo to drain */ +static uint32_t +mveth_stop_tx(int port) +{ +uint32_t active_q; + + active_q = (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) & MV643XX_ETH_TX_ANY_RUNNING); + + if ( active_q ) { + /* Halt TX and wait for activity to stop */ + MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port), MV643XX_ETH_TX_STOP_ALL); + while ( MV643XX_ETH_TX_ANY_RUNNING & MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(port)) ) + /* poll-wait */; + /* Wait for Tx FIFO to drain */ + while ( ! (MV643XX_ETH_PORT_STATUS_R(port) & MV643XX_ETH_PORT_STATUS_TX_FIFO_EMPTY) ) + /* poll-wait */; + } + + return active_q; +} + +void +BSP_mve_promisc_set(struct mveth_private *mp, int promisc) +{ +uint32_t v; + + v = MV_READ(MV643XX_ETH_PORT_CONFIG_R(mp->port_num)); + if ( (mp->promisc = promisc) ) + v |= MV643XX_ETH_UNICAST_PROMISC_MODE; + else + v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE; + MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num), v); +} + +/* update serial port settings from current link status */ + +void +BSP_mve_mcast_filter_clear(struct mveth_private *mp) +{ +int i; +register uint32_t s,o; +uint32_t v = mp->promisc ? 0x01010101 : 0x00000000; + s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num); + o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num); + for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) { + MV_WRITE(s,v); + MV_WRITE(o,v); + s+=4; + o+=4; + } + for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) { + mp->mc_refcnt.specl[i] = 0; + mp->mc_refcnt.other[i] = 0; + } +} + +void +BSP_mve_mcast_filter_accept_all(struct mveth_private *mp) +{ +int i; +register uint32_t s,o; + s = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num); + o = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num); + for (i=0; i<MV643XX_ETH_NUM_MCAST_ENTRIES; i++) { + MV_WRITE(s,0x01010101); + MV_WRITE(o,0x01010101); + s+=4; + o+=4; + /* Not clear what we should do with the reference count. + * For now just increment it. + */ + for (i=0; i<sizeof(mp->mc_refcnt.specl)/sizeof(mp->mc_refcnt.specl[0]); i++) { + mp->mc_refcnt.specl[i]++; + mp->mc_refcnt.other[i]++; + } + } +} + +static void add_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt) +{ +uint32_t val; +uint32_t slot = hash & 0xfc; + + if ( 0 == (*refcnt)[hash]++ ) { + val = MV_READ(off+slot) | ( 1 << ((hash&3)<<3) ); + MV_WRITE(off+slot, val); + } +} + +static void del_entry(uint32_t off, uint8_t hash, Mc_Refcnt *refcnt) +{ +uint32_t val; +uint32_t slot = hash & 0xfc; + + if ( (*refcnt)[hash] > 0 && 0 == --(*refcnt)[hash] ) { + val = MV_READ(off+slot) & ~( 1 << ((hash&3)<<3) ); + MV_WRITE(off+slot, val); + } +} + +void +BSP_mve_mcast_filter_accept_add(struct mveth_private *mp, unsigned char *enaddr) +{ +uint32_t hash; +static const char spec[]={0x01,0x00,0x5e,0x00,0x00}; +static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff}; +uint32_t tabl; +Mc_Refcnt *refcnt; + + if ( ! (0x01 & enaddr[0]) ) { + /* not a multicast address; ignore */ + return; + } + + if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) { + /* broadcast address; ignore */ + return; + } + + if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) { + hash = enaddr[5]; + tabl = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num); + refcnt = &mp->mc_refcnt.specl; + } else { + uint32_t test, mask; + int i; + /* algorithm used by linux driver */ + for ( hash=0, i=0; i<6; i++ ) { + hash = (hash ^ enaddr[i]) << 8; + for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) { + if ( hash & test ) + hash ^= mask; + } + } + tabl = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num); + refcnt = &mp->mc_refcnt.other; + } + add_entry(tabl, hash, refcnt); +} + +void +BSP_mve_mcast_filter_accept_del(struct mveth_private *mp, unsigned char *enaddr) +{ +uint32_t hash; +static const char spec[]={0x01,0x00,0x5e,0x00,0x00}; +static const char bcst[]={0xff,0xff,0xff,0xff,0xff,0xff}; +uint32_t tabl; +Mc_Refcnt *refcnt; + + if ( ! (0x01 & enaddr[0]) ) { + /* not a multicast address; ignore */ + return; + } + + if ( 0 == memcmp(enaddr, bcst, sizeof(bcst)) ) { + /* broadcast address; ignore */ + return; + } + + if ( 0 == memcmp(enaddr, spec, sizeof(spec)) ) { + hash = enaddr[5]; + tabl = MV643XX_ETH_DA_FILTER_SPECL_MCAST_TBL(mp->port_num); + refcnt = &mp->mc_refcnt.specl; + } else { + uint32_t test, mask; + int i; + /* algorithm used by linux driver */ + for ( hash=0, i=0; i<6; i++ ) { + hash = (hash ^ enaddr[i]) << 8; + for ( test=0x8000, mask=0x8380; test>0x0080; test>>=1, mask>>=1 ) { + if ( hash & test ) + hash ^= mask; + } + } + tabl = MV643XX_ETH_DA_FILTER_OTHER_MCAST_TBL(mp->port_num); + refcnt = &mp->mc_refcnt.other; + } + del_entry(tabl, hash, refcnt); +} + +/* Clear all address filters (multi- and unicast) */ +static void +mveth_clear_addr_filters(struct mveth_private *mp) +{ +register int i; +register uint32_t u; + u = MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num); + for (i=0; i<MV643XX_ETH_NUM_UNICAST_ENTRIES; i++) { + MV_WRITE(u,0); + u+=4; + } + BSP_mve_mcast_filter_clear(mp); +} + +/* Setup unicast filter for a given MAC address (least significant nibble) */ +static void +mveth_ucfilter(struct mveth_private *mp, unsigned char mac_lsbyte, int accept) +{ +unsigned nib, slot, bit; +uint32_t val; + /* compute slot in table */ + nib = mac_lsbyte & 0xf; /* strip nibble */ + slot = nib & ~3; /* (nibble/4)*4 */ + bit = (nib & 3)<<3; /* 8*(nibble % 4) */ + val = MV_READ(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot); + if ( accept ) { + val |= 0x01 << bit; + } else { + val &= 0x0e << bit; + } + MV_WRITE(MV643XX_ETH_DA_FILTER_UNICAST_TBL(mp->port_num) + slot, val); +} + +#if defined( ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM ) && 0 +/* Currently unused; small unaligned buffers seem to be rare + * so we just use memcpy()... + */ + +/* memcpy for 0..7 bytes; arranged so that gcc + * optimizes for powerpc... + */ + +static inline void memcpy8(void *to, void *fr, unsigned x) +{ +register uint8_t *d = to, *s = fro; + + d+=l; s+=l; + if ( l & 1 ) { + *--d=*--s; + } + if ( l & 2 ) { + /* pre-decrementing causes gcc to use auto-decrementing + * PPC instructions (lhzu rx, -2(ry)) + */ + d-=2; s-=2; + /* use memcpy; don't cast to short -- accessing + * misaligned data as short is not portable + * (but it works on PPC). + */ + __builtin_memcpy(d,s,2); + } + if ( l & 4 ) { + d-=4; s-=4; + /* see above */ + __builtin_memcpy(d,s,4); + } +} +#endif + +static int +mveth_assign_desc_raw(MvEthTxDesc d, void *buf, int len, void *uptr, unsigned long extra) +{ +int rval = (d->byte_cnt = len); + +#ifdef MVETH_TESTING + assert( !d->u_buf ); + assert( len ); +#endif + + /* set CRC on all descriptors; seems to be necessary */ + d->cmd_sts = extra | (TDESC_GEN_CRC | TDESC_ZERO_PAD); + +#ifdef ENABLE_TX_WORKAROUND_8_BYTE_PROBLEM + /* The buffer must be 64bit aligned if the payload is <8 (??) */ + if ( rval < 8 && ( ((uintptr_t)buf) & 7) ) { + d->buf_ptr = CPUADDR2ENET( d->workaround ); + memcpy((void*)d->workaround, buf, rval); + } else +#endif + { + d->buf_ptr = CPUADDR2ENET( (unsigned long)buf ); + } + d->u_buf = uptr; + d->l4i_chk = 0; + return rval; +} + +/* + * Ring Initialization + * + * ENDIAN ASSUMPTION: DMA engine matches CPU endianness (???) + * + * Linux driver discriminates __LITTLE and __BIG endian for re-arranging + * the u16 fields in the descriptor structs. However, no endian conversion + * is done on the individual fields (SDMA byte swapping is disabled on LE). + */ + +STATIC int +mveth_init_rx_desc_ring(struct mveth_private *mp) +{ +int i,sz; +MvEthRxDesc d; +uintptr_t baddr; + + memset((void*)mp->rx_ring, 0, sizeof(*mp->rx_ring)*mp->rbuf_count); + + mp->rx_desc_dma = CPUADDR2ENET(mp->rx_ring); + + for ( i=0, d = mp->rx_ring; i<mp->rbuf_count; i++, d++ ) { + d->u_buf = mp->alloc_rxbuf(&sz, &baddr); + assert( d->u_buf ); + +#ifndef ENABLE_HW_SNOOPING + /* could reduce the area to max. ethernet packet size */ + INVAL_BUF(baddr, sz); +#endif + + d->buf_size = sz; + d->byte_cnt = 0; + d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA; + d->next = mp->rx_ring + (i+1) % mp->rbuf_count; + + d->buf_ptr = CPUADDR2ENET( baddr ); + d->next_desc_ptr = CPUADDR2ENET(d->next); + FLUSH_DESC(d); + } + FLUSH_BARRIER(); + + mp->d_rx_t = mp->rx_ring; + + /* point the chip to the start of the ring */ + MV_WRITE(MV643XX_ETH_RX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->rx_desc_dma); + + + return i; +} + +STATIC int +mveth_init_tx_desc_ring(struct mveth_private *mp) +{ +int i; +MvEthTxDesc d; + + memset((void*)mp->tx_ring, 0, sizeof(*mp->tx_ring)*mp->xbuf_count); + + /* DMA and CPU live in the same address space (rtems) */ + mp->tx_desc_dma = CPUADDR2ENET(mp->tx_ring); + mp->avail = TX_AVAILABLE_RING_SIZE(mp); + + for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++,d++ ) { + d->l4i_chk = 0; + d->byte_cnt = 0; + d->cmd_sts = 0; + d->buf_ptr = 0; + + d->next = mp->tx_ring + (i+1) % mp->xbuf_count; + d->next_desc_ptr = CPUADDR2ENET(d->next); + FLUSH_DESC(d); + } + FLUSH_BARRIER(); + + mp->d_tx_h = mp->d_tx_t = mp->tx_ring; + + /* point the chip to the start of the ring */ + MV_WRITE(MV643XX_ETH_TX_Q0_CURRENT_DESC_PTR(mp->port_num),mp->tx_desc_dma); + + return i; +} + +/* PUBLIC LOW-LEVEL DRIVER ACCESS */ + +struct mveth_private * +BSP_mve_create( + int unit, + rtems_id tid, + void (*isr)(void*isr_arg), + void *isr_arg, + void (*cleanup_txbuf)(void *user_buf, void *closure, int error_on_tx_occurred), + void *cleanup_txbuf_arg, + void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr), + void (*consume_rxbuf)(void *user_buf, void *closure, int len), + void *consume_rxbuf_arg, + int rx_ring_size, + int tx_ring_size, + int irq_mask +) +{ +struct mveth_private *mp; +int InstallISRSuccessful; + + if ( unit <= 0 || unit > MV643XXETH_NUM_DRIVER_SLOTS ) { + printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, MV643XXETH_NUM_DRIVER_SLOTS); + return 0; + } + + if ( rx_ring_size < 0 && tx_ring_size < 0 ) + return 0; + + if ( MV_64360 != BSP_getDiscoveryVersion(0) ) { + printk(DRVNAME": not mv64360 chip\n"); + return 0; + } + + if ( tx_ring_size < 1 ) { + printk(DRVNAME": tx ring size must not be zero (networking configuration issue?)\n"); + return 0; + } + + if ( rx_ring_size < 1 ) { + printk(DRVNAME": rx ring size must not be zero (networking configuration issue?)\n"); + return 0; + } + + mp = calloc( 1, sizeof *mp ); + + mp->port_num = unit-1; + mp->phy = port2phy(mp->port_num); + + mp->tid = tid; + mp->isr = isr; + mp->isr_arg = isr_arg; + + mp->cleanup_txbuf = cleanup_txbuf; + mp->cleanup_txbuf_arg = cleanup_txbuf_arg; + mp->alloc_rxbuf = alloc_rxbuf; + mp->consume_rxbuf = consume_rxbuf; + mp->consume_rxbuf_arg = consume_rxbuf_arg; + + mp->rbuf_count = rx_ring_size; + mp->xbuf_count = tx_ring_size; + + if ( mp->xbuf_count > 0 ) + mp->xbuf_count += TX_NUM_TAG_SLOTS; + + if ( mp->rbuf_count < 0 ) + mp->rbuf_count = 0; + if ( mp->xbuf_count < 0 ) + mp->xbuf_count = 0; + + /* allocate ring area; add 1 entry -- room for alignment */ + assert( !mp->ring_area ); + mp->ring_area = malloc( sizeof(*mp->ring_area) * (mp->rbuf_count + mp->xbuf_count + 1) ); + assert( mp->ring_area ); + + BSP_mve_stop_hw(mp); + + if ( irq_mask ) { + irq_data[mp->port_num].hdl = mveth_isr; + irq_data[mp->port_num].handle = (rtems_irq_hdl_param)mp; + InstallISRSuccessful = BSP_install_rtems_irq_handler( &irq_data[mp->port_num] ); + assert( InstallISRSuccessful ); + } + + if ( rx_ring_size < 0 ) + irq_mask &= ~ MV643XX_ETH_IRQ_RX_DONE; + if ( tx_ring_size < 0 ) + irq_mask &= ~ MV643XX_ETH_EXT_IRQ_TX_DONE; + + mp->irq_mask = (irq_mask & MV643XX_ETH_IRQ_RX_DONE); + if ( (irq_mask &= (MV643XX_ETH_EXT_IRQ_TX_DONE | MV643XX_ETH_EXT_IRQ_LINK_CHG)) ) { + mp->irq_mask |= MV643XX_ETH_IRQ_EXT_ENA; + mp->xirq_mask = irq_mask; + } else { + mp->xirq_mask = 0; + } + + return mp; +} + +void +BSP_mve_update_serial_port(struct mveth_private *mp, int media) +{ +int port = mp->port_num; +uint32_t old, new; + +#ifdef MVETH_DEBUG + printk(DRVNAME": Entering BSP_mve_update_serial_port()\n"); +#endif + + new = old = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(port)); + + /* mask speed and duplex settings */ + new &= ~( MV643XX_ETH_SET_GMII_SPEED_1000 + | MV643XX_ETH_SET_MII_SPEED_100 + | MV643XX_ETH_SET_FULL_DUPLEX ); + + if ( (MV643XX_MEDIA_FD & media) ) + new |= MV643XX_ETH_SET_FULL_DUPLEX; + + switch ( (media & MV643XX_MEDIA_SPEED_MSK) ) { + default: /* treat as 10 */ + break; + case MV643XX_MEDIA_100: + new |= MV643XX_ETH_SET_MII_SPEED_100; + break; + case MV643XX_MEDIA_1000: + new |= MV643XX_ETH_SET_GMII_SPEED_1000; + break; + } + + + if ( new != old ) { + if ( ! (MV643XX_ETH_SERIAL_PORT_ENBL & new) ) { + /* just write */ + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new); + } else { + uint32_t were_running; + + were_running = mveth_stop_tx(port); + + old &= ~MV643XX_ETH_SERIAL_PORT_ENBL; + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), old); + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new); + /* linux driver writes twice... */ + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(port), new); + + if ( were_running ) { + MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0)); + } + } + } + /* If TX stalled because there was no buffer then whack it */ + mveth_start_tx(mp); +} + +rtems_id +BSP_mve_get_tid(struct mveth_private *mp) +{ + return mp->tid; +} + +int +BSP_mve_detach(struct mveth_private *mp) +{ + BSP_mve_stop_hw(mp); + if ( mp->irq_mask || mp->xirq_mask ) { + if ( !BSP_remove_rtems_irq_handler( &irq_data[mp->port_num] ) ) + return -1; + } + free( (void*)mp->ring_area ); + memset(mp, 0, sizeof(*mp)); + __asm__ __volatile__("":::"memory"); + return 0; +} + +/* MAIN RX-TX ROUTINES + * + * BSP_mve_swipe_tx(): descriptor scavenger; releases mbufs + * BSP_mve_send_buf(): xfer mbufs from IF to chip + * BSP_mve_swipe_rx(): enqueue received mbufs to interface + * allocate new ones and yield them to the + * chip. + */ + +/* clean up the TX ring freeing up buffers */ +int +BSP_mve_swipe_tx(struct mveth_private *mp) +{ +int rval = 0; +register MvEthTxDesc d; + + for ( d = mp->d_tx_t; d->buf_ptr; d = NEXT_TXD(d) ) { + + INVAL_DESC(d); + + if ( (TDESC_DMA_OWNED & d->cmd_sts) + && (uint32_t)d == MV_READ(MV643XX_ETH_CURRENT_SERVED_TX_DESC(mp->port_num)) ) + break; + + /* d->u_buf is only set on the last descriptor in a chain; + * we only count errors in the last descriptor; + */ + if ( d->u_buf ) { + mp->cleanup_txbuf(d->u_buf, mp->cleanup_txbuf_arg, (d->cmd_sts & TDESC_ERROR) ? 1 : 0); + d->u_buf = 0; + } + + d->buf_ptr = 0; + + rval++; + } + mp->d_tx_t = d; + mp->avail += rval; + + return mp->avail; +} + +int +BSP_mve_send_buf_chain(struct mveth_private *mp, MveEthBufIterNext next, MveEthBufIter *it) +{ +int rval; +register MvEthTxDesc l,d,h; +int nmbs; +MveEthBufIter head = *it; + + rval = 0; + + /* if no descriptor is available; try to wipe the queue */ + if ( (mp->avail < 1) && MVETH_CLEAN_ON_SEND(mp)<=0 ) { + /* Maybe TX is stalled and needs to be restarted */ + mveth_start_tx(mp); + return -1; + } + + h = mp->d_tx_h; + +#ifdef MVETH_TESTING + assert( !h->buf_ptr ); + assert( !h->u_buf ); +#endif + + /* Don't use the first descriptor yet because BSP_mve_swipe_tx() + * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we + * start with the second mbuf and fill the first descriptor + * last. + */ + + l = h; + d = NEXT_TXD(h); + + mp->avail--; + + nmbs = 1; + while ( (it = next(it)) ) { + if ( 0 == it->len ) + continue; /* skip empty mbufs */ + + nmbs++; + + if ( mp->avail < 1 && MVETH_CLEAN_ON_SEND(mp)<=0 ) { + /* Maybe TX was stalled - try to restart */ + mveth_start_tx(mp); + + /* not enough descriptors; cleanup... + * the first slot was never used, so we start + * at mp->d_tx_h->next; + */ + for ( l = NEXT_TXD(h); l!=d; l=NEXT_TXD(l) ) { +#ifdef MVETH_TESTING + assert( l->u_buf == 0 ); +#endif + l->buf_ptr = 0; + l->cmd_sts = 0; + mp->avail++; + } + mp->avail++; + if ( nmbs > TX_AVAILABLE_RING_SIZE(mp) ) { + /* this chain will never fit into the ring */ + if ( nmbs > mp->stats.maxchain ) + mp->stats.maxchain = nmbs; + mp->stats.repack++; + /* caller may reorganize chain */ + return -2; + } + return -1; + } + + mp->avail--; + +#ifdef MVETH_TESTING + assert( d != h ); + assert( !d->buf_ptr ); +#endif + + /* fill this slot */ + rval += mveth_assign_desc_raw(d, it->data, it->len, it->uptr, TDESC_DMA_OWNED); + + FLUSH_BUF( (uint32_t)it->data, it->len ); + + l = d; + d = NEXT_TXD(d); + + FLUSH_DESC(l); + } + + /* fill first slot - don't release to DMA yet */ + rval += mveth_assign_desc_raw(h, head.data, head.len, head.uptr, TDESC_FRST); + + + FLUSH_BUF((uint32_t)head.data, head.len); + + + /* tag last slot; this covers the case where 1st==last */ + l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA; + + FLUSH_DESC(l); + + /* Tag end; make sure chip doesn't try to read ahead of here! */ + l->next->cmd_sts = 0; + FLUSH_DESC(l->next); + + membarrier(); + + /* turn over the whole chain by flipping ownership of the first desc */ + h->cmd_sts |= TDESC_DMA_OWNED; + + FLUSH_DESC(h); + + membarrier(); + + /* notify the device */ + MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0)); + + /* Update softc */ + mp->stats.packet++; + if ( nmbs > mp->stats.maxchain ) + mp->stats.maxchain = nmbs; + + /* remember new head */ + mp->d_tx_h = d; + + return rval; /* #bytes sent */ +} + +int +BSP_mve_send_buf_raw( + struct mveth_private *mp, + void *head_p, + int h_len, + void *data_p, + int d_len) +{ +int rval; +register MvEthTxDesc l,d,h; +int needed; +void *frst_buf; +int frst_len; +void *uarg; + + rval = 0; + +#ifdef MVETH_TESTING + assert(head_p || data_p); +#endif + + needed = head_p && data_p ? 2 : 1; + + /* if no descriptor is available; try to wipe the queue */ + if ( ( mp->avail < needed ) + && ( MVETH_CLEAN_ON_SEND(mp) <= 0 || mp->avail < needed ) ) { + /* Maybe TX was stalled and needs a restart */ + mveth_start_tx(mp); + return -1; + } + + h = mp->d_tx_h; + +#ifdef MVETH_TESTING + assert( !h->buf_ptr ); + assert( !h->u_buf ); +#endif + + /* find the 'first' user buffer */ + if ( (frst_buf = head_p) && (h_len > 0) ) { + frst_len = h_len; + } else { + frst_buf = data_p; + frst_len = d_len; + } + + uarg = (head_p && ! h_len) ? head_p : frst_buf; + + /* Legacy: if h_len == 0 but head_p is not then use that for the user arg */ + + /* Don't use the first descriptor yet because BSP_mve_swipe_tx() + * needs mp->d_tx_h->buf_ptr == NULL as a marker. Hence, we + * start with the second (optional) slot and fill the first + * descriptor last. + */ + + l = h; + d = NEXT_TXD(h); + + mp->avail--; + + if ( needed > 1 ) { + mp->avail--; +#ifdef MVETH_TESTING + assert( d != h ); + assert( !d->buf_ptr ); +#endif + rval += mveth_assign_desc_raw(d, data_p, d_len, 0, TDESC_DMA_OWNED); + FLUSH_BUF( (uint32_t)data_p, d_len ); + d->u_buf = data_p; + + l = d; + d = NEXT_TXD(d); + + FLUSH_DESC(l); + } + + /* fill first slot with raw buffer - don't release to DMA yet */ + rval += mveth_assign_desc_raw(h, frst_buf, frst_len, 0, TDESC_FRST); + + FLUSH_BUF( (uint32_t)frst_buf, frst_len); + + /* tag last slot; this covers the case where 1st==last */ + l->cmd_sts |= TDESC_LAST | TDESC_INT_ENA; + + /* first buffer of 'chain' goes into last desc */ + l->u_buf = uarg; + + FLUSH_DESC(l); + + /* Tag end; make sure chip doesn't try to read ahead of here! */ + l->next->cmd_sts = 0; + FLUSH_DESC(l->next); + + membarrier(); + + /* turn over the whole chain by flipping ownership of the first desc */ + h->cmd_sts |= TDESC_DMA_OWNED; + + FLUSH_DESC(h); + + membarrier(); + + /* notify the device */ + MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_TX_START(0)); + + /* Update softc */ + mp->stats.packet++; + if ( needed > mp->stats.maxchain ) + mp->stats.maxchain = needed; + + /* remember new head */ + mp->d_tx_h = d; + + return rval; /* #bytes sent */ +} + +/* send received buffers upwards and replace them + * with freshly allocated ones; + * ASSUMPTION: buffer length NEVER changes and is set + * when the ring is initialized. + * TS 20060727: not sure if this assumption is still necessary - I believe it isn't. + */ + +int +BSP_mve_swipe_rx(struct mveth_private *mp) +{ +int rval = 0, err; +register MvEthRxDesc d; +void *newbuf; +int sz; +uintptr_t baddr; + + for ( d = mp->d_rx_t; ! (INVAL_DESC(d), (RDESC_DMA_OWNED & d->cmd_sts)); d=NEXT_RXD(d) ) { + +#ifdef MVETH_TESTING + assert(d->u_buf); +#endif + + err = (RDESC_ERROR & d->cmd_sts); + + if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) { + /* drop packet and recycle buffer */ + newbuf = d->u_buf; + mp->stats.idrops++; + } else { +#ifdef MVETH_TESTING + assert( d->byte_cnt > 0 ); +#endif + mp->consume_rxbuf(d->u_buf, mp->consume_rxbuf_arg, d->byte_cnt); + +#ifndef ENABLE_HW_SNOOPING + /* could reduce the area to max. ethernet packet size */ + INVAL_BUF(baddr, sz); +#endif + d->u_buf = newbuf; + d->buf_ptr = CPUADDR2ENET(baddr); + d->buf_size = sz; + FLUSH_DESC(d); + } + + membarrier(); + + d->cmd_sts = RDESC_DMA_OWNED | RDESC_INT_ENA; + + FLUSH_DESC(d); + + rval++; + } + MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0)); + mp->d_rx_t = d; + return rval; +} + +/* Stop hardware and clean out the rings */ +void +BSP_mve_stop_hw(struct mveth_private *mp) +{ +MvEthTxDesc d; +MvEthRxDesc r; +int i; + + mveth_disable_irqs(mp, -1); + + mveth_stop_tx(mp->port_num); + + /* cleanup TX rings */ + if (mp->d_tx_t) { /* maybe ring isn't initialized yet */ + for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) { + /* should be safe to clear ownership */ + d->cmd_sts &= ~TDESC_DMA_OWNED; + FLUSH_DESC(d); + } + FLUSH_BARRIER(); + + BSP_mve_swipe_tx(mp); + +#ifdef MVETH_TESTING + assert( mp->d_tx_h == mp->d_tx_t ); + for ( i=0, d=mp->tx_ring; i<mp->xbuf_count; i++, d++ ) { + assert( !d->buf_ptr ); + } +#endif + } + + MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_STOP_ALL); + while ( MV643XX_ETH_RX_ANY_RUNNING & MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num)) ) + /* poll-wait */; + + /* stop serial port */ + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), + MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num)) + & ~( MV643XX_ETH_SERIAL_PORT_ENBL | MV643XX_ETH_FORCE_LINK_FAIL_DISABLE | MV643XX_ETH_FORCE_LINK_PASS) + ); + + /* clear pending interrupts */ + MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0); + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0); + + /* cleanup RX rings */ + if ( mp->rx_ring ) { + for ( i=0, r=mp->rx_ring; i<mp->rbuf_count; i++, r++ ) { + /* should be OK to clear ownership flag */ + r->cmd_sts = 0; + FLUSH_DESC(r); + mp->consume_rxbuf(r->u_buf, mp->consume_rxbuf_arg, 0); + r->u_buf = 0; + } + FLUSH_BARRIER(); + } + + +} + +uint32_t mveth_serial_ctrl_config_val = MVETH_SERIAL_CTRL_CONFIG_VAL; + +/* Fire up the low-level driver + * + * - make sure hardware is halted + * - enable cache snooping + * - clear address filters + * - clear mib counters + * - reset phy + * - initialize (or reinitialize) descriptor rings + * - check that the firmware has set up a reasonable mac address. + * - generate unicast filter entry for our mac address + * - write register config values to the chip + * - start hardware (serial port and SDMA) + */ + +void +BSP_mve_init_hw(struct mveth_private *mp, int promisc, unsigned char *enaddr, int media) +{ +int i; +uint32_t v; +static int inited = 0; + +#ifdef MVETH_DEBUG + printk(DRVNAME"%i: Entering BSP_mve_init_hw()\n", mp->port_num+1); +#endif + + /* since enable/disable IRQ routine only operate on select bitsets + * we must make sure everything is masked initially. + */ + MV_WRITE(MV643XX_ETH_INTERRUPT_ENBL_R(mp->port_num), 0); + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_ENBL_R(mp->port_num), 0); + + BSP_mve_stop_hw(mp); + + memset(&mp->stats, 0, sizeof(mp->stats)); + + mp->promisc = promisc; + + /* MotLoad has cache snooping disabled on the ENET2MEM windows. + * Some comments in (linux) indicate that there are errata + * which cause problems which would be a real bummer. + * We try it anyways... + */ + if ( !inited ) { + unsigned long disbl, bar; + inited = 1; /* FIXME: non-thread safe lazy init */ + disbl = MV_READ(MV643XX_ETH_BAR_ENBL_R); + /* disable all 6 windows */ + MV_WRITE(MV643XX_ETH_BAR_ENBL_R, MV643XX_ETH_BAR_DISBL_ALL); + /* set WB snooping on enabled bars */ + for ( i=0; i<MV643XX_ETH_NUM_BARS*8; i+=8 ) { + if ( (bar = MV_READ(MV643XX_ETH_BAR_0 + i)) && MV_READ(MV643XX_ETH_SIZE_R_0 + i) ) { +#ifdef ENABLE_HW_SNOOPING + MV_WRITE(MV643XX_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB); +#else + MV_WRITE(MV643XX_ETH_BAR_0 + i, bar & ~MV64360_ENET2MEM_SNOOP_MSK); +#endif + /* read back to flush fifo [linux comment] */ + (void)MV_READ(MV643XX_ETH_BAR_0 + i); + } + } + /* restore/re-enable */ + MV_WRITE(MV643XX_ETH_BAR_ENBL_R, disbl); + } + + mveth_clear_mib_counters(mp); + mveth_clear_addr_filters(mp); + +/* Just leave it alone... + reset_phy(); +*/ + + if ( mp->rbuf_count > 0 ) { + mp->rx_ring = (MvEthRxDesc)MV643XX_ALIGN(mp->ring_area, RING_ALIGNMENT); + mveth_init_rx_desc_ring(mp); + } + + if ( mp->xbuf_count > 0 ) { + mp->tx_ring = (MvEthTxDesc)mp->rx_ring + mp->rbuf_count; + mveth_init_tx_desc_ring(mp); + } + + if ( enaddr ) { + /* set ethernet address from arpcom struct */ +#ifdef MVETH_DEBUG + printk(DRVNAME"%i: Writing MAC addr ", mp->port_num+1); + for (i=5; i>=0; i--) { + printk("%02X%c", enaddr[i], i?':':'\n'); + } +#endif + mveth_write_eaddr(mp, enaddr); + } + + /* set mac address and unicast filter */ + + { + uint32_t machi, maclo; + maclo = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num)); + machi = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num)); + /* ASSUME: firmware has set the mac address for us + * - if assertion fails, we have to do more work... + */ + assert( maclo && machi && maclo != 0xffffffff && machi != 0xffffffff ); + mveth_ucfilter(mp, maclo&0xff, 1/* accept */); + } + + /* port, serial and sdma configuration */ + v = MVETH_PORT_CONFIG_VAL; + if ( promisc ) { + /* multicast filters were already set up to + * accept everything (mveth_clear_addr_filters()) + */ + v |= MV643XX_ETH_UNICAST_PROMISC_MODE; + } else { + v &= ~MV643XX_ETH_UNICAST_PROMISC_MODE; + } + MV_WRITE(MV643XX_ETH_PORT_CONFIG_R(mp->port_num), + v); + MV_WRITE(MV643XX_ETH_PORT_CONFIG_XTEND_R(mp->port_num), + MVETH_PORT_XTEND_CONFIG_VAL); + + v = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num)); + v &= ~(MVETH_SERIAL_CTRL_CONFIG_MSK); + v |= mveth_serial_ctrl_config_val; + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), v); + + if ( (MV643XX_MEDIA_LINK & media) ) { + BSP_mve_update_serial_port(mp, media); + } + + /* enable serial port */ + v = MV_READ(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num)); + MV_WRITE(MV643XX_ETH_SERIAL_CONTROL_R(mp->port_num), + v | MV643XX_ETH_SERIAL_PORT_ENBL); + +#ifndef __BIG_ENDIAN__ +#error "byte swapping needs to be disabled for little endian machines" +#endif + MV_WRITE(MV643XX_ETH_SDMA_CONFIG_R(mp->port_num), MVETH_SDMA_CONFIG_VAL); + + /* allow short frames */ + MV_WRITE(MV643XX_ETH_RX_MIN_FRAME_SIZE_R(mp->port_num), MVETH_MIN_FRAMSZ_CONFIG_VAL); + + MV_WRITE(MV643XX_ETH_INTERRUPT_CAUSE_R(mp->port_num), 0); + MV_WRITE(MV643XX_ETH_INTERRUPT_EXTEND_CAUSE_R(mp->port_num), 0); + /* TODO: set irq coalescing */ + + /* enable Rx */ + if ( mp->rbuf_count > 0 ) { + MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_R(mp->port_num), MV643XX_ETH_RX_START(0)); + } + + mveth_enable_irqs(mp, -1); + +#ifdef MVETH_DEBUG + printk(DRVNAME"%i: Leaving BSP_mve_init_hw()\n", mp->port_num+1); +#endif +} + +/* read ethernet address from hw to buffer */ +void +BSP_mve_read_eaddr(struct mveth_private *mp, unsigned char *oeaddr) +{ +int i; +uint32_t x; +unsigned char buf[6], *eaddr; + + eaddr = oeaddr ? oeaddr : buf; + + eaddr += 5; + x = MV_READ(MV643XX_ETH_MAC_ADDR_LO(mp->port_num)); + + /* lo word */ + for (i=2; i; i--, eaddr--) { + *eaddr = (unsigned char)(x & 0xff); + x>>=8; + } + + x = MV_READ(MV643XX_ETH_MAC_ADDR_HI(mp->port_num)); + /* hi word */ + for (i=4; i; i--, eaddr--) { + *eaddr = (unsigned char)(x & 0xff); + x>>=8; + } + + if ( !oeaddr ) { + printf("%02X",buf[0]); + for (i=1; i<sizeof(buf); i++) + printf(":%02X",buf[i]); + printf("\n"); + } +} + +void +BSP_mve_enable_irqs(struct mveth_private *mp) +{ + mveth_enable_irqs(mp, -1); +} + +void +BSP_mve_disable_irqs(struct mveth_private *mp) +{ + mveth_disable_irqs(mp, -1); +} + +uint32_t +BSP_mve_ack_irqs(struct mveth_private *mp) +{ + return mveth_ack_irqs(mp, -1); +} + + +void +BSP_mve_enable_irq_mask(struct mveth_private *mp, uint32_t mask) +{ + mveth_enable_irqs(mp, mask); +} + +uint32_t +BSP_mve_disable_irq_mask(struct mveth_private *mp, uint32_t mask) +{ + return mveth_disable_irqs(mp, mask); +} + +uint32_t +BSP_mve_ack_irq_mask(struct mveth_private *mp, uint32_t mask) +{ + return mveth_ack_irqs(mp, mask); +} + +void +BSP_mve_dump_stats(struct mveth_private *mp, FILE *f) +{ +int p = mp->port_num; +int idx; +uint32_t v; + + if ( !f ) + f = stdout; + + fprintf(f, DRVNAME"%i Statistics:\n", mp->port_num + 1); + fprintf(f, " # IRQS: %i\n", mp->stats.irqs); + fprintf(f, " Max. mbuf chain length: %i\n", mp->stats.maxchain); + fprintf(f, " # repacketed: %i\n", mp->stats.repack); + fprintf(f, " # packets: %i\n", mp->stats.packet); + fprintf(f, " # buffer alloc failed: %i\n", mp->stats.idrops); + fprintf(f, "MIB Counters:\n"); + for ( idx = MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2; + idx < MV643XX_ETH_NUM_MIB_COUNTERS; + idx++ ) { + switch ( idx ) { + case MV643XX_ETH_MIB_GOOD_OCTS_RCVD_LO>>2: + mp->stats.mib.good_octs_rcvd += read_long_mib_counter(p, idx); + fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_rcvd); + idx++; + break; + + case MV643XX_ETH_MIB_GOOD_OCTS_SENT_LO>>2: + mp->stats.mib.good_octs_sent += read_long_mib_counter(p, idx); + fprintf(f, mibfmt[idx], mp->stats.mib.good_octs_sent); + idx++; + break; + + default: + v = ((uint32_t*)&mp->stats.mib)[idx] += read_mib_counter(p, idx); + fprintf(f, mibfmt[idx], v); + break; + } + } + fprintf(f, "\n"); +} + +#ifdef MVETH_DEBUG +/* Display/dump descriptor rings */ + +/* These low-level routines need to be synchronized with + * any Tx/Rx threads! + */ +int +BSP_mve_dring_nonsync(struct mveth_private *mp) +{ +int i; +if (1) { +MvEthRxDesc pr; +printf("RX:\n"); + + for (i=0, pr=mp->rx_ring; i<mp->rbuf_count; i++, pr++) { + printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n", + pr->byte_cnt, pr->buf_size, pr->cmd_sts, (uint32_t)pr->next_desc_ptr, pr->buf_ptr); + } +} +if (1) { +MvEthTxDesc pt; +printf("TX:\n"); + for (i=0, pt=mp->tx_ring; i<mp->xbuf_count; i++, pt++) { + printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x, mb: 0x%08x\n", + pt->byte_cnt, pt->cmd_sts, (uint32_t)pt->next_desc_ptr, pt->buf_ptr, + (uint32_t)pt->u_buf); + } +} + return 0; +} +#endif + +#endif /* LIBBSP_BEATNIK_BSP_H */ diff --git a/rtemsbsd/sys/dev/mve/if_mve_nexus.c b/rtemsbsd/sys/dev/mve/if_mve_nexus.c new file mode 100644 index 00000000..be9433da --- /dev/null +++ b/rtemsbsd/sys/dev/mve/if_mve_nexus.c @@ -0,0 +1,935 @@ +/* RTEMS driver for the mv643xx gigabit ethernet chip */ + +/* Acknowledgement: + * + * Valuable information for developing this driver was obtained + * from the linux open-source driver mv643xx_eth.c which was written + * by the following people and organizations: + * + * Matthew Dharm <mdharm@momenco.com> + * rabeeh@galileo.co.il + * PMC-Sierra, Inc., Manish Lachwani + * Ralf Baechle <ralf@linux-mips.org> + * MontaVista Software, Inc., Dale Farnsworth <dale@farnsworth.org> + * Steven J. Hill <sjhill1@rockwellcollins.com>/<sjhill@realitydiluted.com> + * + * Note however, that in spite of the identical name of this file + * (and some of the symbols used herein) this file provides a + * new implementation and is the original work by the author. + */ + +/* + * Authorship + * ---------- + * This software (mv643xx ethernet driver for RTEMS) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'mv643xx ethernet driver for RTEMS' was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +/* Nexus port by Till Straumann, <till.straumann@psi.ch>, 3/2021 */ + +#include <machine/rtems-bsd-kernel-space.h> +#include <bsp.h> + +#ifdef LIBBSP_BEATNIK_BSP_H + +#include <sys/types.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/ethernet.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <rtems/bsd/local/miibus_if.h> +#include <stdio.h> +#include <bsp/mv643xx_eth.h> + +#define DRVNAME "mv63xx_nexus" + +#undef MVETH_DEBUG + +/* Define default ring sizes */ + +#undef MVETH_TESTING + +#ifdef MVETH_TESTING +/* hard and small defaults */ +#define MV643XX_RX_RING_SIZE 2 +#define MV643XX_TX_QUEUE_SIZE 4 +#define MV643XX_BD_PER_PACKET 1 +#define TX_LOWWATER 1 + +#else /* MVETH_TESTING */ + +#define MV643XX_RX_RING_SIZE 40 /* attached buffers are always 2k clusters, i.e., this + * driver - with a configured ring size of 40 - constantly + * locks 80k of cluster memory - your app config better + * provides enough space! + */ +#define MV643XX_TX_QUEUE_SIZE 40 +#define MV643XX_BD_PER_PACKET 10 +#define TX_LOWWATER (4*(MV643XX_BD_PER_PACKET)) +#endif /* MVETH_TESTING */ + +/* NOTE: tx ring size MUST be > max. # of fragments / mbufs in a chain; + * I observed chains of >17 entries regularly! + */ +#define MV643XX_TX_RING_SIZE ((MV643XX_TX_QUEUE_SIZE) * (MV643XX_BD_PER_PACKET)) + +/* The chip puts the ethernet header at offset 2 into the buffer so + * that the payload is aligned + */ +#define ETH_RX_OFFSET 2 +#define ETH_CRC_LEN 4 /* strip FCS at end of packet */ + +#ifndef __PPC__ +#error "Dont' know how to deal with cache on this CPU architecture" +#endif + +/* Ring entries are 32 bytes; coherency-critical chunks are 16 -> software coherency + * management works for cache line sizes of 16 and 32 bytes only. If the line size + * is bigger, the descriptors could be padded... + */ +#if !defined(PPC_CACHE_ALIGNMENT) +#error "PPC_CACHE_ALIGNMENT not defined" +#elif PPC_CACHE_ALIGMENT != 16 && PPC_CACHE_ALIGNMENT != 32 +#error "Cache line size must be 16 or 32" +#else +#define RX_BUF_ALIGNMENT PPC_CACHE_ALIGNMENT +#endif + +/* HELPER MACROS */ + +/* Align base to alignment 'a' */ +#define MV643XX_ALIGN(b, a) ((((uint32_t)(b)) + (a)-1) & (~((a)-1))) + + +#define IRQ_EVENT RTEMS_EVENT_0 +#define TX_EVENT RTEMS_EVENT_1 + +/* Hacks -- FIXME */ +rtems_id +rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg); +#define SIO_RTEMS_SHOW_STATS _IO('i', 250) + +#define MVE643XX_DUMMY_PHY 0 /* phy is defined by low-level driver */ + +struct mve_enet_softc { + device_t dev; + struct ifnet *ifp; + device_t miibus; + struct mii_data *mii_softc; + struct mveth_private *mp; + struct mtx mtx; + struct callout wdCallout; + rtems_id daemonTid; + int oif_flags; +}; + +static struct mve_enet_softc * ifaces[MV643XXETH_NUM_DRIVER_SLOTS] = { 0 }; + +typedef struct MveMbufIter { + MveEthBufIter it; + struct mbuf *next; + struct mbuf *head; +} MveMbufIter; + +/* Forward Declarations */ +struct mve_enet_softc; + +static void +mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr); + +static int +mve_media_change(struct ifnet *ifp); + +static void +mve_set_filters(struct ifnet *ifp); + +static int +xlateMediaFlags(const struct mii_data *mid); + +static void +mve_ack_link_change(struct mve_enet_softc *sc); + +static __inline__ void +mve_send_event(struct mve_enet_softc *sc, rtems_event_set ev) +{ +rtems_status_code st; + if ( RTEMS_SUCCESSFUL != (st = rtems_event_send(sc->daemonTid, ev)) ) { + printk(DRVNAME": rtems_event_send returned 0x%08x (TID: 0x%08x, sc: 0x%08x)\n", st, sc->daemonTid, sc); + rtems_panic(DRVNAME": rtems_event_send() failed!\n"); + } +} + +static __inline__ void +mve_lock(struct mve_enet_softc *sc, const char *from) +{ + mtx_lock( & sc->mtx ); +/*printk("L V %s\n", from);*/ +} + +static __inline__ void +mve_unlock(struct mve_enet_softc *sc, const char *from) +{ +/*printk("L ^ %s\n", from);*/ + mtx_unlock( & sc->mtx ); +} + +static int +mve_probe(device_t dev) +{ + int unit = device_get_unit(dev); + int err; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_probe (entering)\n"); +#endif + + if ( unit >= 0 && unit < MV643XXETH_NUM_DRIVER_SLOTS ) { + err = BUS_PROBE_DEFAULT; + } else { + err = ENXIO; + } + + return err; +} + +/* + * starting at 'm' scan the buffer chain until we + * find a non-empty buffer (which we return) + */ +static __inline__ struct mbuf * +skipEmpty(struct mbuf *m) +{ + while ( m && ( 0 == m->m_len ) ) { + m = m->m_next; + } + return m; +} + +/* + * Record a buffer's info in the low-leve driver 'iterator' struct. + * Also scan ahead to find the next non-empty buffer (store it in + * the iterator's 'next' field). This info is needed because we + * want to know if 'this' buffer is the last (non-empty!) one + * in a chain. + * + * On entry 'it->next' identifies 'this' buffer and on return + * 'it->next' points to the next non-empty buffer. + */ +static MveEthBufIter * +nextBuf(MveEthBufIter *arg) +{ +MveMbufIter *it = (MveMbufIter*)arg; +struct mbuf *m; + /* If 'this' buffer is non-null */ + if ( (m = it->next) ) { + /* find next non-empty buffer */ + it->next = skipEmpty( m->m_next ); + /* record 'this' buffer's info */ + it->it.data = mtod(m, void*); + it->it.len = m->m_len; + /* if there is a non-empty buffer after 'this' uptr is NULL + * if this is tha last buffer in a chain then record the + * head of the chain in the uptr (for eventual cleanup + * by release_tx_mbuf()). + */ + it->it.uptr = it->next ? 0 : it->head; + return (MveEthBufIter*)it; + } + return 0; +} + +/* + * Initialize the iterator struct + */ +static MveEthBufIter * +initIter(MveMbufIter *it, struct mbuf *m) +{ + /* record the head of the chain */ + it->head = m; + /* initialize 'next' field to the first non-empty buffer. + * This may be NULL if the chain is entirely empty but + * that is handled correctly. + */ + it->next = skipEmpty( m ); + /* Fill with first buf info */ + return nextBuf( &it->it ); +} + +static int +mve_send_mbuf( struct mve_enet_softc *sc, struct mbuf *m_head ) +{ +MveMbufIter iter; +int rval; + + if ( ! m_head ) { + return 0; + } + + if ( ! initIter( &iter, m_head ) ) { + /* completely empty chain */ + m_freem( m_head ); + return 0; + } + + rval = BSP_mve_send_buf_chain( sc->mp, nextBuf, &iter.it ); + + return rval; +} + +static void +mve_isr(void *closure) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)closure; +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_isr; posting event to %x\n", sc->daemonTid); +#endif + BSP_mve_disable_irqs( sc->mp ); + mve_send_event( sc, IRQ_EVENT ); +} + +static void +mve_stop(struct mve_enet_softc *sc) +{ + BSP_mve_stop_hw( sc->mp ); + /* clear IF flags */ + if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING)); +} + +static void +mve_set_filters(struct ifnet *ifp) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); +int iff = if_getflags(ifp); +struct ifmultiaddr *ifma; +unsigned char *lladdr; + + BSP_mve_promisc_set( sc->mp, !!(iff & IFF_PROMISC)); + + if ( iff & (IFF_PROMISC | IFF_ALLMULTI) ) { + BSP_mve_mcast_filter_accept_all(sc->mp); + } else { + BSP_mve_mcast_filter_clear( sc->mp ); + + if_maddr_rlock( ifp ); + + CK_STAILQ_FOREACH( ifma, &ifp->if_multiaddrs, ifma_link ) { + + if ( ifma->ifma_addr->sa_family != AF_LINK ) { + continue; + } + + lladdr = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); + + BSP_mve_mcast_filter_accept_add( sc->mp, lladdr ); + + } + + if_maddr_runlock( ifp ); + } +} + +/* Daemon task does all the 'interrupt' work */ +static void +mve_daemon(void *arg) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) arg; +struct ifnet *ifp = sc->ifp; +rtems_event_set evs; +struct mbuf *m; +int avail; +int sndStat; +uint32_t irqstat; + +#ifdef MVETH_DEBUG + printk(DRVNAME": bsdnet mveth_daemon started\n"); +#endif + + mve_lock( sc, "daemon" ); + + for (;;) { + + mve_unlock( sc, "daemon" ); + if ( RTEMS_SUCCESSFUL != rtems_event_receive( (IRQ_EVENT | TX_EVENT), (RTEMS_WAIT | RTEMS_EVENT_ANY), RTEMS_NO_TIMEOUT, &evs ) ) { + rtems_panic(DRVNAME": rtems_event_receive() failed!\n"); + } + mve_lock( sc, "daemon" ); + +#ifdef MVETH_DEBUG + printk(DRVNAME": bsdnet mveth_daemon event received 0x%x\n", evs); +#endif + + if ( !(if_getflags(ifp) & IFF_UP) ) { + mve_stop(sc); + /* clear flag */ + if_setdrvflagbits(sc->ifp, 0, IFF_DRV_RUNNING); + continue; + } + + if ( ! (if_getdrvflags(ifp) & IFF_DRV_RUNNING) ) { + /* event could have been pending at the time hw was stopped; + * just ignore... + */ + continue; + } + + if ( (evs & IRQ_EVENT) ) { + irqstat = BSP_mve_ack_irqs(sc->mp); + } else { + irqstat = 0; + } + + if ( (MV643XX_ETH_EXT_IRQ_LINK_CHG & irqstat) && sc->mii_softc ) { + /* phy status changed */ + mii_pollstat( sc->mii_softc ); + } + + /* free tx chain and send */ + if ( (evs & TX_EVENT) || (MV643XX_ETH_EXT_IRQ_TX_DONE & irqstat) ) { + while ( (avail = BSP_mve_swipe_tx( sc->mp )) > TX_LOWWATER ) { + IF_DEQUEUE( &ifp->if_snd, m ); + if ( ! m ) { + /* clear active bit */ + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); + break; + } + sndStat = mve_send_mbuf( sc, m ); + if ( sndStat < 0 ) { + /* maybe not enough space right now; requeue and wait for next IRQ */ + IF_PREPEND( &ifp->if_snd, m ); + break; + } + } + } + if ( (MV643XX_ETH_IRQ_RX_DONE & irqstat) ) { + BSP_mve_swipe_rx(sc->mp); + } + + BSP_mve_enable_irqs(sc->mp); + } + + mve_unlock( sc, "daemon (xit)" ); +} + +static void +release_tx_mbuf(void *user_buf, void *closure, int error_on_tx_occurred) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)closure; +struct ifnet *ifp = sc->ifp; +struct mbuf *mb = (struct mbuf*)user_buf; + + if ( error_on_tx_occurred ) { + if_inc_counter( ifp, IFCOUNTER_OERRORS, 1 ); + } else { + if_inc_counter( ifp, IFCOUNTER_OPACKETS, 1 ); + if_inc_counter( ifp, IFCOUNTER_OBYTES, mb->m_pkthdr.len ); + } + m_freem(mb); +} + +static void * +alloc_rx_mbuf(int *p_size, uintptr_t *p_data) +{ +struct mbuf *m; +unsigned long l,o; + + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + + if ( m ) { + + o = mtod(m, unsigned long); + l = MV643XX_ALIGN(o, RX_BUF_ALIGNMENT) - o; + + /* align start of buffer */ + m->m_data += l; + + /* reduced length */ + l = MCLBYTES - l; + + m->m_len = m->m_pkthdr.len = l; + *p_size = m->m_len; + *p_data = mtod(m, uintptr_t); + } + + return (void*) m; +} + + +static void +consume_rx_mbuf(void *user_buf, void *closure, int len) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)closure; +struct ifnet *ifp = sc->ifp; +struct mbuf *m = (struct mbuf*)user_buf; + + if ( len <= 0 ) { + if_inc_counter( ifp, IFCOUNTER_IQDROPS, 1 ); + if ( len < 0 ) { + if_inc_counter( ifp, IFCOUNTER_IERRORS, 1 ); + } + m_freem(m); + } else { + m->m_len = m->m_pkthdr.len = len - ETH_RX_OFFSET - ETH_CRC_LEN; + m->m_data += ETH_RX_OFFSET; + m->m_pkthdr.rcvif = ifp; + + if_inc_counter( ifp, IFCOUNTER_IPACKETS, 1 ); + if_inc_counter( ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len ); + + if (0) { + /* Low-level debugging */ + int i; + for (i=0; i<m->m_len; i++) { + if ( !(i&15) ) + printk("\n"); + printk("0x%02x ",mtod(m,char*)[i]); + } + printk("\n"); + } + + mve_unlock( sc, "rx_cleanup" ); + (*ifp->if_input)(ifp, m); + mve_lock( sc, "rx_cleanup" ); + } +} + +/* Translate IFFLAGS to low-level driver representation */ +static int +xlateMediaFlags(const struct mii_data *mid) +{ +int lowLevelFlags = 0; +int msk = IFM_AVALID | IFM_ACTIVE; + + if ( (mid->mii_media_status & msk) == msk ) { + lowLevelFlags |= MV643XX_MEDIA_LINK; + + if ( IFM_OPTIONS( mid->mii_media_active ) & IFM_FDX ) { + lowLevelFlags |= MV643XX_MEDIA_FD; + } + + switch ( IFM_ETHER_SUBTYPE_GET( mid->mii_media_active ) ) { + default: +#ifdef MVETH_DEBUG + printk(DRVNAME"xlateMediaFlags: UNKNOWN SPEED\n"); +#endif + break; /* UNKNOWN -- FIXME */ + case IFM_10_T: +#ifdef MVETH_DEBUG + printk(DRVNAME"xlateMediaFlags: 10baseT\n"); +#endif + lowLevelFlags |= MV643XX_MEDIA_10; + break; + case IFM_100_TX: +#ifdef MVETH_DEBUG + printk(DRVNAME"xlateMediaFlags: 100baseT\n"); +#endif + lowLevelFlags |= MV643XX_MEDIA_100; + break; + case IFM_1000_T: +#ifdef MVETH_DEBUG + printk(DRVNAME"xlateMediaFlags: 1000baseT\n"); +#endif + lowLevelFlags |= MV643XX_MEDIA_1000; + break; + } + } else { +#ifdef MVETH_DEBUG + printk(DRVNAME"xlateMediaFlags: NO LINK\n"); +#endif + } + return lowLevelFlags; +} + +static void +mve_init(void *arg) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*)arg; +struct ifnet *ifp = sc->ifp; +int lowLevelMediaStatus = 0; +int promisc; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_init (entering)\n"); +#endif + + if ( sc->mii_softc ) { + mii_pollstat( sc->mii_softc ); + lowLevelMediaStatus = xlateMediaFlags( sc->mii_softc ); + if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) { + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); + } else { + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + } + } + + promisc = !! (if_getdrvflags(ifp) & IFF_PROMISC); + + BSP_mve_init_hw(sc->mp, promisc, if_getlladdr(ifp), lowLevelMediaStatus); + + /* if promiscuous then there is no need to change */ + if ( ! promisc ) { + mve_set_filters(ifp); + } + + + if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); +} + +static void +mve_start(struct ifnet *ifp) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); + mve_lock( sc, "mve_start" ); + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + mve_unlock( sc, "mve_start" ); + mve_send_event( sc, TX_EVENT ); +} + +static int +mve_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); +struct ifreq *ifr = (struct ifreq *)data; +int err = 0; +int f, df; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_ioctl (entering)\n"); +#endif + + mve_lock( sc, "mve_ioctl" ); + + switch ( cmd ) { + case SIOCSIFFLAGS: + f = if_getflags( ifp ); + df = if_getdrvflags( ifp ); + if ( (f & IFF_UP) ) { + if ( ! ( df & IFF_DRV_RUNNING ) ) { + mve_init( (void*)sc ); + } else { + if ( (f & IFF_PROMISC) != (sc->oif_flags & IFF_PROMISC) ) { + mve_set_filters(ifp); + } + /* FIXME: other flag changes are ignored/unimplemented */ + } + } else { + if ( df & IFF_DRV_RUNNING ) { + mve_stop(sc); + } + } + sc->oif_flags = f; + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + if ( sc->mii_softc ) { + err = ifmedia_ioctl( ifp, ifr, &sc->mii_softc->mii_media, cmd ); + } else { + err = EINVAL; + } + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if ( if_getdrvflags( ifp ) & IFF_DRV_RUNNING ) { + mve_set_filters(ifp); + } + break; + + case SIO_RTEMS_SHOW_STATS: + BSP_mve_dump_stats(sc->mp, stdout); + break; + + default: + err = ether_ioctl(ifp, cmd, data); + break; + } + + mve_unlock( sc, "mve_ioctl" ); + + return err; +} + +/* SIO RTEMS_SHOW_STATS is too cumbersome to use -- for debugging, provide direct hack */ +int +mv643xx_nexus_dump_stats(int unit, FILE *f) +{ + if ( unit < 0 || unit >= MV643XXETH_NUM_DRIVER_SLOTS || ! ifaces[unit] ) + return -EINVAL; + if ( ! f ) + f = stdout; + BSP_mve_dump_stats(ifaces[unit]->mp, f); + return 0; +} + +/* + * Used to update speed settings in the hardware + * when the phy setup changes. + * + * ASSUME: caller holds lock + */ +static void +mve_ack_link_change(struct mve_enet_softc *sc) +{ +struct mii_data *mii = sc->mii_softc; +int lowLevelMediaStatus; + + if ( !mii ) + return; + + lowLevelMediaStatus = xlateMediaFlags( mii ); + + if ( (lowLevelMediaStatus & MV643XX_MEDIA_LINK) ) { + BSP_mve_update_serial_port( sc->mp, lowLevelMediaStatus ); + if_setdrvflagbits( sc->ifp, 0, IFF_DRV_OACTIVE ); + mve_start( sc->ifp ); + } else { + if_setdrvflagbits( sc->ifp, IFF_DRV_OACTIVE, 0 ); + } +} + +/* Callback from ifmedia_ioctl() + * + * Caller probably holds the lock already but + * since it is recursive we may as well make sure + * in case there are other possible execution paths. + */ +static int +mve_media_change(struct ifnet *ifp) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); +struct mii_data *mii = sc->mii_softc; +int err; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_media_change\n"); +#endif + + if ( ! mii ) { + return ENXIO; + } + + err = mii_mediachg( mii ); + + return err; +} + +static void +mve_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) if_getsoftc( ifp ); +struct mii_data *mii = sc->mii_softc; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_media_status\n"); +#endif + + if ( mii ) { + mii_pollstat( mii ); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + } +} + +static int +mve_attach(device_t dev) +{ +struct mve_enet_softc *sc; +struct ifnet *ifp; +uint8_t hwaddr[ETHER_ADDR_LEN]; +struct mveth_private *mp; +int unit = device_get_unit(dev); +int tx_ring_size = MV643XX_TX_RING_SIZE; +int rx_ring_size = MV643XX_RX_RING_SIZE; +int tx_q_size = MV643XX_TX_QUEUE_SIZE; + + sc = device_get_softc( dev ); + sc->dev = dev; + sc->ifp = ifp = if_alloc(IFT_ETHER); + sc->daemonTid = 0; + sc->mii_softc = 0; + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_attach (entering)\n"); +#endif + + mtx_init( &sc->mtx, device_get_nameunit( sc->dev ), MTX_NETWORK_LOCK, MTX_RECURSE ); + callout_init_mtx( &sc->wdCallout, &sc->mtx, 0 ); + + if_setsoftc ( ifp, sc ); + if_initname ( ifp, device_get_name(dev), unit); + if_setinitfn ( ifp, mve_init ); + if_setioctlfn ( ifp, mve_ioctl ); + if_setstartfn ( ifp, mve_start ); + if_setflags ( ifp, (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX) ); + sc->oif_flags = if_getflags( ifp ); + + if_setsendqlen ( ifp, tx_q_size ); + if_setsendqready( ifp ); + + mp = BSP_mve_create( + unit + 1, /* low-level driver' unit numbers are 1-based */ + 0, + mve_isr, (void*)sc, + release_tx_mbuf, (void*)sc, + alloc_rx_mbuf, + consume_rx_mbuf, (void*)sc, + rx_ring_size, + tx_ring_size, + ( MV643XX_ETH_IRQ_RX_DONE + | MV643XX_ETH_EXT_IRQ_TX_DONE + | MV643XX_ETH_EXT_IRQ_LINK_CHG)); + + if ( ! mp ) { + rtems_panic("Unable to create mv643xx low-level driver"); + } + + sc->mp = mp; + + BSP_mve_read_eaddr( mp, hwaddr ); + + if ( 0 == mii_attach( sc->dev, + &sc->miibus, + ifp, + mve_media_change, + mve_media_status, + BMSR_DEFCAPMASK, + MVE643XX_DUMMY_PHY, + MII_OFFSET_ANY, + 0 ) ) { + sc->mii_softc = device_get_softc( sc->miibus ); + } + + sc->daemonTid = rtems_bsdnet_newproc("MVE", 4096, mve_daemon, (void*)sc); + + ether_ifattach( ifp, hwaddr ); + +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_attach (leaving)\n"); +#endif + + ifaces[unit] = sc; + + return 0; +} + +static int +mve_miibus_read_reg(device_t dev, int phy, int reg) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev); + + /* low-level driver knows what phy to use; ignore arg */ + return (int) BSP_mve_mii_read( sc->mp, reg ); +} + +static int +mve_miibus_write_reg(device_t dev, int phy, int reg, int val) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev); + + /* low-level driver knows what phy to use; ignore arg */ + BSP_mve_mii_write( sc->mp, reg, val ); + return 0; +} + +static void +mve_miibus_statchg(device_t dev) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev); +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_miibus_statchg\n"); +#endif + /* assume this ends up being called either from the ioctl or the driver + * task -- either of which holds the lock. + */ + mve_ack_link_change( sc ); +} + +static void +mve_miibus_linkchg(device_t dev) +{ +struct mve_enet_softc *sc = (struct mve_enet_softc*) device_get_softc(dev); +#ifdef MVETH_DEBUG + printk(DRVNAME": mve_miibus_linkchg\n"); +#endif + /* assume this ends up being called either from the ioctl or the driver + * task -- either of which holds the lock. + */ + mve_ack_link_change( sc ); +} + + +static device_method_t mve_methods[] = { + DEVMETHOD(device_probe, mve_probe ), + DEVMETHOD(device_attach, mve_attach), + + DEVMETHOD(miibus_readreg, mve_miibus_read_reg ), + DEVMETHOD(miibus_writereg, mve_miibus_write_reg), + DEVMETHOD(miibus_statchg , mve_miibus_statchg ), + DEVMETHOD(miibus_linkchg , mve_miibus_linkchg ), + + DEVMETHOD_END +}; + +static driver_t mve_nexus_driver = { + "mve", + mve_methods, + sizeof( struct mve_enet_softc ) +}; + +static devclass_t mve_devclass; + +DRIVER_MODULE(mve, nexus, mve_nexus_driver, mve_devclass, 0, 0); +DRIVER_MODULE(miibus, mve, miibus_driver, miibus_devclass, 0, 0); + +MODULE_DEPEND(mve, nexus, 1, 1, 1); +MODULE_DEPEND(mve, ether, 1, 1, 1); + +#endif /* LIBBSP_BEATNIK_BSP_H */ diff --git a/rtemsbsd/sys/dev/stmac/if_stmac.c b/rtemsbsd/sys/dev/stmac/if_stmac.c index 614c51b9..7e3e07c7 100644 --- a/rtemsbsd/sys/dev/stmac/if_stmac.c +++ b/rtemsbsd/sys/dev/stmac/if_stmac.c @@ -40,6 +40,7 @@ #include <sys/module.h> #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/gsb_crc32.h> #include <net/if.h> #include <net/ethernet.h> diff --git a/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c b/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c index c7c09bb4..d02bba98 100755 --- a/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c +++ b/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <dev/usb/controller/ohci.h> #include <dev/usb/controller/ohcireg.h> +#include <arm/lpc/probe.h> #include <arm/lpc/lpcreg.h> #include <arm/lpc/lpcvar.h> @@ -90,7 +91,7 @@ __FBSDID("$FreeBSD$"); while ((lpc_otg_read_4(_sc, _sreg) & _value) != _value); \ } while (0); -static int lpc_ohci_probe(device_t dev); +static int lpc_ohci_do_probe(device_t dev); static int lpc_ohci_attach(device_t dev); static int lpc_ohci_detach(device_t dev); @@ -107,12 +108,20 @@ static int lpc_otg_i2c_wait_for_transaction_done(struct ohci_softc *sc); static int lpc_otg_i2c_read(const struct usb_otg_transceiver *self, uint8_t reg_addr, uint8_t *value); static int lpc_otg_i2c_write(const struct usb_otg_transceiver *self, uint8_t reg_addr, uint8_t value); +__weak_symbol int +lpc_ohci_probe(int unit) +{ + + (void)unit; + return (BUS_PROBE_DEFAULT); +} + static int -lpc_ohci_probe(device_t dev) +lpc_ohci_do_probe(device_t dev) { device_set_desc(dev, "LPC32x0 USB OHCI controller"); - return (BUS_PROBE_DEFAULT); + return (lpc_ohci_probe(device_get_unit(dev))); } static int @@ -473,7 +482,7 @@ lpc_ohci_resume(device_t dev) static device_method_t lpc_ohci_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, lpc_ohci_probe), + DEVMETHOD(device_probe, lpc_ohci_do_probe), DEVMETHOD(device_attach, lpc_ohci_attach), DEVMETHOD(device_detach, lpc_ohci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), diff --git a/rtemsbsd/sys/net/if_ppp.c b/rtemsbsd/sys/net/if_ppp.c index 709f13e0..e134dc76 100644 --- a/rtemsbsd/sys/net/if_ppp.c +++ b/rtemsbsd/sys/net/if_ppp.c @@ -313,11 +313,12 @@ static rtems_task ppp_txdaemon(rtems_task_argument arg) frag=0; /* initialize output values */ - sc->sc_outfcs = PPP_INITFCS; - sc->sc_outbuf = (u_char *)0; - sc->sc_outlen = (short )0; - sc->sc_outoff = (short )0; - sc->sc_outfcslen = (short )0; + sc->sc_outfcs = PPP_INITFCS; + sc->sc_outbuf = (u_char *)0; + sc->sc_outlen = (short )0; + sc->sc_outoff = (short )0; + sc->sc_outoff_update = false; + sc->sc_outfcslen = (short )0; /* printf("Start Transmit Packet..\n"); */ diff --git a/rtemsbsd/sys/net/if_pppvar.h b/rtemsbsd/sys/net/if_pppvar.h index fdfb56df..bd11bcbc 100644 --- a/rtemsbsd/sys/net/if_pppvar.h +++ b/rtemsbsd/sys/net/if_pppvar.h @@ -117,6 +117,7 @@ struct ppp_softc { struct ifqueue sc_freeq; /* free packets */ short sc_outoff; /* output packet byte offset */ + bool sc_outoff_update; /* outoff needs update in pppstart */ short sc_outflag; /* output status flag */ short sc_outlen; /* length of output packet */ short sc_outfcslen; /* length of output fcs data */ diff --git a/rtemsbsd/sys/net/ppp_tty.c b/rtemsbsd/sys/net/ppp_tty.c index 80d4fee1..2e850dc7 100644 --- a/rtemsbsd/sys/net/ppp_tty.c +++ b/rtemsbsd/sys/net/ppp_tty.c @@ -124,7 +124,7 @@ int pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); int pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); int ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args); int pppinput(int c, struct rtems_termios_tty *tty); -int pppstart(struct rtems_termios_tty *tp); +int pppstart(struct rtems_termios_tty *tp, int len); u_short pppfcs(u_short fcs, u_char *cp, int len); void pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp); @@ -557,7 +557,7 @@ pppasyncctlp( * Called at spltty or higher. */ int -pppstart(struct rtems_termios_tty *tp) +pppstart(struct rtems_termios_tty *tp, int len) { u_char *sendBegin; u_long ioffset = (u_long )0; @@ -567,6 +567,13 @@ pppstart(struct rtems_termios_tty *tp) /* ensure input is valid and we are busy */ if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) { + /* Adapt offsets if necessary */ + if ( sc->sc_outoff_update ) { + sc->sc_stats.ppp_obytes += len; + sc->sc_outoff += len; + sc->sc_outoff_update = false; + } + /* check to see if we need to get the next buffer */ /* Ready with PPP_FLAG Character ? */ @@ -644,8 +651,25 @@ pppstart(struct rtems_termios_tty *tp) /* write out the character(s) and update the stats */ (*tp->handler.write)(ctx, (char *)sendBegin, (ioffset > 0) ? ioffset : 1); - sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; - sc->sc_outoff += ioffset; + /* + * In case of polled drivers, everything is sent here. So adapt the + * offsets. In case of interrupt or task driven drivers, we don't know + * whether all characters have been sent. We only get feedback via + * rtems_termios_dequeue_characters() function which is the one that is + * calling us. + */ + if (tp->handler.mode == TERMIOS_POLLED) { + sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; + sc->sc_outoff += ioffset; + sc->sc_outoff_update = false; + } else { + if (ioffset > 0) { + sc->sc_outoff_update = true; + } else { + sc->sc_outoff_update = false; + sc->sc_stats.ppp_obytes += 1; + } + } return (0); } diff --git a/testsuite/dhcpcd01/test_main.c b/testsuite/dhcpcd01/test_main.c index c1d97a3f..b982bfc9 100644 --- a/testsuite/dhcpcd01/test_main.c +++ b/testsuite/dhcpcd01/test_main.c @@ -44,6 +44,7 @@ #include <rtems/dhcpcd.h> #define TEST_NAME "LIBBSD DHCPCD 1" +#define TEST_STATE_USER_INPUT 1 static void dhcpcd_hook_handler(rtems_dhcpcd_hook *hook, char *const *env) @@ -67,9 +68,7 @@ test_main(void) { rtems_dhcpcd_add_hook(&dhcpcd_hook); - - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_DHCPCD_ENABLE diff --git a/testsuite/dhcpcd02/test_main.c b/testsuite/dhcpcd02/test_main.c index 221b096f..cbfd0846 100644 --- a/testsuite/dhcpcd02/test_main.c +++ b/testsuite/dhcpcd02/test_main.c @@ -40,12 +40,13 @@ #include <rtems.h> #define TEST_NAME "LIBBSD DHCPCD 2" +#define TEST_STATE_USER_INPUT 1 static void test_main(void) { - rtems_task_delete(RTEMS_SELF); - assert(0); + + rtems_task_exit(); } #define DEFAULT_NETWORK_DHCPCD_ENABLE diff --git a/testsuite/evdev01/init.c b/testsuite/evdev01/init.c index fe588ff4..5a8b0beb 100644 --- a/testsuite/evdev01/init.c +++ b/testsuite/evdev01/init.c @@ -341,7 +341,7 @@ evdev_scan_task(rtems_task_argument arg) } } otask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void @@ -401,7 +401,7 @@ err: } } ktask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void @@ -484,7 +484,7 @@ err: } } mtask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void @@ -561,7 +561,7 @@ err: } } ttask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void diff --git a/testsuite/foobarclient/test_main.c b/testsuite/foobarclient/test_main.c index d55b55c6..71b4774d 100644 --- a/testsuite/foobarclient/test_main.c +++ b/testsuite/foobarclient/test_main.c @@ -272,8 +272,7 @@ test_main(void) foobar_register(&question); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_DHCPCD_ENABLE diff --git a/testsuite/ftpd01/test_main.c b/testsuite/ftpd01/test_main.c index 7ec17b96..cc7e8a00 100644 --- a/testsuite/ftpd01/test_main.c +++ b/testsuite/ftpd01/test_main.c @@ -79,8 +79,7 @@ test_main(void) rv = rtems_initialize_ftpd(); assert(rv == 0); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_DHCPCD_ENABLE diff --git a/testsuite/loopback01/test_main.c b/testsuite/loopback01/test_main.c index 1b5c0064..51d5e5b2 100644 --- a/testsuite/loopback01/test_main.c +++ b/testsuite/loopback01/test_main.c @@ -133,7 +133,7 @@ static rtems_task workerTask(rtems_task_argument arg) if (close(s) < 0) printf("Can't close worker task socket: %s\n", strerror(errno)); printf("Worker task terminating.\n"); - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } /* @@ -230,7 +230,7 @@ static rtems_task clientTask(rtems_task_argument arg) clientWorker(arg); sendClientEventToMasterTask(arg); printf("Client task terminating.\n"); - rtems_task_delete( RTEMS_SELF ); + rtems_task_exit(); } /* diff --git a/testsuite/media01/test_main.c b/testsuite/media01/test_main.c index 2a1c9aae..001c80a8 100644 --- a/testsuite/media01/test_main.c +++ b/testsuite/media01/test_main.c @@ -201,6 +201,8 @@ early_initialization(void) #define CONFIGURE_FILESYSTEM_DOSFS +#define CONFIGURE_FILESYSTEM_TFTPFS + #define CONFIGURE_MAXIMUM_PROCESSORS 32 #define CONFIGURE_RECORD_PER_PROCESSOR_ITEMS 4096 diff --git a/testsuite/nfs01/test_main.c b/testsuite/nfs01/test_main.c index 2312040a..21d744d1 100644 --- a/testsuite/nfs01/test_main.c +++ b/testsuite/nfs01/test_main.c @@ -63,8 +63,7 @@ test_main(void) NULL); } while (rv != 0); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_SHELL diff --git a/testsuite/openssl02/test_main.c b/testsuite/openssl02/test_main.c index 32e9c03a..11229e58 100644 --- a/testsuite/openssl02/test_main.c +++ b/testsuite/openssl02/test_main.c @@ -46,6 +46,8 @@ #include <sysexits.h> #include <unistd.h> +#include <rtems/bsd/modules.h> + #include <machine/rtems-bsd-commands.h> #define TEST_NAME "LIBBSD OPENSSL 2" diff --git a/testsuite/pf02/test_main.c b/testsuite/pf02/test_main.c index 5941ea5a..dfb9847b 100644 --- a/testsuite/pf02/test_main.c +++ b/testsuite/pf02/test_main.c @@ -167,6 +167,7 @@ test_main(void) { rtems_status_code sc; int rv; + rtems_shell_env_t env; prepare_files(); @@ -176,9 +177,7 @@ test_main(void) rv = rtems_initialize_ftpd(); assert(rv == 0); - rtems_shell_env_t env; - - memset(&env, 0, sizeof(env)); + rtems_shell_dup_current_env(&env); rtems_shell_main_loop( &env ); exit(0); diff --git a/testsuite/ppp01/test_main.c b/testsuite/ppp01/test_main.c index d4baf5db..b6e9d4d7 100644 --- a/testsuite/ppp01/test_main.c +++ b/testsuite/ppp01/test_main.c @@ -272,8 +272,7 @@ test_main(void) rv = rtems_pppd_connect(); assert(rv == 0); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } RTEMS_BSD_DEFINE_NEXUS_DEVICE(ppp, 0, 0, NULL); diff --git a/testsuite/tcpdump01/test_main.c b/testsuite/tcpdump01/test_main.c new file mode 100644 index 00000000..0f31cdde --- /dev/null +++ b/testsuite/tcpdump01/test_main.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @brief Tests the tcpdump command. + */ + +/* + * Copyright (C) 2022 embedded brains GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <vm/uma.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <err.h> + +#include <assert.h> +#include <ck_epoch.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rtems.h> +#include <rtems/bsd/bsd.h> +#include <rtems/console.h> +#include <rtems/libcsupport.h> + +#include <machine/rtems-bsd-commands.h> + +#define TEST_NAME "LIBBSD TCPDUMP 1" + +typedef struct { + rtems_id main_id; + int sp[2]; +} test_context; + +static test_context test_instance; + +static void +epoch_cleanup(void) +{ + rtems_status_code sc; + + sc = rtems_task_wake_after(CK_EPOCH_LENGTH); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void +init_addr(struct sockaddr_in *addr) +{ + int ok; + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + ok = inet_aton("127.0.0.1", &addr->sin_addr); + assert(ok != 0); +} + +static rtems_id +start_task(rtems_task_entry entry, void *arg) +{ + rtems_task_priority prio; + rtems_id id; + rtems_status_code sc; + + sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_create(rtems_build_name('T', 'E', 'S', 'T' ), prio - 1, + 32 * 1024, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &id); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, entry, (rtems_task_argument)arg); + assert(sc == RTEMS_SUCCESSFUL); + + return id; +} + +static void +test_tcpdump_help(void) +{ + char *argv[] = { + "tcpdump", + "-h", + NULL + }; + rtems_resource_snapshot snapshot; + int exit_code; + + rtems_resource_snapshot_take(&snapshot); + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + assert(rtems_resource_snapshot_check(&snapshot)); +} + +static const char raw_packets_file[] = "packets.bin"; + +static void +run_tcpdump_write_raw_packets(rtems_task_argument arg) +{ + test_context *ctx; + FILE *file; + FILE *saved_stdin; + FILE *saved_stdout; + FILE *saved_stderr; + int rv; + char *argv[] = { + "tcpdump", + "-n", + "-i", + "lo0", + "-w", + RTEMS_DECONST(char *, raw_packets_file), + NULL + }; + int exit_code; + rtems_status_code sc; + + ctx = (test_context *)arg; + + saved_stdin = stdin; + saved_stdout = stdout; + saved_stderr = stderr; + + file = fdopen(ctx->sp[1], "r+"); + assert(file != NULL); + + stdin = file; + stdout = file; + stderr = file; + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + stdin = saved_stdin; + stdout = saved_stdout; + stderr = saved_stderr; + + rv = fclose(file); + assert(rv == 0); + + sc = rtems_event_transient_send(ctx->main_id); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_task_exit(); +} + +static void +test_tcpdump_write_raw_packets(test_context *ctx) +{ + char *argv[] = { + "tcpdump", + "-n", + "-r", + RTEMS_DECONST(char *, raw_packets_file), + NULL + }; + rtems_resource_snapshot snapshot; + int in; + int out; + int rv; + char c; + ssize_t n; + struct sockaddr_in addr; + socklen_t addr_len; + rtems_status_code sc; + int exit_code; + + rtems_resource_snapshot_take(&snapshot); + + rv = socketpair(PF_UNIX, SOCK_STREAM, 0, ctx->sp); + assert(rv == 0); + + start_task(run_tcpdump_write_raw_packets, ctx); + + init_addr(&addr); + + in = socket(PF_INET, SOCK_DGRAM, 0); + assert(out >= 0); + + rv = bind(in, (const struct sockaddr *) &addr, sizeof(addr)); + assert(rv == 0); + + out = socket(PF_INET, SOCK_DGRAM, 0); + assert(out >= 0); + + c = 'x'; + n = sendto(out, &c, sizeof(c), 0, + (const struct sockaddr *) &addr, sizeof(addr)); + assert(n == 1); + + c = 'y'; + addr_len = sizeof(addr); + n = recvfrom(in, &c, sizeof(c), 0, + (struct sockaddr *) &addr, &addr_len); + assert(n == 1); + assert(c == 'x'); + + /* The tcpdump pcap read timeout is 1000ms */ + sc = rtems_task_wake_after(rtems_clock_get_ticks_per_second()); + assert(sc == RTEMS_SUCCESSFUL); + + c = 'q'; + n = write(ctx->sp[0], &c, sizeof(c)); + assert(n == 1); + + rv = close(out); + assert(rv == 0); + + rv = close(in); + assert(rv == 0); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); + + rv = close(ctx->sp[0]); + assert(rv == 0); + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + rv = unlink(raw_packets_file); + assert(rv == 0); + + epoch_cleanup(); + assert(rtems_resource_snapshot_check(&snapshot)); +} + +static void +test_main(void) +{ + test_context *ctx; + FILE *file; + int rv; + + ctx = &test_instance; + ctx->main_id = rtems_task_self(); + + /* Fill dynamic file pool in Newlib */ + file = fopen(CONSOLE_DEVICE_NAME, "r+"); + assert(file != NULL); + rv = fclose(file); + assert(rv == 0); + + /* + * Stop interferences of uma_timeout() which may need some dynamic + * memory. + */ + rtems_uma_drain_timeout(); + + rtems_bsd_ifconfig_lo0(); + epoch_cleanup(); + + test_tcpdump_help(); + test_tcpdump_write_raw_packets(ctx); + + exit(0); +} + +#include <rtems/bsd/test/default-init.h> diff --git a/testsuite/telnetd01/test_main.c b/testsuite/telnetd01/test_main.c index 73d19c4e..d7e50a97 100644 --- a/testsuite/telnetd01/test_main.c +++ b/testsuite/telnetd01/test_main.c @@ -75,8 +75,7 @@ test_main(void) rtems_status_code sc = rtems_telnetd_initialize(); assert(sc == RTEMS_SUCCESSFUL); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_SHELL diff --git a/testsuite/thread01/test_main.c b/testsuite/thread01/test_main.c index 9d5e5bba..48b21452 100644 --- a/testsuite/thread01/test_main.c +++ b/testsuite/thread01/test_main.c @@ -109,13 +109,10 @@ wait_for_worker_thread(void) static void non_bsd_thread(rtems_task_argument arg) { - rtems_status_code sc; test_curthread(""); wake_up_main_thread(); - - sc = rtems_task_delete(RTEMS_SELF); - assert(sc == RTEMS_SUCCESSFUL); + rtems_task_exit(); } static void diff --git a/testsuite/usbkbd01/init.c b/testsuite/usbkbd01/init.c index 0ea2d2b7..9800b871 100644 --- a/testsuite/usbkbd01/init.c +++ b/testsuite/usbkbd01/init.c @@ -101,7 +101,7 @@ usb_keyboard_read_task(rtems_task_argument arg) rtems_message_queue_send(omid, &msg, sizeof(msg)); } rtask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void @@ -141,7 +141,7 @@ usb_keyboard_open_task(rtems_task_argument arg) printf("keyboard device closed\n"); } otask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void diff --git a/testsuite/usbmouse01/init.c b/testsuite/usbmouse01/init.c index 5bf732d8..56518d67 100644 --- a/testsuite/usbmouse01/init.c +++ b/testsuite/usbmouse01/init.c @@ -103,7 +103,7 @@ usb_mouse_read_task(rtems_task_argument arg) } rtask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void @@ -143,7 +143,7 @@ usb_mouse_open_task(rtems_task_argument arg) printf("mouse device closed\n"); } otask_active = false; - rtems_task_delete(RTEMS_SELF); + rtems_task_exit(); } static void diff --git a/testsuite/zerocopy01/test_main.c b/testsuite/zerocopy01/test_main.c index 1be546e4..3a03c12c 100644 --- a/testsuite/zerocopy01/test_main.c +++ b/testsuite/zerocopy01/test_main.c @@ -240,8 +240,7 @@ test_main(void) sc = rtems_task_start(id, network_flood_task, (rtems_task_argument) bc); assert(sc == RTEMS_SUCCESSFUL); - rtems_task_delete(RTEMS_SELF); - assert(0); + rtems_task_exit(); } #define DEFAULT_NETWORK_DHCPCD_ENABLE @@ -32,13 +32,13 @@ POSSIBILITY OF SUCH DAMAGE. import os, sys, inspect -VERSION="2.0.19" -REVISION="1f3c580272b15a03d2566843c5fe872a" -GIT="61ee22b598cf80e260beb64e475966f58b304d0d" +VERSION="2.0.25" +REVISION="767522112be77f8585812fcfaa08e805" +GIT="39ef33e48380a2db38a0eae40a3a4a2c954f4450" INSTALL='' -C1='#6' -C2='#.' -C3='#%' +C1='#+' +C2='#*' +C3='#)' cwd = os.getcwd() join = os.path.join @@ -168,6 +168,6 @@ if __name__ == '__main__': Scripting.waf_entry_point(cwd, VERSION, wafdir) #==> -#BZh91AY&SY9 ½´\¥ÿÿÿ³DPÿÿÿÿÿÿÿÿÿÿÿm (¬#%00e€(b÷/mЀ#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%öÞúzómmkîÖZžÞæ—²U#.´[iÚ¾îõ¹±µ–ú:¥'kd‹î7{ÛïoºµÛ¶ÖµK“¹]Øvµ'ÛßO¾ö¸gv÷s½÷¶N)#.Q+Ù½íp·µÞ]/{mš»<{guÒ‹@Ýó{§«vo;¾ø;ŸvÎiîáÉî44lºï{ß|ûëËßÚU9íõÝŸÝšî·¯y½÷½x#%#%@(}ìh#%` ï²€=âwfí˜:4§[aÓ¹½ y©³A¦€‡¸ê»´ö4=¦öìd+Ö¨ª)ífš0#6 *”¢”{ƒ’Q$#%#6#%YJzÚV½ƒ%çÍíîæ}»j½êºa’ïjÚØá3TTf˦Iv×]s}6óu7¾÷z:#.ÎxûÝW_=³ÛzÖåZ;Û»ÍÝÛ}Þsy¾¯³»ß{¸ûížÖîiÉÔ÷Ëzõ¶§rç>^æû}ñ¾íóÛa zúz{x¹-ìz̀ݳֲ4÷³¼ÛÞ÷fÞÏs¬ô`u¡ÒãF°Û"’EE7w¼#%(J*’OCÀ#%lîè•=÷n{Ywº¹½»ÐdÜöï>}Ü[vÇGÐ`>†ÛEmk®¥ÑMãW`×LæyÛãÚ^u½#%}÷aŽît;o¶û}|{mçO—vpòǼ΀Šo·*WµíƘܶ2>öí®®òÏŸwÖõ»]´î;ºjîí9QÚt×·Zt“ž>÷»Ü®¨ÜÙu÷‡ß|}í«×ܬ‰&ÞíN«îq\îû½:¾Ã.ñŽ^ÙéyaC§¶Ó¶Û›—³®÷Ð¥&nCzî¤|öilöͶíÝîвë[¸˜÷»³Ûºû5ÖkoX«èqØ—nöÐlîõÞÞ/`{´žó½wÌ>ï†Ðê¥PJªPTT´jB¹7uÐv&i¶vÜèº]vú‰Ý›:kÛkÔØëUUܘ{x÷š)º¼»HЃºÚɯfw€#%7ZI#%#%;Ü^êåÉÎó²û3ÊF-Ÿm½ÜözÔíÝ™Üì_U.us[›¶õv]]ó¸|˜Hû†,ÍqÑ»ÝÁæñ{c;úŒçvåJº{+¹éÔ²õ§l÷+ªWg¡»`úùÛÙ;{n#î²Ç]÷}çww»{»»xîvÛ#.¾Øú½mÝEfù‡"sž¼ï¯¼ùÚÀ°ËlÐú$/g¬íÑ”x<ïÜë°VØ6EÇ‘µÞ®ÚGxO{×>öø½ïwÞ´#%À*×Û;Fªµíí7¶;g<ÂÀëu´oSk´ÝëÓmï 9.ó’®Ú×ݬ»Ý¾çwÅówwtåvë¥Þç:#.[.ëwc Ó‚àéÕhÁ”gu“½Þ^ïŸnØu¼ÓÐŒ…/=ÝÚ4#%•c¹éî½Mö{ÜàìJ…U )½{xW»´×`ï{®ñÝÊäÅÖÃV¶•U[}÷IzovƒuÇH*Ší·u$ëIÒÖªîúãÞncÚ[ÓµŽÛ× &Æ»»}öøø‡½óí·³acÜ| ìÁ“G»îñÌͼÜ&:·»}½í6µîÐíç;ï¹ßvÛRÀîï·Ÿw}-âòó[ãnh€ &€#%&€ £CBa0š#.#%‰ä™PÏTz†Ðš#%õ§’{SÔõA) B @†@©©á$zzI☠é4#%#%#%#%#%#%#%‚D! M5TÿMŠoU<ÔôzTý(òÔõ)é¨mG¨#%#%Ñ£@#%#%'ªRD!4dÐODõ$ÙOFž¡£õM#.€ò@#.Sj#%#%#%#%#%#%$!#%&@bh&M#%M#.4SÓiˆŒ4 ¢ #%h#%#%#%I¨ˆ L˜#Až€&Œ¦=&”õmêˆ{SIé” h#%d4#%È#%—ÿÓ?£Uirê\ÕQWwk¹úµZvhʃ>5Zu!LA³ ,L•Q*"€)æ°Pcõ§óü Zü“•5OùÓ¦¸ üæJt¦î£Ä‘8•WoT"¢]^SÌÆ´_3ý†os2ìÀlDs‚4;m»qE6›®ñ‘ÎÊ´ÚMí˜ÖØ`Vd…â]jíâ—˜•5o‚# åñ÷UŒI7wD¼áÌKUå¦/žÝ~«oÔBäE"ªSº»U¦ÖÖ5k3khÈ‹ €7#%H*-E Õ:¥”$HŠ& ˆ" HåP° !ß#%hŠ–‚¡#%ª$@dPÉ@mªfL…’ŒÍCLÓd@M$Rj6Ñ35–25)F”Sm&‰š$ÐJ2ZšQ°h[Fi,ši¢Z!#.F)iM€F¥#.1eM£DRl–¨Š–ZSMhˆYi#.š ƒ(ÌÌcRF£Qµ&ƒJl†BjcI@˜hÒËHÆR›F¦›"[M¶³U´i˜’ÆfLÈM&²m¦ÛM65%)-5±–¦Û3fZL“1‘f´ÄÑd¢‚™l‰B!Qf‘´R`4TH!`ؤ©„f•Jb0lB ‘XhdFIR&B4±ClÍ’&)BFRÊËf$@ÒYŠY5“ccE#6‘d†K) -)¦ ±%&EDš2hhɉIF‘($@VAMEˆ¢fRÒ¦`›É؉1MÍ‚ab6¤Ø–V‹$”›‚$´”PRD•’%¤Q0EaÆIL# ”&RJME™±£XHÒjH’b iM$"H²[bË2ŠFÌ’‰²™3bdE(Í‘˜&U4Ä‹)A³Q`,i¦†Æ"5+%’6(”R"šIˆ&¤a³LcI¡ &¤–Q”Ôi3HÚ("šh¢kP,&YA¤²2‹%&DÐM2‘*4f6”)1¨6ÄÊA! "“1F4,Ë ŠÙ&TÌÕ˜£l¥±(‰™#.H¦!HŒØСYM$QF¤É&ÉØÆJšF¦h±b2’™˜²2³i„¬D`ˆ¢JM52i™!Œ¢)#.š1Sb‹5*R’š)#.‘“2)´…HÅ(ÊHR"‹E$˜’M)´i5DŠFÀ˜Œh&Ti¦DÚ#.ƒ,„Òe‹DÈY‘¦ÉJb”D!f™ k6lmd°$4–Ld5EPZ XR$Ècc1 Â2ƒRXÔY¤J&ŒE©M(Z˜hI™IŠ$2ɲ#)‚E,Ñ¥1„5„²e"$4M¶¦¶´`™BjfŒ¦F&”RLȈ¥6À¥š,Å&‘”%–TÙ¢-L¬-”bC؈RˆšD#HJm~Ãk¢¦©aˆÍ¢ŒlVƶ*6L¥4ÔR¤š44´…¨ØFÉ5Y†¡¦c(ÉS*H¶D‰™¦[%´Q‰IKQµ…£&˜D±5˜±acR#6e¥™2eI´*Ò4TÙB+dË"©TÒT›63š¶,Y“L¬‰S,¦ÖJ²ÙJSLl’‘µ)¬±%¤2RÔZ ªŒ!¨Õ£%AEVMd£jŠÅEH”kDÑ$m‹hÅŠÔl2ѵ€´™0°U@i€”R £F2™&•¦±Æ¦&±‹d‹i Õª–µ–* ”ÍKY4IR1!M¤lY"¶¥Y¶1Jm*–R¦YaZšDF¶•K"e5MM¶„”Êk,Xl²k+,…lÓ ¨ÒD…bÃ4˜‰!´…-£T%¢†KQY&š6LšJ,ˆ&ËŠl¤#."+,‚E1”ÌJ”lÓ4AE¢Ó$&Fm6“F6ÆÈS¦™cE%bHÌÔ#!4LÔQ¢JdR–P5BTÀ4˜Ó J™²Bj-#636£)F̤’Œ£!HbÊkÃi4F5&Éa$YP…-4)Äš4Y”©””²•˜d¬aš,‘±jE¨Õ5£4ECF¥)6b¥fQj4 2ÆA¦&Ä•%I”1Ršcd¤Ía)ME`Û0Ù¤²lf“E˜‰CJ2Zfµ‘hTÍ2–H’l£0D2hªih¬Òl”Ä,LDÒRBAh´[ Q¨ÔQŠÆ-–ÃI†’M#6LŒRˆ#b-f›C2ˆ6*2%,¤©‘Ñ´k£TI¢„Ë5EŠ$Ôš£PdðŒj”¡kA¥4Ë!E$Š¦Ih‚5Eˆ±JÛ"¥F±¤ÁdÑÌ¡jQHfJ$©±(‰•j#V#.2,Y*6Œ)‹4¢Ù2V-&)+)¶D¶M¡¢T’™R¢Âƒccd£dÑ&#¶HÔRLÁ¬ÉƒA#6)³6&"šÆ¨©•“Y‘¤)¤šŠ¢Š&›RV-”’ÆɈ£F‚4˜2JÔˆÑie£he¨’ÑjŠ±”£i5² …Q¶5%)ЙÈ̌ƚ‘LÙ&kDlU%‹hÔ•,«&´LÚ1lj £cc$UE2©¥XÚ6¶1mI˜ÊQ f²±-F+iQµ´©QJV”f*šB(4X"J&ØÖ,Ê’+I[M²“+FbbÑIE[l¶¬R&T*&$¢1PÀ"CFŠi&ÔÃ%XÛØ´Í[F5¬´•42ÖÊY6ÔÔÛ!mI¦¬ME26’QA°ÖjMI™²Êˆ B¢LI&RLˆÈÄd"Ù-¢Ñ‚±“þn··ýÔ¥C)þB51jÄÿTqôe+(a(Æh”‡÷!þ§ ûbåÕ LÿL$hÒlùNzí¿Îó±½9¿‹øºô·¦SUIPª?ë[ŒlÈŸÎÿ·ÖYLâsÈ †ßùë;L(0\:8À¥‰pÁI äˆd˜*ƒ‰Ãß±¢rý*¤çÿœ3ÿ³ôZÑÿÊI(R×+ˆ½”g™,$b/Í0ÿ-‹npz%ZM‡¼íõâ8ßwB¹ÁŒ¨d~ËÕ‹NØœ“ÆZþ,3cRR(l“ŠrrXˆþúݳf¤áV…cÈÌ`I¥Û"lÆLhƒcôzç““G]“¼î˜Þ¹w§¥^¥ã\³Ë/âuçåu™Í\‚LŠëP¦"W‹4LªvcK™@¥JAF&Ä“M‚ê×bÈ‹Ò3ˆ(êñç]¨eñnY½74h6m`Ù—(c2@sªªzoþÝ(‘ 7p‡Êc#6Gv…)†ì,`¼rÂü®R[ŒR}ßÒëdzçgsÅéšÐN×VÄQL0¦Ð¤Y;ùd«Ïô8$ÚÍÏ£˜ØÐØžj¤Ï(%?·râƒþ°Ãµ“ºÀ¡…†JÅxžß÷k¶Œ¶cÂx-›2KËw%€•¬C°UyáyÜ–íÞw^QŽr車esn–CQW6éçqllO²ëå5¼Z4EA¯»ºŸ?_ÆW‹ò-ȦWÅȶÆåÈIºÕø¼u‘¨Û?Go*„Èyùæ|m<™b#4L9cuPEX°ž«©#.¹t@#6A!´ä#ñÆ#.¯)ÎãÂHˆÃz”^+›Ý\Ѩ8šë•ÞwcrŽ•Ë™(Ë®é$s™5öø‘ZA„ÿhÿŒJrÈ.YÚlCÙ’,0!MðÛtÉÈe«#6ýR‹ÁÃ79ô,ýפ¾ìÉþ˜FtÃÏxV¬@Gô¡€dž%lþ «p’—<kìÄ9 c£ðÐÃ|¶Ç™“#tE]HP0îT[æÈ؃Ù_#¨½—zírH ȦwâÔŠŽÍW†7mxþVYê?)Ärvj³oQžwE¦m„e#.¿ÂdÔ‚™ç™×¶b²àþN!ïe §&¢”øuû/ÑÏKà`ö§nínœšùT)"*¤#6d9#c*w&éƒbÛ†ÉðfR6zš®:'ï.àûì¥k,YL#6N*}±ÆyÞ>ÇãŠUË"õÖ“UO«pi)8ª—â”+ñ §Ó¬,‰±Èj[þv¼‹lQôÇôa™1Kèë¯Ç×FÌ÷¿SªÄ7Ím‰Z½”*‰£NŒ¼Pâ-#6¬AË@‰*•{iX<ÙZøW÷»(Éðâ»EEE¼nY5ÆÕ͵þ—ìw’>ÇS6½•ß‹«¦öøÿM‡fhŠF¨%2+zmýW!†ŒbSQIðîÜ®÷uVé(i%"÷@Xš'+¬¥&D§)J²‹šå¢¶/]öï^¯"R¬•k¹bÑ_·-×»±öõÆ*Š|ý{ü=o÷îèë˜ØÔl›|ÏÀÞ1¨4–üŽ‹>õÝŒ>¬žýóL—ÖȲ"4£~"Uä¨ræPaŒLÖ¶jϹ$Â![ÙùzÛ²†F²lWßî«âøùÑÊW=ì¼4D‰Áa«l—AHÒPŤ'Ò'mBµ§…C×Gƒ¶éE2„R]U¥"»wÕ¬ü*ÔðХ߲œœ²ôî²Á‹¨ÀSE#6lÃQMZH"JuœëJ»*”Ó#6I¢L²íãe—¥Â„S²ŠŸ$+b¨¬N¬<ÙkH](©É#6<*žoЗçAJõÂü/•;q°óap×^Ro^X„jÅÄ"_gñ‡Ë<TC—ª¼s×y›¬Xq&ýqK\:05a–áeF1PXäiMö÷3g{O4Ýur™gúkßÙóô€oÄï3Ã)#åªiÔö¢'”־ʣôwr³éº8;+¹+Ÿ†oìÑ®Há m^L¯q#.1¼öÊIr%ÉnCMÏ}‡×–ìƒ6q¸v~„ØÆ5.›|båÙåA„Å#ƒ™S—<*Jtªð¡áô\äáDäÑö%*Éú9ß<}/²Á"#.“L3¦ÙúÀýv½ëåŽ+’ù§T-±·,»í¶g)õïDš!;SñŵaÊà=±3œÏDKA´](´¸åHvÈÍRß#v/6P½E#Ç…‡8qêΰâKè(q<åÅð¹’ý>¼ê÷Œ:+#%ñ²(\HÎpÊ6ç–´zmï*'Ü©×1Ù»á?_kŒ#.êV£„ÊFyûeo–Ðæ”$ê?•ßjfA›vß¾ÚœNü£ƒz…$…!¨.fä³Ü¡Ï\ˆiÌ©Ê#.#¥ŠÉE0F:E&©¯}Ùž…µAîg]°éˆÃp?X7d1€á\NB=}ÙILƘ#6P#6íç;¢gä˜ý=«»†"ž<ú¹áïïRî:I2Éðˆ\õq.Vž)gÉ…,Õ8`¬=jPŽûí‰ÞèqëZ®#.þø¯,nM´B8÷8»è¸×µÛº†ä1ž‡i‹l÷õm±Ï׺|š5Ì=Zí鵦üLuÙ $‘(w0©WX uÒ‘Bd˜N>ù¢Ü¸I¸ì¾½i“íE•éËÒêwë+Õ^{å5ÁZU{Š)ŠãÉÂé¨c¼T˜ì˜í§ @^†Ç¡=4´îç ʉZÛoý4^Û1¶Ã‰±öíªÆË ˜ò-—îûâû™§õoÉÜn¬æU>õéºiúK|e˨†J/±ßåÇ}m}w*IeQ92e@êÛíhQAA9¼CrºõÝO¡¸Ëðuu5¤&÷JÃF}w/Å¡j©jŠÿ}…(© Ÿ+þ«¯½û¿éºÚ|~þëÇT•öµö°ù¥±G‘R{¨«EŠ ¢€úªS>,õ‰÷öæß»åj»çíj܇±†¿•™Yõ¿¯œõâ‚ú·+$‰þ.hÚ>n·‚ªôj£]–P‚ê©¨Æ ×¶{âÝûïg˜œå mk4µ“O§k{Ñ”ÇÛEË£õ;n”dm¥AyÑQŸ#6ÚäúÓ«f‰Í²ãX—8T¾NL\ð—ôP苘1 øˆ63œYî y²úUM3¦ùÝ#.X˜|è¤TWù“7ìÍÇΊD^jÀEŒR,Œ)9Õß¹ÊÈ·)óÜÑŒûúuO³~™¾$_¶ÏŠ ÊsãÆ4?ŒZu>žì]1yÅøÚüžkÓEµÛX)>óOÖâm8s´Ì‚ëéÞO–z\àÚÄÚ¸;â¦R¸Á1ŠŠ~FS_tí“Rn(‘ØPñ¼b˜¤Rf“WYüÊ¡êô„cì×ùúù«ÜËÎP¼B´ ú’Y×…é¤DQQe0¨x~‚Û{*©nf £ªwiX‡T¯)œ’6-Ï;Ë£êw³$3Ê¡¶Ö}•TÛÉ|-ºz²8ï5›`BüéÝââêÖh¢’…ƒÒ¡¸É~¦™J‘‹Î€¤Z+¯¦9r¬èœlÿV´xð¨#6h6ÀêD¶x0¥Ë)AX›³£*0²¹ë¯_#.Ç·†È÷zìe¥HÙÓ,›¿µñïñ²5AòõÁÞŸŠ{žeÔË7Súþ¡&yÖYñ¯¥³LÅSÂœ¹¾Ù?•”¾ŽÙƒÊ-„y¯69^èŽ}ž¦pà†BI‘iK‡&±nÎǨŸþ³…éÝs»Î¹ßŽe²‚ð,¼&2:LäßÏå[‹«¸óxHÇ®*–Ø×ÒU9„åé1䌟DL5;þ²ÏiîÐå‚„QT nUÙ‘`ÒŸ#ÍoJò4†1Sºëïv馫ÚÕéa離Mô4O|®–I${U½órà¼0‡;0©*ÃzG/½7ƒ+–#%Qb ]’öÙK\.ª¸ÌÖ‡÷) I9q×ëa¾¡—¼òó#.ÑýýïÞ5К¾ä¬×w*8ÙA—'<ß:¥˜bÊï¬2×ÂxÕQn:ú,öTl8:<ôáyï9ëCÛ¢M\¡"#.JvX¢=Êóðw¹Ô%g±œCÍ•P´GhaÑû£™ªºÅH…”ö)¬¾U.ÎõÛ™Âî‰A=†”sÈ«Ôs›H]#.¤ú$¢8.‹\Ó³Mìòõò³Þ› TÑTaÓMš}ªP‚ «½È¥>?‚¿½¨èØkÕborR#Rñ/ŸÌç*3ÔÆѦø–Ú4u©ð±o‰c‡ÈÞéñÇ#.vnV»pÁáã)r‹³Z”,ª£Ž.O€êÀ’·}zwîÝlnª¥Ÿ.LQøy×@EHiwýÐçç=Q›q§"%V2&0+VŒq¬¨w=Pë¦uÁ7ºV^-Eu©QQ'çU0D}ÏéÞ™Ni×ôñ$¤úÊ'1ÎK¯U=_“lS#6´íŠ0ã×D1zßÆǾ+âdpÚˆô±æZ?wéžx½\`<+½—f—Jøã×~WKËÕ¸îáÝ8n©$z«G»à<c½Ì/Y€á÷ˆÓ vfˆz3ó¹L´cz7kù%ûÚEΛY¥ñ¹-J`]ÞBvP\ÃÚïŸHm2LˆMßwðrÈ÷4›:ðÅ’µ¼`¡‚¯\Ô½u}˜<(ñf`¨Åˆ³÷ôͽ‰UQ9c:ªO+%‰ŽöPiP/º°<H¬§`±È6,I<Y–e"4ECØ@f‹zÝ«šÉbFŽõ™G¡B>q¡z<À®÷±¢—Ù è‘ì#Œá?Ÿ—™}ûI”¡ÓL»_KÃ'ë—B¶Øÿ#É+ù¢ËÖò„|ÑúåµömŽ±‹×ª©ü°Œá˜Ç’7û"ònþ½bôŠ#sh¡›¶¢~¥?~´›V]6k)0úô£ ¦ÙUBÕñ °Uˆ¢,õ'«@ž5ûÜ+ÏÕlŸ±X6µÉ nŒ.ö{pùèü}´:ÑÚð†y¥ªŸbsf19%¢ØñZ³æ#Ô#6 ‚ ê,&Ñž3|#6y€"ú.$#.#.æuµÅ.÷ éÙד»*{gd¾ŠevKfûQοí¶ÒÌð7N ›hÄe hP"1b±êL`ÅMm¬"ã-ÅX]#6=™©Õ)˜«Î#.äÓ2¿+]øºtÉg“:Ô00Y½UDà’ÆŠÛHœIå#LÇÍ’6\j¾}›Þ#.‚Û»Æ6Ñ=U S¿ÑÏÞštÌ4såÙº"ïg³.¾‰t(ÄÉ:qþ²c1û¦³^¹ÙÈÕýÉn*fb’¢fƒÛŠãš;èXhêöÛ÷Ç1•£a¼s>¬=N#.ä÷Áý(ûqÃÙ†fT`ÒalÚÞœ~2å8ŒÀr¥‘Ÿ¦!:Y@àe¨Öj¡Á¥N¬Íec±;8`i‰j%ÉÓcW?äDM¶@0L‚¸¤\Þ'k‘KŽ«®NºËϧcV*±FÖ˜Òßãñð³Ô9O—äÇ»éìåôÁõ*5,<:Ø’|EI$¹$G4¡Õ{âS§#%bŸeÙ‚‡TöŽ¯äìÚÈQ·Ø!û€PveòóêÞ6‚^—ø\F´÷fX=”*´nïú>Q/ãnNQŠž#64…¯¦E¼×^Æ~ú“’`GÈ'0’õÍ\P”DØLÍÕ7؃Ku„ÑohsyÛÝQ¼ã*Sšçsƒ;5XvPÍf8uŒÁ®[˜ÝÒS¬ÝÏ’³•ÔÍ4”¹²†s?…'ÚÝiÎ;¾n)tYG.å¯K|íMÆ×6AâÖuü×8'¶¿UÊÒ»*se¦Ü™L)e‹8«|Šãý×W#%}O`×|AÊ>ƒbm€fò†\sIÑO##y3£Bé#.⊠}ÏÕ¡n«r£CDb+ÂÛ`ì™úÛn¨>O½Õqòh‹¼’×59·b¢ fŒ~~˜V#+bç±^Ug•:^óŽ×ÿxºTq(Ū¿1™y{T‘áâzÒÔ²?[좧sˆÔ5YÿÆgk’—qjûWXvã_WmMÆñuÍZ3¥Q_{=’žìã³—¦(5#<IÛD9Ü÷3Ï^—’y%0I†jÂÉ[J3NMíT¦nPÿG†4„–_oñï=BÚÓK¤JÍ¿‹˜ï¹¹oŒÕa^ݶxe@eˆëªã8GHºê½ÙGÄÆŠÀú"ûÞ° £‘’wñ†ýž~Sa¢œv®4L§Uz°ÎÞÛß²+f”y´Þ¿#./wWdË«^úPÄ´¤áYKAq:;åG2jT wÌCˆ{¿‡ÚœC¥™k5PuÝrª0àÒs¢l+«3Û¬#Û8]Å‹‘Tœˆò»Ó:—úûâ$KÈr™‰0Êâ(\ñ>ˆ‡„Âæ©CÞØ ¥Î]«m9¹ÙãHˆ X1ºÈ½7¸ÙŸdÉ-”K†OèÜû¿—ŽqÛDË‹âíÜ×s²žó#%$ÌØ@²š%"£ÏiñÁGn¦·—›šÿ¦ågsáºÖÉÑosã¢Ñ+-¯m%b”"¹mofŽŠÁfm{pYpÐØoÆZ”̸Â4¸b³Øúxì^S™ÎuÜÛzVþîlbݵ Ï°POæÀŠ:›»ˆ¾Zn(Ô#{›7)×¹LùσãÕñÁ”€÷YÓ¡á‡õ"6zXø£°ébc™G“ë-þ7J-YSÕ–#.™[òw_#6}P$RFÂ/þª:üó²§HèCþCo:“Të–=49yz¿ÃÆÊræÄ•{´R4IÖÌom¨3 ]•F“m;Àuc£tÇloz‰Á`(]ô¿5Œ¨å¥÷!œ.º¿»ZUǤe(®™¯ù‚Ê<V+ÎŽ3¾Òÿ™Ó²uèæ:»bà-¯°F–|¦W“ìºS·§Œµ‚]ëÑöá« Ø·M(ŒW–ù¯:ŒýuÊ:jÝÚÌ£H¹EÑ£8`ñÅتá¨à³ýk £Ã7c¤ü¶<Î’W‚=ëS¼qé4§5#.-ڃ߾›öÝE3ÂcÈär¨Äžù§L¢^3ýÞ®§r"ßM¼}1(gËDôÑ%¯PÄIƒ¶ôÄ`ƒ³”CȲ-G%nG5—lV°‰À(#6QEc—ærÚéͬ١C8’z³‡`Cß½uˆ.7ªY`ÞD,UGÊRÌÑvp«œOøg[\þ–]EÅš@Bcvß8èˆÕñ]Ñ·7ˆŒBov?Uëì”?ë†oŒ;2ëðÿ…¾>^ŽR÷ F““Ö\«ÈÞ¬Ãô²†Ct½FŽ«X 8Ž,Ò;hŸ˜Xj¾$8ÍûYùüxpå»È6püà ·Ý¤$ÀA7ýc€%#%%"A/üÕê¢c–å9Xãßá]5GóÚY"E5É#ÁÛ/*9/„QÉ?Bu˜jÑm-Ã&é;ýz|ž¯‚££Õ¨l@'ñ(¢¹*öúi|GÀS«êÓ©ÝœKð!7ÕmVÐÒ×>ƒø³9€&u ŽÈ„ƒ#% ’ûÿÕ»Ñþ-¢îÕáøÇîäévÞ»¥ #.cc¢¼¢ ÎD×Ì@?Ç4#6†¡o轶j0–ê**ÂŽ¸ÙsóîÅÇ#.„¾º"MŒ\îª"ˆ¤‘ò©¹#%gíÞœá4yR™b(Ñ>@€òtÆ¡R¿šÒ]eÑ·äsvÓ Én(+VpäÿE®‘+ü'6¹†ðN°¢3¤Ä[(ZŠaÉ»I{–Þa½x=™Ž9"1ˆ[ëJ¯lê1H#.ªñŒŠ%OÙŒ#%”ì#%ÄcÏm¾ÿ¶ç•aùã¤þÑI‡ç³ñåú#.5™ðׯ_ó~µ?èÌO“HÅGTUÙÀM¿ƒðý¶y´»õ¨5ц6¥—Ãcj™b²ø§¹ƒƒ$|_Cºuž0€^~c_ñd°"wƒ#%°>בj>ðõ—ER=Sþñ¶s|º5ŸÛå€Ãm¶fÕ¿.Õ4|œåÝj]“³‘¨:;£únŠ>’Ÿñ:ÿn@ é)ª×fËw#.·l¾¡ßþ0}÷îâ£(WÏÎüoNßÛès’{G4ÆÞ|ö0t9×bbÎ?GÝ÷k_ÁÉfª ž"@îkò•X/E÷;¥fL¡¦¿qößÕ5¼8±“d¢*¡â{/Ìë¿D4áÅtÉšûàûoötgS³wÓ>¬XB§<ÈIÁM•mGý—ùu…9£Š>¿zsáþ¸'^Í¡c®¶7Bªƒ+Ã…À3ïr˜\«poª_P–ÜâÛô=‚TÁÖ“æõ§º»¶4ZMI:îäÙœ³[Ê+YòÈ{Q”Óho³…`#67]±áÄRd1ÌU…²[d"ˆ—”b$#6Jk!¬gÛªLk Š$,¸ûÌ£Ö[ËúžP&¶Ï•¢U´’†ð¼U1#ÅË;§¿&b±A…1dy%*üüóŒî€¨"/Z7—cûÿuËBˆsrœ™§¿-‘œ$ýþ~…mLÀ:z®X»U ÄDq#6“Ïß©s <=Uƒ¨~L …¯R›5¸}ŠÛVIé³íLgï› ¦aóÓáåvº˜ÿ_E—F–– -™áG8˜Ÿ“?ûmRGÒ=bSfqÖ7¶ÆAi+sèü"Ê|;O¦$÷#I±aiñÓíÁº×®[Hå[#.º“œu€ÆÆŽ²X[È—¡J×<óÙT¢ Þº™ÆÕQjª@J’ßü.Å#%…W&û9œo…èîD@¾Àß#.âë…cû§˜A,BCG:l¡úkLuÐ#6”‘Õž?; éõæk¬‡©÷‘ž#.qÌvÊÐ3:^LŸUÈk4Ž#6`#.~•H‰5ðÏÙž>Ãõ›÷þ}¾Ó¯‘[ŠhyѺBJ2\¡~¬dâe#/¯ÿa7·§4ãYUáCÇMs÷þ{¿ÍcB'$Å;Ç©·8¦ø¦#.{,µj€weß#.røâ^˾<0fxþîÍÎ5&Ī¦š6P·cQǘ"5Uô†÷êŸE7¥ã˜y–l)p™Ú7úµ!$—Ó8>ž{K2®rãyòUçD#¯lüw¯åz€ã=wÊ‹Ý#6Dn…¸}^æ¡}ªé«)D¥ÐŠ”‚]âuq·à¿çÛ³2±³…®\ÚS{ûìSXãÅY%qßÀn©ÇA#°óÑUá]=@tÔ³žÅj&†Â»Æ5&fîŒðpK‰ ¶˜Sd&vEÚ}´zGYÌ*B#6 ìÃQ>Gêp¬vþ—Û…m}M‚ææ‰ï¤É*Ý0ƒÞþÓpì÷Æûè|A²vB0;½–k[Èé#6¦h˜"#_ ßzéòøÍ3ã 2&ˆBžÑ…5Â6‡…ܦ2,,»¹Ç|زØR¢"ÈQˆæY¼° ÆÒƒ•ÇLkG>'ôjŽ1* Èéô‹uüi‚S1ëŒu\SdIiÆTˆ°Š²O¨6ƘڱÔá‘¢»µázl_gêÿ8hx”MöX0-ôî ê#ôéŠsüKˆòÿ5ö¨»?#%Ýyx®)–˜À’7 y#%í2òw‰ ÐPc± Æ#%tÀ`=!#.fîÁN¯%Ò[^v…'k³Q÷Þ´R“̧`ÆzÆ) û¼nuí¶#ÎÃí?.ÒIpJ[¥iB¡×*,ÂÒÅ š=ÕÕ`„ìQ×pgc¼Iâèez«ôC,Á†f{Ê2ѪRuš„Æú 빈7©Óyå_æ>£vöt…µÆ|ú9´VKœâR˜;#6(<äwãC)ª((F‚Ïv0ñ2hÊÐŒ–ˆDÊ#0+C“9°z“˜¼•]>ÄlÑJYb¦„ÒTœ-¨¦Å¾bàèÁFrÐpõŽ*(~¨Ñäû£sÐÌꆄÊ4 u»y!jŽÐ#8±sy#.bƒn=>tzËÌh†Á¡ÈÌ\åê¦å…bPõYÄËþ:¹Â—nTÝÐ`¨é“Õñ턱ֽnz1»DR‘Å+‡GèobŽÊØÛÑ£ŒU$2ÖåŸ#tóëñØó^¸émÖ½¹ªO8«,›}YEω{^ÜIfxOÐpLÂÅG•#.pßú¿‡¸ÊYE³>vKUÓç¼çûˆ}šgا©Ú§^ÏÜøÌÍ+#%®[Ÿaœ:9Þšœ9ÉÃd×+àB~e.wµ†¼qalñwE#%{j›,dº*1—®íwyæ]®îëO‘˜ÀFŽn‘snZ*4x’m1|F¢ ˆªÝ4s¡ÊŒýÖž{Ζ¹,äl D {#%ÓDhM´ÔD)$CTÅVƨʣ}íÁ14LT.%"¸ã#%l@'D188Ö÷#.A³èòñ®$Õ^¾0Ʊ³\´h$‡{Þ®#.NUzJ);I?×$è±ØíJö»‹? v#.ê‹Ùö‰T«T¾î°¦‡ãaÆ»EÀø5vÈbãlyA}·É¹»Ròš¢C÷)K.Ç(…ösN\0p¨¨S"Ðoœ*ñ“!WTðCyp2b2„ˆè/mû¬kÙÓY¢Kn9‚†¦µJ:¸Ü³\ü{oM—h]¥ÂŠfŒXn#6àÛ¯d Ó™Â/QƒèØ…E®‘KNÀá®WöÙ=þ=^u¶Ã?×›íÆÊ“5çãœ+8~Ñ…ZF0oÑ›48Ã@òð_¾*Çc0Z4ÛþþJ˜°q …áF‹Ã=’tÌÐÔ%Îln¶b–Š†æ˜¦Àé˜JÞ(BwyÉ.ÅBjܘx†HÃQ•TÊ8¦4c#6Å|mñd@ñ˜#%†ŠÒ奉c‹6PºËÈaFĈ`Ÿ]ÿw&ÅççqÕ2ü2GµÐQˆ¯ŠÛš1R^+¦¯LZ¾•yïÛn@m2(ʼn£-eFK`²(euDÕ8IwN`;ª–4,œ:$VbV66ÄPEBD 2ÙN—ßYö;üó6é}rÛ=ùk²#6_³S0¢³*¸‰B¬¥yÔy¥,ôS°X¾.‡9€¶¤Ëuª‘ë@+ë#%)|ðÆÔÔ@zæX"% F#%Às´õ‹&Á;Æzüiûç|ú¶&í•Ÿïöíˆ0t 6‚5à1”L Þ=Ùôãõ¹H9ív ¥RÜð¿4‡Þ{m›ÇnpíÔ+ãÍ=ŒSº!tî#6oÅgcì—tn€…™©t,–Ülu„VFÆ”±#.Ù%Æ·©ƒ_NÃÕsËÏù*\¶µ8r&Aö„²ÕÚ¨N6˜‘÷KY¾#¥ö’ZÔŸŽÌì:‚w¬9§ƒUf ‰Þj Íñ0“ÀF•‡+IŽuœ,—<H¿ý…ÍF;ù]õ½ =ci?kÓ]w›©XNÚ“ÃC$#."oáo”+wÖÓý6Ì<ärÿ‡gŽ·²ln{²ïé£ú/ä#%Ưۡ¬Ï‰”ªÜåŒô¥ázY].Lè®k¥èÐkš#.Ï·…g/!¡5ªJ ±R%KA¾Ç³8Ávœk#.î#ƒßxÄEûÈ¿•÷þÎÈ•Úìv`‡‡ÁÕåEjÜ¡ˆøØ¢Öˆö%ˆ#d¶{äs1Ü“‚QãËðÓø—ÉÏe·’&¸r¦¶Äj¡ýÓ;•¤5wÙ1#.Ä)rÁ·÷íÌiò/:'D\ÿl–Ì€m#.¦2!Š1Mäñ&¬ˆ¬ƒF)š˜èdXUK¤@md”2,ÈtëE„4'ÖFÁ°5’‘F:Ep[ÌÙRMÔ0õoïº5"HJ)#.’í¤#6)$Õ¤o.Ø…)ÚŠ"0Ñ¥bÈèQ„Ѹ&bÄÌ´‰cˆu·^†ØŒj5 ÔF=3#.M‰C˜]˜o/Õïâ÷~ÞaÆ„DbšÃ'™¢Y鱂‡˜ÍCB&g×LF[o×QLi‚†•Â4ŽòìÏ˃GdÛ78¬Hý]Ñãˆg(q5ÆL¯;•ÆÎEêRiü\©Dyb9iȦaš<µL£Õö½w±Í£ÅBM"1¸È¥—Yi]Ã\†¶…‚Ýb»/•Ì]Nç†úséÇp#fâ‘›Œz܈òëÑF߉Äå .¡‚IÛµË#.oQævyÙŠxq=L”°¤XÁMÀ7E+_î9x:ãOƒF#äøT`¡’œÜ³µq›„ùCåÊjm·}#6±;¤½d‘JHµ!MSxžLÍÁÁˆàé#6\³•*"ÿ©©eã‡;ߎÏxý#.–q#Ö§i¸>NcUGEæÿÏ^ۤɎà˜4ó$„Á;>)Í™n$"˃ýȵ7æÍ–Ñ ÷šÈÙf1¡ýê(v Ž h«éC5ל`ò ã{Ô R#ƒ7(HTZ'ÖcJ:7Zf6NGÌQä8@ª‘sIÊۤ܎jì’Ú#%;qŒÂnwjÙ˜Q±¡3¿Áaªê©i·Š(Vj¡Š(bõëVðÖ\ÓâM´0kD>§¶U‰„zpNzb#.ý:ë8á“âJï}ŸC•ñ•Ov(ÀäO˦Ãÿ¡˜6ˆ8H^&ì×¥±Ó³?òtÇy™ë°#%#ûý¶¼·6é³]Vâ¡3‰ée›Á×GY`IÁ´Ú·%®Š ¼ï|HsϺš˜ÛE“H:u™Å) ²,Fj0ËsVºY#W6éщ(4ÐÅ"´4Yˆ„aŒdtªÙ#6‚#}´‹Ü¶`Ø5ŒMõøf¤ëÀºfmjÎ(#.árµ¯VŸ¢¿í;'\ãS—´)=ǸöòÒ#%'Ü€”#%›½ƒzÜ\‹n@|ʼîmÛ¿6ôÙ ²êö¶¾7Ç¿ eÊçó)vaÒ¡ÃHF‚Á‰ XÏÛwêÖ?!¿òÑŸŸ©›Ââýj—Ìžx‹OuƒÖwð4r }ðÛãæáŸ7>ñ§Æ(8Ñ_Ì]`#÷˜úv#%ƒHÑ=©“UŠ°Q0…þrm¾H%x‘; Öõ‹™ý¹….?½VI|gxûœˆq¨[$›î}PT=]‘#6Lk+ƒì ™•Ïãý¯²K»d9r_ Ÿ¹bD³åAˆÍÝðü(òìù· #6#føåðÝÿ¯c»ì²BŒÜÖÝÕÏtê~jðêêçßlúü3~i»Ónˆn>ûy¾{çñ~ùë]—‹ Þn¨`"1€Ø{ô°õ¯ƒ©Y.HGs$‘å<šÆë½\GŸ<ŸDºáëߧ=~ÏÕþÓCrqy!áã^H³U$ÅÕ2Änà cèúÔb3AÙîù½ùa.ÁGc@õ¼#6\Q\RÒ9¼ôUäÎ)u”Û¯ëqVÂRVÜ°¶·úûJ#%Gh¡ïÿÒ#%f—÷,ÛQ¾ß·èøvKx#% œè¡”#6€”»—wE·B¸cÖáÄîâ§Ï—¹øj<}Åz¤4:CíÖï÷7¥d€B‹b3Ôíh"™µ%“D˜€Í•,J/Îã14i±WöÑÛv¢e»véRŒIKûR…IXñ¥·õ‹jý_È^Ö„ÒVÅ&.Ìýü²Ü2SQui¶ø]ˆ!C†û^~7²^4snë«u*䔩󫺱5øuåw?çÔÕû%`¢åÑ©ÉãüjRD>=>ÿòu>œi>ÊÊ:##69dc|›ŒVþénmü/®ž~çú•´J:3#Þ'$!éþÝPY]oR®ˆm½$òZ¯&Ö¯SQUQF@ö#Ûá aøè}ΑÙCui±œb)f¢y&¨ƒŠ•D éƒ*þn&NSìÓ°%ö$¨áTò¹^%\…™ýÖwbIlI{VTe—ùä§îjÅ‹çƒÞ•¥Ô:±…Ø1†’µ&óWR÷ñþÑùùÜ>2…ÿ#.#ú6q4¿~¿•ù·X30~>êí{P?œëF(¢,Ö>_#6à3~ž‘Úˆ#6 ïž0\îr›fžÁ«#6CõÃü j1T,jƒ¥q¾#6Û6Od'@h'Á¤¢$„K“ð²åª¯1¶ œ½šô†±ùË=rÿˆ2·æðWÕPÅŒùw©1P°æ(óÚ‰ùPŸ™´†îΔVåRh!0ÁV“ñJ@-I[ú¤\T(–#6N=>$oŠ¿ƒïŸ-#ëüþoÌ}÷~?©¿SÄ>áŸçú}+ãä™SÖyà-[O¯?8Ñ[úF©î»ÏDÐÏcÒÿ½tz/Œƒº~˜ùÓïá7|çé6`¶œ¹‚ð‡ÍVúö«Ãñ˹G8©ç°híýqpä"#.ó$`{z—EÂêVsãbÆG˜¹ÄL¯“<„OeпõIGá=}}›’ô,k±Þá<öv}²#.¹—iÒå•ýº{ã¶+¦p±ß³0éý¹@ÒÍîÎÃ{¶uÁ#uwDa n'ª@ÆpTÏÝc#æP”OR˜1ß@y÷^¥ïPÊí8jßeÖÑnvµåô¸aËA¸cüU&dã#6V]#ÛêG²S "‡Í÷ÙKÎw-ÃÑ4¾Pdé9ïÏåp.Q¯„Ÿ~9r—a#.xR^ös›eH»q(â>ƒýºë9ÕÜ{Ϭý°±øï½áäÞQEV§ì±p2”/Xu|¶]æ¢c=!U%äi?Cù…CØcX¦ËìÆýýøPRv²Ä…¥24q`Þam;“ÿƒŸÕÛ¾×Î_\P Wë¾ëÝ2ÒÓÄ«>îþë¤îº~š¤>¶–=TM@òjj*©¢³ÒB''%=-–uûûHkû8ܪpÿXŽËؼ‡¡&>]°CÒp}!é8‘BvþZ>Ö-øÛ꘶*äĄǸ„$M®pƒ9@øI‡Hg2q#.SýuFfŸÑýÿ›3ñyXx{Pî-ô2Ñ°oõIöO¶ž–$˜¬'Ñ¿ÆŠâ4ÊјŠÂCcíÔÓ×å óí5±y¿oœü|zÚ1QÈøÎóK,,$o_»Cd œÌˆbWά¯Ÿ–¥éŠÕáZ¿V3XÀŸÓÐôüŠ¹CŠE.}•<åÔtÖšžv¹W‹:ìN#K»aÝÙ<ïíáËXÿZ0þ:4°4n'ô)¿©cç£*(ÑZ1F ©ûÍIpŒ[Å ]E}¹ýæ™æzï ‘½Ô‰ˆÈ‡@x#Muaͧøô÷{»þyú¾ošÓé6låÕTÏG7°èôÓ6”Õò}Y]ûü¤~zú›)ùí`¯]š$Æ‚–×=ù\¹µYÖïS"Ëàîýßê#õoÛ}¶?=º;~Îícvφ\·X!kÊôCÍ~8ED´Õí«ù¿]mRáã>^Õçá&÷_#68êpbo×—›;ëvدµZSqŽ§iûöÇ÷oöjíôgËÈm‡ysrËG÷t{œvǃƒh²à¢á`×æÒúôÏG7…m óSžÜpa»£:H~ êþRöÄj9\RAï·î~^ÌîéçÇ]%=†"Ëù™é»‡íxâ¦É hæ^†LG’ëe#.·s-”ëÝÑ3Ú÷ÙÌêÏæ|Û%”n³¬|ðjãWuzµ}F×péÌœ°çþS¶1†š¶¯‘ãLSèyµìÑ}˜í{ù`-¼-§z9Ðó%[¶5¡v»º½2Î;§'D‹?/Ã?À؃}öÛfª]wT¸(9=E)#.]ÙYY‰xôpaòÆÁ¿E3Æ£Ü0¹ÏѼF%Ì.lAÀ>2.sºUÍ?¯Öç½FŽ6e2w?.ì·Å¿–=ÛüÇn¢n–;å"^¯Nù]¦ëûi=Ü[ºó´<Js‘CÆÉÝác!»…-9ý6GŸ£M\RD‡8½;ä¬Dèà¨Xhÿk¬1ÛÝîöj|G#àef®zu?|{?ˆb죩]÷<qáó„Ø2óyúW»î4öùüãØì˜sfö_IÄdaÀíÔ2²#í‘·Ù#.ˆªú«¾û+ôçñé¾ÎïÒ-«alÙÞ¿(Œô/£#.lŸ<tìß+{t¤3.—üÂó/°Ú 2´@ÎôcL|>y8bºwc|{a²rÜÞÁÐ#šŸgŽwùv[…qýª$R¿S›ú>]ÚwæÿÔtf¶³×ÖžOåð{£<î¾ßÇKjØtcú ®ê]·yïìDZ¡¯Ú’ÿ°Ëà” F«àËÕ¤pøzŽì¡Aó:Ð}Ù"¼p+ˆQÕ‡“ß_«ÐÃ^‰/±m&îù<‡7;›(|]o”ÎÇO%~Wû™ß2lSœ–7µ|r¯ýæ†ï»,èá†vENJÞá^[#=6{}ŸÂ¶uýŽm™`žóùÌ~ÃýîÑÛŸ]nåÌ)ÖÿîËÕè¯m¶ÿ£Ïª£ò©#6ù¿GFqŸÂ^FÌÒìò7ðü4µ?w·ö¡(?1œ½è„ŒŒ®ßçõ`¶úO·¯¯Ûï)ÍÓ["†ïÆŽH#%õ"ÕËÆÐ2Æ P~kZ#%RE¦)#%éŒ:³»“ÿ£O2ƒŸìô„ý½£•<Ý~¯Ïî·•üsŸ?·åõuåÚ%÷‹›WwPì»4ô¿IÛø×~÷%IôiÓtêüÚoæòšº³¢qüµiAŸ£ªÇçÃ@ïîøgÕÓùj¸aõv{À>ÑÀu.Þ?üB…Í´t¶¿®gºç*¯õhÛDAþóSö䓈yGÇbeÎ>Í_ÝøþÌ)Ón¢¹8h¾>#.[¿g®øÔjý ¿º;¾œœ0v½=†áÑ›Éñ¯Ÿìá¡>1û4Šðx÷ gP#÷h÷óñÙÀpý_Yõ¥©Ü;ü|PåVˆQó•ñ=€ê?~‡u±ßåmAì#6`¿Ç™«–+¿÷¶ÔºÇ%ð#.ý‰Ã“¬óS³÷wt÷/vÎná#Ͷ?!b¿ƒpv ùlîâ¹ù;òžêÌ™/Ð|S¶ž9¢ ãþ?»"(H;G¾÷*Œt<&/»éÖ†ûçë’GK÷Dj`’à–õç9K#%#61ÜT'&D¯žñª¤½Œ[-2è+˜`†IBfH&ùÚ’~;†A΋wù´Åð8,†È¿{#Y^‰ýÙátÁôMÏŽý®7Ü}·»,°§EÜÜpà…#.±J‘ÔÁ€ÐúìŽR#ÕÃîá4¶LÜhâ+µw».©™À’Xê%äqh– !ô¦ÏÇ~žIèù}A7Œ®«wèüº!À²h;ÐÁà·-˜>ðÐB)ؼ³»¥JÒˆ®Ç“>;ÚëZÁZ;ž|%9µdC–PSx½óƒsZËËgDås£wr×+)°±¶1/1B+SéÏkÍÞ<k«ïQ}=:ÕѧBxóÃ&ýÇï"÷´¹8KÎ.óÉÞiYÉê¤kÍÍê” BI×eŸWRÍ “÷zž4åµ%fˆjŽ|x¥¹‚ê΃0Ϩ]¸RÃbo£<±Ã<âñrgóa^ç£Ç¼;y-¾çYð‰&aÈI$¤í"…:¶¾ 8w”Ôu—™²æ\ËÆv³i¯ožM°Õ¥ž„|Yïæ1xÑÀ{]°‚2Çã×^—þa»›Pëø-z×ã¾4-‘]»l¥_3T¿˜*|õ„)8óÌõ:„aΓÉ>·_!†(£«F€+~›4sgì¶W×M«°ìÆç/Ïö´©ÝŽß¶£Ní3¡hžl‰“3û‹Ý-ÌØm=O‹£Ûóp>Ø#&þQ¬½0â/Sß3 þ>mM©‡ñw“÷ì\•ý\}ÿ“—$Ùwü÷y¡ÔR‰$ìØú|¡ô_ÓIØÈDí'¶1ulu³LׄãÏú[=8á'x¿ƒôúè3ú†A¼#%Éé/SØC¡I%yb1ÖFÉ¥Góü™*”å˜bG‹ÑºüCª öIO4|žÿHï½cÀøòŽ»ÚcY|uŠ·‹>Sþÿ—æ#`ó²{ÑÊÌáþBÔfeÌ©cv²Á¨9G…?G¥F5¨4iTlTŽ Ô¢¥nØ€Ðæ7#6ªÒƒÀ¢¢,tþÍÚ›HÁ¶¸}=3†´Ö¤On`˜a´ŽÅ-ŽÀ¦°Aȱ¬a¦ILA«"hhn„)"–4±[VWŒc€ì'Ë#.Ss¬6ÐÚ]&6)":ýº[ÅÖ¡É \’6ö‹B{qZ8dÚu‰ýÿ¶ø[Ñã"?›9ÌgBPP}‡¨üÖÊS<¦³ =a‹5þrÐÍAÉ]E··cˆXw\Š1´™ac0]WëøoýOSø\ýVæœ#¯#±E4DCÄHèé@ŒÖbï¡i7¨1lXT¥Q&FÈCV ±6Æ›f’J¤ƒÿj*P´Y¶Oà9þ¬éšq·ß›åñãrÌӛܙïëûpì—A¾öFþÞŒi|œ-'Ôl³D±€œçj·UuwåËu¾_…ãŸÉfºòöWV¯Ùãõlò:ŸŸëôeñÖ1ýèæÕ»ê(¦áLS·ñþ>ܬù±ý9Hþÿ<ƒ·ˆjÄU±Ýmù}Zbçvù–U²«&¸ê²·ü³×†íú¡[GmC……fŸj#6#Ò$pçwÔ]uGÜ<Ý~ßÓø¯Ó§Ù£O«¸¢Z„xûþ#%8g#65U6ü;ܶ>®aL~ØY¿w?VPèÁwÙu~Uwö¹\ç3Ü®“šÀÂÐÃÉÑkøÿ.¬&5)n—|?±½¿>¯&¿án®nàM>äM¹¬ý“ûôwL[%û"ûBßæ<ëά#6)_@è¸à\S¼|8¿ÁéÎØÄÑ›^F+rEµh‘[J%c§l”õX*5¢gtõu¼^´yçœÛÆ9ÍfRÉ¢((Œ©[\0°Ä£#6’ œÙiéÈ¢ Ôch¥b…€È£°µÂÂ44W VR²ÙÿÒ£FÁ÷R\æŒmFAKTQeBÑlB†#.°Q’ƒtêMæîy3‘wä%r(*`¥2ƒshÙÀXœ;Ýg6®¶JhÇTChÆ%™8Ì+:ª-!ñiÜtu,¥µÌà’‡#.óÅ!ÚÐ@AFšþ§YÙ¬†žuD³Žmé¾#.äQ¡±‰‹$I•8‰ì~UÒI‘#ü,D¢Ö–%\ȪrF‚(3š*ˆÂ®ÔÊŒp#®²R1Œlž°b¹ÓòJ®x3¸ø!U†$‚’IsJCÙõC‹ID&é½’ôAŒô;/ôôÆNô˜}€Ë ´íäë-ûLH ¬^Þ@ u3ÇD>Õ÷z“´ö#.QùUôhÉz°÷ý”OT=¾÷góxáˆ$g±S—óPü-ΊÃáÉj»#6ý£×£ŸLPL*ø–ý§f¶£Ô§ü!½ëÉ3§F9–û§ùj~¸îîh¨xÊìƒÍcÔºåøËãïÏ›""'NõOU87«6«üVûú„ÖY´¹ÄÞÏÇñ}NO#ûjÒõ@Tõ¹€â9Øs‘•ûÊvA#%_œï†${Ó«”ÔŽVì6TÖÙõ¯’=óø~ç–{àäm·l’_/ÊÙµÇÒBÐ’Ä–'Ÿp€âqCó9Ë‹è‡æ÷¯!üyI£×<³ì©«.V|¾ŸÇÕ!‰æª£#6u¬êyÄC¸î'·>Åþ¹õüܯ±öÝAe;6LèǨ4«9ÎCH¡QH2t2˜wT9"+1r_uLUv¹ä“h—ì¯F¬ÿÂÅê‘€wf\„F±>ž™[î÷QâZ%T»…#6ÏÕ¬ªŠÿM[hÅe”£$#ˆÜ‚±#.D¿ºÅlÅ˦ómòØÊŠŠB‚YQYCFF¶Ï7®_ËäÇÝã³áê_{HUuí;wùüÿ§OÉ“Aó¬º!BAT‹‚1žsa虑sÊ,¿] WÚh&6p¦41-6—·n›ÑHÚ)¬1=j ±o\ËA„y©Y¦=Zﶊ°Ì#6Ô«ÉgAèpE30ËBƒH¨Á‰”V¢À*ø¹¢hâÒñ/mˆŒM}RdCÝ7ˆÌy#6Ú´s¶jdßå$ –8ÛAmb{€„&‚ãì͆¬o*ž©H¥›·86AUƒ„Œ‹³àrYb‘ÍZ¨¬ÛÕ§hCZ¸ÆÛ…‘2SSDÍ#.H#6J lXdL1aˆ4KDã#.‹G‚í3³u#.Ðá1¶“¡×l°lôÝXÊ-“m(Uz§ûÿñhÉäŽø1†µ—š(UX¬0âØ”©DƒlópÈ#.Ìi@¢OlƒÂÕ·åtS¼'Þ30<sÁ„l˜Pt⢲oŸ»ø¿“Õæ#6” !B#6‚-ê»o.O‹„6öÚº<AÿlqgºŠØÏwìèõfñf4ÙËÆbýÖ}æSuƒT0Ÿ‰’‡44V\áÿwáîÞ:ŸÙìÛé{yзc•(ž~Qïɨ<Þ O û‡Š¹ñÓͫчJt‚zAíÜ'ku#%ùšÇ"#,,‚6űaiUSõÒªˆ4ã÷]áv,ÄDjGH¸¸ÂðâÒŒi§O®|´°Ud—N¤G#"DÔÂfýV5[ÒDê*#.m4&’Wç§(¡ßÅÆ_ˆt5³…‡¥ˆ3MéСÅA!ðy½ÀÐ’ÑK¥¢#.Tˆ£¡·ÆóÌU:¼]*«EPˆTå·—ôùdì×k»¤kmó0¦T¨J5Ël$2~ßØ?sÏêê¿g¯Ì:?.\`<<øâï‹«@»6žñ™>\G¯øøJ½µ`CT<ʤ2+r‚i÷MŸ„š -+A‘¸·Tc£´øìz^Ƕò—ÅG=Úæ4Rë«Ùî65ÚaŽtHÇ‹µ0 óF‡ÞG[q·º¨ÊN𮋳 þü¥ÅŸ™ˆ¶<ª¢‘¨6Óˆ®Ç!#6^¹"XÞ<(²ÀÐœk]o3ÆÌÀãH›5KœK¸´pLÊ,°¡+&°,”Êp#.#Za¿*V>#%ÐÎýhÂ8p™˜Í†K§9æe¼‹õ².l‘m¬8ÁV6>d4#±C§›à¶——ÔAܺÉ&Fèé ᦦ€¬ÒKbíV4˜Î Ø=ÕÝ ¸Døn$DN÷»A£PÓŒ+gb†XÌ‘Œ®çFPá2-îc¶+Pƒ¥ò)2ÉÂ2™+ç*³v»ö—w?Ãzwò_Ûü9ô[ß™£oƒ×ûiþnþAý— èyÔÆÓýb'j¼ç3Xtß1ám¦,¼3êtäzÉù~îìa#.6uqöMÛ‰ó¦q9°gì,ªÄÊ;÷ ÁÍS¹(v-ª ù`kb—ô»6ßV۾ϱ£)‹`åÈf=NÜRäòAUHtF¨ÚE’ëž1’œÕOSxWxe¶ãjh¨ˆô©Siyiºf6äÜ‘R®©n1v6«D˜E¼ Œqì’T'wÜÏ€.›gÊh#i™£^ÞM¼h½óé¶3`ìQ±q’&Úri3haÔ”9†ÙÆbX±AO}`PwÍUí«3Û¡~ÕoÒ_ÇúFÅš°¤<N=¦,Ü9}Ð'pø”F_smŒÕA—#6#.¬:M³±¸Œ-µÉ°àzÌ! 1IË(Dâ8ìMpî@Τ2ìl+ñ"V½†Üq·ž*t;$î§iœŽ¨Åo›;n3†Ù†-ÏŒu#.põQ…boyN×?u°ƒL…#.¹}#.IŽƒM¤$Á„ x¶ï‹)—Ï®v¼îÑŽ±nú¼…Ë@:kï¯#.K¨iccndë‹ÔªÞAåj«[É•P]ÃK©)pU7ŽUØ"wW;´ÇƒˆÁ’ß’ÛÄ!ÜÔr7 •JQoùŲmÛZé\¨ÂIAƆàˆQÞ#6:26#.Š]î;ñ´ïC®â¶£¨ë³º ¬›ÌK%c¸Tnq°QÍ峺mñÙºâã!X ÷Ðk¶Ö·ÚåÇF=ˤV¬v„NŒSuÕÑÆs'&vl©”4µrÍb< vj—N›19ÆbÉÃ"°Ë0NrcZ6ŒßW$œãdŠB\ÜÖŠëwl#6Ó¨cÇ.Ûldå¤É6µ&†Dm<ÍŽc/³Ür±±5ß ÕoÓ:Ù›D$âoµ}ä«‚ÅÇy溽<¸üþY·íhÕŠ@óμžKaNâÒW•GiÝ/_³ym§,qGr0÷GÂÜœFŒDdªõç›V׆¾†’¿òÜdIÄäF6$ˆ«,Ÿ©…5·\m4üŠb-ßöÐTM^í¶"R§".f哽ÿ¾ºáwu…œ¹RM|an‰¸ê!Ô¥•“ÄAl©·KÆ<F–°´‘¼)ÁF§P6ø¤,½¬-®eß4ð¡“RàoNYyÉ\#6wæïÆ·¶¨Å€ÎînŠ,ÿ…ÒÛ§Gt•ïŸJ“L˜L™ kÞ8!ÉLº÷m?oõxtîåöÅa^øñ×4@üÃe¥ŠnÓ8¹búÇUÖµÕim;'Âyƒhz7,íÎ+¿‘öÉ«þÇyDCá÷˜šT–ToƒÁ89I°šY¾ç´<„ß\±`%dn½;,ù²BÂå68ãu6«7“Ž'}ÆôÛ^÷–YtNÃWdÓ;=ä/fRͲºòc p®FiùUóískˆ[áü3¦†¯²ŠŸ77И{¬1F.™LÍÔ4éç¤<³§n#%·SœáGFÓƒ9“fài©CÓzÒ¯,6õbi#6‹aÝì®îÊómàò7ù¾ÅÚOf#.5Í`ùfz×¥q„aôËÊǵ¦ô»u×[AŒ(g×zÿ”dÅGߨrt‡5:Ú'à®üc´vP¢¨$‹ÞìÛ³Fáàtx‚‘Ãù]L@¢Ùù›¨öVA¬^–yw†17sŽGqì€AÙƒ™ÉdfÒÒ_—Ä£¯Ãó7n·hÓ'²8u,Ü.¤ñyƒ¿0t¾óO`šD…Tò#63ɤ@ºÃjúP3‚<#.þ”‹‘FRØ/(?€7óGŠá:ix¤ú{¹D€ç#%²yþ¼#âôØž¢€8‹=lè{ý}å¥r¸¸éñ¾Šáç\Íï>’ïø2Ý䀹ÐiߥþCÒKíWnר>áüpbx_9³å¬×WÎŽ@žTÛBðÑŠZ·¼Bì–”b>ß_§çcOVz|ymx#6fǼYJ˜…²-™Ê 0#6@ŸŠwßwvOóÓ®ËÒëÎ!‘Þöƒ‚xnpŒF€°Q¨#%Š²ÝjŠ«ÀÎÇ·e#1T˜´ËRV¡Ö1(3‡È40° cpç¯T‡ô沪ÎA›œÏ¨9zâ"3áÅ‚NÇíí<·¹“ycÐœr—v>óZªQà:¹ý탂%ÖД~ND|²EÊÉ´à÷Ô%¸< &ÙÚq4öÁ…)UyøèÌùÿ_ó–Æu«޼?ßàzg nõ¼;qËô;剚ރ†Ò„&LÅSå1ºúeÃyg²)IVì–\—.B„m0J°þ’[qƒkdÅ°ó#´-©`®Rb]8ð3ŠÏcÝÇÊûO¥Ÿ]ÝB“$ÄKÁÇ|\ÀÈ›|jÌÅg}'ò$j•a±áêȵ¿<4Æ=6=&¹|§‹ð»®6…]ºÔOvé¸pX»Ü=ôTŸÖV*yumžì…+¾â1e¼#µöÚgDtž,DãFQiwqlÞŸäÀþµ#.س^O¢ƒàô.é¤îÝϪ’‡-ÇIÐ÷]ÔAõõ…îÆQ72„I8€ïxL’joLk.ËŽˆ¢MDz=ýtï&½ó:oŸ$48;!Cªpóa}j‹ bÝ›94gÖ|«¯3ß½›µ4#.ÒOè%èÛÔØ¡ñ–ÓÞ:Î<4ÅôE#.54òì3R‘¬úTW-Çðk¥³øyçÈcUéN-<#.'çik“é;!:-DŒ¤§ 7)%#.M;î·$®ƒÂ÷h.Ø–CpíJi“˜5Ðéï¬Zñ™9þ®ß#%ÿ‡7±CðÉêpC ‚Ï#ò‰Á´ð ü¹“ßrÞÓ¬Grɧ嶖“9¶šE„“J¥™Í•aÕ…ë¶ú`xf¤-0è´%ùk‚ö2#Ž¼üx#.|^š:+Њ „ÒÉùÌÛS9lVŠo•azâ3!m²<…¦y©CÞo{vþ|eŽûüÿdQ茌¶F÷T½Ä½Ïá~;¬wÚjl.r<0XîÍ1`àžœ1ß¹iê1æйºKj„¶Ó§\ž¾¯‡å;åd“ý|†:ó»OeÑ¡ÌìÉâcs§ãò²Íc↛Zøô<«LÁ“QÖE-¿”Æa H•àòµ0·Nõ3\JܘrSs t UýÒ>\}[ˆìäåúžŽÞc‡ríàXZ.ê,¥¯Ô#Îfi?ú'î¤è—DÁµÊŠ©æÔ÷½`£Ñ@ˆ¨úã´#6ˆoÍÇ~ÏhÊ0*Ü×ã:Ö hïÿKC¼i´Î|½_ðÍÓÃ_.¼71¼§½Âu"˜¹r—Fxô⠘Šç#LþÒ¹Æky™—óé“>Q†9¬€Àȳ÷›#%hÍÊÈ(²…Ÿ¨ˆž+fLmìßãh”}ƒãÄuÚŽŽBN[ëR fJé{ 2ñªA·Pjפ/ñté‚£YÚÚ$ùyPñŽÖ–øêú뢕‹@…)Õ§)O”~U$BO3âud¾‰Û1/5¿<’k«æ‡U«xd›í¬½ìu¶ø¦ta>y6œ¡™û5œÍNîQápNHèºeò¸è>–·D.•÷*EdÌn2,Y—(迃f—ñ/¥sµÒ›ñ˜D‰µÒ‹Óô’ÌØ—›Ð¦wN—¯®ÖIóíîç#.¤PBbÛV¦u]í‡Un=Eœlã‹·ï¿>JªE·":Ç”Ì[~ÊÚ‹Ä&ÂOš¨ÁÄ)ƒ%&UrfIJNgq¾aCF¦p—zP‡™†vß·SC…:l#ƒ:=ɪ/¢6<ç0DU¼F9‘Š¦îÅR3–}m¡ð6‚£y)¤8Õáà7Õ¿QúÜñeìî#$†ã\¦Æ§ò^q1®J=f3£ÕÍkÆÝ$·LùÎã{ˆ–¦Ö=Jì‹mŸ&@׆vµÑ|^m÷"Xî<ºãcèšQÕ¨ŠR„HyrÕòá#6̪\hlæÏ„„#6Qɺ*h9·¹Œ52g(eG=¦!ƒB-½FäÈ= *\¨½[=Ù4³Ê…ܧIm¯ƒÐŠã¹Fo%ë*œ¡açgþsé7s”¾›ð¤ß>üç:¶è$qCñntl ûÜÂŒ=³D”OåùÅ@à}Äýó;Â_+'ç» EFžÍÇD_½@Ê´Î/HÌ(¹%“üñãÖÛ~!ÞʨÁõsÉMžªG4E8ŸˆyKåÒØÚ„¾ôc6Ãä´ÜàÎû6vâv¥l½Ë#.‡g“t>";¢ïm¼Ùu¼,ÉvõutÁ=;2hä!0ßH¿(âÞ}´s^G ap%N=¬c¥çµQ»<dZf˜ÛêïÞWˆå—=¾ïy±[g|̉¥“ÿi¼å¤2ÖÉüLøÅ7Š¯#.¿n˜ßF0‰r ðI8TÝÌŒ·6µD$‰M/#6oñ@üјHÜ¡—ÈYe—V×ÛrÁ‘D¨ïDÔ_‰MºpàütC¯‹y°ý:Ç1_G’ ¦h.:üzÑÓ«‚“&~ÐbªÒqëM—N6kÕmcí99º×ļkg‡X3sS§¶‡–„ûtc˜¼/+ÍìF!ä÷øŸ†2xìåX?]¤BM#%èìùRÔöÁ3. s®)©³ù3F~~!Äi9þ×8ÁIütgHC©B³Ê @é›Fº×E¸éÆÉÔtÎxêýbT{ÈIZkŽšÎŸérÎ[J(7ÕZÇפґ–é½¥“°ô4%ngW³U¡p‰zÜÆš.D…c·Fó\Ïå¢ê ÑsT»f«ø†W#6/á9=jÑ´S¹e‹EØàö¹ÑãÈB#%ÈX±uÏÊÖŠ¬N,&6#6B‹õ=p]Ù#6fˆ§|:×D¹aêF/þ¿©+6Í|Õ‡,2Ø'7;5mÌ©ÙÂû]Ü`x¿2°²kŒ\U_v‹¬X)æûêëò°,àµ{wï…ñYžÞ%åq\jµ|ßxèªÌÕ,`œRWn²Æ°øÙÍËM0º‰ <X5…U’Ûo6<-¨Ç)d^÷Ýb#%ûðçÚ°Šò”®[£±õ¾·>Iz]¸lð«°S·#6eŽh´³$'°´¬çíHf#6^Uî…Ѓt.‡.k„“¤ö#.п4âî6zÛXÛPÅ¥½“\9šÛ1mðR´t}yUQ¯}[;î¨Æûáožs„˜-÷À•<¤¦TvZ§•H¤sÄ•éïã寻Ë&?Áß™Æf}ôèÁ>WÞ³ÅøÕO‡Ùwbe'½øëåÆqžçŒtÕÑ_I&5q¶–"æ¹Öçgõj2àE°™©£•½"*[WÕn¬2¾ëAá¦ÐM*’aFkmö0*áe"ë²°I@.µq|ž%hy±gt>›ûõGÌ0ÍxQ“¨ZQ]~¹„…LfÏ9ÖÑhjÀ’®“'»YžtX?PØçÜôTðQäj?¬½Èo]YQµfÐ[DÔ³áGçtP?ÒóèþØÎeϤ;ûmð÷\ã4•§á˜‘x§5¨íÍKèÒ@¥ÛY ü–—°¡•³([¥uã`£„"ñ%K ¢%b5j!®#TRé,Ы©’ªö`A¬5w,åu1ž…¶K#6¯uÌÍ+;¼òzÜÇEºâko¡.¦ùÕÏVÍ߇Ç>ëä(úXòV÷9Cg–Œ ôuª<²w]ÇÞ7ÆðÛþë+™Þ#6–~J¢ÖÞož8Ð#!žõþ³PJ†#%)W&8Ø9¢/ï•®Îo7v°Ðv¸-õ 6âm¾Žæ¤C+«WA’z)zÄêéVµ{„Ñuå|NÉK›¦Ò¥tßËòܹÆ"‘½E¦/séÑWa›Æº\T:Ü©ÝÆðñ#%̹ÖovJ±$o¨e›@„¦ëtLE#.õHáÐ’æxizÎ@pžßyƒŠ¦M>úgŒV0P´¡ã/ïÚWFŒê ªÆê°ÊgR0y¹ö\÷›Ü+nS×GJÊÕ–^I¸ºY©}ªëÜ轄BÎYC™;-|ŽCÄDfVšsÖ#%Û5·\a?Æ ÖÖv•s>×_Òë5Fó¨÷ypfÝuÓÊ#-/Í\¿Tz>#»¸dqÄËÍKÎ{e¿"ϽFòæŒÁ³Áµ@œ}#6#6pÂi†1šIc¯1Ž¡òª¯ÇÃ|èŽIm'T\&IËlgï™´µp/jº~?†5óÎvÝ ææܲÓ5‘bŒ7fÓnº™N3[al@}sÙ…_XƒFÉÆÛ„ß'mÂ6)k4ïÞ',Ö#6Ö•KdÒUÅCÞî… £¬ô#6F6¡H‰Dp¢JÊ÷ÖÚWS€“ä²R²sýÙí~¥axÆ«aázß5Ä7¾m.mí*E¨$CAlæ¦BIm*øÒ¡ò˳5®Ø45ÖJ·jºï9}æžÖÏxôHü5Z¸QŒ<Wž÷¾»N³VDÕhU¡|ãf+ÏÆ<é¹v„€^-~]ðBäA`Äæ‡n˜ð¬W…éÒô>·W«¯ê‚ñ‘B¢(PŽ%¶ÃD7K#..mØÎLjئ+Ô,#e3m{wlˆ4º/}úî}¼ÎYðsEÞC9H2ƒ¶±ƒtflkA²´ÕM1‹C,áî…`âl„™Ø±„ëkù´OIiN•}¥áù#6nÆ#%ààÍA^†³(ÆÀl˜!Ê.±o7Bù[8fX»HíÚ€Wzò2ÔÕså@ç¬É“¯ËjÎc¯oN=,qkóPxÙ¡ÀË·qÊX8~ =Þ¡O½íÏ’‹Ó¯tÌqÁ8=þø´¼Âžûx–’ÔE†@é#%Åmp‰•‘ÀO˜NÐ’³Ïaj¬ôe“³ÊÈT†I*ƒxzÊÔ¢ˆŽ4äãlûGüGþÞtОq͇¯5K¯ìëâì·VžÉxdÔÊ*Wž6—XËSm³¾‘$ðH/᦯°FŽì¤øS‰Ùà‚<?z̈GP-’;yZæOµD5Ë·gºë«iTÖêœÏéÄ2 Á¿ryº~NKûôøÌGˆâkgÑêv|¿Wç—¿êþÆú~xøLη²1«¨\8û}ÑÓ®ŠÌW¯Î6—¼jS…;TǯOmæÜuW<ß±©38z†%~çrý·–›ÙÄ¢3̦ۤïàåq^˜—úðN¥gÑ'u±k//u65—>Q²{Æh‰e!wº(¦±Ïš]ºÈ—c!‡ïƒÂëOZÏ_…ÍÓy©1L6ðéšP¾·«>ºÃezÑa¦ö_j¸ï©~Z^¢iJáÝtQaè[›9ò-QÍïäzí$o“‰±ýL—÷æsaÕHR1€ÒTÕ ×¡Áâè*aæu®|b¶ž‡µïææyÌ„…Ä“{Sê-p5cÞ§wsÕ_L›ÜÂG‚›ËÖôöû©åŽ¿¦àc}±Œ —«ûû5I³©jJ#fع¾”ÎM$rÂKLîg¡sß9a--JÉ–,°ã¾›õ½`¤Ç|ír]xä+n/ÑÖÕœELm¹‡˜‰‰›Èb3ÍO]aÓ(£ì!^\C᛽¦Õ-(r"„ÇFgRÒ¸nXم꣥ü1½„+/!“ÆšÃ6d#6P ÕdØIá‚ÇT”ÁHS{ÚÔbÿ3Ÿ1棆…N¬ù\¤ë€`- xŠf<Ž3·¡Ù#6 gî®Þ|Ûc$âSâ¹@ág"Ä ÀÝ:9Òà»Ý.mÚ†—¾|×[6âjžg5sÍ¢ðºàÙ½KÚ=WæˆÐ#%U)Aµý³MU7/”Îà³E³V¶û³õb>|ÔÔsDD°#6T2À¦yÁq¢Ð²#6èü¥ŸÒk1~6ñ,ŸÑå%Øâèûgû—K°¶ˆ"hÔi2KúŸ;e#6é f¼¬T¡ÅX]Ó¦h”vÍÖ°NZPqîWP¦õáÐä²I¼|Æág¬í÷ži ã¢\ÒªÊaîa·Øé8ºibP» ”Jr¬ÑÑkLØ0óöÖë¢vÝ\ê£q!ö•ytŸØ :÷Ôܵo‚û<£gŒÏ=Éo6¼IÞbì·låHÜCZýn±ù¯Ö7Fn²“žd»Ê¿_¦Ö„VM‚ü£cîƒ:v¹+F;³Ü¬)&#.M—'ÁÂ#.›Ë‚¯£¶Œb»ÀYÊw:$ƒ†±å½À=ëZ×û°' &hhmZžñX\Ë,€ÊŠÙ9CÆçò¤!9¹0rÊÜ=ÞµmŒ©3¾¶[…ƒ¿è‰ZÁW©TƒŒ·ÈÞÝ+(a19Å‚‘Ìáë<¥Ñéæ¡ÜvÅF³Ôè©xñ‚è~ÅGÁB UU(;}ný½º¯œà•Þ¹™Áµzoô]4Œ‰B:žÐ=.®atÏ$³ôÒeJûœä™í` r=q`ÉiCÂJ¿ç¼ø”D¡ùâÓÁ#.BY`œ‘åfYB¢òó¿Ay ±U /v¶ /—C—3¯¿±òÔ$¬sék:!ßr=®.ê«Y8=}«œ[SdІ*„¼¡÷M¹õ(œö´¯RÔ˜xÁ5&œ¾GÔ†¢¨)´èÉÄp¼Ió{ ã™.xGtÆ¡žÿ',©iAxdÙt½×ôY»7ÓFšs<dçWÙÕÈߣlõúÅ`)N}ÊèÍ™fK¸H™}öC¡ó"qÝQ†™/Džq×hÞ%Y“NuðùËûaØÓüf6¦œ‘O}_+Ës$õÞ;œöçzìm$$L·LÑáz¯bòþøËžš*'%$i:tÙ™cŒ£yªâs‚–Qi':-'‰™·(Þ`„b6†<-‹ã8ž¨ó.£uÐé¶ïËmòÚ]{¿ÜÞg·j9 ¨ š^æJª'ÎæÀo}Ò‡¬ÑÐñD-‘‹W8g{Èm´“ˆqná†êkÏZ9æË9ò›ïŒùÖ, CŒü`ÅNŒ`[£½Â™y#6Z=Ôs'´WïÏ'dë¤\¬ù¦¯ÇUÖ|MÛµÃÑŠé{ùËzürE÷õntœwšæi0²J:Ìñímã¢û åOäzã‰-¹|o)#XÔW·—>ÅÓÐs=o¼[DØЂunÄ2¨æƒû‹`Ü1˜ÛNAö;ñoó$³¶‹›¸x‹<¡³EüqÊíêK‘/–¬ÙßbÐK¬„/aÑt÷h$&c„%n×çl#«'¬s¹â™(éT¿·iاۤªËò¡^v*ø1Ö.)òFÅ<eZÝØxA)³NTÿ(ÃöAБ?”>?NŠá_§X#6ãûbo1QìÐb¼DzÞÒ¸Û¾nB¬htRߌM~Þ¹Ÿ¼çhæ>(â= 6º†6Mº1@ì|]½fÏ.×ösÛž(õ::l¬züø³jîOÁk)¾pVzקk÷û±jÔ3pV×>IÎf¥$™Jý€?LV2e*¤Xpå¹³‹nžÈ(#2òY¸zk0Ö9êŸ<õ-w¨õ°u¡Íˆ¶lÂnIv(˜"`‘îTaŠÙߦ:b×däB®zí†GmÚå»#6õÈyh3å„Œ³#.¡™Œæó‡vÏ=ýB´Ùîïj¸+8;å>N¼Ù8›dÃøݺÌu]:D£~·/Ò®*©z½pIs>•Ó¾Ä¶7¢ð¾ìæ|¡Ð.ÝC×o“ü<©Oz¬Û5*ôÚÐŒ}&E§xãÑŠ»ó!½SbGeœžFI-ÉU#%¦$Ô³I Ù™lM,–01Œ*Fe`÷ S~S G>»2@×ã¾~ï3¬ZÂË/ÒsÛ¤¸zµkÓÆ.xï|~ñÍ‘•D¤#%¼Û鮈u™¯ÍÐ*±§Z#.ßËn¾‹€P>¡…uxi¬ëÍÔ¨&„'a¼S9—2)igkHÏíð|·¯`çÛÜ¡à‚iÖÉÛS{Æ`'Œ+æU<:êI,öæÙ7¿_ǃVñ5î‡O/Iú~!®ìàœZ§ºÜÁáÈR¸÷pùqyàì^Km›ž$?«ÿr¢‡u“à;46CR;,VÒ¤èøu'Ž/•0Î?í5¯{íÀ™iÎÚÞÜsü"Vîu¾ jOð3ˆýKÉOäýN“w™³ª¯ÂÛ¦/½6¨ .¡#6×X”rpÑoHì~!ÑRKz¹£%dn(è)!ëßžnÈ€r†lšÔˆ£§‹G’ÜŸ#D’ÎŽ¸N5›çþwP$È~žåtÔŸNBeåkµîM„ ‚ÏÙènæ²1Â7_êÝóÞ¹¾?5õü;{Óº'àãÕøÏŒ¥¡{ùq(#%`@)ïõ(õ§áôáÔŠç°Ö9MvŽ#Õ(JL+G;I@À€ðèz¼xÔ¾(H)æ„gëxTWÆ®òØ]—÷ào»ýEkù©\ë¹lIi?K¶Wò¨Ø”‹Rm“cÚ-«®¯ñþ5ù³Lˆ–ˆ…>(2Í›ÊþbFmp–ß‹gË~:×ô@ß4>$Ë_#p¼$’ŠÅ"‘AƒY ä&©×‡™z½:œžÛ¬-&OŸÈÌySµgÎ]–ÜžlÈþÔÃfÁõ¤™^¥«Û¾÷Ê“Ao¼?“ñxüGŠ5‘ý7B÷ØH‡Ó\™ü¯íN9†1‚¤IY‘[Gtþ#%²©‚¨qHTi*7+¡þÜõÿ—‰Ëò?¯YC‹‰xþöaÏ(¾zÿ~[Ûá_ÚÏ]>Nt©"rNK(ö·ËçzÔöKíˆd¿»æïžðù´!Ú‡Eá¹tî›V}ëªÚÃÞíèÝnCiü˜]÷ùY??ÎýŽ…ªz¯nÇN¶:*F`6$´t%5®Ææ󳃊\ª#%±|´ãÓ¹ƒþ1“ì?£¾í/ÒÊY¡°ê8KË,H|ñ“‰"~¯Ð©¡ýj!Š#.K©wk|Yž™²äèYû=v&‚Sú7åí}f“›¥h¯P#6ªÌ·Š Ϩ:ý_Býš>¼•s<7E‰a§VNKÎõú]›(ú¶ÅÆQØ/ð~¶w+E@âõL›0½Æ\üƒª"XÉBÌÜ!œ?_þG7‹L˜zß„çmßÂÇ>¯+e§m¿—Á÷¡Øf c(QÆŠ#6‹"šýu9¡Ñ#.P?KóO¹ êL¥09]#%n‡?Ÿøí®@¡/T¨#%ž½t xÎè†"RµœKš Tg¹‘L°ÇJæhZ‡\j ¨µ+r¼ Lt#Èæ"#%oŽŠ®¡òËÒ(~†—ª#%¾± ´é§ëãcßÁmÃfÿU#%èõ@ÝEôÿR ðºØŒÄŸxi¯Ðþ•ëôBañŠ¾`Ù8ú&ØH¨Ù6óòP¿Ÿˆ€XøcÚi®à†í´ÇK™÷$qý4¹a‹ß-)Á>ÏN99¨“Õ‰5v8ñ:je`a"ÅeOXï2€ƒ~ƒZhCq‹ yžÏWiƺ(T¾¦Û¿ol|ïøH,ézþë–(`L$¼{ †9gÕWR|1€¿{ÕŸ¹Ýø™@Äyi<×Þ€ÿ$ïèLJòS(ò‚ýäOgÏIëŽÕ¥OSIïô–õ#Ñzüco*(B¢Êvæý?Ít,¡xë©TÏ[]3«X(~Š¤ž©R”#6¥`UMKõ·;ã6Á¢(ܣ؊y·½?=ÆÝа섀>Š©˜aI\öñ}V$øÁ4º2qÇm¿Êe#.fqpÚi”ÌkZÔ·ü(b§RfÌ%ݵEÔR1#µ¤Ûp2„‚\4SywE9gŸ+ìôŸÐmÒü!Œô¯#Àè€ (&ë]Ì#%¹Öië…uQºâý:vêÙ®¨ÙJË5Iší4ôýn½2‘×m’pŒè«¡ön³DAñ|],ʈ‰[#6Øy`ïÄ#6€ŒPIµoßÕwÊîŽ,ßlN¹¬ç·Ü"‡c;þú†Y³:=Ÿ±Z&W¨å#6‚Çf½Y¦ÈÈ`¢ÃÏÅ3×8ÈŠ7K±´-•T"EÃvÉFQ`¹Š\ÏP.Dp1C¯f¶Öoe¹_}g¶âúà«âc'‰ŸKš³’T¢©Ö¨`¢XD$¡›\æ#6P8ÌüøÀ·Ì£€¾ý—tb•ÓÎOIan0aÓÖ€LŠ bBç#.°‚ ¶ö]\ñ²òBET dØÇ(°so¾)g®Ñà#.4FÌ·e¦`1ÜL`òyJœIÅG§³Â¥ô ï#?øYÖzKéÄ2÷#.ÍÔþ:·Ü7ÃßüÕaÖNQżÿi˃2}}Jo£Èú¯.þ³ÊÍýÇÐïL_fs@ˆvô#6€Ä¥Í7–;Î_{Éž‘Fy"]yXºmý~,@yÆNr+(kîØ®™ñ3zL;,Ÿ"ì¼BN3$ü÷>åq6׿yðö]|'<@¶HZ°¦ „Ýè[ï*¹süÚÍæðX¤ßï”@¤U-0žàeœ‹{¶Ú3ÀÂÓ“ƒíTÆií’7q¢‘I¼y»Î…—'íýVç?rÕëHƒŒõ!d=1#3tÿe–®ÎÝ~AN{º4N¡úÓ‡× ‚I5Ù(åtD# øŒ uÕ™Ü`ÔQP+&Ö—á`KH³ZŒhð!É î¾ÉA ê(‘e<ýd’¼þ½eý÷ímÊ5^äÞ¢)?̸Úþñçš–6`éØÂàäâ{î£Æák¼dVÔ™2S„Ä;¬7ÊN¤@‘`wdÃ@à¢`s¤˜á59—_E·OR« _ªzŽq…›Ks^GlÞ<ЈŠ¹\¡±BÖ³žBdF&!Úë\[S®~zÞd'¼ˆ’¢$6›ÒÙ¢½ÉŸ6NX |¼¡AÀ(噘øïÃrã;XËq-î¨ùöˆÎrI{@Î{"{íLÕźޜ“5y\ˆJ‹Eã›%9×!}ÞCøI(ès=>§X.~Xp^‰éó{ì¨k±âøa§Ë%–&â’’Ñþ„Ww,/òmì¥z¹€Nãõ‡5ÇŽ/mKŸ¦$jìá +ÓK6L²8ª~í1‚o'š\8¸`À-€ #!C<×® lˆá2ô×8ëõÍÙXÃN¾eÌü®R«•b/!ö¥E7Â5ƒˆpdp«¬BÜqÖ;»8]c5Ù½= L=«ô7#%í¾XžïÃ%3#6‰¥,4«ã¤"»¹¼±¦ÿò€uoŠ8‘KÔ<׬(¸§E¤;UZÙÃoXÍ:I¬‚ßMejyyBþBœT¥îú#6=‘q¨<ô,;¢ qÌ·¡Lá-á¨rjß~Ä‚=%³Š¿uû:RcŒ’x+#.ÃVe(Jź•¨C°×¦m"¯ƒ‘1IÃÉ2*˜Ü¼ùÎÔ‡FÆ2…?Ù0¨k˳ߔïÚ?Éðý\ðßCc£{ ž±¥õ‚>Ô儯p/UM†óè<g;e#6,Û¡¬…(àÆz¶bâJ ü¼¢‰®:…Öò7ã œlG1ÑŸát¸ù|±<ŸXÛ'M1çIñà/T½]‘)œÏo9ìð_Urb,ˆÝOèL{Sá_mTܶ§ã³ZY:Tú9°Ïo¿¥ÁÆš‚³(u™l;g}šm@óß‘¿²YµCfMjdÕó<#.x³:O)ºm‘÷/·ú4@[Zô’;Š÷hÙ‹hhP¯;wœìÁÒ‚Vñ¸¥_F”m¥?ºø2_P|M9Ü©|r]¼½–ko{†<x–rÎdLf¡œ,z7±¿ßg>îPxÝ,lû5=¹‡™ËJÔé{CTj‚Çh÷ñ•bìãšc°«¾DƒiÊî:L™$eR‹I¦ÆÚtî×ãÄtç)†¬ëÈß™·žÜŽÑ~“tÔÆã‚Ãœç£#.p²†}wÍ)@))ë 2d¨…t‘`!.3ØYbô(%œD®‡#%ûtdb#ŠÐ7B™Ê©—Ÿ'Ø«ÁYúcþõCµg›ï‰îé¬ÔMRaÿ2[þ4¤ ]g†bÒ•»woÕNÝ«Ï,.1D¦•XËûØö¾ÛTÓ<’€5ÿ'ƒË.¸¿¢ª×?Øä*£b¯iöÅW-«cµ@UTÙ #%AýJÌ#%î?øó>ÝÚô¯á[íê{}¾¤aªô·ï«éE „aûÄEÃû(ÈõÍüÏŽðÝøÉöý–Áä?²ÔðNšxè`ß·¥"lÆPÞ·G?`lû=Úø ®j¹Ë—\ॣ4ʤˆAàP(AÍ&…à¾Ê0Ax2E¼«¸Móˆr“¹Ù2I#6Q0’D%9èÀ÷¯0(^Cg~‚ÁÛ•RT:F¯gŽw÷Ù}}v®‰ÄT$/d*>Q¾•4C´ãÝÞ¨¦ÙˆÇVÍT«Å„Kv#.ïÙÊ[Tú_‘üúl6q™½„Ì:ÑAéé-‘¾ìE.ôñ x4‚à‘†ŽÎ2²#.±ñÞ‹|Â¥ÀÿóääqÚ¡K¥Èj#Åìðý3˜© 2r·2¢ «êÈš#6Óù¬<7ÐêžY’Ö1Ö‘$“â‚Íh>GÛTÌx~2‹ããéŸÊô@‰î*%Ô39hþZš[ÃÏù`tgø·Ø’j«Úcü© Àïð÷Ãz¾ô! °,¹f°ÇÙ”èd"Ô@„2 v¨0é³k(!ïh[YÙR|"€h/ #.(³(00Ýú¸ …˜Mm”°¶>˜+dʈ¦²’ÆDTKƒ¥ÊGE´@ˆÅ2†.¨&c¯u…ù8#aj¥6MIF›EÜ.–3+ˆ;bÁ–$K*˜Ù’”³T”HBn|4D3Š¿Á#6Ù½3¡ç$ú{•OôÙ«ÂÿHô³€i"Q`UK‹È–…s;$>ª¾5ñÌP({èlpùÈ?)ã¨,ý¾r˜b"Zô§KA±Æ’;5WÚ˜øO´~‹Ë~ËýOî„Nâ¡{Zc#1¼¦Ìň…P'OäŠ)Ï·ž±ŠÎ£¼M!+½E>÷TöƒÃßô9¶s¨ÎšÞ?—ä#%“`cnh?½öÝ+ŸBGG%om_}Žþ ¤M¼Q'ÀwG«ÏwE&h¢æÝnï%óªpmœÜ"&ñõëw&©$·)¢rÛu©í³Ùí«ûÉíööñp)\uÆUüdá{‘KãqÚÛãE¦é]RÎ*8#.ñ6lTxÌ2Œi†˜§DéÃL©Ýåj22JË‘ïuPݹš3Tj²‡©ÿ:§Å¦%tCAç0Û³ô=f[ŽªŠ®Û/0MksvLoTõwe1ð C¹{…ÉR‰â_qý“Zk‹ác>Õaü¬ûìfоáÜlJéæBBé€r'·;<[ŒKå€îñÛuïºä±f’È«%3J„a1b‘{Ûì=G\‹ULj#ERX城ncsÁÜr†sVÓmš;ÃX;MÆV Š]±#.Z²·›mÔ2$ †g-$F„ÄÆñ žLŠ%ð.ª_–L©§Ç6íßQSÔxÝš#.I»!¨œM#.”F×Ϫ‡MC€êvB¶ð#%æ!qŽI*™Øt‘§mŒå´Æ¡t:CÖ\$×@0!ª†#6%ÀB‰eV‰7vd”‚À°ò®cÀAÖ©Fvt×FýeÐm6Û¨ëô_^qöÀ©3_éävjᙎ:¤ö7T%â#.aû ŸŽÈ3ÅÀã#’Dõ<d!'š=Ws=Ñá"ƒ{Üð±ür3‚»xXããÑèL“#Ì{ë€FÅ0ñœ“¹<ït²'ö(v²¢Uº¥\±ªÞËs[%k·ÁÖU’ÖÅZåµsl›UÊ®’@ÁK¢¼›ªÆ!E T$UhÁ^³¢“eeÍq0Q›j„¹»6x©$ëÛAICt“×M4iÁ‚šŽ‘@ƒš\!£Ž{í!Êxtš®á™,ØècÄß“³¡x ltH±h<û“yî̯wy£¥|®3¼¥ðìp§Õ+4ðŸ‚)ÒIÍ ŒHŒ‚ÂE‘@;Ð4['H!³¡ljÁQÎ^58uä9^çSi|£E_¬ŠPE‹Üš4æÃixj’–Rd’F[ÏI)-|݇E#.ÉBœ–ÿJÖ¢}•÷Ø ˆ“ÊS0Ž+Ÿ–Zc8VêrØQ„5†TQ¨[u-¶*£guï«^2÷4¯yt£K»kvË_\h¼•G}þ÷{ÇÎNÍߨV I ’tU¯Ìb*ÂäÚ§’Œ‡VKðfá,#†œlìÇŽs·©¿®üwB1‹óQ”"¬ÝØÊN¿]S}|x×?¿ç=,%xo:!ÀI*såÑoÉ‹1¬J:ò¤´¡eÒB Û#.#%,þ$÷ü9g»ŸnòyϨ7#%&êuÆ$3â6;ˆ7ØR71)™¥‡Tð$Ž¸¤¶§#6ø¹!ÅHTZaH$´"%;úQҬ߃(Z„©"²(MPB0ÛËŽw@NÕeóñÙ{]=Üd[»ÁrÈnÀÇVoÔR@<†‹$„D DÉG׶·-"+joaÖà eSUXò'Ò‚ˆòB‚«ÐÆ,ÚºK•Ô¸g¯/7vj»ºRK]#.Ìeâ+µžÿ‡|½xzª”p®ބERÇ“Piƒg>á,üPCª†Ä{Æ–ò½˜½«XÜ©¦_=Þq¤¡A g6ОO¢¦‰_*’P!6E†3Ë87Xd]ä#6æmóŽ±2M#%áF³™k#U@T¢yÂý3Ø›÷o#ÖÉÐÁfÞî,Ü ›;èΗm0T&â&4÷5I$ÂpŽº~¶4Æ1ržÍ/€‡ë›#6íÙj¼wüšXëËh:nx–fø|ñLJgXC§ÒPt/yÒŸ¿áìÍørŠ#6°\ÈÆØÍ(‰< UTȵ\[#%^™H#.}qš¨ÛVFX+1á÷D¨ûºÕÓBà„#..”rªü‚˜m¾È½Í—¡—½Y]ŽZ† I„¸8ÓLÓA5À×ÏN·Ó0$ÑŽ–mÅ#6æ#.€Xõæa÷îÙâ.êôå“\ºHÜŽ9T¥w_–¥v¢E”F`0HƒÊ¡E%xÜÂ+º¸öî2<õç<Œ-“#.áê}›Ï¤Ûy£¶™ÙÜT[§Ï%)Ý7°40¶ãòâæÙO:§dXoY£t¢«º{{»õÆU;ªR%£D P–ÈÌ0ì¼Y3#%€Û*VÃØq@iãAF®L`àîë´'©!ç#´ ÏAVì#º(®RÐBVcÙ3±EÊí’ a „›¶)ÙXª`_€žôÉ X¸h£Dì;£Ûe¼ô‰ŒŽ'¡Ž4QÁJ#6Q`¹”(T"’@ çK¨ ®¬`²ÇînÆ´ÝïZ:uY¹í©ŸÆtFýð›ìÂ-¢˜RTˆÐfµs™K>÷Bo¾Hç¼~YÅuúýsPÓÊÑ¿±ï ˜9:ô–Y†&Û˜:öcU:çÙ›ëBûrÎ0º>È^i…[d6p;÷Š6¡’O‹ðƒ#.¿c>ëU o*&L:ÜÁÀŒ–.$ó³ôLx㤴»§Õ~àÂïÉ9Àë'tldæ…!¤1#.—@Ìäu*n&H÷QT*ÖËCî.졉=9"E‹.Ôœ+u˜e×̪¤HÈA$}á{;~æJ²\¨MâÔDF`aÝGnJB†PÁŒ=Ù#.“ݱâcL¸¡Bž"Yáî¢ýYÏÒj@=½Ï<èq¾í!É‹ùÆÞf—l¹c\ƒü1GVø¦l.o6ÈêûlinDµÄ®ÌCÆD¬ïÁKøµˆÃÖ)Uf[(8?ìBª± §^fÀ] tJëM/œBóC]™éƒ¯…è×»i¡^|ÇE7u[d¥g¥ÊZ;KÚ`¤ÆóÈ3;†óæï`n…節qi‹8šöדOB!2ÌØCP;Èä{Ž]¡GÊ‚¢¼È0†QvDÝ9¼‘¥ºËY=†s³¤íEÃBî4¶:˜vAèC2.û\•|ÓioÝv®ZFQ4ZOí²i2e67î1kÓkð/™#.§]Ž6@‘³4xÊ3töÕÑøželG•Í†²ÍÑ’@R† ]ˆ)˜NýþüueVL5š‡Ú)·é.´É©ü sà7§@4/:UÛ‘Ë]u‹C<äR\€wÂ'UWÞ:çQ“vbª§F†HRÉS©Ð,wÀ×ß=uÃYƒV\<wWa‘"ä¢wÕ÷€Èߤ#ö˜’®qœ”¿£å„.›#8%€vÏÏíωIúu-?µ÷ðž·8>ë2‡“Rª™MÄ£8{ôíåŽíxÍ]z¨Bì<bc«öz:yÿfáÃçG•ŸËhäŸbV…©÷b‰ ÒÖéZ‰Ù‹ÙUð%ž¯óè™Q>V'׿_ÝSÈ2È6½–_g¸ñ¢Öåä#%˜Æð§:¬É©£_ÑÆxÖyßÔ#%ŒÒéDÙ‡¯Š~ªJ†ó$ƒ?Ù~~é†8f>†îÑ=G/‰…Þe%A7Üüq,[Y§â¿o¹€b΢oªd¡ÝŠãà¶4€CÄ™À?Æaûý?ËÉoôÝÝã‰è”Ÿßþ$Ý6aH*2AHe,-3ôWðþ>—|ðoÃpûgŠrñßã‹jËntKç;ÓøÂß%ÂòJŸMY¨TßzÊüúQ÷óÌ<u`ÔáXXCWKqŠ_æA?žÛÇoMWœŒ*ôˤ,«éýŸ£õÿ/7ö0oöÿ‹Ûöþ±/Ý8üq¤¬”I&Éêe…UšÕωk›ôR2ˆXIlW+YsÎC?Û äÚ¡Gþ€€ŠeÝžYg ÜÕ|ÆÚ#%$Ç¡µ¨Ãhý››“[<cOgöNÚk¼Mbf"\ 0íÝ{PÖõÏ?oÈGðª¡)©>p?îüy÷?=BVüsɼcýNG8(´5Y‰yPYú¾ÎÞξ½¢jö«vÚÙÜ1¸ýË}+sk…6édص2½yÛù¯$Ü¡i)_?ï_Œ3÷ÓÇíüûàüéC6ª?·LG÷³û_Àȯ«ï5‹Mu¹=!£~*+LOú¤k2¨‘bÄ2ðÏVÞ 7üDÏDa{ª';âûƒ (#jº£ª€%3t»¬i×¥¦•A‰QÇŽ®¬2ÕYhqßž´w/ù‡øƒã¦Z7¤Åö#6uÑiM«ZÎ0—XL¡ëŒ!…9¼zóü€ª ²zYÏ¿hnÎHr`§fá5©¯N$fá"ßæßV Þ±Æeî>¥?ë.3/«ð>KÔ6½ŸM(Ÿ9ž—Ož‰ÊK#6=mcÒï¾´'ª¬€§J¦1EæwŸ³g¶ËO…õR—¿Õó°"ûå m"À„Œ@¦D¡È_ßØ_éú«ÕÈqè4é|Ÿ`òßR쎉+´j`ŠQ‰(‰âL”&‡ПK#.FM=‡3–ÿ§úñ3£I¢Sø¦Ø¥cÒš ÈȹÄþƒ~î>ÜþËq•U×-Ã^ËuèàH19ôêaY?¸NN·Ñ¯¨]ó#.—y·Ûßù `2É/ÈDÏà‰ê>Ÿ #6m*€ÕHç<\2ê=|.mcÅwž~÷‡w§`PòMêÆ9^Þj¼=ÐXÂŽfulDRžÀç,±þBpˆRH‚ú‡Ð݉™îµ˜)_Å®ðߦ.üîÏÏôúýà|Iõü¸“ò»ãšMJîëáEŸO×ñ"aÚO‰A$ÉF‚ï5ýéúxqçÐû¦„Fwd;zçСËÓ².'œgòêç©äâ|9Êlrå€ó×ê¯l¢:vGÐi2] ™³ @ñ¦Š®3×#M»½‹.À;Gâ¿9BG8ý¯ý\žŽý»D=®h¯^þòÖØøÉýò=k‹â<RÂÐäõ†©‹€DD`_êåî‚"xKyy‘+·75¼â]*ß:Îp#%"t-8¹j°ä €®Ä»ÓëRiö4úi÷>áú¿ÀØñ<ÎzüãËçò%LÑQû>\ÿ3pÓ°êvÇ1gío¡¨Ócj‹ÛÚï^ÿø½\¯:³Hr!i ~ZT×°-î(ÿL½þ›rø†'›™@Ù·Uì:k¶+cJ©Òò]ô8<Ãr¾É¹Ð#6È„Ô˜²¤ƒìüØõ^ˆcÕgqÁ”oTÔL#6$8ˆ=Ìò<Ë1c„‹Š4+?G£âòó¿x#.âÎ\ÝZs ÜŸ™ÀàF’)¡EŽhsŽ•ƒ.²`.z´ñò„Ù0öªÞÒʹQR~m+í»0†Ç._¯ÛË—ÑåÇC«nè5 ÏutßWv#60蔪Z.0òë𷵬žËðSŠF§NOƒµN®#.ÐûEÁ¤Ÿe˜ûøÑ3¦2J¦|;ìïMmQ³ ïºvj†x¼rïJœ¹¾Ý‘~“Ѐpr)‡c§~¢;wo«j£ï‹ïÎö1žsÑõñTh#0Ò!ãóR³UW•×}Úh¥bÍ exƒËá"æ|PH[ǧ:àJžäô/°qŒDC“×I¦™u„ÃGµ_z§ó8Xzgü‰Ï—N×È:ÎÝÓ¿¿x£aF÷›Ó¤ïÅø̺€["·½ò½ejøM†§Û™AéA&¶²¶®6)BЉˆ;XG꧕('ꢵ¬IB¬×(~ a{ŸÕpß5×.êµ55‡½.>#b·—´Þç=ÿ©]oðÃG§Tmü#%AÁP1@zsÍnál?]ÞªzxkÝ@ˆ2 eó*+hÛ:¬¿w›ìݩΆÜ~‚ TJ–^9¿ Í‘4hB&¨ï¿#.xbðPýÀ;Ô¢Ÿ^Æýú}¡‡›¥Ø€K“Ú}´!IŸ+ê@=ªçŸÏ@-êá)"„-±ñ³êa”å7&#.J+Ç¢ñå™ÏL½pæ#.uÚ…ýŸÏó,fƒò¼5à‡(ÌTMB³î9ál¡0á5ŠÕ’:¦s‡V6z=oÝür¼úÙ,åƯ÷~\Ý¿£Œm½ñW#úLv‘ÅÙÏ#.‚{£PP·6Ú).zEËÃÂ{ï»ý›Üan!Ì@ï\Nø¯*}Wÿ†±›þÉ3ÄÒS+ÏPhÅu·¯cãßm’ÙÓ‡Ú]’<ÑÒõyÅÕ'ëïztW{ÛÚ³—êøÞ`Ì«í-XLm#¸‡F—u¢ÓZ±ä¾µïŒÿ9S9œí¶}È8ß+äªnæÓ^ßn$ÊdE[Ó'}ìt”¯íøѵK¥Q´Ûmï·“mˆs³‡ñVhïU¹á _@6½o‡ÞíöO¢êCU˜sª†V“Ãú«:ÇJM,²tnOƒäÛ伎r'Jh±Ï“ªŒÁ¬ˆW•è*˜• IJŽTy`¸ñ´,xÂÆPèL*3(#.ÛàsÇÍ(Ç5Ã.wà~>>j;›A^ZÕŠÂ0MÆÇ¿š*vˆaFš¸7Ï#%÷Ðgˆ}lÌÒÌÁì-a”Ôƒz3urî#.œ‚÷?̶›#6!î8P¹òˆ-ã¡lÕ]EïÇ®ÎZØð™[¥•ðRӇºÝâ“H‘53û5qµ‘ÓÝ¥ƒ¡ƒ(¨*‚—Sv†Akë«Ü´iXE¦ë%qaÅn_–#%ÑEò¸ÙeÑ.’g}‚H#lkÓ>§.¿ÙÔ¯-º(ž2}T|pðÔ=ˆæ ÊÓm.C:)]úÝ«ËÛyï§ÌåÝÖÇð …0«¥7§aÝçYјóÉî®úÁž™ÛEg'>±Ež®LNïˆzûë1Åè§âßÒ(íÓ\x¬ëµÎ©êwƒõÆiYئóãÊe0wóÔ‡%<Gœz¦÷Z¿±a”úÝÊéFK^Ôœ%zd¿M½5:îRª®cw×{Wô©hØOú“¨—o¯œ¾½löyšâÍ$®¨¯zÀ0§mCÓgÀpP®¥hîÒöUA|ÊÀÝ!=yy©DzäsÎ9UI#ºêI¹#6ÉWeý¯gÍóz8V“)tÇáFöƒ®úBÜXöãfñÎþG|Âøoí.lì&)ÄpæôëøMSÓŸô5#.2ŠsQ"„—Þw"×ju÷5ªNþº7Îåí}uKfs=}éØŠzÚ_CŽ¿dlO¶¹²ªrú%Ÿ§Øçß#¤¿|*¦›góßsg~®ÉD\͈zw”¼Ö~h˜é¬»{ˆxHgPî„6ßÂ÷¬8¹ãŠß³Þt[iÖ(N…ÒIÝô—‰Ð‘Œ¿ÅÜSm©Áw—tî‹sÄ:·'³?‘¬g6ムÉÄz)÷=n™çЯ[JDqDQJhµŸ<Â^·gPáñ%mÝäú»·n·=3¼ítd2ïäËÉAíTdýúÌù^sŸÙo–R×j=µì\å,c¾-#%¯Ã³Žx©©; WÍxÙzë†X\µÜéó™3Õ] ΰ»«—K^ûÕGª1Õª÷ć¡–k{¦1Bϧñ êœY±£]é~·<ëí¬‹«%HºîmÆ”2¡™´¸U\ E\¨¥D#6Ö©ýè¥=ÿE̒㶉ÛËrëïÇ‘Yòûáã%»¾f=ÞéMŸÞ³žKÚtZÓÈ'l8•¿8{žß6TF=Eò|"#.ßßUGÙVmÏ‘iûY'.þ÷Æ ´n¤(¦Ôh³ä\ŠjdäW¹MØ£Ç×G¦XÒ|^–uS‚&Æ ú]^Ñ]s}§GPW齑ɵùÛ]¹>íîæ˜~çÚã¯+}ß Ùî"•6ÃõµÁU=c¥Ú8j~>Ï?sÓ×Òs…Å"Cqv…?·åN=3 ÏDü™ƒÆs\ùÿ‚¤õ¤=§¤y-&*ŽJý†öãÃ[ÔÛw™bÄØñéûDfNÖHZZÛóJQù«¿¯bÑÔ|¥¨Áv¼êšŠ±¤z(ó±V‹ÖÁtAµêq¶#.èÄ‘ø6ÔÔrÑþú#¸\ØÇÖgÞü},#6ÛNjBÅp®~ÇBYÅ7ŸàÅË;æßO¶ï‡Ãß«…Ä* Â=µ³\F’˜v©ểÁRÚMܯ©”øeàE\G)×ÈLÅ<ýŸ™];8iÉú‘Æ££í–]Ä ËĺÏYŽ\6Çg#%U¤{’Ø[†»¦.Iœ<:Øg‹#6¨Q.AQÁƒ´7漯#üá#.¬h;û!ƒ]žX–0ÇÏçò¸m‡gÝš1Ž9ÍÿžèmúH¾_H‡–GYÓ¼Ï?N××wíQ:)þ$ø/KyÎi6¡+žvŽJŠ¢ÕE‰B¹@¸ÊƉðˆP¢úz…¢,Š¡–ªÙm–¿¢„ÛiKˆ»eïAxý1_®ùS4`Š÷³…¿wÙ“»N¶{PÔôÖ÷ÅTXPD]Î*çDïCEžüYc¤ô¤ãð^FO¸Žëz]ÕÏéæ’cpÈÚUÊUÐ@œ,#%ŒÂpHmUWùa±ƒµ®*|ÛH¦Îˆ}Úu÷'Ø2›Ô¤æŸŒ¼…ìGC9BSu&3æÖ5ñh÷=3m"±|Ø\!€XPŠ‘.{ØyÝH¸›¹[¹BJ+ÅGPÍS#.O2,,<Ó¿f;r‘÷ú½M`ª)…®¢Ñ@9b\m@ü @@]¶ÐئD #_K®cR(ä?µ‰#QQÄpFñ#%¨ªêªÄÄ:UÙ#%œ¨"ñÓmÝ„²#.ž·4맯É(¾Î^¬(üEJBë…‹23º ¬W¾\îp®4«ÎJê#.¬ËqÂ&zÐB/ò‰!<Ë9#.ølc´“Àw£ôMzME‚×®#.CÁEEÁEà#%‚<så£ñhõyp³R¸„øðá#6ÌÞO}Ž¢„åE§=•ï½ï–8Å»—ðàÙø{q!† ‘¯ÑÅ=ÜÆ¢Û©ˆ)êCöà?Ës_îì‡]#6„ŒêT?ˆ€–@-!öðó÷ÎÌ/™¾¥™Mþ¢Jk覱{Z-@?÷U§œÕë¹™üGê-›ÇŸ·Õ@{ª¼cnÎL‡§Q-ðÿúöòÎÿ”ÛeÐFçÛAùk9ý3xÇx/‡À4¾ÔPÅHDÀÒ¯ §¼z@ìÓüUÿ‰¼x´#%žo2‡2iíé…¶z—® kÒ$~ÇÙcÒ5õ«ŸoÕöü}œù°RH1蹈çèÚ4£}çKêçÎL¥ŸvJjþ©J%ÿñ ìøÐ}ÝAbAr€ðQ1«˜o£Ú·X„#66ÅH.>qÈ|ñ$T½‘Š"~ßÀ$ééí#.YqrA@f#%ûW°@Cë:ÑЊi&s7Ïôì¾&BOCüf+uÙòj” Ù$ßœº×Ïíz³¾EêOæÚ$>ùhÕn¡á™t÷HŒ†ú§¸!#*1"Ú.Nç¸Û;]\xVÙöùú¤šd^ ƒwÏ|gO6ÃϺí;ŒJæ0&é5Ó#%}¡8Ur/$€ß…3‘ì„>Üx¿,CŠq¨;™†•@v/#%å@]¹C9P¤grÏþ¸(9Á Èvkš$§9T¬Æ4˜h ÷~ÿm*ñ8꘻ˆÈ`#%X}¹lJ‚‡^¾ü. #.JCVgˆ‚5t^‚ˆ7!߆÷ eøÆe#%~zT)AY`ʼNµÂùíUö)>Sæ׋rYXP\¨¢!Å&‚NŽ0#6±ƒzY*¥MtÛ ìt‰šÊl,tgÎçg2ˆj—bOåN@–Âq7´ñ&¿FŠ)¶¦=((œ{;›‚P'+ª×Ãw”V_ðÀëá?tf“¸Ÿ@¢ÛnóX.Ž3Q%x]]Ïv[ÒÉk¥×¡TÔ4¢¦ª%…e^ROkl(FX8g&øw†å!£?géâÊ#.#íYÍïj‡~†âi›e•Ä×u'³Ý˜e;g•ÂTüLìq1Ý ¯#¨(òáá#ŒÉ,p†“çt‡Aè•5+ÙldèwäÕÒ{øÞv‡åÆ;Úõm”P•'@î}ˆço=pÊ2H#6OG™ê_™0P&Ú‰J#%íËTO¦\ýæÀ¢j›hDp¿É“ꡧКy©9Sr³xêÚ-ÇhvÔdŠ#.Y|ÓãÃPmSÀˆ_¶V?L_"'(PvÖR«6ã$¾Z'Žxõ×=÷#.A='áTP‘)þ%¦}ýjW¿Íþ\èô´Ò¨õÑ3Ê¡â̸|ÅZ~c¡ÞFÊ0‡V‡(·ÙÛiúÿ+Þíôüt|~!s#.Ë@Å¥ÑZÃñxä·˜aƒ……%»©±ªþ½GŠK1à*ÒpÁþ'Â=6ŸqK½•¶±/öþ®x ©®óÒ½±dRl/U¬ôdÂAÆr³#6+óÁ…G‹Ì&IŸòê“nçôBs\g"ìé_žKâéœ?ŠŸ§èMað{4•„ÃCɸü¤ý³þ~öÜ…ÚázNö}Ëê˜9„)˜Jë³ÒïIÆ€f¸<Êw²Á»¤‹Æ=,µ¶&M•!.üpVí±ðNtÞe°Ø²”Ó¦p„1•Ð˜àƒøôžzrżùX—wÇ+8So£°y1Ï,ð#.›0#йò½ÇÈB9:ƒ-{~Ã1[rµã[öÁå/{Ã"“ V«Ñ*&dÛëqì¶Y-Ï.õâÒÝpœO5Æw‹;-¹’¸ò ¦JÅff Ç»¼Á¤à°Õç–H‰|WÉ¡œ!I¥Æý1eEÖ¿Ö9†AŸtP_ªÈåÐêk‹WHV#6%±¥ìå¬1^ˆ´#0Ó)åªùº°Eóg*ímŲÜëèûßÁV–Bo^Eæñ4ûyÖ°‡.éÄFŸ±¾z4÷ö`€¡(Ù§¢œW'¨f鶹Jb•‚®òÑ;¥:ZÑ;n‘»Íçe¤°,5÷¿_„¡==:©8¼á*è›çñŽ–_ozâ|qä“5v]QsÚö.2ß#6ïÓœ‡Ó~ýá*ÜEÛ‘"cƒ¬|T=ù<³#€‚ˆ#6àœÆ`—Ñ-¶™ŠP¦#.…ÀLï6– ÏÜѺ Gà¨ëÔTt6k®^m¾×¡Îu¾íˆr%ÄD>Ú‡òQŠMŸã~pÝŒ, ¬&»œ_Ag¨šŸ²„Naæ{¼'##6ØÊ°àY•€È‡#søýø²\¿ú-´Ø~mÞÂɱ*ƒ6i¨I@¡¯PUG¶/G$YYzÑÎR0úgÏüŸ—î–å¯Cæ“ô~6·ÌS™PÔŸ^ÎÓ¤é#.Ózý¯kHmiÛm.•3Ìx‡K¦ÜÈÿ~®%Ä"Þ+G;L¡ïncï–53áõ>¬pxq¸dê}ƒŽ†¬=ÓÓ·UýöA¶Ÿ—vr„v¤’9’“4‹>ü‘L¸½p¯´°©gL{Ùþµt6É{<]^ÒÞœ‚™ÓXÈÁ\€‚ ¸ALäo¢—Ïóü¢’Ôð8ºÜP6;Ak…Ù#.†›njú«xõm©ÁäXµEÕ-—">/Ñ£§5ô¦`åä[R÷6qì./Ó#%®Prö9¤¡ÏTXŒù8H^ôѬPòÖ~•Zª¨‚S~§!¡™<פýUîO'›Uú¤–0°*û¡Â!5Éåúõ…`ØY—³¿ÂÁà$µD£#%¡<矘 A8¤y¦ç½â±F*$‚P’IåeÉ#%úZ;dž>žý{/ón\ö»A8*Ž#vw3…*ü5`,rØ5¦#./¾ºËÜŽ 4W‘i•Z¢‰œG˜éŸ!uá&(ÒÇ_q”Då®gˆ·3$g²a:¬ï,ÕMˆ{ÂkÌû!†ÚR [€#.Mßâ–i a½6`3š"»—½§ïØÈNÐ+Ùbv™‡§ˆêëdë—ŠZO9ª$-]»°Û–ü"üfÕÃõ¸p‚ELÂçìîiUHšE¹é±e.™ÂC¼â‡gA¬6y¢gÃë]±éwÁ÷Uîåã½}¿)¯#.A²ÌëðÀ`lAºÁ×dí9Èãjá*Ù݆渻²§°ñ,‘ƒ«hïÜ£dwÌ.°‚»d€åšy„r ‹%(sãeäFzeÚXí¼#.Kó¿i†CÜÚ'~Z6´–#±sY‘”JÉaL”Jƒ˜¦#%39F¸¨™Q" ^Då6{PSS3yÝL†Ý'n˜'´sûõ*ãšz‚¶ƒ«cT¸ˆ#.2!r(PhPÚë37nPᙌF;E6‹ƒ#%ò-®}“˜]…âRkß ×ø°Œ‘ç>Ðt©Ž[â¾Ú²Ù¯kYëõÉ×,oÅѲZf°Øâ'̆ü¼üFæ"_ê•ßv8í<[8›¢XæË«É;ýˆÚru06fåÚ¹$£”ìH½_¿ÅÌÖ_ÈB'ÑsÁ¾Wì$Š“³m#6E]}Ñ#.~j4aÙ£ Mfù‡ ‘À\ö=‚°¶²„„ÔJqå΂{ŠôÅOª÷Üþ§Òj›AéTPº¦Êƒæ}Ëã1¨ò%¦ÿ£Ì÷"‡ÛÍ¢1#6HsMžÇ¡±Q¯5óßâ¬Ì½9ÆÂ>uRÂ#}ì3va¤gìvŽ‘m¹€ZUÀ#ª³qÆîëƒVØX®H2ÚÏßÙ#.ÁÖ›@¨$7›°íc<ƒŠ!"†·ô2¯È.îöö!Ò‡5‰ÐÀ„¡LŒ÷³á±Ú¶æ…™Ÿ`ÆVØäºÑb#6#6õϧë(¢Ý‹a'9ú#6«`Ž‰„4Z†¢ >P4i á~q\KAÔ!nAÌ‘)™ÁÑYÅɼLèÈÉ6Þ¼44mŠ§3r !±é郓Z-*5Þ/!*kâÔ€VäD—K¸ù°;"Ön[z€2bŒˆèé}ˆÚÖ½ÖJ"ÃX¢žÌvh{X£è¹Øf¬b¡Z–ëó‰Šè¾´ò+AŽu~üâOÚ°Éqm©Þ„:¤Œ·C®aïÄ,«&q\È™A̶¿n<l4(ÉÙÛÄW†ŸÎ”"oí?wŠ©zg\.Äf¾]%k€Ù’¢t<æÐ#.c–Êá tgß›r#%s-¤ ÷çmhÅ»]§ˆN4(ãZs´cÎ.ßx*sŸgi5‘ÃÌJI@íod/(&_ÊX·éåøC¥¿ZO¹V?0Ìd<—‰Ö‘¼ÌĉË0æ–•;bù¶ëðzàUö‡Kd3‹³ Ê—áh@Ù€Qm´c`‰ñíYÀíÌÀNò‰1ª8Ø”´œ+n5µ#˜ðF¼]²"†RO]WQ5#.ê/Ùªß~”aêÔàí#%鉣µâÓ˜ê(-ˆ”+ƒGcÒÐÝ`|^D]ÿ¤¿³ÄœÁ#6El\q´`!zI¡¼<)MG~©oÖxEß¿øÍF'Qn#%xTL9ó¸- 4‚€ÜÜÜÝOÂxp8Yx¶@Ø‘o\D÷Níuœ§WL7COÀ»îZ¨#6iY|ŸÊäVú—AÓ]&[óêæ¥À_5·i>sE/#6¸¹€%5ÿ/ÃN¿ÃÝìï(öþlâò9Ðs7Îåú§óˆh£ógTH‚€ŸðYg}ç_Aò0¢VÅSNÄ‚HQ–'Äá×õÀ£UGJÙB3qØ÷dZšÞgÅÒЇq÷q¥¢×‹_aÜ8#%Iü~JÚž79ÀëÒ6ò`á|û6¯/ YÚr´hÄú§]Ù3óþKÕ⻳«—Ä|3ü|cÈužyb3f‡ïíÃø‡ÝCx-®–X3ÐPX‰ú†t?QÃœˆL#6Ô28~±s;{þ|%UVvþ,¿Æp‚gºÿ…ÀY²Tì*”Br)SŽ0e–Çûï¯Éþp>VÇù¸îü¡ü_ášbÖ?©BÈrøð½C9%_ý¹$TÅIÿUP©þ·÷êYE»üZÕôAêa#°^ˆØ”Xá©8Š1#%hÿ]¡0;5gûYý¼³Ö÷vØà|ávçv…†ßë›ûîšÖáþйގc€Ë«±_wNóx©©A3CaÚ— ï:Æ]Û¸…xn4©‰ã×Ìê{3 ®íH¸éÍßYTBºâüT£Ca²lÀ–ºª<ƒý¼ƒ;ª§`xµÍG°{‘Ú€ÀÞõ{ƒ¯œaô{ý.Aô¯³í4A#.PÈû=¨íŠÚ+þ˜ªYÄ; ]ÃäNÁ5%–‘Ñ…î\þK¿ÞÍ5”9€Í=¶Ïâ}™ F²†¡®B Ötüû™§ }ËÔ:Ð$A7ýß¾ºÏîû]MéÎÉ㈠D|_÷*ØUÙý./Žœó,Õ!nÿP=`dÄ_¼çœâÜ&\’B7dªõ{ ²Aåý—ˆŽ qÈP#%)X†u„¬¯# #\>Ïæþ¯G¿å+÷[q7¡ˆç˜b<œ*„™Ïw÷ý=OŸâGÔûôŸH|ï=áãøN®A ÊL’ª´RÅßzáóHò?yˆCÔ”“àVøþí¼…ò>!”0нÈ^‡ûÆÁ„.4ñ6×å#.ý?ipvóÙ7ìj¢Ñ X…˜%.S–7pÂM”ÞbÀò6£ƒ4¡ÖyÂCaΚ#.Ì·¨¬Qv ´†&ËPÿ—<#6ÃvT‡«±}ž‚ûXðÒ¥W–‡Ò`_Ýä }ÝâÄì9Åwœû[wmZ?¼“C`ðã tÌ{àsõ›Û?OqÂöžVÆȨ7RÁ°Æ.¸È’(H0µ˜p½#%o{‹‚íx-)F,=žÂÙ²"œÃÌ„ä—°íÀÚæ9Níw.i…c’vL0ìòÆ‚Ð*ÚÃz}pAZ€sŸmy^®šROÅö…îNÿïòðYGÔT%X›|ËBáá5¦ý4¨TÎ(ÔXÐ#ýeµeþô=]Hê#%ºwZÁÀH“_ž6£áúl¯ïwç£èÃ0%ï»=¡iìÁ'åƒÇ`w‚Ž%#{†ì;r6,#.øÖ,ć¤zdx`¿‡ý9p©CYÐÒTe*ÞiD¢-&¶Ö H<>Rg#65Y$îŸ?.ÔäxRR°Áîú=T²U}ø@ú1ME~ kmmÙG“åô¨óƒ&FØèÃefæj²’~G³M¬2ëôê‚YAÁwYÃâÖ÷ ™#%yM©o®#̉ôlBÉÕ@"Ð$eæ ˆÄ|³5:IF~Œ—¸"Ì-¨É>¤÷x›¸ºŽ"#.?â#6ª[pÆñ”·æ4ï* *˜D¨ uåsØmos¬!ÖÃfM€ð*fÀo5йdãÆ¿ç=1…”V·ñÚÀÓömçÊkû8…6ú„l£\ðgŒbÝ’K!UU;¤’I#6ðïlJüý¸f¶˜Çí86#îu︔öoz©žàÖóׄɄà<è:YhÜðyfÊ–çñΙSlK6ÉÆd–.Õåè‡SøÌöü½Aô–~Ã!#6ü§ù‘|N3ôÿ›»òï;§ÔO‘Úy K~ô¡…×Ä°´—SêœúfÄ=ºÔ#.óévdÖõò?IÆÉõáUê6ü‰“ƒôû”[~@ðˆ@X#6‚Ä`ÈÃ/õ{ü>Ÿ¨ #6èQÚ@Äöl„²Î¦§\Ã)%±·P7À`«³¹ð×…÷C.ŽÐup È`güŠûV}¹Î•|¥F1°bcC„2æ²Ëœæ‡0ž}"£‡A°o‚#. '#%ØÐhü÷‚ìÚ¹&F÷7yGÃÌ2M†Š:Œ„ÖúD(3ü_‹ý}Hlû·§qƒE#.2+ÏM¦äûøæƒÖ039!×ÚFå—9-Eö V#6„‡`d’€êxïk #%ÔOÁ-=fŒŠq/¾Êƒõ¥*`k|X}yÅ^Eí“!l<—FDYºÓA ±¨TD â)#–¢š3S:€™™š‘i°q`wr$îï+à™±›">,Œòq$D©L#6„3ÎÏõk’NðÍÔk‡Ä^!rÈÌC¹éi Ñ93C<µ™½Ø2.¦„#.Y$ˆà ¸ûŸÙÓñŸoXÿËw^º#%r€ÿ™úõˆUvAýù+ŽRWáóÆVoë¸q®ž½v¤ÞŒ”™zíÛ$cÁú»e’XjÿÇý1ž-.õ„XÊf‰]dmffžµ¨Tä!Ô}™§§Å´5N*näl³+”¤CEš‘×’I$™ª5ŠLTËMIikm§™«š²Öjãzef׌º†:õ„'«^kA«ÐÖ·¢šféu†G¼ÇV:ŒÒÄeA)2¬gøY(Î:ü¾Ù#6ŒX#6ª4YH¹„ŸŽ²¨é™ô0 ˜A‘P~_bÑjTmå»2sxqnaÑX„î;ÚŸ%³ïöÞÙýµ£ƒ˜t€Gí^^ÈžÂÆÛýÁ éŒó˼ÉI~}~ÝÕ¼QRü¾ÔúÑ÷}‚q§‡#%è!À´>Ò^„¶Cwl9¨; Œ„‚6ð›IÝ·;¶¯¬ó·Þd]¶d>a؈ZjH M)ßQl‰ÐªïVY¬$ˆ €r¶PRm82d?ðÛc;ŽÆxézZªÎÀ«àU¶#AIE5º&W¾f^%àù§Sš«-5RkÓ„¾]ZÍÌ¿ŸÂ19l=1IAJ~ËöêuEð4+Õ.^‡¿%6‰èßرfÆó£æŽg§-Ô¦ÝɽŠI"H±’~Å÷WN3v¥7(Š)sp‚ƒ*ˆKûû;®Î϶þÒÀû“´ÛïŸ3Ž£ßødc_dDôvö´€’»~¢µQ‹ý![~Æ1m—ؾñ!túíÈÿ©©¿)èlHÅ3ê+ì:ŸöK<¾¢ªQRR”Š"›äÙL„Ù°LÔËsMw¶`¡º îÍieBñ@0bRòK:R¢d|~“n|šâšWnƒGô „ݽ}‘8_¨à<'¯aòV¼Qîó5¯·o\W‹÷Û^0'h7 2u%‘¸Fmîòf±0/ÍÊÀ·ió¸ò@£P.£ùbúÈ+‹?NÎTáõPäDs#%>!ø½Þ@Y68þçxÉ\ż.Ü?€ú-¸QÙþ*°™DjIôßç½a-êzÄRÏ¢ˆ*%ö›Q<ìr0}y,ýÂz ú>Ç[„žäv€ãòƒ`õ#.€²Â½ú&Ì2(Abã:’6ƒ¿ô9œv¾ðû`ç¾É±9ßÙú_¨ì>†Ê§8»ÀþÉù€ö»6x'ã7ˆu'€{Å;H©A5twµñíPI”É(Ö?xyX"DNþ}+»ÅÞy‡sF±èæÆÀY—€3m;0#6ŒJŸÊÌ#%âaAŒö÷D<…‚É„Y(‡Ìò ¯À.pW÷Îapõ÷lòÕs½8¾?~†ç3PGÌpC© :¨3yC³ŠÐÕ?P«¯™»/id+ä?ÇGÞÙúÉõõɬ÷V7LUQX•®4=áù2»Ý–£¯ë‚ø|áçð*úÄ‚êkCÔ¦j˜„‡£’I'±â©æ>·Ò »ø5UŠÈA°4d€>Ÿ/ЯãH¤ŸWb)ÙZ]CÝZ{Ž_\£ßö¨0G±Lùru‹pÖÖÆZžÿG}6\ÒšT…Éá žåõú÷£°20®UöÊ’°8MAÕñ#.7û;³ƒ¬{Š¯Ïàtc$Ÿ:F†Þ,!î:€ìÎ:`âÁbqe¨s꾸äædQÒPÁ“NêƒËJCì2U‘ÕZˆ*>RQÀÑИ†©üèeLæHãc;väáÁbNˆTm÷T†Í&†t”K£Pññø©†tóUŒ‚Hª%HYÇW¯>nÛC-Žmu‹r6ÑêE±½„¹Þô+šn}|=i³Ÿ'2)˜E^úÏS<a‘$Ed@¡$´ZЫFþÎ)Ìí76,BĤJ(~¾'QvVôb•JÁøN|À=ɯ»ß<OZ'ˆIâh<Þ°ö#%`íßÂs#.dòUî6šûcÁ-£È3#%§Mª¥¹ãïù¼_Øû«óåïè/˜_Çk/qcu¨²{¤·´?×?ž#%#49'öJŠ<ªJÿ¡Ä†Ã”5m᥈8`«:m _\‘¸Í©R•JJQ¸kúºu÷OIÝ'lòµ°~3áGb˜â=hòäÒøŸj=ußËã$½!°ÔÃïLý®äwšžò!³Ý(TöC’ÇÙDåÄã÷~C—Ï¡\Èৠ‹T £T¦!S䧊r>Ð2üY"æC}Àí•iòJ;)œ.Ù¹ž½ð˜ h_Ÿ™é籄¾üåw¼!,Œ#6|õ»ùN}Cƒà=åË)BB¡háô"þã3ì• kEµ,ã‚e”'?`vðßù\à£öíç¶>ã‰(}M|)kì`éþ¹áaª]Ë•àa½E½h#ãòF%LæV #%ÚI0%‰¾ Z\Baнìh%RÀ2` øÐlHvE6Œ˜‚(¤\D½€d󈸂HÅH"8‰ERG5Ö ™½Áù²AC€ DÖ55-~£¿Àú}ý#.>(#.ØÈðòÅÓ<³1™Z*¦°°'Qb¨r#%*ãIé}¨kOH~)Û´ÑLAG§QbY()9gb4 ÁˆGô~×ôs¢×3Ü“×fH„z3J³íü`‘œV߶PÁý+_>q°Ù#64X”Ì¢3|»Í¯’r«Ò¸n‘[]0ÙP˜‚²ÙmÝyæ]<(©h–‘ïô›“Wóúý?f’þÐ3MãʳìóžAì};`%õñºéîfú‰#%–½'¼ŠYÍõù½HÃ[±#hqŽÃkóÔ6CôƒH&·j ˜ªY1#€(#.D†B2`ëJhL€é·E(ˆÒŽ*XZÌO/'œ ;+Ó³xBJ<ò9œ/;3§¨^-ûi^Cµ#6@Õ£wëÜŸ¢}”RN5Â7ö†n9ÐõD#%ØpHo(ë u}›J6öÄ+pòi:ºØç¡<½s¶Üíö[c˜Û’.Ó à49°¶¨<ïªÊ<Ïgã³ÙÛƒ;Âä=Åa¨]lùŒ‰úÇ#.ÒÒá)Š#6(£ß½d©ý`~¯YíˆIæIRJìóî9\§ÃÞúîŸ8ÿ‰#6Ù6zC¬÷|ý“>4Ò~Á1ØŠŸÂ¡ð&Il™LatɆ¼,#ZÅò4|˜kf_Ñ‚½š ´¸¹K†\UÔ0½—¼$…´UO°ßÈùq¢úHhG®Ž¬’:Š#žY9!|úÿróŒ=HÍŠ@p2¡ «B#؉ë·×îüèt*KHÍÁÙ·Z<ƒ°ïC$"4˜ëêëç–?}z¢3ŒÔŸx'îM'oÝé#%ø÷ÿ´‹;)âB0®ƒôo%dLƒ›,6f(·—Öߤ¯J”¼u.î¯[ž<r±!‚J‘™´Sâ_í#6Ïíªãø ùßïÅ#%¯P–C2?¢?½öýfYÌ1?I#6¯Úz³:ÃÀÉå”Öh¢ˆ"ƒ’•VŠ£ÌwŒg#6„þ¬)ʲüöTÜ0¯Á=iÚ ÏŽ‰™…Bi0‡Ö“%ö§gpõ c%ÌU!ˆ1¤1*D\?S:PzΟ ®þçæ–Ë—ÉHJMŠ´ŠRÁd¸¸1?;‚ÁcÀÌÝ°.<Îb§ ‡Ö;nçÎN[»›Ñê Ýžõ{Cízƒ!RسãõÙ. S#6 žŠê=‡,”è>½¾zDZN°ëÀàô·•NV’2KÀ.*Ð~› àGX5ºž!¶Å/K›¬Û…Ø©Ó€yâzK¨Š*üÌ`…–êAn߉lä¦ï/g«”*|[•B‰³‰¿âUBP„ Ÿ£âÍù·4„¸Å„á8'Pf,ÍŠ¥d‹Ä1éÿk‰üš;Ô¾Ö#Õ„žQÒRƒQŠñ{ùmzIIJ…0êĉ´Ã–Å…ãd…å1*ç0%v_η?nTÖtÎ#lš1绸UgP=`Š‡*•IùI²8¢º'ʨ´§F¥‰ëPØA¶_NáAJŽ`µ}ÿ¨|ýÅÓÚ/O€>9X<ü|z`î7Éíö¤Š»ÍýVèŸt¹ úd¨HÁ^mQÔЯ€ŒÒkK™ÖH¾‚ƒºëÓ.pâìDéGb\3>:ZA*à¡=^Wû<eÀ|ä 9 âp]û-³•¦hêØyƒš¡¥ÌŠšÁÐðN£{q¤bB:8jð´AKF#6#}븟O`y½JÝü‰Ñ<÷ à]ÈÈJ¬Êª%¤[9‡_Ôöì;#.HÂ.Ò‚PŽó÷áùOžÜ¶ÕÜ’“ÌúˆQœóμ8*eåàx_Xú(ÉA=ÐIÓ퇌É\½èÖÈ,Råí <nÝÔn3Ûò'ÙÙéóøö–_gùUJè â¯Wô‹(X¨7>àý<ž?ÔÕ =>Âcp`¾Æø™ÏðAv}Ï°¦òO"¾€<ªŠƒR†{Ë€¦8r?ŠOësðo¶S·à~4Îj·¹£0gþðˆ¢¢™+dã(€Z‹@·˜A}îlí…rÔåŸØޟ̤]×Ý®¥éÎ#%5I#%M$—ee5hPmØ؇5o¢àLÝpxûÂoJ#.0I Ò,6©‚BÈXõZªPýÑ÷w˜*÷o6`>Ϲ#.¨,~謙ðˆ!"Æ"?» Þ`]Q{“jòNo.ä˾‡0,bd% ¯pA°kó:Î.îz³h*;¾ŸÏ»kõê'©uÑÔ9V/N|Ž¢½%œbªdÏ¡‘?*=…ym+Pw!Ýd#.Œ[*›p… ½ÈÁa°ln7â^€öÂ9„íLÀйp´4#6ú}>¿|{Vuï-¯MŠ«¼ô©)mï¥Ývó·n°EÿQõ½Ä3t6ËnáññõÙºÈÀ®Þn]¯C9Q›pë’]q¾#.ãvË´[ÒQ¦ßô‡ßõ‡…ÌšD÷Fˆ§œ-hja°»^¹B†‡VͶl؈Å#%PX°V0PPÓ®¹ø:ä nî¡zgžxDeñŠÝÚb‡Ÿ³ÇÐ>ˆyÊék¦ô>z{h}Ás1óAˆdÑä–H>Ôéf X}„Ô¾îÍžÌ#¼ð8&`ÛwÐ6pŸÑF¾ý…BBM¬#6I#6çá~Èëž H7V%íü/Äÿxên=@çE¶¡ï‚=jÛQQEV$[jUUD:ü‹•z⤊^*eV“Ø”!ªú¿¨Ì&&r¶l|ô—‡D\Üç´X†€Öi¡š?«Xiê%x¯<íæ®ézîÒfSo—[Ö¨ ¬’s4üåú¿ä'÷åcyÜÕÕáP”Ðv‚SÓú0Ñ"#òÈðÍ‘~éº{ç´×Dª_*9äÕ¸S^t œ§(MÉg#ärö=“§ßÆò}²„)NVú¿A>?Òe ³èÎýPã/#.Yl{d+×V=µpø£µ0têÔ¹2ý0‘‡â{Qnw™vï÷ê8KÎÛ¨àzÊk0Ó2¡#%óØéüú»#.qÉTÕK£ë‡±+WU‚шù÷ÜxÉ°ý*(D¾Ý!Q4ãH“À¢¤çæT,P@X$àY´5eHr€ëþ;lýÐèllWTKw{ºZÄš¬û?‘ü£øN=‰ªg±‹\ļ3à1ê¢Il“¸ù݃ã'0´`Œ°+Ãm÷@#.ÉY†Çî½Éc÷µóy§#êú’éàãœ/ê#%B§ôëé._0þjà%Æ/ò9Q»ür#6Wúÿ=…rý™¥ˆ“âÀ¡(‰#6`1—M3-“ÊS¼ómÛÛËÄï)sª[!÷Œ™D–TL¡Y¬ß¨è™Žhq9"ºT"Õ#6+èAá©…¤©˜¥q„¬©æŸøÚŸàúY¡š…ûfgñ ²¤(kf:ñ£ðåØŒÅCù¬”#. çXÑa¤Å¨klmYçqÎ3Ö~73™®Ô.¦Æ%½Q²’: v-°—r· ê0#6ÄlÖ¯H`³}gÏ¡‘t¼¨Lýïä|~Gôÿ‡ìÛnîv<ÁÌ!ìÊù#.‹ÓÕwÊŸ†,ý†Ã°õ*ŒUŠ0BA_Üá÷KÒ¡‰(æI:§*•‚þM?µ™Í®ßÅÁ5›ä=½ÖN}¼NÍ\ë׳ž&‡í?z Ф´Y-…„¤*¨õÃ~‘#%·žöµ¦ÚSŸõ’ Qk„#%Z…z³#%åÝÈW;ÀÏ„§m`ŽðŒÝ%#%&„âUêï1ó~{Žýq×ÙúùT{,eÃMÙ"bª!œÖŸÍÌ"qùz„Nº|úw¿1ˆÔe”É»D@’å€Ày#6#°2;×₾÷%þ÷2zTXAÄ#%2€8Æð*5@åï'»ˆn„Êl„’V#6~Ž\bHQ^ÿ½èž¿,[>G;H=iêPÈJÞ§b¨$ ¦ð¯ñ”LÒú˜.½ÕÎ`ð4ƒÑm°É(4^?b——S*èdðpéÿ7f§Mó ÜÖñ?A‰£7DË$Ë—tÆûëÌ›dÞ>o#%dˆ„*6<¾Þ<Î= ͸_èyËa°aúðLfë9›ßm‚ÚíŸãÆxjt3û±]]î~N.5¿U4†K.w¤Í…ÒG…QëæìøŠæ°ÞŠi}‚kCeúÉî.§ZÆ8=6t™¸Yr#6„%Ý7"—sPDÖL1ܱ þ’‡^'y·=Ÿë;â*Slb¬lˆ{¼*þR{„\2ˆî@¯çk·¨˜ªØPîᬅâðDçG½#6@<0GzÂò£|~Hø¤þ‡zN† ˜ØûcGÿÍý]ŽbïÓcy×÷Ò…Ø!éÅ!ù‰Æ?ƒí·oÙÜÙ?ÉåTQŽÜ)ÞQñ6ÓÒáÞú_7Ûƒàò‹à#.èðüª½ÚŠpÉê7?v¿~óAÞJî„îç'bœ—û,íÜz@®‘”^í@q(M¶9T*²õ†Ã.Évm‡¶Âºˆ9ψY t Æ"ñÌ&÷Ä;:„×ì<݇Lò0âÃñ{ü×R¬þ/$œúý3Ò#6?¿>þ_Óu,š6æšsl»sÄl˩Ň0â•Õ躨ƒsŸæG#ä.ñuÁgg¹mPÿk¼§l$XóüE‘æv˜Q?™â[òÏÞßÆIGG”HNåwÒSƒîýçâ-‚¹³\Áx„µ”9ù¯ˆs£†{©¤`öù¤J÷ªÕ:^¶‰B4žœË?ÕzfêÞÿ•§„¥¢®¿)#.!£“†a’€û1¬KÚëõÌó€ê†2_‘ã[¬{™lAnµLL#6#.µ› qÍ¡S'[o”½ÂÓGf¬(`ƒ{JÂñw–óç¦$ÛÇRuœŽ:g<®ÏðÛ]3êød¼çŒCpêÖ“4¦8óe2övÏw]Lâ0W½k³8h[¡åÁ,¶ †”{ö}/l\_G–H½£¤á¦#6ù^'…òlŸæ¢å®#6—ÊÙ.rƒ‚w ë0Þáü~-¼ï>]¸ã›ÉÀswsÜ&…ÑÜÝÛe‰ìü§]È]2ý3„Ë4Ù—–£UtÏ[žmjpªž¤9-ÐÁ@AbŒ#6™£AkãÕÓlÔ•ùúøoTqŽ˜4°—gÒ3,Θw<vâ‘/£Ã±ü—3#6¤39ߊ \ëa7gÖâ¸<Ž«I…º×$ #%‚!¼|_á1wç—£6ôtŠ‹3kì'6¥Œe¶>É1~¯&#Ùî+ïUÜ¿îÌ×}.µŒŠðƳӦ³K7wMïTD_UŒÒr{RniÐU!Üñȸ>mòi?]“Ðúsyü®ç:áéõ#6Œõ›3Pÿ[~´ì—ù¯§¹OšÏ.pìà?h‹^UÚfÞ|ð‰ 7䆨 DN&¥6iQ-9z-¶bêwþ{£K–Ý4d@òuL:Ø€ÝrŽËç}ÖÓ¶æ8\à4›Ýœ&dOË‹x”tð£ÕŠ1ÕoêïSßþþt¾þßã}¿FZ÷|iwïòÃ\EÂ^ÃÑq¼.ÎúyµŒß³Ì#F×›šcró°Ê1J?„yŸU`< zŒôê9Ÿ=(ÇV#%Û»#%øÓY]¦˜ÆÉNIör+Í0‰Õ‡”#%)aN^/X#÷$ 2ÂOaA~eœoa#%†aÓÈÅNÍ¿GõŽ‡ðãηÁ8•†ÝóÎ$÷ÍKs{üœtJä^ôeìQú¤ê(LÌ#.!Ž~ž=.gm “iijÞ]¨¦b¸MÐ6Eî@ýŒ´‡Þv`w‡aY<<ëà›;% ‚Ó3!.áé»IÕ35Ç3å·®N†úÇÓ(¯§ëƒù6‰c9vòD[µ4;ȘQT4¢Æ’R.²aV&¤BœÓÕ¯Nh¬Fz *åQH¼Õj´$fU"Â67U’<y„bןžb® »T†#.‹Zd˜‹K©ƒ¨å9Ì‘‘?¼’TRëøq©û߯:ÌÑÜYE‚zh€À‘O¥òúÑ'Â}ßϯú¶´ã´!hRéÿgÉ8_‡ú+ƒvá4¼þxÓËDçèûý]g#.ZŠgùPô˜}šý;ñšlÈ°†± IôKû«ôlpýŸHN#öþ?bpà€~á¹#%—$!!ûß#%Ü•Ul?Úz˜Søól]¸~·a¶ÄÛɘkä öjk#6vè¼]ý#.çˆÓHIH‘Šÿ{µ?¢ËÀ;uM·YMQÃÈÓ[q“Ƀ[N¹´ƒ€&ÚôunµÝW€x¾0óÉ籈×p4-œçPÖ\IÁ¸7\¶Öò¨ªñô¦Ü‚ Béǽÿ9Á¸t<#%<‡3§ê#. 2¿ÛÐs½k•!(Ú*]𒪨°©A+hX™˜’Æ?“Úvÿ)Èi0h~~ë[v[‘¹a,îÍìw ÚÌÖM€N0Ï|¼Ùª<ÝД'Qä{jWÛö[¾¿‰9`±Mà®P³(yÝ9qõEX‡—ós!GWQ®Ú-ñg4'™io/R„ á—«®Pï¡ØùØk„•¬ÈŽBé;"kƒ£s_¤‡}5fŠcfS.ê²ëƒ€Ã2 `D §ÂSIˆ0&„b1"áJ5ih¤˜>fRàH¢Í«‡N¶s8„ˆ¬ Fe…qWžäz’§d¾5àÖ…!;xÀÞ>ï†ç†eÕeB-!Øœïm§0M.Î"Éô¤à7ñ¡NõbÈ>}¾X3ýä…:²íäÖNÅÍ÷ü7º[Sò„aéߦ#HáòÇéwo¦¢Ì³ÙÛ´!€;Z-"¡ø‰è’zbS Á#6ª…°ÐÕ’–²A±¨ÛAp¥i²e¢TA Ð@h=BµËŒº¿ f?´5û†»›q&}Ûrd^Wð?üßk{K5™ Ú,_Öï{¬/+Yüt1Q!%¥*‰d`ü¿ÚŸ@R¾Ä9AžäF"ÕÝ·fÛžPàw†£|}¯ôh„ {·g=×·½¬HER!AÓË´Ößè,?»ßØ=†ËȪŠÄDy_7xÿ<íî,ö‡+ɲ.eñÖàÈÔhX؉‚+VBG=«ÝŠÛV =¼R7–Áý.ÎùrõT'(f¡Úh»V7Ê‘¤–sW´Ð’Ž¦À&’áõQN!ëMpqZ%·d岘—nƒ¶;±'Ú%1†LhˆUQú#6l}i à ó"™e¿¦<BˆÈ|½†3®Ü<<t¹Rð`6¸Ç&ÀvîÛvŸyÂ8Û`«pBº¶DÆd“kOVR\:¤+‰;ï#¡s°îÝÈãLºÅ€xórÇúÝkå.̇xžÔ©¸ë„4Úgu“"0úË!we*ñt5æ—:ÝÎ&e%•ßãD‹¬sì·.¬é5Ĭ^r)Ãg[Äb.;a“3¤ðžœX8:^Ó·¿Ÿ¡Û&Éë“Ïs^½ÛÃõwG•$fž>šWâw}wλw̸á‘ŶòÕš˜Y$6ÎÖa7Åç4E#v8œ–¹omæf¸À¯C'am²H|MÜ4!vkÿ!VBÞ†ðÙ:Æ Å]å&@Éî[ÝÈù1àô#.sžµ3/MC4XÅ#6ÅE)ë‹nØáã´'a‚Ú[–\†£Àº½ŽfÖ@ƒ¬næ¨|?¢©£_w³Ý¨Ï¦ÐàY”ÎÀlô2K™‡?*#%a8xIéç×¾=¾øs¿AÜrø€‡‡fA#6¤–±á·GÃM§o#.F¾™Üϵš*wQ¥íè¥T—ˆ”ñ˜›`Ñö7€õF4kÈAËð#.2ìª0hXøT¬ZÔß´åb µØ=H<àXoA#.!rqíg#%[:yléTËs©ÓT#q¿`Z×Í“^!|´Bl¶Ç¸ò´©Ê=1Ž#ÖÑ8šÆÎ$'`äQ.º%ì+¶&†À÷{¡èzy…‰5 °ÔmyÁ,Tí6¾$pd‡—ø(Q13(%&ŤÂBß²°Ôla¥²HrÏ#.æcÎ<BÙɤôÏÔÞ»«[°ËZPX·wouMÁÈ̪÷LÎi‚]©C£0=ƒ°X¨îuà]ˆñ»$8dï;ˆu!‚ÉÒ@0äPT®a¬xoà„fv‡fåWl×€Œ G–¿àªˆQp@©Öö›¡’”MÇ“qG{tØ&ðºSlƒ* z½39Ã=NùÌÌÈðØy"¥ˆw'ÐUÒq5¶Æé¹v/¡’Ëà24@·øl'âlȳ§w@'©gyÂvk–Ìùµ‹œÒ¢¬d¤Í„4ôÎ¥ë|í#6£Ðà«5t¶õMÚ]î‘<#6i5À{WÓêB<ᤜ‡”16;€¤ ²D`ª#6†ÍɈšN^DYuQX’¥ŽÚhgLm¤»2îxNKaÊ£R+q õ(Xø8œLÎÎoE”¤hÂ.JhÚBHN_C]àYÑÉ.ƒžÅuáŽ-,\à@ Ø+ǯ53¢,UæeÇ™™2æffXÛ1¬«2ÌÉ%Xì<õcˆûªjñl$0n˜Æ&z¸íü'qÚÌQ¶*WÕÜFÞz>7³wœ&–¥éÖû½C›9Û#%!zˆlžP?V[¸·=¾Û»ÊÄsÍÑÖ™Ò„&w·áÁ"TK¯=k9çÓäôzp¼m™)ðièÖšÜæÄÙ3=êFC¾hYCS8G+}9•ÇÏ5®ÍGÞ˜sÔÁÐi“·d%(ô#6×nÜÉBiÄhŸáIw°P¨¡%Õ,±h¨¢^4˜{ûw+Ñ#6Æ]Án™³ÍÊÔJ,!25.!bÌÎ’[úsHƶg6|kë‡P奕èŽÐÐɪ×e‚ìëÁéë#.dÓ’C¸ÌG)¢”AkotcC~[^²Ù#%D¹ÞìÎBI(×¼®Ò´U6U;â´øÀ¸}=‡»Ï|#%Ö«Õ¬´”ÑÂ7:ðäUC#6ŠS¥Áµ;’ȉèáÎ\6Fj«U*F7Û`žr¹á˜t¯äXÈ‚ë@¾v…^µšG1)ã^ï4¡N)LvàYÎò`']ÑL„ª5m²Ý3ã}´Y¼5ÞB@-º·¦ü¦ÏFµ&¶€á®) l‚ÐÑÛµŽm,¹r,±aòãH }3V%O2‘(ö›–„Ðà£J(‹ÐâHk2fdçqªºDôòÚy"èN‰5«Û¹ˆ]Æ#.¡¬Ï7Á£0¡:þÿç‡06î쪻BÌÙµRÉÊ$Ç‘‡cHÃáŠÂûJ$ètU&WD9æÏ‚š*Ë!çÈÜåÞb<BÑ#.#.¤E¡Fy ha½¶E· 38aú-á'/JZ*šV¨i4œ`hRq!]#6ÐΡ«0Q¢e.‘ÿ_B†"ûÉ¥#:+R*‰F䨎ãºq=r@õœ¾_ 9Û!ß/¦MHYˆLÓÓ‘gq.Ôt=vü7]Xu&I¯Ù„(Cy¨¼°jÏ4±K¨d;Ä¢¥Ú…©#.üJ”$E1ΦÚ1‘d‚€k±€×´†³[&ᨡÁÄrGÌXÐ!™"|&“4уIŒƒr`ô<4˜ÒËMkW€gÅ7&»Ó6ínS./ÌçÇÚÖÞ°‡F2õN;@ÕDf¹â“»ãUëÐûŽÀ%NÐn_~L•À ‚DH²Óf©˜¤ß|oŒšR½oªó æ85IF+:ƒ5_`d{ÎuȦ¾¿\–·\g#_-7‘èõ–ì{Œèìî"æ³#YCi#.‹×ØÊW¬¹7R¹ÉØÎ!‡‹±E¹—*.I¦›#6’‚Éw×¢½³áp$Ç‹$‹#.Îxy|FÀPL’Z#.š°’(Ì—‡nÛm&C¶#.F´"뼡%Ï·z9¼ÒjÄ›6¦„™Þ0ð¾oHCøŒÇÇš‰Š¥7L!3 „0q‚Ä#%Æ;{‚[‚þ@o $ÜÙVI6“-Ãp%A<劂O××'ŸP£ÿ¯¹Mu#%†I|E>½Êõž…8q¼D¨-ê½0ÒƘ»²ô:¢äåê=¦‘™&-O醥éÏÛgÆ úîí²]+<GHk%Ù¢˜*>ñ¬K‡¿·M>i#.$×ûwã_ÜŸóÐÑŒ‰¸$ëÌgñ\W«§Ñ3nWVGM§OUªy#.ñ”ÜY7#.ï·»·=h=BÐR´”‡gÌß»´_t=V[(@²2N. c ›!áHôØ>((Q6ÿÅ7Ý*Š…=Š°eHÐÿoµéÅr.#6ë\HîÚæzyŸðCÿ?²e˜³ý“€‡BÔVKÓÝò<`PA>B¢*£!>Ÿy5©÷Tõ.¥(¶fÉ(ε<U”vöú|G¼z¨lô!á×gï"ûN`´é~aõúCäD#6F ‰[Ûº‰7÷«nÓ6R[êž‚P!½ÊPE.xùš®5†#.+i}˜2AA‚ˆûwR@ŠH¡A)Ò¢+4Õ#6˜ÚÊ fkÙƒ:·oNqï$$$¥¯b¸Îô”yØöpÕ$µ@© ‚Ò(øì¡Þ§’pm`<lr°#.ú¯±òÁY±W,ï$ˆÍø àž””ôŠ]CP÷À;?8¤D™v#6#bBÙ-’hÐ I÷ì{ÄB"@ˆæ|§®\¦€ú¢Æ*X4GZ‘A#.ʛÙx‚{i#.¤Pd ‚##%=ÀA`|x_äCR³¥éó4èÔ£`$‰kB1KºíÁ#6Xƨ1tI‡ÅÊ»{m|®Õé¶#%¬Pº5ƒ80.˜HÜÌö¶D[¡·¯¸ê’{-Ïþ0~ðî6#.ÐÀÛœuHKÓÁȬ;‡Æè+ù(ª‡—°0ˆ#6AÍ£3¬%„_²Ÿ\$Í•>‚&@!åÌh!7#%Ü#.[Ó]ì¸F/ˆ5û"•µöi^øUÍÔdwéÖn\¶qüŠ/ ‚êÌpá<`bˆé·¤Éê5e6Û}åcj墩i,ÚAE`d;ˆá;`‚þ興è«UÛ4ÖÖéW¼ªÙ¬”àc‹òz9$ž»u[}’ÌnS(î—ÁG¦"uÆäMö#%²¶×/lM²`Î3ˆ™ €Iˆ‡BÅ…‘ÆêÜ£ÉPbî0*z*RI‹z»·M·7©½MÍv%»´^uå»ùÞy·‹›¦;¹ÕÍË%ewh䉽#.„ºEhÒÐ% Ô¦¯>6õ|,µ•ŸÁ}lƒ@›$~×Ú#%Üà=Ó$.4¡°†eÏE‡Y $$gñ¸|o'¯Øÿ&_xr¤¹ße{ÚƒŒ²qõøç#Øéêô/Í9xóÏsLXËü‚ðDo™Ã7æzF%€A\Gv‚íg–}¡õ¨ÄhKmBˆx#6I!yb°hÚùëí*×O–é¦Ïî§{h“Vø¶¹[sU>þ³Ö2šf00$Y§Ó‘Ä·+?߈ó÷ã–ì#%OPÐ?ÂUHïjÍgy诨·«f#.¼ç•™r£k¸,“‹CÇ•sŒ(lÈd×XT‘˜„¡…#.-¡¦êTÞè`¦–—`0¹þf( äC.¸hïâÜ_<rµXzèý¦.[÷ƒ9WlÑþDÝÇ~++yK”ÜD„Ýèó5Û=ÇÝåó†Ýæ°‡_uZ¬ÎûÛItlìßi!,òîh~aÑCåð#.ïvœ±ß“!@»‡#.W8Gµä´®M[q‘³ó'ôÿ5çc‰yΉ˜èóó\s‚ÚU’Á´ü³1,;næ)šÈ£D£lè¢{Â#6üýE„ª•RŠNÞϤ:oN‹EŽµbz©5RöóžnJ¯\E k}ð„Gp0³5+"¾•N¤zŒ¥|JNq±z©$MÅkÔÃâÁ/H…çƒx8˜ˆSø{Qy´¶"ØØ›}¹ú+<·‹1™#k²*âªh–ü·ÖÐñÓãïí„()de1*#úå¢#ј{<¤©#6B~´0„úÑPPa¶ÉV‹d¢6jÆ’l¢JŒV++-«M²ZI[Ò[YQ¦ÌÐ Š@ŒAdDõ”ü8üú—ÒZ§U¾¹G]WHsÞ"zådHª2#%È õúÐú „˜à×ùuÜßÄgõ¯"ÝV7Õ6‡?e¹¡€ðÐØ늣šˆ5ŒhXdi½ú#.ˆ«,Š_Â*†ƒ›”é’i›â{ÒWÍíï—BI*@<&k(}¼Hšt¯•MÍ#.%€hkI”‚/¤Ò²fIš¯©ÓrÝw‚§º*(»w*R Z(íxÇÕ˜N{Òup£&šÝ¨$[j]8l JÄ*ʽ‘mî°uA}žCË•¬ ê•##%©QM¢:ö捻*$g¸À½3ÂtBE ÁP‰'H¤!‰-EjæÜÙ+šÜ¦l)S(ªf#.EI¤)¨ˆ‚€¢“ç™÷O°h!ØÜÓ&²Ð8@#% HAdA•NÔUÔ£Êúø>|Çí½÷z»Õ‹r¦š7ËHdaÅÂ&ï’€fA=/Q…yžwßv) ß#%ÖHˆ}0!ÂÓã!ì?çîÿ—ðûoçôŸü6*‡œ9Ã}ŸâHß$Áßég‹/ƒŠb¬5B^!Õ i >ÐŒüÝhFŠD"°¢#誨d|M×½÷ÇNV2]Q5J…:4¡x¡²¢(.QÒHMŸnš]E>¶,xC6tŒ‰h/לá†É»²Ô{hÍDhËþ8_£÷ùóÄ“õÒ+µ˜A#.¬Zb‚¡žÿiÞ0"$œqÝ»1ñ;“£n²èÓxIx5S²ù2ûõ#.Ou‚ *}–À©9,Ê1üKûEåžè')®Á²#% ÈB £H싶0›º=IÐøõœþÚ;B³q@lŠi8"d3¿!û±Üx#.ARúì:ýØp´xÔ…ˆ$‘¶¯SÓÖû·¿„'ˆCµ¥ß£sƒì¡ßlQñ»aúpð:r‰S²^uÍz놳ÃéÊdT$Ö`ý²À ”Œ>·†D=‡ÕNž3%c£xIîÝøµÏʼiă=ÏI#.-3}ûüÉr¯ÏõÉÀÃÄ#%ÿ4vvu„#%ÍN‘‘vº÷n¼Bq†ˆYƒ¼ê…(›lÊSiLúÚ¥Äcí&b‰3ãOx±“»#.k#6P2C+Ž´ãLjAçXô9¢”pªq¯ïf÷³®zçíblS¡-§œÚá&+šíXRka\¹ÙrÇŒ`„X#%ˆŒ žâ’¢¡ë ò£À;Ÿx‹¦h}§œ6uò:«1[w~ÿòÑ ³?Ä7¯(iHPjÊj¨¨4£QPuQöt?_‡ïbɱù*îíw(Qa–DçéýM ™ªEbyf:öõ¯ŒìôeÕË8C8èPX‰{il[ÍI~#6!OLcìš¾––@#9OÓçVvÐøX79° #¡Ž@úA¢•V/5MP4€0#.»Bgð¸k7ŸÃ¿ß^×ο}Ò‡¯Êùñ‹(=–côôþÁ~‡'‹¢!ÈD£v^ÿŽ#6îóÊ@²²ZÐXzñÍ}fT°Þ.Rá>çæÞ™¤SÚ¶8‘ècs(Ÿ:óž‹Á¿>z œ,>cº¸½¾1Þt*U¶¼G¡ÔLc3úZo¥î«ÂÁÞµÑáè㥷;WeÓÇc¶¹åpçqF;jÌt,½ÇÙ¤mÖÙ*a\£·¶|kžµÐ/ç¦ÅоÍhŒ¯›ËDP$S¡x7ãmš£"äŠ[lmp`¯h8x–ÁÁ}7:ÙדlíA¦ÕÃÃ|v#6õw;60ný1ljmß>øµ;Q‰šcµnÊ$[ž9µœÚŒ5)Ü‹QžaH$ì£h8ŠâæfÏ{xÅlÔÝ.£Á°_+À£ÐÑðøbsaצóëÇ#%YbdSÎdÆ#.pûŸs{¼Il0ÜûÙR&ÌêAÇ#6ñÿBHjëP‘¹A골)œHTøL3#%!+R¨Ï¢VAH©JÙêÄcv>8}¥hà÷·2Ö|ÊöçÛ!ˆ¿#%ù˜ì÷;vÀ+…Ã"x%õéÑ×Ûc@¤«x@¥Ñ ºï¡Ÿ8`Ŷoê¡ùÁS’'+ä9Ùýâ6*êvòñ‘š¹lØ6‹Ÿ×ÆÛywPõ˜¤/ÊfïWÇ Œ„¬ï¡ëµ#.W#žÃòú¾ ædôn;vêÝFl[Ú ÷†w6%‰9‘ªM–ÛpZód½™òK[?i`ë¿WúX†šAžÔ„†Ó}{–n#.˹ÏeA–Ç=ÎB:£‰ îÎhá#¯$ïR¥ˆ"Ã!ÙÙã>|÷É8Žf#.(¤SôܾöÒcC|¸á6RGdõLÅõý}Œô=H )G¯†÷&r ‚0Á˜ô€z•s:ñ—•wdêßË-㡧"Ö$3!~I$ß¿Ð4!•#(í¿‹ Ó]àôöklÑü™1v.ÂŽsϺ&®]Cj¤„Jöm7†ÊöÚ´õŠšúAôöh†)(r¡ÊV‡T’u©£Ý55#hý~=Yäk©"N(Dï·Ká%OÔŽœLzJ“"À^q\øëÑ•X0¸°&ÃaÅ?Õ³h„FE5|øeëëܼó¨_ ë'_·&µîP5' ;ûè`õVSªS¼Ž–ªˆ*·Us²43d¶º\ÙIÝ]Mœ‹’ÆÚš[]¾TŒR5 ‚²0ƒ¹`¨ÈX¬%JBŒ¡i)¹d¥ÖpìnæDp¹”f²áݳ ²XÒŠÄé½Vù—µôh´55Šf¬Ê‘E$M¯ê ï!åÄ£c#6låÑ1¥gkÏ~ÓcíÝèginÿu[ÇPüúᆤ„ ×#6Ê´—é+¥dÖm¿JâÐÂO}Žˆgº„#%¨‚#%ÆÙCÜ#6„tü¥È|lûžäðv+ªÁÂ"®Ý ÙS)D¨ìr«–4óI£#gm‡±°æ´Sà¨P©Í×p„ã²µma·Ø¢žÏÎu„mwñž`W¹ ¤vëC0‚Ù_·«#%b ž˜n*F¢[föUŽŽÃÛ¦š¸í<¶‰ÞNHO–Nù'ùîHÙ¥#6¬…#.¬meQ€Fˆªd°QB$J”Œ`ÈÓD©*X²R’ A¡iP‰bB‹>&í'5mÌSÀ‡aõP#.ž3¼ù«¯Uõ_\ÊƃnëµXÚ€Iét÷ÄAÓ¹jr‰ir%§Ã^[šõpÉ!1ßй×ÑXZÚ§TÙóYüÕfǦ³¶Kò`^üBþ“™:â"€^%GPß:D×-nóD¿\“iKÛ6ªª§£Ú!ÚE$H#%;±Ä+†¦ûãÛþ:Á‰Ù(gœëw'`v2›OA¸ºÚ¡bˆb$(cÕ¨‡Bô6HÐçªõ&™:å„Á[ýBðn‘6šLÙY¢’&oáoÃa gZæ4ÅS$.vøü}^Gwxù?LD(:íÔl†Ú£Ø|û»^ys*½ oèo’è¡ýþ{o´Ò)”4±"ˆ‚EƒÖŠ"Îg™ÑŒf¯:ºJåM.î›8ˆgÕô8è$€ÍI¬´e¨Ùòˆ”7Ú!ôäþF›9Îòué¬ÌV°WT…vgˆ÷ÙîNž^»Þ×·t) Õc=#j7®çkÏgÔKm&ðŠßÌåܹÁ5.”SêÔÆɸŸk4JApN:lŠ§eÏÛƇm2LÆ?¯]°ËYØ¡¶“¯Áª¤úCÝÂûªC<sLTšCvê‚ÃA ´»†Ê/>!!hl5ç©\¬Ð™J\¯×¥ dHÂdê43d=BÂÁH#¢‘¸pK5Qz 5ÑZt%Î^E†A‚@–@Èœ_àæ÷e{>ñ¢ ³<Ô ‰²Æw+¸s, "õ€5#%B «Piuô+55ƒÁ‚Ú4ÍÖo.Æ#*H) ŒBˆFõ‘ˆ®¦`Ș`¡âÏY¥Âz¢ØÃɘj8MË!KI} ‹A#.``(3ŠU€Àõ¶Ô&¢M•·ÊêëlU”j0À%Ô¥†-Ù_›œá烞;^Q=õ\¿)ŸI#6w¬©”H¹`Íöò€¨Åïå‘|ÙF×mÐA;8ck³èÚ{Γ{44‡ ”JàÉÜ™ÕÏ€}LPCæyBM±dY¾‡«²›ábyOÄ’ýäµ’ý™ˆƒ~šÉ¹úšØà›Õ#.¼C"¶‡I<Û;úÏÕ‹{FÊinlü~}|ßáñBûÅÉ{øºF¾ dìàÉ#6çîà±!!1134ã¹c÷t³Ê'HœC…˜-&Å#6°ªhvÏWqþD€ÈAˆèªt@‹QÙÃÇD¹Ö ‚[!äåRÉÒs'tÃ-‚T#%g£è雕*ª“ÒY“Kt¥ÅF"(«UV#6Ñ0&(÷&T¼Ç0}zšƒŸO‡²‰Qj#Æ%…ŒN¼ƒ±€¤nˆ²Ÿ™(VMBòÑsýì¬ãb¨LcC@! ƒ.¤ð¥t˜1'?]‡ˆŠ& Õã¶ØÀÀ¨‘i‹®(DŽ÷¨æçÌâŽõy¤Z¬Ý*BèÀ½ej·–Mdø¨Fí¢FtHFØÑ}ÃZ0À"'•¦?ÑâÊõŠhØÒ;ðdYC*Ï;C¿ P…Ct_ À#%2Nÿµª©°¢dÔÔH<ü%ÝqHMÝI\uª´’ßßÎ ŒäLĦæêpÚMÒ<ëç#.†ÚÊ8ôã%˜fL‰QÇ&јÅ\‰*…å‹01ñxaj€ ;‰”ž‹ùžª{è™<(…pÑŽ®=¬¢ÿHy!ŽwD0íµÞÇ•˜ÔAc&™´²–b‚˜£Š¤Ø.5sSIý›1ôj2¶ŠEH¢ƒ¥·ÆÏ,k¬Õ=ÍñÚÍÍ2äÁEœ¸¨(ʽˆ„ :¡9ˆZkµ‘©´öO<שMFØÚË!Lc`0Ò3s@ï}Y÷N#6late<˜pÖ0÷J"DzØØÓˆßyCr6±Ë#%=l+§j¹0jÒOþ¯|×f>-=q¦ûÊß:Û¿ƒ×¢ó1Èø¹¨õ’’ ^¼P“\aa£Oö¶³r@^õéu4¨’ãº} ˜xÚc4uÆÙàâ×Xgds°•;îæ"ÆÖ,_ãMþºl„áÇtï¡“ÛKV¬7LÅ¡8ƒ 9ŒÀ„²T(5T‰H†„™ ‘¨Œp_;KŠ¦ùeÉYJ9-Uà AˆìXÛIò–.#.áï#bì’lÃIm£€õ˜U±ØdáA´”Ã)jѹ ÒMF…Ý4m¦¤’j!6I&̓³¦&1>ì!áÞ¦°ãm.[¼R>Ø]™Ã]+ÙÒí.ì]¥ñ•éx·´®jñašJ¥-#.ÐÑÇ#6†ƒ%±dA‹af“ÂÈ[&fVî£ãøIå.Û¹ð‡Ç9ÝML™Í5#›Ô’#|¼™[A‹Úæèu˜‰_kØAÆ:œQB3³eÀÔ/ð°ÎÊF ws+¡-+¬œpä.Q‚S&h%mK‡ƒOÖ¨fö¬¾ÒŠ‡·šñßÝä:yGÈ`ÓÂ$F…½"šˆ„ˆ»|hÙàP;#.aHê‰Å4¦”K_kà@Çip[6‰6y3÷ˆóxpBÿFýfÔLâ[6ãknk׫‰™®TãÝ¥¹„ÊÊ—ÎúNº¬Ó 2I+FÂmá‚ØÙkå>)4+.b‹$馬ú‰¨Ë¶?m…ÃS>^O¹ðã³*0üÉÍhæŸ'£~;j–0æÕº5-Nîše¶F¯Á³9HßGIÚÉr,=ä°4!{nî8nØýÐë’Ùë œ~Æí:gg¿˜Ðƒ`È-@Tùÿ/¯Þ?D/«¹ÕíاÁB °!D±¡DÐE‰Ï% #.&3í÷R’ŽÖâƒ6æ¦÷0Ü Éu*:hë$‘ÌM4h@I&…M/WX(,¹§fh#6l°#%„ÌSÎ`°£X n¦yÓzÚ¹‹©i¥RJùkïVr2L”7käÜr˜E¤¼Ö¦EÇRJðÉ·ÂwXU:½–c7ãweû‰ÚŠ(AÓ×Lo®ÜXçû¡¸×-•=®1&òXËÙL9Éž‰! ’Ù}Á¹IǾä\y$þÉW¦G†~ÃE4ªm©•ëS_ÉþßÌ G®#%ˆ£sºvYBog•?’~ËA%*j×Ú¹âÛˆ,#6ѵ¨¶¼TjæÕ¶5¨ÖÕÍmͶ-V6«¥¥ÖévCÙç.'Q÷¸ÁE5bõG9;#.¶ïY4¥•(ö±Ô÷u;ƒk®ŽÛœ+¦¤ùï4šÖ¿™D’4$‚S&e3JÓ,É)I¦)5E¤ÍAúΤÂZÒ1Q4Ô¡’š"P¢´±¯~Ü¡“ZLY%™[4)“4Ì‘˜hEQC”M½ÝDFÒY)˜¤”–PÃT%¢Ò£EL¦FhÆL•¦)¬T„Ê&ƒ%!MA”¨ÌA¦ƒLÚcH` ‹4ÑÜS¹&óg¶§äe/è#6b|[|X&Aï~lU_SBݘ×Çøf̈þ¢˜;708ëY!,”Ìm¯Òfvòús†Á©Ù9`ÄÞ¬ü8Î#.©‹4czKÖãj\ ‚0Ž¬Î]iÙ¼¼Ú(’5÷Ðz—àmÚn.Ö›¨—,mDñs0³Ž¥xÂxâN;Z-_ßK¡# ý‰}úYJÒ»0teŒ^ÎÝfw†’~âÅçãîùA{*ÂïÃñŒŽƒbm°ÇŒªd© …ïúûZø^Ûo³_‘bc5 £#f²V*(“i–`!Faå³><9ôí0ݽò¬X ›#6"ƒtXaÛô3³ÙŸyèNUMæçaëÔY„b’™Â†+ÏNbC4®}û0_ê®[ç/c´y‡OÀôW¿—¼‡}#êk#6xn4ëO–åûÒ3Ï=GQá’íPœê‹+™|ÎàÉ ÒV_£ãfåÄw&}z^Ë –p{"r>Mõ£ÓG]‡eUY´#.q¨ E)¢AT‘$/rdÇ¥oKý}eÂGÝ2û¶ÛùåßXÇÆiKôôˆ£¬Ê%x4ûmÁ÷cÇ—$I*#1â8-¹¬-ߣ¼8ó#+ígÇö£‡dÎCìÖ“÷µ« ªIm¦úõöÃ{N¹”`g"â–PR¨EΨ¸)µ›xãcB?+ç#6cguVÖˬ!çE®PÓŠ#6Ú+G0Âè'#66[ïG8 ápI5ö,nm_&·É‚Ôè2…ò˜í¶£·ŽWÂc.[õ"^7L³§<1YCŒu-Í4î'¼Ñ¯$º41²Úîg’Œ ®„Ä©OSååšä‡½ðæ^R°öœA虚O?M"… CòqôÂdìNIÈDBª‹´ÊxŒK'²Ùª ÕµÞŽ¢gd6Eõ)×FÛÀ¹m¹™—¼2ÙIb=OiÑ·,(ŸŸÕ5X@ý\µêž{w÷7g FÊHC–ï‰:ڷשÔ'®½]Æðëì±õz¼†— Ãíúëïúv“¢B¤†xà÷Ç}IÁ\³Âw¢â‡vÏ·§Ó–æÖ_¯¥ø? 畧ЪX‰@w Üóßœž5Ìíí†á#6áí)~¿.wðzŒàDà ¢Ÿn”GkBkjl8ògâm»]š•%};àf.äIG^fP–så3 jÓ5'B;Cq¬ ™™#6;뀛<rÝ &\?#€E„C8(p+x#.jÝ_âN®ú9pÜh>?/æåüÛ>é5ú³0ù²Yþ–¥7Q6È£Šö0¦Ä¦ai™ªF—˜»ÔÎELš¢ƒÖ¡•ÂŒœ‘u§÷5˜Ú30ÞW>ØÙ‹šÓ©œê<Ô4̵¶Í<¼ØÍ3‘©t,ņq4hÔQSRJbã5¬D‹(E…Æð¶ÒçVL›WUޜŵ¬ æß´¥(%©ñ?”ÕKľ$–.›¥âÃ1^{¶S{ÛeóL:Ø"ža‚*cŠ“óuo\ a\MLËhz²IÆ´lÆV#6¶Â'¿S³Œ;ÙŒï¬îç;WGÚv Òá8ƒacgµ9t!éî^Ñ´åd»Ìê5+6É5#.ÂÉ,0&àbÛNJÒ:¤é°~g–]øì`ɽ/Ü,7#6ÁŒR[Ì&*_¨€ÊÐõ¡‰êìí§ž4ÍTo#.ª?02!ðnÐ6#.ÂΩª²æÑóÄï4Á&:ÏJFìÀ9]Ѥ]Ò¬ua®y:†š0jæó2w67¶ŒLªL¹‚$ôgç}õ‹´n£ð@ußpBƒŒí…´ñÖ=,æYí?9Š@ôÓRP±áɬ@ºZßlAsø;oˆ‚Nñ©¦™«¬•qbÐ×gÉÙã6ô¯fl-&¢<ºF!ÏOB|VvÌïDDÆÇr¯/“,¸Ú‹z"VnöÍfrg£ÑñSëqH·:Óº¶6´=V_è-³eßÇ®ÚƱã‚æ·mˆO¸Œè¢õ¸t“¤÷)0–ešÔj§=1åŠÎØÐà’F§1žÜWVÕ£i–7îæ)¬Rãžw¾_<ã0Ý®È^ÏP•Üd>ÃÜllg:Žûà5Úã%¬GQÄî²a…3™§¦è:Ó;1¢dÆ9Ž°„LJ¡n5´š£Íš']ºß—ÊßQt×\PÄ##.'yJX5Ñ\F™Ö¸2L‘/Fò.ZX]ÔG¡‚Œ(¸jS}5#6jåVͶã]*—ïXTäÊ•Š°óqdßûªÚöFSB™cÕ\llÏ^sÇ9*Në¡Ü,ßž]Ì•öO,ºK+çThu¿(vÎ[‚=e´Æ™™¹CAibu†S"“q0V^£ Zk¿kO+gX›]Ž°ÎNe6¼™_y#”n˜uÁÕÎkƒ¦©Éct9)¯Y6ª9àZ€nl8\e¢‘±¿#ƒ¿˜A#M|fS®±*CP7ð˜vB¦šEVöU;"áÖ“€X.\†[DY\('¹Ä>›;Öï8‚óghh:yYz™ä×&YNÚ‹0,¶iQ!³é¥ØXlhÍÍÌpÑÓNVŸNÚ]#. ºÑH.q¼†Å:¦ÌR‚IFÈ¡“bÓ<P¹ƒ‰Ô™ÂÀµ)>Û4=¸ÍÃ#6Y¬ŽÛëEÎ&)Ä+æaõ—Æ0[3A”@¡®bXßQÝëí*1‚¤X‚1qI—N~.2ߩݨÛháÛá£Ô7á‰)” ¬neïpOVêÑÙRQ9B&PÆ7Ês‹iõncºÍ7Ûƒu³U·6vu†blâÂçìw‡Ûsðüa½evâæfcyž5Ù9ݬe|[Èu`z§Û™L>8¦²‡·¹O/¦ÅR=:„%›)Ç’:Ó{¸ÜÖZÍQëF72Ìf2û"t[¸—LLLb|¾ZÏÔáFc™êEæðó8™—‡S7G”´ÖQ²´ƒÓgórâ’Êܨ;ç¿©Ç1™£Wœ•· i©#\Z%±pƒˆð²ÌÝUX6嵡s2úBº9‰“†H4qÆ:jn¬21ÉO)&PmV†Ìâë\—[™lÖfõŽ™5,yU–LbÇ0vBŒ ¢&¨©ÒªC¤‰r# šSH‹^éi!°Ó×ÆÊ»I>ívÃ8YÙªüµW›a²EZN©Øχ–+aì'gj0šŽ²ÕUÎ☙ìrÓŠÖ*L¾#6$§Ê 3vðä{Á¨·É"aNû+â(0àe#6Bu öó›Rô`h©µÃ€ŠpPI©š,#. f˜F’èã#6ëÚ°äÚ¸c¸M™©_{RÆ£eé\½1åf2åR;ÎZ©a®šf%‡Ã±Âb"âzÿºïÍ·9V¶ßé2#.¾¦¡#º@DE»ÎuBI‘@aàÞÔs‰¯#]Öhè Ph“}”’‚•èuz1‘Uõç €tÍ®NŒzzOQ(‹¶Twqh÷Ä঴üšÄõRù` »pZPLÒ;Ì7CN]ƒ"ÌŽÍ€äü#6.s׫ZÃ’‰4ý½Ø'»õâΠшä^î‹le,Tm®t• ‘쉌SR™3›@±0îÃt¬y\)&Œ#.:b8ô“!ËK@õ´]NÍc4Ü‚Ó@rÖàš²e53Al2ȈbiA-’™µR‘rîšvÖºS%#6#¥ÍÜ ¶ói"2ÐÀ…°œõ3Sd”ÂÅtvNI-"ÚS#.ó['£‘2ä`éRqfà˜d5eëRªŒ#.XsL%q®i¶L§¤n2éÍc*±<.Gâ(N¶çc²ž¥i¶m£¦TéÂ&pL*ˆ[#%ŒXŒ*tv™‰‚mœÀåŽÈB$I”3¥/ObYÚD³»w\ñ#.»dÃ펋xå/ºï#.Ó‰\lÜêÎ#6eÊ47Uç3}Ç/™ÒÙlpNZÖ)£¢Ájx#u±¡öMXNRÎÒ¬˜³ˆÎ ÔÁ|`5Œ`pËè²3Pò†à‚f—8¬&„7PÐÖÆn°Öj–›;Ã'žCSž…™_¿&™ÓŒPiIÛ+]#%ODö®÷Â,zÜÎùèe̲¤9i 7R#6tÈðS0@e°usÇùM׉#6KÕ5B˜E¥!UAIHX.Ëb004’ÚÏêÀóbŒ;àG±.NâˆÑÔGI–F1T*©ÒNï_»;QwW‹˜m3ŠoüòÊA8ÐTX$GaJt®Þ†Á˜`g£é®á™ N Ž¡}[aY¢¹I‡°êˆÒB5RÙÂ[#%†—l8Øqˆ+CŽûÈ¡¢#.F+2fisÄØÜ l³3Y†ÅÖ¸©Hˆu#.Íî‘„ÌI‘awmwš#6nò“aæqÁÊŒWÃ;‘ÂeUô88JD61C#%CGfú1ÃgÆ$˜±ÆNØÃɆµ#.fŠšåî äi ’q¥º£ Ã0é#.(à›™œ hLÉåJII4ƒdpjŠì•ËrÁ·i3fÕ̺ÇEÐÙ™9—Fm0²jJG8ÒgtÓ^Rg~V@.·uXiØl4I˜%ÝlK9Ã00¡Ü[Xn&uA#%Š0ŒIF ÄúÈ%#6¯qCÿ$R5Á@w³;ÀiSh¦²…Ê#┈1Aÿ6¾*?g€|zœ(† íW¹ *I"Hƒ#$d‚#%‚|jÇØ?´È3$䈌@q:áÔ:7H¤ýhuF¤ˆ@„&È4€¨±TC8Ì •î#%ƒ»-=Ùk<Œ÷˜º›~¸X$Ÿ*vʪL>ô ÷ó¼JÓhiÁ×/‰Ô'‰Ø³‡—7®R™ÆM߬·YEr,;Bó®_}®P«4ó¸ëá›&A±´Æ\©s'M•.áiR¸k5†…ÜÖBh7„nÂ20+aÀ7èu%¶eŽxn„X!ÑÕöõ#%c=¤×Àæ^çõµ’§4pu\0RÈpBÿev#6h•"J¨”ÔËkñ¦[m&òRjµ*ÕᚈPÙŒR€² q¶˜X¡1H_§‡D‰˜#.o=#6“JAµµ‚ÍBp5㊡Œš\¡íö÷¬C$;×á8·SoWÇ4íUú‚*ˆ#%nùnR6._¡S—WwUÙn»³.nºn¨-sd¯å¯5<¿Fîȵ¾*ä}î³ÓÁAáÖ<‰`P¡ý÷©¬ŽÙLv*Žôr†ð8«#6#%„†|ž(u/¼ˆqœz0g-ZŠ"½(àŠ{̸°'ìò@7>™GÔ»ìo?6©2.œþ“0Vè<œŸ²¾Ü?Ø|~rÚ=¹—ÈFÙÙwE¹µÈM44¨ÈÀ,ˆœ;Si#67‹ –P¼o„ÆnF¿½µ°bhÐ1D)¦ ‹õªS@£¦n0—.Ö”™Ò.eÆùA2Ac¿´z¸äf$YÞЂQ#.cG÷±3þ!¬:?+xø…Ë–%êá¹A.‡¦9FòKPí?Vþ?_¶×äUi´&RkF±£Q[FÔIDL“`Í3-‚‹lXÅ|ÿZ0Pˆì´O€ïö¸ñÒ´TîRºÔ᳧zä™K¼º:ŽØk5vˆz€4DŸ+ZÂ"kÂÑ’ÄDŒFÓI0Ž#%¬D‘¨í #”E¶V-ÄÞƒ‡ âêxÝïf§PD`@Ë[΋Iß3_Ùk̹<æÑÛÕŠ~«Qb*H²j}šJ²a_x;wÙ$”œŽ›l[^•ÖAõ4ÑLÔdÂËp‘çbˆ7úN(ŠÒcKi"ÈF'¸„Üf5jå]*¾M½KÓoB5LâÕÙ1‹fR–@l@ÓE`›Œ+K†³D#0ŽQÆR&lcƒ8®åB+ Ö×ËHŸyÂ˱žJEƒ†ˆHÐq ²@Q¶“Uú©oƒ#.ê;˜‚eK¾ü'Ÿô(ï‰éz–”#.s’ddÞí¨»‹¼è‘%Ï$¡ˆïÏë&ðÙ»#.†PÔ…HåïT¥Èõ¢®î°]Æc(i“°·Ej#.^&Ž²Ð†åZHšp0…“8‹ˆW‹‹ª.¢cc#%mÆLN¨–L…uÈÍY^sŲñüÞaÅ#%ò=§w‘Kbm´’lc+A)aLDHÀÆ-Ÿ°5Iq0]i>â k…@ /_¢Àmˆ!š* I,Ëñ ‡Ý›¼;âdç¬D©™_&,ŠúMŽ“õÊŠ6Áý{ˆ8QÌ`o¨¹U¹¾NJÚ## ‘qöe]²gÞRšrE0;>Ç/¼Ú#Ú:í¦Æ>µîÅÇmcz"4ˆŠïU#.è§2†]õÈl0ÒjøáiiZµ}†køw3†FC“®•zª‰¶i!KábÇgØÌ:„'5˜’bCèVmÓc{”^ZÖH8 “‡ ÉË¿+#%Ó¾æÖZøA”ËIÃ4Áùz¶^ym£Á¬ÂÉ'Gi±†êØá9E$åPš«%*‰ ÀUŒeYNÜBº1B)#6×6¦Ô9sypYµ.ݘUfylM‘¥ç—x¸‡kÈDÔëi¦lïÊ‹]ôŽ†ÁúÑ ¡C‡|ÐÁÅF–1#6hÊ7n®ÆbC#%ktE.J Ô˜DbTJ¨š Q$Ø£J#.L„@Àc¤œ#%-P$PRÄ[¼ t`luqlg¨LÍ#6Ð?Æ@ ®åB<5ퟨ;+Æ>ER+ýÜÉŸz¹M8¤Qb{(=Gø+t Ãï ~L>±ÿWTŸª/‚¢ÒkºÓÏó<1G¦A¢|A]fsÕ10#!ëGšú™"‰‚d„’FHÅ"½†«bƨÚɶ¬ZÚM«Š„ "BCÒ÷©š5Ï?=x•T\½KŸJåÈûŸ ó[ʾ§ôÀikE/³Šâk|t¶u+W…þ n.¬…¨ê¬ÞÔrØr$®E#.“{:iÃYÞ%lšeäʵS0:2¥KŠYk8ißjÓm&ìÙ&èdñv5-zÔbŠºSc³AÎ##6pšHÒ.™KÄӃƶð¤¶Ê>-ÌÞI†SŒ1d¼ÔèËÍ<»SâKÛ¦3‡Û’$•Šiȉ3̸jMÙsy†ô@#DmãŽü¼Õ‹Á(ÑŒíju¾N&H†mŠr¦=fÎþW˜ÑÇàËNÔë‡5ÀÈå‡ËµÝÀÆi>ŠSæ)1jnÀI™Ž‘®$ÌÜC#:¨y>ÖÞ*¨i½ðyXÛz›Mp“\ÎJùš}e)œãï3Ã&=¾¢¸É&B°‚âðÇ"íž–7•5¬´ÝÎ+c¤ØàdÌrpQ©»M=íW0ƒarr1Æ@Æõ«t¥XE€D‹LXÄ%‚ѵeÌôö²ÒBÌ´¼›Ë•ôÖkUã\§›©ê^y^¦¶¼¼âƺÜÛiÖíª ,ŠÜÔsK¡B4ªä!_ÁšhR‡M¢†:—«#ÿRDõìÍ”¤Dkm^|œ•ÝÅUÚì›"hƒI°’1Ž<¥jÆY*dÂK èíƒ0š]#6»jí&°n•ÝuÝÅ&ñ\µëµÉ–§›®ó*òlLi[©Ãc]¦£hÒT¼e?äÐÉH‘Ã…(¦Ñ³R¤me-¦U$…”™f±¶5¦¤S5ÔµÒ´²–™5¥™SUFŸ6¾^xMEª*f‹VЕlÒ„T„7–öy™¼túccQ”Õ©£â™`IPÀ€¡Q6››@‚—bQ‘Q‘P´X!º+çÚD='qí°z³ÄõŒ.‡kÓWéaKÞ9S@Ð×î6ýy‡†´Oƒ;‘Øngq ¾ Oz³,§E™ÀËÂqhöëÏKS-Àº#%DŒFßÝOXÅ¥*jXÃɪÓm'ÓO#»;ÎLÀMÉÞ¦l1JœSí"[ÕKŒR¥U(ÑJ01!¤Uý¨¦ÐŠa•#%¨Çj#%¨)"ìØn¢¶Í¸—eµsÆòèéf´Í:ð²ÿfÂs©÷ pÝ#%H…5¦µ.Gf`#6 ò®µ2™ñÞ‰ eRD£T5ïÓ×ûûyk#.Žæñ#.ãÀÇ=AõÕê4\¸Twíé©Øm?2s¦O^ßn’õU„\ˆ«#%rãÑâuJÿo‘¢Æéˆ%òÅ€´AS¶(†L!¯$yB—`w?6Èl„¨íx3ÝŸb…ÍÁ‡L8o\šårEœÎD¹S¤,`&Q¶7ühÄ´t{Î+Áoœn/1~»bµxÙ#%à.jßÞ¡ö ~Ɉ0Tˆ„ªþ—¯æƹ¾óíèlodð8YGçÙ|fQ¯ãûô0*mùÊ‚¨<„ h%µj6¢ùýÕ²Eâì(–’eQ‰’MÍmr,¡–‰¬“Þûµk“M¥c)m&Ê6-")¦Y,¦JUÅ,µ”gå]aM«)˜lÚ1&ÑFÚ¦µMÓŠ+"µ+ºéµ }í®Öí^Ý»*b(2#6em¥)IkjhÆ¥Wµó¹Æ¯~í’lŠ-cd¶¶ÙH›en]ihÒeRMKmçáM‰´Úl¡3#6š°ÛilÚMìêKlcãnŠÍ–ó«¯;’R2hk–êÍRW‚ë5x®Ø”ĪÂFÛÂk±ŠË[L7ô®ßõLUšq¼ó¾T•ÔÇŽîRÈ´,£›^›?/Ëá>Ïw>Bmôs'`˜ÆèOeÅ3$˜SF¯<XqIƒFÎzŸTX@÷Äñ˜…ª’×æmãœ÷_NñW{<{1’MEœC=”#%.b¤3ª#‚E À‰$T B 6Ø£Ç^–S² ¤"-³JÙ¦Ú÷mªé¶±oƒ²³KÍÚå5so›º×”ª¢#6²QdFAôR*fSJl)«iJ)’‘Ô,¢…E’Ö–ÍFÌRÓ3ÚE E¥&©Kmi¶i›Y5°Òš)R›|Vå(“-EeQ-%£(ÓJHQ¡´Û)M"jLÑ°Ó1”b‚Äa£+eØÙ2IdhXÔš±j”ª#6Š”ÙR”ÉT•¢’©Y#jQ#.¨µ›M!BJLX)2“ ¦I¦J–j¦ØƨŠ²$mE,LÚ“$‹6Ö¥šÉ“F”’Ò›l²¶¤Z÷Õk»VÒ²ÛM¤²Ô†’ÞòÚ×M›6µ)ª²V¯f¯6{*¹zÍV-¶R–ÁmFÕ¤J*mm£ZúáÖÞcí³€^ù6g]!‡ n5Æx§“{á·ç5ª÷è`fþÆpb‚›Ézì7ùWkN-ÝðÞW ¸ˆˆîmE<³¤•!‘à#%¤yFäoDz¥ª$„>Xqå×⢵žåE÷Äô^éè†øì\$1gÁÚaž>Ž®ìk£g]7bÙ 3meÌz4º:¶š.L@ݤ¡áÈ"¥+´Ä»/šö7ñ_‡K3ü½©=Úßn9=½™C#6?q°Å‘@P \cha!¼†„ )Ìæ]28ÐƘ‘›à¡ª ƒ(ÁW_@pÄ$•ûŽ -΄¸>õÒlÕsuæ°ÙåÈ)P;+ôø ž:ó‚lŽPùÀ‚.3ôу¿ŽI÷¾×‰ÅLFz%;8ã»m§f¸ñ¼õЫ´Ô¬ovÄÅ.šy‡Ëg ØPÝM±"Ê~¤}þ…b\åö2eÏàØ¥WCó|såÇéл\Lu#6“8TóT>µK‘ƒîªtJZ~ÙVêøPŸvÙÂíͳÏHdÖ°éè#ÅÄØÚ =õ øs«~O†Øõl£qGFù¬Öû#6¤Èƺj–µ¤7Ò6Wi0½«#._Èé}/[onÓ€‹ @òî#%#%‹lj¨Ê²N"Q@R+¥rÔ'8#6Èo(Õàž ‚"2! ÖDëê¥Ñxšíb¹Õu^¬U˜°‰=³¾_vóÒ…‘Xdé[ž&ya–&\T•CA¸œ!Š$Œ*¨c#.ª “SLÖ`O¼I.!&*x³VÏz§@â]7ù=ý«¨á×èv#.çWµ±ç]{|)LcÜšÃPó €fÛÊÖs²šD\OúÙÀ«–‚Îx…#6((S)øbî#úÛËR’dA]%Ù@ÿgìºùaZÞåe±F6ÐÊÊH‘F–Œæª&cD2LŒ#l#6Ðh{ÄC5U.mÈÁ¶“ÄH)fáu'6ÑÆ¡‰†±ÅXƒVFA4^Z®¨ÆÎjv–©g6& b S´·»RÅF[¢ÃK#6ª‘@Q®—I–ŠL*cð¨Râ‘¿J“T#.t#%6:^ôtqs•èÕ(ñQ €jÔÎQ§×hXÔz´A;Pƒl|߶¨4"ÑJÔL©ª‰‹hJ¸XÌîÁò€›`‘8ŤMýàž5çñæk±—°÷§ŒÁÜæ" k;CXx†j/zø/#£Pì|…4ÉL`ZhÚ-AXAKëíÚÛ[EìÔ×9b$>#%ý0¸ Ìèª=V.ná·kmÿ>sê ý¹gźÆS®i{HÔ·t0Jcˆ*ßÁ$çL¼•·ŸZ«ùß$!›Ã¾$ë”ÚwËIƒ;àtn”l øÇ-i¥!I¡#.njßRY²’VTÊÁ[õðð™l…c0¶õ«ìXlA‘4„(Fë¹ËÈ/n•÷Odçèʃô½teú‹&YùA16ºa2‚e8 ÔÁõQv!h+åËbêÅó¿r@Ã…/¥)Æ®)iQÒÆâO±¹9&íBø>ÿ|€Ép©*ÚYKmj”i!´ƒ:I$š””žmDVCCpš€P±Èc&P1èó€´âÚs½s¯gÙ™².Û!›H #6áPªR3ÂxQȵßxÇ™Š¥ƒcQ¢Á:÷Ts‹hiß5¶JÆKF¤„ÉÃ'3ÔGÃœyÍãsKMûé:Ÿ]û`‚ª‡§ ÃÂ2‰UKÕ•JâòÌ«ŒÏZ§N7~R±î(: @"¡ÌȡⶶQfíf´Ä‘ÒiDÓ´ThAŒ´~Œù~ÿNè>‡—èëTšPå›úÇQpº¢ˆóG‚Çšpó ¥€CaFE<Q#%,ˆ2ªœä°®Gíâ&±û¼á9Ťð;õ1A¾¼uŒÈŒhœ)¹¢`Ûk„NÑD’=ó§#.ùüq ¹Ž[tcv¦¢â#.iÉÆLjÆD.Ã1ì˜ÆVí¡¶&q±"J5†Òë`̆/¸:ž”¯l’F#6¾”R¯OQz‹#%ñ=;NÝÖo+fy*wЙ¹çF|û Å"TX¥BSM4…DB —¥×*¯rïšJZÀeE–¤É@òrÎf§„PÜ\/èÆQø#%»¶’(tWx.ǨÚP QÕ‚¤BÉUN#("»ðX¨2#%›LâF›M`”'°fT(#.à2–pâ§.=ZpË×v3œ{×raY &&´Ú²4î¤G]:\„clç¹¾,u/Ëß xµî¹anGÇå¬$46×PŠÁDùkŠ‰’It¼îÂ2žv¹ÍÄÀŽ+¹,Òçžu ñ<xϹ½eäŒmŽ "#%$lŒá`Ü1R Œü{n×z¨¢3D¦ë2Ó™#.äÅž†êí¤¯dò“ê߆¹nŒh/‘!Ý]ñžåîî¶ØnéŸ-ü:»+~A8uˆëÈN3‹5åŠP«Ãp¼Cmí$/R«4²¦ÆîÁ,Ã1=;ÓPp¥'#.¾>Œú UGLc0õâu{2=AÑ+½ëÜ('_¹HCX=˜DàmÆq–zEn€ÆÅ$ONÃ-Ž’¥¯Ë¡e¤šÈ#6¤ÍSY}Ÿ—ƒ“¹‚YîêúÑ#6I£åíª†¸%Ý£HÐÍ?]‰$E/]jôåå˼n¤ÛìnÈ™”HNõæ½Z½jé%»mj©RC¤Š@…àmQcš°^:wn) «—1KÙ)yš#6†QŠÒ€4šlß·ºw7¥´D9Š;¢¾âênïÕ¢ìÑꙧëÛÄtN(Àºü5šîIåÖïãrBÌ©[æq‚_S¾®¦Rg¿s%_Æ—¥àM~%Db+)'æhwJM¬0…«ö5¯YFqtªÁÏé‚ "懲‚:Ê•½Õ4Ñ´L¢‹Z®Q•M4šjW]6èrbK$ج[FßVäbÄVkãJ*¯KÒõ-kÆ嬳oßýþñ¶Éki¶[V½*ÝrttÊ7ĸeÀ ®h'kåŠÐ³)ôãK —]¬Îe´"„¶JJˆPÉB7&®r°„2ý(-„Øo)’€<(˜ û7Îu¡¬²h%,3al!™â ¦±hv>¹3Ù]´l4‚„}»ÒX(¸ÐÞì½qOt”T5(¿åiÀ’¤(‰º#8+!iH@ÛaSòÕ*ŒµVzPT*éd“W˜fTp9°ÌPð5 ëÖàtïôQìꪅ¨…E#5ÝvÆÓ"£I´Ul#%&°ÝíÝ+Èt00p‘²Fù`Åì&á—,Ü}C…pÀ×t,Våp¨CšA2¬ ÛÑo¢|¸¾ÀÞï'´Pg=b,‹q¤ B€=cik=A’~x#6gLüqöÿË€.×HšÂà\‹h]IÕíø1…Œ‘#%¨%扨&?¿dÒI¡ÏÊçÕ~¶ÔØ;Îáâ¨Ë#.ÃÀa a‘Qúùh€ŸFÍpA24‘»Mšjÿ-ŸF?=+áÿ‡ûRâl~C~˜œƒ$4Kç‚^ˆn«&߃Byï‹(íê`=4ñ…x(«C’~¿´ŽA@TTвÏa81#6êå{œ êÒB|<Luß»¤/6ìÙýžðéÙÔ;ÂŒûî„€pt6žøSTSbGz¿Cé¿Êw.;=#%žd#%RIí #6J¥*#6¡DYX@¨©PPfŽôlY‚!x¥EdBD “b[’Š3\0ù_a»ÌË÷¡ƒôq¸Á™+£b‚ÓIbÁNQ²Õ~ƒ«0ŽGqÍ9Ÿe±ìSQù~ý£Ëj±DŸPõ$›SÒžÔ£C N/P¼läV_Òþ íUAd‚:ƒ C—â[!Üak%ªEIH®^E¿Wcâ|s¼R¨ÄÅgßêóåÅ„àX!`≫r'ÈàPë;OyÜbPWGçÄ>'¯—¯ï`Ãæy~6×Üß=a§,»rÞtï£ÔŸHÄT̉I9¨™¦¤¯V–¾Tª‹SRÙÍTþËÁ˜I¦ƒúËúPцjˆ,TU#6©3û®ÜSE,#6@¼•I#6e,%Žì†€Ze¡Cð@ÃQ>9yñþ_›¼ï€Õ-’6#ÆD“ca]‚ªñË<>ÙZcm¦É\ïg:F0¶ 0#BÌ £&D®¤ÍeµÄ±¡Gf–4'ÔF4ÆÒ„qI‰Žlb-ªÍå†LQ”X(‰‹J¶™*™Ef°‹-œH#.Ô’™a4J@fµ@¤ ±I2ÈPµ›„´Ù’œbƒb$]’ÌÐLïR`MS$’•‹µZLibm-äB1ŒŒŒç+–=B`HVZM¨“F`L%¥ª¤mV>Lä±¼xa¶EXVÆ¢ÄÞª²¬ ÕÖAÉF¶áÃ4gJ’Z¢‹,j¨j¥0¤…'6Ñ´®è±\·6Årܾ#.ãc^»½.4<ºí¾-“¹1Šç4\3•¨lêApÌjÓ´KŒ&D`:3±ók0Ó,$i¾K†µbc‡,P¸yA®5&Ψ hÕQ.šHº5@€ák[R²°ðÕ5O<#.ŽC:Q¨€6%Üe{îË]ƒúÓN×Ò!£ Ñ uP2Ëñ»h|€úim²O:“4MiãÁÖÆïØøÈxÕ,#>¸Òc!I¬ÆñÛmwºòeºÍ7YºÐ«áùqüô”Â1Ó ÍÍÓ+p8ñö¼þ#.áߣ .H(ôMTØØ?9ø Ñ0€À«¢¯`1 «þ8÷‘A%Q#FååljT²j,ªê£TI’ñn’ª0±¬QrÕ]JƬQ¶ÜÝm’ÓDbd”@b-eAÔn*¬Z•$A$TɸúÓøC )È°íDÔ@QHXÄHE¤Ç¼ð?ÙÔX#.Gꂤ@ƒÆYÁáõ×g¿Â¬{S(±ƒk—Ùæf¹!¡çò«W²®]¦Ûnºë[ÎerZOºÂ¡.TP¤IËúìÀ&#ƒŒé¹‰ÍuÕñVã1 Ng°þ["ALàlBƒêŽPoÕTBD‘WáU‚š¼ZƒPø¯4²mdÛÎÝJT²«šæ·¯¥Vò̈¢Ù+Xl…TzšÅŠê»ª-zjö»×‘/]nË\Õ|š×šZƯ7uY‰…$¶¤Õ©3J’ö÷í¶ØšA¦@¨¢G¶2<㥩Xý|º!ÔÑò‘kk™E{”\±È5¨p¯Ê‘•E.I#%}3@¡„‘„ËÁ±“,€erIcÇQ4×´Õ0NK2#.É#%½Žçì”è¤0#qÒòœMŽ›ÇnXq[‘l'µ}Ò@aš%Ç¿¯3Ëš‡74Â&iGÊ<Ø!DW‚bUTŠUðË›Â[åHŒ=TvU Äh¸¨Z7aq“P׈ñ0»¹aÌ°oËŽuÍ>¨½ ¥ECOˆbÈ€(¿ˆ|³”Mî®d=` T6qÓr.À;Q$!îa^Ò¥#.-T””iKJTÕcj´×¼®ØÓUšk)êWQ´ŒE%D/å‰Ðñ9™‘çÙê°Ä@º5]°;c{nÑ÷µJ*ÎdBdñaöü’6µñ³'¤.ÿ¤ˆý¾v™íFqp£FC²êNº–3ìBKŸQé£4Ó]®“#6¤Ó‹‡ý#.ËÌg8¨¼±†bCÖ°¡ :ëŒÃPó¨êÎÉ&&42i•´PËZÇ0Û#%G{ª"M18=ɉÝGÜ`‡+hƒ}ñ¡È*Mbð]þáñOC×ÝXd’I"BMçQýQ¹“‘ì<ÏÖônå¦F^Ϻú¹!}zæ±Ë`™ÉûdšWß#"‡%54I7L0µš…°3'øþ|ˆ@å¹ÉY¶çA#6?KämɃ:Ž’®MœÓûlp(¡©ÐÌ“Ò¸×V¹ "ÄëˆÔ§VlÃ@,×j°nÅF•@ˆ$+û™RMŠ6SHDÀ˜B0 D¢¥Ø#P³N5X©Õ4O4D1öÍ—á=ü'§1ÀÁ5š5Ò¤”{Û:ðeQÃýi`êñ×K”ã;4Ï×ú´1$ÐÑеÊc£çF^Ó#Ž¼ô=¥ØΤú¡©“§A>iéTSíMZʸk2Pù|Tà€‘¨ðÛ‡’„‰Â5ˆ¶PajJL–i˜¶¦¶–¤ØÖŒŒe5ù¥tA&‰•2ÒÏØjܶ¦e©²-,Í`•³LKlÛl6³Lµ™m–$µ‹J"©µ3f«4M5M±UQli$’1H³$#.GäiGåL"±£æÙ8î¸l–Ɖš¸Èéáü)D M´VµÔåV¢ÚÅ®¦µ®kvo^aQƒoѴצÕû»ËA'"vC¿¯†€œ#%#%ÛFÈD*TK[›R]Kí´·µUøˆm~B²#ùKÐ=Q_fÚÈH†EQ ÆGúZ#>Õ†–aõóØø„á¼ådzApQÙ¸»h¥âB9¨!áOGŠk§!€' %JŠ¾ØÞ!¡ìNHlá`G´>ÒB ‰zAm¨#%û¢Ü‚%íKtŠD©ìByìçx‹Æqä;ÏÓ×8Ï<Iµ#%CÁÕPÌÅŒ¼Ð“yzÔ´àµ!¶7$¹=ˆÉ6Ý*ax—2š^³30xã—è—pþ#6XXPµÈ…p>W·ÑëU8;€¡¤g‘ê&L‘x‹Ñ;ˆQÄ7V«ZÖ‹œKš“è6˜x#6ÅéØ¡›¼ƒ¸€p[1v›*®š@âƒ7̨‡·Ý£Bò8#. Ò\Ð;Ÿ¤:háŸÜz°žp!¬a#.DV„††‰#„mbL¿ê¯(Ó4tì!#6°I£±…Oú;N¦Ï”Rbå.¡÷Ã-+?£VF0¥VªêãìŠ~}мáö™mFÂiîAÁÆQ:ïÄ•ƒ#%>°Ñ#&’!ƒ¦-ŒcöðtL”‚‰!/Ù¯9ãvþWà¼è¥æÔö€ršÍù[ë9+ÁS:~“r˜âúýt&ø-tœõw–¼¤¦åÆåÒñL ,˜SÝðð4Ç]«Pø¦äº‘C#6(,H„QX€ŒPí‹‚ÇéÓ9À“óx§ï¥½#%2O‡ùæ&ѬH›€ø8Õ–Y!D1ž4P)#.h¤4–ÉÓL*vƒ#6HÛLMûþ¯ŸéIJB#.™žüX11¾"lN9anTG§d#6숒6«Æ%Œ `–6‰ØÄ´wc&µi︷l¼C#.@6dÏZ«Hfh…ãëU)%E`Ò‰„c JO´'ñTŠ¨â*cm¬hæF‰&(}q#%çDBŸ ;sR; SÎTyzg?~—<s/T– œ#.\/lëã:Þo\™qŠFˆ•(P¹¨µî€„âð8' ¬J‰Œô*Æ›‹›%S ×õ-ªl;w£DÑ@äàPƒ@4ÆBˆ‚¤PEÐBÈ”ÅPe'‚Î#6zx¨†vi=>~¼® QÐu€}Þ&`†]|Ñ÷N^@ÃÕUBÅf€ÔUЪ`EZó}MI¢#ðGðGù$=è‘ŽÞ;}%¡&Zi‚Á]ä4¸¸fÇfÙ«EC–n¢ÉBvP§`¾Cqh—„Š\5&+&ÉWsLŠjFà|Ûùfwâ{àrTPœÙ#6`R#.Õ!æÊ%•‰r)(#6a<,<Ï[Þ‰Kž:MåÊd¤.óÏ!Y;0•UQT»¸Y“™¡õñ²‹"‡½®$D0øBR0Š!ÔÜD½.Øbo’ìÀ#Š]œÌš T`Áѱ†É"žˆ.)¢†èÉdrf5Âó"^¬ž¿îi‰hˆžòœŠÝÝ%|Á#6‡ÓeOuB¥´àÈ©PÚW.T²¹[#.½i?†îÍL#%Ez¤#6©36¶~ôâüÞ*Ž”(›Âý4Ƕ¿Í»CVnÙ=è¾»VâHfmÚ¨·aYeÖ”je 5VWE·[Ñ$F¥”¤ŽÂB°ƒNÄy3ó, /¼ŒXŸ¼™½p †8¬§gdpŒ¨:©´>j"ìO=H£EëeäÎh ïË‹“§ÊgؤHÞ’–%?^uÝF§·ÙéV§mTS±ÄºÕ+nj„ÜBðôÕ#6´×9Íâ„BröÓ,à¾81rÂsÚU:âæìbúékÿgÖË:¼µÜ‹|ÖƲ:Š#6K%$—,è`˜#%*¨#%ADP€ÐÈŠÒ¥h€#ͨ¨In1€l+p<;ŠTÈ)í ˜©Ù¿Ó:þ°UyónêïæÔe³#6ÔeëÇ·VÜÞQöº1ÈßÌÕ×ë2Q#%dd!C‹ÇBŽbuðE!¤G³v#6Ð($«U‰`ѽ„ÀsƒqKòƒÙï Ñ£šÄv\5Ê ÎÐHÒž%A#%‚‰Î|É:LòOB§¯ÆSÌ‚N¦#64 / LdM´¼íÍr¼ó¦ëÏ5wŽÚëm¦ÖJI¶ÒËÇ’›BHTˆƒ*‰F2ÀD#6üÿ_¸÷J(-ƒ!þÚnêÖwÁrPl ´ W1¢Šª`Gñúnî¿«Âb£ Œb´Fϸ•:Ä6Ö4kR&'Ó&{‹_¿´)·w¶õÚV7t\-2á˜Ö5bB<* ˆ\K‰lH2Ym@¡&©€ª"Ó-PÒËf{½•nçˆØé¦{ÚG.®ÊÅz¢ç±¦&#.œ¼zPšÕ1`W¨¬PÙ²‡2¸ÛO!-Ý0éà›È”fÙF¢D$ #fKÀ0‡#.`—ömZhmmèØ•áͳŒX"bͲ9PÃ(¼X†m–ÌG0Õ.à£MË쀿˜â§iÅLüI!1²Éb;EP DüÀSqS¿•c²vwñÄä'Ñ祥ÎUñ<þÞzªßòNu؈›'úû¤ÓIŒáÂfÊbWGq'NÄöP”!×#%ÄI¾åmøÛ^ef’Êd‰–’ÒjØÕ)}ʾÖÚL®»U?OÇ—ŒkÆÛ•Êæ°µ0}½ÃÞ^“xÇëaÎ6<îXJ.mèÚ¦Òv¨"«Om¬Õ¨}Pr)N=\w†žü²Ëˆ«Ÿ(ײ|J+±±òT-ªä`UíèvÙïIðƒ{¨óÎ!WžâÛoUx$˜§áUýÇêYÐYy¾áa©<–·ØÍn6˜I6=Î q.ê`˜Â÷ývÇ]tú¦øo¹ƒ+œM`sZõQ4$n@âtÂpÅ&/m…ÇãîHF1מwë߸Æ,bÅè¬ÞBðì&Ù3‘°kŒÕ&˜†72^A#% •·4ß¹çLÌÑL´K3Jj í>E/Œ»ÛêÛçÌÚA!~ï,v7ÞÛ¯é#sµzø%ªì2t‹·‘ƶ€BʵŽ-úð*¨ð ¹FÇò,¬ðç" sž^ÓÅC^´GÌñUGÝ‚!p6m=ßmÃÝŒ#6NÓ0¨^b!”d%]±‚-Ê.ÛJZÊ0O¾^!‰¡ÖÂ0ןbí‹-s¦µy䃉Õe‹´SZ·°òüX›K¾fsMÖï%ç8Tb»üè\²?}{Þ>%ËÂça‹8ð‰øqgêd;1Cð™)æÁ… €ªT'çd%íBnpŸêá·>Ž¡˜¼»f>¥ó‰èÄyKp#ÃææG³´ÕsmGyç…cQ®»·¦Ûš%¶Ì\U#.¡$‰HH0‘Q·™KAŠCo·UïУç»Rˆƒ*·µsà$.?çû‹õà¶KªbÓ\µ…‚ň„aÇY2J2ÄTX’ (·VyÛ¹ÖîuÞªZÛ¦Û#.1A¼A(ˆ‰ð ¬ ^3@¤dâÑnÀÕÁ£ò—ðt£àyžˆ“Åù¿r=‚÷‹·EI&þŸö01ü›„$Õ¥³º[›Ðö"û·'Ã4Š|·låËMÓGÎòçQÝOg”C_˜ù´4èÓwA0Cf±eÂEÃpÑIå¨GGè ö’à$ëªU˜èt§ÝÅÈòZˆ¿0óhäk>1"°Õ—,”W%ëFþä;ùq56z{þÎ@ @qôÙ(”yCScpô_{J!0£:tª4‘“™QZ$†¸ê×\×v庺ͩ¦¬¦ÛNݵu&ÄÚÛ4¶«ªØÑ\¦^.^]ÚVòµ¾l²„@ Å#%C@US_B„Ä«ËÚ”5ê)ALjºr·S9¬¹† 5öTX“lzï€ÀÊM‡†u>#.3ïk¤ÁÖøûí#ÂÈÉ j÷â¿«G„í#.Ã0¾Ãn”º·JYUiKí€:ÍËažÛp¶<h6Ú`g5!‘5‘È0°ØzùpÕŒH¥²”!ÍíÀuþÁë¾pS-VÞM¹”dmÐL¯Ü†á¸6uð|#.ÊäÊÉÜ@à{&ÿ}v›uˆˆÄE'™sj>¦þZ2nÇË׬-å®Wߢæ#%ß`+Âގɬí'm'·õ#.|¹_úuØÑTF#6Ì5å*oµµX~ÍóÂ\èÄgi[á4Gëk®“]ä9*éitQ™0#6ñ'êwÉúgúÿ§îoÛ`§ñ!(RÄæY}_’bû.“»áÁ5Å(,D‡ÙéPºRð¹ßSX§%DAÀµ¶&Œ‚¤?3Y{ÀZ$*Áöm™˜k_ªèzÔ.¹#mäÐl¨AAì[œv,€aÈ$ºvÀ¥‚+ã'C‡-®H4(an~#.ÐÅ¡´ÁëX> 7¼Pˆ“Å£Ÿ›ã“Fs¼ðE’Ó£pè&¦‘—K¨€ü~iÿKn<£ª{6±€g™TSE_çõð¾ÌÏžRI'EÔ,Ìï‰#.™–ümQºC^[ò†#6Èì<¶’èÝPi¥ÀûqL…ñ=Lo³#%{BhÙë Ҭܿ¶lÁs-†…¯¢jgÎ0‰‡€xAËÓ¥¶ßgLeXd¬b‘…û`Y)0(ÏQ3‡I!…áô®ÔùašÃŒý¡ø̽™:ТIÅÔeÁÙ)ýÕ‚Ô<=±®’áÐÁá†c),·[I_òÀ3r^”B8iý5³V-êWBÆCGµ÷cHgM‰ardæ7ÝÍO1U;žæf,Ý1!„Èkq.‚ìaì£P0ëO¯võѤÈgõá§NJ±ÐèO5Ĩw¿€y‡ˆr²þÊçõm|µåê#%ĨƒÂ#%p+ÓUC'‘ÕG Ìñä¦j&¨ª™ßË– ¡!ÞÀ[©#%¦B‡½‘OE«¨¶Ö+Q´Z5mdÆ©5£Y,mb¶@¢²*TEMŒ2…Èì5W‡Ùn—¹\ê4—"Ô–* AR‡æÀá¹Uz,.ã`!i ÅòìÚp:6ßvýøg7nYÁÞúËÝ;«Üd(]Š)5«=:™šC÷«‚Œ7ã„-\õûn}ªcâÀuÓWCÈ2ùmFm’CEli î°2d–S ~Õê(‡åíOyÖ!¤ØwF¿?´"„Œ5jùíÌ<ÁCi²”R‘ÚPl.@ä#6ê%ºéçÓ5„ÊU¨ü=¹Ñ®%O™×?#6\¢p`v㋜NJɆ@;$™Ðs]‹_2B‘ªPôÐöVâ¢ßÌ0`Cm¶¬×7¶Ú9FD‡·7|Y´&©ªVÍ,[þ}¯]tÁ(L:’"W. {Ž§¶@,ϬGüÛoÖͽ”(TÐJÀÕs’ª¤ ó£äI/#6½y³ªîfx²&qK¨*.‘qß<¡ˆ¥¥LÒ®%–Å#6eq}Kw4(#ÔæH€ Ÿò*EZ#66°Ö‰Ÿ-5¸éW¾`[É@DêƒFq#.በ†ÌªMZ¡Pwgåõ{ö²Ÿ7>Gcúìcšò0Ä5™µÕÔâ»×võo1“kpÄ&Á|ÙôO«Y…ñ–¦ãQè‡î>Ž#.zÞ“®ùŇ'èkj—©a¨‰„²ÐÈTʥȔläÏ$ÍíB…mÊ=·e×àšY bø¿]ع`±#%˜ ª£‹.êLãžÅÓ?ɧtÐnòu#%žNÐê„Ø€L8»1²üÁð¢zÏpÝ#.ž½…Ôêôn•‘êÌÇʪKq·t/Bª+5Ö˜kYfŒ…2ÉUBÆÐÀù¾Cˆ®YIô ÙMIÀǵ܄$“Á¨˜Ø:¤Â*š›ËuÖηL«w]¥#jff±PÑh×]uôÕ<®óõ§½æèQfðÀÆÀnBhT¬ci0xÈ`hpTZÔJÄ0`Ä28Ü«hãÕJ!ÁÑS£‘ ÉLkLD²üaÐ6™Þ(Ú߃pHìÃWÖ™û%°Dûo!H¤HI¬j¬¦ºUÍôMÌ‹6J´¥\é23Í×Y2¤ …r»ˆàd¨Å ¢‹Š#6&†Û¤ 3PEÐî÷ZH ¨ÌÝZ@Œë²Ä0ÂíV›52‘ ¥l¥f†Sµ$‘e6›,Û3$ÈÛe-/]Û˵riÝË›rAfë®[sNݽåÍy¼ï"h¡RÔ3–ùýw³Ù›šf¡å輸÷íï¼öÕæ"¢FJ°ë¦2†–šÙˆ¬ˆËAÁ\µh@Ò4EÙcÄôõf1ºÔ6î“#.j*Ócq¡¨ÑÈ0À×ÙUkH°[yÐ÷´IòãÁ¤óßQÆM¦Òp&äbÓ\3PÍÖ†úÀ4Õ½1ΙóEåêÞnÕŠ zÚéEF¾ÊËIµð[¤ö#6<qêšTU¶ÓuÛ5!(£ƒdbå´±#k7‘+®6½ª\®¦øµ]ï™\†÷¾’¥Y•â²"°£i1yŒic$I˜Ùi%ehCÑV‚Žc"sz(ˆ¤ˆÝT‚&0ÝÜD1§~/êˆÔaáˆenÃ)±²á™i©Ä3aCwc®<¥j[J\Mb0s.#.ç¶ÖÆÖ¤2Eõ5Ÿß`i’l(A£§‡£‰G½„MÙ·¥2AžTÍn¦©Üž]ÏDO•µ3JiAÓ«Ê_¬Ý»8Ÿ+ɳskhÁÇgjF—V4Ò.#%ÖcKlÆöõT•MžX…,A(SæX‘ôšçzGí ºó2Ìÿ#FœÜ4ĺf#.„ndÇÕ|PÇí÷k#zLö1Âf˜Ý—Öd6róo?v:WGÆŽ.Š5Fcmäå…tÈWÓÇ°…š1¯‰ÝqƒÆŒM!j´•M¶Vo‰¥Øz¦øã5 ¤§d†„˜vÎUjhÙµ†•#.\"ª9lT¡µ=³C#-‹ÃqÓéîó}&°Æ0#.7B¬¡û÷ Bì¤]”¬‹ˆ&Áê$åÜ,eeU»cõ ¹¸GãO8a¤)¡ ä¥P4/—–ººëtÖ›{¯5E]5fTŠƒ@Â& Â6:é `"0lŒU,P]§DÂQ %Ħÿ¸ „tàtë=A×n¸Ø nìÁìüô³,8¤è×æ¤EþÕiqu#%T#.Pæûqb¾e4~¹(ÄHægÞ·›fŽ='³¦ÓO¾ï×q6ø¿yÃ&ÒVý?²ç‹ª+lMHŸÜúõCÔÞ±\öÍ#.hÅ#3ÚÚmáîÝÔÉK#{{ºNÅËÖåyºjð=šy½\ÖM\l¹Ù‘K*̵ðòJpð÷uÐôÐïÛjØÍ-¿kÙ»£qFb!$‡-ÌÌÛ“¨Ù¼è®¹ãÌÛ„˜F6qÇ8hPhÂ,CöºÂ7ÌÕãµCdÌqÎám#±•M¥„ÙBº¯¹yÐà½ëš|÷3¿y‚!È7稺(4Q®ÛX0“wù¾ƒ,h#6?äè‰!“‰¸\£Êo/£÷õgg^i¹ã‚íÓj#.M,=6ͪ뚷ê³xFpSÑ4¦ì¨‰–€FÛ,„š~¦JôÖ±ÝrðÓ+°iá³Ýdý_>÷Ž„ÖéM¨#6kf©l#6Ì놡Å)”êýáˆ{Á„=óùœû£‚{ vÜé „R$T@›‡Ð# *Ì…°´%Ôl–#%ú H‚š›*GåB XtL„,³:jU(älŠFÒªŽ‚®Õ`]›[†ÖéµIµwŽ‹b×r髵·6îÜÈrêñµðË%‹H´ŒT©«œwUÝÚ±Z•¦¾+Uã[É[Iº@•%rØ¡#6BKI€`‡šW(0ú6nün°££a‘I}ø«Jì¹X½9*–Šae(¡Q#P1EŠZÀôÉŒ.p»Rշӛ͗Æ×ZïrÐÕâ¢%&±’X‚Ñ%¨OsË}2†±P”BTBˆe„EªR–¤_ÂëQM”ZÅf&i¥E±¶5™ŠE¨¶6³+Ó5I²Y”LɉTÑDmLɲlklÕçjº7ैŠ9Ÿ?ÉïÐÐ>ߺDE‰OŸjÚóÔMª+ RRËð9ì¿âŸ‹ÆýÝ^lxêþeËŸÝåEÓ¸°zÃÅ8ÓÕÝóa‡T9—ùhìž !¥ŠÖüíM6´”ÊѾ‡7ѽ]Bͨûf·äV·#6µâ×OÜêêF™æî¢6Ó»³®µÝ¤¥¹ŠŠ«Knk—5]¥+ZV²½vìÖj(ÄJE¦®ÏøHf;ÙYÈŒI–b2_l(†‚Ñ$˜‚D@ Ä:o',À’ÕPBMˆÈ4p#6¡a#.§gW¶¤¡Pm+œÄ4ÚÁ €™—Nκk‘fñÖ¶!4ž€õ…>ûµ>ÖùñkÑ6wć–äÁí0Ϻ¼è¨…Ì]hʈ°Ÿ,Ó`ûO]Œ‰ÿ3]¸™·7µLÌf7?,lc]Ì“MBbAŒ1H¬µ4Ýi†d8w&ßNÓ)Ä”v»Æ#.Áàu?²æñçãµì! 5éá1°<¦ˆt2b²tÙðVþ²ðæ8ÀU;¬"Ç‘¶C’}åtÈŽÏë“|w½µ^]™3aÌ8fùã—=ù6´ì§Í„%µ ~¹åšÑ¶»zÊW\=ÙXÛÔZh¸Ïa†°Ó(±Æ™må÷<H°UýÒvЬbE“È#6NÁÛ±=ôL~+"‡õ†È„eÛ)·‚È~ÏðV<0T‡&*ž“2ÊuJÚ©X¡à†÷BxQGš`…×Øhœ Ÿ-“T–ŠÑªKo•/©ZºˆB2$"cü„\¯IÛ\â£rh¶·’{:²Ulm¨Ú¹Uˆ#Ÿ”U#%Ÿiy?Ò3vµÇ‡$eù»#%ˆb Zü¬ßàTy„/o\½Õ.@Úº[%´×]§·-lfmBÑl@Eá1Á¢#DBùRÈ8$j©À\0z¦Fü¡€¸ á[oZµ¾‚[[fIŒl•m\ÓX¾>Ù*¼î«ˆžË¼UÚDFÒæ»É×>µž¹éw“W–Ù’€“€œãKÁhã*7j*”™A#6´¶³V¥(1Ä*ÛAÍXU¬!R#. aS#6$D•Q#6#6ŠÆ,ÊŽXI˜…vU‡ï€DdЄÂ%¢¤€äÄã0õ‡ázâhÌ RƒLcAA‡¬–T#.9?³¿Ïïç*®·€(øhyÒ]aöàŸsÖÐa`ªsêpÄ%X¬gÕ™3nš#.Ç#.³ÈÂêH9F1˜ÖKQ·nžíùîÑ™ÛÌmµ¶¾©kU~[Â` #.Ä;@¸ˆâ@HŠnüÝ¡ã¦Qð!¼*‰ï'æ£[£Cõmþè¡/C ;¡ø&©“òƽq‡j¯ù#%AD^G9ŸÐÀÓz*‘J#.Š¬¤,XcÍ#6ŽÇ+Ìf¡„zœ#%fθåC8>yóvoÖ¢ŽJ¹ÛïFØØé”8ꦈbCDÐ#%ÅEœ7áÃGÐ*‰¨á%ÎÞÇ¢tºÄ÷Å4Èn#6½¡1*ÃM63âqMí€!œý!ȵ¥ð¨W¬|TaøµX#»#hLCZ¢«xbi(6³‚Š±tŠ\°èYl…ˆEX#%$™—p‰4b9&K“`È°y~5D¼_¼ #%¡ôˆ^3Äê;HÓ× XïYU[ï"zGEM“pùC›Ý‘¶Íêц|J§NqÂIß.k6#.éï?XC߶ óð&‚©UMÛWJ(Õ]Ûeº»±š¿ºÄB¬€%Ÿò\;é(B¢ÔÈîLgÇõÙüÞôÛWÎôNÝWu\v¶Âegd!Q‹ò–Bt?g>YAh7vgyÝ\º2嫆”uÝâòœÜËÍÅfË"i$l&Ê–£ÆÛ´Û&‹S60xÜMæÜ®UÍÜw^vo.Üu×l£•ÝÛ¤W/ñäª9¦Ëy<Ëurîk2Ƈnój•hÈó¶Úæå®›VKhÔ¥ŠÎ·)³,›'ŠÝÝݧ5wft×$RÑœáÊ»eγQhÑÊÔX¥"µDh‚´m› ¹¸#6XTbzà„vA؉CH#%ömõoÊ´;TÄ< 8#%îGû;ƒ¾Š#P„ ¡A;X‰alExýª*ŠoN™¨xþÉÂ{S´pAÀúJA¸!áE ±#%ã›êwŒ'¬+Ó}†Ïu¯‰¥hÂ%öz3…#6ËïÜŸ›´æm:Ïr#%r"1Œ’ ”ÌÒùíêæÛVükZæ+kº¬ÿ¤¹gú£ #6Æ#%™Îžî6S!5²jÅjÐ¥¡–·½5{Ì|‹1À P÷€A!µ%AbÄB’VçjœuÝÔ²±c#.ݵêZðc^úªli¤#.÷„5w!,8‘*àN߉D l&’PƒtI¨ÅiéÓ&Iš#.ˆ½Ö|ý·\{úµ¯UÑæÝÛ½(ÒDH"^‚b#6#.)k‹`‰E•Tb¤"M(0'ñn\ÄÈ)OŠŠVuç#6'÷ð=•øØ 1†„HA„cŠQAû†j=•€Ôáa3‹¼D#%;" T€ÒÍ–ÖiµJ¢¶•fËMô¡ˆ!·/¤¸Ž‡Y@sÑV2#Í©ZdÍQ¶Ú…DüÏ&1‰½#.@ §Ë†HH"Zf0šÚÿmFkB¦km…ˆ7€ÉLÍv¦vÓÆk‹±_T,£T ÂÊ$6#%þDûOPp%*¼CrW¿ªúÖó6óô÷}w~›¢|—ïd`ŸB2¿˜¦gËñꟙ´Cå#%a‚aÌHôÿ¹Xˆ4)RkU‘»M¶ ÈfÈOÆÑv`iñÎŒlD‘HI'2's¤Ñ’õ¡²yˆ?Àáýb€@cÈoSÑ5·câX¢^ü-ëpqû˜ZÇ#%‰ÄÄ#.IÇY%¢ˆiQ8ð$MÊ$4ªB£ŠQ!.pK#.dÔþÕâòºmsWI*å^ï&ÅÄ*6VjBTBW@#6Ö#.c0LK½àŒ1†åËBá-$‹ok#%´Â "JM!hKEÌ©#~NÍŠªð»/8Áo:¶f¾$öû^à쪰pÐÖ„ 331(Ä`m¥ÁØx]âO,’½).àdË0L\Ò²u"Áb…0«‹ÔÁh BX’T°€²+"¢7*© H4uÍ’it52LòêUÖRnݸ6Âhüt#ùÓw2¢H×`ôÂò*ù{Ntp~m£fE…DAÙ‰`=aPP¬&i»PE±*Ð#6E#KT-ѺZÆž^Šv0ù lûa£ï€ƒÄ‘Œ$µb ÉS¯t·\ªvݪ–Êš[§.ê¾»mµõR¶¿’¶×ºØ+ìŠf‘MÄ”± f#.‘¨-RHE9À³‰ŠÐÂѹÑxOd#.Ášyþg2Å>?åDÚñç—ì[Ýa3FÖAÊR±1m6¥ÒqŸÏ#.¾r¯©†×PäqŸPì†4`!‘ÄF˜ÁDm6›¬‰¶òÉ’c‚„$‘¦ÖcÁ¨ñ©˜ÛvHEJèGŒ+ú2LÌRØ&Ç.-S9;7¶£´3P–—´¹”-2µ‹–š}¦Ó’òxPëצè!àDûšOË[ˆm4;CìAÓA?{@~¨ìFêøʈ;gèª#. #°êÞ#6&àÍdT#%¤‚‚O]#.0UXû%H€ð+Qè¨÷#6'dÑg"æ”Ø;¾#%âßh§#%–6‡ÕáüÓ†#.š¶ö!þ]ßzLÉ¿¿¯¥$уHX*fO‚'Æ"°›[>PAÍ#%GÉQMAû={”}ᧃvY¬¯ÑõÖ)Ñu©A_°d FÛϲ½¿†Šc[Ü%•—oEÓ,y†÷¢ˆJ2&óo†tÜÖ‚;¤¼6^o´uç‚A›(77ü“)– µ¶÷Y…ÄLx‹l+Ûš¨SÃù5ä4wòò$;8SV›âT:—<‘t(ñH˜Èª†',ð³™RÚ€ÒâRgpo¤ˆŒÂÉ2"ZBÇË0/‚x†ã~æŸÇTCîûÖþIõ‚h&"´#6bƒéC;¾¯3Ž¯«ÚÉÖÙ’>úWš‰ûc~ÓÊqÖ'lcØÆöœ·0´U>’L#»²8US›3H—¸¨wâ® B?‹ï‡kzþˆú&)¸E–m[p•´!oqÎJЗYÅ{™ÙL7£L€ÁA€Œ¸¦ÓŽV0>²BG.#ÄDDJª® )æŒM+I’¦Ík¥¦=i4b¦—sìž‹'4ƒ³>é}2ksá²HÎó|DaXéw‡kÎú}e°&f´R‹˜ƒÚyiÚΔóKÛù=iæÙ°y/âu+‰`Çxö$ÝÀû0}]‚ÐJ3ñdáË-^Ýø϶Û9@Ѽ#.3]7üºÊê@óÀ¶ñXTÕ˜¬Fôõ{¹Œë²›Q…2fqLd–¦ñ!»o³!‡ ÄtÞ8<µ†çÂôÈ6c8Cg¥B~óQMãøÙKºŒËù®ÇC‰mª¹"9n¨¢H´<J•#Öر–#%׋1Mn ¥ÊéÝÔxaöŸOÚŸÖNÿuQá´ÿb¨Ìñz` œ74*¨9‡N¾›tÌ Sõ–z¡Ö…Ë8 zJãì;EøxW´‘±3Cd¦””6JöˆHŒå¼Òa¯`&C! íŸó<µ,]I˜ZðÇá€Òß:}P#6f27¢– T‘Í6Eún§m¯FØØ™áŽOu—m×êoÙœºSV#6ÌÔýìÞ×éÀÔ’¶I&³#ø}3 lýCÖå¿YãšµÏ]Ú6·©d·‹jsÝ…M)gV\ÕÛÒÕÞ,¯ßë'õ‰r8ÃÒPòC5…U4v!yc:Îpôk¼¶••ÿd^קÃD~„»÷??[TôšðŽE¶»š’wª•;ÀkŽ½WÆÎÊ]!A†ùp£Îrm°d+Û #L`„Œ± ´|P HšÆ¹†ç—_®gXo,›¹iž¹ªË\ XyËú)ò¦á4·†§`ž8ÏkÆïgBŽC¹HÎçÕåNw3‰Uv0/ÏnñÑ8ª¡3'»=·„1Mw™É™1‚Ù}ûÒ2xÃER…¦§‘±PL¿@ã×¢LQRI5=û¼x_ZC‡#.eÒG§ï‘üØke(¤ÞàÒ„ F@½Ù¹€ŸuôWnqÈËÙþ/£ò色§Ù(oÒ`Ä‚H¿I/#% $;ÁðH|‘ëü!ô€ÿ8¬¾$DYDˆ‡vâõtŠŸFþX*G²»ÏÅ^“Ò™ÌÝ@E8*mì81P}°‡f>ÃÞ²âôž“s#.Anã"Ý3-½GCÔtä.9#¿å¼:öŸ´Ô>‰ÄÇpwÇÉÄP+m&™#%f¶FÖ´ÑÛd92hÅŸ$ÑEy#6,:@ä¡í’(:xÔw‡u#6Š©6Ï쯟T®Î®£Æ>ÞHˆ{:¨óÚrz¨öY5zº¹[(úù³¨å•gõ8Àu¢ÚO…±Ú¨¦ ¢0ôV#% FB$š‡¯°Þå<jØÀOfçDšŽ¡Ð+ö8ÍÆ#%àA)hBÀÆ+ Ä®qk_g?ë?¯à̬¤‹ÝOÞS/P@JFÒQ?µ•ªù±À2:‡ß·gˆdªH5R#£Ê‡ˆ;ãM羄Á#%óë‚xN_¼n1¬ÙlX+¤Žg¹·ù_•4k3>÷Vgl6éÎ×Ó©ñCqš×ÐEúW9³‘v@ÓѨa´Nø¥7ì⇲ñvVù¦…éì€?ÔTÆ'»Ÿe¿Ü»Ù;}`£9úì=§„¦ò•…A+©/þnw‹®B’v>û¶çU;QUΆ¤”RtÐ:`#A‹'BÑ1Œ«¾ùa+Ð1 MpAH!ŸþO«mmCPç¢6îÐ*Á#ñÈr=ñ?£?ùûKÑTHØ?ÚáUŠ¦7ÊIÈ—Û—X”ÇrxiÞ7•ÎåÆš˜:tà€^³Í£Á!žKòó©,8AüÏzßóÄw(I ìäh·ÑQúöùw,ù.™1øµZw®íb!&t4!Ç.ü–ú2EŽ”)OkR¶Ä4³¬?eBF1³öeÑ$í8xnÕnùx-ˆPúÉŒé^û,ÇãXFKPÍ<œÇ+•wOÞ×j¤Ñ¬E¶Ëf³MRÍbZRµMR(gfí–sʵ$‘Èu.kOU;ÏïHÝEUõÔ«@È¥~Ïíýש?£ú~dm”eI£0h šm‰¨ŠLBLh”b#M*FJ&…!&Í“a#6ˆ±Šü$åÅögŒxɳ'€«:û“7Ü›o'6úÝyŸ”R’M›vÌ ÜÆ0Øh4MÌÝ4¢¤aKæÞ7t¶zh%*éMð·åÆ^&y}Gå1ÑԦ׃M6`¥·m—8™@¨…{*E#R«5sQƒí‹“øø˜ÞŽ¨Ã&D¡+fCÐÄÆÛxÎ&cz\/Ó†À[]4šªœ„>n¨¤ôÜŸh#.ØL“ ïÖ9obkMNËÒuÕ.Âjõ!2̺ju^ëØÖ8ì3ŸÛë¨fèÎ[ŽG —ç_¸3ýO8†ž°Õ Úm𦶰9ãT’/è„™áž3°ûç™#6ƒRi¾m#%F÷"¢Ö[©Œ”¥m¦œiG#%0NPÈ©-D‚„#61u2H€âˆë—QUË;®JnVÝ®ésuu®ÈïkÎòYšÛ‰×·‰7®«—+lÆ4›hÆ@î’1ˆAš *ˆ‚•º%*»@Â’Žë&M’æ˘ª#%¦_å¬2H¢ÈAB,$Ö™WŠ¸rérÎësk$¢3—*çFד2 ËLEø:UÊA-H¡K29ÇXar„—ŽR×eFÉ‘?6¢teÌeÄÑs4Ñø©…~÷ð/c…ž ò—hâÓX!˜Ë#6Tr!žS“Ñ©/Þ:ãk‚Ãz)\Q„Ñ!TÁ`U«Š¢7*â͈Òll«/c\(›Ž!¡6BÒˆ’¼«³5A”«¥¨Šž;Í·rÊ.»xÖúÇ®î×uQ”õíQ°i…¢I¥Âħ%4Ъ!h¨&MŽ9Q%Œ²ÛSM©·LÆ<D†”ÓÄÜ$‰AƒVeCbz’Ū‰×*:R\£³Û+µ‚(m„UÅ¡:‰WTŠ7"B¡\+-£u´6›6R†Ê–ó Uj…¦<«•5C`À5·—&Á¼éåŽnãÀnUŠ.à»*.ÔÝTZ%ÚÔ&#.*A±Ñ©§¼Å¶e™ÕÞŒøÁŒÆ1š'3²9Daƒ[#.iHH7SlYe «UÆ«A–@¬’;)ucÔN}fÍ=,$‚î|ùWoŽÃAŽR<®Ó&ÂQAg–Û#©Â‹\\CÑz!¦©¦GK1dR0q¨²yܦ8BÙ¼1’EâMjJ#.ÁŽB•mÌKH'…p¬ƒJ¼—šŒŽá*8ÀpìŒ#0o”àÅ-ZN5F†A4¨·Bæˆ 2+±Ðj!B ›SR1F/4Ìâ†0Ê#.býßR ÷Øsȱ˜Tnͯ›7†nnø÷Xµä¢ÉʾNLâ!ILsC#&D™VE¶Fi›„‚¨(a S#6Hƺ-¡2@aZM'"1A‚Æî<j¨í˧¥ÁlUòÃÃÛæM8K‰˜¤A³¡ˆØ¡)‘"ÞZ9fñJ6Þ˜ º‡ÐÑœê äd'̓4Ǹj¨ºN0ü˜fâÆiûi—©²™°°(0ÓbÉQ”ÑHD5qîe‘éån#.nèÀ™O\m Õà*%oŸC#.«ÊŒM’ï‹ìu¦÷Â…wÀjïˆT™•¯¿&Cr—@Þ±¨Š¨„ÄpŸ•6Êäøz$×&p²±@‹V[i¡YDæË(F )96pÒ¡&4©J¸(©0Ö\±‚’…0¸†(ƒæ!B†ÐQ!bJŠ£"¤Á€4‰ŠÕƒ´‰ÈÂÓGâMI)Ǹ9pd!U!Ì[¼;†îíâ+Îòé‹Q’×b‚„ŸžŠQÁHµCTˆEÍIÀ;¤’‚Ú‹mŠ¦Í¦l²Œ"µj …”Cñ`§ë.ÿ3#6ä4êJðüû¯Ì("Å#6ˆˆH°=ùÀ=Rc·.£÷e‹}·ªŠ>üR˜ÕDôÑF¿œ•Y—Ú>REB#%!‰ŒT£AÜ‘Båµé{T}µ*Àì=UíŒ&„æë§ÎÎ00Ò °W!P‹'Û:D¯µg<¼ÕF r†™„O#.4P÷¨ì¬p£þÛ2FÄÙÝÛn®®›[{k®”;¸[ºU0Ir…Y…ƒvÊk^(¦µR˜¡LdÁ’ RËuB¦æ»³qP Ù(f3Т#‰omB‹7û¾¥°·°ø\¼ÌÚÒ㌊L6-Öýš"ò»-ëÛ¹Vçt$YÐI€ÛâóÝkXäœ$Y¬Ùæj±ˆtª/œvA»ˆ>#.¬—½HíÓÒ1ø¶GÛ«ÃD¯P‚VÑõ(þ¯àˆ© N½¤€L¯ÈÏa‚“‰‰r×(‰œ$ìÝÉÐ’³àw ïRb4w‡^×»C¾/…ìX,^¨bK”\«Ù½-!®ÓlßMvª|ºõö!üȦ7@Ï_]ßÌØuåÜ(7Ñúþ©ØÁ#%Ë·I#ú;}+¾?}œn‡*œ>—Û±ÏÒ[ì×{oѤvÒBÅÛ³É~¹¼È?ÈùŒc(šñG‘© ÔU#6„+¿æ‚d礇¼ì½¦ÐðÉßz†R‰Ê'j[br¬#.v#%ôηUŠšûʸT71wVfºËmŽEßÒXJ§^v×# ïEC°yƱ,• ìA2±A„ETù°’á™òNÊR¨QeTÎÞ‰rá˜\ö9Ú5‘jªË#.&t0ßá‰cZb8z¤0À—mE„þf³ÈßçHœŽ°Mq4›¤Š9 #.þš ÃUHr¢’\ªévÜV^ßÈò¼QkÚr¶Kh·²ÖìKrîêÛôK\6¼UÆŽnVéµ·MY#.cnm&Úæ²k—-µÍÞír,m“jQª+—‹;«î-Ã#.âw²Ë»$çžv÷07Šü<¢ŒÍ}Zk¾˜•˜zÓo´=H^Êî"Øκ’!7@A"ä#6´Þ”=¯íÂäD´‘ƒ»¿vú®_†o™ªƒ‹¾ªýQy>ð)Gä#6çøÑá"É4ÖÂ=$±òSè2w@d#%“Gßè—q¢1¤(š‰IBHå%ŠJ*¨Nîòá^T#6Z\# x Ùb¡†*©""(¤›[u#.mt›¦µø~{oF®Ü¨Rd%ÛÝäT]Ñ *½Q@–Q¤ÖHѶÛ%[¿™~k÷!D,#6 éB?õ@Ô#%šÿ$CÏ¥'¾ûHjÆMöFÒ¶FñÇÙ{ZPuðP甼P#%;²f_Œî@O÷A$‘;ý&Ô¬›¡Ôu`¯ª¤ª£Ù¨3`Ð: H#"&Q)òT(uqe-LÍ’IJ1idŒ´i66hmIEbÆÊRRJdÚ4)µ´Eª*ØÖÔkjZV™jZ52¥bÖ‹ci5³[ϺÏn·$cu¬È²#.Ç"6W"Dûne6˜ÛaPÊAÇ$r®tëÓ£Ò®Ï=tªò®<ìiq¨ò¤©¥’D£O c!&$Ü*+hlŒc ¬H˜É-a"#6@£`èÁi†“#.‰H…4ECJ¤P*( B*Zë0$(¾B¡ Ô#6Y2?Íü5°Á#%™ô©DØ%%¦îéݘÜ:ÓõÚô·W®ìÛVÀ(@d‘‚$–f2Óȸ@M°%Ä^û³„B3ã`ûÇNÙ"vÔôôm÷wc¾²³Ù”„…QRN {ABH,O½¸VÆÈŒÜÐö5OÈ¡äØf2vp®§W_—[—,1Z%ê/-l@Ò¨ˆŠ±±Ü¨Mâ xFß—¤jœ¯§1p‰V!TÌH!PáJu”0UR8Gõa£ÜœµõN¦’„µFénãɼ•ÖòË©R™”/Ú]êµsQµ±hÕZŽê®Á¥±ìóp–9‡ávº?®HEÊoz¤ÑïpÛ2#6e_ìÓjÎ`»8C®+dßX{Ap–Â!ê>ÿï(ü±YD©Ë³eJ[LTz÷F"Ë`ç`΃՚‚RúÕ ÿ™ùiÏJ—Šê%áMY¢ªS|š²|‰š®#6‘u¡‘àÖ½usFpÙ"}rC¼"Él³Êª<ÂoבøÏM™Ïr§ý–æØè„#Æ X}¨vµºt¡;?;#'•ËRùi@Ü¡ÍM¸Ôã|]?ÙÒί^¡ÔB}¨#.#%ù`ø€¨ÖîAå—Íã°Ï/Ñžÿ|hÒl\1º**;»3Ú*¥â‘TþÈñÅ4¢ØìçÓ~ö3aƒ¦)¸÷GZ³*¥›z—ÁÑÇUƶÜ` ÂpÞ]ÎÚ£]u\ÊJã‰Q¢ë‡òUÓ3÷˜‘ðÁÆ&Òe¥”ÌI#‰ÆåÛJ{ií'[lüÇ¿Üo5ÕÛÄîÙ¥º'Q#%ä3!O¨"e¨BG½V×ÒH#´'53×ÕîZ×#.ÃP„˜ñçRn tÈCñžxm÷¦‰¾Ù¶Uúûïy/‘ãV°A„<(}ZÒÙ81K²‰$=·E4œ¢Bl‚:E’æÊSlµÉÆW_û×¹/#.ÑÛ‡QuÔîí®:väì³G¸\§”µí{KXî{îV¾¬#%¤LÒ#6Bk¬¨7â¶(/%ÀèÞà÷Ô¦Çb-¬Ä¢õÂÕÄÀÂFÅÆixå$Z³™F®;ûó–©vÂqÙÔ!Äg ÷7tVBZÇS¼•/yÀo#ß«½Þ%™&‡s©X½*77/²cMž±Ár˜øW^3Ý$"“Q?:yÛ„6"£ŠéÅƺ–{åøÉÐ#.ôŠ¡¡”ÌVË~ügƒÉg‰smm9)¸®jWMöÓÃm‹f±“ 虘·â®8kÃÓ[é‘þ]»±6årXöN”VRTâÌYÍZª¥;¢øùžgrª³s BÄyo…,pѾa& q<£“jf)‰ÐÙnÆÛ›ÐÓE¥Å—•›f5Šw©±ŠÑÄâV\º)2›Æƒl`œqÑáDë¾x¶ŒÅf^–a›TûåkĆŠWnëh6“³m<pæyßý_ZÝ>Ø—[ÑÆçhNI/$“ËÆfš7Ž)¤ÖŸô•öÍGŒb$C¥×ÃŒêC–C:ÚÒsŠ/}Ñw§Ê€ò¶DÉJŒnÛTóQíjP÷xÍ÷‡“bëZ:>춖Êü¹Ÿ9õÌW_J×°¦ŠéyƒiÄÆx’»uƒw}²™×:üç´ç”¼Žî'÷u{õõŒa*Ž½^W‹W0ïoèÌÐâò¹˜ô³8ÎÜVx˜«¶®œ§|ʼntªCVo…Ž†#6åUvga*Fñêòª‹éïlg¢/Ç=˜’Ã5ÅéüÔÂln÷.úþöb¢</Deìóիô<¥sïŸ>NÎ lr²¶AÅ׬Æ<EúûcÛÔÑìôþÝ!˜ ‚"D^æy¾8Ü£ŽËB6KÛ8£,g ‘:d©D÷˜ÓìLíoY°¼0PÚŒ/iÈÚyÔsdÛ)Ž…7°²›žTîÃ÷ä&ªhdrå#6%#.-í/Š×Cð&d«©.]ê™'O8çmÃ7£žUãŒIð,¦`œW£2êçµ8ÏNÀÅî$`.èXÌ@ð=Z¢Ã„ì÷m„R†˜m³³£f3ƒg#„RcÀÞQä¼b3x0óš˜ð½0„_”$gB†È›0íÚº‰9¥#6¨ÜÑ)¯±Ò'¬Ï•Ç– keØ yŒc0À)Õ€t™±…(ßÛíÖ ÙdJݧÍ-®¯®ŽAåÖÇ“¯0É<¼–^G¨&ê@1[õ c®UNÃcAÈn>Ð o#.°†(ÐÈ#×LC÷ªó#%€@:óš#6`FãaÀP™˜‡a»ô:£L6ñÕýxõ»Æ`vŒž¥›¤•`qG=æ26ð•9è•ÖkSAC«#%6ª„sÊ^æz±¿v‰•‘ Z3Kˆ—3.ªÞ&˘sxÃ\ã#6?#6«_Dd\¨¡PʸG`{»u½§D¯OÆ.þîO'6÷ûÞ[ž‡“°ìkÅÖÈ,½ÓÀý* “„GÄÂg ¾T©œ"Vsïδ##ËlºNÁƹÓkFÒéaùC·”úÏòghæz¢:§ç™ŽŠ–”žç—>ýcšŠETÚQSSNFüb((±SöÛœM—Äe²Ú{Að]‘Ák]zVÔ4o““Œ{#.”Uû»ð*#%Å9ÇGÖ“ôÚÏ6(¯Û#.oÏ϶;3\4‘Š¡³G>FÎD(Öѽò‹çÇÑp²9–žfª7 Zæ0ÙºÞÝCë¡ã’šÖ‹NÚ21D‘ª!ƒŸ.e-lZ'ÚUbÕõQÃØ¡™ç~%‰@½vÝiVkQ-29¾ysæ83DñÅì^[)X×ÕÚÉš"Dv:e£;F#6Ç~›•Ù¸°ëíÓÓwÃŒãWoÕqÜÌ‹²¿';¢Cs:ö#.aº:ë¶Y¹Tû›èœ¯[–ãÔÇ4v4n s©»x÷ÑÏ;èÝ2÷~öç‰sw~/´j¦<“£\W‰t·Œåóm‚åG‘^5&ŽÉoä wªŸ7AÍÄ%å#¾Þ0Må8pqäñ<³~7SÛ»å߃Ló‘Î¥mZ¡\dõQ†Ð{x09hRÄ¥ˆµ¥«#%}¥ë„ô—‰”D4·–bÍ…èŒ3¨ç’š®E’=¸¼ó‡ ;Hœðà>.Ãx[CUZØ=íô7,Èh¨·tz=<7~†O›œ í†fBñEo7ê9q À°ï‹ˆLBõ«•³üñ6°§«Y܉±Y…„;W¸Žœ–Îå›\¹Þq.ï6…)sf\=®Ë#ÕƒV4(êvµÐ<³Ê@Ç”,,¸Œg ¢(Ôyzw-•HÕ]B¡¡¯E´öq3¤:f,öÒ'!Ñð ì@â†1HóFÔó vM\;€© É3@Úõì.Úg$$VtIm-äSLÛ0w0ÈÁ'‰#%ÕY"aÃßôèU×]õûC#.˜`fá˜+u¸mæò?‰N®°Cw"³0ñ²)qO‘n"xXŽ ‚í¸NÛ&Äy~‘å(ä·°ÇèpÅ`\r ‡Pž <ß‚ð(;ïÍVßáL{U#.>¿ãxKf°ÂwÀõüƒå'™y;`kàýpÃhST«CÙç2°gÏ¥_V«GªG±8v'$ODMáÀÖN}®;O‘[Tb,ŠÈÃäÒ¡E€~ ¯Á°e…D–aì»Ímlš…s˜Ô¸ª’“#I#6±Kº’Ì0ªm&@•<Æ…(Ó`YF91!²²"¨DÈ¢–‚“EXB!$JÆÕ½+F·5¨nZÊèZ©”‹"(ØÁci¬¢ÅFPTÒŠˆ¢aQFR¥‚0ø!\Þg¬âþ&xØ…µ±Î@LñÜî#…# ¹vÐ…á¤é$c9ÍbŠž”Õé¼mãnEɱ*µ¯¹m¶‹V®UQUUé¹UײóÇÐÜŒÍýÐçP:þ~–µÑøC5÷]cÇ-–§AKxæ*Æ1ƒK+udˆ×/¨ÒÁí¸i¶í®oÜ#.hÇHiþc£f-+°£W ¾ù¥SáîÀkN4bJ³ÄòÖ:¸`@¥,×–cÉ –(2ƒtHqbePDiòãOR;Æ]ÓxÖa%‚dH°!V“7V˜Á·Ù(š&ÓicRE,%ÝEcbi¦4C®Z*=Ê[ÌgA§Âu‹wL¤t’d½>ùlÀö›L!P9l›ª#6@Y0šÂfœ‘L7zUàÅ3R·X›€QŽÆ6ëØËÖ¥4ÊÑÛŽv²ÍîFjh£MÔU¬zmkZ¦A¸Lk.<“µ†µcÔèç9«eo†LÑ$D”MqP\`SZ¨X³LÐ*±c‚ñcix1”2ëB‚ÕC$Î¥¯Õ¾5©Ï9;·hÓaYÎS¼JÎ!ª#6A,ØTP”2„ÇcLhÇ»*ëµs½µPAôãn²‡U"^Ck*œêæVú†•“%+XIwÜ&]J&0ghnÀot‚ÇßhsiH“°N'a§ïšiÏ]P\‰ªR8ÙFö0TjŒ?ªãÞºÓÖ“cSˆ‚ò£œµ.¨CZF“Làèd¬q¨Ô"Ú7*ª#6”*à Ѹ”Ðá¤0m0m15+‹‹FÞn-¼™,²»zça›[ ¹tùÐC 2´CdT¨£]ž&09ÜEZÙ*å#.hFe¡›±—mÝF?Sã5@‚ŠLãRùg%¥¶È|4k ¸Ô €ˆÚhŽ¦ª~¬¶ÆŠä$¼*7Ä®é@ì€zi¤„<˜D¨°]8&è .ï®r#.V†FÚqÉ#——B–¡ZYm r˜m†2Lä„ÊlbWfJÌæÚ¢&n\c§ˆF±V=¼§^1Q¼ÁèÞi•®›m·Xˆ9¢VßãÞŸßÞŠ= GÕy˜úe”}#611(÷"Ñ„Ž·e0Qsâšz±ƒXr8c™MAø¹¢@‚œ=6ñalÊSŽ!vH#.0ÕŒÏ ¶–‹€û0\d#3ÉÜ$d9ö¥›:é¨WbTF¡£†MP1#BÌðCV#6æe´Î-ͳZ"ÛhDF¤¨b0fµ8Ò†¸Â±¶FxØ7‘¨Ôƒ{ÔË ¦A¡6Á&'"Ë9#.+µU°ÍNß!UíÏ*ª™Û2‡s—£Û1ó•M`ÁC!0çr‡c$’Ûã½n‹ç€¿¦Ì+¾îÝiL™5–MÓõ6¯ÚÙH•$ä”´•¤$ˆz—O™®;ÅÝóèºbCóHwÀ©ÚªwUŒØÖÀ4†*SmÙüçƒ U+ {}E*ûXSÔÓ^#.“ñqº²±eÓ¦3™~sÈ+?2CÁûàÿ›Ð9¯¥Ag*Î*JAFä#.o³·Ä³Bx«ÇzQ€#È›»û<*±¿®væA§ öœšÁ›Kˆ?~Cóyßì¨×\Ubƒeª•Áå˜ó>\f÷={p1¼$a¦î“»¹0ˆ¿{w@y9;šbƪ¦[ƒ'º0’ÇotÜòä<×Ñ(õÈø¦k´àµÕ÷¤qÁΑHû®øŽ›ü!‘¬í£Q:ǧ å@Hµð†ç©!Í’5iŠ Wj™KV——\Õ‹m]7‹hlPPH¯Ð†¬»öÐÖiä#ÔD~èì9ߥ}~•Œvý"°R(±H#%VZÛ#61´Œ˜Æ&1¤D©(Z¦UŠil[%¤¶¬RQ¶$¬š4(¦Ê£Í¡M5#JM’Q³JHIQÓhD¤KFHS4T¦È¥SF’a¶lÂ%(I1«X!#%øÞ:úx—ôÌÔžg´ê9šÉSÛŒº¬î“¹[Ç4UyÜÐ~ðWæòs5þW‘$$g1$8)×ÃÂÚµâW#o®å$î—VÐElO"¨>œ€#.¶ƒ˜4~‘ ¼Hga¡„’hf6ؽØLKn£’R&¾~§Ûzk³pCõ%ßÚ(2ÆH\Àù9q]‡=½haѹS(ÂBY‰èâ°ª¦$ã…ß´ùû½šÂùïâsþŒCJ‘FÃÅqy§üÚµù¯×ÑÖÇ‹{!Ãë: ûo?“WÝjßµ¨’Û&ÑXªKXÑ÷Ösi±©B“Q£±õÝ«™C!b”R©bXK2ïÈ0'uàEŠ$fPÉ#6>ÿ£"Ù›‹)ƒí¬÷ó.#.ƒ>+„¡Q…¡¦b0ÜürèÕcD>n.ž5ª(àÉX¦¤ŽRb"©¢˜ªŠD.éÊf’¡”+@6lxœËRXÐV,Iˆ.¾Þ1Ó{¯.íГ³šöó«ÌÑŒ¦»6ö•å&ñsD¬ÊÜ·/×–³PQÀº.a#%ÅÝÞ!”`ŠÐ¡GLŒŠÄˆÄ½G¾ôÓIà{è5O‹†EÉŸ'&u1p6e¤J'LHQb`àËVAd¦¢ ŒbŒ¤…(Œó©#.LáGô`6 kgì›Î¼Þ6ór1J¤NŽ2,=¤4,°pˆœ¦˜„| d<ÀÂÛ«6ìjHÚÛElmŠ#6#%ÚÔ(ƒ"3@pBh_²*ÁUY‘U¦#6!ìßÕºLŽ@ ¦‰@¥+†Å-= #%½]”ô¿~7c¿#´…`>ϾÈ÷÷ò3Œþ¨ž‰Cft½B$#!¿ö?‹"dê…„|êÙ¾~h%¡Ð{Ñæ#.‚’Ÿ,(`šä塤|ÈØ”n2¦‰”LÓÈ3ÏÐ@„>€ã7ïØV†Æ’iy¼Â°÷ýÞ=ßµöR|ª2Zûf‹5ïðñÆUo¿[52UQJ–m¯ZÔÆÊJýKï*G;ó&¦¥„uÊqµm¢òêg™*ñ4-o^…°n2nF-tiªD§7C5Æ6Ó&TS`Ò&Œ!*Q›±A÷Ärê]uâ+NA–«B/¯Ô{,¢tòOئÊúÓ’rµÉF¯Aï J+«)è(° Éë;øNsê>«íó]ÊMË°#.ŠšL†|ÊÛéRæ!Á)’Bª9£^¤ÿjfÅ<Ì;¬#6Aî0xw;Þõ†HA)4g˜fzúœqŽòFõcÏ á„ØE¡kõ|¦!»°uªMG&~逸²#%Q;úŒ¿ÜtŠ@d‰"Ȉˆ*¦#.>¸ô/}RŽâb_cóÖìT#D¥:Ζ£Ê±rÖîõý“'5>‹ç|â²âè}.šàý_Tl×=ÎÜÔ²]4X`C$0ÇVêã9'HØv'F³ñIÚj&¥g™õ@>3¹“ŽÐí€#%pàJrê`{ä7s@òq{ÊA/˜”UÒ\zge)^±²=sDþXÜÆ1×Æ£ÔŒå°nd[wof²XŒ‘²¾çg)P’6B·Þ\+ÉÚEµÜ,3âÍ„JS»uUtDÀý19Wž53ÂpTlÐÈÓ#.¤c€h‚` ñ‘0pP#.@ŸÐnªÁ`È%ÿV TU*2ìÈ/&YÛr-Þ¨»5!€PÔÊ0E#Q¤H›a¸’6P";^-ˆš@â–YÇ1Ìnì5Í—™¡#%1”,½!‡sˆYÚŒñ¾¤flzÙ¹Ôé¥ÁciDã&‘Ho?/3²Ð½X2Ž(uÇÌ°´ÃdÝzYg$äÝ&Á5åDˆEPÚ¥HŒA±è~“3#%‚ˆ Lˆ™ªÀC}ŠYf‚-"¼¤}q¥£ÌàIQ%¼†Ø^FZTz³µšHÅKÅ"@Sp¤u^<o.ÈB3@Dmï½àâ…×j”ta¦lrÞX@z‡QfkQ‚Á¨‚À½Aƒ(Ö÷Šóò¯n7ÛžW üï¬"ù:ÈÏÓ7Ò`ÀR7{ƒ¦BdXg&ðS¨f%¤Š‰” É0ð»,í‹ýî“•¶ÜD¶uS2ºcre38ºt#%™aÁ%ç»#6Lp²O§pß’X9¤à»WD¢ƒvkb”Ô+LÄ#.–܈#.»³BñC7<è‰D©#6H2#%ë¸ïšµ‹!£!PÅ X#6ÉŠH žºÄyŽ-•_F¨é<´ŒöÝaš•˜ñ¿n«ÍÛµ±S†o1ï[ÍœVWÁ¦e 2äptc¯,ã2®i²‹í˜Žs¤°ðŽ4F!ÇöR¨±AV,ñ³á‡‰$Eïæm;ÖcHo!Ó@3k9LJ_™'LÁ›YÓB¯iè1@'*kMž.³ˆÆ£6™‰6“ A»m¶ÒÁL\RE΢ŒFe¥%o˜Ý“*—,už›`Á´¾Ñ‘9¥É1260ìo)¯i#.&”÷Ã@V«¦Ä$l‚tšÊvÛck¦—r˜F)œÀKE ÙM‰,vLí.\º{Õ—[>!m´Áiå¬Þc#4Î!äkû}av˜ÚߤœljW¸ä'7qÖ$[¬vŠÚÜßLU»ÆD<´ÑjlìïôH=fUÌœL3™aè’'£>4‹O¬ÈÐŒ!Zõ‰S5{ÓX¦¹‡—CÎ&—;±8k¦îŸ\@r¯2n&‘='I©Zã¤êBÅ FÕ—„,¹\¬*ÍV׳p™`—\ñ©HfJ•Y#%êë㚨‡"ß‘kkÌ›%ñO+vv&º?grà{Þºç(äUÐä×I¤ X¬E#65³6É›!ÅdhmÌóÀé^]04©qs:ÙÁÇ0@ëæE}h·¨nœLeÁÃ}8 ܃^-1³ñ|2£Ãµ÷@¸p´V×›;"'›‚å¡„±•X%ôŒ–ºí#%í5`+IB27©t§#.NZÐÅ©º†B¸–°Aø±b+m:+¤‚BN\¯…mgY¬ñ[6L†ÎÀVælåŒa²DgÑ@iµDбP<ŽýÿB㌱§4ülÔ?nŠMÖÎð„àM$ÕY'¯BÐòtoi´\Ûñ¥Ø+~8ᥢ]-YÃ[Ôtͤp‰?UÿÂQm—2áLØqEÍ#.q™ƒíñØåÓ<<4x¨1 (3Hr›ŽÞ<9²óëktò ¦Æ ‡r³òëz]YÒ1Íñ,ÌŠsÕ¦)³åÈFµ.ÉzˆÂ—y|²ÂÒ+d׳„ÛFó~BÀ™aud¤Ö †l”ŇÇ-Å…µ¾ù‚3XSC´=‹‰±ùq«óëth:j=iu]†Šp3B„Àtž§¯_ m}i¢2HÛ bvvÏxâ«$3@ä½Ì·gnªÕ ³ ŠP—JPÍHÆÜq!¦YÛ%j®`Þˆ"–#I¢#P/¿=¹fgØMœÁC´;,LMµM4Yp'Ò*Úúµ˜·”ÉSìÎxÔEë¹Y¦§vM€Y@ôðSäÌŽœ™è‰åå#6ݹpf#%ÊÏÚ;tíyA&w©b¥‡OLìO#.&Âé?8L89ÞÝ“M7ã%†8Ž9Ê¡Ø-u#. ³/L]Ÿ¯\Õ¿%‚Ú.cxŽ¨b‰4&µ!Ò`,fÄlLM‚á#6˜‰Ó£p:5ÒHÄÄÌü¤Žd‘A¶¢„Hø0Ì‘Áö4EqT¡ªk&§xÝÛ3ÅÖè)ïe£(Ã1YÚ`¢ÇŽ6!Ý]ÛÑ.$#. €àT–0%DH!¹±Z¸å9Ç´ÒQ PP4ˆwŒšÈi8,ÑHŠê%Fl!6aeÈ0à\*hÛiD5Üè8hé™–*¢P ƒK#6¦æÃ@ÀÀALCÄD‘6D“áS*¸è†wB]èÊ4,¨6"ŠwA³½ò3bà‡"¨)ØÙ˜Òi½‘ƒ†ûøU‘’«Hªå¶ÎMlEÜ 1 ˆÃØ#6š6v4#60gSP#.F†¸H¶WU%0MEó& 83ÐíÄ„3œmÂt대ÉHrºâÄ¢ œBB¢ê™•¯3[Ò^6¼¯_#.óˆ±c%%¾²yyôŸCk£U@Ê(¨ˆ°×¦Ž½Èš“n‡£¤ž±°f÷ò C°5#6,"B@MbªPê ‡á¿öôl½€Èë:½u‹yÑ\ƒ²íšeX§—ëïk—°Õy+'J#.?Ö>£MÃ܇)üŽøx¨âÙàm&-£™×B¸kMµ7ⓃIfŒsQ‡fE°Šë»ºf$‘$#6DXÍf¿šY¯§·š#%ó×W%U®ÔEüðMÑÎ^hÂò¨I#%ê¯JS°x|k0ÂJh(¨Gf‚uaÐÆzífˆ?“nôÓ'àÒ«„¨“¹*3#¼¹R'W((q#HªÕÝe’iŽè3³%<ªÙ쪌JÅrØãz#ÈÄ6¹–7oSñkJêF9ÌTÍ@Z¿0TV(NAqKìÍËVè+ÈämÎÜa·4}o{ž«;Ù¬å¦66”˜µ²¶[[:ÁÖ®¿¢>¡DHª{hˇà}*s9e¾Dʳ:¯«d{÷ÅT°3ñD#.¶CvN]GÃL—@SÞ¡#%4„Ž©C»¶Çá^Wf“·DîΗZ²º÷áâÔRñ7p#6ªVŒˆÚX"kÕáË»[Í$2%ñ5;Îéo7v†È®òï^vÉåÒ¹Å×RÉ#6A‘Ü0@4Ћ5*ˆF ´8iQ¡øé3 iŽöGZK(4‡]-ÌUDÖ7v)<´MF¢¡ÇgVƒ#34u*ÌÙbQ „GFùèë쯷»È!ð†<ýZ÷H|ÁpDäA#%¦Ï¡¦3ƒõ†j‘¬¼•dú.ÖÚ1<#P„$xîamˆ…ÁV†ŠÄ®ÉÉL+ÃàÀØšÁ$p ¶”(“Ÿ(7'§¨&µ9w²#6nc±ì³êžlæ!ÜúìçÙ#.:ª&Œª§LYUå™ùû¦ƒ÷×!ŸG´šÈ(|#%ÉÂmr,A-Ùa…NKÎMN8ÓR0;»n[5'Ã)Lª×³¨^b>%¹C3é8]6±uLDÔ`X€ B!:©O¬i悘ç³n%Ú’"öa\ÐØq¥ÑÃK×è‘£ñLôQ#.i‹1Ç¿†0ÚÉ0µö~tm6V,ŒV"$ú‰¬á†sÈkÐÒŒ˜Ê¸ öò…0'º)HH2DO¢"öµ”ZÍiHJÔߪXDVBEGE„ìE—„0cUÆ„e5@Àm©n\0P‰`„M`¯8#%ì#%IîËÑ•…*Bé—øahš<2½Æ¦Z\ÜìŠÈ¤°ƒ² H’€:¯ƒäßbš•X1¿8Íõ#6 #%HŠ’*¾ß–[·|4ÅO4oÕå}#›9†Ñth¼g#.`±Þ»Ž´Å¸3©Õñ*\žY9)h„¢‡#65½P4a£ePM£2X’l+%Ê«EE¨íD‰‘·LNA‰GUÕÂë×yåmÊ^¶²VÌÝv¬V`•%šQV@IÅN†ýWPË3:È$#.EG^2S4#%Ü¥…¤M—2,Às4µ§âPNÞ0:=G§‹Í,0!&*Ç·§ä=ÔÌÃaÂօз;sHc²iÞfÍŸŽtê1ëa°SàßÚ½&ñØÒ 7!,HÈ#%—5ëÃ@ä%驾EsRÏr¢Íýï_kWÏ:ó¶¶*'õÍn¥‰†šHƒ[ïh4×·¢`wAuuÚá#.,‡q89 ‰JþÏáÃ;«¯³‡3€¯ÅO8~kÔ1 Ü$9Ê%¯«y£6ŠZhI¥EG!‘+Ž]£fvßæoíÕ˜8”™`±Òùn¸¿¾¶^Óötš†Y[ÕôãBa»Ö›iAà~_X>ÈH‚&³ì‚‰ÔXb„#.4Ñ©î„5ë%ïë!rKïl}9úÓì='p>ýÉÔ(Ž^7/$‰ˆ¤´š’jYiŒVIJ#6«bÖa´&ÄŠ*kLmµ&ߺÑZ¸Îk¡£Y³k‡s¼ßÛ<“ÕXªå‘˜ûµ£aÞ¢þs”Ôæ: ÇÅ#.#.¾®¾Š+Ÿ˜±;öòÀMI@\Ùô‘²z°/‡aÙ°nâ#%žÕNÑ=ǾꉑäKÁŸFzùÂFC?6ëñ(ŽukµÃ Ž…XE{šJ•ƒ9&ärÔP|üi¶ŠöÔä4Ø-J[hyªÃ´ƒmše;“;ð´#.MÓIÓqA’q«)\»’ÄùÑe®qÄAäÒå˜CDƒ8:ß 7$™l·}uf¶™ÛŽ6c„6ZAI¡%!pj[´-ÑÅ[åÍü¬+cTdë‹ÔçL¨Í¶§fˆÜ€¤#%PYl±’Ú!VYCrhM#.ÑÞîôÅN‚¡êÐ0LoäÅ£JÔ1”ÊȲnÅF´ýJÖ†bÕk#.¥ø?{5²b]%OZZl}Æ0 ¸äE!òó÷΀Ù,"÷•Ég4 )@w}* uAÔ ²$ALpIF wIÏž/ƒ©‰tÊð¨A°O€!##Æ Žj‚U6¼ãÕt±ð<4O‡ ¢+ÙÚt÷ a‚ŠÛ‹L;ÏX#6ɨF §ßæý#%oÙ”1d”@Ç!”ƒ Tñ{õŸWnÿWòmî'y‰üµÍŒó6@gö8A°ÄZ‘´³0?yüä<vuøl¼ôªÄfPx"%7³0Ü'´ws7uÿê"çð’Žš¾ÞöÝ—fÇÓ500.=Ô–l×Àþê:;Xæ¾·ÞQPñã@?LSa#%G1×#6ÜÕAf˧f¡€Xùè£C&3#ÅÔlDhÒKºº #.‘¦WÑÞaû]Û\«›œõæóÏ]ų„†É”Sd5Q‰y7s]¼‹&ÆѶñs\·Æ+»·‹yåv•¤å[y“oÑ[¶Ís!ÅSõ$S`6™mÙó÷þŠ#6*¾%|}¶<L³=AÞIYªa<Í>›é#%Å<Ô®Êû>Ê,U!¬Ûf,ÚÍ´õµ¿5÷øµj÷û"Ñ-62)E’4²’©³jü¿tj7ßÕ~îú#. £D1SQ¶*¥)JÚüz§h’—µ¼'Ì‹x„"#%Z"göBRÖÃÖ1ȸ0ćÐ0–HrHNTŠ$è>ä#.D1¦î¹²)±¬-f¬Q¬lÈÅc+™E²Á‰ëÎò*ˆ„(@Š'](Š]ê4{qM_îòýé©çÜOsèùfaב$ðWÀ šõ‡#%£'¸}—ËeL|ó*j¹#6ý{.³ƒæɃxv÷’,!Ú°3œ…ó˜ÈIÀôªyæ8öÑUãoË{Ø,E˜E'F™ñßt €ž&ny¤À˜ÞB Q¶Äb‘püÈt‡î"€Û@ÖôTÖ¡ódH˜E9§¹Z€¡ ½B!JŠS˜Újh(‘"jKNíÒkTÛRiIª[R’Tšl‘‘@njm¯a0¨ ÿNR‚(”+Ô\/*SÞR¬‹e¬Ë/n£.žÃgUPû£ãÓdtÎ=v£9é.k¯Ni`MÄljh™ú([;³RÑÖ*È5õXV²Oµ8Ð"Å…k°ÞÚ4ì#.y@^K?ÞÑïW-ï%ë¼lcúé#nìˆzK™š!ö¦ ¸X÷¢Ð‡§øþàêüûo–—çãvMÅ)¦%I²5¶1R`ÔFÕ&Û#6Z7æm¿+W‰°ÑZ(FAUdQ$ïî9ú»,ì–i!`¡P*…ˆû¤6+°0rBF"EHÒ(ÄÉ…Š)¢hlÚQ¬,#%”†ýh—Æ}qÏzíÙ/uÝJQþÀ!"kWš±mF- Ú”5F„«6X‹X«QšZÊßÓ[¯3†:zº›üYݽ´ªË%$ÜkìÇègÍ#6Ñü5–#êŒ1KŠL5VÊå˜F·ÓLðкùÀÆ—àIô÷$È«miGlý/$²ÙÛ3"‹*hc<jÖ†Óƒý90Š(„8AK"…Ð2Ú·Én³I©¢•-ë6ÛNìµÝÙ^5æòµÕ6‹&·¥\•ówY›³2«®nÚŠ¹Ú‚KdYµywcMk»«»¤ÙRTÈ”ØÖóº·škΨ¬$IS‚•a!ƒHˆ6Ôb£cÞMi„^›×—j”ÒÙMI–UéZêÞuuçj¼lm(Êe¬¶R×Ü·k»tYc)&A¢aˆ£ÑN™¡àΓ#%É#6ÛÐqV„m—3ø{äš‚è5H±dÜ>²øQ¶EF*‚d‚ÈÇ#%ª@ Sã’¡¬þ¤Ê[Fh¥È“(1P¹{äÁ5×\É&§4)DÚ›7Õ¥GôØ46àYêÓ’äö¢ìþ3OêÁ `>¸ˆ¯pÏ?~ðøfŒEº#6ݧ¾÷#R÷fìˆfKËÇXZ¦#.Yë9¾îã~07"ß^GÏõ–™“¤M#.UJœmG/¤lír$a®îB™1ßèSJë@ë#³o(ƒ$QGÊ)ļ.#.õêLo.Eä`%Áæ1‰¢GP5¦Õñóç/ml·p†B#%|²$Ÿxk‘(#6™(iι8>J¦ç¸iߎ„>ÔÒ9åÈt(a…-Q¢Þ–3oÐÕùUbÙ›õ`|¢‡B hÚ)I¨i¦×£|#.âöA¯qØÔùKŒ˜5Ó"÷gëtód›±BKûòVµw¬¢ö|jë‚P¤Ot~ÃìJ'`O8)¹A°.F´'RK`¨¤,n#¨f4äÈlƽQÁ€ÑÔÂ!³n¶`¢úC#’ØÇwšÆ½!ȱ|*逊DŘaM ‚¶”FŠ›ÕÕšWáœuzC<óËû²œkGG ŽÄêîéÕ‚]Üãjþ?70ÚEy£ÉZ$£Y¨Ï¨ÑÐǽÁäuMmÐ/÷Ð…ÄZè8@¾?jã‚8“ù‹ç¯fƒYÁêF4dýŒ—-DEC=µvNÅ|ªÖÞm¨:ƒ´Pi\Xì"ð#.%t¢#‹Ì¸ÝѨU׎1Qߪ…@ãƒ[8AÀÓ Êö;÷—çKŽ¤B4Dbžƒ:[nXŠ#.édRS(´@Ír:†‘ä|Xr×c'pždl€A±ï47mà¶Ô~¤…f1Þ“‚BG¸Ô_h½GCˆô"W¾s;/~†D#.îfYÚÛÊÚ{aµÝ×oÊ÷}þëiäk×í¸*‰>ÜD-(?„LþdÓ*z©Q£fÜ@ ݨþQD¢¸ß³Ñ2Tm`ô=åWì#%ÇßwïØÁ²>uLä‘™›™˜ÿl#%#%b#%?›Ùÿs¿ñõÿ¿ü¿éýŸôÿ¹íÿóÿûýíÿóîÿ/óÿëþ_òÿHþ]º>_¿ýÙ|¾ß÷Oþÿëëÿ‡þ?ðøÿãáÿ~#ü¿ãÿ/óþïü?ùÙÿ‡ú|åÿ/ôÿ=¸G£üúÿÓËæùGô_ôêüß_Õ¥P÷SÿLBÄ?iþ,ϳüêÈDÊy;"™e\?·ûäE7¨;ˆ‹‡©sÁþ±L@ZüÄm4 þË#%öªŠÂ)40)*ÿšþþǹÝÔI I™ŸF·ÊÙVôh #%âQ³ßÌôjB»M¢Ï¡E˜SYˆ8ˆÛ,×gØ+,€ƒþûö¦C¦Ò‚æ¨x¶æñ#.Öâ×ýÀä÷² ƒ¢îÇ‘^A‰:Õó»0ÉæfØÝ@„#Ì%*ãþU•Êlé·üiÙ\¾ÅŸÙ»Æøyö¡ÃÉvǧ‡¿„eÔ«jÿ݆떅¥&P"ƾrÿïUËrž#.ð7Ï_û«u”a:X˜„Ès+u‘ž#6Ù™ýþ.ÀÀ7µ*jH†þ”¦xii”Qš]d*ši‚—eaËœTÁŒ0ÙÿŠeTñhÞ¶ñïÕ¥ƒpvŒîm©TœYnœ44¼BÒÙl`…ÕÁËsO6e7ª¨5mÚ8øq훓Mmƶ9T¨¨ëÌFdMmT˜I†qx“Ý,ØY.䃆5¨mõyõx*ŧ7ŠFÎîs¢kCºFêâ¬#y{¢ï4êÈh2ùÃá’f´Øäì¹a²…qS1a ïH²F#¸yí‹ÈdŒ¸ÐŽH?F:oÌÌü4ÃÃ)×Цë^EúîÞK¨ŒëN‘±£\-˜ÑNàS4'>:`«é”ßw´ÿJ±·ý4#.pó‹À@ÄžGßF;tk5SÞ’æ ш넞‰‡ gà w#6Hp,†#6¹^>`L³¬5¬R Eò™„ "IEq¸Ov˜]œ.fB¦æ<õÙ3PEATV*AB“9wt¸¦cß·Y˜ÌÊ2 ¯kº\69‰¤U¥€ >È!<NÁ(¿K61$@ 0P’2îHqw”;ó\¨xƒH1Mï}Ÿlı38bÿûKuÊÉ€ž–¬Æ\¬îÙ ,F#6"`–ºT70]#.úwóbs„ ‰‚$LjÄÔJƒlkY¥3[FÔm’¨ÌÒDÅ…‘S_EÛWZªø|:Ö¾¸‚:?àE3€ÿt#%¿]Tµi¸#I(¼co¦üÛªözÜíSlÖÕïéñ#%Mþ}OÒÂFA~©o;|mq>§^²æF4?ícS9öɬצåU1Š"ü«Ç»'_û6Ä+W] 扄8uîKºƒxteæ߶}C3¿¾z„g,r.;À}²“½©½Ç0À×–fÜT9†P^]*zgâ_§Æ³ò8ÎŽQHÔ¼=‰ #6@C&9›Ò’#.³QÁOª‹#.D'ÒáG½\áUò»µŠšP®›CGݼòöœ²áž˜¾¦ÕÍ-ø¾v챯¤ƒ[êk˜Ø´|nmcãm½(ÕìµoSEªMAj½óZåUìÞÝy»¶ë€]#6.æäQ‰#. ©‘’| P?ç!xnãdN2Apã'PQ±Ôí±s¼p]º¡f!‘OVݤ—¿š7áUÁbÇá*J9…¨H{ÿî°÷cÍÔ¼(5É@$fáÌR¿æû'wØÊ=<ÑÜŽ§ÛÈ_.EúØqPôÇX¡ÿ’#"‹(]¨î;µ#D”)Qb(ÁmLÍtÖêÕÙjûËf¤ÅÍh é! H¤€ £þßÃ3ÏëÿÏئ¨¤"Žþ~˜™áã(ø{fYr0Ûm‹CòNÀ.!xN¦ çå,A‘<?à“‡áÿ¨ —ýþ&^â|YY?÷ùB-Þ6áÍtçüŠ¤ÿÿ&EÐý hNí'»ÿ›cÿ`[Óúl¿‰·@³¼%ËAú¼Oìÿ»æÿÜíe÷øCâ.ÃGéʽ1ÍÀ‡ê'¼waÕBžÏ+“Üã!Éä,—yý>^#y;³9ø¾Šÿѵú½gþs(ž?l-A!ñÿÔ¥ÝóG#%‰#%(ö#6”CÛ¢ OùI[¥BY=‹”+¨›4ÃÔkéýÕsø]¯üžB_Fœ*ÀN#.ÿ6pŸñäÑÎJíâqTE3‚o¦«…ÆY̘wÈâfÓ§m3 ÊÊÇðç,Má†/-„±¿Ñ8¨–¼§0aw<}8fJÃ$É o§‚ì]aðx`HŠ$Y@zõnÒ=®Ù i„ÿ~éŽ1éÿµ^#.Jz(ÎLPÛæcè–ªÆ"ÿ“â|xã‡ü†œgê?I¼Ëò~ÿð"‰ÿü]ÉáB@ä&öÐ +#BZh91AY&SY#*s†#)Êwÿÿ°#)Pÿÿÿÿÿÿÿÿÿÿÿeà(Â(€0Í0çŒb¼{¤Æ@#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)÷Ý×}=y”£îâìl=½Á½µ«C(4šÓ··ÞÓÞ³ è>ò·›lÙb#îÒi÷·5ï;µ‘zë´hm2_<>ûåÁ;íëo9tz—QRQ^îë{†íÞÖZS»vÏvn«Vá¤|óÏKz×Ùï–÷G)Ú¦=Û×;ï¯{<w`dñï‹koÃvànû¼âïsœ`Ð#):ÐÐs»#)<t#+0ßf‚x¶{·°z{w´½Üô·ßo°i #)ãZ=2zŠ‡ªÐR‚Û QJR°wc€PP¡TR‚÷¸)QU"-€4S×@êUBŠéZì¶óæö÷]ÕÙöÜojÏoxÛÍÕ©3#*TThm2*Uš·Üõ;h÷Þäðè;ÍÙvڵϷ^½Ý‡<9›»½Þ³íóæö=ؾ¾µõíŸv·sm»]Mïé=ªc¹»åîÞ÷×ÑヒÚöÎŽì¦J%FP!RAÖ´ÞÍÛ+nºÝŽžïw¢öí¼ö÷½çÊëƒZWMÆN°íœÙH’Švó”ÊzÐ #+UD½Øg è¼Ü%/lï{sÕØ[m{ƒJ>Ü#*ß{_ÜÏ}Þ”H#)´´Åmk®úoEË#)%Þ°rM€o¼xyæôìo‘ͽìô-nŸ}ç½ç_uÁêñק ›íÊ£Ó^ÊÔpiÒù›¸w‹>o¾¼ënîÜÛ—tÕÝÚnúÎÞåØúæ÷%³çjuÚî^Ý^¯=Ã=·×wΥؒlÕ4k#*mõîôï°û³Å×-³n肵Ñé«fî¸ïmÛçÔR›^îí\kS7Ϲ¾¼ï¶;ìÛžöí÷==k{‰½—R¾÷uëc_YGgŽÛÝ×uõÏ=é¾D#)7Ó—Ï;Ð.|ÃîðhX:©E€Û!°³#+æËvrT[뒽ݗ`vèí= ¼Ç»Téו{¶Ø®•SŽºžÞ=æR-×m½GBë5¦ÛÛ#)#)žç]¨#)[Ü^¯sÝzyìönñ¤æ½ëÞ^Eî;Ó²Þöˆò½ÝÒjtºŸ{¸|˜öΈ…O‰®:"öàóÞÇ›^ûg¹¹ÓÀ)W£Ò•íÝ0÷·W¨™ƒ¯rxiôú£ï§AÝk뵇>ÛžÇÞ³3înï7ß;›í»»»xît°Ûíƒî÷yîínŽÇ½»ŽàæÛb³×E“`Ø3EhÞÏYÛ£)꧞¶®‚¶Á²©Ïê•Øì/<7}µÚÞ}ÎÀ^ÕªŸ\zR}ÝöôèéÝÑÆ•ÝmÆ#+»MÚÕÑÙÕ÷îw9ÚÏs#+ûk/a½w»¹Åëvî4×J¬”èÐíã2]ØÞ¼èåLêðn·T;PãG{Îò÷Ÿ}®À{[ÈÈ#*ŽYµm¡::#)J¸ò·›]z›ì÷¹ÀØP(¥Ù·{”ó»[lì\nòu—[P¦UU–÷M—wb–ëÀH¢ÝµÔífí¥F»¶éî4÷¹.Æ4î7zu"ïXÛzÒ9s×Öí|CÞùöÛÖ`OcàB=±š=×Ýâ'·›´P¶½í½™uÝÏ}Ï}t:§Ïg5í¥`wwn:xº½áo;ÎŽZ¾5ñw#*4@#)™#)@M#)&L#)O%4Ò4ÓÒ#)hõFj=Ó) B&4Äñ1SÄô“SÙ&SÒz™='¨4#)#)Ð#)#)#)H„!4C@#+i¦$Ÿê¦ñ$üG¢žž¨õÊF#*¨Ó@#)#)h#)#)#)IꔑÒF“MOj&¦ôô‡¨mOSj#)é@úˆ=@#)#)#)#)#)’€ #)L€˜M ¦2##)Ô4É¢z&(Ð#)#)4#)#*#)ÐI¨ˆ ‚hhCL©²O%<ÔOjŸ”ÊhõzOG¨€2#)#)#*#)òÿúF«]rOã9µ©7ôjµ×ñÕkõêµÞÙ‰%ˆ0S=êµ×dÕi“yU®»h¬ª“ᶒ¢ £""à1=gÍ$=¿1ðÔc#+{Ø xƒñ™‡):µ*±„©æe[Ý\Uz™VXÅbŲ‘Cóš¼é^õµp® :Á]ªðˆ„‚4‰½¡PÝ*_vü6¶:U4ËÇ\\¬=:|\QurõŒ<cª-ÞžbqX|DÝã =à”Ã&ýýºþb'¸¶Óm–Ó*¬®î¥U¥µX¶™V5U‹jŠ¨ÛkXѵE¥µ½÷Y5µW³Z¢ñ#)‘±=‘Rˆ©a*(XYJ#)H•ÕV›kj«~#*m[j™“!d£3PÓ4ÙF •h™š„K#)š”£J)¶“aDÍdš FKSQª6#*hÍ%“I¢Z!#*FJDÚSA Ñ©cCLYShÑ›%¢ÔE K-4ÒÚ bZCf‚`Ê33Ô‘¨ÔZƒ$ÐiMÂ(Mš4” †‹,´Œ`E)´ji²%´Ûk+[F˜ÑK™3!4D˜2ɶ›m4ÚÔ”l¦Zkc-M¶eJZL“1‘f´ÄÑd¢‚™l‰B!Qf‘´R`4TH!`ؤلf•Jb1„($D‘-ˆÉ#jDÈF–"fhd‘1J0Ì‚–VX31"’ÈÄRɬ›,Q0‹"É–R4m)¦ ±%&EDš2hi™1 ©(Ò%¤+ ¦Æ‰"ÄQ3)iS0Jd†lD˜¦†fÁ0±ÒlK+E€I)65ZK‘&¢D£AŠ& ÀJd”Â0™Be$¤ÔY›5„‚“RD“ˆKJl!E‚Ø€“Y”R6d”M”È؉›")FlŒÁ2©¦$„YJa³Q`,i¦†Æ"5+%’6(”R"šIˆ&¤a³LcIˆBI©%”e5LÒ6Š¦š(šÔ‰–Pi6FB1d¤Èš ¦R%FŒÂfÒ…&5Á™H$$Rf0"Å‚%’a1A$Ê™š³m”¶%3!©Ä)›+(QP‘E"“$›$cc*i™¢ÅˆÊHRf`SŒ¬Úa-ˆŒII¦¦M3 ¤1”E!³DTØ¢ÍJ”¤¦ŠCddÆLŠm!E’1J2’ˆ¢ÅQI&‰$Ò›F“Q¤H¡¦6ÄcA2¢Í2›A£c0ešL£cH™2 ”Ù)LRˆ„,Ó!-fË ¶JÉ`2Hi,˜ÈjŠ ¨$MaH“!ŒÄƒÊ#*IcQf‘(š1¥4 Qja¡&e&(Ë&ÈŒ¦ ³F”ÆÔÉ”ˆÑ*´ÛkF ”&¦hÊdbiE$̈ŠÐjSl#+Y¢ÌRiH–YSfˆ¨´ÊÂÙF$(¦ÄB”DÒ!BSkùM®ˆJ›ÒÛ¢ Œ1´QŠØŠ“)M5©&#*-!j6²MFÖDa¨i˜Ê2FÊ`%Iȃ134Ëd¶Š1))j6¢´dÓ ©¬Å‹S-,É•&ÐTl«HÑSe“,Š¥RÉS#+lØÌfjØÑdElšedJ™e6²U–ÊR–d[dh”¨±Me‰-!’–¢Õª1!¨Õ£%AF«&²QZŠÅEH”kDÑ$m‹´bÅj6hÚÆÀZL˜Q‚ªL¢M1´É4-ˆ¶4m15Œ[$XÛDµRÖ²ÅC!2™©“D•#4ÚFÅ’+jU›c¦Ò©e*fË#+ÔÒ"5´ªY”µ54lBÚS)¬±a²É¬¬²²ÌPPÊ$HE"ņi01$Ch4&1#+[F¨J%Eš¢²M4l™4”Y#*–)ÙH6DVYJQ”ÌJ”lÓ4AE¢Ó$&Fm6“ccd)„SL‰#+1¢’‹#*1$dÔ#!4LÔQ¢JdR–P5BTÀ4˜³ J™²Bj-"ŒÍ¨ÊQ³)$£ hÈR²›b"˜m&ˆÆ¤Ù,"‚ÉXBŒ–Š†bM,ÊTÊJYJÌ2V0‚ËH؆5"ÔjšÑš"¡£R”›#*1RÆÙ”–£@‘“ LdÄØ’¤©2…)¦6I‰šÂRš`Û0Ù¤²lf“E˜‰¦”RZdmY¦…LÑ)aD‰!Ê2‚!“F©¤lQ¢³I²S±1II £h¶£Q¨£ŒZ3-†“#*$š,™¥FÅZ#+Í6,†e$1²RÊJ™m@F±ª5Dš(L³TPX ‚MIª5L1Æ©JXÚ#*)¦Y#+(Ñ$U2KDª,EˆÊVÙ(ª-&‹&ˆ¦eRŠC2Q%M‰DL«Q°h©‘±dÔmSiE²d¬[ZLRVSl‰l›CD©%2¥E„ ƒcQ²Q²h“ˆÛ$Hj)&`ƒVdÁ …F”Ù›Mcj*edÛ24…4“QHEQ(Z’±l¤–6LE(#Iƒ$H–Z6†Z‰-¨«J6“["Z±©(±H¦„ȦFdf4Ԉġ©›$ÍhŠ¤±m’¥•dÖ‰›R-DlldŠ¨¦U4£hØÛc©3J!,ÖV%¨ÅbÍ*6¢6•*)JÒŒÅB4ÒY@Ñ¢ÁTi6ƱfT‘ZJزm”™Z4kÓŠLhÚ6¶ÙmX¤L¨TLIDb¡€D†ÒM©†2M´m‹lZf£ÖZJške,›jjm¶¤ÓV&Œ¢ˆHJ(6ÍI©™›,ÔEbI2’dFF#!d¶‹2I4ßû¿ý€¾ï•ÿÇ[›¿í½3þS܈ê²*Jaêý¨‡’R,õ±DB{$e±j©'†X;ë#+ÿ¶ƒ#¾?ÀÂð $I6|'=vßÐó±½9¿OéëÒÞ™MÜrª=ÖÛ2'ù_ñäYLâväPCo²³¸E‡G±.)$M·¹‰Ã>f‰ÏñU#ÿGùƒ?ù~{Z?òJµÊâ/e¸+(‘ ¾Ç4Ñþ{ÜàõJ°Ãàvûño»¡\àÆT5¶ÃÃ5bÓ¶'$ñ–¿‹#*R(¢†É8¡·'%ˆÁýõ»fÍ……£ÈÌ`I¥Û"lÆLhƒcõhÉÉ£®ÉÞwHLo\»ÓÒ¯Rñ®YÎå—ùŽ¼üŽ³9«I±u¨S «Åš&U;1¥Ì¡LU)„¤ŠI1H°ÞíºP®‘€‰‡[•xó®ØeñnTŒÞ›š4V´"ÁS8͆@Ö÷.9_ûXk#)àá#*ó)ŒX)Ú¦ºòhñËïv¹IlF1IùÿޢܼYÜñzf´µÕ±S)´)þY*̶Ñ"Ìi^©@Ã"‘ÆnDçD”á÷éWŠ÷†¨XœÐ¶(D%òþgËý×F[1ÝD!²Ð9³$¼nä ÛâÄÕ–F4›iêY#+“qÆA³¸¦W6éd5sn¼v$ØØŸ]×ÊmxÚ,EAoÏÝO§¯ÖW‹ì[‘L¯‹‘mËÿ9 ƒòxë#Q¶~=¼¨"!çç˜Añ´òe¨Rh˜rÆê Š°XOUÔ†Ž\º2MÊM£;®QéÊ7Õß~z»»\¯nò^+›Ý\Ѩ8šë•ÞwcrŽ•Ë™(Ë®é$s™cé¢KÿTþÒS–ArÈ6ÓbÈD‘a#+hg†ØËËV,öQJ>´š~-Ò¶í.¾ofd4x ‰_îQI»)饖«PÅCüè`ìÀQ³ûVá%.x×Ûˆs@ÇG㡆Î[cÌÉ‘º!$Āšê‹|Ù{kädu¶ï\’(3)£^··vj¼1»kÇóÙg¡øaN#“³U›x“:8XMÙ†ØFPÑÉýðû&¤Ï<§^¹ŠÍwÔPCàÊANME)ðëöߣž—ÀÁîNÝÚÝ95ó¨RDUH„ä,Œ©Ü›¦tj#+M4+É1e)Õ–Ód|h*ô¡ã¡e³,YI#+N*}±ÆyÞ>×åŠUË"õÖ“UO¯pi)O$WàÊø„ÓéûrH›†å¿ÜÃ××oL[1þ[¬3&)}]uøúèÈÇCßAbæ¶Ä^¨ŒJFmǶ®Aâp¶˜=8fwŠ^w0ø²µð¯õ{(ÊšÒ…A@P#+m–™5ÆÕ͵þ‡ì÷’>·S6½•^41XýÞ?¶Ã³4E#T™Š¾çÇû/6½5ŒcšŠO‡væn#)(5Qžë#)£6Ïi‘ÞÒç²à”\×-±zï˽z¼ˆFiVJ‡µÜ±h¯Ü–ëÝØü½qQ¡7Ó׿ÃÖñO~‹FÉ·ÐûÍãƒIo±Ð¨°R:§eè!íÅx鵘OrTÅB™)¦jKGñ¨ræPaŒLÖ¶jϽ$ô¥+?+³òu·edÛð÷DvU»½Ð´’ºp²ðÑ$XS†Í²]#ICœ›HÕsÖžM]·J)”"’ê)Ù¥®úµ‘¿Zž»øVS“–^ÖX1a#+p(¡M˜j!i«L‚$¦õœï0J»*‘£ÃDbá‹MZûÒ—ucg²~,'~6ÅQXXy²Ö"<4º:QS’xU<ßb_3²Šå|ìá®Ñ3VoÎMëËX¸„³ú¡ó犈rõWŽ`cï su‹$ß²)kG›AÃFš5Ú”ØdÌ(Ì)¿/s1õ÷´óMƒLOýæoÛòõ€m¡¹ÄîÃÏ$|2Ì¥@Œ¡ïj"*i_mQû{»{p}X‡aùRi“Ç¿WìѤ-´#*©ÉÍ{ˆiçºRJñ¥ÉnCMÏ…‡×–ìƒ1nÇ#+ÈÁ61K¦Â¹vB9&Ò#*Xe5úèÙÆÔyÕ:”éUáCÃÙs“…“GÚ…$ä¾»Z×qZ‡#+9‘JQo`·ÐéX¹Oq\‹åN¨Yœñ'mg2||Ý#ïӌ֒ÈþöÜ\KÉŒP6@{"i:O8–ƒhºQXPüŽÑlŒÕ-ù‰±y²…èú)<!ÌÉŽ“©1¥óN”8žrâ÷ÜÉ~NZ½ãpödn®$g¸esËZ=M]¨ò}Ê‘¡ýs‘ë¾ð ý®07¨UX¾k”‰Ó¾vT9¥ 0àD*Ó?<cµ4fé\[Š¥FyÆõ#+I#+CPXÍÉg½Cž¹Ó›O~™/gÊÊÉE0F:E&©¯}Ùž•Èk^œáÓ†à~NX#*É`8FW_vSr(´è=Fj/~wfgÔÑù²þ[TÎÅ<ytr ÃÛ´iK¸é$Ë'¾!réE·ã s7ïÂ41¯Å¢6¸gl&?H Ç×\â÷[¸áÕWÿ|-“–F·&Ú!z]ô\kÜíÝÆÃrÉêvµmŸ cmŽ~Óçh×0ôzíëµø˜ë²I",P>îaS×¥)F´ÚÇãš6¢#*΃`w©Dï ”T ÝfĈÎ(»W\ÞN0›“í!oǺêŽ3»º„hö4{:Œ#*ñ#+¸øM-;¹È2°âV¶ã[ÿr‹Ýf6Øq6>ݵXÙdȶ_»ï‹îfŸÕ¿'q¸v³™NúøS#Yöbùd6CTEMØßÛ'Õã×è×k7éÑT^D¤AèëEõtE¾§Ü®½wSæÜe÷º(A¢P¦3ë¹~-UKTWúXRŠ™ò¿éºü¿ý¶Ÿ/úñÕ%}ÍE}Ì?Bñ‰ó»o·®ñ`¢*~§no“=b~¹·ïùÚô¨ð»šUÈgóLZ{ŸvØìÅkêܬ’'ù5·Xýð黄—n#†9ìÄ<$’0 1,áÂ|Ý®>¸ÙL¶T¼å0$Õ4ÔºÓÒùÔBQ³”‰ü\†‡?‚л´£#m*ÒŠŒøÖ×'Ñ;0ÔO'IXÏÂb«´W·°äÅÏ ‚„|‚.aûâðXŒËO˜àLTÍéC]Íø Â`áGÙE"¢¿«4dfýš\}(¤Eàf¬F"‘daIήü´©¥Yç¥dÂ|wjŸfýs|4H¿mž#*A”çÇŒ0h´ë-+‡mènnΛÔrÛòy¯=×m`p¦;öš~—iÄë–Ó2§Ÿi>5Îe 2}–¥Ö™;v¦dMŸ¥¨ù&;ÝÅááÛã¸D;/[×0Êe¨ÌõÇàg#š<Ð/¶ŠGƒ5¸SÓ³k˜~ {bÂõ¢Ø ú’Y×…é¤DQQe0¨x~r‚Û{*©nf Øøg·sèÉð„kÃ#bÜ󼺟S½™!žPm¶³ìª¦ÞHóæ´éêÈã¼ÔVmò§w‹ˆ~W«5FA´?8.†¥úš6e*DF/:‘h®¾˜åʳ¢q³ý½hñáPÐmÔ‰lðaK–R‚±7gFTaes×^¾o#*‘Ò÷àbì±,¥7KªÊß\Ï«fÜËFá5L´*éù“÷9æ]L³u·óôŒ,aï?æÐÎÊÙu9s}r~û)|ݳ‹Ñ-Áð‡7ÒïŸgÖ"+EÅ3|E£[³±è'ÿyÂôî¹nó®[ñÊ[(/ËÂc#¤ÎMü¾5¸º;7„Œuv†kBoyùqòª#Š¤:¤*!šãü…žãß¡Ë¢¨@ÜÚì…2,Sæ\&¹X±@•E©¢$@Ájô°Œ÷SѦú%ѯ9Ar*¨[Úï›—á„9Ù…H±T›Ò9ÿ#*|PוÖ+ŽJÔemA×ÂŽûis…õWô9šÂÐä^å!UdT±Ä ¨q‘¹pöæ÷¹ûÔ¡)M¡_DÏO߇7•ª9;¤Ò™&)¡/)ãUE¸ëêYùL6”î8:<öp½wœõ¡íÑ+‰q°.~ŽÇäô°ô?“á߯•Æ´üwZ·ÙQgí¾YgoKR!e=Šcë—ê¥ÕÞºø“ŸÛ›oä¶Ú`èéΓq©+¥µ\”GÓkšvji7XÁÀœÔH0U4UtÁSfŸrƒD^8Ç·™üß˧oy±áóã=˜‚ÍO*÷9ßú1‰btE†WZ»»#*&5Oçׇ‡NzŽåÜ\패gÆv“Ç“:T‹³Z”()ÇÃ'Àu€®•\ð><¼û:è<&.Ò#*iEíƒÙϪEÙöP~úáPØë9*±‘18pÎóM‡µú0ôÞ¸Ätëm«Ž²HøŠ][ÑŸVµu”·ì©üûS)¡#*:þI)D}èá‘ÈU}g]_“lS#+´íŠ0ã×D¶ v>wNšÛb8mDzØÆó-¿òžx½8À}¦^©i»~8õß•ÒÁrõn;¸wCéÖƒ‹•O'Dô׶øæ1;ÜÂô˜x< •”փܛ÷*E''Ni<·HôD}¡*¼Áq½Él‚SìòÁ°Ýç¥víãsx±-¼kÁÈ##ÜÒlëËJÖñ‚†#+½sRõþö`ò4£Å™‚£"Ïæé›{ª¢rÆ6uTú®¸¾•ïÈnä²°<H¨ËÈvA²„‘ÂË»å6<8b?©š-íts¬PZk%‰|e… øçÆ…éJÓüj6J¸É8Mü„ÃËêëóñåf_~²eèt³"߈d¢/ø ¦¸ÆF=ªDŠaø3eëyB>Hý2Úú¶ÇHÅ‚”Î~·\¸n‰GKùTä·÷ç²¥Crh¥fí¨Ÿ,ù8Œæ`Û{åÌÂ3Ѹc0qÖ£QËãAdXŠ"ÏDôÐ+–j_Á¢Ü}•º¯ÅÐYŒ‚ØÏžÜ~Ú?OmŽ´v¼ážij§ØœÙŒNIiÏ_qßη÷§ow…Ò¡¿G8K‘åU¦ý€Ž›?dÈ~ó:Úâ—k†³Ržú¨v æ´•ÜÕ ì®Élßj9µú»¶Û0üÞ#)†éÁ3mpŒ¡-#+F,V!ý Œ©µ„\bŸ«¡G·5:¥3yÁ¢šfXøµÐO‹§LÜòbÛE\É:b£Em¤MÉå#LÄã¢Çtˆ”бÞîDk³Æ6Ñ<ë¤8™äû!û¬7ÍWËÝRçz-s½žÜºú%У$éÇü„Æc÷Íf"6½’.u¡ËùÙ^E¤J)*&h=Ø®9£¾…†Ž®ŠøÓXKa i†±å›C«Bâ¼hJüB¬lßÙlĨÁ¤Âè黌?bª<M`¨¨šÿI0^T€ðj#*Dæ¤GN6Ï6³YXÅlGÓg¤Ff¤¡J¢P±F^>¼Râ€ÉQUÕ)YSWŽÝÛ›Äír)qÕuÉ×YyõljÀbkxs#<ý°ØÀêòMüy°w2Ô¨tÔ°õõ±$ù#+’IrHŽR‡Uï‰NœŠ|ÿž.@˜ËîÕbX÷Ô}Á¾Ð#)A0#)A©»ù²¸n½/ò\FÄ÷ä°z(T 9hÝßçù„¿}¹¹F*y”i>+_\‹z.½Œþz™Òñ‡“Ò>“J÷j«Ä3ŠžPS„}4›&Q¶Ïhsy[ÝQ|£*S&; Ù4 ÙöP¡!šÌpëƒ\·„iÛrjÕø¶×‹£Œêh=~í9ÛqmõÞ"1R;ëj–QùkÎß;FfãPÙ@·OXý°Û#eÙ~E‚‰`©iF!Å1!ä8¥–,âò«ø]\ö=ƒ]ñ‡(úŒa‰¶›ÎqÊNŠy™Í¡HÀi/U#)Ãó|7?^•ºÊ#*0qˆ®ûm€|42eoæmÚàù>÷UÇͦ.óKdÔ}&ݪˆ%”côõB±Û=Šò«<©Ô÷œw?ú‹¥GŒZ«ô—‘g¹PD†ù¬da´ÌÍÈGŠÐ´#Næ¨j²=¾ù¬pH.]Ũsë]!ÛŒD}µ7Å×*´gJ¢ðýÞ)ÆÉãHg#U(+mV¼)¦UÎñÛl\*!"·Ž¬,•´¡c8ÔäÞÕ@á›^¾e\7ErûvóÐ-4ºD¬Û÷¹ŽÜšHü– `6ãˆn—#)ÛQ¡v“Øýå¥ÚOËqñ1¢°>ˆ¾÷¬Óº÷âI7ïÏ“ô£*a#>êfÜ0“Õ†v÷^øÍ)X+4£Í¦õøéxÓº¸*aO‰¿tl1Vc;ee`àã=xwËc£8É™AnËÌ‚NˆPÊNKYªƒnÃôÞÌŽZnt¥vföíöÒbäU'A#+ã“ÑK—£s3…ü‡%ʘ“, æþ"…ž'¸‘ðƒƒQ¼Õ({Û¹eÚ¶Ó‘K–ÏD@JÁÖEé½Æ̱#+hYʆS¹-Ø.6-sÊØá0ç(<1ÄìqÛ‹‚‚ȤÕ&X³5lS‰û9¿ž”;õµ¸\½Ü×ý—+=hË‘~-lÝù6ˆòYn{j(ŠRdW=Íå†QÓ1Ü+–Í׬¹´60æÕ«H’“¦Y.!\1Yƒ©m…„aÇk¹n²Ã¨íŮԸmÇ&mŠHIõ 'ó"š¿7îÄ”Ôh©2¬ŒªÅçªÁÀÄŽ¨ÆíŽ0€ù,êÐðÃûÈ…Í,|QØu11åGÕürßñߦZ]SÆ´Æ#*y[òöã¥O¦d‚@ˆÀøP%ÿÕGW–vT鎉?å‚z(x&gAaÉBC‡?öñæÙN\ø’¯vŸï#LlÇ܃Bí»@BØt´ÞRµùü2~WjÝÜÕ½›gºú@ßÆŽšÆTrÒûJ&ùæs/³KH–}ÒöDdü#+W•g}¥ÿQϪuææ:;bà-—Ô#K/+Ãì.tíçß`—zó}¸jÂv-ÓJ#ã|וF~šäŽz·EõÚ„ÝÏC›œñ´¯¬‚œõMUÃYÁ´}Ë £Ë–çp Ð.p~A¶™ºf—<ºO†–ëAí¾›õÝEã;4JbNC•F$öštÊ%Ú_6ŽÈÆ!š4«qŒ¡£=2´ÓL”:½c&Ü8Sm€¼¢E‘j9+r9¬»jµ„N@RfV9ý’ü¦ºìm\½¼Ü‰O†þ'ª*±Å?¸·íÕÛŽŠ±T19b7;·š®q?ÛBÚçõ0Öê+ýùHLoÝ鿤Dk÷Ý×»/!œpäE‰åzùÀð#þp$œ×#*[ÿºþïw¿¹Æˆ½ÓÈÀW§º®Ïæº.:üƒª=–°(q™¬wQ>±aUÞÀÝb‹}÷ão#)#)‡¿¼¾½‘r ŸŸõ`ÁM3#*¿»]#û\·)ÍlqŠðñ®ª£ú-,‘"»$‘æ.ÛqQÈq|"ŽIú“¬|üüã^›h‘nlÛ¨ðø5y½Ÿ#*GO³XÚ!ÝÅW·Õ;¢=¥:¾Í:Ñaˆ¼:ðA¹TX…ä^¡þ#*NàÁµîBrAH€ 'Óú®ãøZ.žïKbúá“¥ÝzÅñ×@;@2Ùì-`üþ¼¯‡rö/öåïѤ_R4#)ýôþÕ¼Ú¿ú>×!Öÿ‚‰fnÈB$Ãxw Hƒó>u7##)ýÛÖ0o2ÒíÚp½_Ùû#*Ïç„DuH??=¤»·Êï•ÝίH=²àPYc¸ô?ösÆËZkûÞÿVåþ3¸£]êd¹è¨‰.ò¦(æS#*ùòô³íÈסؔÌ5íM#*áÂ:“U¥Ø@´¶8~xŠf„—Ö#)4§_Li€ÆçyÁpŠÛ«à‡Éí•o¥—ü¿2 ÿ<B‹@ÄTUÙĎ΃ÛõdðFõ\1cW6Ú–_#*ªeŠËâžæä„É×þ)û}Ëçc0t?I¯üÂL–d@ƒ¼\€€¹ðF¼†µx‚˦©.º-.xÀÛ9¾}:ÇÕñyà0Ým™ÏñoÓçÀÚ¦ƒÓ›œ¢;íK³v‚5‡G|]ÑGÒSþggðÌè!…5Ñû,Û`æèþm×m¾¡ß(þ}÷ïâ£8U}=Æôîþ§9 „z#+è³q»WöÈÛïõúõj÷wÑuƈ;Zü¥VÂiõcœæ֣܈mÃë?L|‡Ö2l”EIHà4ŠÙé1ÄR¤ÁáëäaÑ-È¥ÔA%Y¢êÅ„*sÈ„œÙVÔ×FS›¡{üçÝËoîç³==œ¢Ž(ì6™$,Ñ‹Ì-'òd{¹Vàïd¿0–íÛõM‚TÁÖ“q{Ì*H(Ñé©"'CýÜ›3–kyEk?ÂÊ•ô½¬}¾’ÿ“ëÞa.|ý¨”m°ù;wÞ#*§Û>Æ2a™º&„0Ö›:|–½Ç—¿×0·ÈÎdYq÷™G¤·õéÁ0…¶xÔ«%[I(në½T$~W”ëãâ!>ë·hjI6õâ·Èò›7Ã#ôo.ÇöþË–…æå93O~6Fp“ö÷ñø+jf_´4 eÝd(K….ë?§2Íàóî«—åÚhfDjë0é[‡Ô ½µd˜šÛ>±TÆoí¬X[0ùçïñvý?ÅÌèî¶}QUÊ6”®ùq—>¥?½kÐ#Ìv%6g#{`,d’·>oÂ,§Ã´ùâOrbè5)ïÏëÁº×¦[Hä‡ØmÔ¯¤†°°ÐÃýôt’ÂÞD¼Í·òÏ–û6.ë¸w8wk3{eùÿ£–º¦Ýûu“UÇÒWKèÓõ"ÕpGÅxºáXÿƒÒÄ$Tèf~ÉË’e$uño†ï½„õ|cŸýÑ.9®ë߯Ìï0zr2}yÍ#‚˜}Åä#)8Ot¹ Q[ñ]ñYÔ.…´*}`#)ƒ™ÎHYrØ-ÞŠdpó¢:Ë_êíRzNša£ä¡#+#+Ï×øÝþk9&)Þ=#*¹c„CWdÑƬ!TÎYÜ—Çö^ópÁ™áûxFv<–ºGtIPï°EG`ˆÕWÕ˾íÓq—9á´‡'¸Líý’Kçƒ:(äBûd¡4Z L1á-õ®`,•õ‘hTƒƒ;±ß›‰Öø›ÍW÷½ék”AÁr4‘#©ß¬uš3_ÓÆùËéIÀííÛb˜ÊÀèæŽýêÉ([ŽýÃuN: ‡_5ï/ Z#*a{ÿ¶±c±Ä¯QLšÄ69øGׂtToËN7}F"í^ê=#°âˆ*B#+ íÃY9ŽõñÃàZX`¼P!¾N`XžÐPŠL“P°"Ó=ŸÖnžøß}ˆ6NÈFaתÍb(VÇBœiÅÂÂwÞº|þSLøÁ(‰ „)í#‰®ÉÖ»ÂF‘j4ˆ™¦Š[W~³bËaJˆ‹!F#™fWAB-(0¹\tÁÖ±¤s ÕñÅöëTäŽnšSû3‡–ºõyfl+¼F2¤E€ÄI&fûƒ3s—ž†Õ”'¾6‹Éü‡ù@Ú¤ßaEƒßNê¢o–³ãü+´ý_íWÅéö¹ÓÏæGßàT¦xìÆÞ^¸´‘òb‡À'ÝÀGp Æ b@1@00{Ëa(zÂÍÝ¢”âkˈ‰t†öÛ¡¡IÚì¨øbÂ÷‡—#*ê€FW´HqFYT_…"Ú,P~ÕµZI.3©Ku-(T:åE˜ZX¡2}uØ!;vÜØæïHÝïU®˜ça“=åjÖ†¡1‚sŽ©3#+½ÓQ}²•þcáJ7oQ÷HR'Eã¿9jàøÆâ÷y?šî’¸»…(=$yq¡”Õ#Qg»(^ɧ;B¶2Z!(ŒÀlæÁêNEäªé¹ö Õf˜ÚRμÛÑ:]yìë‡é£™8·<”X‡Hç΢‡ètny™PЙF”:ݼ!ª#*œ‡lÆB¥œI:¥š:è˦Â849‹œ½BÃœ‘ºØV%UfeÔ±oߣœ)vä fìƒG<ž\%Ž•ésÍÚ"”„Ž)Xæì:?õ(çؼÚ8ÅQ²C-nP°7/.#*KÓÕ/.—tÍ•ëÈtnª5<±VY6ú²‹žòö½x“ ð¹Â0±Q↸ñý¾¦Â)™ñ£<¾?~BóüÈ}•3ìSÑ;TëÕõ£ùöÒÓoA ü|*Ã(tô=5¸ƒ›¶Ís¾Ä'Ö¢…Îæ(#W2Ì4U>ÿjWzòòmç]„K×v»¼ó.×wu§ŽÈÌ`#G7²™) ,ѯ-q¡æКUtÚc{ù^}œßv3—ÊúN^÷’Ê–Â+H…$ƒ`Õ1U…1ƒlj'XÐ×Ë^¸,[fˆ©‘¦n8Ã#)H³ƒèrdCÀ5Û–âG·.+õ#*×J lÇ-$ #aÞ÷«ƒS—£‚MÝ8°Ê^M^ŸÌ÷Úïy³òȃ¾´^Ï´J¥Z¥òÀšH(\Xb·0í`CÔ[!‹±âë¾N'—¿r`?S…Ú¡Í-÷óÍ*#)ªÈ´ç#+¼dÈUÕ<ÞD\˜Œ¡ý¢í¡ßu{:k4ImÇ0PÔâFÇÃÁΉΧ—ÃÖï–ùE¬©¨úUÓäL#áÒêeVßI6µNu£°ìûúùÎJZv#*r_#c¾àó¡ó˜E±÷Û.Š ?FVÄÀX¸7é@ˆŸ!#)F¾8ÊF´rê͵óh^øEXìf£Mºâb£.Ôh»gºN^Þ¶5#*9ºÎëf)d¨n)Šl™„â„'xÐñXX’)œ²Þk0˜™‘¤$`Q1¬aX£@ÞѤK"ŒÀ4V—-,KX!3e¬° e…0Hóãö'aÇÇKêÇé±|»7è<à¤6M¹£%쮚½1jûŠóß¹¶4È£&ŒÚ(ÞÁ4d¶"†XTMPÄ—tæÝT±¡dáÑ"°+j±°1¶"Q„$@‘C(çmõ—c¿Ï3f—Ö-¯ßÓݶ#+_»[0¢³*¸ B¬¥yÖz%,è¦5`±|]“mH!–ëU#Ú€WÛ#)Rùᩬ€õÉ`ˆ–0ì@í~Ám'c۳̟ÆxO²ô߶ sþ‹tDèქ´{£^aˆ„¢eóoÑ©?Ÿ7srtZ&ìR¥º 5ýr§z´}~[to¡_(æ{4ö°qNø…Õ¼)½JÎÓí–Ún€…™©t,–ÜXë¬)b²KoS¾‡¥Ï/?ÓR嵩Ñ2´%–®Õ@*q°ÄÀÔ²ZÍñ﬒֤ûög`ùT½`‘Í=µVbž¡„$§ÞÂO<Â+v“8Y,á݇ß~¢&#+?½]°Dé©—„á¤Ú í7R0°µ'v†HDߺß(9Öï§øÛ0ó‘Ëý½^:^ɱ¹îË¿žá5~¼ÍfbU©Ü`z;Þl®—&z+šézµ#*s@¼û¸¬i£ÌkxMª’ˆ,V A…’ÐKsÄí#nø©.ÝŒ‘‰aÛ÷Žß±oý»0ðÆé¶;pCÇ`ìyQZ·(A+#)”ZÑı`Œ–ÏqþS™Žäœ._«OñÉÏ^BvB";3Ö)á¡HÏï|a¶Î¾šŠFâ¹VàÛû—Ù˜Óä^TNˆ¹ýÞ¹-˜%#)ÚLdCŽ&òx“VDVA£N”ÍL@ô2,*¥Ò 6²Jd :u¢Â€ë#`Ø)c¤QG¼É#*•$ÝCMþBà&¤Ò+J‡,µÆˆ£áÆ;§Î"7bøõÕ3^îÙïué{¼ÒöÆZU‘,q¶àëÐÐ;F¤ˆÇ¦a¢A‰±!ˆbÓ%Ù†òý/wîæ¡™¡7¸†ý±…×@ä¡»iÈ[dikðÛÂݼm¿ME1¤w.#+WÒ;K³<8G'Ž©¶nX¬HýÑ߈g(q5ÆL¯+•ÆÎEêRiü©4xÄriȦa‚<j™F?«ëzíc;›G·U¶‘ÜdRˬ´¶<>ôáBâ±£s¹‹©Áâ|ðß>~ÌpÇ6n)ɱèÇÈ.œÔmø@°nP’è$ºÜ°ÖõgW˜§€GÐÉK#+EŒÜpäRµþÛ–`é>#*L…F#+)Èý‹:×I±ˆO”>\¤zR«0«ñCµÊKÖI¤‹R×7‰ÙçɹœØ”äÛ›êT¨‹þ–¥—Žêí}ú½ãô6YÄŒOJ¦à÷¹9Uדÿ,}:î“&;`ÓÌ’ìø§6d]¸‹,öâÔß|?H-£AìuȹHƇ÷ª4¡Ú‚:¢¬ts¥ lV¹âé+Té‡F:Ä}W”½v}›ü˜Ût<ÅÎÂÖ™“‘ô”y#)Ð*¤\Òr¶ù7#•vÉm#)ü~¼ts»V̶4&`à×ùl5]UL«IŠ(Vj¡Š”1zõ«xk.iò&Û0âúžÙTn&éÁ9ëƒioé×XqÃÔxQ½Ÿ3’øJ§»`r'ã~Saÿ«0mp¼J%ŸlÅ//Lg•û>¶„#) “*Ä#ìM4×5~ø(LÄ´²Íà룫šÀ“siµÎ‡&ëæ§ ªÚËA7cÎ¥7þÐÕœ‹šN.-R6‰6£·5k¥’5phˆ’QVˆ©#*RK܉jºQc*¶CÊÁPDo°[H½Ëf#*„Ò†K_vjN¼¦fÖ¡Ìâ€Þ5¨5–iUÂeúNQ×8Ôèö'´öž°ž@ûP€w—AoÉ[¬ÌN=û媼ô[¿´¿ìòñJü¹Ñûž¯klñ|{øî>PÃ@¿K³J5Óth,šŒþ+¿^Ñû‡Ý§GGZ6¨¤!òªZS<ÐêYßÀÑÈ%øÃo_.ûú8#*^"ƒñíÅÖ?‰«j€þ©ð¦u·+•C ²q›_S~ܾ¹Þa?¿*—ÙVI|gâ^H¿žãñ–øóØܧŸq\f#*ep}‚”2¹ð<cùöCÍb´G7úA÷,ŽywŒ@–]ð_Ëð.ߟzuj#)Q!–^ñ¿Ãõíw…–HQ›žÛºú.OÍ^n¾·ýü-ŸgŽ_TÀßëÒýçå«GÓ³iûü~í®Í¢È7£®Œ`6Ÿ#*L=‹âêVAÀEƒ‹Â;Ü’G<Ûû½œ}'DŸDºáü'u±îúð CRzi æ#+¤#™T£0dbýÿZŒ0 ÷|ŸOÑ–ìv4[Æ#*?d˜ÔqXW7ž¡™œRë)·_Ôâ„F¤¹alÿgø»2#)Ghøí#)F±éñ2À¢“O?×ÛîÝ?˜#)R•PˆJ@J_ÏÕmϦö8q{Ǽ¨ñÃ;¦7õ…ç$HfG §3¢**9S°¨QlFzZ¦mIdÑ& 3eK‹ó8ÌMlUýjôvݨ£X5RŠh€TI\Ki_ب뷇¸Ý³ŸÞuêMæÜõ›“#*¿ü8å¸d¦¢èÓmïv …,ûï²æPXÁTR™*Š @I)R çWt/bkñéÊþþ¿SWì•r‹46„§lç·øìÔ„_—óq<ï“ð¬Bdšëêö™|›ŒVþånV5õ¿7øRÏÔÉ¢PÑ™.ð)92«ýšeAêUÑ#*·¤‘µÒŽò® (aÁTUS!<añëÐ?Ä~½Âó;hn£m6#ŒE,Â/‹8h+‘H(#*ŸÙêmmþÎ~ óºaÿ:Eë„úɃ*ÛW—÷î77£,Òüu/óÙïR”Î4ÿ!DºZÒ[0ÒV¤Þjê^þ?¨ãs8kV¾åýÇlV#*Ï)í,®GG%Äâ@?ÖŒQDY¬|¾4pǧï¿ì¾9XdRÎÛ(ñY¥•Tsg ŽCV"†ééKQˆ*¡cT+÷ýµÉâü‘ð @ý²¡C`ŽäÓzÃ"Š„MD¾íÁaƒ,~räd¿Ú[óxOÊ#(×ãîlYCq!7iCôD~Éh&©¤ÊŠ¼“÷Rä@pÁV“ôJd–͹ÿ±³†ŠÛe/oÊÂ7ǃáügËók£çúÏwåúþç~¸û¼¾¯«ë|=kæçLéí=0‡-§Û§¤jŒýCdÇøÝê¢igOŠöCñ]^¼%0î·¶5#WÐÆ núÚlÁm9ó…æ‡ÓVû·+ÃñÏÁG@R-Ñ`ÓÝû"à:D& ^ßé¸]JÎ|lXÈó—8‰•óè‰íºþ¹(ý3ÙÙÓy¹/BÆ»]ò è³ðˆ]Ì»N—,fïðÓá#*ÒmT®ý¹¯ßœ#*-àá]8;od7W|F†òp*°9jÊž6Û’Ã@T_½0c¾€òí½KÞ¡¼QiKû1*ÒÃâ£Moäà#*‡-à@;¯¹ y—ÄB"˜ñÑŒ÷Ӕ˯xÿ_¸Ÿ)™úi£þ>™¥òƒ'QÑ~;rœÒ}øçÊ]¤5áH@U|8Lf-È€ð7J‘ÞñŽ#ë?¾‹‘˜v0ûað÷^ðño(¢¿hVø(¸Z£0yØöþ¯o¯¤Ìøžœ6ºTrÿØl9ç—DÉåÔÞußÇÇ#)j#+NöX´¦S#*n…Æ#+ŠÆè©ãû¼7:Mvõ° Wí¾ëÝÈ-5#+ÃNt |`™2žJ¤Ò¤£ÕDÔ6°æ¢ªš+0mD(pRsSÖÙè_ÑÜ¢B~û*õõÀëC„y+ðˆeyPd+Ê‚J´§ôÓø0ÓoÈßšbÝkµ'oÞ‘Mï¦#*/½SÁ5á¢Ên䟦¨ÌÓú·ñÁ“?!•‡‡±Ü_¾± Iz¯²}´õ±$Åa>þTW¦Vˆ4Æ(H"¨€4š¼¿µBïUWÀ%Ägrõù¶4#+b£‘ó–XXHà¿Ž–ÉA9Ùį©X“¯TCA˯צkûÝODZW(qH¡O€#*ÒP- Àn¡H‘¢¢¢=©9ñ=<§•ýœ9kìFÇF–Äþ•7ô Ñ*å%¢T-¢#*DK)·œ:T—żÔWןÜižiÕ®ú Ýs²?¬À<†)—]üÿÏ«¿Ùáôï槳èú.>³”¶ò늪o«ŸÚuúé£bgòýVY\8yÈûëìlç鵂½vé|ÓJ[]çrå®ÎÇ{_àÞÃúøn¾Û¢Ý=ßw~Á¿oÅ.[ìµåzaè¿"¢Zªö×ýÏ×cT¸yOŸ¹z9¤×{áGoMû3ôhrŽÝ÷+Joï"ÑÖí_ŽèÿÝ}Þù¢ðï>\³Óþ=>÷Ñæpm6\\,'vz5>½SÓÏã[h=è·‹ØoéÐ’¡=ŸÒ^èƒîG!#)ËŠ@i>þÂ+Û¡Ý]줧´ÄY!ô=7ãñ~wŽ*l–™qçédÄy®¶PÝw:ÙNÍñm8ó½¯}›.dé§^ŸCæÙ¬£uƒé€×ÆŒ4õû5ý¦×qêÉ9ðéþ“¶1†ª¶¿•ãTÏ¡å¯fˆÝkè4ÇkßÇmëiÞŽt= Vîh]²î†¯L´ùÉÑ"ÆÑÇôhø[oîÂëÙ[ï”Á€ÛÈ¥(ý}ùÙJ‰ytö°ù±ÁñóÛËŸÖ;uç4kÏâc#+`|LvR®–TÌýÏ-?Íð9ïQ§™ãÇ ;›ÓË›–ù8rÃnïAÛ¨›c†çyÈ—³×¾VéôÞ{©=ü[Û44<T0è",‡“»›ŠÆC5-:=vGŸ£U\RD‡Ð8½<$¬DéæT,4ÿÒëw{ýºÄø˜×W=:Ÿ¾ù}þt4«¿ŽþšÆ^OBöþžïGœ|.͇,†—Òq˜p;E5ŒìˆÃ·lmöÃj*¾ªïÆÊýš<š¯³£KûµjØ[6w¯Ê#=+èÃc'Ó!Ïîá;»^Éu?è™}ÆÕ•¢‡£cäúdኪjßñîŽÙK{{HŽTû¼³¿Í¶Ü(£Gïa2–|v'FKõ|¼5ógÿAÕ˜½¶›ÿ7jy¿§·âŒô:û-M¯qÓüò”½p?¼+»W}þ¬;òïhmø€óLa÷û§8·2÷l¾>ͼ4Bƒæu ûô"¼q+ˆQÙ‡£óWìÀu0Ù¦Kð£å×Ìï•óÁØtt¹³‡¿ªMóØéæ¯Îÿ‘׌›èAåí_,«þ‘¡¿ðÏB8a¡‘S’€GŽ`x8W–ØÏUŸ·ùVÎϾÑÏ·<è?¸ýIûù]§»FÊÝÊ p§cÿÇ?gª½ÖÛüÊN¸~ŸÜG£ô…•®wN£Æ^fÉ¥Ûæ#*ü¿F¦§ð÷~ô%¸PŒ=î1B,Xןúß—˜aúyyiŠÿЩ´Þ¢WÞ39Ôéw_/+<Ä~_ AõÕE€(Xb˜Ã¯C¹?òúµs¨:~ïXOßÜ9SÑÒ0ùõýÿ7Éw>´ŸWÅ/gf}Â_ˆ±™µ÷õŽÛ±ôOSõß ß§ÔݹsD[lêÙ²ÕÙ·ëÙG Ô…Û©—è^ô厮Ë?»–‘äðø§ÛÙûµÜ0û{þîœs±èßÍåP¹nM³óLÏ.ûáý,gëÕºÄAþKôS÷Ü“yÇËbhèvÏñü¿nê·O×\Ü4Ž/ß·à¾5ÅFÏRpçŽÿ·7³Wi¸tÃéó|Ëéû¹´§È?oðÅGæÑ€#ùL8|‚Ƕl?-ŸO8ßÈ”~ϼü)byŸœkè€G*´B¬¯•öy-Ëc»ÂÚ‚¸h)€uÿ&f®X®ÞCõ6Ô¥ApoïNnvÙé§ðòuù˜]·Ÿ¦ù.}Òù‹ý-ÌìôÛßÅ[O'þéï¬I—ÖÄù'm<óEX#Ëüÿ†DPw/„)ò*Œtœ<f/»í؆ûçÍÙΑÔýñØ Ÿ°¨§Ã¢@æm,#)(ÇyPœ™¾šÆª’÷0alµK¤®C2œu®8ek—hltx׺bô+Ör4.l?¤"r:Jì•Œë ¦¢i^ŒxiŸ’Ì°ù|w—»FŒiÕG\8©CnR¤Dv0`5>»°r‘Î?‹¸É-©—(¸Šï^g`EÃÙ38KA¼ŽC¨nÔ>ÔÛúøiÛ螟œ'Ïöoü…ÿ~˜sØMƒºX<æ±ÒÚì/#*" ËÊå˜+]òiDWsÌdãѲְVŽèù)óÛOÆQ/ÜÆþ/ŒààÖ²òÙÄQ9\ônîZæ²›có"µ1þ´ö¼Ýãƺ>õÍóÏ¥]päÛÔæÇì?!O]PB:®ús…G}ëeaµP¥u²™Ñ3eˆ¤Ò*ú¹qþc‡/`¯øÿ“'–{ÒViÎô„µÏ· ºô ÈhÖ.à-¼ÞœÀTh–8hœ^"®Mœ+àñ§ãxúõ7žÛîužù&C„”ÄP¢G×ßX ?=ßUê<ˆÍ®pBç/ÞÍæ½~Y6Ã>f4W‚7¢Ã˜ y‡Æí¤A–?.Šõ?ìùõŽÏŠÑaǤQ=º<!·JÙÚºÊUó5Kù§ÕXIÒ“9ïS¬A Qí„›þ9ö:ù1Ezt ú¬ÓÏ£¶Ù_]UþÎ÷œ¿WàÒ¤ríw#*Õ·êDóæL™ŸÞXùofÃqë|\í?ÓÌ~(#&q°Á0â/]¾:êôlmŒ<Ç‹¼ßÇréu¼¯íåêgüÙüúuܯôÝè„`=Šv¤“v×ÓáŪþªNÆB'i=ш{«c˜ó•á8ô~Nž¼p“©äþPÕðThöÃxDä½oa•$•åˆÇaü¶Í*?»ädªS–C<ž÷âQ²JyGÍó÷X7¯–QÌ#).ymÁ¨6—Ç`+wéÑ?òüßA†lŸ:9Oò*?pf@ç9œå%”› Y`Ô‚#ƒÂŸF5¨4iTlTŽÔ¢¥nØ€Ðæ7#+ªÒƒÀ¢¢,tÿíM¤`Vjîå5fYš¨èЈD0QJ…ÑŠ[M`ƒ‘cXÃL’˜ƒVDÐÐÝRE,h5b¶¬®9ÇØOŸ#*Ss¬6ÐÚ]&6) ºýº[xºÔ90$½¢ÐžìVŽ6bí¾ôxÈÙœæ3¡((>¿ÉÔ~kÖS<¦³ =a‹5ÿ$´3QÉ]E··cˆXwBñR‘dK¢Â`z¿¯òÖqõÿ|&àÏôò"4i[F2DHèé@ŒÖbï¡i7¢C$M¨R%dl!#*YRM±¦Ù…¤’©$sþlˆm»gí:>Ý ”ãoÏ—ÍåÆ噧?ÆšþÁ?χÉ>“}ìþ8ÒØ$2p´iŸY²Í2ÆsªÝu×äÏ–û}ÇGžÍ•åð×^¿Ûåø6‰yÇ©VÏ¿óz³xìF_·ª.êèÙÃí2N¹'åü±}º,ú²ýZ$ªAÜÂ1lx[~{4˜ÅÎîô,«eVMq×eoùç²9ñ5Ç0¶Žë„J0Ê}È(H’AáߘºêÀz;=ß«ò_·W·N¯gyD´A˜¯Þ8s8#)á /ÔQMŠ¦ï™À]q×ðt#+ed,á¿£¯8táÁ¬‰:ן÷YþG½ì÷¬a75¡…Á‡›ªçòþ—_0©Ku;âýîüz5ù¶+uój»˜š~›²³öÏñÓß1l–@L/í‹í ô¿J°(¤}Ý 8=u¢ãýQNñðâþÏ^vÆ&ŒÚò1[ª-«DŠÚPÈ9+¥®–#+Œ0‡q,j‡Ó[»¦KAi¦ˆ$J‘D›·||×£^·^¡|š©R§§"ˆƒPlchŠ1J1BÀdQØZáa++)YlÿWÖ£F¡ã*\æŒmFAKT£Q[*‹£86ÁFH2#*Ó©7›¹äÌ#+F5ß”MÈAS(Á„˜0£FÌ&bpïuœÚºÙ) lcQ#*¤c̉†fUø‚4î::RÚæpIC†ù₉mh £üͧ`2ãzXUÖ»]b¥0Q‰‹$I•8‰ì~UÒIGù E,I´W2*œ„ÐEsEQUÚ™QŽde¤cÙ=€ÓDérf†Î Ü|ªÃAI$¨åJCÙo!AŠ¼–„Ý"÷²^ˆ1ž—báÞ¾¨ÉÞ³¸a/úNîN²ßÎdjEböóž:aù×ßìNãÚ5ÇæTRÝ:s^¼>º)쇻çvà ÕSž‰º¹"°÷?ä±]u>ñìÏ–ˆ ˜UÅÉâ0H#Ç°=z™6Ê)R#k“¡Þ©»”BƒžÏÝšV=A{®_y}~m‰²""tçñ^©ë§3zò×aŸ…¿6ÁÐôþãU¦Žq8³óüŸiÒù?¾¡ýoQdOeÏp‡K‚Ar2ÉNâ 50Èhû6tMHåçnãeD ~µé¹µ÷z‹Ôª¥ÈI%™UU®ðQ8$whM 9,HÙbzy¼‚B>SÄâ‡èþéË‹è—åó¯!üz=‚÷Øþ#+‘-Õc®>M¨É¬’[ 5þÔ<SÐ÷Ûd$Ü>’]þ¬ù¿L5òøo¶ê)Ù²gF1ý#*/¾²XnFDy»:|V51ï°9$, ½0¾¦*»œòI¸HKöŠ×§#*740±zä`ÛŸ!°O¿¯®zï÷ûÔkF …Tf@ ’žÙ"ªáï&ˉw\í{÷[ÎÓu_×¥]`OóåÓy¶‰yteŠ(È7b–¤dkîô{eý>\ÿËç·ßÚ4þ˜UÃ!”ûûþhyž Å“Q#+#+¤XŒŒõë›RfDQÌr¡Kò„ØOÐlfrñ¦41-6—·n›ÑHÚ)¬1=j ±o\ËA„y©Y¦=Zﺊ°Ì#+ÑFy#â¨=¦fhPi12ŠÔX_;š&Ž-/ö؈Ä××&D+‚剕.œ!&ˆíš™7ùI%‚Î6Ðmlst+¥#*ß¼Œ†hŒ5`£yTðeLzDm,ݹÁ²#+¬ä$d]Ÿ#)Ë’ËtŽjÐøÕEfÞ;BÕmÆ6Ü,‰’šÝëq3cRbˆlfÐrP¡™&%‚L"#)´nåµG[#Hê¡Âcm'[C®Ù`Ø2麰!05i™ÈgNªéÿ=Pp…©$Xj§0C^ž¼eÌ]wî:õÔw¦P(“Û Ö¿+¢á8Fñ™ãž)JÁ`ÙÂÒ´ÛãûÏâØþOØTáÀ1ÞË·räø¸Cw€G”;ð†÷MIg瘸(!Áàƒ‹1¦È&^3òÙ÷MÌ8aŒýæˆ=AÀ¯/qÿ~3Aм}ÛåÌqµBÝŽt¢zømG¿6 ôûA>Ãò#+èÇW-~¬:S¤Òh v¸-ž #*áî..T–AbŒX°´ª¯Ï“U44ã÷Þ1nEtˆHé7^ZQ"TéöO£KVItêDqH2$HÝMCŒÁß®ÍEĉÔTíšÃ~¡£DžÝÞg‹¶ l=½±zM7§B‡v<„WÁæôk@KEÓÈ´A¢#+‚q64(¸ÃXĸÜæÕÒª´U…N3éý”uÆb!П:¦”ŠM¸Û(ŽoÊÛ†V~[ÿ¼ŸÙ×~ßgœtþþ\`<}âï^‘vZ¼Ióâ<=ŸÏÆUî«¢‰ýП‰T§ÞÂ#*Óî›? 4.ZVƒ#qnÎ&:Ç”øíxöö›ÚÀgNŽ|æ4Rë«Úî½æé˘cŽmcÒ´Â@ƒÌ}äu·{ªŒ¤ï#+è»2ïÊXHÜQàÈØÙùÌE±å\b0A¶œF:7„)zÑ6ñáE–„ãZëyž6fDÙª\â]Å£‚`ÆQe…AY5d¦C`1T‚ùAX„oª$e*QM5CEZ¬-Ý#*ÿH®YÚÃŒccæCB;:y¾#+ÛiypMDˬ’dnŽ’`ºh#+Í$¶.ÕcIŒçš6Œ]Ú„O–âDDï{´5#*8±¦w(eŒÉÈÚèèÊ&E½À¬vÅ`j0t¡E&Y#FS%|åFX3äÐg~v™nÔ÷tË„.1z~8æ[Ê3ʦ6˜þ‘ͪóœÍ[¦ùm†²ðÏ©Ó‘é'Çêä™ÁÌŽp8QZãÇmùá¢hø*®åûÐ`æΩܔ;ÕPVü°M!”_ã§[m¾·mŸcFSÁÉÈf=¼Rà¸@“mˆóc®1´¬òÌѤ_C¸5-Æ«¯:úÙ¶ØÆ?8¢ðÎ<o¦j6äÜ‘R®©n1v6«D˜E¼ Œƒ$M±ÕBws=ÀºmŸ(#* ¦fzømãEï˜×=¸ça¢‘¼—43“¦—B#JHçXÌX()ð¬-óU{jÌÞÜ5¶ßÍBôÁ±ý¦Åš°¤<Ci‹7t Ü>—ÜÛc5P ‘0Ú±ÇI¶q·kYäp8Íé0„$Å',¡ˆã±5ùC:˱°`¬Åü‰X~ÖqÆÞX¨aÐì’yØiœŽˆÅ{q¬¸Ã}Cç¹ÃÎFÜõ£#+ÄÞòî~ëa™]]Íú’7›HIƒñmßS/—LíyÝ£#ZÝõy–€t×ß^—@ÒÆÆÜ>QÒcVò+UZÞLª‚î]IK‚´*ùNþjì;«Îºc…ÁÄ`ÉoȶÃ@ŒA‚Í@G!¸xL¨ÚR‹x·Î-“nÚ×:ä¢>é%·‚!Dvx(æÈØ6)v¸íÆÓ½»#+6ÚŽƒ®®ê#+ɼIJV;…Fç¯-ÓoŽ¨¥Ó#+ÀO¾ƒX°Ü#*¶µ¾×.:1ì¹ÅjÇhDèÅ7M]g2r3³eI(ijäÍb<@ìÕ.6bsŒÅ“†6Ea–`0œäcZ6ƒ7ÑÉ'8Ù¢—+šÑ].íaZu`Øäí¶ÆNM žIµ©42 Ãiæls}žã’ÆÄ×ncV¿<ëfm“‰¾µö’®ÐÌ!(nÇ,~>éµáÜ)2pç:䤡KÄ9S!mDø¨ë;¥éí¼¶Ó–#*ÖŽ)¸‘‡º=öäâ0„b#%To¯,Ú¶¼5ó4•ÿŽã"N'"1±$@Xùdý)ºci§ä)ˆx·×AQ5{¶Ø‰Tˆ‹™‡ygWþK®gQYË•$×½F蛎‚JYY1D1–Ê›t»ã¼ikIÂœTi#+uoŠBËÚÁñÚæ]óO#+3¥"‹Û0EPû)<TG›ê$&I7~WEÏÓIÑÏ#*|qƒhÁŒPšp¾%ц=;fõÓýw;¹}1XW¾;Å÷Í?(l´±MÖgW,_1øèºVº--§`„øO0mB&å¹b°ñ©lš¿ëq÷”D>y‰¥IeFø;“ƒ<™A¦²?Ïh&‰ ¾¹âÀJÈÝzvØ#*ò-d…„ Êl#26«7“Ž'}ÆôÛ_–YtNÃWdÓ;=ä/fRͲºòcRá\ŒÓò«åÚæ×·Ãù³¦†£²ŠŸ'7И{ì1î5HtΚáØž~¶Ç¥_iM[AÍJ6E;àñ¬Ü#*1µ(zïZUå†Þ¬M1¡¶2„’ƒ.–¬±¡°DûN‹A2Dàá½\69Ø/ZãÂ%ë—•ŽkMév뮶ƒ8ux¼üá#+‹ÂÖð-2‰ºtl_¸Æ.Ž#*€A$Xð¯fß¡j7§È<YGé|N€QJ}æ—ûJ‰ÜÚŠ§–a"âõØo… ƒ³g'Õl¨éì/ÓïQÝæ£wívr{#€‡bÍÁ‚ëO@wÔ/ÄÓÚ&‘!EU<â‚̆I¨@»kúÐ3‡ã÷9ÝHÚ bÅz2Ç‘8z³óGËV¾¼õ{•ï½D€è#)²z¾Ü#ãì°"#È EÌèüÿi\£v.:¼¯¢¸zW&Àø®Íx|nó@\è4ïÔÿ1i%÷+·kÔxß蘞ÎACíùë5Æ•öQÈʃ„—È0›FB뙌01Ú2ÏŸ¿ñÁ¿ÃmþîßÞ¾"™åà,¥#)Ì…LôÍÊ 0~Iß}÷÷©ÓýÚ—e—¥÷œC#¾vñÞá!`£X#)$;¤#¾×6C¿ÈU®*?#*±£vÑÉg~ GT$Ä'ÏðƒC#)–7ŠõÈQnVC¹@°9È2è3ë^ȈŒpùÀIÔýcg“{™7Œy“ŽIvcí5ª§ô#)s£ŸÐ.¸1x"]m GääGÇ$\¬›Nj‚¥ÁàI6ÌÓ‰§¶)J¨{ÏÃF`?Úý?Æ[…\åÝþmÑÂDyÁÚ·ãñ¥Å)¢‰xØ0L™Š§ÊcuóʆñžÈ¥%[²YpF\¹#+Q´Á*ÃøÛŒ[&-‡™¡hKrI‰pCŒ…G©îãã}OÂϦî¡I’b%àã¶.`ä&ß³1CÀ™ßIü5WÕ[Ãæ‘Ÿ#+áÝ®ºIHB¥§Ù4,²tJÄzÅÂqæØÜUÛ]nk»tà0X»Ü=ôTŸÔV*y:¶ÏvB•ˆ_aG˜²ÝÑÖúí3¢9Ï#+–"q£$@‘LT&¯¾!u½“<ÖaàoWƒzi™UK‘OIC–ã¤è{Œ®Ê úý!{±”MÁÑÇM¤"ˆ9æµå2I©¬#+Xv\sG™'ÙÝtï&½Aé’’yê½Y±GfXFÞ©ˆèì:f ‡94gÒ|«§)ÖïÚÍÚšç'ôômê^èÑ8ßéO¶zßLãÚwæLY¬ÔÈ„´ðV}Url„¯DÚk$ÿ4óÈJhTψƒ‚ž‡eçik“è;#ŠþIqÏ1þ#6úÈÛO´:U$øUü’ørðÆŠæ8ðü/v‚í‰d7'hèSK…Ì'p»k㔜-÷a¹ôt(Ä$x°2˜1åÈ~HœO#+?½p™= Î[ÖuˆáÎLš~;ii1#›aAI¤XI1áAóΛ*ãÓl9óÀðÍHZaÑhJò×ìDG9|8#*õÓžŽjô"ˆ!4²~U¹›cö‘•3–Áôh¦øÖ¦#2к£À´Ï5(r¹ëìÝd#µzü¬ñ¤‰4"·T½Ä½Óã~;D¬xZjm9ËQï…ðäÞí§ÆˆG±2¹'¨tBw#+Ï¥þ‹Ïb_É;ä‚2Iÿ#᎜ ·iÀÜŒ¢"´B¬È樻³„㼄t&§pÃ7Í1Ñ$RÛðùLf†2TOsÅ©…ºw§™®)nL9)ˆÄÈÈ_ÎGË«q\œ¿CÍÛºlpî]¼EÝE”µß¹øˆò£ÕšO¼ãýã÷RsKš`Úå5Tójû^°Qæ DT}1ˆÚD7æㇶÏhÊ0*Ü×ß:Ö h#)íúæZi4QÃRÆZØR:¯¤À$:h§2€`UéžÄ6ÖeV1É#*vÄYÆ©–ëÇ"ÌýerÌïò!ðþ\ø3â0Ç*Ë+YQ_ÀFéuž-Å”,ýdDó™±··‡•¢Qö“Ùhtsc%[ìR fŠê{ 3òªA·ÐkÙ¨ªë¢Ó• Œ%d®PñŽ¶–øèú颕‹@…)Õ§)Oˆû¢ªH„žg¼êÉ}¶b^j~8y$*×GÍ«VðÉ7×Y{ØémðLèÂ|ò6œ¡™úµœ¦§w(î¸V§$s\òù\sK[¢ÑÆ©vÃæ!sYP¢·N+å3Ç¥|Õm¿”sÎ áß&×:/OÎK3mäô)Ó¥ééµ’|ºû¹tÀp&`ȃѧ4995‘’…l2®„Û™{Ü#*-\ÌædèÛð6VÔ^!6x–óŸUr“í·Xm´üD6sž*kçÓb'&ëx\Ö®]éBfÛŽ¼)ÓaŒÑîMQ|ѱå¢ÜÝŸxêºÇvb©ƒ»ñTŒå£ci|#* ¨ÆY—<…ü•ƒhYÁoÒá…ÞËÙÜFI#*Ç°”ØÔþKÊ&5È£Òc:=Ö»íÎKtÏœáž7¸‰jmcЮ¨¶ÙøÑ )’*DÜw(:¤‡Š@*…as¯6¾‰©Py#+‰¶Û$ûE)}ë'Æï}'nkcg6|$ PàòŽFè© åor8'jeä;MF‹ílr½FôÐ= *\¨½:ÛEÙ´²8‚بz’i=ÊðŠã±Fo%ë*œ¡açgþ3ç7s”¾{ð¤ß>üg:¶æ$qCñnsl û\ÂŒ=³<U"¸x/ÊO` •,'è{¨´•YE]*4íöéXóAƒ§ÅÃÆûyæÙÁâ¿nÇ¥·Ø‡{*£Öç…6z)Ñâ~!å/;cjûQŒÛ’ÓrÁölíÄíJÙ{–Ï&èy%ÝØ‹´”Ùu¼,ÉvõutÁ=ZÏjø}¦o¢ÿÀ¿8âÞ}´s^G ap%N4e °iQ‘Ieâ]©„–¢üÈRÆQãËÌس¾fDÒÉá߬FÞRÒkdýæ{⛽Wv߯<o£ ˜D¹qÉÂ¥cŽ‰fFVÛ›[ãhròÄ$Þ”:éùÚÿWÐØæä?ëQÇ÷åVܘ2(ƒu¡ðäÔOLnû‡ß¢|ɇçȶ9E|ÞH1™Í+¯³®N½j",evY®sBSóF:ÓeӇɚôŠH6±öœœï]|ñ×icàÍƵL#+¥ž e¡>ÜØå#)vƒåy=ˆÄ<žàßïÆNý\«ë´ˆI _*ZžÀ"Á&eÁ.Pjâš›?ߟÏÜû¾rÚbgýIX¯È¢ê+äS\Õ}ÞuFŠ/ê«>Í‹¦ìu]dÀë:FNxëýbT{ÈIZkŽªÎŸ$érÎ[J(7ÕZÊõR:چ齄óv¦„ÉÕÁl×h[…¤0¢^·1£´ÜD…e-×FóÜÏå¦ú ÓsT»f«ùW#+/期«šÑLõYf#¡òxÃ#½áåÐ!#)tÎÖ“ïnŽW4Ubsa1´RXŸµèèÙß“¡L¢)áŽÕÕ.Xmz†Q‹ÿ·ÉjJÅÚQÁgÏXoÃ=¢ss²¹*vÅn± »ËÏâ¬*pƒW[¦Ú¬óþ:]~p6œáLqi1Þ³={ËÊâ¸Õjù_hæªÌÕ,`œRWsÇÀŠÇü§}²ù*šÅFÀª²[,çÚڌ2–SXBX€>Ǽ9ÁFmd"ÊR¢Ý-ó¹òKÐÙk÷#*ž6:#+váLñÊ-,’ØZØtw&Aâ%å^è]7Jéråpu™¦G‹à8Âü§/q°X4VتÆÚ†-.› éÌÖÙ‹EðR´t}yuQ³…[Cî¨Æûáo¦s„˜-÷°&žRS*:SʤR9q%yßù£ã¯³ÆL.ܧ™ö§"!ÙÃÊ̦æÐð9B†Õ²üë(ÊâéYµô×åI|m¥ˆ¹\ët3úõ™slLÔÓÊÞ¡-«ƒk·^ßp´mV‚iT“#+3X»¯±W(ñ]‚Jl_'‰AZŒYÝ/§#*qƳ2¼(ÍÔ1¹QŸ†Ùš8Yž]”Òò{¯>Dob|»ú,Ô÷ïKÓƒýƒÚk"§Š3Qý…îCzìί-%´ÍK>qn‡AåôÂZW\e'(âʺé¿då2^$õ°‡'¨œÛ»*_F’.ÜÈM¿¹¢ä½…Lî¡BÝK²¶#+:x’¥ÐQ±µ’â5Å.’Í#+ºy*¯fÃ_zÎW@]¬ë™†Ñ€¨»ÆÝ33JÎÏ<K˜æ·\Mmó%Öªuqx{6^qŒto¾B¥¯%os”4ìZ°~„tÇŒ—a÷ñ¼6ÿ²Êå;ÁRÏȪ!mäùã2h½´ÅÔ¡€#+GMÉq°r¿Âsvƒy»¹†“¹Áhg¬I·“môw="™]Zº“ÓHìØ&Ñ¥)W<0r±Î9çI[ Ädn}ÍèµmKTYyQú ár÷¼:5vyWK«Š‡CŸ™ ñ•;øÞ ù×BÍîÍV$Šp(Ë6€XJo·LÄPßP´Ž#+Ù.w ™Õ9û±Â{}æ*™Ý§Ï·<ñšÆ#+”<eý¶Ï<lÀNª#+¬n«™¼¦ˆóB‘ƒÍϲç¼Ø^[sžÊ:Tlv¬³óMÅÒÊ—Ú®½Î‹ØH!a-”9“¶×Èæ<„Fei«E`#*³[vFü¢#*ma»qX×'ÚëúdÞ+1ªwŽÛ®šyS¤e¥ùUËñµG›â;;†IÙ㉟/E˜7ÎO~‚Ϫ\Ò¬f#*ž-®ãêP Rîl(«TEE&’XìÈë‘ÇŽ‰UWšññ_:#’[‰× ’s¤s¿}vÌÚZ›‘zÜmÏïû±·Ë9Þtƒ•Í¹e¦n"7EoËTv8#+g8šÛ{fjë¢Ì*øbÄ6hÀDï6Ü&öÝ„,RÖjátq¨¼0¥'HÖ dšJ¸({ÝÒ´u‚>¡HÆÔ)#¨ŽIY_#+ÛJêp|–JBÖNaỞ×á`ÎVŒj¶kÖøÙ²!¾y´\¹piR-A bg=3KiWÆ•–}¹Zí£KQíd«v»®Ðå¬Âï¡óÖÙïiv«W#+1‡ŠíòÞ÷×YÖjÈ—|•C¨_(ÙŠÁ³óG¦›—`ÈH·Œ¯£UÈ\ƒ,œÐíÓŠð½:^‡ÑÕêëõ8àÔŒÊB„q-º]#*òÃS›~4±â3Sƒ„j²™n{w46Ä]¾û¶_bó9hÁÍx•å ÊÜÆ#*Ó“cZ#*µ¦ºjŒZèt+d$ÎÅŒ'[_Èç¦z¨éÑZ°´ÀC1MøÀ¨+ÒÖgØ#*“¤#EÖ-æè_+g–.Ô;· żŒƒµµ@Á\÷#+59ÂBþpœ!M6i€Pgä,2¢1ýÒT¥ƒY)ø€÷z>÷·/#+,:νÓ1Çàöö‹KÈSáoÒ@úˆ°Ì@¡Î2²8 áÕ)ÜÒVyí-U~œóv‰C#+É%PoYZ”QÆœœ6Ï©¥ÿ¿ÍîšÃŽ9°ãôåQTº~®îËuj™/šÙEJôFÒëjm£ÒxR$‚ ãd5UáöÑÝ´ƒ_#+q#ƒ<‚<ŠÌˆGX-š;Zä/µD5Ë·Wºé«iTÒèœÏèÄ2 Á¿bÖÁëh´Cªk3dÖ9ñt{¨±ëmª!îô…¬ßË|Ìëxú£±Ê…÷ÙÍ:ç/f/Óå/x™N;Tǧ?]æÜuG<Ÿ±©3+#+¡·û^×ìw)ŸÝÊZsÉDmÛy™L?ÝÈ港LKý|©RÔŽ#*¡à]lZËãKÝMÍeÁÏ”lŸ0Ê"DYH]ånª)ßòOë·IáÏÏ:¿|žZzÛ]~77Mæ¤tÄs%YIQĘN¦u¾T¢¬ÈLÚFÃÌ`o¦ÑµKæKÔM)U¼;®Š,=xý•ƒŸ“ùmDt¬8upŽq qc%ãMù¹°ì¤)Àl*j„î€Ôàñt0ô:×>1[OSÚ÷ô; d„…Ä“{“79È·ƒß»Ó»žŠùäÞæ;û+o,ÛaéïöÓË0Cuüqoœà¨L½_Øã³T™Û:–¤¢6m‹›á ršE˜ËKÞ_Þsû)ªÖ{gÖ6ß,±e‡>tá±ë&<'k’è+Åœö./ÓÚÕ‚TÃ÷Ûô‘!#yFG{Sà¬6:e#)”}¤+Ë€é|1Ò·´fê—N<ˆ‰1Ó“©i\7¬lÂõQÖþloa#+ËÎdñª°Ë$˜c×Aš |zåÕºt¨äǤjÿR<×íGžÎ{¼ª}~>LRú´,9¡ø³½÷½»óùcÁ¢C;¯»£-ñ’r)ñÜ©ÆÎrÄ ÀÝ:9Òâ»UÝNmúƧ¾}[6âjž‡5tM¢ð» Ùx/pö_”ft€J6ç÷LY5TÞ¾pGC‚ÍÍ{îÛˆúr¦³”DK#)¡•C,#+h¼:- ð0!CÜ$trŽY¤…øÙÄi°NWœ—a‹°÷Sø-tœnªšµZLš¿±ô×CôÊÝa.Ž›U*BñVÄul˜J;FûX#*Ç -È8÷«¨S‚ót¹,’sšáA‹<EYë{A¾sÏ!L²¸Klª²˜{˜nŶºN.šX”.éB‰NUƒš:i›þŽêÝ`´BNÁ›«¡Tj#k-RÃEïÎèØ9QÐr>È‹ìòž3<¸{’ÞÝs£3û¿‹ûr÷ë;XÏÄû§zí̽ƒDfáÛ)9æK¼«ïuÑ:mhEdׯÌl}ÐgN×)‚À£„<ÙïV¤˜56\Ÿ6^xü0¥}]´`2+µÌœgs¢@x8lkÜÞ°Å¿ñp”Aa¥¢–&=}jŽ,ùxâ=xÅÞ<K–|+ûÛݶ¦9«µ/+°,÷|ÛYRg…l·†Ð%k^µR0~ï3{µ¬¡„,ÄçR9Ü>Ê]>¾y#+çtTl0-AÒnŠ¼ýCÍ‹>ˆ±”„D’ƒúÏŸÝü{øúuv&çÉœ_±ÖÿUÕHÈ”#©êÝ#Öêä.Ûæ–Ž“ZL©_~1º/Ûe½úkeÎl}ÚXqaœÿGWð ¹8$ýià†¥,°NHŒs€³<áÓ#+yú¤¼ƒ#+ت„^í@^™.—.N¾þ×ËX’±Ñ©®4釅Èö¸»®eý#)öw.mM“Bªò‡ß6èÖ¢sÜÒ½KRBaãÖš³ù_Ruþ¢0r8z\AÝDŸW°NxïÒº¡i£Uþ~Œ©iAxb@© is‘=ãÀ†G!¹QD¤¹ŽbJ)ËÑ–"é#FB´§W2Ò3fY…RîDHÒ®œwÇÝ{#lü/ëÅúeþë3-vŽ"U™4欤·EPMwŽ¢‡ìgNu.¾Çb-ÂÚ¿I!"`}¸’fŽëÑ|«—öÆ~ݼ÷5—Hô^žœw˜ÇlÏDm»ö^Bn±b3F”ÛŸÞ³Š’˜Þðj!l¢ìÒ ö°Þ/¥VÔ¤k$™Ã%²Us±Áâׂ |&i{™)þÔOJÌl+ç¬}X}6z^V…¶sk1ƒ†‡¼†ßI0X‡ã>7p¤ôÎbÛ` -ÐèeùÖ, CŒü`Æ×[È©®Ì{¥£ÎŽRzÅ~Üò:§\âågÉ5~:¨e\æ³ÞnÝ®ŒPßUïå-éðÉÛѸFµÎqÚk”ÓZ9ád*”t™ãÖÛ¿5ôƒ’žÈôÇ[r|o)#XÔW·—>‹Ÿ˜æz^x¶‰±¡ê݈eQʃû#*‹`Ü1˜ÛNAõ;ñoò$³®‹›¸x‹<Cf‹øc•×;Ô—#Z_f³g~AÚ-¹ñwÒ·ž¾D‰ ‘·sô6‰×›Ö:ñLÔ]9½Ë¯P_qÒNK>¹¼¬O_3EÅ>HاŒ«\àMœÜ_Ñ™~¨:'ñÝÏ“\•ùó€®?œMæ*=ZWxKÂù×c×ÉÈU‚b-Š[ñƒ ¯×Ó3öœ¶ž`ƒàŽ#Îk¨cdÛ£ÇÁÓHdIZ©Vám…ÊA„‚9ÛW5~!ÛŒä[åg¥yõ¿ov"ÍZ†n#+ÚçÂs”Ô¤‰oéìé‡ÆaÓƒ¡ÑÀÿêøG‘ÁŽzö·ÝòCÛ &™(B~ðž[ÃP:mPžÌG~ýÖÔÓíQ@E#äTa’ÛåÕ#G]›Ñ8s>—_X¡xhs›rëxÐgÆ2Ì4j†f3›™(¶x!ðê¦Ï{Ux+Y8;å>w^`Óq6ɇï»s%˜è,ºt‰Fý._\T Rôzà’æ |'+Ÿm‰loEá}™Ì÷þ®dxáÐCbù?ÃÊ”ù‹ÕfÜ©W®Ö„cé2-Ixãà‹»ò!½bGeœžÚ(Ô®"LI´'š¶Kbjd±ˆÈ¤d¬ä#+oÃR`äèÙb&d#*}ûgìò:C qÐì!¼eùÎzó—Fy÷Ä7Ž÷ÇãŸÑ¹YTJ@;šè‡Xþ]‰M;oþ›¶tÚîúØQ_—UgX¦žµA4!;MàbšÄºÇ#OC<_ˇjtnïPàA4‹ëdí)½ã 'Œ+éU<Ê•#*$–‹rÛ7¿g˃^‘ïkÝ®^ÃöûÆË´pejžûrBÇ¿›çÅäwjòm›Þ$?³ÿ‚£™¨;ìŸ0n—f1U#¶#+Ú”?´òÅò£¢¦ò5½¦µìûp&Z~ÚÞÜrý±"ÝΗÄ#*IáÞqŠð§ò~‡9Œ;ÌÙÑWÝmÑÚ›TÆ—B!WÆosÝãËæ}™ì1+°ð/8ç2·z³RB+×ÃM €tg¡mAH ºY4rЖh|K::Òq¬ß,cøËZ„ &Có÷(;&¤úr/ï°…@tØB˜,ý¾¦æ_@×™Žºÿg? €ð2åòú/¯éîïNøŸ‡WË>2–•ðåÄ #)§ÏìPìOÑõãÖŠç°Ø9Mw#Ù(JL+G;Q@À€ðè{<¸ÖK ! Až½(AF#©õƒãWyl.£%ýç8Ãöÿ¡v¿œ•Î»–Ä–“õ;e6‰HÚ“l›ªå¶åµuÕ§¯@ðbq2"Z"@ú4 Ë6o+ùü,q‰µÂ[~-Ÿ,øk_Ï|Ðù‰–¾FåxI$"‘AƒRIæ&©×‡™z½:›†r:L-&OŸÄÌx§jÎ-œ»-±<Ù‘ýp®™j9I2½KW²}¯&‚ßh'Ùáó7#+&-žû¡{ì$Cì®È#)GÌþä㘋`ªˆ$-Qµ]Ê¿º8,ªdU,…F’£rºÞ›¿eEž'ÛP Øåo±(Í¡mÿd“^çü€»‚‹ªHœ“’Ê=D-òùÞƒ=’ûb/çòwÏhYäb›zêÞ96½]µ‡ÎîÝ0nCqýÌ.ü|ìŸÒ#*®…ªzïnbb5i£¦¤dÔÓҔػZCŸÒÎ)rª%‹ça{à®èRˆö9#MLЩ‘; $=‰Bj}¥HøÓCåÃ嬉°‘?GØ©¡ý*!Š#*K©wkSî¨ÅÈ?ƒÜ˜ê„#+}s³˜íÜ"—kU‚€@UVeÀUœ7íËoÔ¿v¿‡ñ%\ÏÄ«B#*Ór\E³¨dн0_±Ùè³|\eÁ‚ÿ'ígsÚ*ƒ“Ôj2l…î2é稈yc%3p†€ýŸæsy5Iø„ç˜FÛ{òá k‡çܨ¡XÊr¢’¢È¦~úw@ß8§Ý>öÀ{“)LW@¡Ïñÿ%ðB!àkRw!%"_VºU<'lC&ˆVnÂÎp#+d÷°Õ)4`/Žµ‡\дž,¤†¥Ô“D¡¡°á» †ìxpƈ#+Tv‘½µ%ƒÙg#)ùL¢#OF³»i“µÒÅ„þˆC®ÀžÏ‹¬„½Öl£öNºJõøÂañŠ¾`Ù8ú&Ø`“Fvk¾}N¿ãÞ =øõšk¸!„zí13H쇶7*¥NëT] ]ê£v̯>[0nƒÝ®…ÎiÑGTqâtÔÊÀÂEŠÊ®Àoj¢Ê#)¤’P Ì°‚ÒL{Ww-%éfá…ÉíU½íuÏîª%í:ûïFÍÀ`¯o—LïøÕÀ”žØÀ_¹êÏØîŽ]¦P#qŒ´€lÏQ#)}î«"Ýb³“ì^<#Ìë£{÷o9¬ã*]U×»â_‚ãõßì…‘mdÉÔ(ß„ˆ9_7¢¬™J^UÁAÞªBzJ” Pµ+ªj_©¹Üï¶#*FãŸ$z¨Ó‡/[O2F•PÍU3Œ) K—^÷ÑbO|4Òè´ÉÇ1¶ÿ ”5¶q‰ººXG]uÖ/q<2‰´Û=ªc-ƒQuŒHí@i6Ī"Àm!¼Š;¢œ³Ï•özè6é~Æ}uç<§VF²&¡«½€:ÍBªë£»##*Z·kÛ²¨Ù¢¼Š\DAN=†W<„1”ˆJ¡`Qf¡YAá¾7MÇñõ°*"%l+a僿 (1A&×Ç]ß3ºhàÂrr^õ{ñ䨡ØÎÿ¡–lÎgîV‰•õÔ#+@žæD*šõf›#!‚‹O‚f[ïÕž×oeùn+݉FS?Ÿ¶qœ@ýÓs#ÎÐàH˜Hj )2q¶Þø|7¤vžoŽ$ìLÇõ“62½×5g$&¨ESPÁIÉ4J«ÎŽ`¥ŒÏÓŒ}#)z¹…÷í»§®®€ªz‹qƒ®Ä†„ïd-.Šð/Ôˆ¼úÝyüuåÕIQÏXçnÅ,ø-pÐ#)ÕDl–ìõL‚‚#0®´šq'#+žÎê—΃´ŒÿØΰ›Î_N!^À–Áîì˜\:BnÛè/Š™•ícÆ<ÂÔ`IßQCmßQóy¿Eã·¤ò@ù¿°ù ç‹êÎi€îäC·˜T%.TÞ1ÚrûÞLóˆîòye› TŸ›DgˆÏF›œÃÎÊû¶«…æ|F‘ŒÞ“Ï7ȃ;#o§HՌʼn?MϹ\E#*«Ï4¥0½B)œhBÐ-L »Ð·àUrçúõ›Íà±I¿á(HªZa<!ÀË94œ.¶Ç #„1§'Ö©ŒÓÚ#*$nãE"#+’xòw.O×øÛœ¾Å«Ö‘èBÈzbF;¦fçþË-]z|Bœ÷shœCó%§®Bæ[ÝÆqãžÆJÁÕ)ç¾—Á\l[›†ùstG˹ ‘Ë+Qƒ`-$9$ÙÛ(!=e,£Ë¢÷#ôsÞåÛ\{uÜ£UîAè*Oò.6¿´yåRÆÌN¸ƒ™-ó_•ÔxÞ-w”ŠÚ“³6JsLC¾Ã|¤á*Dª… pGÍ#*ÃAÎŒòMni×Ío¯B«®zzëÍ2‡@ÂÍ£5¹¯#ºoˆ€ÄEÜ®PØ¡aËaÑ!¶# #*0îu‚.-×?Eo3à ÄIQÃq½-š,ŒÙñƒf傇ÍÊÁG,™†úØ–¨EKn% vouGˬFs’H3ÖsÕ|k‘mß~ÍØð$䙨ÊäBTZ/üy(й‹îÌ.D’×SÍcèt‚çã‡ay§§ÍﲡýnÄS‹ß†Ÿ,±7”–ˆ—ó"»9ax§“hU+ÑÌ0ÇékŽü^º2—/ž$jêá +Ýpe™œU?~˜Á7ΓÍ.\0`ÀP#+q7’n%ƒ(B”Rç‰óžŸqTç¸^Ûâý=ßGï^9ºwÆéá\›soã{”I#*;Ï[°ûŽ±ÙÙÂë¨^ççdym_ƒp®»å‰ìü2S0¨‘ùÒÃJ°N:B+³›Ëoä|`^¿4¤mÑCÍ{‹ŠqtZ@•zöpÛÖ1Œ$Ö@o"Á•0ÞC½Y$S¥¢imIçô(ø²g€{w,Rîú¼Õ#+ZÞ‡÷ìH#Ñs[9•û¯ÛÒ”98̉'‚°Þ5æ¥ Z·ÒÊ€Ä;š¦Ò*ø9: ¬ ‘TÆåçÎpØtlc*ÑæSüæÑ#*yv{ñûmwTø~Žw_ÄØÂ(ÞÂBg¤zVöÄFërÂWˆ¸ª¦Óyõ€Ža›ÇÊX#+·Ãa#+QÁŒõíÅÄ‚€È??8¢lŽ±u¼Ä8é'È.EÝ›8p‹íI¦‚Ý-,€£ÈÔ¨CŠ)yOW‚ú+“dFêÇ>õÕMËj~Û5¨Õ'J‚ßW>-ò·õ¸8ÓJ°V`ųs-‡tï³Hmȯ]pkâÐeØÊfõF©äctÕmèÚFhMÛrúÿ‚ˆk^`’GQ‘^í#ïm#*#+tå¶3˜:PJÞ7”«èÃ0ò¸§øßKêO‰§C•/Žo·‹oOßšÛºáŽýå‡Ü³”ˆlÔ3‘ã$m¬]Øɘ˜9#+ùæT@æÀã5¢MÌE#+*€CÙÆý\ötÚ(Þ°sÝ°¡Ã=Å%b¦Í(´‘laM§^ý~\GNr˜jμ‹ß‘nS™Q—Oæ¾áIÂjcÁaŽ®sብ»#åéôë¼áÀ8o¿’;êF¼“G“¦‰[¿‚‡Å1)ŒùOç!\Húڎμÿ\ïo$î¥éÍö*Ð’žÄ?ÙPbJk<èG+¢‘D„qþd1üæåhºÎÅ¥+vîß°*Ý…Æ(”ÂR«ü¿Ùí{ò©¦x¥#)iþ>÷Ž]q~º¨LþÏñŠ¨Å„+Ü|Ì“ïôwÖYÂgßAUOv€ þ0OH19ùq<r{×ëöC¡'Sߟ^X¨ª¤$ÿ#*ð- C÷È‹‡õP#’òÍüφðÝö?‡×õ[ˆþ«SÀ=iá¡€3~¾t‰³@/zÝô_?^Îb„×*¹ËÍK®p#+Rєʢ2BxÙâ„/öQ€‹»)YÛÆ»„ß8‡1>ýþ—F:Þ9Ž¿V»ã^’"p…ç¿ãÕ,_©Ñ*",õ{|s¸ç¸ÖËëë°åtN" )!{!Qð*ô©¢§îõE6ÌF:¶j¥a‘Y·‘1Žk{¿„ûÏëۉDZÖyJ GJ €ãÀyùËdo~#)ú‘K›|ûÂ]Í`«éhÃGgYØøïE‹>ARá?´xp˜˜å½B—N#œl#Éí¯êœÅM“•¹Õ_VDñb|ÿ–É×¥wۨݙCƒ ‚°Uûƒê.VÁ÷frõýŠ†;ÿ+Ÿ¡ý_/LþOPçOyQ(¼#)zXÚlD¿×òÿùÿ'ü?Ïþ¯ö}ß÷þÿ«ÿ‡ÿµûsÿgÿoüáøûoûÍõÿ£ý?7«ýÑû}ß÷ÿ·þÿ›ÿú?ÓˆÿÇþÿò¯üñÿ/ú¿ãÛþïõYÿ³þùy>ÃÏôWÏþÿ÷¿ïÿwûáÛÿøÿÇø~`#)ŸÆÿo÷ãþfäþ«XUª?žËSûÌXq|¿ö¦¡ýÿêåÚ¯üˆCû"—ÿQè.Y¬0~tfS¡’£Q#)rPÈ\€ ýª‡D:D,Ãñb¢e:¢97ÖØ¡Ë4°#)H‚ú€Ò€»2‚a¥ˆé#)Áˆ+#)‰²–Õð‚¶L¨Šk),dEI¸:\¤tQºPY#ʸ2 ™Ž½Öø\°†5R&¤£M¢îK•ŒÄ±`ŒK%•LlÉJYªFDƒ%ÔPÎ*ÿß¡mŸæžÿ:/úUÿ—ÒÏ/îéÿXÿK8õøÚ,è“=§u* bwòy‰îËüÛÖ7üôl8#+Ùp\†ÿéBÿ¶±§èsx$–š»A¦ÀdCa5±³æÀ!Ù^däîË¢ß÷g¢Še®Ð½1‘˜ÞSfb¶ºxÞ¨ãžæhÔ>ªo-cGhšBWzŠ}î©íw¿÷\Û9ÔgE»ÇýNÉ&ÀÆܨ>Ô½¹×/2GGom_fÉ=´Ó3rèÃÂ@z³ÈH6i¡°R™(•V ±n‚pmœÜ"&ñõëwa!šH´q™s£·ˆ~þ!°/1üxÛˆ‚¸ëŒ«û¤á{ÑKãqÖëFÞ|!YÓ'¢YÅG¾&ÍŠ†‹ˆe'u×ìᶡÅðõZŒŒ’mè~á–Dw`w³FjVPõ?ÚãΩòi‹¨ö$³ÇgWæv˜ll<Í㢲ë›õÓÌøÃòYDéÝtZe1ð!!ÇÞ‡ƒ=£ÎBÖšØc™ÿ¥á#*q{ìiÂÚ¬?8k?ã`Ë6…ïîÓbW?"È?ìÀ9Ùž-Æ%ŽâÀvø+FM1f’ËY)šT³ZfJbEïo°õr,r4UU1¤”UBÎÝ}˜j#*ÚO{r;#\C9ìpr.S³p˜7ØÍÉ0GY|è‹HÆȘDˆ°ìHg“$" E=å‘_„M-6iòÇ#*»wÔTõ7fƒRnÆ2AðØÙDmqLú(tÔ8‡d+owZ€KBl‘ ÅS;’4í£±‘þ<¡›'vÐÞd‚Òf„-04 ê È(xÂ#+’mŽ©¤V H…ƒ®·YÖ©Fv5Ñ¿YF´E#*¶è:¼ï¯8û Tšcëàtœ\µSo +!á :,jθ‘ÚÎ04âàq‘É"z^2“É‹¹žØ†p‘Á5VD9?øh4šUºòöt¬ŒXži×PMŠ`ã9'rx#ÞédN(ìPíeDT#+H¦ì·5²V±«|eY*Ø«\«\Û%Zæ«¥µz²/:ïÆó»×uÊ«èùôØ)4`¯HÅÑI²³ÊâdMñøWÎUt×/°>—§¬È;¾˜â½@A¥£ÎèpC§áŠøðY¿f“…©j4•9<Ìx›òvt/#*Ž‰-Ÿro=ù•ïão"tkçP¡å/‡c€µ>¹Xñ èg„øøÜO¹¶ú–É´VÆÌÛE_N¢Ù9Á#*œËcV#+Žrñ©Ã« Á£ÎY‘_1ôrUñÈ¥X¹ÝÉ£@Ǫ«ƒ–©)e&I$e¼ñT’’ׂ“$ædS’ßçZÁÐO²¾Ûx”Ì#«6>7šÂ+u9l(Öƒ‰BÃ*(ˆÔ ˆÈ튄¨ÙÝ«{×àmk×û·ÀlYHªÔJX%PIR$;ï€<6t:ûý®6÷”[·@<X$&IÐ;¾6ë!Š°¹6©ä£!Õ’Ä<†ø2‹‚ ³2¥çˆgŽu:íß Ž;9£È¡æ£(AVn„ØÊN¿]S}|x×?ãóž–¼7à$•9òè·äŘÖ%yRZP²é!Pm†À€ß'ÃãË=Üûw=Gpn#)MÔêŒI gÄlvo°¤z#)höñ%ˆR³Ó7ÛP5ò†ˆ‘"Ó#+@Y%¡(9ßÒŽ•gLš%¨J’+"„ÚÕ##*¼¸çtì™nð×;2Å`,!†UHwÍÌ œ¾]!¦É!#)Q'rQĵí±ËHŠÚœv8(äSUXò‡Ô‚ˆòB‚«ÐÆ, P—+ו׃<òóq×f«»¥$¨.†æ…â+µžÿ‡|#ì¸ëÑT£€UÖ<Éš•#*A¦#*œ÷Ø{„³ðAªì4·‹Ù‹Øú5ÉH4‚ùní»¡Ä=BœÛBy>Šš%|êIB@D5dXc<³ƒuEÞ@¡:ž“o”u‰’dŽlx"gwÓŠ›äåyNჟ.dzY:,ÛÝÌ%›3g`}Ò〦#+„ÜCÊeoP;»Èøc».¨L„!²ÊÊo@ÿ?Êl+Þ2ÇÁ‚ûR`]Q“‘w4lÉQLHR³%„Âx›Êý~]ØÉãFÀ”KBmTŠ„Ì©7ﲓ»¬ËÎô£¨¼d=ßfÂÖ4î{÷†‡·ˆCœ>è•gJºu¨K€w—J9*¿L6ßT^æËŽ°Ëƒ^Œ®Ç&¡¨a Dn4Ð(#+;öñž÷!ÅvŒÚÀå‚@ Ay&6c×™‡ß»gˆ»«Ó–Mré#r8ê’©Jî¿-JíD‹(Œ"À`‘—kŠJñ¹„WuqíÜdyëÎx,Ax0—¥‘ïàqÇŽ4ž Ù¼©T94¦„òò)Hþ齡…°ŸŸ‹›e<ê‘`y¼â—FéEWt÷ww댪wT¤KFˆ‘´¼N8½‡#+ KF„d‰&¿d§¹1ƒƒ»®Ðž¤'œŽÒƒ==[¬Ç7ßœŸ/7Ço³œÞ}²x¾ìPîˆpíŠ|;ªm¬U0/ÄNøz$΄ج\4Q¢v.ŒékyéOCh£‚”*¢Ár2(³ƒ%*øNœãçÛ¥vÿ]pû9äéÕ:¬ÜöWqÙG¾;ÏÍöaÓL(ðûW:궂öÁË}k]®]¿-bz}>kÒ¸¨iä´mê{ÌŽf|å†Ç{=V#*'&#)NÃàÁlbJ§b{³œKåLã«ì…è˜U¶AÓ`wLj£jm1Åy Ãwÿ&}Öª@ÞTL˜v9ƒ¬\I^‚ý:‚ÿF}rÒîœ_MûC¿$éÔ&NèØÈ1Ò…@Ù"1#*—@ÌäuàÜà&„{¨ªku¡÷—vPćžœÑ"Å—êN5ºÌQ“\À\ªD¸„A7Þ·»þ¦†')Cqµ#)µ¢r£Ž#+Dh‰žRÖHz4y˜Ó.(P§ˆ–wûè…?kÀVsóšokÏ0 åP懧!3„”@$î‹Q¯Må ZæølŽ¶Æ–äKQƒ.›1X~kBÖ¹s2ìWyS„V#`¥T:l àüŸ¹#+w›Hë²#+€u¶h~»ÃÂ^æAâ~¸ßs†ß]²•éÑЯ>c¢›Ã:²R³Òå-¤Â¡Ø MÀSvÆ›ô-@@ânXêÊŒŽÃ>UÕØÓ̈L³6ÔŽòÅùã…×hQÆr ‡(¯IÊ.È›§KÉf$náï´Ö¸6W&¬'²Ä8@í!™}®J»#*!‹’B ŒCL‹I³lšL™MÝmî1–4ÚG±œ6v8ÙFÌÑã(ÍÓÝfçÐèZ烉À¹ˆEP{š% rœ`0ÛŸá]íì˜j15=´SoÎ]i’?'ñž¹ÚÏ øPÍ#)P×K-<*x,ƒÔ”l÷Õ}C®u7aXª¥:´0!±,xDC˜@ÜÐmì¾·é±F¯§Ã“ú–$Ícy;œùÀÄoΑú†LIW8ÎJ_δHMúáœ#*¥ÓÔŸû~Xê*ve¡þùéÖ÷Ì\øÙ”<˜zd4y§Óo>ÜúpβNÿÆu#)KˆX?ÊxÄϧþç£@êíÿn°Ùð£¶Çü÷;Ç0>ä#+'áŠA¥JÝ/qóÎ.H¾²pý_Ž™•åb}[õýµ<€,€k×eñ†qK-n^@ ׌o#+sªÌ&¨˜ûé¸)G<ãñ#)bi´Ç³Ù'\AøÀðÂyŸp¨>˜óö˜cÍó8v‰ìê9¾&y”•ÝÿcñımfŸˆ>–ý¾Ö‹: ¾‰’‡v+‚ØÓ#)ÂÄ™À<Àû¿§÷Ùÿžüùüó5¼fîØÁ þù ºe… ¨É!¢.XZgzþù<îÿõà߆áõOåã¿ËÕ–7:%‡ð;ÿxêÂߣ±!)'_›Î‡\åî|y9ý0#*Q ÿäô̈jçn1Küçþræ…[³ŽÞz¯?¸.wd ö¶¢€'Áÿoú|ÿõûÑÿ‡ýrÿ¶Gþå™QøÿäÐX:´•’m®f•ŒçÊ|"¢¿Š·ê¬éHZ-ÊåjEœíœã_Q§h¬H#+ó#)H( eÙž_*4í3#)GDwœ#)G#)"kíO—®^¸#)C,?=ƒ3”A‡xt|'ñŠ©QêÞÿ¦ˆ@ïÆÃ|}"Ï¢¨•D*ä??oæúº9φ`ŽpFCÇ÷éÑÂçþ^G3¤Z¬Èa¤&ny½EÛu®ãkʽÛ#9˜‚Îrº ÁÔ°}¤%¤'6·ø3n–M‹Qô«×¿œòO7B¤3fâŸä÷{½spõ‚ÀRJ£ïƒ|îø}ÀÞ@¾Ÿy¬Ó]nGêÍñEZbᑯl‡-‹ËÍ¢À@wv=1…ïˆKî€ xªè"ŽÊ#)”ˤ~£P¦Î!’&ÇÕ-A™Q¢¯õQâ:^GÜî#)@Ü¿ÛÔûÁ¸7ÏjLjæJŒm¸[Rlvãeˆ(W£n¿pã'y”"¬êƒH¶îÏ߃¦l Ó]úÔoÙÀ„2LδûY~šÅµC375_[PÆøïb l?,ïþ&œGʼؽþuÜm{~šaO”ÏeÓÂ'¢CJ2„>—3¶ÖÒ²ä3Š*£ {G·ÊÞ½žË>Ê#ð*”·ü¿#)Á;9 Éôh`‡6P#+°!#)‘(|³ø6§OýO£#Æò»ýñ:ïBoL½NãÕ:?mwgÕ_«²ÃQ´‘_‹ÓCÝÂq3"åân6êú¿ùÏ®;âm†P6CöCKÒÆyT¡"Å“VÖtçÙó×ó¾Æª¼[ëÕÂE¤”NZØV@L~q98:ßNαwÐ6Ýçáo‡îÀg›Àly‹Ï¤ò_¶~N³èâ4lmCÕ<î{=²\ÝœíÑ´y-¿Ñêðz,ýˆ•µ#)æ#+¯{™Æ2UûnÿKÌXžçõØ}¼¶œ ½jijY™µôîfs(§ï/6G÷—ݤ4¢¸nÿ¥ÆÉkåyih‹„Pa*††©ò\̨ü™™Å·¹›s RžÀ€ïîé#)u„îì¨O9)W©#+ç]ÜÍEŸgßñ‡"aàO•Š‰s…G³¯²oêøx|D#*–3ÆKÏÝüšèêdéU=Ï#*éò”%º†¶ÛåÄuÜt<ŸGYL¸=´èË~ë<‘”‡nðÿš:wÓ¤zÂ#*®#+ ô*–/ÊHœÁç„ÔÛåøÚP‡ú—ì(HëÅÿ³¥èïãÀCäsE{øò§®¼±ûRÿFWâý«ìÏ^D·õºÄ… äH0y1×úAÚv÷W®!ú¶+õîê±Û÷j]óÛÿC+cî†èg’(+îP"@>±Ó#):»uóÉî¶~wÂâ=Lõ#*°_*º«ƒ¡ˆ‰¿ß˜¢y¾a¾`{;÷yG¯ÙéJ™¢§~Qëק-#dy9K‚"€1s8l#*H⺥zÈìÎc „A¬üu¨»pZæQÿ¾¯fíúd>Q…‰éèP›·ë¿hëp;•S®è}½”yšf.Y(øbæ£4¦äEsò©ff#*!¾ê¯±6(»,Éyb'?†ÝjŒ4põ|ª‚]íLÕ«qÃ~ŽÍ:ÐpO–L#)̃=ÜÛŸ˜òþé:EÍyPŠî9õµ¢W[wAþ,0d(Sy âÏ3Fïf LNÏ£«;y°ù4[q 7ºyôqXjÆÂ]S›v4äHuˆŠ3^·ºQLB"$…rå.kªöíߦ}·®¿vÍ×ØÖª†“MÂdž±VËßè3í¾…BADR!æ)FÍ÷ÖSm¶az«”8Ê5èÕ‚"4˜lòùî²F›lx»\C#c`‘YJ=šÞ]™ øA*w'°z>Æ1Om&š´÷œˆ™kØ*Êò§#*Üx‡-ÁÈííöuvNØwÚØèeŒ2óÕN¾@æ@+[ª(M]dð÷ÍAŒ7ÄFI÷ÓΕöAp)#)â¬TˆDENø»²Fr‰Ï*s`Ž›…#*Žùe:„DHyj"&]€#óôuý½º¸¢í5ü€;]%†ñ'¿²yfoî¿£Vüÿ¯o5èì~íßmÃXg–b¯@«°CZ 6¯§x ‡?Pÿù¤v_dîÑwjs¡·´ƒ†TT;‚s.l¸ï¿xt]'ŸõmÛeÚ½½¡atÓp.¸C+i‹Á@ ßÈùýŒ,ü77ôŸ¸0ôíu#)%Þãî ùJLùßRîW<þzhøŸW I!mÏŸ™†s”ܘ5(¯«Ç¤`g=Röà 5×köÿ‡Ö±š×xkÁQ‘Q5#+зø/+å›Ñ&Ÿ#*PîêÉÌš‡Hìªü¿Õ˜Ã×É/Å<&Ÿì÷j-{cñGlUÈþs¤qvs¼C`pÅÃç,*)G<›nh9YX¶ÕW•`Ñ5(‹x¢âwÇlÕUySê¸'üŒßõÉž&’™^ZƒF+¥½z6úè„–È^|>Ò褑äŽw«Î.©?Og§Ev½½k9~˜Þ$Ì¢úËCHî!Ñ¥Ùh´×b’úW´gøÈzÌlçXu³îAÆù_Rò˜¹îþË"e2"链öé)_ÏáFÔa.uDuÓm·µ¼›lC¯o—ÎÊEÄcâïΈµ[±ðâûÝÂÉôØN¤1µY‰B¨`åa <?¥ºô,u$ÒË'Fäø>MÂKÈè"t¦›ù0a#+¨È5‘#+ò½&æLKÜ MbŽUy`²[âhXñ‚Š„£2€ÝÞS¢>YF9\3è~äã裰¹±´å±X¬##)Ülªúa×¼±àÚÓÉᲫcËoÇxʯð¹PrƒÄÔ‹‚3uòï#* ‚õ‰ ¥r,HeƒXËoˆ‚Þ9–ÍUÐ^zÉIÿSÂeN–ÞÏI—ÊÅnñI¤B&¦V×#Ÿ»Ò ¾pæâqy¦æC®zY]³²¯rѤa›¬•Å†7¸M~¦XEÊãe—DºBI¡ö ±¯TúܳýÓqΗu’å·É¤åK9D¹[6eÈgE+¿K¸Uã×yí§ÌåÝÖÇí …0«7ŸQÝçYјòÉî®úAžyÛEg'/H¢ÏG&'wÄ=}µ˜â‹óS‰qoçuç®;ÖuÖçTõ;Aúc4¬ƒêSyïâe0vòÔ‡"ž#Ê=³{_xÖ¿nX°ÊÝ"ùâ%.Èm™ýÔ_¦þšw)UWG±»ë½*ñÎ%ðûšo>Õég«Ì×h9Ñìòzíú7)½¿’êsÙ>µhîá®ÕA„KÕ‰7ÌSnˆz)D‚Tä^™ÕÒGã¶m¨(y#*©ñþšŠmTZ”“¢‘£ñ£rÐußH[‹ÌlÞ=/ævmo³¦(áPaN#‡7§_¶hâžœÿó¨i”Sš‰$¾ã±ºÓ¨í¹RwóѾw/ké¨Ò[3™é숧¥ñC(SåaÒÎ×;`÷If‹uyØu¼)'ÐÆGU*º<x;IÞ&íÞfÆMIûß?S2ùõÌE>rÊØΡÝm¿mïXqrãŠß³Út[)Ö(@ñäßIw ËüÅ6ÑywNè·;²L;\ÄâÒ” X‡Äz©ø=n™èÒ¯^l9$˜d-”ÏwûãÈrÞ]j[ÓñÝ(Š·ìbeW8…˜s_¦c‘A¶‚‡*$=“³„¥.Ø=¤…èÐ-®zÄ"c´¿Î:"¦¤íX‚=œW+À~Û×d0zÀŠç²çOœæÉ¢¨;)pè;˜ä«îú}±Ö¹véÚìñ½=aɤÄi.œ½#+T¤„#+è!·—ؽêðLJ%HºîÊ”;pwJö88Ö#*šÅJhÑ‹ä=‰œ~‰—¿e̒㶉ÛÆå×ÛgÇÛ-Ýó1åäðYþ|佧A¥<ðyæVý!ð{}YQxù‡}ò{âÚªª¬Û—‘iûY''~¯ŒÈømsœ&äh³ä\ŠjdäW¹MØ£Çæ£Ó<i>/K:é`g0hâÕíÓ7Ötq~€{Ù¯ÊÚíÇú]ÄÒÜû\uïç¶ûþl¡³ÞE*m‡èk‚ª2#*v#*;ÎjÊúûºx9së6Áx•R \G²Ø ø}bqç™|j'âÌóšt>ï–d='ˆì´˜ª7+óûpÇŸ}ºÞ vî2ʼn±ÛÊ!öˆÌl´µùJ?AøŸ£·òèZ9” ùŽÄHþÁ^…Me?ÚÒ=`ˆ”yÚ«Eì`º ÚÒ,¤E^"ÄGº>æÚšŽ@¿÷¨ŽÁp KcIŸgãêy`P¸†ÚsRŽ(¨úÝ aþôÞ_sCrZãóûeßø{µp¸…A8Cò¶tQ‘5ÄjÄÐ~·«2'uKi7pR¾¶Sáš±™>ß5GõßS>ßÐkÏÙ¦Dç¡mñÕóªo™ ËĺÏIŽNÆØêà#+±´r@ü(ù{¹èæ “8xö0ÑP¢\BàQáÁú[ÄXþ#+§½BˆiLxrDÛ)‡f”³øû¢KA‰‡úM„éås_Ëáp»»··€!)uÓ¼Ï/Ÿ[éƒ;õ¨ÿh/KyNi6¡+ž[G$èoÁܵQbP®p.2±¢|b龞Áh…„"¨&µjÚþt&ØãJ\EÛ/zÇåúaÝ•.Q!"ð›_[®ÿ”åï¤$=ØK»$ñø…Ήކ‹<;ù24ÇIëIÇà¿][ý9Ï»Ùo«íôèòÞtÍÒ¯N*º 0æVE´G\.ï©Œ’OgÄ»~#+ÉVƒò³òŽèýf:ê¥'4ø°ôeä(ä‡b<êÊf—=¨PžÖežŒ<\¦¬…¤ö¡x(¦`BB*Dú0aéu"âoåo(e(¯%c:–FЮ‘a`pqæú±Ôp»”ˆôw‰²¨¦²ì;¢€pĸÛ"@üÐ"J9$I¯HQïŠ6½ãT*Âꘊ“,ÈÌ0™ 2Íî´B'}Q„<P.Txé¶îÒYÏÍ:Ä)ìóJ¯¼r¨á„£ñ•)®,È, Î낱^‰s¹Â¸Ò¯9«¨73-Æ(™æKA¼#ÄI æYÈo·luèQ\ƒµŸ|×DZ.zâÔ>D…#) ý1¿=?°~qìóáfµpÿ辬úú¥jt¥Kd¶‹{ø×ÓÆ™:ŒÄW·—ëÁ³ïö~ÒC#á³ÑÉ=ÝóYë×ð?‡ùìçþ“ŽE"Ãôr,Ÿ´€Bðj~¾ÏÚúd;¿34V?2¦?Pµ+î©YÅÚTI#)þÛVžˆÿõö\Ìý‡é-›Ç§Ýê =õ^1‚9a+7>”0âËÿÁüÏþÆׄGÿ3ˆfæ&“÷8L§ûy}ôøêùÿÏ2Wæh´¨† ê¬B?À}ÁÙ§ûÕÿ‘¼xh=„ÿGÁΚû„z†Cãmßñã÷A.zDÿµ÷žêgÔ7v+Ÿæöü•éÐ;I ˨^æ#§¨0WjÔ<bøO«Ÿ8-3”J~ÅÝ)«ú¤H(—üƒÊƒ»äAøvˆÊÁDæ\¬{Ç5^Ö_j(Û•!—¤rLF I$/`#)bˆŸ¿ôœSìϾ\Úóâä‚€Ì4ùÂöˆ#+oükÜÓaFf¹#*/“Ðþãºêù?¾¥(6$§‘…÷¿é÷=Yß*õ«ëÞ$?i×n±ã’é)ï ‘´`9ÊŒH¶‹“¹í6ÎÇW¶}F~@~ô†P`€H‚#*ßMñ=D>ëµmR1+‘7I¬˜ó„檻5R@é#*ú) h”!ùðnÅâüñqN5'…’ç]$î¯"ôKøQkÓõgÛ§?ú=EDõsŽÑmr„‰)ÐD„ÕVcL4{ÿº•xœuÌ]ÄhŽ,`c.[ ¡×¯Ãˆ#)U¯'ˆ’5ôÞˆ7¡á‡ gùFe#)~z”)Aa`A‰Ö¸_!}ª¾Õ$z§f-ÈnfAaA¾ÉŠ› äAß/p’F`öØcòÌ’ÂÉÎ&k)°°EÑŸ+œÊ!ª]‰?e9#)XÉÄ޳Ěü4P)Mµ1ç@øçDãÕÜÜÛú9]½û¼¢²ÿv^ùû#4ÄúÕJXG2Átñš‰+Àšëï{³à–Ke(Ö½#+¦±©0½Q,+*ÚJé׉b$€XŠY-$R%Ë»‹(4g7½ªøn‰¦m–W]”ÆÏfa”ì8qœuW Sñ>²D1Ê¢+™!ôä:‚ѯ*µ9jW$±Â3VŸf)ƒÑ*lW¶Ø™¹ž(¶ößyÚ“!Œv¬ã¶QBTTr"ÚhŒ£4€¤ðÄz¥ñI‘Í‚€A6Ð4JPoZ 8ë}3èð6#)ý3TÚJ#…þlÞU#*>”ÕÏIÌ{•œ^án;ƒ· {$PkÏáçŸmaµÏ!|"ÙØýQ|ˆœ¡AÝYJ¬ÛÌBùiž:#Ù]Ü4Ü õ‰QG8ïÐËÎ,¨ü¸Ó^žÉû·ÑÚ@´2ªô8äìpš”¯QVŸ”s;HÙFêÐåõú»m?Oßu„`W|ÆýárÖ@#)‚HŵÓWÃòxä¯8Ã%…%¿±ªýÿŠ$–cÄU¤áƒý^oˆz´î?kÁ•·1sü¿×uŒˆÒ#Ïn:gÏ]Ë5|›üOÁg-¶ËVó©ü“SW3»M‹+ïê³Ä"4kŒä]]!c+óÉ|]3‡îSóüX{ë^%a0åàf–x8y =1\`–…ÚázNö}Ë¡ê˜9„)•×h¥Þ²-#)Êàó)ÜF"ªIŒtÀ@Ò*JL:T…ûûqÁ[¶Ç½9Ïy–ÃbÊSN™ÂDÆK*1A`aê»â}×Ü‚#V‹D#*þIeÉiïõ÷8†Ze¦²ÈÑè\ù^ãç! î Ïný“†EmÎ׌MoݦéPˆ<&ÖÆG‚·¦jÇŠ&dÛéqê¶Y-Ï«½¥ºá8žkŒïuZ7s$qäL4•ŠÌÌAv#yƒH%ØXjÇBuãÃ3t·gÏLÅù‚iq¿TGÛQu¯Ãàã0èD_$k‡¶:zàÔÔ¥‚ˆìgj{9i+AÇDZ#*ˆÓ)åªMG¢Òé3•}£Þ£Ç¾wUµs¬vöâõK¹y¼M>ÞKu¬!ËÃ:q§ò7Ï6žÞŒ&I£¾®6uÙüTÁ3öÏúpø$e)ŠV#+¸lÏLî”ék3©REUДZ˜•D#*}¯ÓÚPŒž~}œ^p•sMñûã—×Ùq=øƒrIš».¨Ž™ë{?Ž Ë{ß·>Yž0ý»BU¸‹¯!"cƒ¤ZnÏP÷áàíÐ.¥¹fý[è´ú%¶Ó"”)ƒapûÍ¥€tºQªC:ËÅ÷…G3fºäómï.¸ôYÖû´rä&Kˆˆ}µáDJ)6u÷mÃv0° Hpð#*Œÿu-}~ŽáÌü´Bƒ°ô yVÆU‡Ì¬#)ŒE©ìì{ p ]ù|-*u¾Òɵ*ƒ,¦ }…›ðžrÅVì³òY‘‡Ú>Yôÿ±ó\¿l™1è|Ò~Xc}E:‘òE#*ÁÃíô‹;8ؼø‡Ãî{ZCkNØirrTÏ8í—=¹Kýšºš·…#+QËiƒºt"íÌ}’Ʀ{¾§ÍŽî7Øþ¸›ÔÔ^ŽÙæoæaÛ©å"žç±¤j$ŽrRf‘kÝ¢)—'û }#+–tÇ©#*ŸêWLé¶K¡åŠ«Ú[Ï«S;uåÝ yaqZ‚š¦—Ïïù…%àqu¸ lv‚<÷³d-#*6ÞÕõÖñëÝSƒÈ±j‹®[nD|^ÿNž¬¯¥2PsgäÝ&<à¥W¥./Âc.M;>/déMçî¬y«?RUTA)ÃSÒÌ—$½tîO“ϪíRJ°¾°0`»í ÖùÀÃ^¢‘²#)m…žŸo‡ƒÄIj(‰úß«õüC}f¿#*ñ‚úäÐNϲeQb©<¬¹ #)‚p¥£ºIåêðÙ¶ÿ@¶åÑk´ƒz¨â7ès8m½uõêq/ÁêH2×>t~6~ÏŧBö‘É*µE@9Õ[>RëÂLQ¨®¾â (‰ËdÏnL‘žÙ„·®ßàFºí@ìd„ßd0ÝJDpæÖÞIe!$82È#*f˜®õðiüûYè;€¯mˆ!ÚFL=xíGWc'd¼’ÔzuQ!jî߆ìøaã6¨ñ†±ÃšQI ©`º;{ÚUR&ƒ‘nFº¬YKªpÅÑxTRâ’µáÎÉBê~ÓX:^ðzmVÅýñ’PG<òuø`06 ß`ì²vqµp•lïÃ#*&s\]ÛSÚx–hÁÕ´xïQ¶;Âf`A]Ò@sÊy‹„s ‹%(tceäFz¥¡ÚíXî¼#*kô¿q†cÞÚg~zw4–#ñsqág ò÷·‡3±Û'ZðhÛ«ç»i9”áÑ Êlö ¦¦Méu3µÚ žáÑóëUÇ)ë#+ÚN½Râ 4°Ì…Ì¡A¥Cl¬Ìݽ\"S#†ÞáMÂàÀ<‹k£lÀçax”˜^ù¿É„d:0ž“¤`ô¦óÐöÛ-šõµžŸL2ÆüYÌà\Û%¦kccˆœ"òòɪ"Ì5e±î8Õ˜:È"‚—55¬w«„¦«È§'CaunNÕÈ’ŽIØ‘z?oƒ™¬0¿x„OšÓrà|¯ÔIR¤êÛBŸÂ®¾È†¿%rúÆD·Õhr ÏcÚ+k(HAA¡ÊƒqN<ºOy^¨©æÎ /yß¿£Ù#+ÑSx##*jŠeAú *ù‡{Æm˜r:ÍaMÌ€ bàÊ&’ÀifWÍçBùVd½ZÒ>…RÂ#…ì2íÃP.ÑÚí=BÛriW#)l$; .…½ö†¥ª¹ TÈ,{«?Ÿ¶ƒ6PH½ÆŽÓ‚¾ÓQ 5¿¤A•~Qw|è'·´xÙ”:³µ:J”Ä1Óƒ>k]N¬¡fO°c+lr]h±{'Õ}”GÑnÅ°“œý%U°GD‹B-CQ¨uPs_ WÔÐu[„Ps¤Jdàè¬âäà&.B$M·§#*#*b©ÌÜ‚HlyùàÁá·=Ýä2M“¼Zpê܈•²êwFçlZÃmËoXBCQ‘O±b×¾ÉDXkSÛŽÝ/kq6Ð#V©PKtÆùÄÅsúTK+AŽu~ÙÆkÞ÷áñm7©Þ„:¤Œ·Ã²aïÄ,«&q\‘$@µÉ¯×ŽçK#*J2uvïݧ¼3¥›úÇÙùÜî©´H.b2¾e%k€Ûš¢t”=Ð#*cžÚá¤tèá—n^`»¿$ Mu^Qî`£—¾m¶üÍclRŽ5§:Æ<¡Âí÷‚§0yuv“Y<€D¤”ÖøõBñËø–-źy~éoÒ“îUÆÌÂÈó^u¤Do3q"’Èò–¥;Íbù¶ì0zß‚´.žØhÍt¸hBÜ‹m£O—rÎv@0¼ð(“ã‰KI¶ã[R9dkÅÛb(e$òUÕuXà¢ýºàîêF®½nÒ hi¡Ö4LBc¬ ¶"P¬d#*¯KG`™‡Ãë/íò'8B‘Z®@Ü0ÇÁð঳Ã\¸k#)¼"ˆpáÆ÷à#5žÅE¸ã` sépZ€Ò#+sóóõ¿ áÌp²ñl°(3"ÞȉïÛ*+9O¾¨o†¯…x\µTJjY³_$#+·Ôºzç2ߟG5.ù-ºÉòœy©xwí,)³û¿FŸ£ßíÿ8÷}zät ço¥ËõOèÑGסQ̉'ü+Nxá;}sé±Ù¶ªkò>I¡VsåsÝîBŒiT,ˆŽ•[²…g$ã±ïȵ4MFñ`{~> Ž„;Ï¿-¼ZûñÌ'òùkjy\ç³PÝÊN#)B1ùßÛ¹yy‚Ì#*Õ£N'Ôe:ïÍŸ£÷/_’îÞø£ùyG˜ê<¥xÃâ“p¼¼þƒpü!`o²]øEè(,DýcB¬ç†VD#*&j?`ǽŽœþ§ª«ý™aÃï#)JúýؽÀY²Të*”Br)SŽ0e–Ç÷3Ý_‡úÐøÛÝÇwåÙðýsBO܇õ…ô$A€ašúAÃngüÍ¡¤FÿÈÕT*¹ý¤º–@íþ]jùÁêa#«`¼4‰E€.“ˆ£`õÚÀóP¶ÎÏè-ãž··²Çç…Ûººoîºk[‡ûªœ3s¹Ç—GZ0¾î}ÆñSR‚f†Ã±.AÞu»·q#+ïÜiSÙâŒrk¼òÔ8”*¬™ðï„Æ8BWŒ_™J0T6(Ì kª£È?ßÈ3ºªu—ƒ]*=cÚŽÔë÷£Ú]1‡¿Ýèr’úþ³AÐÕZ;"µÿdT,+Þ.áð'Pš%–‘Ñ…î\þK¿ÚÍ5”9€Í=M¶ÏØú²@e#*C\„™Óù¶73O =‹Ð:Ð$A7Ÿgð.³¿²¬¦äè²wúKõÇÅÿj…]ŸÞq|tç˜1f©wùƒÕüU„ÿEô]£å¥-–GÃo==Cd¥_C™. Y@#)¥`Ê•ätk‡ÝýÏøý_?ÌWð¶ârõ0kmd#*š£ÙPŠ6}œunÀTí` ie•Ã蘇ñ½Ý Ði#+vBÛ1>â’m>“StKçKP}Ej¿÷éÖIÖzÃ.Þ^ä/Cý£`Âx„‚kò†þÄ\½;&ýTZ4°A)rœ±»†l¤nô‹#)Á°Ô#*쥬ò„†Â#*œô™nQX¢í$òÅÌÝj×<#+ǃ*CÕؾÖÏAþV|4©UÆå¡õå÷ù‡“¨!ÍìNä+¼éímÚšâ»VÀiö’j9(K¦cᇬÞÙü]ÇÔqÆóÎÂØÙêXK"œX°YH—q; ® t¥Áv¼”£H¿YlÙNé¹±©{NÜ#*®c”î×ráÁ6†ŽIÙ0ÁÁűB¯€t‡æ“ø É% w¿¥{qWM)'Ùõ…îNïíñïY@ô• VÛ6ù†¾kMú´¨TÎ(ÔXÐ#ýcNù ù O´#)@#+éÜ]k"M~˜ÚŽw겿Åß~Õ´Ä‘û±#ÚžÌ~X;ðux!×÷F2Œï¸n÷#abÀßbÌHzG©FFààŸû#'#+”0E#*%Ažræ”J"ÒkmbƒÃôÐÊ×5ˆj"²H§äŸ?br;é)X`öûý4®U{íðïÅ5ù€ÖÿmÙGsãï?yòƒ&G&mfækBôdŸ‹Ù®l2ëì!Ô²ƒ\"ty\ŸŸ·MP¦g7;¾üÏ_s,ûu†vÉNÿÐà ‚ŒGÚyé6:š$£OnKà,͆$«Ô'¼i=¾'‡YÐ!Óïýaµ¬¶â¿sÈ#+RÜc¸¨$ªa %—•Ëô›`êu)”]#)æS‡ü%ÃSžE›æÝÿĹH„™s™Iàh„½ÖÒÜ1©özÿƒGz)K¶¦Üµ×JŠº™G9Îj•UG,ê²KÏ—fÕɘÇìx6#í.M{ðé=†{ÞŠg¸6=!ØáÔFA„#*Ù‡<üŒ¡°è:L×H;Þ53ijlœfIbíQM²ó‡C÷_oÇÒ"ÏÔd!_”þèIÌÛïÝýÝ<Ÿ`úÎ'ˆ”±'ó%.¾%… ¬ºŸ9ºÿzlCÛ‡`´EzÄ`½|ÀŒcdúìªõ A°ðÿäL¨+˜b['æ#+´‚K¹Æéµ±gë¹?Ùú¾ÙûCcj¯Úz\[B™ÔÔë˜e$¶#6ð)ƒR<AÝychî‹òn´ƒ…€ƒåg+ô‘ý5z›V4iDPHŒŒ(Åã8²ç9¡ÌçŸH¨´µˆ6(#)4N± Ñù÷‚ìÚµ&F÷7yGÃÈ2M†€ºY‰¬!ò Óìû?ÛІߩúùöH4PÓ î¥6›“í㚯PÅÌä‡Waå—9-Eö V#+„û‡Xd’€êxïk #)ÔO½,÷—#*‹!±ßn›“Ý#+TÀÖø°úgy¶L…°ð\9I»ÈAÐÌ)„8€È娦ŒÔÀ&feõ"Ù¸q`vò$íî+à™±š¢þfF{fUXSQ#+D×[ŸÛÁ.7~°Þq9'gœ\²3îz$:'1æ`¨g–³7¨-£"êaˆ@Ð5’HŽ#+™Èþ®¿¸éëÙrÝW£ò@#*¨\?£ðÍUÊJIúpVËšåßËý½ô6ýþk§¯]©7£ #*DEAAëÃUWFoü¿;Æ!¹á’ÒïQ¸EŒ¦h•ÖFÖhÖiëZ…NA²@ÇÙš|nKhjœTÝÈÙfW)H†‹5#¯ $’LÕšÅ&*eÖ¦¤´µ¶ÓÌÕÍYk5q½2³ëÆ]CzÂÕ¯5 Õˆhk[ÑM3tºÃ#Þc«FYF5ÈÍ6Ó¯í[”½½}ßØý®ÌjrѵDEúóRàL°þ»Ðef“ú‰¨õnv#*Ü·äœþ<[œtÖ!;Æn÷'ËjôfÔwÄQ4@zÀ«á#+î.•*00(E,nʸˆB)ò(@v÷ûéGÛõÆž˜‡RÓô»×hÞ„CŸeK&¡ ÌdTE0Ñï\ÝÆ%¡ÿYò‡ï,»lÈ|‚&#©´Ô6@šS¾¢Ù¡UÞ¬³X0IA#)ä)l ¤Ú>PdÉ:Û·ÆrhY+{‹„’I¶#Wyô]ãÉÎ:¹e%5º&V‘ŒKDux#*¸w6Þ¡Ãn®4îàsø”øñ‰ËaèŠJ#+Sõ_³Sª/y¡X>‰p2ó{²Shža›ú‚Ö,ØÞs|‘Ìát应Áö}Zû™´6aYû7箜fíJnP.nS)QMÝ´äÃ&a‡{w†#)xˆ—‘;Gƒ<y¤ÅÞ¿€_ˆWQAgÇâ¢|Q:‡è7¨#*¯ÔŽ6©†é6Oa!8zuî+æpüo¼k.%GÚ+àp=xâØóúÊ©EIJR(Šo“i#*q⓼o½5ÜBÙ‚†è€»5¥„KÅ#)Á‰JÅ,éH)‘ó|#v#*r#*í+»PÑý õ“äé‰?#©:½Œ“Ì@±Z#+(e,ÄO½H‡óE-í†ôN²²7Î®ï ¶kñܬ«pvŸ=À/’uåˆaGé ®,ü¶p§_ʉ Âj#)"ܯéùÏVúü–»›ý ùõöŸæ?§§QB#1ãü9Y» ý•B¿Ž?&Jõ„·©ëK>ŠZ ¨—ÚmDó±ÈÁõd\³ö‰èƒèúÝn>i=Èì9ÇäÁêe„9{ôM˜dP‚Ä"¼èH}#*wçs8í{ÍáöAÏ|?’cr»¯ô?IÖ8CeP}”»XÀýÓóíxîÝàŸyÄC¥<#)#Þ)Ú@‘«£À#*Ïj‚L¦IF±ûƒÊÁŠ zwóë®ÿyæ]ÍÇ£ÔiËhBµqàGŒïâSi*›oôŽ¦ˆ†»N]²D‘YdR2>X9úÂε€é€w '¸È gŽ«ÉÅðû´7;ø˜Z‚>HtÁ„€ê Íå¾*?©ú€¨}]]%þì½…¯ÿx_dWê'Ô>§Õ&³ÛXÝ1UD bV¸Ð÷åÊïnZŽ¯®ßôCËàUõ[ˆÔÖ‡¥LÔ1 <FI$ž´ª§úŸ@&ïáÔ!V+ ]°4d€>Яà‘I>Ž´S®;µº¶´öœ¾™GW ÁÕ3çäê5…[¥ÚØËSßãÅà_B#*—/¥šT† ßà‚ãôú·£°20®Uõ*ZÉ3#*ûî#*º|½5‘œeÙõ•_Á¬ðc$Ÿ=#C‚ïvö#)uç0q`±8…‹IjúoyÇî99™s”0d$Ûz…àòûLàˆjb¢#J””p2nF!ª~ô2¦s$q±»rp‰`±'G/öR¢qÙØÖ¡CˆJOg³îÌ@Ä<ÕDc ’*‰RqÕëÏ›¶ÐËFc›ÄŒnFÚ=¶7°—;žet¦çÕÃÔ›:y9‘LÂ*ðß<5Lñ†$Ed›˜P’Z-hU£_é; ½¹r%"QCôò:K°õ¨Õp »lªV#*pã:t#)÷ Nÿ„ò>0O:ÄÐ>|Þ ë#)ÁÙ¿„éd@<U{M¦¾ÈÿðKhòÀ)àSj©Eîx{¾w‹úŸm~Œ½ÜÂ¥óøb#*aÅî,nµOl–öûgóÀÒãDMIþ9QG•IB¿ô8Ør†«xib˜*ΛHÃ#)ob£J”¤ªRUjþŽ}]³ÐvÉÙ<mlqð£Lq="/דKâ}¨Dô¨–þošIzC[a©†Š?â™ûÈï5=¤Cg¶P©ì‡%®õ—ßøœ§3ìF¹;ÁOA2©AE!P˜…OŠ›|‘õŸÙš.8\XÖ¨ƒW˜ âQÚ$N»¦æzø@mr`%¥~®w§¦Ë}¹Êïx ¢Yùkwòœ:¤èð±í0¡JP‡¨P¨Z8}¿¸ÁŒû%h¢"€9»Bñö¯NÉ°€—?·&ûŽ¢põ5óS*×ØÁÒ1ýsFð¶šÃ7.W†õõ¤F%ÇæF%LæV #)ÚI0*ÔÉœKˆ@Ì9ö²mªU¸Q”*Í€¨nÈý#+7Œ™‚(Á“†/`<à® ’1RŽ"QTÑv(&op~9¡Äƒ¢kš–ú±ÌðÉÚ÷õ| 4#c#ÃËcîÔÎ¥h,PMad'Qb¨r@)c)$Sö¡ú6'¨?”îÜjS3XQêÖX–J#+Ndؘ1H„GìG4éÚ-s=é8Ú¯T‰ÊmW¾…/¤4UXSà}w‰Th¥‘YPX-™”Fo—y[ä£\ªô®¤V×L6T& ¬¶ZUq*l¢›ajb†'öáØWÃÓõç<qíŠpˆ2ϳ)âÇÓ¸öPPo_£§¹˜2é$Zôžò)g7Õäô##*nÄŽA ¦:ͯѨ#+l‡ïH&·j ˜ªX@ŒFDa #+2 €K8.p©‡#)C¦tRˆ}(⥅¬ÄðRò” :ë¿“³xBJ<²:NyÓÐ/À–ýH´/!Ú… jÑ»‚unOÑ>º)'á›û74=#)6Ê:ˆ#)_fÒ½‘#+Ü<šNŽ€v9èÏTì·M¾»lsrEÚdÍ…´…@Ðaå}VQé=ydëìÁ‰:àO¬¬ÊLIsÜI÷¶— LPQEýë%Oðü™=gÍ€¾áiZ/w¡Û‚žÿsêº|ñþe6z‹è÷ø·¹ë©PüH_Œgü$MŸx´*ÒÓ3Ó&jBð°Œ!†ö(ö,’¬’Hû\ô`ú÷ɺœ;õkRZÀ51 ÐfT´<cl„¹I$}FþGLJÈ6„z¨èÉ#¨¢9å“’Ï«øצ2 ô 6)ÀÊ„8&¬ X>¨ÏW·ó¡Ì©-#7^Ýhò³¹ˆÒc«£«¦%~Ú(í !ìIøCäýÉêåñíTõôÿš<eÆ”ð!W1÷ô´“‘“˜wÄ‘‰–w3Ô†%´ UA‰S³³KÈ´††¦ÑO‰|O¬kü€ §Ø#*«ø ùßîÅ#)ïP–C2?½àúñ”»ô‘§úý‡§ì8'Qƒ³ÍÑEE%*G ïÎ ý8S•uúl¨2/Àa_©=‰Ú ˜óJÀbŠÌ*I€äûR{\©,Æq'TU, •V½Û) B)ñWñH‹‡æ Aõ8Ó¬çò#+îí{ùél¹|”„ tØ«H¥!Bâà ÄûÁÜæfèEqé:D3O@?¨,_³®}ÂrÝÚlÞA#)Üö«ØcÐ#+FÀªÉpHª˜PLôWQçÖrÉNa“êÛå¬zÔê ë8yTåi#$¼âïY:ÀÔñ#*¶)yÜÝa6Ü.É!¿XyâzK¨Š*üÌ`…–ýpçëÿR(ÛÉMގ߃”*|›ÕB‰³‰¿âUBP„ £§âÍòïh q‹ ÂpN°ÌX?ŸJɉ“3î!ñ_Ó£½Kíb=0“Ê:J@j1^/.o *T‘5¨UʇT†dK9lQˆ^ºõ’‰ˆaW,À”IÕ*ÜýyPr¬éœGéßFÆ|øw#+mÖ¨r©TŸœ›£•Ñ>UE¥:5,OZ†ÀZ#*²úwâ#+Ts‚Ôa÷þ¡óö%j:¾`|s°x<9xõ`î7˜Éíö¤Š¼#*ý6êO“g"w`¤P°jI&éTp2߬„rs©3:ÉÀWÀ îºó˦]ˆœâ²ìK†gϧ;H%CÂÜ'®§*÷w–Ë€>ùÈ;@ rAÄà»ö[g+LÑÕ°"ôƒš¡¥ÐEM`èw§A½¸Ò1!#*p Õà#h"–H‰@Àäo½tÛ‰óB{ÉèPíîõ½^àøì=[66"N ëiUÀz-ý\N<gCÙ°ë5#»J B;Ïá‡â}rÛTrZO!ØìBŒç–ußÁS(/¼bú‡ÎŒß>ñ¨xÌ•Ëàl‚€¢—/lD$ð»wQ¸ÏlPÊŸ__£Ëæì-:>¿ô 4-Ò€xB½ÔH",¡b Þû€gõrxÿ#T€ôûÉÁ‚¯½YÞDç¡ùì>’8ydTó**n¥÷–%,"pä~Ô6(ŸÍϵ¾’¾Óî å™êlÌ_è¿ÏÎÎŽ7£‡ÍãÃœƒwà~ŠíÿÕoÇá{Þœ³âÓø©uä7k©zs€#*D’D¦’#+˲²š´*mØØæ-ôh ƒà÷`>¤rBÁ#*éA«’#*!óa´#*lu84BÀG :•R‡ì³¸ÁW¸»zY€ú~Ä6¨±û"²g „‹,ˆÿ4¸:€º¢ö¦Õä/.Ô˺‡0,Bd% ¯hA°kò:Ž.îY´wÇónÚà}Z†Éé]ttU‹Â„_ ¯;’Î ±U2H?á¡‘?zÊñÚV íC¶È»Æèì¡,ä`Ž0Ø67ñ#+/@zÃaŒBv%¡EÂÐÐ+ãèõ{ {š³üw¾}²dP¯‚(ŒšA*Š—Jn°EÿŒúÞâºe·pŒGôñõÙºÈÀ®Þn]¯C9Q›pë’]q¾#*ãvË´[ÒQ¦ßó‡ßõ‡…1ìÍ<¡kCS#*…ÚõJ0Ä8"ï/ÅåñµzÌU1¡š(¯~ûºñ÷ºä nî¡xÏ<¼"2¤š+wiŠŸ_‡˜ùÃÊW;X}¡òÓÙCí™’C ."²À=‰Û='È3àpFP¬}ñ„Ô¾Þ½ž¼#¼ï8&`Ûw¼là?:8z¸”Š/(…AJïõã©8ògàðI€œˆÊLoü÷â ÔÜz΋mað‚=jÛ$„@Ë;]wwe}ßؼÝçÃ×+!kÓüuü7mQ8ú¿€ÃcÝBaÊñA£ðÃD«BOoÝ®˜p¤Ã]ŽÐ˜EŸÎ°6ÓÔJÓalU6Ù dˆcc.ª @M„[™§æ:ÔOíÅçpOO…BSAÚ]OOçÃDŠÈ.?#Ã0Y?cÍû¬áCU*9äÕ¸S^t œ§$u#*¯´Ûã8ÈoùøÞO®R…)ÊßœÔpîþÓ(Mžÿ®ýRÑŒ¨xóÜöÉW¦¬{*áñGr`ãÓ©rd/ú!"Cò=¨·;Ì»wûu%ç#+¿ñj8²šÌ$4̨g@¸ö:>®Ã\rU7©6Ÿ$ù….ýÖÆw‰[øÞS Z‡Ö……—Üh¹Ò‰§Â&/—ŸÄˆ¢€«#)a`“d<ªào¥Ð NñÛgí‡P±±]Q,EÝîê¶DŽÈôýÇÝcòN_Þjìd!ËLÄ»³ØcÐvfh@À’ƒsÒ{@è¹ë]ÁhDƒ,ŠðÛ}ÐrVa±ûorXýý}/Jr=ßB\~{ÎaõXCò*^Þ¢åôîW.1s•´!É!å [ëõ0oÂõ,–õ|º]e®jfót̶#*‚#*]É*EE’ËF¬˜eRÙÀC,D%”%DÊÚš®¦å_hq=[VkAU¡E`<50´•3®0••dzØ&ÔþÏ¥š©Qÿ¸f8M•!C[1׈0µÿ€~½ˆÌQ-1ùª *ÄóÀ÷¼°SÃVo¶„ÏYú\Îf»Pº›–ô#*DÈRHè2ì[h®îVäý&XšÀö`io¡úpKÊ÷”ÏßþGâOøþ–ìè±âdfWòp+jõußó'èÖ¿´ÚwµQ’±FH+ü\"þùzÔ12É'C«dåR°_ÜÓüìÎm¶þN ´ß!îðåüæœûxš¹×¯g<L!å?™PhRZ,–ÁˆBRTzáŽ?P€[Ï‘khíIÓû ¨¹Â ~§ˆ ‡ÔqåAåÛ:å½´þ¬jrõò4ÉwNÏλÌ|Ÿ—aߦ:x~ž*=V2á¦êŽ1UÖeŽãœïgòcô„N??2°‰×O—N÷æ#ÑŒ²‚9F‚ˆCýØœ¡;C#¾+ïr_åìžµVPq#) „1¼#+…AE9{‡×Ä7Be6BIH+Ÿ·ƒœbHÕ|?/ßõçn,únQ<ýX¾†U¯ê¢ÌŒ·‹ðÕDñ¿RfïŸîýÞ{ŸîLÁAè/³!¿,ð'ɤóèÔ}èÅ/õL«™’C¹Àø»0|E:o‘#)øìæ·‰ùŒMº&Y&\Ó{í¯"m“|¼<Ș„*6<}|¾ù<Ž=`͸_àÄW&Ã`ÃóܘÍÖr 7´Y¶h¶‡á©Ó3ûŽÜkÒ=ÏÌâá£[ô¦ÉeÎô™°ºHð¡èuÌX+óŒeÌ º ¦ùŒš„ˆùäD™gZÄx>£ix|šÃõkÈy!Õ->;2 ı þ²‡‰^'Ásþ¼"*St^¬lˆoº<¥ÃÜ3ˆï@Ïèk¸(˜ªØP4îæØBñx"s£Þ 'Àá*7É槒Oéw¬éa* îº4/ÿoölrŽ]Úlo:¾ÚP»=¤?W×nÏ«µ²1ýÜB‡bᤌÈ*£¤¡±fv5§™Ã Ø„èŽtx~J½²íE8dõŸÃ_Ãy ï%wBwsDÀ§#eþÑžNÑ¿PÄh‹Ý8”#+,jí{(*]{aÁçÚñïÈnªöÚWYJ}ù…GJb0âo~ ôq½±¾ÀcÑØtÁWþæXþšèUŸ¹ä‘r¢Ž}²oëåÑÛãzo¥ƒ&¹DY«-·8B¹u¸¢ñb8§…*ôÝb Þçú#)ÆQÌù‹€üAðÙÛï[T?Üï9Ý =d|í0¢(ºCÄx:'æŸÎßÎIGG”HNåwØS‹îý+éä-‚¹²¸5‚ñk~WÄ9ÑÃEÔÔ0{}#*%{ÕU:V^¶‰B4ž§äÑÕý—®ŽïùšxVsÓcßœ† ÑÍà @uTfköºýc·Dà;!Œ—åxØëæ[[±SƒufÈrÒ©›óÜái£¨ù— ˃¥a€»:»E8W+ç)#+QAE`ÓÁwRwgÑðÉyO†áÕ&iLq‡fÊeêížÎºÄ`¯e®¬á¡n‡—²Ø€Qí³ézââù¼¡('ntZa¡´¯âx_&ÍñzŠV˜*]0{fXå..Ž{·pHëY†÷Ø«ímåyï׎0ì0'w1#*Âh\ÝÍݶXë@þS®Ä.y~yÂešlâ±2o›¦zÜókS…Tõ!Én†"ELÑ µñêé¶jJˆmÜÃz#ŒsÁ¬:êúFe™Óç~¼@Ò%óqìT³l‚)œïÉP.…°†ôlq\g]¤ÀÂÝ_òI#)ˆ#) ˆpååø¾‚ï¾^œ¸# ÈÄTY–ÎÒ^¯ŒgßT‰˜¿G“ëöÆ&Ê“°¿žf»g¥c"¼#±ñºéÉë7wÍïTdFê´œ““Ú“sH†‚©´¿¢Y©/åë˜ËõÐù<ÏŸ;Ïåw9×O¨Tg¬Ù˜z‡úB| ü#vÂí&w(µQ@Vh39T,4ć#)á[C !P@ˆØ§°¢&Ýj$EÇ?U×L~¬+äüøJ·ÚêÈä`P)Ì@ %ÄbxÃ#GR¢6Ù†¨÷iœXOÆ5ñ(ëð£ÕŠ1Ñl}ê{¿áÒ } õþdêí…nïTwñóͲ"á/ié¸Þo5¾¾{mF#øîô.̹朡„#+"ªO€¦cʯMÄB2Éd)°~Yr»Ðrš#)û= ˆ„\ËåÈR&fî°.²A” )@–åäøÁ!ž¸ñL:÷Vúõ³A$)‡ˆr…Rì¡ÍIÇ£ÈzG3öñå[àœJÃnùå‰=¦¥¹Bÿ'¹ÙF:”~2t&fHG/Ÿ;™ÛBdÇ’P»vâ¦LÈd„Ýd^äÜËHpíå1Ôz<½_Þ›;%¦€€óÌÈK¸yîÒ@”DƒX®vtÕ!p}f¼bbÎ!ü|X[[EÈ%%O‹v¦‡`9ìlÂ=îuôgÎ3‘ÑÏ‹ZbjD)Ï={5eˆÒ/Ca%BqævßÑ`ì5$fªE¤nnL/«$ytįOLÅ\†É´É1V—S#+ÕñäëˆB>rˆŠ„‡/Íb§Ê{_#)ŸŒ¬s,Q`‡è Š|ìËêÿ\|ßöýþŽÏéÿ=iÇhBФ+Õþï8_‡úëƒvá4¼þxÓÆ)ÓèôzºŽ´49¿ÙóEÀÄî…Jûþku¹j‹"&l ƒâZ¤ý_}ÏÝûПú‘óˆ ñMa§¥//íÆE½5UVóž¦ÔÁ„þLųq@sÙ·8@u—1`6ìð2ߺ›“`S»P#)Qw÷œ#*…¦’•#"1þ×jE—€vj›¢¥Q¯¬Ë;I|r#*nu:æÒ#)\›kÑÕº×u^âøñLšC@8j"ÑÜôYq'àÝrÛ[Ê¢«ÃfÑN=Ïø‡3¼¼'>#Ü€<4Ç_<Pwâ¸4£G"HbzÕ#*ê™8i|BšHàÓt×ð\žã·÷v˜Ó‡çïµ·e±¹–ÌT¹aë íW¼ëCX B5–ç6±ƒ›º„è<OgíJû>»wWñ¡g# ,)¼Êˆâ'C·gsˆy~‡œÈQÕÔk¶‹|eB™mc¿ÈȆ‚xeÁèë’ô;+#*pÂ}‹Ö3ez&;1r°íöŒú"•B&ªqdŽ³³ôàð$ÃÆ#*@ cX`Œ‰¡ŒD€¸RAšZ,¬à<vz ÁÚ4®úØÝ„} gƒ1V!{QiM¥öŽäà¶5¯v÷iòØî(‡—E‡£*¼• @Œ-iI-Òí,ŸaëNa¼'™#+x+@ õnô@smÑú #+uçÝɬ‹—è÷u^én³û£(¿†¨C›èæww®¢ÌôYݸA€q*„$‡ÖC¶Ûv¢:àURZ&FqiÅꉶ"áJÓdËD¨‚A €Ðz#+ÔC.2êþ “0ü¿pÀ‚D(ÜšµßÃæÞ&Eå~ÿù?§ÚÞÒÍfh6‹ú½ïu‰yXÚÏâó¡¥yÒQAú¨–FÇúÝ©ï#+WÖ‡(@ôH1®í»6Üò„¼5ãîÔ ÑPÇ»vpÁ“Ý{{5€I°*D(9øìbõ–ôþƒÙØl¼Š¨¬DG•ówï½ÅŸ0íÂØ•åÊU.J`¿pÎËFÎŽCšÁ¶"`ŠÃ•‘År÷â¶Õˆw…<˃ú]Òåê¨$NPÍ!C´Ñv¬o•$¨4òmú›‡¡ÈÚ¨ü¡!ÚÎ0îúcKNÄ5CSXª©È–voMT0|D¢æ!ÉJª?9Myšh0È<ˆ¦@™oçŽð¢25¡Œë¯Æn@"j^À·äØÝÛnÁsð8Gln+»‹ê+ÊTîÑp*v ÙÓðîhýGvîG-2ëàgçscüýkã.̇xžÔ©¸ãh)´Îë&D0aõBîÊUâèj#Ò—:Î&e%•ÝáD‹¬së·.¬é5Ĭ^r)Ãg[Äb.;a“3¤ðžœX8:7ƒo<û(‡yú»ó·®·…Óv9@îŠR´’¿»ë¾uÞ÷ÇŽy[o-Y©…’Clíf|^sDR7c‰Ék–öÞfkŒ#+ô2pöÛ$‡ÀÝÃBV¿òiÔ-áøn퓤`œUÞPòaDžÕ½ÜË,x<Ã\éئ…é¡èf‹¡X¨¥=qmË`áã´&hl#*nX r:Žòêõ¹›XXM±»š¡ðþŠ¦}¾¿n£>¡À³)€Ùæd—3#)a8wIçåÓ¶=Þý{ùoÌw¾ !ÇaÖ*’ZÇ|.Ýý6œ5ùçs<JÖh©ÛFfÞŠQEAyx‰O‰¶#*Sw@ä#*£^j_€iŸeQƒBÇÀ ÍbÖ¦æËH¥®ÁêAçÃzi“k5„lLç㳜H ES-ΧMPÆýakœ)5âËD&Ëaœpë+Jœ£×â=‘+‰¬lêÒBuŽEâë¢^»bhlo¶o? ±&¡6¯LÀENÃ`á0òI“D¬W¶ñxÆÂa;´X(‚`YXj60ÒƒÕ$9gvò1åNž!läÒzg¼Uû‰Q#+ P6Í{Ú"!W¬ÄfáDõ 'a¡Ôf°vŽœ©÷c‡ƒ=§ˆ„t—¡"™šZ[}áÀzu€ÇRÓ˘#)rxdˆ3·‡ôU0P“$#+Oaº)DÜpá™7w7M‚o¥6È-ÁKáܘ–®‡†äSP¶È¸BHï$ùǶ»Úòˆ=ßaɳ~#+4ÈÎŽŠ<}|¹M™tîèà5,ï8NÍrÙŸ6±sšTUY) sa#*=3©zß;B¨Æ8<*Í]-½Sv—{¤O#BƒMp/‰ ¹2]¤Ú†ÆhtPEQ‚¨*4po&&’†rò%j˪ŠÄ”…0ì7—)‡#*ײ=§sF!ÀÞg&ø(Pò(Xø8œLÎÎoE”¤u3XÉMHI Ëæ×xªF…¥zy™ëÊ´]N‡:9pû~o-fSlUæeÇ™™2æffXÛ1¬«2ÌÉ%Xí™è.Åü5[ZöÝm#*ˆ;´qÆg§]¼ÝówNÖb´iR¾ÿqD¥’“<8šZ—ŸKìõ#+lä7¶#)Bô6;ì®±ãCÄóõô/†¼ê°ë|ùé“®e((Œª*qå@¤©—^zÖsϦ&#ÉèôáxÛ2SàÒæžñ#*ÈÄÙ3=ªFC¶hYCS8G%¾œÊÖãç•k«QÇ·vfº92uìE±£Ð+]»s% ¤¢v|»…%Üq¢¥Ýt·Æò:ìJcè¼¾ç»JñÔú¸‹AX˸-Ó#Vy9Z‘©E„&F ÅÄ,Y™ÒKb_NiÖÌæÏaÝcê´¹{* ØŠq¦X.μž°ÖM9$;ŒÄrš)AD¶÷F47åµì Q—þ`PNs¤ãª**Ñá^bsð›É!Êéá§ÂÃå‘îÏð¾#*€kUèÖZJ÷háœËwò*¡ˆÈE#+©‡ RàÚɘ>ŸZ“Ûw}ß"tvé˃^YxòÆZ‰Û¯½°èã˜_€»IWf«QßÌJx×£{Ëq#t:eƒ‹9o&uÍ-ÈL!ñZ£ZNV¼xn4:( [ÍæF¦:©s¬ÚVðá(¼#+#*daÃ…ÓZ#‹.\‹,X|üiö.d_1úΊÂhpQ¥Eèq$5À™32s¸Õ]"zuÂhšuÂL‡Z+[^Âèì"H‘½÷ÌÍ¡…_E{_çÑæ^ßY-aLËn1¦Ã¹6W&¤Ì’Í šc9ê0IÐèªL®hs£>#+`HçAëÁ£²Ü-ÐÚDZa“À#*Â\'Œœ#)×RŠËÈ4ÎòPj…†ž‹xIËÒ–Š¦• i‹kn»°XèÜa’±Û»€ÀšG-¯9!üré‘úÖ÷äÓ=ÇlërTÇqÝ8ž¹ v;= ×QÅL_n+5Eªè!‰‰Tß`ºèæyùXwò4ÜAuaÕ#*!ÃäÀD¢Cs#*†àƒ5ÖT‰¥‡p”T»P¢t!¿‰Ma!}Ôé”b›I#*€qÉÆpã#*f¶MÃQCƒˆäJoH^Œé™–X°ÄK‘a#+ Ô©ƒÐðÒcHs-5^Á¯ƒ:F¹õuF¡‰ nÜ·ù'b<,!ÑŒ½SŽÐ5Q‘®\Rw|j½#€ZqØ;v#)cDx¢M]ôQ”¥’ÆÑ4Ùªf(G1ÐЄH.ò,‡™Ò85IF+:5_`d{ŽšäS_OªK[ª3‘¯–ˆÈóz‹#+õ½¦tuö¡‘sY‘¬¡´†Åêëe+Ô\›©\äëgÃÅ؇"„2åEÉ3Ý Â–úòÌÞ«ôH…ó†Ê‚O„ÑJ°{ $ˆ÷1íë×ZB!»·B¾ü@òæÒ&9Í—c|<¼Y^~166«l ¨t›V¦„”—™_ÓÂøVN×›òòÕË<ÞÆÐÄ0\`±#)1PÈCnW¾(#*¤›‹*É&Ò`%·mĨ G”±@PIúyÑ»#ë0Lÿúܦ¼€d—ÁYôܯYèTÊ’˜S²}¬âœkl‚奵¿¸üNZM£lìug膥å×Ûë›5§>›»l—:¹ž#œ'¢ ´‰8*ñxdø¤;D#÷Ϋý#+Äd#+X/ef3Òø®+Ñ6#*‰ÜÂÀé²éÝò¾MZà†8ßg_fzÐyAJÒR]û«ÏEÞDžiÛbÑ¢a€ #*‚;!ÝHóØ=è(Q6ÿ’o!²UJJœP—#+!`Ê‘ =þßkÓŠyw¸+ñ#+O»×†z”_ü¨ôûfY‡ü?×8tEd·rïP#)€%/Ø„ƒ·]µ¿?ë[ZŸž§©v”¢Ù›&Qjþ&Û:û>Ï·õmúƒÌ”#*Cg þ«?iØt‚Ó¥úCéôÄšR“T¶™5JDÄíÝòZHÅDBSÃaJ7¹J¥ÏÑUÆ¡pÀ•hÛÂñP¦‰?‘òï{×-X¶+>¹*ˆ®´ÓT*ck(%™¯nxwsèHï`{É!!%-zÕÆw¤£ÊÀ>ÿÕÈõI#*P*A¨ ´Š>;iDG¥èN-¬Ž‹#)ߦñ;,—û•rÎòIêÖo^¨x¤)…="%ÔšÃã#)ìaIf]‚ˆØ¶Kdš4~;H‰#™òž¹r‚€ú"Æ*X4GZ#*ʛäȼA=´†Ò0"A€àà °>|/òR³¥éŸ´z5(Ø‘-hF)w]¸¤c ŠTI‡ÅÊ»{m|®Õé¶#%«X¡tkp`]0‘¹˜ò¶D[¡¯¯´áYQá—¾ÇÖ‡3dvxHIÕÐnbtÑ:2WÄŠ¨y{C#)X€¤0ô zLÎ –~ª}P“6T÷¨à<¹&à«zk½À7Åñ¿¾ÈV××¥w›áEÍÔdwiÔn\¶iüŠ/˜EÕ˜áÂ(x@*Ä #)4ÛÎdô2›m¾¥cj墩i,ÚT„Qõ†C¸Ž² /킀ȊH""«"ˆ#)±)ÀÇâóä’zÑmöKnS#+;eðQè‰B6ÒÕE“êKVlâUÝFÖ‚nbåŒ%È°†#)Ü Ýu«ãy^YëäWøäùŠe‘5êx×¢¥$˜·«»xôÛp½Mênk±(ÝÝ ’ðë¨×6ïñ<óo7Lwr®nY++»G$Mèh”%Ò+F–À”2 ©Lÿ‡>6õ|,ÚÊÏâ¾rlƒ@›$~ÕØÜà=³$.4¡°†eœÏ ÄET`{ æOfãòŸÕ“·í'‡!KöQÁ¨8Ë!G_–r=Žžž¥ù§ ïyîi‹ˆb^‘ð-ó8fá|ÏHHÁä°+ˆïÒ]§TóѤt¾µ)m¨Q#)ðI$/,V#*_=}…ZéñÝ4ÙþŠw¶€90Uo‹mµÊÛš¶4ûºÏXÊi˜ÀÀ‘fŸ,Ž&t9YþؼG¨#)N~캷¤`?¬ª‘ÞÕšÊóξ‚Þœ9˜ÛÓ<h\Ë•]ÁawD$‘-¶·1( éÁžhY<!Pp2DVb†4¶†›©S{¡‚šXR\l€Âçø±@1"u@Ø;Gâ÷á㕪ÃÕGñ¹oßå]“GõùÍÜwâ°â·”¹MÁ¤HMÞ~F»u'´üž1?°Û¸Öà«í«Uƒµß{`K /p]ëg^ûI g—kCó†·EŒW¼;÷Ÿ Ý«£.üÙ#+ýüxê¹Â=ï%¥rjÛˆ<Íž?Ÿúnó±Ä©ç¢'z<¼—°[J²A6ƒ?–I‰aÛw1KcŒ(ãQ(Û9„¨ž³ï‚¿?¯¢ˆBUJ©E'g_È9ïNƒEŽ¡bzi5RötÏ'!Wª" Ð5 º";…™©Y‘Eô*t+Ðe+æ):cbõQXs-PóBNÚ„éÁUšýÝð½-ˆ¶6&ÁŸn~5ž[Ř̑µÙqUDŽü·ÖÐðÓæ÷vB4²2˜•ý2Ñßnµ¥*ø@¸]t$ 5Š´Û%Z-’ˆÙ«I²‰*1X¬¬¶¬M6Éi%lkImdeF‹À‚)#)V1‘Ò~_¿ÏйmnžëüÚ<j¼¿¡}P;XI ‚W©|#)°ƒ“#)‚`;Ð>öøŒãàµãd[ªÁú°&ÐÿUvæB†ÃCc®*Žj Ô21¡aY¤Fñ6(¬°©~ø#)˜VlFTÛHmkŽÜ¢÷VˆüñHªcQÎ$Ê4¶h›x&‘4é_*›šJ2-#)Á0±_@/¥dÌ“5^=žåºïOlQQv›•)-v‚ÎÆ|5#)éÏzN®dÓ[µ‹mK§#*”˜‰I…Uü¨{X—áõ×ÖζÅÓŒ¶Ú¹Í¯žÖú>s²ÎÕÉE,÷#)X~6$#*ñH’@`Å~yk•ŒIj+W6æÉ\Öå3aJ™ES0j*Mlm!ÎÉ(¨‹~mû{ëw«ÞWÞ–rÁš†Ð8@#) HAdA•NÀ#)5(ò¾¾—Hýw¾ïIù=8·*i£|´†F\"nø¨dÐôxW‘Þ'h=×b’€@O¶°ùB4‡OšCÖÍÝÿ¿ëþ/ÍèÿñØ€žp|ç#*ôB">–! ŽŽÛÛÏ]£O\À©»zjûíÓm¼#)÷çH0còu!h QŠÂˆœ‘›?9ã3<‰î÷zÓitÑÓŒ‹•iyþ¸ ¹D9!6}Zit¨GøýM¯û¿ÆÃó0ð›É?ZOve%â°ôn®ÈeÑKâ”ë!oÝIÓÎvî9‰'ïÒ+µ˜A#*¬Zb‚¡žÿià1픉Œ;+.ýú‘©9¶ê!N}„—ƒŒPá×æÐ_Û®ÍoŠÉ•>å¸*NK2Œ~ò¿‘G[ P>X늢QC .ØÂoêzS¨ùuœÿ%¡Ù¸ 6E4œ2T†]%rNEX7³8û#+^´'øI” ëb¬½ý“yáóŸg@ü"O#)‡bÿc¿Fçʇ}±GÆí‡çÃÀæUÊ|œ>/×ëütt#+ª ðƒÄ˜?|°#¡1÷¨Añ>çWæÔ<óQ(hvïÅ®_ï§#*9W#*gN¥Ù³È½ËŸôÜÚ0Ç#)?¾"»:ú‚#)f§8È»]H{w^ ìP,\ï:¡J fÛ2”ÚS>â„×âbÛãFûz›ãbrÛáãØÇZq¦5 §#+¥Pžˆ NC>+ü3wf³¬âí!’t2å´ó›BüÐ"b±ÅÇ33Š·u‹(7êCÄ€È#)BÀ" í)**¡ñ;Àµ÷ºf'¾”òˆ†Î®GEf«nß×üÔC¾D„,Ïç?£¿2¨Æšª*#*(ÔDæª>Þ‡ˆü‌ÇÙWwk¹CE†X“_‡íþÃtP ™ªEbxæ:¶õ/„ëóË£–pMP×b‚ƽ¯7îqÖBèˆUjúÚY#)Œ<äE?‹Î¬í¡‡p¡äaîLxGCôE#)¥d8H#)Ä™E&ŸF|ë°²ö¯ÐÊ@ÃrÙŒ5@5™7uß2ղʇT;wÄ?u¤edÅ °wûûwéňîíÂè!KÉÕ/ì®ÿï„Þµ±ÄC!Ú¡×…mÑ0ÁÑ1Y6&#*#+Y½Î²3 //23q0-ŒsÏèi¾toº®èeÐ íZÀèîôqÎÛŽ}kªçߎ‘×\¹.ãŽ(Ç]YŽe—¸û4ºÛ%B0.HëÃížúåÒ¹…ñ¼óغ:qîf‡£¡´EE0º7ƒ~6Ù®2.H¥¶Æ×#+ôa`)“’'óÜégNFÙÚƒM«‡ 3†ølèî#+vl`ÝùâØÔÛ¾}¢ÔíF&hŽµ»(tدýË¿ª†µ;Ñj4L)‚>Š0ƒˆ®.fm¦Q}ét*;›#*|–!G™£ßïÄæç=çÓŽ#)²Äȇ”Éà7÷>ç÷w“¸a¹{3¶N8ˆN\uŸÃ™×í *ôCÀ÷{#+‡»Ê~Yù¤r€BYa b3ê–H)¡}¾ÌF7kÕ¥Çbþ›8JÇa^XòRìž ÷—ãèšr@vLæxztu÷DÔØ+Aé*Þ)ghŠ&™íÜ•œ0bÛ7ôPü°Tä‰ÊùFËØFÆ™²ÛQ8o%“ƵÅ>kÚÌv(M!ê€;2#+!·Ÿ#)ˆFB@ÖwÐõZ†«‘Ó°øúk2û¯p#*Û4n;uèÝlKÚ öîlKrÕ&„JfÀš¹²v5¡w&¸Ý8W¤à€moˆmR"Lytì6Y¸7,Lnç.ªƒ-Ž]ŽA}"…C¶PdÜä§^DZª•,AFÎÏösß$Lâ9˜4¢‘O¥âüVD`Œvi¢´,ªn¨OmcÝîàcÐõ"€¥úõYq‚/7í@îŠæuc/í>©ÑÓ·N„ØÛ´»ÔLuŒztú‰i9M“®ýí§L!v†óõüÌklÑûÙ1,Š%ç…òôa¿oq.ªÂ¾\Ž€üMµø¦qš(|<¥ÜiF#+¨r¾n:¤“¨Õé©©GéíèȎ漉qB'}s¾TïËx%'›4ôf뮹gw³‹l6Yøý;6ˆDdSWÏÃ/WVåé΢A|Cª^Ìš×¹@þ½iÐ}ÌšÎtµY½…—T`„ #+b‚ÈÐÍ’Úése'uu6r.KiKk·êyrÝÍ×uÚ¼Q„ËFBÅX㈆†Q(ŠnY)v{¹‘.ce¬¸wlÈ,–E´„"±#)Â:7\0mI’jkʬÊ-¶|÷õÏÉZà1›#)¢¨B£$4 |–,ãÛ`ªuÛÉ“nìVá;~ïâJëp”üK”‹(ÐÔ… XŒ#$õPz¢ª¼n› žp#+@"¥Ð<²#)¢&éø—!ñ³î{S½Ø®¨Š»t$Nî I‡@g“Ð.ˆ/Õ#*i™AÙòã/caÍh¦1ÁP¡SšÍŠ×„»™BˆMe†º>5ªåHìÛ}àW¹ ¤vëC0‚Ù_³«#)b žˆn*F¢[föUŽnÃÛ¦š¸í<v‰Ü‘NHO–•uô¾ˆ2Æ]k§†xnëE«šêó.óÈ€¢"T¤c£M7BJ b”‘#)Š#*@$K#+QcÖj•#*ÒKBCœÁâ{¨Ic©¸–ÖˆQpätL¬X6î»U¨¾¿Zþ’h:Ö-´WƒEŸFþ®éÍzpÉ!1¿˜pÛ>«Bíe›Ù¡ì˜ü–åÍŽMgl—äÀ½ø…ýF2uÄE#)¼K:”ÜüšSç-Þb‚Wê’m)c[bfÕUTù7¨Áê&a&"A#)íÇ®¦ûãÙû«'\¢=Yx‡)´ôÛ‹¨Ã0(…FB¤grB˜ó ª'9=Þzìë}]Ý¢oìÅX±dM¦†ÇS6Vh¤‰›ø[ðØhÖ¹1T„á¯?³hN ä(Kd*EŠ£¤xìÖ™Ã1Uï§Ñhå1EúzíóÇ#fCDÚňˆ$X=h¡,æyÆj󫤮U1ULå§ú¾gÄ’©5–•¬µ >"qIñ·£y¼ëš9ñÁÖúo©$¬ÔªB»3Ä{ì÷§@Ï]ïkÀá[ºj‚‘=cj7®çkÏgÔKm&ðŠßÌåܹÀ¸.”SëÔÆɸŸs4„JApN:l™ÍEÏ×Ƈm2LÆ?¯]pËYÔ¡¶“§½Á‰”•R}Aïá}Õ!ž9Φ(šCvê‚ÚÃA ´»†Ê/>!!hl5ç©Vê‚d)p.¿N”E# “¨ к XX)sC‚ ðnÍ@Ôd„#*sV rË (°È îHÈ‹ûœÞì¯WÃ>4Dg‚1 •Ö$~ÑÌ°$‹Ô#)Ô#+‚A¥×̬ÔÖhÒk7Y¼»Œ© ¥¨LBˆFõ‘¤WS#*#*0dL0Pqg°ÒÖˆá="ØÃɘj8NÆXRÒz‹A#*``(3ŠS@F“Q¦ÊÛåuu¶»Ë¯„Æ.¥,0ðÙnäy~Îs‡žxížB&}ØŸ¾$qìM¶EädÜN#*†°€°æûy@TbørȾL£k¶è š3›O—3àpd›Ù¡¤9#)üâPNäή|ëb„yÖ‹’ÈȲ:²;¸Ô¶»ë6âæ]ÅÝWd…ÙǦûOºi@,òIÆÎÖ#*•[ä6q>rÉ.0å\3kÛá¯Âzûõ(d½Üf£_°màÉ~úéöðX˜˜™š#*)³Qc÷ô³Ê'HœC…˜-&Å#+©TDhvÏOiþd€ÈAˆæªsF¶¼ÞZ%αÙ0g,#+–N£’wÁÌ3Ú%@…î{nÝÝËòo,¾n<âó ’ Ï€«h˜{Ó*^#+c˜>½MÿÃóaë¢TZˆñ‰ac$œ/ è\)¢(DOÖ”#+«¦¡yh¹‚©~¬¬ãb©#+¦1¡ #*ÐA+$ð¥t˜1'?]‡ˆŠ& ÕçÎó‘P#*"Ó\P‰ïAÒçÒq·z½(Ò“…ÌlÄ&7eú¶¦×É =‚ÅZFtHFØÑ}ãZ0À"'•¦?Æ=Ä4Ä·“QC¸¼ôl©çV}Gd¡GH¾Ã#)âT“Ãîjªn(šÂ2§’^„ÝÔ•ÇZ«@yðÍüªÎF‘)†ù:œ6“t:ùGka¶²Ž=8ÉfY’]•ürmŒUÈ’¨^X³à>w†¨#+¼™Iêõ½T,øQ2xQ#+á£\z›¬¢þÆHy!ŽwD0íµÞÇ•š™-겑µ#M$g!S•`Ób™¥>Êb1èÔX2¶ŠEH¢ƒ¥·ÆÏ,ã…Ãc«¬õkmy3OF£‚kÙصj#+2¯j!FN¨C˜…¦±ûY†žÉç–õ)hÛ²ÆÈS`6ÒcHÍͼôϺpTƒc£*òaÃXÀ[Ý*Ee;±±¦¾ò†ämc–#){Zv‹“#)Æ$ñŸÑß5Ù‹WL–ï fIÑõÙ¹’ÇwX‰§U0Hzq"LYq…†?͵›’÷¯;©¥D—“ìéÃÆÓ£¦6ϺC;#–ÂBTï&ï嘌#*¬Ø¿Æ›ý„Ù ÃŽ&çÛC'¶–Xn™‹@vEÜE#*b6H’ª¨B 2&.A#P;áZ¾v—MòË’²”rZ«Á@ƒØ±¶“ä,\/ËÄ¥ qJª“D¢MC°ÁsA›¦ŒÐáA´¢a‚% f´nh4“Q(Q#*ÓFÚa#+a&¢d˜lØ;7-2Ëtp£#+ ©1h¥ÖÒE“„Ú2V“ƒ"""ÈÃX´0dLÒU)hn†Ž8Q4-‹"X 1f“ÂÈ[&fVî£á÷Iâ]·sߎYÝML™Í5#•ê I¾^LÆŠÎ ÄÞÏ7C¬ÄJ=èÖ9‘°ƒŒt8¢„gf ˨_ØÃ;*1h¤ 'æbÇãÓG—”+Æ\{HƉ#*“* @›RáÁ Óôª#)Ù°í„k/ I0—GåÇØÙ̺>|ä†Æ¥½hYJˆÑª)r! .ï6øÓXD.š=ZΈ´À6ïá8#× >ÇeÑ€šÈó44Ó-”›åÏÏWßüút^aª¯gÂtš“×z‰dMtSŒ[w–é ••/ž4©ívÌf©]€Î6„0…•ÀàðÔÉTSâ“B²æ(²N»5gØAF]±ú!¶&¦|¼‹#+ˆ.{+Empµó½d6&ºMæ+&Rhú‘9jwpDÓ-²0>-™ÊD†ú9ÎÖK‘gÀº#*¡B;üànèý°ê’Ùë œ~mÆí9™ggähA°dN9X¦ß›ÑÔN„|ö•ß£±ÝB °!D±¡DÐE‰Ï% #*&3ï÷Ò’¯ŠÁC…‡K0ÒÂ#)•F$ÔI“:É$sMÐeXŒ<5\ldµ¾µ°aÑ#)!yåÍ6:à1@iØ5‰i²$#)„ jMÁ„Œ%#*Úù7‡è»›&&ÀY—¤=˜5{‹Q#À{þ³¿»/ÞNäR@I¶u®Ìô•ç¤ß9‘ YŠ^ï|•6¤b]*#)4&¥Ì¢ðÕÕ‹ÁøÜ&Z+NòNr?#+¹¨e)Á‰ù™,̸¨bœ¥ú;õ}Àƒ<Ð Œ@TnwÎÒÊxÓ<éì>x’HB¦~eÏÜA`VEµâ£W-[cZÚŠÚ¹¹²È€2(A!CBì<5_œ¸œˆ_¹Æ#+)«ª:¤ë6Û¹W*¦@š33Òp:K<C<¦šu¾ç ø6HEDê!‰$hI¦LÊf•¦Y’R“LRj‹IšƒùN¤ÂZÒ1Q4Ô¡’š"P£ZX׿nPÉ&,’‰LšÉ‰šfHÂTPÄ¥Cêî¢#i,Š‰†)%%”0ÕÉA¨´¨ÑD”Â(ÍÉ’´Å5Š™DÐd¤)¨2•ˆ4Ði›LcIMïîî)Ü“y³ÛSˆò²—ì#+’²{'t{?++UWÐÆ(}Ù|?uÙ‘Ò;!·äÈ;8H¨Ü*9>ã•á†s³¬#*ôç#*ƒS²rÁ‰¼YúqœS(hÆô–Þ™å#)àŒ#«3—7ZuïïKEF£>ê6%øv„Û‹‡m¦ê%ËA<Ì,ã©]‚õ\vidZ¿Æ—CZFú“|wë‚.µvc±êÌnúðµÒ6—óˆö—_`?ø¡¿YBß~+˜Èè6&ÛpÀÈʦAáJšØýZø^Ûoů±bc- £1³Y6ŠŠ#d´Ë(„a;3ãçŸQ†íè·bÀLØQ×4àíø3³ÙŸcÌÍ7›œa‡¯AfŠJg9W–œ8Ć62i\û®[é®å/c°zCŸÄH`MþÒ”›WS·aèéOŽÕûóÇ=G"Ã!v¨NŠ¢ÀJè/™Ö4JËô|,ܸŽäÏž†›rÅ%œ¨†Ü‹}bóÑ×D!×UVm\jQJA(U$I#)‹Ø™1ç[ÒÿWW×p‘öL£~ݶþYwÖ1ðšRüüâ(é2‰F^#*>Ûp}1ŒcÇ"$•o7Û|^ZàèÜžrXL´g/.Û>^?Î#+ø‰³ƒû5¤þ#*jè*’[i¾½°ÞÓ‡îe¸¥…†*t*.#+mfà8ÅXèPÎù†úVÚó¦Ç(iÅl£˜_€€zÐ Q›g¾ôrÁ‚Iú¯›WÅò`µº L¡|dŽ»j:÷ä½órß¡ñºe8yaŠÊc¡ni§q=æxK›C Í®Æyapü& EJzŸ3\ˆ{ßeá%+iÄi™¤òï¤Ò(P”?KÇÕ GdêpÚNB"T]¦SÄbY=¶ÍP¡#)Æ®ôu;¡²/©Nº6ÞËmÌ̽á–Ê"lG¡ì9 ve…óúf«§–½SËnþÖìîäÈÙIrÝð'SVú5:„õW§´Þ]v>OˆÁãA8}_Eq½ÿAÓi9¤*HgŽtwÔœË<!öyÜC¬íÙõsùe°ÇïZËôs ßâ9Z{ÕK±(Ñ;^ùÉ禷;{¡¸B¸{Š_§—;ø½Fp"aQO»JRGkBkbl8ògâm»]š•%|¶;€Ì]È’*ŽŽ¼&P–så3 jÓ5'2;Cq¬üŽù™™#+;«€›<2Ý 'Ê÷ÞÂX°ˆgE%p@ûkùS§¾ŽŽÌ‡§«õlÏ5|*³öã=©W_ÜʳK…h•#“ëhŽŒc#+ãZ‘Ž7•™o´6Ìš¢ƒÖ¡•ÂŒœ‘u§÷5˜6™óq™†ò¹÷FÌXÜÔnLçQ桦e¶iåæÆiœK¡d´ÅâhѨ¢¦¥0ŠáWb$YB,.7…¶—:²fÚŠ‡zsÖ°'›|JÒ” –¦wÄþSU/ø“éº^,3ç±ûe7½±ÖQ~ɇ[#)Dgá¦ø Á2¦8©?7VõÀ–ÄÔ̶‡«9Ñ©¨¶pi•‚°„ÉðÔÇÎì§y+;ö“ðCµs}§j#*.Sˆ0¶6{P#“¤éOrðf§+%ÞgQzœÔC#*Cp²Kf¸¶Ä“’´Ž©:l¦³Ë.üv0dÕA:oØ,œÄ7#+ÁŒUEÅAbåúYžŽÎiç–™ªáµGßÆAËœ>#*ÚÁ¸YÑ5V\Ú0>x’æ˜$ÇIçHݘ5êΙwJ±Õ†B¹äêh`Á«›ÌX;!÷67¶ŒLjL¾ =ù_mbí¨Ç.›îPq°¶ž#ZÐ'¥œË=§å˜¤:ØÑ5%ÜšÀ„öÄ0ÿ{¶ñ01€l´“¼G¯ji¦jë%\X´5Ùòvxãͽ4V4ØZMDxç‡<üÉïYÛ0gµ;iʼ¼bL²ãj-è‰Y»Û5™Éœ^ŒW7ÅN·Å#:LèNèvØÚÐõYšÛ6Pñ<zm¬kHüpbo†Ü„üÎÅŸ¥Ã¤¹C¨ÆD¤ÊY}Ö«hÕNyãÆ(#;cC‚HMœÆzñ\¤j9¼ow1Mb—ò½òùåŒÃsz»!z½BT;AÆJÓì>#ccYÐÔw߬n×(}q|oWÄî²a…3™§¦è:Ó;1¢dÆ9Ž°„LJ©n5´š£Íš']ºß—ÊßQt×\PÄ##)^Nò”:±¡µÑ82%pd™"^!ä\´°»¨(2CAl(¸jS}5\7š¢¨HÂIÓlª^mK‘a+a[æâ*ɾ÷UµìŒ¦„!2Æ(1ª¸ ØÙž¼§ŽY5‡«òíd7ç—s%}“Ë.’ÊùÕoÉͧ)8ÇRÚcLÌÜÐcZXƒ!”ŤÜL—¨Ç2@ª&ßhƒ”Cà†–I¶5$äËÁmÉ·wŽHÝ0냦`á\ö§%‹C’šõ“j£–3fàHâA–ÌÃìí ˆÐ—#üÁÄ5ï™NºD©#*@\Ü@;ÂaÙ#+ši[ÙT싇ZN#)]`¹rmep œnçô‘¼%–Ì>ÎPiI#+4óÉ6I‡ƒjvÅ0,¶iQ!³é¥ØXlhÍÍÌpÑÏNVŸNÚ]#* ºQH.q¼†Æ.¶bÔJ2¦E›6™äz…Èr'i3…jR}¶huhfá…,ˆÖGmõ¢çHBºfY|c90ÌÒB P×±!¾j1»½ý%EàÖ‡N74BbeÓŸŽK„Œ„7èîŒÔm´píƒpRj¯âã#*'Œ5xîs/ps[Dìr·‘1„Qvkwg·JÃ]Þq•ÛÂEBIìÙB –HÄ9ú”amoaq&õ•ØS‹™™ŒLMæxÔ;dçv±•ð#*o!Õé8fÜÈm¢qãKf‰¹¼s%O6;ª‘éÔ!,ÙH¹D»¨#+¤®%'©ˆE@ª‰IæQ(îšQnâ\ñ11ˆyññÖxƧ#+3§¡[›ÃÌáæTB¥Uqx‡Úk ¨ÙZGžÏä‡-é,ʃyóÓã.‰vÆX¨Ì¼!$œª‹UH–ÔÑ-‹„ÌG€5–fêJ½1·[ƒs2ú™Bº9‰“†H4qÆ:jn¬21ÉO)&PmV†Ìâë\—[™lÖfõŽ™5,yU–LbÇ0vB‰ÓW5£YÓÖ™fBÞ0Ì £Ý+.ì2çÎêç#+ªAâÎ1¬“BåPÜÒÕi:§c=ÞX‡°¨Âj8rËUW8Šbvg±ËN+X©0Nø4a©Ë9Þåqä{Á¨·É"aNû+â(0àe#+Bu öó›Rõ`h©µÃ„E8($ÔÍN–3L#Itq…FõîXrm\1Ü&ÖÌÔ¯½©cQ²ê¤EÒÂ%*‘ÚrÕK#*tÓ1#>"<4[»K5ýl^«¼;6ÜåZÛ|g®È95{ÛdæŠmP)MÂÝç#)º¡$Ì 0ñoj9ÆÄÙ‘²‹ë4tP)Q´IÂÊI@ìÍæxúªÄ°… iÙ4J¥L©Ù‹¶TwdZ>h€!#)4Ãß“B£Xž¡#+_,nÛ¦Pí„&RÌá‰Ë°dY‘Ù°Ž¥Ü±Ñ>á!ÿÐá‘W<ÖDwÀ6é"ðd^»åÉDk¡H¤Š1Ršd-œXZ‰‡vCϤ0é‹C€ÊÇgys( AÍ1š®Âej‰–³7Õ)©ša–D@ÈÓJ l”ͪ”‹—viÛZéN”(XŽ”S7p‚ÛͤˆËCa9ëZf¦É)!…Šè윒ZE´¦æ¶O7"eÈÁÒ¤âÌ<Á0ÈjËÖ¥:3T#*°æ˜Jã\ÙÁsC…U¶xò¬eV'—'qøƒ#+¹X¡àèÑ¢Ó@¥Nœ"g¨…ØÊãc8zŒöf\»#)CÔPà†È1Œ6`ÚuFòjlAé;H–wnË—Û¶L>Ð8è·ŽHy}×hn|Jãfå«n#+eɪó™>ã—Êt¶C›Ê¡WŽ4TÎ…õJ.ô½ßc¢vk\8RÎÒ¬˜³ˆÎ ÔÁ|`5Œ`pËî¸ÅG5D´Lbð¥ñ®¬]CC[¸.Œa½n–œ!“ŠÏ!©ÏaA¦WíÉ„˜™ÓŒPiIÛ+] gw6÷¾ü2ÇÌï—æf²„9i 7U@88û±³0…6šD¼rî+„Ýx¤½WÁ\Ö+Ùr»º¹kǦ©-Nô\)–Ä``i’ÚÏêÀè’âãA.NâˆÑÔGI–F1¶ÂHÀcfÒíåxüÚæË•c¬ik#¿í*Fï%‚Dv ‡JíèlËRQ]+y¦—"€9 aÔ4ë8†æy¬r¡˜2„6(kX›mlá.@!µÛlyˆkCŽûÈ¡¢#*F+2fisÄØÜ l³3Y†ÅÖ…²U)¡ÎQÓ#)e2É•%d#)rá¹™#+9ŽÅ‡32£ðÆŽäp‚UC=N A‚#*ŒBÀÑÙ¾ŒpÙÂ+q‰%ÛʈÝÒÐÎhÎ2\fÐÜ$#*†DN4”;œÄÅ1Í‹ FÃ9²4SlÁdÌž)Iy#pt(q“3a4ìnf:Í«™t5Ž‹³aÁ¢ê23i…“RR8Æ‹Æv´±={›f¤Í¨Ûss!€¦D‰w[ÎpÌ#)ÅC¨@Àî#)bú†âgT£Ä‘„bõ€% °‚P¡ú·?ÈI„MDÐìÎðTÚ)¬¡rˆûR‘(#_é×ÅGǼ=ý …ÔŠö´I$IddŒ’BO}Q¸úöcœ€Q€"'T:F韡ˆÔ‘Blƒ@Q(#+‹@D3ŒÀ™#)ÀP.àH;²Óß–³ÈÏ‹ i°p‡é…‚IñNÙUI‡Ã>”ÜâV›Cûuœü®Ëâu âv,áÅ¥ÍÁ«”¦kFñ“wë-ÖQEÜ‹h^uËïµÄL«4ó¸ëá›&Rc'j_ÃXGåxÎœk—’ÛWg`ÐÉÍ`f!æƒxFì##¶<fó¡-°[,pCÃp„"ÁŽŒo· ë úÍŵ²Rän„¹ÂK”A#ÈpBÿ:ì‚ 4Ñ*D•Q*4Ëkñ¦j¬›ÉIªÔÚÕåðQ#+"ïðŠPT!ÓÔ&)óïæ‘2éЩ 4¤B¨,Ô'^8ª(É¥ÊÏgpÄ2C¹~ò‹u6ô|Ù§b¯À ‚*¹EUÝónRZ¾•Ë÷Õ9uwu]˜Öë»2æë¦ê‚×6Jþ槗ïîì‹[äÕìvˆê¡àK…ï½#)\vÊc±Tw ;7Àüø#)ä$3äñC¡}ÄCŒãÌ¡ƒ8‘jÔQæaGSÜ`=¥?Htsáßב´}+¾ÆóðÕ&EÃò‡ô™‚·Aääý-•ö`Ùþ'Íðc–Ñì̾B6ÊzîçfiZLPOB0@cK.ªÃµ6£xº eÀöøLfà´kü;[&ÐdBšb±oQ*¥4#+:\sq„¹v´¤Î‘s.7Ê ’ýƒÑÇ#4"Î愈k;ϵ‰˜‡ë"Ûñ·‡€\¹b^®”èz#”o$±‘57Îý‹ù=~ã_b«M¢IL¶*±¢Ñµ£j$Æ¢&I°f™–DQm‹¯§ã©$Be¢|±Ç†•¢§h‚•Ô§#*œû—$È2]åÑÔv@Y«°CÒæ‘¢#÷Ý؈šð´Ad±#´ÂL#À+$Ej;Håm U‹qy€ÍÂx:žosשÔ2ÁÔôÑi;¦kþD{Œ5î|¨á™)ƒKõXQ¤‰s>5a¼$ô€'-ZDŒW‰@Hm<ùä®2¼3+¬ƒêi¢™¨0É…–á#ÎÅH7üGEi1¥Ž´‘d#ÜBn^šÕʺU|›z—¦Þ„j™#+°.ÉŒ[2”²bš+ÜaZ\34B1c@ÔsùÎ2‘3cÅw,!hF¶¾X#+Dü]ˆðªDˆÁÇÆäh8Y (ÛIƒ@U~ªXž8ªM;¹ˆ&T»ïÂyþš;byÞ¥¥\ä™7»j.â"††ôC‰µË}ëÚc* 6È5$*G/z¥.G5ÝàÛÜD¢Ñ;tfõ$^&Ž’ІäŒ6ÚfjÃLâ*qLuquEÔLhF1IoÄGTK&Bºäf¬¯:ql¼? ã#)=¡ìIæz{J˜(À*À-!VD˜S04ªýÓx#F%ûÆ…¬*’ðU÷Ø#*±D3‚0cº#*ƒ4þ$À!°|µ÷KxÅz[úÌÇòý4g<0æFÖ:N%E`Ö™ú7p£˜ÀßQr0«s|œªÚ## ‘qöe]²cûÊCNH¦§gØå÷›DÒ˜oÃ8ªßÂæÃwhº"4ˆŠïTØuñ£L4úãAÈÑ´-«ã…¥¥jÖAl"¿–á$á‡2k³B¨TLí³H#+g‘NÇ6:Ç™ÍÅ®(láã¡Y·MŒ{”^ZÖH8[΃3™<Ÿ#)÷¾æÖU¸ehÃå ¨ýúN¦Ã¥‘œ¤Í¹=†Œ’(Jv›nN<mmƒåPš«%*‰ ÀUŒeYNÜ9#+)áÕaŒ:°Ö@mQõ'u¡=p®pì’ëSɱ4\CbF”ñqÖ=‰©}lô‹7Ë;VôÆ„ub‚ÂŽl El0,±ˆSFQ»uv0È3[¢)e x#*À„aL*˜d@!L@£*#*Ì#)¸_zÀ-$BE,$˜: bmã7ì–k¸B㬊Ð?ä PWr¡ö…ÏÒuà×ÔH…£2gÞ®SN)XžÊQþ#+Ý4@õº°.yø³¡±_#+zÛf¸c±Néç‹Çû&@Qéh‡ßWYœõLL#)ˆÈ{澦H¢`™!$‘’1Mõk^6¶þzŶ‹Uj-m "#+H$‰ Cܦh|êž^Zðܹz—>#+•Ë‘ö>!ã5¼¡ïè#*-h¥õq\MoŽvÎ^øA¸ÕY[QÑY½¨äØr$®E#*“{9éÃYÞ%lšeäʵS0:2¥K‹ßl4ïµi¶“vl“t2Vø»–¯V1FÛÜlc6h9Äq£šHÒ.™KÄӃƶð¤¶Ê>s7’a”ã6ÍWIT%³/4ò嫈’öçŒáöäD´¬SNDIžRá©7DMÌ—C€é‡ÚsF7Êš€ˆ¼Œ1N·ÉÄÉÍ£qNv˧º£~Q&˜Ç؈ƒh5)ßa=`C§‡8·Š´Û§ E2±J|Å&-MØ 31Î5Ä™›µ3žµfgS´œb¨i½ðyXÛz›Mp“\ÎJùš}d£3œ}æxdÇ·ÔW!2„dž9lð4(ÚwM‡ƒc&úU/“›dØ¢™¨sLêgïgjRP@Æc$"1a¹9ã czÕºR‚,"ˆÁ`‹L1É`´mYGË]¾qµK¥ŒŠ¥%!Ð##+\¨ŒP´0hH¥ƒhmQª’†” "D‹"·5œÒèP@@`Œ’~äË V¬,0ÜqJÓʹ¢ƒÔƒ€ØØ"í²8ÆqUv‡;bì×MŠŽî¯I#ÊV¬e’¦HÜ!²ŽæVÁ‰ÒÍ75t*ê×i5ƒt®ë®î)7Šå¯]®L´í<Ýw™W“bcJÝMní4H¤‰,ÊÍø)80¥Ú6x¯m¸·Œ¥´Ê¤²“"lÖ6Æ´ÔŠfº–ºV–RÒÉm,Êšª4ú5òóÂj6¨0X©š-[IŠ± B*BËzüŒÞH:#+ü£cV©@YKj@æÁD8¦EØd0 (TM¦æÐ ¥Ø”D ACœAìnŠùDv‘AÚ{,œñ=$#¡Øóý²–œr,¦¡¯Úmúsýj‡œ'>bŠè ï@¶a€´èµ¬¸Á‡fn¼´±°51bÜ HÈhûìê$Ì•5,aâÕi¶“ŽiŠ§‰ÛæØÜCЩ6¥O‚}oßd@êŠ\b•*©Fˆ„‚ÔBàÅ,þ Z2"S¨F;¤†ÒïÜò„ðüiâw®œo.Ž‘†kGìÔeÃ]‹}yº,n§å#)ת 2!MiK‘٘ˆ<«…L¦Ez鄤0©"@ŠÑª÷éêýŽý¼µ†Çsdx†ñàc‰ž újõ.\*;öóÔì6Ÿzi¿p¿C~–g%éT2r "¬ËŽ-Ž#rý9™,æå!3`ZI!æÈ!“kÉ*ð—¤*“ k„˜8噧&¶(\¨Ž:aÂë%e²;N_#6Yð f”Ký[Z‰8&›ajt'áwM¬íÈ 3 ¤š·÷(}JªD#)Œ"¡Þøú¾v5Òû¯™±¼“¼áež*²øÌ£_¯ôä](’:~B’IBv{[Vñ¥ã²Z¨€þÿº£VH¼]…ÒLª12I¹®E”2Ñ5’b·¾íZäÓi´e-¤ÙFŤE4Ë%”ÉJ¢˜¥›P)F~EÖÚ³LÃfÐÌi‰6Š*ÔÖ©¢zqEdV¥w]6¡/«iÚÍ^Ý»*b(2#+f¶ÒŒÖ”¶¤ÚÄš1iUû«UÖ¾—"XÕïݲM‘E¬l•¶D’&ÙµË-LªI©m¼ó¯)Q-6›(L¦¬6Ú[6“{:µ©mŒb¢<mÑY²ÞuuçrJU¦M#*rÝYªJð]f¯Û˜•XHÛxMvM 0E#$Æÿ“—¦eViËç|©+-ýÀ°,£œèÈø|;+ÑÕ¦á’j4ªÖÝ í¸¦d“¡×Ùª-Dhå2ãîé|R"bOk”º¨¤=¬–ÓN‰ÒZe·,XˆŒ€e×#)jID‡tËKM¥”ÒÚ6Ô¤ÕHr²o#*®CÉ€¤QE$Œ’$TÊ*Qs”ÄbBÍ%@jæßGu¯)ªém±W65¨k}…”Š™‡1Ò›#+jÚRŠdéjß+e·6ª‹%-š˜ÒÓ3ÚE E¥&©Kmi¶TͬšØiM©M¾+r†I–¢²¨›IA(Ê4Ò’hm6ÊSHš“4l4Ìe ±hVÊ)±²bKBƤÚÆÚ”ª#*EJl©JdªJÑIT–’6¥Ú‹Y´Ð²2RcAI”˜Jdšd©fªmˆÕVD¨¥‰›Rd‘fµ©f²dÑ¥$´¦Û,¬„ ™ %R#+@`©„4†’ÞòÚ×M›-ZSUe‘,Ä#)¨‰v 2"±ªRØ-¨Ú´‰U¦¥€"´mæ?Puœ÷Ìèq°‹:é2:B}ÛÍŠ÷ÃoË5ªöÐÀÍýöpb‚›¦uëòÎ9J&£'ºÊôq¹ÃM¨§–t’¤Èï#*G‡xR<£r7‰á×RÕB,8ñ¿ïø g¸E}ñ<ïtó†øìT$1g½¸ƒ’ÈÅ~Žý˜×6ιîų@fÚÊ ˜óivz.•Mù”£v’‡‡ Š”®Óì¾H+ѽ7Àe§ý¬†ß;Ž³ºëÒsq!~FDÉ2lÀm \cha!¼†„#)S™ÌóÙsšL–oðõt˜%)ºõu«¼‘B +÷Êy€T·E p}ª™³UÍÔtÍa²)ËR u#+*Wèî)A=|5Hqf‰÷ŒÀ‚.3î£#*L“ð}Î6dXšs1š"„$]º‰nû{Ó&¼ÍolË¡=8¼½7¬]Î(³€Üêp׳]Hû<ÊĹÉö2RÃeÝùŸ·èšìßçdBS1Ô*LáPT_×PúÕ.F¾©Ñ)iûYá`'ëqŽg#*¶`E’FtªM*CzµX^7:µ½ß£ª£›º±jSI£|Ök}„ˆÙ®ÑFrp[ö‡œB¢\†™<äH¥ ÑÓLÔUU"„€!˸#)#)V-±ª£Ûé•w]·!êpövÈVyF¨·Tô„‘ Z‹ÜÉ´ÉØœpc±¾üÝ÷iVUÆD`üßSŽ½‡¾ÂHƒ#)Y;+s™…8e‰†’‘Çfw†„m}Ù²¯weŒp¶tìÆcoM>ƒWÌhJ~=;6û„@=ã¿ÅïçÚºÎ6óv#*çG±±Ý][{éLcÚšÓPô„P,Àý;nÉÞù »!&'ù¿ÅÀ«–‚Îx…Q®\‰úþ»ÌŸÌyìíË^›)6†#*¥iÿÖþ¾XV·¹YlQ´2²’$QŒhÑœÕRhÖ4C DÈÂ6À‡¼D5$Öê-pÁ´#*‘‚9m&ˆRÍ(¦7#JhÃ\Ã#*cŠ±¬Œ‚h¼°Š³†7#*»KTŠ3›ˆlLÐÝeq‹±Å,TCD.ÚXUTŠÆº]$˜*Z´<R)0©Î¡HkŠFý*LàH’·€í—MÜ\åz5J<BGàµó”B)Á5Ú5NÄ Ú×ÒƒÏÄÈÒƒ4çCÜR4j’±Ì#+pvàøÄ]©Æ-"jí8s*Wg¯qž†'Ó¦Ná\„$€Ãw0'M;}§£z·"˜Ø·7;†±#+²•@TFñAj#+Àº#+_gmoÐ?«Z¶‹Ù©®rÄH|ú~p¸ ÌêU‹7pÛµ¶ÿŸ¦}ÒNg•B ¤Ožø·>÷è¨1£ñMnx$œé˜W’¶âÓâëUc^o#ŽMÉ! y§h^õ Q‰¡²ÒÛˆoŠkÙŒ»±“4!¸L «}IfÈzIYS*#oÓ½#*àþœ›ãCòü¸{öcÂô2>þÅHT#áÓJ)Xùö˜`üh˜øæb¾Ú!ºE›¡X R$ÕÒS$™>]ˆZ¾<¶.¬_;ö¤8RñN0$‡™µœÅýS䘵àü>¶&µÂ¶ïm%ãü¼¦šm£jõiå&4jRRy´zj"²„Ô…Ž@£2>8#*¸>Öw8æ篌ì’ä1vb]00ŽÌÍ…PȵHÏ à=G"Ö÷’3Tm´âp Ëéí©Ü¡\}js¢f‹F¤„ÉÃ'`²Ãa¨‰«Zôt0Q¥ii¿}'Sé~éUŒDì=9”Jª^¬¨‚P'–e\fzÕ:q»ò•yì°êD#)€É ÉÁê÷Nbœ¥CŽ“J&˜õ & @C8„D»Ï¾½¿w~è>g—áÚ©4¡Ë7õŽ¢áuEÕËiÃÎÒ`€sCgÀ|#*#)Q0jHõ¢Â¹»ˆšÇïó„瓘ú(7׎±™…74Lmu¢‰Ú#¨€MCgÓ—@îíËïÄ&ä¶æÆíMD#*ÄÓ’5Œ˜ÕŒ-8ŠvÄÏI±Ô9:ÌbÚË‘(ÖK€!¨™1ÎÓ€8rUb*ú¨¥^ž²õâzvœ3»¬ÞVÌòT.4ï;¡3sÎŒø9ö Ðb‘*,R¡)Œ`f‹"DB —¥×*¯zïšIÚÚJXB“%ÉË9˜FœCqp¿£GàîÚH¡Í]ໃiH¢tGV#+‘$iU8Œ@ ŠïÁb È#ꢱ˜$¢»™‹„ \Yu«JIK‹NzîÆszîLo;®îõ›ØƒœSÍ>÷5&#*æÁH©µR*Šª†ÌZôD´†‰I4ªuÔ›3‘¦†ÚêXˆÚ|µÅDÉ$ Ë"de<ís›‰.W[rY¥Ï<ëAâxñŸkzËÎä' "#)$lŒá`Ü1çéÛv»ÕEš%0ÐXpe§2Q0{º–Ý„'Cü[Ñ›cÛ[J;¥PaŸ*C·Z&»ã=ËÚ#Ûm°ÝÏ>[øtuÖ ë࣯ Y8Î,×–)B¯-ÂñXµLTªÍ,©±»°K¯áÔ˜Šé¨8RŽ„6øyçͨ:c¯£Ù‘éi]ÏP¦áA:¸´íÊBúëÂ'n3Œ|sÒ+tÄF,Âzvlt•-~}-$Ö@U&j˜*ÈÃíü°h9;˜%žþ©ëD(YzwÜ°À—€jN,0â©‚e캒EÖ—®µzròåÞ7Rmõ·dLÊ$'zó^^µt“c7m«ww@5*Ha(’™´Qcš°O;·„Õ˘¥ì”¼ËUCV(ÅiH@M6ïÛß;›ÒÚ"Žè¯´º›»µh»4z&cèúvñŠD §¬¹½‹íðœú³¹RãMpÜuH§ÞwÞêf“=û™5~´½/kë]f"±‘‚’~¶‡t¤ÚÃZ¿kZõhÕ“j¬ŒÃý©ÁP:U2dfÃ`mEouM4m(¢Ö«”iTÓI¥¥ºè¹·C“Y‹hÛó*ÜŒXŠÑ|iEUéz^¦Ö¼nZË6þóûÞñ¶É«i¶km¥é::byôÐÅ) *p%—Î\TâMHùÍÃ#*Kƒ8 –BЊRâ2DZq1'+C oЂØM†ñ2P‡rËHD}¯…ç:ÈÐÖY4‰–°´š¤•wfa#*r½5ølmØ›=›œ €IŸ>l#*“¼Ühov^¸§¶J*”_ô„rÖ-0¢v&èŒà¬…¥!m…OÊ©Teª³Ò‚¡WK$š¼Ã2£Í†YÖp€ëÖàtîó£!ÙÓU#+#Q#+ŠD‰UKLŠ&ÑTju¶Ûªµôïfé^#¡„k„*7Ë/a7¹fä{ª+†»ab·(ôÁ ”‚dYQ·½óãÅõ†÷y8ൢƒ:uˆ²-Ɔ€‰²#)ó,¥¬ôI÷íà)œM3ðÇ×þü#)vºDÖä[Bê‚NgÀÙŒ(4dˆA(þèš¿ë°ä³CŸ•Ï®ým©°wÃÅQ–‡€¢,#*„Aéä ¢{ök‚ ‘ªCb%ò58þ\4ùj™m¯³ü÷¢9üGákè D‡T]°õdÞˆn»&ߥ¡=ŇœwuŒðºyB¼U¡Í?o“ÜG àìì}/Ž?Š$D‡'&\^¾ˆo¯Ì£¦ûºBónÍŸÕðC¼! ˆÏ¼äP:Í€ç¾Õ؃â#µ_›Íô_å;^Hž$PRI‘Dë #+J¥*#+¡DUYXD¨©PPfŽälY€¡x@ ‘,‚ä‰%f¸añ¾¤Nìk3.?Þ†=Ž·3Rº0V(,i,X)ÀÊ6Bý¹î\r;”é>«SìSQù~Ý«Ëj±DŸ@ô$›SОģC˜N/P¼läV_Ôþ€å$¤ ÂPÀ‡eø–ÈwGÜÉj‘BÒR+†—‘D‡o×ØøŸ,Âïª11Yøz¼ùqa8X8¢j܉ó8:ÎÓœdŠÓaí¨#u›¼…AÚ5m,WÀ»5¦ XiË.Ì·œû¨ô§Ü¤NÒ*^D’"tÈa±æ5ðÙ°¾¤—TY*¥6È.j§ó³,?6a&šòìuCFª ±QV$6kùy ´ÐDj6€dÀîÈaX¡†Z? °QÖú){~å]j¬iRD@‚›]C–*H¢†0PžrÜ5uÉ8b¤™EX¤®wγ##*ÛŽ‰fQ“"#+×Rf²ÚâXÄj°+HìÍ46„úˆÀf˜ÚPŽ)11Ò#*ŒµYÆTdÅE‚ˆ˜´«a)’©”Vk²ÙÁ”€ÝBS ,†‰H춨„)&Y#+³p–›2SŒPaD‹²X„Æõ!l –’•‹#*m&4‚±6–ò!ÀÆFFs•ËÚ!0! «-&‰•hÌ „´µƒtªÒÁ ‘¼–7 6È«#+Ãp´X›Õ¬«L°rt5¶ŽÞÝ{{öÛÁŠòwvwnk–¹sV6•Ý+–åQ\·/ƒxĘ׮ïK.»o‹dÁ®IŠç4\3•¨lêApÌjÓ´KŒ&Di:3±öu˜i–4ßÃZ±1£–(\'(2ƤÙÕ#*ª0%ÓI@ 8ZÖÔ¬¬<5MSÏXÛ3¥‰b]ÆW¾ìµØ?±4ì}0œÆA,¾çmˆ*[l“ʤÀ…ÍZxpu±»õ>KϦ4ÀˆšÌoªÝçn¼™n³MÖn²‹«áùqý”Â1Ó ÍÇžVàqãìz~#*áÝ£ .H(óMTÖÔ?<û Ñ0€À«Š¯X1 «ûãÜE•DˆFåæ¶5*Y-UvØÆ•d¼[¤ªŒ,k\µWR±«m·7[d´ÓX™%ƒYPuŠ«#)–¥II¼²n>”ýaäXv¨j ¤,b$"Ò?»yÞ}_A`5~ôUXŒ³ƒ¿é®¿w}XõŽ¦Qc×/«ÈÍrCCËPbP¤ŠPBªT`T"¯ÆáP—*(R$åþ0 …ˆàã:njÄ€çºêù+q˜„§3Ú‡-£›ˆ’" <MˆP}¥!ñ½UD$I~X)¡Å¨5#*!å,•²mçn¥*YUÍs[Æ×Üm¯,ÈŠ-’Ŷ†ÈUG©¬X®«º¢×¦¯k½yõÖìµÍWÉy¥¬jówQE˜˜RMjMZ“4ÚKÛß°Û`i˜I#)#+Dt dyÇKR±û9uC©¢ÞE˜$Ê+Ü¢åˆìƒQJW#+ü©….I#)}@!x!ˆâ&X‹ˆ b6 íƒb"Ù™ R¼€;›ŽÙ#)&¥@¶ÊŸGðQì#b0d•0›AþÂîmù½ôžCrÊؤ‹a=‹í’#)ëÑ.=ÝYž=ô• oi„L¥8ô`…«Á1*ªE*ègÏÆá/nÔˆÃÕS²¨N#EÅBØÝ…ÆMC^$Ø`1v rÿCòdgW+×0úbõAJŠ†¯ˆbÊ#)h¿ˆ|¯¢&÷W2°ª8êÜ‹°ÔCÉ{†ÁØWƒ´©Fí»ŠJ4¥¥*j±µÚkÞWliªÍ5”õ+¨¬(±F0XDd•¿¯¡âs2Ó·}ƒèÕv@ìí»GÞÕ(P]«šŒ`îÐ>^å8ʵáQíû‹¿Õá ~'ÇG<n¸Ñ캓®¥Œûƒ’ÃåÔzhÍ4›h¦ATšqpÿá¹<ÆsŠ‹Ëf$1#*k#+CT¦ï®0fŽ—#*î¸I#¬¥ª(ecƒm€#½Õ&˜ŽäÄŒî£î0aC•´A¾øÐ䱇½wû„Á<ޮتÀê$’IhLUG÷£s'#Öyç»–™zþÛêä…õëšÇ-‚c¾œW*ùÖ,®ð©NPYT.ÂÔZjBÀÌŸëý¼‚@å¹ÉY¶çA?Bô3Ãuå\›9¦#õØàQCS¡™&>^ÌJ8×V¹ "ÒuˆÄjS«6a k‚907ÓM‡ƒrb&'üD¦Å0Ù#*d†IPŠ0¡l0F¡fœj±RF¨¦y#+!®l¿ îäi=ŽÍÈ5Ï$w¡¾L±Ã\jð…‚f÷bäv¬C<¡ÿŸ÷òZK&$HànÙdÁá&l½¡‘Ç^zÂŒìgR}ÔÉϘŸ:z#)CÒûV€r®Ì”>?#)Õ8 $j<#)¶Æáãj4[Ö"ÙƒRRd³Lŵ5´µ&Æ´d˜Êkõev “DÊ™igìµnm©™jl‹E3X%lÅSÆÛ5T6²Ìµ™m–"Ö-(Š¦ÔÌMš¬Ñ4Õ6ÅUE°¥ ͦÏ}WÊþfêÛöû&¿Nãç~EÓ–üÙlµ$"jp+#ÕãúÛ¤µ¹¶ŠÖºœÛjµ‹]Mk\ÖìÞ#+¼Â£ßÁ´×¨¡µ°IÁiÌîêá '@6Ѳ6æ®s·6(¤º—å´·¶Ùê’ ø]‘Ê^”èŠúöÐFBD2$N8À¤‡ÒÑ0)ö¨0üÙ‡“‚|Ù1q@a>ÎVGœ{æÅ1jéC¿ž~ þ‡N€'( %J€² whzÓ¡#*úØ‘óÐQ!•(dñI-$$)#+@ý‘nAö¥ºE"#+Tõ¡<Bös¼E‹cï>3Ë=»¶\ׂÁ‹#)%ªÇ S">³¿Ê¥§m©#*±¹%Éê"¶éMà\˨¹”Òõ™™ƒÀß¿<º«€ÏïRÂÀк…®D+ñ½½þJ§'`4Œñ=#¤VNÂOy„£°9×Wwj2jÃéï6˜x#)!ÅçÖ¡›¼ƒ¸€p[5v›»ËAÕ‚o/“Ç•7# Hp¡’m`q>»#*Sø9m+¥.â!Fb+BCCD‘Â6°L¿Ð¼£LÑÓ°„,ÜXšË•;Þçì:>1J=h}¿”º‡Û¹œ~n¶kIêµP¿²)øIötSBó‡Úeµ §¹'s«ý|a®#)p® ¬-Aç®×_Ï‘ÑŠQ’÷ýÚðãž7oåñ¡çE/6¡ p)¬ß‘µ¾°³’¼3§ñäÀŸ'×ë )&©#+§YA””²’„´ ,˜Sßñð4Ç]«Pù&云kÑe•ˆeIŠß…׬z _;ª‘#*ûxƒoMt#)‡Oñÿ»È ²å˜µ1¦¬²É‚ ‘Œò¢´Ž!n[$#M0©Ø)#m$_/w·ìÁ£Ý)œùb`H‹¥E)ƒ—°·*#Ó²vDIUãÆVŠ´@Z-QzÖal¢¸£Á5«OšâÞv=òñ5#)Ù“=UZH_#)ÁÛæÙ,H ™B™ˆÊ†ðŒPjp´ ûjETq1¶Ö4s#D‰>¸€i‚‘@ ¯L`)ªv@§G—çðÒçžeê’Àá5ÀÕÂöΰŽ3æñ¡µÉ—I#+5ˆàÂ3‹Œ@!ádêuhAë†ð-íÐÍ-ç-1¡‡4X…”þñdîxžža,H2:#+0ˆÒ‘0…B’†Å4#*K …‘)Š¡ ÊNMœõx¨†vi=>~½Ö(è:À>ß0C.¾jú]½¾$Núª$dG ”É!ETB›G|¶«bªŽúOb~)¦]ÈÁàfÑ·ôÄ!,ƒç4FDZŸ&NAóŸBÜ`5±Ý®lÔtfë,”'e[_e·ç·¶ÛÛƽ#já©0‘QØSAˆSR0×èßÓ3Ãå’¢„æÈRBn©FPÉ,¬KØ¢¢±õù^gïD¥ÓÇI¼¹L”…Þyå#o¼é"½ $M¶[QR]Áªo(²(|Íq"!‡Äª‚‘¢(‡YÐÆ]ÚÐi¦u¢Ó#|½-0"`ÁÓdƒKùÈbz ¸¦Š£$mŠq£IÎ×I2íâ05“ÙâÍ3±-±äS‘.î’¿80ˆûiÝqâÐÛ*JåÊ–W"€Ka·'óník#)þ„‚D‰•º¨EOy©$($4#*²¨q[ñ¶BqK â¼]FžCl Áã–&M›eÖ”je 5VWE·[Ñ$F¥”¬ŽÂB q‡’?5î‘À2·wbÄý¤Íè€hGràE<3ƒ¢§U6‡ÍD]‰ç_Û1"bvÁ'Pe;dÙeƒgÍÙÒRħêλ¨Ð#4öû=*ÔíªŠv8—Z¥mÍP›ˆ^OMWñ«MsœÞ(@d'/m1òÎãƒ,'=¥QC®0òÖ³´B×oô~ÔéÕÓå®ä[æ¶5‘ÔPPÒZ³cyq»UÝÕR‘Eµ^²Ýu4»^3bÑ(Þ–)²DTqŒa[áÜPxê¦AOi#),ÀH®Íþ™ÕõŠ#)vgœoˆ€åþm½0€WöWÛ®0Ýçà5¹°ÈßÒjêõ™( 2#)²ˆ!Åã¡GHGR:Dz÷`‚JµX–#*ÚØ@\#)q8—¼Rü`õúh#*}]^HjÛ¼íÓ2jÜYÖ“8›‹ê}Þ—V¹žIæ©êð”Äò “¡ŠMèÈ’B$ÆÆ’b…°j •Äˆ&äÛM¬›mRm´²ñä£ZT…Hˆ2¨”c,@ ÏÏú=ç¼ðB°d?è¡vîi|%À›Bn%I¸û-³ú½ë[Cb¶CCàU³-¤0Â3U;¥ià]¾=¡M»½·®Ò±»¢ái—Ʊª4 öš¹I^eæ^5%ªæÞ^;WKj˜#+¢-2Ð0å,¶f«(E¶›»ÎŽšg½¤rêé/óåEÎ!cLL9xô¡5ªbÀ¯P#X¡²ed9diä%»¦<yŒÛ#hÔH„$lÉx0á¬þ½«@#*½¼9 öñ‹B,\*…°ii@eàÄ3l¶b8†©wn_\þ\ç;*gâjI –KÚUŠ8è#)ʘˊž|ë³°¿ 6'!>ŸM-.rÞïg¨^ÀCôÎu؈›'ù·;I¦“Ãá8š'½ÜIÏ#)}t%u@1$D8×y•šK*5’¶&Z6KI«cT¦µùÕ~VÚL®»U=ÖÙlX[$¤)#+a 0?OBz ‹ÃòïK˜Øò¹e(¹·›j˜8 ã´UXz;-f¬…Cß5"”ãÌå×ËFžì²ËŠ«Ÿ×®|ÅÖØøª7ׂ02¶Wº¨;nõ²| âê<³ˆU¶åÛoUx$˜§Á#*ýk¢È¶‚ËÍðŸ#*Iä·Ø¹¨Úa$Ñ8UA‰vSÀ&·Ólw×?™Í¹ï†û)ôÄÖH"Ð7ªˆ ¡#rž†)1{l.¸ßop0ˆ²B1Ž¼ó¿VýÉFyä#c¼ù½ð7ÄCD‰¤0Iƒ®%¬:EGs“|AAÓo-/Ù3¤m]'щ)MA=gÁKá.öú¶Å¹ò6H_³Æ:›ïmÓô¹ÖŽ=;’Õv9ÅÛÈìÖÐÈ@ëóxâFýØ?™åJª@(/#+6¿‘eg‡9ë máÔ7¢õ¢>G‚ª>Üé³iëíúîؼ`Rv…@ñï£!*íŒnQvÚRÕ»f…ï‚ÄMü–O6Bdm@8LÊŒÒZ¼òAÄê²ÅÚ)ÛØy~LM¥÷Á¶²"&V¶Ð\s!JD»‚„H@zp.¥É†çÂÓ‘çÀ†‡.äǬJ¾ÁÙÍ[Õ#+y°aB`*• û {P›œ'û¼6àGÑÔ1…åÛ09ô_(žŒG”·1Œ>Na{{D-¨ï<ð¬j5ÝÛÓmÍ:mVÌ\U#*¡$‰HH0‘Q·‘KAŠCo³UïÌ£éݨ#*Á•([¼Ú¹„õÇüÿy~¼ÉuAb ,Zk€¶°º,D#&:É’Q–"¢ÄH0n°lP±Hà¤p˜”M$…PofK>E„AÃ!š#'‹v®#*”¿sóÈóDïÁéôcÚ/yê»tT’a¿èÿ_ÎÜ 9&-ÒV)7‰ëEöîO†iøîÙË–8›¦•å΃¶ž=q#*~ÁóhiѦî‚`†Ì5bË$ &ᢓËPŽoÍAë%ÀIÓTª)1¡Ð`Fœ#w#ÈIj¶"ü’óhäkÝ‘XHš²Œå’Šä½HßÚ‡XŸ&¡ÏO‡ÛÈ>«%2jlqî‡ÁìqŘƒ‡N•F’#rs*+A°×ZëšîÜ·WYµ4Õ”µgnÚº“d•¶Í5ªê¶4W)—‹——v•¼o£,Ñd#)ˆ#)d›:0Ô¦ªlê(† }~z¥+MzŠPS†nœÔÎk.Ea„ŠQµöÐ,#+I¾=—Å”›¾¸?ø5Ò`ë|~‘ádd„µ|Ø…‚_Û“”œƒcPÔÇ–Õ&üÚ‘Aª#+Ú¤“sc£ðÿ^álxÐl6%´ÀÎjC"j“PÈ4FXl=œ‡ƒ¸jÎÆ$RÈZ±`„#4g·Õú7¨Nè9S-VÞM¹”dmÐL¯Oj†³¯ƒÞnW&VBÞ~ÐlÈõÎ>êî7í Qˆ#)Ï2æô}M÷ïBÆMØð=Z‚¼uJøtyÜÁ€ëwÛÏ©ày•'¥·õ|ù_ûºìhª#f€òQuÌ:eaú·Ï s£¥lá1Gèk}8¯ª¨«¥¥ÐIDdPÀ+ÄŸ©ß/ëý¿×ÿWðo²À-OæDàÎSßRú¿$Åö]'v5ÂkŠPX‰·çˆ±²ð¹ßSX§%DAÀµ¶&Œ‚¤?9¬½à-`û6ÌÌ5¯ãºµ„.HÛy4#)jP{çÆÝ‹ B˜oQp<AuòÃÌñ#*áN‡PûŸŠó1hm0zÖ¨#*ÀïV¢ÙáÑ¿â±’‰ÎóÁKNØššF\ì‚îù'íJ›^ƒ¦¡EI…P¨¡]ãæ½Õˆñ$ÉÍuK39gpÖ³fÝx¶ÈQ-žÈcB’b8L6dfêƒM.ÛŠ`D/ˆaí#+bð@!Kž4UÌtóxäÁ¦Ðbñ´7âÄa‡€xAËÓ¥¶ßgLeXPó.„ÄzàY)0(Ï€¢g’C»è>|¥ƒ.œ× Øþ!õ·;ô‹Â‰+"dÌŠ¡òÈÿšaB;)™ç=‡^yÌàö¤‘ÀcK-ÒÒLÅþü7"ðŒ¢ÃOèš´xÞ¥s,LWÇëÑÓkŒC;”ò9y^ýáÖy[u¬Øvªdl‰pIÀf–—mAk<hÌŒ:ÓëÞòÜ݉(6ëÊcz0èRR5|m¼µV]áÒ2ÉRÈýûÊéú6¾:òô bÐA„a¨‚•èª„!“Èè£fxrS4ST#)jëÛqÈS¦’KRPNŸ…±xÚ-XFÛXFÑhÕ¶4[ ‹RkF²XÚƵ*´«^5mÊ£msY#ºfÙƒ]ÎŽíúe÷æ݈Á v"• Œ)CñÀá¹Uz,.ã`!i Ä<zöœm·Ý¿vÄMÄD–pw>¢Å7NÚö™#+bŠMjÏF¥nYÇLgöQ³nÔ-Tôúî}jcàÀtÓW3Àd7ñµM¶H0`¹yào#*Ðíu#ÑÌ1ç'qB~ï8}“aÛüÞÀŠ0Ôy+å·0ò#*¦ÊHHˆ^Ìz„döŽü"÷{õ`{rÃø}¸sdÃ¯Ò m“gø;6Q80;qÅÎc½dà ’Ìæ9‹Ç¦Å¯‘!HÕ(zh{+qQ@ïˆf?¬!¶ÛVb£9µHC!•?E) ªj•³Kÿ~·®º`”&#*I·€Žy$ Œw»mõºÙ¡—®…#+ƒº X®™*ªJ Ê>$‘ñï«×“:.æg‹"g±ª‚¢éMñÆŠZTÍ âYlP¦WÒuÜ Ò ŒWS™ X(‚‚U £a[#*aA˜†°þN{-{æg#)]!7#)‰Õ8ŒâÃ2A#*™U š*µB 8îÏÍõ{ÝïK=yz¸Ñtg™ƒf#!A@Ò…STU7I20Š9Áð‡uxâ÷/Œµ7D?qôpkØô“’Añû»k ï—TæÝâ×ik"9ŽqE8QŒs,86iÁ-2wC³c8wÇF¼‹€‹àý6bå‚Äb‚ªŽ,x»©3ÏžÚêŸßm\ë¯YáôûAú~{ì#)¹^‡DÛà ÅQ ê=£t8üx˜î÷ž3jÐøjgïªo²½˜ªQW<èÒ!¦uˆå¨¥Eª¢FD€ óNCˆ®YIô ÙMIÀÓÚîBU„Á¨˜Ø<aRa¦¢¢„v®«w]¥#jff±hhÚ!#*‹Ð—òʃz”Y¼(TP$ÆIe¢#p”`48*j¥â0bnVÑÆj £HptkFTĨÂ$HrEiˆ–A” КÓ;Å[ð$‡1¯dOÊ®è‡!únfUDTD1j²šéW7©¹‘fÉV”«&Fyºë&T…(´#+åv7ÀÉ[Q‹AD#%£[( LÑÜo##+a‚#+ŠË+&†Y¶©FÑkA4š”#)¨5+e+4%1±‹RI&…6›,Û3$ÈÛe+/]ÛËriÝËš¹ ³u×-¹§nÞòæ¼Þw‘4P©jË}>»Ùì͆ÀE³#+YK¥’óâŠ"”¡é¼Ðr#*£uœSl5X<'Z4A vXñ==YŒcnµ#*»§dÃZŠ´Çƒ#*}•V±„‹·‘jÚ$ùqàÒyð¨ã&Ói@¸r1i®†(fëC}`j˜ÓqÒŸD^^æíXª #+×®”QH×ùYi6¾tžÕäôÓ›3,–«ÛºÍUY)¡Ò.YA@Ë1³pÉ°Úá£!*‚›$#+Ò1#+E¬45-—w%¦WŠÈŠÂ¤Ä1än0-¥Œ‘&`Ùi%ehCÑV‚“SšØÆ1±&;"ÐÆf;jcß».qÂ#Q†7†!•»¤n¸LÉšœ@ã67v:ãÊV¥´¥ÄÐWˉ¼÷ZØÚÔ†H¾¦£Óûì#*2M…4tðõq(÷°‰»6ô¦CÈ NyVëu5Hÿ*ÕÜó@qø¶¦iM(9ôyCKô€u»¶âgåbY#ÃVnmm8álíHÀá€jÆšEÃ`ÌhÛ1½½U”ÄÙç¤)b#*¡M$}&¹Þƒv]ö1̳?ÄÑ„§7#*0á.™ƒa™1ô_#)Ç©úþs¥²÷ÓSb<4$²àwOÄô°¿.y™~nžl¶Ç\èë‘I–XåW²ÙŠ-ôÅd1ì!fŒkâD7\``ñ£HZ%Sm•›âir=S|qš„ÒSŠ^5©aÛ9U¨E£fÖT5pŠ©#¶*PŽMOF,ÐÈÁ‹bðÃÜG¬ùû¼ŸI¬1ŒDPÅ#*Ы(é»)e ë â °z‰9R·A™UnØÆýnnÆQøÓÎh ¡ ä¥P4-¼µÕ×[¦´ÛÝy¨Ú*é«6¤TCH˜ƒØè0c¤,%€ˆÁ²B1T±Av D$—›þЀrÓϨô‡T}šàC`»¯¯å¥™aÅ'4î¿4H‹ýjÒâêZ¨¡Ì1õâÄ?„Êhý4Qˆ‘Ì>Ͻoz4që=½6›Ÿuß¡ÄÛâýç›I[ù]ÏTáX‹bjDþçפ=Ö+žé¡á£F'÷6#*¼=ûº™)doowIعqû¯7M^³O7«šÉ«—;2)eY–¾INþššúí[¥·ë{7tn(ÌD$å¹™›ru7•Ó<yp“ÆÎ3¸ãG#*#+#*Eˆ~×XFùš¼p6¢À¨b™Ž9ÝÒ;TÚXM‘$+ªî[—Ùr§ÁÛs;÷ö0D9üºšƒB£]v°a&íò}˜Ð&~ÒŒn^Œ>‡ÒÎG‘Xg~{–õÏϬ©Oƒ9ñÁ¯..Ýš„’Å>òÿt’L˜õa#Ü)»*"e ¶Ë!†æŸŸ†©’½5©ïÇ)N‡K¨Ÿl®ò7ðü<-ä6lC¤eÀ~홦¶j–À¬Î¸jR™N¯àùÀCá?SŸ|pO|Â{ÀÝ!0ŠAdŠˆ ÷ˆÈŠ³aDl- u%‘>ˆ¢š›*GãB Y#)Ý!Κyw“¸»wM;Æòy[ÇJ⫳kpºmRm]ã±b¬my×.šºµ;s!ίQO²X´‹HÅJš¹Çu]Ý«Ôª4×ÅZ¼[y6´›¥[ªëÏ7ŒV4mmâÚ5^¬|Y\ ÃèÙ»ó4ÝaF=FÂ9"’õ]+®åbôä*Z(Q…”"…4Éu¶ìÚ©µçš©ö‹f^ª.!{,4„¬¤H…¡ ÍkµíµäÍÙ^–«Öµy«¢÷–úe#*b¡)„© …@ËTj¥)jEú]j)²‹X¬ÆfšT[cQ©˜¨ØÔZ‹ck2°hÑ3T›%™D̘•J(©™6@Ímš¼íWK;)@¢"¤gÙá™ ~Ý÷‘G!O§Uµç¨4•¨¬%I"H)eø;/öO³Âý½Lxêþ~»·?ÑãEÓ´°õ‡Šp8#§;«»æè(s/ò£²xI%µ¥ŠÖüÍM6´”Íhß77Ïzº…š5Qùf·ØÖ·#+µâ×Oézº‚Ѧžnê#m;»:êÝÚJZÛ˜¨ª±¤¶æ¹sYÕÚnÎiZÊõÛ³Y¨‰#)#+R-4}6Û!˜î7eg"1&Yˆ~%Å_t(†‚Ñ$˜‚D`b#*‹€‰7“–`Ij¨ ‰#*È´p#+¡a#*§_G¶¤¡Pm+½Êlr„50^5+´¹†)Â6!4žoª@§Ýv§¼u¾\Zó›;¢HCÇqÉó3¾¼è¨…Ì]hʈ°Ÿ<Ó`û6l<ê£ú™ÃZÆ ºK1Œ&~VX8ØÆ2»™&š„ă#+b‘X3jiº8$ÓÉpîM¾¦S‰(íQ‰qàu?ªæñåßì! 5éá1°<¦ˆt2b²sÙðVþ’ðæ8ÀU;¬"Ç‘¶C’}¥s—ceòw¼o0<&…1d¼ØeÌ"ò9Æ.{òmiÙO“P–Öû'–kFÚíì)[hítKEH³*Ó¸Áƒ†¥“#*1.ïg¹àšE‚¯ð“¶…c,žDèÀRs†Îû…fGaºò²ˆ#+&Õ6g-Ÿ³îñ¡þšÇ†*C“bô™”SªVÕK5¼î„ï5QG’P…Àõ†š'7í5¬›dµlmF©-¾TûêÁDB‘!÷0?ÌAÊô‘Î#+>§Åmo$öu¤ªØÛQµpA,[w±€+oeªåi÷«Ä8coEò¤ @Ã×åfÿ Éð…íê—º¥äm]-’Úk®ÓÛ‹¶3#+"…¢Ø€‹Âb-‚8#DFˆ-37lZRE ÀÑ÷=šüA€!·Â¶ÞªÖù’ÚÛ2LFÉ«jæšÅñöÉUçu\Dö]â®Ò"6—5ÞN¹øzç¥ÞM^[f2@IÀ@Îq¥à´q•µHÌ …FÚ#*[FÙ«R”âm ˆf¬*Ö©ÆÐ0©…#+’"J¨…#+…#+ÅcÈeG,¤ÌBÞ0«ßDdЄÂ%¢€ƒ“®aìÎõÄј@¤'˜Æ ‚ƒxÐ8_ùxõåõgb1ˆ¤/+=]çè?'Üõ´X*œúŽx„«Œú3&mÓYƒ·vgÒd…$£Ìk%¨Û·Onü÷hÈèUN$E#)‘;KHFI$„$ h‡`UH OÇ°<3Ëè> t…PúGì£;Q‘÷éþ? <!l‹Å5@üÓTÁùF½Q‡…ÓþxEäs™ý¬#*7„Œd<–2qO_»}ÏÍ“OŽ¡N?,ß|Ç:Áë9hTOç@Z‚u:ˆ¤d.Hв€(?IF¸[.^2#)1Qg#*øpÁÑô#+¢j8Is·¶³µ‚ó³ /º)¦CpQÿ.Š˜–0ÑŠ'¡µšè€A7öÄÎg\#¾n=±´Û#+xŒ8°ÙÊåØ7Ì¢€l]"•Pô)ZE&Û#) Š¸yZÂÂiÄrL—&Á‘`òû•!†OÚ#)à“3R½ûö¾±<þž ¶7÷ÖÅS‰ãÖ©ô>Ê›&áò‡6»#m›Ñ£ø•Nœâ3„“½*z€QCøƒLà_!¤òeAws®m«¥j®í²Ý]ÚF!Ò”1«" gü×êJ¨µr;Sñý6|.;Å#*’òš¨#+’‘b£D!Q‹ó–Bt?w>,Yi^½çžygyÝ\º2嫆”uÝâòœÜËÍÅfË"i$l&Ê–£ÆÛ´Û%(¦l`ñ¸š%͹\«›¸î¼æ^MÇ]vÊ9й]ݺErñoJ£šl·“Ì·W.æ³,hvï6©VŒ;m®nZéµd¶JX¬ër›2Édñ[»»£tæ®ìΚäŠZ3œ9Wl¹ÖTZ4rµ»i¶åÝ-·_áy^j#)ÜÜ,*=P#*Â; ìD€!¤#)zöúwƒ@åØg¦b0#)v£û»Cº€‹#P„ ¡A;‰al@ExýjŠoNy¨x~©Â{AS°qè)à‡| ‚ÄŽo¦=¾ž ¯Eö=¶¾&• —Ø!çŸp¤û(P ü¾íÉøö&Ó¨öƒ`#)7 2#Õ¨Êfi}6õr«[ñb£ )TØ\³ýQEc#)Lç?o&¶½”–5²jÅjÐ¥¡„&€ÀÐañ>IŽ‡À #*©*+—âW›ÇjœuÝÔÙX¨²ªC"Bб‹—c 1<BŒÞä%‡%ZëøBY(0vm¾‰ôé“$ÍÄ^äâ!#x#)° ÝJ#*éL`Ú)#+5ézk[ÔÕz‘V·‘@Ò‘f¸¶eÈQ@´ƒLF*†£œý›—12#+SæAJμ¡DþÞ¬2¿€¦0ЉŒb±J!ƒÞëš]`5¸C¤5¦qwŠ#)\Kb¦«+RÍ–ÖiµJ¢”€1`‘Þ†"&ܾEÄt:ˆ‚ñÛf5“fÔ-2f¨Ê¡$Q #)éò<XÆ&ô5#)$vŸj(¤Ô–™Œ&¶¿ÀÛQˆ’@#X„.8Ü"þ¨:dkµ3²ž3T]`˜ƒ#NqS]ŠÐ÷Ìw’M@˜QÏÙ“¦Q3eËgm–Ñ=ï@ƒÁÖ†0Oz3?^÷é÷Wã}wŠ¢Õ¤#)áXq„ÔýŒðT6ÚcÈ3‰4 ;YÏ04¤'åh»04øÈgF6"H¤$“ƒ‡8èç‡ÇCè]ñ‡ðüÃa~!òy,Òr<À-%ÇØCM>ZÇ#)‰ÄÄ#*IÇY%¢–#+U„"mA#‰#)l(DÓtRŒ„]0KDdK#+”ÐAŒ`FÝi&ÅÄ*6VjBTE+ k±˜3¦ÙPƆ٘î\´.ÐRH¶ö°AL R$¤Ð‰!@’XÂ(&eIòvlI$–ÑTÉ8ŠÂ‚«ÞâOoµáPîÊ«3h}Á“” H\U3‚Ô*”\ÍcÂï@zyd•ëõŠÔ4Ö#*7¨ÛÚ<í'ŒW5ÞRŽ¼ø^¯²#*ˆ- ȈH€£qR¡@”¨(!´Üþ]!³lnqÒèîŠë)7nÜá4}Ô#ù“wIRBB@Ž»¢‡‰WËØtÑÁùÛFЦå’× Àz ¡XLÓv iQÊÀˆHm-P·FékxyÓ±‡Î°óÃG݉#Ihä©Õº#*#)%- X#)± Ñ*@t*©È ©øCm{ˆÒ¾¸¦i]½ZvÍÁÌ#PZ¡ŠtÀ³‰ŠÐÂÐE¹ÍxO\MÁšy'KŒ(HÈzŠÈ(‰µãÎ?ܶn°™£kª–ª¬¢Ø˜¶ˆ@sjÝ'ü°Ðkå*ú˜mpEg/Í<î½5ê´¹ÚæJÔ·y›o!,™&8(BIa]f<™·d„T®„’ÿL1‹þ}†Ù#)â®0‡'ŽîF¼>ãò-A*ËÊ«m°¯+X¹i§Öm9/'…½zaa¢áHÄî> ñÖÔ6šõ é‚ Ÿ¿ ?Dv#u|%D³óÕØtopãdPª.Òµiúýnʪ¦þK«Kò„¨ˆsT{B®h³‘sJloÛ#)qo€KSè;äþiÃÍ[zÐÿNïµ&GcÔßÖiI4A¤,3EŸ³·Í‘E„ÚÙñˆŽ`€ê>"ŠjÔñëÜ£í=<²Ì}#+ý¿JÅ:.µ(+÷”¶ÇEòì¯GoᢘÖ÷ eeÛÑtËaƒ>¢Œ‰¼Ûã75‡ Žé/#*—›íà†PfÊ#*ÍÿI”ËZ[{¬Ââ&6ŶíÍT)ˆáˆüÍy#*ü¼‰ÆNÕñ*žVÆȺx$LdUC#*–xY‰L©m@iq)3Š¸7Ò#*D#)ÆadÆ-!cã˜?—½;ÄCq¿sb‰Útd‡äûVÞ¬WÜÈ·d”’ óS»°Ùœîòc³$}´®%9õ<Æýf‰ÇH±SÚrÜÂÑT`ùÉ0Œ>îÈáUNlÌ "^â¡ßŠ¸%ýϾëú#昦>ÁYµmÂVÐ…½Ç,¡.³Š÷²þ]²˜oF™‚ƒ3q‹N8L-a}d,„ŽYÍ<cÆ2H#*#*‚0oPŹ°ÑÍk¥¦=i4b¦—sìž‹'4ƒ‡Ÿ£Çe*ý,sNèÞñ#Hè„,I8£h«Óë-0ŠQszÏ&¬çO4½{Öžm›#)·’þB¸–vRMѼ°ÇÑØ-£?N™jöíÆ}vØ)Êàišç¼o㤮„<nõMÖ^YEû}\5Œ¤eÆ@æjmÑ!Ù%©¼HnÛíÈaê17Ž-a¹ó^™Ìgló¨OÚb*)»þë ©wQ™%Ôæq-µW$G-Âu4B!‰@6‡‰R¤z›"Àñf)¡#*ı¹];zë>³àÉúÓúC‰ßìª1ûvŸëUÞ/OßȆæ…U ïçÕÏn™*~’ÏD"ºÐ¹gA\}y·È¿®óŠöñ6&hl€sÒ’‚& ^Ñ |·šL5íI2Ðùlÿož¥‹¢É3Aà\0CÝçOªLÀŒè¥¨$D3M‡AFþ{©Ûkä ›<3±Éî£ríµº?¿nrè}l<X+5 Çð`~ö¸÷Τ•²I5½j¿›é˜·ƒíJIõ¶ÅÃâª!0$D–‰eh#žü*h$m®¬¹«·¥«¼YϨãøH—#Œ=%$3XUSGRgŒgYÏF»Ë`IY_øâ÷=>#õ eß½ùû¤ï¤×„r-µÜГ½T©Ø¾a®:ô¾6p&Pƒ{wÇh|QØcÑÏ! ™Åi¼@Rö¡dN¢íAV)‰GJ-ùtúfu†ñ‘ów-*zf§-paäG'óS⛄ÒÝÓ>Ì?Ÿ#+R” ÜÜѹñåmçQ•v0/ÏnñÑ8ª¡3'»=·„1Kø)ê–`Ėȃ§¶Æ§N9ß#*Tò´Öô!†1]OCã´ÑJ®óÕÏÙ× zð1SGÐ#+·,62”RopiB#0^ì¹ÀŸ…ô³áÆÁÌé:L½Ëïüºbl©õJÃò°bA$_‘ ¼#)$PîG½!ñG¨/ð‡ÈùÅ`Ýð Š$€$""@ C»qz¸ŽÄ~þX*G®»²½¡2™º€ŠpzຎcÐñØC¯QîNÉq#)ùƒs#*Aná#ó-¼GCÒsä.6c’;þ7ÇñÂǾq1Ú qñq.ùt–rîÀ SîÕµmó‰h<4¶ÓkñfÐDW‘@¢Ã~9({¤Š¾5ÝB¢ªMóû«ììJíçÜu;×ǶH@ùwQÍ`ÄDÉGK Ÿ>X¶ÅG›¬ä1‚ÇÊ¢ci>Çb¢˜Šƒ"vɤ`¹‡Uš›*Ó^y…ø»³àHàà0×ê‚^:=¡#)¥ìIKB#)Æ1XH ås‹Zû9ÿ+úþfee$^ú~ò˜Ñz‚Åd—z[-Úé@Ðî'Ó—`i! Jª‘ PÔ<Aßo=Ô&»Åë#ßç9™àq¼Ùçð£.J¦„O%~ËÒš5™›ufvÃnœí}:ŸrCq3Cú¢‚ÿus›8d#*1úa(«GÐÒ"Àú°tý’€Ýù¬BÉ.Á; è!†Wóµ¿<û:+_5#*<GIµk+Ø´#+‚WB_ûºo\„7$ë}×lΊv6¢«;;Ë…(:Ùç°óÀNb™XÅêÁŒ‹¾ùð•èÐ&¸ ¤Ïϳõxžt.9B¿?!(6¿>ųøš?·–}‰‘°µÂ«Ln3”’9‘/·.±)Žä÷ïÜ;¦õŒªÌ©Dæýúà³{%à˜Úû÷Ù[™¡óÑŸ¿åˆîP’AÙÈÑoª¢_˜]HÄúwL˜üZ;×u‰±55(øtЇ»°;èÉR:R¥:íeT‘@ÙÖª¡#Ùú²è’vœ<7eú1*2‡Í,˜Î•ë;rÌ~jÂ2Z…J‰,JŒr¹Wtýê»U&b-¶[5šj–kÒ•ªj6©³ñîÙd#*Ï*Ô’D7!й¬\»ºîêøuŸ(Fè¢(z¨‡®¥Z#)°Eîü9Ì`gú?O‡™#)›FeRDhÌš(&›D¢j"““%ˆÓJ‘’‰¡HI³dØP‘£$é]»'Ž6 'È‹¤^d’;Èzâúã·‡6ú]y”R’M›vÌ ÜÆ0Øh5$˜l²AšQR0%óoº[=4È ˆ®Ú8o‰‹ùñ•€ü‡“‚’G4ÓÁ߇+kí÷›0‰9ùvg\vruÙ{R·ŸÉû½2÷ÑæÎL£(JÙÀô11¶Ýó‰˜Þ—ïÃ`-®šMU_@µi–0bVÇ ‰šÇ-ìMci©ãŠ‡ÙU'ß߀nk±Ù¤ec‚á¬j˜TC§Ûë¨fèÎ[‰‘À ËóÏÚróˆië©ß#+kkž5I"þX@É—ýoò猉Þðù‘T“Mópµ$-e±*˜ÉJVÚiÆ(âKBjEIj0 Q‹¬i’@´FÝQUË;®JW+n×t¹ºº…µ’êÅd#IJ4fÑŠÅÄC#+Û1&Ú1;¤Œ`f¢#+€âà¥n‰J„.Ð0¤£¶É”´×6\ÅP2ÿÂ#)(²PˆÂMi•x«W.—,î·5d”Frã>òÖÅ\èÚòfT#+ÌEùHSËH"Og¹£°i-±¼knâq¶H܃oͨspÅ!4\Í4Eý´Â¿ƒù‹Øágˆ<„eÄÚ8tÖHL%ÀB„•ˆg”äôFªKýã®6¸*:„mä1›bCb%mä„`tDy¶>ñm#I°y²¬`½ppl¢¶n8„F„Ú11!9¦ÞZ4ÉcŠ#*‚'Žómܲ‹®Þ5¿#)õÝv»¨Œ§³jƒHÌ-M#*Œ @áüJrSM#+¢Š‚a´ØãŽ(’ÆYm©¦ÔÛ‰¦c"ÃJibnD Á«²¡±=#*ÉbƒUDë•V).QÙ„m•ÖÚÁ6Â*âÐaD«ªE‘!P®•Ú1§CiºÓe(l©o0•Q†¨ZcÂaUƒJŒ0lCezïOv9»*A)V(»‚쨻SEÝÄ´¹j @űѩ§¼Å¶e™ÕÞŒøÁc®„¬—µvCg@TF4±pÖ”ŠÔƒqs”¥`«UÆ«A–@–Úì2¦AÕŒ#V„‡«M3OK »Ÿ.UÑ×€ÀÀÊAÇ•Úbb¤ØJ ˆ,à’ºÒ|¢µÀuÄ=7¢jšdt³EÁƶ¢Éçpf˜á3fðÆIkRPnr¨ãnbZ@Á<(Ó„}dU¬—šŒŽá*8˜` wÈÂ3ùNXÕ¤ãT`hdJ‹t.hŠ"³d‚j!B!›SUPj8ŽöÎŒ@ÉŒ3ƒ@F¿oЈ/¢‹”à#XšGdÕm5œÊÐ&ÄQ‘@ݤÎ*Ò”ÁW:Ô22dI•@PËdI¦™¸H*‚†Š(ÑšhË#+Й °£B©¤äA(0XѽÀGUý¹tôÅnÒ\LA]ª²Ðà†¤‚IqЩDÚYcŽY¼R±éŠ¨}#*œ¸ƒ‘<Ÿ6`Ó᪢é8ÃðA6á(¥â =M„8@ ¤†’£)¢ ˆµqîe‘éån#*nèÀ™OdnDœDóêaµyQ‰²]ò}Ž´ÞâXP¯¬Xˆ–”ãîÑÜ¥Ð7¬j"ªB$5çf‰lŸ7ªMrg+µe°FÓ"&˜Ï&©8±xtí¸Œ¶ª$ˆ’Z!LìaMHÒZ#*Š(ƒæ!B†ÐQ!bJŠ£"¤Á€524ÚK7 )"#)8ZhýpÞPŸÅÌ;zÒR%R”Å%ZÕ+wvñ?›çytŨÉk½ut·ïuÄõr;§rV;å|-ôWàÚJj-¶(Z›6™²É“Vú6ÝÐBÊ!÷X§é.ÿGšnÛ45*êv‹²ÍÂüÀ2‚,P¨ „‹ÝœÔ Yé’n‡Lß銤€Œ¦jC;Ðü(£‡âµZ˜r'¹Y "#)P€Â1©F‚¹"…ËkÒörAöÔ¤¨‡y±‡tÏ/}ˆ^T$IB\Œ*dû§H•÷0,ç—š¨Á.PÓ0‰â¦’#+;+$(ÿÓ`fHØ›;»b1±ÕÕÓkomuÒ‡w`ÂwJ¢Æ .P¡‹0°nÙ@b˃¥ÀÖªQ³)Œ€ø2CöŠYrT PjnkºeËF()fÉC×BˆŽ$p½µ#+.<ßîûÂÞÃápd͵61.ÎòX× QÞÈnO¶ÍŠño#*o»‹;˜#*¾/=”ÍIÂEJÍžf«üA¨¨½Ùî ÷¶²^õ#·L_HÄpæm:/§W~‰^‘£éP5ýÃR@[EÒrŸy¯%C°Ë‚ðPÃTP‡‘‡'BJÏ܃¼MIˆÑÚ}ý[^Ýè½÷±`±z¡‰.Qr¯f,C^&Ù¾šë9TøõkëCøO‰LK g¯ªïâÔueÚ‚7Ñú~¥ØÁ#)Ë×)%í·½·•ç#)Ó–«Ç2Ðai¾§Äþÿ¼™ñ|DG¾˜Þ™†–ÞAÆÝKÇÉîeÅød"I¯yé’#*EP¨@B»þtìÛHûÏY…À|,fcœ¿n³& N.È=ÌFÕåX,Ù:V*mî(zà PTÜÅÝZµšë-¶:#+@'?‘`{ñ*yÛ\ŒP„èȇ`ò;b\”Ø‚eb‚Š©ö0’á™óNÊR¨QmTÎÞ¤¹Q¤Uñs´k"ÕU– Lèa¿ÃÆ´Èj樤0À—mE„ýMg‘¾#*Α9H<\f·µÉ±´&Ä›#m¿è1Éóë\’åWH»¶â²öþŸÊñFɽ§+d¶‹{5·b[—wVßÁ-pÚñTk9¹[¦ÖÝ5d5¹´š·5“\¹U¹S»Ý®E²mAŠ5¼W"ÒÒ5AüKpÃD8ì²îÉ7cu=#*Q_€g”@âQ™Zú4׌œÄ™‡©6ûÌÉÙ]Ä[Ð7RD"†èŠ#D@<QV›Ò‡±þ,D@»I;»·oªå÷æù¨8»ê /Ñ#î~ ®|÷}ȇë"Щ6ðŸÏI,|DÂ:Á†“ª#+E#)ªÁv<ùUéL) Q‚"FÒP’74‡ Ÿè0'Õ"Òà0XŽÈdk0#)6¨µm¤·jÐÖ×I°X€œöyíÀŠ…&B]½Þ‚¢îˆªªü-ªYF“Y#FÛl "³ÀùÑD,(Ž çB?Ø#)Ÿô€&¿ËîçIÕn’ŒZ¡X0™/ÉCÑE!+Ê•<ïkJ®#+1 KÄQз&e÷ ‰ÿ$ƒ §w Ú•“t:ì•ùÒ‡u¸ùnÆ¢ä„XKݮߛm]m_ÛÙKS3d’R…ŒZY#-MšRQX±²””’™6#+VÚ#j[Ú¶¥¥i–¥£S*V-h¶2ГB¿aŸ*Ý$‚cnµ™¶C\ÑÏM®/Û]öùêõzò‘TyC)Ü`Gpo2ä7b4À¸ÔyR@ˆTÒ€É"Q§1Ž“n‰±6FÆAX”‘1¨åŒ$AB¨l-0ÃRÔBŠV!"Œ¤¤ P!#)‚-u4_!P‘j,`ÅŸ_êÎÁpAÇm)h@'.ºjnîÙÃ>Õv½A ½Sm("!bBch‰C¬@M°%Ô^별B3ã`û‡NÉ"vTôsmöö㺲³×”„…QRN {AD‘!ìÛ‡ôllˆÍÍkTþE&˜SG]Ÿ¡º0±öô††€–\Z#\b»‰Œl2× ÷(–!„mùq€Q#+@†©Áú|ük.ë1ìb>f‘€ÆlÑú¬QjªGþœ4{S‚v!Ü©ÐÉ#*Îk¦Ü;Ç™¼•ÖòË©R™”/Ü]êµrѵ±hÖ„$ª@©!pil@züœ%Žü3¡í×Gù€Q‚¦1TšUw¸p̤B™GÓùtÙê˜K*Pt—Êo¤= ¸Kaõo÷~X¬¢TåÙ²¥-¦?§dW<`ã•Ìõ‰ºx¹¤Ý7Þ)ÿKóÕ¢4•/!Õª¡0#+Yš*¥07É«'È™ªà«Œò*Ðû÷üÛÎþÞ'#*’'×$;Â,–Ë<ª£™Î²ë‰ídçr§–þ«slsB߬>Ô;ZîãuÄt~—Ǻ)ã‚øaº õ=â¿òigW¯Pê!>æ#)샱š^(quÔ¨ryqTOŸ›´i6.Ý–ÝYíRñH„ªTwâšQlvróßµŒØ`çŠn=ÑÒ¬ÁŠ©fÞ¥ðsqÕq·0œ7%Üëª5ÓXô̪qĨÑuÃøUc2íÐ|oq@²°™‰$q8ܳ=U2Ím³òoq¼×Gnó»f–èœ<r¢!ÈfBž%PDËP„e[_9 Ž°œÔÏOG¹k\7#*BþU&à—<„?29æìÙM|®%l«õw^ò._Â`‚N"Dh}ZÒÜœ¥ŠYD’뢚M¬Ò:@$¹°¥6Á\œeuÂÝ[’QÉ7ÕnJèvv× G»rvY£Ü.Iå-@ûBŽHQ¶3üØHœh‘`1ÚÂ4]…A¼ÚwíÑA.Ü:.}Jmv"ÚÌJ/\-\L!$aŒ\f—ŸVXã«ëI§~Ûûg-Rí„㳨CˆÏ1î9ªn欄µŽ‡i*^ó€ÞG¿G{¼K2MçB±zT.W7/²cMž‘ÁrŽã˜÷×N|óÝ$"“Q?*y[„6"£ŠçÅƺ{Kñ“˜èô873C(!˜–ý¸Ï…ž%͵´äL¦â¹T®>{í§†ÛÍc&AÍ31oÄ#*\pׇ¦·ÒiÈþÿz„¦Fx ]YsCÊ—C¶é¦ žžI$;º/€O™å;•U›#ÆøQaÌ"Ç#*è`—cÄr6¦b˜#*•ì;w;è\kg#*Û/+6ÌkïSb1£‰Ä¬¹tRrÎËÛÂAÛŽõ2yÊîuëž-£1Y—¥˜fÕ>ùZï!¢•ÛºÚ#*¤êÛO9ž[ÿŸÒ·O¶%Öôq¹Ö’KÉ$òxÌÓFñÅ4šÓâ^’¾¹¨ïŒDˆtºwqHrd3'8¢÷Ýz|¨6È™)QÛmî¹\zá@êAqÙ=ˆ0zˆ¯Jè1žKRØ_—)îóŸLÅtï;RzŠâ»[ám8ƒ8ÏÕפ6îûe3®Züç´ç‰yÜOÏÜžý=#J£§G•ÞÕº›6de6 k›L£*YYã#+b®´JÚºró%Ò©#*YÕìð¼àywyï=pô¡'Fñèòª‹éïlgš/Ç=˜‘ašâô‡~U0›½Ë¾¿¹˜…æŽëÍ™{0àÞµ«ðyJçÚ|¹]‘—%•².IŒw‹ôõǯ ú;ö#*ü[–qØwb÷3ÍñÆåvXÂq²XÆÝiÅc8LŒiÓ%J'¼ÅŸ3Ís°ß4.¯Ör6žDtÃ6Êc™Mê,¦å³ÊØ~܈ðÕMŽNP¢PÒÞ²øs1¿fJºàeÞ©’tóŽ[hƼÜ|òTlŽ1'¼¶)˜'<u,áGf(kA2Ê”¸;¸[x„¸pņåÚjç’^Ä#*æ¤u鮡4Á³‘Â)1Üoáw$ÄfðV"³c³RëÏ!Î=Ôìb#6.†º¡»WQ G4¡Uš%5ãØ!šCäözà½t ;@©l¼ƒF1˜`èÀ:LØ”oìökAa†Ü+a˜2pu姃œ§è©<9Àzp±6Ìö¼Wœ:FÅ®]šp#+Aà pL·é@ÇM*ÆÆ7ƒpÜ}¡@Ü$É$gL"kØÎLCø*ó#)€@>#+ )„@#„Aµ#—-ãôqØlߣúqéwŒÁˆa¸s¸ã3¨iaHN(ç¼ÆFÞ§N‰]Fµ4:0ƒaš (@ˆ<eîg«÷h™YPš´º s2êâl¹‡7Œ5Î0£ðªµôFA5ÁèŠ ëDv·³[ØsJô|ÒríÜtm”NÜïí-Ï3ðìk½ÖÈ,½ÓÀüê2p‰øLäWÉJ™Â%g>ÙÁv„dym—9Ø8Õ³IÛ6£”˜¤*fíN²#+á*5®¼†¼¶¹®/32{ž\ûôŽU"Š©´¢*¦¦œøÄPQb§ë·,M—Äe²ÚzÁï]QÁk]9ÖÔ4nû““Œz‚FQWîíÀ¨LçßZKµ´óBŠý°Öüüû`c³5ÃIª4q“ç;B×u´o|€ï|»ñ-#™iå5Q½j×(Ãdvéxwu®g~E5´db‰#T@Ç/¥-lZð¶é/yÂŨáìPÌó¿Ä ^›4n´«5¨–™ß¼¹‹sN™¢xâö/-”¬kèíd͈¢:œòÑ£c·=ÊêÜXtõç牻\!œjãmú.;‘uWã´ ˜ÁÓ¨k vGMuË7%O¹¾‰Àºt¹n=r£©£uý˜«Ç¸Žny_6æYí»Îòæîü_XÕL0xNq]åÒÞ3—Ͷ•ßx™“GT·Ÿ#¼Tù8bW—‰öï‚o)Ä{ƒÉ›îº.<»ðr žr9Ô«T+OC*0Ñðúw-#+X”±÷4µ`#)Ï´½pžƒRñ˜Â¨†–ñ˜³ay£ê9r)ªàtY#Û‹Êp¨Ò§<8‹°ÞÐãUV¶{@þå™#*î7£'víÌÉòsƒð:á™»ÐüÍúŽ\h0,;¢â£}jålÿ<M¬)èÖv¢lC–aaÅí#§å„3¹f×.wK»Í¡C#+\Ù—c²Èô`Õ¤#*#+:o,ò1å.#ÂhŠ5.W!N岩«¨T0kÁG‘m=œL陋=Ô«I°j:º HJh¼²›Ó&·”Ø…—3˜ëP"ºÀ9O‹$åQìŒ]i-¥¼S¹ÐÓ6Ì2¨I#)š2·ˆ=¥÷Ï´Ý\IK#)}M@§£Ìþ%:û#*ÞŠÌÃÊÈ¥Å>e¸ˆAáb:·`PnQšßÚVù€¼t#*~Ê#*s¨òæ!tÛV\Äò~À g6û;Ã4q[1êUT4úŽuÝ-˜)1„ïëù‡Ì2òvÀ×ÁúC#*¡MR—_’°gÓί«U£Ñ#)£¨=idO8›Ã¬œû\vŸ2¶¨ÄY‡Í¥B,‹#)ü_ƒ`Õ…D–aí»Ímlš…s˜Ô±U%&F’b—uBDá Ø¢d SÌhXЂ6”c#I#*•‚U@’ ³x"–‚s@ˆACUkzVnkQZܵ•ÓlÖ(v¦R,ˆ ‡u‚¦¨5*2‚ Æ”TE#+Š2•($…FñÊ3='ð3ÆÄ-¬!™È#)É€ýÛ„p°R.Ú¼4$‚¢,g9¨¢§§+ÓxÛÆÜ‹“cm*µ¯Î¶[E«W-TkU^›•]{2×ô7#3t9Ô¿—…¥t~Í}×XñËe©ÐRÞ9Š±Œc`ÒÅ#+ÝD"5Ëçj4°{nmŽÚæðÍÀÖŒt†Ÿç1h‘]…2¸™÷Í*ŸvlëZq£U˜Ž'–±ÕÃ)f¼³M±A¤« ÊC‹*‚#H¯—z‘Þ2î›Æ³‘,"E#+´™º´Æ#*¸æÈaDÔi6›K’)a.ê+M1¢@%rÑQîSüO1#+|'X·u²¡ÒHW£>úlÀö›L#¢Ù7T€²`&5„Í81"Ìvî\¦jVãp#+1ØÆÝ{zÔ¦™Z;ñÎÖY½ÈÍMi¢ŠµMkTÈ7 glÓÔ–ÃZ±êts‹œÕ²·Ã ‚6Ò ¸È†<Á³‰`"Í3@ªÅŽÅ¥àÄVPË+m†IK_¦øÖ§<äîÝ£L…d39Nñ+;rDŽHcB÷Aê„@Ô ˜ãŒi÷cÅ]c®w¢ªC1¶ã!sR%à4²©Æ®eo˜iY2R³ .õ³7 —R‰ŒÚ›°Ý ±Ç·ÔV¹´¤IØ'tRÙ«#*wÍ4ç‹®¨.DÕ)l£|˜Dä4<ÿRãÞºÓÖ“cSˆ‚ò£œµ.¨CZF“Làèd¬q¨Ô"Ú7*ª#+”*à Ѹ”Ðá¤0m0m15+‹‹FÞn-¼™,²»zça›[ ¹tùÐC 2´CdT¨£]ž&09ÜEZÙ*å#*hFe¡›±—mÝF=]q›„DËš&Zþ㙢ðà•¬½ÍˆòÞа¨iSq—W²©U[UO$¼*7Ä®ôéif›:˜pÌw`ôäcL…"½®ûb†[¥cMUSW³E¥…(V›UÖ‚ÇZ1ŒÐµ¢r3LäÅ=š&g6Õ3rã<@Ê5Š±ÑÅ›òıqɦ3ËN•Um!C4@ŠÛý]éþ®ôQíj>«ÌÇÓ(£è Qˆ±¯sA_-š$u»)‚‹¯(h1êÄn#*`9ÐáŽe4<iäæ‰#+pôÛÅ…³)L8…Ù 4ÃV3<“m-÷aZ¸2ÈF;g›¸HÈmá&47,ÍÜJˆÔ4pɪ$bˆYžjÁ\̬Mnñ¢g%MfHT06™ %‰Tø¦r±$!htq`8XqƒFŠ\ŠX¬ï¬Ä5–tc`ÎÜqœ˜RcõÖ®“éxú’I/’>.¢v“O«æçñj¥,Hˆ,F#+Q؆ˆv2I-¾;Vè¾\üóþaüÝœae2m–MÓíÚ¿oe&¸}ývÝ®HIô®Ÿ9®;ÅÍóÂÕ'Øb ÒNÕSº¬fƵn¤1R˜ËnÏÞq(0‘UQ²»ÔR¯¹…=M5àÙ?G²5{©•ðšîà’O{Öx§9òPÕöv‡5ô b¨,åVÈe&8O—Ÿ°'êØ}`oìé#+2;GŸ«Ë×Užž/ždJpšÛ×'iäõµ±®‚¦ôh?wÆÿœöd£¬PlµR¸<³gÏÆos×n7„Œm#*H1É"a~öî€òrwnÍ›»žÿUdöÆXãá\÷<¹BùÊ= r;àƺi![k«ð„Hãƒ"ûðûŸÒÌge‰Ô<øOE¨÷7=ˆ`–•ènb¶ìÛIIWj™JBHF!6$‚#*V’`@H”*#+{ÐÕ€7~ÊÉ<Dz‡èân·m{»kׯ¿ùá¢ÄbÕ5CLµ¶ci1ŒLcH‰RPµL«ÒضKImX¤£lIY4hQM•F!›BšjF”›$£f”’¢41¦Ñ‰H–Œ¦h©M‘J¦Œ-$Ãl0Ù„JP’cV°AUoî7Þùôð/虨Ng°è:MHd)ì‹F]o9ÚÎÇÝ4Uy\ÐvðWçy9šÿ+È’3‡‡#)œêáßmzæ%r6ú®RNÙum´ƒ/Ràzñ@#+ mC À½jŒp%ÁV[1¶ÅîÂb[pÝÌ”‚Ù0eô}0~1xʲ@ûáks9QBF+ ¯nà>.AÀÜQÖtíêCÈ¢™FÌO>!¶òI!pNƒ]ä{ý9¢¿WQ¹éíŒÕF©©ˆNÜÙ~ʈ\ÛóÑ«µØæ§P#+š?ˆ3Vüm¨ÕD–Ù6ˆŠÀ˜RmcGÝZµÍ¦Æ¥#+MFŒkb3ð]«™VZ•ŠJ¤}ia, Ë¿À·€ÈÈB3(d…‡³"Ù›”Á÷Vtö`ÏŠá(TGaE¨i˜Œ7?,º5XÑ“‹§CªŠ82V)©#”˜ˆ¢Ûf#*UE"#+tå³FÉÐË!`#+@ÐqÅÜ“ I‰çÉ%±jouåݺvs^Þuyš1”×FLˆX#-(`£Ä%$¦ýÔ&j#+8EÁጠ¸»»Ä2‚lZ(à‚ ‘‘X‘—ªèøC¾÷µï>ê#*F“äá‘`rgÅäÁn¦.Ì´‰Jû©EˆÜ×I‘j#L!(ÊHRˆÏ:ÔÎn`ºÐü«b9×›1·›‘ŠU"tq‘aî!¡o@ƒ„Då0„Ä#ß!éon¬ #±©#kmA±¶(*¶kH‚"Àpä#+K†Hä[Å’D’I#€U†*!ëßѺLŽ@i¢d)Já£qKO5„ˆ^žÆÊz·±Ý‘ØB°WÛ#)ä{»¹8Æ~´¨žr†ÌçzdHFBÿn/ë~̉“ª:zjÙ¾^H%¡Ì{‘Ò‰ª¡ÓuËÖ:DŠx µ%BÉ„bce+kS4ñóó Bðæ›÷ì+C",dæö¢Ðñørðý«Òå1*í጗Yøxxã*Š7ßš™*¨¥K6×jãe%=WÞTŽwçLMKê”ãjÛD½CHÄŽºŒšW°Ø»øäûo#ÌÒ`=¦"Þ¦©œÝ[S[ÆÚdÊŠlA`‰£5%4ÝŠº [—Bë¯yZrµZ}^“×`ÕŸˆz8®Å6WÒœ“•®J5yžê¢Žìš<§ ¢ÀHƒ'¬ïàYÃN}GÕ}¾k±éøɹv±SIÏœ¾….b'zFIJ¡S‘ê5êOöflSÌÁ°ãºÀ¤ãcµØï/¬2B I£<ƒ3ÕÌTãŒwj7éV<ñ@M„Z¨þ?œ¨nìj“2`ÃîÝô#qõÀÊ%»¡ÐA÷{NqHR,’""#+©ƒO¤z¾©Gq1/±û5´mƒPq#à{ì=ØJaoÏ÷þǵÂGæÎ3†’x%Éôºkƒøþ¨Ù®{¹©d*ºh°À†U0ÚÝ\C’t€‡btÅ^~I;Lƒ ©XÕï=¡½;éòî/Ú#)'‡‰?e‰óh·ÂÙO;ʤÂA/˜”UÒ\yge)^±²=sDiù~{ÜãŒuñ¨õ#9d,™ÝÛÙ¬–"]Ò!ntr• #d+}å»»H¶»…†|Y°‰Jwa¢*®ˆ˜ž'*óƦxN#+š„G x„(€` Y#)wÄfAƒ‚€€jþSuVA/úB¢ hœäI†ù9Qw.äÖì뀰8e˜$R5)&Øn$”ŽÅpÉc#*Ò„ÚQF´Â¡0&¹9팈@ÂËÒp,@2ÎÔgõ,3cÎÍÊvÒAÓK‚Æ4‰"q“H¤·Ÿ—™Údœ:äK'[àY†˜l›µ¯K,䜒¡ãaF¼¨q¢*T©€p(6<ÏÚf`P1)‘5B08o±lÐE¤W”®<mlçaÁœ¤•\e!…‹uLîÖîFaÁ #*‰ X'W»¸ÁÇ$DHÉawÃn:vèïÁÅ®Õ(èÃLØå¼°€õ¢Éªt2BC¢#)bõ£[Þ+ËÅ>7Û—%È–úÁ’/‘ÒF~y¸v“‘»ÜE2"Ã97€š@³1-$TL NI‡…Õgl_éÿ’NVÛqÙÕLÊçÉ”ÌâçÌ|e‡—–¶ê)1ÂÉ>}ƒ~D°r¤àº×4¢ƒvkcõ#+Ä1e·2áƒnìмPÍÏ:"PÔ…$€uÜwÍZ…ƒ"À4d)/BV²b’ °Šg®q'^c«¹š5@·Iå¥lgºëÔ¬Çûµ^nÝŠœ3yzÞhõâ²¾#*3(I—#ƒ£ìíy`•p“HöXÈßlÄs 5‡…vA[ÄâñèØ韧—¾ü:fÓ½f4ˆÖò0æmg8pâÂpëàÓ$é˜3k:{OAŠ9 6q8v5´ÌNÂRd7m¶ÚX)‹‘Ê’(Lè®ZŠ1–”•¾cvLª4f\±ÖyíÃdɽ>ñ¡9²äLG&FæŽ%5í!¤Òžù8ÐdZ®{‘² Òvk)Ûm®š]ÊHŠg0ÑH6SDâK“;K—.žõeÖψ[m0Zyk.eŠF«—Mý:’-“_g|X™á[§pBsqáWbEºÁÇXÍñ4Æ´Nòò2bš-Mâ>‰£ŒÊ²Ã‚Y“‰†s-š00¹æ§ ¬S®pUœ1ízD©š½é¬S\¡åÐó‰¥Ëv'#*tÝ“ëˆJñs&âiÒtîÔ‹\sH`Za#*YxBË•ÉaVj¶»&àdKŒØZ{§pwreè¨âÈP·_.u«aw<‡×móMs±\œjJ݉€®oÕÞà{Þºg(ä*ær5Îih+BFìIJfÁÈ8¬#*¹ž\šÕåÓJ—)ÖÎ9‚Xw0rô :^¡¹ñ1–;õNå5âÓ!?'Ã*8;_}®fà´Žøk(D$N 6)ËC f•`ãf(i®»@;MX#+ÄRP„M#)Æ“¼)ÃS–´1jn¡®å·öÁºZHº+¤‚BN\¯…mgY¬ù%C]ÞÅV…@§„#*4ÑœèLkå#)¼»"È@x;vüe9§àcf¡øétR^›=k4Q&ªÉ=š‡“£{M¢æߊm‚ãb5éhÚÎÜæ.ƒ¦m#„Iøßíû¥öÙs.›"—!ybi¤ü|òqζò°ø#+ƒ„˜l×Ƨwu#)i×ÁÖ¯®ó\uK!®~~·¥Õ#ßrÌÈNz´ÉXÍQLÍ;T_!5qUŠÔ¾®èj齜&Ú7›ð, –FJMjfÁ‰LX|2ÜX[[ï˜#5…1 !#+ÆÃعb£á«0tÔLb 6Òê#+»#*àf… €é\&8æ¹>LJd†½áõÒw+mÆ4,¶(»ÜËuvèZ0¡ÉÄ (K(f…¤cn8é>{rko)Þ¨ †˜ij!¡A¡¦ ñÅàÇQ4ZsжÖ&&Ú¦‚,¸ÓÖß™®`—s¢ÙÅD^±Û•‘Êk;¦¸Ë ©MNNpŽËW4W*aÛ“€ëPÐ&~±×ŸX¼ £;ï¬Qažœv3†“atŸ¤&ïnɦ›ñ’ÃGåÐ캆„‹Yƒ®.ÏÙ®jß’ÁmáÌé1ðà ÞÅÄS{qßb: !0dG4lä]+T£p:5Ò‰‰™ù¤Žd‘A¶¢„HòCªhEáAFH"¸ªPÕ5“S¼–”ºÄ8:ðšÑ”a˜¬áÍ0QcLjNîºà<ÙSlð°;*0%DH!¹¡.æ¢ì+TК÷™‚Y0#*#*L#)ŒN’.jdë2#*¹¢‘ÔJŒØCSÕâ„5&²Ìš,•œMÃV6feŠ¨”`àQ®ç›ã:š½V™iE®Û]\Q$ÅÇxTÊ®:!Зz2*#*ˆ¢ÐlïC |ŒØ¸#aȪ#+v6f4šodADà ġ¾þdd„jÂҥ͕MŒ„P6' HD†€6NÃ4#+’0`éFp†Í$Á50J€uÑœQ´3#)€¦ˆÜ`Îq·é:Á# 2:ÎÚ@Æñ…¨Ø#+S&pÃI`³Øâˆ^0Àgi¢¢‘H±DŸByyôŸÆÖ9Fª”QQ`1¯Má#*áËcêð_PØ3{¹!Ö! &°U#+‚(tCïßú‹yì½€ñ:ŽUbÞTW òKóvÒ³S%Éùú¥gy3>Fø[JÞPÇðE£MÃ܇)üç|=º¾6¥MmºåTÞchS”uá÷H…s#3A7bÙÒÃ$†8lªŠ\¹$ r‘¯çK5òìé^zêäª õZˆ¿š º2˹DJöR* UzRƒÃåY†SAEB;4«€ö0ã×k4AüvïM2p#**¸J‰;’£2;Ë•"påp2‚‡24ŠP}öQ-çµ#*{4GâV‘}’&™2xäïvÇàÄms,:nÞ8§èÖ•ÔŒ8"s˜¨!š€´#*~°¨¬Pœ‚â—Ù›–Í,%ì5J¾Ø’ÓÑòWoÒxzœ¦BBLÉTEÅ£ÃÆ u/¨UL}*ˆ‘TöQ—_Àù)ÌèÏ„‰htß^ØìCÝ#)Àϲ m²²rè>d¼‚žå¤$uJ%U+'L,P`Æ¥#+5Q¡(ßÀäNN5J¦dÝÀ*v©Z0b#i`ˆŒ+q“µ¼ÒC&J-âjwÒÞní6ÒfH –$ÇH0Ž6BÉ#+AvaˆHX€i #Ôª i Z4(Ðû©3 IŽæG\“H2?=Ãjæ¸ï§(b¹«Â4jÂ%Ö…#34u*ÌÙbQ „GFùçÕ×;goˆCáwÚµîùј"rN€€YÈúc/è#*XA‘¬·“ŸEÚÛF'„j#)ðƒ¤Ì5™‘Í#+´4V%vH˜†Ja^0kbk‘‚ÚPƒ< ÜPžŽ€šÔäqÞÈ)¹ŽÁw²Ó¹óg1ç×g>ÈhÑÕQ4eU=jbʯ,È_Ýäô¸r²ÉÂ}¼C8~è¾&à·e†9/958ãMHÀîí¹lÔŸeV¸¥˜…Bóïq-ÊŸ(Ó…ÓkTÄMAÔˆÎ!²¢‘÷z†ž‘ÇN͸<WjH@ˆ×…sCaÆ—G#*5|zg¢ˆkLYŒ}ý»±†Ð^H`1…¯«ó£-²±db±'±(ùÎg<†½#*(É+€ZS{b”„ƒ$D÷ÁZE%³kZRmM÷z‘XDVBEGE„VìE—!F[L!‹3p„¸(·.(D€°B&´W¦#);#){róÈ¢‘¥H]2ÿ"ìCg~UËÐÞ!Õ‡vØ9Î,‘a0‘"HBê½ü;þˆt¾µ5*±c~qšï+‚‚ šþ8Û·áž*xp®ù¾¼o¤p€›6t†Ñth¼g#*`¡Þ»Ž¤Å½û9†³{[#‰AŽZHSÌ0Ѳ¨ ¦ÑÀ™,I6’åU¢›kÉo'žk».™gt¶ç;x«…×®óÊÛ”½ZÉY¦ëµd,Á*K4¢¬€“ŠœÍú®¡–fuHŠŽ¼d¦l‚®å,"l¹‘f™¥>Åìã›Ðz8½)a 1V=œÿÛKà6-h]s·1´†;&ælÐÉùgN¢ó#*‚˜ÏþÀìæÙ7ŽÀ6‘¹âQW"#)‘16ìã sôÔ…ß2½©g½Qfúö08D$Pu¨S @‘!2)#)Î&½Ü!0PGkT<†ìUZž,Ö–C¸œ„ÄŒ¥?ßãÃ;«¯»›h Wä§Ã0ü¯PÄ'xè(–¼e[Ì…´ÒУÆo8œJ-9—‡—:—ÂTãî8ùõ9ac©¡JñÝq›å.ÇòæBÀØhÓÇ=ÜD¡6“½ºgÑê× Ö}PQ:P€A©R†IJך'Œ|DÀ¸é,ü5øÃõóÑ_väŒVÈ éG/—’DˆÁR)›I©%¥–˜Åd” ª¶-f&Л(©1jÒmû«Œæº5‹¡Üï7Ä6ÏôÇ*¹df¾ÝhØw¨‡»¦oñšœÇD´ùÐÛéêæ#+¹ùÏo,8Ù‘dEÍŸ"6ONïãÒ{¶î( ìTìÚ{®™NB¼ÛfA$ŒÆŽ}÷âQê×s‡I*°Š74” +–Ô´½A#)ñ7ËáM´W®§!¦ÁjRÛCÍQÇH6Ù¦S¹3¿@0ÔÝ47 G²•Ë¹,O6PjàaWDÙ6fÑ ëEƒ·ÂDÉ&FZеŒ)ƒäuã˜á#*¤ÀÖRhIHnbítqVùsF?+#+ØÕ:âõ9Ê\1¶ÔìÀÑ€#+-–2[BU‹(nC- ¡u¡±ùõ»ÝÞˆ©ÁïT>1`!}î¦L˸Á,Å¥LPæìTkA¿ãV´0X³«Xpm/À°ûÙ“c"úYXS“ù2áÐèÆÄ`:û=/0l–Q{Šä³»¥#+P]¿%¸ï,‰B#ÚC¿‘„æ²tôâø:—L¯#+‰Ðð0"0!Ò1sUb©Ó¸èºXøú'ÃÌ¡¯FÿAÈÄ’K@9& *'IÞF/X¢£C^óXIÑ{ÒˆPE¤ä2t#+ž!o~Ãêíßêý;{‰ÞbG?>£9±žfÈìó¾Ó‡"v‹R6–fï=aE½ž;o=J±(#+<Q¿ŸÛÞ'¸wó·öC{÷ÉG=__sn»³c蚀‡U…ËÛIvÍ|í¡£©ÜÇ5ô…¾ÒŠ‡ˆ7ùE6sq@ ]à½4l±:»5Š¯/¦Š0$2c2<]FÄF&]ÕÐHl™¦WϼÃöû¶¹W79ëÍçž»³„‘²RŠl†¢ònæºyM£mãs\·Æ+»·‹yåv•¤æ¼É·ðV¡•v*Ÿ¼‘M‚@PÚe·gÏï;ü%U|Jøûlx˜/fzƒ¸’³TÂyšyßH)éP::ß4d#)„‘«(ÅIu´Þ=b!ŸQ ’A"ÈÂ)E’4²’©³jõùãQ¾î«÷wÌÒ#+4Cš¢¨Úi¦cm¯Çjvˆˆ&Il?“`l!¯êF¡+aêä\X]O#aM°GmBB.ò}ª*øJõ¦î¹²)±¬-f¬QQ£fF+X©”[,ž¼ïm&µ*mJmcª”E.õ#)½¸¢&¯÷øþüÔôö“Úùüs0ëÈ’w«ÞMzÀQ“Ú>gÇeL|ù•5\……~—YˆAòdż:Ä{‰ì#*XÎH.yÌ„Ê/yèòÌq좫ٻ°±…!"ŠN3ä?Ít €ž&ny¤À˜ÞB Q¶Äb‘pû oMýw#+‚€Û@ÖóAÖ¡ñÉ‘0Št§µZ€¡ ½!BŠS¼|·WFšÔ–Û¤Ö©¶¥"”’ ÐdÓdùé¨ 85¶Ù´˜U«)#*aJ€ë.•)ï)VE‡²Öe—Cý†¾Š¡÷GÇž4Æ!ûøkáaÃûŒ5†W§4°&âcÄ´LüVuÅ3Wch« ×ÒµÚ}èÁÆ€›M¢%Í 9ßjõ-òÀß&ÄÕ£è{Æ÷>rõÚ61ýT‘Ç+õ`ËÁ„{½?áWû@ ðWRC¤i„IŠSLJ“dj)lb¤Á¨ªM¶´oÕm¿#W‰°ÑZ(ÚM2€Ø•,ôôÛç[(ËD$#+B©‘„<ÔЫ |æØ@è*F…F&L(÷ÑMCfÒa`¡7ë@ïô}0ÏzíÙ/uÝ[imoçÔkWš±mF- Ú”5F„«6X‹X«RÆ „ø’3†:t6ù3·kiU–JHœËÆÿl}ð(€!£õÖX¦0Å.)E4¤»ÂƒžQFzžQ%Û馗àIôx$È«miGlþ'‡šYl홑#*€Å…„«‰9æí‚ÇûŸ=‡ECˆ&íÝWMãô-Öi54R ±4›a‰ˆ’&¢ª€4‚ÉéW%E¼ÝÖfì̪뛶¢®v ’Ùm^]ØÓDÚîêîêÒl©*dJlhV@U#*V$©ÉJ°ÁÀ·k¡¹o"o%i„^•ëˈµJil¦¤Ë*ôuo:º¼óWŠŠÊ3LÛe²–¼îå»]ۢ˗Mtšå®Üö©Ùšì˜HVØF€íÄZ´`&ÍOÜ5åUY¡t¤X²nBøQ’ñ°˜){Z6gªTÛW9d¢ck?žô™KhÍ¡ø¤ÊAT.F¨’oÅ#)9 vŽÝÎpéÓ\MÎp,ôi‚Ér{Qv~×/มpõBK°‘îˆyü7‡Ç0ôźsÛéŒI¼ž†Ú¶éƒ•)¶uF±±á¼·âBÝÚñË‘ñüȦF$Ç©CUR§WÊtÎÑoÎ÷¼QŒ-õx™˜zä)ØaöíådŠ(â¹E#8—…Á¾½Iâå¯â½„#)5:‘0î¡5$ÑÇÃ3U‘wà°þ̤—øæÍ8;x_°jùœþ©+.ëIéìcìE±<@yr#+RÕ!®*F<¾ÀÖ±ÛU‹foÕñŠÈ%£h¥G|6×U:žóPj” ~VoÜv•#*ñÞpÅ`×L‹ÝŸ¦žl“v›³ôhœKxP¼¿„³4pcoGê>ÖìâÌ ç7$ä5¦-XêI0TR'·!À4¶ª/pÖšÄëj hêa×»[0Qüá‘Élc·É#+Ù]©´±':µ@¶¤YzêÛÓ\ñJmå5ÓuÖÜŽWC%Û‡Ôq ä<e~äe"hóƒÉK©8>YãÉÈ[9Ï|Çîù¹‚Öè|l‡pYyL(7Æ|5NˆÞöÁò<-šX ýî8 M[‡Ñó.8#‰1YÚˆËÁäŒpÃ÷2\µ†{h$ìŠùÕ¼›Pnh Òþ¨6±ØEì’ºQÅæFÜn‹hÔ*ëǨïÆ…@ãƒ[8AÀÓ Êö;÷—çAÇÒ!"1OAªs¶Ü±2ÒȤ¦Qhšät Á‡-u1ßp–dl0Ày±»o¶£ï=(ð1Žäœl=¦¢ûEè9œG™È"¸=г™Úxû´2 os+:ίmåm=ÚŒí¯Êöý¾Ûgâç«TO®àd ¤úñ´ ýñ3ød„L¨-é¡ršCp…@C·Qü…Šã~Ï4ÉPUµƒÌóOftë#)OfYvë35Ãǵ^úUsb¡2ýë#) ?ýÉ$ÿâR†V¼wÎÕާцRÄÜá™íúN±LL§#)¤p`óõHŠo!Pv‘#*%η°S+VEÀö´2²Z¿@CbŽïQnóí¿—ŸØ÷;º‰$ 33çò¶U¿ÕwUðï$rφB@;3Õ©.í6ˆkC’2tBÚ9DmžG}ü/dp¬°‚uÇfý©é´ ¹ª¡mÒñ#*ÖâƒÕè'º/ÐŒÊ{†qäW„bA€µ|îÌ3ñ‹À;:hž÷d\:_ìÈ`Ï6l€Ctè~+—Ú³õ_Ëðò=íC‡’íLáCáÂ2éJêóøCxŠ#+,]d†'ŠD$í¯”‡oóUËrOü#*Ê7ãKýšÝe¥‰ˆL‡1Ò·Yàþs#5¯×Íà{R¦¤ˆo½)ž:Zef—Y#+¡¦†#+]”#*‡—šTÁŒ0ÙÿŠeTò´o[x÷ìÒÁ§îS¯sÅ#;µ^ûlÝÃL++UŒº¢X9aðiæ̦õ@£µ»G‡Ù¹4Ñ#)fÜkc•AšŠŽ°lÄa¦DÑ!vÕI„œ^$ö–l,—rA‚C šÔ6ú¼ú¼bÓ›Å#gw9h‚Ð„8ƒ+Þ^è†{Í:‡²¾~YŒ£ø&l&Ï6ì¹°ÙB¸©˜°w‰$Y#‹\ž{bò#)c.4£™èÇB#*ùLÏÇL<2t)«zׂƒ}vo …iÒ64k…³)Ü#+fì‰ÓÇL}2›îöB±³è h3‡œ^iIäqÝôac·F³U1]é.`AHŒIàˆ˜z†|ØK¸RCd0UÊñóüy=ûŸ#*¸ax1¥wfLò¹ƒ¶à‹ÏÛ³¯]×8óÔ,glÍ+P=X¢#+•ðÝÓÂâ™vÝf``3(HÈ&½®épØæ&‘V† ÷‹ „Pð:¢üìØPÄ‘@$HÁBHË´e!ÅÞAyð–á(8caÆ—Ð0û¿¸ŒÌáÿ{MÂüì;Œ¹Yݲ@XŒ DÀ'-t¨n`ºô6îébtÂ#+D„Õ´¤LjÄÔJƒlkY¥3[FÔm’¨ÌÒDÅ…‘S_;¶®Ú¨Ï::"füO˜Še#)úȇß#)/ΪZŠ·,Rزs=r€Ë‰M@±=ý?ÝãÉùÏÍ##*"¿L·¾k]O¥×¬Á¡ðcS9öɬצåU1Š#€•sóèèéüÍäÛ\ç•pè-Ü—uñËþëû¨mŸPÌïð€^¡Ë‹Žðl¤ïjoEwÊ [å%®ð†=Ç•N›æ7©¥<X?Íí럨N#+3ÉšgY,ØÕL#+š<³}<*¶j8# ©‹#*D'ÒáG½D᡽ÑqIâJò5–¿=7§ÈÙmJS{¦8r›W4 °RlÉ8²¢E…¡E]o¾×1±hø6ÜŒW¶ô£W²Õ½MTš6‚Õ{æµÌ@iªß ¦ë³°X6*<0Ý0HF ¤22OŒ#+÷¼7q²§ ¸q“¨(ÖêvعÜ8.ÝP³#+ЩÝ˸ǚ7áUÁbÇã*J9…¨DôÿÞ‹öA]Kƒ\‘dFnÅ+óýS·»êez=(îGSìä/"Œ ýl¸¨yͬPþÈŒŠ,X mv£¸íÔP§6kk%µ2šéÕ«³jú–&ÍI¯WѪ×Û$ѨªRÀäw³ÝðÌòúPÿõ)ª)£¿§ÑÑ;ü%c¦¦eò²Ó÷=g0@ÂfóxÈ{˜}íˆÈÿgÞ—‡ßýÀ€í €âïÂ&¼l=PH,Š#+,Ÿçò„Zÿ·žœÿ¾U'ú?¯"‡=d12„÷ÿÇô½>í·ñ6éx¹h?ÃÈþßëô~§iô/Ï㌻#*<Ú+:³qM:ãÉïøuЧ·Îä÷„ùG²y‹%ÞŸ_ŸˆàNøŒ÷§þV'—ˆÕûÄOAQä $»ùiwDüeàp#+?dYðêÉ×ÿ6•occ-3{(WQ6éÿ›Ø#³ÞUßæf'üuâ¥Ä”ù6Qû*Qþå³Ò»xœULà›çªáq–s¦ò8‡ÇÕ´éÛDè2²±ûye‰¼#pÅå°–7áá'ו´æ.ÇŸÁȬ2LMf¬yÙpx`HŠ$Y@zõïÔ=²Ù j‰ýÞÍÏ«_ŸûŸ©®E=Tg6(‡ÚgÝ-UŒF7°;·m¾Ïö™m÷Ž_—øy ¨ÿÿrE8P#*s† #<== -#-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEivIt5aBoIuNHTzxwSbTGfAUneqoFAl3aW3cACgkQSbTGfAUn\neqruqA//Y9oJ46ZR8W7YB/e45bfrYxGbN7NnkvkwSPNziObYur+n1QpQEOaPTn/U\n5kFtPWHXRJzaG/A9poKn7pl1Xd7Edcu1aalfoEazZbuD37VOxIp9lnrefCAeICqj\nGv0SD96Zac91CbA+b20Q4xnqxKMi3LSI4NPjfFGy62FkSk3MS4p6Rdp0/WAKwwNj\nw7WEjQCNmLb37z+FGSzXg28aljYeteBZEthsVmGJ5QqVwMBwgj2+y5FOTzFfxmqB\nrWgjFYS0l85kgYRZv9yzdNmFs5SScwafwpT8Xmdr49tFn/+0LxXyRxX+rdODgrpV\nY4EOiQz0fd6mMMnaTDXlLSXls3JyVYmbTjeNL/9gcHmnStzJ851CJQfyQg7A+JoC\nc7nz0HbiFyTgB+PUZr1OhGj3A7287o8XQ0tqR3oa7jXIOX0OynrGplMQKr++0jE1\nBgKzjLoE9CTbjkQfICLG+aUy3S1ZyDk/BcO+5+Ytbru+qXuDsIgAdVosMfNSv9jJ\nXvOINsbRMekdejYMZv8fIkn5OEjCFHVhNpobEsCb768bjB3p7alQGECBvjHCm6dy\nXZPzl9cBMWIXcBjPTS+GZj+PIXGcu76pbsx6HBHWf+uJ+4xgOsUCVu//0AV09jvA\n0MjtLWwQ8mdRH6Wt4hsp4HKtSvQrhmljf2OnuYBgaFmcdJkN1zI=\n=C0oT\n-----END PGP SIGNATURE-----\n +#-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEECzlystnjLqtCPS4PIr4MYv+/pUgFAmOxj14ACgkQIr4MYv+/\npUgg7A//X6agCAo9x3REEDFk4GTbW8nMkH7gD+ixNnMNcDF96pmp1f3Qdkm4DU19\nscpa1IPN5ik9xeU4Xs7+SifSlJrT1h9gj2bCFIPWWVlXjCXbn52mU4lijQ4iyaV7\nwLuD4ebG8UU9QK5gP1U2hERdTbkuOxuhQijTijDpfOuUnR1N5YoZmONszgYvYmAL\nr7Zr+Cuc+0HiEdsgMUabp1LTyY+urkZJoHcOTMe0QoyrTvM/CFgB4V3ppw9006VQ\nV4XdoAXEkNNfdJUE1s+4SrQxWT2AC2n9X7vjxbqNwfglzrujf862JrloOjybffdg\ngMPXwLpfT8TrVHFSs5aQK++8YhgwcgDz4Biqt/aq68iM424XnUYSwkzZTowGM/A7\nhyM7Jh+Mp/Of10pIx6PBbjjhbh3dH4OUtFv48uYLh1V95ICQ538UypMfBOK9mEPL\n8zpyTbQ8U873Ri+awOcpoJ4738gZNHAbEHZ3Ctr+g7eoayNlFMENG8bMrLwOkiUQ\nLZVXzNPtPs/OFe0rYu6okVONs8MLmuArnIy7v21Ti73Dtc4ABP6V4CFfc3AGqO+l\n3SmEb5r31h+iXvc4vdp33tESohxUFosIgMGjD8ZMyVFWy78wgp5I9qSbSPdVhl60\nF8WGX/ydvcf6D8NDZqjrsRyFtxKn6xLRQgUI+6DKsNLwRzJBVas=\n=mYk7\n-----END PGP SIGNATURE-----\n diff --git a/waf_libbsd.py b/waf_libbsd.py index 070d3eac..f1088584 100644 --- a/waf_libbsd.py +++ b/waf_libbsd.py @@ -180,16 +180,17 @@ class Builder(builder.ModuleManager): mandatory=False) elif configTest == 'library': for l in self.data['configure'][configTest][cfg]: - conf.check_cc(lib=l, - fragment=rtems.test_application(), - execute=False, - mandatory=False) + if conf.check_cc(lib=l, + fragment=rtems.test_application(), + execute=False, + mandatory=False): + conf.env['HAVE_%s' % l.upper()] = True else: bld.fatal('invalid config test: %s' % (configTest)) - section_flags = ["-fdata-sections", "-ffunction-sections"] - _add_flags_if_not_present(conf.env.CFLAGS, section_flags) - _add_flags_if_not_present(conf.env.CXXFLAGS, section_flags) - _add_flags_if_not_present(conf.env.LINKFLAGS, ["-Wl,--gc-sections"]) + section_flags = ["-fdata-sections", "-ffunction-sections"] + _add_flags_if_not_present(conf.env.CFLAGS, section_flags) + _add_flags_if_not_present(conf.env.CXXFLAGS, section_flags) + _add_flags_if_not_present(conf.env.LINKFLAGS, ["-Wl,--gc-sections"]) def build(self, bld): # @@ -538,17 +539,24 @@ class Builder(builder.ModuleManager): if 'header-paths' in config: headerPaths = config['header-paths'] cpu = bld.get_env()['RTEMS_ARCH'] - if cpu == "i386": - cpu = 'x86' for headers in headerPaths: - # Get the dest path - ipath = os.path.join(arch_inc_path, headers[2]) - start_dir = bld.path.find_dir(headers[0].replace('@CPU@', cpu)) - if start_dir != None: - bld.install_files("${PREFIX}/" + ipath, - start_dir.ant_glob(headers[1]), - cwd=start_dir, - relative_trick=True) + paths = [headers[0].replace('@CPU@', cpu)] + # Apply the path mappings + for source, targets in config['path-mappings']: + if source in paths: + i = paths.index(source) + paths.remove(source) + paths[i:i] = targets + + for hp in paths: + # Get the dest path + ipath = os.path.join(arch_inc_path, headers[2]) + start_dir = bld.path.find_dir(hp) + if start_dir != None: + bld.install_files("${PREFIX}/" + ipath, + start_dir.ant_glob(headers[1]), + cwd=start_dir, + relative_trick=True) bld.install_files(os.path.join("${PREFIX}", arch_inc_path, module_header_path), @@ -168,10 +168,6 @@ def options(opt): def bsp_configure(conf, arch_bsp): conf.check(header_name="dlfcn.h", features="c") conf.check(header_name="rtems/pci.h", features="c", mandatory=False) - if not rtems.check_posix(conf): - conf.fatal( - "RTEMS kernel POSIX support is disabled; configure RTEMS with --enable-posix" - ) if rtems.check_networking(conf): conf.fatal( "RTEMS kernel contains the old network support;" \ |