Commit 18dabf47 authored by Jens Axboe's avatar Jens Axboe

Change table chaining layout

Change the page member of the scatterlist structure to be an unsigned
long, and encode more stuff in the lower bits:

- Bits 0 and 1 zero: this is a normal sg entry. Next sg entry is located
  at sg + 1.
- Bit 0 set: this is a chain entry, the next real entry is at ->page_link
  with the two low bits masked off.
- Bit 1 set: this is the final entry in the sg entry. sg_next() will return
  NULL when passed such an entry.

It's thus important that sg table users use the proper accessors to get
and set the page member.
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 58b053e4
......@@ -5,7 +5,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -5,7 +5,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page; /* buffer page */
unsigned long page_link;
unsigned int offset; /* buffer offset */
dma_addr_t dma_address; /* dma address */
unsigned int length; /* length */
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -4,7 +4,7 @@
#include <linux/mm.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -6,7 +6,7 @@ struct scatterlist {
unsigned int length;
/* The following is i386 highmem junk - not used by us */
struct page * page; /* Location for highmem page, if any */
unsigned long page_link;
unsigned int offset;/* for highmem, page offset */
};
......
......@@ -22,7 +22,7 @@
* and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
*/
struct scatterlist {
struct page *page; /* Location for highmem page, if any */
unsigned long page_link;
unsigned int offset; /* for highmem, page offset */
dma_addr_t dma_address;
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -9,7 +9,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length; /* buffer length */
......
......@@ -6,7 +6,7 @@
struct scatterlist {
char * address; /* Location data is to be transferred to, NULL for
* highmem page */
struct page * page; /* Location for highmem page, if any */
unsigned long page_link;
unsigned int offset;/* for highmem, page offset */
dma_addr_t dma_address;
......
......@@ -4,7 +4,7 @@
#include <linux/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -5,7 +5,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page * page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -5,7 +5,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -14,7 +14,7 @@
#include <asm/dma.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -2,7 +2,7 @@
#define _ASMS390_SCATTERLIST_H
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
};
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page * page; /* Location for highmem page, if any */
unsigned long page_link;
unsigned int offset;/* for highmem, page offset */
dma_addr_t dma_address;
unsigned int length;
......
......@@ -14,7 +14,7 @@
#include <asm/types.h>
struct scatterlist {
struct page * page; /* Location for highmem page, if any */
unsigned long page_link;
unsigned int offset;/* for highmem, page offset */
dma_addr_t dma_address;
unsigned int length;
......
......@@ -5,7 +5,7 @@
#include <linux/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -6,7 +6,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
......
......@@ -17,7 +17,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned offset;
dma_addr_t dma_address;
unsigned length;
......
......@@ -45,9 +45,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
WARN_ON(nents == 0 || sglist[0].length == 0);
for_each_sg(sglist, sg, nents, i) {
BUG_ON(!sg->page);
BUG_ON(!sg_page(sg));
sg->dma_address = page_to_phys(sg->page) + sg->offset;
sg->dma_address = sg_phys(sg);
}
flush_write_buffers();
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -4,7 +4,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
dma_addr_t dma_address;
......
......@@ -14,7 +14,7 @@
#include <asm/types.h>
struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
......
......@@ -2,9 +2,26 @@
#define _LINUX_SCATTERLIST_H
#include <asm/scatterlist.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <asm/io.h>
/*
* Notes on SG table design.
*
* Architectures must provide an unsigned long page_link field in the
* scatterlist struct. We use that to place the page pointer AND encode
* information about the sg table as well. The two lower bits are reserved
* for this information.
*
* If bit 0 is set, then the page_link contains a pointer to the next sg
* table list. Otherwise the next entry is at sg + 1.
*
* If bit 1 is set, then this sg entry is the last element in a list.
*
* See sg_next().
*
*/
/**
* sg_set_page - Set sg entry to point at given page
......@@ -20,11 +37,20 @@
**/
static inline void sg_set_page(struct scatterlist *sg, struct page *page)
{
sg->page = page;
unsigned long page_link = sg->page_link & 0x3;
sg->page_link = page_link | (unsigned long) page;
}
#define sg_page(sg) ((sg)->page)
#define sg_page(sg) ((struct page *) ((sg)->page_link & ~0x3))
/**
* sg_set_buf - Set sg entry to point at given data
* @sg: SG entry
* @buf: Data
* @buflen: Data length
*
**/
static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
unsigned int buflen)
{
......@@ -38,26 +64,27 @@ static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
* a valid sg entry, or whether it points to the start of a new scatterlist.
* Those low bits are there for everyone! (thanks mason :-)
*/
#define sg_is_chain(sg) ((unsigned long) (sg)->page & 0x01)
#define sg_is_chain(sg) ((sg)->page_link & 0x01)
#define sg_is_last(sg) ((sg)->page_link & 0x02)
#define sg_chain_ptr(sg) \
((struct scatterlist *) ((unsigned long) (sg)->page & ~0x01))
((struct scatterlist *) ((sg)->page_link & ~0x03))
/**
* sg_next - return the next scatterlist entry in a list
* @sg: The current sg entry
*
* Usually the next entry will be @sg@ + 1, but if this sg element is part
* of a chained scatterlist, it could jump to the start of a new
* scatterlist array.
*
* Note that the caller must ensure that there are further entries after
* the current entry, this function will NOT return NULL for an end-of-list.
* Description:
* Usually the next entry will be @sg@ + 1, but if this sg element is part
* of a chained scatterlist, it could jump to the start of a new
* scatterlist array.
*
*/
**/
static inline struct scatterlist *sg_next(struct scatterlist *sg)
{
sg++;
if (sg_is_last(sg))
return NULL;
sg++;
if (unlikely(sg_is_chain(sg)))
sg = sg_chain_ptr(sg);
......@@ -75,14 +102,15 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg)
* @sgl: First entry in the scatterlist
* @nents: Number of entries in the scatterlist
*
* Should only be used casually, it (currently) scan the entire list
* to get the last entry.
* Description:
* Should only be used casually, it (currently) scan the entire list
* to get the last entry.
*
* Note that the @sgl@ pointer passed in need not be the first one,
* the important bit is that @nents@ denotes the number of entries that
* exist from @sgl@.
* Note that the @sgl@ pointer passed in need not be the first one,
* the important bit is that @nents@ denotes the number of entries that
* exist from @sgl@.
*
*/
**/
static inline struct scatterlist *sg_last(struct scatterlist *sgl,
unsigned int nents)
{
......@@ -105,16 +133,17 @@ static inline struct scatterlist *sg_last(struct scatterlist *sgl,
* @prv_nents: Number of entries in prv
* @sgl: Second scatterlist
*
* Links @prv@ and @sgl@ together, to form a longer scatterlist.
* Description:
* Links @prv@ and @sgl@ together, to form a longer scatterlist.
*
*/
**/
static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
struct scatterlist *sgl)
{
#ifndef ARCH_HAS_SG_CHAIN
BUG();
#endif
prv[prv_nents - 1].page = (struct page *) ((unsigned long) sgl | 0x01);
prv[prv_nents - 1].page_link = (unsigned long) sgl | 0x01;
}
/**
......@@ -128,13 +157,14 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
**/
static inline void sg_mark_end(struct scatterlist *sgl, unsigned int nents)
{
sgl[nents - 1].page_link = 0x02;
}
static inline void __sg_mark_end(struct scatterlist *sg)
{
sg->page_link |= 0x02;
}
/**
* sg_init_one - Initialize a single entry sg list
* @sg: SG entry
......@@ -187,7 +217,7 @@ static inline unsigned long sg_phys(struct scatterlist *sg)
/**
* sg_virt - Return virtual address of an sg entry
* @sg: SG entry
* @sg: SG entry
*
* Description:
* This calls page_address() on the page in this sg entry, and adds the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment