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) */