[knet driver] fix PCI device init race condition

Broadcom CS5982299 fix.

Signed-off-by: Ying Xie <ying.xie@microsoft.com>
This commit is contained in:
Ying Xie 2018-11-22 00:37:18 +00:00
parent a11c28de46
commit 560d35bf42
3 changed files with 73 additions and 55 deletions

View File

@ -58,7 +58,7 @@
#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
#endif
extern void _dma_init(int robo_switch);
extern void _dma_init(int robo_switch, int dev_index);
extern int _dma_cleanup(void);
extern void _dma_pprint(void);
extern uint32_t *_salloc(int d, int size, const char *name);

View File

@ -540,6 +540,40 @@ _parse_eb_args(char *str, char * format, ...)
return 0;
}
static void
_bde_add_device(void)
{
/*
* In order to be backward compatible with the user mode BDE
* (specifically the interrupt IOCTLs) and the CM, switch devices
* *must* come first. If this is not the case (due to the probing
* order), we let the non-switch device(s) drop down to the end of
* the device array.
*/
if (_switch_ndevices > 0) {
bde_ctrl_t tmp_dev;
int i, s = 0;
while (s < _switch_ndevices) {
if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) {
s++;
continue;
}
tmp_dev = _devices[s];
for (i = s; i < _ndevices - 1; i++) {
_devices[i] = _devices[i+1];
}
_devices[i] = tmp_dev;
}
}
/* Initialize device locks and dma */
if (_ndevices > 0) {
spin_lock_init(&_devices[_ndevices-1].lock);
_dma_init(robo_switch, _ndevices-1);
}
}
static int
_eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw)
{
@ -575,6 +609,8 @@ _eb_device_create(resource_size_t paddr, int irq, int rd_hw, int wr_hw)
ctrl->isr = NULL;
ctrl->isr_data = NULL;
_bde_add_device();
gprintk("Created EB device at BA=%x IRQ=%d RD16=%d WR16=%d device=0x%x\n",
(unsigned int)paddr, irq, rd_hw, wr_hw, ctrl->bde_dev.device);
@ -627,6 +663,10 @@ sand_device_create(void)
ctrl->dev_type |= BDE_PCI_DEV_TYPE | BDE_SWITCH_DEV_TYPE;
}
#ifndef __DUNE_LINUX_BCM_CPU_PCIE__
_bde_add_device();
#endif
return 0;
}
#endif
@ -734,6 +774,7 @@ iproc_cmicd_probe(struct platform_device *pldev)
#endif
/* Let's boogie */
_bde_add_device();
return 0;
}
@ -991,6 +1032,7 @@ _ics_bde_create(void)
ctrl->isr = NULL;
ctrl->isr_data = NULL;
_bde_add_device();
printk("Created ICS device ..%x\n", ctrl->bde_dev.base_address);
}
@ -2629,6 +2671,10 @@ _pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
ctrl->dma_dev = &dev->dev;
#endif
if (!rescan) {
_bde_add_device();
}
if (debug >= 2) {
gprintk("_pci_probe: configured dev:0x%x rev:0x%x with base_addresses: 0x%lx 0x%lx\n",
(unsigned)ctrl->bde_dev.device, (unsigned)ctrl->bde_dev.rev,
@ -2968,6 +3014,7 @@ probe_robo_switch_iproc_spi(void)
ctrl->isr = NULL;
ctrl->isr_data = NULL;
robo_switch++;
_bde_add_device();
}
@ -3181,6 +3228,7 @@ probe_robo_switch(void)
#if defined(KEYSTONE)
spi_freq = _spi_id_table[match_idx].spifreq;
#endif
_bde_add_device();
}
#if defined(KEYSTONE)
@ -3226,6 +3274,8 @@ map_local_bus(uint64_t addr, uint32_t size)
ctrl->bde_dev.base_address = (sal_vaddr_t)IOREMAP(addr, size);
ctrl->phys_address = addr;
_bde_add_device();
return(ctrl);
}
@ -3377,6 +3427,8 @@ map_local_bus2(bde_ctrl_t *plx_ctrl, uint32_t dev_base, uint32_t size)
ctrl->bde_dev.device = dev_rev_id >> 16;
ctrl->bde_dev.rev = (dev_rev_id & 0xFF);
_bde_add_device();
switch (ctrl->bde_dev.device) {
case BCM88130_DEVICE_ID:
case BME3200_DEVICE_ID:
@ -3697,41 +3749,6 @@ _init(void)
tok = strtok(NULL,",");
}
}
_dma_init(robo_switch);
/*
* In order to be backward compatible with the user mode BDE
* (specifically the interrupt IOCTLs) and the CM, switch devices
* *must* come first. If this is not the case (due to the probing
* order), we let the non-switch device(s) drop down to the end of
* the device array.
*/
if (_switch_ndevices > 0) {
bde_ctrl_t tmp_dev;
int i, s = 0;
while (s < _switch_ndevices) {
if (_devices[s].dev_type & BDE_SWITCH_DEV_TYPE) {
s++;
continue;
}
tmp_dev = _devices[s];
for (i = s; i < _ndevices - 1; i++) {
_devices[i] = _devices[i+1];
}
_devices[i] = tmp_dev;
}
}
/* Initialize device locks */
if (_ndevices > 0) {
int i;
for (i = 0; i < _ndevices; i++) {
spin_lock_init(&_devices[i].lock);
}
}
return 0;
}

View File

@ -590,9 +590,7 @@ _pgcleanup(void)
static void
_alloc_mpool(size_t size)
{
int i, ndevices;
unsigned long pbase = 0;
unsigned long orig_pbase = 0;
#if defined(__arm__) && !defined(CONFIG_HIGHMEM)
if (_use_himem) {
@ -649,27 +647,18 @@ _alloc_mpool(size_t size)
return;
}
_cpu_pbase = virt_to_bus(_dma_vbase);
ndevices = BDE_NUM_DEVICES(BDE_ALL_DEVICES);
for (i = 0; i < ndevices && DMA_DEV(i); i ++) {
/* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */
pbase = dma_map_single(DMA_DEV(i), _dma_vbase, size, DMA_BIDIRECTIONAL);
if (_use_dma_mapping && (orig_pbase != pbase)) {
/* Bus address/IOVA must be identical for all devices. */
gprintk("deivce %d has different pbase: %lx (should be %lx)\n",
i, pbase, orig_pbase);
dma_unmap_single(DMA_DEV(i), (dma_addr_t)pbase, size, DMA_BIDIRECTIONAL);
while (--i >= 0 && DMA_DEV(i)) {
dma_unmap_single(DMA_DEV(i), (dma_addr_t)orig_pbase, size, DMA_BIDIRECTIONAL);
}
_use_dma_mapping = 0;
/* Use dma_map_single to obtain DMA bus address or IOVA if iommu is present. */
if (DMA_DEV(0)) {
pbase = dma_map_single(DMA_DEV(0), _dma_vbase, size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(DMA_DEV(0), pbase)) {
gprintk("Failed to map memory at %p\n", _dma_vbase);
_pgcleanup();
_dma_vbase = NULL;
_cpu_pbase = 0;
return;
}
orig_pbase = pbase;
_use_dma_mapping = 1;
}
if (!_use_dma_mapping) {
} else {
/* Device has not been probed. */
pbase = _cpu_pbase;
}
@ -730,8 +719,20 @@ _dma_cleanup(void)
return 0;
}
void _dma_init(int robo_switch)
void _dma_init(int robo_switch, int dev_index)
{
unsigned long pbase;
if (dev_index > 0) {
if ((_use_dma_mapping == 1) && DMA_DEV(dev_index) && _dma_vbase) {
pbase = dma_map_single(DMA_DEV(dev_index), _dma_vbase, _dma_mem_size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(DMA_DEV(dev_index), pbase)) {
gprintk("Failed to map memory for device %d at %p\n", dev_index, _dma_vbase);
}
}
return;
}
/* DMA Setup */
if (dmasize) {
if ((dmasize[strlen(dmasize)-1] & ~0x20) == 'M') {