openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

phycommon.c (12323B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:    phycommon.c
      8  * Purpose: common infrastructure for the various phy methods, 
      9  * callback registrations, etc.
     10  */
     11 #include <soc/drv.h>
     12 #include <soc/debug.h>
     13 #include <soc/error.h>
     14 #include <soc/phyreg.h>
     15 
     16 #include <soc/phy.h>
     17 #include <soc/phy/phyctrl.h>
     18 #include <soc/phy/drv.h>
     19 
     20 typedef struct phycommon_info_s {
     21     /*
     22      * Reset overloading tables
     23      */
     24     soc_port_phy_reset_cb_t  phy_reset_default;
     25     soc_port_phy_reset_cb_t  phy_reset;
     26     void                    *phy_reset_arg;
     27     /*
     28      * Medium change notification tables
     29      */
     30     soc_port_medium_status_cb_t  medium_status_cb;
     31     void                        *medium_status_cb_arg;
     32 } phycommon_info_t;
     33 
     34 phycommon_info_t *pi[SOC_MAX_NUM_DEVICES];
     35 
     36 #define PHYCOMMON_INIT(unit) \
     37         if (pi[unit] == NULL) { return SOC_E_INIT; }
     38 
     39 /* Port translation call-back function */
     40 int (*soc_phy_cb_xlate_port_func)(int, int *);
     41 
     42 /*
     43  * Function:
     44  *      soc_phy_common_detach
     45  * Description:
     46  *      De-allocates memory and initializes data structures needed for common
     47  *      PHY code
     48  * Parameter:
     49  *      unit -- unit number
     50  * Returns:
     51  *      SOC_E_NONE
     52  *      SOC_E_MEMORY
     53  */
     54 int
     55 soc_phy_common_detach(int unit)
     56 {
     57     sal_free(pi[unit]);
     58     pi[unit] = NULL;
     59     return SOC_E_NONE;
     60 }
     61 
     62 /*
     63  * Function:
     64  *      soc_phy_common_init
     65  * Description:
     66  *      Allocates memory and initializes data structures needed for common
     67  *      PHY code
     68  * Parameter:
     69  *      unit -- unit number
     70  * Returns:
     71  *      SOC_E_NONE
     72  *      SOC_E_MEMORY
     73  */
     74 int
     75 soc_phy_common_init(int unit)
     76 {
     77     if (pi[unit] == NULL) {
     78         pi[unit] = sal_alloc(sizeof(phycommon_info_t) * SOC_MAX_NUM_PORTS,
     79                              "phycommon_info");
     80         if (pi[unit] == NULL) {
     81             return SOC_E_MEMORY;
     82         }
     83     }
     84 
     85     sal_memset(pi[unit], 0, sizeof(phycommon_info_t) * SOC_MAX_NUM_PORTS);
     86     return SOC_E_NONE;
     87 }
     88 
     89 /*
     90  * Function:
     91  *      soc_phy_cb_xlate_port
     92  * Description:
     93  *      Provides port translation for API call-backs
     94  * Parameter:
     95  *      unit -- unit number
     96  *      port -- port number to be translated
     97  * Returns:
     98  *      SOC_E_xxx
     99  */
    100 int
    101 soc_phy_cb_xlate_port(int unit, int *port)
    102 {
    103     if (soc_phy_cb_xlate_port_func != NULL) {
    104         return soc_phy_cb_xlate_port_func(unit, port);
    105     }
    106     return SOC_E_NONE;
    107 }
    108 
    109 /* 
    110  * Function:
    111  *      soc_port_phy_reset_register
    112  * Description:
    113  *      Register a callback function to be called whenever a PHY driver
    114  *      needs to perform a PHY reset 
    115  * Parameters:
    116  *      unit      - Device number
    117  *      port      - port number
    118  *      callback  - The callback function to call
    119  *      user_data - An opaque cookie to pass to callback function 
    120  *                  whenever it is called
    121  *      reg_default -- This parameter should be set to TRUE when a default 
    122  *                     reset function is being registered from _bcm_port_init
    123  * Returns:
    124  *      SOC_E_NONE
    125  *      SOC_E_PARAM       -- Bad {unit, port} combination
    126  *      SOC_E_NOT_FOUND   -- The specified {unit, port, callback, user_data} 
    127  *                           combination have not been registered before
    128  * Notes:
    129  *      The function registers the reset function for the PHY. During the 
    130  *      system initialization, the function will be used to register the
    131  *      original, PHY-specific reset function (this will be a standard 
    132  *      phy_fe_ge_reset() or phy_null_reset function) with the reg_default
    133  *      parameter set to TRUE. The user_data parameter will be ignored in this
    134  *      case.
    135  *      Then the user can register another reset function if he wants to (with 
    136  *      reg_default = 0).
    137  *      This allows us to provide support for the customers that want to do 
    138  *      additional PHY programming at the reset time.
    139  *
    140  *      The curent implementation allows to register only one callback per 
    141  *      {unit, port}
    142  */
    143 int
    144 soc_phy_reset_register(int                      unit, 
    145                        soc_port_t               port, 
    146                        soc_port_phy_reset_cb_t  callback,
    147                        void                    *user_data,
    148                        int                      reg_default)
    149 {
    150     int rv;
    151     phycommon_info_t *pip;
    152 
    153     PHYCOMMON_INIT(unit);
    154 
    155     pip = &pi[unit][port];
    156 
    157     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    158         (0 <= port && port < SOC_MAX_NUM_PORTS) &&
    159         callback != NULL) {
    160         if (reg_default) {
    161             pip->phy_reset_default = callback;
    162             rv = SOC_E_NONE;
    163         } else {
    164             if (pip->phy_reset == NULL ) {
    165                 pip->phy_reset     = callback;
    166                 pip->phy_reset_arg = user_data;
    167                 rv  = SOC_E_NONE;
    168             } else {
    169                 if (pip->phy_reset == callback && 
    170                     pip->phy_reset_arg == user_data) {
    171                     rv = SOC_E_EXISTS;
    172                 } else {
    173                     rv = SOC_E_FULL;
    174                 }
    175             }
    176         }
    177     } else {
    178         rv = SOC_E_PARAM;
    179     }
    180     
    181     return (rv);
    182 }
    183 
    184 /* 
    185  * Function:
    186  *      soc_port_phy_reset_unregister
    187  * Description:
    188  *      Unregister a callback function to be called whenever a PHY driver
    189  *      needs to perform a PHY reset 
    190  * Parameters:
    191  *      unit      - Device number
    192  *      port      - port number
    193  *      callback  - The callback function to call
    194  *      user_data - An opaque cookie to pass to callback function 
    195  *                  whenever it is called
    196  * Returns:
    197  *      SOC_E_NONE
    198  *      SOC_E_PARAM       -- Bad {unit, port} combination
    199  *      SOC_E_NOT_FOUND   -- The specified {unit, port, callback, user_data} 
    200  *                           combination have not been registered before
    201  *      SOC_E_EXISTS      -- The same callback function with the same parameter
    202  *                           have already been registered
    203  * Notes:
    204  *      This function verifies that the specified callback has really been
    205  *      registered before.
    206  */
    207 int
    208 soc_phy_reset_unregister(int                      unit, 
    209                          soc_port_t               port, 
    210                          soc_port_phy_reset_cb_t  callback,
    211                          void                    *user_data)
    212 {
    213     int rv;
    214     phycommon_info_t *pip;
    215 
    216     PHYCOMMON_INIT(unit);
    217 
    218     pip = &pi[unit][port];
    219 
    220 
    221     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    222         (0 <= port && port < SOC_MAX_NUM_PORTS)) {
    223         if ((pip->phy_reset == callback) &&
    224             (pip->phy_reset_arg == user_data)) {
    225             pip->phy_reset     = NULL;
    226             pip->phy_reset_arg = NULL;
    227             rv  = SOC_E_NONE;
    228         } else {
    229             rv = SOC_E_NOT_FOUND;
    230         }
    231     } else {
    232         rv = SOC_E_PARAM;
    233     }
    234     
    235     return (rv);
    236 }
    237 
    238 /* 
    239  * Function:
    240  *      soc_phy_reset
    241  * Description:
    242  *      This functions is called to perform the device reset using the reset
    243  *      callback function(s) previously registered with soc_phy_reset_register.
    244  * Parameters:
    245  *      unit -- Device number
    246  *      port -- Port number
    247  * Returns:
    248  *      SOC_E_XXX
    249  * Note:
    250  *      During system initialization the code actually registers the original
    251  *      PHY reset function. It will be called unless the user had registered
    252  *      another reset function.
    253  */
    254 int
    255 soc_phy_reset(int unit, soc_port_t port)
    256 {
    257     int rv;
    258     phycommon_info_t *pip;
    259 
    260     PHYCOMMON_INIT(unit);
    261 
    262     pip = &pi[unit][port];
    263 
    264 
    265     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    266         (0 <= port && port < SOC_MAX_NUM_PORTS)) {
    267         if (pip->phy_reset == NULL) {
    268             if (pip->phy_reset_default != NULL) {
    269                 rv = pip->phy_reset_default(unit, port, NULL);
    270             } else {
    271                 rv = SOC_E_INTERNAL;
    272             }
    273         } else {
    274             soc_phy_cb_xlate_port(unit, &port);
    275             rv = pip->phy_reset(unit, port, pip->phy_reset_arg);
    276         }
    277     } else {
    278         rv = SOC_E_PARAM;
    279     }
    280     
    281     return (rv);
    282 }
    283 
    284 /* 
    285  * Function:
    286  *      soc_phy_medium_status_register
    287  * Description:
    288  *      Register a callback function to be called on medium change event
    289  * Parameters:
    290  *      unit      - Device number
    291  *      port      - port number
    292  *      callback  - The callback function to call
    293  *      user_data - An opaque cookie to pass to callback function 
    294  *                  whenever it is called
    295  * Returns:
    296  *      SOC_E_NONE
    297  *      SOC_E_PARAM  -- NULL function pointer or bad {unit, port} combination
    298  *      SOC_E_FULL   -- Cannot register more than 1 callback per {unit, port}
    299  *      SOC_E_EXISTS -- The same callback function with the same parameter 
    300  *                      have already been registered
    301  * Notes:
    302  *      The current implementation supports only one callback function per
    303  *      {unit, port}
    304  */
    305 int
    306 soc_phy_medium_status_register(int                          unit, 
    307                                soc_port_t                   port, 
    308                                soc_port_medium_status_cb_t  callback,
    309                                void                        *user_data)
    310 {
    311     int rv;
    312     phycommon_info_t *pip;
    313 
    314     PHYCOMMON_INIT(unit);
    315 
    316     pip = &pi[unit][port];
    317 
    318 
    319     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    320         (0 <= port && port < SOC_MAX_NUM_PORTS) &&
    321         callback != NULL) {
    322         if (pip->medium_status_cb == NULL) {
    323             pip->medium_status_cb     = callback;
    324             pip->medium_status_cb_arg = user_data;
    325             rv = SOC_E_NONE;
    326         } else {
    327             if (pip->medium_status_cb == callback  &&
    328                 pip->medium_status_cb_arg == user_data) {
    329                 rv = SOC_E_EXISTS;
    330             } else {
    331                 rv = SOC_E_FULL;
    332             }
    333         }
    334     } else {
    335         return SOC_E_PARAM;
    336     }
    337     
    338     return (rv);
    339 }
    340 
    341 /* 
    342  * Function:
    343  *      soc_phy_medium_status_unregister
    344  * Description:
    345  *      Unegister a callback function to be called on medium change event
    346  * Parameters:
    347  *      unit      - Device number
    348  *      port      - port number
    349  *      callback  - The callback function to call
    350  *      user_data - An opaque cookie to pass to callback function 
    351  *                  whenever it is called
    352  * Returns:
    353  *      SOC_E_NONE
    354  *      SOC_E_PARAM       -- Bad {unit, port} combination
    355  *      SOC_E_NOT_FOUND   -- The specified {unit, port, callback, user_data} 
    356  *                           combination have not been registered before
    357  */
    358 int
    359 soc_phy_medium_status_unregister(int                          unit, 
    360                                  soc_port_t                   port, 
    361                                  soc_port_medium_status_cb_t  callback,
    362                                  void                        *user_data)
    363 {
    364     int rv;
    365     phycommon_info_t *pip;
    366 
    367     PHYCOMMON_INIT(unit);
    368 
    369     pip = &pi[unit][port];
    370 
    371     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    372         (0 <= port && port < SOC_MAX_NUM_PORTS)) {
    373         if ((pip->medium_status_cb == callback) &&
    374             (pip->medium_status_cb_arg == user_data)) {
    375             pip->medium_status_cb     = NULL;
    376             pip->medium_status_cb_arg = NULL;
    377             rv = SOC_E_NONE;
    378         } else {
    379             rv = SOC_E_NOT_FOUND;
    380         }
    381     } else {
    382         return SOC_E_PARAM;
    383     }
    384     
    385     return (rv);
    386 }
    387 
    388 /*
    389  * Function:
    390  *      soc_phy_medium_status_notify
    391  * Description:
    392  *      This function is used to invoke the callback(s) registered via 
    393  *      soc_phy_medium_status_register(). 
    394  * Parameters:
    395  *      unit   -- Device number
    396  *      port   -- Port number
    397  *      medium -- New active medium
    398  * Returns:
    399  *      Nothing
    400  */
    401 void
    402 soc_phy_medium_status_notify(int unit, soc_port_t port,
    403                              soc_port_medium_t medium)
    404 {
    405     phycommon_info_t *pip;
    406 
    407     /*
    408      * Since this function returns void, we can't use PHYCOMMON_INIT check 
    409      * here. Replace it with an explicit one
    410      */
    411     if (pi[unit] == NULL) {
    412         return;
    413     }
    414 
    415     pip = &pi[unit][port];
    416 
    417     if ((0 <= unit && unit < SOC_MAX_NUM_DEVICES) && 
    418         (0 <= port && port < SOC_MAX_NUM_PORTS) &&
    419         pip->medium_status_cb != NULL) {
    420         pip->medium_status_cb(unit, port, medium, pip->medium_status_cb_arg);
    421     }
    422 }