Index: share/man/man4/pci.4 =================================================================== --- share/man/man4/pci.4 +++ share/man/man4/pci.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 17, 2019 +.Dd July 26, 2021 .Dt PCI 4 .Os .Sh NAME @@ -419,6 +419,33 @@ of mapping. Currently attempt to mmap an inactive BAR results in error. .El +.It PCIOCIOPORTIO +This +.Xr ioctl 2 +command allows users to perform I/O to I/O port BARs. +The I/O request parameters are passed in a +.Va struct pci_ioport_io +structure, which has the following fields: +.Bl -tag +.It Vt struct pcisel pii_sel +Describes the device to operate on. +.It Vt int pii_op +The operation to perform. +Currently supported values are +.Dv PCIIOPORT_READ +and +.Dv PCIIOPORT_WRITE . +.It Vt uint32_t pii_bar +The index of the BAR on which to operate. +.It Vt uint32_t pii_offset +The offset into the BAR at which to operate. +.It Vt uint32_t pii_width +The size of the I/O operation. +1-byte, 2-byte and 4-byte operations are supported. +.It Vt uint32_t pii_value +For reads, the value is returned in this field. +For writes, the caller specifies the value to be written in this field. +.El .El .Sh LOADER TUNABLES Tunables can be set at the Index: sys/dev/pci/pci_user.c =================================================================== --- sys/dev/pci/pci_user.c +++ sys/dev/pci/pci_user.c @@ -923,6 +923,84 @@ return (error); } +static int +pci_bar_io(device_t pcidev, struct pci_ioport_io *pii) +{ + struct pci_map *pm; + struct resource *res; + bus_space_handle_t handle; + bus_space_tag_t tag; + uint32_t offset, width; + int error, bar; + + if (pii->pii_op != PCIIOPORT_READ && + pii->pii_op != PCIIOPORT_WRITE) + return (EINVAL); + if (pii->pii_bar > PCIR_MAX_BAR_0) + return (EINVAL); + + bar = PCIR_BAR(pii->pii_bar); + pm = pci_find_bar(pcidev, bar); + if (pm == NULL) + return (EINVAL); + + res = bus_alloc_resource_any(pcidev, SYS_RES_IOPORT, &bar, RF_ACTIVE); + if (res == NULL) + return (ENOENT); + handle = rman_get_bushandle(res); + tag = rman_get_bustag(res); + + offset = pii->pii_offset; + width = pii->pii_width; + + if (offset + width < offset || + rman_get_size(res) < offset + width) { + error = EINVAL; + goto out; + } + + error = 0; + switch (pii->pii_op) { + case PCIIOPORT_READ: + switch (pii->pii_width) { + case 1: + pii->pii_value = bus_space_read_1(tag, handle, offset); + break; + case 2: + pii->pii_value = bus_space_read_2(tag, handle, offset); + break; + case 4: + pii->pii_value = bus_space_read_4(tag, handle, offset); + break; + default: + error = EINVAL; + break; + } + break; + case PCIIOPORT_WRITE: + switch (pii->pii_width) { + case 1: + bus_space_write_1(tag, handle, offset, pii->pii_value); + break; + case 2: + bus_space_write_2(tag, handle, offset, pii->pii_value); + break; + case 4: + bus_space_write_4(tag, handle, offset, pii->pii_value); + break; + default: + error = EINVAL; + break; + } + break; + } + +out: + bus_release_resource(pcidev, SYS_RES_IOPORT, bar, res); + + return (error); +} + static int pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { @@ -932,6 +1010,7 @@ struct pci_conf_io *cio = NULL; struct pci_devinfo *dinfo; struct pci_io *io; + struct pci_ioport_io *pii; struct pci_bar_io *bio; struct pci_list_vpd_io *lvio; struct pci_match_conf *pattern_buf; @@ -1302,6 +1381,19 @@ error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); break; + case PCIOCIOPORTIO: + pii = (struct pci_ioport_io *)data; + + pcidev = pci_find_dbsf(pii->pii_sel.pc_domain, + pii->pii_sel.pc_bus, pii->pii_sel.pc_dev, + pii->pii_sel.pc_func); + if (pcidev == NULL) { + error = ENODEV; + break; + } + error = pci_bar_io(pcidev, pii); + break; + default: error = ENOTTY; break; Index: sys/sys/pciio.h =================================================================== --- sys/sys/pciio.h +++ sys/sys/pciio.h @@ -151,6 +151,17 @@ int pbm_memattr; }; +struct pci_ioport_io { + struct pcisel pii_sel; /* device to operate on */ +#define PCIIOPORT_READ 0x1 +#define PCIIOPORT_WRITE 0x2 + int pii_op; + uint32_t pii_bar; + uint32_t pii_offset; + uint32_t pii_width; + uint32_t pii_value; +}; + #define PCIIO_BAR_MMAP_FIXED 0x01 #define PCIIO_BAR_MMAP_EXCL 0x02 #define PCIIO_BAR_MMAP_RW 0x04 @@ -163,5 +174,6 @@ #define PCIOCGETBAR _IOWR('p', 6, struct pci_bar_io) #define PCIOCLISTVPD _IOWR('p', 7, struct pci_list_vpd_io) #define PCIOCBARMMAP _IOWR('p', 8, struct pci_bar_mmap) +#define PCIOCIOPORTIO _IOWR('p', 9, struct pci_ioport_io) #endif /* !_SYS_PCIIO_H_ */