freebsd_network: Clean up and break PCI methods out of bus.cpp.
This commit is contained in:
@@ -41,6 +41,7 @@ KernelStaticLibrary libfreebsd_network.a :
|
|||||||
mbuf.c
|
mbuf.c
|
||||||
mii.c
|
mii.c
|
||||||
mutex.c
|
mutex.c
|
||||||
|
pci.cpp
|
||||||
priv.cpp
|
priv.cpp
|
||||||
smp.c
|
smp.c
|
||||||
subr_autoconf.cpp
|
subr_autoconf.cpp
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ extern "C" {
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
|
#include <PCI_x86.h>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
#include <int.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <compat/dev/pci/pcireg.h>
|
#include <compat/dev/pci/pcireg.h>
|
||||||
@@ -25,11 +25,6 @@ extern "C" {
|
|||||||
#include <compat/sys/bus.h>
|
#include <compat/sys/bus.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
// private kernel header to get B_NO_HANDLED_INFO
|
|
||||||
#include <int.h>
|
|
||||||
|
|
||||||
#include <PCI_x86.h>
|
|
||||||
|
|
||||||
|
|
||||||
//#define DEBUG_BUS_SPACE_RW
|
//#define DEBUG_BUS_SPACE_RW
|
||||||
#ifdef DEBUG_BUS_SPACE_RW
|
#ifdef DEBUG_BUS_SPACE_RW
|
||||||
@@ -38,13 +33,6 @@ extern "C" {
|
|||||||
# define TRACE_BUS_SPACE_RW(x)
|
# define TRACE_BUS_SPACE_RW(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define DEBUG_PCI
|
|
||||||
#ifdef DEBUG_PCI
|
|
||||||
# define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
|
|
||||||
#else
|
|
||||||
# define TRACE_PCI(dev, format, args...) do { } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
struct internal_intr {
|
struct internal_intr {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
@@ -580,450 +568,3 @@ bus_enumerate_hinted_children(device_t bus)
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - PCI functions
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
pci_read_config(device_t dev, int offset, int size)
|
|
||||||
{
|
|
||||||
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
|
|
||||||
uint32_t value = gPci->read_pci_config(info->bus, info->device,
|
|
||||||
info->function, offset, size);
|
|
||||||
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
pci_write_config(device_t dev, int offset, uint32_t value, int size)
|
|
||||||
{
|
|
||||||
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
|
|
||||||
TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
|
|
||||||
|
|
||||||
gPci->write_pci_config(info->bus, info->device, info->function, offset,
|
|
||||||
size, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t
|
|
||||||
pci_get_vendor(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_vendor_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t
|
|
||||||
pci_get_device(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_device_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t
|
|
||||||
pci_get_subvendor(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t
|
|
||||||
pci_get_subdevice(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_subsystem_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pci_get_revid(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_revision, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
pci_get_domain(device_t dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
pci_get_devid(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_device_id, 2) << 16 |
|
|
||||||
pci_read_config(dev, PCI_vendor_id, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pci_get_cachelnsz(device_t dev)
|
|
||||||
{
|
|
||||||
return pci_read_config(dev, PCI_line_size, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *
|
|
||||||
pci_get_ether(device_t dev)
|
|
||||||
{
|
|
||||||
/* used in if_dc to get the MAC from CardBus CIS for Xircom card */
|
|
||||||
return NULL; /* NULL is handled in the caller correctly */
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pci_get_bus(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info
|
|
||||||
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
return info->bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pci_get_slot(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info
|
|
||||||
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
return info->device;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
pci_get_function(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info
|
|
||||||
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
return info->function;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_t
|
|
||||||
pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func)
|
|
||||||
{
|
|
||||||
// We don't support that yet - if we want to support the multi port
|
|
||||||
// feature of the Broadcom BCM 570x driver, we would have to change
|
|
||||||
// that.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
pci_set_command_bit(device_t dev, uint16_t bit)
|
|
||||||
{
|
|
||||||
uint16_t command = pci_read_config(dev, PCI_command, 2);
|
|
||||||
pci_write_config(dev, PCI_command, command | bit, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_enable_busmaster(device_t dev)
|
|
||||||
{
|
|
||||||
pci_set_command_bit(dev, PCI_command_master);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_enable_io(device_t dev, int space)
|
|
||||||
{
|
|
||||||
/* adapted from FreeBSD's pci_enable_io_method */
|
|
||||||
int bit = 0;
|
|
||||||
|
|
||||||
switch (space) {
|
|
||||||
case SYS_RES_IOPORT:
|
|
||||||
bit = PCI_command_io;
|
|
||||||
break;
|
|
||||||
case SYS_RES_MEMORY:
|
|
||||||
bit = PCI_command_memory;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_set_command_bit(dev, bit);
|
|
||||||
if (pci_read_config(dev, PCI_command, 2) & bit)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
|
|
||||||
|
|
||||||
return ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_find_cap(device_t dev, int capability, int *capreg)
|
|
||||||
{
|
|
||||||
return pci_find_extcap(dev, capability, capreg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
|
|
||||||
{
|
|
||||||
uint8 capabilityPointer;
|
|
||||||
uint8 headerType;
|
|
||||||
uint16 status;
|
|
||||||
|
|
||||||
status = pci_read_config(child, PCIR_STATUS, 2);
|
|
||||||
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
|
|
||||||
return ENXIO;
|
|
||||||
|
|
||||||
headerType = pci_read_config(child, PCI_header_type, 1);
|
|
||||||
switch (headerType & PCIM_HDRTYPE) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
capabilityPointer = PCIR_CAP_PTR;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
capabilityPointer = PCIR_CAP_PTR_2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ENXIO;
|
|
||||||
}
|
|
||||||
capabilityPointer = pci_read_config(child, capabilityPointer, 1);
|
|
||||||
|
|
||||||
while (capabilityPointer != 0) {
|
|
||||||
if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
|
|
||||||
== capability) {
|
|
||||||
if (_capabilityRegister != NULL)
|
|
||||||
*_capabilityRegister = capabilityPointer;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
capabilityPointer = pci_read_config(child,
|
|
||||||
capabilityPointer + PCICAP_NEXTPTR, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_msi_count(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info;
|
|
||||||
if (gPCIx86 == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
return gPCIx86->get_msi_count(info->bus, info->device, info->function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_alloc_msi(device_t dev, int *count)
|
|
||||||
{
|
|
||||||
pci_info *info;
|
|
||||||
uint8 startVector = 0;
|
|
||||||
if (gPCIx86 == NULL)
|
|
||||||
return ENODEV;
|
|
||||||
|
|
||||||
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
|
|
||||||
if (gPCIx86->configure_msi(info->bus, info->device, info->function, *count,
|
|
||||||
&startVector) != B_OK) {
|
|
||||||
return ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
((struct root_device_softc *)dev->root->softc)->is_msi = true;
|
|
||||||
info->u.h0.interrupt_line = startVector;
|
|
||||||
return EOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_release_msi(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info;
|
|
||||||
if (gPCIx86 == NULL)
|
|
||||||
return ENODEV;
|
|
||||||
|
|
||||||
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
gPCIx86->unconfigure_msi(info->bus, info->device, info->function);
|
|
||||||
((struct root_device_softc *)dev->root->softc)->is_msi = false;
|
|
||||||
((struct root_device_softc *)dev->root->softc)->is_msix = false;
|
|
||||||
return EOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_msix_table_bar(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
|
|
||||||
uint8 capability_offset;
|
|
||||||
if (gPci->find_pci_capability(info->bus, info->device, info->function,
|
|
||||||
PCI_cap_id_msix, &capability_offset) != B_OK)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
uint32 table_value = gPci->read_pci_config(info->bus, info->device, info->function,
|
|
||||||
capability_offset + PCI_msix_table, 4);
|
|
||||||
|
|
||||||
uint32 bar = table_value & PCI_msix_bir_mask;
|
|
||||||
return PCIR_BAR(bar);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_msix_count(device_t dev)
|
|
||||||
{
|
|
||||||
pci_info *info;
|
|
||||||
if (gPCIx86 == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
return gPCIx86->get_msix_count(info->bus, info->device, info->function);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_alloc_msix(device_t dev, int *count)
|
|
||||||
{
|
|
||||||
pci_info *info;
|
|
||||||
uint8 startVector = 0;
|
|
||||||
if (gPCIx86 == NULL)
|
|
||||||
return ENODEV;
|
|
||||||
|
|
||||||
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
|
||||||
|
|
||||||
if (gPCIx86->configure_msix(info->bus, info->device, info->function, *count,
|
|
||||||
&startVector) != B_OK) {
|
|
||||||
return ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
((struct root_device_softc *)dev->root->softc)->is_msix = true;
|
|
||||||
info->u.h0.interrupt_line = startVector;
|
|
||||||
return EOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_get_max_read_req(device_t dev)
|
|
||||||
{
|
|
||||||
int cap;
|
|
||||||
uint16_t val;
|
|
||||||
|
|
||||||
if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
|
|
||||||
return (0);
|
|
||||||
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
|
|
||||||
val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
|
|
||||||
val >>= 12;
|
|
||||||
return (1 << (val + 7));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_set_max_read_req(device_t dev, int size)
|
|
||||||
{
|
|
||||||
int cap;
|
|
||||||
uint16_t val;
|
|
||||||
|
|
||||||
if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
|
|
||||||
return (0);
|
|
||||||
if (size < 128)
|
|
||||||
size = 128;
|
|
||||||
if (size > 4096)
|
|
||||||
size = 4096;
|
|
||||||
size = (1 << (fls(size) - 1));
|
|
||||||
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
|
|
||||||
val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST;
|
|
||||||
val |= (fls(size) - 8) << 12;
|
|
||||||
pci_write_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, val, 2);
|
|
||||||
return (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_get_powerstate(device_t dev)
|
|
||||||
{
|
|
||||||
int capabilityRegister;
|
|
||||||
uint16 status;
|
|
||||||
int powerState = PCI_POWERSTATE_D0;
|
|
||||||
|
|
||||||
if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
|
|
||||||
return powerState;
|
|
||||||
|
|
||||||
status = pci_read_config(dev, capabilityRegister + PCIR_POWER_STATUS, 2);
|
|
||||||
switch (status & PCI_pm_mask) {
|
|
||||||
case PCI_pm_state_d0:
|
|
||||||
break;
|
|
||||||
case PCI_pm_state_d1:
|
|
||||||
powerState = PCI_POWERSTATE_D1;
|
|
||||||
break;
|
|
||||||
case PCI_pm_state_d2:
|
|
||||||
powerState = PCI_POWERSTATE_D2;
|
|
||||||
break;
|
|
||||||
case PCI_pm_state_d3:
|
|
||||||
powerState = PCI_POWERSTATE_D3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
powerState = PCI_POWERSTATE_UNKNOWN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_PCI(dev, "%s: D%i\n", __func__, powerState);
|
|
||||||
return powerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
pci_set_powerstate(device_t dev, int newPowerState)
|
|
||||||
{
|
|
||||||
int capabilityRegister;
|
|
||||||
int oldPowerState;
|
|
||||||
uint8 currentPowerManagementStatus;
|
|
||||||
uint8 newPowerManagementStatus;
|
|
||||||
uint16 powerManagementCapabilities;
|
|
||||||
bigtime_t stateTransitionDelayInUs = 0;
|
|
||||||
|
|
||||||
if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
|
|
||||||
return EOPNOTSUPP;
|
|
||||||
|
|
||||||
oldPowerState = pci_get_powerstate(dev);
|
|
||||||
if (oldPowerState == newPowerState)
|
|
||||||
return EOK;
|
|
||||||
|
|
||||||
switch (std::max(oldPowerState, newPowerState)) {
|
|
||||||
case PCI_POWERSTATE_D2:
|
|
||||||
stateTransitionDelayInUs = 200;
|
|
||||||
break;
|
|
||||||
case PCI_POWERSTATE_D3:
|
|
||||||
stateTransitionDelayInUs = 10000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPowerManagementStatus = pci_read_config(dev, capabilityRegister
|
|
||||||
+ PCIR_POWER_STATUS, 2);
|
|
||||||
newPowerManagementStatus = currentPowerManagementStatus & ~PCI_pm_mask;
|
|
||||||
powerManagementCapabilities = pci_read_config(dev, capabilityRegister
|
|
||||||
+ PCIR_POWER_CAP, 2);
|
|
||||||
|
|
||||||
switch (newPowerState) {
|
|
||||||
case PCI_POWERSTATE_D0:
|
|
||||||
newPowerManagementStatus |= PCIM_PSTAT_D0;
|
|
||||||
break;
|
|
||||||
case PCI_POWERSTATE_D1:
|
|
||||||
if ((powerManagementCapabilities & PCI_pm_d1supp) == 0)
|
|
||||||
return EOPNOTSUPP;
|
|
||||||
newPowerManagementStatus |= PCIM_PSTAT_D1;
|
|
||||||
break;
|
|
||||||
case PCI_POWERSTATE_D2:
|
|
||||||
if ((powerManagementCapabilities & PCI_pm_d2supp) == 0)
|
|
||||||
return EOPNOTSUPP;
|
|
||||||
newPowerManagementStatus |= PCIM_PSTAT_D2;
|
|
||||||
break;
|
|
||||||
case PCI_POWERSTATE_D3:
|
|
||||||
newPowerManagementStatus |= PCIM_PSTAT_D3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_PCI(dev, "%s: D%i -> D%i\n", __func__, oldPowerState, newPowerState);
|
|
||||||
pci_write_config(dev, capabilityRegister + PCIR_POWER_STATUS,
|
|
||||||
newPowerManagementStatus, 2);
|
|
||||||
if (stateTransitionDelayInUs != 0)
|
|
||||||
snooze(stateTransitionDelayInUs);
|
|
||||||
|
|
||||||
return EOK;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,466 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include <compat/machine/resource.h>
|
||||||
|
#include <compat/dev/pci/pcireg.h>
|
||||||
|
#include <compat/dev/pci/pcivar.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <PCI.h>
|
||||||
|
#include <PCI_x86.h>
|
||||||
|
|
||||||
|
|
||||||
|
//#define DEBUG_PCI
|
||||||
|
#ifdef DEBUG_PCI
|
||||||
|
# define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
|
||||||
|
#else
|
||||||
|
# define TRACE_PCI(dev, format, args...) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
pci_read_config(device_t dev, int offset, int size)
|
||||||
|
{
|
||||||
|
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
|
||||||
|
uint32_t value = gPci->read_pci_config(info->bus, info->device,
|
||||||
|
info->function, offset, size);
|
||||||
|
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
pci_write_config(device_t dev, int offset, uint32_t value, int size)
|
||||||
|
{
|
||||||
|
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
|
||||||
|
TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
|
||||||
|
|
||||||
|
gPci->write_pci_config(info->bus, info->device, info->function, offset,
|
||||||
|
size, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
pci_get_vendor(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_vendor_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
pci_get_device(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_device_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
pci_get_subvendor(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
pci_get_subdevice(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_subsystem_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pci_get_revid(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_revision, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
pci_get_domain(device_t dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
pci_get_devid(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_device_id, 2) << 16 |
|
||||||
|
pci_read_config(dev, PCI_vendor_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pci_get_cachelnsz(device_t dev)
|
||||||
|
{
|
||||||
|
return pci_read_config(dev, PCI_line_size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
pci_get_ether(device_t dev)
|
||||||
|
{
|
||||||
|
/* used in if_dc to get the MAC from CardBus CIS for Xircom card */
|
||||||
|
return NULL; /* NULL is handled in the caller correctly */
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pci_get_bus(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info
|
||||||
|
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
return info->bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pci_get_slot(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info
|
||||||
|
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
return info->device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pci_get_function(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info
|
||||||
|
= &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
return info->function;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t
|
||||||
|
pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func)
|
||||||
|
{
|
||||||
|
// We don't support that yet - if we want to support the multi port
|
||||||
|
// feature of the Broadcom BCM 570x driver, we would have to change
|
||||||
|
// that.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_set_command_bit(device_t dev, uint16_t bit)
|
||||||
|
{
|
||||||
|
uint16_t command = pci_read_config(dev, PCI_command, 2);
|
||||||
|
pci_write_config(dev, PCI_command, command | bit, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_enable_busmaster(device_t dev)
|
||||||
|
{
|
||||||
|
pci_set_command_bit(dev, PCI_command_master);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_enable_io(device_t dev, int space)
|
||||||
|
{
|
||||||
|
/* adapted from FreeBSD's pci_enable_io_method */
|
||||||
|
int bit = 0;
|
||||||
|
|
||||||
|
switch (space) {
|
||||||
|
case SYS_RES_IOPORT:
|
||||||
|
bit = PCI_command_io;
|
||||||
|
break;
|
||||||
|
case SYS_RES_MEMORY:
|
||||||
|
bit = PCI_command_memory;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_set_command_bit(dev, bit);
|
||||||
|
if (pci_read_config(dev, PCI_command, 2) & bit)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
|
||||||
|
|
||||||
|
return ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_find_cap(device_t dev, int capability, int *capreg)
|
||||||
|
{
|
||||||
|
return pci_find_extcap(dev, capability, capreg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
|
||||||
|
{
|
||||||
|
uint8 capabilityPointer;
|
||||||
|
uint8 headerType;
|
||||||
|
uint16 status;
|
||||||
|
|
||||||
|
status = pci_read_config(child, PCIR_STATUS, 2);
|
||||||
|
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
headerType = pci_read_config(child, PCI_header_type, 1);
|
||||||
|
switch (headerType & PCIM_HDRTYPE) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
capabilityPointer = PCIR_CAP_PTR;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
capabilityPointer = PCIR_CAP_PTR_2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ENXIO;
|
||||||
|
}
|
||||||
|
capabilityPointer = pci_read_config(child, capabilityPointer, 1);
|
||||||
|
|
||||||
|
while (capabilityPointer != 0) {
|
||||||
|
if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
|
||||||
|
== capability) {
|
||||||
|
if (_capabilityRegister != NULL)
|
||||||
|
*_capabilityRegister = capabilityPointer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
capabilityPointer = pci_read_config(child,
|
||||||
|
capabilityPointer + PCICAP_NEXTPTR, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_msi_count(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info;
|
||||||
|
if (gPCIx86 == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
return gPCIx86->get_msi_count(info->bus, info->device, info->function);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_alloc_msi(device_t dev, int *count)
|
||||||
|
{
|
||||||
|
pci_info *info;
|
||||||
|
uint8 startVector = 0;
|
||||||
|
if (gPCIx86 == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
|
||||||
|
if (gPCIx86->configure_msi(info->bus, info->device, info->function, *count,
|
||||||
|
&startVector) != B_OK) {
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
((struct root_device_softc *)dev->root->softc)->is_msi = true;
|
||||||
|
info->u.h0.interrupt_line = startVector;
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_release_msi(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info;
|
||||||
|
if (gPCIx86 == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
gPCIx86->unconfigure_msi(info->bus, info->device, info->function);
|
||||||
|
((struct root_device_softc *)dev->root->softc)->is_msi = false;
|
||||||
|
((struct root_device_softc *)dev->root->softc)->is_msix = false;
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_msix_table_bar(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
|
||||||
|
uint8 capability_offset;
|
||||||
|
if (gPci->find_pci_capability(info->bus, info->device, info->function,
|
||||||
|
PCI_cap_id_msix, &capability_offset) != B_OK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint32 table_value = gPci->read_pci_config(info->bus, info->device, info->function,
|
||||||
|
capability_offset + PCI_msix_table, 4);
|
||||||
|
|
||||||
|
uint32 bar = table_value & PCI_msix_bir_mask;
|
||||||
|
return PCIR_BAR(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_msix_count(device_t dev)
|
||||||
|
{
|
||||||
|
pci_info *info;
|
||||||
|
if (gPCIx86 == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
return gPCIx86->get_msix_count(info->bus, info->device, info->function);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_alloc_msix(device_t dev, int *count)
|
||||||
|
{
|
||||||
|
pci_info *info;
|
||||||
|
uint8 startVector = 0;
|
||||||
|
if (gPCIx86 == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
|
||||||
|
|
||||||
|
if (gPCIx86->configure_msix(info->bus, info->device, info->function, *count,
|
||||||
|
&startVector) != B_OK) {
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
((struct root_device_softc *)dev->root->softc)->is_msix = true;
|
||||||
|
info->u.h0.interrupt_line = startVector;
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_get_max_read_req(device_t dev)
|
||||||
|
{
|
||||||
|
int cap;
|
||||||
|
uint16_t val;
|
||||||
|
|
||||||
|
if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
|
||||||
|
return (0);
|
||||||
|
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
|
||||||
|
val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
|
||||||
|
val >>= 12;
|
||||||
|
return (1 << (val + 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_set_max_read_req(device_t dev, int size)
|
||||||
|
{
|
||||||
|
int cap;
|
||||||
|
uint16_t val;
|
||||||
|
|
||||||
|
if (pci_find_extcap(dev, PCIY_EXPRESS, &cap) != 0)
|
||||||
|
return (0);
|
||||||
|
if (size < 128)
|
||||||
|
size = 128;
|
||||||
|
if (size > 4096)
|
||||||
|
size = 4096;
|
||||||
|
size = (1 << (fls(size) - 1));
|
||||||
|
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
|
||||||
|
val &= ~PCIM_EXP_CTL_MAX_READ_REQUEST;
|
||||||
|
val |= (fls(size) - 8) << 12;
|
||||||
|
pci_write_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, val, 2);
|
||||||
|
return (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_get_powerstate(device_t dev)
|
||||||
|
{
|
||||||
|
int capabilityRegister;
|
||||||
|
uint16 status;
|
||||||
|
int powerState = PCI_POWERSTATE_D0;
|
||||||
|
|
||||||
|
if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
|
||||||
|
return powerState;
|
||||||
|
|
||||||
|
status = pci_read_config(dev, capabilityRegister + PCIR_POWER_STATUS, 2);
|
||||||
|
switch (status & PCI_pm_mask) {
|
||||||
|
case PCI_pm_state_d0:
|
||||||
|
break;
|
||||||
|
case PCI_pm_state_d1:
|
||||||
|
powerState = PCI_POWERSTATE_D1;
|
||||||
|
break;
|
||||||
|
case PCI_pm_state_d2:
|
||||||
|
powerState = PCI_POWERSTATE_D2;
|
||||||
|
break;
|
||||||
|
case PCI_pm_state_d3:
|
||||||
|
powerState = PCI_POWERSTATE_D3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
powerState = PCI_POWERSTATE_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_PCI(dev, "%s: D%i\n", __func__, powerState);
|
||||||
|
return powerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_set_powerstate(device_t dev, int newPowerState)
|
||||||
|
{
|
||||||
|
int capabilityRegister;
|
||||||
|
int oldPowerState;
|
||||||
|
uint8 currentPowerManagementStatus;
|
||||||
|
uint8 newPowerManagementStatus;
|
||||||
|
uint16 powerManagementCapabilities;
|
||||||
|
bigtime_t stateTransitionDelayInUs = 0;
|
||||||
|
|
||||||
|
if (pci_find_extcap(dev, PCIY_PMG, &capabilityRegister) != EOK)
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
|
||||||
|
oldPowerState = pci_get_powerstate(dev);
|
||||||
|
if (oldPowerState == newPowerState)
|
||||||
|
return EOK;
|
||||||
|
|
||||||
|
switch (max_c(oldPowerState, newPowerState)) {
|
||||||
|
case PCI_POWERSTATE_D2:
|
||||||
|
stateTransitionDelayInUs = 200;
|
||||||
|
break;
|
||||||
|
case PCI_POWERSTATE_D3:
|
||||||
|
stateTransitionDelayInUs = 10000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPowerManagementStatus = pci_read_config(dev, capabilityRegister
|
||||||
|
+ PCIR_POWER_STATUS, 2);
|
||||||
|
newPowerManagementStatus = currentPowerManagementStatus & ~PCI_pm_mask;
|
||||||
|
powerManagementCapabilities = pci_read_config(dev, capabilityRegister
|
||||||
|
+ PCIR_POWER_CAP, 2);
|
||||||
|
|
||||||
|
switch (newPowerState) {
|
||||||
|
case PCI_POWERSTATE_D0:
|
||||||
|
newPowerManagementStatus |= PCIM_PSTAT_D0;
|
||||||
|
break;
|
||||||
|
case PCI_POWERSTATE_D1:
|
||||||
|
if ((powerManagementCapabilities & PCI_pm_d1supp) == 0)
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
newPowerManagementStatus |= PCIM_PSTAT_D1;
|
||||||
|
break;
|
||||||
|
case PCI_POWERSTATE_D2:
|
||||||
|
if ((powerManagementCapabilities & PCI_pm_d2supp) == 0)
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
newPowerManagementStatus |= PCIM_PSTAT_D2;
|
||||||
|
break;
|
||||||
|
case PCI_POWERSTATE_D3:
|
||||||
|
newPowerManagementStatus |= PCIM_PSTAT_D3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_PCI(dev, "%s: D%i -> D%i\n", __func__, oldPowerState, newPowerState);
|
||||||
|
pci_write_config(dev, capabilityRegister + PCIR_POWER_STATUS,
|
||||||
|
newPowerManagementStatus, 2);
|
||||||
|
if (stateTransitionDelayInUs != 0)
|
||||||
|
snooze(stateTransitionDelayInUs);
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user