mirror of
https://github.com/apache/nuttx.git
synced 2025-12-17 10:16:49 +08:00
pci: add ioctl for userspace
which is same as OpenBSD: https://github.com/openbsd/src/blob/master/sys/sys/pciio.h Signed-off-by: lipengfei28 <lipengfei28@xiaomi.com>
This commit is contained in:
@@ -25,6 +25,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <sys/pciio.h>
|
||||||
|
#include <sys/endian.h>
|
||||||
|
|
||||||
#include <nuttx/kmalloc.h>
|
#include <nuttx/kmalloc.h>
|
||||||
#include <nuttx/pci/pci.h>
|
#include <nuttx/pci/pci.h>
|
||||||
@@ -113,6 +115,12 @@
|
|||||||
(id)->subdevice == (dev)->subsystem_device) && \
|
(id)->subdevice == (dev)->subsystem_device) && \
|
||||||
(((id)->class ^ (dev)->class) & ((id)->class_mask == 0)))
|
(((id)->class ^ (dev)->class) & ((id)->class_mask == 0)))
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int pci_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -125,6 +133,17 @@ static struct list_node g_pci_driver_list =
|
|||||||
static struct list_node g_pci_ctrl_list =
|
static struct list_node g_pci_ctrl_list =
|
||||||
LIST_INITIAL_VALUE(g_pci_ctrl_list);
|
LIST_INITIAL_VALUE(g_pci_ctrl_list);
|
||||||
|
|
||||||
|
static const struct file_operations g_pci_fops =
|
||||||
|
{
|
||||||
|
NULL, /* open */
|
||||||
|
NULL, /* close */
|
||||||
|
NULL, /* read */
|
||||||
|
NULL, /* write */
|
||||||
|
NULL, /* seek */
|
||||||
|
pci_ioctl, /* ioctl */
|
||||||
|
NULL, /* mmap */
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -157,6 +176,219 @@ pci_do_find_device_from_bus(FAR struct pci_bus_s *bus, uint8_t busno,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pci_vpd_read(FAR struct pci_bus_s *bus, uint32_t devfn,
|
||||||
|
int offset, int count, FAR uint32_t *data)
|
||||||
|
{
|
||||||
|
uint8_t pos;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (offset + count >= PCI_VPD_ADDR_MASK || data != NULL)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_VPD);
|
||||||
|
if (pos == 0)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++, offset += 4)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
pci_bus_write_config_word(bus, devfn, pos + PCI_VPD_ADDR, offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCI 2.2 does not specify how long we should poll
|
||||||
|
* for completion nor whether the operation can fail.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
uint16_t addr;
|
||||||
|
|
||||||
|
pci_bus_read_config_word(bus, devfn, pos + PCI_VPD_ADDR, &addr);
|
||||||
|
if (addr & PCI_VPD_ADDR_F)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++j == 20)
|
||||||
|
{
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
up_udelay(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_bus_read_config_dword(bus, devfn, pos + PCI_VPD_DATA, &data[i]);
|
||||||
|
data[i] = le32toh(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: pci_ioctl
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* for lspci read/write pci config space
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* filep - The open file description
|
||||||
|
* cmd - The cmd to read/write cmd
|
||||||
|
* arg - The arg to pass ioctl
|
||||||
|
* Returned Value:
|
||||||
|
* The length of the param
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int pci_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
FAR struct pci_controller_s *ctrl;
|
||||||
|
FAR struct pcisel *sel;
|
||||||
|
uint32_t devfn;
|
||||||
|
uint8_t i = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sel = (FAR struct pcisel *)arg;
|
||||||
|
devfn = PCI_DEVFN(sel->pc_dev, sel->pc_func);
|
||||||
|
|
||||||
|
ret = nxmutex_lock(&g_pci_lock);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_every_entry(&g_pci_ctrl_list, ctrl, struct pci_controller_s, node)
|
||||||
|
{
|
||||||
|
if (i == sel->pc_domain)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxmutex_unlock(&g_pci_lock);
|
||||||
|
|
||||||
|
if (i != sel->pc_domain)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case PCIOCREAD:
|
||||||
|
{
|
||||||
|
FAR struct pci_io *io = (FAR struct pci_io *)arg;
|
||||||
|
ret = pci_bus_read_config(ctrl->bus, devfn, io->pi_reg,
|
||||||
|
io->pi_width, &io->pi_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCIOCWRITE:
|
||||||
|
{
|
||||||
|
FAR struct pci_io *io = (FAR struct pci_io *)arg;
|
||||||
|
ret = pci_bus_write_config(ctrl->bus, devfn, io->pi_reg,
|
||||||
|
io->pi_width, io->pi_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCIOCGETROMLEN:
|
||||||
|
{
|
||||||
|
FAR struct pci_rom *rom = (FAR struct pci_rom *)arg;
|
||||||
|
FAR struct pci_device_s *dev =
|
||||||
|
pci_find_device_from_bus(ctrl->bus, sel->pc_bus, devfn);
|
||||||
|
if (dev == NULL)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
rom->pr_romlen = pci_resource_len(dev, PCI_ROM_RESOURCE);
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCIOCGETROM:
|
||||||
|
{
|
||||||
|
FAR void *p;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
FAR struct pci_rom *rom = (FAR struct pci_rom *)arg;
|
||||||
|
FAR struct pci_device_s *dev =
|
||||||
|
pci_find_device_from_bus(ctrl->bus, sel->pc_bus, devfn);
|
||||||
|
if (dev == NULL)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = pci_resource_start(dev, PCI_ROM_RESOURCE);
|
||||||
|
len = pci_resource_len(dev, PCI_ROM_RESOURCE);
|
||||||
|
if (rom->pr_romlen < len)
|
||||||
|
{
|
||||||
|
rom->pr_romlen = len;
|
||||||
|
ret = -E2BIG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pci_map_bar(dev, PCI_ROM_RESOURCE);
|
||||||
|
if (p == NULL)
|
||||||
|
{
|
||||||
|
ret = -ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_bus_write_config_dword(ctrl->bus, devfn, PCI_ROM_ADDRESS,
|
||||||
|
addr | PCI_ROM_ADDRESS_ENABLE);
|
||||||
|
memcpy(rom->pr_rom, p, len);
|
||||||
|
pci_bus_write_config_dword(ctrl->bus, devfn,
|
||||||
|
PCI_ROM_ADDRESS, addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCIOCREADMASK:
|
||||||
|
{
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
FAR struct pci_io *io = (FAR struct pci_io *)arg;
|
||||||
|
if (io->pi_width != 4 || (io->pi_reg & 0x3) ||
|
||||||
|
io->pi_reg < PCI_BASE_ADDRESS_0 ||
|
||||||
|
io->pi_reg >= PCI_BASE_ADDRESS_SPACE)
|
||||||
|
{
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_bus_read_config_dword(ctrl->bus, devfn, io->pi_reg, &data);
|
||||||
|
pci_bus_write_config_dword(ctrl->bus, devfn, io->pi_reg,
|
||||||
|
0xffffffff);
|
||||||
|
pci_bus_read_config_dword(ctrl->bus, devfn,
|
||||||
|
io->pi_reg, &io->pi_data);
|
||||||
|
pci_bus_write_config_dword(ctrl->bus, devfn, io->pi_reg, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCIOCGETVPD:
|
||||||
|
{
|
||||||
|
FAR struct pci_vpd_req *pv = (FAR struct pci_vpd_req *)arg;
|
||||||
|
ret = pci_vpd_read(ctrl->bus, devfn, pv->pv_offset,
|
||||||
|
pv->pv_count, pv->pv_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ret = -ENOTTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: pci_change_master
|
* Name: pci_change_master
|
||||||
*
|
*
|
||||||
@@ -1427,6 +1659,22 @@ uint8_t pci_bus_find_capability(FAR struct pci_bus_s *bus,
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: pci_dev_register
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Create an pci dev driver.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) on success; A negated errno value on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int pci_dev_register(void)
|
||||||
|
{
|
||||||
|
return register_driver("/dev/pci", &g_pci_fops, 0666, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
PCI_BUS_READ_CONFIG(byte, uint8_t, 1)
|
PCI_BUS_READ_CONFIG(byte, uint8_t, 1)
|
||||||
PCI_BUS_READ_CONFIG(word, uint16_t, 2)
|
PCI_BUS_READ_CONFIG(word, uint16_t, 2)
|
||||||
PCI_BUS_READ_CONFIG(dword, uint32_t, 4)
|
PCI_BUS_READ_CONFIG(dword, uint32_t, 4)
|
||||||
|
|||||||
@@ -100,6 +100,7 @@
|
|||||||
#define _SYSLOGBASE (0x3c00) /* Syslog device ioctl commands */
|
#define _SYSLOGBASE (0x3c00) /* Syslog device ioctl commands */
|
||||||
#define _STEPIOBASE (0x3d00) /* Stepper device ioctl commands */
|
#define _STEPIOBASE (0x3d00) /* Stepper device ioctl commands */
|
||||||
#define _FPGACFGBASE (0x3e00) /* FPGA configuration ioctl commands */
|
#define _FPGACFGBASE (0x3e00) /* FPGA configuration ioctl commands */
|
||||||
|
#define _PCIBASE (0x4100) /* Pci ioctl commands */
|
||||||
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
|
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
|
||||||
|
|
||||||
/* boardctl() commands share the same number space */
|
/* boardctl() commands share the same number space */
|
||||||
@@ -710,6 +711,11 @@
|
|||||||
#define _FPGACFGVALID(c) (_IOC_TYPE(c) == _FPGACFGBASE)
|
#define _FPGACFGVALID(c) (_IOC_TYPE(c) == _FPGACFGBASE)
|
||||||
#define _FPGACFGIOC(nr) _IOC(_FPGACFGBASE, nr)
|
#define _FPGACFGIOC(nr) _IOC(_FPGACFGBASE, nr)
|
||||||
|
|
||||||
|
/* Pci controller drivers ***************************************************/
|
||||||
|
|
||||||
|
#define _PCIIOCVALID(c) (_IOC_TYPE(c)==_PCIBASE)
|
||||||
|
#define _PCIIOC(nr) _IOC(_PCIBASE,nr)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Type Definitions
|
* Public Type Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
77
include/sys/pciio.h
Normal file
77
include/sys/pciio.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* include/sys/pciio.h
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __INCLUDE_SYS_PCIIO_H
|
||||||
|
#define __INCLUDE_SYS_PCIIO_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/fs/ioctl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define PCIOCREAD _PCIIOC(1)
|
||||||
|
#define PCIOCWRITE _PCIIOC(2)
|
||||||
|
#define PCIOCGETROMLEN _PCIIOC(3)
|
||||||
|
#define PCIOCGETROM _PCIIOC(4)
|
||||||
|
#define PCIOCREADMASK _PCIIOC(5)
|
||||||
|
#define PCIOCGETVPD _PCIIOC(6)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Type Declarations
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct pcisel
|
||||||
|
{
|
||||||
|
uint8_t pc_domain;
|
||||||
|
uint8_t pc_bus;
|
||||||
|
uint8_t pc_dev;
|
||||||
|
uint8_t pc_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pci_io
|
||||||
|
{
|
||||||
|
struct pcisel pi_sel;
|
||||||
|
int pi_reg;
|
||||||
|
int pi_width;
|
||||||
|
uint32_t pi_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pci_rom
|
||||||
|
{
|
||||||
|
struct pcisel pr_sel;
|
||||||
|
int pr_romlen;
|
||||||
|
FAR char *pr_rom;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pci_vpd_req
|
||||||
|
{
|
||||||
|
struct pcisel pv_sel;
|
||||||
|
int pv_offset;
|
||||||
|
int pv_count;
|
||||||
|
FAR uint32_t *pv_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __INCLUDE_SYS_PCIIO_H */
|
||||||
Reference in New Issue
Block a user