Skip to Content.
Sympa Menu

sm-commit - [SM-Commit] GIT changes to master z-rejected grimoire by Florian Franzmann (de4d893a8f4973d32f3a272e9db2954e7e0eedf8)

sm-commit AT lists.ibiblio.org

Subject: Source Mage code commit list

List archive

Chronological Thread  
  • From: Florian Franzmann <scm AT sourcemage.org>
  • To: sm-commit AT lists.ibiblio.org
  • Subject: [SM-Commit] GIT changes to master z-rejected grimoire by Florian Franzmann (de4d893a8f4973d32f3a272e9db2954e7e0eedf8)
  • Date: Sun, 7 Jul 2013 04:09:21 -0500

GIT changes to master z-rejected grimoire by Florian Franzmann
<siflfran AT hawo.stw.uni-erlangen.de>:

z-kernels/nvidia_driver/HISTORY | 4
z-kernels/nvidia_driver/PRE_BUILD | 4
z-kernels/nvidia_driver/nvidia-linux-3.10.patch | 602
++++++++++++++++++++++++
3 files changed, 609 insertions(+), 1 deletion(-)

New commits:
commit de4d893a8f4973d32f3a272e9db2954e7e0eedf8
Author: Florian Franzmann <siflfran AT hawo.stw.uni-erlangen.de>
Commit: Florian Franzmann <siflfran AT hawo.stw.uni-erlangen.de>

z-kernels/nvidia_driver: apply patch to avoid build error with linux 3.10

diff --git a/z-kernels/nvidia_driver/HISTORY b/z-kernels/nvidia_driver/HISTORY
index fb95f6f..7983904 100644
--- a/z-kernels/nvidia_driver/HISTORY
+++ b/z-kernels/nvidia_driver/HISTORY
@@ -1,3 +1,7 @@
+2013-07-07 Florian Franzmann <siflfran AT hawo.stw.uni-erlangen.de>
+ * PRE_BUILD, nvidia-linux-3.10.patch: apply patch from archlinux
+ to prevent build error with linux 3.10
+
2013-05-25 Florian Franzmann <siflfran AT hawo.stw.uni-erlangen.de>
* DETAILS: 319.23 (x86_64)

diff --git a/z-kernels/nvidia_driver/PRE_BUILD
b/z-kernels/nvidia_driver/PRE_BUILD
index e89cf99..4bc8ce2 100755
--- a/z-kernels/nvidia_driver/PRE_BUILD
+++ b/z-kernels/nvidia_driver/PRE_BUILD
@@ -17,4 +17,6 @@ sedit 's:depmod -ae:& \$(KERNEL_UNAME):'
kernel/Makefile.kbuild &&
# Setup Makefile symlink
#
cd $SOURCE_DIRECTORY/kernel &&
-ln -sfn Makefile.kbuild Makefile
+ln -sfn Makefile.kbuild Makefile &&
+
+patch -Np2 < $SPELL_DIRECTORY/nvidia-linux-3.10.patch
diff --git a/z-kernels/nvidia_driver/nvidia-linux-3.10.patch
b/z-kernels/nvidia_driver/nvidia-linux-3.10.patch
new file mode 100644
index 0000000..621c29c
--- /dev/null
+++ b/z-kernels/nvidia_driver/nvidia-linux-3.10.patch
@@ -0,0 +1,602 @@
+--- NVIDIA-Linux-x86_64-319.17-no-compat32.orig/kernel/nv-i2c.c
2013-04-26 00:22:30.000000000 -0400
++++ NVIDIA-Linux-x86_64-319.17-no-compat32/kernel/nv-i2c.c 2013-05-13
05:20:55.571981365 -0400
+@@ -311,8 +311,6 @@
+ BOOL NV_API_CALL nv_i2c_del_adapter(nv_state_t *nv, void *data)
+ {
+ struct i2c_adapter *pI2cAdapter = (struct i2c_adapter *)data;
+- int osstatus = 0;
+- BOOL wasReleased = FALSE;
+
+ #if defined(KERNEL_2_4)
+ if (!NV_WEAK_SYMBOL_PRESENT(i2c_add_adapter))
+@@ -324,15 +322,10 @@
+ if (!pI2cAdapter) return FALSE;
+
+ // attempt release with the OS
+- osstatus = i2c_del_adapter(pI2cAdapter);
++ i2c_del_adapter(pI2cAdapter);
++ os_free_mem(pI2cAdapter);
+
+- if (!osstatus)
+- {
+- os_free_mem(pI2cAdapter);
+- wasReleased = TRUE;
+- }
+-
+- return wasReleased;
++ return TRUE;
+ }
+
+ #else // (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE))
+diff -ur -X - NVIDIA-Linux-x86_64-319.17-no-compat32.orig/kernel/nv-procfs.c
NVIDIA-Linux-x86_64-319.17-no-compat32/kernel/nv-procfs.c
+--- NVIDIA-Linux-x86_64-319.17-no-compat32.orig/kernel/nv-procfs.c
2013-04-26 00:22:30.000000000 -0400
++++ NVIDIA-Linux-x86_64-319.17-no-compat32/kernel/nv-procfs.c 2013-05-22
04:52:45.229495748 -0400
+@@ -60,60 +60,41 @@
+ __entry; \
+ })
+
+-#define NV_CREATE_PROC_FILE(name,parent,__read_proc, \
+- __write_proc,__fops,__data) \
+- ({ \
+- struct proc_dir_entry *__entry; \
+- int __mode = (S_IFREG | S_IRUGO); \
+- if ((NvUPtr)(__write_proc) != 0) \
+- __mode |= S_IWUSR; \
+- __entry = NV_CREATE_PROC_ENTRY(name, __mode, parent); \
+- if (__entry != NULL) \
+- { \
+- if ((NvUPtr)(__read_proc) != 0) \
+- __entry->read_proc = (__read_proc); \
+- if ((NvUPtr)(__write_proc) != 0) \
+- { \
+- __entry->write_proc = (__write_proc); \
+- __entry->proc_fops = (__fops); \
+- } \
+- __entry->data = (__data); \
+- } \
+- __entry; \
+- })
++#define NV_PROC_RW (S_IFREG|S_IRUGO|S_IWUSR)
++#define NV_PROC_RO (S_IFREG|S_IRUGO)
+
+ #define NV_CREATE_PROC_DIR(name,parent) \
+ ({ \
+ struct proc_dir_entry *__entry; \
+ int __mode = (S_IFDIR | S_IRUGO | S_IXUGO); \
+- __entry = NV_CREATE_PROC_ENTRY(name, __mode, parent); \
++ __entry = proc_mkdir_mode(name, __mode, parent); \
+ __entry; \
+ })
+
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,9,255)
++static inline void *PDE_DATA(const struct inode *inode) {
++ return PDE(inode)->data;
++}
++#endif
++
+ #define NV_PROC_WRITE_BUFFER_SIZE (64 * RM_PAGE_SIZE)
+
+ static int
+-nv_procfs_read_gpu_info(
+- char *page,
+- char **start,
+- off_t off,
+- int count,
+- int *eof,
+- void *data
++nv_procfs_show_gpu_info(
++ struct seq_file *m,
++ void *v
+ )
+ {
+- nv_state_t *nv = data;
++ nv_state_t *nv = m->private;
+ nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
+ struct pci_dev *dev = nvl->dev;
+ char *type, *fmt, tmpstr[NV_DEVICE_NAME_LENGTH];
+- int len = 0, status;
++ int status;
+ NvU8 *uuid;
+ NvU32 vbios_rev1, vbios_rev2, vbios_rev3, vbios_rev4, vbios_rev5;
+ NvU32 fpga_rev1, fpga_rev2, fpga_rev3;
+ nv_stack_t *sp = NULL;
+
+- *eof = 1;
+-
+ NV_KMEM_CACHE_ALLOC_STACK(sp);
+ if (sp == NULL)
+ {
+@@ -134,31 +115,31 @@
+ if (rm_get_device_name(sp, nv, dev->device, dev->subsystem_vendor,
+ dev->subsystem_device, NV_DEVICE_NAME_LENGTH,
+ tmpstr) != RM_OK)
+- {
++ {
+ strcpy (tmpstr, "Unknown");
+ }
+ }
+
+- len += sprintf(page+len, "Model: \t\t %s\n", tmpstr);
+- len += sprintf(page+len, "IRQ: \t\t %d\n", nv->interrupt_line);
++ seq_printf(m, "Model: \t\t %s\n", tmpstr);
++ seq_printf(m, "IRQ: \t\t %d\n", nv->interrupt_line);
+
+ if (NV_IS_GVI_DEVICE(nv))
+ {
+ status = rm_gvi_get_firmware_version(sp, nv, &fpga_rev1, &fpga_rev2,
+ &fpga_rev3);
+ if (status != RM_OK)
+- len += sprintf(page+len, "Firmware: \t ????.??.??\n");
++ seq_printf(m, "Firmware: \t ????.??.??\n");
+ else
+ {
+ fmt = "Firmware: \t %x.%x.%x\n";
+- len += sprintf(page+len, fmt, fpga_rev1, fpga_rev2, fpga_rev3);
++ seq_printf(m, fmt, fpga_rev1, fpga_rev2, fpga_rev3);
+ }
+ }
+ else
+ {
+ if (rm_get_gpu_uuid(sp, nv, &uuid, NULL) == RM_OK)
+ {
+- len += sprintf(page+len, "GPU UUID: \t %s\n", (char *)uuid);
++ seq_printf(m, "GPU UUID: \t %s\n", (char *)uuid);
+ os_free_mem(uuid);
+ }
+
+@@ -166,12 +147,12 @@
+ &vbios_rev3, &vbios_rev4,
+ &vbios_rev5) != RM_OK)
+ {
+- len += sprintf(page+len, "Video BIOS: \t ??.??.??.??.??\n");
++ seq_printf(m, "Video BIOS: \t ??.??.??.??.??\n");
+ }
+ else
+ {
+ fmt = "Video BIOS: \t %02x.%02x.%02x.%02x.%02x\n";
+- len += sprintf(page+len, fmt, vbios_rev1, vbios_rev2,
vbios_rev3,
++ seq_printf(m, fmt, vbios_rev1, vbios_rev2, vbios_rev3,
+ vbios_rev4, vbios_rev5);
+ }
+ }
+@@ -180,12 +161,12 @@
+ type = "PCI-E";
+ else
+ type = "PCI";
+- len += sprintf(page+len, "Bus Type: \t %s\n", type);
++ seq_printf(m, "Bus Type: \t %s\n", type);
+
+- len += sprintf(page+len, "DMA Size: \t %d bits\n",
++ seq_printf(m, "DMA Size: \t %d bits\n",
+ nv_count_bits(dev->dma_mask));
+- len += sprintf(page+len, "DMA Mask: \t 0x%llx\n", dev->dma_mask);
+- len += sprintf(page+len, "Bus Location: \t %04x:%02x.%02x.%x\n",
++ seq_printf(m, "DMA Mask: \t 0x%llx\n", dev->dma_mask);
++ seq_printf(m, "Bus Location: \t %04x:%02x.%02x.%x\n",
+ nv->domain, nv->bus, nv->slot, PCI_FUNC(dev->devfn));
+ #if defined(DEBUG)
+ do
+@@ -193,7 +174,7 @@
+ int j;
+ for (j = 0; j < NV_GPU_NUM_BARS; j++)
+ {
+- len += sprintf(page+len, "BAR%u: \t\t 0x%llx (%lluMB)\n",
++ seq_printf(m, "BAR%u: \t\t 0x%llx (%lluMB)\n",
+ j, nv->bars[j].address, (nv->bars[j].size >>
20));
+ }
+ } while (0);
+@@ -201,26 +182,120 @@
+
+ NV_KMEM_CACHE_FREE_STACK(sp);
+
+- return len;
++ return 0;
+ }
+
+ static int
+-nv_procfs_read_version(
+- char *page,
+- char **start,
+- off_t off,
+- int count,
+- int *eof,
+- void *data
++nv_procfs_open_gpu_info(
++ struct inode *inode,
++ struct file *file
++)
++{
++ return single_open(file, nv_procfs_show_gpu_info, PDE_DATA(inode));
++}
++
++static const struct file_operations nv_procfs_gpu_info_fops = {
++ .owner = THIS_MODULE,
++ .open = nv_procfs_open_gpu_info,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int
++nv_procfs_show_version(
++ struct seq_file *m,
++ void *v
++)
++{
++ seq_printf(m, "NVRM version: %s\n", pNVRM_ID);
++ seq_printf(m, "GCC version: %s\n", NV_COMPILER);
++
++ return 0;
++}
++
++static int
++nv_procfs_open_version(
++ struct inode *inode,
++ struct file *file
++)
++{
++ return single_open(file, nv_procfs_show_version, NULL);
++}
++
++static const struct file_operations nv_procfs_version_fops = {
++ .owner = THIS_MODULE,
++ .open = nv_procfs_open_version,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int
++nv_procfs_show_registry(
++ struct seq_file *m,
++ void *v
++)
++{
++ nv_state_t *nv = m->private;
++ nv_linux_state_t *nvl = NULL;
++ char *registry_keys;
++
++ if (nv != NULL)
++ nvl = NV_GET_NVL_FROM_NV_STATE(nv);
++ registry_keys = ((nvl != NULL) ?
++ nvl->registry_keys : nv_registry_keys);
++
++ seq_printf(m, "Binary: \"%s\"\n", registry_keys);
++
++ return 0;
++}
++
++static ssize_t
++nv_procfs_write_registry(
++ struct file *file,
++ const char __user *buffer,
++ size_t count,
++ loff_t *pos
+ )
+ {
+- int len = 0;
+- *eof = 1;
++ int status = 0;
++ nv_file_private_t *nvfp = NV_GET_FILE_PRIVATE(file);
++ char *proc_buffer;
++ unsigned long bytes_left;
++
++ down(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]);
++
++ bytes_left = (NV_PROC_WRITE_BUFFER_SIZE - nvfp->off - 1);
++
++ if (count == 0)
++ {
++ status = -EINVAL;
++ goto done;
++ }
++ else if ((bytes_left == 0) || (count > bytes_left))
++ {
++ status = -ENOSPC;
++ goto done;
++ }
++
++ proc_buffer = &((char *)nvfp->data)[nvfp->off];
++
++ if (copy_from_user(proc_buffer, buffer, count))
++ {
++ nv_printf(NV_DBG_ERRORS, "NVRM: failed to copy in proc data!\n");
++ status = -EFAULT;
++ }
++ else
++ {
++ nvfp->proc_data = PDE_DATA(file->f_inode);
++ nvfp->off += count;
++ }
+
+- len += sprintf(page+len, "NVRM version: %s\n", pNVRM_ID);
+- len += sprintf(page+len, "GCC version: %s\n", NV_COMPILER);
++done:
++ up(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]);
+
+- return len;
++ return ((status < 0) ? status : count);
+ }
+
+ static int
+@@ -233,7 +308,7 @@
+ nv_stack_t *sp = NULL;
+
+ if (0 == (file->f_mode & FMODE_WRITE))
+- return 0;
++ return single_open(file, nv_procfs_show_registry, PDE_DATA(inode));
+
+ nvfp = nv_alloc_file_private();
+ if (nvfp == NULL)
+@@ -282,6 +357,9 @@
+ RM_STATUS rm_status;
+ int rc = 0;
+
++ if (0 == (file->f_mode & FMODE_WRITE))
++ return single_release(inode, file);
++
+ nvfp = NV_GET_FILE_PRIVATE(file);
+ if (nvfp == NULL)
+ return 0;
+@@ -346,122 +424,81 @@
+ return rc;
+ }
+
+-static struct file_operations nv_procfs_registry_fops = {
++static const struct file_operations nv_procfs_registry_fops = {
+ .open = nv_procfs_open_registry,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .write = nv_procfs_write_registry,
+ .release = nv_procfs_close_registry,
+ };
+
+ static int
+-nv_procfs_read_params(
+- char *page,
+- char **start,
+- off_t off,
+- int count,
+- int *eof,
+- void *data
++nv_procfs_show_params(
++ struct seq_file *m,
++ void *v
+ )
+ {
+ unsigned int i;
+- int len = 0;
+ nv_parm_t *entry;
+
+- *eof = 1;
+
+ for (i = 0; (entry = &nv_parms[i])->name != NULL; i++)
+- len += sprintf(page+len, "%s: %u\n", entry->name, *entry->data);
++ seq_printf(m, "%s: %u\n", entry->name, *entry->data);
+
+- len += sprintf(page+len, "RegistryDwords: \"%s\"\n",
++ seq_printf(m, "RegistryDwords: \"%s\"\n",
+ (NVreg_RegistryDwords != NULL) ? NVreg_RegistryDwords : "");
+- len += sprintf(page+len, "RmMsg: \"%s\"\n",
++ seq_printf(m, "RmMsg: \"%s\"\n",
+ (NVreg_RmMsg != NULL) ? NVreg_RmMsg : "");
+
+- return len;
++ return 0;
+ }
+
+ static int
+-nv_procfs_read_registry(
+- char *page,
+- char **start,
+- off_t off,
+- int count,
+- int *eof,
+- void *data
+-)
++nv_procfs_open_params(
++ struct inode *inode,
++ struct file *file
++)
+ {
+- nv_state_t *nv = data;
+- nv_linux_state_t *nvl = NULL;
+- char *registry_keys;
++ return single_open(file, nv_procfs_show_params, NULL);
++}
+
+- if (nv != NULL)
+- nvl = NV_GET_NVL_FROM_NV_STATE(nv);
+- registry_keys = ((nvl != NULL) ?
+- nvl->registry_keys : nv_registry_keys);
++static const struct file_operations nv_procfs_params_fops = {
++ .owner = THIS_MODULE,
++ .open = nv_procfs_open_params,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
+
+- *eof = 1;
+- return sprintf(page, "Binary: \"%s\"\n", registry_keys);
+-}
+
+ static int
+-nv_procfs_write_registry(
+- struct file *file,
+- const char *buffer,
+- unsigned long count,
+- void *data
++nv_procfs_show_text_file(
++ struct seq_file *m,
++ void *v
+ )
+ {
+- int status = 0;
+- nv_file_private_t *nvfp = NV_GET_FILE_PRIVATE(file);
+- char *proc_buffer;
+- unsigned long bytes_left;
+-
+- down(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]);
+-
+- bytes_left = (NV_PROC_WRITE_BUFFER_SIZE - nvfp->off - 1);
++ seq_printf(m, "%s", (char *)m->private);
+
+- if (count == 0)
+- {
+- status = -EINVAL;
+- goto done;
+- }
+- else if ((bytes_left == 0) || (count > bytes_left))
+- {
+- status = -ENOSPC;
+- goto done;
+- }
+-
+- proc_buffer = &((char *)nvfp->data)[nvfp->off];
+-
+- if (copy_from_user(proc_buffer, buffer, count))
+- {
+- nv_printf(NV_DBG_ERRORS, "NVRM: failed to copy in proc data!\n");
+- status = -EFAULT;
+- }
+- else
+- {
+- nvfp->proc_data = data;
+- nvfp->off += count;
+- }
+-
+-done:
+- up(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]);
+-
+- return ((status < 0) ? status : (int)count);
++ return 0;
+ }
+
+ static int
+-nv_procfs_read_text_file(
+- char *page,
+- char **start,
+- off_t off,
+- int count,
+- int *eof,
+- void *data
++nv_procfs_open_text_file(
++ struct inode *inode,
++ struct file *file
+ )
+ {
+- *eof = 1;
+- return sprintf(page, "%s", (char *)data);
++ return single_open(file, nv_procfs_show_text_file, PDE_DATA(inode));
+ }
+
++static const struct file_operations nv_procfs_text_fops = {
++ .owner = THIS_MODULE,
++ .open = nv_procfs_open_text_file,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
+ static void
+ nv_procfs_add_text_file(
+ struct proc_dir_entry *parent,
+@@ -469,22 +506,7 @@
+ const char *text
+ )
+ {
+- NV_CREATE_PROC_FILE(filename, parent,
+- nv_procfs_read_text_file, NULL, NULL, (void *)text);
+-}
+-
+-static void nv_procfs_unregister_all(struct proc_dir_entry *entry)
+-{
+- while (entry)
+- {
+- struct proc_dir_entry *next = entry->next;
+- if (entry->subdir)
+- nv_procfs_unregister_all(entry->subdir);
+- remove_proc_entry(entry->name, entry->parent);
+- if (entry == proc_nvidia)
+- break;
+- entry = next;
+- }
++ proc_create_data(filename, NV_PROC_RO, parent, &nv_procfs_text_fops,
(void *)text);
+ }
+ #endif
+
+@@ -513,26 +535,11 @@
+ if (!proc_nvidia)
+ goto failed;
+
+- entry = NV_CREATE_PROC_FILE("params", proc_nvidia,
+- nv_procfs_read_params, NULL, NULL, NULL);
++ entry = proc_create("params", NV_PROC_RO, proc_nvidia,
&nv_procfs_params_fops);
+ if (!entry)
+ goto failed;
+
+- /*
+- * entry->proc_fops originally points to a constant
+- * structure, so to add more methods for the
+- * binary registry write path, we need to replace the
+- * said entry->proc_fops with a new fops structure.
+- * However, in preparation for this, we need to preserve
+- * the procfs read() and write() operations.
+- */
+- nv_procfs_registry_fops.read = entry->proc_fops->read;
+- nv_procfs_registry_fops.write = entry->proc_fops->write;
+-
+- entry = NV_CREATE_PROC_FILE("registry", proc_nvidia,
+- nv_procfs_read_registry,
+- nv_procfs_write_registry,
+- &nv_procfs_registry_fops, NULL);
++ entry = proc_create("registry", NV_PROC_RW, proc_nvidia,
&nv_procfs_registry_fops);
+ if (!entry)
+ goto failed;
+
+@@ -553,8 +560,7 @@
+
+ nv_procfs_add_text_file(proc_nvidia_patches, "README",
__README_patches);
+
+- entry = NV_CREATE_PROC_FILE("version", proc_nvidia,
+- nv_procfs_read_version, NULL, NULL, NULL);
++ entry = proc_create("version", NV_PROC_RO, proc_nvidia,
&nv_procfs_version_fops);
+ if (!entry)
+ goto failed;
+
+@@ -571,15 +577,11 @@
+ if (!proc_nvidia_gpu)
+ goto failed;
+
+- entry = NV_CREATE_PROC_FILE("information", proc_nvidia_gpu,
+- nv_procfs_read_gpu_info, NULL, NULL, nv);
++ entry = proc_create_data("information", NV_PROC_RO, proc_nvidia_gpu,
&nv_procfs_gpu_info_fops, nv);
+ if (!entry)
+ goto failed;
+
+- entry = NV_CREATE_PROC_FILE("registry", proc_nvidia_gpu,
+- nv_procfs_read_registry,
+- nv_procfs_write_registry,
+- &nv_procfs_registry_fops, nv);
++ entry = proc_create_data("registry", NV_PROC_RW, proc_nvidia_gpu,
&nv_procfs_registry_fops, nv);
+ if (!entry)
+ goto failed;
+ }
+@@ -587,7 +589,7 @@
+ return 0;
+ #if defined(CONFIG_PROC_FS)
+ failed:
+- nv_procfs_unregister_all(proc_nvidia);
++ remove_proc_subtree("nvidia", proc_nvidia);
+ return -1;
+ #endif
+ }
+@@ -595,6 +597,6 @@
+ void nv_unregister_procfs(void)
+ {
+ #if defined(CONFIG_PROC_FS)
+- nv_procfs_unregister_all(proc_nvidia);
++ remove_proc_subtree("nvidia", proc_nvidia);
+ #endif
+ }



  • [SM-Commit] GIT changes to master z-rejected grimoire by Florian Franzmann (de4d893a8f4973d32f3a272e9db2954e7e0eedf8), Florian Franzmann, 07/07/2013

Archive powered by MHonArc 2.6.24.

Top of Page