#define PIIX_FLAGS_PREFETCH 4
#define PIIX_FLAGS_FAST_DMA 8
-typedef struct {
- unsigned d0_flags :4;
- unsigned d1_flags :4;
- unsigned recovery :2;
- unsigned reserved :2;
- unsigned sample :2;
- unsigned sidetim_enabled:1;
- unsigned ports_enabled :1;
-} piix_timing_t;
+
+union chip_en_reg_u {
+ struct {
+ unsigned d0_flags :4;
+ unsigned d1_flags :4;
+ unsigned recovery :2;
+ unsigned reserved :2;
+ unsigned sample :2;
+ unsigned sidetim_enabled:1;
+ unsigned ports_enabled :1;
+ } piix_s;
+ struct {
+ unsigned sec_en :1;
+ unsigned pri_en :1;
+ unsigned reserved :14;
+ } via_s;
+};
+
+typedef union chip_en_reg_u piix_timing_t;
typedef struct {
unsigned pri_recovery :2;
printk("%s: pcibios read failed\n", HWIF(drive)->name);
return 1;
}
- dflags = drive->select.b.unit ? timing.d1_flags : timing.d0_flags;
+ dflags = drive->select.b.unit ? timing.piix_s.d1_flags : timing.piix_s.d0_flags;
if (dflags & PIIX_FLAGS_FAST_PIO) {
if (func == ide_dma_on && drive->media == ide_disk)
dflags |= PIIX_FLAGS_FAST_DMA;
else
dflags &= ~PIIX_FLAGS_FAST_DMA;
if (drive->select.b.unit == 0)
- timing.d0_flags = dflags;
+ timing.piix_s.d0_flags = dflags;
else
- timing.d1_flags = dflags;
+ timing.piix_s.d1_flags = dflags;
if (pcibios_write_config_word(piix_pci_bus, piix_pci_fn, reg, *(short *)&timing)) {
printk("%s: pcibios write failed\n", HWIF(drive)->name);
return 1;
chipset = "PIIX4";
else if (devid == PCI_DEVICE_ID_INTEL_82371SB_1)
chipset = "PIIX3";
- else
+ else if (devid == PCI_DEVICE_ID_INTEL_82371_1)
chipset = "PIIX";
+ else if (devid == PCI_DEVICE_ID_VIA_82C586_1)
+ chipset = "VP1";
+ else {
+ printk("Unknown PCI IDE interface 0x%x\n", devid);
+ goto quit;
+ }
printk("%s: bus-master IDE device on PCI bus %d function %d\n", chipset, bus, fn);
printk("%s: IDE ports are not enabled (BIOS)\n", chipset);
goto quit;
}
- if ((rc = pcibios_read_config_word(bus, fn, 0x40, (short *)&timings[0])))
- goto quit;
- if ((rc = pcibios_read_config_word(bus, fn, 0x42, (short *)&timings[1])))
- goto quit;
- if ((!timings[0].ports_enabled) && (!timings[1].ports_enabled)) {
- printk("%s: neither IDE port is enabled\n", chipset);
- goto quit;
+ if (devid == PCI_DEVICE_ID_VIA_82C586_1) {
+ /* pri and sec channel enables are in port 0x40 */
+ if ((rc = pcibios_read_config_word(bus, fn, 0x40, (short *)&timings[0])))
+ goto quit;
+ if ((!timings[0].via_s.pri_en && (!timings[0].via_s.sec_en))) {
+ printk("%s: neither IDE port is enabled\n", chipset);
+ goto quit;
+ }
+ }
+ else { /* INTEL piix */
+ if ((rc = pcibios_read_config_word(bus, fn, 0x40, (short *)&timings[0])))
+ goto quit;
+ if ((rc = pcibios_read_config_word(bus, fn, 0x42, (short *)&timings[1])))
+ goto quit;
+ if ((!timings[0].piix_s.ports_enabled) && (!timings[1].piix_s.ports_enabled)) {
+ printk("%s: neither IDE port is enabled\n", chipset);
+ goto quit;
+ }
}
/*
case 0x170: pri_sec = 1; break;
default: continue;
}
+
+ if (devid == PCI_DEVICE_ID_VIA_82C586_1) {
+ timing = timings[0];
+ switch (h) {
+ case 0:
+ if (!timing.piix_s.ports_enabled) {
+ printk("port 0 DMA not enabled\n");
+ continue;
+ }
+ case 1:
+ if (!timing.piix_s.sidetim_enabled) {
+ printk("port 1 DMA not enabled\n");
+ continue;
+ }
+ }
+ hwif->chipset = ide_via;
+ }
+ else { /* PIIX */
+
timing = timings[pri_sec];
- if (!timing.ports_enabled) /* interface disabled? */
+ if (!timing.piix_s.ports_enabled) /* interface disabled? */
continue;
hwif->chipset = ide_triton;
+ }
if (dma_enabled)
init_piix_dma(hwif, bmiba + (pri_sec ? 8 : 0));
#ifdef DISPLAY_PIIX_TIMINGS
{
const char *slave;
piix_sidetim_t sidetim;
- byte sample = 5 - timing.sample;
- byte recovery = 4 - timing.recovery;
+ byte sample = 5 - timing.piix_s.sample;
+ byte recovery = 4 - timing.piix_s.recovery;
+ unsigned int drvtim;
+
+ if (devid == PCI_DEVICE_ID_VIA_82C586_1) {
+ pcibios_read_config_dword(bus, fn, 0x48, &drvtim);
+ if (pri_sec == 0) {
+ printk(" %s master: active_pulse_CLKs=%d, recovery_CLKs=%d\n", hwif->name, 1+(drvtim>>28), 1+((drvtim & 0x0f000000)>>24));
+ printk(" %s slave: active_pulse_CLKs=%d, recovery_CLKs=%d\n", hwif->name, 1+((drvtim & 0xf00000)>>20), 1+((drvtim & 0x0f0000)>>16));
+ continue;
+ } else {
+ printk(" %s master: active_pulse_CLKs=%d, recovery_CLKs=%d\n", hwif->name, 1+((drvtim & 0xf000)>>12), 1+((drvtim & 0x0f00)>>8));
+ printk(" %s slave: active_pulse_CLKs=%d, recovery_CLKs=%d\n", hwif->name, 1+((drvtim & 0xf0)>>4), 1+(drvtim & 0x0f));
+ continue;
+ }
+ }
+
if ((devid == PCI_DEVICE_ID_INTEL_82371SB_1
|| devid == PCI_DEVICE_ID_INTEL_82371AB)
- && timing.sidetim_enabled
+ && timing.piix_s.sidetim_enabled
&& !pcibios_read_config_byte(bus, fn, 0x44, (byte *) &sidetim))
slave = ""; /* PIIX3 and later */
else
slave = "/slave"; /* PIIX, or PIIX3 in compatibility mode */
printk(" %s master%s: sample_CLKs=%d, recovery_CLKs=%d\n", hwif->name, slave, sample, recovery);
- print_piix_drive_flags ("master:", timing.d0_flags);
+ print_piix_drive_flags ("master:", timing.piix_s.d0_flags);
if (!*slave) {
if (pri_sec == 0) {
sample = 5 - sidetim.pri_sample;
}
printk(" slave : sample_CLKs=%d, recovery_CLKs=%d\n", sample, recovery);
}
- print_piix_drive_flags ("slave :", timing.d1_flags);
+ print_piix_drive_flags ("slave :", timing.piix_s.d1_flags);
}
#endif /* DISPLAY_PIIX_TIMINGS */
}
#include <linux/fs.h>
#include <linux/dalloc.h>
#include <linux/dlists.h>
+#include <linux/malloc.h>
/* this should be removed after the beta phase */
/* #define DEBUG */
#define D_RECURSIVE 4
#define D_NO_FREE 8
-/* adjust these constants if you know a probability distribution ... */
-#define D_SMALL 16
-#define D_MEDIUM 64
-#define D_LARGE 256
-#define D_HUGE D_MAXLEN
-
-#define BASE_DHEADER(x) (struct dheader*)((unsigned long)(x) & ~(PAGE_SIZE-1))
-#define BYTE_ADD(x,n) (void*)((char*)(x) + (n))
-#define BYTE_SUB(x,n) (void*)((char*)(x) - (n))
-
-/* This is for global allocation of dentries. Remove this when
- * converting to SLAB.
- */
-struct dheader {
- struct dentry * emptylist;
- short free, maxfree;
- struct dheader * next;
- struct dheader * prev;
-};
-
-struct anchors {
- struct dheader * free; /* each contains at least 1 empty dentry */
- struct dheader * full; /* all the used up ones */
- struct dheader * dir_free;
- struct dheader * dir_full;
-};
-
/* This is only used for directory dentries. Think of it as an extension
* of the dentry.
* It is defined as separate struct, so it uses up space only
unsigned short dd_negs; /* # of negative entries */
};
-DEF_INSERT(header,struct dheader,next,prev)
-DEF_REMOVE(header,struct dheader,next,prev)
-
DEF_INSERT(alias,struct dentry,d_next,d_prev)
DEF_REMOVE(alias,struct dentry,d_next,d_prev)
DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev)
DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev)
-static struct anchors anchors[4];
-
struct dentry * the_root = NULL;
unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
{
- memset(anchors, 0, sizeof(anchors));
return mem_start;
}
{
if(!IS_ROOT(entry))
printpath(entry->d_parent);
- printk("/%s", entry->d_name);
+ printk("/%s", entry->d_name.name);
}
static inline long has_sons(struct ddir * ddir)
panic("VFS: dcache directory corruption");
}
+/*
+ * IF this is a directory, the ddir has been allocated right
+ * after the dentry.
+ */
static inline struct ddir * d_dir(struct dentry * entry)
{
- struct ddir * res = BYTE_SUB(entry, sizeof(struct ddir));
-
if(!(entry->d_flag & D_DIR))
d_panic();
-#ifdef DEBUG
- if(!entry)
- panic("entry NULL!");
- if(BASE_DHEADER(res) != BASE_DHEADER(entry))
- printk("Scheisse!!!\n");
-#endif
- return res;
+ return (struct ddir *) (entry+1);
}
-static /*inline*/ struct dheader * dinit(int isdir, int size)
+#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
+
+struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
{
- struct dheader * res = (struct dheader*)__get_free_page(GFP_KERNEL);
- int restlen = PAGE_SIZE - sizeof(struct dheader);
- struct dentry * ptr = BYTE_ADD(res, sizeof(struct dheader));
+ struct dentry *res;
+ int size = sizeof(struct dentry);
+ int flag = 0;
- if(!res)
- return NULL;
- memset(res, 0, sizeof(struct dheader));
- if(isdir) {
- ptr = BYTE_ADD(ptr, sizeof(struct ddir));
+ if (isdir) {
size += sizeof(struct ddir);
+ flag = D_DIR;
}
- if(BASE_DHEADER(ptr) != res)
- panic("Bad kernel page alignment");
- size += sizeof(struct dentry) - D_MAXLEN;
- res->emptylist = NULL;
- res->free = 0;
- while(restlen >= size) {
-#ifdef DEBUG
- ins(ptr);
- if(BASE_DHEADER(ptr) != res)
- panic("Wrong dinit!");
-#endif
- ptr->d_next = res->emptylist;
- res->emptylist = ptr;
- ptr = BYTE_ADD(ptr, size);
- res->free++;
- restlen -= size;
- }
- res->maxfree = res->free;
- return res;
-}
+ res = kmalloc(size, GFP_KERNEL);
+ if (!res)
+ return NULL;
+ memset(res, 0, size);
+ res->d_flag = flag;
-static /*inline*/ struct dentry * __dalloc(struct anchors * anchor,
- struct dentry * parent, int isdir,
- int len, int size)
-{
- struct dheader ** free = isdir ? &anchor->dir_free : &anchor->free;
- struct dheader ** full = isdir ? &anchor->dir_full : &anchor->full;
- struct dheader * base = *free;
- struct dentry * res;
-
- if(!base) {
- base = dinit(isdir, size);
- if(!base)
- return NULL;
- insert_header(free, base);
- }
- base->free--;
- res = base->emptylist;
- if(!(base->emptylist = res->d_next)) {
- remove_header(free, base);
- insert_header(full, base);
- }
- memset(res, 0, sizeof(struct dentry) - D_MAXLEN);
- if(isdir) {
- res->d_flag = D_DIR;
- memset(d_dir(res), 0, sizeof(struct ddir));
+ res->d_name.name = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+ if (!res->d_name.name) {
+ kfree(res);
+ return NULL;
}
- res->d_len = len;
+
+ res->d_name.len = len;
res->d_parent = parent;
if(parent) {
struct ddir * pdir = d_dir(parent);
return res;
}
-struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
-{
- int i, size;
-
-#ifdef DEBUG
- if(the_root)
- recursive_test(the_root);
- LOG("d_alloc", parent);
-#endif
- if(len >= D_MEDIUM) {
- if(len >= D_LARGE) {
- i = 3;
- size = D_HUGE;
- } else {
- i = 2;
- size = D_LARGE;
- }
- } else if(len >= D_SMALL) {
- i = 1;
- size = D_MEDIUM;
- } else {
- i = 0;
- size = D_SMALL;
- }
- return __dalloc(&anchors[i], parent, isdir, len, size);
-}
-
extern blocking struct dentry * d_alloc_root(struct inode * root_inode)
{
struct dentry * res = the_root;
the_root = res = d_alloc(NULL, 0, 1);
LOG("d_alloc_root", res);
res->d_parent = res;
- res->d_name[0]='\0';
+ res->d_name.name[0]='\0';
ddir = d_dir(res);
ddir->dd_alloced = 999; /* protect from deletion */
}
static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry)
{
- return &pdir->dd_hashtable[d_hash(entry->d_name[0],
- entry->d_name[entry->d_len-1])];
+ return &pdir->dd_hashtable[d_hash(entry->d_name.name[0],
+ entry->d_name.name[entry->d_name.len-1])];
}
static inline struct dentry ** d_base_qstr(struct ddir * pdir,
}
static /*inline*/ blocking void _d_del(struct dentry * entry,
- struct anchors * anchor,
int flags)
{
- struct dheader ** free;
- struct dheader ** full;
- struct dheader * base = BASE_DHEADER(entry);
struct ddir * ddir = NULL;
struct ddir * pdir;
struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode;
printk("VFS: dcache parent is NULL\n");
return;
}
- if(entry->d_flag & D_DIR) {
- free = &anchor->dir_free;
- full = &anchor->dir_full;
- } else {
- free = &anchor->free;
- full = &anchor->full;
- }
pdir = d_dir(entry->d_parent);
if(!IS_ROOT(entry))
_d_remove_from_parent(entry, pdir, inode, flags);
}
}
if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) {
- base->free++;
- if(base->free == base->maxfree) {
-#ifndef DEBUG
- remove_header(free, base);
- free_page((unsigned long)base);
- goto done;
-#endif
- }
- entry->d_next = base->emptylist;
- base->emptylist = entry;
- if(!entry->d_next) {
- remove_header(full, base);
- insert_header(free, base);
- }
+ kfree(entry->d_name.name);
+ kfree(entry);
#ifdef DEBUG
x_freed++;
#endif
}
-#ifndef DEBUG
-done:
-#else
+#ifdef DEBUG
x_free++;
#endif
}
blocking void d_del(struct dentry * entry, int flags)
{
- int i;
-
if(!entry)
return;
LOG("d_clear", entry);
- if(entry->d_len >= D_MEDIUM) {
- if(entry->d_len >= D_LARGE) {
- i = 3;
- } else {
- i = 2;
- }
- } else if(entry->d_len >= D_SMALL) {
- i = 1;
- } else {
- i = 0;
- }
- _d_del(entry, &anchors[i], flags);
+ _d_del(entry, flags);
}
static inline struct dentry * __dlookup(struct dentry ** base,
if(appendix)
totallen += appendix->len;
do {
- if(tmp->d_len == totallen &&
+ if(tmp->d_name.len == totallen &&
!(tmp->d_flag & D_DUPLICATE) &&
- !strncmp(tmp->d_name, name->name, name->len) &&
- (!appendix || !strncmp(tmp->d_name+name->len,
+ !strncmp(tmp->d_name.name, name->name, name->len) &&
+ (!appendix || !strncmp(tmp->d_name.name+name->len,
appendix->name, appendix->len)))
return tmp;
tmp = tmp->d_hash_next;
if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) {
struct dentry * tmp = inode->i_dentry;
printk("Auweia inode=%p entry=%p (%p %p %s)\n",
- inode, entry, parent->u.d_inode, parent, parent->d_name);
+ inode, entry, parent->u.d_inode, parent, parent->d_name.name);
printk("entry path="); printpath(entry); printk("\n");
do {
TST("auweia",tmp);
LOG("d_add", entry);
#endif
if(ininame) {
- if(ininame->len != entry->d_len) {
+ if(ininame->len != entry->d_name.len) {
printk("VFS: d_add with wrong string length");
- entry->d_len = ininame->len; /* kludge */
+ entry->d_name.len = ininame->len; /* kludge */
}
- memcpy(entry->d_name, ininame->name, ininame->len);
- entry->d_name[ininame->len] = '\0';
+ memcpy(entry->d_name.name, ininame->name, ininame->len);
+ entry->d_name.name[ininame->len] = '\0';
} else {
- dummy.name = entry->d_name;
- dummy.len = entry->d_len;
+ dummy.name = entry->d_name.name;
+ dummy.len = entry->d_name.len;
ininame = &dummy;
}
if(entry->d_flag & D_HASHED)
}
}
+static inline void alloc_new_name(struct dentry * entry, int len)
+{
+ int alloc_len = NAME_ALLOC_LEN(len);
+ char *name;
+
+ if (alloc_len == NAME_ALLOC_LEN(entry->d_name.len))
+ return;
+ name = kmalloc(alloc_len, GFP_KERNEL);
+ if (!name)
+ printk("out of memory for dcache\n");
+ kfree(entry->d_name.name);
+ entry->d_name.name = name;
+}
+
+static inline void d_remove_old_parent(struct dentry * entry)
+{
+ struct ddir * pdir;
+ struct inode * inode;
+
+ pdir = d_dir(entry->d_parent);
+ inode = entry->u.d_inode;
+ _d_remove_from_parent(entry, pdir, inode, D_NO_CLEAR_INODE);
+}
+
+static inline void d_add_new_parent(struct dentry * entry, struct inode * new_parent)
+{
+ struct ddir * pdir;
+ struct inode * inode;
+
+ pdir = d_dir(entry->d_parent = new_parent->i_dentry);
+ inode = entry->u.d_inode;
+
+ _d_insert_to_parent(entry, pdir, inode, &entry->d_name, entry->d_flag);
+}
+
+
blocking void d_move(struct dentry * entry, struct inode * newdir,
struct qstr * newname, struct qstr * newapp)
{
- struct ddir tmp;
- struct dentry * new;
struct inode * inode;
int len;
int flags;
return;
}
#if 0
-printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name,
+printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name.name,
newname->name, newapp ? newapp->name : "", inode->i_dent_count);
#endif
if(flags & D_ZOMBIE) {
printk("VFS: moving zombie entry\n");
}
- if(flags & D_DIR) {
- struct ddir * ddir = d_dir(entry);
- memcpy(&tmp, ddir, sizeof(struct ddir));
+ d_remove_old_parent(entry);
- /* Simulate empty dir for d_del(). */
- memset(ddir, 0, sizeof(struct ddir));
- }
len = newname->len;
if(newapp) {
len += newapp->len;
flags |= D_BASKET;
} else
flags &= ~D_BASKET;
- new = d_alloc(newdir->i_dentry, len, flags & D_DIR);
- memcpy(new->d_name, newname->name, newname->len);
+ alloc_new_name(entry, len);
+ memcpy(entry->d_name.name, newname->name, newname->len);
if(newapp)
- memcpy(new->d_name+newname->len, newapp->name, newapp->len);
- new->d_name[len] = '\0';
- d_del(entry, D_NO_CLEAR_INODE);
- d_add(new, inode, NULL, flags & (D_DIR|D_BASKET));
- if(flags & D_DIR) {
- struct ddir * ddir = d_dir(new);
-
- memcpy(ddir, &tmp, sizeof(struct ddir));
- }
+ memcpy(entry->d_name.name+newname->len, newapp->name, newapp->len);
+ entry->d_name.name[len] = '\0';
+ entry->d_name.len = len;
+
+ d_add_new_parent(entry, newdir);
}
int d_path(struct dentry * entry, struct inode * chroot, char * buf)
*buf++ = '/';
len++;
}
- memcpy(buf, entry->d_name, entry->d_len);
- return len + entry->d_len;
+ memcpy(buf, entry->d_name.name, entry->d_name.len);
+ return len + entry->d_name.len;
}
}
#ifdef CONFIG_DCACHE_PRELOAD
if(entry->d_flag & D_PRELIMINARY) {
- struct qstr name = { entry->d_name, entry->d_len };
+ struct qstr name = { entry->d_name.name, entry->d_name.len };
struct ddir * pdir = d_dir(entry->d_parent);
struct dentry ** base = d_base_qstr(pdir, &name, NULL);
struct dentry * found;
d_del(entry, D_NO_CLEAR_INODE);
*changing_entry = found;
} else if(S_ISDIR(inode->i_mode)) {
- struct dentry * new = d_alloc(entry->d_parent, entry->d_len, 1);
+ struct dentry * new = d_alloc(entry->d_parent, entry->d_name.len, 1);
if(new)
d_add(new, inode, &name, D_DIR);
*changing_entry = new;