Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
30424eb
Documentation
LICENSES
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
agp
Kconfig
Makefile
agp.h
ali-agp.c
alpha-agp.c
amd-k7-agp.c
amd64-agp.c
ati-agp.c
backend.c
compat_ioctl.c
compat_ioctl.h
efficeon-agp.c
frontend.c
generic.c
hp-agp.c
i460-agp.c
intel-agp.c
intel-agp.h
intel-gtt.c
isoch.c
nvidia-agp.c
parisc-agp.c
sis-agp.c
sworks-agp.c
uninorth-agp.c
via-agp.c
hw_random
ipmi
mwave
pcmcia
tpm
xilinx_hwicap
xillybus
Kconfig
Makefile
adi.c
apm-emulation.c
applicom.c
applicom.h
bsr.c
ds1620.c
dsp56k.c
dtlk.c
hangcheck-timer.c
hpet.c
lp.c
mem.c
misc.c
mspec.c
nsc_gpio.c
nvram.c
nwbutton.c
nwbutton.h
nwflash.c
pc8736x_gpio.c
powernv-op-panel.c
ppdev.c
ps3flash.c
random.c
scx200_gpio.c
sonypi.c
tb0219.c
tlclk.c
toshiba.c
ttyprintk.c
uv_mmtimer.c
virtio_console.c
clk
clocksource
comedi
connector
counter
cpufreq
cpuidle
crypto
cxl
dax
dca
devfreq
dio
dma-buf
dma
edac
eisa
extcon
firewire
firmware
fpga
fsi
gnss
gpio
gpu
greybus
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
i3c
idle
iio
infiniband
input
interconnect
iommu
ipack
irqchip
isdn
leds
macintosh
mailbox
mcb
md
media
memory
memstick
message
mfd
misc
mmc
most
mtd
mux
net
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
opp
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sh
siox
slimbus
soc
soundwire
spi
spmi
ssb
staging
target
tc
tee
thermal
thunderbolt
tty
uio
usb
vdpa
vfio
vhost
video
virt
virtio
visorbus
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
drivers
/
char
/
agp
/
ati-agp.c
Blame
Blame
Latest commit
History
History
590 lines (491 loc) · 14.6 KB
Breadcrumbs
linux
/
drivers
/
char
/
agp
/
ati-agp.c
Top
File metadata and controls
Code
Blame
590 lines (491 loc) · 14.6 KB
Raw
/* * ATi AGPGART routines. */ #include <linux/types.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/agp_backend.h> #include <asm/agp.h> #include <asm/set_memory.h> #include "agp.h" #define ATI_GART_MMBASE_BAR 1 #define ATI_RS100_APSIZE 0xac #define ATI_RS100_IG_AGPMODE 0xb0 #define ATI_RS300_APSIZE 0xf8 #define ATI_RS300_IG_AGPMODE 0xfc #define ATI_GART_FEATURE_ID 0x00 #define ATI_GART_BASE 0x04 #define ATI_GART_CACHE_SZBASE 0x08 #define ATI_GART_CACHE_CNTRL 0x0c #define ATI_GART_CACHE_ENTRY_CNTRL 0x10 static const struct aper_size_info_lvl2 ati_generic_sizes[7] = { {2048, 524288, 0x0000000c}, {1024, 262144, 0x0000000a}, {512, 131072, 0x00000008}, {256, 65536, 0x00000006}, {128, 32768, 0x00000004}, {64, 16384, 0x00000002}, {32, 8192, 0x00000000} }; static struct gatt_mask ati_generic_masks[] = { { .mask = 1, .type = 0} }; struct ati_page_map { unsigned long *real; unsigned long __iomem *remapped; }; static struct _ati_generic_private { volatile u8 __iomem *registers; struct ati_page_map **gatt_pages; int num_tables; } ati_generic_private; static int ati_create_page_map(struct ati_page_map *page_map) { int i, err; page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); if (page_map->real == NULL) return -ENOMEM; set_memory_uc((unsigned long)page_map->real, 1); err = map_page_into_agp(virt_to_page(page_map->real)); if (err) { free_page((unsigned long)page_map->real); return err; } page_map->remapped = page_map->real; for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { writel(agp_bridge->scratch_page, page_map->remapped+i); readl(page_map->remapped+i); /* PCI Posting. */ } return 0; } static void ati_free_page_map(struct ati_page_map *page_map) { unmap_page_from_agp(virt_to_page(page_map->real)); set_memory_wb((unsigned long)page_map->real, 1); free_page((unsigned long) page_map->real); } static void ati_free_gatt_pages(void) { int i; struct ati_page_map **tables; struct ati_page_map *entry; tables = ati_generic_private.gatt_pages; for (i = 0; i < ati_generic_private.num_tables; i++) { entry = tables[i]; if (entry != NULL) { if (entry->real != NULL) ati_free_page_map(entry); kfree(entry); } } kfree(tables); } static int ati_create_gatt_pages(int nr_tables) { struct ati_page_map **tables; struct ati_page_map *entry; int retval = 0; int i; tables = kcalloc(nr_tables + 1, sizeof(struct ati_page_map *), GFP_KERNEL); if (tables == NULL) return -ENOMEM; for (i = 0; i < nr_tables; i++) { entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL); tables[i] = entry; if (entry == NULL) { retval = -ENOMEM; break; } retval = ati_create_page_map(entry); if (retval != 0) break; } ati_generic_private.num_tables = i; ati_generic_private.gatt_pages = tables; if (retval != 0) ati_free_gatt_pages(); return retval; } static int is_r200(void) { if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) || (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) || (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) || (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250)) return 1; return 0; } static int ati_fetch_size(void) { int i; u32 temp; struct aper_size_info_lvl2 *values; if (is_r200()) pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); else pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); temp = (temp & 0x0000000e); values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes); for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); agp_bridge->aperture_size_idx = i; return values[i].size; } } return 0; } static void ati_tlbflush(struct agp_memory * mem) { writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL); readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL); /* PCI Posting. */ } static void ati_cleanup(void) { struct aper_size_info_lvl2 *previous_size; u32 temp; previous_size = A_SIZE_LVL2(agp_bridge->previous_size); /* Write back the previous size and disable gart translation */ if (is_r200()) { pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp); } else { pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); temp = ((temp & ~(0x0000000f)) | previous_size->size_value); pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); } iounmap((volatile u8 __iomem *)ati_generic_private.registers); } static int ati_configure(void) { phys_addr_t reg; u32 temp; /* Get the memory mapped registers */ reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR); ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096); if (!ati_generic_private.registers) return -ENOMEM; if (is_r200()) pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); else pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); /* address to map to */ /* agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev, AGP_APERTURE_BAR); printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); */ writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */ pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp); pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14)); /* Write out the address of the gatt table */ writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE); readl(ati_generic_private.registers+ATI_GART_BASE); /* PCI Posting. */ return 0; } #ifdef CONFIG_PM static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) { pci_save_state(dev); pci_set_power_state(dev, PCI_D3hot); return 0; } static int agp_ati_resume(struct pci_dev *dev) { pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); return ati_configure(); } #endif /* *Since we don't need contiguous memory we just try * to get the gatt table once */ #define GET_PAGE_DIR_OFF(addr) (addr >> 22) #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr)) #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) #undef GET_GATT #define GET_GATT(addr) (ati_generic_private.gatt_pages[\ GET_PAGE_DIR_IDX(addr)]->remapped) static int ati_insert_memory(struct agp_memory * mem, off_t pg_start, int type) { int i, j, num_entries; unsigned long __iomem *cur_gatt; unsigned long addr; int mask_type; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; mask_type = agp_generic_type_to_mask_type(mem->bridge, type); if (mask_type != 0 || type != mem->type) return -EINVAL; if (mem->page_count == 0) return 0; if ((pg_start + mem->page_count) > num_entries) return -EINVAL; j = pg_start; while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr)))) return -EBUSY; j++; } if (!mem->is_flushed) { /*CACHE_FLUSH(); */ global_cache_flush(); mem->is_flushed = true; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->driver->mask_memory(agp_bridge, page_to_phys(mem->pages[i]), mem->type), cur_gatt+GET_GATT_OFF(addr)); } readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, int type) { int i; unsigned long __iomem *cur_gatt; unsigned long addr; int mask_type; mask_type = agp_generic_type_to_mask_type(mem->bridge, type); if (mask_type != 0 || type != mem->type) return -EINVAL; if (mem->page_count == 0) return 0; for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } static int ati_create_gatt_table(struct agp_bridge_data *bridge) { struct aper_size_info_lvl2 *value; struct ati_page_map page_dir; unsigned long __iomem *cur_gatt; unsigned long addr; int retval; u32 temp; int i; struct aper_size_info_lvl2 *current_size; value = A_SIZE_LVL2(agp_bridge->current_size); retval = ati_create_page_map(&page_dir); if (retval != 0) return retval; retval = ati_create_gatt_pages(value->num_entries / 1024); if (retval != 0) { ati_free_page_map(&page_dir); return retval; } agp_bridge->gatt_table_real = (u32 *)page_dir.real; agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped; agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); /* Write out the size register */ current_size = A_SIZE_LVL2(agp_bridge->current_size); if (is_r200()) { pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); temp = (((temp & ~(0x0000000e)) | current_size->size_value) | 0x00000001); pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp); pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp); } else { pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); temp = (((temp & ~(0x0000000e)) | current_size->size_value) | 0x00000001); pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp); pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp); } /* * Get the address for the gart region. * This is a bus address even on the alpha, b/c its * used to program the agp master not the cpu */ addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR); agp_bridge->gart_bus_addr = addr; /* Calculate the agp offset */ for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1, page_dir.remapped+GET_PAGE_DIR_OFF(addr)); readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ } for (i = 0; i < value->num_entries; i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); } return 0; } static int ati_free_gatt_table(struct agp_bridge_data *bridge) { struct ati_page_map page_dir; page_dir.real = (unsigned long *)agp_bridge->gatt_table_real; page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table; ati_free_gatt_pages(); ati_free_page_map(&page_dir); return 0; } static const struct agp_bridge_driver ati_generic_bridge = { .owner = THIS_MODULE, .aperture_sizes = ati_generic_sizes, .size_type = LVL2_APER_SIZE, .num_aperture_sizes = 7, .needs_scratch_page = true, .configure = ati_configure, .fetch_size = ati_fetch_size, .cleanup = ati_cleanup, .tlb_flush = ati_tlbflush, .mask_memory = agp_generic_mask_memory, .masks = ati_generic_masks, .agp_enable = agp_generic_enable, .cache_flush = global_cache_flush, .create_gatt_table = ati_create_gatt_table, .free_gatt_table = ati_free_gatt_table, .insert_memory = ati_insert_memory, .remove_memory = ati_remove_memory, .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids ati_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_ATI_RS100, .chipset_name = "IGP320/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS200, .chipset_name = "IGP330/340/345/350/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS200_B, .chipset_name = "IGP345M", }, { .device_id = PCI_DEVICE_ID_ATI_RS250, .chipset_name = "IGP7000/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS300_100, .chipset_name = "IGP9100/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS300_133, .chipset_name = "IGP9100/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS300_166, .chipset_name = "IGP9100/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS300_200, .chipset_name = "IGP9100/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS350_133, .chipset_name = "IGP9000/M", }, { .device_id = PCI_DEVICE_ID_ATI_RS350_200, .chipset_name = "IGP9100/M", }, { }, /* dummy final entry, always present */ }; static int agp_ati_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_device_ids *devs = ati_agp_device_ids; struct agp_bridge_data *bridge; u8 cap_ptr; int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; /* probe for known chipsets */ for (j = 0; devs[j].chipset_name; j++) { if (pdev->device == devs[j].device_id) goto found; } dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n", pdev->vendor, pdev->device); return -ENODEV; found: bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; bridge->dev = pdev; bridge->capndx = cap_ptr; bridge->driver = &ati_generic_bridge; dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } static void agp_ati_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); agp_remove_bridge(bridge); agp_put_bridge(bridge); } static const struct pci_device_id agp_ati_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_ATI, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { } }; MODULE_DEVICE_TABLE(pci, agp_ati_pci_table); static struct pci_driver agp_ati_pci_driver = { .name = "agpgart-ati", .id_table = agp_ati_pci_table, .probe = agp_ati_probe, .remove = agp_ati_remove, #ifdef CONFIG_PM .suspend = agp_ati_suspend, .resume = agp_ati_resume, #endif }; static int __init agp_ati_init(void) { if (agp_off) return -EINVAL; return pci_register_driver(&agp_ati_pci_driver); } static void __exit agp_ati_cleanup(void) { pci_unregister_driver(&agp_ati_pci_driver); } module_init(agp_ati_init); module_exit(agp_ati_cleanup); MODULE_AUTHOR("Dave Jones"); MODULE_LICENSE("GPL and additional rights");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
You can’t perform that action at this time.