Skip to content

Commit

Permalink
pci: add config space locking and set ecsm bit
Browse files Browse the repository at this point in the history
Set ecsm to 1 in pci_cfg_set_addr to ensure that configuration
cycles are generated.

Add a global pci_cfg_lock spinlock in pci_cfg.c and corresponding
spin_lock/spin_unlock sections in pci_{read,write}* to ensure that
access to the config address and data IO ports are synchronized.

Signed-off-by: Connor Davis <[email protected]>
  • Loading branch information
cjams authored and dkgupta-amzn committed Nov 28, 2021
1 parent ffb0e79 commit 1c347d9
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
28 changes: 28 additions & 0 deletions arch/x86/pci_cfg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright © 2021 Amazon.com, Inc. or its affiliates.
* 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 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.
*/
#include <pci_cfg.h>

/* Lock to synchronize PCI config data and address IO ports */
spinlock_t pci_cfg_lock = SPINLOCK_INIT;
46 changes: 43 additions & 3 deletions include/arch/x86/pci_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@

#include <ktf.h>
#include <lib.h>
#include <spinlock.h>

#define PCI_IO_PORT_ADDRESS 0xcf8
#define PCI_IO_PORT_DATA 0xcfc

extern spinlock_t pci_cfg_lock;

union pci_cfg_addr {
struct {
uint32_t zero : 2, reg : 6, fn : 3, dev : 5, bus : 8, rsvd : 7, ecsm : 1;
Expand All @@ -56,42 +59,79 @@ static inline void pci_cfg_set_addr(uint8_t bus, uint8_t dev, uint8_t func, uint
addr.fn = func;
addr.dev = dev;
addr.bus = bus;
addr.ecsm = 1;

outd(PCI_IO_PORT_ADDRESS, addr.val);
}

static inline uint8_t pci_cfg_read8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) {
uint8_t ret;

spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
return inb(PCI_IO_PORT_DATA);
ret = inb(PCI_IO_PORT_DATA);

spin_unlock(&pci_cfg_lock);

return ret;
}

static inline void pci_cfg_write8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg,
uint8_t value) {
spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
outb(PCI_IO_PORT_DATA, value);

spin_unlock(&pci_cfg_lock);
}

static inline uint16_t pci_cfg_read16(uint8_t bus, uint8_t dev, uint8_t func,
uint8_t reg) {
uint16_t ret;

spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
return inw(PCI_IO_PORT_DATA);
ret = inw(PCI_IO_PORT_DATA);

spin_unlock(&pci_cfg_lock);

return ret;
}

static inline void pci_cfg_write16(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg,
uint16_t value) {
spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
outw(PCI_IO_PORT_DATA, value);

spin_unlock(&pci_cfg_lock);
}

static inline uint32_t pci_cfg_read(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) {
uint32_t ret;

spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
return ind(PCI_IO_PORT_DATA);
ret = ind(PCI_IO_PORT_DATA);

spin_unlock(&pci_cfg_lock);

return ret;
}

static inline void pci_cfg_write(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg,
uint32_t value) {
spin_lock(&pci_cfg_lock);

pci_cfg_set_addr(bus, dev, func, reg);
outd(PCI_IO_PORT_DATA, value);

spin_unlock(&pci_cfg_lock);
}

/* External declarations */
Expand Down

0 comments on commit 1c347d9

Please sign in to comment.