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

pciutil.c (12048B)


      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:    internal_stack.c
      8  *
      9  * Purpose: 
     10  *
     11  * Functions:
     12  *      esw_init_pci
     13  *      set_ext_stack_pciconfig
     14  *      ks_pci_info_setup
     15  *
     16  *      _bcm_ptp_write_ks_uint32
     17  *      _bcm_ptp_read_ks_uint32
     18  *      _bcm_ptp_write_pcishared_uint32
     19  *      _bcm_ptp_read_pcishared_uint32
     20  *      _bcm_ptp_write_pcishared_uint8
     21  *      _bcm_ptp_read_pcishared_uint8
     22  */
     23 
     24 #if defined(INCLUDE_PTP)
     25 #include <sal/types.h>
     26 #include <sal/core/spl.h>
     27 #include <sal/core/libc.h>
     28 #include <soc/types.h>
     29 #include <soc/cm.h>
     30 #include <soc/cmext.h>
     31 #include <soc/defs.h>
     32 #include <soc/drv.h>
     33 #include <assert.h>
     34 
     35 #if defined(PTP_KEYSTONE_STACK)
     36 #ifndef __KERNEL__
     37 #include <errno.h>
     38 #include <fcntl.h>
     39 #include <sys/mman.h>
     40 #include <unistd.h>
     41 #endif
     42 
     43 #include <bcm/ptp.h>
     44 #include <bcm/error.h>
     45 #include <bcm_int/common/ptp.h>
     46 
     47 #ifdef BCM_PTP_SWAP_PCIENDIAN
     48   #define PCI_SWAP(x) (((x & 0xFF000000) >> 24) | \
     49                         ((x & 0x00FF0000) >> 8) | \
     50                         ((x & 0x0000FF00) << 8) | \
     51                         ((x & 0x000000FF) << 24))
     52 
     53 #else
     54   #define PCI_SWAP(x) (x)
     55 #endif
     56 
     57 /* For each Keystone TOP, we keep the information needed to do PCIe shared
     58  *   memory reads & writes:
     59  */
     60 typedef struct _bcm_esw_ptp_pci_info_s {
     61     sal_vaddr_t host_membase;   /* window base address in host's address space */
     62     uint32 device_membase;      /* window base address in TOP device's address space */
     63     uint32 pci_dev_idx;         /* PCIe device index */
     64 } _bcm_esw_ptp_pci_info_t;
     65 
     66 /* While Keystone TOP's are directly connected to the host via PCIe, they also have an associated Unit, and
     67  * a stack number within that unit.  So the maximum that we can support is BCM_MAX_NUM_UNITS * PTP_MAX_STACKS_PER_UNIT
     68  *
     69  * After enumerating a given Keystone/BCM53903, the information is stored here:
     70  */
     71 _bcm_esw_ptp_pci_info_t _bcm_esw_ptp_pci_info[BCM_MAX_NUM_UNITS * PTP_MAX_STACKS_PER_UNIT] = {{0}};
     72 
     73 /* A lock has been introduced to prevent concurrent execution of keystone
     74  * shared memory access(read/write) through pci by any other task during
     75  * PTP initialisation.Otherwise this leads to box crash.
     76  */
     77 _bcm_ptp_mutex_t pcibus_mutex = 0;
     78 
     79 /* Function pointer for PCI configuration function: */
     80 bcm_ptp_pci_setconfig_t esw_pciconfig_func = (bcm_ptp_pci_setconfig_t)0;
     81 
     82 /* Wrapper that uses esw_pciconfig_func if set, else soc_cm_pci_conf_write */
     83 int set_ext_stack_pciconfig(int idx, uint32 pciconfig_register, uint32 value);
     84 
     85 static int create_mutex_if_needed(void)
     86 {
     87     if (!pcibus_mutex) {
     88         if (!(pcibus_mutex = _bcm_ptp_mutex_create("ToP PCI access mutex"))) {
     89             pcibus_mutex = 0;
     90             return BCM_E_MEMORY;
     91         }
     92     }
     93     return BCM_E_NONE;
     94 }
     95 
     96 int ks_pci_info_setup(int ks_num);
     97 
     98 /*
     99  * Function:
    100  *      esw_set_pci_config_func
    101  * Purpose:
    102  *      Can be used to override set_ext_stack_pciconfig() as the
    103  *      function called to set PCI configuration memory
    104  * Parameters:
    105  *      pci_setconfig - (IN) The function to be used to set PCI configuration memory
    106  * Returns:
    107  *      BCM_E_xxx
    108  * Notes:
    109  */
    110 
    111 int esw_init_pci (bcm_ptp_pci_setconfig_t pci_setconfig)
    112 {
    113     int rv = create_mutex_if_needed();
    114     if (rv) {
    115         return rv;
    116     }
    117 
    118     esw_pciconfig_func = pci_setconfig;
    119     return BCM_E_NONE;
    120 }
    121 
    122 int _bcm_ptp_ext_stack_lock_pci(void)
    123 {
    124     int rv = create_mutex_if_needed();
    125     if (rv == BCM_E_NONE) {
    126         /* Since passing -1(mutex wait forever) will lead to _bcm_ptp_mutex_take() failure,
    127          * 2 secs(much more than PTP initialisation duration) time out for mutex is used.
    128          */
    129         rv = _bcm_ptp_mutex_take(pcibus_mutex, 2000000);
    130     }
    131 
    132     return rv;
    133 }
    134 
    135 int _bcm_ptp_ext_stack_unlock_pci(void)
    136 {
    137     return _bcm_ptp_mutex_give(pcibus_mutex);
    138 }
    139 
    140 
    141 /*
    142  * Function:
    143  *      _bcm_ptp_write_ks_uint32
    144  * Purpose:
    145  *      Write a word to PCI shared memory for a given indexed TOP
    146  * Parameters:
    147  *      idx     - (IN) index of Keystone TOP
    148  *      addr    - (IN) address to write to
    149  *      val     - (IN) value to write
    150  * Returns:
    151  *      BCM_E_NONE
    152  * Notes:
    153  *      used for _bcm_ptp_stack_info_t->writed_fn
    154  */
    155 int _bcm_ptp_write_ks_uint32(int idx, uint32 addr, uint32 val)
    156 {
    157     uint32 new_window_base = (addr & 0xfffff000);
    158     uint32 offset = (addr - new_window_base) / sizeof(uint32);
    159     volatile uint32 *mapped_base;
    160     int spl;
    161 
    162     int rv = create_mutex_if_needed();
    163     if (rv) {
    164         return rv;
    165     }
    166 
    167     if ((rv =_bcm_ptp_mutex_take(pcibus_mutex, 2000000)) != BCM_E_NONE) {
    168         return rv;
    169     }
    170 
    171     rv = ks_pci_info_setup(idx);
    172     if (rv != BCM_E_NONE) {
    173         return rv;
    174     }
    175 
    176     mapped_base = (volatile uint32 *)UINTPTR_TO_PTR(_bcm_esw_ptp_pci_info[idx].host_membase);
    177 
    178     val = PCI_SWAP(val);
    179     spl = sal_splhi();
    180 
    181     if (_bcm_esw_ptp_pci_info[idx].device_membase != new_window_base) {
    182         _bcm_esw_ptp_pci_info[idx].device_membase = new_window_base;
    183         rv = set_ext_stack_pciconfig(idx, 0x80, new_window_base);
    184     }
    185     if (rv == BCM_E_NONE) {
    186         mapped_base[offset] = val;
    187     }
    188 
    189     sal_spl(spl);
    190 
    191     _bcm_ptp_mutex_give(pcibus_mutex);
    192     return 0;
    193 }
    194 
    195 /*
    196  * Function:
    197  *      _bcm_ptp_read_ks_uint32
    198  * Purpose:
    199  *      Read a word from PCI shared memory for a given indexed TOP
    200  * Parameters:
    201  *      idx     - (IN) index of Keystone TOP
    202  *      addr    - (IN) address to read from
    203  *      value   - (OUT) value read
    204  * Returns:
    205  *      BCM_E_NONE
    206  * Notes:
    207  *      used for _bcm_ptp_stack_info_t->read_fn
    208  */
    209 int _bcm_ptp_read_ks_uint32(int idx, uint32 addr, uint32 *value)
    210 {
    211     uint32 new_window_base = (addr & 0xfffff000);
    212     uint32 offset = (addr - new_window_base) / sizeof(uint32);
    213     volatile uint32 *mapped_base;
    214     int rv = create_mutex_if_needed();
    215     if (rv) {
    216         return rv;
    217     }
    218 
    219     rv = ks_pci_info_setup(idx);
    220     if (rv != BCM_E_NONE) {
    221         return rv;
    222     }
    223 
    224     mapped_base = (volatile uint32 *)UINTPTR_TO_PTR(_bcm_esw_ptp_pci_info[idx].host_membase);
    225 
    226     if (_bcm_ptp_mutex_take(pcibus_mutex, 2000000)) {
    227         return BCM_E_INTERNAL;
    228     }
    229 
    230     int spl = sal_splhi();
    231 
    232     if (_bcm_esw_ptp_pci_info[idx].device_membase != new_window_base) {
    233         _bcm_esw_ptp_pci_info[idx].device_membase = new_window_base;
    234         rv = set_ext_stack_pciconfig(idx, 0x80, new_window_base);
    235     }
    236     if (rv == BCM_E_NONE) {
    237         *value = mapped_base[offset];
    238     }
    239 
    240     sal_spl(spl);
    241     _bcm_ptp_mutex_give(pcibus_mutex);
    242 
    243     *value = PCI_SWAP(*value);
    244 
    245     return rv;
    246 }
    247 
    248 
    249 int set_ext_stack_pciconfig(int idx, uint32 pciconfig_register, uint32 value) {
    250     if (esw_pciconfig_func) {
    251         esw_pciconfig_func(_bcm_esw_ptp_pci_info[idx].pci_dev_idx, pciconfig_register, value);
    252     } else {
    253         soc_cm_pci_conf_write(_bcm_esw_ptp_pci_info[idx].pci_dev_idx, pciconfig_register, value);
    254     }
    255     return 0;
    256 }
    257 
    258 /* Enumerate the given Keystone on the PCI bus */
    259 int ks_pci_info_setup(int ks_num)
    260 {
    261     int dev;
    262     uint16 dev_id;
    263     uint8 rev_id;
    264     int dev_count;
    265     int ks_count = 0;
    266     int rv = BCM_E_NONE;
    267 
    268     /* If we've already found this TOP via enumeration, just return */
    269     if (_bcm_esw_ptp_pci_info[ks_num].host_membase != 0) {
    270         return BCM_E_NONE;
    271     }
    272 
    273     if (soc_cm_device_supported(BCM53000PCIE_DEVICE_ID,
    274             BCM53000_A0_REV_ID)) {
    275         LOG_ERROR(BSL_LS_BCM_PTP,
    276                   (BSL_META("Keystone device not supported\n")));
    277         return BCM_E_UNAVAIL;
    278     }
    279 
    280     dev_count = soc_cm_get_num_devices();
    281     for (dev = 0; dev < dev_count; dev++) {
    282         dev_id = 0;
    283         rev_id = 0;
    284         soc_cm_get_id(dev, &dev_id, &rev_id);
    285         if (dev_id == BCM53000PCIE_DEVICE_ID) {
    286             if (ks_count == ks_num) {
    287                 /* This is the Keystone we want */
    288 
    289                 /* cache the PCI device index */
    290                 _bcm_esw_ptp_pci_info[ks_num].pci_dev_idx = dev;
    291 
    292                 /* cache the base address for future operations */
    293                 _bcm_esw_ptp_pci_info[ks_num].host_membase = soc_cm_get_base_address(dev);
    294 
    295                 /* Set the window base to zero */
    296                 _bcm_esw_ptp_pci_info[ks_num].device_membase = 0;
    297                 rv = set_ext_stack_pciconfig(ks_num, 0x80, 0);
    298 
    299                 /*Update  Command/Status (0x4) <- 0x00100146 */
    300                 return rv;
    301             }
    302             ks_count++;
    303         }
    304     }
    305     return BCM_E_FAIL;
    306 }
    307 
    308 
    309 /*
    310  * Function:
    311  *      _bcm_ptp_write_pcishared_uint32
    312  * Purpose:
    313  *      Write a word to PCI shared memory
    314  * Parameters:
    315  *      cookie  - (IN) indicates the KS that we will write to
    316  *      addr    - (IN) address to write to
    317  *      val     - (IN) value to write
    318  * Returns:
    319  *      BCM_E_NONE
    320  * Notes:
    321  *      used for _bcm_ptp_stack_info_t->writed_fn
    322  */
    323 int _bcm_ptp_write_pcishared_uint32(void *cookie, uint32 addr, uint32 val)
    324 {
    325     return _bcm_ptp_write_ks_uint32(PTR_TO_INT(cookie), addr, val);
    326 }
    327 
    328 /*
    329  * Function:
    330  *      _bcm_ptp_read_pcishared_uint32
    331  * Purpose:
    332  *      Read a word from PCI shared memory
    333  * Parameters:
    334  *      cookie  - (IN) PCI memory base
    335  *      addr    - (IN) address to read from
    336  *      value   - (OUT) value read
    337  * Returns:
    338  *      BCM_E_NONE
    339  * Notes:
    340  *      used for _bcm_ptp_stack_info_t->read_fn
    341  */
    342 int _bcm_ptp_read_pcishared_uint32(void *cookie, uint32 addr, uint32 *value)
    343 {
    344     return _bcm_ptp_read_ks_uint32(PTR_TO_INT(cookie), addr, value);
    345 }
    346 
    347 
    348 /* /\* Note, this implementation can be optimized if it is known that 8-bit accesses *\/ */
    349 /* /\*   via PCI shared memory work correctly.  This is meant to be a                *\/ */
    350 /* /\*   lowest-common-denominator portable version.                                 *\/ */
    351 void _bcm_ptp_write_pcishared_uint8(bcm_ptp_external_stack_info_t *stack_p, uint32 addr, uint8 val)
    352 {
    353     uint32 aligned_addr = (addr & 0xfffffffc);
    354     uint32 orig_word;
    355     unsigned shift;
    356     uint32 masked_word;
    357     uint32 new_word;
    358 
    359     stack_p->read_fn(stack_p->cookie, aligned_addr, &orig_word);
    360 
    361     /* Find shift needed to put the low byte of the word into the desired position */
    362     /* BCM53903 is big-endian, so first byte (offset 0) has shift 24,              */
    363     /*    last byte (offset 3) has shift 0                                         */
    364     shift = 8 * (3 - (addr - aligned_addr));
    365 
    366     masked_word = orig_word & ~(0xff << shift);
    367     new_word = masked_word | (((uint32)val) << shift);
    368 
    369     stack_p->write_fn(stack_p->cookie, aligned_addr, new_word);
    370 }
    371 
    372 
    373 /* Note, this implementation can be optimized if it is known that 8-bit accesses */
    374 /*   via PCI shared memory work correctly.  This is meant to be a                */
    375 /*   lowest-common-denominator portable version.                                 */
    376 uint8 _bcm_ptp_read_pcishared_uint8(bcm_ptp_external_stack_info_t *stack_p, uint32 addr)
    377 {
    378     uint32 aligned_addr = (addr & 0xfffffffc);
    379     uint32 value32;
    380     unsigned shift;
    381     uint8 ret;
    382 
    383     stack_p->read_fn(stack_p->cookie, aligned_addr, &value32);
    384 
    385     /* Find shift needed to put the low byte of the word into the desired position */
    386     /* BCM53903 is big-endian, so first byte (offset 0) has shift 24,              */
    387     /*    last byte (offset 3) has shift 0                                         */
    388     shift = 8 * (3 - (addr - aligned_addr));
    389     ret = value32 >> shift;
    390 
    391     return ret;
    392 }
    393 
    394 
    395 /* void _bcm_ptp_read_pcishared_uint8_aligned_array(bcm_ptp_external_stack_info_t *stack_p, uint32 addr, uint8 * array, int array_len) */
    396 /* { */
    397 /*     while (array_len > 0) { */
    398 /*         uint32 value; */
    399 /*         _bcm_ptp_read_pcishared_uint32(stack_p->cookie, addr, &value); */
    400 /*         array[0] = (value >> 24); */
    401 /*         array[1] = (value >> 16); */
    402 /*         array[2] = (value >> 8); */
    403 /*         array[3] = value; */
    404 /*         array += 4; */
    405 /*         array_len -= 4; */
    406 /*         addr += 4; */
    407 /*     } */
    408 /* } */
    409 
    410 
    411 
    412 #endif /* defined(PTP_KEYSTONE_STACK) */
    413 #endif /* defined(INCLUDE_PTP) */