Skip to content

Commit

Permalink
Change table chaining layout
Browse files Browse the repository at this point in the history
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: Jens Axboe <jens.axboe@oracle.com>
  • Loading branch information
Jens Axboe committed Oct 22, 2007
1 parent 58b053e commit 18dabf4
Show file tree
Hide file tree
Showing 25 changed files with 79 additions and 49 deletions.
2 changes: 1 addition & 1 deletion include/asm-alpha/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <asm/types.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;

unsigned int length;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-arm/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion include/asm-avr32/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-blackfin/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-cris/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

};
Expand Down
2 changes: 1 addition & 1 deletion include/asm-frv/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-h8300/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-ia64/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion include/asm-m32r/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-m68k/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <linux/types.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;

Expand Down
2 changes: 1 addition & 1 deletion include/asm-m68knommu/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-mips/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-parisc/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <asm/types.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;

unsigned int length;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-powerpc/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <asm/dma.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;

Expand Down
2 changes: 1 addition & 1 deletion include/asm-s390/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define _ASMS390_SCATTERLIST_H

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;
unsigned int length;
};
Expand Down
2 changes: 1 addition & 1 deletion include/asm-sh/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-sh64/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-sparc/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <linux/types.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;

unsigned int length;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-sparc64/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <asm/types.h>

struct scatterlist {
struct page *page;
unsigned long page_link;
unsigned int offset;

unsigned int length;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-v850/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions include/asm-x86/dma-mapping_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion include/asm-x86/scatterlist_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-x86/scatterlist_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion include/asm-xtensa/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
78 changes: 54 additions & 24 deletions include/linux/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
{
Expand All @@ -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);

Expand All @@ -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)
{
Expand All @@ -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;
}

/**
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 18dabf4

Please sign in to comment.