LinuxKPI: Import MTRR support functions from drm-kmod

They are superseded by PAT and mostly useless nowadays but still can be
used on Pentium III/IV era processors. Unlike drm-kmod version, this one
ignores MTRR if PAT is available that fixes confusing "Failed to add WC
MTRR for [0xXXXX-0xYYYY]: 22; performance may suffer" message often
appearing during drm-kmod initialization process.

MFC after:	1 week
Reviewed by:	hselasky, manu
Differential Revision:	https://reviews.freebsd.org/D33561
This commit is contained in:
Vladimir Kondratyev 2021-12-09 00:12:51 +03:00
parent 1456816425
commit 98b129783c
2 changed files with 80 additions and 0 deletions

View File

@ -482,4 +482,12 @@ memunmap(void *addr)
iounmap(addr);
}
#define __MTRR_ID_BASE 1
int lkpi_arch_phys_wc_add(unsigned long, unsigned long);
void lkpi_arch_phys_wc_del(int);
#define arch_phys_wc_add(...) lkpi_arch_phys_wc_add(__VA_ARGS__)
#define arch_phys_wc_del(...) lkpi_arch_phys_wc_del(__VA_ARGS__)
#define arch_phys_wc_index(x) \
(((x) < __MTRR_ID_BASE) ? -1 : ((x) - __MTRR_ID_BASE))
#endif /* _LINUX_IO_H_ */

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/rwlock.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/memrange.h>
#include <machine/bus.h>
@ -63,6 +64,15 @@ __FBSDID("$FreeBSD$");
#include <linux/preempt.h>
#include <linux/fs.h>
#include <linux/shmem_fs.h>
#include <linux/kernel.h>
#include <linux/idr.h>
#include <linux/io.h>
#ifdef __i386__
DEFINE_IDR(mtrr_idr);
static MALLOC_DEFINE(M_LKMTRR, "idr", "Linux MTRR compat");
extern int pat_works;
#endif
void
si_meminfo(struct sysinfo *si)
@ -357,3 +367,65 @@ lkpi_unmap_mapping_range(void *obj, loff_t const holebegin __unused,
vm_object_deallocate(devobj);
}
}
int
lkpi_arch_phys_wc_add(unsigned long base, unsigned long size)
{
#ifdef __i386__
struct mem_range_desc *mrdesc;
int error, id, act;
/* If PAT is available, do nothing */
if (pat_works)
return (0);
mrdesc = malloc(sizeof(*mrdesc), M_LKMTRR, M_WAITOK);
mrdesc->mr_base = base;
mrdesc->mr_len = size;
mrdesc->mr_flags = MDF_WRITECOMBINE;
strlcpy(mrdesc->mr_owner, "drm", sizeof(mrdesc->mr_owner));
act = MEMRANGE_SET_UPDATE;
error = mem_range_attr_set(mrdesc, &act);
if (error == 0) {
error = idr_get_new(&mtrr_idr, mrdesc, &id);
MPASS(idr_find(&mtrr_idr, id) == mrdesc);
if (error != 0) {
act = MEMRANGE_SET_REMOVE;
mem_range_attr_set(mrdesc, &act);
}
}
if (error != 0) {
free(mrdesc, M_LKMTRR);
pr_warn(
"Failed to add WC MTRR for [%p-%p]: %d; "
"performance may suffer\n",
(void *)base, (void *)(base + size - 1), error);
} else
pr_warn("Successfully added WC MTRR for [%p-%p]\n",
(void *)base, (void *)(base + size - 1));
return (error != 0 ? -error : id + __MTRR_ID_BASE);
#else
return (0);
#endif
}
void
lkpi_arch_phys_wc_del(int reg)
{
#ifdef __i386__
struct mem_range_desc *mrdesc;
int act;
/* Check if arch_phys_wc_add() failed. */
if (reg < __MTRR_ID_BASE)
return;
mrdesc = idr_find(&mtrr_idr, reg - __MTRR_ID_BASE);
MPASS(mrdesc != NULL);
idr_remove(&mtrr_idr, reg - __MTRR_ID_BASE);
act = MEMRANGE_SET_REMOVE;
mem_range_attr_set(mrdesc, &act);
free(mrdesc, M_LKMTRR);
#endif
}